Merge lp:~alan-griffiths/qtmir/import-WindowManagement-code-from-Mir-examples into lp:qtmir
- import-WindowManagement-code-from-Mir-examples
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Gerry Boland |
Approved revision: | 422 |
Merged at revision: | 454 |
Proposed branch: | lp:~alan-griffiths/qtmir/import-WindowManagement-code-from-Mir-examples |
Merge into: | lp:qtmir |
Diff against target: |
3203 lines (+3132/-0) 13 files modified
src/platforms/mirserver/CMakeLists.txt (+2/-0) src/platforms/mirserver/wm-wip/CMakeLists.txt (+22/-0) src/platforms/mirserver/wm-wip/README (+5/-0) src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp (+312/-0) src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h (+252/-0) src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp (+946/-0) src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h (+132/-0) src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp (+640/-0) src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h (+124/-0) src/platforms/mirserver/wm-wip/server_example_window_management.cpp (+155/-0) src/platforms/mirserver/wm-wip/server_example_window_management.h (+33/-0) src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp (+406/-0) src/platforms/mirserver/wm-wip/server_example_window_management_info.h (+103/-0) |
To merge this branch: | bzr merge lp:~alan-griffiths/qtmir/import-WindowManagement-code-from-Mir-examples |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity8 CI Bot (community) | continuous-integration | Needs Fixing | |
Gerry Boland (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Review via email: mp+278719@code.launchpad.net |
Commit message
Copy the Window Management work-in-progress from Mir examples.
Description of the change
Copy the Window Management work-in-progress from Mir examples. (Just builds the library, no attempt to use it yet.)
PS Jenkins bot (ps-jenkins) wrote : | # |
Alan Griffiths (alan-griffiths) wrote : | # |
Why Wily?
(Failures are unrelated to MP)
Daniel d'Andrada (dandrader) wrote : | # |
In src/platforms/
"""
+ std::shared_ptr <scene::Surface> titlebar;
""
A QML shell won't be using mir surfaces for placing title bars. They will be QML items in the compositor's qml scene. Mir will be oblivious to that.
Daniel d'Andrada (dandrader) wrote : | # |
"""
void init_titlebar(
void paint_titlebar(int intensity);
"""
Likewise
Daniel d'Andrada (dandrader) wrote : | # |
I don't get the point of dumping this code, unmodified, here in qtmir.
Alan Griffiths (alan-griffiths) wrote : | # |
> I don't get the point of dumping this code, unmodified, here in qtmir.
This code is a snapshot of the different Mir examples of Window Management ("canonical", "tiling", "fullscreen"). While these are simplistic examples they are also helpful reference cases to getting generic WM support right.
The the code isn't published by libmirserver as mir-team do not want to publish the API until we get it stable, and we've been using the feedback from the Mir examples to evolve it. It is a work-in-progress and now want feedback from integration into Qtmir.
"Dumping" it here accomplishes two goals:
/1/ it makes it available to Qtmir without exposing it in the Mir API
/2/ feedback is easier to accomplish with the code here, so that we can change it without tying it to the Mir release cycle.
In the medium term changes will be fed back into Mir, published as a supported API and the code deleted from Qtmir.
To aid the tracking of changes for feedback to Mir this MI is just the unmodified code. Any tailoring for the needs of Qtmir or Unity8 will be done in subsequent MPs.
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:418
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
- 419. By Alan Griffiths
-
merge lp:qtmir
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:419
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:419
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 420. By Alan Griffiths
-
Re-sync with mir/examples
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:420
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:420
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
FAILURE: http://
The following packages have unmet dependencies:
pbuilder-
Do we care about wily (and Mir 0,17 support) here?
Gerry Boland (gerboland) wrote : | # |
Can you please have this be only built when a cmake flag is set? Just to avoid building it unnecessarily.
- 421. By Alan Griffiths
-
Only build the mir example Window Managers with cmake -DEXAMPLE_
MIR_WINDOW_ MANAGERS= on
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:421
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
- 422. By Alan Griffiths
-
Fix compile options
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:421
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:422
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:422
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:422
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'src/platforms/mirserver/CMakeLists.txt' |
2 | --- src/platforms/mirserver/CMakeLists.txt 2015-12-07 10:51:03 +0000 |
3 | +++ src/platforms/mirserver/CMakeLists.txt 2016-01-20 19:52:54 +0000 |
4 | @@ -36,6 +36,8 @@ |
5 | ${APPLICATION_API_INCLUDE_DIRS} |
6 | ) |
7 | |
8 | +add_subdirectory(wm-wip) |
9 | + |
10 | # We have to remove -pedantic for tracepoints.c |
11 | string (REPLACE " -pedantic " " " CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) |
12 | # Needed to compile tracepoints in C99 mode. |
13 | |
14 | === added directory 'src/platforms/mirserver/wm-wip' |
15 | === added file 'src/platforms/mirserver/wm-wip/CMakeLists.txt' |
16 | --- src/platforms/mirserver/wm-wip/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
17 | +++ src/platforms/mirserver/wm-wip/CMakeLists.txt 2016-01-20 19:52:54 +0000 |
18 | @@ -0,0 +1,22 @@ |
19 | +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fPIC") |
20 | + |
21 | +add_library(experimentalwindowmanager STATIC |
22 | + server_example_basic_window_manager.cpp |
23 | + server_example_basic_window_manager.h |
24 | + server_example_window_management_info.cpp |
25 | + server_example_window_management_info.h |
26 | +) |
27 | + |
28 | + |
29 | +if (EXAMPLE_MIR_WINDOW_MANAGERS) |
30 | + |
31 | +add_library(examplewindowmanager STATIC |
32 | + server_example_canonical_window_manager.h |
33 | + server_example_tiling_window_manager.h |
34 | + server_example_window_management.h |
35 | + server_example_canonical_window_manager.cpp |
36 | + server_example_tiling_window_manager.cpp |
37 | + server_example_window_management.cpp |
38 | +) |
39 | + |
40 | +endif() |
41 | |
42 | === added file 'src/platforms/mirserver/wm-wip/README' |
43 | --- src/platforms/mirserver/wm-wip/README 1970-01-01 00:00:00 +0000 |
44 | +++ src/platforms/mirserver/wm-wip/README 2016-01-20 19:52:54 +0000 |
45 | @@ -0,0 +1,5 @@ |
46 | +examples for mir clients. you should have package 'libmirclient-dev' installed |
47 | + |
48 | +you can compile with a command like: |
49 | + g++ -std=c++0x -o mir_demo_client_scroll `pkg-config --libs --cflags mirclient` demo_client_scroll.cpp graphics_utils.cpp |
50 | + gcc -o mir_demo_client_flicker `pkg-config --libs --cflags mirclient` demo_client_flicker.c |
51 | |
52 | === added file 'src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp' |
53 | --- src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp 1970-01-01 00:00:00 +0000 |
54 | +++ src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp 2016-01-20 19:52:54 +0000 |
55 | @@ -0,0 +1,312 @@ |
56 | +/* |
57 | + * Copyright © 2015 Canonical Ltd. |
58 | + * |
59 | + * This program is free software: you can redistribute it and/or modify it |
60 | + * under the terms of the GNU General Public License version 3, |
61 | + * as published by the Free Software Foundation. |
62 | + * |
63 | + * This program is distributed in the hope that it will be useful, |
64 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
65 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
66 | + * GNU General Public License for more details. |
67 | + * |
68 | + * You should have received a copy of the GNU General Public License |
69 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
70 | + * |
71 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
72 | + */ |
73 | + |
74 | +#include "server_example_basic_window_manager.h" |
75 | + |
76 | +#include "mir/scene/session.h" |
77 | +#include "mir/scene/surface.h" |
78 | +#include "mir/scene/surface_creation_parameters.h" |
79 | + |
80 | +namespace me = mir::examples; |
81 | + |
82 | +me::BasicWindowManager::BasicWindowManager( |
83 | + shell::FocusController* focus_controller, |
84 | + std::unique_ptr<WindowManagementPolicy> policy) : |
85 | + focus_controller(focus_controller), |
86 | + policy(std::move(policy)) |
87 | +{ |
88 | +} |
89 | + |
90 | +void me::BasicWindowManager::add_session(std::shared_ptr<scene::Session> const& session) |
91 | +{ |
92 | + std::lock_guard<decltype(mutex)> lock(mutex); |
93 | + session_info[session] = SessionInfo(); |
94 | + policy->handle_session_info_updated(session_info, displays); |
95 | +} |
96 | + |
97 | +void me::BasicWindowManager::remove_session(std::shared_ptr<scene::Session> const& session) |
98 | +{ |
99 | + std::lock_guard<decltype(mutex)> lock(mutex); |
100 | + session_info.erase(session); |
101 | + policy->handle_session_info_updated(session_info, displays); |
102 | +} |
103 | + |
104 | +auto me::BasicWindowManager::add_surface( |
105 | + std::shared_ptr<scene::Session> const& session, |
106 | + scene::SurfaceCreationParameters const& params, |
107 | + std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) |
108 | +-> frontend::SurfaceId |
109 | +{ |
110 | + std::lock_guard<decltype(mutex)> lock(mutex); |
111 | + scene::SurfaceCreationParameters const placed_params = policy->handle_place_new_surface(session, params); |
112 | + auto const result = build(session, placed_params); |
113 | + auto const surface = session->surface(result); |
114 | + surface_info.emplace(surface, SurfaceInfo{session, surface, placed_params}); |
115 | + policy->handle_new_surface(session, surface); |
116 | + policy->generate_decorations_for(session, surface, surface_info, build); |
117 | + return result; |
118 | +} |
119 | + |
120 | +void me::BasicWindowManager::modify_surface( |
121 | + std::shared_ptr<scene::Session> const& session, |
122 | + std::shared_ptr<scene::Surface> const& surface, |
123 | + shell::SurfaceSpecification const& modifications) |
124 | +{ |
125 | + std::lock_guard<decltype(mutex)> lock(mutex); |
126 | + policy->handle_modify_surface(session, surface, modifications); |
127 | +} |
128 | + |
129 | +void me::BasicWindowManager::remove_surface( |
130 | + std::shared_ptr<scene::Session> const& session, |
131 | + std::weak_ptr<scene::Surface> const& surface) |
132 | +{ |
133 | + std::lock_guard<decltype(mutex)> lock(mutex); |
134 | + policy->handle_delete_surface(session, surface); |
135 | + |
136 | + surface_info.erase(surface); |
137 | +} |
138 | + |
139 | +void me::BasicWindowManager::forget(std::weak_ptr<scene::Surface> const& surface) |
140 | +{ |
141 | + surface_info.erase(surface); |
142 | +} |
143 | + |
144 | +void me::BasicWindowManager::add_display(geometry::Rectangle const& area) |
145 | +{ |
146 | + std::lock_guard<decltype(mutex)> lock(mutex); |
147 | + displays.add(area); |
148 | + policy->handle_displays_updated(session_info, displays); |
149 | +} |
150 | + |
151 | +void me::BasicWindowManager::remove_display(geometry::Rectangle const& area) |
152 | +{ |
153 | + std::lock_guard<decltype(mutex)> lock(mutex); |
154 | + displays.remove(area); |
155 | + policy->handle_displays_updated(session_info, displays); |
156 | +} |
157 | + |
158 | +bool me::BasicWindowManager::handle_keyboard_event(MirKeyboardEvent const* event) |
159 | +{ |
160 | + std::lock_guard<decltype(mutex)> lock(mutex); |
161 | + update_event_timestamp(event); |
162 | + return policy->handle_keyboard_event(event); |
163 | +} |
164 | + |
165 | +bool me::BasicWindowManager::handle_touch_event(MirTouchEvent const* event) |
166 | +{ |
167 | + std::lock_guard<decltype(mutex)> lock(mutex); |
168 | + update_event_timestamp(event); |
169 | + return policy->handle_touch_event(event); |
170 | +} |
171 | + |
172 | +bool me::BasicWindowManager::handle_pointer_event(MirPointerEvent const* event) |
173 | +{ |
174 | + std::lock_guard<decltype(mutex)> lock(mutex); |
175 | + update_event_timestamp(event); |
176 | + |
177 | + cursor = { |
178 | + mir_pointer_event_axis_value(event, mir_pointer_axis_x), |
179 | + mir_pointer_event_axis_value(event, mir_pointer_axis_y)}; |
180 | + |
181 | + return policy->handle_pointer_event(event); |
182 | +} |
183 | + |
184 | +void me::BasicWindowManager::handle_raise_surface( |
185 | + std::shared_ptr<scene::Session> const& session, |
186 | + std::shared_ptr<scene::Surface> const& surface, |
187 | + uint64_t timestamp) |
188 | +{ |
189 | + std::lock_guard<decltype(mutex)> lock(mutex); |
190 | + if (timestamp >= last_input_event_timestamp) |
191 | + policy->handle_raise_surface(session, surface); |
192 | +} |
193 | + |
194 | +int me::BasicWindowManager::set_surface_attribute( |
195 | + std::shared_ptr<scene::Session> const& /*session*/, |
196 | + std::shared_ptr<scene::Surface> const& surface, |
197 | + MirSurfaceAttrib attrib, |
198 | + int value) |
199 | +{ |
200 | + std::lock_guard<decltype(mutex)> lock(mutex); |
201 | + switch (attrib) |
202 | + { |
203 | + case mir_surface_attrib_state: |
204 | + { |
205 | + auto const state = policy->handle_set_state(surface, MirSurfaceState(value)); |
206 | + return surface->configure(attrib, state); |
207 | + } |
208 | + default: |
209 | + return surface->configure(attrib, value); |
210 | + } |
211 | +} |
212 | + |
213 | +auto me::BasicWindowManager::find_session(std::function<bool(SessionInfo const& info)> const& predicate) |
214 | +-> std::shared_ptr<scene::Session> |
215 | + { |
216 | + for(auto& info : session_info) |
217 | + { |
218 | + if (predicate(info.second)) |
219 | + { |
220 | + return info.first.lock(); |
221 | + } |
222 | + } |
223 | + |
224 | + return std::shared_ptr<scene::Session>{}; |
225 | + } |
226 | + |
227 | +auto me::BasicWindowManager::info_for(std::weak_ptr<scene::Session> const& session) const |
228 | +-> SessionInfo& |
229 | +{ |
230 | + return const_cast<SessionInfo&>(session_info.at(session)); |
231 | +} |
232 | + |
233 | +auto me::BasicWindowManager::info_for(std::weak_ptr<scene::Surface> const& surface) const |
234 | +-> SurfaceInfo& |
235 | +{ |
236 | + return const_cast<SurfaceInfo&>(surface_info.at(surface)); |
237 | +} |
238 | + |
239 | +auto me::BasicWindowManager::focused_session() const |
240 | +-> std::shared_ptr<scene::Session> |
241 | +{ |
242 | + return focus_controller->focused_session(); |
243 | +} |
244 | + |
245 | +auto me::BasicWindowManager::focused_surface() const |
246 | +->std::shared_ptr<scene::Surface> |
247 | +{ |
248 | + return focus_controller->focused_surface(); |
249 | +} |
250 | + |
251 | +void me::BasicWindowManager::focus_next_session() |
252 | +{ |
253 | + focus_controller->focus_next_session(); |
254 | +} |
255 | + |
256 | +void me::BasicWindowManager::set_focus_to( |
257 | + std::shared_ptr<scene::Session> const& focus, |
258 | + std::shared_ptr<scene::Surface> const& surface) |
259 | +{ |
260 | + focus_controller->set_focus_to(focus, surface); |
261 | +} |
262 | + |
263 | +auto me::BasicWindowManager::surface_at(geometry::Point cursor) const |
264 | +-> std::shared_ptr<scene::Surface> |
265 | +{ |
266 | + return focus_controller->surface_at(cursor); |
267 | +} |
268 | + |
269 | +auto me::BasicWindowManager::active_display() |
270 | +-> geometry::Rectangle const |
271 | +{ |
272 | + geometry::Rectangle result; |
273 | + |
274 | + // 1. If a window has input focus, whichever display contains the largest |
275 | + // proportion of the area of that window. |
276 | + if (auto const surface = focused_surface()) |
277 | + { |
278 | + auto const surface_rect = surface->input_bounds(); |
279 | + int max_overlap_area = -1; |
280 | + |
281 | + for (auto const& display : displays) |
282 | + { |
283 | + auto const intersection = surface_rect.intersection_with(display).size; |
284 | + if (intersection.width.as_int()*intersection.height.as_int() > max_overlap_area) |
285 | + { |
286 | + max_overlap_area = intersection.width.as_int()*intersection.height.as_int(); |
287 | + result = display; |
288 | + } |
289 | + } |
290 | + return result; |
291 | + } |
292 | + |
293 | + // 2. Otherwise, if any window previously had input focus, for the window that had |
294 | + // it most recently, the display that contained the largest proportion of the |
295 | + // area of that window at the moment it closed, as long as that display is still |
296 | + // available. |
297 | + |
298 | + // 3. Otherwise, the display that contains the pointer, if there is one. |
299 | + for (auto const& display : displays) |
300 | + { |
301 | + if (display.contains(cursor)) |
302 | + { |
303 | + // Ignore the (unspecified) possiblity of overlapping displays |
304 | + return display; |
305 | + } |
306 | + } |
307 | + |
308 | + // 4. Otherwise, the primary display, if there is one (for example, the laptop display). |
309 | + |
310 | + // 5. Otherwise, the first display. |
311 | + if (displays.size()) |
312 | + result = *displays.begin(); |
313 | + |
314 | + return result; |
315 | +} |
316 | + |
317 | +void me::BasicWindowManager::raise_tree(std::shared_ptr<scene::Surface> const& root) |
318 | +{ |
319 | + SurfaceSet surfaces; |
320 | + std::function<void(std::weak_ptr<scene::Surface> const& surface)> const add_children = |
321 | + [&,this](std::weak_ptr<scene::Surface> const& surface) |
322 | + { |
323 | + auto const& info = info_for(surface); |
324 | + surfaces.insert(begin(info.children), end(info.children)); |
325 | + for (auto const& child : info.children) |
326 | + add_children(child); |
327 | + }; |
328 | + |
329 | + surfaces.insert(root); |
330 | + add_children(root); |
331 | + |
332 | + focus_controller->raise(surfaces); |
333 | +} |
334 | + |
335 | +void me::BasicWindowManager::update_event_timestamp(MirKeyboardEvent const* kev) |
336 | +{ |
337 | + auto iev = mir_keyboard_event_input_event(kev); |
338 | + last_input_event_timestamp = mir_input_event_get_event_time(iev); |
339 | +} |
340 | + |
341 | +void me::BasicWindowManager::update_event_timestamp(MirPointerEvent const* pev) |
342 | +{ |
343 | + auto iev = mir_pointer_event_input_event(pev); |
344 | + auto pointer_action = mir_pointer_event_action(pev); |
345 | + |
346 | + if (pointer_action == mir_pointer_action_button_up || |
347 | + pointer_action == mir_pointer_action_button_down) |
348 | + { |
349 | + last_input_event_timestamp = mir_input_event_get_event_time(iev); |
350 | + } |
351 | +} |
352 | + |
353 | +void me::BasicWindowManager::update_event_timestamp(MirTouchEvent const* tev) |
354 | +{ |
355 | + auto iev = mir_touch_event_input_event(tev); |
356 | + auto touch_count = mir_touch_event_point_count(tev); |
357 | + for (unsigned i = 0; i < touch_count; i++) |
358 | + { |
359 | + auto touch_action = mir_touch_event_action(tev, i); |
360 | + if (touch_action == mir_touch_action_up || |
361 | + touch_action == mir_touch_action_down) |
362 | + { |
363 | + last_input_event_timestamp = mir_input_event_get_event_time(iev); |
364 | + break; |
365 | + } |
366 | + } |
367 | +} |
368 | |
369 | === added file 'src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h' |
370 | --- src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h 1970-01-01 00:00:00 +0000 |
371 | +++ src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h 2016-01-20 19:52:54 +0000 |
372 | @@ -0,0 +1,252 @@ |
373 | +/* |
374 | + * Copyright © 2015 Canonical Ltd. |
375 | + * |
376 | + * This program is free software: you can redistribute it and/or modify it |
377 | + * under the terms of the GNU General Public License version 3, |
378 | + * as published by the Free Software Foundation. |
379 | + * |
380 | + * This program is distributed in the hope that it will be useful, |
381 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
382 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
383 | + * GNU General Public License for more details. |
384 | + * |
385 | + * You should have received a copy of the GNU General Public License |
386 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
387 | + * |
388 | + * Authored By: Alan Griffiths <alan@octopull.co.uk> |
389 | + */ |
390 | + |
391 | +#ifndef MIR_EXAMPLE_BASIC_WINDOW_MANAGER_H_ |
392 | +#define MIR_EXAMPLE_BASIC_WINDOW_MANAGER_H_ |
393 | + |
394 | +#include "server_example_window_management_info.h" |
395 | + |
396 | +#include "mir/geometry/rectangles.h" |
397 | +#include "mir/shell/abstract_shell.h" |
398 | +#include "mir/shell/window_manager.h" |
399 | + |
400 | +#include <map> |
401 | +#include <mutex> |
402 | + |
403 | +///\example server_example_basic_window_manager.h |
404 | +/// A generic policy-based window manager implementation |
405 | + |
406 | +namespace mir |
407 | +{ |
408 | +namespace examples |
409 | +{ |
410 | +using shell::SurfaceSet; |
411 | + |
412 | +/// The interface through which the policy instructs the controller. |
413 | +/// These functions assume that the BasicWindowManager data structures can be accessed freely. |
414 | +/// I.e. should only be invoked by the policy handle_... methods (where any necessary locks are held). |
415 | +class WindowManagerTools |
416 | +{ |
417 | +public: |
418 | + using SurfaceInfoMap = std::map<std::weak_ptr<scene::Surface>, SurfaceInfo, std::owner_less<std::weak_ptr<scene::Surface>>>; |
419 | + using SessionInfoMap = std::map<std::weak_ptr<scene::Session>, SessionInfo, std::owner_less<std::weak_ptr<scene::Session>>>; |
420 | + |
421 | + virtual auto find_session(std::function<bool(SessionInfo const& info)> const& predicate) |
422 | + -> std::shared_ptr<scene::Session> = 0; |
423 | + |
424 | + virtual auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& = 0; |
425 | + |
426 | + virtual auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& = 0; |
427 | + |
428 | + virtual std::shared_ptr<scene::Session> focused_session() const = 0; |
429 | + |
430 | + virtual std::shared_ptr<scene::Surface> focused_surface() const = 0; |
431 | + |
432 | + virtual void focus_next_session() = 0; |
433 | + |
434 | + virtual void set_focus_to( |
435 | + std::shared_ptr<scene::Session> const& focus, |
436 | + std::shared_ptr<scene::Surface> const& surface) = 0; |
437 | + |
438 | + virtual auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> = 0; |
439 | + |
440 | + virtual auto active_display() -> geometry::Rectangle const = 0; |
441 | + |
442 | + virtual void forget(std::weak_ptr<scene::Surface> const& surface) = 0; |
443 | + |
444 | + virtual void raise_tree(std::shared_ptr<scene::Surface> const& root) = 0; |
445 | + |
446 | + virtual ~WindowManagerTools() = default; |
447 | + WindowManagerTools() = default; |
448 | + WindowManagerTools(WindowManagerTools const&) = delete; |
449 | + WindowManagerTools& operator=(WindowManagerTools const&) = delete; |
450 | +}; |
451 | + |
452 | +class WindowManagementPolicy |
453 | +{ |
454 | +public: |
455 | + using SessionInfoMap = typename WindowManagerTools::SessionInfoMap; |
456 | + using SurfaceInfoMap = typename WindowManagerTools::SurfaceInfoMap; |
457 | + |
458 | + virtual void handle_session_info_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays) = 0; |
459 | + |
460 | + virtual void handle_displays_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays) = 0; |
461 | + |
462 | + virtual auto handle_place_new_surface( |
463 | + std::shared_ptr<scene::Session> const& session, |
464 | + scene::SurfaceCreationParameters const& request_parameters) |
465 | + -> scene::SurfaceCreationParameters = 0; |
466 | + |
467 | + virtual void handle_new_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface) = 0; |
468 | + |
469 | + virtual void handle_modify_surface( |
470 | + std::shared_ptr<scene::Session> const& session, |
471 | + std::shared_ptr<scene::Surface> const& surface, |
472 | + shell::SurfaceSpecification const& modifications) = 0; |
473 | + |
474 | + virtual void handle_delete_surface(std::shared_ptr<scene::Session> const& session, std::weak_ptr<scene::Surface> const& surface) = 0; |
475 | + |
476 | + virtual int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value) = 0; |
477 | + |
478 | + virtual void generate_decorations_for( |
479 | + std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface, |
480 | + SurfaceInfoMap& surface_info, |
481 | + std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const&, scene::SurfaceCreationParameters const&)> const& build) = 0; |
482 | + |
483 | + virtual bool handle_keyboard_event(MirKeyboardEvent const* event) = 0; |
484 | + |
485 | + virtual bool handle_touch_event(MirTouchEvent const* event) = 0; |
486 | + |
487 | + virtual bool handle_pointer_event(MirPointerEvent const* event) = 0; |
488 | + |
489 | + virtual void handle_raise_surface( |
490 | + std::shared_ptr<scene::Session> const& session, |
491 | + std::shared_ptr<scene::Surface> const& surface) = 0; |
492 | + |
493 | + virtual ~WindowManagementPolicy() = default; |
494 | + WindowManagementPolicy() = default; |
495 | + WindowManagementPolicy(WindowManagementPolicy const&) = delete; |
496 | + WindowManagementPolicy& operator=(WindowManagementPolicy const&) = delete; |
497 | +}; |
498 | + |
499 | +/// A policy based window manager. |
500 | +/// This takes care of the management of any meta implementation held for the sessions and surfaces. |
501 | +class BasicWindowManager : public virtual shell::WindowManager, |
502 | + protected WindowManagerTools |
503 | +{ |
504 | +protected: |
505 | + BasicWindowManager( |
506 | + shell::FocusController* focus_controller, |
507 | + std::unique_ptr<WindowManagementPolicy> policy); |
508 | + |
509 | +public: |
510 | + using typename WindowManagerTools::SurfaceInfoMap; |
511 | + using typename WindowManagerTools::SessionInfoMap; |
512 | + |
513 | + void add_session(std::shared_ptr<scene::Session> const& session) override; |
514 | + |
515 | + void remove_session(std::shared_ptr<scene::Session> const& session) override; |
516 | + |
517 | + auto add_surface( |
518 | + std::shared_ptr<scene::Session> const& session, |
519 | + scene::SurfaceCreationParameters const& params, |
520 | + std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) |
521 | + -> frontend::SurfaceId override; |
522 | + |
523 | + void modify_surface( |
524 | + std::shared_ptr<scene::Session> const& session, |
525 | + std::shared_ptr<scene::Surface> const& surface, |
526 | + shell::SurfaceSpecification const& modifications) override; |
527 | + |
528 | + void remove_surface( |
529 | + std::shared_ptr<scene::Session> const& session, |
530 | + std::weak_ptr<scene::Surface> const& surface) override; |
531 | + |
532 | + void forget(std::weak_ptr<scene::Surface> const& surface) override; |
533 | + |
534 | + void add_display(geometry::Rectangle const& area) override; |
535 | + |
536 | + void remove_display(geometry::Rectangle const& area) override; |
537 | + |
538 | + bool handle_keyboard_event(MirKeyboardEvent const* event) override; |
539 | + |
540 | + bool handle_touch_event(MirTouchEvent const* event) override; |
541 | + |
542 | + bool handle_pointer_event(MirPointerEvent const* event) override; |
543 | + |
544 | + void handle_raise_surface( |
545 | + std::shared_ptr<scene::Session> const& session, |
546 | + std::shared_ptr<scene::Surface> const& surface, |
547 | + uint64_t timestamp) override; |
548 | + |
549 | + int set_surface_attribute( |
550 | + std::shared_ptr<scene::Session> const& /*session*/, |
551 | + std::shared_ptr<scene::Surface> const& surface, |
552 | + MirSurfaceAttrib attrib, |
553 | + int value) override; |
554 | + |
555 | + auto find_session(std::function<bool(SessionInfo const& info)> const& predicate) |
556 | + -> std::shared_ptr<scene::Session> override; |
557 | + |
558 | + auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& override; |
559 | + |
560 | + auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& override; |
561 | + |
562 | + std::shared_ptr<scene::Session> focused_session() const override; |
563 | + |
564 | + std::shared_ptr<scene::Surface> focused_surface() const override; |
565 | + |
566 | + void focus_next_session() override; |
567 | + |
568 | + void set_focus_to( |
569 | + std::shared_ptr<scene::Session> const& focus, |
570 | + std::shared_ptr<scene::Surface> const& surface) override; |
571 | + |
572 | + auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> override; |
573 | + |
574 | + auto active_display() -> geometry::Rectangle const override; |
575 | + |
576 | + void raise_tree(std::shared_ptr<scene::Surface> const& root) override; |
577 | + |
578 | +private: |
579 | + shell::FocusController* const focus_controller; |
580 | + std::unique_ptr<WindowManagementPolicy> const policy; |
581 | + |
582 | + std::mutex mutex; |
583 | + SessionInfoMap session_info; |
584 | + SurfaceInfoMap surface_info; |
585 | + geometry::Rectangles displays; |
586 | + geometry::Point cursor; |
587 | + uint64_t last_input_event_timestamp{0}; |
588 | + |
589 | + void update_event_timestamp(MirKeyboardEvent const* kev); |
590 | + void update_event_timestamp(MirPointerEvent const* pev); |
591 | + void update_event_timestamp(MirTouchEvent const* tev); |
592 | +}; |
593 | + |
594 | +/// A policy based window manager. This exists to initialize BasicWindowManager and |
595 | +/// the WMPolicy (in an awkward manner). |
596 | +/// TODO revisit this initialization sequence. |
597 | +template<typename WMPolicy> |
598 | +class WindowManagerBuilder : public BasicWindowManager |
599 | +{ |
600 | +public: |
601 | + |
602 | + template <typename... PolicyArgs> |
603 | + WindowManagerBuilder( |
604 | + shell::FocusController* focus_controller, |
605 | + PolicyArgs&&... policy_args) : |
606 | + BasicWindowManager( |
607 | + focus_controller, |
608 | + build_policy(std::forward<PolicyArgs>(policy_args)...)) |
609 | + { |
610 | + } |
611 | + |
612 | +private: |
613 | + template <typename... PolicyArgs> |
614 | + auto build_policy(PolicyArgs&&... policy_args) |
615 | + -> std::unique_ptr<WMPolicy> |
616 | + { |
617 | + return std::unique_ptr<WMPolicy>( |
618 | + new WMPolicy(this, std::forward<PolicyArgs>(policy_args)...)); |
619 | + } |
620 | +}; |
621 | +} |
622 | +} |
623 | + |
624 | +#endif /* MIR_EXAMPLE_BASIC_WINDOW_MANAGER_H_ */ |
625 | |
626 | === added file 'src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp' |
627 | --- src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp 1970-01-01 00:00:00 +0000 |
628 | +++ src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp 2016-01-20 19:52:54 +0000 |
629 | @@ -0,0 +1,946 @@ |
630 | +/* |
631 | + * Copyright © 2015 Canonical Ltd. |
632 | + * |
633 | + * This program is free software: you can redistribute it and/or modify it |
634 | + * under the terms of the GNU General Public License version 3, |
635 | + * as published by the Free Software Foundation. |
636 | + * |
637 | + * This program is distributed in the hope that it will be useful, |
638 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
639 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
640 | + * GNU General Public License for more details. |
641 | + * |
642 | + * You should have received a copy of the GNU General Public License |
643 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
644 | + * |
645 | + * Authored By: Alan Griffiths <alan@octopull.co.uk> |
646 | + */ |
647 | + |
648 | +#include "server_example_canonical_window_manager.h" |
649 | + |
650 | +#include "mir/scene/session.h" |
651 | +#include "mir/scene/surface.h" |
652 | +#include "mir/scene/surface_creation_parameters.h" |
653 | +#include "mir/shell/surface_ready_observer.h" |
654 | +#include "mir/shell/display_layout.h" |
655 | + |
656 | +#include <linux/input.h> |
657 | +#include <csignal> |
658 | +#include <algorithm> |
659 | + |
660 | +namespace me = mir::examples; |
661 | +namespace ms = mir::scene; |
662 | +using namespace mir::geometry; |
663 | + |
664 | +///\example server_example_canonical_window_manager.cpp |
665 | +// Based on "Mir and Unity: Surfaces, input, and displays (v0.3)" |
666 | + |
667 | +namespace |
668 | +{ |
669 | +int const title_bar_height = 10; |
670 | +Size titlebar_size_for_window(Size window_size) |
671 | +{ |
672 | + return {window_size.width, Height{title_bar_height}}; |
673 | +} |
674 | + |
675 | +Point titlebar_position_for_window(Point window_position) |
676 | +{ |
677 | + return { |
678 | + window_position.x, |
679 | + window_position.y - DeltaY(title_bar_height) |
680 | + }; |
681 | +} |
682 | +} |
683 | + |
684 | +me::CanonicalWindowManagerPolicyCopy::CanonicalWindowManagerPolicyCopy( |
685 | + WindowManagerTools* const tools, |
686 | + std::shared_ptr<shell::DisplayLayout> const& display_layout) : |
687 | + tools{tools}, |
688 | + display_layout{display_layout} |
689 | +{ |
690 | +} |
691 | + |
692 | +void me::CanonicalWindowManagerPolicyCopy::click(Point cursor) |
693 | +{ |
694 | + if (auto const surface = tools->surface_at(cursor)) |
695 | + select_active_surface(surface); |
696 | +} |
697 | + |
698 | +void me::CanonicalWindowManagerPolicyCopy::handle_session_info_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/) |
699 | +{ |
700 | +} |
701 | + |
702 | +void me::CanonicalWindowManagerPolicyCopy::handle_displays_updated(SessionInfoMap& /*session_info*/, Rectangles const& displays) |
703 | +{ |
704 | + display_area = displays.bounding_rectangle(); |
705 | + |
706 | + for (auto const weak_surface : fullscreen_surfaces) |
707 | + { |
708 | + if (auto const surface = weak_surface.lock()) |
709 | + { |
710 | + auto const& info = tools->info_for(weak_surface); |
711 | + Rectangle rect{surface->top_left(), surface->size()}; |
712 | + |
713 | + display_layout->place_in_output(info.output_id.value(), rect); |
714 | + surface->move_to(rect.top_left); |
715 | + surface->resize(rect.size); |
716 | + } |
717 | + } |
718 | +} |
719 | + |
720 | +void me::CanonicalWindowManagerPolicyCopy::resize(Point cursor) |
721 | +{ |
722 | + select_active_surface(tools->surface_at(old_cursor)); |
723 | + resize(active_surface(), cursor, old_cursor, display_area); |
724 | +} |
725 | + |
726 | +auto me::CanonicalWindowManagerPolicyCopy::handle_place_new_surface( |
727 | + std::shared_ptr<ms::Session> const& session, |
728 | + ms::SurfaceCreationParameters const& request_parameters) |
729 | +-> ms::SurfaceCreationParameters |
730 | +{ |
731 | + auto parameters = request_parameters; |
732 | + auto surf_type = parameters.type.is_set() ? parameters.type.value() : mir_surface_type_normal; |
733 | + bool const needs_titlebar = SurfaceInfo::needs_titlebar(surf_type); |
734 | + |
735 | + if (needs_titlebar) |
736 | + parameters.size.height = parameters.size.height + DeltaY{title_bar_height}; |
737 | + |
738 | + if (!parameters.state.is_set()) |
739 | + parameters.state = mir_surface_state_restored; |
740 | + |
741 | + auto const active_display = tools->active_display(); |
742 | + |
743 | + auto const width = parameters.size.width.as_int(); |
744 | + auto const height = parameters.size.height.as_int(); |
745 | + |
746 | + bool positioned = false; |
747 | + |
748 | + auto const parent = parameters.parent.lock(); |
749 | + |
750 | + if (parameters.output_id != mir::graphics::DisplayConfigurationOutputId{0}) |
751 | + { |
752 | + Rectangle rect{parameters.top_left, parameters.size}; |
753 | + display_layout->place_in_output(parameters.output_id, rect); |
754 | + parameters.top_left = rect.top_left; |
755 | + parameters.size = rect.size; |
756 | + parameters.state = mir_surface_state_fullscreen; |
757 | + positioned = true; |
758 | + } |
759 | + else if (!parent) // No parent => client can't suggest positioning |
760 | + { |
761 | + if (auto const default_surface = session->default_surface()) |
762 | + { |
763 | + static Displacement const offset{title_bar_height, title_bar_height}; |
764 | + |
765 | + parameters.top_left = default_surface->top_left() + offset; |
766 | + |
767 | + geometry::Rectangle display_for_app{default_surface->top_left(), default_surface->size()}; |
768 | + |
769 | + display_layout->size_to_output(display_for_app); |
770 | + |
771 | + positioned = display_for_app.overlaps(Rectangle{parameters.top_left, parameters.size}); |
772 | + } |
773 | + } |
774 | + |
775 | + if (parent && parameters.aux_rect.is_set() && parameters.edge_attachment.is_set()) |
776 | + { |
777 | + auto const edge_attachment = parameters.edge_attachment.value(); |
778 | + auto const aux_rect = parameters.aux_rect.value(); |
779 | + auto const parent_top_left = parent->top_left(); |
780 | + auto const top_left = aux_rect.top_left -Point{} + parent_top_left; |
781 | + auto const top_right= aux_rect.top_right() -Point{} + parent_top_left; |
782 | + auto const bot_left = aux_rect.bottom_left()-Point{} + parent_top_left; |
783 | + |
784 | + if (edge_attachment & mir_edge_attachment_vertical) |
785 | + { |
786 | + if (active_display.contains(top_right + Displacement{width, height})) |
787 | + { |
788 | + parameters.top_left = top_right; |
789 | + positioned = true; |
790 | + } |
791 | + else if (active_display.contains(top_left + Displacement{-width, height})) |
792 | + { |
793 | + parameters.top_left = top_left + Displacement{-width, 0}; |
794 | + positioned = true; |
795 | + } |
796 | + } |
797 | + |
798 | + if (edge_attachment & mir_edge_attachment_horizontal) |
799 | + { |
800 | + if (active_display.contains(bot_left + Displacement{width, height})) |
801 | + { |
802 | + parameters.top_left = bot_left; |
803 | + positioned = true; |
804 | + } |
805 | + else if (active_display.contains(top_left + Displacement{width, -height})) |
806 | + { |
807 | + parameters.top_left = top_left + Displacement{0, -height}; |
808 | + positioned = true; |
809 | + } |
810 | + } |
811 | + } |
812 | + else if (parent) |
813 | + { |
814 | + // o Otherwise, if the dialog is not the same as any previous dialog for the |
815 | + // same parent window, and/or it does not have user-customized position: |
816 | + // o It should be optically centered relative to its parent, unless this |
817 | + // would overlap or cover the title bar of the parent. |
818 | + // o Otherwise, it should be cascaded vertically (but not horizontally) |
819 | + // relative to its parent, unless, this would cause at least part of |
820 | + // it to extend into shell space. |
821 | + auto const parent_top_left = parent->top_left(); |
822 | + auto const centred = parent_top_left |
823 | + + 0.5*(as_displacement(parent->size()) - as_displacement(parameters.size)) |
824 | + - DeltaY{(parent->size().height.as_int()-height)/6}; |
825 | + |
826 | + parameters.top_left = centred; |
827 | + positioned = true; |
828 | + } |
829 | + |
830 | + if (!positioned) |
831 | + { |
832 | + auto const centred = active_display.top_left |
833 | + + 0.5*(as_displacement(active_display.size) - as_displacement(parameters.size)) |
834 | + - DeltaY{(active_display.size.height.as_int()-height)/6}; |
835 | + |
836 | + switch (parameters.state.value()) |
837 | + { |
838 | + case mir_surface_state_fullscreen: |
839 | + case mir_surface_state_maximized: |
840 | + parameters.top_left = active_display.top_left; |
841 | + parameters.size = active_display.size; |
842 | + break; |
843 | + |
844 | + case mir_surface_state_vertmaximized: |
845 | + parameters.top_left = centred; |
846 | + parameters.top_left.y = active_display.top_left.y; |
847 | + parameters.size.height = active_display.size.height; |
848 | + break; |
849 | + |
850 | + case mir_surface_state_horizmaximized: |
851 | + parameters.top_left = centred; |
852 | + parameters.top_left.x = active_display.top_left.x; |
853 | + parameters.size.width = active_display.size.width; |
854 | + break; |
855 | + |
856 | + default: |
857 | + parameters.top_left = centred; |
858 | + } |
859 | + |
860 | + if (parameters.top_left.y < display_area.top_left.y) |
861 | + parameters.top_left.y = display_area.top_left.y; |
862 | + } |
863 | + |
864 | + if (parameters.state != mir_surface_state_fullscreen && needs_titlebar) |
865 | + { |
866 | + parameters.top_left.y = parameters.top_left.y + DeltaY{title_bar_height}; |
867 | + parameters.size.height = parameters.size.height - DeltaY{title_bar_height}; |
868 | + } |
869 | + |
870 | + return parameters; |
871 | +} |
872 | + |
873 | +void me::CanonicalWindowManagerPolicyCopy::generate_decorations_for( |
874 | + std::shared_ptr<scene::Session> const& session, |
875 | + std::shared_ptr<scene::Surface> const& surface, |
876 | + SurfaceInfoMap& surface_map, |
877 | + std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) |
878 | +{ |
879 | + if (!SurfaceInfo::needs_titlebar(surface->type())) |
880 | + return; |
881 | + |
882 | + auto format = mir_pixel_format_xrgb_8888; |
883 | + ms::SurfaceCreationParameters params; |
884 | + params.of_size(titlebar_size_for_window(surface->size())) |
885 | + .of_name("decoration") |
886 | + .of_pixel_format(format) |
887 | + .of_buffer_usage(mir::graphics::BufferUsage::software) |
888 | + .of_position(titlebar_position_for_window(surface->top_left())) |
889 | + .of_type(mir_surface_type_gloss); |
890 | + auto id = build(session, params); |
891 | + auto titlebar = session->surface(id); |
892 | + titlebar->set_alpha(0.9); |
893 | + |
894 | + auto& surface_info = tools->info_for(surface); |
895 | + surface_info.titlebar = titlebar; |
896 | + surface_info.titlebar_id = id; |
897 | + surface_info.children.push_back(titlebar); |
898 | + |
899 | + SurfaceInfo& titlebar_info = |
900 | + surface_map.emplace(titlebar, SurfaceInfo{session, titlebar, {}}).first->second; |
901 | + titlebar_info.is_titlebar = true; |
902 | + titlebar_info.parent = surface; |
903 | + titlebar_info.init_titlebar(titlebar); |
904 | +} |
905 | + |
906 | +void me::CanonicalWindowManagerPolicyCopy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface) |
907 | +{ |
908 | + auto& surface_info = tools->info_for(surface); |
909 | + if (auto const parent = surface_info.parent.lock()) |
910 | + { |
911 | + tools->info_for(parent).children.push_back(surface); |
912 | + } |
913 | + |
914 | + tools->info_for(session).surfaces.push_back(surface); |
915 | + |
916 | + if (surface_info.can_be_active()) |
917 | + { |
918 | + surface->add_observer(std::make_shared<shell::SurfaceReadyObserver>( |
919 | + [this](std::shared_ptr<scene::Session> const& /*session*/, |
920 | + std::shared_ptr<scene::Surface> const& surface) |
921 | + { |
922 | + select_active_surface(surface); |
923 | + }, |
924 | + session, |
925 | + surface)); |
926 | + } |
927 | + |
928 | + if (surface_info.state == mir_surface_state_fullscreen) |
929 | + fullscreen_surfaces.insert(surface); |
930 | +} |
931 | + |
932 | +void me::CanonicalWindowManagerPolicyCopy::handle_modify_surface( |
933 | + std::shared_ptr<scene::Session> const& session, |
934 | + std::shared_ptr<scene::Surface> const& surface, |
935 | + shell::SurfaceSpecification const& modifications) |
936 | +{ |
937 | + auto& surface_info_old = tools->info_for(surface); |
938 | + |
939 | + auto surface_info = surface_info_old; |
940 | + |
941 | + if (modifications.parent.is_set()) |
942 | + surface_info.parent = modifications.parent.value(); |
943 | + |
944 | + if (modifications.type.is_set() && |
945 | + surface_info.type != modifications.type.value()) |
946 | + { |
947 | + auto const new_type = modifications.type.value(); |
948 | + |
949 | + if (!surface_info.can_morph_to(new_type)) |
950 | + { |
951 | + throw std::runtime_error("Unsupported surface type change"); |
952 | + } |
953 | + |
954 | + surface_info.type = new_type; |
955 | + |
956 | + if (surface_info.must_not_have_parent()) |
957 | + { |
958 | + if (modifications.parent.is_set()) |
959 | + throw std::runtime_error("Target surface type does not support parent"); |
960 | + |
961 | + surface_info.parent.reset(); |
962 | + } |
963 | + else if (surface_info.must_have_parent()) |
964 | + { |
965 | + if (!surface_info.parent.lock()) |
966 | + throw std::runtime_error("Target surface type requires parent"); |
967 | + } |
968 | + |
969 | + surface->configure(mir_surface_attrib_type, new_type); |
970 | + } |
971 | + |
972 | + #define COPY_IF_SET(field)\ |
973 | + if (modifications.field.is_set())\ |
974 | + surface_info.field = modifications.field.value() |
975 | + |
976 | + COPY_IF_SET(min_width); |
977 | + COPY_IF_SET(min_height); |
978 | + COPY_IF_SET(max_width); |
979 | + COPY_IF_SET(max_height); |
980 | + COPY_IF_SET(min_width); |
981 | + COPY_IF_SET(width_inc); |
982 | + COPY_IF_SET(height_inc); |
983 | + COPY_IF_SET(min_aspect); |
984 | + COPY_IF_SET(max_aspect); |
985 | + COPY_IF_SET(output_id); |
986 | + |
987 | + #undef COPY_IF_SET |
988 | + |
989 | + std::swap(surface_info, surface_info_old); |
990 | + |
991 | + if (modifications.name.is_set()) |
992 | + surface->rename(modifications.name.value()); |
993 | + |
994 | + if (modifications.streams.is_set()) |
995 | + { |
996 | + auto v = modifications.streams.value(); |
997 | + std::vector<shell::StreamSpecification> l (v.begin(), v.end()); |
998 | + session->configure_streams(*surface, l); |
999 | + } |
1000 | + |
1001 | + if (modifications.input_shape.is_set()) |
1002 | + { |
1003 | + surface->set_input_region(modifications.input_shape.value()); |
1004 | + } |
1005 | + |
1006 | + if (modifications.width.is_set() || modifications.height.is_set()) |
1007 | + { |
1008 | + auto new_size = surface->size(); |
1009 | + |
1010 | + if (modifications.width.is_set()) |
1011 | + new_size.width = modifications.width.value(); |
1012 | + |
1013 | + if (modifications.height.is_set()) |
1014 | + new_size.height = modifications.height.value(); |
1015 | + |
1016 | + auto top_left = surface->top_left(); |
1017 | + |
1018 | + surface_info.constrain_resize( |
1019 | + surface, |
1020 | + top_left, |
1021 | + new_size, |
1022 | + false, |
1023 | + false, |
1024 | + display_area); |
1025 | + |
1026 | + apply_resize(surface, surface_info.titlebar, top_left, new_size); |
1027 | + } |
1028 | + |
1029 | + if (modifications.state.is_set()) |
1030 | + { |
1031 | + auto const state = handle_set_state(surface, modifications.state.value()); |
1032 | + surface->configure(mir_surface_attrib_state, state); |
1033 | + } |
1034 | +} |
1035 | + |
1036 | +void me::CanonicalWindowManagerPolicyCopy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface) |
1037 | +{ |
1038 | + fullscreen_surfaces.erase(surface); |
1039 | + |
1040 | + auto& info = tools->info_for(surface); |
1041 | + |
1042 | + if (auto const parent = info.parent.lock()) |
1043 | + { |
1044 | + auto& siblings = tools->info_for(parent).children; |
1045 | + |
1046 | + for (auto i = begin(siblings); i != end(siblings); ++i) |
1047 | + { |
1048 | + if (surface.lock() == i->lock()) |
1049 | + { |
1050 | + siblings.erase(i); |
1051 | + break; |
1052 | + } |
1053 | + } |
1054 | + } |
1055 | + |
1056 | + session->destroy_surface(surface); |
1057 | + if (info.titlebar) |
1058 | + { |
1059 | + session->destroy_surface(info.titlebar_id); |
1060 | + tools->forget(info.titlebar); |
1061 | + } |
1062 | + |
1063 | + auto& surfaces = tools->info_for(session).surfaces; |
1064 | + |
1065 | + for (auto i = begin(surfaces); i != end(surfaces); ++i) |
1066 | + { |
1067 | + if (surface.lock() == i->lock()) |
1068 | + { |
1069 | + surfaces.erase(i); |
1070 | + break; |
1071 | + } |
1072 | + } |
1073 | + |
1074 | + if (surfaces.empty() && session == tools->focused_session()) |
1075 | + { |
1076 | + active_surface_.reset(); |
1077 | + tools->focus_next_session(); |
1078 | + select_active_surface(tools->focused_surface()); |
1079 | + } |
1080 | +} |
1081 | + |
1082 | +int me::CanonicalWindowManagerPolicyCopy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value) |
1083 | +{ |
1084 | + auto& info = tools->info_for(surface); |
1085 | + |
1086 | + switch (value) |
1087 | + { |
1088 | + case mir_surface_state_restored: |
1089 | + case mir_surface_state_maximized: |
1090 | + case mir_surface_state_vertmaximized: |
1091 | + case mir_surface_state_horizmaximized: |
1092 | + case mir_surface_state_fullscreen: |
1093 | + case mir_surface_state_hidden: |
1094 | + case mir_surface_state_minimized: |
1095 | + break; |
1096 | + |
1097 | + default: |
1098 | + return info.state; |
1099 | + } |
1100 | + |
1101 | + if (info.state == mir_surface_state_restored) |
1102 | + { |
1103 | + info.restore_rect = {surface->top_left(), surface->size()}; |
1104 | + } |
1105 | + |
1106 | + if (info.state != mir_surface_state_fullscreen) |
1107 | + { |
1108 | + info.output_id = decltype(info.output_id){}; |
1109 | + fullscreen_surfaces.erase(surface); |
1110 | + } |
1111 | + else |
1112 | + { |
1113 | + fullscreen_surfaces.insert(surface); |
1114 | + } |
1115 | + |
1116 | + if (info.state == value) |
1117 | + { |
1118 | + return info.state; |
1119 | + } |
1120 | + |
1121 | + auto const old_pos = surface->top_left(); |
1122 | + Displacement movement; |
1123 | + |
1124 | + switch (value) |
1125 | + { |
1126 | + case mir_surface_state_restored: |
1127 | + movement = info.restore_rect.top_left - old_pos; |
1128 | + surface->resize(info.restore_rect.size); |
1129 | + if (info.titlebar) |
1130 | + { |
1131 | + info.titlebar->resize(titlebar_size_for_window(info.restore_rect.size)); |
1132 | + info.titlebar->show(); |
1133 | + } |
1134 | + break; |
1135 | + |
1136 | + case mir_surface_state_maximized: |
1137 | + movement = display_area.top_left - old_pos; |
1138 | + surface->resize(display_area.size); |
1139 | + if (info.titlebar) |
1140 | + info.titlebar->hide(); |
1141 | + break; |
1142 | + |
1143 | + case mir_surface_state_horizmaximized: |
1144 | + movement = Point{display_area.top_left.x, info.restore_rect.top_left.y} - old_pos; |
1145 | + surface->resize({display_area.size.width, info.restore_rect.size.height}); |
1146 | + if (info.titlebar) |
1147 | + { |
1148 | + info.titlebar->resize(titlebar_size_for_window({display_area.size.width, info.restore_rect.size.height})); |
1149 | + info.titlebar->show(); |
1150 | + } |
1151 | + break; |
1152 | + |
1153 | + case mir_surface_state_vertmaximized: |
1154 | + movement = Point{info.restore_rect.top_left.x, display_area.top_left.y} - old_pos; |
1155 | + surface->resize({info.restore_rect.size.width, display_area.size.height}); |
1156 | + if (info.titlebar) |
1157 | + info.titlebar->hide(); |
1158 | + break; |
1159 | + |
1160 | + case mir_surface_state_fullscreen: |
1161 | + { |
1162 | + Rectangle rect{old_pos, surface->size()}; |
1163 | + |
1164 | + if (info.output_id.is_set()) |
1165 | + { |
1166 | + display_layout->place_in_output(info.output_id.value(), rect); |
1167 | + } |
1168 | + else |
1169 | + { |
1170 | + display_layout->size_to_output(rect); |
1171 | + } |
1172 | + |
1173 | + movement = rect.top_left - old_pos; |
1174 | + surface->resize(rect.size); |
1175 | + break; |
1176 | + } |
1177 | + |
1178 | + case mir_surface_state_hidden: |
1179 | + case mir_surface_state_minimized: |
1180 | + if (info.titlebar) |
1181 | + info.titlebar->hide(); |
1182 | + surface->hide(); |
1183 | + return info.state = value; |
1184 | + |
1185 | + default: |
1186 | + break; |
1187 | + } |
1188 | + |
1189 | + // TODO It is rather simplistic to move a tree WRT the top_left of the root |
1190 | + // TODO when resizing. But for more sophistication we would need to encode |
1191 | + // TODO some sensible layout rules. |
1192 | + move_tree(surface, movement); |
1193 | + |
1194 | + info.state = value; |
1195 | + |
1196 | + if (info.is_visible()) |
1197 | + surface->show(); |
1198 | + |
1199 | + return info.state; |
1200 | +} |
1201 | + |
1202 | +void me::CanonicalWindowManagerPolicyCopy::drag(Point cursor) |
1203 | +{ |
1204 | + select_active_surface(tools->surface_at(old_cursor)); |
1205 | + drag(active_surface(), cursor, old_cursor, display_area); |
1206 | +} |
1207 | + |
1208 | +void me::CanonicalWindowManagerPolicyCopy::handle_raise_surface( |
1209 | + std::shared_ptr<ms::Session> const& /*session*/, |
1210 | + std::shared_ptr<ms::Surface> const& surface) |
1211 | +{ |
1212 | + select_active_surface(surface); |
1213 | +} |
1214 | + |
1215 | +bool me::CanonicalWindowManagerPolicyCopy::handle_keyboard_event(MirKeyboardEvent const* event) |
1216 | +{ |
1217 | + auto const action = mir_keyboard_event_action(event); |
1218 | + auto const scan_code = mir_keyboard_event_scan_code(event); |
1219 | + auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask; |
1220 | + |
1221 | + if (action == mir_keyboard_action_down && scan_code == KEY_F11) |
1222 | + { |
1223 | + switch (modifiers) |
1224 | + { |
1225 | + case mir_input_event_modifier_alt: |
1226 | + toggle(mir_surface_state_maximized); |
1227 | + return true; |
1228 | + |
1229 | + case mir_input_event_modifier_shift: |
1230 | + toggle(mir_surface_state_vertmaximized); |
1231 | + return true; |
1232 | + |
1233 | + case mir_input_event_modifier_ctrl: |
1234 | + toggle(mir_surface_state_horizmaximized); |
1235 | + return true; |
1236 | + |
1237 | + default: |
1238 | + break; |
1239 | + } |
1240 | + } |
1241 | + else if (action == mir_keyboard_action_down && scan_code == KEY_F4) |
1242 | + { |
1243 | + if (auto const session = tools->focused_session()) |
1244 | + { |
1245 | + switch (modifiers) |
1246 | + { |
1247 | + case mir_input_event_modifier_alt: |
1248 | + kill(session->process_id(), SIGTERM); |
1249 | + return true; |
1250 | + |
1251 | + case mir_input_event_modifier_ctrl: |
1252 | + if (auto const surf = session->default_surface()) |
1253 | + { |
1254 | + surf->request_client_surface_close(); |
1255 | + return true; |
1256 | + } |
1257 | + |
1258 | + default: |
1259 | + break; |
1260 | + } |
1261 | + } |
1262 | + } |
1263 | + else if (action == mir_keyboard_action_down && |
1264 | + modifiers == mir_input_event_modifier_alt && |
1265 | + scan_code == KEY_TAB) |
1266 | + { |
1267 | + tools->focus_next_session(); |
1268 | + if (auto const surface = tools->focused_surface()) |
1269 | + select_active_surface(surface); |
1270 | + |
1271 | + return true; |
1272 | + } |
1273 | + else if (action == mir_keyboard_action_down && |
1274 | + modifiers == mir_input_event_modifier_alt && |
1275 | + scan_code == KEY_GRAVE) |
1276 | + { |
1277 | + if (auto const prev = tools->focused_surface()) |
1278 | + { |
1279 | + if (auto const app = tools->focused_session()) |
1280 | + select_active_surface(app->surface_after(prev)); |
1281 | + } |
1282 | + |
1283 | + return true; |
1284 | + } |
1285 | + |
1286 | + return false; |
1287 | +} |
1288 | + |
1289 | +bool me::CanonicalWindowManagerPolicyCopy::handle_touch_event(MirTouchEvent const* event) |
1290 | +{ |
1291 | + auto const count = mir_touch_event_point_count(event); |
1292 | + |
1293 | + long total_x = 0; |
1294 | + long total_y = 0; |
1295 | + |
1296 | + for (auto i = 0U; i != count; ++i) |
1297 | + { |
1298 | + total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x); |
1299 | + total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y); |
1300 | + } |
1301 | + |
1302 | + Point const cursor{total_x/count, total_y/count}; |
1303 | + |
1304 | + bool is_drag = true; |
1305 | + for (auto i = 0U; i != count; ++i) |
1306 | + { |
1307 | + switch (mir_touch_event_action(event, i)) |
1308 | + { |
1309 | + case mir_touch_action_up: |
1310 | + return false; |
1311 | + |
1312 | + case mir_touch_action_down: |
1313 | + is_drag = false; |
1314 | + |
1315 | + case mir_touch_action_change: |
1316 | + continue; |
1317 | + } |
1318 | + } |
1319 | + |
1320 | + bool consumes_event = false; |
1321 | + if (is_drag) |
1322 | + { |
1323 | + switch (count) |
1324 | + { |
1325 | + case 2: |
1326 | + resize(cursor); |
1327 | + consumes_event = true; |
1328 | + break; |
1329 | + |
1330 | + case 3: |
1331 | + drag(cursor); |
1332 | + consumes_event = true; |
1333 | + break; |
1334 | + } |
1335 | + } |
1336 | + |
1337 | + old_cursor = cursor; |
1338 | + return consumes_event; |
1339 | +} |
1340 | + |
1341 | +bool me::CanonicalWindowManagerPolicyCopy::handle_pointer_event(MirPointerEvent const* event) |
1342 | +{ |
1343 | + auto const action = mir_pointer_event_action(event); |
1344 | + auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask; |
1345 | + Point const cursor{ |
1346 | + mir_pointer_event_axis_value(event, mir_pointer_axis_x), |
1347 | + mir_pointer_event_axis_value(event, mir_pointer_axis_y)}; |
1348 | + |
1349 | + bool consumes_event = false; |
1350 | + |
1351 | + if (action == mir_pointer_action_button_down) |
1352 | + { |
1353 | + click(cursor); |
1354 | + } |
1355 | + else if (action == mir_pointer_action_motion && |
1356 | + modifiers == mir_input_event_modifier_alt) |
1357 | + { |
1358 | + if (mir_pointer_event_button_state(event, mir_pointer_button_primary)) |
1359 | + { |
1360 | + drag(cursor); |
1361 | + consumes_event = true; |
1362 | + } |
1363 | + |
1364 | + if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary)) |
1365 | + { |
1366 | + resize(cursor); |
1367 | + consumes_event = true; |
1368 | + } |
1369 | + } |
1370 | + else if (action == mir_pointer_action_motion && !modifiers) |
1371 | + { |
1372 | + if (mir_pointer_event_button_state(event, mir_pointer_button_primary)) |
1373 | + { |
1374 | + if (auto const possible_titlebar = tools->surface_at(old_cursor)) |
1375 | + { |
1376 | + if (tools->info_for(possible_titlebar).is_titlebar) |
1377 | + { |
1378 | + drag(cursor); |
1379 | + consumes_event = true; |
1380 | + } |
1381 | + } |
1382 | + } |
1383 | + } |
1384 | + |
1385 | + old_cursor = cursor; |
1386 | + return consumes_event; |
1387 | +} |
1388 | + |
1389 | +void me::CanonicalWindowManagerPolicyCopy::toggle(MirSurfaceState state) |
1390 | +{ |
1391 | + if (auto const surface = active_surface()) |
1392 | + { |
1393 | + auto& info = tools->info_for(surface); |
1394 | + |
1395 | + if (info.state == state) |
1396 | + state = mir_surface_state_restored; |
1397 | + |
1398 | + auto const value = handle_set_state(surface, MirSurfaceState(state)); |
1399 | + surface->configure(mir_surface_attrib_state, value); |
1400 | + } |
1401 | +} |
1402 | + |
1403 | +void me::CanonicalWindowManagerPolicyCopy::select_active_surface(std::shared_ptr<ms::Surface> const& surface) |
1404 | +{ |
1405 | + if (surface == active_surface_.lock()) |
1406 | + return; |
1407 | + |
1408 | + if (!surface) |
1409 | + { |
1410 | + if (auto const active_surface = active_surface_.lock()) |
1411 | + { |
1412 | + if (auto const titlebar = tools->info_for(active_surface).titlebar) |
1413 | + { |
1414 | + tools->info_for(titlebar).paint_titlebar(0x3F); |
1415 | + } |
1416 | + } |
1417 | + |
1418 | + if (active_surface_.lock()) |
1419 | + tools->set_focus_to({}, {}); |
1420 | + |
1421 | + active_surface_.reset(); |
1422 | + return; |
1423 | + } |
1424 | + |
1425 | + auto const& info_for = tools->info_for(surface); |
1426 | + |
1427 | + if (info_for.can_be_active()) |
1428 | + { |
1429 | + if (auto const active_surface = active_surface_.lock()) |
1430 | + { |
1431 | + if (auto const titlebar = tools->info_for(active_surface).titlebar) |
1432 | + { |
1433 | + tools->info_for(titlebar).paint_titlebar(0x3F); |
1434 | + } |
1435 | + } |
1436 | + if (auto const titlebar = tools->info_for(surface).titlebar) |
1437 | + { |
1438 | + tools->info_for(titlebar).paint_titlebar(0xFF); |
1439 | + } |
1440 | + tools->set_focus_to(info_for.session.lock(), surface); |
1441 | + tools->raise_tree(surface); |
1442 | + active_surface_ = surface; |
1443 | + } |
1444 | + else |
1445 | + { |
1446 | + // Cannot have input focus - try the parent |
1447 | + if (auto const parent = info_for.parent.lock()) |
1448 | + select_active_surface(parent); |
1449 | + } |
1450 | +} |
1451 | + |
1452 | +auto me::CanonicalWindowManagerPolicyCopy::active_surface() const |
1453 | +-> std::shared_ptr<ms::Surface> |
1454 | +{ |
1455 | + if (auto const surface = active_surface_.lock()) |
1456 | + return surface; |
1457 | + |
1458 | + if (auto const session = tools->focused_session()) |
1459 | + { |
1460 | + if (auto const surface = session->default_surface()) |
1461 | + return surface; |
1462 | + } |
1463 | + |
1464 | + return std::shared_ptr<ms::Surface>{}; |
1465 | +} |
1466 | + |
1467 | +bool me::CanonicalWindowManagerPolicyCopy::resize(std::shared_ptr<ms::Surface> const& surface, Point cursor, Point old_cursor, Rectangle bounds) |
1468 | +{ |
1469 | + if (!surface || !surface->input_area_contains(old_cursor)) |
1470 | + return false; |
1471 | + |
1472 | + auto const top_left = surface->top_left(); |
1473 | + Rectangle const old_pos{top_left, surface->size()}; |
1474 | + |
1475 | + auto anchor = top_left; |
1476 | + |
1477 | + for (auto const& corner : { |
1478 | + old_pos.top_right(), |
1479 | + old_pos.bottom_left(), |
1480 | + old_pos.bottom_right()}) |
1481 | + { |
1482 | + if ((old_cursor - anchor).length_squared() < |
1483 | + (old_cursor - corner).length_squared()) |
1484 | + { |
1485 | + anchor = corner; |
1486 | + } |
1487 | + } |
1488 | + |
1489 | + bool const left_resize = anchor.x != top_left.x; |
1490 | + bool const top_resize = anchor.y != top_left.y; |
1491 | + int const x_sign = left_resize? -1 : 1; |
1492 | + int const y_sign = top_resize? -1 : 1; |
1493 | + |
1494 | + auto const delta = cursor-old_cursor; |
1495 | + |
1496 | + Size new_size{old_pos.size.width + x_sign*delta.dx, old_pos.size.height + y_sign*delta.dy}; |
1497 | + |
1498 | + Point new_pos = top_left + left_resize*delta.dx + top_resize*delta.dy; |
1499 | + |
1500 | + |
1501 | + auto const& surface_info = tools->info_for(surface); |
1502 | + |
1503 | + surface_info.constrain_resize(surface, new_pos, new_size, left_resize, top_resize, bounds); |
1504 | + |
1505 | + apply_resize(surface, surface_info.titlebar, new_pos, new_size); |
1506 | + |
1507 | + return true; |
1508 | +} |
1509 | + |
1510 | +void me::CanonicalWindowManagerPolicyCopy::apply_resize( |
1511 | + std::shared_ptr<ms::Surface> const& surface, |
1512 | + std::shared_ptr<ms::Surface> const& titlebar, |
1513 | + Point const& new_pos, |
1514 | + Size const& new_size) const |
1515 | +{ |
1516 | + if (titlebar) |
1517 | + titlebar->resize({new_size.width, Height{title_bar_height}}); |
1518 | + |
1519 | + surface->resize(new_size); |
1520 | + |
1521 | + move_tree(surface, new_pos-surface->top_left()); |
1522 | +} |
1523 | + |
1524 | +bool me::CanonicalWindowManagerPolicyCopy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle /*bounds*/) |
1525 | +{ |
1526 | + if (!surface) |
1527 | + return false; |
1528 | + |
1529 | + if (!surface->input_area_contains(from) && !tools->info_for(surface).titlebar) |
1530 | + return false; |
1531 | + |
1532 | + auto movement = to - from; |
1533 | + |
1534 | + // placeholder - constrain onscreen |
1535 | + |
1536 | + switch (tools->info_for(surface).state) |
1537 | + { |
1538 | + case mir_surface_state_restored: |
1539 | + break; |
1540 | + |
1541 | + // "A vertically maximised surface is anchored to the top and bottom of |
1542 | + // the available workspace and can have any width." |
1543 | + case mir_surface_state_vertmaximized: |
1544 | + movement.dy = DeltaY(0); |
1545 | + break; |
1546 | + |
1547 | + // "A horizontally maximised surface is anchored to the left and right of |
1548 | + // the available workspace and can have any height" |
1549 | + case mir_surface_state_horizmaximized: |
1550 | + movement.dx = DeltaX(0); |
1551 | + break; |
1552 | + |
1553 | + // "A maximised surface is anchored to the top, bottom, left and right of the |
1554 | + // available workspace. For example, if the launcher is always-visible then |
1555 | + // the left-edge of the surface is anchored to the right-edge of the launcher." |
1556 | + case mir_surface_state_maximized: |
1557 | + case mir_surface_state_fullscreen: |
1558 | + default: |
1559 | + return true; |
1560 | + } |
1561 | + |
1562 | + move_tree(surface, movement); |
1563 | + |
1564 | + return true; |
1565 | +} |
1566 | + |
1567 | +void me::CanonicalWindowManagerPolicyCopy::move_tree(std::shared_ptr<ms::Surface> const& root, Displacement movement) const |
1568 | +{ |
1569 | + root->move_to(root->top_left() + movement); |
1570 | + |
1571 | + for (auto const& child: tools->info_for(root).children) |
1572 | + { |
1573 | + move_tree(child.lock(), movement); |
1574 | + } |
1575 | +} |
1576 | |
1577 | === added file 'src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h' |
1578 | --- src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h 1970-01-01 00:00:00 +0000 |
1579 | +++ src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h 2016-01-20 19:52:54 +0000 |
1580 | @@ -0,0 +1,132 @@ |
1581 | +/* |
1582 | + * Copyright © 2015 Canonical Ltd. |
1583 | + * |
1584 | + * This program is free software: you can redistribute it and/or modify it |
1585 | + * under the terms of the GNU General Public License version 3, |
1586 | + * as published by the Free Software Foundation. |
1587 | + * |
1588 | + * This program is distributed in the hope that it will be useful, |
1589 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1590 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1591 | + * GNU General Public License for more details. |
1592 | + * |
1593 | + * You should have received a copy of the GNU General Public License |
1594 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1595 | + * |
1596 | + * Authored By: Alan Griffiths <alan@octopull.co.uk> |
1597 | + */ |
1598 | + |
1599 | +#ifndef MIR_EXAMPLE_CANONICAL_WINDOW_MANAGER_H_ |
1600 | +#define MIR_EXAMPLE_CANONICAL_WINDOW_MANAGER_H_ |
1601 | + |
1602 | +#include "server_example_basic_window_manager.h" |
1603 | + |
1604 | +#include "mir/geometry/displacement.h" |
1605 | + |
1606 | +#include <atomic> |
1607 | +#include <set> |
1608 | + |
1609 | +///\example server_example_canonical_window_manager.h |
1610 | +// Based on "Mir and Unity: Surfaces, input, and displays (v0.3)" |
1611 | + |
1612 | +namespace mir |
1613 | +{ |
1614 | +namespace shell { class DisplayLayout; } |
1615 | +namespace examples |
1616 | +{ |
1617 | +// standard window management algorithm: |
1618 | +// o Switch apps: tap or click on the corresponding tile |
1619 | +// o Move window: Alt-leftmousebutton drag (three finger drag) |
1620 | +// o Resize window: Alt-middle_button drag (two finger drag) |
1621 | +// o Maximize/restore current window (to display size): Alt-F11 |
1622 | +// o Maximize/restore current window (to display height): Shift-F11 |
1623 | +// o Maximize/restore current window (to display width): Ctrl-F11 |
1624 | +// o client requests to maximize, vertically maximize & restore |
1625 | +class CanonicalWindowManagerPolicyCopy : public WindowManagementPolicy |
1626 | +{ |
1627 | +public: |
1628 | + |
1629 | + explicit CanonicalWindowManagerPolicyCopy( |
1630 | + WindowManagerTools* const tools, |
1631 | + std::shared_ptr<shell::DisplayLayout> const& display_layout); |
1632 | + |
1633 | + void click(geometry::Point cursor); |
1634 | + |
1635 | + void handle_session_info_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays); |
1636 | + |
1637 | + void handle_displays_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays); |
1638 | + |
1639 | + void resize(geometry::Point cursor); |
1640 | + |
1641 | + auto handle_place_new_surface( |
1642 | + std::shared_ptr<scene::Session> const& session, |
1643 | + scene::SurfaceCreationParameters const& request_parameters) |
1644 | + -> scene::SurfaceCreationParameters; |
1645 | + |
1646 | + void handle_new_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface); |
1647 | + |
1648 | + void handle_modify_surface( |
1649 | + std::shared_ptr<scene::Session> const& session, |
1650 | + std::shared_ptr<scene::Surface> const& surface, |
1651 | + shell::SurfaceSpecification const& modifications); |
1652 | + |
1653 | + void handle_delete_surface(std::shared_ptr<scene::Session> const& session, std::weak_ptr<scene::Surface> const& surface); |
1654 | + |
1655 | + int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value); |
1656 | + |
1657 | + void drag(geometry::Point cursor); |
1658 | + |
1659 | + bool handle_keyboard_event(MirKeyboardEvent const* event); |
1660 | + |
1661 | + bool handle_touch_event(MirTouchEvent const* event); |
1662 | + |
1663 | + bool handle_pointer_event(MirPointerEvent const* event); |
1664 | + |
1665 | + void handle_raise_surface( |
1666 | + std::shared_ptr<scene::Session> const& session, |
1667 | + std::shared_ptr<scene::Surface> const& surface); |
1668 | + |
1669 | + void generate_decorations_for( |
1670 | + std::shared_ptr<scene::Session> const& session, |
1671 | + std::shared_ptr<scene::Surface> const& surface, |
1672 | + SurfaceInfoMap& surface_map, |
1673 | + std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build); |
1674 | + |
1675 | +private: |
1676 | + static const int modifier_mask = |
1677 | + mir_input_event_modifier_alt | |
1678 | + mir_input_event_modifier_shift | |
1679 | + mir_input_event_modifier_sym | |
1680 | + mir_input_event_modifier_ctrl | |
1681 | + mir_input_event_modifier_meta; |
1682 | + |
1683 | + void toggle(MirSurfaceState state); |
1684 | + |
1685 | + // "Mir and Unity: Surfaces, input, and displays (v0.3)" talks about active |
1686 | + // *window*,but Mir really only understands surfaces |
1687 | + void select_active_surface(std::shared_ptr<scene::Surface> const& surface); |
1688 | + auto active_surface() const -> std::shared_ptr<scene::Surface>; |
1689 | + |
1690 | + bool resize(std::shared_ptr<scene::Surface> const& surface, geometry::Point cursor, geometry::Point old_cursor, geometry::Rectangle bounds); |
1691 | + bool drag(std::shared_ptr<scene::Surface> surface, geometry::Point to, geometry::Point from, geometry::Rectangle bounds); |
1692 | + void move_tree(std::shared_ptr<scene::Surface> const& root, geometry::Displacement movement) const; |
1693 | + void apply_resize( |
1694 | + std::shared_ptr<mir::scene::Surface> const& surface, |
1695 | + std::shared_ptr<mir::scene::Surface> const& titlebar, |
1696 | + geometry::Point const& new_pos, |
1697 | + geometry::Size const& new_size) const; |
1698 | + |
1699 | + WindowManagerTools* const tools; |
1700 | + std::shared_ptr<shell::DisplayLayout> const display_layout; |
1701 | + |
1702 | + geometry::Rectangle display_area; |
1703 | + geometry::Point old_cursor{}; |
1704 | + std::weak_ptr<scene::Surface> active_surface_; |
1705 | + using FullscreenSurfaces = std::set<std::weak_ptr<scene::Surface>, std::owner_less<std::weak_ptr<scene::Surface>>>; |
1706 | + |
1707 | + FullscreenSurfaces fullscreen_surfaces; |
1708 | +}; |
1709 | +} |
1710 | +} |
1711 | + |
1712 | +#endif /* MIR_EXAMPLE_CANONICAL_WINDOW_MANAGER_H_ */ |
1713 | |
1714 | === added file 'src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp' |
1715 | --- src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp 1970-01-01 00:00:00 +0000 |
1716 | +++ src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp 2016-01-20 19:52:54 +0000 |
1717 | @@ -0,0 +1,640 @@ |
1718 | +/* |
1719 | + * Copyright © 2015 Canonical Ltd. |
1720 | + * |
1721 | + * This program is free software: you can redistribute it and/or modify it |
1722 | + * under the terms of the GNU General Public License version 3, |
1723 | + * as published by the Free Software Foundation. |
1724 | + * |
1725 | + * This program is distributed in the hope that it will be useful, |
1726 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1727 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1728 | + * GNU General Public License for more details. |
1729 | + * |
1730 | + * You should have received a copy of the GNU General Public License |
1731 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1732 | + * |
1733 | + * Authored By: Alan Griffiths <alan@octopull.co.uk> |
1734 | + */ |
1735 | + |
1736 | +#include "server_example_tiling_window_manager.h" |
1737 | + |
1738 | +#include "mir/scene/session.h" |
1739 | +#include "mir/scene/surface.h" |
1740 | +#include "mir/scene/surface_creation_parameters.h" |
1741 | +#include "mir/shell/surface_specification.h" |
1742 | +#include "mir/shell/surface_stack.h" |
1743 | +#include "mir/shell/surface_ready_observer.h" |
1744 | +#include "mir/geometry/displacement.h" |
1745 | + |
1746 | +#include <linux/input.h> |
1747 | +#include <csignal> |
1748 | + |
1749 | +namespace me = mir::examples; |
1750 | +namespace ms = mir::scene; |
1751 | +namespace mf = mir::frontend; |
1752 | +using namespace mir::geometry; |
1753 | + |
1754 | +///\example server_example_tiling_window_manager.cpp |
1755 | +/// Demonstrate implementing a simple tiling algorithm |
1756 | + |
1757 | +me::TilingWindowManagerPolicy::TilingWindowManagerPolicy(WindowManagerTools* const tools) : |
1758 | + tools{tools} |
1759 | +{ |
1760 | +} |
1761 | + |
1762 | +void me::TilingWindowManagerPolicy::click(Point cursor) |
1763 | +{ |
1764 | + auto const session = session_under(cursor); |
1765 | + auto const surface = tools->surface_at(cursor); |
1766 | + select_active_surface(session, surface); |
1767 | +} |
1768 | + |
1769 | +void me::TilingWindowManagerPolicy::handle_session_info_updated(SessionInfoMap& session_info, Rectangles const& displays) |
1770 | +{ |
1771 | + update_tiles(session_info, displays); |
1772 | +} |
1773 | + |
1774 | +void me::TilingWindowManagerPolicy::handle_displays_updated(SessionInfoMap& session_info, Rectangles const& displays) |
1775 | +{ |
1776 | + update_tiles(session_info, displays); |
1777 | +} |
1778 | + |
1779 | +void me::TilingWindowManagerPolicy::resize(Point cursor) |
1780 | +{ |
1781 | + if (auto const session = session_under(cursor)) |
1782 | + { |
1783 | + if (session == session_under(old_cursor)) |
1784 | + { |
1785 | + if (auto const surface = select_active_surface(session, tools->surface_at(old_cursor))) |
1786 | + { |
1787 | + resize(surface, cursor, old_cursor, tools->info_for(session).tile); |
1788 | + } |
1789 | + } |
1790 | + } |
1791 | +} |
1792 | + |
1793 | +auto me::TilingWindowManagerPolicy::handle_place_new_surface( |
1794 | + std::shared_ptr<ms::Session> const& session, |
1795 | + ms::SurfaceCreationParameters const& request_parameters) |
1796 | +-> ms::SurfaceCreationParameters |
1797 | +{ |
1798 | + auto parameters = request_parameters; |
1799 | + |
1800 | + Rectangle const& tile = tools->info_for(session).tile; |
1801 | + parameters.top_left = parameters.top_left + (tile.top_left - Point{0, 0}); |
1802 | + |
1803 | + if (auto const parent = parameters.parent.lock()) |
1804 | + { |
1805 | + auto const width = parameters.size.width.as_int(); |
1806 | + auto const height = parameters.size.height.as_int(); |
1807 | + |
1808 | + if (parameters.aux_rect.is_set() && parameters.edge_attachment.is_set()) |
1809 | + { |
1810 | + auto const edge_attachment = parameters.edge_attachment.value(); |
1811 | + auto const aux_rect = parameters.aux_rect.value(); |
1812 | + auto const parent_top_left = parent->top_left(); |
1813 | + auto const top_left = aux_rect.top_left -Point{} + parent_top_left; |
1814 | + auto const top_right= aux_rect.top_right() -Point{} + parent_top_left; |
1815 | + auto const bot_left = aux_rect.bottom_left()-Point{} + parent_top_left; |
1816 | + |
1817 | + if (edge_attachment & mir_edge_attachment_vertical) |
1818 | + { |
1819 | + if (tile.contains(top_right + Displacement{width, height})) |
1820 | + { |
1821 | + parameters.top_left = top_right; |
1822 | + } |
1823 | + else if (tile.contains(top_left + Displacement{-width, height})) |
1824 | + { |
1825 | + parameters.top_left = top_left + Displacement{-width, 0}; |
1826 | + } |
1827 | + } |
1828 | + |
1829 | + if (edge_attachment & mir_edge_attachment_horizontal) |
1830 | + { |
1831 | + if (tile.contains(bot_left + Displacement{width, height})) |
1832 | + { |
1833 | + parameters.top_left = bot_left; |
1834 | + } |
1835 | + else if (tile.contains(top_left + Displacement{width, -height})) |
1836 | + { |
1837 | + parameters.top_left = top_left + Displacement{0, -height}; |
1838 | + } |
1839 | + } |
1840 | + } |
1841 | + else |
1842 | + { |
1843 | + auto const parent_top_left = parent->top_left(); |
1844 | + auto const centred = parent_top_left |
1845 | + + 0.5*(as_displacement(parent->size()) - as_displacement(parameters.size)) |
1846 | + - DeltaY{(parent->size().height.as_int()-height)/6}; |
1847 | + |
1848 | + parameters.top_left = centred; |
1849 | + } |
1850 | + } |
1851 | + |
1852 | + clip_to_tile(parameters, tile); |
1853 | + return parameters; |
1854 | +} |
1855 | + |
1856 | +void me::TilingWindowManagerPolicy::generate_decorations_for( |
1857 | + std::shared_ptr<ms::Session> const&, |
1858 | + std::shared_ptr<ms::Surface> const&, |
1859 | + SurfaceInfoMap&, |
1860 | + std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const&, ms::SurfaceCreationParameters const&)> const&) |
1861 | +{ |
1862 | +} |
1863 | + |
1864 | +void me::TilingWindowManagerPolicy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface) |
1865 | +{ |
1866 | + tools->info_for(session).surfaces.push_back(surface); |
1867 | + |
1868 | + auto& surface_info = tools->info_for(surface); |
1869 | + if (auto const parent = surface_info.parent.lock()) |
1870 | + { |
1871 | + tools->info_for(parent).children.push_back(surface); |
1872 | + } |
1873 | + |
1874 | + if (surface_info.can_be_active()) |
1875 | + { |
1876 | + surface->add_observer(std::make_shared<shell::SurfaceReadyObserver>( |
1877 | + [this](std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface) |
1878 | + { select_active_surface(session, surface); }, |
1879 | + session, |
1880 | + surface)); |
1881 | + } |
1882 | +} |
1883 | + |
1884 | +void me::TilingWindowManagerPolicy::handle_modify_surface( |
1885 | + std::shared_ptr<scene::Session> const& /*session*/, |
1886 | + std::shared_ptr<scene::Surface> const& surface, |
1887 | + shell::SurfaceSpecification const& modifications) |
1888 | +{ |
1889 | + if (modifications.name.is_set()) |
1890 | + surface->rename(modifications.name.value()); |
1891 | +} |
1892 | + |
1893 | +void me::TilingWindowManagerPolicy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface) |
1894 | +{ |
1895 | + auto& info = tools->info_for(surface); |
1896 | + |
1897 | + if (auto const parent = info.parent.lock()) |
1898 | + { |
1899 | + auto& siblings = tools->info_for(parent).children; |
1900 | + |
1901 | + for (auto i = begin(siblings); i != end(siblings); ++i) |
1902 | + { |
1903 | + if (surface.lock() == i->lock()) |
1904 | + { |
1905 | + siblings.erase(i); |
1906 | + break; |
1907 | + } |
1908 | + } |
1909 | + } |
1910 | + |
1911 | + auto& surfaces = tools->info_for(session).surfaces; |
1912 | + |
1913 | + for (auto i = begin(surfaces); i != end(surfaces); ++i) |
1914 | + { |
1915 | + if (surface.lock() == i->lock()) |
1916 | + { |
1917 | + surfaces.erase(i); |
1918 | + break; |
1919 | + } |
1920 | + } |
1921 | + |
1922 | + session->destroy_surface(surface); |
1923 | + |
1924 | + if (surfaces.empty() && session == tools->focused_session()) |
1925 | + { |
1926 | + tools->focus_next_session(); |
1927 | + select_active_surface(tools->focused_session(), tools->focused_surface()); |
1928 | + } |
1929 | +} |
1930 | + |
1931 | +int me::TilingWindowManagerPolicy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value) |
1932 | +{ |
1933 | + auto& info = tools->info_for(surface); |
1934 | + |
1935 | + switch (value) |
1936 | + { |
1937 | + case mir_surface_state_restored: |
1938 | + case mir_surface_state_maximized: |
1939 | + case mir_surface_state_vertmaximized: |
1940 | + case mir_surface_state_horizmaximized: |
1941 | + break; |
1942 | + |
1943 | + default: |
1944 | + return info.state; |
1945 | + } |
1946 | + |
1947 | + if (info.state == mir_surface_state_restored) |
1948 | + { |
1949 | + info.restore_rect = {surface->top_left(), surface->size()}; |
1950 | + } |
1951 | + |
1952 | + if (info.state == value) |
1953 | + { |
1954 | + return info.state; |
1955 | + } |
1956 | + |
1957 | + auto const& tile = tools->info_for(info.session).tile; |
1958 | + |
1959 | + switch (value) |
1960 | + { |
1961 | + case mir_surface_state_restored: |
1962 | + surface->resize(info.restore_rect.size); |
1963 | + drag(surface, info.restore_rect.top_left, surface->top_left(), tile); |
1964 | + break; |
1965 | + |
1966 | + case mir_surface_state_maximized: |
1967 | + surface->resize(tile.size); |
1968 | + drag(surface, tile.top_left, surface->top_left(), tile); |
1969 | + break; |
1970 | + |
1971 | + case mir_surface_state_horizmaximized: |
1972 | + surface->resize({tile.size.width, info.restore_rect.size.height}); |
1973 | + drag(surface, {tile.top_left.x, info.restore_rect.top_left.y}, surface->top_left(), tile); |
1974 | + break; |
1975 | + |
1976 | + case mir_surface_state_vertmaximized: |
1977 | + surface->resize({info.restore_rect.size.width, tile.size.height}); |
1978 | + drag(surface, {info.restore_rect.top_left.x, tile.top_left.y}, surface->top_left(), tile); |
1979 | + break; |
1980 | + |
1981 | + default: |
1982 | + break; |
1983 | + } |
1984 | + |
1985 | + return info.state = value; |
1986 | +} |
1987 | + |
1988 | +void me::TilingWindowManagerPolicy::drag(Point cursor) |
1989 | +{ |
1990 | + if (auto const session = session_under(cursor)) |
1991 | + { |
1992 | + if (session == session_under(old_cursor)) |
1993 | + { |
1994 | + if (auto const surface = select_active_surface(session, tools->surface_at(old_cursor))) |
1995 | + { |
1996 | + drag(surface, cursor, old_cursor, tools->info_for(session).tile); |
1997 | + } |
1998 | + } |
1999 | + } |
2000 | +} |
2001 | + |
2002 | +void me::TilingWindowManagerPolicy::handle_raise_surface( |
2003 | + std::shared_ptr<ms::Session> const& session, |
2004 | + std::shared_ptr<ms::Surface> const& surface) |
2005 | +{ |
2006 | + select_active_surface(session, surface); |
2007 | +} |
2008 | + |
2009 | +bool me::TilingWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event) |
2010 | +{ |
2011 | + auto const action = mir_keyboard_event_action(event); |
2012 | + auto const scan_code = mir_keyboard_event_scan_code(event); |
2013 | + auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask; |
2014 | + |
2015 | + if (action == mir_keyboard_action_down && scan_code == KEY_F11) |
2016 | + { |
2017 | + switch (modifiers & modifier_mask) |
2018 | + { |
2019 | + case mir_input_event_modifier_alt: |
2020 | + toggle(mir_surface_state_maximized); |
2021 | + return true; |
2022 | + |
2023 | + case mir_input_event_modifier_shift: |
2024 | + toggle(mir_surface_state_vertmaximized); |
2025 | + return true; |
2026 | + |
2027 | + case mir_input_event_modifier_ctrl: |
2028 | + toggle(mir_surface_state_horizmaximized); |
2029 | + return true; |
2030 | + |
2031 | + default: |
2032 | + break; |
2033 | + } |
2034 | + } |
2035 | + else if (action == mir_keyboard_action_down && scan_code == KEY_F4) |
2036 | + { |
2037 | + if (auto const session = tools->focused_session()) |
2038 | + { |
2039 | + switch (modifiers & modifier_mask) |
2040 | + { |
2041 | + case mir_input_event_modifier_alt: |
2042 | + kill(session->process_id(), SIGTERM); |
2043 | + return true; |
2044 | + |
2045 | + case mir_input_event_modifier_ctrl: |
2046 | + if (auto const surf = session->default_surface()) |
2047 | + { |
2048 | + surf->request_client_surface_close(); |
2049 | + return true; |
2050 | + } |
2051 | + |
2052 | + default: |
2053 | + break; |
2054 | + } |
2055 | + } |
2056 | + } |
2057 | + else if (action == mir_keyboard_action_down && |
2058 | + modifiers == mir_input_event_modifier_alt && |
2059 | + scan_code == KEY_TAB) |
2060 | + { |
2061 | + tools->focus_next_session(); |
2062 | + select_active_surface(tools->focused_session(), tools->focused_surface()); |
2063 | + |
2064 | + return true; |
2065 | + } |
2066 | + else if (action == mir_keyboard_action_down && |
2067 | + modifiers == mir_input_event_modifier_alt && |
2068 | + scan_code == KEY_GRAVE) |
2069 | + { |
2070 | + if (auto const prev = tools->focused_surface()) |
2071 | + { |
2072 | + if (auto const app = tools->focused_session()) |
2073 | + if (auto const surface = app->surface_after(prev)) |
2074 | + { |
2075 | + select_active_surface(app, surface); |
2076 | + } |
2077 | + } |
2078 | + |
2079 | + return true; |
2080 | + } |
2081 | + |
2082 | + return false; |
2083 | +} |
2084 | + |
2085 | +bool me::TilingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event) |
2086 | +{ |
2087 | + auto const count = mir_touch_event_point_count(event); |
2088 | + |
2089 | + long total_x = 0; |
2090 | + long total_y = 0; |
2091 | + |
2092 | + for (auto i = 0U; i != count; ++i) |
2093 | + { |
2094 | + total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x); |
2095 | + total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y); |
2096 | + } |
2097 | + |
2098 | + Point const cursor{total_x/count, total_y/count}; |
2099 | + |
2100 | + bool is_drag = true; |
2101 | + for (auto i = 0U; i != count; ++i) |
2102 | + { |
2103 | + switch (mir_touch_event_action(event, i)) |
2104 | + { |
2105 | + case mir_touch_action_up: |
2106 | + return false; |
2107 | + |
2108 | + case mir_touch_action_down: |
2109 | + is_drag = false; |
2110 | + |
2111 | + case mir_touch_action_change: |
2112 | + continue; |
2113 | + } |
2114 | + } |
2115 | + |
2116 | + bool consumes_event = false; |
2117 | + if (is_drag) |
2118 | + { |
2119 | + switch (count) |
2120 | + { |
2121 | + case 2: |
2122 | + resize(cursor); |
2123 | + consumes_event = true; |
2124 | + break; |
2125 | + |
2126 | + case 3: |
2127 | + drag(cursor); |
2128 | + consumes_event = true; |
2129 | + break; |
2130 | + } |
2131 | + } |
2132 | + |
2133 | + old_cursor = cursor; |
2134 | + return consumes_event; |
2135 | +} |
2136 | + |
2137 | +bool me::TilingWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event) |
2138 | +{ |
2139 | + auto const action = mir_pointer_event_action(event); |
2140 | + auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask; |
2141 | + Point const cursor{ |
2142 | + mir_pointer_event_axis_value(event, mir_pointer_axis_x), |
2143 | + mir_pointer_event_axis_value(event, mir_pointer_axis_y)}; |
2144 | + |
2145 | + bool consumes_event = false; |
2146 | + |
2147 | + if (action == mir_pointer_action_button_down) |
2148 | + { |
2149 | + click(cursor); |
2150 | + } |
2151 | + else if (action == mir_pointer_action_motion && |
2152 | + modifiers == mir_input_event_modifier_alt) |
2153 | + { |
2154 | + if (mir_pointer_event_button_state(event, mir_pointer_button_primary)) |
2155 | + { |
2156 | + drag(cursor); |
2157 | + consumes_event = true; |
2158 | + } |
2159 | + else if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary)) |
2160 | + { |
2161 | + resize(cursor); |
2162 | + consumes_event = true; |
2163 | + } |
2164 | + } |
2165 | + |
2166 | + old_cursor = cursor; |
2167 | + return consumes_event; |
2168 | +} |
2169 | + |
2170 | +void me::TilingWindowManagerPolicy::toggle(MirSurfaceState state) |
2171 | +{ |
2172 | + if (auto const session = tools->focused_session()) |
2173 | + { |
2174 | + if (auto const surface = session->default_surface()) |
2175 | + { |
2176 | + if (surface->state() == state) |
2177 | + state = mir_surface_state_restored; |
2178 | + |
2179 | + auto const value = handle_set_state(surface, MirSurfaceState(state)); |
2180 | + surface->configure(mir_surface_attrib_state, value); |
2181 | + } |
2182 | + } |
2183 | +} |
2184 | + |
2185 | +std::shared_ptr<ms::Session> me::TilingWindowManagerPolicy::session_under(Point position) |
2186 | +{ |
2187 | + return tools->find_session([&](SessionInfo const& info) { return info.tile.contains(position);}); |
2188 | +} |
2189 | + |
2190 | +void me::TilingWindowManagerPolicy::update_tiles( |
2191 | + SessionInfoMap& session_info, |
2192 | + Rectangles const& displays) |
2193 | +{ |
2194 | + if (session_info.size() < 1 || displays.size() < 1) return; |
2195 | + |
2196 | + auto const sessions = session_info.size(); |
2197 | + |
2198 | + auto const bounding_rect = displays.bounding_rectangle(); |
2199 | + |
2200 | + auto const total_width = bounding_rect.size.width.as_int(); |
2201 | + auto const total_height = bounding_rect.size.height.as_int(); |
2202 | + |
2203 | + auto index = 0; |
2204 | + |
2205 | + for (auto& info : session_info) |
2206 | + { |
2207 | + auto const x = (total_width*index)/sessions; |
2208 | + ++index; |
2209 | + auto const dx = (total_width*index)/sessions - x; |
2210 | + |
2211 | + auto const old_tile = info.second.tile; |
2212 | + Rectangle const new_tile{{x, 0}, {dx, total_height}}; |
2213 | + |
2214 | + update_surfaces(info.first, old_tile, new_tile); |
2215 | + |
2216 | + info.second.tile = new_tile; |
2217 | + } |
2218 | +} |
2219 | + |
2220 | +void me::TilingWindowManagerPolicy::update_surfaces(std::weak_ptr<ms::Session> const& session, Rectangle const& old_tile, Rectangle const& new_tile) |
2221 | +{ |
2222 | + auto displacement = new_tile.top_left - old_tile.top_left; |
2223 | + auto& info = tools->info_for(session); |
2224 | + |
2225 | + for (auto const& ps : info.surfaces) |
2226 | + { |
2227 | + if (auto const surface = ps.lock()) |
2228 | + { |
2229 | + auto const old_pos = surface->top_left(); |
2230 | + surface->move_to(old_pos + displacement); |
2231 | + |
2232 | + fit_to_new_tile(*surface, old_tile, new_tile); |
2233 | + } |
2234 | + } |
2235 | +} |
2236 | + |
2237 | +void me::TilingWindowManagerPolicy::clip_to_tile(ms::SurfaceCreationParameters& parameters, Rectangle const& tile) |
2238 | +{ |
2239 | + auto const displacement = parameters.top_left - tile.top_left; |
2240 | + |
2241 | + auto width = std::min(tile.size.width.as_int()-displacement.dx.as_int(), parameters.size.width.as_int()); |
2242 | + auto height = std::min(tile.size.height.as_int()-displacement.dy.as_int(), parameters.size.height.as_int()); |
2243 | + |
2244 | + parameters.size = Size{width, height}; |
2245 | +} |
2246 | + |
2247 | +void me::TilingWindowManagerPolicy::fit_to_new_tile(ms::Surface& surface, Rectangle const& old_tile, Rectangle const& new_tile) |
2248 | +{ |
2249 | + auto const displacement = surface.top_left() - new_tile.top_left; |
2250 | + |
2251 | + // For now just scale if was filling width/height of tile |
2252 | + auto const old_size = surface.size(); |
2253 | + auto const scaled_width = old_size.width == old_tile.size.width ? new_tile.size.width : old_size.width; |
2254 | + auto const scaled_height = old_size.height == old_tile.size.height ? new_tile.size.height : old_size.height; |
2255 | + |
2256 | + auto width = std::min(new_tile.size.width.as_int()-displacement.dx.as_int(), scaled_width.as_int()); |
2257 | + auto height = std::min(new_tile.size.height.as_int()-displacement.dy.as_int(), scaled_height.as_int()); |
2258 | + |
2259 | + surface.resize({width, height}); |
2260 | +} |
2261 | + |
2262 | +void me::TilingWindowManagerPolicy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle bounds) |
2263 | +{ |
2264 | + if (surface && surface->input_area_contains(from)) |
2265 | + { |
2266 | + auto movement = to - from; |
2267 | + |
2268 | + constrained_move(surface, movement, bounds); |
2269 | + |
2270 | + for (auto const& child: tools->info_for(surface).children) |
2271 | + { |
2272 | + auto move = movement; |
2273 | + constrained_move(child.lock(), move, bounds); |
2274 | + } |
2275 | + } |
2276 | +} |
2277 | + |
2278 | +void me::TilingWindowManagerPolicy::constrained_move( |
2279 | + std::shared_ptr<scene::Surface> const& surface, |
2280 | + Displacement& movement, |
2281 | + Rectangle const& bounds) |
2282 | +{ |
2283 | + auto const top_left = surface->top_left(); |
2284 | + auto const surface_size = surface->size(); |
2285 | + auto const bottom_right = top_left + as_displacement(surface_size); |
2286 | + |
2287 | + if (movement.dx < DeltaX{0}) |
2288 | + movement.dx = std::max(movement.dx, (bounds.top_left - top_left).dx); |
2289 | + |
2290 | + if (movement.dy < DeltaY{0}) |
2291 | + movement.dy = std::max(movement.dy, (bounds.top_left - top_left).dy); |
2292 | + |
2293 | + if (movement.dx > DeltaX{0}) |
2294 | + movement.dx = std::min(movement.dx, (bounds.bottom_right() - bottom_right).dx); |
2295 | + |
2296 | + if (movement.dy > DeltaY{0}) |
2297 | + movement.dy = std::min(movement.dy, (bounds.bottom_right() - bottom_right).dy); |
2298 | + |
2299 | + auto new_pos = surface->top_left() + movement; |
2300 | + |
2301 | + surface->move_to(new_pos); |
2302 | +} |
2303 | + |
2304 | +void me::TilingWindowManagerPolicy::resize(std::shared_ptr<ms::Surface> surface, Point cursor, Point old_cursor, Rectangle bounds) |
2305 | +{ |
2306 | + if (surface && surface->input_area_contains(old_cursor)) |
2307 | + { |
2308 | + auto const top_left = surface->top_left(); |
2309 | + |
2310 | + auto const old_displacement = old_cursor - top_left; |
2311 | + auto const new_displacement = cursor - top_left; |
2312 | + |
2313 | + auto const scale_x = new_displacement.dx.as_float()/std::max(1.0f, old_displacement.dx.as_float()); |
2314 | + auto const scale_y = new_displacement.dy.as_float()/std::max(1.0f, old_displacement.dy.as_float()); |
2315 | + |
2316 | + if (scale_x <= 0.0f || scale_y <= 0.0f) return; |
2317 | + |
2318 | + auto const old_size = surface->size(); |
2319 | + Size new_size{scale_x*old_size.width, scale_y*old_size.height}; |
2320 | + |
2321 | + auto const size_limits = as_size(bounds.bottom_right() - top_left); |
2322 | + |
2323 | + if (new_size.width > size_limits.width) |
2324 | + new_size.width = size_limits.width; |
2325 | + |
2326 | + if (new_size.height > size_limits.height) |
2327 | + new_size.height = size_limits.height; |
2328 | + |
2329 | + surface->resize(new_size); |
2330 | + } |
2331 | +} |
2332 | + |
2333 | +std::shared_ptr<ms::Surface> me::TilingWindowManagerPolicy::select_active_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<scene::Surface> const& surface) |
2334 | +{ |
2335 | + if (!surface) |
2336 | + { |
2337 | + tools->set_focus_to({}, {}); |
2338 | + return surface; |
2339 | + } |
2340 | + |
2341 | + auto const& info_for = tools->info_for(surface); |
2342 | + |
2343 | + if (info_for.can_be_active()) |
2344 | + { |
2345 | + tools->set_focus_to(session, surface); |
2346 | + tools->raise_tree(surface); |
2347 | + return surface; |
2348 | + } |
2349 | + else |
2350 | + { |
2351 | + // Cannot have input focus - try the parent |
2352 | + if (auto const parent = info_for.parent.lock()) |
2353 | + return select_active_surface(session, parent); |
2354 | + |
2355 | + return {}; |
2356 | + } |
2357 | +} |
2358 | |
2359 | === added file 'src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h' |
2360 | --- src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h 1970-01-01 00:00:00 +0000 |
2361 | +++ src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h 2016-01-20 19:52:54 +0000 |
2362 | @@ -0,0 +1,124 @@ |
2363 | +/* |
2364 | + * Copyright © 2015 Canonical Ltd. |
2365 | + * |
2366 | + * This program is free software: you can redistribute it and/or modify it |
2367 | + * under the terms of the GNU General Public License version 3, |
2368 | + * as published by the Free Software Foundation. |
2369 | + * |
2370 | + * This program is distributed in the hope that it will be useful, |
2371 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2372 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2373 | + * GNU General Public License for more details. |
2374 | + * |
2375 | + * You should have received a copy of the GNU General Public License |
2376 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2377 | + * |
2378 | + * Authored By: Alan Griffiths <alan@octopull.co.uk> |
2379 | + */ |
2380 | + |
2381 | +#ifndef MIR_EXAMPLE_TILING_WINDOW_MANAGER_H_ |
2382 | +#define MIR_EXAMPLE_TILING_WINDOW_MANAGER_H_ |
2383 | + |
2384 | +#include "server_example_basic_window_manager.h" |
2385 | + |
2386 | +///\example server_example_tiling_window_manager.h |
2387 | +/// Demonstrate implementing a simple tiling algorithm |
2388 | + |
2389 | +namespace mir |
2390 | +{ |
2391 | +namespace examples |
2392 | +{ |
2393 | +// simple tiling algorithm: |
2394 | +// o Switch apps: tap or click on the corresponding tile |
2395 | +// o Move window: Alt-leftmousebutton drag (three finger drag) |
2396 | +// o Resize window: Alt-middle_button drag (two finger drag) |
2397 | +// o Maximize/restore current window (to tile size): Alt-F11 |
2398 | +// o Maximize/restore current window (to tile height): Shift-F11 |
2399 | +// o Maximize/restore current window (to tile width): Ctrl-F11 |
2400 | +// o client requests to maximize, vertically maximize & restore |
2401 | +class TilingWindowManagerPolicy : public WindowManagementPolicy |
2402 | +{ |
2403 | +public: |
2404 | + explicit TilingWindowManagerPolicy(WindowManagerTools* const tools); |
2405 | + |
2406 | + void click(geometry::Point cursor); |
2407 | + |
2408 | + void handle_session_info_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays); |
2409 | + |
2410 | + void handle_displays_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays); |
2411 | + |
2412 | + void resize(geometry::Point cursor); |
2413 | + |
2414 | + auto handle_place_new_surface( |
2415 | + std::shared_ptr<scene::Session> const& session, |
2416 | + scene::SurfaceCreationParameters const& request_parameters) |
2417 | + -> scene::SurfaceCreationParameters; |
2418 | + |
2419 | + void handle_new_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface); |
2420 | + |
2421 | + void handle_modify_surface( |
2422 | + std::shared_ptr<scene::Session> const& session, |
2423 | + std::shared_ptr<scene::Surface> const& surface, |
2424 | + shell::SurfaceSpecification const& modifications); |
2425 | + |
2426 | + void handle_delete_surface(std::shared_ptr<scene::Session> const& session, std::weak_ptr<scene::Surface> const& surface); |
2427 | + |
2428 | + int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value); |
2429 | + |
2430 | + void drag(geometry::Point cursor); |
2431 | + |
2432 | + bool handle_keyboard_event(MirKeyboardEvent const* event); |
2433 | + |
2434 | + bool handle_touch_event(MirTouchEvent const* event); |
2435 | + |
2436 | + bool handle_pointer_event(MirPointerEvent const* event); |
2437 | + |
2438 | + void handle_raise_surface( |
2439 | + std::shared_ptr<scene::Session> const& session, |
2440 | + std::shared_ptr<scene::Surface> const& surface); |
2441 | + |
2442 | + void generate_decorations_for( |
2443 | + std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface, |
2444 | + SurfaceInfoMap& surface_info, |
2445 | + std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const&, scene::SurfaceCreationParameters const&)> const& build); |
2446 | + |
2447 | +private: |
2448 | + static const int modifier_mask = |
2449 | + mir_input_event_modifier_alt | |
2450 | + mir_input_event_modifier_shift | |
2451 | + mir_input_event_modifier_sym | |
2452 | + mir_input_event_modifier_ctrl | |
2453 | + mir_input_event_modifier_meta; |
2454 | + |
2455 | + void toggle(MirSurfaceState state); |
2456 | + |
2457 | + std::shared_ptr<scene::Session> session_under(geometry::Point position); |
2458 | + |
2459 | + void update_tiles( |
2460 | + SessionInfoMap& session_info, |
2461 | + geometry::Rectangles const& displays); |
2462 | + |
2463 | + void update_surfaces(std::weak_ptr<scene::Session> const& session, geometry::Rectangle const& old_tile, geometry::Rectangle const& new_tile); |
2464 | + |
2465 | + static void clip_to_tile(scene::SurfaceCreationParameters& parameters, geometry::Rectangle const& tile); |
2466 | + |
2467 | + static void fit_to_new_tile(scene::Surface& surface, geometry::Rectangle const& old_tile, geometry::Rectangle const& new_tile); |
2468 | + |
2469 | + void drag(std::shared_ptr<scene::Surface> surface, geometry::Point to, geometry::Point from, geometry::Rectangle bounds); |
2470 | + |
2471 | + static void resize(std::shared_ptr<scene::Surface> surface, geometry::Point cursor, geometry::Point old_cursor, geometry::Rectangle bounds); |
2472 | + |
2473 | + static void constrained_move(std::shared_ptr<scene::Surface> const& surface, geometry::Displacement& movement, geometry::Rectangle const& bounds); |
2474 | + |
2475 | + std::shared_ptr<scene::Surface> select_active_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface); |
2476 | + |
2477 | + WindowManagerTools* const tools; |
2478 | + |
2479 | + geometry::Point old_cursor{}; |
2480 | +}; |
2481 | + |
2482 | +using TilingWindowManager = WindowManagerBuilder<TilingWindowManagerPolicy>; |
2483 | +} |
2484 | +} |
2485 | + |
2486 | +#endif /* MIR_EXAMPLE_TILING_WINDOW_MANAGER_H_ */ |
2487 | |
2488 | === added file 'src/platforms/mirserver/wm-wip/server_example_window_management.cpp' |
2489 | --- src/platforms/mirserver/wm-wip/server_example_window_management.cpp 1970-01-01 00:00:00 +0000 |
2490 | +++ src/platforms/mirserver/wm-wip/server_example_window_management.cpp 2016-01-20 19:52:54 +0000 |
2491 | @@ -0,0 +1,155 @@ |
2492 | +/* |
2493 | + * Copyright © 2014 Canonical Ltd. |
2494 | + * |
2495 | + * This program is free software: you can redistribute it and/or modify it |
2496 | + * under the terms of the GNU General Public License version 3, |
2497 | + * as published by the Free Software Foundation. |
2498 | + * |
2499 | + * This program is distributed in the hope that it will be useful, |
2500 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2501 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2502 | + * GNU General Public License for more details. |
2503 | + * |
2504 | + * You should have received a copy of the GNU General Public License |
2505 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2506 | + * |
2507 | + * Authored By: Alan Griffiths <alan@octopull.co.uk> |
2508 | + */ |
2509 | + |
2510 | +#include "server_example_window_management.h" |
2511 | + |
2512 | +#include "server_example_tiling_window_manager.h" |
2513 | +#include "server_example_canonical_window_manager.h" |
2514 | + |
2515 | +#include "mir/abnormal_exit.h" |
2516 | +#include "mir/server.h" |
2517 | +#include "mir/input/composite_event_filter.h" |
2518 | +#include "mir/options/option.h" |
2519 | +#include "mir/scene/session.h" |
2520 | +#include "mir/scene/surface_creation_parameters.h" |
2521 | +#include "mir/shell/display_layout.h" |
2522 | +#include "mir/shell/system_compositor_window_manager.h" |
2523 | + |
2524 | +namespace me = mir::examples; |
2525 | +namespace mf = mir::frontend; |
2526 | +namespace mg = mir::graphics; |
2527 | +namespace mi = mir::input; |
2528 | +namespace ms = mir::scene; |
2529 | +namespace msh = mir::shell; |
2530 | +using namespace mir::geometry; |
2531 | + |
2532 | +///\example server_example_window_management.cpp |
2533 | +/// Demonstrate introducing a window management strategy |
2534 | + |
2535 | +namespace |
2536 | +{ |
2537 | +char const* const wm_option = "window-manager"; |
2538 | +char const* const wm_description = "window management strategy [{tiling|fullscreen|canonical|system-compositor}]"; |
2539 | + |
2540 | +char const* const wm_tiling = "tiling"; |
2541 | +char const* const wm_fullscreen = "fullscreen"; |
2542 | +char const* const wm_canonical = "canonical"; |
2543 | +char const* const wm_system_compositor = "system-compositor"; |
2544 | + |
2545 | +// Very simple - make every surface fullscreen |
2546 | +class FullscreenWindowManagerPolicy : public me::WindowManagementPolicy |
2547 | +{ |
2548 | +public: |
2549 | + FullscreenWindowManagerPolicy(me::WindowManagerTools* const /*tools*/, std::shared_ptr<msh::DisplayLayout> const& display_layout) : |
2550 | + display_layout{display_layout} {} |
2551 | + |
2552 | + void handle_session_info_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/) {} |
2553 | + |
2554 | + void handle_displays_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/) {} |
2555 | + |
2556 | + auto handle_place_new_surface( |
2557 | + std::shared_ptr<ms::Session> const& /*session*/, |
2558 | + ms::SurfaceCreationParameters const& request_parameters) |
2559 | + -> ms::SurfaceCreationParameters |
2560 | + { |
2561 | + auto placed_parameters = request_parameters; |
2562 | + |
2563 | + Rectangle rect{request_parameters.top_left, request_parameters.size}; |
2564 | + display_layout->size_to_output(rect); |
2565 | + placed_parameters.size = rect.size; |
2566 | + |
2567 | + return placed_parameters; |
2568 | + } |
2569 | + void handle_modify_surface( |
2570 | + std::shared_ptr<ms::Session> const& /*session*/, |
2571 | + std::shared_ptr<ms::Surface> const& /*surface*/, |
2572 | + msh::SurfaceSpecification const& /*modifications*/) |
2573 | + { |
2574 | + } |
2575 | + |
2576 | + void handle_new_surface(std::shared_ptr<ms::Session> const& /*session*/, std::shared_ptr<ms::Surface> const& /*surface*/) |
2577 | + { |
2578 | + } |
2579 | + |
2580 | + void handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface) |
2581 | + { session->destroy_surface(surface); } |
2582 | + |
2583 | + int handle_set_state(std::shared_ptr<ms::Surface> const& /*surface*/, MirSurfaceState value) |
2584 | + { return value; } |
2585 | + |
2586 | + bool handle_keyboard_event(MirKeyboardEvent const* /*event*/) { return false; } |
2587 | + |
2588 | + bool handle_touch_event(MirTouchEvent const* /*event*/) { return false; } |
2589 | + |
2590 | + bool handle_pointer_event(MirPointerEvent const* /*event*/) { return false; } |
2591 | + |
2592 | + void handle_raise_surface( |
2593 | + std::shared_ptr<ms::Session> const& /*session*/, |
2594 | + std::shared_ptr<ms::Surface> const& /*surface*/) |
2595 | + { |
2596 | + } |
2597 | + |
2598 | + void generate_decorations_for( |
2599 | + std::shared_ptr<ms::Session> const&, |
2600 | + std::shared_ptr<ms::Surface> const&, |
2601 | + SurfaceInfoMap&, |
2602 | + std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const&, ms::SurfaceCreationParameters const&)> const&) |
2603 | + { |
2604 | + } |
2605 | +private: |
2606 | + std::shared_ptr<msh::DisplayLayout> const display_layout; |
2607 | +}; |
2608 | + |
2609 | +} |
2610 | + |
2611 | +using FullscreenWindowManager = me::WindowManagerBuilder<FullscreenWindowManagerPolicy>; |
2612 | +using CanonicalWindowManager = me::WindowManagerBuilder<me::CanonicalWindowManagerPolicyCopy>; |
2613 | + |
2614 | +void me::add_window_manager_option_to(Server& server) |
2615 | +{ |
2616 | + server.add_configuration_option(wm_option, wm_description, wm_canonical); |
2617 | + |
2618 | + server.override_the_window_manager_builder([&server](msh::FocusController* focus_controller) |
2619 | + -> std::shared_ptr<msh::WindowManager> |
2620 | + { |
2621 | + auto const options = server.get_options(); |
2622 | + auto const selection = options->get<std::string>(wm_option); |
2623 | + |
2624 | + if (selection == wm_tiling) |
2625 | + { |
2626 | + return std::make_shared<TilingWindowManager>(focus_controller); |
2627 | + } |
2628 | + else if (selection == wm_fullscreen) |
2629 | + { |
2630 | + return std::make_shared<FullscreenWindowManager>(focus_controller, server.the_shell_display_layout()); |
2631 | + } |
2632 | + else if (selection == wm_canonical) |
2633 | + { |
2634 | + return std::make_shared<CanonicalWindowManager>(focus_controller, server.the_shell_display_layout()); |
2635 | + } |
2636 | + else if (selection == wm_system_compositor) |
2637 | + { |
2638 | + return std::make_shared<msh::SystemCompositorWindowManager>( |
2639 | + focus_controller, |
2640 | + server.the_shell_display_layout(), |
2641 | + server.the_session_coordinator()); |
2642 | + } |
2643 | + |
2644 | + throw mir::AbnormalExit("Unknown window manager: " + selection); |
2645 | + }); |
2646 | +} |
2647 | |
2648 | === added file 'src/platforms/mirserver/wm-wip/server_example_window_management.h' |
2649 | --- src/platforms/mirserver/wm-wip/server_example_window_management.h 1970-01-01 00:00:00 +0000 |
2650 | +++ src/platforms/mirserver/wm-wip/server_example_window_management.h 2016-01-20 19:52:54 +0000 |
2651 | @@ -0,0 +1,33 @@ |
2652 | +/* |
2653 | + * Copyright © 2014 Canonical Ltd. |
2654 | + * |
2655 | + * This program is free software: you can redistribute it and/or modify it |
2656 | + * under the terms of the GNU General Public License version 3, |
2657 | + * as published by the Free Software Foundation. |
2658 | + * |
2659 | + * This program is distributed in the hope that it will be useful, |
2660 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2661 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2662 | + * GNU General Public License for more details. |
2663 | + * |
2664 | + * You should have received a copy of the GNU General Public License |
2665 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2666 | + * |
2667 | + * Authored By: Alan Griffiths <alan@octopull.co.uk> |
2668 | + */ |
2669 | + |
2670 | +#ifndef MIR_EXAMPLES_WINDOW_MANAGEMENT_H_ |
2671 | +#define MIR_EXAMPLES_WINDOW_MANAGEMENT_H_ |
2672 | + |
2673 | +namespace mir |
2674 | +{ |
2675 | +class Server; |
2676 | + |
2677 | +namespace examples |
2678 | +{ |
2679 | +void add_window_manager_option_to(Server& server); |
2680 | +} |
2681 | +} // namespace mir |
2682 | + |
2683 | + |
2684 | +#endif // MIR_EXAMPLES_WINDOW_MANAGEMENT_H_ |
2685 | |
2686 | === added file 'src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp' |
2687 | --- src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp 1970-01-01 00:00:00 +0000 |
2688 | +++ src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp 2016-01-20 19:52:54 +0000 |
2689 | @@ -0,0 +1,406 @@ |
2690 | +/* |
2691 | + * Copyright © 2015 Canonical Ltd. |
2692 | + * |
2693 | + * This program is free software: you can redistribute it and/or modify it |
2694 | + * under the terms of the GNU General Public License version 3, |
2695 | + * as published by the Free Software Foundation. |
2696 | + * |
2697 | + * This program is distributed in the hope that it will be useful, |
2698 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2699 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2700 | + * GNU General Public License for more details. |
2701 | + * |
2702 | + * You should have received a copy of the GNU General Public License |
2703 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2704 | + * |
2705 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
2706 | + */ |
2707 | + |
2708 | +#include "server_example_window_management_info.h" |
2709 | + |
2710 | +#include "mir/scene/surface.h" |
2711 | +#include "mir/scene/surface_creation_parameters.h" |
2712 | + |
2713 | +#include "mir/graphics/buffer.h" |
2714 | + |
2715 | +#include <atomic> |
2716 | + |
2717 | +namespace me = mir::examples; |
2718 | +namespace ms = mir::scene; |
2719 | +namespace mg = mir::graphics; |
2720 | +using namespace mir::geometry; |
2721 | + |
2722 | +me::SurfaceInfo::SurfaceInfo( |
2723 | + std::shared_ptr<scene::Session> const& session, |
2724 | + std::shared_ptr<scene::Surface> const& surface, |
2725 | + scene::SurfaceCreationParameters const& params) : |
2726 | + type{surface->type()}, |
2727 | + state{surface->state()}, |
2728 | + restore_rect{surface->top_left(), surface->size()}, |
2729 | + session{session}, |
2730 | + parent{params.parent}, |
2731 | + min_width{params.min_width.is_set() ? params.min_width.value() : Width{}}, |
2732 | + min_height{params.min_height.is_set() ? params.min_height.value() : Height{}}, |
2733 | + max_width{params.max_width.is_set() ? params.max_width.value() : Width{std::numeric_limits<int>::max()}}, |
2734 | + max_height{params.max_height.is_set() ? params.max_height.value() : Height{std::numeric_limits<int>::max()}}, |
2735 | + width_inc{params.width_inc}, |
2736 | + height_inc{params.height_inc}, |
2737 | + min_aspect{params.min_aspect}, |
2738 | + max_aspect{params.max_aspect} |
2739 | +{ |
2740 | + if (params.output_id != mir::graphics::DisplayConfigurationOutputId{0}) |
2741 | + output_id = params.output_id; |
2742 | +} |
2743 | + |
2744 | +bool me::SurfaceInfo::can_be_active() const |
2745 | +{ |
2746 | + switch (type) |
2747 | + { |
2748 | + case mir_surface_type_normal: /**< AKA "regular" */ |
2749 | + case mir_surface_type_utility: /**< AKA "floating" */ |
2750 | + case mir_surface_type_dialog: |
2751 | + case mir_surface_type_satellite: /**< AKA "toolbox"/"toolbar" */ |
2752 | + case mir_surface_type_freestyle: |
2753 | + case mir_surface_type_menu: |
2754 | + case mir_surface_type_inputmethod: /**< AKA "OSK" or handwriting etc. */ |
2755 | + return true; |
2756 | + |
2757 | + case mir_surface_type_gloss: |
2758 | + case mir_surface_type_tip: /**< AKA "tooltip" */ |
2759 | + default: |
2760 | + // Cannot have input focus |
2761 | + return false; |
2762 | + } |
2763 | +} |
2764 | + |
2765 | +bool me::SurfaceInfo::must_have_parent() const |
2766 | +{ |
2767 | + switch (type) |
2768 | + { |
2769 | + case mir_surface_type_overlay:; |
2770 | + case mir_surface_type_inputmethod: |
2771 | + case mir_surface_type_satellite: |
2772 | + case mir_surface_type_tip: |
2773 | + return true; |
2774 | + |
2775 | + default: |
2776 | + return false; |
2777 | + } |
2778 | +} |
2779 | + |
2780 | +bool me::SurfaceInfo::can_morph_to(MirSurfaceType new_type) const |
2781 | +{ |
2782 | + switch (new_type) |
2783 | + { |
2784 | + case mir_surface_type_normal: |
2785 | + case mir_surface_type_utility: |
2786 | + case mir_surface_type_satellite: |
2787 | + switch (type) |
2788 | + { |
2789 | + case mir_surface_type_normal: |
2790 | + case mir_surface_type_utility: |
2791 | + case mir_surface_type_dialog: |
2792 | + case mir_surface_type_satellite: |
2793 | + return true; |
2794 | + |
2795 | + default: |
2796 | + break; |
2797 | + } |
2798 | + break; |
2799 | + |
2800 | + case mir_surface_type_dialog: |
2801 | + switch (type) |
2802 | + { |
2803 | + case mir_surface_type_normal: |
2804 | + case mir_surface_type_utility: |
2805 | + case mir_surface_type_dialog: |
2806 | + case mir_surface_type_popover: |
2807 | + case mir_surface_type_satellite: |
2808 | + return true; |
2809 | + |
2810 | + default: |
2811 | + break; |
2812 | + } |
2813 | + break; |
2814 | + |
2815 | + default: |
2816 | + break; |
2817 | + } |
2818 | + |
2819 | + return false; |
2820 | +} |
2821 | + |
2822 | +bool me::SurfaceInfo::must_not_have_parent() const |
2823 | +{ |
2824 | + switch (type) |
2825 | + { |
2826 | + case mir_surface_type_normal: |
2827 | + case mir_surface_type_utility: |
2828 | + return true; |
2829 | + |
2830 | + default: |
2831 | + return false; |
2832 | + } |
2833 | +} |
2834 | + |
2835 | +bool me::SurfaceInfo::is_visible() const |
2836 | +{ |
2837 | + switch (state) |
2838 | + { |
2839 | + case mir_surface_state_hidden: |
2840 | + case mir_surface_state_minimized: |
2841 | + return false; |
2842 | + default: |
2843 | + break; |
2844 | + } |
2845 | + return true; |
2846 | +} |
2847 | + |
2848 | +struct mir::examples::SurfaceInfo::StreamPainter |
2849 | +{ |
2850 | + virtual void paint(int) = 0; |
2851 | + virtual ~StreamPainter() = default; |
2852 | + StreamPainter() = default; |
2853 | + StreamPainter(StreamPainter const&) = delete; |
2854 | + StreamPainter& operator=(StreamPainter const&) = delete; |
2855 | +}; |
2856 | + |
2857 | +struct mir::examples::SurfaceInfo::SwappingPainter |
2858 | + : mir::examples::SurfaceInfo::StreamPainter |
2859 | +{ |
2860 | + SwappingPainter(std::shared_ptr<frontend::BufferStream> const& buffer_stream) : |
2861 | + buffer_stream{buffer_stream}, buffer{nullptr} |
2862 | + { |
2863 | + swap_buffers(); |
2864 | + } |
2865 | + |
2866 | + void swap_buffers() |
2867 | + { |
2868 | + auto const callback = [this](mir::graphics::Buffer* new_buffer) |
2869 | + { |
2870 | + buffer.store(new_buffer); |
2871 | + }; |
2872 | + |
2873 | + buffer_stream->swap_buffers(buffer, callback); |
2874 | + } |
2875 | + |
2876 | + void paint(int intensity) override |
2877 | + { |
2878 | + if (auto const buf = buffer.load()) |
2879 | + { |
2880 | + auto const format = buffer_stream->pixel_format(); |
2881 | + auto const sz = buf->size().height.as_int() * |
2882 | + buf->size().width.as_int() * MIR_BYTES_PER_PIXEL(format); |
2883 | + std::vector<unsigned char> pixels(sz, intensity); |
2884 | + buf->write(pixels.data(), sz); |
2885 | + swap_buffers(); |
2886 | + } |
2887 | + } |
2888 | + |
2889 | + std::shared_ptr<frontend::BufferStream> const buffer_stream; |
2890 | + std::atomic<graphics::Buffer*> buffer; |
2891 | +}; |
2892 | + |
2893 | +struct mir::examples::SurfaceInfo::AllocatingPainter |
2894 | + : mir::examples::SurfaceInfo::StreamPainter |
2895 | +{ |
2896 | + AllocatingPainter(std::shared_ptr<frontend::BufferStream> const& buffer_stream, Size size) : |
2897 | + buffer_stream(buffer_stream), |
2898 | + properties({ |
2899 | + size, |
2900 | + buffer_stream->pixel_format(), |
2901 | + mg::BufferUsage::software |
2902 | + }), |
2903 | + front_buffer(buffer_stream->allocate_buffer(properties)), |
2904 | + back_buffer(buffer_stream->allocate_buffer(properties)) |
2905 | + { |
2906 | + } |
2907 | + |
2908 | + void paint(int intensity) override |
2909 | + { |
2910 | + buffer_stream->with_buffer(back_buffer, |
2911 | + [this, intensity](graphics::Buffer& buffer) |
2912 | + { |
2913 | + auto const format = buffer.pixel_format(); |
2914 | + auto const sz = buffer.size().height.as_int() * |
2915 | + buffer.size().width.as_int() * MIR_BYTES_PER_PIXEL(format); |
2916 | + std::vector<unsigned char> pixels(sz, intensity); |
2917 | + buffer.write(pixels.data(), sz); |
2918 | + buffer_stream->swap_buffers(&buffer, [](mg::Buffer*){}); |
2919 | + }); |
2920 | + std::swap(front_buffer, back_buffer); |
2921 | + } |
2922 | + |
2923 | + ~AllocatingPainter() |
2924 | + { |
2925 | + buffer_stream->remove_buffer(front_buffer); |
2926 | + buffer_stream->remove_buffer(back_buffer); |
2927 | + } |
2928 | + |
2929 | + std::shared_ptr<frontend::BufferStream> const buffer_stream; |
2930 | + mg::BufferProperties properties; |
2931 | + mg::BufferID front_buffer; |
2932 | + mg::BufferID back_buffer; |
2933 | +}; |
2934 | + |
2935 | +void mir::examples::SurfaceInfo::init_titlebar(std::shared_ptr<scene::Surface> const& surface) |
2936 | +{ |
2937 | + auto stream = surface->primary_buffer_stream(); |
2938 | + try |
2939 | + { |
2940 | + stream_painter = std::make_shared<AllocatingPainter>(stream, surface->size()); |
2941 | + } |
2942 | + catch (...) |
2943 | + { |
2944 | + stream_painter = std::make_shared<SwappingPainter>(stream); |
2945 | + } |
2946 | +} |
2947 | + |
2948 | +void mir::examples::SurfaceInfo::paint_titlebar(int intensity) |
2949 | +{ |
2950 | + stream_painter->paint(intensity); |
2951 | +} |
2952 | + |
2953 | +void me::SurfaceInfo::constrain_resize( |
2954 | + std::shared_ptr<ms::Surface> const& surface, |
2955 | + Point& requested_pos, |
2956 | + Size& requested_size, |
2957 | + bool const left_resize, |
2958 | + bool const top_resize, |
2959 | + Rectangle const& /*bounds*/) const |
2960 | +{ |
2961 | + Point new_pos = requested_pos; |
2962 | + Size new_size = requested_size; |
2963 | + |
2964 | + if (min_aspect.is_set()) |
2965 | + { |
2966 | + auto const ar = min_aspect.value(); |
2967 | + |
2968 | + auto const error = new_size.height.as_int()*long(ar.width) - new_size.width.as_int()*long(ar.height); |
2969 | + |
2970 | + if (error > 0) |
2971 | + { |
2972 | + // Add (denominator-1) to numerator to ensure rounding up |
2973 | + auto const width_correction = (error+(ar.height-1))/ar.height; |
2974 | + auto const height_correction = (error+(ar.width-1))/ar.width; |
2975 | + |
2976 | + if (width_correction < height_correction) |
2977 | + { |
2978 | + new_size.width = new_size.width + DeltaX(width_correction); |
2979 | + } |
2980 | + else |
2981 | + { |
2982 | + new_size.height = new_size.height - DeltaY(height_correction); |
2983 | + } |
2984 | + } |
2985 | + } |
2986 | + |
2987 | + if (max_aspect.is_set()) |
2988 | + { |
2989 | + auto const ar = max_aspect.value(); |
2990 | + |
2991 | + auto const error = new_size.width.as_int()*long(ar.height) - new_size.height.as_int()*long(ar.width); |
2992 | + |
2993 | + if (error > 0) |
2994 | + { |
2995 | + // Add (denominator-1) to numerator to ensure rounding up |
2996 | + auto const height_correction = (error+(ar.width-1))/ar.width; |
2997 | + auto const width_correction = (error+(ar.height-1))/ar.height; |
2998 | + |
2999 | + if (width_correction < height_correction) |
3000 | + { |
3001 | + new_size.width = new_size.width - DeltaX(width_correction); |
3002 | + } |
3003 | + else |
3004 | + { |
3005 | + new_size.height = new_size.height + DeltaY(height_correction); |
3006 | + } |
3007 | + } |
3008 | + } |
3009 | + |
3010 | + if (min_width > new_size.width) |
3011 | + new_size.width = min_width; |
3012 | + |
3013 | + if (min_height > new_size.height) |
3014 | + new_size.height = min_height; |
3015 | + |
3016 | + if (max_width < new_size.width) |
3017 | + new_size.width = max_width; |
3018 | + |
3019 | + if (max_height < new_size.height) |
3020 | + new_size.height = max_height; |
3021 | + |
3022 | + if (width_inc.is_set()) |
3023 | + { |
3024 | + auto const width = new_size.width.as_int() - min_width.as_int(); |
3025 | + auto inc = width_inc.value().as_int(); |
3026 | + if (width % inc) |
3027 | + new_size.width = min_width + DeltaX{inc*(((2L*width + inc)/2)/inc)}; |
3028 | + } |
3029 | + |
3030 | + if (height_inc.is_set()) |
3031 | + { |
3032 | + auto const height = new_size.height.as_int() - min_height.as_int(); |
3033 | + auto inc = height_inc.value().as_int(); |
3034 | + if (height % inc) |
3035 | + new_size.height = min_height + DeltaY{inc*(((2L*height + inc)/2)/inc)}; |
3036 | + } |
3037 | + |
3038 | + if (left_resize) |
3039 | + new_pos.x += new_size.width - requested_size.width; |
3040 | + |
3041 | + if (top_resize) |
3042 | + new_pos.y += new_size.height - requested_size.height; |
3043 | + |
3044 | + // placeholder - constrain onscreen |
3045 | + |
3046 | + switch (state) |
3047 | + { |
3048 | + case mir_surface_state_restored: |
3049 | + break; |
3050 | + |
3051 | + // "A vertically maximised surface is anchored to the top and bottom of |
3052 | + // the available workspace and can have any width." |
3053 | + case mir_surface_state_vertmaximized: |
3054 | + new_pos.y = surface->top_left().y; |
3055 | + new_size.height = surface->size().height; |
3056 | + break; |
3057 | + |
3058 | + // "A horizontally maximised surface is anchored to the left and right of |
3059 | + // the available workspace and can have any height" |
3060 | + case mir_surface_state_horizmaximized: |
3061 | + new_pos.x = surface->top_left().x; |
3062 | + new_size.width = surface->size().width; |
3063 | + break; |
3064 | + |
3065 | + // "A maximised surface is anchored to the top, bottom, left and right of the |
3066 | + // available workspace. For example, if the launcher is always-visible then |
3067 | + // the left-edge of the surface is anchored to the right-edge of the launcher." |
3068 | + case mir_surface_state_maximized: |
3069 | + default: |
3070 | + new_pos.x = surface->top_left().x; |
3071 | + new_pos.y = surface->top_left().y; |
3072 | + new_size.width = surface->size().width; |
3073 | + new_size.height = surface->size().height; |
3074 | + break; |
3075 | + } |
3076 | + |
3077 | + requested_pos = new_pos; |
3078 | + requested_size = new_size; |
3079 | +} |
3080 | + |
3081 | +bool me::SurfaceInfo::needs_titlebar(MirSurfaceType type) |
3082 | +{ |
3083 | + switch (type) |
3084 | + { |
3085 | + case mir_surface_type_freestyle: |
3086 | + case mir_surface_type_menu: |
3087 | + case mir_surface_type_inputmethod: |
3088 | + case mir_surface_type_gloss: |
3089 | + case mir_surface_type_tip: |
3090 | + // No decorations for these surface types |
3091 | + return false; |
3092 | + default: |
3093 | + return true; |
3094 | + } |
3095 | +} |
3096 | |
3097 | === added file 'src/platforms/mirserver/wm-wip/server_example_window_management_info.h' |
3098 | --- src/platforms/mirserver/wm-wip/server_example_window_management_info.h 1970-01-01 00:00:00 +0000 |
3099 | +++ src/platforms/mirserver/wm-wip/server_example_window_management_info.h 2016-01-20 19:52:54 +0000 |
3100 | @@ -0,0 +1,103 @@ |
3101 | +/* |
3102 | + * Copyright © 2015 Canonical Ltd. |
3103 | + * |
3104 | + * This program is free software: you can redistribute it and/or modify it |
3105 | + * under the terms of the GNU General Public License version 3, |
3106 | + * as published by the Free Software Foundation. |
3107 | + * |
3108 | + * This program is distributed in the hope that it will be useful, |
3109 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3110 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3111 | + * GNU General Public License for more details. |
3112 | + * |
3113 | + * You should have received a copy of the GNU General Public License |
3114 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3115 | + * |
3116 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
3117 | + */ |
3118 | + |
3119 | +#ifndef MIR_SERVER_EXAMPLE_WINDOW_MANAGEMENT_INFO_H |
3120 | +#define MIR_SERVER_EXAMPLE_WINDOW_MANAGEMENT_INFO_H |
3121 | + |
3122 | +#include "mir/geometry/rectangles.h" |
3123 | +#include "mir/optional_value.h" |
3124 | +#include "mir/shell/surface_specification.h" |
3125 | + |
3126 | +#include <vector> |
3127 | + |
3128 | +namespace mir |
3129 | +{ |
3130 | +namespace scene { class Session; class Surface; class SurfaceCreationParameters; } |
3131 | +namespace examples |
3132 | +{ |
3133 | +struct SurfaceInfo |
3134 | +{ |
3135 | + SurfaceInfo( |
3136 | + std::shared_ptr <scene::Session> const& session, |
3137 | + std::shared_ptr <scene::Surface> const& surface, |
3138 | + scene::SurfaceCreationParameters const& params); |
3139 | + |
3140 | + bool can_be_active() const; |
3141 | + |
3142 | + bool can_morph_to(MirSurfaceType new_type) const; |
3143 | + |
3144 | + bool must_have_parent() const; |
3145 | + |
3146 | + bool must_not_have_parent() const; |
3147 | + |
3148 | + bool is_visible() const; |
3149 | + |
3150 | + static bool needs_titlebar(MirSurfaceType type); |
3151 | + |
3152 | + void constrain_resize( |
3153 | + std::shared_ptr <scene::Surface> const& surface, |
3154 | + geometry::Point& requested_pos, |
3155 | + geometry::Size& requested_size, |
3156 | + const bool left_resize, |
3157 | + const bool top_resize, |
3158 | + geometry::Rectangle const& bounds) const; |
3159 | + |
3160 | + MirSurfaceType type; |
3161 | + MirSurfaceState state; |
3162 | + geometry::Rectangle restore_rect; |
3163 | + std::weak_ptr <scene::Session> session; |
3164 | + std::weak_ptr <scene::Surface> parent; |
3165 | + std::vector <std::weak_ptr<scene::Surface>> children; |
3166 | + std::shared_ptr <scene::Surface> titlebar; |
3167 | + frontend::SurfaceId titlebar_id; |
3168 | + bool is_titlebar = false; |
3169 | + geometry::Width min_width; |
3170 | + geometry::Height min_height; |
3171 | + geometry::Width max_width; |
3172 | + geometry::Height max_height; |
3173 | + mir::optional_value<geometry::DeltaX> width_inc; |
3174 | + mir::optional_value<geometry::DeltaY> height_inc; |
3175 | + mir::optional_value<shell::SurfaceAspectRatio> min_aspect; |
3176 | + mir::optional_value<shell::SurfaceAspectRatio> max_aspect; |
3177 | + mir::optional_value<graphics::DisplayConfigurationOutputId> output_id; |
3178 | + |
3179 | + void init_titlebar(std::shared_ptr <scene::Surface> const& surface); |
3180 | + |
3181 | + void paint_titlebar(int intensity); |
3182 | + |
3183 | +private: |
3184 | + |
3185 | + struct StreamPainter; |
3186 | + struct AllocatingPainter; |
3187 | + struct SwappingPainter; |
3188 | + |
3189 | + std::shared_ptr <StreamPainter> stream_painter; |
3190 | +}; |
3191 | + |
3192 | +struct SessionInfo |
3193 | +{ |
3194 | + std::vector<std::weak_ptr<scene::Surface>> surfaces; |
3195 | + |
3196 | + // This is only used by the TilingWindowManagerPolicy, |
3197 | + // perhaps we need a more extensible mechanism. (std::experimental::any?) |
3198 | + geometry::Rectangle tile; |
3199 | +}; |
3200 | +} |
3201 | +} |
3202 | + |
3203 | +#endif //MIR_SERVER_EXAMPLE_WINDOW_MANAGEMENT_INFO_H |
FAILED: Continuous integration, rev:418 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 578/ jenkins. qa.ubuntu. com/job/ qtmir-vivid- amd64-ci/ 274 jenkins. qa.ubuntu. com/job/ qtmir-vivid- armhf-ci/ 274 jenkins. qa.ubuntu. com/job/ qtmir-vivid- armhf-ci/ 274/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ qtmir-vivid- i386-ci/ 156 jenkins. qa.ubuntu. com/job/ qtmir-wily- amd64-ci/ 311/console jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 311/console jenkins. qa.ubuntu. com/job/ qtmir-wily- i386-ci/ 156/console
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/578/ rebuild
http://