Mir

Merge lp:~alan-griffiths/mir/default-to-canonical-window-manager into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 2441
Proposed branch: lp:~alan-griffiths/mir/default-to-canonical-window-manager
Merge into: lp:mir
Prerequisite: lp:~alan-griffiths/mir/make-window-management-configurable
Diff against target: 2018 lines (+1300/-118)
23 files modified
examples/server_example_basic_window_manager.h (+8/-8)
examples/server_example_canonical_window_manager.cpp (+24/-24)
examples/server_example_canonical_window_manager.h (+7/-7)
examples/server_example_tiling_window_manager.h (+1/-1)
examples/server_example_window_management.cpp (+4/-4)
src/server/shell/CMakeLists.txt (+1/-0)
src/server/shell/abstract_shell.cpp (+12/-7)
src/server/shell/basic_window_manager.h (+273/-0)
src/server/shell/canonical_window_manager.cpp (+693/-0)
src/server/shell/canonical_window_manager.h (+130/-0)
src/server/shell/default_configuration.cpp (+3/-5)
src/server/symbols.map (+15/-0)
tests/acceptance-tests/test_client_library.cpp (+4/-4)
tests/acceptance-tests/test_client_surface_events.cpp (+3/-3)
tests/acceptance-tests/test_client_surface_visibility.cpp (+5/-3)
tests/acceptance-tests/test_debug_api.cpp (+23/-11)
tests/acceptance-tests/test_display_configuration.cpp (+10/-6)
tests/acceptance-tests/test_nested_mir.cpp (+2/-2)
tests/acceptance-tests/test_shell_control_of_surface_configuration.cpp (+58/-28)
tests/acceptance-tests/throwback/test_custom_input_dispatcher.cpp (+1/-4)
tests/include/mir_test_framework/fake_event_hub_server_configuration.h (+3/-0)
tests/integration-tests/test_surface_first_frame_sync.cpp (+6/-0)
tests/mir_test_framework/fake_event_hub_server_configuration.cpp (+14/-1)
To merge this branch: bzr merge lp:~alan-griffiths/mir/default-to-canonical-window-manager
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Kevin DuBois (community) Approve
Robert Carr (community) Abstain
Review via email: mp+253950@code.launchpad.net

Commit message

Change the default window management policy to CanonicalWindowManager

Description of the change

Change the default window management policy to CanonicalWindowManager

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

I think you forgot to remove the old WM from examples?

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> I think you forgot to remove the old WM from examples?

No. Having a private snapshot of the example is intentional.

See the "RFC Evolving Mir support for writing shells" on mir_devel for the rationale.

Revision history for this message
Kevin DuBois (kdub) wrote :

106 + virtual auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& = 0;
108 + virtual std::shared_ptr<scene::Session> focused_session() const = 0;
why mixed return value declaration types?

I do like having the 'private snapshot' thats the vetted code we're happy with that was pulled from examples/, but I also think its worthwhile to distinguish the "server_example_canonical_window_manager" from the "canonical_window_manager" that's in src

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

> I do like having the 'private snapshot' thats the vetted code we're happy with
> that was pulled from examples/, but I also think its worthwhile to distinguish
> the "server_example_canonical_window_manager" from the
> "canonical_window_manager" that's in src

Just for clarity's sake, it took me a bit of staring to realize that there were 2 "CanonicalWindowManager" objects... and it might have been clearer if we had "StandardWindowManager" in src, and CanonicalWindowManager in examples maybe

Revision history for this message
Robert Carr (robertcarr) :
review: Abstain
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> Just for clarity's sake, it took me a bit of staring to realize that there
> were 2 "CanonicalWindowManager" objects... and it might have been clearer if
> we had "StandardWindowManager" in src, and CanonicalWindowManager in examples
> maybe

There are several considerations to balance here and I'm not sure of the best resolution.

I'm not particularly fond of having duplicate code between shell and examples but that's what we decided on (for now).

As duplicate code is unusual I think there ought to be some strong suggestion of the existence of this duplication and corresponding names is one approach. How about this?

namespace shell { CanonicalWindowManager, BasicWindowManager, CanonicalWindowManagerPolicy, CanonicalSessionInfo, CanonicalSurfaceInfo }

namespace examples { CanonicalWindowManagerCopy, BasicWindowManagerCopy, CanonicalWindowManagerPolicyCopy, CanonicalSessionInfoCopy, CanonicalSurfaceInfoCopy }

Revision history for this message
Kevin DuBois (kdub) wrote :

The couterpoint on duplicated code (and I guess the impetus for duplicating in the first place) is that we've decided where we want our users to duplicate some of the code for their own intents. A shell that does extra stuff (the examples/ version) vs a shell that doesnt (the src/server/shell one) is just the sort of duplication that we're hoping the shell writers go and make in their respective projects. So, I guess I'm okay with forking the src/server/shell code from the examples code in their names and what they're doing. (and cross-pollinating the features we find in examples/ that are good, and not spreading the examples/ features that arent so good)

Revision history for this message
Kevin DuBois (kdub) wrote :

and for the names I'm okay with the proposed:

namespace shell { CanonicalWindowManager, BasicWindowManager, CanonicalWindowManagerPolicy, CanonicalSessionInfo, CanonicalSurfaceInfo }

namespace examples { CanonicalWindowManagerCopy, BasicWindowManagerCopy, CanonicalWindowManagerPolicyCopy, CanonicalSessionInfoCopy, CanonicalSurfaceInfoCopy }

but I think "Staging" might make more sense, given the intended diverge (until we drop or move the divergent features into the shell namespace)

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> As duplicate code is unusual I think there ought to be some strong suggestion
> of the existence of this duplication and corresponding names is one approach.
> How about this?
>
> namespace shell { CanonicalWindowManager, BasicWindowManager,
> CanonicalWindowManagerPolicy, CanonicalSessionInfo, CanonicalSurfaceInfo }
>
> namespace examples { CanonicalWindowManagerCopy, BasicWindowManagerCopy,
> CanonicalWindowManagerPolicyCopy, CanonicalSessionInfoCopy,
> CanonicalSurfaceInfoCopy }

+1

Revision history for this message
Kevin DuBois (kdub) wrote :

lgtm!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

I have noticed some slightly strange behavior when running the multiwin example, in particular the third surface is not cascaded, but that's not blocking for this MP.

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> Looks good.
>
> I have noticed some slightly strange behavior when running the multiwin
> example, in particular the third surface is not cascaded, but that's not
> blocking for this MP.

That's related to some outstanding restructuring needed for better window management: At present "the app’s most recently active window" is being interpreted as session->default_surface(); and, currently, there is no way to change the session's default surface from the oldest.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/server_example_basic_window_manager.h'
2--- examples/server_example_basic_window_manager.h 2015-03-27 06:58:51 +0000
3+++ examples/server_example_basic_window_manager.h 2015-03-27 16:37:31 +0000
4@@ -55,7 +55,7 @@
5 /// I.e. should only be invoked by the policy handle_... methods (where any necessary locks are held).
6 // TODO extract commonality with FocusController (once that's separated from shell::FocusController)
7 template<typename SessionInfo, typename SurfaceInfo>
8-class BasicWindowManagerTools
9+class BasicWindowManagerToolsCopy
10 {
11 public:
12 virtual auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
13@@ -79,10 +79,10 @@
14
15 virtual void raise(SurfaceSet const& surfaces) = 0;
16
17- virtual ~BasicWindowManagerTools() = default;
18- BasicWindowManagerTools() = default;
19- BasicWindowManagerTools(BasicWindowManagerTools const&) = delete;
20- BasicWindowManagerTools& operator=(BasicWindowManagerTools const&) = delete;
21+ virtual ~BasicWindowManagerToolsCopy() = default;
22+ BasicWindowManagerToolsCopy() = default;
23+ BasicWindowManagerToolsCopy(BasicWindowManagerToolsCopy const&) = delete;
24+ BasicWindowManagerToolsCopy& operator=(BasicWindowManagerToolsCopy const&) = delete;
25 };
26
27 /// A policy based window manager.
28@@ -106,12 +106,12 @@
29 ///
30 /// \tparam SurfaceInfo must be constructable from (std::shared_ptr<ms::Session>, std::shared_ptr<ms::Surface>)
31 template<typename WindowManagementPolicy, typename SessionInfo, typename SurfaceInfo>
32-class BasicWindowManager : public shell::WindowManager,
33- private BasicWindowManagerTools<SessionInfo, SurfaceInfo>
34+class BasicWindowManagerCopy : public shell::WindowManager,
35+ private BasicWindowManagerToolsCopy<SessionInfo, SurfaceInfo>
36 {
37 public:
38 template <typename... PolicyArgs>
39- BasicWindowManager(
40+ BasicWindowManagerCopy(
41 shell::FocusController* focus_controller,
42 PolicyArgs&&... policy_args) :
43 focus_controller(focus_controller),
44
45=== modified file 'examples/server_example_canonical_window_manager.cpp'
46--- examples/server_example_canonical_window_manager.cpp 2015-03-27 06:58:51 +0000
47+++ examples/server_example_canonical_window_manager.cpp 2015-03-27 16:37:31 +0000
48@@ -55,7 +55,7 @@
49 }
50 }
51
52-me::CanonicalSurfaceInfo::CanonicalSurfaceInfo(
53+me::CanonicalSurfaceInfoCopy::CanonicalSurfaceInfoCopy(
54 std::shared_ptr<scene::Session> const& session,
55 std::shared_ptr<scene::Surface> const& surface) :
56 state{mir_surface_state_restored},
57@@ -65,7 +65,7 @@
58 {
59 }
60
61-me::CanonicalWindowManagerPolicy::CanonicalWindowManagerPolicy(
62+me::CanonicalWindowManagerPolicyCopy::CanonicalWindowManagerPolicyCopy(
63 Tools* const tools,
64 std::shared_ptr<shell::DisplayLayout> const& display_layout) :
65 tools{tools},
66@@ -73,7 +73,7 @@
67 {
68 }
69
70-void me::CanonicalWindowManagerPolicy::click(Point cursor)
71+void me::CanonicalWindowManagerPolicyCopy::click(Point cursor)
72 {
73 if (auto const surface = tools->surface_at(cursor))
74 select_active_surface(surface);
75@@ -81,23 +81,23 @@
76 old_cursor = cursor;
77 }
78
79-void me::CanonicalWindowManagerPolicy::handle_session_info_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& /*displays*/)
80+void me::CanonicalWindowManagerPolicyCopy::handle_session_info_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& /*displays*/)
81 {
82 }
83
84-void me::CanonicalWindowManagerPolicy::handle_displays_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& displays)
85+void me::CanonicalWindowManagerPolicyCopy::handle_displays_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& displays)
86 {
87 display_area = displays.bounding_rectangle();
88 }
89
90-void me::CanonicalWindowManagerPolicy::resize(Point cursor)
91+void me::CanonicalWindowManagerPolicyCopy::resize(Point cursor)
92 {
93 select_active_surface(tools->surface_at(old_cursor));
94 resize(active_surface(), cursor, old_cursor, display_area);
95 old_cursor = cursor;
96 }
97
98-auto me::CanonicalWindowManagerPolicy::handle_place_new_surface(
99+auto me::CanonicalWindowManagerPolicyCopy::handle_place_new_surface(
100 std::shared_ptr<ms::Session> const& session,
101 ms::SurfaceCreationParameters const& request_parameters)
102 -> ms::SurfaceCreationParameters
103@@ -195,7 +195,7 @@
104 return parameters;
105 }
106
107-std::vector<std::shared_ptr<ms::Surface>> me::CanonicalWindowManagerPolicy::generate_decorations_for(
108+std::vector<std::shared_ptr<ms::Surface>> me::CanonicalWindowManagerPolicyCopy::generate_decorations_for(
109 std::shared_ptr<ms::Session> const& session,
110 std::shared_ptr<ms::Surface> const& surface)
111 {
112@@ -248,7 +248,7 @@
113 {
114 public:
115 SurfaceReadyObserver(
116- me::CanonicalWindowManagerPolicy::Tools* const focus_controller,
117+ me::CanonicalWindowManagerPolicyCopy::Tools* const focus_controller,
118 std::shared_ptr<ms::Session> const& session,
119 std::shared_ptr<ms::Surface> const& surface) :
120 focus_controller{focus_controller},
121@@ -267,13 +267,13 @@
122 }
123 }
124
125- me::CanonicalWindowManagerPolicy::Tools* const focus_controller;
126+ me::CanonicalWindowManagerPolicyCopy::Tools* const focus_controller;
127 std::weak_ptr<ms::Session> const session;
128 std::weak_ptr<ms::Surface> const surface;
129 };
130 }
131
132-void me::CanonicalWindowManagerPolicy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
133+void me::CanonicalWindowManagerPolicyCopy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
134 {
135 if (auto const parent = surface->parent())
136 {
137@@ -306,7 +306,7 @@
138 }
139 }
140
141-void me::CanonicalWindowManagerPolicy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
142+void me::CanonicalWindowManagerPolicyCopy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
143 {
144 if (auto const parent = tools->info_for(surface).parent.lock())
145 {
146@@ -331,7 +331,7 @@
147 }
148 }
149
150-int me::CanonicalWindowManagerPolicy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value)
151+int me::CanonicalWindowManagerPolicyCopy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value)
152 {
153 auto& info = tools->info_for(surface);
154
155@@ -409,14 +409,14 @@
156 return info.state = value;
157 }
158
159-void me::CanonicalWindowManagerPolicy::drag(Point cursor)
160+void me::CanonicalWindowManagerPolicyCopy::drag(Point cursor)
161 {
162 select_active_surface(tools->surface_at(old_cursor));
163 drag(active_surface(), cursor, old_cursor, display_area);
164 old_cursor = cursor;
165 }
166
167-bool me::CanonicalWindowManagerPolicy::handle_key_event(MirKeyboardEvent const* event)
168+bool me::CanonicalWindowManagerPolicyCopy::handle_key_event(MirKeyboardEvent const* event)
169 {
170 auto const action = mir_keyboard_event_action(event);
171 auto const scan_code = mir_keyboard_event_scan_code(event);
172@@ -468,7 +468,7 @@
173 return false;
174 }
175
176-bool me::CanonicalWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event)
177+bool me::CanonicalWindowManagerPolicyCopy::handle_touch_event(MirTouchEvent const* event)
178 {
179 auto const count = mir_touch_event_point_count(event);
180
181@@ -511,7 +511,7 @@
182 }
183 }
184
185-bool me::CanonicalWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event)
186+bool me::CanonicalWindowManagerPolicyCopy::handle_pointer_event(MirPointerEvent const* event)
187 {
188 auto const action = mir_pointer_event_action(event);
189 auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask;
190@@ -543,7 +543,7 @@
191 return false;
192 }
193
194-void me::CanonicalWindowManagerPolicy::toggle(MirSurfaceState state)
195+void me::CanonicalWindowManagerPolicyCopy::toggle(MirSurfaceState state)
196 {
197 if (auto const surface = active_surface())
198 {
199@@ -557,7 +557,7 @@
200 }
201 }
202
203-void me::CanonicalWindowManagerPolicy::select_active_surface(std::shared_ptr<ms::Surface> const& surface)
204+void me::CanonicalWindowManagerPolicyCopy::select_active_surface(std::shared_ptr<ms::Surface> const& surface)
205 {
206 if (!surface)
207 {
208@@ -591,7 +591,7 @@
209 }
210 }
211
212-auto me::CanonicalWindowManagerPolicy::active_surface() const
213+auto me::CanonicalWindowManagerPolicyCopy::active_surface() const
214 -> std::shared_ptr<ms::Surface>
215 {
216 if (auto const surface = active_surface_.lock())
217@@ -606,7 +606,7 @@
218 return std::shared_ptr<ms::Surface>{};
219 }
220
221-bool me::CanonicalWindowManagerPolicy::resize(std::shared_ptr<ms::Surface> const& surface, Point cursor, Point old_cursor, Rectangle bounds)
222+bool me::CanonicalWindowManagerPolicyCopy::resize(std::shared_ptr<ms::Surface> const& surface, Point cursor, Point old_cursor, Rectangle bounds)
223 {
224 if (!surface || !surface->input_area_contains(cursor))
225 return false;
226@@ -708,7 +708,7 @@
227 return true;
228 }
229
230-bool me::CanonicalWindowManagerPolicy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle bounds)
231+bool me::CanonicalWindowManagerPolicyCopy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle bounds)
232 {
233 if (surface && surface->input_area_contains(from))
234 {
235@@ -738,7 +738,7 @@
236 return false;
237 }
238
239-void me::CanonicalWindowManagerPolicy::move_tree(std::shared_ptr<ms::Surface> const& root, Displacement movement) const
240+void me::CanonicalWindowManagerPolicyCopy::move_tree(std::shared_ptr<ms::Surface> const& root, Displacement movement) const
241 {
242 root->move_to(root->top_left() + movement);
243
244@@ -748,7 +748,7 @@
245 }
246 }
247
248-void me::CanonicalWindowManagerPolicy::raise_tree(std::shared_ptr<scene::Surface> const& root) const
249+void me::CanonicalWindowManagerPolicyCopy::raise_tree(std::shared_ptr<scene::Surface> const& root) const
250 {
251 SurfaceSet surfaces;
252 std::function<void(std::weak_ptr<scene::Surface> const& surface)> const add_children =
253
254=== modified file 'examples/server_example_canonical_window_manager.h'
255--- examples/server_example_canonical_window_manager.h 2015-03-27 06:58:51 +0000
256+++ examples/server_example_canonical_window_manager.h 2015-03-27 16:37:31 +0000
257@@ -31,14 +31,14 @@
258 namespace shell { class DisplayLayout; }
259 namespace examples
260 {
261-struct CanonicalSessionInfo
262+struct CanonicalSessionInfoCopy
263 {
264 int surfaces{0};
265 };
266
267-struct CanonicalSurfaceInfo
268+struct CanonicalSurfaceInfoCopy
269 {
270- CanonicalSurfaceInfo(
271+ CanonicalSurfaceInfoCopy(
272 std::shared_ptr<scene::Session> const& session,
273 std::shared_ptr<scene::Surface> const& surface);
274
275@@ -58,13 +58,13 @@
276 // o Maximize/restore current window (to display height): Shift-F11
277 // o Maximize/restore current window (to display width): Ctrl-F11
278 // o client requests to maximize, vertically maximize & restore
279-class CanonicalWindowManagerPolicy
280+class CanonicalWindowManagerPolicyCopy
281 {
282 public:
283- using Tools = BasicWindowManagerTools<CanonicalSessionInfo, CanonicalSurfaceInfo>;
284- using CanonicalSessionInfoMap = typename SessionTo<CanonicalSessionInfo>::type;
285+ using Tools = BasicWindowManagerToolsCopy<CanonicalSessionInfoCopy, CanonicalSurfaceInfoCopy>;
286+ using CanonicalSessionInfoMap = typename SessionTo<CanonicalSessionInfoCopy>::type;
287
288- explicit CanonicalWindowManagerPolicy(
289+ explicit CanonicalWindowManagerPolicyCopy(
290 Tools* const tools,
291 std::shared_ptr<shell::DisplayLayout> const& display_layout);
292
293
294=== modified file 'examples/server_example_tiling_window_manager.h'
295--- examples/server_example_tiling_window_manager.h 2015-03-27 06:58:51 +0000
296+++ examples/server_example_tiling_window_manager.h 2015-03-27 16:37:31 +0000
297@@ -56,7 +56,7 @@
298 class TilingWindowManagerPolicy
299 {
300 public:
301- using Tools = BasicWindowManagerTools<TilingSessionInfo, TilingSurfaceInfo>;
302+ using Tools = BasicWindowManagerToolsCopy<TilingSessionInfo, TilingSurfaceInfo>;
303 using TilingSessionInfoMap = typename SessionTo<TilingSessionInfo>::type;
304
305 explicit TilingWindowManagerPolicy(Tools* const tools);
306
307=== modified file 'examples/server_example_window_management.cpp'
308--- examples/server_example_window_management.cpp 2015-03-27 06:58:51 +0000
309+++ examples/server_example_window_management.cpp 2015-03-27 16:37:31 +0000
310@@ -64,7 +64,7 @@
311 class FullscreenWindowManagerPolicy
312 {
313 public:
314- using Tools = me::BasicWindowManagerTools<NullSessionInfo, NullSurfaceInfo>;
315+ using Tools = me::BasicWindowManagerToolsCopy<NullSessionInfo, NullSurfaceInfo>;
316 using SessionInfoMap = typename me::SessionTo<NullSessionInfo>::type;
317
318 FullscreenWindowManagerPolicy(Tools* const /*tools*/, std::shared_ptr<msh::DisplayLayout> const& display_layout) :
319@@ -115,9 +115,9 @@
320
321 }
322
323-using TilingWindowManager = me::BasicWindowManager<me::TilingWindowManagerPolicy, me::TilingSessionInfo, me::TilingSurfaceInfo>;
324-using FullscreenWindowManager = me::BasicWindowManager<FullscreenWindowManagerPolicy, NullSessionInfo, NullSurfaceInfo>;
325-using CanonicalWindowManager = me::BasicWindowManager<me::CanonicalWindowManagerPolicy, me::CanonicalSessionInfo, me::CanonicalSurfaceInfo>;
326+using TilingWindowManager = me::BasicWindowManagerCopy<me::TilingWindowManagerPolicy, me::TilingSessionInfo, me::TilingSurfaceInfo>;
327+using FullscreenWindowManager = me::BasicWindowManagerCopy<FullscreenWindowManagerPolicy, NullSessionInfo, NullSurfaceInfo>;
328+using CanonicalWindowManager = me::BasicWindowManagerCopy<me::CanonicalWindowManagerPolicyCopy, me::CanonicalSessionInfoCopy, me::CanonicalSurfaceInfoCopy>;
329
330 void me::add_window_manager_option_to(Server& server)
331 {
332
333=== modified file 'src/server/shell/CMakeLists.txt'
334--- src/server/shell/CMakeLists.txt 2015-03-25 02:48:40 +0000
335+++ src/server/shell/CMakeLists.txt 2015-03-27 16:37:31 +0000
336@@ -2,6 +2,7 @@
337 SHELL_SOURCES
338
339 abstract_shell.cpp
340+ canonical_window_manager.cpp
341 default_placement_strategy.cpp
342 frontend_shell.cpp
343 graphics_display_layout.cpp
344
345=== modified file 'src/server/shell/abstract_shell.cpp'
346--- src/server/shell/abstract_shell.cpp 2015-03-25 02:48:40 +0000
347+++ src/server/shell/abstract_shell.cpp 2015-03-27 16:37:31 +0000
348@@ -165,13 +165,18 @@
349 {
350 if (surface)
351 {
352- // Ensure the surface has really taken the focus before notifying it that it is focused
353- surface->take_input_focus(input_targeter);
354- if (auto current_focus = focus_surface.lock())
355- current_focus->configure(mir_surface_attrib_focus, mir_surface_unfocused);
356-
357- surface->configure(mir_surface_attrib_focus, mir_surface_focused);
358- focus_surface = surface;
359+ auto current_focus = focus_surface.lock();
360+
361+ if (surface != current_focus)
362+ {
363+ // Ensure the surface has really taken the focus before notifying it that it is focused
364+ surface->take_input_focus(input_targeter);
365+ if (current_focus)
366+ current_focus->configure(mir_surface_attrib_focus, mir_surface_unfocused);
367+
368+ surface->configure(mir_surface_attrib_focus, mir_surface_focused);
369+ focus_surface = surface;
370+ }
371 }
372 else
373 {
374
375=== added file 'src/server/shell/basic_window_manager.h'
376--- src/server/shell/basic_window_manager.h 1970-01-01 00:00:00 +0000
377+++ src/server/shell/basic_window_manager.h 2015-03-27 16:37:31 +0000
378@@ -0,0 +1,273 @@
379+/*
380+ * Copyright © 2015 Canonical Ltd.
381+ *
382+ * This program is free software: you can redistribute it and/or modify it
383+ * under the terms of the GNU General Public License version 3,
384+ * as published by the Free Software Foundation.
385+ *
386+ * This program is distributed in the hope that it will be useful,
387+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
388+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
389+ * GNU General Public License for more details.
390+ *
391+ * You should have received a copy of the GNU General Public License
392+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
393+ *
394+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
395+ */
396+
397+#ifndef MIR_SHELL_BASIC_WINDOW_MANAGER_H_
398+#define MIR_SHELL_BASIC_WINDOW_MANAGER_H_
399+
400+#include "mir/geometry/rectangles.h"
401+#include "mir/scene/session.h"
402+#include "mir/scene/surface.h"
403+#include "mir/scene/surface_creation_parameters.h"
404+#include "mir/shell/abstract_shell.h"
405+#include "mir/shell/window_manager.h"
406+
407+#include <map>
408+#include <mutex>
409+
410+namespace mir
411+{
412+namespace shell
413+{
414+template<typename Info>
415+struct SurfaceTo
416+{
417+ using type = std::map<std::weak_ptr<scene::Surface>, Info, std::owner_less<std::weak_ptr<scene::Surface>>>;
418+};
419+
420+template<typename Info>
421+struct SessionTo
422+{
423+ using type = std::map<std::weak_ptr<scene::Session>, Info, std::owner_less<std::weak_ptr<scene::Session>>>;
424+};
425+
426+/// The interface through which the policy instructs the controller.
427+/// These functions assume that the BasicWindowManager data structures can be accessed freely.
428+/// I.e. should only be invoked by the policy handle_... methods (where any necessary locks are held).
429+template<typename SessionInfo, typename SurfaceInfo>
430+class BasicWindowManagerTools
431+{
432+public:
433+ virtual auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
434+ -> std::shared_ptr<scene::Session> = 0;
435+
436+ virtual auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& = 0;
437+
438+ virtual auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& = 0;
439+
440+ virtual auto focused_session() const -> std::shared_ptr<scene::Session> = 0;
441+
442+ virtual auto focused_surface() const -> std::shared_ptr<scene::Surface> = 0;
443+
444+ virtual void focus_next() = 0;
445+
446+ virtual void set_focus_to(
447+ std::shared_ptr<scene::Session> const& focus,
448+ std::shared_ptr<scene::Surface> const& surface) = 0;
449+
450+ virtual auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> = 0;
451+
452+ virtual void raise(SurfaceSet const& surfaces) = 0;
453+
454+ virtual ~BasicWindowManagerTools() = default;
455+ BasicWindowManagerTools() = default;
456+ BasicWindowManagerTools(BasicWindowManagerTools const&) = delete;
457+ BasicWindowManagerTools& operator=(BasicWindowManagerTools const&) = delete;
458+};
459+
460+/// A policy based window manager.
461+/// This takes care of the management of any meta implementation held for the sessions and surfaces.
462+///
463+/// \tparam WindowManagementPolicy the constructor must take a pointer to BasicWindowManagerTools<>
464+/// as its first parameter. (Any additional parameters can be forwarded by
465+/// BasicWindowManager::BasicWindowManager.)
466+/// In addition WindowManagementPolicy must implement the following methods:
467+/// - void handle_session_info_updated(SessionInfoMap& session_info, Rectangles const& displays);
468+/// - void handle_displays_updated(SessionInfoMap& session_info, Rectangles const& displays);
469+/// - auto handle_place_new_surface(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& request_parameters) -> ms::SurfaceCreationParameters;
470+/// - void handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface);
471+/// - void handle_delete_surface(std::shared_ptr<ms::Session> const& /*session*/, std::weak_ptr<ms::Surface> const& /*surface*/);
472+/// - int handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value);
473+/// - bool handle_key_event(MirKeyInputEvent const* event);
474+/// - bool handle_touch_event(MirTouchInputEvent const* event);
475+/// - bool handle_pointer_event(MirPointerInputEvent const* event);
476+///
477+/// \tparam SessionInfo must be default constructable.
478+///
479+/// \tparam SurfaceInfo must be constructable from (std::shared_ptr<ms::Session>, std::shared_ptr<ms::Surface>)
480+template<typename WindowManagementPolicy, typename SessionInfo, typename SurfaceInfo>
481+class BasicWindowManager : public WindowManager,
482+ private BasicWindowManagerTools<SessionInfo, SurfaceInfo>
483+{
484+public:
485+ template <typename... PolicyArgs>
486+ BasicWindowManager(
487+ FocusController* focus_controller,
488+ PolicyArgs&&... policy_args) :
489+ focus_controller(focus_controller),
490+ policy(this, std::forward<PolicyArgs>(policy_args)...)
491+ {
492+ }
493+
494+protected:
495+ void add_session(std::shared_ptr<scene::Session> const& session) override
496+ {
497+ std::lock_guard<decltype(mutex)> lock(mutex);
498+ session_info[session] = SessionInfo();
499+ policy.handle_session_info_updated(session_info, displays);
500+ }
501+
502+ void remove_session(std::shared_ptr<scene::Session> const& session) override
503+ {
504+ std::lock_guard<decltype(mutex)> lock(mutex);
505+ session_info.erase(session);
506+ policy.handle_session_info_updated(session_info, displays);
507+ }
508+
509+ frontend::SurfaceId add_surface(
510+ std::shared_ptr<scene::Session> const& session,
511+ scene::SurfaceCreationParameters const& params,
512+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) override
513+ {
514+ std::lock_guard<decltype(mutex)> lock(mutex);
515+ scene::SurfaceCreationParameters const placed_params = policy.handle_place_new_surface(session, params);
516+ auto const result = build(session, placed_params);
517+ auto const surface = session->surface(result);
518+ policy.handle_new_surface(session, surface);
519+ surface_info.emplace(surface, SurfaceInfo{session, surface});
520+ return result;
521+ }
522+
523+ void remove_surface(
524+ std::shared_ptr<scene::Session> const& session,
525+ std::weak_ptr<scene::Surface> const& surface) override
526+ {
527+ std::lock_guard<decltype(mutex)> lock(mutex);
528+ policy.handle_delete_surface(session, surface);
529+
530+ surface_info.erase(surface);
531+ }
532+
533+ void add_display(geometry::Rectangle const& area) override
534+ {
535+ std::lock_guard<decltype(mutex)> lock(mutex);
536+ displays.add(area);
537+ policy.handle_displays_updated(session_info, displays);
538+ }
539+
540+ void remove_display(geometry::Rectangle const& area) override
541+ {
542+ std::lock_guard<decltype(mutex)> lock(mutex);
543+ displays.remove(area);
544+ policy.handle_displays_updated(session_info, displays);
545+ }
546+
547+ bool handle_key_event(MirKeyboardEvent const* event) override
548+ {
549+ std::lock_guard<decltype(mutex)> lock(mutex);
550+ return policy.handle_key_event(event);
551+ }
552+
553+ bool handle_touch_event(MirTouchEvent const* event) override
554+ {
555+ std::lock_guard<decltype(mutex)> lock(mutex);
556+ return policy.handle_touch_event(event);
557+ }
558+
559+ bool handle_pointer_event(MirPointerEvent const* event) override
560+ {
561+ std::lock_guard<decltype(mutex)> lock(mutex);
562+ return policy.handle_pointer_event(event);
563+ }
564+
565+ int set_surface_attribute(
566+ std::shared_ptr<scene::Session> const& /*session*/,
567+ std::shared_ptr<scene::Surface> const& surface,
568+ MirSurfaceAttrib attrib,
569+ int value) override
570+ {
571+ std::lock_guard<decltype(mutex)> lock(mutex);
572+ switch (attrib)
573+ {
574+ case mir_surface_attrib_state:
575+ {
576+ auto const state = policy.handle_set_state(surface, MirSurfaceState(value));
577+ return surface->configure(attrib, state);
578+ }
579+ default:
580+ return surface->configure(attrib, value);
581+ }
582+ }
583+
584+ auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
585+ -> std::shared_ptr<scene::Session> override
586+ {
587+ for(auto& info : session_info)
588+ {
589+ if (predicate(info.second))
590+ {
591+ return info.first.lock();
592+ }
593+ }
594+
595+ return std::shared_ptr<scene::Session>{};
596+ }
597+
598+ auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& override
599+ {
600+ return const_cast<SessionInfo&>(session_info.at(session));
601+ }
602+
603+ auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& override
604+ {
605+ return const_cast<SurfaceInfo&>(surface_info.at(surface));
606+ }
607+
608+ auto focused_session() const -> std::shared_ptr<scene::Session> override
609+ {
610+ return focus_controller->focused_session();
611+ }
612+
613+ auto focused_surface() const -> std::shared_ptr<scene::Surface> override
614+ {
615+ return focus_controller->focused_surface();
616+ }
617+
618+ void focus_next() override
619+ {
620+ focus_controller->focus_next();
621+ }
622+
623+ void set_focus_to(
624+ std::shared_ptr<scene::Session> const& focus,
625+ std::shared_ptr<scene::Surface> const& surface) override
626+ {
627+ focus_controller->set_focus_to(focus, surface);
628+ }
629+
630+ auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> override
631+ {
632+ return focus_controller->surface_at(cursor);
633+ }
634+
635+ void raise(SurfaceSet const& surfaces) override
636+ {
637+ focus_controller->raise(surfaces);
638+ }
639+
640+ FocusController* const focus_controller;
641+ WindowManagementPolicy policy;
642+
643+ std::mutex mutex;
644+ typename SessionTo<SessionInfo>::type session_info;
645+ typename SurfaceTo<SurfaceInfo>::type surface_info;
646+ geometry::Rectangles displays;
647+};
648+}
649+}
650+
651+#endif /* MIR_SHELL_BASIC_WINDOW_MANAGER_H_ */
652
653=== added file 'src/server/shell/canonical_window_manager.cpp'
654--- src/server/shell/canonical_window_manager.cpp 1970-01-01 00:00:00 +0000
655+++ src/server/shell/canonical_window_manager.cpp 2015-03-27 16:37:31 +0000
656@@ -0,0 +1,693 @@
657+/*
658+ * Copyright © 2015 Canonical Ltd.
659+ *
660+ * This program is free software: you can redistribute it and/or modify it
661+ * under the terms of the GNU General Public License version 3,
662+ * as published by the Free Software Foundation.
663+ *
664+ * This program is distributed in the hope that it will be useful,
665+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
666+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
667+ * GNU General Public License for more details.
668+ *
669+ * You should have received a copy of the GNU General Public License
670+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
671+ *
672+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
673+ */
674+
675+#include "canonical_window_manager.h"
676+
677+#include "mir/scene/surface.h"
678+#include "mir/scene/null_surface_observer.h"
679+#include "mir/shell/display_layout.h"
680+#include "mir/geometry/displacement.h"
681+
682+#include <linux/input.h>
683+#include <csignal>
684+
685+namespace msh = mir::shell;
686+namespace ms = mir::scene;
687+using namespace mir::geometry;
688+
689+namespace
690+{
691+int const title_bar_height = 10;
692+}
693+
694+msh::CanonicalSurfaceInfo::CanonicalSurfaceInfo(
695+ std::shared_ptr<scene::Session> const& session,
696+ std::shared_ptr<scene::Surface> const& surface) :
697+ state{mir_surface_state_restored},
698+ restore_rect{surface->top_left(), surface->size()},
699+ session{session},
700+ parent{surface->parent()}
701+{
702+}
703+
704+msh::CanonicalWindowManagerPolicy::CanonicalWindowManagerPolicy(
705+ Tools* const tools,
706+ std::shared_ptr<DisplayLayout> const& display_layout) :
707+ tools{tools},
708+ display_layout{display_layout}
709+{
710+}
711+
712+void msh::CanonicalWindowManagerPolicy::click(Point cursor)
713+{
714+ if (auto const surface = tools->surface_at(cursor))
715+ select_active_surface(surface);
716+
717+ old_cursor = cursor;
718+}
719+
720+void msh::CanonicalWindowManagerPolicy::handle_session_info_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& /*displays*/)
721+{
722+}
723+
724+void msh::CanonicalWindowManagerPolicy::handle_displays_updated(CanonicalSessionInfoMap& /*session_info*/, Rectangles const& displays)
725+{
726+ display_area = displays.bounding_rectangle();
727+}
728+
729+void msh::CanonicalWindowManagerPolicy::resize(Point cursor)
730+{
731+ select_active_surface(tools->surface_at(old_cursor));
732+ resize(active_surface(), cursor, old_cursor, display_area);
733+ old_cursor = cursor;
734+}
735+
736+auto msh::CanonicalWindowManagerPolicy::handle_place_new_surface(
737+ std::shared_ptr<ms::Session> const& session,
738+ ms::SurfaceCreationParameters const& request_parameters)
739+-> ms::SurfaceCreationParameters
740+{
741+ auto parameters = request_parameters;
742+
743+ auto width = std::min(display_area.size.width.as_int(), parameters.size.width.as_int());
744+ auto height = std::min(display_area.size.height.as_int(), parameters.size.height.as_int());
745+ if (!width) width = 1;
746+ if (!height) height = 1;
747+ parameters.size = Size{width, height};
748+
749+ bool positioned = false;
750+
751+ auto const parent = parameters.parent.lock();
752+
753+ if (parameters.output_id != mir::graphics::DisplayConfigurationOutputId{0})
754+ {
755+ Rectangle rect{parameters.top_left, parameters.size};
756+ display_layout->place_in_output(parameters.output_id, rect);
757+ parameters.top_left = rect.top_left;
758+ parameters.size = rect.size;
759+ parameters.state = mir_surface_state_fullscreen;
760+ positioned = true;
761+ }
762+ else if (!parent) // No parent => client can't suggest positioning
763+ {
764+ if (auto const default_surface = session->default_surface())
765+ {
766+ // "If an app does not suggest a position for a regular surface when opening
767+ // it, and the app has at least one regular surface already open, and there
768+ // is room to do so, Mir should place it one title bar’s height below and to
769+ // the right (in LTR languages) or to the left (in RTL languages) of the app’s
770+ // most recently active window, so that you can see the title bars of both."
771+ static Displacement const offset{title_bar_height, title_bar_height};
772+
773+ parameters.top_left = default_surface->top_left() + offset;
774+
775+ // "If there is not room to do that, Mir should place it as if it was the app’s
776+ // only regular surface."
777+ positioned = display_area.contains(parameters.top_left + as_displacement(parameters.size));
778+ }
779+ }
780+
781+ if (parent && parameters.aux_rect.is_set() && parameters.edge_attachment.is_set())
782+ {
783+ auto const edge_attachment = parameters.edge_attachment.value();
784+ auto const aux_rect = parameters.aux_rect.value();
785+ auto const parent_top_left = parent->top_left();
786+ auto const top_left = aux_rect.top_left -Point{} + parent_top_left;
787+ auto const top_right= aux_rect.top_right() -Point{} + parent_top_left;
788+ auto const bot_left = aux_rect.bottom_left()-Point{} + parent_top_left;
789+
790+ if (edge_attachment && mir_edge_attachment_vertical)
791+ {
792+ if (display_area.contains(top_right + Displacement{width, height}))
793+ {
794+ parameters.top_left = top_right;
795+ positioned = true;
796+ }
797+ else if (display_area.contains(top_left + Displacement{-width, height}))
798+ {
799+ parameters.top_left = top_left + Displacement{-width, 0};
800+ positioned = true;
801+ }
802+ }
803+
804+ if (edge_attachment && mir_edge_attachment_horizontal)
805+ {
806+ if (display_area.contains(bot_left + Displacement{width, height}))
807+ {
808+ parameters.top_left = bot_left;
809+ positioned = true;
810+ }
811+ else if (display_area.contains(top_left + Displacement{width, -height}))
812+ {
813+ parameters.top_left = top_left + Displacement{0, -height};
814+ positioned = true;
815+ }
816+ }
817+ }
818+
819+ if (!positioned)
820+ {
821+ // "If an app does not suggest a position for its only regular surface when
822+ // opening it, Mir should position it horizontally centered, and vertically
823+ // such that the top margin is half the bottom margin. (Vertical centering
824+ // would look too low, and would allow little room for cascading.)"
825+ auto centred = display_area.top_left + 0.5*(
826+ as_displacement(display_area.size) - as_displacement(parameters.size));
827+
828+ parameters.top_left = centred - DeltaY{(display_area.size.height.as_int()-height)/6};
829+ }
830+
831+ return parameters;
832+}
833+
834+namespace
835+{
836+class SurfaceReadyObserver : public ms::NullSurfaceObserver,
837+ public std::enable_shared_from_this<SurfaceReadyObserver>
838+{
839+public:
840+ SurfaceReadyObserver(
841+ msh::CanonicalWindowManagerPolicy::Tools* const focus_controller,
842+ std::shared_ptr<ms::Session> const& session,
843+ std::shared_ptr<ms::Surface> const& surface) :
844+ focus_controller{focus_controller},
845+ session{session},
846+ surface{surface}
847+ {
848+ }
849+
850+private:
851+ void frame_posted(int) override
852+ {
853+ if (auto const s = surface.lock())
854+ {
855+ focus_controller->set_focus_to(session.lock(), s);
856+ s->remove_observer(shared_from_this());
857+ }
858+ }
859+
860+ msh::CanonicalWindowManagerPolicy::Tools* const focus_controller;
861+ std::weak_ptr<ms::Session> const session;
862+ std::weak_ptr<ms::Surface> const surface;
863+};
864+}
865+
866+void msh::CanonicalWindowManagerPolicy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
867+{
868+ if (auto const parent = surface->parent())
869+ {
870+ tools->info_for(parent).children.push_back(surface);
871+ }
872+
873+ tools->info_for(session).surfaces++;
874+
875+ switch (surface->type())
876+ {
877+ case mir_surface_type_normal: /**< AKA "regular" */
878+ case mir_surface_type_utility: /**< AKA "floating" */
879+ case mir_surface_type_dialog:
880+ case mir_surface_type_satellite: /**< AKA "toolbox"/"toolbar" */
881+ case mir_surface_type_freestyle:
882+ case mir_surface_type_menu:
883+ case mir_surface_type_inputmethod: /**< AKA "OSK" or handwriting etc. */
884+ // TODO There's currently no way to insert surfaces into an active (or inactive)
885+ // TODO window tree while keeping the order stable or consistent with spec.
886+ // TODO Nor is there a way to update the "default surface" when appropriate!!
887+ surface->add_observer(std::make_shared<SurfaceReadyObserver>(tools, session, surface));
888+ active_surface_ = surface;
889+ break;
890+
891+ case mir_surface_type_gloss:
892+ case mir_surface_type_tip: /**< AKA "tooltip" */
893+ default:
894+ // Cannot have input focus
895+ break;
896+ }
897+}
898+
899+void msh::CanonicalWindowManagerPolicy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
900+{
901+ if (auto const parent = tools->info_for(surface).parent.lock())
902+ {
903+ auto& siblings = tools->info_for(parent).children;
904+
905+ for (auto i = begin(siblings); i != end(siblings); ++i)
906+ {
907+ if (surface.lock() == i->lock())
908+ {
909+ siblings.erase(i);
910+ break;
911+ }
912+ }
913+ }
914+
915+
916+ if (!--tools->info_for(session).surfaces && session == tools->focused_session())
917+ {
918+ tools->focus_next();
919+ if (auto const surface = tools->focused_surface())
920+ tools->raise({surface});
921+ }
922+}
923+
924+int msh::CanonicalWindowManagerPolicy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value)
925+{
926+ auto& info = tools->info_for(surface);
927+
928+ switch (value)
929+ {
930+ case mir_surface_state_restored:
931+ case mir_surface_state_maximized:
932+ case mir_surface_state_vertmaximized:
933+ case mir_surface_state_horizmaximized:
934+ case mir_surface_state_fullscreen:
935+ break;
936+
937+ default:
938+ return info.state;
939+ }
940+
941+ if (info.state == mir_surface_state_restored)
942+ {
943+ info.restore_rect = {surface->top_left(), surface->size()};
944+ }
945+
946+ if (info.state == value)
947+ {
948+ return info.state;
949+ }
950+
951+ auto const old_pos = surface->top_left();
952+ Displacement movement;
953+
954+ switch (value)
955+ {
956+ case mir_surface_state_restored:
957+ movement = info.restore_rect.top_left - old_pos;
958+ surface->resize(info.restore_rect.size);
959+ break;
960+
961+ case mir_surface_state_maximized:
962+ movement = display_area.top_left - old_pos;
963+ surface->resize(display_area.size);
964+ break;
965+
966+ case mir_surface_state_horizmaximized:
967+ movement = Point{display_area.top_left.x, info.restore_rect.top_left.y} - old_pos;
968+ surface->resize({display_area.size.width, info.restore_rect.size.height});
969+ break;
970+
971+ case mir_surface_state_vertmaximized:
972+ movement = Point{info.restore_rect.top_left.x, display_area.top_left.y} - old_pos;
973+ surface->resize({info.restore_rect.size.width, display_area.size.height});
974+ break;
975+
976+ case mir_surface_state_fullscreen:
977+ {
978+ Rectangle rect{old_pos, surface->size()};
979+ display_layout->size_to_output(rect);
980+ movement = rect.top_left - old_pos;
981+ surface->resize(rect.size);
982+ }
983+
984+ default:
985+ break;
986+ }
987+
988+ // TODO It is rather simplistic to move a tree WRT the top_left of the root
989+ // TODO when resizing. But for more sophistication we would need to encode
990+ // TODO some sensible layout rules.
991+ move_tree(surface, movement);
992+
993+ return info.state = value;
994+}
995+
996+void msh::CanonicalWindowManagerPolicy::drag(Point cursor)
997+{
998+ select_active_surface(tools->surface_at(old_cursor));
999+ drag(active_surface(), cursor, old_cursor, display_area);
1000+ old_cursor = cursor;
1001+}
1002+
1003+bool msh::CanonicalWindowManagerPolicy::handle_key_event(MirKeyboardEvent const* event)
1004+{
1005+ auto const action = mir_keyboard_event_action(event);
1006+ auto const scan_code = mir_keyboard_event_scan_code(event);
1007+ auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
1008+
1009+ if (action == mir_keyboard_action_down && scan_code == KEY_F11)
1010+ {
1011+ switch (modifiers & modifier_mask)
1012+ {
1013+ case mir_input_event_modifier_alt:
1014+ toggle(mir_surface_state_maximized);
1015+ return true;
1016+
1017+ case mir_input_event_modifier_shift:
1018+ toggle(mir_surface_state_vertmaximized);
1019+ return true;
1020+
1021+ case mir_input_event_modifier_ctrl:
1022+ toggle(mir_surface_state_horizmaximized);
1023+ return true;
1024+
1025+ default:
1026+ break;
1027+ }
1028+ }
1029+ else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
1030+ {
1031+ if (auto const session = tools->focused_session())
1032+ {
1033+ switch (modifiers & modifier_mask)
1034+ {
1035+ case mir_input_event_modifier_alt:
1036+ kill(session->process_id(), SIGTERM);
1037+ return true;
1038+
1039+ case mir_input_event_modifier_ctrl:
1040+ if (auto const surf = session->default_surface())
1041+ {
1042+ surf->request_client_surface_close();
1043+ return true;
1044+ }
1045+
1046+ default:
1047+ break;
1048+ }
1049+ }
1050+ }
1051+
1052+ return false;
1053+}
1054+
1055+bool msh::CanonicalWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event)
1056+{
1057+ auto const count = mir_touch_event_point_count(event);
1058+
1059+ long total_x = 0;
1060+ long total_y = 0;
1061+
1062+ for (auto i = 0U; i != count; ++i)
1063+ {
1064+ total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x);
1065+ total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y);
1066+ }
1067+
1068+ Point const cursor{total_x/count, total_y/count};
1069+
1070+ bool is_drag = true;
1071+ for (auto i = 0U; i != count; ++i)
1072+ {
1073+ switch (mir_touch_event_action(event, i))
1074+ {
1075+ case mir_touch_action_up:
1076+ return false;
1077+
1078+ case mir_touch_action_down:
1079+ is_drag = false;
1080+
1081+ case mir_touch_action_change:
1082+ continue;
1083+ }
1084+ }
1085+
1086+ if (is_drag && count == 3)
1087+ {
1088+ drag(cursor);
1089+ return true;
1090+ }
1091+ else
1092+ {
1093+ click(cursor);
1094+ return false;
1095+ }
1096+}
1097+
1098+bool msh::CanonicalWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event)
1099+{
1100+ auto const action = mir_pointer_event_action(event);
1101+ auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask;
1102+ Point const cursor{
1103+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
1104+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
1105+
1106+ if (action == mir_pointer_action_button_down)
1107+ {
1108+ click(cursor);
1109+ return false;
1110+ }
1111+ else if (action == mir_pointer_action_motion &&
1112+ modifiers == mir_input_event_modifier_alt)
1113+ {
1114+ if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
1115+ {
1116+ drag(cursor);
1117+ return true;
1118+ }
1119+
1120+ if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary))
1121+ {
1122+ resize(cursor);
1123+ return true;
1124+ }
1125+ }
1126+
1127+ return false;
1128+}
1129+
1130+void msh::CanonicalWindowManagerPolicy::toggle(MirSurfaceState state)
1131+{
1132+ if (auto const surface = active_surface())
1133+ {
1134+ auto& info = tools->info_for(surface);
1135+
1136+ if (info.state == state)
1137+ state = mir_surface_state_restored;
1138+
1139+ auto const value = handle_set_state(surface, MirSurfaceState(state));
1140+ surface->configure(mir_surface_attrib_state, value);
1141+ }
1142+}
1143+
1144+void msh::CanonicalWindowManagerPolicy::select_active_surface(std::shared_ptr<ms::Surface> const& surface)
1145+{
1146+ if (!surface)
1147+ {
1148+ active_surface_.reset();
1149+ return;
1150+ }
1151+
1152+ auto const& info_for = tools->info_for(surface);
1153+
1154+ switch (surface->type())
1155+ {
1156+ case mir_surface_type_normal: /**< AKA "regular" */
1157+ case mir_surface_type_utility: /**< AKA "floating" */
1158+ case mir_surface_type_dialog:
1159+ case mir_surface_type_satellite: /**< AKA "toolbox"/"toolbar" */
1160+ case mir_surface_type_freestyle:
1161+ case mir_surface_type_menu:
1162+ case mir_surface_type_inputmethod: /**< AKA "OSK" or handwriting etc. */
1163+ tools->set_focus_to(info_for.session.lock(), surface);
1164+ raise_tree(surface);
1165+ active_surface_ = surface;
1166+ break;
1167+
1168+ case mir_surface_type_gloss:
1169+ case mir_surface_type_tip: /**< AKA "tooltip" */
1170+ default:
1171+ // Cannot have input focus - try the parent
1172+ if (auto const parent = info_for.parent.lock())
1173+ select_active_surface(parent);
1174+ break;
1175+ }
1176+}
1177+
1178+auto msh::CanonicalWindowManagerPolicy::active_surface() const
1179+-> std::shared_ptr<ms::Surface>
1180+{
1181+ if (auto const surface = active_surface_.lock())
1182+ return surface;
1183+
1184+ if (auto const session = tools->focused_session())
1185+ {
1186+ if (auto const surface = session->default_surface())
1187+ return surface;
1188+ }
1189+
1190+ return std::shared_ptr<ms::Surface>{};
1191+}
1192+
1193+bool msh::CanonicalWindowManagerPolicy::resize(std::shared_ptr<ms::Surface> const& surface, Point cursor, Point old_cursor, Rectangle bounds)
1194+{
1195+ if (!surface || !surface->input_area_contains(cursor))
1196+ return false;
1197+
1198+ auto const top_left = surface->top_left();
1199+ Rectangle const old_pos{top_left, surface->size()};
1200+
1201+ auto anchor = top_left;
1202+
1203+ for (auto const& corner : {
1204+ old_pos.top_right(),
1205+ old_pos.bottom_left(),
1206+ old_pos.bottom_right()})
1207+ {
1208+ if ((old_cursor - anchor).length_squared() <
1209+ (old_cursor - corner).length_squared())
1210+ {
1211+ anchor = corner;
1212+ }
1213+ }
1214+
1215+ bool const left_resize = anchor.x != top_left.x;
1216+ bool const top_resize = anchor.y != top_left.y;
1217+ int const x_sign = left_resize? -1 : 1;
1218+ int const y_sign = top_resize? -1 : 1;
1219+
1220+ auto const delta = cursor-old_cursor;
1221+
1222+ Size new_size{old_pos.size.width + x_sign*delta.dx, old_pos.size.height + y_sign*delta.dy};
1223+
1224+ Point new_pos = top_left + left_resize*delta.dx + top_resize*delta.dy;
1225+
1226+ if (left_resize)
1227+ {
1228+ if (new_pos.x < bounds.top_left.x)
1229+ {
1230+ new_size.width = new_size.width + (new_pos.x - bounds.top_left.x);
1231+ new_pos.x = bounds.top_left.x;
1232+ }
1233+ }
1234+ else
1235+ {
1236+ auto to_bottom_right = bounds.bottom_right() - (new_pos + as_displacement(new_size));
1237+ if (to_bottom_right.dx < DeltaX{0})
1238+ new_size.width = new_size.width + to_bottom_right.dx;
1239+ }
1240+
1241+ if (top_resize)
1242+ {
1243+ if (new_pos.y < bounds.top_left.y)
1244+ {
1245+ new_size.height = new_size.height + (new_pos.y - bounds.top_left.y);
1246+ new_pos.y = bounds.top_left.y;
1247+ }
1248+ }
1249+ else
1250+ {
1251+ auto to_bottom_right = bounds.bottom_right() - (new_pos + as_displacement(new_size));
1252+ if (to_bottom_right.dy < DeltaY{0})
1253+ new_size.height = new_size.height + to_bottom_right.dy;
1254+ }
1255+
1256+ switch (tools->info_for(surface).state)
1257+ {
1258+ case mir_surface_state_restored:
1259+ break;
1260+
1261+ // "A vertically maximised surface is anchored to the top and bottom of
1262+ // the available workspace and can have any width."
1263+ case mir_surface_state_vertmaximized:
1264+ new_pos.y = old_pos.top_left.y;
1265+ new_size.height = old_pos.size.height;
1266+ break;
1267+
1268+ // "A horizontally maximised surface is anchored to the left and right of
1269+ // the available workspace and can have any height"
1270+ case mir_surface_state_horizmaximized:
1271+ new_pos.x = old_pos.top_left.x;
1272+ new_size.width = old_pos.size.width;
1273+ break;
1274+
1275+ // "A maximised surface is anchored to the top, bottom, left and right of the
1276+ // available workspace. For example, if the launcher is always-visible then
1277+ // the left-edge of the surface is anchored to the right-edge of the launcher."
1278+ case mir_surface_state_maximized:
1279+ default:
1280+ return true;
1281+ }
1282+
1283+ surface->resize(new_size);
1284+
1285+ // TODO It is rather simplistic to move a tree WRT the top_left of the root
1286+ // TODO when resizing. But for more sophistication we would need to encode
1287+ // TODO some sensible layout rules.
1288+ move_tree(surface, new_pos-top_left);
1289+
1290+ return true;
1291+}
1292+
1293+bool msh::CanonicalWindowManagerPolicy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle bounds)
1294+{
1295+ if (surface && surface->input_area_contains(from))
1296+ {
1297+ auto const top_left = surface->top_left();
1298+ auto const surface_size = surface->size();
1299+ auto const bottom_right = top_left + as_displacement(surface_size);
1300+
1301+ auto movement = to - from;
1302+
1303+ if (movement.dx < DeltaX{0})
1304+ movement.dx = std::max(movement.dx, (bounds.top_left - top_left).dx);
1305+
1306+ if (movement.dy < DeltaY{0})
1307+ movement.dy = std::max(movement.dy, (bounds.top_left - top_left).dy);
1308+
1309+ if (movement.dx > DeltaX{0})
1310+ movement.dx = std::min(movement.dx, (bounds.bottom_right() - bottom_right).dx);
1311+
1312+ if (movement.dy > DeltaY{0})
1313+ movement.dy = std::min(movement.dy, (bounds.bottom_right() - bottom_right).dy);
1314+
1315+ move_tree(surface, movement);
1316+
1317+ return true;
1318+ }
1319+
1320+ return false;
1321+}
1322+
1323+void msh::CanonicalWindowManagerPolicy::move_tree(std::shared_ptr<ms::Surface> const& root, Displacement movement) const
1324+{
1325+ root->move_to(root->top_left() + movement);
1326+
1327+ for (auto const& child: tools->info_for(root).children)
1328+ {
1329+ move_tree(child.lock(), movement);
1330+ }
1331+}
1332+
1333+void msh::CanonicalWindowManagerPolicy::raise_tree(std::shared_ptr<scene::Surface> const& root) const
1334+{
1335+ SurfaceSet surfaces;
1336+ std::function<void(std::weak_ptr<scene::Surface> const& surface)> const add_children =
1337+ [&,this](std::weak_ptr<scene::Surface> const& surface)
1338+ {
1339+ auto const& info_for = tools->info_for(surface);
1340+ surfaces.insert(begin(info_for.children), end(info_for.children));
1341+ for (auto const& child : info_for.children)
1342+ add_children(child);
1343+ };
1344+
1345+ surfaces.insert(root);
1346+ add_children(root);
1347+
1348+ tools->raise(surfaces);
1349+}
1350
1351=== added file 'src/server/shell/canonical_window_manager.h'
1352--- src/server/shell/canonical_window_manager.h 1970-01-01 00:00:00 +0000
1353+++ src/server/shell/canonical_window_manager.h 2015-03-27 16:37:31 +0000
1354@@ -0,0 +1,130 @@
1355+/*
1356+ * Copyright © 2015 Canonical Ltd.
1357+ *
1358+ * This program is free software: you can redistribute it and/or modify it
1359+ * under the terms of the GNU General Public License version 3,
1360+ * as published by the Free Software Foundation.
1361+ *
1362+ * This program is distributed in the hope that it will be useful,
1363+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1364+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1365+ * GNU General Public License for more details.
1366+ *
1367+ * You should have received a copy of the GNU General Public License
1368+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1369+ *
1370+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
1371+ */
1372+
1373+#ifndef MIR_SHELL_CANONICAL_WINDOW_MANAGER_H_
1374+#define MIR_SHELL_CANONICAL_WINDOW_MANAGER_H_
1375+
1376+#include "basic_window_manager.h"
1377+
1378+#include "mir/geometry/displacement.h"
1379+
1380+namespace mir
1381+{
1382+namespace shell
1383+{
1384+class DisplayLayout;
1385+
1386+struct CanonicalSessionInfo
1387+{
1388+ int surfaces{0};
1389+};
1390+
1391+struct CanonicalSurfaceInfo
1392+{
1393+ CanonicalSurfaceInfo(
1394+ std::shared_ptr<scene::Session> const& session,
1395+ std::shared_ptr<scene::Surface> const& surface);
1396+
1397+ MirSurfaceState state;
1398+ geometry::Rectangle restore_rect;
1399+ std::weak_ptr<scene::Session> session;
1400+ std::weak_ptr<scene::Surface> parent;
1401+ std::vector<std::weak_ptr<scene::Surface>> children;
1402+};
1403+
1404+// standard window management algorithm:
1405+// o Switch apps: tap or click on the corresponding tile
1406+// o Move window: Alt-leftmousebutton drag
1407+// o Resize window: Alt-middle_button drag
1408+// o Maximize/restore current window (to display size): Alt-F11
1409+// o Maximize/restore current window (to display height): Shift-F11
1410+// o Maximize/restore current window (to display width): Ctrl-F11
1411+// o client requests to maximize, vertically maximize & restore
1412+class CanonicalWindowManagerPolicy
1413+{
1414+public:
1415+ using Tools = BasicWindowManagerTools<CanonicalSessionInfo, CanonicalSurfaceInfo>;
1416+ using CanonicalSessionInfoMap = typename SessionTo<CanonicalSessionInfo>::type;
1417+
1418+ explicit CanonicalWindowManagerPolicy(
1419+ Tools* const tools,
1420+ std::shared_ptr<shell::DisplayLayout> const& display_layout);
1421+
1422+ void click(geometry::Point cursor);
1423+
1424+ void handle_session_info_updated(CanonicalSessionInfoMap& session_info, geometry::Rectangles const& displays);
1425+
1426+ void handle_displays_updated(CanonicalSessionInfoMap& session_info, geometry::Rectangles const& displays);
1427+
1428+ void resize(geometry::Point cursor);
1429+
1430+ auto handle_place_new_surface(
1431+ std::shared_ptr<scene::Session> const& session,
1432+ scene::SurfaceCreationParameters const& request_parameters)
1433+ -> scene::SurfaceCreationParameters;
1434+
1435+ void handle_new_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);
1436+
1437+ void handle_delete_surface(std::shared_ptr<scene::Session> const& session, std::weak_ptr<scene::Surface> const& surface);
1438+
1439+ int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value);
1440+
1441+ void drag(geometry::Point cursor);
1442+
1443+ bool handle_key_event(MirKeyboardEvent const* event);
1444+
1445+ bool handle_touch_event(MirTouchEvent const* event);
1446+
1447+ bool handle_pointer_event(MirPointerEvent const* event);
1448+
1449+ std::vector<std::shared_ptr<scene::Surface>> generate_decorations_for(
1450+ std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);
1451+
1452+private:
1453+ static const int modifier_mask =
1454+ mir_input_event_modifier_alt |
1455+ mir_input_event_modifier_shift |
1456+ mir_input_event_modifier_sym |
1457+ mir_input_event_modifier_ctrl |
1458+ mir_input_event_modifier_meta;
1459+
1460+ void toggle(MirSurfaceState state);
1461+
1462+ // "Mir and Unity: Surfaces, input, and displays (v0.3)" talks about active
1463+ // *window*,but Mir really only understands surfaces
1464+ void select_active_surface(std::shared_ptr<scene::Surface> const& surface);
1465+ auto active_surface() const -> std::shared_ptr<scene::Surface>;
1466+
1467+ bool resize(std::shared_ptr<scene::Surface> const& surface, geometry::Point cursor, geometry::Point old_cursor, geometry::Rectangle bounds);
1468+ bool drag(std::shared_ptr<scene::Surface> surface, geometry::Point to, geometry::Point from, geometry::Rectangle bounds);
1469+ void move_tree(std::shared_ptr<scene::Surface> const& root, geometry::Displacement movement) const;
1470+ void raise_tree(std::shared_ptr<scene::Surface> const& root) const;
1471+
1472+ Tools* const tools;
1473+ std::shared_ptr<DisplayLayout> const display_layout;
1474+
1475+ geometry::Rectangle display_area;
1476+ geometry::Point old_cursor{};
1477+ std::weak_ptr<scene::Surface> active_surface_;
1478+};
1479+
1480+using CanonicalWindowManager = BasicWindowManager<CanonicalWindowManagerPolicy, CanonicalSessionInfo, CanonicalSurfaceInfo>;
1481+}
1482+}
1483+
1484+#endif /* MIR_SHELL_CANONICAL_WINDOW_MANAGER_H_ */
1485
1486=== modified file 'src/server/shell/default_configuration.cpp'
1487--- src/server/shell/default_configuration.cpp 2015-03-27 06:58:51 +0000
1488+++ src/server/shell/default_configuration.cpp 2015-03-27 16:37:31 +0000
1489@@ -21,7 +21,7 @@
1490
1491
1492 #include "default_placement_strategy.h"
1493-#include "default_window_manager.h"
1494+#include "canonical_window_manager.h"
1495 #include "mir/input/composite_event_filter.h"
1496 #include "mir/shell/abstract_shell.h"
1497 #include "frontend_shell.h"
1498@@ -52,11 +52,9 @@
1499 auto mir::DefaultServerConfiguration::the_window_manager_builder() -> shell::WindowManagerBuilder
1500 {
1501 return [this](msh::FocusController* focus_controller)
1502- { return std::make_shared<msh::DefaultWindowManager>(
1503+ { return std::make_shared<msh::CanonicalWindowManager>(
1504 focus_controller,
1505- the_placement_strategy(),
1506- the_session_coordinator(),
1507- the_surface_configurator()); };
1508+ the_shell_display_layout()); };
1509 }
1510
1511 auto mir::DefaultServerConfiguration::wrap_shell(std::shared_ptr<msh::Shell> const& wrapped) -> std::shared_ptr<msh::Shell>
1512
1513=== modified file 'src/server/symbols.map'
1514--- src/server/symbols.map 2015-03-27 06:58:51 +0000
1515+++ src/server/symbols.map 2015-03-27 16:37:31 +0000
1516@@ -510,6 +510,21 @@
1517 vtable?for?mir::compositor::RecentlyUsedCache;
1518
1519 # these symbols are needed by the test framework but are not intended to be public
1520+ mir::shell::CanonicalWindowManagerPolicy::handle_set_state*;
1521+ mir::shell::CanonicalWindowManagerPolicy::CanonicalWindowManagerPolicy*;
1522+ mir::shell::CanonicalWindowManagerPolicy::handle_session_info_updated*;
1523+ mir::shell::CanonicalWindowManagerPolicy::handle_session_info_updated*;
1524+ mir::shell::CanonicalWindowManagerPolicy::handle_place_new_surface*;
1525+ mir::shell::CanonicalWindowManagerPolicy::handle_new_surface*;
1526+ mir::shell::CanonicalSurfaceInfo::CanonicalSurfaceInfo*;
1527+ mir::shell::CanonicalWindowManagerPolicy::handle_delete_surface*;
1528+ mir::shell::CanonicalWindowManagerPolicy::handle_displays_updated*;
1529+ mir::shell::CanonicalWindowManagerPolicy::handle_displays_updated*;
1530+ mir::shell::CanonicalWindowManagerPolicy::handle_key_event*;
1531+ mir::shell::CanonicalWindowManagerPolicy::handle_touch_event*;
1532+ mir::shell::CanonicalWindowManagerPolicy::handle_pointer_event*;
1533+ mir::shell::DefaultWindowManager::DefaultWindowManager*;
1534+
1535 mir::DefaultServerConfiguration::clock*;
1536 mir::DefaultServerConfiguration::DefaultServerConfiguration*;
1537 mir::DefaultServerConfiguration::is_key_repeat_enabled*;
1538
1539=== modified file 'tests/acceptance-tests/test_client_library.cpp'
1540--- tests/acceptance-tests/test_client_library.cpp 2015-03-25 02:48:40 +0000
1541+++ tests/acceptance-tests/test_client_library.cpp 2015-03-27 16:37:31 +0000
1542@@ -273,11 +273,11 @@
1543 mir_wait_for(mir_surface_set_state(surface, static_cast<MirSurfaceState>(999)));
1544 EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_fullscreen));
1545
1546- mir_wait_for(mir_surface_set_state(surface, mir_surface_state_minimized));
1547- EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_minimized));
1548+ mir_wait_for(mir_surface_set_state(surface, mir_surface_state_horizmaximized));
1549+ EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_horizmaximized));
1550
1551 mir_wait_for(mir_surface_set_state(surface, static_cast<MirSurfaceState>(888)));
1552- EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_minimized));
1553+ EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_horizmaximized));
1554
1555 // Stress-test synchronization logic with some flooding
1556 for (int i = 0; i < 100; i++)
1557@@ -540,7 +540,7 @@
1558 b.join();
1559 c.join();
1560
1561- EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_minimized));
1562+ EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_fullscreen));
1563
1564 mir_surface_release_sync(surface);
1565
1566
1567=== modified file 'tests/acceptance-tests/test_client_surface_events.cpp'
1568--- tests/acceptance-tests/test_client_surface_events.cpp 2015-03-25 02:48:40 +0000
1569+++ tests/acceptance-tests/test_client_surface_events.cpp 2015-03-27 16:37:31 +0000
1570@@ -156,7 +156,7 @@
1571
1572 {
1573 mir_wait_for(mir_surface_set_state(surface, mir_surface_state_fullscreen));
1574- mir_wait_for(mir_surface_set_state(other_surface, mir_surface_state_minimized));
1575+ mir_wait_for(mir_surface_set_state(other_surface, mir_surface_state_vertmaximized));
1576
1577 std::lock_guard<decltype(last_event_mutex)> last_event_lock{last_event_mutex};
1578
1579@@ -182,7 +182,7 @@
1580 reset_last_event();
1581
1582 {
1583- mir_wait_for(mir_surface_set_state(surface, mir_surface_state_minimized));
1584+ mir_wait_for(mir_surface_set_state(surface, mir_surface_state_vertmaximized));
1585
1586 std::lock_guard<decltype(last_event_mutex)> last_event_lock{last_event_mutex};
1587
1588@@ -190,7 +190,7 @@
1589 EXPECT_THAT(last_event.type, Eq(mir_event_type_surface));
1590 EXPECT_THAT(last_event.surface.id, Eq(surface_id));
1591 EXPECT_THAT(last_event.surface.attrib, Eq(mir_surface_attrib_state));
1592- EXPECT_THAT(last_event.surface.value, Eq(mir_surface_state_minimized));
1593+ EXPECT_THAT(last_event.surface.value, Eq(mir_surface_state_vertmaximized));
1594 }
1595
1596 reset_last_event();
1597
1598=== modified file 'tests/acceptance-tests/test_client_surface_visibility.cpp'
1599--- tests/acceptance-tests/test_client_surface_visibility.cpp 2015-03-27 06:58:51 +0000
1600+++ tests/acceptance-tests/test_client_surface_visibility.cpp 2015-03-27 16:37:31 +0000
1601@@ -58,9 +58,11 @@
1602 std::shared_ptr<ms::Session> const& session,
1603 ms::SurfaceCreationParameters const& params) override
1604 {
1605- auto const surface = msh::ShellWrapper::create_surface(session, params);
1606- surfaces.push_back(session->surface(surface));
1607- return surface;
1608+ auto const result = msh::ShellWrapper::create_surface(session, params);
1609+ auto const surface = session->surface(result);
1610+ surface->move_to({0, 0});
1611+ surfaces.push_back(surface);
1612+ return result;
1613 }
1614
1615 std::shared_ptr<ms::Surface> surface(int index)
1616
1617=== modified file 'tests/acceptance-tests/test_debug_api.cpp'
1618--- tests/acceptance-tests/test_debug_api.cpp 2015-01-21 07:34:50 +0000
1619+++ tests/acceptance-tests/test_debug_api.cpp 2015-03-27 16:37:31 +0000
1620@@ -1,5 +1,5 @@
1621 /*
1622- * Copyright © 2014 Canonical Ltd.
1623+ * Copyright © 2014-2015 Canonical Ltd.
1624 *
1625 * This program is free software: you can redistribute it and/or modify
1626 * it under the terms of the GNU General Public License version 3 as
1627@@ -16,8 +16,10 @@
1628 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
1629 */
1630
1631+#include "mir/scene/session.h"
1632+#include "mir/scene/surface.h"
1633 #include "mir/scene/surface_creation_parameters.h"
1634-#include "mir/scene/placement_strategy.h"
1635+#include "mir/shell/shell_wrapper.h"
1636
1637 #include "mir_test_framework/headless_test.h"
1638 #include "mir_test_framework/any_surface.h"
1639@@ -29,20 +31,26 @@
1640 #include <gmock/gmock.h>
1641
1642 namespace ms = mir::scene;
1643+namespace msh = mir::shell;
1644
1645 namespace mtf = mir_test_framework;
1646
1647 namespace
1648 {
1649-class SimpleConfigurablePlacementStrategy : public ms::PlacementStrategy
1650+class SimpleConfigurablePlacementShell : public msh::ShellWrapper
1651 {
1652 public:
1653- ms::SurfaceCreationParameters place(ms::Session const& /*session*/,
1654- ms::SurfaceCreationParameters const& request_parameters) override
1655+ using msh::ShellWrapper::ShellWrapper;
1656+
1657+ mir::frontend::SurfaceId create_surface(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)
1658 {
1659- return ms::SurfaceCreationParameters(request_parameters)
1660- .of_position(placement.top_left)
1661- .of_size(placement.size);
1662+ auto const result = msh::ShellWrapper::create_surface(session, params);
1663+ auto const surface = session->surface(result);
1664+
1665+ surface->move_to(placement.top_left);
1666+ surface->resize(placement.size);
1667+
1668+ return result;
1669 }
1670
1671 mir::geometry::Rectangle placement{{0, 0}, {100, 100}};
1672@@ -62,7 +70,12 @@
1673 {
1674 add_to_environment("MIR_SERVER_NO_FILE", "");
1675
1676- server.override_the_placement_strategy([&]{ return placement_strategy; });
1677+ server.wrap_shell([&](std::shared_ptr<msh::Shell> const& wrapped)
1678+ {
1679+ return placement_strategy =
1680+ std::make_shared<SimpleConfigurablePlacementShell>(wrapped);
1681+ });
1682+
1683 mtf::HeadlessTest::SetUp();
1684 }
1685
1686@@ -107,8 +120,7 @@
1687 MirConnection* connection{nullptr};
1688
1689 private:
1690- std::shared_ptr<SimpleConfigurablePlacementStrategy> const placement_strategy
1691- {std::make_shared<SimpleConfigurablePlacementStrategy>()};
1692+ std::shared_ptr<SimpleConfigurablePlacementShell> placement_strategy;
1693 };
1694 }
1695
1696
1697=== modified file 'tests/acceptance-tests/test_display_configuration.cpp'
1698--- tests/acceptance-tests/test_display_configuration.cpp 2015-03-25 02:48:40 +0000
1699+++ tests/acceptance-tests/test_display_configuration.cpp 2015-03-27 16:37:31 +0000
1700@@ -232,15 +232,22 @@
1701 void connect()
1702 {
1703 connection = mir_connect_sync(mir_test_socket.c_str(), __PRETTY_FUNCTION__);
1704+
1705+ auto const spec = mir_connection_create_spec_for_normal_surface(connection, 100, 100, mir_pixel_format_abgr_8888);
1706+ surface = mir_surface_create_sync(spec);
1707+ mir_surface_spec_release(spec);
1708+ mir_buffer_stream_swap_buffers_sync(mir_surface_get_buffer_stream(surface));
1709 }
1710
1711 void disconnect()
1712 {
1713+ mir_surface_release_sync(surface);
1714 mir_connection_release(connection);
1715 }
1716
1717 std::string mir_test_socket;
1718 MirConnection* connection{nullptr};
1719+ MirSurface* surface{nullptr};
1720 };
1721
1722 struct DisplayClient : SimpleClient
1723@@ -282,16 +289,15 @@
1724 {
1725 EXPECT_CALL(mock_display, configure(_)).Times(0);
1726
1727- DisplayClient display_client{new_connection()};
1728 SimpleClient simple_client{new_connection()};
1729
1730- display_client.connect();
1731-
1732 /* Connect the simple client. After this the simple client should have the focus. */
1733 simple_client.connect();
1734
1735 /* Apply the display config while not focused */
1736- display_client.apply_config();
1737+ auto const configuration = mir_connection_create_display_config(connection);
1738+ mir_wait_for(mir_connection_apply_display_config(connection, configuration));
1739+ mir_display_config_destroy(configuration);
1740
1741 wait_for_server_actions_to_finish(*server.the_main_loop());
1742 testing::Mock::VerifyAndClearExpectations(&mock_display);
1743@@ -306,8 +312,6 @@
1744
1745 wait_for_server_actions_to_finish(*server.the_main_loop());
1746 testing::Mock::VerifyAndClearExpectations(&mock_display);
1747-
1748- display_client.disconnect();
1749 }
1750
1751 TEST_F(DisplayConfigurationTest, changing_focus_from_client_with_config_to_client_without_config_configures_display)
1752
1753=== modified file 'tests/acceptance-tests/test_nested_mir.cpp'
1754--- tests/acceptance-tests/test_nested_mir.cpp 2015-03-26 01:40:32 +0000
1755+++ tests/acceptance-tests/test_nested_mir.cpp 2015-03-27 16:37:31 +0000
1756@@ -21,7 +21,7 @@
1757 #include "mir/graphics/display.h"
1758 #include "mir/graphics/display_configuration.h"
1759 #include "mir/main_loop.h"
1760-#include "mir/shell/focus_controller.h"
1761+#include "mir/scene/session_coordinator.h"
1762 #include "mir/scene/session.h"
1763 #include "mir/shell/host_lifecycle_event_listener.h"
1764
1765@@ -190,7 +190,7 @@
1766
1767 void trigger_lifecycle_event(MirLifecycleState const lifecycle_state)
1768 {
1769- auto const app = server.the_focus_controller()->focused_session();
1770+ auto const app = server.the_session_coordinator()->successor_of({});
1771
1772 EXPECT_TRUE(app != nullptr) << "Nested server not connected";
1773
1774
1775=== modified file 'tests/acceptance-tests/test_shell_control_of_surface_configuration.cpp'
1776--- tests/acceptance-tests/test_shell_control_of_surface_configuration.cpp 2015-03-25 02:48:40 +0000
1777+++ tests/acceptance-tests/test_shell_control_of_surface_configuration.cpp 2015-03-27 16:37:31 +0000
1778@@ -16,70 +16,100 @@
1779 * Authored by: Robert Carr <robert.carr@canonical.com>
1780 */
1781
1782-#include "mir/scene/surface_configurator.h"
1783 #include "mir/scene/surface.h"
1784
1785-#include "mir_test/fake_shared.h"
1786-#include "mir_test_doubles/mock_surface_configurator.h"
1787 #include "mir_test_framework/connected_client_with_a_surface.h"
1788
1789+#include "src/server/shell/canonical_window_manager.h"
1790+
1791 #include "mir_toolkit/mir_client_library.h"
1792
1793 #include <gtest/gtest.h>
1794 #include <gmock/gmock.h>
1795
1796 namespace ms = mir::scene;
1797+namespace msh = mir::shell;
1798
1799-namespace mt = mir::test;
1800-namespace mtd = mt::doubles;
1801 namespace mtf = mir_test_framework;
1802 using namespace ::testing;
1803
1804 namespace
1805 {
1806+struct MockWindowManager : msh::CanonicalWindowManager
1807+{
1808+ using msh::CanonicalWindowManager::CanonicalWindowManager;
1809+
1810+ MOCK_METHOD4(set_surface_attribute,
1811+ int(std::shared_ptr<ms::Session> const& session,
1812+ std::shared_ptr<ms::Surface> const& surface,
1813+ MirSurfaceAttrib attrib,
1814+ int value));
1815+
1816+ int real_set_surface_attribute(std::shared_ptr<ms::Session> const& session,
1817+ std::shared_ptr<ms::Surface> const& surface,
1818+ MirSurfaceAttrib attrib,
1819+ int value)
1820+ {
1821+ return msh::CanonicalWindowManager::set_surface_attribute(session, surface, attrib, value);
1822+ }
1823+};
1824+
1825 struct ShellSurfaceConfiguration : mtf::ConnectedClientWithASurface
1826 {
1827 void SetUp() override
1828 {
1829- server.override_the_surface_configurator([this]
1830+ server.override_the_window_manager_builder([this]
1831+ (msh::FocusController* focus_controller) -> std::shared_ptr<msh::WindowManager>
1832 {
1833- return mt::fake_shared(mock_configurator);
1834+ mock_window_manager = std::make_shared<MockWindowManager>(
1835+ focus_controller,
1836+ server.the_shell_display_layout());
1837+
1838+ ON_CALL(*mock_window_manager, set_surface_attribute(_, _, _, _))
1839+ .WillByDefault(Invoke(
1840+ mock_window_manager.get(), &MockWindowManager::real_set_surface_attribute));
1841+
1842+ EXPECT_CALL(*mock_window_manager,
1843+ set_surface_attribute(_, _, Ne(mir_surface_attrib_state), _))
1844+ .Times(AnyNumber());
1845+
1846+ return mock_window_manager;
1847 });
1848
1849 mtf::ConnectedClientWithASurface::SetUp();
1850 }
1851
1852- mtd::MockSurfaceConfigurator mock_configurator;
1853+ std::shared_ptr<MockWindowManager> mock_window_manager;
1854 };
1855 }
1856
1857-TEST_F(ShellSurfaceConfiguration, the_shell_surface_configurator_is_notified_of_attribute_changes)
1858+TEST_F(ShellSurfaceConfiguration, the_window_manager_is_notified_of_attribute_changes)
1859 {
1860-
1861- EXPECT_CALL(mock_configurator, select_attribute_value(_, Ne(mir_surface_attrib_state), _))
1862- .Times(AnyNumber())
1863- .WillRepeatedly(ReturnArg<2>());
1864- EXPECT_CALL(mock_configurator, attribute_set(_, Ne(mir_surface_attrib_state), _)).Times(AnyNumber());
1865-
1866- ON_CALL(mock_configurator, select_attribute_value(_, _, _)).WillByDefault(Return(mir_surface_state_maximized));
1867- EXPECT_CALL(mock_configurator, select_attribute_value(_, mir_surface_attrib_state, Eq(mir_surface_state_maximized))).Times(1);
1868- EXPECT_CALL(mock_configurator, attribute_set(_, mir_surface_attrib_state, Eq(mir_surface_state_maximized))).Times(1);
1869+ EXPECT_CALL(*mock_window_manager,
1870+ set_surface_attribute(_, _, mir_surface_attrib_state, Eq(mir_surface_state_maximized)));
1871
1872 mir_wait_for(mir_surface_set_state(surface, mir_surface_state_maximized));
1873- EXPECT_EQ(mir_surface_state_maximized, mir_surface_get_state(surface));
1874+
1875+ EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_maximized));
1876 }
1877
1878-TEST_F(ShellSurfaceConfiguration, the_shell_surface_configurator_may_interfere_with_attribute_changes)
1879+TEST_F(ShellSurfaceConfiguration, the_window_manager_may_interfere_with_attribute_changes)
1880 {
1881- EXPECT_CALL(mock_configurator, select_attribute_value(_, Ne(mir_surface_attrib_state), _))
1882- .Times(AnyNumber())
1883- .WillRepeatedly(ReturnArg<2>());
1884- EXPECT_CALL(mock_configurator, attribute_set(_, Ne(mir_surface_attrib_state), _)).Times(AnyNumber());
1885+ auto const set_to_vertmax = [this](
1886+ std::shared_ptr<ms::Session> const& session,
1887+ std::shared_ptr<ms::Surface> const& surface,
1888+ MirSurfaceAttrib attrib,
1889+ int /*value*/)
1890+ {
1891+ return mock_window_manager->real_set_surface_attribute(
1892+ session, surface, attrib, mir_surface_state_vertmaximized);
1893+ };
1894
1895- EXPECT_CALL(mock_configurator, select_attribute_value(_, mir_surface_attrib_state, Eq(mir_surface_state_maximized))).Times(1)
1896- .WillOnce(Return(mir_surface_state_maximized));
1897- EXPECT_CALL(mock_configurator, attribute_set(_, mir_surface_attrib_state, Eq(mir_surface_state_maximized))).Times(1);
1898+ EXPECT_CALL(*mock_window_manager,
1899+ set_surface_attribute(_, _, mir_surface_attrib_state, Eq(mir_surface_state_maximized)))
1900+ .WillOnce(Invoke(set_to_vertmax));
1901
1902 mir_wait_for(mir_surface_set_state(surface, mir_surface_state_maximized));
1903- EXPECT_EQ(mir_surface_state_maximized, mir_surface_get_state(surface));
1904+
1905+ EXPECT_THAT(mir_surface_get_state(surface), Eq(mir_surface_state_vertmaximized));
1906 }
1907
1908=== modified file 'tests/acceptance-tests/throwback/test_custom_input_dispatcher.cpp'
1909--- tests/acceptance-tests/throwback/test_custom_input_dispatcher.cpp 2015-03-25 02:48:40 +0000
1910+++ tests/acceptance-tests/throwback/test_custom_input_dispatcher.cpp 2015-03-27 16:37:31 +0000
1911@@ -166,10 +166,7 @@
1912 using namespace ::testing;
1913 auto const dispatcher = the_input_dispatcher_mock();
1914
1915- InSequence seq;
1916- EXPECT_CALL(*dispatcher, focus_cleared()).Times(1);
1917- EXPECT_CALL(*dispatcher, focus_changed(_)).Times(1);
1918- EXPECT_CALL(*dispatcher, focus_cleared()).Times(1)
1919+ EXPECT_CALL(*dispatcher, focus_changed(_)).Times(1)
1920 .WillOnce(InvokeWithoutArgs([this] { dispatching_done.signal_ready(); }));
1921 }
1922 } server_config;
1923
1924=== modified file 'tests/include/mir_test_framework/fake_event_hub_server_configuration.h'
1925--- tests/include/mir_test_framework/fake_event_hub_server_configuration.h 2015-01-21 07:34:50 +0000
1926+++ tests/include/mir_test_framework/fake_event_hub_server_configuration.h 2015-03-27 16:37:31 +0000
1927@@ -47,6 +47,9 @@
1928 std::shared_ptr<mir::shell::InputTargeter> the_input_targeter() override;
1929 std::shared_ptr<mir::input::InputSender> the_input_sender() override;
1930
1931+ // TODO remove reliance on legacy window management
1932+ auto the_window_manager_builder() -> shell::WindowManagerBuilder override;
1933+
1934 std::shared_ptr<mir::input::android::FakeEventHub> fake_event_hub;
1935 };
1936
1937
1938=== modified file 'tests/integration-tests/test_surface_first_frame_sync.cpp'
1939--- tests/integration-tests/test_surface_first_frame_sync.cpp 2015-03-25 02:48:40 +0000
1940+++ tests/integration-tests/test_surface_first_frame_sync.cpp 2015-03-27 16:37:31 +0000
1941@@ -23,6 +23,7 @@
1942 #include "mir/compositor/compositor.h"
1943 #include "mir/compositor/display_buffer_compositor.h"
1944 #include "mir/compositor/display_buffer_compositor_factory.h"
1945+#include "mir/shell/shell.h"
1946 #include "mir/compositor/scene.h"
1947 #include "mir/scene/legacy_scene_change_notification.h"
1948
1949@@ -55,15 +56,18 @@
1950 {
1951 public:
1952 SynchronousCompositor(std::shared_ptr<mg::Display> const& display_,
1953+ std::shared_ptr<mc::DisplayListener> const& display_listener,
1954 std::shared_ptr<mc::Scene> const& s,
1955 std::shared_ptr<mc::DisplayBufferCompositorFactory> const& dbc_factory)
1956 : display{display_},
1957+ display_listener{display_listener},
1958 scene{s}
1959 {
1960 display->for_each_display_sync_group([this, &dbc_factory](mg::DisplaySyncGroup& group)
1961 {
1962 group.for_each_display_buffer([this, &dbc_factory](mg::DisplayBuffer& display_buffer)
1963 {
1964+ this->display_listener->add_display(display_buffer.view_area());
1965 auto dbc = dbc_factory->create_compositor_for(display_buffer);
1966 scene->register_compositor(dbc.get());
1967 display_buffer_compositor_map[&display_buffer] = std::move(dbc);
1968@@ -115,6 +119,7 @@
1969
1970 private:
1971 std::shared_ptr<mg::Display> const display;
1972+ std::shared_ptr<mc::DisplayListener> const display_listener;
1973 std::shared_ptr<mc::Scene> const scene;
1974 std::unordered_map<mg::DisplayBuffer*,std::unique_ptr<mc::DisplayBufferCompositor>> display_buffer_compositor_map;
1975
1976@@ -229,6 +234,7 @@
1977 sync_compositor =
1978 std::make_shared<SynchronousCompositor>(
1979 the_display(),
1980+ the_shell(),
1981 the_scene(),
1982 the_display_buffer_compositor_factory());
1983 }
1984
1985=== modified file 'tests/mir_test_framework/fake_event_hub_server_configuration.cpp'
1986--- tests/mir_test_framework/fake_event_hub_server_configuration.cpp 2015-01-21 07:34:50 +0000
1987+++ tests/mir_test_framework/fake_event_hub_server_configuration.cpp 2015-03-27 16:37:31 +0000
1988@@ -1,5 +1,5 @@
1989 /*
1990- * Copyright © 2013-2014 Canonical Ltd.
1991+ * Copyright © 2013-2015 Canonical Ltd.
1992 *
1993 * This program is free software: you can redistribute it and/or modify it
1994 * under the terms of the GNU General Public License version 3,
1995@@ -21,6 +21,8 @@
1996
1997 #include "mir_test/fake_event_hub.h"
1998
1999+#include "src/server/shell/default_window_manager.h"
2000+
2001 namespace mtf = mir_test_framework;
2002 namespace mi = mir::input;
2003 namespace ms = mir::shell;
2004@@ -60,3 +62,14 @@
2005
2006 return fake_event_hub;
2007 }
2008+
2009+auto mtf::FakeEventHubServerConfiguration::the_window_manager_builder() -> shell::WindowManagerBuilder
2010+{
2011+ return [&](ms::FocusController* focus_controller)
2012+ { return std::make_shared<ms::DefaultWindowManager>(
2013+ focus_controller,
2014+ the_placement_strategy(),
2015+ the_session_coordinator(),
2016+ the_surface_configurator()); };
2017+}
2018+

Subscribers

People subscribed via source and target branches