~ubuntu-branches/ubuntu/wily/mir/wily-proposed

« back to all changes in this revision

Viewing changes to examples/server_example_window_management.cpp

  • Committer: Package Import Robot
  • Author(s): CI Train Bot
  • Date: 2015-05-12 13:12:55 UTC
  • mto: This revision was merged to the branch mainline in revision 96.
  • Revision ID: package-import@ubuntu.com-20150512131255-y7z12i8n4pbvo70x
Tags: upstream-0.13.0+15.10.20150512
ImportĀ upstreamĀ versionĀ 0.13.0+15.10.20150512

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 * Authored By: Alan Griffiths <alan@octopull.co.uk>
17
17
 */
18
18
 
19
 
#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER 
20
 
 
21
19
#include "server_example_window_management.h"
22
 
#include "server_example_fullscreen_placement_strategy.h"
 
20
 
 
21
#include "server_example_tiling_window_manager.h"
 
22
#include "server_example_canonical_window_manager.h"
 
23
#include "server_example_basic_window_manager.h"
23
24
 
24
25
#include "mir/abnormal_exit.h"
25
26
#include "mir/server.h"
26
 
#include "mir/geometry/rectangles.h"
27
 
#include "mir/geometry/displacement.h"
28
27
#include "mir/input/composite_event_filter.h"
29
28
#include "mir/options/option.h"
30
 
#include "mir/scene/session_listener.h"
31
 
#include "mir/shell/focus_controller.h"
32
 
 
33
 
#include <linux/input.h>
34
 
 
35
 
#include <map>
36
 
#include <vector>
37
 
#include <mutex>
38
 
 
39
 
namespace mc = mir::compositor;
 
29
#include "mir/shell/display_layout.h"
 
30
 
40
31
namespace me = mir::examples;
 
32
namespace mf = mir::frontend;
41
33
namespace mg = mir::graphics;
42
34
namespace mi = mir::input;
43
35
namespace ms = mir::scene;
45
37
using namespace mir::geometry;
46
38
 
47
39
///\example server_example_window_management.cpp
48
 
/// Demonstrate simple window management strategies
49
 
 
50
 
char const* const me::wm_option = "window-manager";
51
 
char const* const me::wm_description = "window management strategy [{tiling|fullscreen}]";
 
40
/// Demonstrate introducing a window management strategy
52
41
 
53
42
namespace
54
43
{
 
44
char const* const wm_option = "window-manager";
 
45
char const* const wm_description = "window management strategy [{tiling|fullscreen|canonical}]";
 
46
 
55
47
char const* const wm_tiling = "tiling";
56
48
char const* const wm_fullscreen = "fullscreen";
 
49
char const* const wm_canonical = "canonical";
 
50
 
 
51
struct NullSessionInfo
 
52
{
 
53
};
 
54
 
 
55
struct NullSurfaceInfo
 
56
{
 
57
    NullSurfaceInfo(
 
58
        std::shared_ptr<ms::Session> const& /*session*/,
 
59
        std::shared_ptr<ms::Surface> const& /*surface*/,
 
60
        ms::SurfaceCreationParameters const& /*params*/) {}
 
61
};
 
62
 
57
63
 
58
64
// Very simple - make every surface fullscreen
59
 
class FullscreenWindowManager : public me::WindowManager, me::FullscreenPlacementStrategy
60
 
{
61
 
public:
62
 
    using me::FullscreenPlacementStrategy::FullscreenPlacementStrategy;
63
 
 
64
 
private:
65
 
    void add_surface(std::shared_ptr<ms::Surface> const&, ms::Session*) override {}
66
 
 
67
 
    void remove_surface(std::weak_ptr<ms::Surface> const&, ms::Session*) override {}
68
 
 
69
 
    void add_session(std::shared_ptr<ms::Session> const&) override {}
70
 
 
71
 
    void remove_session(std::shared_ptr<ms::Session> const&) override {}
72
 
 
73
 
    void add_display(Rectangle const&) override {}
74
 
 
75
 
    void remove_display(Rectangle const&) override {}
76
 
 
77
 
    void click(Point) override {}
78
 
 
79
 
    void drag(Point) override {}
80
 
 
81
 
    void resize(Point) override {}
82
 
 
83
 
    void toggle(MirSurfaceState) override {}
84
 
 
85
 
    int select_attribute_value(ms::Surface const&, MirSurfaceAttrib, int requested_value) override
86
 
        { return requested_value; }
87
 
 
88
 
    void attribute_set(ms::Surface const&, MirSurfaceAttrib, int) override {}
89
 
};
90
 
 
91
 
// simple tiling algorithm:
92
 
//  o Switch apps: tap or click on the corresponding tile
93
 
//  o Move window: Alt-leftmousebutton drag
94
 
//  o Resize window: Alt-middle_button drag
95
 
//  o Maximize/restore current window (to tile size): Alt-F11
96
 
//  o Maximize/restore current window (to tile height): Shift-F11
97
 
//  o Maximize/restore current window (to tile width): Ctrl-F11
98
 
//  o client requests to maximize, vertically maximize & restore
99
 
class TilingWindowManager : public me::WindowManager
100
 
{
101
 
public:
102
 
    // We can't take the msh::FocusController directly as we create a WindowManager
103
 
    // in the_session_listener() and that is called when creating the focus controller
104
 
    using FocusControllerFactory = std::function<std::shared_ptr<msh::FocusController>()>;
105
 
 
106
 
    explicit TilingWindowManager(FocusControllerFactory const& focus_controller) :
107
 
        focus_controller{focus_controller}
108
 
    {
109
 
    }
110
 
 
111
 
    auto place(ms::Session const& session, ms::SurfaceCreationParameters const& request_parameters)
112
 
    -> ms::SurfaceCreationParameters override
113
 
    {
114
 
        auto parameters = request_parameters;
115
 
 
116
 
        std::lock_guard<decltype(mutex)> lock(mutex);
117
 
        auto const ptile = session_info.find(&session);
118
 
        if (ptile != end(session_info))
119
 
        {
120
 
            Rectangle const& tile = ptile->second.tile;
121
 
            parameters.top_left = parameters.top_left + (tile.top_left - Point{0, 0});
122
 
 
123
 
            clip_to_tile(parameters, tile);
124
 
        }
125
 
 
126
 
        return parameters;
127
 
    }
128
 
 
129
 
    void add_surface(
130
 
        std::shared_ptr<ms::Surface> const& surface,
131
 
        ms::Session* session) override
132
 
    {
133
 
        std::lock_guard<decltype(mutex)> lock(mutex);
134
 
        session_info[session].surfaces.push_back(surface);
135
 
        surface_info[surface].session = session_info[session].session;
136
 
        surface_info[surface].state = mir_surface_state_restored;
137
 
    }
138
 
 
139
 
    void remove_surface(
140
 
        std::weak_ptr<ms::Surface> const& surface,
141
 
        ms::Session* session) override
142
 
    {
143
 
        std::lock_guard<decltype(mutex)> lock(mutex);
144
 
        auto& surfaces = session_info[session].surfaces;
145
 
 
146
 
        for (auto i = begin(surfaces); i != end(surfaces); ++i)
147
 
        {
148
 
            if (surface.lock() == i->lock())
149
 
            {
150
 
                surfaces.erase(i);
151
 
                break;
152
 
            }
153
 
        }
154
 
 
155
 
        surface_info.erase(surface);
156
 
    }
157
 
 
158
 
    void add_session(std::shared_ptr<ms::Session> const& session) override
159
 
    {
160
 
        std::lock_guard<decltype(mutex)> lock(mutex);
161
 
        session_info[session.get()] = session;
162
 
        update_tiles();
163
 
    }
164
 
 
165
 
    void remove_session(std::shared_ptr<ms::Session> const& session) override
166
 
    {
167
 
        std::lock_guard<decltype(mutex)> lock(mutex);
168
 
        session_info.erase(session.get());
169
 
        update_tiles();
170
 
    }
171
 
 
172
 
    void add_display(Rectangle const& area) override
173
 
    {
174
 
        std::lock_guard<decltype(mutex)> lock(mutex);
175
 
        displays.add(area);
176
 
        update_tiles();
177
 
    }
178
 
 
179
 
    void remove_display(Rectangle const& area) override
180
 
    {
181
 
        std::lock_guard<decltype(mutex)> lock(mutex);
182
 
        displays.remove(area);
183
 
        update_tiles();
184
 
    }
185
 
 
186
 
    void click(Point cursor) override
187
 
    {
188
 
        std::lock_guard<decltype(mutex)> lock(mutex);
189
 
 
190
 
        if (auto const session = session_under(cursor))
191
 
            focus_controller()->set_focus_to(session);
192
 
 
193
 
        old_cursor = cursor;
194
 
    }
195
 
 
196
 
    void drag(Point cursor) override
197
 
    {
198
 
        std::lock_guard<decltype(mutex)> lock(mutex);
199
 
 
200
 
        if (auto const session = session_under(cursor))
201
 
        {
202
 
            if (session == session_under(old_cursor))
203
 
            {
204
 
                auto const& info = session_info[session.get()];
205
 
 
206
 
                if (drag(old_surface.lock(), cursor, old_cursor, info.tile))
207
 
                {
208
 
                    // Still dragging the same old_surface
209
 
                }
210
 
                else if (drag(session->default_surface(), cursor, old_cursor, info.tile))
211
 
                {
212
 
                    old_surface = session->default_surface();
213
 
                }
214
 
                else
215
 
                {
216
 
                    for (auto const& ps : info.surfaces)
217
 
                    {
218
 
                        auto const new_surface = ps.lock();
219
 
 
220
 
                        if (drag(new_surface, cursor, old_cursor, info.tile))
221
 
                        {
222
 
                            old_surface = new_surface;
223
 
                            break;
224
 
                        }
225
 
                    }
226
 
                }
227
 
            }
228
 
        }
229
 
 
230
 
        old_cursor = cursor;
231
 
    }
232
 
 
233
 
    void resize(Point cursor) override
234
 
    {
235
 
        std::lock_guard<decltype(mutex)> lock(mutex);
236
 
 
237
 
        if (auto const session = session_under(cursor))
238
 
        {
239
 
            if (session == session_under(old_cursor))
240
 
            {
241
 
                auto const& info = session_info[session.get()];
242
 
 
243
 
                if (resize(old_surface.lock(), cursor, old_cursor, info.tile))
244
 
                {
245
 
                    // Still dragging the same old_surface
246
 
                }
247
 
                else if (resize(session->default_surface(), cursor, old_cursor, info.tile))
248
 
                {
249
 
                    old_surface = session->default_surface();
250
 
                }
251
 
                else
252
 
                {
253
 
                    for (auto const& ps : info.surfaces)
254
 
                    {
255
 
                        auto const new_surface = ps.lock();
256
 
 
257
 
                        if (resize(new_surface, cursor, old_cursor, info.tile))
258
 
                        {
259
 
                            old_surface = new_surface;
260
 
                            break;
261
 
                        }
262
 
                    }
263
 
                }
264
 
            }
265
 
        }
266
 
 
267
 
        old_cursor = cursor;
268
 
    }
269
 
 
270
 
    void toggle(MirSurfaceState state) override
271
 
    {
272
 
        if (auto const focussed_session = focus_controller()->focussed_application().lock())
273
 
        {
274
 
            if (auto const focussed_surface = focussed_session->default_surface())
275
 
            {
276
 
                {
277
 
                    std::lock_guard<decltype(mutex)> lock(mutex);
278
 
 
279
 
                    if (surface_info[focussed_surface].state == state)
280
 
                        state = mir_surface_state_restored;
281
 
                }
282
 
 
283
 
                focussed_surface->configure(mir_surface_attrib_state, state);
284
 
                attribute_set(*focussed_surface, mir_surface_attrib_state, state);
285
 
            }
286
 
        }
287
 
    }
288
 
 
289
 
    int select_attribute_value(ms::Surface const&, MirSurfaceAttrib, int requested_value) override
290
 
        { return requested_value; }
291
 
 
292
 
    void attribute_set(ms::Surface const& surface, MirSurfaceAttrib attrib, int value) override
293
 
    {
294
 
        switch (attrib)
295
 
        {
296
 
        case mir_surface_attrib_state:
297
 
        {
298
 
            std::lock_guard<decltype(mutex)> lock(mutex);
299
 
            set_state(surface, value);
300
 
            break;
301
 
        }
302
 
        default:
303
 
            break;
304
 
        }
305
 
    }
306
 
 
307
 
private:
308
 
    void update_tiles()
309
 
    {
310
 
        if (session_info.size() < 1 || displays.size() < 1) return;
311
 
 
312
 
        auto const sessions = session_info.size();
313
 
 
314
 
        auto const bounding_rect = displays.bounding_rectangle();
315
 
 
316
 
        auto const total_width  = bounding_rect.size.width.as_int();
317
 
        auto const total_height = bounding_rect.size.height.as_int();
318
 
 
319
 
        auto index = 0;
320
 
 
321
 
        for (auto& info : session_info)
322
 
        {
323
 
            auto const x = (total_width*index)/sessions;
324
 
            ++index;
325
 
            auto const dx = (total_width*index)/sessions - x;
326
 
 
327
 
            auto const old_tile = info.second.tile;
328
 
            Rectangle const new_tile{{x, 0}, {dx, total_height}};
329
 
 
330
 
            update_surfaces(info.first, old_tile, new_tile);
331
 
 
332
 
            info.second.tile = new_tile;
333
 
        }
334
 
    }
335
 
 
336
 
    void update_surfaces(ms::Session const* session, Rectangle const& old_tile, Rectangle const& new_tile)
337
 
    {
338
 
        auto displacement = new_tile.top_left - old_tile.top_left;
339
 
        auto& info = session_info[session];
340
 
 
341
 
        for (auto const& ps : info.surfaces)
342
 
        {
343
 
            if (auto const surface = ps.lock())
344
 
            {
345
 
                auto const old_pos = surface->top_left();
346
 
                surface->move_to(old_pos + displacement);
347
 
 
348
 
                fit_to_new_tile(*surface, old_tile, new_tile);
349
 
            }
350
 
        }
351
 
    }
352
 
 
353
 
    static void clip_to_tile(ms::SurfaceCreationParameters& parameters, Rectangle const& tile)
354
 
    {
355
 
        auto const displacement = parameters.top_left - tile.top_left;
356
 
 
357
 
        auto width = std::min(tile.size.width.as_int()-displacement.dx.as_int(), parameters.size.width.as_int());
358
 
        auto height = std::min(tile.size.height.as_int()-displacement.dy.as_int(), parameters.size.height.as_int());
359
 
 
360
 
        parameters.size = Size{width, height};
361
 
    }
362
 
 
363
 
    static void fit_to_new_tile(ms::Surface& surface, Rectangle const& old_tile, Rectangle const& new_tile)
364
 
    {
365
 
        auto const displacement = surface.top_left() - new_tile.top_left;
366
 
 
367
 
        // For now just scale if was filling width/height of tile
368
 
        auto const old_size = surface.size();
369
 
        auto const scaled_width = old_size.width == old_tile.size.width ? new_tile.size.width : old_size.width;
370
 
        auto const scaled_height = old_size.height == old_tile.size.height ? new_tile.size.height : old_size.height;
371
 
 
372
 
        auto width = std::min(new_tile.size.width.as_int()-displacement.dx.as_int(), scaled_width.as_int());
373
 
        auto height = std::min(new_tile.size.height.as_int()-displacement.dy.as_int(), scaled_height.as_int());
374
 
 
375
 
        surface.resize({width, height});
376
 
    }
377
 
 
378
 
    static bool drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle bounds)
379
 
    {
380
 
        if (surface && surface->input_area_contains(from))
381
 
        {
382
 
            auto const top_left = surface->top_left();
383
 
            auto const surface_size = surface->size();
384
 
            auto const bottom_right = top_left + as_displacement(surface_size);
385
 
 
386
 
            auto movement = to - from;
387
 
 
388
 
            if (movement.dx < DeltaX{0})
389
 
                movement.dx = std::max(movement.dx, (bounds.top_left - top_left).dx);
390
 
 
391
 
            if (movement.dy < DeltaY{0})
392
 
                movement.dy = std::max(movement.dy, (bounds.top_left - top_left).dy);
393
 
 
394
 
            if (movement.dx > DeltaX{0})
395
 
                movement.dx = std::min(movement.dx, (bounds.bottom_right() - bottom_right).dx);
396
 
 
397
 
            if (movement.dy > DeltaY{0})
398
 
                movement.dy = std::min(movement.dy, (bounds.bottom_right() - bottom_right).dy);
399
 
 
400
 
            auto new_pos = surface->top_left() + movement;
401
 
 
402
 
            surface->move_to(new_pos);
403
 
            return true;
404
 
        }
405
 
 
406
 
        return false;
407
 
    }
408
 
 
409
 
    static bool resize(std::shared_ptr<ms::Surface> surface, Point cursor, Point old_cursor, Rectangle bounds)
410
 
    {
411
 
        if (surface && surface->input_area_contains(old_cursor))
412
 
        {
413
 
            auto const top_left = surface->top_left();
414
 
 
415
 
            auto const old_displacement = old_cursor - top_left;
416
 
            auto const new_displacement = cursor - top_left;
417
 
 
418
 
            auto const scale_x = new_displacement.dx.as_float()/std::max(1.0f, old_displacement.dx.as_float());
419
 
            auto const scale_y = new_displacement.dy.as_float()/std::max(1.0f, old_displacement.dy.as_float());
420
 
 
421
 
            if (scale_x <= 0.0f || scale_y <= 0.0f) return false;
422
 
 
423
 
            auto const old_size = surface->size();
424
 
            Size new_size{scale_x*old_size.width, scale_y*old_size.height};
425
 
 
426
 
            auto const size_limits = as_size(bounds.bottom_right() - top_left);
427
 
 
428
 
            if (new_size.width > size_limits.width)
429
 
                new_size.width = size_limits.width;
430
 
 
431
 
            if (new_size.height > size_limits.height)
432
 
                new_size.height = size_limits.height;
433
 
 
434
 
            surface->resize(new_size);
435
 
 
436
 
            return true;
437
 
        }
438
 
 
439
 
        return false;
440
 
    }
441
 
 
442
 
    struct SurfaceInfo
443
 
    {
444
 
        SurfaceInfo() = default;
445
 
        std::weak_ptr<ms::Session> session;
446
 
        MirSurfaceState state;
447
 
        Rectangle restore_rect;
448
 
    };
449
 
 
450
 
    void set_state(ms::Surface const& surface, int value)
451
 
    {
452
 
        auto new_state = mir_surface_state_restored;
453
 
 
454
 
        switch (value)
455
 
        {
456
 
        case mir_surface_state_restored:
457
 
            new_state = mir_surface_state_restored;
458
 
            break;
459
 
 
460
 
        case mir_surface_state_maximized:
461
 
            new_state = mir_surface_state_maximized;
462
 
            break;
463
 
 
464
 
        case mir_surface_state_vertmaximized:
465
 
            new_state = mir_surface_state_vertmaximized;
466
 
            break;
467
 
 
468
 
        case mir_surface_state_horizmaximized:
469
 
            new_state = mir_surface_state_horizmaximized;
470
 
            break;
471
 
 
472
 
        default:
473
 
            return;
474
 
        }
475
 
 
476
 
        for (auto& i : surface_info)
477
 
        {
478
 
            if (auto const sp = i.first.lock())
479
 
            {
480
 
                if (sp.get() == &surface)
481
 
                {
482
 
                    auto& surface_info = i.second;
483
 
 
484
 
                    if (surface_info.state == mir_surface_state_restored)
485
 
                    {
486
 
                        surface_info.restore_rect = {sp->top_left(), sp->size()};
487
 
                    }
488
 
 
489
 
                    if (surface_info.state == new_state)
490
 
                    {
491
 
                        return; // Nothing to do
492
 
                    }
493
 
 
494
 
                    auto const& session_info =
495
 
                        this->session_info[surface_info.session.lock().get()];
496
 
 
497
 
                    switch (new_state)
498
 
                    {
499
 
                    case mir_surface_state_restored:
500
 
                        sp->move_to(surface_info.restore_rect.top_left);
501
 
                        sp->resize(surface_info.restore_rect.size);
502
 
                        break;
503
 
 
504
 
                    case mir_surface_state_maximized:
505
 
                        sp->move_to(session_info.tile.top_left);
506
 
                        sp->resize(session_info.tile.size);
507
 
                        break;
508
 
 
509
 
                    case mir_surface_state_horizmaximized:
510
 
                        sp->move_to({session_info.tile.top_left.x, surface_info.restore_rect.top_left.y});
511
 
                        sp->resize({session_info.tile.size.width, surface_info.restore_rect.size.height});
512
 
                        break;
513
 
 
514
 
                    case mir_surface_state_vertmaximized:
515
 
                        sp->move_to({surface_info.restore_rect.top_left.x, session_info.tile.top_left.y});
516
 
                        sp->resize({surface_info.restore_rect.size.width, session_info.tile.size.height});
517
 
                        break;
518
 
 
519
 
                    default:
520
 
                        break;
521
 
                    }
522
 
 
523
 
                    surface_info.state = new_state;
524
 
                }
525
 
            }
526
 
        }
527
 
    }
528
 
 
529
 
    std::shared_ptr<ms::Session> session_under(Point position)
530
 
    {
531
 
        for(auto& info : session_info)
532
 
        {
533
 
            if (info.second.tile.contains(position))
534
 
            {
535
 
                return info.second.session.lock();
536
 
            }
537
 
        }
538
 
 
539
 
        return std::shared_ptr<ms::Session>{};
540
 
    }
541
 
 
542
 
    struct SessionInfo
543
 
    {
544
 
        SessionInfo() = default;
545
 
        SessionInfo& operator=(std::weak_ptr<ms::Session> const& session)
546
 
        {
547
 
            this->session = session;
548
 
            surfaces.clear();
549
 
            return *this;
550
 
        }
551
 
        std::weak_ptr<ms::Session> session;
552
 
        Rectangle tile;
553
 
        std::vector<std::weak_ptr<ms::Surface>> surfaces;
554
 
    };
555
 
 
556
 
    FocusControllerFactory const focus_controller;
557
 
 
558
 
    std::mutex mutex;
559
 
    Rectangles displays;
560
 
 
561
 
    std::map<ms::Session const*, SessionInfo> session_info;
562
 
    std::map<std::weak_ptr<ms::Surface>, SurfaceInfo, std::owner_less<std::weak_ptr<ms::Surface>>> surface_info;
563
 
 
564
 
    Point old_cursor{};
565
 
    std::weak_ptr<ms::Surface> old_surface;
566
 
};
 
65
class FullscreenWindowManagerPolicy
 
66
{
 
67
public:
 
68
    using Tools = me::BasicWindowManagerToolsCopy<NullSessionInfo, NullSurfaceInfo>;
 
69
    using SessionInfoMap = typename me::SessionTo<NullSessionInfo>::type;
 
70
    using SurfaceInfoMap = typename me::SurfaceTo<NullSurfaceInfo>::type;
 
71
 
 
72
    FullscreenWindowManagerPolicy(Tools* const /*tools*/, std::shared_ptr<msh::DisplayLayout> const& display_layout) :
 
73
        display_layout{display_layout} {}
 
74
 
 
75
    void handle_session_info_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/) {}
 
76
 
 
77
    void handle_displays_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/) {}
 
78
 
 
79
    auto handle_place_new_surface(
 
80
        std::shared_ptr<ms::Session> const& /*session*/,
 
81
        ms::SurfaceCreationParameters const& request_parameters)
 
82
    -> ms::SurfaceCreationParameters
 
83
    {
 
84
        auto placed_parameters = request_parameters;
 
85
 
 
86
        Rectangle rect{request_parameters.top_left, request_parameters.size};
 
87
        display_layout->size_to_output(rect);
 
88
        placed_parameters.size = rect.size;
 
89
 
 
90
        return placed_parameters;
 
91
    }
 
92
    void handle_modify_surface(
 
93
        std::shared_ptr<ms::Session> const& /*session*/,
 
94
        std::shared_ptr<ms::Surface> const& /*surface*/,
 
95
        msh::SurfaceSpecification const& /*modifications*/)
 
96
    {
 
97
    }
 
98
 
 
99
    void handle_new_surface(std::shared_ptr<ms::Session> const& /*session*/, std::shared_ptr<ms::Surface> const& /*surface*/)
 
100
    {
 
101
    }
 
102
 
 
103
    void handle_delete_surface(std::shared_ptr<ms::Session> const& /*session*/, std::weak_ptr<ms::Surface> const& /*surface*/) {}
 
104
 
 
105
    int handle_set_state(std::shared_ptr<ms::Surface> const& /*surface*/, MirSurfaceState value)
 
106
        { return value; }
 
107
 
 
108
    bool handle_keyboard_event(MirKeyboardEvent const* /*event*/) { return false; }
 
109
 
 
110
    bool handle_touch_event(MirTouchEvent const* /*event*/) { return false; }
 
111
 
 
112
    bool handle_pointer_event(MirPointerEvent const* /*event*/) { return false; }
 
113
 
 
114
    void generate_decorations_for(
 
115
        std::shared_ptr<ms::Session> const&,
 
116
        std::shared_ptr<ms::Surface> const&,
 
117
        SurfaceInfoMap&)
 
118
    {
 
119
    }
 
120
private:
 
121
    std::shared_ptr<msh::DisplayLayout> const display_layout;
 
122
};
 
123
 
567
124
}
568
125
 
569
 
class me::EventTracker : public mi::EventFilter
570
 
{
571
 
public:
572
 
    explicit EventTracker(std::shared_ptr<me::WindowManager> const& window_manager) :
573
 
        window_manager{window_manager} {}
574
 
 
575
 
    bool handle(MirEvent const& event) override
576
 
    {
577
 
        switch (event.type)
578
 
        {
579
 
        case mir_event_type_key:
580
 
            return handle_key_event(event.key);
581
 
 
582
 
        case mir_event_type_motion:
583
 
            return handle_motion_event(event.motion);
584
 
 
585
 
        default:
586
 
            return false;
587
 
        }
588
 
    }
589
 
 
590
 
private:
591
 
    bool handle_key_event(MirKeyEvent const& event)
592
 
    {
593
 
        static const int modifier_mask =
594
 
            mir_key_modifier_alt |
595
 
            mir_key_modifier_shift |
596
 
            mir_key_modifier_sym |
597
 
            mir_key_modifier_ctrl |
598
 
            mir_key_modifier_meta;
599
 
 
600
 
        if (event.action == mir_key_action_down &&
601
 
            event.scan_code == KEY_F11)
602
 
        {
603
 
            if (auto const wm = window_manager.lock())
604
 
            switch (event.modifiers & modifier_mask)
605
 
            {
606
 
            case mir_key_modifier_alt:
607
 
                wm->toggle(mir_surface_state_maximized);
608
 
                return true;
609
 
 
610
 
            case mir_key_modifier_shift:
611
 
                wm->toggle(mir_surface_state_vertmaximized);
612
 
                return true;
613
 
 
614
 
            case mir_key_modifier_ctrl:
615
 
                wm->toggle(mir_surface_state_horizmaximized);
616
 
                return true;
617
 
 
618
 
            default:
619
 
                break;
620
 
            }
621
 
        }
622
 
 
623
 
        return false;
624
 
    }
625
 
 
626
 
    bool handle_motion_event(MirMotionEvent const& event)
627
 
    {
628
 
        if (event.action == mir_motion_action_down ||
629
 
            event.action == mir_motion_action_pointer_down)
630
 
        {
631
 
            if (auto const wm = window_manager.lock())
632
 
            {
633
 
                wm->click(average_pointer(event.pointer_count, event.pointer_coordinates));
634
 
                return false;
635
 
            }
636
 
        }
637
 
        else if (event.action == mir_motion_action_move &&
638
 
                 event.modifiers & mir_key_modifier_alt)
639
 
        {
640
 
            if (auto const wm = window_manager.lock())
641
 
            {
642
 
                switch (event.button_state)
643
 
                {
644
 
                case mir_motion_button_primary:
645
 
                    wm->drag(average_pointer(event.pointer_count, event.pointer_coordinates));
646
 
                    return true;
647
 
 
648
 
                case mir_motion_button_tertiary:
649
 
                    wm->resize(average_pointer(event.pointer_count, event.pointer_coordinates));
650
 
                    return true;
651
 
 
652
 
                default:
653
 
                    ;// ignore
654
 
                }
655
 
            }
656
 
        }
657
 
 
658
 
        return false;
659
 
    }
660
 
 
661
 
    static Point average_pointer(size_t pointer_count, MirMotionPointer const* pointer_coordinates)
662
 
    {
663
 
        long total_x = 0;
664
 
        long total_y = 0;
665
 
 
666
 
        for (auto p = pointer_coordinates; p != pointer_coordinates + pointer_count; ++p)
667
 
        {
668
 
            total_x += p->x;
669
 
            total_y += p->y;
670
 
        }
671
 
 
672
 
        return Point{total_x/pointer_count, total_y/pointer_count};
673
 
    }
674
 
 
675
 
    std::weak_ptr<me::WindowManager> const window_manager;
676
 
};
677
 
 
678
 
auto me::WindowManagmentFactory::window_manager() -> std::shared_ptr<me::WindowManager>
679
 
{
680
 
    auto tmp = wm.lock();
681
 
 
682
 
    if (!tmp)
683
 
    {
684
 
        auto const options = server.get_options();
685
 
        auto const selection = options->get<std::string>(wm_option);
686
 
 
687
 
        if (selection == wm_tiling)
688
 
        {
689
 
            auto focus_controller_factory = [this] { return server.the_focus_controller(); };
690
 
            tmp = std::make_shared<TilingWindowManager>(focus_controller_factory);
691
 
        }
692
 
        else if (selection == wm_fullscreen)
693
 
            tmp = std::make_shared<FullscreenWindowManager>(server.the_shell_display_layout());
694
 
        else
 
126
using TilingWindowManager = me::BasicWindowManagerCopy<me::TilingWindowManagerPolicy, me::TilingSessionInfo, me::TilingSurfaceInfo>;
 
127
using FullscreenWindowManager = me::BasicWindowManagerCopy<FullscreenWindowManagerPolicy, NullSessionInfo, NullSurfaceInfo>;
 
128
using CanonicalWindowManager = me::BasicWindowManagerCopy<me::CanonicalWindowManagerPolicyCopy, me::CanonicalSessionInfoCopy, me::CanonicalSurfaceInfoCopy>;
 
129
 
 
130
void me::add_window_manager_option_to(Server& server)
 
131
{
 
132
    server.add_configuration_option(wm_option, wm_description, wm_canonical);
 
133
 
 
134
    server.override_the_window_manager_builder([&server](msh::FocusController* focus_controller)
 
135
        -> std::shared_ptr<msh::WindowManager>
 
136
        {
 
137
            auto const options = server.get_options();
 
138
            auto const selection = options->get<std::string>(wm_option);
 
139
 
 
140
            if (selection == wm_tiling)
 
141
            {
 
142
                return std::make_shared<TilingWindowManager>(focus_controller);
 
143
            }
 
144
            else if (selection == wm_fullscreen)
 
145
            {
 
146
                return std::make_shared<FullscreenWindowManager>(focus_controller, server.the_shell_display_layout());
 
147
            }
 
148
            else if (selection == wm_canonical)
 
149
            {
 
150
                return std::make_shared<CanonicalWindowManager>(focus_controller, server.the_shell_display_layout());
 
151
            }
 
152
 
695
153
            throw mir::AbnormalExit("Unknown window manager: " + selection);
696
 
 
697
 
        et = std::make_shared<EventTracker>(tmp);
698
 
        server.the_composite_event_filter()->prepend(et);
699
 
        wm = tmp;
700
 
    }
701
 
 
702
 
    return tmp;
 
154
        });
703
155
}