Merge lp:~alan-griffiths/mir/drag-and-drop-II into lp:mir
- drag-and-drop-II
- Merge into development-branch
Status: | Superseded |
---|---|
Proposed branch: | lp:~alan-griffiths/mir/drag-and-drop-II |
Merge into: | lp:mir |
Diff against target: |
2548 lines (+1425/-27) 75 files modified
examples/server_example_basic_window_manager.cpp (+8/-0) examples/server_example_basic_window_manager.h (+5/-0) include/client/mir/events/event_builders.h (+2/-0) include/client/mir_toolkit/extensions/drag_and_drop.h (+81/-0) include/server/mir/scene/null_surface_observer.h (+1/-0) include/server/mir/scene/surface.h (+1/-0) include/server/mir/scene/surface_observer.h (+2/-0) include/server/mir/shell/abstract_shell.h (+8/-0) include/server/mir/shell/focus_controller.h (+5/-0) include/server/mir/shell/input_targeter.h (+5/-0) include/server/mir/shell/shell.h (+4/-0) include/server/mir/shell/shell_wrapper.h (+8/-0) include/server/mir/shell/system_compositor_window_manager.h (+5/-0) include/server/mir/shell/window_manager.h (+5/-0) include/test/mir/test/doubles/mock_window_manager.h (+1/-0) include/test/mir/test/doubles/stub_surface.h (+1/-0) include/test/mir_test_framework/observant_shell.h (+8/-0) src/capnproto/mir_event.capnp (+5/-1) src/client/CMakeLists.txt (+2/-0) src/client/drag_and_drop.cpp (+85/-0) src/client/drag_and_drop.h (+32/-0) src/client/events/event_builders.cpp (+25/-0) src/client/mir_blob.cpp (+1/-8) src/client/mir_connection.cpp (+4/-0) src/client/mir_surface.cpp (+32/-0) src/client/mir_surface.h (+4/-0) src/client/rpc/mir_display_server.cpp (+9/-0) src/client/rpc/mir_display_server.h (+4/-0) src/client/symbols.map (+2/-0) src/common/events/pointer_event.cpp (+41/-3) src/common/events/surface_event.cpp (+39/-1) src/common/symbols.map (+4/-0) src/include/common/mir/events/pointer_event.h (+6/-1) src/include/common/mir/events/surface_event.h (+6/-1) src/include/common/mir/protobuf/display_server.h (+4/-0) src/include/common/mir_blob.h (+32/-0) src/include/server/mir/frontend/shell.h (+5/-0) src/include/server/mir/scene/surface_event_source.h (+1/-0) src/include/server/mir/scene/surface_observers.h (+1/-0) src/include/server/mir/shell/basic_window_manager.h (+15/-0) src/include/server/mir/shell/canonical_window_manager.h (+4/-0) src/protobuf/mir_protobuf.proto (+5/-0) src/protobuf/symbols.map (+26/-0) src/server/frontend/protobuf_message_processor.cpp (+4/-0) src/server/frontend/session_mediator.cpp (+20/-1) src/server/frontend/session_mediator.h (+4/-0) src/server/frontend/shell_wrapper.cpp (+8/-0) src/server/frontend/shell_wrapper.h (+5/-0) src/server/input/null_input_targeter.h (+3/-0) src/server/input/surface_input_dispatcher.cpp (+42/-8) src/server/input/surface_input_dispatcher.h (+5/-1) src/server/scene/basic_surface.cpp (+11/-0) src/server/scene/basic_surface.h (+1/-0) src/server/scene/legacy_surface_change_notification.cpp (+4/-0) src/server/scene/legacy_surface_change_notification.h (+1/-0) src/server/scene/null_surface_observer.cpp (+1/-0) src/server/scene/surface_event_source.cpp (+5/-0) src/server/shell/abstract_shell.cpp (+17/-0) src/server/shell/basic_window_manager.cpp (+21/-0) src/server/shell/canonical_window_manager.cpp (+13/-0) src/server/shell/frontend_shell.cpp (+10/-0) src/server/shell/frontend_shell.h (+5/-0) src/server/shell/shell_wrapper.cpp (+18/-0) src/server/shell/system_compositor_window_manager.cpp (+7/-0) src/server/symbols.map (+10/-0) tests/acceptance-tests/CMakeLists.txt (+2/-0) tests/acceptance-tests/drag_and_drop.cpp (+624/-0) tests/acceptance-tests/test_client_cursor_api.cpp (+1/-0) tests/include/mir/test/doubles/mock_input_targeter.h (+3/-0) tests/include/mir/test/doubles/mock_shell.h (+3/-0) tests/include/mir/test/doubles/stub_display_server.h (+4/-0) tests/include/mir/test/doubles/stub_input_targeter.h (+3/-0) tests/include/mir/test/doubles/stub_scene_surface.h (+1/-0) tests/mir_test_framework/observant_shell.cpp (+21/-2) tests/mir_test_framework/stub_surface.cpp (+4/-0) |
To merge this branch: | bzr merge lp:~alan-griffiths/mir/drag-and-drop-II |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Needs Information | ||
Andreas Pokorny (community) | Needs Information | ||
Chris Halse Rogers | Needs Information | ||
Brandon Schaefer (community) | Approve | ||
Cemil Azizoglu (community) | Needs Information | ||
Mir CI Bot | continuous-integration | Approve | |
Kevin DuBois (community) | Approve | ||
Review via email: mp+319820@code.launchpad.net |
This proposal supersedes a proposal from 2017-03-13.
This proposal has been superseded by a proposal from 2017-03-17.
Commit message
Initial support for Drag and Drop: tests (and implementation for) starting drag and releasing on target surface
Description of the change
Initial support for Drag and Drop: tests (and implementation for) starting drag and releasing on target surface
One more episode to follow for handling the cancellation from content hub.
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
18:39:25 [ RUN ] DragAndDrop.
...
18:39:25 /<<BUILDDIR>
18:39:25 Value of: have_cookie.
18:39:25 Expected: is equal to true
18:39:25 Actual: false (of type bool)
18:39:25 ==11713== Invalid read of size 8
The memory errors and FD leaks that follow result from following the resulting nullptr.
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
> 18:39:25 [ RUN ]
> DragAndDrop.
> ...
> 18:39:25 /<<BUILDDIR>
> tests/drag_
> 18:39:25 Value of: have_cookie.
> 18:39:25 Expected: is equal to true
> 18:39:25 Actual: false (of type bool)
> 18:39:25 ==11713== Invalid read of size 8
>
> The memory errors and FD leaks that follow result from following the resulting
> nullptr.
Hmm wrong paste buffer, but still I don't see how this can happen:
18:35:34 11: [ RUN ] DragAndDrop.
...
18:37:06 11: /<<BUILDDIR>
18:37:06 11: Value of: have_cookie.
18:37:06 11: Expected: is equal to true
18:37:06 11: Actual: false (of type bool)
18:37:06 11: ==11713== Invalid read of size 8
Basically, the click isn't seen by the window. And on this branch the window has definitely received {mir_window_
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:4088
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: 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:4089
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:/
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:4090
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:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:4091
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Alan Griffiths (alan-griffiths) wrote : | # |
Failure is unrelated (lp:1660889)
So that's 3 CI runs with the new tests passing. (And soak testing them locally.)
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4092
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:/
Kevin DuBois (kdub) wrote : | # |
l773 could use comment here as well (like the other comment noting how CapPnP has problems)
+ //std::
+// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20).
1995 +// But it isn't essential for the test and we've probably waited long enough
1996 +// for the mouse-down needed by the test to reach the window.
1997 +// EXPECT_
does that need a bug?
both those minor, lgtm overall
Alan Griffiths (alan-griffiths) wrote : | # |
> l773 could use comment here as well (like the other comment noting how CapPnP
> has problems)
> + //std::
> back_inserter(
Fixed.
> +// We miss the "mouseover" occasionally (with valgrind and heavy stress about
> 1/20).
> 1995 +// But it isn't essential for the test and we've probably waited long
> enough
> 1996 +// for the mouse-down needed by the test to reach the window.
> 1997 +// EXPECT_
> Eq(true));
> does that need a bug?
Possibly. It would appear there is a lack of consistency between the window management "model" that says the surface is ready and has focus (hence the mir_window_
I doubt we'll see an issue in "real life".
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4094
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:/
Cemil Azizoglu (cemil-azizoglu) wrote : | # |
Why is this an extension? Because it requires an outside entity like a content hub?
-------
Is this needed?
130 + mir_surface_
-------
Alan Griffiths (alan-griffiths) wrote : | # |
> Why is this an extension? Because it requires an outside entity like a content
> hub?
So that we can evolve the API without breaking ABI
> Is this needed?
>
> 130 + mir_surface_
> -------
It doesn't have to be done this way, but the mir_surface_attribs and mir_window_attribs enum members have to be kept in step somehow. This seemed the clearest approach.
Kevin DuBois (kdub) wrote : | # |
> > Why is this an extension? Because it requires an outside entity like a
> content
> > hub?
>
> So that we can evolve the API without breaking ABI
+1 to evolving client api this way, keeps 1.0 stable, and can be incorporated to main api once the work is done and there are no more warts.
Brandon Schaefer (brandontschaefer) wrote : | # |
lgtm
Chris Halse Rogers (raof) wrote : | # |
Needs info:
I'm not sure that overriding the events is appropriate - as I understand it, this will result in Mir sending pointer_
It looks like this will cause clients to behave incorrectly unless their event handler checks each pointer event for a drag handle, and treats pointer events with drag handles as not pointer events?
For example: given a client B that doesn't check pointer events for drag handles, if you initiate a drag and then move the pointer over B's window, this will act like you're just moving the pointer normally over B's window, and B will highlight buttons, perform on-hover actions, and so on? And then if you release the drag over a button in B's window, B will respond as if you mouse-button-
Nit: The locking in
+void MirSurface:
appears unnecessary? All of the things it accesses are stack variables (cookie) or written-
Is the locking for the appeasement of ThreadSanitizer?
Andreas Pokorny (andreas-pokorny) wrote : | # |
> Needs info:
> I'm not sure that overriding the events is appropriate - as I understand it,
> this will result in Mir sending pointer_
> events in cases where we currently don't?
Yes leaving the boundaries of a window even when buttons are pressed will cause the source window to receive a pointer leave and potentially crossed windows to receive pointer_enter and motion events even though pointer buttons are still pressed.
>
> It looks like this will cause clients to behave incorrectly unless their event
> handler checks each pointer event for a drag handle, and treats pointer events
> with drag handles as not pointer events?
I doubt ui toolkits unaware of the drag handle will treat it as a click sequence, so there is wrong behavior but not really severe.
We cannot safely expand enums with extensions - so we either expand the MirPointerAction enum in an unsafe and problematic way (i.e. we have values like mir_pointer_
Andreas Pokorny (andreas-pokorny) wrote : | # |
Now looking again - why do we need a surface attribute for drag and drop?
Are downstreams using values like: mir_window_attribs?
I think we should remove those.
Besides the enum changes and window attribute - lgtm
Alan Griffiths (alan-griffiths) wrote : | # |
> > Needs info:
> > I'm not sure that overriding the events is appropriate - as I understand it,
> > this will result in Mir sending pointer_
> > events in cases where we currently don't?
>
> Yes leaving the boundaries of a window even when buttons are pressed will
> cause the source window to receive a pointer leave and potentially crossed
> windows to receive pointer_enter and motion events even though pointer buttons
> are still pressed.
>
> >
> > It looks like this will cause clients to behave incorrectly unless their
> event
> > handler checks each pointer event for a drag handle, and treats pointer
> events
> > with drag handles as not pointer events?
>
> I doubt ui toolkits unaware of the drag handle will treat it as a click
> sequence, so there is wrong behavior but not really severe.
The Nuremberg defence: https:/
Alan Griffiths (alan-griffiths) wrote : | # |
> Now looking again - why do we need a surface attribute for drag and drop?
>
> Are downstreams using values like: mir_window_attribs?
>
> I think we should remove those.
>
> Besides the enum changes and window attribute - lgtm
We needed some event to carry the drag handle. Extending the window event seemed the path of least resistance. But we've hard-coded the existence of an attribute value pair into the API.
I can think of two alternatives:
/1/ Use window events as the transport, but filter out those with a D&D handle (and pass the handle to an entirely separate callback registered through the extension API).
/2/ Introduce a new drag-and-drop event to the transport.
If we were to introduce a new drag-and-drop event to carry the initial handle then we could also use it for leave/enter/
OTOH /1/ seems simpler.
*Seeking guidance* on /1/ or /2/
Andreas Pokorny (andreas-pokorny) wrote : | # |
Which route will allow us to easily expand drag and drop to touch guestures?
Alan Griffiths (alan-griffiths) wrote : | # |
> Which route will allow us to easily expand drag and drop to touch guestures?
I imagine the client-side processing needs to be different (i.e. different visual effects) so it might be easier to "piggy back" on the existing input events. But without a design for D&D touch I can't be sure.
/me wonders if Unity7 has prior art.
Chris Halse Rogers (raof) wrote : | # |
I'd be reasonably happy with (1).
If people don't like throwing in an ad-hoc callback for each extension, an alternative would be to assign event types *in* the extension, like so:
struct DnDv1
{
int (*dnd_event_
MirDndEvent const* (*dnd_event_
MirBlob* (*dnd_event_
MirDndAction (*dnd_event_
}
…
DnDv1* dnd = mir_drag_
…
<in event handler>
if (mir_event_
{
MirDndEvent const* dnd_event = dnd->dnd_
if (dnd->dnd_
{
…
}
}
I prefer this to one-callback-
Alan Griffiths (alan-griffiths) wrote : | # |
> I'd be reasonably happy with (1).
>
> If people don't like throwing in an ad-hoc callback for each extension, an
> alternative would be to assign event types *in* the extension, like so:
...
> if (mir_event_
Perhaps:
- if (mir_event_
+ if (dnd && dnd->is_
Chris Halse Rogers (raof) wrote : | # |
Also happy with that :)
Preview Diff
1 | === modified file 'examples/server_example_basic_window_manager.cpp' |
2 | --- examples/server_example_basic_window_manager.cpp 2017-01-18 02:29:37 +0000 |
3 | +++ examples/server_example_basic_window_manager.cpp 2017-03-17 15:49:43 +0000 |
4 | @@ -136,6 +136,14 @@ |
5 | policy->handle_raise_surface(session, surface); |
6 | } |
7 | |
8 | +void me::BasicWindowManager::handle_request_drag_and_drop( |
9 | + std::shared_ptr<scene::Session> const& /*session*/, |
10 | + std::shared_ptr<scene::Surface> const& /*surface*/, |
11 | + uint64_t /*timestamp*/) |
12 | +{ |
13 | + // Not supported in example servers |
14 | +} |
15 | + |
16 | int me::BasicWindowManager::set_surface_attribute( |
17 | std::shared_ptr<scene::Session> const& /*session*/, |
18 | std::shared_ptr<scene::Surface> const& surface, |
19 | |
20 | === modified file 'examples/server_example_basic_window_manager.h' |
21 | --- examples/server_example_basic_window_manager.h 2017-01-18 02:29:37 +0000 |
22 | +++ examples/server_example_basic_window_manager.h 2017-03-17 15:49:43 +0000 |
23 | @@ -174,6 +174,11 @@ |
24 | std::shared_ptr<scene::Surface> const& surface, |
25 | uint64_t timestamp) override; |
26 | |
27 | + void handle_request_drag_and_drop( |
28 | + std::shared_ptr<scene::Session> const& session, |
29 | + std::shared_ptr<scene::Surface> const& surface, |
30 | + uint64_t timestamp) override; |
31 | + |
32 | int set_surface_attribute( |
33 | std::shared_ptr<scene::Session> const& /*session*/, |
34 | std::shared_ptr<scene::Surface> const& surface, |
35 | |
36 | === modified file 'include/client/mir/events/event_builders.h' |
37 | --- include/client/mir/events/event_builders.h 2017-02-15 13:36:35 +0000 |
38 | +++ include/client/mir/events/event_builders.h 2017-03-17 15:49:43 +0000 |
39 | @@ -161,6 +161,8 @@ |
40 | void transform_positions(MirEvent& event, mir::geometry::Displacement const& movement); |
41 | void set_window_id(MirEvent& event, int window_id); |
42 | |
43 | +EventUPtr make_start_drag_and_drop_event(frontend::SurfaceId const& surface_id, std::vector<uint8_t> const& handle); |
44 | +void set_drag_and_drop_handle(MirEvent& event, std::vector<uint8_t> const& handle); |
45 | } |
46 | } |
47 | |
48 | |
49 | === added file 'include/client/mir_toolkit/extensions/drag_and_drop.h' |
50 | --- include/client/mir_toolkit/extensions/drag_and_drop.h 1970-01-01 00:00:00 +0000 |
51 | +++ include/client/mir_toolkit/extensions/drag_and_drop.h 2017-03-17 15:49:43 +0000 |
52 | @@ -0,0 +1,81 @@ |
53 | +/* |
54 | + * Copyright © 2017 Canonical Ltd. |
55 | + * |
56 | + * This program is free software: you can redistribute it and/or modify it |
57 | + * under the terms of the GNU Lesser General Public License version 3, |
58 | + * as published by the Free Software Foundation. |
59 | + * |
60 | + * This program is distributed in the hope that it will be useful, |
61 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
62 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
63 | + * GNU Lesser General Public License for more details. |
64 | + * |
65 | + * You should have received a copy of the GNU Lesser General Public License |
66 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
67 | + * |
68 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
69 | + */ |
70 | + |
71 | +#ifndef MIR_DRAG_AND_DROP_H |
72 | +#define MIR_DRAG_AND_DROP_H |
73 | + |
74 | +#include "mir_toolkit/mir_extension_core.h" |
75 | +#include "mir_toolkit/client_types.h" |
76 | + |
77 | +#ifdef __cplusplus |
78 | +extern "C" { |
79 | +#endif |
80 | + |
81 | +typedef struct MirDragAndDropEvent MirDragAndDropEvent; |
82 | + |
83 | +typedef struct MirDragAndDropV1 |
84 | +{ |
85 | + /** |
86 | + * Request drag and drop. If the request succeeds a window event with a |
87 | + * "start drag" handle will be received. |
88 | + * |
89 | + * \warning An invalid cookie will terminate the client connection. |
90 | + * |
91 | + * \param [in] window The source window |
92 | + * \param [in] cookie A cookie instance obtained from an input event. |
93 | + */ |
94 | + void (*request_drag_and_drop)(MirWindow* window, MirCookie const* cookie); |
95 | + |
96 | + /** |
97 | + * Set the drag and drop callback. This receives |
98 | + * |
99 | + * \param [in] window The window |
100 | + * \param [in] callback The callback function. |
101 | + * \param [in] context To be passed to callback |
102 | + */ |
103 | + void (*set_start_drag_and_drop_callback)(MirWindow* window, |
104 | + void (*callback)(MirWindow* window, MirDragAndDropEvent const* event, void* context), |
105 | + void* context); |
106 | + |
107 | + /** |
108 | + * Retrieve any "drag & drop" handle associated with the event. |
109 | + * |
110 | + * \param [in] event The event |
111 | + * \return The associated drag handle or NULL |
112 | + */ |
113 | + MirBlob* (*start_drag_and_drop)(MirDragAndDropEvent const* event); |
114 | + |
115 | + /** |
116 | + * Retrieve any "drag & drop" handle associated with the event. |
117 | + * |
118 | + * \param [in] event The event |
119 | + * \return The associated drag handle or NULL |
120 | + */ |
121 | + MirBlob* (*pointer_drag_and_drop)(MirPointerEvent const* event); |
122 | + |
123 | +} MirDragAndDropV1; |
124 | + |
125 | +static inline MirDragAndDropV1 const* mir_drag_and_drop_v1(MirConnection* connection) |
126 | +{ |
127 | + return (MirDragAndDropV1 const*) mir_connection_request_extension(connection, "mir_drag_and_drop", 1); |
128 | +} |
129 | + |
130 | +#ifdef __cplusplus |
131 | +} |
132 | +#endif |
133 | +#endif //MIR_DRAG_AND_DROP_H |
134 | \ No newline at end of file |
135 | |
136 | === modified file 'include/server/mir/scene/null_surface_observer.h' |
137 | --- include/server/mir/scene/null_surface_observer.h 2017-02-15 13:36:35 +0000 |
138 | +++ include/server/mir/scene/null_surface_observer.h 2017-03-17 15:49:43 +0000 |
139 | @@ -47,6 +47,7 @@ |
140 | void cursor_image_removed() override; |
141 | void placed_relative(geometry::Rectangle const& placement) override; |
142 | void input_consumed(MirEvent const* event) override; |
143 | + void start_drag_and_drop(std::vector<uint8_t> const& handle) override; |
144 | |
145 | protected: |
146 | NullSurfaceObserver(NullSurfaceObserver const&) = delete; |
147 | |
148 | === modified file 'include/server/mir/scene/surface.h' |
149 | --- include/server/mir/scene/surface.h 2017-02-15 14:45:41 +0000 |
150 | +++ include/server/mir/scene/surface.h 2017-03-17 15:49:43 +0000 |
151 | @@ -116,6 +116,7 @@ |
152 | virtual MirPointerConfinementState confine_pointer_state() const = 0; |
153 | |
154 | virtual void placed_relative(geometry::Rectangle const& placement) = 0; |
155 | + virtual void start_drag_and_drop(std::vector<uint8_t> const& handle) = 0; |
156 | }; |
157 | } |
158 | } |
159 | |
160 | === modified file 'include/server/mir/scene/surface_observer.h' |
161 | --- include/server/mir/scene/surface_observer.h 2017-02-15 13:36:35 +0000 |
162 | +++ include/server/mir/scene/surface_observer.h 2017-03-17 15:49:43 +0000 |
163 | @@ -27,6 +27,7 @@ |
164 | |
165 | #include <glm/glm.hpp> |
166 | #include <string> |
167 | +#include <vector> |
168 | |
169 | namespace mir |
170 | { |
171 | @@ -62,6 +63,7 @@ |
172 | virtual void cursor_image_removed() = 0; |
173 | virtual void placed_relative(geometry::Rectangle const& placement) = 0; |
174 | virtual void input_consumed(MirEvent const* event) = 0; |
175 | + virtual void start_drag_and_drop(std::vector<uint8_t> const& handle) = 0; |
176 | |
177 | protected: |
178 | SurfaceObserver() = default; |
179 | |
180 | === modified file 'include/server/mir/shell/abstract_shell.h' |
181 | --- include/server/mir/shell/abstract_shell.h 2017-01-18 02:29:37 +0000 |
182 | +++ include/server/mir/shell/abstract_shell.h 2017-03-17 15:49:43 +0000 |
183 | @@ -82,6 +82,11 @@ |
184 | std::shared_ptr<scene::Surface> const& surface, |
185 | uint64_t timestamp) override; |
186 | |
187 | + void request_drag_and_drop( |
188 | + std::shared_ptr<scene::Session> const& session, |
189 | + std::shared_ptr<scene::Surface> const& surface, |
190 | + uint64_t timestamp) override; |
191 | + |
192 | std::shared_ptr<scene::PromptSession> start_prompt_session_for( |
193 | std::shared_ptr<scene::Session> const& session, |
194 | scene::PromptSessionCreationParameters const& params) override; |
195 | @@ -124,6 +129,9 @@ |
196 | |
197 | void update_focused_surface_confined_region(); |
198 | |
199 | + void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override; |
200 | + void clear_drag_and_drop_handle() override; |
201 | + |
202 | protected: |
203 | std::shared_ptr<InputTargeter> const input_targeter; |
204 | std::shared_ptr<SurfaceStack> const surface_stack; |
205 | |
206 | === modified file 'include/server/mir/shell/focus_controller.h' |
207 | --- include/server/mir/shell/focus_controller.h 2016-01-29 08:18:22 +0000 |
208 | +++ include/server/mir/shell/focus_controller.h 2017-03-17 15:49:43 +0000 |
209 | @@ -19,8 +19,10 @@ |
210 | #ifndef MIR_SHELL_FOCUS_CONTROLLER_H_ |
211 | #define MIR_SHELL_FOCUS_CONTROLLER_H_ |
212 | |
213 | +#include <stddef.h> |
214 | #include <memory> |
215 | #include <set> |
216 | +#include <vector> |
217 | |
218 | namespace mir |
219 | { |
220 | @@ -54,6 +56,9 @@ |
221 | |
222 | virtual void raise(SurfaceSet const& surfaces) = 0; |
223 | |
224 | + virtual void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) = 0; |
225 | + virtual void clear_drag_and_drop_handle() = 0; |
226 | + |
227 | protected: |
228 | FocusController() = default; |
229 | FocusController(FocusController const&) = delete; |
230 | |
231 | === modified file 'include/server/mir/shell/input_targeter.h' |
232 | --- include/server/mir/shell/input_targeter.h 2015-06-18 02:46:16 +0000 |
233 | +++ include/server/mir/shell/input_targeter.h 2017-03-17 15:49:43 +0000 |
234 | @@ -19,7 +19,9 @@ |
235 | #ifndef MIR_SHELL_INPUT_TARGETER_H_ |
236 | #define MIR_SHELL_INPUT_TARGETER_H_ |
237 | |
238 | +#include <stddef.h> |
239 | #include <memory> |
240 | +#include <vector> |
241 | |
242 | namespace mir |
243 | { |
244 | @@ -40,6 +42,9 @@ |
245 | virtual void set_focus(std::shared_ptr<input::Surface> const& focus_surface) = 0; |
246 | virtual void clear_focus() = 0; |
247 | |
248 | + virtual void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) = 0; |
249 | + virtual void clear_drag_and_drop_handle() = 0; |
250 | + |
251 | protected: |
252 | InputTargeter() = default; |
253 | InputTargeter(InputTargeter const&) = delete; |
254 | |
255 | === modified file 'include/server/mir/shell/shell.h' |
256 | --- include/server/mir/shell/shell.h 2017-01-19 00:27:55 +0000 |
257 | +++ include/server/mir/shell/shell.h 2017-03-17 15:49:43 +0000 |
258 | @@ -100,6 +100,10 @@ |
259 | std::shared_ptr<scene::Surface> const& surface, |
260 | uint64_t timestamp) = 0; |
261 | |
262 | + virtual void request_drag_and_drop( |
263 | + std::shared_ptr<scene::Session> const& session, |
264 | + std::shared_ptr<scene::Surface> const& surface, |
265 | + uint64_t timestamp) = 0; |
266 | /** @} */ |
267 | }; |
268 | } |
269 | |
270 | === modified file 'include/server/mir/shell/shell_wrapper.h' |
271 | --- include/server/mir/shell/shell_wrapper.h 2017-01-18 02:29:37 +0000 |
272 | +++ include/server/mir/shell/shell_wrapper.h 2017-03-17 15:49:43 +0000 |
273 | @@ -85,11 +85,19 @@ |
274 | std::shared_ptr<scene::Surface> const& surface, |
275 | uint64_t timestamp) override; |
276 | |
277 | + void request_drag_and_drop( |
278 | + std::shared_ptr<scene::Session> const& session, |
279 | + std::shared_ptr<scene::Surface> const& surface, |
280 | + uint64_t timestamp) override; |
281 | + |
282 | void add_display(geometry::Rectangle const& area) override; |
283 | void remove_display(geometry::Rectangle const& area) override; |
284 | |
285 | bool handle(MirEvent const& event) override; |
286 | |
287 | + void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override; |
288 | + void clear_drag_and_drop_handle() override; |
289 | + |
290 | protected: |
291 | std::shared_ptr<Shell> const wrapped; |
292 | }; |
293 | |
294 | === modified file 'include/server/mir/shell/system_compositor_window_manager.h' |
295 | --- include/server/mir/shell/system_compositor_window_manager.h 2017-01-18 02:29:37 +0000 |
296 | +++ include/server/mir/shell/system_compositor_window_manager.h 2017-03-17 15:49:43 +0000 |
297 | @@ -95,6 +95,11 @@ |
298 | std::shared_ptr<scene::Surface> const& surface, |
299 | uint64_t timestamp) override; |
300 | |
301 | + void handle_request_drag_and_drop( |
302 | + std::shared_ptr<scene::Session> const& session, |
303 | + std::shared_ptr<scene::Surface> const& surface, |
304 | + uint64_t timestamp) override; |
305 | + |
306 | int set_surface_attribute( |
307 | std::shared_ptr<scene::Session> const& session, |
308 | std::shared_ptr<scene::Surface> const& surface, |
309 | |
310 | === modified file 'include/server/mir/shell/window_manager.h' |
311 | --- include/server/mir/shell/window_manager.h 2017-01-18 02:29:37 +0000 |
312 | +++ include/server/mir/shell/window_manager.h 2017-03-17 15:49:43 +0000 |
313 | @@ -76,6 +76,11 @@ |
314 | std::shared_ptr<scene::Surface> const& surface, |
315 | uint64_t timestamp) = 0; |
316 | |
317 | + virtual void handle_request_drag_and_drop( |
318 | + std::shared_ptr<scene::Session> const& session, |
319 | + std::shared_ptr<scene::Surface> const& surface, |
320 | + uint64_t timestamp) = 0; |
321 | + |
322 | virtual ~WindowManager() = default; |
323 | WindowManager() = default; |
324 | WindowManager(WindowManager const&) = delete; |
325 | |
326 | === modified file 'include/test/mir/test/doubles/mock_window_manager.h' |
327 | --- include/test/mir/test/doubles/mock_window_manager.h 2017-01-18 02:29:37 +0000 |
328 | +++ include/test/mir/test/doubles/mock_window_manager.h 2017-03-17 15:49:43 +0000 |
329 | @@ -58,6 +58,7 @@ |
330 | MOCK_METHOD1(handle_pointer_event, bool(MirPointerEvent const*)); |
331 | |
332 | MOCK_METHOD3(handle_raise_surface, void(std::shared_ptr<scene::Session> const&, std::shared_ptr<scene::Surface> const&, uint64_t)); |
333 | + MOCK_METHOD3(handle_request_drag_and_drop, void(std::shared_ptr<scene::Session> const&, std::shared_ptr<scene::Surface> const&, uint64_t)); |
334 | |
335 | MOCK_METHOD4(set_surface_attribute, |
336 | int(std::shared_ptr<scene::Session> const& session, |
337 | |
338 | === modified file 'include/test/mir/test/doubles/stub_surface.h' |
339 | --- include/test/mir/test/doubles/stub_surface.h 2017-02-15 14:45:41 +0000 |
340 | +++ include/test/mir/test/doubles/stub_surface.h 2017-03-17 15:49:43 +0000 |
341 | @@ -70,6 +70,7 @@ |
342 | void set_confine_pointer_state(MirPointerConfinementState state) override; |
343 | MirPointerConfinementState confine_pointer_state() const override; |
344 | void placed_relative(geometry::Rectangle const& placement) override; |
345 | + void start_drag_and_drop(std::vector<uint8_t> const& handle) override; |
346 | }; |
347 | } |
348 | } |
349 | |
350 | === modified file 'include/test/mir_test_framework/observant_shell.h' |
351 | --- include/test/mir_test_framework/observant_shell.h 2017-01-20 00:01:50 +0000 |
352 | +++ include/test/mir_test_framework/observant_shell.h 2017-03-17 15:49:43 +0000 |
353 | @@ -96,6 +96,14 @@ |
354 | std::shared_ptr<mir::scene::Surface> const& window, |
355 | uint64_t timestamp) override; |
356 | |
357 | + void request_drag_and_drop( |
358 | + std::shared_ptr<mir::scene::Session> const& session, |
359 | + std::shared_ptr<mir::scene::Surface> const& window, |
360 | + uint64_t timestamp) override; |
361 | + |
362 | + void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override; |
363 | + void clear_drag_and_drop_handle() override; |
364 | + |
365 | private: |
366 | std::shared_ptr<mir::shell::Shell> const wrapped; |
367 | std::shared_ptr<mir::scene::SurfaceObserver> const surface_observer; |
368 | |
369 | === modified file 'src/capnproto/mir_event.capnp' |
370 | --- src/capnproto/mir_event.capnp 2017-02-17 08:46:05 +0000 |
371 | +++ src/capnproto/mir_event.capnp 2017-03-17 15:49:43 +0000 |
372 | @@ -104,6 +104,8 @@ |
373 | |
374 | buttons @7 :UInt32; |
375 | |
376 | + dndHandle @8 :List(UInt8); |
377 | + |
378 | enum PointerAction |
379 | { |
380 | up @0; |
381 | @@ -149,6 +151,7 @@ |
382 | id @0 :Int32; |
383 | attrib @1 :Attrib; |
384 | value @2 :Int32; |
385 | + dndHandle @3 :List(UInt8); |
386 | |
387 | enum Attrib |
388 | { |
389 | @@ -160,8 +163,9 @@ |
390 | dpi @4; |
391 | visibility @5; |
392 | preferredOrientation @6; |
393 | + startDragAndDrop @7; |
394 | # Must be last |
395 | - surfaceAttrib @7; |
396 | + surfaceAttrib @8; |
397 | } |
398 | } |
399 | |
400 | |
401 | === modified file 'src/client/CMakeLists.txt' |
402 | --- src/client/CMakeLists.txt 2017-01-24 13:43:12 +0000 |
403 | +++ src/client/CMakeLists.txt 2017-03-17 15:49:43 +0000 |
404 | @@ -49,6 +49,7 @@ |
405 | add_library(mirclientobjects OBJECT |
406 | |
407 | display_configuration.cpp |
408 | + drag_and_drop.cpp drag_and_drop.h |
409 | error_connections.cpp |
410 | event.cpp |
411 | event_printer.cpp |
412 | @@ -105,6 +106,7 @@ |
413 | ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_error.h |
414 | mir_extension_core.cpp |
415 | ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_extension_core.h |
416 | + ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/extensions/drag_and_drop.h |
417 | ) |
418 | |
419 | # Ensure protobuf C++ headers have been produced before |
420 | |
421 | === added file 'src/client/drag_and_drop.cpp' |
422 | --- src/client/drag_and_drop.cpp 1970-01-01 00:00:00 +0000 |
423 | +++ src/client/drag_and_drop.cpp 2017-03-17 15:49:43 +0000 |
424 | @@ -0,0 +1,85 @@ |
425 | +/* |
426 | + * Copyright © 2017 Canonical Ltd. |
427 | + * |
428 | + * This program is free software: you can redistribute it and/or modify it |
429 | + * under the terms of the GNU Lesser General Public License version 3, |
430 | + * as published by the Free Software Foundation. |
431 | + * |
432 | + * This program is distributed in the hope that it will be useful, |
433 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
434 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
435 | + * GNU Lesser General Public License for more details. |
436 | + * |
437 | + * You should have received a copy of the GNU Lesser General Public License |
438 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
439 | + * |
440 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
441 | + */ |
442 | + |
443 | +#include "drag_and_drop.h" |
444 | +#include "mir_toolkit/extensions/drag_and_drop.h" |
445 | + |
446 | +#include "mir/uncaught.h" |
447 | +#include "mir/events/surface_event.h" |
448 | +#include "mir/events/pointer_event.h" |
449 | + |
450 | +#include "mir_surface.h" |
451 | + |
452 | +namespace |
453 | +{ |
454 | + |
455 | +void request_drag_and_drop(MirWindow* window, MirCookie const* cookie) |
456 | +try |
457 | +{ |
458 | + window->request_drag_and_drop(cookie); |
459 | +} |
460 | +catch (std::exception const& e) |
461 | +{ |
462 | + MIR_LOG_UNCAUGHT_EXCEPTION(e); |
463 | + abort(); |
464 | +} |
465 | + |
466 | +void set_start_drag_and_drop_callback(MirWindow* window, |
467 | + void (*callback)(MirWindow* window, MirDragAndDropEvent const* event, void* context), |
468 | + void* context) |
469 | +try |
470 | +{ |
471 | + window->set_drag_and_drop_start_handler([callback,window,context](MirWindowEvent const* event) |
472 | + { callback(window, reinterpret_cast<MirDragAndDropEvent const*>(event), context); }); |
473 | +} |
474 | +catch (std::exception const& e) |
475 | +{ |
476 | + MIR_LOG_UNCAUGHT_EXCEPTION(e); |
477 | + abort(); |
478 | +} |
479 | + |
480 | +MirBlob* start_drag_and_drop(MirDragAndDropEvent const* event) |
481 | +try |
482 | +{ |
483 | + return reinterpret_cast<MirWindowEvent const*>(event)->dnd_handle(); |
484 | +} |
485 | +catch (std::exception const& e) |
486 | +{ |
487 | + MIR_LOG_UNCAUGHT_EXCEPTION(e); |
488 | + abort(); |
489 | +} |
490 | + |
491 | +MirBlob* pointer_drag_and_drop(MirPointerEvent const* event) |
492 | +try |
493 | +{ |
494 | + return event->dnd_handle(); |
495 | +} |
496 | +catch (std::exception const& e) |
497 | +{ |
498 | + MIR_LOG_UNCAUGHT_EXCEPTION(e); |
499 | + abort(); |
500 | +} |
501 | + |
502 | +MirDragAndDropV1 const impl{ |
503 | + &request_drag_and_drop, |
504 | + &set_start_drag_and_drop_callback, |
505 | + &start_drag_and_drop, |
506 | + &pointer_drag_and_drop}; |
507 | +} |
508 | + |
509 | +MirDragAndDropV1 const* const mir::drag_and_drop::v1 = &impl; |
510 | |
511 | === added file 'src/client/drag_and_drop.h' |
512 | --- src/client/drag_and_drop.h 1970-01-01 00:00:00 +0000 |
513 | +++ src/client/drag_and_drop.h 2017-03-17 15:49:43 +0000 |
514 | @@ -0,0 +1,32 @@ |
515 | +/* |
516 | + * Copyright © 2017 Canonical Ltd. |
517 | + * |
518 | + * This program is free software: you can redistribute it and/or modify it |
519 | + * under the terms of the GNU Lesser General Public License version 3, |
520 | + * as published by the Free Software Foundation. |
521 | + * |
522 | + * This program is distributed in the hope that it will be useful, |
523 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
524 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
525 | + * GNU Lesser General Public License for more details. |
526 | + * |
527 | + * You should have received a copy of the GNU Lesser General Public License |
528 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
529 | + * |
530 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
531 | + */ |
532 | + |
533 | +#ifndef MIR_DRAG_AND_DROP_V1_H |
534 | +#define MIR_DRAG_AND_DROP_V1_H |
535 | + |
536 | +typedef struct MirDragAndDropV1 MirDragAndDropV1; |
537 | + |
538 | +namespace mir |
539 | +{ |
540 | +namespace drag_and_drop |
541 | +{ |
542 | +extern MirDragAndDropV1 const* const v1; |
543 | +} |
544 | +} |
545 | + |
546 | +#endif //MIR_DRAG_AND_DROP_V1_H |
547 | |
548 | === modified file 'src/client/events/event_builders.cpp' |
549 | --- src/client/events/event_builders.cpp 2017-02-15 13:36:35 +0000 |
550 | +++ src/client/events/event_builders.cpp 2017-03-17 15:49:43 +0000 |
551 | @@ -110,6 +110,20 @@ |
552 | return make_uptr_event(e); |
553 | } |
554 | |
555 | +auto mev::make_start_drag_and_drop_event(frontend::SurfaceId const& surface_id, std::vector<uint8_t> const& handle) |
556 | + -> EventUPtr |
557 | +{ |
558 | + auto e = new_event<MirWindowEvent>(); |
559 | + |
560 | + e->set_id(surface_id.as_value()); |
561 | + e->set_attrib(mir_window_attribs); |
562 | + e->set_value(0); |
563 | + e->set_dnd_handle(handle); |
564 | + |
565 | + return make_uptr_event(e); |
566 | + |
567 | +} |
568 | + |
569 | mir::EventUPtr mev::make_event(mf::SurfaceId const& surface_id) |
570 | { |
571 | auto e = new_event<MirCloseWindowEvent>(); |
572 | @@ -450,3 +464,14 @@ |
573 | BOOST_THROW_EXCEPTION(std::invalid_argument("Event has no window id.")); |
574 | } |
575 | } |
576 | + |
577 | +void mev::set_drag_and_drop_handle(MirEvent& event, std::vector<uint8_t> const& handle) |
578 | +{ |
579 | + if (event.type() == mir_event_type_input) |
580 | + { |
581 | + auto const input_event = event.to_input(); |
582 | + if (mir_input_event_get_type(input_event) == mir_input_event_type_pointer) |
583 | + const_cast<MirPointerEvent*>(mir_input_event_get_pointer_event(input_event))->set_dnd_handle(handle); |
584 | + } |
585 | +} |
586 | + |
587 | |
588 | === modified file 'src/client/mir_blob.cpp' |
589 | --- src/client/mir_blob.cpp 2017-01-18 02:29:37 +0000 |
590 | +++ src/client/mir_blob.cpp 2017-03-17 15:49:43 +0000 |
591 | @@ -16,6 +16,7 @@ |
592 | * Authored by: Alan Griffiths <alan@octopull.co.uk> |
593 | */ |
594 | |
595 | +#include "mir_blob.h" |
596 | #include "display_configuration.h" |
597 | |
598 | #include "mir_toolkit/mir_blob.h" |
599 | @@ -25,14 +26,6 @@ |
600 | |
601 | namespace mp = mir::protobuf; |
602 | |
603 | -struct MirBlob |
604 | -{ |
605 | - virtual size_t size() const = 0; |
606 | - virtual void const* data() const = 0; |
607 | - |
608 | - virtual ~MirBlob() = default; |
609 | -}; |
610 | - |
611 | namespace |
612 | { |
613 | struct MirManagedBlob : MirBlob |
614 | |
615 | === modified file 'src/client/mir_connection.cpp' |
616 | --- src/client/mir_connection.cpp 2017-03-14 04:41:33 +0000 |
617 | +++ src/client/mir_connection.cpp 2017-03-17 15:49:43 +0000 |
618 | @@ -17,6 +17,7 @@ |
619 | */ |
620 | |
621 | #include "mir_connection.h" |
622 | +#include "drag_and_drop.h" |
623 | #include "mir_surface.h" |
624 | #include "mir_prompt_session.h" |
625 | #include "mir_toolkit/extensions/graphics_module.h" |
626 | @@ -1451,6 +1452,9 @@ |
627 | if (!strcmp(name, "mir_extension_graphics_module") && (version == 1) && graphics_module_extension.is_set()) |
628 | return &graphics_module_extension.value(); |
629 | |
630 | + if (!strcmp(name, "mir_drag_and_drop") && (version == 1)) |
631 | + return const_cast<MirDragAndDropV1*>(mir::drag_and_drop::v1); |
632 | + |
633 | return platform->request_interface(name, version); |
634 | } |
635 | |
636 | |
637 | === modified file 'src/client/mir_surface.cpp' |
638 | --- src/client/mir_surface.cpp 2017-03-14 04:41:33 +0000 |
639 | +++ src/client/mir_surface.cpp 2017-03-17 15:49:43 +0000 |
640 | @@ -24,6 +24,7 @@ |
641 | #include "connection_surface_map.h" |
642 | |
643 | #include "mir_toolkit/mir_client_library.h" |
644 | +#include "mir_toolkit/mir_blob.h" |
645 | #include "mir/frontend/client_constants.h" |
646 | #include "mir/client_buffer.h" |
647 | #include "mir/mir_buffer_stream.h" |
648 | @@ -32,6 +33,7 @@ |
649 | #include "mir/cookie/cookie.h" |
650 | #include "mir_cookie.h" |
651 | #include "mir/time/posix_timestamp.h" |
652 | +#include "mir/events/surface_event.h" |
653 | |
654 | #include <cassert> |
655 | #include <unistd.h> |
656 | @@ -493,7 +495,14 @@ |
657 | auto sev = mir_event_get_window_event(&e); |
658 | auto a = mir_window_event_get_attribute(sev); |
659 | if (a < mir_window_attribs) |
660 | + { |
661 | attrib_cache[a] = mir_window_event_get_attribute_value(sev); |
662 | + } |
663 | + else |
664 | + { |
665 | + handle_drag_and_drop_start_callback(sev); |
666 | + return; |
667 | + } |
668 | break; |
669 | } |
670 | case mir_event_type_input: |
671 | @@ -598,6 +607,29 @@ |
672 | google::protobuf::NewCallback(google::protobuf::DoNothing)); |
673 | } |
674 | |
675 | +void MirSurface::request_drag_and_drop(MirCookie const* cookie) |
676 | +{ |
677 | + mp::RequestAuthority authority; |
678 | + |
679 | + std::unique_lock<decltype(mutex)> lock(mutex); |
680 | + authority.mutable_surface_id()->set_value(surface->id().value()); |
681 | + |
682 | + auto const event_cookie = authority.mutable_cookie(); |
683 | + |
684 | + event_cookie->set_cookie(cookie->cookie().data(), cookie->size()); |
685 | + |
686 | + server->request_drag_and_drop( |
687 | + &authority, |
688 | + void_response.get(), |
689 | + google::protobuf::NewCallback(google::protobuf::DoNothing)); |
690 | +} |
691 | + |
692 | +void MirSurface::set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback) |
693 | +{ |
694 | + std::lock_guard<decltype(mutex)> lock(mutex); |
695 | + handle_drag_and_drop_start_callback = callback; |
696 | +} |
697 | + |
698 | MirBufferStream* MirSurface::get_buffer_stream() |
699 | { |
700 | std::lock_guard<decltype(mutex)> lock(mutex); |
701 | |
702 | === modified file 'src/client/mir_surface.h' |
703 | --- src/client/mir_surface.h 2017-02-15 14:45:41 +0000 |
704 | +++ src/client/mir_surface.h 2017-03-17 15:49:43 +0000 |
705 | @@ -200,6 +200,8 @@ |
706 | MirWaitHandle* set_preferred_orientation(MirOrientationMode mode); |
707 | |
708 | void raise_surface(MirCookie const* cookie); |
709 | + void request_drag_and_drop(MirCookie const* cookie); |
710 | + void set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback); |
711 | |
712 | MirWaitHandle* configure_cursor(MirCursorConfiguration const* cursor); |
713 | |
714 | @@ -262,6 +264,8 @@ |
715 | std::shared_ptr<mir::client::FrameClock> const frame_clock; |
716 | |
717 | std::function<void(MirEvent const*)> handle_event_callback; |
718 | + std::function<void(MirWindowEvent const*)> handle_drag_and_drop_start_callback = [](auto){}; |
719 | + |
720 | std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread; |
721 | |
722 | //a bit batty, but the creation handle has to exist for as long as the MirSurface does, |
723 | |
724 | === modified file 'src/client/rpc/mir_display_server.cpp' |
725 | --- src/client/rpc/mir_display_server.cpp 2017-02-15 07:38:33 +0000 |
726 | +++ src/client/rpc/mir_display_server.cpp 2017-03-17 15:49:43 +0000 |
727 | @@ -238,6 +238,15 @@ |
728 | { |
729 | channel->call_method(std::string(__func__), request, response, done); |
730 | } |
731 | + |
732 | +void mclr::DisplayServer::request_drag_and_drop( |
733 | + mir::protobuf::RequestAuthority const* request, |
734 | + mir::protobuf::Void* response, |
735 | + google::protobuf::Closure* done) |
736 | +{ |
737 | + channel->call_method(std::string(__func__), request, response, done); |
738 | +} |
739 | + |
740 | void mclr::DisplayServer::apply_input_configuration( |
741 | mir::protobuf::InputConfigurationRequest const* request, |
742 | mir::protobuf::Void* response, |
743 | |
744 | === modified file 'src/client/rpc/mir_display_server.h' |
745 | --- src/client/rpc/mir_display_server.h 2017-02-15 07:38:33 +0000 |
746 | +++ src/client/rpc/mir_display_server.h 2017-03-17 15:49:43 +0000 |
747 | @@ -155,6 +155,10 @@ |
748 | mir::protobuf::RaiseRequest const* request, |
749 | mir::protobuf::Void* response, |
750 | google::protobuf::Closure* done) override; |
751 | + void request_drag_and_drop( |
752 | + mir::protobuf::RequestAuthority const* request, |
753 | + mir::protobuf::Void* response, |
754 | + google::protobuf::Closure* done) override; |
755 | void apply_input_configuration( |
756 | mir::protobuf::InputConfigurationRequest const* request, |
757 | mir::protobuf::Void* response, |
758 | |
759 | === modified file 'src/client/symbols.map' |
760 | --- src/client/symbols.map 2017-03-14 04:41:33 +0000 |
761 | +++ src/client/symbols.map 2017-03-17 15:49:43 +0000 |
762 | @@ -604,6 +604,8 @@ |
763 | global: |
764 | extern "C++" { |
765 | mir::events::set_window_id*; |
766 | + mir::events::make_start_drag_and_drop_event*; |
767 | + mir::events::set_drag_and_drop_handle*; |
768 | }; |
769 | } MIR_CLIENT_DETAIL_0.26.1; |
770 | |
771 | |
772 | === modified file 'src/common/events/pointer_event.cpp' |
773 | --- src/common/events/pointer_event.cpp 2016-11-07 23:02:26 +0000 |
774 | +++ src/common/events/pointer_event.cpp 2017-03-17 15:49:43 +0000 |
775 | @@ -1,5 +1,5 @@ |
776 | /* |
777 | - * Copyright © 2016 Canonical Ltd. |
778 | + * Copyright © 2016-2017 Canonical Ltd. |
779 | * |
780 | * This program is free software: you can redistribute it and/or modify it |
781 | * under the terms of the GNU Lesser General Public License version 3, |
782 | @@ -16,10 +16,11 @@ |
783 | * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
784 | */ |
785 | |
786 | +#include "mir/events/pointer_event.h" |
787 | +#include "mir_blob.h" |
788 | + |
789 | #include <boost/throw_exception.hpp> |
790 | |
791 | -#include "mir/events/pointer_event.h" |
792 | - |
793 | MirPointerEvent::MirPointerEvent() |
794 | { |
795 | event.initInput(); |
796 | @@ -132,3 +133,40 @@ |
797 | { |
798 | event.getInput().getPointer().setAction(static_cast<mir::capnp::PointerEvent::PointerAction>(action)); |
799 | } |
800 | + |
801 | +void MirPointerEvent::set_dnd_handle(std::vector<uint8_t> const& handle) |
802 | +{ |
803 | + event.getInput().getPointer().initDndHandle(handle.size()); |
804 | + event.getInput().getPointer().setDndHandle(::kj::ArrayPtr<uint8_t const>{&*begin(handle), &*end(handle)}); |
805 | +} |
806 | + |
807 | +namespace |
808 | +{ |
809 | +struct MyMirBlob : MirBlob |
810 | +{ |
811 | + |
812 | + size_t size() const override { return data_.size(); } |
813 | + virtual void const* data() const override { return data_.data(); } |
814 | + |
815 | + std::vector<uint8_t> data_; |
816 | +}; |
817 | +} |
818 | + |
819 | +MirBlob* MirPointerEvent::dnd_handle() const |
820 | +{ |
821 | + auto const reader = event.asReader().getInput().getPointer(); |
822 | + |
823 | + if (!reader.hasDndHandle()) |
824 | + return nullptr; |
825 | + |
826 | + auto const dnd_handle = reader.getDndHandle(); |
827 | + |
828 | + auto blob = std::make_unique<MyMirBlob>(); |
829 | + blob->data_.reserve(dnd_handle.size()); |
830 | + |
831 | + // Can't use std::copy() as the CapnP iterators don't provide an iterator category |
832 | + for (auto p = dnd_handle.begin(); p != dnd_handle.end(); ++p) |
833 | + blob->data_.push_back(*p); |
834 | + |
835 | + return blob.release(); |
836 | +} |
837 | |
838 | === modified file 'src/common/events/surface_event.cpp' |
839 | --- src/common/events/surface_event.cpp 2017-01-23 03:38:33 +0000 |
840 | +++ src/common/events/surface_event.cpp 2017-03-17 15:49:43 +0000 |
841 | @@ -1,5 +1,5 @@ |
842 | /* |
843 | - * Copyright © 2016 Canonical Ltd. |
844 | + * Copyright © 2016-2017 Canonical Ltd. |
845 | * |
846 | * This program is free software: you can redistribute it and/or modify it |
847 | * under the terms of the GNU Lesser General Public License version 3, |
848 | @@ -17,6 +17,7 @@ |
849 | */ |
850 | |
851 | #include "mir/events/surface_event.h" |
852 | +#include "mir_blob.h" |
853 | |
854 | // MirSurfaceEvent is a deprecated type, but we need to implement it |
855 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
856 | @@ -55,3 +56,40 @@ |
857 | { |
858 | event.getSurface().setValue(value); |
859 | } |
860 | + |
861 | +void MirSurfaceEvent::set_dnd_handle(std::vector<uint8_t> const& handle) |
862 | +{ |
863 | + event.getSurface().initDndHandle(handle.size()); |
864 | + event.getSurface().setDndHandle(::kj::ArrayPtr<uint8_t const>{&*begin(handle), &*end(handle)}); |
865 | +} |
866 | + |
867 | +namespace |
868 | +{ |
869 | +struct MyMirBlob : MirBlob |
870 | +{ |
871 | + |
872 | + size_t size() const override { return data_.size(); } |
873 | + virtual void const* data() const override { return data_.data(); } |
874 | + |
875 | + std::vector<uint8_t> data_; |
876 | +}; |
877 | +} |
878 | + |
879 | +MirBlob* MirSurfaceEvent::dnd_handle() const |
880 | +{ |
881 | + if (!event.asReader().getSurface().hasDndHandle()) |
882 | + return nullptr; |
883 | + |
884 | + auto blob = std::make_unique<MyMirBlob>(); |
885 | + |
886 | + auto reader = event.asReader().getSurface().getDndHandle(); |
887 | + |
888 | + blob->data_.reserve(reader.size()); |
889 | + |
890 | + // Can't use std::copy() as the CapnP iterators don't provide an iterator category |
891 | + for (auto p = reader.begin(); p != reader.end(); ++p) |
892 | + blob->data_.push_back(*p); |
893 | + |
894 | + return blob.release(); |
895 | +} |
896 | + |
897 | |
898 | === modified file 'src/common/symbols.map' |
899 | --- src/common/symbols.map 2017-02-28 08:53:57 +0000 |
900 | +++ src/common/symbols.map 2017-03-17 15:49:43 +0000 |
901 | @@ -432,5 +432,9 @@ |
902 | MirInputEvent::window_id*; |
903 | MirKeyboardEvent::set_text*; |
904 | MirKeyboardEvent::text*; |
905 | + MirPointerEvent::dnd_handle*; |
906 | + MirPointerEvent::set_dnd_handle*; |
907 | + MirSurfaceEvent::dnd_handle*; |
908 | + MirSurfaceEvent::set_dnd_handle*; |
909 | }; |
910 | } MIR_COMMON_0.26; |
911 | |
912 | === modified file 'src/include/common/mir/events/pointer_event.h' |
913 | --- src/include/common/mir/events/pointer_event.h 2016-09-22 19:21:34 +0000 |
914 | +++ src/include/common/mir/events/pointer_event.h 2017-03-17 15:49:43 +0000 |
915 | @@ -1,5 +1,5 @@ |
916 | /* |
917 | - * Copyright © 2016 Canonical Ltd. |
918 | + * Copyright © 2016-2017 Canonical Ltd. |
919 | * |
920 | * This program is free software: you can redistribute it and/or modify it |
921 | * under the terms of the GNU Lesser General Public License version 3, |
922 | @@ -21,6 +21,8 @@ |
923 | |
924 | #include "mir/events/input_event.h" |
925 | |
926 | +typedef struct MirBlob MirBlob; |
927 | + |
928 | struct MirPointerEvent : MirInputEvent |
929 | { |
930 | MirPointerEvent(); |
931 | @@ -60,6 +62,9 @@ |
932 | |
933 | MirPointerButtons buttons() const; |
934 | void set_buttons(MirPointerButtons buttons); |
935 | + |
936 | + void set_dnd_handle(std::vector<uint8_t> const& handle); |
937 | + MirBlob* dnd_handle() const; |
938 | private: |
939 | }; |
940 | |
941 | |
942 | === modified file 'src/include/common/mir/events/surface_event.h' |
943 | --- src/include/common/mir/events/surface_event.h 2017-01-18 02:29:37 +0000 |
944 | +++ src/include/common/mir/events/surface_event.h 2017-03-17 15:49:43 +0000 |
945 | @@ -1,5 +1,5 @@ |
946 | /* |
947 | - * Copyright © 2016 Canonical Ltd. |
948 | + * Copyright © 2016-2017 Canonical Ltd. |
949 | * |
950 | * This program is free software: you can redistribute it and/or modify it |
951 | * under the terms of the GNU Lesser General Public License version 3, |
952 | @@ -21,6 +21,8 @@ |
953 | |
954 | #include "mir/events/event.h" |
955 | |
956 | +typedef struct MirBlob MirBlob; |
957 | + |
958 | struct MirSurfaceEvent : MirEvent |
959 | { |
960 | MirSurfaceEvent(); |
961 | @@ -33,6 +35,9 @@ |
962 | |
963 | int value() const; |
964 | void set_value(int value); |
965 | + |
966 | + void set_dnd_handle(std::vector<uint8_t> const& handle); |
967 | + MirBlob* dnd_handle() const; |
968 | }; |
969 | |
970 | #endif /* MIR_COMMON_SURFACE_EVENT_H_ */ |
971 | |
972 | === modified file 'src/include/common/mir/protobuf/display_server.h' |
973 | --- src/include/common/mir/protobuf/display_server.h 2017-02-15 07:38:33 +0000 |
974 | +++ src/include/common/mir/protobuf/display_server.h 2017-03-17 15:49:43 +0000 |
975 | @@ -151,6 +151,10 @@ |
976 | mir::protobuf::RaiseRequest const* request, |
977 | mir::protobuf::Void* response, |
978 | google::protobuf::Closure* done) = 0; |
979 | + virtual void request_drag_and_drop( |
980 | + mir::protobuf::RequestAuthority const* request, |
981 | + mir::protobuf::Void* response, |
982 | + google::protobuf::Closure* done) = 0; |
983 | virtual void apply_input_configuration( |
984 | mir::protobuf::InputConfigurationRequest const* request, |
985 | mir::protobuf::Void* response, |
986 | |
987 | === added file 'src/include/common/mir_blob.h' |
988 | --- src/include/common/mir_blob.h 1970-01-01 00:00:00 +0000 |
989 | +++ src/include/common/mir_blob.h 2017-03-17 15:49:43 +0000 |
990 | @@ -0,0 +1,32 @@ |
991 | +/* |
992 | + * Copyright © 2017 Canonical Ltd. |
993 | + * |
994 | + * This program is free software: you can redistribute it and/or modify |
995 | + * it under the terms of the GNU Lesser General Public License version 3 as |
996 | + * published by the Free Software Foundation. |
997 | + * |
998 | + * This program is distributed in the hope that it will be useful, |
999 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1000 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1001 | + * GNU Lesser General Public License for more details. |
1002 | + * |
1003 | + * You should have received a copy of the GNU Lesser General Public License |
1004 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1005 | + * |
1006 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
1007 | + */ |
1008 | + |
1009 | +#ifndef MIR_MIR_BLOB_H_H |
1010 | +#define MIR_MIR_BLOB_H_H |
1011 | + |
1012 | +#include <stddef.h> |
1013 | + |
1014 | +struct MirBlob |
1015 | +{ |
1016 | + virtual size_t size() const = 0; |
1017 | + virtual void const* data() const = 0; |
1018 | + |
1019 | + virtual ~MirBlob() = default; |
1020 | +}; |
1021 | + |
1022 | +#endif //MIR_MIR_BLOB_H_H |
1023 | |
1024 | === modified file 'src/include/server/mir/frontend/shell.h' |
1025 | --- src/include/server/mir/frontend/shell.h 2017-01-18 02:29:37 +0000 |
1026 | +++ src/include/server/mir/frontend/shell.h 2017-03-17 15:49:43 +0000 |
1027 | @@ -87,6 +87,11 @@ |
1028 | SurfaceId surface_id, |
1029 | uint64_t timestamp) = 0; |
1030 | |
1031 | + virtual void request_drag_and_drop( |
1032 | + std::shared_ptr<Session> const& session, |
1033 | + SurfaceId surface_id, |
1034 | + uint64_t timestamp) = 0; |
1035 | + |
1036 | protected: |
1037 | Shell() = default; |
1038 | Shell(const Shell&) = delete; |
1039 | |
1040 | === modified file 'src/include/server/mir/scene/surface_event_source.h' |
1041 | --- src/include/server/mir/scene/surface_event_source.h 2017-02-15 13:36:35 +0000 |
1042 | +++ src/include/server/mir/scene/surface_event_source.h 2017-03-17 15:49:43 +0000 |
1043 | @@ -51,6 +51,7 @@ |
1044 | std::string const& variant, std::string const& options) override; |
1045 | void placed_relative(geometry::Rectangle const& placement) override; |
1046 | void input_consumed(MirEvent const* event) override; |
1047 | + void start_drag_and_drop(std::vector<uint8_t> const& handle) override; |
1048 | |
1049 | private: |
1050 | frontend::SurfaceId const id; |
1051 | |
1052 | === modified file 'src/include/server/mir/scene/surface_observers.h' |
1053 | --- src/include/server/mir/scene/surface_observers.h 2017-02-15 13:36:35 +0000 |
1054 | +++ src/include/server/mir/scene/surface_observers.h 2017-03-17 15:49:43 +0000 |
1055 | @@ -51,6 +51,7 @@ |
1056 | void cursor_image_removed() override; |
1057 | void placed_relative(geometry::Rectangle const& placement) override; |
1058 | void input_consumed(MirEvent const* event) override; |
1059 | + void start_drag_and_drop(std::vector<uint8_t> const& handle) override; |
1060 | }; |
1061 | |
1062 | } |
1063 | |
1064 | === modified file 'src/include/server/mir/shell/basic_window_manager.h' |
1065 | --- src/include/server/mir/shell/basic_window_manager.h 2017-01-18 02:29:37 +0000 |
1066 | +++ src/include/server/mir/shell/basic_window_manager.h 2017-03-17 15:49:43 +0000 |
1067 | @@ -65,6 +65,9 @@ |
1068 | |
1069 | virtual void raise_tree(std::shared_ptr<scene::Surface> const& root) = 0; |
1070 | |
1071 | + virtual void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) = 0; |
1072 | + virtual void clear_drag_and_drop_handle() = 0; |
1073 | + |
1074 | virtual ~WindowManagerTools() = default; |
1075 | WindowManagerTools() = default; |
1076 | WindowManagerTools(WindowManagerTools const&) = delete; |
1077 | @@ -107,6 +110,10 @@ |
1078 | std::shared_ptr<scene::Session> const& session, |
1079 | std::shared_ptr<scene::Surface> const& surface) = 0; |
1080 | |
1081 | + virtual void handle_request_drag_and_drop( |
1082 | + std::shared_ptr<scene::Session> const& session, |
1083 | + std::shared_ptr<scene::Surface> const& surface) = 0; |
1084 | + |
1085 | virtual ~WindowManagementPolicy() = default; |
1086 | WindowManagementPolicy() = default; |
1087 | WindowManagementPolicy(WindowManagementPolicy const&) = delete; |
1088 | @@ -163,6 +170,11 @@ |
1089 | std::shared_ptr<scene::Surface> const& surface, |
1090 | uint64_t timestamp) override; |
1091 | |
1092 | + void handle_request_drag_and_drop( |
1093 | + std::shared_ptr<scene::Session> const& session, |
1094 | + std::shared_ptr<scene::Surface> const& surface, |
1095 | + uint64_t timestamp) override; |
1096 | + |
1097 | int set_surface_attribute( |
1098 | std::shared_ptr<scene::Session> const& /*session*/, |
1099 | std::shared_ptr<scene::Surface> const& surface, |
1100 | @@ -192,6 +204,9 @@ |
1101 | |
1102 | void raise_tree(std::shared_ptr<scene::Surface> const& root) override; |
1103 | |
1104 | + void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override; |
1105 | + void clear_drag_and_drop_handle() override; |
1106 | + |
1107 | private: |
1108 | shell::FocusController* const focus_controller; |
1109 | std::unique_ptr<WindowManagementPolicy> const policy; |
1110 | |
1111 | === modified file 'src/include/server/mir/shell/canonical_window_manager.h' |
1112 | --- src/include/server/mir/shell/canonical_window_manager.h 2017-01-18 02:29:37 +0000 |
1113 | +++ src/include/server/mir/shell/canonical_window_manager.h 2017-03-17 15:49:43 +0000 |
1114 | @@ -75,6 +75,10 @@ |
1115 | std::shared_ptr<scene::Session> const& session, |
1116 | std::shared_ptr<scene::Surface> const& surface) override; |
1117 | |
1118 | + void handle_request_drag_and_drop( |
1119 | + std::shared_ptr<scene::Session> const& session, |
1120 | + std::shared_ptr<scene::Surface> const& surface) override; |
1121 | + |
1122 | private: |
1123 | static const int modifier_mask = |
1124 | mir_input_event_modifier_alt | |
1125 | |
1126 | === modified file 'src/protobuf/mir_protobuf.proto' |
1127 | --- src/protobuf/mir_protobuf.proto 2017-03-14 04:41:33 +0000 |
1128 | +++ src/protobuf/mir_protobuf.proto 2017-03-17 15:49:43 +0000 |
1129 | @@ -444,6 +444,11 @@ |
1130 | required SurfaceId surface_id = 2; |
1131 | } |
1132 | |
1133 | +message RequestAuthority { |
1134 | + required Cookie cookie = 1; |
1135 | + required SurfaceId surface_id = 2; |
1136 | +} |
1137 | + |
1138 | message InputDevices { |
1139 | repeated InputDeviceInfo device_info = 1; |
1140 | } |
1141 | |
1142 | === modified file 'src/protobuf/symbols.map' |
1143 | --- src/protobuf/symbols.map 2017-02-15 07:38:33 +0000 |
1144 | +++ src/protobuf/symbols.map 2017-03-17 15:49:43 +0000 |
1145 | @@ -1112,3 +1112,29 @@ |
1146 | vtable?for?mir::protobuf::PromptSession; |
1147 | }; |
1148 | } MIR_PROTOBUF_0.22; |
1149 | + |
1150 | +MIR_PROTOBUF_0.27 { |
1151 | + global: |
1152 | + extern "C++" { |
1153 | + mir::protobuf::RequestAuthority::ByteSize*; |
1154 | + mir::protobuf::RequestAuthority::CheckTypeAndMergeFrom*; |
1155 | + mir::protobuf::RequestAuthority::Clear*; |
1156 | + mir::protobuf::RequestAuthority::CopyFrom*; |
1157 | + mir::protobuf::RequestAuthority::default_instance*; |
1158 | + mir::protobuf::RequestAuthority::DiscardUnknownFields*; |
1159 | + mir::protobuf::RequestAuthority::GetTypeName*; |
1160 | + mir::protobuf::RequestAuthority::IsInitialized*; |
1161 | + mir::protobuf::RequestAuthority::kCookieFieldNumber*; |
1162 | + mir::protobuf::RequestAuthority::kSurfaceIdFieldNumber*; |
1163 | + mir::protobuf::RequestAuthority::MergeFrom*; |
1164 | + mir::protobuf::RequestAuthority::MergePartialFromCodedStream*; |
1165 | + mir::protobuf::RequestAuthority::New*; |
1166 | + mir::protobuf::RequestAuthority::?RequestAuthority*; |
1167 | + mir::protobuf::RequestAuthority::RequestAuthority*; |
1168 | + mir::protobuf::RequestAuthority::SerializeWithCachedSizes*; |
1169 | + mir::protobuf::RequestAuthority::Swap*; |
1170 | + non-virtual?thunk?to?mir::protobuf::RequestAuthority::?RequestAuthority*; |
1171 | + typeinfo?for?mir::protobuf::RequestAuthority; |
1172 | + vtable?for?mir::protobuf::RequestAuthority; |
1173 | + }; |
1174 | +} MIR_PROTOBUF_0.26; |
1175 | |
1176 | === modified file 'src/server/frontend/protobuf_message_processor.cpp' |
1177 | --- src/server/frontend/protobuf_message_processor.cpp 2017-02-15 07:38:33 +0000 |
1178 | +++ src/server/frontend/protobuf_message_processor.cpp 2017-03-17 15:49:43 +0000 |
1179 | @@ -305,6 +305,10 @@ |
1180 | { |
1181 | invoke(this, display_server.get(), &protobuf::DisplayServer::stop_prompt_session, invocation); |
1182 | } |
1183 | + else if ("request_drag_and_drop" == invocation.method_name()) |
1184 | + { |
1185 | + invoke(this, display_server.get(), &protobuf::DisplayServer::request_drag_and_drop, invocation); |
1186 | + } |
1187 | else if ("disconnect" == invocation.method_name()) |
1188 | { |
1189 | invoke(this, display_server.get(), &DisplayServer::disconnect, invocation); |
1190 | |
1191 | === modified file 'src/server/frontend/session_mediator.cpp' |
1192 | --- src/server/frontend/session_mediator.cpp 2017-03-14 04:41:33 +0000 |
1193 | +++ src/server/frontend/session_mediator.cpp 2017-03-17 15:49:43 +0000 |
1194 | @@ -1175,6 +1175,26 @@ |
1195 | done->Run(); |
1196 | } |
1197 | |
1198 | +void mir::frontend::SessionMediator::request_drag_and_drop(mir::protobuf::RequestAuthority const* request, |
1199 | + mir::protobuf::Void*, google::protobuf::Closure* done) |
1200 | +{ |
1201 | + auto const session = weak_session.lock(); |
1202 | + if (!session) |
1203 | + BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); |
1204 | + |
1205 | + auto const cookie = request->cookie(); |
1206 | + auto const surface_id = request->surface_id(); |
1207 | + |
1208 | + auto cookie_string = cookie.cookie(); |
1209 | + |
1210 | + std::vector<uint8_t> cookie_bytes(cookie_string.begin(), cookie_string.end()); |
1211 | + auto const cookie_ptr = cookie_authority->make_cookie(cookie_bytes); |
1212 | + |
1213 | + shell->request_drag_and_drop(session, mf::SurfaceId{surface_id.value()}, cookie_ptr->timestamp()); |
1214 | + |
1215 | + done->Run(); |
1216 | +} |
1217 | + |
1218 | void mf::SessionMediator::apply_input_configuration( |
1219 | mir::protobuf::InputConfigurationRequest const* request, |
1220 | mir::protobuf::Void*, |
1221 | @@ -1254,7 +1274,6 @@ |
1222 | screencast_buffer_tracker.remove_session(id); |
1223 | } |
1224 | |
1225 | - |
1226 | auto mf::detail::PromptSessionStore::insert(std::shared_ptr<PromptSession> const& session) -> PromptSessionId |
1227 | { |
1228 | std::lock_guard<decltype(mutex)> lock{mutex}; |
1229 | |
1230 | === modified file 'src/server/frontend/session_mediator.h' |
1231 | --- src/server/frontend/session_mediator.h 2017-03-14 02:26:28 +0000 |
1232 | +++ src/server/frontend/session_mediator.h 2017-03-17 15:49:43 +0000 |
1233 | @@ -249,6 +249,10 @@ |
1234 | mir::protobuf::RaiseRequest const* request, |
1235 | mir::protobuf::Void*, |
1236 | google::protobuf::Closure* done) override; |
1237 | + void request_drag_and_drop( |
1238 | + mir::protobuf::RequestAuthority const* request, |
1239 | + mir::protobuf::Void*, |
1240 | + google::protobuf::Closure* done) override; |
1241 | void apply_input_configuration( |
1242 | mir::protobuf::InputConfigurationRequest const* request, |
1243 | mir::protobuf::Void* response, |
1244 | |
1245 | === modified file 'src/server/frontend/shell_wrapper.cpp' |
1246 | --- src/server/frontend/shell_wrapper.cpp 2017-01-18 02:29:37 +0000 |
1247 | +++ src/server/frontend/shell_wrapper.cpp 2017-03-17 15:49:43 +0000 |
1248 | @@ -106,3 +106,11 @@ |
1249 | { |
1250 | wrapped->raise_surface(session, surface_id, timestamp); |
1251 | } |
1252 | + |
1253 | +void mf::ShellWrapper::request_drag_and_drop( |
1254 | + std::shared_ptr<Session> const& session, |
1255 | + SurfaceId surface_id, |
1256 | + uint64_t timestamp) |
1257 | +{ |
1258 | + wrapped->request_drag_and_drop(session, surface_id, timestamp); |
1259 | +} |
1260 | |
1261 | === modified file 'src/server/frontend/shell_wrapper.h' |
1262 | --- src/server/frontend/shell_wrapper.h 2017-01-18 02:29:37 +0000 |
1263 | +++ src/server/frontend/shell_wrapper.h 2017-03-17 15:49:43 +0000 |
1264 | @@ -80,6 +80,11 @@ |
1265 | SurfaceId surface_id, |
1266 | uint64_t timestamp) override; |
1267 | |
1268 | + void request_drag_and_drop( |
1269 | + std::shared_ptr<Session> const& session, |
1270 | + SurfaceId surface_id, |
1271 | + uint64_t timestamp) override; |
1272 | + |
1273 | protected: |
1274 | std::shared_ptr<Shell> const wrapped; |
1275 | }; |
1276 | |
1277 | === modified file 'src/server/input/null_input_targeter.h' |
1278 | --- src/server/input/null_input_targeter.h 2017-02-15 14:45:41 +0000 |
1279 | +++ src/server/input/null_input_targeter.h 2017-03-17 15:49:43 +0000 |
1280 | @@ -38,6 +38,9 @@ |
1281 | void clear_focus() override |
1282 | { |
1283 | } |
1284 | + |
1285 | + void set_drag_and_drop_handle(std::vector<uint8_t> const&) override {} |
1286 | + void clear_drag_and_drop_handle() override {} |
1287 | }; |
1288 | |
1289 | } |
1290 | |
1291 | === modified file 'src/server/input/surface_input_dispatcher.cpp' |
1292 | --- src/server/input/surface_input_dispatcher.cpp 2017-01-18 02:29:37 +0000 |
1293 | +++ src/server/input/surface_input_dispatcher.cpp 2017-03-17 15:49:43 +0000 |
1294 | @@ -70,7 +70,10 @@ |
1295 | std::function<void(ms::Surface*)> const on_removed; |
1296 | }; |
1297 | |
1298 | -void deliver_without_relative_motion(std::shared_ptr<mi::Surface> const& surface, MirEvent const* ev) |
1299 | +void deliver_without_relative_motion( |
1300 | + std::shared_ptr<mi::Surface> const& surface, |
1301 | + MirEvent const* ev, |
1302 | + std::vector<uint8_t> const& drag_and_drop_handle) |
1303 | { |
1304 | auto const* input_ev = mir_event_get_input_event(ev); |
1305 | auto const* pev = mir_input_event_get_pointer_event(input_ev); |
1306 | @@ -98,12 +101,21 @@ |
1307 | 0.0f); |
1308 | |
1309 | mev::transform_positions(*to_deliver, geom::Displacement{bounds.top_left.x.as_int(), bounds.top_left.y.as_int()}); |
1310 | + if (!drag_and_drop_handle.empty()) |
1311 | + mev::set_drag_and_drop_handle(*to_deliver, drag_and_drop_handle); |
1312 | surface->consume(to_deliver.get()); |
1313 | } |
1314 | |
1315 | -void deliver(std::shared_ptr<mi::Surface> const& surface, MirEvent const* ev) |
1316 | +void deliver( |
1317 | + std::shared_ptr<mi::Surface> const& surface, |
1318 | + MirEvent const* ev, |
1319 | + std::vector<uint8_t> const& drag_and_drop_handle) |
1320 | { |
1321 | auto to_deliver = mev::clone_event(*ev); |
1322 | + |
1323 | + if (!drag_and_drop_handle.empty()) |
1324 | + mev::set_drag_and_drop_handle(*to_deliver, drag_and_drop_handle); |
1325 | + |
1326 | auto const& bounds = surface->input_bounds(); |
1327 | mev::transform_positions(*to_deliver, geom::Displacement{bounds.top_left.x.as_int(), bounds.top_left.y.as_int()}); |
1328 | surface->consume(to_deliver.get()); |
1329 | @@ -243,6 +255,8 @@ |
1330 | mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x), |
1331 | mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y)); |
1332 | |
1333 | + if (!drag_and_drop_handle.empty()) |
1334 | + mev::set_drag_and_drop_handle(*event, drag_and_drop_handle); |
1335 | surface->consume(event.get()); |
1336 | } |
1337 | |
1338 | @@ -270,12 +284,17 @@ |
1339 | |
1340 | if (pointer_state.gesture_owner) |
1341 | { |
1342 | - deliver(pointer_state.gesture_owner, ev); |
1343 | - |
1344 | - if (is_gesture_terminator(pev)) |
1345 | + deliver(pointer_state.gesture_owner, ev, drag_and_drop_handle); |
1346 | + |
1347 | + auto const gesture_terminated = is_gesture_terminator(pev); |
1348 | + |
1349 | + if (gesture_terminated) |
1350 | { |
1351 | pointer_state.gesture_owner.reset(); |
1352 | + } |
1353 | |
1354 | + if (gesture_terminated || !drag_and_drop_handle.empty()) |
1355 | + { |
1356 | auto target = find_target_surface(event_x_y); |
1357 | |
1358 | if (pointer_state.current_target != target) |
1359 | @@ -286,6 +305,9 @@ |
1360 | pointer_state.current_target = target; |
1361 | if (target) |
1362 | send_enter_exit_event(target, pev, mir_pointer_action_enter); |
1363 | + |
1364 | + if (!gesture_terminated) |
1365 | + pointer_state.gesture_owner = target; |
1366 | } |
1367 | } |
1368 | |
1369 | @@ -323,11 +345,11 @@ |
1370 | if (sent_ev) |
1371 | { |
1372 | if (action != mir_pointer_action_motion) |
1373 | - deliver_without_relative_motion(target, ev); |
1374 | + deliver_without_relative_motion(target, ev, drag_and_drop_handle); |
1375 | } |
1376 | else |
1377 | { |
1378 | - deliver(target, ev); |
1379 | + deliver(target, ev, drag_and_drop_handle); |
1380 | } |
1381 | return true; |
1382 | } |
1383 | @@ -383,7 +405,7 @@ |
1384 | |
1385 | if (gesture_owner) |
1386 | { |
1387 | - deliver(gesture_owner, ev); |
1388 | + deliver(gesture_owner, ev, drag_and_drop_handle); |
1389 | |
1390 | if (is_gesture_end(tev)) |
1391 | gesture_owner.reset(); |
1392 | @@ -450,3 +472,15 @@ |
1393 | set_focus_locked(lg, nullptr); |
1394 | } |
1395 | |
1396 | +void mir::input::SurfaceInputDispatcher::set_drag_and_drop_handle(std::vector<uint8_t> const& handle) |
1397 | +{ |
1398 | + std::lock_guard<std::mutex> lg(dispatcher_mutex); |
1399 | + drag_and_drop_handle = handle; |
1400 | +} |
1401 | + |
1402 | +void mir::input::SurfaceInputDispatcher::clear_drag_and_drop_handle() |
1403 | +{ |
1404 | + std::lock_guard<std::mutex> lg(dispatcher_mutex); |
1405 | + drag_and_drop_handle.clear(); |
1406 | +} |
1407 | + |
1408 | |
1409 | === modified file 'src/server/input/surface_input_dispatcher.h' |
1410 | --- src/server/input/surface_input_dispatcher.h 2016-10-05 13:18:38 +0000 |
1411 | +++ src/server/input/surface_input_dispatcher.h 2017-03-17 15:49:43 +0000 |
1412 | @@ -54,7 +54,10 @@ |
1413 | // InputTargeter |
1414 | void set_focus(std::shared_ptr<input::Surface> const& target) override; |
1415 | void clear_focus() override; |
1416 | - |
1417 | + |
1418 | + void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override; |
1419 | + void clear_drag_and_drop_handle() override; |
1420 | + |
1421 | private: |
1422 | void device_reset(MirInputDeviceId reset_device_id, std::chrono::nanoseconds when); |
1423 | bool dispatch_key(MirEvent const* kev); |
1424 | @@ -92,6 +95,7 @@ |
1425 | |
1426 | std::mutex dispatcher_mutex; |
1427 | std::weak_ptr<input::Surface> focus_surface; |
1428 | + std::vector<uint8_t> drag_and_drop_handle; |
1429 | bool started; |
1430 | }; |
1431 | |
1432 | |
1433 | === modified file 'src/server/scene/basic_surface.cpp' |
1434 | --- src/server/scene/basic_surface.cpp 2017-02-15 14:45:41 +0000 |
1435 | +++ src/server/scene/basic_surface.cpp 2017-03-17 15:49:43 +0000 |
1436 | @@ -144,6 +144,12 @@ |
1437 | { observer->input_consumed(event); }); |
1438 | } |
1439 | |
1440 | +void ms::SurfaceObservers::start_drag_and_drop(std::vector<uint8_t> const& handle) |
1441 | +{ |
1442 | + for_each([&](std::shared_ptr<SurfaceObserver> const& observer) |
1443 | + { observer->start_drag_and_drop(handle); }); |
1444 | +} |
1445 | + |
1446 | |
1447 | struct ms::CursorStreamImageAdapter |
1448 | { |
1449 | @@ -923,3 +929,8 @@ |
1450 | { |
1451 | observers.placed_relative(placement); |
1452 | } |
1453 | + |
1454 | +void mir::scene::BasicSurface::start_drag_and_drop(std::vector<uint8_t> const& handle) |
1455 | +{ |
1456 | + observers.start_drag_and_drop(handle); |
1457 | +} |
1458 | |
1459 | === modified file 'src/server/scene/basic_surface.h' |
1460 | --- src/server/scene/basic_surface.h 2017-02-15 14:45:41 +0000 |
1461 | +++ src/server/scene/basic_surface.h 2017-03-17 15:49:43 +0000 |
1462 | @@ -139,6 +139,7 @@ |
1463 | void set_confine_pointer_state(MirPointerConfinementState state) override; |
1464 | MirPointerConfinementState confine_pointer_state() const override; |
1465 | void placed_relative(geometry::Rectangle const& placement) override; |
1466 | + void start_drag_and_drop(std::vector<uint8_t> const& handle) override; |
1467 | |
1468 | private: |
1469 | bool visible(std::unique_lock<std::mutex>&) const; |
1470 | |
1471 | === modified file 'src/server/scene/legacy_surface_change_notification.cpp' |
1472 | --- src/server/scene/legacy_surface_change_notification.cpp 2017-02-15 13:36:35 +0000 |
1473 | +++ src/server/scene/legacy_surface_change_notification.cpp 2017-03-17 15:49:43 +0000 |
1474 | @@ -108,3 +108,7 @@ |
1475 | void ms::LegacySurfaceChangeNotification::input_consumed(MirEvent const*) |
1476 | { |
1477 | } |
1478 | + |
1479 | +void ms::LegacySurfaceChangeNotification::start_drag_and_drop(std::vector<uint8_t> const& /*handle*/) |
1480 | +{ |
1481 | +} |
1482 | \ No newline at end of file |
1483 | |
1484 | === modified file 'src/server/scene/legacy_surface_change_notification.h' |
1485 | --- src/server/scene/legacy_surface_change_notification.h 2017-02-15 13:36:35 +0000 |
1486 | +++ src/server/scene/legacy_surface_change_notification.h 2017-03-17 15:49:43 +0000 |
1487 | @@ -51,6 +51,7 @@ |
1488 | void cursor_image_removed() override; |
1489 | void placed_relative(geometry::Rectangle const& placement) override; |
1490 | void input_consumed(MirEvent const* event) override; |
1491 | + void start_drag_and_drop(std::vector<uint8_t> const& handle) override; |
1492 | |
1493 | private: |
1494 | std::function<void()> const notify_scene_change; |
1495 | |
1496 | === modified file 'src/server/scene/null_surface_observer.cpp' |
1497 | --- src/server/scene/null_surface_observer.cpp 2017-02-15 13:36:35 +0000 |
1498 | +++ src/server/scene/null_surface_observer.cpp 2017-03-17 15:49:43 +0000 |
1499 | @@ -41,3 +41,4 @@ |
1500 | void ms::NullSurfaceObserver::cursor_image_removed() {} |
1501 | void ms::NullSurfaceObserver::placed_relative(geometry::Rectangle const& /*placement*/) {} |
1502 | void ms::NullSurfaceObserver::input_consumed(MirEvent const* /*event*/) {} |
1503 | +void ms::NullSurfaceObserver::start_drag_and_drop(std::vector<uint8_t> const& /*handle*/) {} |
1504 | |
1505 | === modified file 'src/server/scene/surface_event_source.cpp' |
1506 | --- src/server/scene/surface_event_source.cpp 2017-02-15 13:36:35 +0000 |
1507 | +++ src/server/scene/surface_event_source.cpp 2017-03-17 15:49:43 +0000 |
1508 | @@ -101,3 +101,8 @@ |
1509 | mev::set_window_id(*ev, id.as_value()); |
1510 | event_sink->handle_event(*ev); |
1511 | } |
1512 | + |
1513 | +void ms::SurfaceEventSource::start_drag_and_drop(std::vector<uint8_t> const& handle) |
1514 | +{ |
1515 | + event_sink->handle_event(*mev::make_start_drag_and_drop_event(id, handle)); |
1516 | +} |
1517 | |
1518 | === modified file 'src/server/shell/abstract_shell.cpp' |
1519 | --- src/server/shell/abstract_shell.cpp 2017-03-10 19:47:57 +0000 |
1520 | +++ src/server/shell/abstract_shell.cpp 2017-03-17 15:49:43 +0000 |
1521 | @@ -251,6 +251,14 @@ |
1522 | window_manager->handle_raise_surface(session, surface, timestamp); |
1523 | } |
1524 | |
1525 | +void msh::AbstractShell::request_drag_and_drop( |
1526 | + std::shared_ptr<scene::Session> const& session, |
1527 | + std::shared_ptr<scene::Surface> const& surface, |
1528 | + uint64_t timestamp) |
1529 | +{ |
1530 | + window_manager->handle_request_drag_and_drop(session, surface, timestamp); |
1531 | +} |
1532 | + |
1533 | void msh::AbstractShell::focus_next_session() |
1534 | { |
1535 | std::unique_lock<std::mutex> lock(focus_mutex); |
1536 | @@ -401,3 +409,12 @@ |
1537 | report->surfaces_raised(surfaces); |
1538 | } |
1539 | |
1540 | +void msh::AbstractShell::set_drag_and_drop_handle(std::vector<uint8_t> const& handle) |
1541 | +{ |
1542 | + input_targeter->set_drag_and_drop_handle(handle); |
1543 | +} |
1544 | + |
1545 | +void msh::AbstractShell::clear_drag_and_drop_handle() |
1546 | +{ |
1547 | + input_targeter->clear_drag_and_drop_handle(); |
1548 | +} |
1549 | |
1550 | === modified file 'src/server/shell/basic_window_manager.cpp' |
1551 | --- src/server/shell/basic_window_manager.cpp 2017-01-18 02:29:37 +0000 |
1552 | +++ src/server/shell/basic_window_manager.cpp 2017-03-17 15:49:43 +0000 |
1553 | @@ -135,6 +135,16 @@ |
1554 | policy->handle_raise_surface(session, surface); |
1555 | } |
1556 | |
1557 | +void msh::BasicWindowManager::handle_request_drag_and_drop( |
1558 | + std::shared_ptr<scene::Session> const& session, |
1559 | + std::shared_ptr<scene::Surface> const& surface, |
1560 | + uint64_t timestamp) |
1561 | +{ |
1562 | + std::lock_guard<decltype(mutex)> lock(mutex); |
1563 | + if (timestamp >= last_input_event_timestamp) |
1564 | + policy->handle_request_drag_and_drop(session, surface); |
1565 | +} |
1566 | + |
1567 | int msh::BasicWindowManager::set_surface_attribute( |
1568 | std::shared_ptr<scene::Session> const& /*session*/, |
1569 | std::shared_ptr<scene::Surface> const& surface, |
1570 | @@ -309,3 +319,14 @@ |
1571 | } |
1572 | } |
1573 | } |
1574 | + |
1575 | +void mir::shell::BasicWindowManager::set_drag_and_drop_handle(std::vector<uint8_t> const& handle) |
1576 | +{ |
1577 | + focus_controller->set_drag_and_drop_handle(handle); |
1578 | +} |
1579 | + |
1580 | +void mir::shell::BasicWindowManager::clear_drag_and_drop_handle() |
1581 | +{ |
1582 | + focus_controller->clear_drag_and_drop_handle(); |
1583 | +} |
1584 | + |
1585 | |
1586 | === modified file 'src/server/shell/canonical_window_manager.cpp' |
1587 | --- src/server/shell/canonical_window_manager.cpp 2017-03-10 19:47:57 +0000 |
1588 | +++ src/server/shell/canonical_window_manager.cpp 2017-03-17 15:49:43 +0000 |
1589 | @@ -24,6 +24,7 @@ |
1590 | #include "mir/shell/surface_ready_observer.h" |
1591 | #include "mir/shell/display_layout.h" |
1592 | |
1593 | +#include <uuid/uuid.h> |
1594 | #include <linux/input.h> |
1595 | #include <csignal> |
1596 | |
1597 | @@ -583,6 +584,18 @@ |
1598 | select_active_surface(surface); |
1599 | } |
1600 | |
1601 | +void msh::CanonicalWindowManagerPolicy::handle_request_drag_and_drop( |
1602 | + std::shared_ptr<ms::Session> const& /*session*/, |
1603 | + std::shared_ptr<ms::Surface> const& surface) |
1604 | +{ |
1605 | + uuid_t uuid; |
1606 | + uuid_generate(uuid); |
1607 | + std::vector<uint8_t> const handle{std::begin(uuid), std::end(uuid)}; |
1608 | + |
1609 | + surface->start_drag_and_drop(handle); |
1610 | + tools->set_drag_and_drop_handle(handle); |
1611 | +} |
1612 | + |
1613 | bool msh::CanonicalWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event) |
1614 | { |
1615 | auto const action = mir_keyboard_event_action(event); |
1616 | |
1617 | === modified file 'src/server/shell/frontend_shell.cpp' |
1618 | --- src/server/shell/frontend_shell.cpp 2017-01-18 02:29:37 +0000 |
1619 | +++ src/server/shell/frontend_shell.cpp 2017-03-17 15:49:43 +0000 |
1620 | @@ -157,3 +157,13 @@ |
1621 | auto const surface = scene_session->surface(surface_id); |
1622 | wrapped->raise_surface(scene_session, surface, timestamp); |
1623 | } |
1624 | + |
1625 | +void msh::FrontendShell::request_drag_and_drop( |
1626 | + std::shared_ptr<mf::Session> const& session, |
1627 | + mf::SurfaceId surface_id, |
1628 | + uint64_t timestamp) |
1629 | +{ |
1630 | + auto const scene_session = std::dynamic_pointer_cast<ms::Session>(session); |
1631 | + auto const surface = scene_session->surface(surface_id); |
1632 | + wrapped->request_drag_and_drop(scene_session, surface, timestamp); |
1633 | +} |
1634 | |
1635 | === modified file 'src/server/shell/frontend_shell.h' |
1636 | --- src/server/shell/frontend_shell.h 2017-01-18 02:29:37 +0000 |
1637 | +++ src/server/shell/frontend_shell.h 2017-03-17 15:49:43 +0000 |
1638 | @@ -91,6 +91,11 @@ |
1639 | std::shared_ptr<mf::Session> const& session, |
1640 | mf::SurfaceId surface_id, |
1641 | uint64_t timestamp) override; |
1642 | + |
1643 | + void request_drag_and_drop( |
1644 | + std::shared_ptr<mf::Session> const& session, |
1645 | + mf::SurfaceId surface_id, |
1646 | + uint64_t timestamp) override; |
1647 | }; |
1648 | } |
1649 | } |
1650 | |
1651 | === modified file 'src/server/shell/shell_wrapper.cpp' |
1652 | --- src/server/shell/shell_wrapper.cpp 2017-01-18 02:29:37 +0000 |
1653 | +++ src/server/shell/shell_wrapper.cpp 2017-03-17 15:49:43 +0000 |
1654 | @@ -120,6 +120,14 @@ |
1655 | wrapped->raise_surface(session, surface, timestamp); |
1656 | } |
1657 | |
1658 | +void msh::ShellWrapper::request_drag_and_drop( |
1659 | + std::shared_ptr<ms::Session> const& session, |
1660 | + std::shared_ptr<ms::Surface> const& surface, |
1661 | + uint64_t timestamp) |
1662 | +{ |
1663 | + wrapped->request_drag_and_drop(session, surface, timestamp); |
1664 | +} |
1665 | + |
1666 | void msh::ShellWrapper::add_display(geometry::Rectangle const& area) |
1667 | { |
1668 | wrapped->add_display(area); |
1669 | @@ -149,3 +157,13 @@ |
1670 | { |
1671 | return wrapped->raise(surfaces); |
1672 | } |
1673 | + |
1674 | +void msh::ShellWrapper::set_drag_and_drop_handle(std::vector<uint8_t> const& handle) |
1675 | +{ |
1676 | + wrapped->set_drag_and_drop_handle(handle); |
1677 | +} |
1678 | + |
1679 | +void msh::ShellWrapper::clear_drag_and_drop_handle() |
1680 | +{ |
1681 | + wrapped->clear_drag_and_drop_handle(); |
1682 | +} |
1683 | |
1684 | === modified file 'src/server/shell/system_compositor_window_manager.cpp' |
1685 | --- src/server/shell/system_compositor_window_manager.cpp 2017-01-18 02:29:37 +0000 |
1686 | +++ src/server/shell/system_compositor_window_manager.cpp 2017-03-17 15:49:43 +0000 |
1687 | @@ -201,3 +201,10 @@ |
1688 | uint64_t /*timestamp*/) |
1689 | { |
1690 | } |
1691 | + |
1692 | +void msh::SystemCompositorWindowManager::handle_request_drag_and_drop( |
1693 | + std::shared_ptr<ms::Session> const& /*session*/, |
1694 | + std::shared_ptr<ms::Surface> const& /*surface*/, |
1695 | + uint64_t /*timestamp*/) |
1696 | +{ |
1697 | +} |
1698 | |
1699 | === modified file 'src/server/symbols.map' |
1700 | --- src/server/symbols.map 2017-03-15 10:38:02 +0000 |
1701 | +++ src/server/symbols.map 2017-03-17 15:49:43 +0000 |
1702 | @@ -129,6 +129,7 @@ |
1703 | mir::scene::NullSurfaceObserver::reception_mode_set_to*; |
1704 | mir::scene::NullSurfaceObserver::renamed*; |
1705 | mir::scene::NullSurfaceObserver::resized_to*; |
1706 | + mir::scene::NullSurfaceObserver::start_drag_and_drop*; |
1707 | mir::scene::NullSurfaceObserver::transformation_set_to*; |
1708 | mir::scene::Observer::?Observer*; |
1709 | mir::scene::Observer::Observer*; |
1710 | @@ -293,6 +294,7 @@ |
1711 | mir::shell::ShellReport::ShellReport*; |
1712 | mir::shell::ShellWrapper::add_display*; |
1713 | mir::shell::ShellWrapper::add_prompt_provider_for*; |
1714 | + mir::shell::ShellWrapper::clear_drag_and_drop_handle*; |
1715 | mir::shell::ShellWrapper::close_session*; |
1716 | mir::shell::ShellWrapper::create_surface*; |
1717 | mir::shell::ShellWrapper::destroy_surface*; |
1718 | @@ -306,9 +308,11 @@ |
1719 | mir::shell::ShellWrapper::raise*; |
1720 | mir::shell::ShellWrapper::raise_surface*; |
1721 | mir::shell::ShellWrapper::remove_display*; |
1722 | + mir::shell::ShellWrapper::request_drag_and_drop*; |
1723 | mir::shell::ShellWrapper::set_focus_to*; |
1724 | mir::shell::ShellWrapper::set_surface_attribute*; |
1725 | mir::shell::ShellWrapper::ShellWrapper*; |
1726 | + mir::shell::ShellWrapper::set_drag_and_drop_handle*; |
1727 | mir::shell::ShellWrapper::start_prompt_session_for*; |
1728 | mir::shell::ShellWrapper::stop_prompt_session*; |
1729 | mir::shell::ShellWrapper::surface_at*; |
1730 | @@ -338,6 +342,7 @@ |
1731 | mir::shell::SystemCompositorWindowManager::remove_display*; |
1732 | mir::shell::SystemCompositorWindowManager::remove_session*; |
1733 | mir::shell::SystemCompositorWindowManager::remove_surface*; |
1734 | + mir::shell::SystemCompositorWindowManager::handle_request_drag_and_drop*; |
1735 | mir::shell::SystemCompositorWindowManager::set_surface_attribute*; |
1736 | mir::shell::SystemCompositorWindowManager::SystemCompositorWindowManager*; |
1737 | mir::shell::WindowManager::operator*; |
1738 | @@ -695,6 +700,7 @@ |
1739 | mir::shell::CanonicalWindowManagerPolicy::handle_touch_event*; |
1740 | mir::shell::CanonicalWindowManagerPolicy::handle_pointer_event*; |
1741 | mir::shell::CanonicalWindowManagerPolicy::handle_raise_surface*; |
1742 | + mir::shell::CanonicalWindowManagerPolicy::handle_request_drag_and_drop*; |
1743 | typeinfo?for?mir::shell::CanonicalWindowManagerPolicy; |
1744 | vtable?for?mir::shell::CanonicalWindowManagerPolicy; |
1745 | VTT?for?mir::shell::CanonicalWindowManagerPolicy; |
1746 | @@ -831,6 +837,7 @@ |
1747 | mir::shell::BasicWindowManager::add_session*; |
1748 | mir::shell::BasicWindowManager::add_surface*; |
1749 | mir::shell::BasicWindowManager::BasicWindowManager*; |
1750 | + mir::shell::BasicWindowManager::clear_drag_and_drop_handle*; |
1751 | mir::shell::BasicWindowManager::find_session*; |
1752 | mir::shell::BasicWindowManager::focused_session*; |
1753 | mir::shell::BasicWindowManager::focused_surface*; |
1754 | @@ -839,6 +846,7 @@ |
1755 | mir::shell::BasicWindowManager::handle_keyboard_event*; |
1756 | mir::shell::BasicWindowManager::handle_pointer_event*; |
1757 | mir::shell::BasicWindowManager::handle_raise_surface*; |
1758 | + mir::shell::BasicWindowManager::handle_request_drag_and_drop*; |
1759 | mir::shell::BasicWindowManager::handle_touch_event*; |
1760 | mir::shell::BasicWindowManager::info_for*; |
1761 | mir::shell::BasicWindowManager::modify_surface*; |
1762 | @@ -846,6 +854,7 @@ |
1763 | mir::shell::BasicWindowManager::remove_display*; |
1764 | mir::shell::BasicWindowManager::remove_session*; |
1765 | mir::shell::BasicWindowManager::remove_surface*; |
1766 | + mir::shell::BasicWindowManager::set_drag_and_drop_handle*; |
1767 | mir::shell::BasicWindowManager::set_focus_to*; |
1768 | mir::shell::BasicWindowManager::set_surface_attribute*; |
1769 | mir::shell::BasicWindowManager::surface_at*; |
1770 | @@ -856,6 +865,7 @@ |
1771 | virtual?thunk?to?mir::shell::BasicWindowManager::handle_keyboard_event*; |
1772 | virtual?thunk?to?mir::shell::BasicWindowManager::handle_pointer_event*; |
1773 | virtual?thunk?to?mir::shell::BasicWindowManager::handle_raise_surface*; |
1774 | + virtual?thunk?to?mir::shell::BasicWindowManager::handle_request_drag_and_drop*; |
1775 | virtual?thunk?to?mir::shell::BasicWindowManager::handle_touch_event*; |
1776 | virtual?thunk?to?mir::shell::BasicWindowManager::modify_surface*; |
1777 | virtual?thunk?to?mir::shell::BasicWindowManager::remove_display*; |
1778 | |
1779 | === modified file 'tests/acceptance-tests/CMakeLists.txt' |
1780 | --- tests/acceptance-tests/CMakeLists.txt 2017-03-10 19:47:57 +0000 |
1781 | +++ tests/acceptance-tests/CMakeLists.txt 2017-03-17 15:49:43 +0000 |
1782 | @@ -3,6 +3,8 @@ |
1783 | set( |
1784 | SOURCES |
1785 | |
1786 | + drag_and_drop.cpp |
1787 | + |
1788 | # Catch double-free bugs by wrapping close() and abort()ing on EBADF |
1789 | strict_close.cpp |
1790 | |
1791 | |
1792 | === added file 'tests/acceptance-tests/drag_and_drop.cpp' |
1793 | --- tests/acceptance-tests/drag_and_drop.cpp 1970-01-01 00:00:00 +0000 |
1794 | +++ tests/acceptance-tests/drag_and_drop.cpp 2017-03-17 15:49:43 +0000 |
1795 | @@ -0,0 +1,624 @@ |
1796 | +/* |
1797 | + * Copyright © 2017 Canonical Ltd. |
1798 | + * |
1799 | + * This program is free software: you can redistribute it and/or modify it |
1800 | + * under the terms of the GNU General Public License version 3, |
1801 | + * as published by the Free Software Foundation. |
1802 | + * |
1803 | + * This program is distributed in the hope that it will be useful, |
1804 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1805 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1806 | + * GNU General Public License for more details. |
1807 | + * |
1808 | + * You should have received a copy of the GNU General Public License |
1809 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1810 | + * |
1811 | + * Authored by: Alan Griffiths <alan@octopull.co.uk> |
1812 | + */ |
1813 | + |
1814 | +#include <mir_toolkit/extensions/drag_and_drop.h> |
1815 | +#include <mir_toolkit/mir_blob.h> |
1816 | + |
1817 | +#include <mir/geometry/displacement.h> |
1818 | +#include <mir/input/input_device_info.h> |
1819 | +#include <mir/input/device_capability.h> |
1820 | +#include <mir/shell/shell.h> |
1821 | + |
1822 | +#include <mir_test_framework/connected_client_with_a_window.h> |
1823 | +#include <mir_test_framework/fake_input_device.h> |
1824 | +#include <mir_test_framework/stub_server_platform_factory.h> |
1825 | +#include <mir/test/event_factory.h> |
1826 | +#include <mir/test/signal.h> |
1827 | + |
1828 | +#include <gmock/gmock.h> |
1829 | +#include <gtest/gtest.h> |
1830 | + |
1831 | +#include <linux/input.h> |
1832 | + |
1833 | +#include <boost/throw_exception.hpp> |
1834 | +#include <atomic> |
1835 | + |
1836 | +using namespace std::chrono_literals; |
1837 | +using namespace mir::geometry; |
1838 | +using namespace testing; |
1839 | +using mir::test::Signal; |
1840 | + |
1841 | +namespace |
1842 | +{ |
1843 | +class Cookie |
1844 | +{ |
1845 | +public: |
1846 | + Cookie() = default; |
1847 | + explicit Cookie(MirCookie const* cookie) : self{cookie, deleter} {} |
1848 | + |
1849 | + operator MirCookie const*() const { return self.get(); } |
1850 | + auto get() const -> MirCookie const* { return self.get(); } |
1851 | + |
1852 | + void reset() { self.reset(); } |
1853 | + void reset(MirCookie const* cookie) { self.reset(cookie, deleter); } |
1854 | + |
1855 | +private: |
1856 | + static void deleter(MirCookie const* cookie) { mir_cookie_release(cookie); } |
1857 | + std::shared_ptr<MirCookie const> self; |
1858 | +}; |
1859 | + |
1860 | +void mir_cookie_release(Cookie const&) = delete; |
1861 | + |
1862 | +class Blob |
1863 | +{ |
1864 | +public: |
1865 | + Blob() = default; |
1866 | + explicit Blob(MirBlob* blob) : self{blob, deleter} {} |
1867 | + |
1868 | + operator MirBlob*() const { return self.get(); } |
1869 | + auto get() const -> MirBlob* { return self.get(); } |
1870 | + |
1871 | + void reset() { self.reset(); } |
1872 | + void reset(MirBlob* blob) { self.reset(blob, deleter); } |
1873 | + |
1874 | +private: |
1875 | + static void deleter(MirBlob* blob) { mir_blob_release(blob); } |
1876 | + std::shared_ptr<MirBlob> self; |
1877 | +}; |
1878 | + |
1879 | +void mir_blob_release(Blob const&) = delete; |
1880 | + |
1881 | +struct MouseMoverAndFaker |
1882 | +{ |
1883 | + void start_dragging_mouse() |
1884 | + { |
1885 | + using namespace mir::input::synthesis; |
1886 | + fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT)); |
1887 | + } |
1888 | + |
1889 | + void move_mouse(Displacement const& displacement) |
1890 | + { |
1891 | + using mir::input::synthesis::a_pointer_event; |
1892 | + fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int())); |
1893 | + } |
1894 | + |
1895 | + void release_mouse() |
1896 | + { |
1897 | + using namespace mir::input::synthesis; |
1898 | + fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT)); |
1899 | + } |
1900 | + |
1901 | +private: |
1902 | + std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{ |
1903 | + mir_test_framework::add_fake_input_device( |
1904 | + mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer})}; |
1905 | +}; |
1906 | + |
1907 | +Rectangle const screen_geometry{{0,0}, {800,600}}; |
1908 | +auto const receive_event_timeout = 90s; |
1909 | + |
1910 | +struct DragAndDrop : mir_test_framework::ConnectedClientWithAWindow, |
1911 | + MouseMoverAndFaker |
1912 | +{ |
1913 | + MirDragAndDropV1 const* dnd = nullptr; |
1914 | + |
1915 | + void SetUp() override |
1916 | + { |
1917 | + initial_display_layout({screen_geometry}); |
1918 | + mir_test_framework::ConnectedClientWithAWindow::SetUp(); |
1919 | + dnd = mir_drag_and_drop_v1(connection); |
1920 | + mir_window_set_event_handler(window, &window_event_handler, this); |
1921 | + if (dnd) dnd->set_start_drag_and_drop_callback(window, &window_dnd_start_handler, this); |
1922 | + |
1923 | + create_target_window(); |
1924 | + |
1925 | + paint_window(window); |
1926 | + |
1927 | + center_mouse(); |
1928 | + } |
1929 | + |
1930 | + void TearDown() override |
1931 | + { |
1932 | + reset_window_event_handler(target_window); |
1933 | + reset_window_event_handler(window); |
1934 | + mir_window_release_sync(target_window); |
1935 | + mir_connection_release(another_connection); |
1936 | + mir_test_framework::ConnectedClientWithAWindow::TearDown(); |
1937 | + } |
1938 | + |
1939 | + auto user_initiates_drag() -> Cookie; |
1940 | + auto client_requests_drag(Cookie const& cookie) -> Blob; |
1941 | + auto handle_from_mouse_move() -> Blob; |
1942 | + auto handle_from_mouse_leave() -> Blob; |
1943 | + auto handle_from_mouse_enter() -> Blob; |
1944 | + auto handle_from_mouse_release() -> Blob; |
1945 | + auto count_of_handles_when_moving_mouse() -> int; |
1946 | + |
1947 | +private: |
1948 | + void center_mouse(); |
1949 | + void paint_window(MirWindow* w); |
1950 | + void set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler); |
1951 | + void set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler); |
1952 | + void reset_window_event_handler(MirWindow* window); |
1953 | + |
1954 | + void create_target_window() |
1955 | + { |
1956 | + another_connection = mir_connect_sync(new_connection().c_str(), "another_connection"); |
1957 | + auto const spec = mir_create_normal_window_spec( |
1958 | + connection, screen_geometry.size.width.as_int(), screen_geometry.size.height.as_int()); |
1959 | + mir_window_spec_set_pixel_format(spec, mir_pixel_format_abgr_8888); |
1960 | + mir_window_spec_set_name(spec, "target_window"); |
1961 | + mir_window_spec_set_buffer_usage(spec, mir_buffer_usage_hardware); |
1962 | + mir_window_spec_set_event_handler(spec, &window_event_handler, this); |
1963 | + |
1964 | + target_window = mir_create_window_sync(spec); |
1965 | + mir_window_spec_release(spec); |
1966 | + |
1967 | + paint_window(target_window); |
1968 | + } |
1969 | + |
1970 | + void invoke_window_event_handler(MirWindow* window, MirEvent const* event) |
1971 | + { |
1972 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
1973 | + if (window == this->window) window_event_handler_(event); |
1974 | + if (window == target_window) target_window_event_handler_(event); |
1975 | + } |
1976 | + |
1977 | + void invoke_window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event) |
1978 | + { |
1979 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
1980 | + if (window == this->window) window_dnd_start_(event); |
1981 | + } |
1982 | + |
1983 | + std::mutex window_event_handler_mutex; |
1984 | + std::function<void(MirDragAndDropEvent const* event)> window_dnd_start_ = [](MirDragAndDropEvent const*) {}; |
1985 | + std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {}; |
1986 | + std::function<void(MirEvent const* event)> target_window_event_handler_ = [](MirEvent const*) {}; |
1987 | + |
1988 | + static void window_event_handler(MirWindow* window, MirEvent const* event, void* context); |
1989 | + static void window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context); |
1990 | + |
1991 | + MirConnection* another_connection{nullptr}; |
1992 | + MirWindow* target_window{nullptr}; |
1993 | +}; |
1994 | + |
1995 | +void DragAndDrop::set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler) |
1996 | +{ |
1997 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
1998 | + if (window == this->window) window_event_handler_ = handler; |
1999 | + if (window == target_window) target_window_event_handler_ = handler; |
2000 | +} |
2001 | + |
2002 | +void DragAndDrop::set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler) |
2003 | +{ |
2004 | + std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex}; |
2005 | + if (window == this->window) window_dnd_start_ = handler; |
2006 | +} |
2007 | + |
2008 | + |
2009 | +void DragAndDrop::reset_window_event_handler(MirWindow* window) |
2010 | +{ |
2011 | + if (window == this->window) window_event_handler_ = [](MirEvent const*) {}; |
2012 | + if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {}; |
2013 | +} |
2014 | + |
2015 | +void DragAndDrop::paint_window(MirWindow* w) |
2016 | +{ |
2017 | + Signal have_focus; |
2018 | + |
2019 | + set_window_event_handler(w, [&](MirEvent const* event) |
2020 | + { |
2021 | + if (mir_event_get_type(event) != mir_event_type_window) |
2022 | + return; |
2023 | + |
2024 | + auto const window_event = mir_event_get_window_event(event); |
2025 | + if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus) |
2026 | + return; |
2027 | + |
2028 | + if (mir_window_event_get_attribute_value(window_event)) |
2029 | + have_focus.raise(); |
2030 | + }); |
2031 | + |
2032 | + mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(w)); |
2033 | + |
2034 | + EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true)); |
2035 | + |
2036 | + reset_window_event_handler(w); |
2037 | +} |
2038 | + |
2039 | +void DragAndDrop::center_mouse() |
2040 | +{ |
2041 | + Signal have_mouseover; |
2042 | + |
2043 | + set_window_event_handler(window, [&](MirEvent const* event) |
2044 | + { |
2045 | + if (mir_event_get_type(event) != mir_event_type_input) |
2046 | + return; |
2047 | + |
2048 | + auto const input_event = mir_event_get_input_event(event); |
2049 | + |
2050 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
2051 | + return; |
2052 | + |
2053 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
2054 | + |
2055 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) |
2056 | + return; |
2057 | + |
2058 | + have_mouseover.raise(); |
2059 | + }); |
2060 | + |
2061 | + move_mouse(0.5 * as_displacement(screen_geometry.size)); |
2062 | + |
2063 | +// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20). |
2064 | +// But it isn't essential for the test and we've probably waited long enough |
2065 | +// for the mouse-down needed by the test to reach the window. |
2066 | +// EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true)); |
2067 | + have_mouseover.wait_for(receive_event_timeout); |
2068 | + |
2069 | + reset_window_event_handler(window); |
2070 | +} |
2071 | + |
2072 | +void DragAndDrop::window_event_handler(MirWindow* window, MirEvent const* event, void* context) |
2073 | +{ |
2074 | + static_cast<DragAndDrop*>(context)->invoke_window_event_handler(window, event); |
2075 | +} |
2076 | + |
2077 | +void DragAndDrop::window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context) |
2078 | +{ |
2079 | + static_cast<DragAndDrop*>(context)->invoke_window_dnd_start_handler(window, event); |
2080 | +} |
2081 | + |
2082 | + |
2083 | +auto DragAndDrop::user_initiates_drag() -> Cookie |
2084 | +{ |
2085 | + Cookie cookie; |
2086 | + Signal have_cookie; |
2087 | + |
2088 | + set_window_event_handler(window, [&](MirEvent const* event) |
2089 | + { |
2090 | + if (mir_event_get_type(event) != mir_event_type_input) |
2091 | + return; |
2092 | + |
2093 | + auto const input_event = mir_event_get_input_event(event); |
2094 | + |
2095 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
2096 | + return; |
2097 | + |
2098 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
2099 | + |
2100 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down) |
2101 | + return; |
2102 | + |
2103 | + cookie = Cookie{mir_input_event_get_cookie(input_event)}; |
2104 | + have_cookie.raise(); |
2105 | + }); |
2106 | + |
2107 | + start_dragging_mouse(); |
2108 | + |
2109 | + EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true)); |
2110 | + |
2111 | + reset_window_event_handler(window); |
2112 | + return cookie; |
2113 | +} |
2114 | + |
2115 | +auto DragAndDrop::client_requests_drag(Cookie const& cookie) -> Blob |
2116 | +{ |
2117 | + Blob blob; |
2118 | + Signal initiated; |
2119 | + |
2120 | + set_window_dnd_start_handler(window, [&](MirDragAndDropEvent const* event) |
2121 | + { |
2122 | + if (dnd) |
2123 | + blob.reset(dnd->start_drag_and_drop(event)); |
2124 | + |
2125 | + if (blob) |
2126 | + initiated.raise(); |
2127 | + }); |
2128 | + |
2129 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
2130 | + |
2131 | + if (dnd) |
2132 | + dnd->request_drag_and_drop(window, cookie); |
2133 | + |
2134 | + EXPECT_TRUE(initiated.wait_for(receive_event_timeout)); |
2135 | + |
2136 | + reset_window_event_handler(window); |
2137 | + return blob; |
2138 | +} |
2139 | + |
2140 | +auto DragAndDrop::handle_from_mouse_move() -> Blob |
2141 | +{ |
2142 | + Blob blob; |
2143 | + Signal have_blob; |
2144 | + |
2145 | + set_window_event_handler(window, [&](MirEvent const* event) |
2146 | + { |
2147 | + if (mir_event_get_type(event) != mir_event_type_input) |
2148 | + return; |
2149 | + |
2150 | + auto const input_event = mir_event_get_input_event(event); |
2151 | + |
2152 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
2153 | + return; |
2154 | + |
2155 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
2156 | + |
2157 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
2158 | + |
2159 | + if (dnd) |
2160 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
2161 | + |
2162 | + if (blob) |
2163 | + have_blob.raise(); |
2164 | + }); |
2165 | + |
2166 | + move_mouse({1,1}); |
2167 | + |
2168 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
2169 | + |
2170 | + reset_window_event_handler(window); |
2171 | + return blob; |
2172 | +} |
2173 | + |
2174 | +auto DragAndDrop::handle_from_mouse_leave() -> Blob |
2175 | +{ |
2176 | + Blob blob; |
2177 | + Signal have_blob; |
2178 | + |
2179 | + set_window_event_handler(window, [&](MirEvent const* event) |
2180 | + { |
2181 | + if (mir_event_get_type(event) != mir_event_type_input) |
2182 | + return; |
2183 | + |
2184 | + auto const input_event = mir_event_get_input_event(event); |
2185 | + |
2186 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
2187 | + return; |
2188 | + |
2189 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
2190 | + |
2191 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_leave) |
2192 | + return; |
2193 | + |
2194 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
2195 | + |
2196 | + if (dnd) |
2197 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
2198 | + |
2199 | + if (blob) |
2200 | + have_blob.raise(); |
2201 | + }); |
2202 | + |
2203 | + move_mouse({1,1}); |
2204 | + move_mouse(0.5 * as_displacement(surface_size)); |
2205 | + |
2206 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
2207 | + |
2208 | + reset_window_event_handler(window); |
2209 | + return blob; |
2210 | +} |
2211 | + |
2212 | +auto DragAndDrop::handle_from_mouse_enter() -> Blob |
2213 | +{ |
2214 | + Blob blob; |
2215 | + Signal have_blob; |
2216 | + |
2217 | + set_window_event_handler(target_window, [&](MirEvent const* event) |
2218 | + { |
2219 | + if (mir_event_get_type(event) != mir_event_type_input) |
2220 | + return; |
2221 | + |
2222 | + auto const input_event = mir_event_get_input_event(event); |
2223 | + |
2224 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
2225 | + return; |
2226 | + |
2227 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
2228 | + |
2229 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter) |
2230 | + return; |
2231 | + |
2232 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
2233 | + |
2234 | + if (dnd) |
2235 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
2236 | + |
2237 | + if (blob) |
2238 | + have_blob.raise(); |
2239 | + }); |
2240 | + |
2241 | + move_mouse({1,1}); |
2242 | + move_mouse(0.5 * as_displacement(surface_size)); |
2243 | + |
2244 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
2245 | + |
2246 | + reset_window_event_handler(target_window); |
2247 | + return blob; |
2248 | +} |
2249 | + |
2250 | +auto DragAndDrop::handle_from_mouse_release() -> Blob |
2251 | +{ |
2252 | + Blob blob; |
2253 | + Signal have_blob; |
2254 | + |
2255 | + set_window_event_handler(target_window, [&](MirEvent const* event) |
2256 | + { |
2257 | + if (mir_event_get_type(event) != mir_event_type_input) |
2258 | + return; |
2259 | + |
2260 | + auto const input_event = mir_event_get_input_event(event); |
2261 | + |
2262 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
2263 | + return; |
2264 | + |
2265 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
2266 | + |
2267 | + if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_up) |
2268 | + return; |
2269 | + |
2270 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
2271 | + |
2272 | + if (dnd) |
2273 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
2274 | + |
2275 | + if (blob) |
2276 | + have_blob.raise(); |
2277 | + }); |
2278 | + |
2279 | + move_mouse({1,1}); |
2280 | + move_mouse(0.5 * as_displacement(surface_size)); |
2281 | + release_mouse(); |
2282 | + |
2283 | + EXPECT_TRUE(have_blob.wait_for(receive_event_timeout)); |
2284 | + |
2285 | + reset_window_event_handler(target_window); |
2286 | + return blob; |
2287 | +} |
2288 | + |
2289 | +auto DragAndDrop::count_of_handles_when_moving_mouse() -> int |
2290 | +{ |
2291 | + Signal have_3_events; |
2292 | + std::atomic<int> events{0}; |
2293 | + std::atomic<int> handles{0}; |
2294 | + |
2295 | + auto counter = [&](MirEvent const* event) |
2296 | + { |
2297 | + if (mir_event_get_type(event) != mir_event_type_input) |
2298 | + return; |
2299 | + |
2300 | + auto const input_event = mir_event_get_input_event(event); |
2301 | + |
2302 | + if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) |
2303 | + return; |
2304 | + |
2305 | + auto const pointer_event = mir_input_event_get_pointer_event(input_event); |
2306 | + |
2307 | + EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension"; |
2308 | + |
2309 | + Blob blob; |
2310 | + if (dnd) |
2311 | + blob.reset(dnd->pointer_drag_and_drop(pointer_event)); |
2312 | + |
2313 | + if (blob) |
2314 | + handles.fetch_add(1); |
2315 | + |
2316 | + if (events.fetch_add(1) == 2) |
2317 | + have_3_events.raise(); |
2318 | + }; |
2319 | + |
2320 | + set_window_event_handler(window, counter); |
2321 | + set_window_event_handler(target_window, counter); |
2322 | + |
2323 | + start_dragging_mouse(); |
2324 | + move_mouse({1,1}); |
2325 | + release_mouse(); |
2326 | + |
2327 | + EXPECT_TRUE(have_3_events.wait_for(receive_event_timeout)); |
2328 | + |
2329 | + reset_window_event_handler(window); |
2330 | + reset_window_event_handler(target_window); |
2331 | + return handles; |
2332 | +} |
2333 | + |
2334 | +MATCHER_P(BlobContentEq, p, "") |
2335 | +{ |
2336 | + if (!arg || !p) |
2337 | + return false; |
2338 | + if (mir_blob_size(arg) != mir_blob_size(p)) |
2339 | + return false; |
2340 | + return !memcmp(mir_blob_data(arg), mir_blob_data(p), mir_blob_size(p)); |
2341 | +} |
2342 | +} |
2343 | + |
2344 | +TEST_F(DragAndDrop, when_user_initiates_drag_client_receives_cookie) |
2345 | +{ |
2346 | + auto const cookie = user_initiates_drag(); |
2347 | + |
2348 | + EXPECT_THAT(cookie.get(), NotNull()); |
2349 | +} |
2350 | + |
2351 | +TEST_F(DragAndDrop, when_client_requests_drags_it_receives_handle) |
2352 | +{ |
2353 | + auto const cookie = user_initiates_drag(); |
2354 | + ASSERT_THAT(cookie.get(), NotNull()); |
2355 | + |
2356 | + auto const handle = client_requests_drag(cookie); |
2357 | + |
2358 | + EXPECT_THAT(handle.get(), NotNull()); |
2359 | +} |
2360 | + |
2361 | +TEST_F(DragAndDrop, during_drag_when_user_moves_mouse_client_receives_handle) |
2362 | +{ |
2363 | + auto const cookie = user_initiates_drag(); |
2364 | + ASSERT_THAT(cookie.get(), NotNull()); |
2365 | + auto const handle_from_request = client_requests_drag(cookie); |
2366 | + |
2367 | + auto const handle = handle_from_mouse_move(); |
2368 | + |
2369 | + EXPECT_THAT(handle.get(), NotNull()); |
2370 | + EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get())); |
2371 | +} |
2372 | + |
2373 | +TEST_F(DragAndDrop, when_drag_moves_from_window_leave_event_contains_handle) |
2374 | +{ |
2375 | + auto const cookie = user_initiates_drag(); |
2376 | + ASSERT_THAT(cookie.get(), NotNull()); |
2377 | + auto const handle_from_request = client_requests_drag(cookie); |
2378 | + |
2379 | + auto const handle = handle_from_mouse_leave(); |
2380 | + |
2381 | + EXPECT_THAT(handle.get(), NotNull()); |
2382 | + EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get())); |
2383 | +} |
2384 | + |
2385 | +TEST_F(DragAndDrop, when_drag_enters_target_window_enter_event_contains_handle) |
2386 | +{ |
2387 | + auto const cookie = user_initiates_drag(); |
2388 | + ASSERT_THAT(cookie.get(), NotNull()); |
2389 | + auto const handle_from_request = client_requests_drag(cookie); |
2390 | + |
2391 | + auto const handle = handle_from_mouse_enter(); |
2392 | + |
2393 | + EXPECT_THAT(handle.get(), NotNull()); |
2394 | + EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get())); |
2395 | +} |
2396 | + |
2397 | +TEST_F(DragAndDrop, when_drag_releases_target_window_release_event_contains_handle) |
2398 | +{ |
2399 | + auto const cookie = user_initiates_drag(); |
2400 | + ASSERT_THAT(cookie.get(), NotNull()); |
2401 | + auto const handle_from_request = client_requests_drag(cookie); |
2402 | + |
2403 | + auto const handle = handle_from_mouse_release(); |
2404 | + |
2405 | + EXPECT_THAT(handle.get(), NotNull()); |
2406 | + EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get())); |
2407 | +} |
2408 | + |
2409 | +TEST_F(DragAndDrop, after_drag_finishes_pointer_events_no_longer_contain_handle) |
2410 | +{ |
2411 | + auto const cookie = user_initiates_drag(); |
2412 | + ASSERT_THAT(cookie.get(), NotNull()); |
2413 | + client_requests_drag(cookie); |
2414 | + handle_from_mouse_release(); |
2415 | + |
2416 | + server.the_shell()->clear_drag_and_drop_handle(); |
2417 | + |
2418 | + EXPECT_THAT(count_of_handles_when_moving_mouse(), Eq(0)); |
2419 | +} |
2420 | |
2421 | === modified file 'tests/acceptance-tests/test_client_cursor_api.cpp' |
2422 | --- tests/acceptance-tests/test_client_cursor_api.cpp 2017-02-28 08:53:57 +0000 |
2423 | +++ tests/acceptance-tests/test_client_cursor_api.cpp 2017-03-17 15:49:43 +0000 |
2424 | @@ -82,6 +82,7 @@ |
2425 | MOCK_METHOD0(cursor_image_removed, void()); |
2426 | MOCK_METHOD1(placed_relative, void(geom::Rectangle const& placement)); |
2427 | MOCK_METHOD1(input_consumed, void(MirEvent const*)); |
2428 | + MOCK_METHOD1(start_drag_and_drop, void(std::vector<uint8_t> const& handle)); |
2429 | }; |
2430 | |
2431 | |
2432 | |
2433 | === modified file 'tests/include/mir/test/doubles/mock_input_targeter.h' |
2434 | --- tests/include/mir/test/doubles/mock_input_targeter.h 2015-06-18 02:46:16 +0000 |
2435 | +++ tests/include/mir/test/doubles/mock_input_targeter.h 2017-03-17 15:49:43 +0000 |
2436 | @@ -35,6 +35,9 @@ |
2437 | virtual ~MockInputTargeter() noexcept(true) {} |
2438 | MOCK_METHOD1(set_focus, void(std::shared_ptr<input::Surface> const&)); |
2439 | MOCK_METHOD0(clear_focus, void()); |
2440 | + |
2441 | + void set_drag_and_drop_handle(std::vector<uint8_t> const&) override {} |
2442 | + void clear_drag_and_drop_handle() override {} |
2443 | }; |
2444 | |
2445 | } |
2446 | |
2447 | === modified file 'tests/include/mir/test/doubles/mock_shell.h' |
2448 | --- tests/include/mir/test/doubles/mock_shell.h 2017-01-18 02:29:37 +0000 |
2449 | +++ tests/include/mir/test/doubles/mock_shell.h 2017-03-17 15:49:43 +0000 |
2450 | @@ -72,6 +72,9 @@ |
2451 | |
2452 | MOCK_METHOD3(raise_surface, void(std::shared_ptr<frontend::Session> const& session, |
2453 | frontend::SurfaceId surface_id, uint64_t timestamp)); |
2454 | + |
2455 | + MOCK_METHOD3(request_drag_and_drop, void(std::shared_ptr<frontend::Session> const& session, |
2456 | + frontend::SurfaceId surface_id, uint64_t timestamp)); |
2457 | }; |
2458 | |
2459 | } |
2460 | |
2461 | === modified file 'tests/include/mir/test/doubles/stub_display_server.h' |
2462 | --- tests/include/mir/test/doubles/stub_display_server.h 2017-02-15 07:38:33 +0000 |
2463 | +++ tests/include/mir/test/doubles/stub_display_server.h 2017-03-17 15:49:43 +0000 |
2464 | @@ -158,6 +158,10 @@ |
2465 | mir::protobuf::RaiseRequest const* /*request*/, |
2466 | mir::protobuf::Void* /*response*/, |
2467 | google::protobuf::Closure* /*done*/) {} |
2468 | + void request_drag_and_drop( |
2469 | + mir::protobuf::RequestAuthority const* /*request*/, |
2470 | + mir::protobuf::Void* /*response*/, |
2471 | + google::protobuf::Closure* /*done*/) {} |
2472 | void apply_input_configuration( |
2473 | mir::protobuf::InputConfigurationRequest const* /*request*/, |
2474 | mir::protobuf::Void* /*response*/, |
2475 | |
2476 | === modified file 'tests/include/mir/test/doubles/stub_input_targeter.h' |
2477 | --- tests/include/mir/test/doubles/stub_input_targeter.h 2015-06-18 02:46:16 +0000 |
2478 | +++ tests/include/mir/test/doubles/stub_input_targeter.h 2017-03-17 15:49:43 +0000 |
2479 | @@ -36,6 +36,9 @@ |
2480 | void clear_focus() |
2481 | { |
2482 | } |
2483 | + |
2484 | + void set_drag_and_drop_handle(std::vector<uint8_t> const&) override {} |
2485 | + void clear_drag_and_drop_handle() override {} |
2486 | }; |
2487 | |
2488 | } |
2489 | |
2490 | === modified file 'tests/include/mir/test/doubles/stub_scene_surface.h' |
2491 | --- tests/include/mir/test/doubles/stub_scene_surface.h 2017-02-15 14:45:41 +0000 |
2492 | +++ tests/include/mir/test/doubles/stub_scene_surface.h 2017-03-17 15:49:43 +0000 |
2493 | @@ -94,6 +94,7 @@ |
2494 | void set_confine_pointer_state(MirPointerConfinementState /*state*/) override {} |
2495 | MirPointerConfinementState confine_pointer_state() const override { return {}; } |
2496 | void placed_relative(geometry::Rectangle const& /*placement*/) override {} |
2497 | + void start_drag_and_drop(std::vector<uint8_t> const& /*handle*/) override {} |
2498 | }; |
2499 | |
2500 | } |
2501 | |
2502 | === modified file 'tests/mir_test_framework/observant_shell.cpp' |
2503 | --- tests/mir_test_framework/observant_shell.cpp 2017-01-20 00:01:50 +0000 |
2504 | +++ tests/mir_test_framework/observant_shell.cpp 2017-03-17 15:49:43 +0000 |
2505 | @@ -155,7 +155,26 @@ |
2506 | void mtf::ObservantShell::raise_surface( |
2507 | std::shared_ptr<msc::Session> const& session, |
2508 | std::shared_ptr<msc::Surface> const& window, |
2509 | + uint64_t timestamp) |
2510 | +{ |
2511 | + return wrapped->raise_surface(session, window, timestamp); |
2512 | +} |
2513 | + |
2514 | +void mtf::ObservantShell::request_drag_and_drop( |
2515 | + std::shared_ptr<msc::Session> const& session, |
2516 | + std::shared_ptr<msc::Surface> const& window, |
2517 | uint64_t timestamp) |
2518 | { |
2519 | - return wrapped->raise_surface(session, window, timestamp); |
2520 | -} |
2521 | + return wrapped->request_drag_and_drop(session, window, timestamp); |
2522 | +} |
2523 | + |
2524 | +void mtf::ObservantShell::set_drag_and_drop_handle(std::vector<uint8_t> const& handle) |
2525 | +{ |
2526 | + wrapped->set_drag_and_drop_handle(handle); |
2527 | +} |
2528 | + |
2529 | +void mtf::ObservantShell::clear_drag_and_drop_handle() |
2530 | +{ |
2531 | + wrapped->clear_drag_and_drop_handle(); |
2532 | +} |
2533 | + |
2534 | |
2535 | === modified file 'tests/mir_test_framework/stub_surface.cpp' |
2536 | --- tests/mir_test_framework/stub_surface.cpp 2017-02-15 14:45:41 +0000 |
2537 | +++ tests/mir_test_framework/stub_surface.cpp 2017-03-17 15:49:43 +0000 |
2538 | @@ -198,6 +198,10 @@ |
2539 | { |
2540 | } |
2541 | |
2542 | +void mtd::StubSurface::start_drag_and_drop(std::vector<uint8_t> const& /*handle*/) |
2543 | +{ |
2544 | +} |
2545 | + |
2546 | namespace |
2547 | { |
2548 | // Ensure we don't accidentally have an abstract class |
FAILED: Continuous integration, rev:4086 /mir-jenkins. ubuntu. com/job/ mir-ci/ 3142/ /mir-jenkins. ubuntu. com/job/ build-mir/ 4216/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/4303 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 4293 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 4293 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= zesty/4293 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= zesty/4243 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= zesty/4243/ artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4243 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4243/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= zesty/4243/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 4243 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 4243/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 4243 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 4243/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4243 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 4243/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: 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/ 3142/rebuild
https:/