~alan-griffiths/mir/fix-1654023

« back to all changes in this revision

Viewing changes to src/server/shell/basic_window_manager.h

  • Committer: Daniel van Vugt
  • Date: 2015-04-28 07:54:10 UTC
  • mfrom: (2517 development-branch)
  • mto: This revision was merged to the branch mainline in revision 2673.
  • Revision ID: daniel.van.vugt@canonical.com-20150428075410-rwskshfuar7voesp
Merge latest trunk and fix conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2015 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 3,
 
6
 * as published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored By: Alan Griffiths <alan@octopull.co.uk>
 
17
 */
 
18
 
 
19
#ifndef MIR_SHELL_BASIC_WINDOW_MANAGER_H_
 
20
#define MIR_SHELL_BASIC_WINDOW_MANAGER_H_
 
21
 
 
22
#include "mir/geometry/rectangles.h"
 
23
#include "mir/scene/session.h"
 
24
#include "mir/scene/surface.h"
 
25
#include "mir/scene/surface_creation_parameters.h"
 
26
#include "mir/shell/abstract_shell.h"
 
27
#include "mir/shell/window_manager.h"
 
28
 
 
29
#include <map>
 
30
#include <mutex>
 
31
 
 
32
namespace mir
 
33
{
 
34
namespace shell
 
35
{
 
36
template<typename Info>
 
37
struct SurfaceTo
 
38
{
 
39
    using type = std::map<std::weak_ptr<scene::Surface>, Info, std::owner_less<std::weak_ptr<scene::Surface>>>;
 
40
};
 
41
 
 
42
template<typename Info>
 
43
struct SessionTo
 
44
{
 
45
    using type = std::map<std::weak_ptr<scene::Session>, Info, std::owner_less<std::weak_ptr<scene::Session>>>;
 
46
};
 
47
 
 
48
/// The interface through which the policy instructs the controller.
 
49
/// These functions assume that the BasicWindowManager data structures can be accessed freely.
 
50
/// I.e. should only be invoked by the policy handle_... methods (where any necessary locks are held).
 
51
template<typename SessionInfo, typename SurfaceInfo>
 
52
class BasicWindowManagerTools
 
53
{
 
54
public:
 
55
    virtual auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
 
56
    -> std::shared_ptr<scene::Session> = 0;
 
57
 
 
58
    virtual auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& = 0;
 
59
 
 
60
    virtual auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& = 0;
 
61
 
 
62
    virtual auto focused_session() const -> std::shared_ptr<scene::Session> = 0;
 
63
 
 
64
    virtual auto focused_surface() const -> std::shared_ptr<scene::Surface> = 0;
 
65
 
 
66
    virtual void focus_next_session() = 0;
 
67
 
 
68
    virtual void set_focus_to(
 
69
        std::shared_ptr<scene::Session> const& focus,
 
70
        std::shared_ptr<scene::Surface> const& surface) = 0;
 
71
 
 
72
    virtual auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> = 0;
 
73
 
 
74
    virtual void raise(SurfaceSet const& surfaces) = 0;
 
75
 
 
76
    virtual auto active_display() -> geometry::Rectangle const = 0;
 
77
 
 
78
    virtual ~BasicWindowManagerTools() = default;
 
79
    BasicWindowManagerTools() = default;
 
80
    BasicWindowManagerTools(BasicWindowManagerTools const&) = delete;
 
81
    BasicWindowManagerTools& operator=(BasicWindowManagerTools const&) = delete;
 
82
};
 
83
 
 
84
/// A policy based window manager.
 
85
/// This takes care of the management of any meta implementation held for the sessions and surfaces.
 
86
///
 
87
/// \tparam WindowManagementPolicy the constructor must take a pointer to BasicWindowManagerTools<>
 
88
/// as its first parameter. (Any additional parameters can be forwarded by
 
89
/// BasicWindowManager::BasicWindowManager.)
 
90
/// In addition WindowManagementPolicy must implement the following methods:
 
91
/// - void handle_session_info_updated(SessionInfoMap& session_info, Rectangles const& displays);
 
92
/// - void handle_displays_updated(SessionInfoMap& session_info, Rectangles const& displays);
 
93
/// - auto handle_place_new_surface(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& request_parameters) -> ms::SurfaceCreationParameters;
 
94
/// - void handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface);
 
95
/// - void handle_delete_surface(std::shared_ptr<ms::Session> const& /*session*/, std::weak_ptr<ms::Surface> const& /*surface*/);
 
96
/// - int handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value);
 
97
/// - bool handle_keyboard_event(MirKeyboardEvent const* event);
 
98
/// - bool handle_touch_event(MirTouchEvent const* event);
 
99
/// - bool handle_pointer_event(MirPointerEvent const* event);
 
100
///
 
101
/// \tparam SessionInfo must be default constructable.
 
102
///
 
103
/// \tparam SurfaceInfo must be constructable from (std::shared_ptr<ms::Session>, std::shared_ptr<ms::Surface>, ms::SurfaceCreationParameters const& params)
 
104
template<typename WindowManagementPolicy, typename SessionInfo, typename SurfaceInfo>
 
105
class BasicWindowManager : public WindowManager,
 
106
    private BasicWindowManagerTools<SessionInfo, SurfaceInfo>
 
107
{
 
108
public:
 
109
    template <typename... PolicyArgs>
 
110
    BasicWindowManager(
 
111
        FocusController* focus_controller,
 
112
        PolicyArgs&&... policy_args) :
 
113
        focus_controller(focus_controller),
 
114
        policy(this, std::forward<PolicyArgs>(policy_args)...)
 
115
    {
 
116
    }
 
117
 
 
118
protected:
 
119
    void add_session(std::shared_ptr<scene::Session> const& session) override
 
120
    {
 
121
        std::lock_guard<decltype(mutex)> lock(mutex);
 
122
        session_info[session] = SessionInfo();
 
123
        policy.handle_session_info_updated(session_info, displays);
 
124
    }
 
125
 
 
126
    void remove_session(std::shared_ptr<scene::Session> const& session) override
 
127
    {
 
128
        std::lock_guard<decltype(mutex)> lock(mutex);
 
129
        session_info.erase(session);
 
130
        policy.handle_session_info_updated(session_info, displays);
 
131
    }
 
132
 
 
133
    frontend::SurfaceId add_surface(
 
134
        std::shared_ptr<scene::Session> const& session,
 
135
        scene::SurfaceCreationParameters const& params,
 
136
        std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) override
 
137
    {
 
138
        std::lock_guard<decltype(mutex)> lock(mutex);
 
139
        scene::SurfaceCreationParameters const placed_params = policy.handle_place_new_surface(session, params);
 
140
        auto const result = build(session, placed_params);
 
141
        auto const surface = session->surface(result);
 
142
        policy.handle_new_surface(session, surface);
 
143
        surface_info.emplace(surface, SurfaceInfo{session, surface, placed_params});
 
144
        return result;
 
145
    }
 
146
 
 
147
    void modify_surface(
 
148
        std::shared_ptr<scene::Session> const& session,
 
149
        std::shared_ptr<scene::Surface> const& surface,
 
150
        shell::SurfaceSpecification const& modifications) override
 
151
    {
 
152
        std::lock_guard<decltype(mutex)> lock(mutex);
 
153
        policy.handle_modify_surface(session, surface, modifications);
 
154
    }
 
155
 
 
156
    void remove_surface(
 
157
        std::shared_ptr<scene::Session> const& session,
 
158
        std::weak_ptr<scene::Surface> const& surface) override
 
159
    {
 
160
        std::lock_guard<decltype(mutex)> lock(mutex);
 
161
        policy.handle_delete_surface(session, surface);
 
162
 
 
163
        surface_info.erase(surface);
 
164
    }
 
165
 
 
166
    void add_display(geometry::Rectangle const& area) override
 
167
    {
 
168
        std::lock_guard<decltype(mutex)> lock(mutex);
 
169
        displays.add(area);
 
170
        policy.handle_displays_updated(session_info, displays);
 
171
    }
 
172
 
 
173
    void remove_display(geometry::Rectangle const& area) override
 
174
    {
 
175
        std::lock_guard<decltype(mutex)> lock(mutex);
 
176
        displays.remove(area);
 
177
        policy.handle_displays_updated(session_info, displays);
 
178
    }
 
179
 
 
180
    bool handle_keyboard_event(MirKeyboardEvent const* event) override
 
181
    {
 
182
        std::lock_guard<decltype(mutex)> lock(mutex);
 
183
        return policy.handle_keyboard_event(event);
 
184
    }
 
185
 
 
186
    bool handle_touch_event(MirTouchEvent const* event) override
 
187
    {
 
188
        std::lock_guard<decltype(mutex)> lock(mutex);
 
189
        return policy.handle_touch_event(event);
 
190
    }
 
191
 
 
192
    bool handle_pointer_event(MirPointerEvent const* event) override
 
193
    {
 
194
        std::lock_guard<decltype(mutex)> lock(mutex);
 
195
 
 
196
        cursor = {
 
197
            mir_pointer_event_axis_value(event, mir_pointer_axis_x),
 
198
            mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
 
199
 
 
200
        return policy.handle_pointer_event(event);
 
201
    }
 
202
 
 
203
    int set_surface_attribute(
 
204
        std::shared_ptr<scene::Session> const& /*session*/,
 
205
        std::shared_ptr<scene::Surface> const& surface,
 
206
        MirSurfaceAttrib attrib,
 
207
        int value) override
 
208
    {
 
209
        std::lock_guard<decltype(mutex)> lock(mutex);
 
210
        switch (attrib)
 
211
        {
 
212
        case mir_surface_attrib_state:
 
213
        {
 
214
            auto const state = policy.handle_set_state(surface, MirSurfaceState(value));
 
215
            return surface->configure(attrib, state);
 
216
        }
 
217
        default:
 
218
            return surface->configure(attrib, value);
 
219
        }
 
220
    }
 
221
 
 
222
    auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
 
223
    -> std::shared_ptr<scene::Session> override
 
224
    {
 
225
        for(auto& info : session_info)
 
226
        {
 
227
            if (predicate(info.second))
 
228
            {
 
229
                return info.first.lock();
 
230
            }
 
231
        }
 
232
 
 
233
        return std::shared_ptr<scene::Session>{};
 
234
    }
 
235
 
 
236
    auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& override
 
237
    {
 
238
        return const_cast<SessionInfo&>(session_info.at(session));
 
239
    }
 
240
 
 
241
    auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& override
 
242
    {
 
243
        return const_cast<SurfaceInfo&>(surface_info.at(surface));
 
244
    }
 
245
 
 
246
    auto focused_session() const -> std::shared_ptr<scene::Session> override
 
247
    {
 
248
        return focus_controller->focused_session();
 
249
    }
 
250
 
 
251
    auto focused_surface() const -> std::shared_ptr<scene::Surface> override
 
252
    {
 
253
        return focus_controller->focused_surface();
 
254
    }
 
255
 
 
256
    void focus_next_session() override
 
257
    {
 
258
        focus_controller->focus_next_session();
 
259
    }
 
260
 
 
261
    void set_focus_to(
 
262
        std::shared_ptr<scene::Session> const& focus,
 
263
        std::shared_ptr<scene::Surface> const& surface) override
 
264
    {
 
265
        focus_controller->set_focus_to(focus, surface);
 
266
    }
 
267
 
 
268
    auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> override
 
269
    {
 
270
        return focus_controller->surface_at(cursor);
 
271
    }
 
272
 
 
273
    void raise(SurfaceSet const& surfaces) override
 
274
    {
 
275
        focus_controller->raise(surfaces);
 
276
    }
 
277
 
 
278
    auto active_display() -> geometry::Rectangle const override
 
279
    {
 
280
        geometry::Rectangle result;
 
281
 
 
282
        // 1. If a window has input focus, whichever display contains the largest
 
283
        //    proportion of the area of that window.
 
284
        if (auto const surface = focused_surface())
 
285
        {
 
286
            auto const surface_rect = surface->input_bounds();
 
287
            int max_overlap_area = -1;
 
288
 
 
289
            for (auto const& display : displays)
 
290
            {
 
291
                auto const intersection = surface_rect.intersection_with(display).size;
 
292
                if (intersection.width.as_int()*intersection.height.as_int() > max_overlap_area)
 
293
                {
 
294
                    max_overlap_area = intersection.width.as_int()*intersection.height.as_int();
 
295
                    result = display;
 
296
                }
 
297
            }
 
298
            return result;
 
299
        }
 
300
 
 
301
        // 2. Otherwise, if any window previously had input focus, for the window that had
 
302
        //    it most recently, the display that contained the largest proportion of the
 
303
        //    area of that window at the moment it closed, as long as that display is still
 
304
        //    available.
 
305
 
 
306
        // 3. Otherwise, the display that contains the pointer, if there is one.
 
307
        for (auto const& display : displays)
 
308
        {
 
309
            if (display.contains(cursor))
 
310
            {
 
311
                // Ignore the (unspecified) possiblity of overlapping displays
 
312
                return display;
 
313
            }
 
314
        }
 
315
 
 
316
        // 4. Otherwise, the primary display, if there is one (for example, the laptop display).
 
317
 
 
318
        // 5. Otherwise, the first display.
 
319
        if (displays.size())
 
320
            result = *displays.begin();
 
321
 
 
322
        return result;
 
323
    }
 
324
 
 
325
    FocusController* const focus_controller;
 
326
    WindowManagementPolicy policy;
 
327
 
 
328
    std::mutex mutex;
 
329
    typename SessionTo<SessionInfo>::type session_info;
 
330
    typename SurfaceTo<SurfaceInfo>::type surface_info;
 
331
    geometry::Rectangles displays;
 
332
    geometry::Point cursor;
 
333
};
 
334
}
 
335
}
 
336
 
 
337
#endif /* MIR_SHELL_BASIC_WINDOW_MANAGER_H_ */