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