Merge lp:~mir-team/miral/1.4 into lp:miral/release
- 1.4
- Merge into release
Proposed by
Brandon Schaefer
Status: | Rejected |
---|---|
Rejected by: | Alan Griffiths |
Proposed branch: | lp:~mir-team/miral/1.4 |
Merge into: | lp:miral/release |
Diff against target: |
1523 lines (+1194/-19) 18 files modified
CMakeLists.txt (+2/-2) debian/changelog (+13/-2) debian/libmiral2.symbols (+4/-0) include/miral/window_management_policy_addendum2.h (+70/-0) include/miral/window_manager_tools.h (+12/-0) miral-shell/miral-screencast.sh (+1/-1) miral/CMakeLists.txt (+1/-0) miral/basic_window_manager.cpp (+76/-12) miral/basic_window_manager.h (+14/-0) miral/symbols.map (+21/-0) miral/window_management_trace.cpp (+18/-0) miral/window_management_trace.h (+2/-0) miral/window_manager_tools.cpp (+6/-0) miral/window_manager_tools_implementation.h (+3/-0) scripts/process_doxygen_xml.py (+12/-1) test/CMakeLists.txt (+13/-1) test/client_mediated_gestures.cpp (+285/-0) test/drag_and_drop.cpp (+641/-0) |
To merge this branch: | bzr merge lp:~mir-team/miral/1.4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Disapprove | ||
Review via email: mp+322533@code.launchpad.net |
Commit message
1.4 Release
Description of the change
1.4 Release
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2017-03-24 17:44:48 +0000 |
3 | +++ CMakeLists.txt 2017-04-13 15:18:28 +0000 |
4 | @@ -41,8 +41,8 @@ |
5 | include_directories(include SYSTEM ${MIRCLIENT_INCLUDE_DIRS}) |
6 | |
7 | set(MIRAL_VERSION_MAJOR 1) |
8 | -set(MIRAL_VERSION_MINOR 3) |
9 | -set(MIRAL_VERSION_PATCH 2) |
10 | +set(MIRAL_VERSION_MINOR 4) |
11 | +set(MIRAL_VERSION_PATCH 0) |
12 | |
13 | set(MIRAL_VERSION ${MIRAL_VERSION_MAJOR}.${MIRAL_VERSION_MINOR}.${MIRAL_VERSION_PATCH}) |
14 | |
15 | |
16 | === modified file 'debian/changelog' |
17 | --- debian/changelog 2017-03-30 14:18:38 +0000 |
18 | +++ debian/changelog 2017-04-13 15:18:28 +0000 |
19 | @@ -1,3 +1,14 @@ |
20 | +miral (1.4.0) UNRELEASED; urgency=medium |
21 | + |
22 | + * New upstream release 1.4.0 (https://launchpad.net/miral/+milestone/1.4.0) |
23 | + - ABI summary: |
24 | + . miral ABI unchanged at 2 |
25 | + - Enhancements: |
26 | + . Support for passing messages to enable Drag & Drop |
27 | + - Bugs fixed: |
28 | + |
29 | + -- Alan Griffiths <alan@Octopull-X1c3> Tue, 21 Mar 2017 17:57:20 +0000 |
30 | + |
31 | miral (1.3.2+17.04.20170330.5-0ubuntu1) zesty; urgency=medium |
32 | |
33 | * New upstream release 1.3.2 (https://launchpad.net/miral/+milestone/1.3.2) |
34 | @@ -74,11 +85,11 @@ |
35 | . Chrome-less shell hint does not work any more (LP: #1658117) |
36 | . WindowSpec::set_state() wrapper for mir_window_spec_set_state() |
37 | (LP: #1661256) |
38 | - . "$ miral-app -kiosk" fails with "Unknown command line options: |
39 | + . "$ miral-app -kiosk" fails with "Unknown command line options: |
40 | --desktop_file_hint=miral-shell.desktop" (LP: #1660933) |
41 | . libmiral] Fix focus and movement rules for Input Method and Satellite |
42 | windows. (LP: #1660691) |
43 | - |
44 | + |
45 | |
46 | -- Alan Griffiths <alan.griffiths@canonical.com> Wed, 15 Feb 2017 14:05:46 +0000 |
47 | |
48 | |
49 | === modified file 'debian/libmiral2.symbols' |
50 | --- debian/libmiral2.symbols 2017-03-15 17:44:36 +0000 |
51 | +++ debian/libmiral2.symbols 2017-04-13 15:18:28 +0000 |
52 | @@ -389,3 +389,7 @@ |
53 | (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.3.1 |
54 | (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.3.1 |
55 | (c++)"miral::SetWindowManagementPolicy::operator()(mir::Server&) const@MIRAL_1.3.1" 1.3.1 |
56 | + MIRAL_1.4.0@MIRAL_1.4.0 1.4.0 |
57 | + (c++)"miral::WindowManagerTools::end_drag_and_drop()@MIRAL_1.4.0" 1.4.0 |
58 | + (c++)"miral::WindowManagerTools::start_drag_and_drop(miral::WindowInfo&, std::vector<unsigned char, std::allocator<unsigned char> > const&)@MIRAL_1.4.0" 1.4.0 |
59 | + (c++)"typeinfo for miral::WindowManagementPolicyAddendum2@MIRAL_1.4.0" 1.4.0 |
60 | |
61 | === added file 'include/miral/window_management_policy_addendum2.h' |
62 | --- include/miral/window_management_policy_addendum2.h 1970-01-01 00:00:00 +0000 |
63 | +++ include/miral/window_management_policy_addendum2.h 2017-04-13 15:18:28 +0000 |
64 | @@ -0,0 +1,70 @@ |
65 | +/* |
66 | + * Copyright © 2017 Canonical Ltd. |
67 | + * |
68 | + * This program is free software: you can redistribute it and/or modify it |
69 | + * under the terms of the GNU General Public License version 3, |
70 | + * as published by the Free Software Foundation. |
71 | + * |
72 | + * This program is distributed in the hope that it will be useful, |
73 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
74 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
75 | + * GNU General Public License for more details. |
76 | + * |
77 | + * You should have received a copy of the GNU General Public License |
78 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
79 | + * |
80 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
81 | + */ |
82 | + |
83 | +#ifndef MIRAL_WINDOW_MANAGEMENT_ADDENDUM2_H |
84 | +#define MIRAL_WINDOW_MANAGEMENT_ADDENDUM2_H |
85 | + |
86 | +#include <mir_toolkit/client_types.h> |
87 | +#include <mir/version.h> |
88 | + |
89 | +namespace miral |
90 | +{ |
91 | +struct WindowInfo; |
92 | + |
93 | +/** |
94 | + * Handle additional client requests. |
95 | + * |
96 | + * \note This interface is intended to be implemented by a WindowManagementPolicy |
97 | + * implementation, we can't add these functions directly to that interface without |
98 | + * breaking ABI (the vtab could be incompatible). |
99 | + * When initializing the window manager this interface will be detected by |
100 | + * dynamic_cast and registered accordingly. |
101 | + */ |
102 | +class WindowManagementPolicyAddendum2 |
103 | +{ |
104 | +public: |
105 | +/** @name handle requests originating from the client |
106 | + * The policy is expected to update the model as appropriate |
107 | + * @{ */ |
108 | + /** request from client to initiate drag and drop |
109 | + * \note the request has already been validated against the requesting event |
110 | + * |
111 | + * @param window_info the window |
112 | + */ |
113 | + virtual void handle_request_drag_and_drop(WindowInfo& window_info) = 0; |
114 | + |
115 | + /** request from client to initiate move |
116 | + * \note the request has already been validated against the requesting event |
117 | + * |
118 | + * @param window_info the window |
119 | + * @param input_event the requesting event |
120 | + */ |
121 | + virtual void handle_request_move(WindowInfo& window_info, MirInputEvent const* input_event) = 0; |
122 | +/** @} */ |
123 | + |
124 | + virtual ~WindowManagementPolicyAddendum2() = default; |
125 | + WindowManagementPolicyAddendum2() = default; |
126 | + WindowManagementPolicyAddendum2(WindowManagementPolicyAddendum2 const&) = delete; |
127 | + WindowManagementPolicyAddendum2& operator=(WindowManagementPolicyAddendum2 const&) = delete; |
128 | +}; |
129 | +#if MIRAL_VERSION >= MIR_VERSION_NUMBER(2, 0, 0) |
130 | +#error "We've presumably broken ABI - please roll this interface into WindowManagementPolicy" |
131 | +#endif |
132 | +} |
133 | + |
134 | +#endif //MIRAL_WINDOW_MANAGEMENT_ADDENDUM2_H |
135 | |
136 | === modified file 'include/miral/window_manager_tools.h' |
137 | --- include/miral/window_manager_tools.h 2017-03-02 14:29:04 +0000 |
138 | +++ include/miral/window_manager_tools.h 2017-04-13 15:18:28 +0000 |
139 | @@ -166,6 +166,18 @@ |
140 | /// Raise window and all its children |
141 | void raise_tree(Window const& root); |
142 | |
143 | + /** Start drag and drop. The handle will be passed to the client which can |
144 | + * then use it to talk to the whatever service is being used to support drag |
145 | + * and drop (e.g. on Ubuntu the content hub). |
146 | + * |
147 | + * @param window_info source window |
148 | + * @param handle drag handle |
149 | + */ |
150 | + void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle); |
151 | + |
152 | + /// End drag and drop |
153 | + void end_drag_and_drop(); |
154 | + |
155 | /// Apply modifications to a window |
156 | void modify_window(WindowInfo& window_info, WindowSpecification const& modifications); |
157 | |
158 | |
159 | === modified file 'miral-shell/miral-screencast.sh' |
160 | --- miral-shell/miral-screencast.sh 2016-12-09 11:08:07 +0000 |
161 | +++ miral-shell/miral-screencast.sh 2017-04-13 15:18:28 +0000 |
162 | @@ -2,7 +2,7 @@ |
163 | width=1920 |
164 | height=1080 |
165 | output=screencast.mp4 |
166 | -socket=${XDG_RUNTIME_DIR}/mir_socket |
167 | +socket=${XDG_RUNTIME_DIR}/miral_socket |
168 | if [ -v MIR_SERVER ]; then socket=${MIR_SERVER}; fi |
169 | |
170 | while [ $# -gt 0 ] |
171 | |
172 | === modified file 'miral/CMakeLists.txt' |
173 | --- miral/CMakeLists.txt 2017-03-20 12:28:06 +0000 |
174 | +++ miral/CMakeLists.txt 2017-04-13 15:18:28 +0000 |
175 | @@ -61,6 +61,7 @@ |
176 | ${CMAKE_SOURCE_DIR}/include/mir/client/display_config.h |
177 | ${CMAKE_SOURCE_DIR}/include/mir/client/window.h |
178 | ${CMAKE_SOURCE_DIR}/include/mir/client/detail/mir_forward_compatibility.h |
179 | + ${CMAKE_SOURCE_DIR}/include/miral/window_management_policy_addendum2.h |
180 | ) |
181 | |
182 | target_link_libraries(miral |
183 | |
184 | === modified file 'miral/basic_window_manager.cpp' |
185 | --- miral/basic_window_manager.cpp 2017-03-21 12:30:42 +0000 |
186 | +++ miral/basic_window_manager.cpp 2017-04-13 15:18:28 +0000 |
187 | @@ -19,6 +19,7 @@ |
188 | #include "basic_window_manager.h" |
189 | #include "miral/window_manager_tools.h" |
190 | #include "miral/workspace_policy.h" |
191 | +#include "miral/window_management_policy_addendum2.h" |
192 | |
193 | #include <mir/scene/session.h> |
194 | #include <mir/scene/surface.h> |
195 | @@ -70,7 +71,6 @@ |
196 | |
197 | namespace |
198 | { |
199 | - |
200 | auto find_workspace_policy(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WorkspacePolicy* |
201 | { |
202 | miral::WorkspacePolicy* result = dynamic_cast<miral::WorkspacePolicy*>(policy.get()); |
203 | @@ -82,6 +82,23 @@ |
204 | |
205 | return &null_workspace_policy; |
206 | } |
207 | + |
208 | +auto find_policy_addendum2(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WindowManagementPolicyAddendum2* |
209 | +{ |
210 | + miral::WindowManagementPolicyAddendum2* result = dynamic_cast<miral::WindowManagementPolicyAddendum2*>(policy.get()); |
211 | + |
212 | + if (result) |
213 | + return result; |
214 | + |
215 | + struct NullWindowManagementPolicyAddendum2 : miral::WindowManagementPolicyAddendum2 |
216 | + { |
217 | + void handle_request_drag_and_drop(miral::WindowInfo&) override {} |
218 | + void handle_request_move(miral::WindowInfo&, MirInputEvent const*) override {} |
219 | + }; |
220 | + static NullWindowManagementPolicyAddendum2 null_workspace_policy; |
221 | + |
222 | + return &null_workspace_policy; |
223 | +} |
224 | } |
225 | |
226 | |
227 | @@ -94,10 +111,18 @@ |
228 | display_layout(display_layout), |
229 | persistent_surface_store{persistent_surface_store}, |
230 | policy(build(WindowManagerTools{this})), |
231 | - workspace_policy{find_workspace_policy(policy)} |
232 | + workspace_policy{find_workspace_policy(policy)}, |
233 | + policy2{find_policy_addendum2(policy)} |
234 | { |
235 | } |
236 | |
237 | +miral::BasicWindowManager::~BasicWindowManager() |
238 | +{ |
239 | +#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
240 | + if (last_input_event) |
241 | + mir_event_unref(last_input_event); |
242 | +#endif |
243 | +} |
244 | void miral::BasicWindowManager::add_session(std::shared_ptr<scene::Session> const& session) |
245 | { |
246 | Locker lock{this}; |
247 | @@ -362,10 +387,24 @@ |
248 | #if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
249 | void miral::BasicWindowManager::handle_request_drag_and_drop( |
250 | std::shared_ptr<mir::scene::Session> const& /*session*/, |
251 | - std::shared_ptr<mir::scene::Surface> const& /*surface*/, |
252 | - uint64_t /*timestamp*/) |
253 | -{ |
254 | - // TODO |
255 | + std::shared_ptr<mir::scene::Surface> const& surface, |
256 | + uint64_t timestamp) |
257 | +{ |
258 | + Locker lock{this}; |
259 | + if (timestamp >= last_input_event_timestamp) |
260 | + policy2->handle_request_drag_and_drop(info_for(surface)); |
261 | +} |
262 | + |
263 | +void miral::BasicWindowManager::handle_request_move( |
264 | + std::shared_ptr<mir::scene::Session> const& /*session*/, |
265 | + std::shared_ptr<mir::scene::Surface> const& surface, |
266 | + uint64_t timestamp) |
267 | +{ |
268 | + std::lock_guard<decltype(mutex)> lock(mutex); |
269 | + if (timestamp >= last_input_event_timestamp && last_input_event) |
270 | + { |
271 | + policy2->handle_request_move(info_for(surface), mir_event_get_input_event(last_input_event)); |
272 | + } |
273 | } |
274 | #endif |
275 | |
276 | @@ -741,6 +780,24 @@ |
277 | focus_controller->raise({begin(windows), end(windows)}); |
278 | } |
279 | |
280 | +void miral::BasicWindowManager::start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) |
281 | +{ |
282 | +#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
283 | + std::shared_ptr<scene::Surface>(window_info.window())->start_drag_and_drop(handle); |
284 | + focus_controller->set_drag_and_drop_handle(handle); |
285 | +#else |
286 | + (void)window_info; |
287 | + (void)handle; |
288 | +#endif |
289 | +} |
290 | + |
291 | +void miral::BasicWindowManager::end_drag_and_drop() |
292 | +{ |
293 | +#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
294 | + focus_controller->clear_drag_and_drop_handle(); |
295 | +#endif |
296 | +} |
297 | + |
298 | void miral::BasicWindowManager::move_tree(miral::WindowInfo& root, mir::geometry::Displacement movement) |
299 | { |
300 | if (movement == mir::geometry::Displacement{}) |
301 | @@ -1163,25 +1220,22 @@ |
302 | |
303 | void miral::BasicWindowManager::update_event_timestamp(MirKeyboardEvent const* kev) |
304 | { |
305 | - auto iev = mir_keyboard_event_input_event(kev); |
306 | - last_input_event_timestamp = mir_input_event_get_event_time(iev); |
307 | + update_event_timestamp(mir_keyboard_event_input_event(kev)); |
308 | } |
309 | |
310 | void miral::BasicWindowManager::update_event_timestamp(MirPointerEvent const* pev) |
311 | { |
312 | - auto iev = mir_pointer_event_input_event(pev); |
313 | auto pointer_action = mir_pointer_event_action(pev); |
314 | |
315 | if (pointer_action == mir_pointer_action_button_up || |
316 | pointer_action == mir_pointer_action_button_down) |
317 | { |
318 | - last_input_event_timestamp = mir_input_event_get_event_time(iev); |
319 | + update_event_timestamp(mir_pointer_event_input_event(pev)); |
320 | } |
321 | } |
322 | |
323 | void miral::BasicWindowManager::update_event_timestamp(MirTouchEvent const* tev) |
324 | { |
325 | - auto iev = mir_touch_event_input_event(tev); |
326 | auto touch_count = mir_touch_event_point_count(tev); |
327 | for (unsigned i = 0; i < touch_count; i++) |
328 | { |
329 | @@ -1189,12 +1243,22 @@ |
330 | if (touch_action == mir_touch_action_up || |
331 | touch_action == mir_touch_action_down) |
332 | { |
333 | - last_input_event_timestamp = mir_input_event_get_event_time(iev); |
334 | + update_event_timestamp(mir_touch_event_input_event(tev)); |
335 | break; |
336 | } |
337 | } |
338 | } |
339 | |
340 | +void miral::BasicWindowManager::update_event_timestamp(MirInputEvent const* iev) |
341 | +{ |
342 | + last_input_event_timestamp = mir_input_event_get_event_time(iev); |
343 | +#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
344 | + if (last_input_event) |
345 | + mir_event_unref(last_input_event); |
346 | + last_input_event = mir_event_ref(mir_input_event_get_event(iev)); |
347 | +#endif |
348 | +} |
349 | + |
350 | void miral::BasicWindowManager::invoke_under_lock(std::function<void()> const& callback) |
351 | { |
352 | Locker lock{this}; |
353 | |
354 | === modified file 'miral/basic_window_manager.h' |
355 | --- miral/basic_window_manager.h 2017-03-21 12:30:42 +0000 |
356 | +++ miral/basic_window_manager.h 2017-04-13 15:18:28 +0000 |
357 | @@ -46,6 +46,7 @@ |
358 | namespace miral |
359 | { |
360 | class WorkspacePolicy; |
361 | +class WindowManagementPolicyAddendum2; |
362 | using mir::shell::SurfaceSet; |
363 | using WindowManagementPolicyBuilder = |
364 | std::function<std::unique_ptr<miral::WindowManagementPolicy>(miral::WindowManagerTools const& tools)>; |
365 | @@ -61,6 +62,7 @@ |
366 | std::shared_ptr<mir::shell::DisplayLayout> const& display_layout, |
367 | std::shared_ptr<mir::shell::PersistentSurfaceStore> const& persistent_surface_store, |
368 | WindowManagementPolicyBuilder const& build); |
369 | + ~BasicWindowManager(); |
370 | |
371 | void add_session(std::shared_ptr<mir::scene::Session> const& session) override; |
372 | |
373 | @@ -101,6 +103,11 @@ |
374 | std::shared_ptr<mir::scene::Session> const& session, |
375 | std::shared_ptr<mir::scene::Surface> const& surface, |
376 | uint64_t timestamp) override; |
377 | + |
378 | + void handle_request_move( |
379 | + std::shared_ptr<mir::scene::Session> const& session, |
380 | + std::shared_ptr<mir::scene::Surface> const& surface, |
381 | + uint64_t timestamp) override; |
382 | #endif |
383 | |
384 | int set_surface_attribute( |
385 | @@ -161,6 +168,8 @@ |
386 | auto active_display() -> mir::geometry::Rectangle const override; |
387 | |
388 | void raise_tree(Window const& root) override; |
389 | + void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) override; |
390 | + void end_drag_and_drop() override; |
391 | |
392 | void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override; |
393 | |
394 | @@ -190,6 +199,7 @@ |
395 | |
396 | std::unique_ptr<WindowManagementPolicy> const policy; |
397 | WorkspacePolicy* const workspace_policy; |
398 | + WindowManagementPolicyAddendum2* const policy2; |
399 | |
400 | std::mutex mutex; |
401 | SessionInfoMap app_info; |
402 | @@ -197,6 +207,9 @@ |
403 | mir::geometry::Rectangles displays; |
404 | mir::geometry::Point cursor; |
405 | uint64_t last_input_event_timestamp{0}; |
406 | +#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
407 | + MirEvent const* last_input_event{nullptr}; |
408 | +#endif |
409 | miral::MRUWindowList mru_active_windows; |
410 | using FullscreenSurfaces = std::set<Window>; |
411 | FullscreenSurfaces fullscreen_surfaces; |
412 | @@ -213,6 +226,7 @@ |
413 | void update_event_timestamp(MirKeyboardEvent const* kev); |
414 | void update_event_timestamp(MirPointerEvent const* pev); |
415 | void update_event_timestamp(MirTouchEvent const* tev); |
416 | + void update_event_timestamp(MirInputEvent const* iev); |
417 | |
418 | auto can_activate_window_for_session(miral::Application const& session) -> bool; |
419 | auto can_activate_window_for_session_in_workspace( |
420 | |
421 | === modified file 'miral/symbols.map' |
422 | --- miral/symbols.map 2017-03-15 17:44:36 +0000 |
423 | +++ miral/symbols.map 2017-04-13 15:18:28 +0000 |
424 | @@ -401,3 +401,24 @@ |
425 | vtable?for?miral::SetWindowManagementPolicy; |
426 | }; |
427 | } MIRAL_1.3; |
428 | + |
429 | +MIRAL_1.4.0 { |
430 | +global: |
431 | + extern "C++" { |
432 | + miral::WindowManagementPolicyAddendum2::?WindowManagementPolicyAddendum2*; |
433 | + miral::WindowManagementPolicyAddendum2::WindowManagementPolicyAddendum2*; |
434 | + miral::WindowManagementPolicyAddendum2::operator*; |
435 | + miral::WindowManagerTools::end_drag_and_drop*; |
436 | + miral::WindowManagerTools::start_drag_and_drop*; |
437 | + miral::toolkit::Window::Window*; |
438 | + non-virtual?thunk?to?miral::WindowManagementPolicyAddendum2::?WindowManagementPolicyAddendum2*; |
439 | + typeinfo?for?miral::WindowManagementPolicyAddendum2; |
440 | + typeinfo?for?miral::toolkit::Window; |
441 | + typeinfo?for?miral::toolkit::WindowId; |
442 | + typeinfo?for?miral::toolkit::WindowSpec; |
443 | + vtable?for?miral::WindowManagementPolicyAddendum2; |
444 | + vtable?for?miral::toolkit::Window; |
445 | + vtable?for?miral::toolkit::WindowId; |
446 | + vtable?for?miral::toolkit::WindowSpec; |
447 | + }; |
448 | +} MIRAL_1.3.1; |
449 | |
450 | === modified file 'miral/window_management_trace.cpp' |
451 | --- miral/window_management_trace.cpp 2017-03-03 10:06:02 +0000 |
452 | +++ miral/window_management_trace.cpp 2017-04-13 15:18:28 +0000 |
453 | @@ -547,6 +547,24 @@ |
454 | } |
455 | MIRAL_TRACE_EXCEPTION |
456 | |
457 | +void miral::WindowManagementTrace::start_drag_and_drop(miral::WindowInfo& window_info, std::vector<uint8_t> const& handle) |
458 | +try { |
459 | + log_input(); |
460 | + mir::log_info("%s window_info=%s", __func__, dump_of(window_info).c_str()); |
461 | + trace_count++; |
462 | + wrapped.start_drag_and_drop(window_info, handle); |
463 | +} |
464 | +MIRAL_TRACE_EXCEPTION |
465 | + |
466 | +void miral::WindowManagementTrace::end_drag_and_drop() |
467 | +try { |
468 | + log_input(); |
469 | + mir::log_info("%s window_info=%s", __func__); |
470 | + trace_count++; |
471 | + wrapped.end_drag_and_drop(); |
472 | +} |
473 | +MIRAL_TRACE_EXCEPTION |
474 | + |
475 | void miral::WindowManagementTrace::modify_window( |
476 | miral::WindowInfo& window_info, miral::WindowSpecification const& modifications) |
477 | try { |
478 | |
479 | === modified file 'miral/window_management_trace.h' |
480 | --- miral/window_management_trace.h 2017-03-02 14:29:04 +0000 |
481 | +++ miral/window_management_trace.h 2017-04-13 15:18:28 +0000 |
482 | @@ -69,6 +69,8 @@ |
483 | virtual void focus_prev_within_application() override; |
484 | |
485 | virtual void raise_tree(Window const& root) override; |
486 | + virtual void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) override; |
487 | + virtual void end_drag_and_drop() override; |
488 | |
489 | virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override; |
490 | |
491 | |
492 | === modified file 'miral/window_manager_tools.cpp' |
493 | --- miral/window_manager_tools.cpp 2017-03-02 14:29:04 +0000 |
494 | +++ miral/window_manager_tools.cpp 2017-04-13 15:18:28 +0000 |
495 | @@ -83,6 +83,12 @@ |
496 | void miral::WindowManagerTools::raise_tree(Window const& root) |
497 | { tools->raise_tree(root); } |
498 | |
499 | +void miral::WindowManagerTools::start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) |
500 | +{ tools->start_drag_and_drop(window_info, handle); } |
501 | + |
502 | +void miral::WindowManagerTools::end_drag_and_drop() |
503 | +{ tools->end_drag_and_drop(); } |
504 | + |
505 | void miral::WindowManagerTools::modify_window(WindowInfo& window_info, WindowSpecification const& modifications) |
506 | { tools->modify_window(window_info,modifications); } |
507 | |
508 | |
509 | === modified file 'miral/window_manager_tools_implementation.h' |
510 | --- miral/window_manager_tools_implementation.h 2017-03-02 14:29:04 +0000 |
511 | +++ miral/window_manager_tools_implementation.h 2017-04-13 15:18:28 +0000 |
512 | @@ -26,6 +26,7 @@ |
513 | |
514 | #include <functional> |
515 | #include <memory> |
516 | +#include <vector> |
517 | |
518 | namespace mir { namespace scene { class Surface; } } |
519 | |
520 | @@ -66,6 +67,8 @@ |
521 | virtual auto window_at(mir::geometry::Point cursor) const -> Window = 0; |
522 | virtual auto active_display() -> mir::geometry::Rectangle const = 0; |
523 | virtual void raise_tree(Window const& root) = 0; |
524 | + virtual void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) = 0; |
525 | + virtual void end_drag_and_drop() = 0; |
526 | virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) = 0; |
527 | virtual auto info_for_window_id(std::string const& id) const -> WindowInfo& = 0; |
528 | virtual auto id_for_window(Window const& window) const -> std::string = 0; |
529 | |
530 | === modified file 'scripts/process_doxygen_xml.py' |
531 | --- scripts/process_doxygen_xml.py 2017-03-15 17:44:36 +0000 |
532 | +++ scripts/process_doxygen_xml.py 2017-04-13 15:18:28 +0000 |
533 | @@ -476,10 +476,21 @@ |
534 | |
535 | MIRAL_1.3.1 { |
536 | global: |
537 | + extern "C++" { |
538 | + miral::SetWindowManagementPolicy::?SetWindowManagementPolicy*; |
539 | + miral::SetWindowManagementPolicy::SetWindowManagementPolicy*; |
540 | + miral::SetWindowManagementPolicy::operator*; |
541 | + typeinfo?for?miral::SetWindowManagementPolicy; |
542 | + vtable?for?miral::SetWindowManagementPolicy; |
543 | + }; |
544 | +} MIRAL_1.3; |
545 | + |
546 | +MIRAL_1.4.0 { |
547 | +global: |
548 | extern "C++" {''' |
549 | |
550 | END_NEW_STANZA = ''' }; |
551 | -} MIRAL_1.3;''' |
552 | +} MIRAL_1.3.1;''' |
553 | |
554 | def _print_report(): |
555 | print OLD_STANZAS |
556 | |
557 | === modified file 'test/CMakeLists.txt' |
558 | --- test/CMakeLists.txt 2017-02-13 16:23:29 +0000 |
559 | +++ test/CMakeLists.txt 2017-04-13 15:18:28 +0000 |
560 | @@ -39,6 +39,16 @@ |
561 | ${GTEST_INCLUDE_DIR} |
562 | ) |
563 | |
564 | +# MIRAL_TEST_MODERN_FEATURES lists test sourcefiles that require a recent version of Mir |
565 | +if (MIRTEST_VERSION VERSION_LESS 0.27) |
566 | + set(MIRAL_TEST_MODERN_FEATURES) |
567 | +else() |
568 | + set(MIRAL_TEST_MODERN_FEATURES |
569 | + drag_and_drop.cpp |
570 | + client_mediated_gestures.cpp |
571 | + ) |
572 | +endif() |
573 | + |
574 | add_executable(miral-test |
575 | mru_window_list.cpp |
576 | active_outputs.cpp |
577 | @@ -56,7 +66,9 @@ |
578 | display_reconfiguration.cpp |
579 | active_window.cpp |
580 | raise_tree.cpp |
581 | - workspaces.cpp) |
582 | + workspaces.cpp |
583 | + ${MIRAL_TEST_MODERN_FEATURES} |
584 | +) |
585 | |
586 | target_link_libraries(miral-test |
587 | ${MIRTEST_LDFLAGS} |
588 | |
589 | === added file 'test/client_mediated_gestures.cpp' |
590 | --- test/client_mediated_gestures.cpp 1970-01-01 00:00:00 +0000 |
591 | +++ test/client_mediated_gestures.cpp 2017-04-13 15:18:28 +0000 |
592 | @@ -0,0 +1,285 @@ |
593 | +/* |
594 | + * Copyright © 2017 Canonical Ltd. |
595 | + * |
596 | + * This program is free software: you can redistribute it and/or modify it |
597 | + * under the terms of the GNU General Public License version 3, |
598 | + * as published by the Free Software Foundation. |
599 | + * |
600 | + * This program is distributed in the hope that it will be useful, |
601 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
602 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
603 | + * GNU General Public License for more details. |
604 | + * |
605 | + * You should have received a copy of the GNU General Public License |
606 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
607 | + * |
608 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
609 | + */ |
610 | + |
611 | +#include <mir_toolkit/mir_window.h> |
612 | +#include <mir_toolkit/mir_blob.h> |
613 | + |
614 | +#include <mir/geometry/displacement.h> |
615 | +#include <mir/input/input_device_info.h> |
616 | +#include <mir/input/device_capability.h> |
617 | +#include <mir/shell/canonical_window_manager.h> |
618 | +#include <mir/shell/shell.h> |
619 | + |
620 | +#include <mir_test_framework/connected_client_with_a_window.h> |
621 | +#include <mir_test_framework/fake_input_device.h> |
622 | +#include <mir_test_framework/stub_server_platform_factory.h> |
623 | +#include <mir/test/event_factory.h> |
624 | +#include <mir/test/fake_shared.h> |
625 | +#include <mir/test/signal.h> |
626 | + |
627 | +#include <gmock/gmock.h> |
628 | +#include <gtest/gtest.h> |
629 | + |
630 | +#include <linux/input.h> |
631 | + |
632 | +#include <atomic> |
633 | + |
634 | +using namespace std::chrono_literals; |
635 | +using namespace mir::geometry; |
636 | +using namespace testing; |
637 | +using mir::test::fake_shared; |
638 | +using mir::test::Signal; |
639 | + |
640 | +namespace |
641 | +{ |
642 | +class Cookie |
643 | +{ |
644 | +public: |
645 | + Cookie() = default; |
646 | + |
647 | + explicit Cookie(MirCookie const* cookie) : self{cookie, deleter} {} |
648 | + |
649 | + operator MirCookie const*() const { return self.get(); } |
650 | + |
651 | + auto get() const -> MirCookie const* { return self.get(); } |
652 | + |
653 | + void reset() { self.reset(); } |
654 | + |
655 | + void reset(MirCookie const* cookie) { self.reset(cookie, deleter); } |
656 | + |
657 | +private: |
658 | + static void deleter(MirCookie const* cookie) { mir_cookie_release(cookie); } |
659 | + |
660 | + std::shared_ptr<MirCookie const> self; |
661 | +}; |
662 | + |
663 | +void mir_cookie_release(Cookie const&) = delete; |
664 | + |
665 | +#pragma GCC diagnostic push |
666 | +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
667 | +struct MockWindowManager : mir::shell::CanonicalWindowManager |
668 | +{ |
669 | + using mir::shell::CanonicalWindowManager::CanonicalWindowManager; |
670 | + |
671 | + MOCK_METHOD3(handle_request_move, |
672 | + void(std::shared_ptr<mir::scene::Session> const&, std::shared_ptr<mir::scene::Surface> const&, uint64_t)); |
673 | +}; |
674 | +#pragma GCC diagnostic pop |
675 | + |
676 | +struct MouseMoverAndFaker |
677 | +{ |
678 | + void start_dragging_mouse() |
679 | + { |
680 | + using namespace mir::input::synthesis; |
681 | + fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT)); |
682 | + } |
683 | + |
684 | + void move_mouse(Displacement const& displacement) |
685 | + { |
686 | + using mir::input::synthesis::a_pointer_event; |
687 | + fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int())); |
688 | + } |
689 | + |
690 | + void release_mouse() |
691 | + { |
692 | + using namespace mir::input::synthesis; |
693 | + fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT)); |
694 | + } |
695 | + |
696 | +private: |
697 | + std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{ |
698 | + mir_test_framework::add_fake_input_device( |
699 | + mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer}) |
700 | + }; |
701 | +}; |
702 | + |
703 | +Rectangle const screen_geometry{{0, 0}, {800, 600}}; |
704 | +auto const receive_event_timeout = 90s; |
705 | + |
706 | +struct ClientMediatedUserGestures : mir_test_framework::ConnectedClientWithAWindow, |
707 | + MouseMoverAndFaker |
708 | +{ |
709 | + void SetUp() override |
710 | + { |
711 | + initial_display_layout({screen_geometry}); |
712 | + server.override_the_window_manager_builder([this](mir::shell::FocusController* focus_controller) |
713 | + { |
714 | + return window_manager = |
715 | + std::make_shared<MockWindowManager>(focus_controller, server.the_shell_display_layout()); |
716 | + }); |
717 | + |
718 | + mir_test_framework::ConnectedClientWithAWindow::SetUp(); |
719 | + mir_window_set_event_handler(window, &window_event_handler, this); |
720 | + |
721 | + paint_window(); |
722 | + |
723 | + center_mouse(); |
724 | + } |
725 | + |
726 | + void TearDown() override |
727 | + { |
728 | + reset_window_event_handler(); |
729 | + window_manager.reset(); |
730 | + mir_test_framework::ConnectedClientWithAWindow::TearDown(); |
731 | + } |
732 | + |
733 | + auto user_initiates_gesture() -> Cookie; |
734 | + |
735 | + std::shared_ptr<MockWindowManager> window_manager; |
736 | + |
737 | +private: |
738 | + void center_mouse(); |
739 | + void paint_window(); |
740 | + void set_window_event_handler(std::function<void(MirEvent const* event)> const& handler); |
741 | + void reset_window_event_handler(); |
742 | + void invoke_window_event_handler(MirEvent const* event) |
743 | + { |
744 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
745 | + window_event_handler_(event); |
746 | + } |
747 | + |
748 | + std::mutex window_event_handler_mutex; |
749 | + std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {}; |
750 | + |
751 | + static void window_event_handler(MirWindow* window, MirEvent const* event, void* context); |
752 | +}; |
753 | + |
754 | +void ClientMediatedUserGestures::set_window_event_handler(std::function<void(MirEvent const* event)> const& handler) |
755 | +{ |
756 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
757 | + window_event_handler_ = handler; |
758 | +} |
759 | + |
760 | +void ClientMediatedUserGestures::reset_window_event_handler() |
761 | +{ |
762 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
763 | + window_event_handler_ = [](MirEvent const*) {}; |
764 | +} |
765 | + |
766 | +void ClientMediatedUserGestures::window_event_handler(MirWindow* /*window*/, MirEvent const* event, void* context) |
767 | +{ |
768 | + static_cast<ClientMediatedUserGestures*>(context)->invoke_window_event_handler(event); |
769 | +} |
770 | + |
771 | +void ClientMediatedUserGestures::paint_window() |
772 | +{ |
773 | + Signal have_focus; |
774 | + |
775 | + set_window_event_handler([&](MirEvent const* event) |
776 | + { |
777 | + if (mir_event_get_type(event) != mir_event_type_window) |
778 | + return; |
779 | + |
780 | + auto const window_event = mir_event_get_window_event(event); |
781 | + if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus) |
782 | + return; |
783 | + |
784 | + if (mir_window_event_get_attribute_value(window_event)) |
785 | + have_focus.raise(); |
786 | + }); |
787 | + |
788 | + mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(window)); |
789 | + |
790 | + EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true)); |
791 | + |
792 | + reset_window_event_handler(); |
793 | +} |
794 | + |
795 | +void ClientMediatedUserGestures::center_mouse() |
796 | +{ |
797 | + Signal have_mouseover; |
798 | + |
799 | + set_window_event_handler([&](MirEvent const* event) |
800 | + { |
801 | + if (mir_event_get_type(event) != mir_event_type_input) |
802 | + return; |
803 | + |
804 | + auto const input_event = mir_event_get_input_event(event); |
805 | + |
806 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
807 | + return; |
808 | + |
809 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
810 | + |
811 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) |
812 | + return; |
813 | + |
814 | + have_mouseover.raise(); |
815 | + }); |
816 | + |
817 | + move_mouse(0.5 * as_displacement(screen_geometry.size)); |
818 | + |
819 | +// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20). |
820 | +// But it isn't essential for the test and we've probably waited long enough |
821 | +// for the mouse-down needed by the test to reach the window. |
822 | +// EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true)); |
823 | + have_mouseover.wait_for(receive_event_timeout); |
824 | + |
825 | + reset_window_event_handler(); |
826 | +} |
827 | + |
828 | +auto ClientMediatedUserGestures::user_initiates_gesture() -> Cookie |
829 | +{ |
830 | + Cookie cookie; |
831 | + Signal have_cookie; |
832 | + |
833 | + set_window_event_handler([&](MirEvent const* event) |
834 | + { |
835 | + if (mir_event_get_type(event) != mir_event_type_input) |
836 | + return; |
837 | + |
838 | + auto const input_event = mir_event_get_input_event(event); |
839 | + |
840 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
841 | + return; |
842 | + |
843 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
844 | + |
845 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down) |
846 | + return; |
847 | + |
848 | + cookie = Cookie{mir_input_event_get_cookie(input_event)}; |
849 | + have_cookie.raise(); |
850 | + }); |
851 | + |
852 | + start_dragging_mouse(); |
853 | + |
854 | + EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true)); |
855 | + |
856 | + reset_window_event_handler(); |
857 | + return cookie; |
858 | +} |
859 | +} |
860 | + |
861 | +TEST_F(ClientMediatedUserGestures, when_user_initiates_gesture_client_receives_cookie) |
862 | +{ |
863 | + auto const cookie = user_initiates_gesture(); |
864 | + |
865 | + EXPECT_THAT(cookie.get(), NotNull()); |
866 | +} |
867 | + |
868 | +TEST_F(ClientMediatedUserGestures, when_client_initiates_move_window_manager_handles_request) |
869 | +{ |
870 | + auto const cookie = user_initiates_gesture(); |
871 | + Signal have_request; |
872 | + EXPECT_CALL(*window_manager, handle_request_move(_, _, _)).WillOnce(InvokeWithoutArgs([&]{ have_request.raise(); })); |
873 | + |
874 | + mir_window_request_user_move(window, cookie); |
875 | + |
876 | + EXPECT_THAT(have_request.wait_for(receive_event_timeout), Eq(true)); |
877 | +} |
878 | |
879 | === added file 'test/drag_and_drop.cpp' |
880 | --- test/drag_and_drop.cpp 1970-01-01 00:00:00 +0000 |
881 | +++ test/drag_and_drop.cpp 2017-04-13 15:18:28 +0000 |
882 | @@ -0,0 +1,641 @@ |
883 | +/* |
884 | + * Copyright © 2017 Canonical Ltd. |
885 | + * |
886 | + * This program is free software: you can redistribute it and/or modify it |
887 | + * under the terms of the GNU General Public License version 3, |
888 | + * as published by the Free Software Foundation. |
889 | + * |
890 | + * This program is distributed in the hope that it will be useful, |
891 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
892 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
893 | + * GNU General Public License for more details. |
894 | + * |
895 | + * You should have received a copy of the GNU General Public License |
896 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
897 | + * |
898 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
899 | + */ |
900 | + |
901 | +#include <miral/window_management_policy_addendum2.h> |
902 | + |
903 | +#include <mir/client/blob.h> |
904 | +#include <mir/client/cookie.h> |
905 | +#include <mir/client/window.h> |
906 | +#include <mir/client/window_spec.h> |
907 | +#include <mir_toolkit/mir_buffer_stream.h> |
908 | +#include <mir_toolkit/extensions/drag_and_drop.h> |
909 | + |
910 | +#include <mir/geometry/displacement.h> |
911 | +#include <mir/input/input_device_info.h> |
912 | +#include <mir/input/device_capability.h> |
913 | +#include <mir/shell/shell.h> |
914 | + |
915 | +#include "test_server.h" |
916 | +#include <mir_test_framework/fake_input_device.h> |
917 | +#include <mir_test_framework/stub_server_platform_factory.h> |
918 | +#include <mir/test/event_factory.h> |
919 | +#include <mir/test/signal.h> |
920 | + |
921 | +#include <gmock/gmock.h> |
922 | +#include <gtest/gtest.h> |
923 | + |
924 | +#include <linux/input.h> |
925 | +#include <uuid/uuid.h> |
926 | + |
927 | +#include <boost/throw_exception.hpp> |
928 | +#include <atomic> |
929 | + |
930 | +using namespace std::chrono_literals; |
931 | +using namespace mir::client; |
932 | +using namespace mir::geometry; |
933 | +using namespace testing; |
934 | +using mir::test::Signal; |
935 | + |
936 | +namespace |
937 | +{ |
938 | +struct MouseMoverAndFaker |
939 | +{ |
940 | + void start_dragging_mouse() |
941 | + { |
942 | + using namespace mir::input::synthesis; |
943 | + fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT)); |
944 | + } |
945 | + |
946 | + void move_mouse(Displacement const& displacement) |
947 | + { |
948 | + using mir::input::synthesis::a_pointer_event; |
949 | + fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int())); |
950 | + } |
951 | + |
952 | + void release_mouse() |
953 | + { |
954 | + using namespace mir::input::synthesis; |
955 | + fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT)); |
956 | + } |
957 | + |
958 | +private: |
959 | + std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{ |
960 | + mir_test_framework::add_fake_input_device( |
961 | + mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer})}; |
962 | +}; |
963 | + |
964 | +Rectangle const screen_geometry{{0,0}, {800,600}}; |
965 | +auto const receive_event_timeout = 1s; //90s; |
966 | + |
967 | +struct ConnectedClientWithAWindow : miral::TestServer |
968 | +{ |
969 | + Connection connection; |
970 | + Window window; |
971 | + |
972 | + void SetUp() override |
973 | + { |
974 | + miral::TestServer::SetUp(); |
975 | + connection = connect_client(__func__); |
976 | + window = WindowSpec::for_normal_window(connection, surface_size.width.as_int(), surface_size.height.as_int()) |
977 | + .set_pixel_format(mir_pixel_format_abgr_8888) |
978 | + .set_name("ConnectedClientWithAWindow") |
979 | + .set_buffer_usage(mir_buffer_usage_hardware) |
980 | + .create_window(); |
981 | + } |
982 | + |
983 | + void TearDown() override |
984 | + { |
985 | + window.reset(); |
986 | + connection.reset(); |
987 | + miral::TestServer::TearDown(); |
988 | + } |
989 | + |
990 | + mir::geometry::Size const surface_size {640, 480}; |
991 | +}; |
992 | + |
993 | +struct DragAndDrop : ConnectedClientWithAWindow, |
994 | + MouseMoverAndFaker |
995 | +{ |
996 | + MirDragAndDropV1 const* dnd = nullptr; |
997 | + |
998 | + void SetUp() override |
999 | + { |
1000 | + mir_test_framework::set_next_display_rects(std::unique_ptr<std::vector<Rectangle>>(new std::vector<Rectangle>({screen_geometry}))); |
1001 | + |
1002 | + ConnectedClientWithAWindow::SetUp(); |
1003 | + dnd = mir_drag_and_drop_v1(connection); |
1004 | + mir_window_set_event_handler(window, &window_event_handler, this); |
1005 | + if (dnd) dnd->set_start_drag_and_drop_callback(window, &window_dnd_start_handler, this); |
1006 | + |
1007 | + create_target_window(); |
1008 | + |
1009 | + paint_window(window); |
1010 | + |
1011 | + center_mouse(); |
1012 | + } |
1013 | + |
1014 | + void TearDown() override |
1015 | + { |
1016 | + reset_window_event_handler(target_window); |
1017 | + reset_window_event_handler(window); |
1018 | + target_window.reset(); |
1019 | + another_connection.reset(); |
1020 | + ConnectedClientWithAWindow::TearDown(); |
1021 | + } |
1022 | + |
1023 | + auto user_initiates_drag() -> Cookie; |
1024 | + auto client_requests_drag(Cookie const& cookie) -> Blob; |
1025 | + auto handle_from_mouse_move() -> Blob; |
1026 | + auto handle_from_mouse_leave() -> Blob; |
1027 | + auto handle_from_mouse_enter() -> Blob; |
1028 | + auto handle_from_mouse_release() -> Blob; |
1029 | + auto count_of_handles_when_moving_mouse() -> int; |
1030 | + |
1031 | +private: |
1032 | + auto build_window_manager_policy(miral::WindowManagerTools const& tools) -> std::unique_ptr<TestWindowManagerPolicy> override; |
1033 | + void center_mouse(); |
1034 | + void paint_window(MirWindow* w); |
1035 | + void set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler); |
1036 | + void set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler); |
1037 | + void reset_window_event_handler(MirWindow* window); |
1038 | + |
1039 | + void create_target_window() |
1040 | + { |
1041 | + another_connection = connect_client("another_connection"); |
1042 | + target_window = WindowSpec:: |
1043 | + for_normal_window(connection, screen_geometry.size.width.as_int(), screen_geometry.size.height.as_int()) |
1044 | + .set_pixel_format(mir_pixel_format_abgr_8888) |
1045 | + .set_name("target_window") |
1046 | + .set_buffer_usage(mir_buffer_usage_hardware) |
1047 | + .set_event_handler(&window_event_handler, this) |
1048 | + .create_window(); |
1049 | + |
1050 | + paint_window(target_window); |
1051 | + } |
1052 | + |
1053 | + void invoke_window_event_handler(MirWindow* window, MirEvent const* event) |
1054 | + { |
1055 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
1056 | + if (window == this->window) window_event_handler_(event); |
1057 | + if (window == target_window) target_window_event_handler_(event); |
1058 | + } |
1059 | + |
1060 | + void invoke_window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event) |
1061 | + { |
1062 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
1063 | + if (window == this->window) window_dnd_start_(event); |
1064 | + } |
1065 | + |
1066 | + std::mutex window_event_handler_mutex; |
1067 | + std::function<void(MirDragAndDropEvent const* event)> window_dnd_start_ = [](MirDragAndDropEvent const*) {}; |
1068 | + std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {}; |
1069 | + std::function<void(MirEvent const* event)> target_window_event_handler_ = [](MirEvent const*) {}; |
1070 | + |
1071 | + static void window_event_handler(MirWindow* window, MirEvent const* event, void* context); |
1072 | + static void window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context); |
1073 | + |
1074 | + Connection another_connection; |
1075 | + Window target_window; |
1076 | +}; |
1077 | + |
1078 | +void DragAndDrop::set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler) |
1079 | +{ |
1080 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
1081 | + if (window == this->window) window_event_handler_ = handler; |
1082 | + if (window == target_window) target_window_event_handler_ = handler; |
1083 | +} |
1084 | + |
1085 | +void DragAndDrop::set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler) |
1086 | +{ |
1087 | +std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
1088 | +if (window == this->window) window_dnd_start_ = handler; |
1089 | +} |
1090 | + |
1091 | + |
1092 | +void DragAndDrop::reset_window_event_handler(MirWindow* window) |
1093 | +{ |
1094 | + if (window == this->window) window_event_handler_ = [](MirEvent const*) {}; |
1095 | + if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {}; |
1096 | +} |
1097 | + |
1098 | +void DragAndDrop::paint_window(MirWindow* w) |
1099 | +{ |
1100 | + Signal have_focus; |
1101 | + |
1102 | + set_window_event_handler(w, [&](MirEvent const* event) |
1103 | + { |
1104 | + if (mir_event_get_type(event) != mir_event_type_window) |
1105 | + return; |
1106 | + |
1107 | + auto const window_event = mir_event_get_window_event(event); |
1108 | + if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus) |
1109 | + return; |
1110 | + |
1111 | + if (mir_window_event_get_attribute_value(window_event)) |
1112 | + have_focus.raise(); |
1113 | + }); |
1114 | + |
1115 | + mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(w)); |
1116 | + |
1117 | + EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true)); |
1118 | + |
1119 | + reset_window_event_handler(w); |
1120 | +} |
1121 | + |
1122 | +void DragAndDrop::center_mouse() |
1123 | +{ |
1124 | + Signal have_mouseover; |
1125 | + |
1126 | + set_window_event_handler(window, [&](MirEvent const* event) |
1127 | + { |
1128 | + if (mir_event_get_type(event) != mir_event_type_input) |
1129 | + return; |
1130 | + |
1131 | + auto const input_event = mir_event_get_input_event(event); |
1132 | + |
1133 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
1134 | + return; |
1135 | + |
1136 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
1137 | + |
1138 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) |
1139 | + return; |
1140 | + |
1141 | + have_mouseover.raise(); |
1142 | + }); |
1143 | + |
1144 | + move_mouse(0.5 * as_displacement(screen_geometry.size)); |
1145 | + |
1146 | +// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20). |
1147 | +// But it isn't essential for the test and we've probably waited long enough |
1148 | +// for the mouse-down needed by the test to reach the window. |
1149 | +// EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true)); |
1150 | + have_mouseover.wait_for(receive_event_timeout); |
1151 | + |
1152 | + reset_window_event_handler(window); |
1153 | +} |
1154 | + |
1155 | +void DragAndDrop::window_event_handler(MirWindow* window, MirEvent const* event, void* context) |
1156 | +{ |
1157 | + static_cast<DragAndDrop*>(context)->invoke_window_event_handler(window, event); |
1158 | +} |
1159 | + |
1160 | +void DragAndDrop::window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context) |
1161 | +{ |
1162 | + static_cast<DragAndDrop*>(context)->invoke_window_dnd_start_handler(window, event); |
1163 | +} |
1164 | + |
1165 | + |
1166 | +auto DragAndDrop::user_initiates_drag() -> Cookie |
1167 | +{ |
1168 | + Cookie cookie; |
1169 | + Signal have_cookie; |
1170 | + |
1171 | + set_window_event_handler(window, [&](MirEvent const* event) |
1172 | + { |
1173 | + if (mir_event_get_type(event) != mir_event_type_input) |
1174 | + return; |
1175 | + |
1176 | + auto const input_event = mir_event_get_input_event(event); |
1177 | + |
1178 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
1179 | + return; |
1180 | + |
1181 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
1182 | + |
1183 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down) |
1184 | + return; |
1185 | + |
1186 | + cookie = Cookie{mir_input_event_get_cookie(input_event)}; |
1187 | + have_cookie.raise(); |
1188 | + }); |
1189 | + |
1190 | + start_dragging_mouse(); |
1191 | + |
1192 | + EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true)); |
1193 | + |
1194 | + reset_window_event_handler(window); |
1195 | + return cookie; |
1196 | +} |
1197 | + |
1198 | +auto DragAndDrop::client_requests_drag(Cookie const& cookie) -> Blob |
1199 | +{ |
1200 | + Blob blob; |
1201 | + Signal initiated; |
1202 | + |
1203 | + set_window_dnd_start_handler(window, [&](MirDragAndDropEvent const* event) |
1204 | + { |
1205 | + if (dnd) |
1206 | + blob.reset(dnd->start_drag_and_drop(event)); |
1207 | + |
1208 | + if (blob) |
1209 | + initiated.raise(); |
1210 | + }); |
1211 | + |
1212 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
1213 | + |
1214 | + if (dnd) |
1215 | + dnd->request_drag_and_drop(window, cookie); |
1216 | + |
1217 | + EXPECT_TRUE(initiated.wait_for(receive_event_timeout)); |
1218 | + |
1219 | + reset_window_event_handler(window); |
1220 | + return blob; |
1221 | +} |
1222 | + |
1223 | +auto DragAndDrop::handle_from_mouse_move() -> Blob |
1224 | +{ |
1225 | + Blob blob; |
1226 | + Signal have_blob; |
1227 | + |
1228 | + set_window_event_handler(window, [&](MirEvent const* event) |
1229 | + { |
1230 | + if (mir_event_get_type(event) != mir_event_type_input) |
1231 | + return; |
1232 | + |
1233 | + auto const input_event = mir_event_get_input_event(event); |
1234 | + |
1235 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
1236 | + return; |
1237 | + |
1238 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
1239 | + |
1240 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
1241 | + |
1242 | + if (dnd) |
1243 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
1244 | + |
1245 | + if (blob) |
1246 | + have_blob.raise(); |
1247 | + }); |
1248 | + |
1249 | + move_mouse({1,1}); |
1250 | + |
1251 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
1252 | + |
1253 | + reset_window_event_handler(window); |
1254 | + return blob; |
1255 | +} |
1256 | + |
1257 | +auto DragAndDrop::handle_from_mouse_leave() -> Blob |
1258 | +{ |
1259 | + Blob blob; |
1260 | + Signal have_blob; |
1261 | + |
1262 | + set_window_event_handler(window, [&](MirEvent const* event) |
1263 | + { |
1264 | + if (mir_event_get_type(event) != mir_event_type_input) |
1265 | + return; |
1266 | + |
1267 | + auto const input_event = mir_event_get_input_event(event); |
1268 | + |
1269 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
1270 | + return; |
1271 | + |
1272 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
1273 | + |
1274 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_leave) |
1275 | + return; |
1276 | + |
1277 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
1278 | + |
1279 | + if (dnd) |
1280 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
1281 | + |
1282 | + if (blob) |
1283 | + have_blob.raise(); |
1284 | + }); |
1285 | + |
1286 | + move_mouse({1,1}); |
1287 | + move_mouse(0.5 * as_displacement(surface_size)); |
1288 | + |
1289 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
1290 | + |
1291 | + reset_window_event_handler(window); |
1292 | + return blob; |
1293 | +} |
1294 | + |
1295 | +auto DragAndDrop::handle_from_mouse_enter() -> Blob |
1296 | +{ |
1297 | + Blob blob; |
1298 | + Signal have_blob; |
1299 | + |
1300 | + set_window_event_handler(target_window, [&](MirEvent const* event) |
1301 | + { |
1302 | + if (mir_event_get_type(event) != mir_event_type_input) |
1303 | + return; |
1304 | + |
1305 | + auto const input_event = mir_event_get_input_event(event); |
1306 | + |
1307 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
1308 | + return; |
1309 | + |
1310 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
1311 | + |
1312 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) |
1313 | + return; |
1314 | + |
1315 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
1316 | + |
1317 | + if (dnd) |
1318 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
1319 | + |
1320 | + if (blob) |
1321 | + have_blob.raise(); |
1322 | + }); |
1323 | + |
1324 | + move_mouse({1,1}); |
1325 | + move_mouse(0.5 * as_displacement(surface_size)); |
1326 | + |
1327 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
1328 | + |
1329 | + reset_window_event_handler(target_window); |
1330 | + return blob; |
1331 | +} |
1332 | + |
1333 | +auto DragAndDrop::handle_from_mouse_release() -> Blob |
1334 | +{ |
1335 | + Blob blob; |
1336 | + Signal have_blob; |
1337 | + |
1338 | + set_window_event_handler(target_window, [&](MirEvent const* event) |
1339 | + { |
1340 | + if (mir_event_get_type(event) != mir_event_type_input) |
1341 | + return; |
1342 | + |
1343 | + auto const input_event = mir_event_get_input_event(event); |
1344 | + |
1345 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
1346 | + return; |
1347 | + |
1348 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
1349 | + |
1350 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_up) |
1351 | + return; |
1352 | + |
1353 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
1354 | + |
1355 | + if (dnd) |
1356 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
1357 | + |
1358 | + if (blob) |
1359 | + have_blob.raise(); |
1360 | + }); |
1361 | + |
1362 | + move_mouse({1,1}); |
1363 | + move_mouse(0.5 * as_displacement(surface_size)); |
1364 | + release_mouse(); |
1365 | + |
1366 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
1367 | + |
1368 | + reset_window_event_handler(target_window); |
1369 | + return blob; |
1370 | +} |
1371 | + |
1372 | +auto DragAndDrop::count_of_handles_when_moving_mouse() -> int |
1373 | +{ |
1374 | + Signal have_3_events; |
1375 | + std::atomic<int> events{0}; |
1376 | + std::atomic<int> handles{0}; |
1377 | + |
1378 | + auto counter = [&](MirEvent const* event) |
1379 | + { |
1380 | + if (mir_event_get_type(event) != mir_event_type_input) |
1381 | + return; |
1382 | + |
1383 | + auto const input_event = mir_event_get_input_event(event); |
1384 | + |
1385 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
1386 | + return; |
1387 | + |
1388 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
1389 | + |
1390 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
1391 | + |
1392 | + Blob blob; |
1393 | + if (dnd) |
1394 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
1395 | + |
1396 | + if (blob) |
1397 | + handles.fetch_add(1); |
1398 | + |
1399 | + if (events.fetch_add(1) == 2) |
1400 | + have_3_events.raise(); |
1401 | + }; |
1402 | + |
1403 | + set_window_event_handler(window, counter); |
1404 | + set_window_event_handler(target_window, counter); |
1405 | + |
1406 | + start_dragging_mouse(); |
1407 | + move_mouse({1,1}); |
1408 | + release_mouse(); |
1409 | + |
1410 | + EXPECT_TRUE(have_3_events.wait_for(receive_event_timeout)); |
1411 | + |
1412 | + reset_window_event_handler(window); |
1413 | + reset_window_event_handler(target_window); |
1414 | + return handles; |
1415 | +} |
1416 | + |
1417 | +auto DragAndDrop::build_window_manager_policy(miral::WindowManagerTools const& tools) -> std::unique_ptr<TestWindowManagerPolicy> |
1418 | +{ |
1419 | + struct DnDWindowManagerPolicy : miral::TestServer::TestWindowManagerPolicy, miral::WindowManagementPolicyAddendum2 |
1420 | + { |
1421 | + using miral::TestServer::TestWindowManagerPolicy::TestWindowManagerPolicy; |
1422 | + |
1423 | + void handle_request_drag_and_drop(miral::WindowInfo& window_info) override |
1424 | + { |
1425 | + uuid_t uuid; |
1426 | + uuid_generate(uuid); |
1427 | + std::vector<uint8_t> const handle{std::begin(uuid), std::end(uuid)}; |
1428 | + |
1429 | + tools.start_drag_and_drop(window_info, handle); |
1430 | + } |
1431 | + |
1432 | + void handle_request_move(miral::WindowInfo&, MirInputEvent const*) override {} |
1433 | + }; |
1434 | + |
1435 | + return std::make_unique<DnDWindowManagerPolicy>(tools, *this); |
1436 | +} |
1437 | + |
1438 | +MATCHER_P(BlobContentEq, p, "") |
1439 | +{ |
1440 | + if (!arg || !p) |
1441 | + return false; |
1442 | + if (mir_blob_size(arg) != mir_blob_size(p)) |
1443 | + return false; |
1444 | + return !memcmp(mir_blob_data(arg), mir_blob_data(p), mir_blob_size(p)); |
1445 | +} |
1446 | +} |
1447 | + |
1448 | +TEST_F(DragAndDrop, when_user_initiates_drag_client_receives_cookie) |
1449 | +{ |
1450 | + auto const cookie = user_initiates_drag(); |
1451 | + |
1452 | + EXPECT_THAT(cookie, NotNull()); |
1453 | +} |
1454 | + |
1455 | +TEST_F(DragAndDrop, when_client_requests_drags_it_receives_handle) |
1456 | +{ |
1457 | + auto const cookie = user_initiates_drag(); |
1458 | + ASSERT_THAT(cookie, NotNull()); |
1459 | + |
1460 | + auto const handle = client_requests_drag(cookie); |
1461 | + |
1462 | + EXPECT_THAT(handle, NotNull()); |
1463 | +} |
1464 | + |
1465 | +TEST_F(DragAndDrop, during_drag_when_user_moves_mouse_client_receives_handle) |
1466 | +{ |
1467 | + auto const cookie = user_initiates_drag(); |
1468 | + ASSERT_THAT(cookie, NotNull()); |
1469 | + auto const handle_from_request = client_requests_drag(cookie); |
1470 | + |
1471 | + auto const handle = handle_from_mouse_move(); |
1472 | + |
1473 | + EXPECT_THAT(handle, NotNull()); |
1474 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1475 | +} |
1476 | + |
1477 | +TEST_F(DragAndDrop, when_drag_moves_from_window_leave_event_contains_handle) |
1478 | +{ |
1479 | + auto const cookie = user_initiates_drag(); |
1480 | + ASSERT_THAT(cookie, NotNull()); |
1481 | + auto const handle_from_request = client_requests_drag(cookie); |
1482 | + |
1483 | + auto const handle = handle_from_mouse_leave(); |
1484 | + |
1485 | + EXPECT_THAT(handle, NotNull()); |
1486 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1487 | +} |
1488 | + |
1489 | +TEST_F(DragAndDrop, when_drag_enters_target_window_enter_event_contains_handle) |
1490 | +{ |
1491 | + auto const cookie = user_initiates_drag(); |
1492 | + ASSERT_THAT(cookie, NotNull()); |
1493 | + auto const handle_from_request = client_requests_drag(cookie); |
1494 | + |
1495 | + auto const handle = handle_from_mouse_enter(); |
1496 | + |
1497 | + EXPECT_THAT(handle, NotNull()); |
1498 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1499 | +} |
1500 | + |
1501 | +TEST_F(DragAndDrop, when_drag_releases_target_window_release_event_contains_handle) |
1502 | +{ |
1503 | + auto const cookie = user_initiates_drag(); |
1504 | + ASSERT_THAT(cookie, NotNull()); |
1505 | + auto const handle_from_request = client_requests_drag(cookie); |
1506 | + |
1507 | + auto const handle = handle_from_mouse_release(); |
1508 | + |
1509 | + EXPECT_THAT(handle, NotNull()); |
1510 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1511 | +} |
1512 | + |
1513 | +TEST_F(DragAndDrop, after_drag_finishes_pointer_events_no_longer_contain_handle) |
1514 | +{ |
1515 | + auto const cookie = user_initiates_drag(); |
1516 | + ASSERT_THAT(cookie, NotNull()); |
1517 | + client_requests_drag(cookie); |
1518 | + handle_from_mouse_release(); |
1519 | + |
1520 | + invoke_tools([](miral::WindowManagerTools& tools) { tools.end_drag_and_drop(); }); |
1521 | + |
1522 | + EXPECT_THAT(count_of_handles_when_moving_mouse(), Eq(0)); |
1523 | +} |
We're going to restart this with the Mir 0.27 release