Merge lp:~alan-griffiths/mir/default-to-canonical-window-manager into lp:mir
- default-to-canonical-window-manager
- Merge into development-branch
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 |
Related bugs: |
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 CanonicalWindow
Description of the change
Change the default window management policy to CanonicalWindow
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2420
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2421
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2422
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Robert Carr (robertcarr) wrote : | # |
I think you forgot to remove the old WM from examples?
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.
Kevin DuBois (kdub) wrote : | # |
106 + virtual auto info_for(
108 + virtual std::shared_
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_
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2424
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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_
> "canonical_
Just for clarity's sake, it took me a bit of staring to realize that there were 2 "CanonicalWindo
Robert Carr (robertcarr) : | # |
Alan Griffiths (alan-griffiths) wrote : | # |
> Just for clarity's sake, it took me a bit of staring to realize that there
> were 2 "CanonicalWindo
> we had "StandardWindow
> 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 { CanonicalWindow
namespace examples { CanonicalWindow
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)
Kevin DuBois (kdub) wrote : | # |
and for the names I'm okay with the proposed:
namespace shell { CanonicalWindow
namespace examples { CanonicalWindow
but I think "Staging" might make more sense, given the intended diverge (until we drop or move the divergent features into the shell namespace)
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 { CanonicalWindow
> CanonicalWindow
>
> namespace examples { CanonicalWindow
> CanonicalWindow
> CanonicalSurfac
+1
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2426
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
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-
Preview Diff
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 | + |
FAILED: Continuous integration, rev:2419 jenkins. qa.ubuntu. com/job/ mir-ci/ 3335/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/1785 jenkins. qa.ubuntu. com/job/ mir-clang- vivid-amd64- build/1784/ console jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/1736/ console jenkins. qa.ubuntu. com/job/ mir-vivid- amd64-ci/ 1332/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 1736/console
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/3335/ rebuild
http://