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

Proposed by Alan Griffiths
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 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

Remove spurious checkin

Unmerged revisions

373. By Alan Griffiths

Remove spurious checkin

372. By Alan Griffiths

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

371. By Alan Griffiths

Tidy up logging string

370. By Alan Griffiths

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

369. By Alan Griffiths

merge lp:qtmir

368. By Alan Griffiths

Strip legacy code

367. By Alan Griffiths

Switch MirWindowManager implementation to CanonicalWindowManagerPolicy

366. By Alan Griffiths

Add stubs and mocks to make the calling context more realistic

365. By Alan Griffiths

Extend WindowManager tests

364. By Alan Griffiths

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