Merge lp:~alan-griffiths/qtmir/window-management into lp:qtmir

Proposed by Alan Griffiths on 2015-10-13
Status: Work in progress
Proposed branch: lp:~alan-griffiths/qtmir/window-management
Merge into: lp:qtmir
Prerequisite: lp:~alan-griffiths/qtmir/test-harness-for-MirWindowManager
Diff against target: 1819 lines (+1542/-137)
7 files modified
src/platforms/mirserver/CMakeLists.txt (+1/-0)
src/platforms/mirserver/basic_window_manager.h (+339/-0)
src/platforms/mirserver/canonical_window_manager_info.cpp (+154/-0)
src/platforms/mirserver/canonical_window_manager_info.h (+92/-0)
src/platforms/mirserver/mirwindowmanager.cpp (+940/-113)
src/platforms/mirserver/qteventfeeder.cpp (+13/-21)
src/platforms/mirserver/qteventfeeder.h (+3/-3)
To merge this branch: bzr merge lp:~alan-griffiths/qtmir/window-management
Reviewer Review Type Date Requested Status
Mir development team 2015-10-13 Pending
Review via email: mp+274241@code.launchpad.net

Commit Message

Import of Window Management framework from lp:mir so that we can prototype in lp:qtmir. Stuff we're not using yet is commented out.

Description of the Change

Import of Window Management framework from lp:mir so that we can prototype in lp:qtmir. Stuff we're not using yet is commented out.

We'll eventually move much of this code back to Mir and make it part of the public API there.

To post a comment you must log in.
373. By Alan Griffiths on 2015-10-13

Remove spurious checkin

Unmerged revisions

373. By Alan Griffiths on 2015-10-13

Remove spurious checkin

372. By Alan Griffiths on 2015-10-13

merge lp:~alan-griffiths/qtmir/window-management/

371. By Alan Griffiths on 2015-10-13

Tidy up logging string

370. By Alan Griffiths on 2015-10-13

merge lp:~alan-griffiths/qtmir/test-harness-for-MirWindowManager

369. By Alan Griffiths on 2015-10-13

merge lp:qtmir

368. By Alan Griffiths on 2015-08-05

Strip legacy code

367. By Alan Griffiths on 2015-08-05

Switch MirWindowManager implementation to CanonicalWindowManagerPolicy

366. By Alan Griffiths on 2015-08-05

Add stubs and mocks to make the calling context more realistic

365. By Alan Griffiths on 2015-08-04

Extend WindowManager tests

364. By Alan Griffiths on 2015-08-04

Extend WindowManager tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/platforms/mirserver/CMakeLists.txt'
2--- src/platforms/mirserver/CMakeLists.txt 2015-08-11 19:25:04 +0000
3+++ src/platforms/mirserver/CMakeLists.txt 2015-10-13 11:30:46 +0000
4@@ -41,6 +41,7 @@
5
6 set(MIRSERVER_QPA_PLUGIN_SRC
7 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
8+ canonical_window_manager_info.cpp
9 mirwindowmanager.cpp
10 qteventfeeder.cpp
11 plugin.cpp
12
13=== added file 'src/platforms/mirserver/basic_window_manager.h'
14--- src/platforms/mirserver/basic_window_manager.h 1970-01-01 00:00:00 +0000
15+++ src/platforms/mirserver/basic_window_manager.h 2015-10-13 11:30:46 +0000
16@@ -0,0 +1,339 @@
17+/*
18+ * Copyright © 2015 Canonical Ltd.
19+ *
20+ * This program is free software: you can redistribute it and/or modify it
21+ * under the terms of the GNU General Public License version 3,
22+ * as published by the Free Software Foundation.
23+ *
24+ * This program is distributed in the hope that it will be useful,
25+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+ * GNU General Public License for more details.
28+ *
29+ * You should have received a copy of the GNU General Public License
30+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
31+ *
32+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
33+ */
34+
35+#ifndef MIR_SHELL_BASIC_WINDOW_MANAGER_H_
36+#define MIR_SHELL_BASIC_WINDOW_MANAGER_H_
37+
38+#include "mirwindowmanager.h"
39+
40+#include "mir/geometry/rectangles.h"
41+#include "mir/scene/session.h"
42+#include "mir/scene/surface.h"
43+#include "mir/scene/surface_creation_parameters.h"
44+#include "mir/shell/abstract_shell.h"
45+#include "mir/shell/window_manager.h"
46+
47+#include <map>
48+#include <mutex>
49+
50+namespace mir
51+{
52+namespace shell
53+{
54+template<typename Info>
55+struct QtmirSurfaceTo
56+{
57+ using type = std::map<std::weak_ptr<scene::Surface>, Info, std::owner_less<std::weak_ptr<scene::Surface>>>;
58+};
59+
60+template<typename Info>
61+struct QtmirSessionTo
62+{
63+ using type = std::map<std::weak_ptr<scene::Session>, Info, std::owner_less<std::weak_ptr<scene::Session>>>;
64+};
65+
66+/// The interface through which the policy instructs the controller.
67+/// These functions assume that the BasicWindowManager data structures can be accessed freely.
68+/// I.e. should only be invoked by the policy handle_... methods (where any necessary locks are held).
69+template<typename SessionInfo, typename SurfaceInfo>
70+class QtmirBasicWindowManagerTools
71+{
72+public:
73+ virtual auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
74+ -> std::shared_ptr<scene::Session> = 0;
75+
76+ virtual auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& = 0;
77+
78+ virtual auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& = 0;
79+
80+ virtual auto focused_session() const -> std::shared_ptr<scene::Session> = 0;
81+
82+ virtual auto focused_surface() const -> std::shared_ptr<scene::Surface> = 0;
83+
84+ virtual void focus_next_session() = 0;
85+
86+ virtual void set_focus_to(
87+ std::shared_ptr<scene::Session> const& focus,
88+ std::shared_ptr<scene::Surface> const& surface) = 0;
89+
90+ virtual auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> = 0;
91+
92+ virtual void raise(SurfaceSet const& surfaces) = 0;
93+
94+ virtual auto active_display() -> geometry::Rectangle const = 0;
95+
96+ virtual ~QtmirBasicWindowManagerTools() = default;
97+ QtmirBasicWindowManagerTools() = default;
98+ QtmirBasicWindowManagerTools(QtmirBasicWindowManagerTools const&) = delete;
99+ QtmirBasicWindowManagerTools& operator=(QtmirBasicWindowManagerTools const&) = delete;
100+};
101+
102+/// A policy based window manager.
103+/// This takes care of the management of any meta implementation held for the sessions and surfaces.
104+///
105+/// \tparam WindowManagementPolicy the constructor must take a pointer to BasicWindowManagerTools<>
106+/// as its first parameter. (Any additional parameters can be forwarded by
107+/// BasicWindowManager::BasicWindowManager.)
108+/// In addition WindowManagementPolicy must implement the following methods:
109+/// - void handle_session_info_updated(SessionInfoMap& session_info, Rectangles const& displays);
110+/// - void handle_displays_updated(SessionInfoMap& session_info, Rectangles const& displays);
111+/// - auto handle_place_new_surface(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& request_parameters) -> ms::SurfaceCreationParameters;
112+/// - void handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface);
113+/// - void handle_delete_surface(std::shared_ptr<ms::Session> const& /*session*/, std::weak_ptr<ms::Surface> const& /*surface*/);
114+/// - int handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value);
115+/// - bool handle_keyboard_event(MirKeyboardEvent const* event);
116+/// - bool handle_touch_event(MirTouchEvent const* event);
117+/// - bool handle_pointer_event(MirPointerEvent const* event);
118+///
119+/// \tparam SessionInfo must be default constructable.
120+///
121+/// \tparam SurfaceInfo must be constructable from (std::shared_ptr<ms::Session>, std::shared_ptr<ms::Surface>, ms::SurfaceCreationParameters const& params)
122+template<typename WindowManagementPolicy, typename SessionInfo, typename SurfaceInfo>
123+class QtmirBasicWindowManager : public MirWindowManager,
124+ private QtmirBasicWindowManagerTools<SessionInfo, SurfaceInfo>
125+{
126+public:
127+ template <typename... PolicyArgs>
128+ QtmirBasicWindowManager(
129+ FocusController* focus_controller,
130+ PolicyArgs&&... policy_args) :
131+ focus_controller(focus_controller),
132+ policy(this, std::forward<PolicyArgs>(policy_args)...)
133+ {
134+ }
135+
136+protected:
137+ void add_session(std::shared_ptr<scene::Session> const& session) override
138+ {
139+ std::lock_guard<decltype(mutex)> lock(mutex);
140+ session_info[session] = SessionInfo();
141+ policy.handle_session_info_updated(session_info, displays);
142+ }
143+
144+ void remove_session(std::shared_ptr<scene::Session> const& session) override
145+ {
146+ std::lock_guard<decltype(mutex)> lock(mutex);
147+ session_info.erase(session);
148+ policy.handle_session_info_updated(session_info, displays);
149+ }
150+
151+ frontend::SurfaceId add_surface(
152+ std::shared_ptr<scene::Session> const& session,
153+ scene::SurfaceCreationParameters const& params,
154+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) override
155+ {
156+ std::lock_guard<decltype(mutex)> lock(mutex);
157+ scene::SurfaceCreationParameters const placed_params = policy.handle_place_new_surface(session, params);
158+ auto const result = build(session, placed_params);
159+ auto const surface = session->surface(result);
160+ surface_info.emplace(surface, SurfaceInfo{session, surface, placed_params});
161+ policy.handle_new_surface(session, surface);
162+ return result;
163+ }
164+
165+ void modify_surface(
166+ std::shared_ptr<scene::Session> const& session,
167+ std::shared_ptr<scene::Surface> const& surface,
168+ shell::SurfaceSpecification const& modifications) override
169+ {
170+ std::lock_guard<decltype(mutex)> lock(mutex);
171+ policy.handle_modify_surface(session, surface, modifications);
172+ }
173+
174+ void remove_surface(
175+ std::shared_ptr<scene::Session> const& session,
176+ std::weak_ptr<scene::Surface> const& surface) override
177+ {
178+ std::lock_guard<decltype(mutex)> lock(mutex);
179+ policy.handle_delete_surface(session, surface);
180+
181+ surface_info.erase(surface);
182+ }
183+
184+ void add_display(geometry::Rectangle const& area) override
185+ {
186+ std::lock_guard<decltype(mutex)> lock(mutex);
187+ displays.add(area);
188+ policy.handle_displays_updated(session_info, displays);
189+ }
190+
191+ void remove_display(geometry::Rectangle const& area) override
192+ {
193+ std::lock_guard<decltype(mutex)> lock(mutex);
194+ displays.remove(area);
195+ policy.handle_displays_updated(session_info, displays);
196+ }
197+
198+ bool handle_keyboard_event(MirKeyboardEvent const* event) override
199+ {
200+ std::lock_guard<decltype(mutex)> lock(mutex);
201+ return policy.handle_keyboard_event(event);
202+ }
203+
204+ bool handle_touch_event(MirTouchEvent const* event) override
205+ {
206+ std::lock_guard<decltype(mutex)> lock(mutex);
207+ return policy.handle_touch_event(event);
208+ }
209+
210+ bool handle_pointer_event(MirPointerEvent const* event) override
211+ {
212+ std::lock_guard<decltype(mutex)> lock(mutex);
213+
214+ cursor = {
215+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
216+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
217+
218+ return policy.handle_pointer_event(event);
219+ }
220+
221+ int set_surface_attribute(
222+ std::shared_ptr<scene::Session> const& /*session*/,
223+ std::shared_ptr<scene::Surface> const& surface,
224+ MirSurfaceAttrib attrib,
225+ int value) override
226+ {
227+ std::lock_guard<decltype(mutex)> lock(mutex);
228+ switch (attrib)
229+ {
230+ case mir_surface_attrib_state:
231+ {
232+ auto const state = policy.handle_set_state(surface, MirSurfaceState(value));
233+ return surface->configure(attrib, state);
234+ }
235+ default:
236+ return surface->configure(attrib, value);
237+ }
238+ }
239+
240+ auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
241+ -> std::shared_ptr<scene::Session> override
242+ {
243+ for(auto& info : session_info)
244+ {
245+ if (predicate(info.second))
246+ {
247+ return info.first.lock();
248+ }
249+ }
250+
251+ return std::shared_ptr<scene::Session>{};
252+ }
253+
254+ auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& override
255+ {
256+ return const_cast<SessionInfo&>(session_info.at(session));
257+ }
258+
259+ auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& override
260+ {
261+ return const_cast<SurfaceInfo&>(surface_info.at(surface));
262+ }
263+
264+ auto focused_session() const -> std::shared_ptr<scene::Session> override
265+ {
266+ return focus_controller->focused_session();
267+ }
268+
269+ auto focused_surface() const -> std::shared_ptr<scene::Surface> override
270+ {
271+ return focus_controller->focused_surface();
272+ }
273+
274+ void focus_next_session() override
275+ {
276+ focus_controller->focus_next_session();
277+ }
278+
279+ void set_focus_to(
280+ std::shared_ptr<scene::Session> const& focus,
281+ std::shared_ptr<scene::Surface> const& surface) override
282+ {
283+ focus_controller->set_focus_to(focus, surface);
284+ }
285+
286+ auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> override
287+ {
288+ return focus_controller->surface_at(cursor);
289+ }
290+
291+ void raise(SurfaceSet const& surfaces) override
292+ {
293+ focus_controller->raise(surfaces);
294+ }
295+
296+ auto active_display() -> geometry::Rectangle const override
297+ {
298+ geometry::Rectangle result;
299+
300+ // 1. If a window has input focus, whichever display contains the largest
301+ // proportion of the area of that window.
302+ if (auto const surface = focused_surface())
303+ {
304+ auto const surface_rect = surface->input_bounds();
305+ int max_overlap_area = -1;
306+
307+ for (auto const& display : displays)
308+ {
309+ auto const intersection = surface_rect.intersection_with(display).size;
310+ if (intersection.width.as_int()*intersection.height.as_int() > max_overlap_area)
311+ {
312+ max_overlap_area = intersection.width.as_int()*intersection.height.as_int();
313+ result = display;
314+ }
315+ }
316+ return result;
317+ }
318+
319+ // 2. Otherwise, if any window previously had input focus, for the window that had
320+ // it most recently, the display that contained the largest proportion of the
321+ // area of that window at the moment it closed, as long as that display is still
322+ // available.
323+
324+ // 3. Otherwise, the display that contains the pointer, if there is one.
325+ for (auto const& display : displays)
326+ {
327+ if (display.contains(cursor))
328+ {
329+ // Ignore the (unspecified) possiblity of overlapping displays
330+ return display;
331+ }
332+ }
333+
334+ // 4. Otherwise, the primary display, if there is one (for example, the laptop display).
335+
336+ // 5. Otherwise, the first display.
337+ if (displays.size())
338+ result = *displays.begin();
339+
340+ return result;
341+ }
342+
343+ FocusController* const focus_controller;
344+ WindowManagementPolicy policy;
345+
346+ std::mutex mutex;
347+ typename QtmirSessionTo<SessionInfo>::type session_info;
348+ typename QtmirSurfaceTo<SurfaceInfo>::type surface_info;
349+ geometry::Rectangles displays;
350+ geometry::Point cursor;
351+};
352+}
353+}
354+
355+#endif /* MIR_SHELL_BASIC_WINDOW_MANAGER_H_ */
356
357=== added file 'src/platforms/mirserver/canonical_window_manager_info.cpp'
358--- src/platforms/mirserver/canonical_window_manager_info.cpp 1970-01-01 00:00:00 +0000
359+++ src/platforms/mirserver/canonical_window_manager_info.cpp 2015-10-13 11:30:46 +0000
360@@ -0,0 +1,154 @@
361+/*
362+ * Copyright © 2015 Canonical Ltd.
363+ *
364+ * This program is free software: you can redistribute it and/or modify it
365+ * under the terms of the GNU General Public License version 3,
366+ * as published by the Free Software Foundation.
367+ *
368+ * This program is distributed in the hope that it will be useful,
369+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
370+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
371+ * GNU General Public License for more details.
372+ *
373+ * You should have received a copy of the GNU General Public License
374+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
375+ *
376+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
377+ */
378+
379+#include "canonical_window_manager_info.h"
380+
381+#include "mir/scene/surface_creation_parameters.h"
382+#include "mir/scene/surface.h"
383+#include "mir/shell/display_layout.h"
384+#include "mir/shell/surface_specification.h"
385+#include "mir/geometry/displacement.h"
386+
387+#include <linux/input.h>
388+#include <csignal>
389+
390+#include <climits>
391+
392+namespace msh = mir::shell;
393+namespace ms = mir::scene;
394+using namespace mir::geometry;
395+
396+msh::QtmirSurfaceInfo::QtmirSurfaceInfo(
397+ std::shared_ptr<scene::Session> const& session,
398+ std::shared_ptr<scene::Surface> const& surface,
399+ scene::SurfaceCreationParameters const& params) :
400+ type{surface->type()},
401+ state{surface->state()},
402+ restore_rect{surface->top_left(), surface->size()},
403+ session{session},
404+ parent{params.parent},
405+ min_width{params.min_width.is_set() ? params.min_width.value() : Width{}},
406+ min_height{params.min_height.is_set() ? params.min_height.value() : Height{}},
407+ max_width{params.max_width.is_set() ? params.max_width.value() : Width{std::numeric_limits<int>::max()}},
408+ max_height{params.max_height.is_set() ? params.max_height.value() : Height{std::numeric_limits<int>::max()}},
409+ width_inc{params.width_inc},
410+ height_inc{params.height_inc},
411+ min_aspect{params.min_aspect},
412+ max_aspect{params.max_aspect}
413+{
414+}
415+
416+bool msh::QtmirSurfaceInfo::can_be_active() const
417+{
418+ switch (type)
419+ {
420+ case mir_surface_type_normal: /**< AKA "regular" */
421+ case mir_surface_type_utility: /**< AKA "floating" */
422+ case mir_surface_type_dialog:
423+ case mir_surface_type_satellite: /**< AKA "toolbox"/"toolbar" */
424+ case mir_surface_type_freestyle:
425+ case mir_surface_type_menu:
426+ case mir_surface_type_inputmethod: /**< AKA "OSK" or handwriting etc. */
427+ return true;
428+
429+ case mir_surface_type_gloss:
430+ case mir_surface_type_tip: /**< AKA "tooltip" */
431+ default:
432+ // Cannot have input focus
433+ return false;
434+ }
435+}
436+
437+bool msh::QtmirSurfaceInfo::must_have_parent() const
438+{
439+ return must_have_parent(type);
440+}
441+
442+bool msh::QtmirSurfaceInfo::can_morph_to(MirSurfaceType new_type) const
443+{
444+ switch (new_type)
445+ {
446+ case mir_surface_type_normal:
447+ case mir_surface_type_utility:
448+ case mir_surface_type_satellite:
449+ switch (type)
450+ {
451+ case mir_surface_type_normal:
452+ case mir_surface_type_utility:
453+ case mir_surface_type_dialog:
454+ case mir_surface_type_satellite:
455+ return true;
456+
457+ default:
458+ break;
459+ }
460+ break;
461+
462+ case mir_surface_type_dialog:
463+ switch (type)
464+ {
465+ case mir_surface_type_normal:
466+ case mir_surface_type_utility:
467+ case mir_surface_type_dialog:
468+ case mir_surface_type_popover:
469+ case mir_surface_type_satellite:
470+ return true;
471+
472+ default:
473+ break;
474+ }
475+ break;
476+
477+ default:
478+ break;
479+ }
480+
481+ return false;
482+}
483+
484+bool msh::QtmirSurfaceInfo::must_not_have_parent() const
485+{
486+ return must_not_have_parent(type);
487+}
488+
489+bool msh::QtmirSurfaceInfo::must_not_have_parent(MirSurfaceType type)
490+{
491+ switch (type)
492+ {
493+ case mir_surface_type_normal:
494+ case mir_surface_type_utility:
495+ return true;
496+
497+ default:
498+ return false;
499+ }
500+}
501+
502+bool msh::QtmirSurfaceInfo::must_have_parent(MirSurfaceType type)
503+{
504+ switch (type)
505+ {
506+ case mir_surface_type_overlay:;
507+ case mir_surface_type_satellite:
508+ case mir_surface_type_tip:
509+ return true;
510+
511+ default:
512+ return false;
513+ }
514+}
515
516=== added file 'src/platforms/mirserver/canonical_window_manager_info.h'
517--- src/platforms/mirserver/canonical_window_manager_info.h 1970-01-01 00:00:00 +0000
518+++ src/platforms/mirserver/canonical_window_manager_info.h 2015-10-13 11:30:46 +0000
519@@ -0,0 +1,92 @@
520+/*
521+ * Copyright © 2015 Canonical Ltd.
522+ *
523+ * This program is free software: you can redistribute it and/or modify it
524+ * under the terms of the GNU General Public License version 3,
525+ * as published by the Free Software Foundation.
526+ *
527+ * This program is distributed in the hope that it will be useful,
528+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
529+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
530+ * GNU General Public License for more details.
531+ *
532+ * You should have received a copy of the GNU General Public License
533+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
534+ *
535+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
536+ */
537+
538+#ifndef MIR_SHELL_CANONICAL_WINDOW_MANAGER_INFO_H_
539+#define MIR_SHELL_CANONICAL_WINDOW_MANAGER_INFO_H_
540+
541+#include <mir/geometry/rectangle.h>
542+#include <mir/geometry/displacement.h>
543+#include <mir/optional_value.h>
544+#include <mir/shell/surface_specification.h>
545+#include <mir_toolkit/common.h>
546+
547+#include <memory>
548+#include <vector>
549+
550+namespace mir
551+{
552+namespace scene
553+{
554+class Session;
555+class Surface;
556+class SurfaceCreationParameters;
557+}
558+
559+namespace shell
560+{
561+class DisplayLayout;
562+
563+struct QtmirSessionInfo
564+{
565+ int surfaces{0};
566+};
567+
568+struct QtmirSurfaceInfo
569+{
570+ QtmirSurfaceInfo(
571+ std::shared_ptr<scene::Session> const& session,
572+ std::shared_ptr<scene::Surface> const& surface,
573+ scene::SurfaceCreationParameters const& params);
574+
575+ bool can_be_active() const;
576+
577+ bool can_morph_to(MirSurfaceType new_type) const;
578+ bool must_have_parent() const;
579+ bool must_not_have_parent() const;
580+
581+ static bool must_not_have_parent(MirSurfaceType type);
582+ static bool must_have_parent(MirSurfaceType type);
583+
584+ void constrain_resize(
585+ std::shared_ptr<scene::Surface> const& surface,
586+ geometry::Point& requested_pos,
587+ geometry::Size& requested_size,
588+ const bool left_resize,
589+ const bool top_resize,
590+ geometry::Rectangle const& bounds) const;
591+
592+ MirSurfaceType type;
593+ MirSurfaceState state;
594+ geometry::Rectangle restore_rect;
595+ std::weak_ptr<scene::Session> session;
596+ std::weak_ptr<scene::Surface> parent;
597+ std::vector<std::weak_ptr<scene::Surface>> children;
598+ geometry::Width min_width;
599+ geometry::Height min_height;
600+ geometry::Width max_width;
601+ geometry::Height max_height;
602+ mir::optional_value<geometry::DeltaX> width_inc;
603+ mir::optional_value<geometry::DeltaY> height_inc;
604+ mir::optional_value<SurfaceAspectRatio> min_aspect;
605+ mir::optional_value<SurfaceAspectRatio> max_aspect;
606+};
607+
608+}
609+}
610+
611+#endif /* MIR_SHELL_CANONICAL_WINDOW_MANAGER_INFO_H_ */
612
613=== modified file 'src/platforms/mirserver/mirwindowmanager.cpp'
614--- src/platforms/mirserver/mirwindowmanager.cpp 2015-10-13 11:30:46 +0000
615+++ src/platforms/mirserver/mirwindowmanager.cpp 2015-10-13 11:30:46 +0000
616@@ -15,149 +15,976 @@
617 */
618
619 #include "mirwindowmanager.h"
620+#include "basic_window_manager.h"
621+#include "canonical_window_manager_info.h"
622 #include "logging.h"
623 #include "tracepoints.h" // generated from tracepoints.tp
624
625-#include <mir/geometry/rectangle.h>
626-#include <mir/scene/session.h>
627-#include <mir/scene/surface_creation_parameters.h>
628-#include <mir/scene/surface.h>
629 #include <mir/shell/display_layout.h>
630+#include <mir/shell/surface_ready_observer.h>
631
632 namespace ms = mir::scene;
633+namespace msh = mir::shell;
634+using namespace mir::geometry;
635
636 namespace
637 {
638-class MirWindowManagerImpl : public MirWindowManager
639+class CanonicalWindowManagerPolicy
640 {
641 public:
642-
643- MirWindowManagerImpl(const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout);
644-
645- void add_session(std::shared_ptr<mir::scene::Session> const& session) override;
646-
647- void remove_session(std::shared_ptr<mir::scene::Session> const& session) override;
648-
649- mir::frontend::SurfaceId add_surface(
650- std::shared_ptr<mir::scene::Session> const& session,
651- mir::scene::SurfaceCreationParameters const& params,
652- std::function<mir::frontend::SurfaceId(std::shared_ptr<mir::scene::Session> const& session, mir::scene::SurfaceCreationParameters const& params)> const& build) override;
653-
654- void remove_surface(
655- std::shared_ptr<mir::scene::Session> const& session,
656- std::weak_ptr<mir::scene::Surface> const& surface) override;
657-
658- void add_display(mir::geometry::Rectangle const& area) override;
659-
660- void remove_display(mir::geometry::Rectangle const& area) override;
661-
662- bool handle_keyboard_event(MirKeyboardEvent const* event) override;
663-
664- bool handle_touch_event(MirTouchEvent const* event) override;
665-
666- bool handle_pointer_event(MirPointerEvent const* event) override;
667-
668- int set_surface_attribute(
669+ using Tools = mir::shell::QtmirBasicWindowManagerTools<mir::shell::QtmirSessionInfo, mir::shell::QtmirSurfaceInfo>;
670+ using CanonicalSessionInfoMap = typename mir::shell::QtmirSessionTo<mir::shell::QtmirSessionInfo>::type;
671+ using CanonicalSurfaceInfoMap = typename mir::shell::QtmirSurfaceTo<mir::shell::QtmirSurfaceInfo>::type;
672+
673+ explicit CanonicalWindowManagerPolicy(
674+ Tools* const tools,
675+ std::shared_ptr<mir::shell::DisplayLayout> const& display_layout);
676+
677+// void click(mir::geometry::Point cursor);
678+//
679+ void handle_session_info_updated(
680+ CanonicalSessionInfoMap& session_info,
681+ mir::geometry::Rectangles const& displays);
682+
683+ void handle_displays_updated(
684+ CanonicalSessionInfoMap& session_info,
685+ mir::geometry::Rectangles const& displays);
686+
687+// void resize(mir::geometry::Point cursor);
688+//
689+ auto handle_place_new_surface(
690+ std::shared_ptr<mir::scene::Session> const& session,
691+ mir::scene::SurfaceCreationParameters const& request_parameters)
692+ -> mir::scene::SurfaceCreationParameters;
693+
694+ void handle_new_surface(
695+ std::shared_ptr<mir::scene::Session> const& session,
696+ std::shared_ptr<mir::scene::Surface> const& surface);
697+
698+ void handle_modify_surface(
699 std::shared_ptr<mir::scene::Session> const& session,
700 std::shared_ptr<mir::scene::Surface> const& surface,
701- MirSurfaceAttrib attrib,
702- int value) override;
703-
704- void modify_surface(const std::shared_ptr<mir::scene::Session>&, const std::shared_ptr<mir::scene::Surface>&, const mir::shell::SurfaceSpecification&);
705+ mir::shell::SurfaceSpecification const& modifications);
706+
707+ void handle_delete_surface(
708+ std::shared_ptr<mir::scene::Session> const& session,
709+ std::weak_ptr<mir::scene::Surface> const& surface);
710+
711+ int handle_set_state(
712+ std::shared_ptr<mir::scene::Surface> const& surface, MirSurfaceState value);
713+
714+// void drag(mir::geometry::Point cursor);
715+//
716+ bool handle_keyboard_event(MirKeyboardEvent const* event);
717+
718+ bool handle_touch_event(MirTouchEvent const* event);
719+
720+ bool handle_pointer_event(MirPointerEvent const* event);
721+
722+ std::vector<std::shared_ptr<mir::scene::Surface>> generate_decorations_for(
723+ std::shared_ptr<mir::scene::Session> const& session,
724+ std::shared_ptr<mir::scene::Surface> const& surface);
725
726 private:
727- std::shared_ptr<mir::shell::DisplayLayout> const m_displayLayout;
728+ Tools* const tools;
729+ std::shared_ptr<mir::shell::DisplayLayout> const display_layout;
730 };
731-
732-}
733-
734-MirWindowManagerImpl::MirWindowManagerImpl(const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout) :
735- m_displayLayout{displayLayout}
736-{
737- qCDebug(QTMIR_MIR_MESSAGES) << "MirWindowManagerImpl::MirWindowManagerImpl";
738-}
739-
740-void MirWindowManagerImpl::add_session(std::shared_ptr<ms::Session> const& /*session*/)
741-{
742-}
743-
744-void MirWindowManagerImpl::remove_session(std::shared_ptr<ms::Session> const& /*session*/)
745-{
746-}
747-
748-mir::frontend::SurfaceId MirWindowManagerImpl::add_surface(
749- std::shared_ptr<ms::Session> const& session,
750- ms::SurfaceCreationParameters const& requestParameters,
751- std::function<mir::frontend::SurfaceId(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)> const& build)
752-{
753+}
754+
755+CanonicalWindowManagerPolicy::CanonicalWindowManagerPolicy(
756+ Tools* const tools,
757+ std::shared_ptr<msh::DisplayLayout> const& display_layout) :
758+ tools{tools},
759+ display_layout{display_layout}
760+{
761+}
762+
763+//void CanonicalWindowManagerPolicy::click(Point cursor)
764+//{
765+// // TODO
766+//}
767+//
768+void CanonicalWindowManagerPolicy::handle_session_info_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& /*displays*/)
769+{
770+ // TODO
771+}
772+
773+void CanonicalWindowManagerPolicy::handle_displays_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& /*displays*/)
774+{
775+ // TODO
776+}
777+
778+//void CanonicalWindowManagerPolicy::resize(Point cursor)
779+//{
780+// // TODO
781+//}
782+
783+auto CanonicalWindowManagerPolicy::handle_place_new_surface(
784+ std::shared_ptr<ms::Session> const& /*session*/,
785+ ms::SurfaceCreationParameters const& request_parameters)
786+-> ms::SurfaceCreationParameters
787+{
788+ auto parameters = request_parameters;
789+
790 tracepoint(qtmirserver, surfacePlacementStart);
791
792 // TODO: Callback unity8 so that it can make a decision on that.
793 // unity8 must bear in mind that the called function will be on a Mir thread though.
794 // The QPA shouldn't be deciding for itself on such things.
795
796- ms::SurfaceCreationParameters placedParameters = requestParameters;
797-
798 // Just make it fullscreen for now
799- mir::geometry::Rectangle rect{requestParameters.top_left, requestParameters.size};
800- m_displayLayout->size_to_output(rect);
801- placedParameters.size = rect.size;
802+ mir::geometry::Rectangle rect{request_parameters.top_left, request_parameters.size};
803+ display_layout->size_to_output(rect);
804+ parameters.size = rect.size;
805
806- qCDebug(QTMIR_MIR_MESSAGES) << "MirWindowManagerImpl::add_surface(): size requested ("
807- << requestParameters.size.width.as_int() << "," << requestParameters.size.height.as_int() << ") and placed ("
808- << placedParameters.size.width.as_int() << "," << placedParameters.size.height.as_int() << ")";
809+ qCDebug(QTMIR_MIR_MESSAGES) << "CanonicalWindowManagerPolicy::handle_place_new_surface(): size requested ("
810+ << request_parameters.size.width.as_int() << "," << request_parameters.size.height.as_int() << ") and placed ("
811+ << parameters.size.width.as_int() << "," << parameters.size.height.as_int() << ")";
812
813 tracepoint(qtmirserver, surfacePlacementEnd);
814
815- return build(session, placedParameters);
816-}
817-
818-void MirWindowManagerImpl::remove_surface(
819- std::shared_ptr<ms::Session> const& /*session*/,
820- std::weak_ptr<ms::Surface> const& /*surface*/)
821-{
822-}
823-
824-void MirWindowManagerImpl::add_display(mir::geometry::Rectangle const& /*area*/)
825-{
826-}
827-
828-void MirWindowManagerImpl::remove_display(mir::geometry::Rectangle const& /*area*/)
829-{
830-}
831-
832-bool MirWindowManagerImpl::handle_keyboard_event(MirKeyboardEvent const* /*event*/)
833-{
834- return false;
835-}
836-
837-bool MirWindowManagerImpl::handle_touch_event(MirTouchEvent const* /*event*/)
838-{
839- return false;
840-}
841-
842-bool MirWindowManagerImpl::handle_pointer_event(MirPointerEvent const* /*event*/)
843-{
844- return false;
845-}
846-
847-int MirWindowManagerImpl::set_surface_attribute(
848- std::shared_ptr<ms::Session> const& /*session*/,
849+// if (!parameters.type.is_set())
850+// throw std::runtime_error("Surface type must be provided");
851+//
852+// if (!parameters.state.is_set())
853+// parameters.state = mir_surface_state_restored;
854+//
855+// auto const active_display = tools->active_display();
856+//
857+// auto const width = parameters.size.width.as_int();
858+// auto const height = parameters.size.height.as_int();
859+//
860+// bool positioned = false;
861+//
862+// auto const parent = parameters.parent.lock();
863+//
864+// if (msh::QtmirSurfaceInfo::must_not_have_parent(parameters.type.value()) && parent)
865+// throw std::runtime_error("Surface type cannot have parent");
866+//
867+// if (msh::QtmirSurfaceInfo::must_have_parent(parameters.type.value()) && !parent)
868+// throw std::runtime_error("Surface type must have parent");
869+//
870+// if (parameters.output_id != mir::graphics::DisplayConfigurationOutputId{0})
871+// {
872+// Rectangle rect{parameters.top_left, parameters.size};
873+// display_layout->place_in_output(parameters.output_id, rect);
874+// parameters.top_left = rect.top_left;
875+// parameters.size = rect.size;
876+// parameters.state = mir_surface_state_fullscreen;
877+// positioned = true;
878+// }
879+// else if (!parent) // No parent => client can't suggest positioning
880+// {
881+// if (auto const default_surface = session->default_surface())
882+// {
883+// static Displacement const offset{title_bar_height, title_bar_height};
884+//
885+// parameters.top_left = default_surface->top_left() + offset;
886+//
887+// geometry::Rectangle display_for_app{default_surface->top_left(), default_surface->size()};
888+// display_layout->size_to_output(display_for_app);
889+//
890+//// // TODO This is what is currently in the spec, but I think it's wrong
891+//// if (!display_for_app.contains(parameters.top_left + as_displacement(parameters.size)))
892+//// {
893+//// parameters.size = as_size(display_for_app.bottom_right() - parameters.top_left);
894+//// }
895+////
896+//// positioned = display_for_app.contains(Rectangle{parameters.top_left, parameters.size});
897+//
898+//
899+// positioned = display_for_app.overlaps(Rectangle{parameters.top_left, parameters.size});
900+// }
901+// }
902+//
903+// if (parent && parameters.aux_rect.is_set() && parameters.edge_attachment.is_set())
904+// {
905+// auto const edge_attachment = parameters.edge_attachment.value();
906+// auto const aux_rect = parameters.aux_rect.value();
907+// auto const parent_top_left = parent->top_left();
908+// auto const top_left = aux_rect.top_left -Point{} + parent_top_left;
909+// auto const top_right= aux_rect.top_right() -Point{} + parent_top_left;
910+// auto const bot_left = aux_rect.bottom_left()-Point{} + parent_top_left;
911+//
912+// if (edge_attachment & mir_edge_attachment_vertical)
913+// {
914+// if (active_display.contains(top_right + Displacement{width, height}))
915+// {
916+// parameters.top_left = top_right;
917+// positioned = true;
918+// }
919+// else if (active_display.contains(top_left + Displacement{-width, height}))
920+// {
921+// parameters.top_left = top_left + Displacement{-width, 0};
922+// positioned = true;
923+// }
924+// }
925+//
926+// if (edge_attachment & mir_edge_attachment_horizontal)
927+// {
928+// if (active_display.contains(bot_left + Displacement{width, height}))
929+// {
930+// parameters.top_left = bot_left;
931+// positioned = true;
932+// }
933+// else if (active_display.contains(top_left + Displacement{width, -height}))
934+// {
935+// parameters.top_left = top_left + Displacement{0, -height};
936+// positioned = true;
937+// }
938+// }
939+// }
940+// else if (parent)
941+// {
942+// // o Otherwise, if the dialog is not the same as any previous dialog for the
943+// // same parent window, and/or it does not have user-customized position:
944+// // o It should be optically centered relative to its parent, unless this
945+// // would overlap or cover the title bar of the parent.
946+// // o Otherwise, it should be cascaded vertically (but not horizontally)
947+// // relative to its parent, unless, this would cause at least part of
948+// // it to extend into shell space.
949+// auto const parent_top_left = parent->top_left();
950+// auto const centred = parent_top_left
951+// + 0.5*(as_displacement(parent->size()) - as_displacement(parameters.size))
952+// - DeltaY{(parent->size().height.as_int()-height)/6};
953+//
954+// parameters.top_left = centred;
955+// positioned = true;
956+// }
957+//
958+// if (!positioned)
959+// {
960+// auto const centred = active_display.top_left
961+// + 0.5*(as_displacement(active_display.size) - as_displacement(parameters.size))
962+// - DeltaY{(active_display.size.height.as_int()-height)/6};
963+//
964+// switch (parameters.state.value())
965+// {
966+// case mir_surface_state_fullscreen:
967+// case mir_surface_state_maximized:
968+// parameters.top_left = active_display.top_left;
969+// parameters.size = active_display.size;
970+// break;
971+//
972+// case mir_surface_state_vertmaximized:
973+// parameters.top_left = centred;
974+// parameters.top_left.y = active_display.top_left.y;
975+// parameters.size.height = active_display.size.height;
976+// break;
977+//
978+// case mir_surface_state_horizmaximized:
979+// parameters.top_left = centred;
980+// parameters.top_left.x = active_display.top_left.x;
981+// parameters.size.width = active_display.size.width;
982+// break;
983+//
984+// default:
985+// parameters.top_left = centred;
986+// }
987+//
988+// if (parameters.top_left.y < display_area.top_left.y)
989+// parameters.top_left.y = display_area.top_left.y;
990+// }
991+
992+ return parameters;
993+}
994+
995+void CanonicalWindowManagerPolicy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
996+{
997+ auto& surface_info = tools->info_for(surface);
998+ if (auto const parent = surface->parent())
999+ {
1000+ tools->info_for(parent).children.push_back(surface);
1001+ }
1002+
1003+ tools->info_for(session).surfaces++;
1004+
1005+ if (surface_info.can_be_active())
1006+ {
1007+ surface->add_observer(std::make_shared<msh::SurfaceReadyObserver>(
1008+ [this](std::shared_ptr<ms::Session> const& /*session*/,
1009+ std::shared_ptr<ms::Surface> const& /*surface*/)
1010+ {
1011+// select_active_surface(surface);
1012+ },
1013+ session,
1014+ surface));
1015+ }
1016+}
1017+
1018+void CanonicalWindowManagerPolicy::handle_modify_surface(
1019+ std::shared_ptr<ms::Session> const& session,
1020 std::shared_ptr<ms::Surface> const& surface,
1021- MirSurfaceAttrib attrib,
1022- int value)
1023-{
1024- return surface->configure(attrib, value);
1025-}
1026-
1027-void MirWindowManagerImpl::modify_surface(const std::shared_ptr<mir::scene::Session>&, const std::shared_ptr<mir::scene::Surface>&, const mir::shell::SurfaceSpecification&)
1028-{
1029- // TODO support surface modifications
1030-}
1031+ msh::SurfaceSpecification const& modifications)
1032+{
1033+ auto& surface_info_old = tools->info_for(surface);
1034+
1035+ auto surface_info = surface_info_old;
1036+
1037+ if (modifications.parent.is_set())
1038+ surface_info.parent = modifications.parent.value();
1039+
1040+ if (modifications.type.is_set() &&
1041+ surface_info.type != modifications.type.value())
1042+ {
1043+ auto const new_type = modifications.type.value();
1044+
1045+ if (!surface_info.can_morph_to(new_type))
1046+ {
1047+ throw std::runtime_error("Unsupported surface type change");
1048+ }
1049+
1050+ surface_info.type = new_type;
1051+
1052+ if (surface_info.must_not_have_parent())
1053+ {
1054+ if (modifications.parent.is_set())
1055+ throw std::runtime_error("Target surface type does not support parent");
1056+
1057+ surface_info.parent.reset();
1058+ }
1059+ else if (surface_info.must_have_parent())
1060+ {
1061+ if (!surface_info.parent.lock())
1062+ throw std::runtime_error("Target surface type requires parent");
1063+ }
1064+
1065+ surface->configure(mir_surface_attrib_type, new_type);
1066+ }
1067+
1068+ #define COPY_IF_SET(field)\
1069+ if (modifications.field.is_set())\
1070+ surface_info.field = modifications.field.value()
1071+
1072+ COPY_IF_SET(min_width);
1073+ COPY_IF_SET(min_height);
1074+ COPY_IF_SET(max_width);
1075+ COPY_IF_SET(max_height);
1076+ COPY_IF_SET(min_width);
1077+ COPY_IF_SET(width_inc);
1078+ COPY_IF_SET(height_inc);
1079+ COPY_IF_SET(min_aspect);
1080+ COPY_IF_SET(max_aspect);
1081+
1082+ #undef COPY_IF_SET
1083+
1084+ std::swap(surface_info, surface_info_old);
1085+
1086+ if (modifications.name.is_set())
1087+ surface->rename(modifications.name.value());
1088+
1089+ if (modifications.streams.is_set())
1090+ {
1091+ auto v = modifications.streams.value();
1092+ std::vector<msh::StreamSpecification> l (v.begin(), v.end());
1093+ session->configure_streams(*surface, l);
1094+ }
1095+
1096+ if (modifications.width.is_set() || modifications.height.is_set())
1097+ {
1098+ auto new_size = surface->size();
1099+
1100+ if (modifications.width.is_set())
1101+ new_size.width = modifications.width.value();
1102+
1103+ if (modifications.height.is_set())
1104+ new_size.height = modifications.height.value();
1105+
1106+// auto top_left = surface->top_left();
1107+//
1108+// surface_info.constrain_resize(
1109+// surface,
1110+// top_left,
1111+// new_size,
1112+// false,
1113+// false,
1114+// display_area);
1115+//
1116+// apply_resize(surface, top_left, new_size);
1117+ }
1118+
1119+// if (modifications.input_shape.is_set())
1120+// surface->set_input_region(modifications.input_shape.value());
1121+}
1122+
1123+void CanonicalWindowManagerPolicy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
1124+{
1125+ auto& info = tools->info_for(surface);
1126+
1127+ if (auto const parent = info.parent.lock())
1128+ {
1129+ auto& siblings = tools->info_for(parent).children;
1130+
1131+ for (auto i = begin(siblings); i != end(siblings); ++i)
1132+ {
1133+ if (surface.lock() == i->lock())
1134+ {
1135+ siblings.erase(i);
1136+ break;
1137+ }
1138+ }
1139+ }
1140+
1141+ if (!--tools->info_for(session).surfaces && session == tools->focused_session())
1142+ {
1143+// active_surface_.reset();
1144+ tools->focus_next_session();
1145+// select_active_surface(tools->focused_surface());
1146+ }
1147+}
1148+
1149+int CanonicalWindowManagerPolicy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value)
1150+{
1151+ auto& info = tools->info_for(surface);
1152+
1153+// switch (value)
1154+// {
1155+// case mir_surface_state_restored:
1156+// case mir_surface_state_maximized:
1157+// case mir_surface_state_vertmaximized:
1158+// case mir_surface_state_horizmaximized:
1159+// case mir_surface_state_fullscreen:
1160+// case mir_surface_state_hidden:
1161+// case mir_surface_state_minimized:
1162+// break;
1163+//
1164+// default:
1165+// return info.state;
1166+// }
1167+//
1168+// if (info.state == mir_surface_state_restored)
1169+// {
1170+// info.restore_rect = {surface->top_left(), surface->size()};
1171+// }
1172+//
1173+// if (info.state == value)
1174+// {
1175+// return info.state;
1176+// }
1177+//
1178+// auto const old_pos = surface->top_left();
1179+// Displacement movement;
1180+//
1181+// switch (value)
1182+// {
1183+// case mir_surface_state_restored:
1184+// movement = info.restore_rect.top_left - old_pos;
1185+// surface->resize(info.restore_rect.size);
1186+// break;
1187+//
1188+// case mir_surface_state_maximized:
1189+// movement = display_area.top_left - old_pos;
1190+// surface->resize(display_area.size);
1191+// break;
1192+//
1193+// case mir_surface_state_horizmaximized:
1194+// movement = Point{display_area.top_left.x, info.restore_rect.top_left.y} - old_pos;
1195+// surface->resize({display_area.size.width, info.restore_rect.size.height});
1196+// break;
1197+//
1198+// case mir_surface_state_vertmaximized:
1199+// movement = Point{info.restore_rect.top_left.x, display_area.top_left.y} - old_pos;
1200+// surface->resize({info.restore_rect.size.width, display_area.size.height});
1201+// break;
1202+//
1203+// case mir_surface_state_fullscreen:
1204+// {
1205+// Rectangle rect{old_pos, surface->size()};
1206+// display_layout->size_to_output(rect);
1207+// movement = rect.top_left - old_pos;
1208+// surface->resize(rect.size);
1209+// break;
1210+// }
1211+//
1212+// case mir_surface_state_hidden:
1213+// case mir_surface_state_minimized:
1214+// surface->hide();
1215+// return info.state = value;
1216+//
1217+// default:
1218+// break;
1219+// }
1220+//
1221+// // TODO It is rather simplistic to move a tree WRT the top_left of the root
1222+// // TODO when resizing. But for more sophistication we would need to encode
1223+// // TODO some sensible layout rules.
1224+// move_tree(surface, movement);
1225+
1226+ return info.state = value;
1227+}
1228+
1229+//void CanonicalWindowManagerPolicy::drag(Point cursor)
1230+//{
1231+// select_active_surface(tools->surface_at(old_cursor));
1232+// drag(active_surface(), cursor, old_cursor, display_area);
1233+// old_cursor = cursor;
1234+//}
1235+
1236+bool CanonicalWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* /*event*/)
1237+{
1238+// auto const action = mir_keyboard_event_action(event);
1239+// auto const scan_code = mir_keyboard_event_scan_code(event);
1240+// auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
1241+//
1242+// if (action == mir_keyboard_action_down && scan_code == KEY_F11)
1243+// {
1244+// switch (modifiers)
1245+// {
1246+// case mir_input_event_modifier_alt:
1247+// toggle(mir_surface_state_maximized);
1248+// return true;
1249+//
1250+// case mir_input_event_modifier_shift:
1251+// toggle(mir_surface_state_vertmaximized);
1252+// return true;
1253+//
1254+// case mir_input_event_modifier_ctrl:
1255+// toggle(mir_surface_state_horizmaximized);
1256+// return true;
1257+//
1258+// default:
1259+// break;
1260+// }
1261+// }
1262+// else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
1263+// {
1264+// if (auto const session = tools->focused_session())
1265+// {
1266+// switch (modifiers)
1267+// {
1268+// case mir_input_event_modifier_alt:
1269+// kill(session->process_id(), SIGTERM);
1270+// return true;
1271+//
1272+// case mir_input_event_modifier_ctrl:
1273+// if (auto const surf = session->default_surface())
1274+// {
1275+// surf->request_client_surface_close();
1276+// return true;
1277+// }
1278+//
1279+// default:
1280+// break;
1281+// }
1282+// }
1283+// }
1284+// else if (action == mir_keyboard_action_down &&
1285+// modifiers == mir_input_event_modifier_alt &&
1286+// scan_code == KEY_TAB)
1287+// {
1288+// tools->focus_next_session();
1289+// if (auto const surface = tools->focused_surface())
1290+// select_active_surface(surface);
1291+//
1292+// return true;
1293+// }
1294+// else if (action == mir_keyboard_action_down &&
1295+// modifiers == mir_input_event_modifier_alt &&
1296+// scan_code == KEY_GRAVE)
1297+// {
1298+// if (auto const prev = tools->focused_surface())
1299+// {
1300+// if (auto const app = tools->focused_session())
1301+// select_active_surface(app->surface_after(prev));
1302+// }
1303+//
1304+// return true;
1305+// }
1306+
1307+ return false;
1308+}
1309+
1310+bool CanonicalWindowManagerPolicy::handle_touch_event(MirTouchEvent const* /*event*/)
1311+{
1312+// auto const count = mir_touch_event_point_count(event);
1313+//
1314+// long total_x = 0;
1315+// long total_y = 0;
1316+//
1317+// for (auto i = 0U; i != count; ++i)
1318+// {
1319+// total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x);
1320+// total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y);
1321+// }
1322+//
1323+// Point const cursor{total_x/count, total_y/count};
1324+//
1325+// bool is_drag = true;
1326+// for (auto i = 0U; i != count; ++i)
1327+// {
1328+// switch (mir_touch_event_action(event, i))
1329+// {
1330+// case mir_touch_action_up:
1331+// return false;
1332+//
1333+// case mir_touch_action_down:
1334+// is_drag = false;
1335+//
1336+// case mir_touch_action_change:
1337+// continue;
1338+// }
1339+// }
1340+//
1341+// if (is_drag && count == 3)
1342+// {
1343+// drag(cursor);
1344+// return true;
1345+// }
1346+// else
1347+// {
1348+// click(cursor);
1349+// return false;
1350+// }
1351+ return false;
1352+}
1353+
1354+bool CanonicalWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* /*event*/)
1355+{
1356+// auto const action = mir_pointer_event_action(event);
1357+// auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask;
1358+// Point const cursor{
1359+// mir_pointer_event_axis_value(event, mir_pointer_axis_x),
1360+// mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
1361+//
1362+// if (action == mir_pointer_action_button_down)
1363+// {
1364+// click(cursor);
1365+// return false;
1366+// }
1367+// else if (action == mir_pointer_action_motion &&
1368+// modifiers == mir_input_event_modifier_alt)
1369+// {
1370+// if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
1371+// {
1372+// drag(cursor);
1373+// return true;
1374+// }
1375+//
1376+// if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary))
1377+// {
1378+// resize(cursor);
1379+// return true;
1380+// }
1381+// }
1382+
1383+ return false;
1384+}
1385+
1386+//void CanonicalWindowManagerPolicy::toggle(MirSurfaceState state)
1387+//{
1388+// if (auto const surface = active_surface())
1389+// {
1390+// auto& info = tools->info_for(surface);
1391+//
1392+// if (info.state == state)
1393+// state = mir_surface_state_restored;
1394+//
1395+// auto const value = handle_set_state(surface, MirSurfaceState(state));
1396+// surface->configure(mir_surface_attrib_state, value);
1397+// }
1398+//}
1399+//
1400+//void CanonicalWindowManagerPolicy::select_active_surface(std::shared_ptr<ms::Surface> const& surface)
1401+//{
1402+// if (!surface)
1403+// {
1404+// if (active_surface_.lock())
1405+// tools->set_focus_to({}, {});
1406+//
1407+// active_surface_.reset();
1408+// return;
1409+// }
1410+//
1411+// auto const& info_for = tools->info_for(surface);
1412+//
1413+// if (info_for.can_be_active())
1414+// {
1415+// tools->set_focus_to(info_for.session.lock(), surface);
1416+// raise_tree(surface);
1417+// active_surface_ = surface;
1418+// }
1419+// else
1420+// {
1421+// // Cannot have input focus - try the parent
1422+// if (auto const parent = info_for.parent.lock())
1423+// select_active_surface(parent);
1424+// }
1425+//}
1426+
1427+//auto CanonicalWindowManagerPolicy::active_surface() const
1428+//-> std::shared_ptr<ms::Surface>
1429+//{
1430+// if (auto const surface = active_surface_.lock())
1431+// return surface;
1432+//
1433+// if (auto const session = tools->focused_session())
1434+// {
1435+// if (auto const surface = session->default_surface())
1436+// return surface;
1437+// }
1438+//
1439+// return std::shared_ptr<ms::Surface>{};
1440+//}
1441+
1442+//bool CanonicalWindowManagerPolicy::resize(std::shared_ptr<ms::Surface> const& surface, Point cursor, Point old_cursor, Rectangle bounds)
1443+//{
1444+// if (!surface || !surface->input_area_contains(old_cursor))
1445+// return false;
1446+//
1447+// auto const top_left = surface->top_left();
1448+// Rectangle const old_pos{top_left, surface->size()};
1449+//
1450+// auto anchor = top_left;
1451+//
1452+// for (auto const& corner : {
1453+// old_pos.top_right(),
1454+// old_pos.bottom_left(),
1455+// old_pos.bottom_right()})
1456+// {
1457+// if ((old_cursor - anchor).length_squared() <
1458+// (old_cursor - corner).length_squared())
1459+// {
1460+// anchor = corner;
1461+// }
1462+// }
1463+//
1464+// bool const left_resize = anchor.x != top_left.x;
1465+// bool const top_resize = anchor.y != top_left.y;
1466+// int const x_sign = left_resize? -1 : 1;
1467+// int const y_sign = top_resize? -1 : 1;
1468+//
1469+// auto const delta = cursor-old_cursor;
1470+//
1471+// Size new_size{old_pos.size.width + x_sign*delta.dx, old_pos.size.height + y_sign*delta.dy};
1472+//
1473+// Point new_pos = top_left + left_resize*delta.dx + top_resize*delta.dy;
1474+//
1475+//
1476+// auto const& surface_info = tools->info_for(surface);
1477+//
1478+// surface_info.constrain_resize(surface, new_pos, new_size, left_resize, top_resize, bounds);
1479+//
1480+// apply_resize(surface, new_pos, new_size);
1481+//
1482+// return true;
1483+//}
1484+
1485+//void msh::QtmirSurfaceInfo::constrain_resize(
1486+// std::shared_ptr<ms::Surface> const& surface,
1487+// Point& requested_pos,
1488+// Size& requested_size,
1489+// bool const left_resize,
1490+// bool const top_resize,
1491+// Rectangle const& /*bounds*/) const
1492+//{
1493+// Point new_pos = requested_pos;
1494+// Size new_size = requested_size;
1495+//
1496+// if (min_aspect.is_set())
1497+// {
1498+// auto const ar = min_aspect.value();
1499+//
1500+// auto const error = new_size.height.as_int()*long(ar.width) - new_size.width.as_int()*long(ar.height);
1501+//
1502+// if (error > 0)
1503+// {
1504+// // Add (denominator-1) to numerator to ensure rounding up
1505+// auto const width_correction = (error+(ar.height-1))/ar.height;
1506+// auto const height_correction = (error+(ar.width-1))/ar.width;
1507+//
1508+// if (width_correction < height_correction)
1509+// {
1510+// new_size.width = new_size.width + DeltaX(width_correction);
1511+// }
1512+// else
1513+// {
1514+// new_size.height = new_size.height - DeltaY(height_correction);
1515+// }
1516+// }
1517+// }
1518+//
1519+// if (max_aspect.is_set())
1520+// {
1521+// auto const ar = max_aspect.value();
1522+//
1523+// auto const error = new_size.width.as_int()*long(ar.height) - new_size.height.as_int()*long(ar.width);
1524+//
1525+// if (error > 0)
1526+// {
1527+// // Add (denominator-1) to numerator to ensure rounding up
1528+// auto const height_correction = (error+(ar.width-1))/ar.width;
1529+// auto const width_correction = (error+(ar.height-1))/ar.height;
1530+//
1531+// if (width_correction < height_correction)
1532+// {
1533+// new_size.width = new_size.width - DeltaX(width_correction);
1534+// }
1535+// else
1536+// {
1537+// new_size.height = new_size.height + DeltaY(height_correction);
1538+// }
1539+// }
1540+// }
1541+//
1542+// if (min_width > new_size.width)
1543+// new_size.width = min_width;
1544+//
1545+// if (min_height > new_size.height)
1546+// new_size.height = min_height;
1547+//
1548+// if (max_width < new_size.width)
1549+// new_size.width = max_width;
1550+//
1551+// if (max_height < new_size.height)
1552+// new_size.height = max_height;
1553+//
1554+// if (width_inc.is_set())
1555+// {
1556+// auto const width = new_size.width.as_int() - min_width.as_int();
1557+// auto inc = width_inc.value().as_int();
1558+// if (width % inc)
1559+// new_size.width = min_width + DeltaX{inc*(((2L*width + inc)/2)/inc)};
1560+// }
1561+//
1562+// if (height_inc.is_set())
1563+// {
1564+// auto const height = new_size.height.as_int() - min_height.as_int();
1565+// auto inc = height_inc.value().as_int();
1566+// if (height % inc)
1567+// new_size.height = min_height + DeltaY{inc*(((2L*height + inc)/2)/inc)};
1568+// }
1569+//
1570+// if (left_resize)
1571+// new_pos.x += new_size.width - requested_size.width;
1572+//
1573+// if (top_resize)
1574+// new_pos.y += new_size.height - requested_size.height;
1575+//
1576+// // placeholder - constrain onscreen
1577+//
1578+// switch (state)
1579+// {
1580+// case mir_surface_state_restored:
1581+// break;
1582+//
1583+// // "A vertically maximised surface is anchored to the top and bottom of
1584+// // the available workspace and can have any width."
1585+// case mir_surface_state_vertmaximized:
1586+// new_pos.y = surface->top_left().y;
1587+// new_size.height = surface->size().height;
1588+// break;
1589+//
1590+// // "A horizontally maximised surface is anchored to the left and right of
1591+// // the available workspace and can have any height"
1592+// case mir_surface_state_horizmaximized:
1593+// new_pos.x = surface->top_left().x;
1594+// new_size.width = surface->size().width;
1595+// break;
1596+//
1597+// // "A maximised surface is anchored to the top, bottom, left and right of the
1598+// // available workspace. For example, if the launcher is always-visible then
1599+// // the left-edge of the surface is anchored to the right-edge of the launcher."
1600+// case mir_surface_state_maximized:
1601+// default:
1602+// new_pos.x = surface->top_left().x;
1603+// new_pos.y = surface->top_left().y;
1604+// new_size.width = surface->size().width;
1605+// new_size.height = surface->size().height;
1606+// break;
1607+// }
1608+//
1609+// requested_pos = new_pos;
1610+// requested_size = new_size;
1611+//}
1612+
1613+//void CanonicalWindowManagerPolicy::apply_resize(
1614+// std::shared_ptr<ms::Surface> const& surface,
1615+// Point const& new_pos,
1616+// Size const& new_size) const
1617+//{
1618+// surface->resize(new_size);
1619+//
1620+// // TODO It is rather simplistic to move a tree WRT the top_left of the root
1621+// // TODO when resizing. But for more sophistication we would need to encode
1622+// // TODO some sensible layout rules.
1623+// move_tree(surface, new_pos-surface->top_left());
1624+//}
1625+
1626+//bool CanonicalWindowManagerPolicy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle /*bounds*/)
1627+//{
1628+// if (!surface)
1629+// return false;
1630+//
1631+// if (!surface->input_area_contains(from))
1632+// return false;
1633+//
1634+// auto movement = to - from;
1635+//
1636+// // placeholder - constrain onscreen
1637+//
1638+// switch (tools->info_for(surface).state)
1639+// {
1640+// case mir_surface_state_restored:
1641+// break;
1642+//
1643+// // "A vertically maximised surface is anchored to the top and bottom of
1644+// // the available workspace and can have any width."
1645+// case mir_surface_state_vertmaximized:
1646+// movement.dy = DeltaY(0);
1647+// break;
1648+//
1649+// // "A horizontally maximised surface is anchored to the left and right of
1650+// // the available workspace and can have any height"
1651+// case mir_surface_state_horizmaximized:
1652+// movement.dx = DeltaX(0);
1653+// break;
1654+//
1655+// // "A maximised surface is anchored to the top, bottom, left and right of the
1656+// // available workspace. For example, if the launcher is always-visible then
1657+// // the left-edge of the surface is anchored to the right-edge of the launcher."
1658+// case mir_surface_state_maximized:
1659+// case mir_surface_state_fullscreen:
1660+// default:
1661+// return true;
1662+// }
1663+//
1664+// move_tree(surface, movement);
1665+//
1666+// return true;
1667+//}
1668+
1669+//void CanonicalWindowManagerPolicy::move_tree(std::shared_ptr<ms::Surface> const& root, Displacement movement) const
1670+//{
1671+// root->move_to(root->top_left() + movement);
1672+//
1673+// for (auto const& child: tools->info_for(root).children)
1674+// {
1675+// move_tree(child.lock(), movement);
1676+// }
1677+//}
1678+
1679+//void CanonicalWindowManagerPolicy::raise_tree(std::shared_ptr<scene::Surface> const& root) const
1680+//{
1681+// SurfaceSet surfaces;
1682+// std::function<void(std::weak_ptr<scene::Surface> const& surface)> const add_children =
1683+// [&,this](std::weak_ptr<scene::Surface> const& surface)
1684+// {
1685+// auto const& info_for = tools->info_for(surface);
1686+// surfaces.insert(begin(info_for.children), end(info_for.children));
1687+// for (auto const& child : info_for.children)
1688+// add_children(child);
1689+// };
1690+//
1691+// surfaces.insert(root);
1692+// add_children(root);
1693+//
1694+// tools->raise(surfaces);
1695+//}
1696
1697 std::unique_ptr<MirWindowManager> MirWindowManager::create(
1698- mir::shell::FocusController* /*focus_controller*/,
1699+ mir::shell::FocusController* focus_controller,
1700 const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout)
1701 {
1702- return std::make_unique<MirWindowManagerImpl>(displayLayout);
1703+ using WindowManager = msh::QtmirBasicWindowManager<CanonicalWindowManagerPolicy, msh::QtmirSessionInfo, msh::QtmirSurfaceInfo>;
1704+ return std::make_unique<WindowManager>(focus_controller, displayLayout);
1705 }
1706
1707=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
1708--- src/platforms/mirserver/qteventfeeder.cpp 2015-08-27 16:10:20 +0000
1709+++ src/platforms/mirserver/qteventfeeder.cpp 2015-10-13 11:30:46 +0000
1710@@ -446,20 +446,22 @@
1711
1712 bool QtEventFeeder::dispatch(MirEvent const& event)
1713 {
1714- auto type = mir_event_get_type(&event);
1715- if (type != mir_event_type_input)
1716+ if (mir_event_get_type(&event) != mir_event_type_input)
1717 return false;
1718- auto iev = mir_event_get_input_event(&event);
1719+ auto const iev = mir_event_get_input_event(&event);
1720+
1721+ // Convert nanoseconds to milliseconds, precision lost but time difference suitable
1722+ auto const timestamp = mir_input_event_get_event_time(iev) / 1000000;
1723
1724 switch (mir_input_event_get_type(iev)) {
1725 case mir_input_event_type_key:
1726- dispatchKey(iev);
1727+ dispatchKey(mir_input_event_get_keyboard_event(iev), timestamp);
1728 break;
1729 case mir_input_event_type_touch:
1730- dispatchTouch(iev);
1731+ dispatchTouch(mir_input_event_get_touch_event(iev), timestamp);
1732 break;
1733 case mir_input_event_type_pointer:
1734- dispatchPointer(iev);
1735+ dispatchPointer(mir_input_event_get_pointer_event(iev), timestamp);
1736 default:
1737 break;
1738 }
1739@@ -506,16 +508,11 @@
1740 }
1741 }
1742
1743-void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)
1744+void QtEventFeeder::dispatchPointer(MirPointerEvent const* pev, ulong timestamp)
1745 {
1746 if (!mQtWindowSystem->hasTargetWindow())
1747 return;
1748
1749- auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
1750-
1751- auto pev = mir_input_event_get_pointer_event(ev);
1752- qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirPointerEventToString(pev));
1753-
1754 auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev));
1755 auto buttons = getQtMouseButtonsfromMirPointerEvent(pev);
1756
1757@@ -526,14 +523,11 @@
1758 buttons, modifiers);
1759 }
1760
1761-void QtEventFeeder::dispatchKey(MirInputEvent const* event)
1762+void QtEventFeeder::dispatchKey(MirKeyboardEvent const* kev, ulong timestamp)
1763 {
1764 if (!mQtWindowSystem->hasTargetWindow())
1765 return;
1766
1767- ulong timestamp = mir_input_event_get_event_time(event) / 1000000;
1768-
1769- auto kev = mir_input_event_get_keyboard_event(event);
1770 xkb_keysym_t xk_sym = mir_keyboard_event_key_code(kev);
1771
1772 // Key modifier and unicode index mapping.
1773@@ -583,12 +577,11 @@
1774 mir_keyboard_event_modifiers(kev), text, is_auto_rep);
1775 }
1776
1777-void QtEventFeeder::dispatchTouch(MirInputEvent const* event)
1778+void QtEventFeeder::dispatchTouch(MirTouchEvent const* tev, ulong timestamp)
1779 {
1780 if (!mQtWindowSystem->hasTargetWindow())
1781 return;
1782
1783- auto tev = mir_input_event_get_touch_event(event);
1784 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));
1785
1786 // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
1787@@ -633,13 +626,12 @@
1788
1789 // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
1790 // any insanity.
1791- validateTouches(mir_input_event_get_event_time(event) / 1000000, touchPoints);
1792+ validateTouches(timestamp, touchPoints);
1793
1794 // Touch event propagation.
1795 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
1796 mQtWindowSystem->handleTouchEvent(
1797- //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable
1798- mir_input_event_get_event_time(event) / 1000000,
1799+ timestamp,
1800 mTouchDevice,
1801 touchPoints);
1802 }
1803
1804=== modified file 'src/platforms/mirserver/qteventfeeder.h'
1805--- src/platforms/mirserver/qteventfeeder.h 2015-08-11 12:08:32 +0000
1806+++ src/platforms/mirserver/qteventfeeder.h 2015-10-13 11:30:46 +0000
1807@@ -64,9 +64,9 @@
1808 void stop() override;
1809
1810 private:
1811- void dispatchKey(MirInputEvent const* event);
1812- void dispatchTouch(MirInputEvent const* event);
1813- void dispatchPointer(MirInputEvent const* event);
1814+ void dispatchKey(MirKeyboardEvent const* kev, ulong timestamp);
1815+ void dispatchTouch(MirTouchEvent const* tev, ulong timestamp);
1816+ void dispatchPointer(MirPointerEvent const* pev, ulong timestamp);
1817 void validateTouches(ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints);
1818 bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint);
1819 void sendActiveTouchRelease(ulong timestamp, int id);

Subscribers

People subscribed via source and target branches