Merge lp:~alan-griffiths/miral/drag-and-drop into lp:miral
- drag-and-drop
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Brandon Schaefer |
Approved revision: | 558 |
Merged at revision: | 549 |
Proposed branch: | lp:~alan-griffiths/miral/drag-and-drop |
Merge into: | lp:miral |
Prerequisite: | lp:~alan-griffiths/miral/1.3 |
Diff against target: |
1092 lines (+850/-11) 16 files modified
CMakeLists.txt (+2/-2) debian/changelog (+13/-2) debian/libmiral2.symbols (+4/-0) include/miral/window_management_policy_addendum2.h (+61/-0) include/miral/window_manager_tools.h (+12/-0) miral/CMakeLists.txt (+1/-0) miral/basic_window_manager.cpp (+42/-5) miral/basic_window_manager.h (+4/-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 (+10/-1) test/drag_and_drop.cpp (+639/-0) |
To merge this branch: | bzr merge lp:~alan-griffiths/miral/drag-and-drop |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Approve | |
Brandon Schaefer (community) | Approve | ||
Albert Astals Cid | Pending | ||
Review via email: mp+321593@code.launchpad.net |
This proposal supersedes a proposal from 2017-03-21.
Commit message
[libmiral] Support for Drag and Drop messages
Description of the change
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
> By just reading the documentation i would not know on what to pass as
> std::vector<
> want"?
>
> I guess it is since it's a randomly generated uuid in the example.
>
> But what is this parameter for? I mean as a miral user, you pass it in, but do
> you ever get it back? It seems not, so maybe miral can constrcut the uuid
> itself?
OK, so the documentation needs to state that "the handle will be passed to the client which can then use it to talk to the whatever service is being used to support drag and drop (e.g. on Ubuntu the content hub)".
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
> > By just reading the documentation i would not know on what to pass as
> > std::vector<
> > want"?
> >
> > I guess it is since it's a randomly generated uuid in the example.
> >
> > But what is this parameter for? I mean as a miral user, you pass it in, but
> do
> > you ever get it back? It seems not, so maybe miral can constrcut the uuid
> > itself?
>
> OK, so the documentation needs to state that "the handle will be passed to the
> client which can then use it to talk to the whatever service is being used to
> support drag and drop (e.g. on Ubuntu the content hub)".
That looks good to me :)
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Looks good to me
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:556
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:556
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:557
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 558. By Alan Griffiths
-
1.3.2 release changelog
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:558
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Brandon Schaefer (brandontschaefer) wrote : | # |
lgtm
Mir CI Bot (mir-ci-bot) : | # |
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2017-04-05 08:25:21 +0000 |
3 | +++ CMakeLists.txt 2017-04-05 08:25:21 +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-04-05 08:25:21 +0000 |
18 | +++ debian/changelog 2017-04-05 08:25:21 +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-05 08:25:21 +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-05 08:25:21 +0000 |
64 | @@ -0,0 +1,61 @@ |
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/version.h> |
87 | + |
88 | +namespace miral |
89 | +{ |
90 | +struct WindowInfo; |
91 | + |
92 | +/** |
93 | + * Handle additional client requests. |
94 | + * |
95 | + * \note This interface is intended to be implemented by a WindowManagementPolicy |
96 | + * implementation, we can't add these functions directly to that interface without |
97 | + * breaking ABI (the vtab could be incompatible). |
98 | + * When initializing the window manager this interface will be detected by |
99 | + * dynamic_cast and registered accordingly. |
100 | + */ |
101 | +class WindowManagementPolicyAddendum2 |
102 | +{ |
103 | +public: |
104 | +/** @name handle requests originating from the client |
105 | + * The policy is expected to update the model as appropriate |
106 | + * @{ */ |
107 | + /** request from client to initiate drag and drop |
108 | + * \note the request has already been validated against the requesting event |
109 | + * |
110 | + * @param window_info the window |
111 | + */ |
112 | + virtual void handle_request_drag_and_drop(WindowInfo& window_info) = 0; |
113 | +/** @} */ |
114 | + |
115 | + virtual ~WindowManagementPolicyAddendum2() = default; |
116 | + WindowManagementPolicyAddendum2() = default; |
117 | + WindowManagementPolicyAddendum2(WindowManagementPolicyAddendum2 const&) = delete; |
118 | + WindowManagementPolicyAddendum2& operator=(WindowManagementPolicyAddendum2 const&) = delete; |
119 | +}; |
120 | +#if MIRAL_VERSION >= MIR_VERSION_NUMBER(2, 0, 0) |
121 | +#error "We've presumably broken ABI - please roll this interface into WindowManagementPolicy" |
122 | +#endif |
123 | +} |
124 | + |
125 | +#endif //MIRAL_WINDOW_MANAGEMENT_ADDENDUM2_H |
126 | |
127 | === modified file 'include/miral/window_manager_tools.h' |
128 | --- include/miral/window_manager_tools.h 2017-03-02 14:29:04 +0000 |
129 | +++ include/miral/window_manager_tools.h 2017-04-05 08:25:21 +0000 |
130 | @@ -166,6 +166,18 @@ |
131 | /// Raise window and all its children |
132 | void raise_tree(Window const& root); |
133 | |
134 | + /** Start drag and drop. The handle will be passed to the client which can |
135 | + * then use it to talk to the whatever service is being used to support drag |
136 | + * and drop (e.g. on Ubuntu the content hub). |
137 | + * |
138 | + * @param window_info source window |
139 | + * @param handle drag handle |
140 | + */ |
141 | + void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle); |
142 | + |
143 | + /// End drag and drop |
144 | + void end_drag_and_drop(); |
145 | + |
146 | /// Apply modifications to a window |
147 | void modify_window(WindowInfo& window_info, WindowSpecification const& modifications); |
148 | |
149 | |
150 | === modified file 'miral/CMakeLists.txt' |
151 | --- miral/CMakeLists.txt 2017-03-20 12:28:06 +0000 |
152 | +++ miral/CMakeLists.txt 2017-04-05 08:25:21 +0000 |
153 | @@ -61,6 +61,7 @@ |
154 | ${CMAKE_SOURCE_DIR}/include/mir/client/display_config.h |
155 | ${CMAKE_SOURCE_DIR}/include/mir/client/window.h |
156 | ${CMAKE_SOURCE_DIR}/include/mir/client/detail/mir_forward_compatibility.h |
157 | + ${CMAKE_SOURCE_DIR}/include/miral/window_management_policy_addendum2.h |
158 | ) |
159 | |
160 | target_link_libraries(miral |
161 | |
162 | === modified file 'miral/basic_window_manager.cpp' |
163 | --- miral/basic_window_manager.cpp 2017-03-21 12:30:42 +0000 |
164 | +++ miral/basic_window_manager.cpp 2017-04-05 08:25:21 +0000 |
165 | @@ -19,6 +19,7 @@ |
166 | #include "basic_window_manager.h" |
167 | #include "miral/window_manager_tools.h" |
168 | #include "miral/workspace_policy.h" |
169 | +#include "miral/window_management_policy_addendum2.h" |
170 | |
171 | #include <mir/scene/session.h> |
172 | #include <mir/scene/surface.h> |
173 | @@ -70,7 +71,6 @@ |
174 | |
175 | namespace |
176 | { |
177 | - |
178 | auto find_workspace_policy(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WorkspacePolicy* |
179 | { |
180 | miral::WorkspacePolicy* result = dynamic_cast<miral::WorkspacePolicy*>(policy.get()); |
181 | @@ -82,6 +82,22 @@ |
182 | |
183 | return &null_workspace_policy; |
184 | } |
185 | + |
186 | +auto find_policy_addendum2(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WindowManagementPolicyAddendum2* |
187 | +{ |
188 | + miral::WindowManagementPolicyAddendum2* result = dynamic_cast<miral::WindowManagementPolicyAddendum2*>(policy.get()); |
189 | + |
190 | + if (result) |
191 | + return result; |
192 | + |
193 | + struct NullWindowManagementPolicyAddendum2 : miral::WindowManagementPolicyAddendum2 |
194 | + { |
195 | + void handle_request_drag_and_drop(miral::WindowInfo&) override {} |
196 | + }; |
197 | + static NullWindowManagementPolicyAddendum2 null_workspace_policy; |
198 | + |
199 | + return &null_workspace_policy; |
200 | +} |
201 | } |
202 | |
203 | |
204 | @@ -94,7 +110,8 @@ |
205 | display_layout(display_layout), |
206 | persistent_surface_store{persistent_surface_store}, |
207 | policy(build(WindowManagerTools{this})), |
208 | - workspace_policy{find_workspace_policy(policy)} |
209 | + workspace_policy{find_workspace_policy(policy)}, |
210 | + policy2{find_policy_addendum2(policy)} |
211 | { |
212 | } |
213 | |
214 | @@ -362,10 +379,12 @@ |
215 | #if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
216 | void miral::BasicWindowManager::handle_request_drag_and_drop( |
217 | std::shared_ptr<mir::scene::Session> const& /*session*/, |
218 | - std::shared_ptr<mir::scene::Surface> const& /*surface*/, |
219 | - uint64_t /*timestamp*/) |
220 | + std::shared_ptr<mir::scene::Surface> const& surface, |
221 | + uint64_t timestamp) |
222 | { |
223 | - // TODO |
224 | + Locker lock{this}; |
225 | + if (timestamp >= last_input_event_timestamp) |
226 | + policy2->handle_request_drag_and_drop(info_for(surface)); |
227 | } |
228 | #endif |
229 | |
230 | @@ -741,6 +760,24 @@ |
231 | focus_controller->raise({begin(windows), end(windows)}); |
232 | } |
233 | |
234 | +void miral::BasicWindowManager::start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) |
235 | +{ |
236 | +#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
237 | + std::shared_ptr<scene::Surface>(window_info.window())->start_drag_and_drop(handle); |
238 | + focus_controller->set_drag_and_drop_handle(handle); |
239 | +#else |
240 | + (void)window_info; |
241 | + (void)handle; |
242 | +#endif |
243 | +} |
244 | + |
245 | +void miral::BasicWindowManager::end_drag_and_drop() |
246 | +{ |
247 | +#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0) |
248 | + focus_controller->clear_drag_and_drop_handle(); |
249 | +#endif |
250 | +} |
251 | + |
252 | void miral::BasicWindowManager::move_tree(miral::WindowInfo& root, mir::geometry::Displacement movement) |
253 | { |
254 | if (movement == mir::geometry::Displacement{}) |
255 | |
256 | === modified file 'miral/basic_window_manager.h' |
257 | --- miral/basic_window_manager.h 2017-03-21 12:30:42 +0000 |
258 | +++ miral/basic_window_manager.h 2017-04-05 08:25:21 +0000 |
259 | @@ -46,6 +46,7 @@ |
260 | namespace miral |
261 | { |
262 | class WorkspacePolicy; |
263 | +class WindowManagementPolicyAddendum2; |
264 | using mir::shell::SurfaceSet; |
265 | using WindowManagementPolicyBuilder = |
266 | std::function<std::unique_ptr<miral::WindowManagementPolicy>(miral::WindowManagerTools const& tools)>; |
267 | @@ -161,6 +162,8 @@ |
268 | auto active_display() -> mir::geometry::Rectangle const override; |
269 | |
270 | void raise_tree(Window const& root) override; |
271 | + void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) override; |
272 | + void end_drag_and_drop() override; |
273 | |
274 | void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override; |
275 | |
276 | @@ -190,6 +193,7 @@ |
277 | |
278 | std::unique_ptr<WindowManagementPolicy> const policy; |
279 | WorkspacePolicy* const workspace_policy; |
280 | + WindowManagementPolicyAddendum2* const policy2; |
281 | |
282 | std::mutex mutex; |
283 | SessionInfoMap app_info; |
284 | |
285 | === modified file 'miral/symbols.map' |
286 | --- miral/symbols.map 2017-03-15 17:44:36 +0000 |
287 | +++ miral/symbols.map 2017-04-05 08:25:21 +0000 |
288 | @@ -401,3 +401,24 @@ |
289 | vtable?for?miral::SetWindowManagementPolicy; |
290 | }; |
291 | } MIRAL_1.3; |
292 | + |
293 | +MIRAL_1.4.0 { |
294 | +global: |
295 | + extern "C++" { |
296 | + miral::WindowManagementPolicyAddendum2::?WindowManagementPolicyAddendum2*; |
297 | + miral::WindowManagementPolicyAddendum2::WindowManagementPolicyAddendum2*; |
298 | + miral::WindowManagementPolicyAddendum2::operator*; |
299 | + miral::WindowManagerTools::end_drag_and_drop*; |
300 | + miral::WindowManagerTools::start_drag_and_drop*; |
301 | + miral::toolkit::Window::Window*; |
302 | + non-virtual?thunk?to?miral::WindowManagementPolicyAddendum2::?WindowManagementPolicyAddendum2*; |
303 | + typeinfo?for?miral::WindowManagementPolicyAddendum2; |
304 | + typeinfo?for?miral::toolkit::Window; |
305 | + typeinfo?for?miral::toolkit::WindowId; |
306 | + typeinfo?for?miral::toolkit::WindowSpec; |
307 | + vtable?for?miral::WindowManagementPolicyAddendum2; |
308 | + vtable?for?miral::toolkit::Window; |
309 | + vtable?for?miral::toolkit::WindowId; |
310 | + vtable?for?miral::toolkit::WindowSpec; |
311 | + }; |
312 | +} MIRAL_1.3.1; |
313 | |
314 | === modified file 'miral/window_management_trace.cpp' |
315 | --- miral/window_management_trace.cpp 2017-03-03 10:06:02 +0000 |
316 | +++ miral/window_management_trace.cpp 2017-04-05 08:25:21 +0000 |
317 | @@ -547,6 +547,24 @@ |
318 | } |
319 | MIRAL_TRACE_EXCEPTION |
320 | |
321 | +void miral::WindowManagementTrace::start_drag_and_drop(miral::WindowInfo& window_info, std::vector<uint8_t> const& handle) |
322 | +try { |
323 | + log_input(); |
324 | + mir::log_info("%s window_info=%s", __func__, dump_of(window_info).c_str()); |
325 | + trace_count++; |
326 | + wrapped.start_drag_and_drop(window_info, handle); |
327 | +} |
328 | +MIRAL_TRACE_EXCEPTION |
329 | + |
330 | +void miral::WindowManagementTrace::end_drag_and_drop() |
331 | +try { |
332 | + log_input(); |
333 | + mir::log_info("%s window_info=%s", __func__); |
334 | + trace_count++; |
335 | + wrapped.end_drag_and_drop(); |
336 | +} |
337 | +MIRAL_TRACE_EXCEPTION |
338 | + |
339 | void miral::WindowManagementTrace::modify_window( |
340 | miral::WindowInfo& window_info, miral::WindowSpecification const& modifications) |
341 | try { |
342 | |
343 | === modified file 'miral/window_management_trace.h' |
344 | --- miral/window_management_trace.h 2017-03-02 14:29:04 +0000 |
345 | +++ miral/window_management_trace.h 2017-04-05 08:25:21 +0000 |
346 | @@ -69,6 +69,8 @@ |
347 | virtual void focus_prev_within_application() override; |
348 | |
349 | virtual void raise_tree(Window const& root) override; |
350 | + virtual void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) override; |
351 | + virtual void end_drag_and_drop() override; |
352 | |
353 | virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override; |
354 | |
355 | |
356 | === modified file 'miral/window_manager_tools.cpp' |
357 | --- miral/window_manager_tools.cpp 2017-03-02 14:29:04 +0000 |
358 | +++ miral/window_manager_tools.cpp 2017-04-05 08:25:21 +0000 |
359 | @@ -83,6 +83,12 @@ |
360 | void miral::WindowManagerTools::raise_tree(Window const& root) |
361 | { tools->raise_tree(root); } |
362 | |
363 | +void miral::WindowManagerTools::start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) |
364 | +{ tools->start_drag_and_drop(window_info, handle); } |
365 | + |
366 | +void miral::WindowManagerTools::end_drag_and_drop() |
367 | +{ tools->end_drag_and_drop(); } |
368 | + |
369 | void miral::WindowManagerTools::modify_window(WindowInfo& window_info, WindowSpecification const& modifications) |
370 | { tools->modify_window(window_info,modifications); } |
371 | |
372 | |
373 | === modified file 'miral/window_manager_tools_implementation.h' |
374 | --- miral/window_manager_tools_implementation.h 2017-03-02 14:29:04 +0000 |
375 | +++ miral/window_manager_tools_implementation.h 2017-04-05 08:25:21 +0000 |
376 | @@ -26,6 +26,7 @@ |
377 | |
378 | #include <functional> |
379 | #include <memory> |
380 | +#include <vector> |
381 | |
382 | namespace mir { namespace scene { class Surface; } } |
383 | |
384 | @@ -66,6 +67,8 @@ |
385 | virtual auto window_at(mir::geometry::Point cursor) const -> Window = 0; |
386 | virtual auto active_display() -> mir::geometry::Rectangle const = 0; |
387 | virtual void raise_tree(Window const& root) = 0; |
388 | + virtual void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) = 0; |
389 | + virtual void end_drag_and_drop() = 0; |
390 | virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) = 0; |
391 | virtual auto info_for_window_id(std::string const& id) const -> WindowInfo& = 0; |
392 | virtual auto id_for_window(Window const& window) const -> std::string = 0; |
393 | |
394 | === modified file 'scripts/process_doxygen_xml.py' |
395 | --- scripts/process_doxygen_xml.py 2017-03-15 17:44:36 +0000 |
396 | +++ scripts/process_doxygen_xml.py 2017-04-05 08:25:21 +0000 |
397 | @@ -476,10 +476,21 @@ |
398 | |
399 | MIRAL_1.3.1 { |
400 | global: |
401 | + extern "C++" { |
402 | + miral::SetWindowManagementPolicy::?SetWindowManagementPolicy*; |
403 | + miral::SetWindowManagementPolicy::SetWindowManagementPolicy*; |
404 | + miral::SetWindowManagementPolicy::operator*; |
405 | + typeinfo?for?miral::SetWindowManagementPolicy; |
406 | + vtable?for?miral::SetWindowManagementPolicy; |
407 | + }; |
408 | +} MIRAL_1.3; |
409 | + |
410 | +MIRAL_1.4.0 { |
411 | +global: |
412 | extern "C++" {''' |
413 | |
414 | END_NEW_STANZA = ''' }; |
415 | -} MIRAL_1.3;''' |
416 | +} MIRAL_1.3.1;''' |
417 | |
418 | def _print_report(): |
419 | print OLD_STANZAS |
420 | |
421 | === modified file 'test/CMakeLists.txt' |
422 | --- test/CMakeLists.txt 2017-02-13 16:23:29 +0000 |
423 | +++ test/CMakeLists.txt 2017-04-05 08:25:21 +0000 |
424 | @@ -39,6 +39,13 @@ |
425 | ${GTEST_INCLUDE_DIR} |
426 | ) |
427 | |
428 | +# MIRAL_TEST_MODERN_FEATURES lists test sourcefiles that require a recent version of Mir |
429 | +if (MIRTEST_VERSION VERSION_LESS 0.27) |
430 | + set(MIRAL_TEST_MODERN_FEATURES) |
431 | +else() |
432 | + set(MIRAL_TEST_MODERN_FEATURES drag_and_drop.cpp) |
433 | +endif() |
434 | + |
435 | add_executable(miral-test |
436 | mru_window_list.cpp |
437 | active_outputs.cpp |
438 | @@ -56,7 +63,9 @@ |
439 | display_reconfiguration.cpp |
440 | active_window.cpp |
441 | raise_tree.cpp |
442 | - workspaces.cpp) |
443 | + workspaces.cpp |
444 | + ${MIRAL_TEST_MODERN_FEATURES} |
445 | +) |
446 | |
447 | target_link_libraries(miral-test |
448 | ${MIRTEST_LDFLAGS} |
449 | |
450 | === added file 'test/drag_and_drop.cpp' |
451 | --- test/drag_and_drop.cpp 1970-01-01 00:00:00 +0000 |
452 | +++ test/drag_and_drop.cpp 2017-04-05 08:25:21 +0000 |
453 | @@ -0,0 +1,639 @@ |
454 | +/* |
455 | + * Copyright © 2017 Canonical Ltd. |
456 | + * |
457 | + * This program is free software: you can redistribute it and/or modify it |
458 | + * under the terms of the GNU General Public License version 3, |
459 | + * as published by the Free Software Foundation. |
460 | + * |
461 | + * This program is distributed in the hope that it will be useful, |
462 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
463 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
464 | + * GNU General Public License for more details. |
465 | + * |
466 | + * You should have received a copy of the GNU General Public License |
467 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
468 | + * |
469 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
470 | + */ |
471 | + |
472 | +#include <miral/window_management_policy_addendum2.h> |
473 | + |
474 | +#include <mir/client/blob.h> |
475 | +#include <mir/client/cookie.h> |
476 | +#include <mir/client/window.h> |
477 | +#include <mir/client/window_spec.h> |
478 | +#include <mir_toolkit/mir_buffer_stream.h> |
479 | +#include <mir_toolkit/extensions/drag_and_drop.h> |
480 | + |
481 | +#include <mir/geometry/displacement.h> |
482 | +#include <mir/input/input_device_info.h> |
483 | +#include <mir/input/device_capability.h> |
484 | +#include <mir/shell/shell.h> |
485 | + |
486 | +#include "test_server.h" |
487 | +#include <mir_test_framework/fake_input_device.h> |
488 | +#include <mir_test_framework/stub_server_platform_factory.h> |
489 | +#include <mir/test/event_factory.h> |
490 | +#include <mir/test/signal.h> |
491 | + |
492 | +#include <gmock/gmock.h> |
493 | +#include <gtest/gtest.h> |
494 | + |
495 | +#include <linux/input.h> |
496 | +#include <uuid/uuid.h> |
497 | + |
498 | +#include <boost/throw_exception.hpp> |
499 | +#include <atomic> |
500 | + |
501 | +using namespace std::chrono_literals; |
502 | +using namespace mir::client; |
503 | +using namespace mir::geometry; |
504 | +using namespace testing; |
505 | +using mir::test::Signal; |
506 | + |
507 | +namespace |
508 | +{ |
509 | +struct MouseMoverAndFaker |
510 | +{ |
511 | + void start_dragging_mouse() |
512 | + { |
513 | + using namespace mir::input::synthesis; |
514 | + fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT)); |
515 | + } |
516 | + |
517 | + void move_mouse(Displacement const& displacement) |
518 | + { |
519 | + using mir::input::synthesis::a_pointer_event; |
520 | + fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int())); |
521 | + } |
522 | + |
523 | + void release_mouse() |
524 | + { |
525 | + using namespace mir::input::synthesis; |
526 | + fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT)); |
527 | + } |
528 | + |
529 | +private: |
530 | + std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{ |
531 | + mir_test_framework::add_fake_input_device( |
532 | + mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer})}; |
533 | +}; |
534 | + |
535 | +Rectangle const screen_geometry{{0,0}, {800,600}}; |
536 | +auto const receive_event_timeout = 1s; //90s; |
537 | + |
538 | +struct ConnectedClientWithAWindow : miral::TestServer |
539 | +{ |
540 | + Connection connection; |
541 | + Window window; |
542 | + |
543 | + void SetUp() override |
544 | + { |
545 | + miral::TestServer::SetUp(); |
546 | + connection = connect_client(__func__); |
547 | + window = WindowSpec::for_normal_window(connection, surface_size.width.as_int(), surface_size.height.as_int()) |
548 | + .set_pixel_format(mir_pixel_format_abgr_8888) |
549 | + .set_name("ConnectedClientWithAWindow") |
550 | + .set_buffer_usage(mir_buffer_usage_hardware) |
551 | + .create_window(); |
552 | + } |
553 | + |
554 | + void TearDown() override |
555 | + { |
556 | + window.reset(); |
557 | + connection.reset(); |
558 | + miral::TestServer::TearDown(); |
559 | + } |
560 | + |
561 | + mir::geometry::Size const surface_size {640, 480}; |
562 | +}; |
563 | + |
564 | +struct DragAndDrop : ConnectedClientWithAWindow, |
565 | + MouseMoverAndFaker |
566 | +{ |
567 | + MirDragAndDropV1 const* dnd = nullptr; |
568 | + |
569 | + void SetUp() override |
570 | + { |
571 | + mir_test_framework::set_next_display_rects(std::unique_ptr<std::vector<Rectangle>>(new std::vector<Rectangle>({screen_geometry}))); |
572 | + |
573 | + ConnectedClientWithAWindow::SetUp(); |
574 | + dnd = mir_drag_and_drop_v1(connection); |
575 | + mir_window_set_event_handler(window, &window_event_handler, this); |
576 | + if (dnd) dnd->set_start_drag_and_drop_callback(window, &window_dnd_start_handler, this); |
577 | + |
578 | + create_target_window(); |
579 | + |
580 | + paint_window(window); |
581 | + |
582 | + center_mouse(); |
583 | + } |
584 | + |
585 | + void TearDown() override |
586 | + { |
587 | + reset_window_event_handler(target_window); |
588 | + reset_window_event_handler(window); |
589 | + target_window.reset(); |
590 | + another_connection.reset(); |
591 | + ConnectedClientWithAWindow::TearDown(); |
592 | + } |
593 | + |
594 | + auto user_initiates_drag() -> Cookie; |
595 | + auto client_requests_drag(Cookie const& cookie) -> Blob; |
596 | + auto handle_from_mouse_move() -> Blob; |
597 | + auto handle_from_mouse_leave() -> Blob; |
598 | + auto handle_from_mouse_enter() -> Blob; |
599 | + auto handle_from_mouse_release() -> Blob; |
600 | + auto count_of_handles_when_moving_mouse() -> int; |
601 | + |
602 | +private: |
603 | + auto build_window_manager_policy(miral::WindowManagerTools const& tools) -> std::unique_ptr<TestWindowManagerPolicy> override; |
604 | + void center_mouse(); |
605 | + void paint_window(MirWindow* w); |
606 | + void set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler); |
607 | + void set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler); |
608 | + void reset_window_event_handler(MirWindow* window); |
609 | + |
610 | + void create_target_window() |
611 | + { |
612 | + another_connection = connect_client("another_connection"); |
613 | + target_window = WindowSpec:: |
614 | + for_normal_window(connection, screen_geometry.size.width.as_int(), screen_geometry.size.height.as_int()) |
615 | + .set_pixel_format(mir_pixel_format_abgr_8888) |
616 | + .set_name("target_window") |
617 | + .set_buffer_usage(mir_buffer_usage_hardware) |
618 | + .set_event_handler(&window_event_handler, this) |
619 | + .create_window(); |
620 | + |
621 | + paint_window(target_window); |
622 | + } |
623 | + |
624 | + void invoke_window_event_handler(MirWindow* window, MirEvent const* event) |
625 | + { |
626 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
627 | + if (window == this->window) window_event_handler_(event); |
628 | + if (window == target_window) target_window_event_handler_(event); |
629 | + } |
630 | + |
631 | + void invoke_window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event) |
632 | + { |
633 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
634 | + if (window == this->window) window_dnd_start_(event); |
635 | + } |
636 | + |
637 | + std::mutex window_event_handler_mutex; |
638 | + std::function<void(MirDragAndDropEvent const* event)> window_dnd_start_ = [](MirDragAndDropEvent const*) {}; |
639 | + std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {}; |
640 | + std::function<void(MirEvent const* event)> target_window_event_handler_ = [](MirEvent const*) {}; |
641 | + |
642 | + static void window_event_handler(MirWindow* window, MirEvent const* event, void* context); |
643 | + static void window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context); |
644 | + |
645 | + Connection another_connection; |
646 | + Window target_window; |
647 | +}; |
648 | + |
649 | +void DragAndDrop::set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler) |
650 | +{ |
651 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
652 | + if (window == this->window) window_event_handler_ = handler; |
653 | + if (window == target_window) target_window_event_handler_ = handler; |
654 | +} |
655 | + |
656 | +void DragAndDrop::set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler) |
657 | +{ |
658 | +std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
659 | +if (window == this->window) window_dnd_start_ = handler; |
660 | +} |
661 | + |
662 | + |
663 | +void DragAndDrop::reset_window_event_handler(MirWindow* window) |
664 | +{ |
665 | + if (window == this->window) window_event_handler_ = [](MirEvent const*) {}; |
666 | + if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {}; |
667 | +} |
668 | + |
669 | +void DragAndDrop::paint_window(MirWindow* w) |
670 | +{ |
671 | + Signal have_focus; |
672 | + |
673 | + set_window_event_handler(w, [&](MirEvent const* event) |
674 | + { |
675 | + if (mir_event_get_type(event) != mir_event_type_window) |
676 | + return; |
677 | + |
678 | + auto const window_event = mir_event_get_window_event(event); |
679 | + if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus) |
680 | + return; |
681 | + |
682 | + if (mir_window_event_get_attribute_value(window_event)) |
683 | + have_focus.raise(); |
684 | + }); |
685 | + |
686 | + mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(w)); |
687 | + |
688 | + EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true)); |
689 | + |
690 | + reset_window_event_handler(w); |
691 | +} |
692 | + |
693 | +void DragAndDrop::center_mouse() |
694 | +{ |
695 | + Signal have_mouseover; |
696 | + |
697 | + set_window_event_handler(window, [&](MirEvent const* event) |
698 | + { |
699 | + if (mir_event_get_type(event) != mir_event_type_input) |
700 | + return; |
701 | + |
702 | + auto const input_event = mir_event_get_input_event(event); |
703 | + |
704 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
705 | + return; |
706 | + |
707 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
708 | + |
709 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) |
710 | + return; |
711 | + |
712 | + have_mouseover.raise(); |
713 | + }); |
714 | + |
715 | + move_mouse(0.5 * as_displacement(screen_geometry.size)); |
716 | + |
717 | +// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20). |
718 | +// But it isn't essential for the test and we've probably waited long enough |
719 | +// for the mouse-down needed by the test to reach the window. |
720 | +// EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true)); |
721 | + have_mouseover.wait_for(receive_event_timeout); |
722 | + |
723 | + reset_window_event_handler(window); |
724 | +} |
725 | + |
726 | +void DragAndDrop::window_event_handler(MirWindow* window, MirEvent const* event, void* context) |
727 | +{ |
728 | + static_cast<DragAndDrop*>(context)->invoke_window_event_handler(window, event); |
729 | +} |
730 | + |
731 | +void DragAndDrop::window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context) |
732 | +{ |
733 | + static_cast<DragAndDrop*>(context)->invoke_window_dnd_start_handler(window, event); |
734 | +} |
735 | + |
736 | + |
737 | +auto DragAndDrop::user_initiates_drag() -> Cookie |
738 | +{ |
739 | + Cookie cookie; |
740 | + Signal have_cookie; |
741 | + |
742 | + set_window_event_handler(window, [&](MirEvent const* event) |
743 | + { |
744 | + if (mir_event_get_type(event) != mir_event_type_input) |
745 | + return; |
746 | + |
747 | + auto const input_event = mir_event_get_input_event(event); |
748 | + |
749 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
750 | + return; |
751 | + |
752 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
753 | + |
754 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down) |
755 | + return; |
756 | + |
757 | + cookie = Cookie{mir_input_event_get_cookie(input_event)}; |
758 | + have_cookie.raise(); |
759 | + }); |
760 | + |
761 | + start_dragging_mouse(); |
762 | + |
763 | + EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true)); |
764 | + |
765 | + reset_window_event_handler(window); |
766 | + return cookie; |
767 | +} |
768 | + |
769 | +auto DragAndDrop::client_requests_drag(Cookie const& cookie) -> Blob |
770 | +{ |
771 | + Blob blob; |
772 | + Signal initiated; |
773 | + |
774 | + set_window_dnd_start_handler(window, [&](MirDragAndDropEvent const* event) |
775 | + { |
776 | + if (dnd) |
777 | + blob.reset(dnd->start_drag_and_drop(event)); |
778 | + |
779 | + if (blob) |
780 | + initiated.raise(); |
781 | + }); |
782 | + |
783 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
784 | + |
785 | + if (dnd) |
786 | + dnd->request_drag_and_drop(window, cookie); |
787 | + |
788 | + EXPECT_TRUE(initiated.wait_for(receive_event_timeout)); |
789 | + |
790 | + reset_window_event_handler(window); |
791 | + return blob; |
792 | +} |
793 | + |
794 | +auto DragAndDrop::handle_from_mouse_move() -> Blob |
795 | +{ |
796 | + Blob blob; |
797 | + Signal have_blob; |
798 | + |
799 | + set_window_event_handler(window, [&](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 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
812 | + |
813 | + if (dnd) |
814 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
815 | + |
816 | + if (blob) |
817 | + have_blob.raise(); |
818 | + }); |
819 | + |
820 | + move_mouse({1,1}); |
821 | + |
822 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
823 | + |
824 | + reset_window_event_handler(window); |
825 | + return blob; |
826 | +} |
827 | + |
828 | +auto DragAndDrop::handle_from_mouse_leave() -> Blob |
829 | +{ |
830 | + Blob blob; |
831 | + Signal have_blob; |
832 | + |
833 | + set_window_event_handler(window, [&](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_leave) |
846 | + return; |
847 | + |
848 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
849 | + |
850 | + if (dnd) |
851 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
852 | + |
853 | + if (blob) |
854 | + have_blob.raise(); |
855 | + }); |
856 | + |
857 | + move_mouse({1,1}); |
858 | + move_mouse(0.5 * as_displacement(surface_size)); |
859 | + |
860 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
861 | + |
862 | + reset_window_event_handler(window); |
863 | + return blob; |
864 | +} |
865 | + |
866 | +auto DragAndDrop::handle_from_mouse_enter() -> Blob |
867 | +{ |
868 | + Blob blob; |
869 | + Signal have_blob; |
870 | + |
871 | + set_window_event_handler(target_window, [&](MirEvent const* event) |
872 | + { |
873 | + if (mir_event_get_type(event) != mir_event_type_input) |
874 | + return; |
875 | + |
876 | + auto const input_event = mir_event_get_input_event(event); |
877 | + |
878 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
879 | + return; |
880 | + |
881 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
882 | + |
883 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) |
884 | + return; |
885 | + |
886 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
887 | + |
888 | + if (dnd) |
889 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
890 | + |
891 | + if (blob) |
892 | + have_blob.raise(); |
893 | + }); |
894 | + |
895 | + move_mouse({1,1}); |
896 | + move_mouse(0.5 * as_displacement(surface_size)); |
897 | + |
898 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
899 | + |
900 | + reset_window_event_handler(target_window); |
901 | + return blob; |
902 | +} |
903 | + |
904 | +auto DragAndDrop::handle_from_mouse_release() -> Blob |
905 | +{ |
906 | + Blob blob; |
907 | + Signal have_blob; |
908 | + |
909 | + set_window_event_handler(target_window, [&](MirEvent const* event) |
910 | + { |
911 | + if (mir_event_get_type(event) != mir_event_type_input) |
912 | + return; |
913 | + |
914 | + auto const input_event = mir_event_get_input_event(event); |
915 | + |
916 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
917 | + return; |
918 | + |
919 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
920 | + |
921 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_up) |
922 | + return; |
923 | + |
924 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
925 | + |
926 | + if (dnd) |
927 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
928 | + |
929 | + if (blob) |
930 | + have_blob.raise(); |
931 | + }); |
932 | + |
933 | + move_mouse({1,1}); |
934 | + move_mouse(0.5 * as_displacement(surface_size)); |
935 | + release_mouse(); |
936 | + |
937 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
938 | + |
939 | + reset_window_event_handler(target_window); |
940 | + return blob; |
941 | +} |
942 | + |
943 | +auto DragAndDrop::count_of_handles_when_moving_mouse() -> int |
944 | +{ |
945 | + Signal have_3_events; |
946 | + std::atomic<int> events{0}; |
947 | + std::atomic<int> handles{0}; |
948 | + |
949 | + auto counter = [&](MirEvent const* event) |
950 | + { |
951 | + if (mir_event_get_type(event) != mir_event_type_input) |
952 | + return; |
953 | + |
954 | + auto const input_event = mir_event_get_input_event(event); |
955 | + |
956 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
957 | + return; |
958 | + |
959 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
960 | + |
961 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
962 | + |
963 | + Blob blob; |
964 | + if (dnd) |
965 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
966 | + |
967 | + if (blob) |
968 | + handles.fetch_add(1); |
969 | + |
970 | + if (events.fetch_add(1) == 2) |
971 | + have_3_events.raise(); |
972 | + }; |
973 | + |
974 | + set_window_event_handler(window, counter); |
975 | + set_window_event_handler(target_window, counter); |
976 | + |
977 | + start_dragging_mouse(); |
978 | + move_mouse({1,1}); |
979 | + release_mouse(); |
980 | + |
981 | + EXPECT_TRUE(have_3_events.wait_for(receive_event_timeout)); |
982 | + |
983 | + reset_window_event_handler(window); |
984 | + reset_window_event_handler(target_window); |
985 | + return handles; |
986 | +} |
987 | + |
988 | +auto DragAndDrop::build_window_manager_policy(miral::WindowManagerTools const& tools) -> std::unique_ptr<TestWindowManagerPolicy> |
989 | +{ |
990 | + struct DnDWindowManagerPolicy : miral::TestServer::TestWindowManagerPolicy, miral::WindowManagementPolicyAddendum2 |
991 | + { |
992 | + using miral::TestServer::TestWindowManagerPolicy::TestWindowManagerPolicy; |
993 | + |
994 | + void handle_request_drag_and_drop(miral::WindowInfo& window_info) override |
995 | + { |
996 | + uuid_t uuid; |
997 | + uuid_generate(uuid); |
998 | + std::vector<uint8_t> const handle{std::begin(uuid), std::end(uuid)}; |
999 | + |
1000 | + tools.start_drag_and_drop(window_info, handle); |
1001 | + } |
1002 | + }; |
1003 | + |
1004 | + return std::make_unique<DnDWindowManagerPolicy>(tools, *this); |
1005 | +} |
1006 | + |
1007 | +MATCHER_P(BlobContentEq, p, "") |
1008 | +{ |
1009 | + if (!arg || !p) |
1010 | + return false; |
1011 | + if (mir_blob_size(arg) != mir_blob_size(p)) |
1012 | + return false; |
1013 | + return !memcmp(mir_blob_data(arg), mir_blob_data(p), mir_blob_size(p)); |
1014 | +} |
1015 | +} |
1016 | + |
1017 | +TEST_F(DragAndDrop, when_user_initiates_drag_client_receives_cookie) |
1018 | +{ |
1019 | + auto const cookie = user_initiates_drag(); |
1020 | + |
1021 | + EXPECT_THAT(cookie, NotNull()); |
1022 | +} |
1023 | + |
1024 | +TEST_F(DragAndDrop, when_client_requests_drags_it_receives_handle) |
1025 | +{ |
1026 | + auto const cookie = user_initiates_drag(); |
1027 | + ASSERT_THAT(cookie, NotNull()); |
1028 | + |
1029 | + auto const handle = client_requests_drag(cookie); |
1030 | + |
1031 | + EXPECT_THAT(handle, NotNull()); |
1032 | +} |
1033 | + |
1034 | +TEST_F(DragAndDrop, during_drag_when_user_moves_mouse_client_receives_handle) |
1035 | +{ |
1036 | + auto const cookie = user_initiates_drag(); |
1037 | + ASSERT_THAT(cookie, NotNull()); |
1038 | + auto const handle_from_request = client_requests_drag(cookie); |
1039 | + |
1040 | + auto const handle = handle_from_mouse_move(); |
1041 | + |
1042 | + EXPECT_THAT(handle, NotNull()); |
1043 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1044 | +} |
1045 | + |
1046 | +TEST_F(DragAndDrop, when_drag_moves_from_window_leave_event_contains_handle) |
1047 | +{ |
1048 | + auto const cookie = user_initiates_drag(); |
1049 | + ASSERT_THAT(cookie, NotNull()); |
1050 | + auto const handle_from_request = client_requests_drag(cookie); |
1051 | + |
1052 | + auto const handle = handle_from_mouse_leave(); |
1053 | + |
1054 | + EXPECT_THAT(handle, NotNull()); |
1055 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1056 | +} |
1057 | + |
1058 | +TEST_F(DragAndDrop, when_drag_enters_target_window_enter_event_contains_handle) |
1059 | +{ |
1060 | + auto const cookie = user_initiates_drag(); |
1061 | + ASSERT_THAT(cookie, NotNull()); |
1062 | + auto const handle_from_request = client_requests_drag(cookie); |
1063 | + |
1064 | + auto const handle = handle_from_mouse_enter(); |
1065 | + |
1066 | + EXPECT_THAT(handle, NotNull()); |
1067 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1068 | +} |
1069 | + |
1070 | +TEST_F(DragAndDrop, when_drag_releases_target_window_release_event_contains_handle) |
1071 | +{ |
1072 | + auto const cookie = user_initiates_drag(); |
1073 | + ASSERT_THAT(cookie, NotNull()); |
1074 | + auto const handle_from_request = client_requests_drag(cookie); |
1075 | + |
1076 | + auto const handle = handle_from_mouse_release(); |
1077 | + |
1078 | + EXPECT_THAT(handle, NotNull()); |
1079 | + EXPECT_THAT(handle, BlobContentEq(handle_from_request)); |
1080 | +} |
1081 | + |
1082 | +TEST_F(DragAndDrop, after_drag_finishes_pointer_events_no_longer_contain_handle) |
1083 | +{ |
1084 | + auto const cookie = user_initiates_drag(); |
1085 | + ASSERT_THAT(cookie, NotNull()); |
1086 | + client_requests_drag(cookie); |
1087 | + handle_from_mouse_release(); |
1088 | + |
1089 | + invoke_tools([](miral::WindowManagerTools& tools) { tools.end_drag_and_drop(); }); |
1090 | + |
1091 | + EXPECT_THAT(count_of_handles_when_moving_mouse(), Eq(0)); |
1092 | +} |
By just reading the documentation i would not know on what to pass as std::vector< uint8_t> const& handle in start_drag_ and_drop, is it "whatever i want"?
I guess it is since it's a randomly generated uuid in the example.
But what is this parameter for? I mean as a miral user, you pass it in, but do you ever get it back? It seems not, so maybe miral can constrcut the uuid itself?