Merge lp:~alan-griffiths/mir/client-initiates-user-move-and-resize into lp:mir
- client-initiates-user-move-and-resize
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Daniel van Vugt |
Approved revision: | no longer in the source branch. |
Merged at revision: | 4129 |
Proposed branch: | lp:~alan-griffiths/mir/client-initiates-user-move-and-resize |
Merge into: | lp:mir |
Prerequisite: | lp:~alan-griffiths/mir/request-with-authority |
Diff against target: |
385 lines (+293/-0) 9 files modified
include/client/mir_toolkit/mir_window.h (+9/-0) src/client/mir_surface.cpp (+5/-0) src/client/mir_surface.h (+1/-0) src/client/mir_surface_api.cpp (+14/-0) src/client/symbols.map (+2/-0) src/protobuf/mir_protobuf.proto (+1/-0) tests/acceptance-tests/CMakeLists.txt (+1/-0) tests/acceptance-tests/client_mediated_user_gestures.cpp (+259/-0) tests/acceptance-tests/drag_and_drop.cpp (+1/-0) |
To merge this branch: | bzr merge lp:~alan-griffiths/mir/client-initiates-user-move-and-resize |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Approve | |
Gerry Boland (community) | Abstain | ||
Daniel van Vugt | Abstain | ||
Chris Halse Rogers | Approve | ||
Andreas Pokorny (community) | Approve | ||
Review via email: mp+320917@code.launchpad.net |
Commit message
Client side and initial tests for a client initiating a user move gesture
Description of the change
Mir CI Bot (mir-ci-bot) wrote : | # |
Daniel van Vugt (vanvugt) wrote : | # |
I've linked the 'move' bug 1420334.
But why write more code for client-initiated resizing? That already works :)
Daniel van Vugt (vanvugt) wrote : | # |
As an example of a self-resizing client, try 'tiled' which has a resize grip in the bottom right corner. It already works.
Alan Griffiths (alan-griffiths) wrote : | # |
> I've linked the 'move' bug 1420334.
>
> But why write more code for client-initiated resizing? That already works :)
No it doesn't. ;)
I agree clients can resize, but they can't request the shell to initiate a resize gesture. There is no way to invoke the touch resize handles under U8, drag the left edge or top.
Daniel van Vugt (vanvugt) wrote : | # |
That's true, but the feature you're talking about in Unity7 also does not have resize handles (right click titlebar and then Resize, or just Alt+F8).
So either the client initiates the resize, and that works perfectly already; or
the server initiates resize, and that works perfectly already too.
Even if you did want it to pop up the resize handles, that's still a shell operation since the window menu itself is part of the shell. Not part of the client.
I think this branch should be just about movement.
Andreas Pokorny (andreas-pokorny) wrote : | # |
There is a difference between submitting a buffer with a different size, and resizing a window. So if we want to support CSD, this change is necessary.
Gerry Boland (gerboland) wrote : | # |
How is this API to be used by the client? I.e. where is the client specifying the new size/position?
Is it that the client gets a mouseDown event with a cookie that it decides should cause a resize/move, so calls the mir_window_
(a) shell intercepts all other input events, instead sending resize events to the client? Or
(b) shell keep sending the mouseMove events to the client, and client resizes its window/buffer as it pleases (WM can restrict those choices though)?
On resize completion, mouseUp event finally sent to client?
If a user wants to resize the top-left corner of a window, is that a move & resize? Should that be an atomic operation instead?
The only reason I see that Mir's current window resize api is insufficient for client-
Alan Griffiths (alan-griffiths) wrote : | # |
> How is this API to be used by the client? I.e. where is the client specifying
> the new size/position?
The client isn't specifying the position or size. It is requesting the shell treats an input event as the beginning of a gesture.
> Is it that the client gets a mouseDown event with a cookie that it decides
> should cause a resize/move, so calls the mir_window_
> that cookie. Then
> (a) shell intercepts all other input events, instead sending resize events to
> the client? Or
> (b) shell keep sending the mouseMove events to the client, and client resizes
> its window/buffer as it pleases (WM can restrict those choices though)?
> On resize completion, mouseUp event finally sent to client?
(a)
> If a user wants to resize the top-left corner of a window, is that a move &
> resize? Should that be an atomic operation instead?
That's an atomic operation in those shells that currently support it. Initiating the resize through a client API shouldn't change that.
> The only reason I see that Mir's current window resize api is insufficient for
> client-
> shell-themed resize image, and to remain that image even if the cursor moves
> beyond the window borders.
Hmm, I can see it will be easier to reach consensus on the USER_MOVE codepath. Maybe I should split that out?
William Hua (attente) wrote : | # |
Andreas is right, even if we can change the buffer size, this isn't the same as requesting a resize operation from an input event.
In gtk, we have this api we're expected to implement:
https:/
So for mir_window_
I wouldn't expect the client to get a mouse up event on completion of the resize, or any events other than resize ones during the client's resizing. So from Gerry's comment, (a) is the most sensible for us in gtk, especially from the api's point of view. If there's non-resizable windows, the server should already know that from the time the window was created, and just reject any resize operation in that case.
It also needs to be implemented so that the user can also resize using the keyboard arrow keys as well.
Alan Griffiths (alan-griffiths) wrote : | # |
> Hmm, I can see it will be easier to reach consensus on the USER_MOVE codepath.
> Maybe I should split that out?
OK, I'm dropping the resize code from this MP as it clearly needs further consideration.
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4115
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:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Chris Halse Rogers (raof) wrote : | # |
This seems sensible to me.
Daniel van Vugt (vanvugt) wrote : | # |
*shrug*
My request has been satisfied but I would hazard a guess this functionality may take us a few attempts to cover all the major use cases.
Daniel van Vugt (vanvugt) wrote : | # |
I'm fairly sure we need zero more work done on resizing. All the resizing use cases are covered by existing APIs.
On the topic of client-initiated movement though, please start thinking about the Chrome/Chromium use case too: You drag a tab out of the window, that then creates a new window where the cursor remains on the same relative tab coordinate in the new window. If it's not baked in to the drag action then we'll need to be able to create that new top-level window at a precise coordinate relative to the old window (which may be the parent but can also be closed leaving just the child open).
Gerry Boland (gerboland) wrote : | # |
No objections here
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
None: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Daniel van Vugt (vanvugt) wrote : | # |
04:02:04 Text conflict in src/client/
04:02:04 1 conflicts encountered.
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4116
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:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'include/client/mir_toolkit/mir_window.h' | |||
2 | --- include/client/mir_toolkit/mir_window.h 2017-03-14 04:41:33 +0000 | |||
3 | +++ include/client/mir_toolkit/mir_window.h 2017-03-29 08:37:58 +0000 | |||
4 | @@ -738,6 +738,15 @@ | |||
5 | 738 | void mir_window_raise(MirWindow* window, MirCookie const* cookie); | 738 | void mir_window_raise(MirWindow* window, MirCookie const* cookie); |
6 | 739 | 739 | ||
7 | 740 | /** | 740 | /** |
8 | 741 | * Informs the window manager that the user is moving the window. | ||
9 | 742 | * | ||
10 | 743 | * \param [in] window The window to move | ||
11 | 744 | * \param [in] cookie A cookie instance obtained from an input event. | ||
12 | 745 | * An invalid cookie will terminate the client connection. | ||
13 | 746 | */ | ||
14 | 747 | void mir_window_request_user_move(MirWindow* window, MirCookie const* cookie); | ||
15 | 748 | |||
16 | 749 | /** | ||
17 | 741 | * Get the type (purpose) of a window. | 750 | * Get the type (purpose) of a window. |
18 | 742 | * \param [in] window The window to query | 751 | * \param [in] window The window to query |
19 | 743 | * \return The type of the window | 752 | * \return The type of the window |
20 | 744 | 753 | ||
21 | === modified file 'src/client/mir_surface.cpp' | |||
22 | --- src/client/mir_surface.cpp 2017-03-28 14:28:26 +0000 | |||
23 | +++ src/client/mir_surface.cpp 2017-03-29 08:37:58 +0000 | |||
24 | @@ -588,6 +588,11 @@ | |||
25 | 588 | request_operation(cookie, mp::RequestOperation::MAKE_ACTIVE); | 588 | request_operation(cookie, mp::RequestOperation::MAKE_ACTIVE); |
26 | 589 | } | 589 | } |
27 | 590 | 590 | ||
28 | 591 | void MirSurface::request_user_move(MirCookie const* cookie) | ||
29 | 592 | { | ||
30 | 593 | request_operation(cookie, mp::RequestOperation::USER_MOVE); | ||
31 | 594 | } | ||
32 | 595 | |||
33 | 591 | void MirSurface::request_drag_and_drop(MirCookie const* cookie) | 596 | void MirSurface::request_drag_and_drop(MirCookie const* cookie) |
34 | 592 | { | 597 | { |
35 | 593 | request_operation(cookie, mp::RequestOperation::START_DRAG_AND_DROP); | 598 | request_operation(cookie, mp::RequestOperation::START_DRAG_AND_DROP); |
36 | 594 | 599 | ||
37 | === modified file 'src/client/mir_surface.h' | |||
38 | --- src/client/mir_surface.h 2017-03-28 14:28:26 +0000 | |||
39 | +++ src/client/mir_surface.h 2017-03-29 08:37:58 +0000 | |||
40 | @@ -200,6 +200,7 @@ | |||
41 | 200 | MirWaitHandle* set_preferred_orientation(MirOrientationMode mode); | 200 | MirWaitHandle* set_preferred_orientation(MirOrientationMode mode); |
42 | 201 | 201 | ||
43 | 202 | void raise_surface(MirCookie const* cookie); | 202 | void raise_surface(MirCookie const* cookie); |
44 | 203 | void request_user_move(MirCookie const* cookie); | ||
45 | 203 | void request_drag_and_drop(MirCookie const* cookie); | 204 | void request_drag_and_drop(MirCookie const* cookie); |
46 | 204 | void set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback); | 205 | void set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback); |
47 | 205 | 206 | ||
48 | 206 | 207 | ||
49 | === modified file 'src/client/mir_surface_api.cpp' | |||
50 | --- src/client/mir_surface_api.cpp 2017-03-14 04:41:33 +0000 | |||
51 | +++ src/client/mir_surface_api.cpp 2017-03-29 08:37:58 +0000 | |||
52 | @@ -695,6 +695,20 @@ | |||
53 | 695 | } | 695 | } |
54 | 696 | } | 696 | } |
55 | 697 | 697 | ||
56 | 698 | void mir_window_request_user_move(MirWindow* window, MirCookie const* cookie) | ||
57 | 699 | { | ||
58 | 700 | mir::require(mir_window_is_valid(window)); | ||
59 | 701 | |||
60 | 702 | try | ||
61 | 703 | { | ||
62 | 704 | window->request_user_move(cookie); | ||
63 | 705 | } | ||
64 | 706 | catch (std::exception const& ex) | ||
65 | 707 | { | ||
66 | 708 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); | ||
67 | 709 | } | ||
68 | 710 | } | ||
69 | 711 | |||
70 | 698 | MirWindowType mir_window_get_type(MirWindow* window) | 712 | MirWindowType mir_window_get_type(MirWindow* window) |
71 | 699 | { | 713 | { |
72 | 700 | MirWindowType type = mir_window_type_normal; | 714 | MirWindowType type = mir_window_type_normal; |
73 | 701 | 715 | ||
74 | === modified file 'src/client/symbols.map' | |||
75 | --- src/client/symbols.map 2017-03-28 11:32:58 +0000 | |||
76 | +++ src/client/symbols.map 2017-03-29 08:37:58 +0000 | |||
77 | @@ -604,6 +604,8 @@ | |||
78 | 604 | mir_keyboard_event_key_text; | 604 | mir_keyboard_event_key_text; |
79 | 605 | mir_output_get_logical_height; | 605 | mir_output_get_logical_height; |
80 | 606 | mir_output_get_logical_width; | 606 | mir_output_get_logical_width; |
81 | 607 | mir_window_request_user_move; | ||
82 | 608 | mir_window_request_user_resize; | ||
83 | 607 | mir_touchscreen_config_get_mapping_mode; | 609 | mir_touchscreen_config_get_mapping_mode; |
84 | 608 | mir_touchscreen_config_get_output_id; | 610 | mir_touchscreen_config_get_output_id; |
85 | 609 | mir_touchscreen_config_set_mapping_mode; | 611 | mir_touchscreen_config_set_mapping_mode; |
86 | 610 | 612 | ||
87 | === modified file 'src/protobuf/mir_protobuf.proto' | |||
88 | --- src/protobuf/mir_protobuf.proto 2017-03-23 15:00:37 +0000 | |||
89 | +++ src/protobuf/mir_protobuf.proto 2017-03-29 08:37:58 +0000 | |||
90 | @@ -443,6 +443,7 @@ | |||
91 | 443 | UNKNOWN = 0; | 443 | UNKNOWN = 0; |
92 | 444 | START_DRAG_AND_DROP = 1; | 444 | START_DRAG_AND_DROP = 1; |
93 | 445 | MAKE_ACTIVE = 2; | 445 | MAKE_ACTIVE = 2; |
94 | 446 | USER_MOVE = 3; | ||
95 | 446 | } | 447 | } |
96 | 447 | 448 | ||
97 | 448 | message RequestWithAuthority { | 449 | message RequestWithAuthority { |
98 | 449 | 450 | ||
99 | === modified file 'tests/acceptance-tests/CMakeLists.txt' | |||
100 | --- tests/acceptance-tests/CMakeLists.txt 2017-03-15 09:30:18 +0000 | |||
101 | +++ tests/acceptance-tests/CMakeLists.txt 2017-03-29 08:37:58 +0000 | |||
102 | @@ -3,6 +3,7 @@ | |||
103 | 3 | set( | 3 | set( |
104 | 4 | SOURCES | 4 | SOURCES |
105 | 5 | 5 | ||
106 | 6 | client_mediated_user_gestures.cpp | ||
107 | 6 | drag_and_drop.cpp | 7 | drag_and_drop.cpp |
108 | 7 | 8 | ||
109 | 8 | # Catch double-free bugs by wrapping close() and abort()ing on EBADF | 9 | # Catch double-free bugs by wrapping close() and abort()ing on EBADF |
110 | 9 | 10 | ||
111 | === added file 'tests/acceptance-tests/client_mediated_user_gestures.cpp' | |||
112 | --- tests/acceptance-tests/client_mediated_user_gestures.cpp 1970-01-01 00:00:00 +0000 | |||
113 | +++ tests/acceptance-tests/client_mediated_user_gestures.cpp 2017-03-29 08:37:58 +0000 | |||
114 | @@ -0,0 +1,259 @@ | |||
115 | 1 | /* | ||
116 | 2 | * Copyright © 2017 Canonical Ltd. | ||
117 | 3 | * | ||
118 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
119 | 5 | * under the terms of the GNU General Public License version 3, | ||
120 | 6 | * as published by the Free Software Foundation. | ||
121 | 7 | * | ||
122 | 8 | * This program is distributed in the hope that it will be useful, | ||
123 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
124 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
125 | 11 | * GNU General Public License for more details. | ||
126 | 12 | * | ||
127 | 13 | * You should have received a copy of the GNU General Public License | ||
128 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
129 | 15 | * | ||
130 | 16 | * Authored by: Alan Griffiths <alan@octopull.co.uk> | ||
131 | 17 | */ | ||
132 | 18 | |||
133 | 19 | #include <mir_toolkit/mir_window.h> | ||
134 | 20 | #include <mir_toolkit/mir_blob.h> | ||
135 | 21 | |||
136 | 22 | #include <mir/geometry/displacement.h> | ||
137 | 23 | #include <mir/input/input_device_info.h> | ||
138 | 24 | #include <mir/input/device_capability.h> | ||
139 | 25 | #include <mir/shell/shell.h> | ||
140 | 26 | |||
141 | 27 | #include <mir_test_framework/connected_client_with_a_window.h> | ||
142 | 28 | #include <mir_test_framework/fake_input_device.h> | ||
143 | 29 | #include <mir_test_framework/stub_server_platform_factory.h> | ||
144 | 30 | #include <mir/test/event_factory.h> | ||
145 | 31 | #include <mir/test/signal.h> | ||
146 | 32 | |||
147 | 33 | #include <gmock/gmock.h> | ||
148 | 34 | #include <gtest/gtest.h> | ||
149 | 35 | |||
150 | 36 | #include <linux/input.h> | ||
151 | 37 | |||
152 | 38 | #include <atomic> | ||
153 | 39 | |||
154 | 40 | using namespace std::chrono_literals; | ||
155 | 41 | using namespace mir::geometry; | ||
156 | 42 | using namespace testing; | ||
157 | 43 | using mir::test::Signal; | ||
158 | 44 | |||
159 | 45 | namespace | ||
160 | 46 | { | ||
161 | 47 | class Cookie | ||
162 | 48 | { | ||
163 | 49 | public: | ||
164 | 50 | Cookie() = default; | ||
165 | 51 | |||
166 | 52 | explicit Cookie(MirCookie const* cookie) : self{cookie, deleter} {} | ||
167 | 53 | |||
168 | 54 | operator MirCookie const*() const { return self.get(); } | ||
169 | 55 | |||
170 | 56 | auto get() const -> MirCookie const* { return self.get(); } | ||
171 | 57 | |||
172 | 58 | void reset() { self.reset(); } | ||
173 | 59 | |||
174 | 60 | void reset(MirCookie const* cookie) { self.reset(cookie, deleter); } | ||
175 | 61 | |||
176 | 62 | private: | ||
177 | 63 | static void deleter(MirCookie const* cookie) { mir_cookie_release(cookie); } | ||
178 | 64 | |||
179 | 65 | std::shared_ptr<MirCookie const> self; | ||
180 | 66 | }; | ||
181 | 67 | |||
182 | 68 | void mir_cookie_release(Cookie const&) = delete; | ||
183 | 69 | |||
184 | 70 | struct MouseMoverAndFaker | ||
185 | 71 | { | ||
186 | 72 | void start_dragging_mouse() | ||
187 | 73 | { | ||
188 | 74 | using namespace mir::input::synthesis; | ||
189 | 75 | fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT)); | ||
190 | 76 | } | ||
191 | 77 | |||
192 | 78 | void move_mouse(Displacement const& displacement) | ||
193 | 79 | { | ||
194 | 80 | using mir::input::synthesis::a_pointer_event; | ||
195 | 81 | fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int())); | ||
196 | 82 | } | ||
197 | 83 | |||
198 | 84 | void release_mouse() | ||
199 | 85 | { | ||
200 | 86 | using namespace mir::input::synthesis; | ||
201 | 87 | fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT)); | ||
202 | 88 | } | ||
203 | 89 | |||
204 | 90 | private: | ||
205 | 91 | std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{ | ||
206 | 92 | mir_test_framework::add_fake_input_device( | ||
207 | 93 | mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer}) | ||
208 | 94 | }; | ||
209 | 95 | }; | ||
210 | 96 | |||
211 | 97 | Rectangle const screen_geometry{{0, 0}, {800, 600}}; | ||
212 | 98 | auto const receive_event_timeout = 90s; | ||
213 | 99 | |||
214 | 100 | struct ClientMediatedUserGestures : mir_test_framework::ConnectedClientWithAWindow, | ||
215 | 101 | MouseMoverAndFaker | ||
216 | 102 | { | ||
217 | 103 | void SetUp() override | ||
218 | 104 | { | ||
219 | 105 | initial_display_layout({screen_geometry}); | ||
220 | 106 | mir_test_framework::ConnectedClientWithAWindow::SetUp(); | ||
221 | 107 | mir_window_set_event_handler(window, &window_event_handler, this); | ||
222 | 108 | |||
223 | 109 | paint_window(); | ||
224 | 110 | |||
225 | 111 | center_mouse(); | ||
226 | 112 | } | ||
227 | 113 | |||
228 | 114 | void TearDown() override | ||
229 | 115 | { | ||
230 | 116 | reset_window_event_handler(); | ||
231 | 117 | mir_test_framework::ConnectedClientWithAWindow::TearDown(); | ||
232 | 118 | } | ||
233 | 119 | |||
234 | 120 | auto user_initiates_gesture() -> Cookie; | ||
235 | 121 | |||
236 | 122 | private: | ||
237 | 123 | void center_mouse(); | ||
238 | 124 | void paint_window(); | ||
239 | 125 | void set_window_event_handler(std::function<void(MirEvent const* event)> const& handler); | ||
240 | 126 | void reset_window_event_handler(); | ||
241 | 127 | void invoke_window_event_handler(MirEvent const* event) | ||
242 | 128 | { | ||
243 | 129 | std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; | ||
244 | 130 | window_event_handler_(event); | ||
245 | 131 | } | ||
246 | 132 | |||
247 | 133 | std::mutex window_event_handler_mutex; | ||
248 | 134 | std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {}; | ||
249 | 135 | |||
250 | 136 | static void window_event_handler(MirWindow* window, MirEvent const* event, void* context); | ||
251 | 137 | }; | ||
252 | 138 | |||
253 | 139 | void ClientMediatedUserGestures::set_window_event_handler(std::function<void(MirEvent const* event)> const& handler) | ||
254 | 140 | { | ||
255 | 141 | std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; | ||
256 | 142 | window_event_handler_ = handler; | ||
257 | 143 | } | ||
258 | 144 | |||
259 | 145 | void ClientMediatedUserGestures::reset_window_event_handler() | ||
260 | 146 | { | ||
261 | 147 | std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; | ||
262 | 148 | window_event_handler_ = [](MirEvent const*) {}; | ||
263 | 149 | } | ||
264 | 150 | |||
265 | 151 | void ClientMediatedUserGestures::window_event_handler(MirWindow* /*window*/, MirEvent const* event, void* context) | ||
266 | 152 | { | ||
267 | 153 | static_cast<ClientMediatedUserGestures*>(context)->invoke_window_event_handler(event); | ||
268 | 154 | } | ||
269 | 155 | |||
270 | 156 | void ClientMediatedUserGestures::paint_window() | ||
271 | 157 | { | ||
272 | 158 | Signal have_focus; | ||
273 | 159 | |||
274 | 160 | set_window_event_handler([&](MirEvent const* event) | ||
275 | 161 | { | ||
276 | 162 | if (mir_event_get_type(event) != mir_event_type_window) | ||
277 | 163 | return; | ||
278 | 164 | |||
279 | 165 | auto const window_event = mir_event_get_window_event(event); | ||
280 | 166 | if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus) | ||
281 | 167 | return; | ||
282 | 168 | |||
283 | 169 | if (mir_window_event_get_attribute_value(window_event)) | ||
284 | 170 | have_focus.raise(); | ||
285 | 171 | }); | ||
286 | 172 | |||
287 | 173 | mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(window)); | ||
288 | 174 | |||
289 | 175 | EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true)); | ||
290 | 176 | |||
291 | 177 | reset_window_event_handler(); | ||
292 | 178 | } | ||
293 | 179 | |||
294 | 180 | void ClientMediatedUserGestures::center_mouse() | ||
295 | 181 | { | ||
296 | 182 | Signal have_mouseover; | ||
297 | 183 | |||
298 | 184 | set_window_event_handler([&](MirEvent const* event) | ||
299 | 185 | { | ||
300 | 186 | if (mir_event_get_type(event) != mir_event_type_input) | ||
301 | 187 | return; | ||
302 | 188 | |||
303 | 189 | auto const input_event = mir_event_get_input_event(event); | ||
304 | 190 | |||
305 | 191 | if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) | ||
306 | 192 | return; | ||
307 | 193 | |||
308 | 194 | auto const pointer_event = mir_input_event_get_pointer_event(input_event); | ||
309 | 195 | |||
310 | 196 | if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) | ||
311 | 197 | return; | ||
312 | 198 | |||
313 | 199 | have_mouseover.raise(); | ||
314 | 200 | }); | ||
315 | 201 | |||
316 | 202 | move_mouse(0.5 * as_displacement(screen_geometry.size)); | ||
317 | 203 | |||
318 | 204 | // We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20). | ||
319 | 205 | // But it isn't essential for the test and we've probably waited long enough | ||
320 | 206 | // for the mouse-down needed by the test to reach the window. | ||
321 | 207 | // EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true)); | ||
322 | 208 | have_mouseover.wait_for(receive_event_timeout); | ||
323 | 209 | |||
324 | 210 | reset_window_event_handler(); | ||
325 | 211 | } | ||
326 | 212 | |||
327 | 213 | auto ClientMediatedUserGestures::user_initiates_gesture() -> Cookie | ||
328 | 214 | { | ||
329 | 215 | Cookie cookie; | ||
330 | 216 | Signal have_cookie; | ||
331 | 217 | |||
332 | 218 | set_window_event_handler([&](MirEvent const* event) | ||
333 | 219 | { | ||
334 | 220 | if (mir_event_get_type(event) != mir_event_type_input) | ||
335 | 221 | return; | ||
336 | 222 | |||
337 | 223 | auto const input_event = mir_event_get_input_event(event); | ||
338 | 224 | |||
339 | 225 | if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) | ||
340 | 226 | return; | ||
341 | 227 | |||
342 | 228 | auto const pointer_event = mir_input_event_get_pointer_event(input_event); | ||
343 | 229 | |||
344 | 230 | if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down) | ||
345 | 231 | return; | ||
346 | 232 | |||
347 | 233 | cookie = Cookie{mir_input_event_get_cookie(input_event)}; | ||
348 | 234 | have_cookie.raise(); | ||
349 | 235 | }); | ||
350 | 236 | |||
351 | 237 | start_dragging_mouse(); | ||
352 | 238 | |||
353 | 239 | EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true)); | ||
354 | 240 | |||
355 | 241 | reset_window_event_handler(); | ||
356 | 242 | return cookie; | ||
357 | 243 | } | ||
358 | 244 | } | ||
359 | 245 | |||
360 | 246 | TEST_F(ClientMediatedUserGestures, when_user_initiates_gesture_client_receives_cookie) | ||
361 | 247 | { | ||
362 | 248 | auto const cookie = user_initiates_gesture(); | ||
363 | 249 | |||
364 | 250 | EXPECT_THAT(cookie.get(), NotNull()); | ||
365 | 251 | } | ||
366 | 252 | |||
367 | 253 | // TODO extend this test when server side implemented | ||
368 | 254 | TEST_F(ClientMediatedUserGestures, when_client_initiates_move_nothing_bad_happens) | ||
369 | 255 | { | ||
370 | 256 | auto const cookie = user_initiates_gesture(); | ||
371 | 257 | |||
372 | 258 | mir_window_request_user_move(window, cookie); | ||
373 | 259 | } | ||
374 | 0 | 260 | ||
375 | === modified file 'tests/acceptance-tests/drag_and_drop.cpp' | |||
376 | --- tests/acceptance-tests/drag_and_drop.cpp 2017-03-17 15:32:15 +0000 | |||
377 | +++ tests/acceptance-tests/drag_and_drop.cpp 2017-03-29 08:37:58 +0000 | |||
378 | @@ -213,6 +213,7 @@ | |||
379 | 213 | 213 | ||
380 | 214 | void DragAndDrop::reset_window_event_handler(MirWindow* window) | 214 | void DragAndDrop::reset_window_event_handler(MirWindow* window) |
381 | 215 | { | 215 | { |
382 | 216 | std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; | ||
383 | 216 | if (window == this->window) window_event_handler_ = [](MirEvent const*) {}; | 217 | if (window == this->window) window_event_handler_ = [](MirEvent const*) {}; |
384 | 217 | if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {}; | 218 | if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {}; |
385 | 218 | } | 219 | } |
PASSED: Continuous integration, rev:4112 /mir-jenkins. ubuntu. com/job/ mir-ci/ 3238/ /mir-jenkins. ubuntu. com/job/ build-mir/ 4358 /mir-jenkins. ubuntu. com/job/ build-0- fetch/4445 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 4435 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 4435 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= zesty/4435 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= zesty/4390 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= zesty/4390/ artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4390 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4390/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= zesty/4390 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= zesty/4390/ artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 4390 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 4390/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 4390 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 4390/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4390 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4390/artifact/ output/ *zip*/output. zip
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:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 3238/rebuild
https:/