Mir

Merge lp:~alan-griffiths/mir/drag-and-drop-II into lp:mir

Proposed by Alan Griffiths
Status: Merged
Merged at revision: 4100
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
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Approve
Kevin DuBois (community) Approve
Andreas Pokorny (community) Approve
Mir CI Bot continuous-integration Approve
Chris Halse Rogers Pending
Alan Griffiths Pending
Cemil Azizoglu Pending
Review via email: mp+320215@code.launchpad.net

This proposal supersedes a proposal from 2017-03-14.

Commit message

Support for Drag and Drop

Description of the change

Support for Drag and Drop

This completes the Mir role in https://goo.gl/AfG5v2

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:4086
https://mir-jenkins.ubuntu.com/job/mir-ci/3142/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4216/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4303
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4293
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4293
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4293
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4243
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4243/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4243
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4243/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4243/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4243
        deb: https://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
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4243
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4243/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4243
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4243/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3142/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

18:39:25 [ RUN ] DragAndDrop.when_drag_moves_from_window_leave_event_contains_cookie
...
18:39:25 /<<BUILDDIR>>/mir-0.26.0+zesty4293bzr4086/tests/acceptance-tests/drag_and_drop.cpp:256: Failure
18:39:25 Value of: have_cookie.wait_for(receive_event_timeout)
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.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> 18:39:25 [ RUN ]
> DragAndDrop.when_drag_moves_from_window_leave_event_contains_cookie
> ...
> 18:39:25 /<<BUILDDIR>>/mir-0.26.0+zesty4293bzr4086/tests/acceptance-
> tests/drag_and_drop.cpp:256: Failure
> 18:39:25 Value of: have_cookie.wait_for(receive_event_timeout)
> 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.when_drag_moves_from_window_leave_event_contains_cookie
...
18:37:06 11: /<<BUILDDIR>>/mir-0.26.0+zesty4293bzr4086/tests/acceptance-tests/drag_and_drop.cpp:256: Failure
18:37:06 11: Value of: have_cookie.wait_for(receive_event_timeout)
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_attrib_focus, true}

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:4088
https://mir-jenkins.ubuntu.com/job/mir-ci/3151/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4230/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4317
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4307
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4307
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4307
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4257
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4257/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4257
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4257/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4257/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4257
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4257/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4257
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4257/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4257
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4257/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3151/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:4089
https://mir-jenkins.ubuntu.com/job/mir-ci/3153/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4232
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4319
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4309
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4309
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4309
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4259
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4259/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4259
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4259/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4259
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4259/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4259
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4259/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4259
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4259/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4259
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4259/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3153/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:4090
https://mir-jenkins.ubuntu.com/job/mir-ci/3154/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4233
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4320
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4310
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4310
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4310
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4260
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4260/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4260
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4260/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4260
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4260/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4260
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4260/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4260
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4260/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4260
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4260/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3154/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:4091
https://mir-jenkins.ubuntu.com/job/mir-ci/3155/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4234/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4321
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4311
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4311
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4311
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4261
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4261/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4261
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4261/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4261
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4261/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4261/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4261/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4261
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4261/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4261
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4261/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3155/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Failure is unrelated (lp:1660889)

So that's 3 CI runs with the new tests passing. (And soak testing them locally.)

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:4092
https://mir-jenkins.ubuntu.com/job/mir-ci/3158/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4237
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4324
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4314
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4314
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4314
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4264
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4264/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4264
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4264/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4264
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4264/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4264
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4264/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4264
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4264/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4264
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4264/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3158/rebuild

review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

l773 could use comment here as well (like the other comment noting how CapPnP has problems)
+ //std::copy(dnd_handle.begin(), dnd_handle.end(), back_inserter(blob->data_));

+// 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_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true));
does that need a bug?

both those minor, lgtm overall

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> l773 could use comment here as well (like the other comment noting how CapPnP
> has problems)
> + //std::copy(dnd_handle.begin(), dnd_handle.end(),
> back_inserter(blob->data_));

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_THAT(have_mouseover.wait_for(receive_event_timeout),
> 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_attrib_focus notification in paint_window) and the input "model" that does not (yet) route input to the surface. That's what you get by updating observers asynchronously - which, given the code we landed to support it, appears to have been a deliberate decision.

I doubt we'll see an issue in "real life".

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:4094
https://mir-jenkins.ubuntu.com/job/mir-ci/3168/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4251
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4338
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4328
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4328
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4328
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4278
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4278/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4278
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4278/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4278
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4278/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4278
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4278/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4278
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4278/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4278
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4278/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3168/rebuild

review: Approve (continuous-integration)
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

Why is this an extension? Because it requires an outside entity like a content hub?
---------------------------------

Is this needed?

130 + mir_surface_attrib_drag_and_drop_handle,
---------------------------------

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> 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_attrib_drag_and_drop_handle,
> ---------------------------------

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.

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

> > 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.

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote : Posted in a previous version of this proposal

lgtm

review: Approve
Revision history for this message
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

Needs info:
I'm not sure that overriding the events is appropriate - as I understand it, this will result in Mir sending pointer_enter/pointer_leave/pointer_motion events in cases where we currently don't?

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-released on that button, possibly activating it?

Nit: The locking in
+void MirSurface::request_drag_and_drop(MirCookie const* cookie)
appears unnecessary? All of the things it accesses are stack variables (cookie) or written-once-at-initialisation (surface_id).

Is the locking for the appeasement of ThreadSanitizer?

review: Needs Information
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote : Posted in a previous version of this proposal

> Needs info:
> I'm not sure that overriding the events is appropriate - as I understand it,
> this will result in Mir sending pointer_enter/pointer_leave/pointer_motion
> 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_actions) or we do not treat this as an extension or we accept the possible damage we do to current clients.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote : Posted in a previous version of this proposal

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

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> > Needs info:
> > I'm not sure that overriding the events is appropriate - as I understand it,
> > this will result in Mir sending pointer_enter/pointer_leave/pointer_motion
> > 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://goo.gl/AfG5v2 - shows the D&D handle carried by the mouse movement events. I don't know the domain well enough to be certain if the behaviour of drag-and-drop oblivious clients could be significantly affected, but it seems unlikely.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> 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/move/release - which would address some of the concerns about using pointer made above.

OTOH /1/ seems simpler.

*Seeking guidance* on /1/ or /2/

review: Needs Information
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote : Posted in a previous version of this proposal

Which route will allow us to easily expand drag and drop to touch guestures?

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> 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.

Revision history for this message
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

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_type)();
    MirDndEvent const* (*dnd_event_from_event)(MirEvent const*);
    MirBlob* (*dnd_event_get_handle)(MirDndEvent const*);
    MirDndAction (*dnd_event_get_action)(MirDndEvent const*);
}

…
DnDv1* dnd = mir_drag_and_drop_v1(connection);
…
<in event handler>
if (mir_event_get_type(event) == dnd->dnd_event_type())
{
    MirDndEvent const* dnd_event = dnd->dnd_event_from_event(event);
    if (dnd->dnd_event_get_action(dnd_event) == mir_dnd_event_enter)
    {
        handle_drop_enter_with_handle(dnd->dnd_event_get_handle(dnd_event));
        â€¦
    }
}

I prefer this to one-callback-per-extension, but not strongly enough to block. I don't *think* it'd be significantly more work to implement than (1), though.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> 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_get_type(event) == dnd->dnd_event_type())

Perhaps:

- if (mir_event_get_type(event) == dnd->dnd_event_type())
+ if (dnd && dnd->is_dnd_event(event))

Revision history for this message
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

Also happy with that :)

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4097
https://mir-jenkins.ubuntu.com/job/mir-ci/3182/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4278
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4365
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4355
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4355
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4355
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4305
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4305/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4305
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4305/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4305
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4305/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4305
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4305/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4305
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4305/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4305
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4305/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3182/rebuild

review: Approve (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

looks good

review: Approve
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

+ drag_and_drop.cpp drag_and_drop.h

Header added here, which is added below this as well

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Well those are both different headers, nm!

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Some small nits, otherwise looks good

Revision history for this message
Kevin DuBois (kdub) wrote :

lgtm

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

On 20/03/17 18:52, Brandon Schaefer wrote:
> + const_cast<MirPointerEvent*>(mir_input_event_get_pointer_event(input_event))->set_dnd_handle(handle);
> Why const cast this?

Because mir_input_event_get_pointer_event() returns a MirPointerEvent
const* which makes the set_dnd_handle() call illegal.

> You can do auto input_event = event.to_input(); Or if it defaults to const, MirInputEvent* input_event = event.to_input()

Eh?

--
Alan Griffiths +44 (0)798 9938 758
Octopull Ltd http://www.octopull.co.uk/

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

O yeah ... was thinking about the *.to_input() call not the client API call. Opps.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

On 20/03/17 18:52, Brandon Schaefer wrote:
>> + // Can't use std::copy() as the CapnP iterators don't provide an iterator category
>> + for (auto p = dnd_handle.begin(); p != dnd_handle.end(); ++p)
>> + blob->data_.push_back(*p);
> You should be able to do:
> std::copy(std::begin(dnd_handle), std::end(dnd_handle), std::begin(blob->data_));

Well, I can't.

> Able to do this with the cookie, which seems to work
>

Maybe there's something else needed too: the return type of
getDndHandle() is ::capnp::List< ::uint8_t>::Reader whereas getCookie()
returns ::capnp::Data::Reader.

--
Alan Griffiths +44 (0)798 9938 758
Octopull Ltd http://www.octopull.co.uk/

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

On 20/03/17 18:52, Brandon Schaefer wrote:
>> +void MirPointerEvent::set_dnd_handle(std::vector<uint8_t> const& handle)
>> +{
>> + event.getInput().getPointer().initDndHandle(handle.size());
>> + event.getInput().getPointer().setDndHandle(::kj::ArrayPtr<uint8_t const>{&*begin(handle), &*end(handle)});
> This could be done a bit different, though up to you:
> ::capnp::Data::Reader handle_data(handle.data(), handle.size());
> event.getInput().getPointer().setDndHandle(handle_data);
>

Tried this: The tests hang (didn't investigate further).

--
Alan Griffiths +44 (0)798 9938 758
Octopull Ltd http://www.octopull.co.uk/

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

lgtm (forgot to approve)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'examples/server_example_basic_window_manager.cpp'
--- examples/server_example_basic_window_manager.cpp 2017-01-18 02:29:37 +0000
+++ examples/server_example_basic_window_manager.cpp 2017-03-17 15:52:51 +0000
@@ -136,6 +136,14 @@
136 policy->handle_raise_surface(session, surface);136 policy->handle_raise_surface(session, surface);
137}137}
138138
139void me::BasicWindowManager::handle_request_drag_and_drop(
140 std::shared_ptr<scene::Session> const& /*session*/,
141 std::shared_ptr<scene::Surface> const& /*surface*/,
142 uint64_t /*timestamp*/)
143{
144 // Not supported in example servers
145}
146
139int me::BasicWindowManager::set_surface_attribute(147int me::BasicWindowManager::set_surface_attribute(
140 std::shared_ptr<scene::Session> const& /*session*/,148 std::shared_ptr<scene::Session> const& /*session*/,
141 std::shared_ptr<scene::Surface> const& surface,149 std::shared_ptr<scene::Surface> const& surface,
142150
=== modified file 'examples/server_example_basic_window_manager.h'
--- examples/server_example_basic_window_manager.h 2017-01-18 02:29:37 +0000
+++ examples/server_example_basic_window_manager.h 2017-03-17 15:52:51 +0000
@@ -174,6 +174,11 @@
174 std::shared_ptr<scene::Surface> const& surface,174 std::shared_ptr<scene::Surface> const& surface,
175 uint64_t timestamp) override;175 uint64_t timestamp) override;
176176
177 void handle_request_drag_and_drop(
178 std::shared_ptr<scene::Session> const& session,
179 std::shared_ptr<scene::Surface> const& surface,
180 uint64_t timestamp) override;
181
177 int set_surface_attribute(182 int set_surface_attribute(
178 std::shared_ptr<scene::Session> const& /*session*/,183 std::shared_ptr<scene::Session> const& /*session*/,
179 std::shared_ptr<scene::Surface> const& surface,184 std::shared_ptr<scene::Surface> const& surface,
180185
=== modified file 'include/client/mir/events/event_builders.h'
--- include/client/mir/events/event_builders.h 2017-02-15 13:36:35 +0000
+++ include/client/mir/events/event_builders.h 2017-03-17 15:52:51 +0000
@@ -161,6 +161,8 @@
161void transform_positions(MirEvent& event, mir::geometry::Displacement const& movement);161void transform_positions(MirEvent& event, mir::geometry::Displacement const& movement);
162void set_window_id(MirEvent& event, int window_id);162void set_window_id(MirEvent& event, int window_id);
163163
164EventUPtr make_start_drag_and_drop_event(frontend::SurfaceId const& surface_id, std::vector<uint8_t> const& handle);
165void set_drag_and_drop_handle(MirEvent& event, std::vector<uint8_t> const& handle);
164}166}
165}167}
166168
167169
=== added file 'include/client/mir_toolkit/extensions/drag_and_drop.h'
--- include/client/mir_toolkit/extensions/drag_and_drop.h 1970-01-01 00:00:00 +0000
+++ include/client/mir_toolkit/extensions/drag_and_drop.h 2017-03-17 15:52:51 +0000
@@ -0,0 +1,81 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#ifndef MIR_DRAG_AND_DROP_H
20#define MIR_DRAG_AND_DROP_H
21
22#include "mir_toolkit/mir_extension_core.h"
23#include "mir_toolkit/client_types.h"
24
25#ifdef __cplusplus
26extern "C" {
27#endif
28
29typedef struct MirDragAndDropEvent MirDragAndDropEvent;
30
31typedef struct MirDragAndDropV1
32{
33 /**
34 * Request drag and drop. If the request succeeds a window event with a
35 * "start drag" handle will be received.
36 *
37 * \warning An invalid cookie will terminate the client connection.
38 *
39 * \param [in] window The source window
40 * \param [in] cookie A cookie instance obtained from an input event.
41 */
42 void (*request_drag_and_drop)(MirWindow* window, MirCookie const* cookie);
43
44 /**
45 * Set the drag and drop callback. This receives
46 *
47 * \param [in] window The window
48 * \param [in] callback The callback function.
49 * \param [in] context To be passed to callback
50 */
51 void (*set_start_drag_and_drop_callback)(MirWindow* window,
52 void (*callback)(MirWindow* window, MirDragAndDropEvent const* event, void* context),
53 void* context);
54
55 /**
56 * Retrieve any "drag & drop" handle associated with the event.
57 *
58 * \param [in] event The event
59 * \return The associated drag handle or NULL
60 */
61 MirBlob* (*start_drag_and_drop)(MirDragAndDropEvent const* event);
62
63 /**
64 * Retrieve any "drag & drop" handle associated with the event.
65 *
66 * \param [in] event The event
67 * \return The associated drag handle or NULL
68 */
69 MirBlob* (*pointer_drag_and_drop)(MirPointerEvent const* event);
70
71} MirDragAndDropV1;
72
73static inline MirDragAndDropV1 const* mir_drag_and_drop_v1(MirConnection* connection)
74{
75 return (MirDragAndDropV1 const*) mir_connection_request_extension(connection, "mir_drag_and_drop", 1);
76}
77
78#ifdef __cplusplus
79}
80#endif
81#endif //MIR_DRAG_AND_DROP_H
0\ No newline at end of file82\ No newline at end of file
183
=== modified file 'include/server/mir/scene/null_surface_observer.h'
--- include/server/mir/scene/null_surface_observer.h 2017-02-15 13:36:35 +0000
+++ include/server/mir/scene/null_surface_observer.h 2017-03-17 15:52:51 +0000
@@ -47,6 +47,7 @@
47 void cursor_image_removed() override;47 void cursor_image_removed() override;
48 void placed_relative(geometry::Rectangle const& placement) override;48 void placed_relative(geometry::Rectangle const& placement) override;
49 void input_consumed(MirEvent const* event) override;49 void input_consumed(MirEvent const* event) override;
50 void start_drag_and_drop(std::vector<uint8_t> const& handle) override;
5051
51protected:52protected:
52 NullSurfaceObserver(NullSurfaceObserver const&) = delete;53 NullSurfaceObserver(NullSurfaceObserver const&) = delete;
5354
=== modified file 'include/server/mir/scene/surface.h'
--- include/server/mir/scene/surface.h 2017-02-15 14:45:41 +0000
+++ include/server/mir/scene/surface.h 2017-03-17 15:52:51 +0000
@@ -116,6 +116,7 @@
116 virtual MirPointerConfinementState confine_pointer_state() const = 0;116 virtual MirPointerConfinementState confine_pointer_state() const = 0;
117117
118 virtual void placed_relative(geometry::Rectangle const& placement) = 0;118 virtual void placed_relative(geometry::Rectangle const& placement) = 0;
119 virtual void start_drag_and_drop(std::vector<uint8_t> const& handle) = 0;
119};120};
120}121}
121}122}
122123
=== modified file 'include/server/mir/scene/surface_observer.h'
--- include/server/mir/scene/surface_observer.h 2017-02-15 13:36:35 +0000
+++ include/server/mir/scene/surface_observer.h 2017-03-17 15:52:51 +0000
@@ -27,6 +27,7 @@
2727
28#include <glm/glm.hpp>28#include <glm/glm.hpp>
29#include <string>29#include <string>
30#include <vector>
3031
31namespace mir32namespace mir
32{33{
@@ -62,6 +63,7 @@
62 virtual void cursor_image_removed() = 0;63 virtual void cursor_image_removed() = 0;
63 virtual void placed_relative(geometry::Rectangle const& placement) = 0;64 virtual void placed_relative(geometry::Rectangle const& placement) = 0;
64 virtual void input_consumed(MirEvent const* event) = 0;65 virtual void input_consumed(MirEvent const* event) = 0;
66 virtual void start_drag_and_drop(std::vector<uint8_t> const& handle) = 0;
6567
66protected:68protected:
67 SurfaceObserver() = default;69 SurfaceObserver() = default;
6870
=== modified file 'include/server/mir/shell/abstract_shell.h'
--- include/server/mir/shell/abstract_shell.h 2017-01-18 02:29:37 +0000
+++ include/server/mir/shell/abstract_shell.h 2017-03-17 15:52:51 +0000
@@ -82,6 +82,11 @@
82 std::shared_ptr<scene::Surface> const& surface,82 std::shared_ptr<scene::Surface> const& surface,
83 uint64_t timestamp) override;83 uint64_t timestamp) override;
8484
85 void request_drag_and_drop(
86 std::shared_ptr<scene::Session> const& session,
87 std::shared_ptr<scene::Surface> const& surface,
88 uint64_t timestamp) override;
89
85 std::shared_ptr<scene::PromptSession> start_prompt_session_for(90 std::shared_ptr<scene::PromptSession> start_prompt_session_for(
86 std::shared_ptr<scene::Session> const& session,91 std::shared_ptr<scene::Session> const& session,
87 scene::PromptSessionCreationParameters const& params) override;92 scene::PromptSessionCreationParameters const& params) override;
@@ -124,6 +129,9 @@
124129
125 void update_focused_surface_confined_region();130 void update_focused_surface_confined_region();
126131
132 void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override;
133 void clear_drag_and_drop_handle() override;
134
127protected:135protected:
128 std::shared_ptr<InputTargeter> const input_targeter;136 std::shared_ptr<InputTargeter> const input_targeter;
129 std::shared_ptr<SurfaceStack> const surface_stack;137 std::shared_ptr<SurfaceStack> const surface_stack;
130138
=== modified file 'include/server/mir/shell/focus_controller.h'
--- include/server/mir/shell/focus_controller.h 2016-01-29 08:18:22 +0000
+++ include/server/mir/shell/focus_controller.h 2017-03-17 15:52:51 +0000
@@ -19,8 +19,10 @@
19#ifndef MIR_SHELL_FOCUS_CONTROLLER_H_19#ifndef MIR_SHELL_FOCUS_CONTROLLER_H_
20#define MIR_SHELL_FOCUS_CONTROLLER_H_20#define MIR_SHELL_FOCUS_CONTROLLER_H_
2121
22#include <stddef.h>
22#include <memory>23#include <memory>
23#include <set>24#include <set>
25#include <vector>
2426
25namespace mir27namespace mir
26{28{
@@ -54,6 +56,9 @@
5456
55 virtual void raise(SurfaceSet const& surfaces) = 0;57 virtual void raise(SurfaceSet const& surfaces) = 0;
5658
59 virtual void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) = 0;
60 virtual void clear_drag_and_drop_handle() = 0;
61
57protected:62protected:
58 FocusController() = default;63 FocusController() = default;
59 FocusController(FocusController const&) = delete;64 FocusController(FocusController const&) = delete;
6065
=== modified file 'include/server/mir/shell/input_targeter.h'
--- include/server/mir/shell/input_targeter.h 2015-06-18 02:46:16 +0000
+++ include/server/mir/shell/input_targeter.h 2017-03-17 15:52:51 +0000
@@ -19,7 +19,9 @@
19#ifndef MIR_SHELL_INPUT_TARGETER_H_19#ifndef MIR_SHELL_INPUT_TARGETER_H_
20#define MIR_SHELL_INPUT_TARGETER_H_20#define MIR_SHELL_INPUT_TARGETER_H_
2121
22#include <stddef.h>
22#include <memory>23#include <memory>
24#include <vector>
2325
24namespace mir26namespace mir
25{27{
@@ -40,6 +42,9 @@
40 virtual void set_focus(std::shared_ptr<input::Surface> const& focus_surface) = 0;42 virtual void set_focus(std::shared_ptr<input::Surface> const& focus_surface) = 0;
41 virtual void clear_focus() = 0;43 virtual void clear_focus() = 0;
4244
45 virtual void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) = 0;
46 virtual void clear_drag_and_drop_handle() = 0;
47
43protected:48protected:
44 InputTargeter() = default;49 InputTargeter() = default;
45 InputTargeter(InputTargeter const&) = delete;50 InputTargeter(InputTargeter const&) = delete;
4651
=== modified file 'include/server/mir/shell/shell.h'
--- include/server/mir/shell/shell.h 2017-01-19 00:27:55 +0000
+++ include/server/mir/shell/shell.h 2017-03-17 15:52:51 +0000
@@ -100,6 +100,10 @@
100 std::shared_ptr<scene::Surface> const& surface,100 std::shared_ptr<scene::Surface> const& surface,
101 uint64_t timestamp) = 0;101 uint64_t timestamp) = 0;
102102
103 virtual void request_drag_and_drop(
104 std::shared_ptr<scene::Session> const& session,
105 std::shared_ptr<scene::Surface> const& surface,
106 uint64_t timestamp) = 0;
103/** @} */107/** @} */
104};108};
105}109}
106110
=== modified file 'include/server/mir/shell/shell_wrapper.h'
--- include/server/mir/shell/shell_wrapper.h 2017-01-18 02:29:37 +0000
+++ include/server/mir/shell/shell_wrapper.h 2017-03-17 15:52:51 +0000
@@ -85,11 +85,19 @@
85 std::shared_ptr<scene::Surface> const& surface,85 std::shared_ptr<scene::Surface> const& surface,
86 uint64_t timestamp) override;86 uint64_t timestamp) override;
8787
88 void request_drag_and_drop(
89 std::shared_ptr<scene::Session> const& session,
90 std::shared_ptr<scene::Surface> const& surface,
91 uint64_t timestamp) override;
92
88 void add_display(geometry::Rectangle const& area) override;93 void add_display(geometry::Rectangle const& area) override;
89 void remove_display(geometry::Rectangle const& area) override;94 void remove_display(geometry::Rectangle const& area) override;
9095
91 bool handle(MirEvent const& event) override;96 bool handle(MirEvent const& event) override;
9297
98 void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override;
99 void clear_drag_and_drop_handle() override;
100
93protected:101protected:
94 std::shared_ptr<Shell> const wrapped;102 std::shared_ptr<Shell> const wrapped;
95};103};
96104
=== modified file 'include/server/mir/shell/system_compositor_window_manager.h'
--- include/server/mir/shell/system_compositor_window_manager.h 2017-01-18 02:29:37 +0000
+++ include/server/mir/shell/system_compositor_window_manager.h 2017-03-17 15:52:51 +0000
@@ -95,6 +95,11 @@
95 std::shared_ptr<scene::Surface> const& surface,95 std::shared_ptr<scene::Surface> const& surface,
96 uint64_t timestamp) override;96 uint64_t timestamp) override;
9797
98 void handle_request_drag_and_drop(
99 std::shared_ptr<scene::Session> const& session,
100 std::shared_ptr<scene::Surface> const& surface,
101 uint64_t timestamp) override;
102
98 int set_surface_attribute(103 int set_surface_attribute(
99 std::shared_ptr<scene::Session> const& session,104 std::shared_ptr<scene::Session> const& session,
100 std::shared_ptr<scene::Surface> const& surface,105 std::shared_ptr<scene::Surface> const& surface,
101106
=== modified file 'include/server/mir/shell/window_manager.h'
--- include/server/mir/shell/window_manager.h 2017-01-18 02:29:37 +0000
+++ include/server/mir/shell/window_manager.h 2017-03-17 15:52:51 +0000
@@ -76,6 +76,11 @@
76 std::shared_ptr<scene::Surface> const& surface,76 std::shared_ptr<scene::Surface> const& surface,
77 uint64_t timestamp) = 0;77 uint64_t timestamp) = 0;
7878
79 virtual void handle_request_drag_and_drop(
80 std::shared_ptr<scene::Session> const& session,
81 std::shared_ptr<scene::Surface> const& surface,
82 uint64_t timestamp) = 0;
83
79 virtual ~WindowManager() = default;84 virtual ~WindowManager() = default;
80 WindowManager() = default;85 WindowManager() = default;
81 WindowManager(WindowManager const&) = delete;86 WindowManager(WindowManager const&) = delete;
8287
=== modified file 'include/test/mir/test/doubles/mock_window_manager.h'
--- include/test/mir/test/doubles/mock_window_manager.h 2017-01-18 02:29:37 +0000
+++ include/test/mir/test/doubles/mock_window_manager.h 2017-03-17 15:52:51 +0000
@@ -58,6 +58,7 @@
58 MOCK_METHOD1(handle_pointer_event, bool(MirPointerEvent const*));58 MOCK_METHOD1(handle_pointer_event, bool(MirPointerEvent const*));
5959
60 MOCK_METHOD3(handle_raise_surface, void(std::shared_ptr<scene::Session> const&, std::shared_ptr<scene::Surface> const&, uint64_t));60 MOCK_METHOD3(handle_raise_surface, void(std::shared_ptr<scene::Session> const&, std::shared_ptr<scene::Surface> const&, uint64_t));
61 MOCK_METHOD3(handle_request_drag_and_drop, void(std::shared_ptr<scene::Session> const&, std::shared_ptr<scene::Surface> const&, uint64_t));
6162
62 MOCK_METHOD4(set_surface_attribute,63 MOCK_METHOD4(set_surface_attribute,
63 int(std::shared_ptr<scene::Session> const& session,64 int(std::shared_ptr<scene::Session> const& session,
6465
=== modified file 'include/test/mir/test/doubles/stub_surface.h'
--- include/test/mir/test/doubles/stub_surface.h 2017-02-15 14:45:41 +0000
+++ include/test/mir/test/doubles/stub_surface.h 2017-03-17 15:52:51 +0000
@@ -70,6 +70,7 @@
70 void set_confine_pointer_state(MirPointerConfinementState state) override;70 void set_confine_pointer_state(MirPointerConfinementState state) override;
71 MirPointerConfinementState confine_pointer_state() const override;71 MirPointerConfinementState confine_pointer_state() const override;
72 void placed_relative(geometry::Rectangle const& placement) override;72 void placed_relative(geometry::Rectangle const& placement) override;
73 void start_drag_and_drop(std::vector<uint8_t> const& handle) override;
73};74};
74}75}
75}76}
7677
=== modified file 'include/test/mir_test_framework/observant_shell.h'
--- include/test/mir_test_framework/observant_shell.h 2017-01-20 00:01:50 +0000
+++ include/test/mir_test_framework/observant_shell.h 2017-03-17 15:52:51 +0000
@@ -96,6 +96,14 @@
96 std::shared_ptr<mir::scene::Surface> const& window,96 std::shared_ptr<mir::scene::Surface> const& window,
97 uint64_t timestamp) override;97 uint64_t timestamp) override;
9898
99 void request_drag_and_drop(
100 std::shared_ptr<mir::scene::Session> const& session,
101 std::shared_ptr<mir::scene::Surface> const& window,
102 uint64_t timestamp) override;
103
104 void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override;
105 void clear_drag_and_drop_handle() override;
106
99private:107private:
100 std::shared_ptr<mir::shell::Shell> const wrapped;108 std::shared_ptr<mir::shell::Shell> const wrapped;
101 std::shared_ptr<mir::scene::SurfaceObserver> const surface_observer;109 std::shared_ptr<mir::scene::SurfaceObserver> const surface_observer;
102110
=== modified file 'src/capnproto/mir_event.capnp'
--- src/capnproto/mir_event.capnp 2017-02-17 08:46:05 +0000
+++ src/capnproto/mir_event.capnp 2017-03-17 15:52:51 +0000
@@ -104,6 +104,8 @@
104104
105 buttons @7 :UInt32;105 buttons @7 :UInt32;
106106
107 dndHandle @8 :List(UInt8);
108
107 enum PointerAction109 enum PointerAction
108 {110 {
109 up @0;111 up @0;
@@ -149,6 +151,7 @@
149 id @0 :Int32;151 id @0 :Int32;
150 attrib @1 :Attrib;152 attrib @1 :Attrib;
151 value @2 :Int32;153 value @2 :Int32;
154 dndHandle @3 :List(UInt8);
152155
153 enum Attrib156 enum Attrib
154 {157 {
@@ -160,8 +163,9 @@
160 dpi @4;163 dpi @4;
161 visibility @5;164 visibility @5;
162 preferredOrientation @6;165 preferredOrientation @6;
166 startDragAndDrop @7;
163 # Must be last167 # Must be last
164 surfaceAttrib @7;168 surfaceAttrib @8;
165 }169 }
166}170}
167171
168172
=== modified file 'src/client/CMakeLists.txt'
--- src/client/CMakeLists.txt 2017-01-24 13:43:12 +0000
+++ src/client/CMakeLists.txt 2017-03-17 15:52:51 +0000
@@ -49,6 +49,7 @@
49add_library(mirclientobjects OBJECT49add_library(mirclientobjects OBJECT
5050
51 display_configuration.cpp51 display_configuration.cpp
52 drag_and_drop.cpp drag_and_drop.h
52 error_connections.cpp53 error_connections.cpp
53 event.cpp54 event.cpp
54 event_printer.cpp55 event_printer.cpp
@@ -105,6 +106,7 @@
105 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_error.h106 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_error.h
106 mir_extension_core.cpp107 mir_extension_core.cpp
107 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_extension_core.h108 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_extension_core.h
109 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/extensions/drag_and_drop.h
108)110)
109111
110# Ensure protobuf C++ headers have been produced before112# Ensure protobuf C++ headers have been produced before
111113
=== added file 'src/client/drag_and_drop.cpp'
--- src/client/drag_and_drop.cpp 1970-01-01 00:00:00 +0000
+++ src/client/drag_and_drop.cpp 2017-03-17 15:52:51 +0000
@@ -0,0 +1,85 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#include "drag_and_drop.h"
20#include "mir_toolkit/extensions/drag_and_drop.h"
21
22#include "mir/uncaught.h"
23#include "mir/events/surface_event.h"
24#include "mir/events/pointer_event.h"
25
26#include "mir_surface.h"
27
28namespace
29{
30
31void request_drag_and_drop(MirWindow* window, MirCookie const* cookie)
32try
33{
34 window->request_drag_and_drop(cookie);
35}
36catch (std::exception const& e)
37{
38 MIR_LOG_UNCAUGHT_EXCEPTION(e);
39 abort();
40}
41
42void set_start_drag_and_drop_callback(MirWindow* window,
43 void (*callback)(MirWindow* window, MirDragAndDropEvent const* event, void* context),
44 void* context)
45try
46{
47 window->set_drag_and_drop_start_handler([callback,window,context](MirWindowEvent const* event)
48 { callback(window, reinterpret_cast<MirDragAndDropEvent const*>(event), context); });
49}
50catch (std::exception const& e)
51{
52 MIR_LOG_UNCAUGHT_EXCEPTION(e);
53 abort();
54}
55
56MirBlob* start_drag_and_drop(MirDragAndDropEvent const* event)
57try
58{
59 return reinterpret_cast<MirWindowEvent const*>(event)->dnd_handle();
60}
61catch (std::exception const& e)
62{
63 MIR_LOG_UNCAUGHT_EXCEPTION(e);
64 abort();
65}
66
67MirBlob* pointer_drag_and_drop(MirPointerEvent const* event)
68try
69{
70 return event->dnd_handle();
71}
72catch (std::exception const& e)
73{
74 MIR_LOG_UNCAUGHT_EXCEPTION(e);
75 abort();
76}
77
78MirDragAndDropV1 const impl{
79 &request_drag_and_drop,
80 &set_start_drag_and_drop_callback,
81 &start_drag_and_drop,
82 &pointer_drag_and_drop};
83}
84
85MirDragAndDropV1 const* const mir::drag_and_drop::v1 = &impl;
086
=== added file 'src/client/drag_and_drop.h'
--- src/client/drag_and_drop.h 1970-01-01 00:00:00 +0000
+++ src/client/drag_and_drop.h 2017-03-17 15:52:51 +0000
@@ -0,0 +1,32 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#ifndef MIR_DRAG_AND_DROP_V1_H
20#define MIR_DRAG_AND_DROP_V1_H
21
22typedef struct MirDragAndDropV1 MirDragAndDropV1;
23
24namespace mir
25{
26namespace drag_and_drop
27{
28extern MirDragAndDropV1 const* const v1;
29}
30}
31
32#endif //MIR_DRAG_AND_DROP_V1_H
033
=== modified file 'src/client/events/event_builders.cpp'
--- src/client/events/event_builders.cpp 2017-02-15 13:36:35 +0000
+++ src/client/events/event_builders.cpp 2017-03-17 15:52:51 +0000
@@ -110,6 +110,20 @@
110 return make_uptr_event(e);110 return make_uptr_event(e);
111}111}
112112
113auto mev::make_start_drag_and_drop_event(frontend::SurfaceId const& surface_id, std::vector<uint8_t> const& handle)
114 -> EventUPtr
115{
116 auto e = new_event<MirWindowEvent>();
117
118 e->set_id(surface_id.as_value());
119 e->set_attrib(mir_window_attribs);
120 e->set_value(0);
121 e->set_dnd_handle(handle);
122
123 return make_uptr_event(e);
124
125}
126
113mir::EventUPtr mev::make_event(mf::SurfaceId const& surface_id)127mir::EventUPtr mev::make_event(mf::SurfaceId const& surface_id)
114{128{
115 auto e = new_event<MirCloseWindowEvent>();129 auto e = new_event<MirCloseWindowEvent>();
@@ -450,3 +464,14 @@
450 BOOST_THROW_EXCEPTION(std::invalid_argument("Event has no window id."));464 BOOST_THROW_EXCEPTION(std::invalid_argument("Event has no window id."));
451 }465 }
452}466}
467
468void mev::set_drag_and_drop_handle(MirEvent& event, std::vector<uint8_t> const& handle)
469{
470 if (event.type() == mir_event_type_input)
471 {
472 auto const input_event = event.to_input();
473 if (mir_input_event_get_type(input_event) == mir_input_event_type_pointer)
474 const_cast<MirPointerEvent*>(mir_input_event_get_pointer_event(input_event))->set_dnd_handle(handle);
475 }
476}
477
453478
=== modified file 'src/client/mir_blob.cpp'
--- src/client/mir_blob.cpp 2017-01-18 02:29:37 +0000
+++ src/client/mir_blob.cpp 2017-03-17 15:52:51 +0000
@@ -16,6 +16,7 @@
16 * Authored by: Alan Griffiths <alan@octopull.co.uk>16 * Authored by: Alan Griffiths <alan@octopull.co.uk>
17 */17 */
1818
19#include "mir_blob.h"
19#include "display_configuration.h"20#include "display_configuration.h"
2021
21#include "mir_toolkit/mir_blob.h"22#include "mir_toolkit/mir_blob.h"
@@ -25,14 +26,6 @@
2526
26namespace mp = mir::protobuf;27namespace mp = mir::protobuf;
2728
28struct MirBlob
29{
30 virtual size_t size() const = 0;
31 virtual void const* data() const = 0;
32
33 virtual ~MirBlob() = default;
34};
35
36namespace29namespace
37{30{
38struct MirManagedBlob : MirBlob31struct MirManagedBlob : MirBlob
3932
=== modified file 'src/client/mir_connection.cpp'
--- src/client/mir_connection.cpp 2017-03-14 04:41:33 +0000
+++ src/client/mir_connection.cpp 2017-03-17 15:52:51 +0000
@@ -17,6 +17,7 @@
17 */17 */
1818
19#include "mir_connection.h"19#include "mir_connection.h"
20#include "drag_and_drop.h"
20#include "mir_surface.h"21#include "mir_surface.h"
21#include "mir_prompt_session.h"22#include "mir_prompt_session.h"
22#include "mir_toolkit/extensions/graphics_module.h"23#include "mir_toolkit/extensions/graphics_module.h"
@@ -1451,6 +1452,9 @@
1451 if (!strcmp(name, "mir_extension_graphics_module") && (version == 1) && graphics_module_extension.is_set())1452 if (!strcmp(name, "mir_extension_graphics_module") && (version == 1) && graphics_module_extension.is_set())
1452 return &graphics_module_extension.value();1453 return &graphics_module_extension.value();
14531454
1455 if (!strcmp(name, "mir_drag_and_drop") && (version == 1))
1456 return const_cast<MirDragAndDropV1*>(mir::drag_and_drop::v1);
1457
1454 return platform->request_interface(name, version);1458 return platform->request_interface(name, version);
1455}1459}
14561460
14571461
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2017-03-14 04:41:33 +0000
+++ src/client/mir_surface.cpp 2017-03-17 15:52:51 +0000
@@ -24,6 +24,7 @@
24#include "connection_surface_map.h"24#include "connection_surface_map.h"
2525
26#include "mir_toolkit/mir_client_library.h"26#include "mir_toolkit/mir_client_library.h"
27#include "mir_toolkit/mir_blob.h"
27#include "mir/frontend/client_constants.h"28#include "mir/frontend/client_constants.h"
28#include "mir/client_buffer.h"29#include "mir/client_buffer.h"
29#include "mir/mir_buffer_stream.h"30#include "mir/mir_buffer_stream.h"
@@ -32,6 +33,7 @@
32#include "mir/cookie/cookie.h"33#include "mir/cookie/cookie.h"
33#include "mir_cookie.h"34#include "mir_cookie.h"
34#include "mir/time/posix_timestamp.h"35#include "mir/time/posix_timestamp.h"
36#include "mir/events/surface_event.h"
3537
36#include <cassert>38#include <cassert>
37#include <unistd.h>39#include <unistd.h>
@@ -493,7 +495,14 @@
493 auto sev = mir_event_get_window_event(&e);495 auto sev = mir_event_get_window_event(&e);
494 auto a = mir_window_event_get_attribute(sev);496 auto a = mir_window_event_get_attribute(sev);
495 if (a < mir_window_attribs)497 if (a < mir_window_attribs)
498 {
496 attrib_cache[a] = mir_window_event_get_attribute_value(sev);499 attrib_cache[a] = mir_window_event_get_attribute_value(sev);
500 }
501 else
502 {
503 handle_drag_and_drop_start_callback(sev);
504 return;
505 }
497 break;506 break;
498 }507 }
499 case mir_event_type_input:508 case mir_event_type_input:
@@ -598,6 +607,29 @@
598 google::protobuf::NewCallback(google::protobuf::DoNothing));607 google::protobuf::NewCallback(google::protobuf::DoNothing));
599}608}
600609
610void MirSurface::request_drag_and_drop(MirCookie const* cookie)
611{
612 mp::RequestAuthority authority;
613
614 std::unique_lock<decltype(mutex)> lock(mutex);
615 authority.mutable_surface_id()->set_value(surface->id().value());
616
617 auto const event_cookie = authority.mutable_cookie();
618
619 event_cookie->set_cookie(cookie->cookie().data(), cookie->size());
620
621 server->request_drag_and_drop(
622 &authority,
623 void_response.get(),
624 google::protobuf::NewCallback(google::protobuf::DoNothing));
625}
626
627void MirSurface::set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback)
628{
629 std::lock_guard<decltype(mutex)> lock(mutex);
630 handle_drag_and_drop_start_callback = callback;
631}
632
601MirBufferStream* MirSurface::get_buffer_stream()633MirBufferStream* MirSurface::get_buffer_stream()
602{634{
603 std::lock_guard<decltype(mutex)> lock(mutex);635 std::lock_guard<decltype(mutex)> lock(mutex);
604636
=== modified file 'src/client/mir_surface.h'
--- src/client/mir_surface.h 2017-02-15 14:45:41 +0000
+++ src/client/mir_surface.h 2017-03-17 15:52:51 +0000
@@ -200,6 +200,8 @@
200 MirWaitHandle* set_preferred_orientation(MirOrientationMode mode);200 MirWaitHandle* set_preferred_orientation(MirOrientationMode mode);
201201
202 void raise_surface(MirCookie const* cookie);202 void raise_surface(MirCookie const* cookie);
203 void request_drag_and_drop(MirCookie const* cookie);
204 void set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback);
203205
204 MirWaitHandle* configure_cursor(MirCursorConfiguration const* cursor);206 MirWaitHandle* configure_cursor(MirCursorConfiguration const* cursor);
205207
@@ -262,6 +264,8 @@
262 std::shared_ptr<mir::client::FrameClock> const frame_clock;264 std::shared_ptr<mir::client::FrameClock> const frame_clock;
263265
264 std::function<void(MirEvent const*)> handle_event_callback;266 std::function<void(MirEvent const*)> handle_event_callback;
267 std::function<void(MirWindowEvent const*)> handle_drag_and_drop_start_callback = [](auto){};
268
265 std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread;269 std::shared_ptr<mir::dispatch::ThreadedDispatcher> input_thread;
266270
267 //a bit batty, but the creation handle has to exist for as long as the MirSurface does,271 //a bit batty, but the creation handle has to exist for as long as the MirSurface does,
268272
=== modified file 'src/client/rpc/mir_display_server.cpp'
--- src/client/rpc/mir_display_server.cpp 2017-02-15 07:38:33 +0000
+++ src/client/rpc/mir_display_server.cpp 2017-03-17 15:52:51 +0000
@@ -238,6 +238,15 @@
238{238{
239 channel->call_method(std::string(__func__), request, response, done);239 channel->call_method(std::string(__func__), request, response, done);
240}240}
241
242void mclr::DisplayServer::request_drag_and_drop(
243 mir::protobuf::RequestAuthority const* request,
244 mir::protobuf::Void* response,
245 google::protobuf::Closure* done)
246{
247 channel->call_method(std::string(__func__), request, response, done);
248}
249
241void mclr::DisplayServer::apply_input_configuration(250void mclr::DisplayServer::apply_input_configuration(
242 mir::protobuf::InputConfigurationRequest const* request,251 mir::protobuf::InputConfigurationRequest const* request,
243 mir::protobuf::Void* response,252 mir::protobuf::Void* response,
244253
=== modified file 'src/client/rpc/mir_display_server.h'
--- src/client/rpc/mir_display_server.h 2017-02-15 07:38:33 +0000
+++ src/client/rpc/mir_display_server.h 2017-03-17 15:52:51 +0000
@@ -155,6 +155,10 @@
155 mir::protobuf::RaiseRequest const* request,155 mir::protobuf::RaiseRequest const* request,
156 mir::protobuf::Void* response,156 mir::protobuf::Void* response,
157 google::protobuf::Closure* done) override;157 google::protobuf::Closure* done) override;
158 void request_drag_and_drop(
159 mir::protobuf::RequestAuthority const* request,
160 mir::protobuf::Void* response,
161 google::protobuf::Closure* done) override;
158 void apply_input_configuration(162 void apply_input_configuration(
159 mir::protobuf::InputConfigurationRequest const* request,163 mir::protobuf::InputConfigurationRequest const* request,
160 mir::protobuf::Void* response,164 mir::protobuf::Void* response,
161165
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2017-03-14 04:41:33 +0000
+++ src/client/symbols.map 2017-03-17 15:52:51 +0000
@@ -604,6 +604,8 @@
604 global:604 global:
605 extern "C++" {605 extern "C++" {
606 mir::events::set_window_id*;606 mir::events::set_window_id*;
607 mir::events::make_start_drag_and_drop_event*;
608 mir::events::set_drag_and_drop_handle*;
607 };609 };
608} MIR_CLIENT_DETAIL_0.26.1;610} MIR_CLIENT_DETAIL_0.26.1;
609611
610612
=== modified file 'src/common/events/pointer_event.cpp'
--- src/common/events/pointer_event.cpp 2016-11-07 23:02:26 +0000
+++ src/common/events/pointer_event.cpp 2017-03-17 15:52:51 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2016 Canonical Ltd.2 * Copyright © 2016-2017 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,5 * under the terms of the GNU Lesser General Public License version 3,
@@ -16,10 +16,11 @@
16 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>16 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
17 */17 */
1818
19#include "mir/events/pointer_event.h"
20#include "mir_blob.h"
21
19#include <boost/throw_exception.hpp>22#include <boost/throw_exception.hpp>
2023
21#include "mir/events/pointer_event.h"
22
23MirPointerEvent::MirPointerEvent()24MirPointerEvent::MirPointerEvent()
24{25{
25 event.initInput();26 event.initInput();
@@ -132,3 +133,40 @@
132{133{
133 event.getInput().getPointer().setAction(static_cast<mir::capnp::PointerEvent::PointerAction>(action));134 event.getInput().getPointer().setAction(static_cast<mir::capnp::PointerEvent::PointerAction>(action));
134}135}
136
137void MirPointerEvent::set_dnd_handle(std::vector<uint8_t> const& handle)
138{
139 event.getInput().getPointer().initDndHandle(handle.size());
140 event.getInput().getPointer().setDndHandle(::kj::ArrayPtr<uint8_t const>{&*begin(handle), &*end(handle)});
141}
142
143namespace
144{
145struct MyMirBlob : MirBlob
146{
147
148 size_t size() const override { return data_.size(); }
149 virtual void const* data() const override { return data_.data(); }
150
151 std::vector<uint8_t> data_;
152};
153}
154
155MirBlob* MirPointerEvent::dnd_handle() const
156{
157 auto const reader = event.asReader().getInput().getPointer();
158
159 if (!reader.hasDndHandle())
160 return nullptr;
161
162 auto const dnd_handle = reader.getDndHandle();
163
164 auto blob = std::make_unique<MyMirBlob>();
165 blob->data_.reserve(dnd_handle.size());
166
167 // Can't use std::copy() as the CapnP iterators don't provide an iterator category
168 for (auto p = dnd_handle.begin(); p != dnd_handle.end(); ++p)
169 blob->data_.push_back(*p);
170
171 return blob.release();
172}
135173
=== modified file 'src/common/events/surface_event.cpp'
--- src/common/events/surface_event.cpp 2017-01-23 03:38:33 +0000
+++ src/common/events/surface_event.cpp 2017-03-17 15:52:51 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2016 Canonical Ltd.2 * Copyright © 2016-2017 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,5 * under the terms of the GNU Lesser General Public License version 3,
@@ -17,6 +17,7 @@
17 */17 */
1818
19#include "mir/events/surface_event.h"19#include "mir/events/surface_event.h"
20#include "mir_blob.h"
2021
21// MirSurfaceEvent is a deprecated type, but we need to implement it22// MirSurfaceEvent is a deprecated type, but we need to implement it
22#pragma GCC diagnostic ignored "-Wdeprecated-declarations"23#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -55,3 +56,40 @@
55{56{
56 event.getSurface().setValue(value);57 event.getSurface().setValue(value);
57}58}
59
60void MirSurfaceEvent::set_dnd_handle(std::vector<uint8_t> const& handle)
61{
62 event.getSurface().initDndHandle(handle.size());
63 event.getSurface().setDndHandle(::kj::ArrayPtr<uint8_t const>{&*begin(handle), &*end(handle)});
64}
65
66namespace
67{
68struct MyMirBlob : MirBlob
69{
70
71 size_t size() const override { return data_.size(); }
72 virtual void const* data() const override { return data_.data(); }
73
74 std::vector<uint8_t> data_;
75};
76}
77
78MirBlob* MirSurfaceEvent::dnd_handle() const
79{
80 if (!event.asReader().getSurface().hasDndHandle())
81 return nullptr;
82
83 auto blob = std::make_unique<MyMirBlob>();
84
85 auto reader = event.asReader().getSurface().getDndHandle();
86
87 blob->data_.reserve(reader.size());
88
89 // Can't use std::copy() as the CapnP iterators don't provide an iterator category
90 for (auto p = reader.begin(); p != reader.end(); ++p)
91 blob->data_.push_back(*p);
92
93 return blob.release();
94}
95
5896
=== modified file 'src/common/symbols.map'
--- src/common/symbols.map 2017-02-28 08:53:57 +0000
+++ src/common/symbols.map 2017-03-17 15:52:51 +0000
@@ -432,5 +432,9 @@
432 MirInputEvent::window_id*;432 MirInputEvent::window_id*;
433 MirKeyboardEvent::set_text*;433 MirKeyboardEvent::set_text*;
434 MirKeyboardEvent::text*;434 MirKeyboardEvent::text*;
435 MirPointerEvent::dnd_handle*;
436 MirPointerEvent::set_dnd_handle*;
437 MirSurfaceEvent::dnd_handle*;
438 MirSurfaceEvent::set_dnd_handle*;
435 };439 };
436} MIR_COMMON_0.26;440} MIR_COMMON_0.26;
437441
=== modified file 'src/include/common/mir/events/pointer_event.h'
--- src/include/common/mir/events/pointer_event.h 2016-09-22 19:21:34 +0000
+++ src/include/common/mir/events/pointer_event.h 2017-03-17 15:52:51 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2016 Canonical Ltd.2 * Copyright © 2016-2017 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,5 * under the terms of the GNU Lesser General Public License version 3,
@@ -21,6 +21,8 @@
2121
22#include "mir/events/input_event.h"22#include "mir/events/input_event.h"
2323
24typedef struct MirBlob MirBlob;
25
24struct MirPointerEvent : MirInputEvent26struct MirPointerEvent : MirInputEvent
25{27{
26 MirPointerEvent();28 MirPointerEvent();
@@ -60,6 +62,9 @@
6062
61 MirPointerButtons buttons() const;63 MirPointerButtons buttons() const;
62 void set_buttons(MirPointerButtons buttons);64 void set_buttons(MirPointerButtons buttons);
65
66 void set_dnd_handle(std::vector<uint8_t> const& handle);
67 MirBlob* dnd_handle() const;
63private:68private:
64};69};
6570
6671
=== modified file 'src/include/common/mir/events/surface_event.h'
--- src/include/common/mir/events/surface_event.h 2017-01-18 02:29:37 +0000
+++ src/include/common/mir/events/surface_event.h 2017-03-17 15:52:51 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2016 Canonical Ltd.2 * Copyright © 2016-2017 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,5 * under the terms of the GNU Lesser General Public License version 3,
@@ -21,6 +21,8 @@
2121
22#include "mir/events/event.h"22#include "mir/events/event.h"
2323
24typedef struct MirBlob MirBlob;
25
24struct MirSurfaceEvent : MirEvent26struct MirSurfaceEvent : MirEvent
25{27{
26 MirSurfaceEvent();28 MirSurfaceEvent();
@@ -33,6 +35,9 @@
3335
34 int value() const;36 int value() const;
35 void set_value(int value);37 void set_value(int value);
38
39 void set_dnd_handle(std::vector<uint8_t> const& handle);
40 MirBlob* dnd_handle() const;
36};41};
3742
38#endif /* MIR_COMMON_SURFACE_EVENT_H_ */43#endif /* MIR_COMMON_SURFACE_EVENT_H_ */
3944
=== modified file 'src/include/common/mir/protobuf/display_server.h'
--- src/include/common/mir/protobuf/display_server.h 2017-02-15 07:38:33 +0000
+++ src/include/common/mir/protobuf/display_server.h 2017-03-17 15:52:51 +0000
@@ -151,6 +151,10 @@
151 mir::protobuf::RaiseRequest const* request,151 mir::protobuf::RaiseRequest const* request,
152 mir::protobuf::Void* response,152 mir::protobuf::Void* response,
153 google::protobuf::Closure* done) = 0;153 google::protobuf::Closure* done) = 0;
154 virtual void request_drag_and_drop(
155 mir::protobuf::RequestAuthority const* request,
156 mir::protobuf::Void* response,
157 google::protobuf::Closure* done) = 0;
154 virtual void apply_input_configuration(158 virtual void apply_input_configuration(
155 mir::protobuf::InputConfigurationRequest const* request,159 mir::protobuf::InputConfigurationRequest const* request,
156 mir::protobuf::Void* response,160 mir::protobuf::Void* response,
157161
=== added file 'src/include/common/mir_blob.h'
--- src/include/common/mir_blob.h 1970-01-01 00:00:00 +0000
+++ src/include/common/mir_blob.h 2017-03-17 15:52:51 +0000
@@ -0,0 +1,32 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#ifndef MIR_MIR_BLOB_H_H
20#define MIR_MIR_BLOB_H_H
21
22#include <stddef.h>
23
24struct MirBlob
25{
26 virtual size_t size() const = 0;
27 virtual void const* data() const = 0;
28
29 virtual ~MirBlob() = default;
30};
31
32#endif //MIR_MIR_BLOB_H_H
033
=== modified file 'src/include/server/mir/frontend/shell.h'
--- src/include/server/mir/frontend/shell.h 2017-01-18 02:29:37 +0000
+++ src/include/server/mir/frontend/shell.h 2017-03-17 15:52:51 +0000
@@ -87,6 +87,11 @@
87 SurfaceId surface_id,87 SurfaceId surface_id,
88 uint64_t timestamp) = 0;88 uint64_t timestamp) = 0;
8989
90 virtual void request_drag_and_drop(
91 std::shared_ptr<Session> const& session,
92 SurfaceId surface_id,
93 uint64_t timestamp) = 0;
94
90protected:95protected:
91 Shell() = default;96 Shell() = default;
92 Shell(const Shell&) = delete;97 Shell(const Shell&) = delete;
9398
=== modified file 'src/include/server/mir/scene/surface_event_source.h'
--- src/include/server/mir/scene/surface_event_source.h 2017-02-15 13:36:35 +0000
+++ src/include/server/mir/scene/surface_event_source.h 2017-03-17 15:52:51 +0000
@@ -51,6 +51,7 @@
51 std::string const& variant, std::string const& options) override;51 std::string const& variant, std::string const& options) override;
52 void placed_relative(geometry::Rectangle const& placement) override;52 void placed_relative(geometry::Rectangle const& placement) override;
53 void input_consumed(MirEvent const* event) override;53 void input_consumed(MirEvent const* event) override;
54 void start_drag_and_drop(std::vector<uint8_t> const& handle) override;
5455
55private:56private:
56 frontend::SurfaceId const id;57 frontend::SurfaceId const id;
5758
=== modified file 'src/include/server/mir/scene/surface_observers.h'
--- src/include/server/mir/scene/surface_observers.h 2017-02-15 13:36:35 +0000
+++ src/include/server/mir/scene/surface_observers.h 2017-03-17 15:52:51 +0000
@@ -51,6 +51,7 @@
51 void cursor_image_removed() override;51 void cursor_image_removed() override;
52 void placed_relative(geometry::Rectangle const& placement) override;52 void placed_relative(geometry::Rectangle const& placement) override;
53 void input_consumed(MirEvent const* event) override;53 void input_consumed(MirEvent const* event) override;
54 void start_drag_and_drop(std::vector<uint8_t> const& handle) override;
54};55};
5556
56}57}
5758
=== modified file 'src/include/server/mir/shell/basic_window_manager.h'
--- src/include/server/mir/shell/basic_window_manager.h 2017-01-18 02:29:37 +0000
+++ src/include/server/mir/shell/basic_window_manager.h 2017-03-17 15:52:51 +0000
@@ -65,6 +65,9 @@
6565
66 virtual void raise_tree(std::shared_ptr<scene::Surface> const& root) = 0;66 virtual void raise_tree(std::shared_ptr<scene::Surface> const& root) = 0;
6767
68 virtual void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) = 0;
69 virtual void clear_drag_and_drop_handle() = 0;
70
68 virtual ~WindowManagerTools() = default;71 virtual ~WindowManagerTools() = default;
69 WindowManagerTools() = default;72 WindowManagerTools() = default;
70 WindowManagerTools(WindowManagerTools const&) = delete;73 WindowManagerTools(WindowManagerTools const&) = delete;
@@ -107,6 +110,10 @@
107 std::shared_ptr<scene::Session> const& session,110 std::shared_ptr<scene::Session> const& session,
108 std::shared_ptr<scene::Surface> const& surface) = 0;111 std::shared_ptr<scene::Surface> const& surface) = 0;
109112
113 virtual void handle_request_drag_and_drop(
114 std::shared_ptr<scene::Session> const& session,
115 std::shared_ptr<scene::Surface> const& surface) = 0;
116
110 virtual ~WindowManagementPolicy() = default;117 virtual ~WindowManagementPolicy() = default;
111 WindowManagementPolicy() = default;118 WindowManagementPolicy() = default;
112 WindowManagementPolicy(WindowManagementPolicy const&) = delete;119 WindowManagementPolicy(WindowManagementPolicy const&) = delete;
@@ -163,6 +170,11 @@
163 std::shared_ptr<scene::Surface> const& surface,170 std::shared_ptr<scene::Surface> const& surface,
164 uint64_t timestamp) override;171 uint64_t timestamp) override;
165172
173 void handle_request_drag_and_drop(
174 std::shared_ptr<scene::Session> const& session,
175 std::shared_ptr<scene::Surface> const& surface,
176 uint64_t timestamp) override;
177
166 int set_surface_attribute(178 int set_surface_attribute(
167 std::shared_ptr<scene::Session> const& /*session*/,179 std::shared_ptr<scene::Session> const& /*session*/,
168 std::shared_ptr<scene::Surface> const& surface,180 std::shared_ptr<scene::Surface> const& surface,
@@ -192,6 +204,9 @@
192204
193 void raise_tree(std::shared_ptr<scene::Surface> const& root) override;205 void raise_tree(std::shared_ptr<scene::Surface> const& root) override;
194206
207 void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override;
208 void clear_drag_and_drop_handle() override;
209
195private:210private:
196 shell::FocusController* const focus_controller;211 shell::FocusController* const focus_controller;
197 std::unique_ptr<WindowManagementPolicy> const policy;212 std::unique_ptr<WindowManagementPolicy> const policy;
198213
=== modified file 'src/include/server/mir/shell/canonical_window_manager.h'
--- src/include/server/mir/shell/canonical_window_manager.h 2017-01-18 02:29:37 +0000
+++ src/include/server/mir/shell/canonical_window_manager.h 2017-03-17 15:52:51 +0000
@@ -75,6 +75,10 @@
75 std::shared_ptr<scene::Session> const& session,75 std::shared_ptr<scene::Session> const& session,
76 std::shared_ptr<scene::Surface> const& surface) override;76 std::shared_ptr<scene::Surface> const& surface) override;
7777
78 void handle_request_drag_and_drop(
79 std::shared_ptr<scene::Session> const& session,
80 std::shared_ptr<scene::Surface> const& surface) override;
81
78private:82private:
79 static const int modifier_mask =83 static const int modifier_mask =
80 mir_input_event_modifier_alt |84 mir_input_event_modifier_alt |
8185
=== modified file 'src/protobuf/mir_protobuf.proto'
--- src/protobuf/mir_protobuf.proto 2017-03-14 04:41:33 +0000
+++ src/protobuf/mir_protobuf.proto 2017-03-17 15:52:51 +0000
@@ -444,6 +444,11 @@
444 required SurfaceId surface_id = 2;444 required SurfaceId surface_id = 2;
445}445}
446446
447message RequestAuthority {
448 required Cookie cookie = 1;
449 required SurfaceId surface_id = 2;
450}
451
447message InputDevices {452message InputDevices {
448 repeated InputDeviceInfo device_info = 1;453 repeated InputDeviceInfo device_info = 1;
449}454}
450455
=== modified file 'src/protobuf/symbols.map'
--- src/protobuf/symbols.map 2017-02-15 07:38:33 +0000
+++ src/protobuf/symbols.map 2017-03-17 15:52:51 +0000
@@ -1112,3 +1112,29 @@
1112 vtable?for?mir::protobuf::PromptSession;1112 vtable?for?mir::protobuf::PromptSession;
1113 };1113 };
1114} MIR_PROTOBUF_0.22;1114} MIR_PROTOBUF_0.22;
1115
1116MIR_PROTOBUF_0.27 {
1117 global:
1118 extern "C++" {
1119 mir::protobuf::RequestAuthority::ByteSize*;
1120 mir::protobuf::RequestAuthority::CheckTypeAndMergeFrom*;
1121 mir::protobuf::RequestAuthority::Clear*;
1122 mir::protobuf::RequestAuthority::CopyFrom*;
1123 mir::protobuf::RequestAuthority::default_instance*;
1124 mir::protobuf::RequestAuthority::DiscardUnknownFields*;
1125 mir::protobuf::RequestAuthority::GetTypeName*;
1126 mir::protobuf::RequestAuthority::IsInitialized*;
1127 mir::protobuf::RequestAuthority::kCookieFieldNumber*;
1128 mir::protobuf::RequestAuthority::kSurfaceIdFieldNumber*;
1129 mir::protobuf::RequestAuthority::MergeFrom*;
1130 mir::protobuf::RequestAuthority::MergePartialFromCodedStream*;
1131 mir::protobuf::RequestAuthority::New*;
1132 mir::protobuf::RequestAuthority::?RequestAuthority*;
1133 mir::protobuf::RequestAuthority::RequestAuthority*;
1134 mir::protobuf::RequestAuthority::SerializeWithCachedSizes*;
1135 mir::protobuf::RequestAuthority::Swap*;
1136 non-virtual?thunk?to?mir::protobuf::RequestAuthority::?RequestAuthority*;
1137 typeinfo?for?mir::protobuf::RequestAuthority;
1138 vtable?for?mir::protobuf::RequestAuthority;
1139 };
1140} MIR_PROTOBUF_0.26;
11151141
=== modified file 'src/server/frontend/protobuf_message_processor.cpp'
--- src/server/frontend/protobuf_message_processor.cpp 2017-02-15 07:38:33 +0000
+++ src/server/frontend/protobuf_message_processor.cpp 2017-03-17 15:52:51 +0000
@@ -305,6 +305,10 @@
305 {305 {
306 invoke(this, display_server.get(), &protobuf::DisplayServer::stop_prompt_session, invocation);306 invoke(this, display_server.get(), &protobuf::DisplayServer::stop_prompt_session, invocation);
307 }307 }
308 else if ("request_drag_and_drop" == invocation.method_name())
309 {
310 invoke(this, display_server.get(), &protobuf::DisplayServer::request_drag_and_drop, invocation);
311 }
308 else if ("disconnect" == invocation.method_name())312 else if ("disconnect" == invocation.method_name())
309 {313 {
310 invoke(this, display_server.get(), &DisplayServer::disconnect, invocation);314 invoke(this, display_server.get(), &DisplayServer::disconnect, invocation);
311315
=== modified file 'src/server/frontend/session_mediator.cpp'
--- src/server/frontend/session_mediator.cpp 2017-03-14 04:41:33 +0000
+++ src/server/frontend/session_mediator.cpp 2017-03-17 15:52:51 +0000
@@ -1175,6 +1175,26 @@
1175 done->Run();1175 done->Run();
1176}1176}
11771177
1178void mir::frontend::SessionMediator::request_drag_and_drop(mir::protobuf::RequestAuthority const* request,
1179 mir::protobuf::Void*, google::protobuf::Closure* done)
1180{
1181 auto const session = weak_session.lock();
1182 if (!session)
1183 BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));
1184
1185 auto const cookie = request->cookie();
1186 auto const surface_id = request->surface_id();
1187
1188 auto cookie_string = cookie.cookie();
1189
1190 std::vector<uint8_t> cookie_bytes(cookie_string.begin(), cookie_string.end());
1191 auto const cookie_ptr = cookie_authority->make_cookie(cookie_bytes);
1192
1193 shell->request_drag_and_drop(session, mf::SurfaceId{surface_id.value()}, cookie_ptr->timestamp());
1194
1195 done->Run();
1196}
1197
1178void mf::SessionMediator::apply_input_configuration(1198void mf::SessionMediator::apply_input_configuration(
1179 mir::protobuf::InputConfigurationRequest const* request,1199 mir::protobuf::InputConfigurationRequest const* request,
1180 mir::protobuf::Void*,1200 mir::protobuf::Void*,
@@ -1254,7 +1274,6 @@
1254 screencast_buffer_tracker.remove_session(id);1274 screencast_buffer_tracker.remove_session(id);
1255}1275}
12561276
1257
1258auto mf::detail::PromptSessionStore::insert(std::shared_ptr<PromptSession> const& session) -> PromptSessionId1277auto mf::detail::PromptSessionStore::insert(std::shared_ptr<PromptSession> const& session) -> PromptSessionId
1259{1278{
1260 std::lock_guard<decltype(mutex)> lock{mutex};1279 std::lock_guard<decltype(mutex)> lock{mutex};
12611280
=== modified file 'src/server/frontend/session_mediator.h'
--- src/server/frontend/session_mediator.h 2017-03-14 02:26:28 +0000
+++ src/server/frontend/session_mediator.h 2017-03-17 15:52:51 +0000
@@ -249,6 +249,10 @@
249 mir::protobuf::RaiseRequest const* request,249 mir::protobuf::RaiseRequest const* request,
250 mir::protobuf::Void*,250 mir::protobuf::Void*,
251 google::protobuf::Closure* done) override;251 google::protobuf::Closure* done) override;
252 void request_drag_and_drop(
253 mir::protobuf::RequestAuthority const* request,
254 mir::protobuf::Void*,
255 google::protobuf::Closure* done) override;
252 void apply_input_configuration(256 void apply_input_configuration(
253 mir::protobuf::InputConfigurationRequest const* request,257 mir::protobuf::InputConfigurationRequest const* request,
254 mir::protobuf::Void* response,258 mir::protobuf::Void* response,
255259
=== modified file 'src/server/frontend/shell_wrapper.cpp'
--- src/server/frontend/shell_wrapper.cpp 2017-01-18 02:29:37 +0000
+++ src/server/frontend/shell_wrapper.cpp 2017-03-17 15:52:51 +0000
@@ -106,3 +106,11 @@
106{106{
107 wrapped->raise_surface(session, surface_id, timestamp);107 wrapped->raise_surface(session, surface_id, timestamp);
108}108}
109
110void mf::ShellWrapper::request_drag_and_drop(
111 std::shared_ptr<Session> const& session,
112 SurfaceId surface_id,
113 uint64_t timestamp)
114{
115 wrapped->request_drag_and_drop(session, surface_id, timestamp);
116}
109117
=== modified file 'src/server/frontend/shell_wrapper.h'
--- src/server/frontend/shell_wrapper.h 2017-01-18 02:29:37 +0000
+++ src/server/frontend/shell_wrapper.h 2017-03-17 15:52:51 +0000
@@ -80,6 +80,11 @@
80 SurfaceId surface_id,80 SurfaceId surface_id,
81 uint64_t timestamp) override;81 uint64_t timestamp) override;
8282
83 void request_drag_and_drop(
84 std::shared_ptr<Session> const& session,
85 SurfaceId surface_id,
86 uint64_t timestamp) override;
87
83protected:88protected:
84 std::shared_ptr<Shell> const wrapped;89 std::shared_ptr<Shell> const wrapped;
85};90};
8691
=== modified file 'src/server/input/null_input_targeter.h'
--- src/server/input/null_input_targeter.h 2017-02-15 14:45:41 +0000
+++ src/server/input/null_input_targeter.h 2017-03-17 15:52:51 +0000
@@ -38,6 +38,9 @@
38 void clear_focus() override38 void clear_focus() override
39 {39 {
40 }40 }
41
42 void set_drag_and_drop_handle(std::vector<uint8_t> const&) override {}
43 void clear_drag_and_drop_handle() override {}
41};44};
4245
43}46}
4447
=== modified file 'src/server/input/surface_input_dispatcher.cpp'
--- src/server/input/surface_input_dispatcher.cpp 2017-01-18 02:29:37 +0000
+++ src/server/input/surface_input_dispatcher.cpp 2017-03-17 15:52:51 +0000
@@ -70,7 +70,10 @@
70 std::function<void(ms::Surface*)> const on_removed;70 std::function<void(ms::Surface*)> const on_removed;
71};71};
7272
73void deliver_without_relative_motion(std::shared_ptr<mi::Surface> const& surface, MirEvent const* ev)73void deliver_without_relative_motion(
74 std::shared_ptr<mi::Surface> const& surface,
75 MirEvent const* ev,
76 std::vector<uint8_t> const& drag_and_drop_handle)
74{77{
75 auto const* input_ev = mir_event_get_input_event(ev);78 auto const* input_ev = mir_event_get_input_event(ev);
76 auto const* pev = mir_input_event_get_pointer_event(input_ev);79 auto const* pev = mir_input_event_get_pointer_event(input_ev);
@@ -98,12 +101,21 @@
98 0.0f);101 0.0f);
99102
100 mev::transform_positions(*to_deliver, geom::Displacement{bounds.top_left.x.as_int(), bounds.top_left.y.as_int()});103 mev::transform_positions(*to_deliver, geom::Displacement{bounds.top_left.x.as_int(), bounds.top_left.y.as_int()});
104 if (!drag_and_drop_handle.empty())
105 mev::set_drag_and_drop_handle(*to_deliver, drag_and_drop_handle);
101 surface->consume(to_deliver.get());106 surface->consume(to_deliver.get());
102}107}
103108
104void deliver(std::shared_ptr<mi::Surface> const& surface, MirEvent const* ev)109void deliver(
110 std::shared_ptr<mi::Surface> const& surface,
111 MirEvent const* ev,
112 std::vector<uint8_t> const& drag_and_drop_handle)
105{113{
106 auto to_deliver = mev::clone_event(*ev);114 auto to_deliver = mev::clone_event(*ev);
115
116 if (!drag_and_drop_handle.empty())
117 mev::set_drag_and_drop_handle(*to_deliver, drag_and_drop_handle);
118
107 auto const& bounds = surface->input_bounds();119 auto const& bounds = surface->input_bounds();
108 mev::transform_positions(*to_deliver, geom::Displacement{bounds.top_left.x.as_int(), bounds.top_left.y.as_int()});120 mev::transform_positions(*to_deliver, geom::Displacement{bounds.top_left.x.as_int(), bounds.top_left.y.as_int()});
109 surface->consume(to_deliver.get());121 surface->consume(to_deliver.get());
@@ -243,6 +255,8 @@
243 mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x),255 mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x),
244 mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y));256 mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y));
245257
258 if (!drag_and_drop_handle.empty())
259 mev::set_drag_and_drop_handle(*event, drag_and_drop_handle);
246 surface->consume(event.get());260 surface->consume(event.get());
247}261}
248262
@@ -270,12 +284,17 @@
270284
271 if (pointer_state.gesture_owner)285 if (pointer_state.gesture_owner)
272 {286 {
273 deliver(pointer_state.gesture_owner, ev);287 deliver(pointer_state.gesture_owner, ev, drag_and_drop_handle);
274288
275 if (is_gesture_terminator(pev))289 auto const gesture_terminated = is_gesture_terminator(pev);
290
291 if (gesture_terminated)
276 {292 {
277 pointer_state.gesture_owner.reset();293 pointer_state.gesture_owner.reset();
294 }
278295
296 if (gesture_terminated || !drag_and_drop_handle.empty())
297 {
279 auto target = find_target_surface(event_x_y);298 auto target = find_target_surface(event_x_y);
280299
281 if (pointer_state.current_target != target)300 if (pointer_state.current_target != target)
@@ -286,6 +305,9 @@
286 pointer_state.current_target = target;305 pointer_state.current_target = target;
287 if (target)306 if (target)
288 send_enter_exit_event(target, pev, mir_pointer_action_enter);307 send_enter_exit_event(target, pev, mir_pointer_action_enter);
308
309 if (!gesture_terminated)
310 pointer_state.gesture_owner = target;
289 }311 }
290 }312 }
291313
@@ -323,11 +345,11 @@
323 if (sent_ev)345 if (sent_ev)
324 {346 {
325 if (action != mir_pointer_action_motion)347 if (action != mir_pointer_action_motion)
326 deliver_without_relative_motion(target, ev);348 deliver_without_relative_motion(target, ev, drag_and_drop_handle);
327 }349 }
328 else350 else
329 {351 {
330 deliver(target, ev);352 deliver(target, ev, drag_and_drop_handle);
331 }353 }
332 return true;354 return true;
333 }355 }
@@ -383,7 +405,7 @@
383405
384 if (gesture_owner)406 if (gesture_owner)
385 {407 {
386 deliver(gesture_owner, ev);408 deliver(gesture_owner, ev, drag_and_drop_handle);
387409
388 if (is_gesture_end(tev))410 if (is_gesture_end(tev))
389 gesture_owner.reset();411 gesture_owner.reset();
@@ -450,3 +472,15 @@
450 set_focus_locked(lg, nullptr);472 set_focus_locked(lg, nullptr);
451}473}
452474
475void mir::input::SurfaceInputDispatcher::set_drag_and_drop_handle(std::vector<uint8_t> const& handle)
476{
477 std::lock_guard<std::mutex> lg(dispatcher_mutex);
478 drag_and_drop_handle = handle;
479}
480
481void mir::input::SurfaceInputDispatcher::clear_drag_and_drop_handle()
482{
483 std::lock_guard<std::mutex> lg(dispatcher_mutex);
484 drag_and_drop_handle.clear();
485}
486
453487
=== modified file 'src/server/input/surface_input_dispatcher.h'
--- src/server/input/surface_input_dispatcher.h 2016-10-05 13:18:38 +0000
+++ src/server/input/surface_input_dispatcher.h 2017-03-17 15:52:51 +0000
@@ -54,7 +54,10 @@
54 // InputTargeter54 // InputTargeter
55 void set_focus(std::shared_ptr<input::Surface> const& target) override;55 void set_focus(std::shared_ptr<input::Surface> const& target) override;
56 void clear_focus() override;56 void clear_focus() override;
57 57
58 void set_drag_and_drop_handle(std::vector<uint8_t> const& handle) override;
59 void clear_drag_and_drop_handle() override;
60
58private:61private:
59 void device_reset(MirInputDeviceId reset_device_id, std::chrono::nanoseconds when);62 void device_reset(MirInputDeviceId reset_device_id, std::chrono::nanoseconds when);
60 bool dispatch_key(MirEvent const* kev);63 bool dispatch_key(MirEvent const* kev);
@@ -92,6 +95,7 @@
9295
93 std::mutex dispatcher_mutex;96 std::mutex dispatcher_mutex;
94 std::weak_ptr<input::Surface> focus_surface;97 std::weak_ptr<input::Surface> focus_surface;
98 std::vector<uint8_t> drag_and_drop_handle;
95 bool started;99 bool started;
96};100};
97101
98102
=== modified file 'src/server/scene/basic_surface.cpp'
--- src/server/scene/basic_surface.cpp 2017-02-15 14:45:41 +0000
+++ src/server/scene/basic_surface.cpp 2017-03-17 15:52:51 +0000
@@ -144,6 +144,12 @@
144 { observer->input_consumed(event); });144 { observer->input_consumed(event); });
145}145}
146146
147void ms::SurfaceObservers::start_drag_and_drop(std::vector<uint8_t> const& handle)
148{
149 for_each([&](std::shared_ptr<SurfaceObserver> const& observer)
150 { observer->start_drag_and_drop(handle); });
151}
152
147153
148struct ms::CursorStreamImageAdapter154struct ms::CursorStreamImageAdapter
149{155{
@@ -923,3 +929,8 @@
923{929{
924 observers.placed_relative(placement);930 observers.placed_relative(placement);
925}931}
932
933void mir::scene::BasicSurface::start_drag_and_drop(std::vector<uint8_t> const& handle)
934{
935 observers.start_drag_and_drop(handle);
936}
926937
=== modified file 'src/server/scene/basic_surface.h'
--- src/server/scene/basic_surface.h 2017-02-15 14:45:41 +0000
+++ src/server/scene/basic_surface.h 2017-03-17 15:52:51 +0000
@@ -139,6 +139,7 @@
139 void set_confine_pointer_state(MirPointerConfinementState state) override;139 void set_confine_pointer_state(MirPointerConfinementState state) override;
140 MirPointerConfinementState confine_pointer_state() const override;140 MirPointerConfinementState confine_pointer_state() const override;
141 void placed_relative(geometry::Rectangle const& placement) override;141 void placed_relative(geometry::Rectangle const& placement) override;
142 void start_drag_and_drop(std::vector<uint8_t> const& handle) override;
142143
143private:144private:
144 bool visible(std::unique_lock<std::mutex>&) const;145 bool visible(std::unique_lock<std::mutex>&) const;
145146
=== modified file 'src/server/scene/legacy_surface_change_notification.cpp'
--- src/server/scene/legacy_surface_change_notification.cpp 2017-02-15 13:36:35 +0000
+++ src/server/scene/legacy_surface_change_notification.cpp 2017-03-17 15:52:51 +0000
@@ -108,3 +108,7 @@
108void ms::LegacySurfaceChangeNotification::input_consumed(MirEvent const*)108void ms::LegacySurfaceChangeNotification::input_consumed(MirEvent const*)
109{109{
110}110}
111
112void ms::LegacySurfaceChangeNotification::start_drag_and_drop(std::vector<uint8_t> const& /*handle*/)
113{
114}
111\ No newline at end of file115\ No newline at end of file
112116
=== modified file 'src/server/scene/legacy_surface_change_notification.h'
--- src/server/scene/legacy_surface_change_notification.h 2017-02-15 13:36:35 +0000
+++ src/server/scene/legacy_surface_change_notification.h 2017-03-17 15:52:51 +0000
@@ -51,6 +51,7 @@
51 void cursor_image_removed() override;51 void cursor_image_removed() override;
52 void placed_relative(geometry::Rectangle const& placement) override;52 void placed_relative(geometry::Rectangle const& placement) override;
53 void input_consumed(MirEvent const* event) override;53 void input_consumed(MirEvent const* event) override;
54 void start_drag_and_drop(std::vector<uint8_t> const& handle) override;
5455
55private:56private:
56 std::function<void()> const notify_scene_change;57 std::function<void()> const notify_scene_change;
5758
=== modified file 'src/server/scene/null_surface_observer.cpp'
--- src/server/scene/null_surface_observer.cpp 2017-02-15 13:36:35 +0000
+++ src/server/scene/null_surface_observer.cpp 2017-03-17 15:52:51 +0000
@@ -41,3 +41,4 @@
41void ms::NullSurfaceObserver::cursor_image_removed() {}41void ms::NullSurfaceObserver::cursor_image_removed() {}
42void ms::NullSurfaceObserver::placed_relative(geometry::Rectangle const& /*placement*/) {}42void ms::NullSurfaceObserver::placed_relative(geometry::Rectangle const& /*placement*/) {}
43void ms::NullSurfaceObserver::input_consumed(MirEvent const* /*event*/) {}43void ms::NullSurfaceObserver::input_consumed(MirEvent const* /*event*/) {}
44void ms::NullSurfaceObserver::start_drag_and_drop(std::vector<uint8_t> const& /*handle*/) {}
4445
=== modified file 'src/server/scene/surface_event_source.cpp'
--- src/server/scene/surface_event_source.cpp 2017-02-15 13:36:35 +0000
+++ src/server/scene/surface_event_source.cpp 2017-03-17 15:52:51 +0000
@@ -101,3 +101,8 @@
101 mev::set_window_id(*ev, id.as_value());101 mev::set_window_id(*ev, id.as_value());
102 event_sink->handle_event(*ev);102 event_sink->handle_event(*ev);
103}103}
104
105void ms::SurfaceEventSource::start_drag_and_drop(std::vector<uint8_t> const& handle)
106{
107 event_sink->handle_event(*mev::make_start_drag_and_drop_event(id, handle));
108}
104109
=== modified file 'src/server/shell/abstract_shell.cpp'
--- src/server/shell/abstract_shell.cpp 2017-03-10 19:47:57 +0000
+++ src/server/shell/abstract_shell.cpp 2017-03-17 15:52:51 +0000
@@ -251,6 +251,14 @@
251 window_manager->handle_raise_surface(session, surface, timestamp);251 window_manager->handle_raise_surface(session, surface, timestamp);
252}252}
253253
254void msh::AbstractShell::request_drag_and_drop(
255 std::shared_ptr<scene::Session> const& session,
256 std::shared_ptr<scene::Surface> const& surface,
257 uint64_t timestamp)
258{
259 window_manager->handle_request_drag_and_drop(session, surface, timestamp);
260}
261
254void msh::AbstractShell::focus_next_session()262void msh::AbstractShell::focus_next_session()
255{263{
256 std::unique_lock<std::mutex> lock(focus_mutex);264 std::unique_lock<std::mutex> lock(focus_mutex);
@@ -401,3 +409,12 @@
401 report->surfaces_raised(surfaces);409 report->surfaces_raised(surfaces);
402}410}
403411
412void msh::AbstractShell::set_drag_and_drop_handle(std::vector<uint8_t> const& handle)
413{
414 input_targeter->set_drag_and_drop_handle(handle);
415}
416
417void msh::AbstractShell::clear_drag_and_drop_handle()
418{
419 input_targeter->clear_drag_and_drop_handle();
420}
404421
=== modified file 'src/server/shell/basic_window_manager.cpp'
--- src/server/shell/basic_window_manager.cpp 2017-01-18 02:29:37 +0000
+++ src/server/shell/basic_window_manager.cpp 2017-03-17 15:52:51 +0000
@@ -135,6 +135,16 @@
135 policy->handle_raise_surface(session, surface);135 policy->handle_raise_surface(session, surface);
136}136}
137137
138void msh::BasicWindowManager::handle_request_drag_and_drop(
139 std::shared_ptr<scene::Session> const& session,
140 std::shared_ptr<scene::Surface> const& surface,
141 uint64_t timestamp)
142{
143 std::lock_guard<decltype(mutex)> lock(mutex);
144 if (timestamp >= last_input_event_timestamp)
145 policy->handle_request_drag_and_drop(session, surface);
146}
147
138int msh::BasicWindowManager::set_surface_attribute(148int msh::BasicWindowManager::set_surface_attribute(
139 std::shared_ptr<scene::Session> const& /*session*/,149 std::shared_ptr<scene::Session> const& /*session*/,
140 std::shared_ptr<scene::Surface> const& surface,150 std::shared_ptr<scene::Surface> const& surface,
@@ -309,3 +319,14 @@
309 }319 }
310 }320 }
311}321}
322
323void mir::shell::BasicWindowManager::set_drag_and_drop_handle(std::vector<uint8_t> const& handle)
324{
325 focus_controller->set_drag_and_drop_handle(handle);
326}
327
328void mir::shell::BasicWindowManager::clear_drag_and_drop_handle()
329{
330 focus_controller->clear_drag_and_drop_handle();
331}
332
312333
=== modified file 'src/server/shell/canonical_window_manager.cpp'
--- src/server/shell/canonical_window_manager.cpp 2017-03-10 19:47:57 +0000
+++ src/server/shell/canonical_window_manager.cpp 2017-03-17 15:52:51 +0000
@@ -24,6 +24,7 @@
24#include "mir/shell/surface_ready_observer.h"24#include "mir/shell/surface_ready_observer.h"
25#include "mir/shell/display_layout.h"25#include "mir/shell/display_layout.h"
2626
27#include <uuid/uuid.h>
27#include <linux/input.h>28#include <linux/input.h>
28#include <csignal>29#include <csignal>
2930
@@ -583,6 +584,18 @@
583 select_active_surface(surface);584 select_active_surface(surface);
584}585}
585586
587void msh::CanonicalWindowManagerPolicy::handle_request_drag_and_drop(
588 std::shared_ptr<ms::Session> const& /*session*/,
589 std::shared_ptr<ms::Surface> const& surface)
590{
591 uuid_t uuid;
592 uuid_generate(uuid);
593 std::vector<uint8_t> const handle{std::begin(uuid), std::end(uuid)};
594
595 surface->start_drag_and_drop(handle);
596 tools->set_drag_and_drop_handle(handle);
597}
598
586bool msh::CanonicalWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event)599bool msh::CanonicalWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event)
587{600{
588 auto const action = mir_keyboard_event_action(event);601 auto const action = mir_keyboard_event_action(event);
589602
=== modified file 'src/server/shell/frontend_shell.cpp'
--- src/server/shell/frontend_shell.cpp 2017-01-18 02:29:37 +0000
+++ src/server/shell/frontend_shell.cpp 2017-03-17 15:52:51 +0000
@@ -157,3 +157,13 @@
157 auto const surface = scene_session->surface(surface_id);157 auto const surface = scene_session->surface(surface_id);
158 wrapped->raise_surface(scene_session, surface, timestamp);158 wrapped->raise_surface(scene_session, surface, timestamp);
159}159}
160
161void msh::FrontendShell::request_drag_and_drop(
162 std::shared_ptr<mf::Session> const& session,
163 mf::SurfaceId surface_id,
164 uint64_t timestamp)
165{
166 auto const scene_session = std::dynamic_pointer_cast<ms::Session>(session);
167 auto const surface = scene_session->surface(surface_id);
168 wrapped->request_drag_and_drop(scene_session, surface, timestamp);
169}
160170
=== modified file 'src/server/shell/frontend_shell.h'
--- src/server/shell/frontend_shell.h 2017-01-18 02:29:37 +0000
+++ src/server/shell/frontend_shell.h 2017-03-17 15:52:51 +0000
@@ -91,6 +91,11 @@
91 std::shared_ptr<mf::Session> const& session,91 std::shared_ptr<mf::Session> const& session,
92 mf::SurfaceId surface_id,92 mf::SurfaceId surface_id,
93 uint64_t timestamp) override;93 uint64_t timestamp) override;
94
95 void request_drag_and_drop(
96 std::shared_ptr<mf::Session> const& session,
97 mf::SurfaceId surface_id,
98 uint64_t timestamp) override;
94};99};
95}100}
96}101}
97102
=== modified file 'src/server/shell/shell_wrapper.cpp'
--- src/server/shell/shell_wrapper.cpp 2017-01-18 02:29:37 +0000
+++ src/server/shell/shell_wrapper.cpp 2017-03-17 15:52:51 +0000
@@ -120,6 +120,14 @@
120 wrapped->raise_surface(session, surface, timestamp);120 wrapped->raise_surface(session, surface, timestamp);
121}121}
122122
123void msh::ShellWrapper::request_drag_and_drop(
124 std::shared_ptr<ms::Session> const& session,
125 std::shared_ptr<ms::Surface> const& surface,
126 uint64_t timestamp)
127{
128 wrapped->request_drag_and_drop(session, surface, timestamp);
129}
130
123void msh::ShellWrapper::add_display(geometry::Rectangle const& area)131void msh::ShellWrapper::add_display(geometry::Rectangle const& area)
124{132{
125 wrapped->add_display(area);133 wrapped->add_display(area);
@@ -149,3 +157,13 @@
149{157{
150 return wrapped->raise(surfaces);158 return wrapped->raise(surfaces);
151}159}
160
161void msh::ShellWrapper::set_drag_and_drop_handle(std::vector<uint8_t> const& handle)
162{
163 wrapped->set_drag_and_drop_handle(handle);
164}
165
166void msh::ShellWrapper::clear_drag_and_drop_handle()
167{
168 wrapped->clear_drag_and_drop_handle();
169}
152170
=== modified file 'src/server/shell/system_compositor_window_manager.cpp'
--- src/server/shell/system_compositor_window_manager.cpp 2017-01-18 02:29:37 +0000
+++ src/server/shell/system_compositor_window_manager.cpp 2017-03-17 15:52:51 +0000
@@ -201,3 +201,10 @@
201 uint64_t /*timestamp*/)201 uint64_t /*timestamp*/)
202{202{
203}203}
204
205void msh::SystemCompositorWindowManager::handle_request_drag_and_drop(
206 std::shared_ptr<ms::Session> const& /*session*/,
207 std::shared_ptr<ms::Surface> const& /*surface*/,
208 uint64_t /*timestamp*/)
209{
210}
204211
=== modified file 'src/server/symbols.map'
--- src/server/symbols.map 2017-03-15 10:38:02 +0000
+++ src/server/symbols.map 2017-03-17 15:52:51 +0000
@@ -129,6 +129,7 @@
129 mir::scene::NullSurfaceObserver::reception_mode_set_to*;129 mir::scene::NullSurfaceObserver::reception_mode_set_to*;
130 mir::scene::NullSurfaceObserver::renamed*;130 mir::scene::NullSurfaceObserver::renamed*;
131 mir::scene::NullSurfaceObserver::resized_to*;131 mir::scene::NullSurfaceObserver::resized_to*;
132 mir::scene::NullSurfaceObserver::start_drag_and_drop*;
132 mir::scene::NullSurfaceObserver::transformation_set_to*;133 mir::scene::NullSurfaceObserver::transformation_set_to*;
133 mir::scene::Observer::?Observer*;134 mir::scene::Observer::?Observer*;
134 mir::scene::Observer::Observer*;135 mir::scene::Observer::Observer*;
@@ -293,6 +294,7 @@
293 mir::shell::ShellReport::ShellReport*;294 mir::shell::ShellReport::ShellReport*;
294 mir::shell::ShellWrapper::add_display*;295 mir::shell::ShellWrapper::add_display*;
295 mir::shell::ShellWrapper::add_prompt_provider_for*;296 mir::shell::ShellWrapper::add_prompt_provider_for*;
297 mir::shell::ShellWrapper::clear_drag_and_drop_handle*;
296 mir::shell::ShellWrapper::close_session*;298 mir::shell::ShellWrapper::close_session*;
297 mir::shell::ShellWrapper::create_surface*;299 mir::shell::ShellWrapper::create_surface*;
298 mir::shell::ShellWrapper::destroy_surface*;300 mir::shell::ShellWrapper::destroy_surface*;
@@ -306,9 +308,11 @@
306 mir::shell::ShellWrapper::raise*;308 mir::shell::ShellWrapper::raise*;
307 mir::shell::ShellWrapper::raise_surface*;309 mir::shell::ShellWrapper::raise_surface*;
308 mir::shell::ShellWrapper::remove_display*;310 mir::shell::ShellWrapper::remove_display*;
311 mir::shell::ShellWrapper::request_drag_and_drop*;
309 mir::shell::ShellWrapper::set_focus_to*;312 mir::shell::ShellWrapper::set_focus_to*;
310 mir::shell::ShellWrapper::set_surface_attribute*;313 mir::shell::ShellWrapper::set_surface_attribute*;
311 mir::shell::ShellWrapper::ShellWrapper*;314 mir::shell::ShellWrapper::ShellWrapper*;
315 mir::shell::ShellWrapper::set_drag_and_drop_handle*;
312 mir::shell::ShellWrapper::start_prompt_session_for*;316 mir::shell::ShellWrapper::start_prompt_session_for*;
313 mir::shell::ShellWrapper::stop_prompt_session*;317 mir::shell::ShellWrapper::stop_prompt_session*;
314 mir::shell::ShellWrapper::surface_at*;318 mir::shell::ShellWrapper::surface_at*;
@@ -338,6 +342,7 @@
338 mir::shell::SystemCompositorWindowManager::remove_display*;342 mir::shell::SystemCompositorWindowManager::remove_display*;
339 mir::shell::SystemCompositorWindowManager::remove_session*;343 mir::shell::SystemCompositorWindowManager::remove_session*;
340 mir::shell::SystemCompositorWindowManager::remove_surface*;344 mir::shell::SystemCompositorWindowManager::remove_surface*;
345 mir::shell::SystemCompositorWindowManager::handle_request_drag_and_drop*;
341 mir::shell::SystemCompositorWindowManager::set_surface_attribute*;346 mir::shell::SystemCompositorWindowManager::set_surface_attribute*;
342 mir::shell::SystemCompositorWindowManager::SystemCompositorWindowManager*;347 mir::shell::SystemCompositorWindowManager::SystemCompositorWindowManager*;
343 mir::shell::WindowManager::operator*;348 mir::shell::WindowManager::operator*;
@@ -695,6 +700,7 @@
695 mir::shell::CanonicalWindowManagerPolicy::handle_touch_event*;700 mir::shell::CanonicalWindowManagerPolicy::handle_touch_event*;
696 mir::shell::CanonicalWindowManagerPolicy::handle_pointer_event*;701 mir::shell::CanonicalWindowManagerPolicy::handle_pointer_event*;
697 mir::shell::CanonicalWindowManagerPolicy::handle_raise_surface*;702 mir::shell::CanonicalWindowManagerPolicy::handle_raise_surface*;
703 mir::shell::CanonicalWindowManagerPolicy::handle_request_drag_and_drop*;
698 typeinfo?for?mir::shell::CanonicalWindowManagerPolicy;704 typeinfo?for?mir::shell::CanonicalWindowManagerPolicy;
699 vtable?for?mir::shell::CanonicalWindowManagerPolicy;705 vtable?for?mir::shell::CanonicalWindowManagerPolicy;
700 VTT?for?mir::shell::CanonicalWindowManagerPolicy;706 VTT?for?mir::shell::CanonicalWindowManagerPolicy;
@@ -831,6 +837,7 @@
831 mir::shell::BasicWindowManager::add_session*;837 mir::shell::BasicWindowManager::add_session*;
832 mir::shell::BasicWindowManager::add_surface*;838 mir::shell::BasicWindowManager::add_surface*;
833 mir::shell::BasicWindowManager::BasicWindowManager*;839 mir::shell::BasicWindowManager::BasicWindowManager*;
840 mir::shell::BasicWindowManager::clear_drag_and_drop_handle*;
834 mir::shell::BasicWindowManager::find_session*;841 mir::shell::BasicWindowManager::find_session*;
835 mir::shell::BasicWindowManager::focused_session*;842 mir::shell::BasicWindowManager::focused_session*;
836 mir::shell::BasicWindowManager::focused_surface*;843 mir::shell::BasicWindowManager::focused_surface*;
@@ -839,6 +846,7 @@
839 mir::shell::BasicWindowManager::handle_keyboard_event*;846 mir::shell::BasicWindowManager::handle_keyboard_event*;
840 mir::shell::BasicWindowManager::handle_pointer_event*;847 mir::shell::BasicWindowManager::handle_pointer_event*;
841 mir::shell::BasicWindowManager::handle_raise_surface*;848 mir::shell::BasicWindowManager::handle_raise_surface*;
849 mir::shell::BasicWindowManager::handle_request_drag_and_drop*;
842 mir::shell::BasicWindowManager::handle_touch_event*;850 mir::shell::BasicWindowManager::handle_touch_event*;
843 mir::shell::BasicWindowManager::info_for*;851 mir::shell::BasicWindowManager::info_for*;
844 mir::shell::BasicWindowManager::modify_surface*;852 mir::shell::BasicWindowManager::modify_surface*;
@@ -846,6 +854,7 @@
846 mir::shell::BasicWindowManager::remove_display*;854 mir::shell::BasicWindowManager::remove_display*;
847 mir::shell::BasicWindowManager::remove_session*;855 mir::shell::BasicWindowManager::remove_session*;
848 mir::shell::BasicWindowManager::remove_surface*;856 mir::shell::BasicWindowManager::remove_surface*;
857 mir::shell::BasicWindowManager::set_drag_and_drop_handle*;
849 mir::shell::BasicWindowManager::set_focus_to*;858 mir::shell::BasicWindowManager::set_focus_to*;
850 mir::shell::BasicWindowManager::set_surface_attribute*;859 mir::shell::BasicWindowManager::set_surface_attribute*;
851 mir::shell::BasicWindowManager::surface_at*;860 mir::shell::BasicWindowManager::surface_at*;
@@ -856,6 +865,7 @@
856 virtual?thunk?to?mir::shell::BasicWindowManager::handle_keyboard_event*;865 virtual?thunk?to?mir::shell::BasicWindowManager::handle_keyboard_event*;
857 virtual?thunk?to?mir::shell::BasicWindowManager::handle_pointer_event*;866 virtual?thunk?to?mir::shell::BasicWindowManager::handle_pointer_event*;
858 virtual?thunk?to?mir::shell::BasicWindowManager::handle_raise_surface*;867 virtual?thunk?to?mir::shell::BasicWindowManager::handle_raise_surface*;
868 virtual?thunk?to?mir::shell::BasicWindowManager::handle_request_drag_and_drop*;
859 virtual?thunk?to?mir::shell::BasicWindowManager::handle_touch_event*;869 virtual?thunk?to?mir::shell::BasicWindowManager::handle_touch_event*;
860 virtual?thunk?to?mir::shell::BasicWindowManager::modify_surface*;870 virtual?thunk?to?mir::shell::BasicWindowManager::modify_surface*;
861 virtual?thunk?to?mir::shell::BasicWindowManager::remove_display*;871 virtual?thunk?to?mir::shell::BasicWindowManager::remove_display*;
862872
=== modified file 'tests/acceptance-tests/CMakeLists.txt'
--- tests/acceptance-tests/CMakeLists.txt 2017-03-10 19:47:57 +0000
+++ tests/acceptance-tests/CMakeLists.txt 2017-03-17 15:52:51 +0000
@@ -3,6 +3,8 @@
3set(3set(
4 SOURCES4 SOURCES
55
6 drag_and_drop.cpp
7
6 # Catch double-free bugs by wrapping close() and abort()ing on EBADF8 # Catch double-free bugs by wrapping close() and abort()ing on EBADF
7 strict_close.cpp9 strict_close.cpp
810
911
=== added file 'tests/acceptance-tests/drag_and_drop.cpp'
--- tests/acceptance-tests/drag_and_drop.cpp 1970-01-01 00:00:00 +0000
+++ tests/acceptance-tests/drag_and_drop.cpp 2017-03-17 15:52:51 +0000
@@ -0,0 +1,624 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#include <mir_toolkit/extensions/drag_and_drop.h>
20#include <mir_toolkit/mir_blob.h>
21
22#include <mir/geometry/displacement.h>
23#include <mir/input/input_device_info.h>
24#include <mir/input/device_capability.h>
25#include <mir/shell/shell.h>
26
27#include <mir_test_framework/connected_client_with_a_window.h>
28#include <mir_test_framework/fake_input_device.h>
29#include <mir_test_framework/stub_server_platform_factory.h>
30#include <mir/test/event_factory.h>
31#include <mir/test/signal.h>
32
33#include <gmock/gmock.h>
34#include <gtest/gtest.h>
35
36#include <linux/input.h>
37
38#include <boost/throw_exception.hpp>
39#include <atomic>
40
41using namespace std::chrono_literals;
42using namespace mir::geometry;
43using namespace testing;
44using mir::test::Signal;
45
46namespace
47{
48class Cookie
49{
50public:
51 Cookie() = default;
52 explicit Cookie(MirCookie const* cookie) : self{cookie, deleter} {}
53
54 operator MirCookie const*() const { return self.get(); }
55 auto get() const -> MirCookie const* { return self.get(); }
56
57 void reset() { self.reset(); }
58 void reset(MirCookie const* cookie) { self.reset(cookie, deleter); }
59
60private:
61 static void deleter(MirCookie const* cookie) { mir_cookie_release(cookie); }
62 std::shared_ptr<MirCookie const> self;
63};
64
65void mir_cookie_release(Cookie const&) = delete;
66
67class Blob
68{
69public:
70 Blob() = default;
71 explicit Blob(MirBlob* blob) : self{blob, deleter} {}
72
73 operator MirBlob*() const { return self.get(); }
74 auto get() const -> MirBlob* { return self.get(); }
75
76 void reset() { self.reset(); }
77 void reset(MirBlob* blob) { self.reset(blob, deleter); }
78
79private:
80 static void deleter(MirBlob* blob) { mir_blob_release(blob); }
81 std::shared_ptr<MirBlob> self;
82};
83
84void mir_blob_release(Blob const&) = delete;
85
86struct MouseMoverAndFaker
87{
88 void start_dragging_mouse()
89 {
90 using namespace mir::input::synthesis;
91 fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT));
92 }
93
94 void move_mouse(Displacement const& displacement)
95 {
96 using mir::input::synthesis::a_pointer_event;
97 fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int()));
98 }
99
100 void release_mouse()
101 {
102 using namespace mir::input::synthesis;
103 fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT));
104 }
105
106private:
107 std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{
108 mir_test_framework::add_fake_input_device(
109 mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer})};
110};
111
112Rectangle const screen_geometry{{0,0}, {800,600}};
113auto const receive_event_timeout = 90s;
114
115struct DragAndDrop : mir_test_framework::ConnectedClientWithAWindow,
116 MouseMoverAndFaker
117{
118 MirDragAndDropV1 const* dnd = nullptr;
119
120 void SetUp() override
121 {
122 initial_display_layout({screen_geometry});
123 mir_test_framework::ConnectedClientWithAWindow::SetUp();
124 dnd = mir_drag_and_drop_v1(connection);
125 mir_window_set_event_handler(window, &window_event_handler, this);
126 if (dnd) dnd->set_start_drag_and_drop_callback(window, &window_dnd_start_handler, this);
127
128 create_target_window();
129
130 paint_window(window);
131
132 center_mouse();
133 }
134
135 void TearDown() override
136 {
137 reset_window_event_handler(target_window);
138 reset_window_event_handler(window);
139 mir_window_release_sync(target_window);
140 mir_connection_release(another_connection);
141 mir_test_framework::ConnectedClientWithAWindow::TearDown();
142 }
143
144 auto user_initiates_drag() -> Cookie;
145 auto client_requests_drag(Cookie const& cookie) -> Blob;
146 auto handle_from_mouse_move() -> Blob;
147 auto handle_from_mouse_leave() -> Blob;
148 auto handle_from_mouse_enter() -> Blob;
149 auto handle_from_mouse_release() -> Blob;
150 auto count_of_handles_when_moving_mouse() -> int;
151
152private:
153 void center_mouse();
154 void paint_window(MirWindow* w);
155 void set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler);
156 void set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler);
157 void reset_window_event_handler(MirWindow* window);
158
159 void create_target_window()
160 {
161 another_connection = mir_connect_sync(new_connection().c_str(), "another_connection");
162 auto const spec = mir_create_normal_window_spec(
163 connection, screen_geometry.size.width.as_int(), screen_geometry.size.height.as_int());
164 mir_window_spec_set_pixel_format(spec, mir_pixel_format_abgr_8888);
165 mir_window_spec_set_name(spec, "target_window");
166 mir_window_spec_set_buffer_usage(spec, mir_buffer_usage_hardware);
167 mir_window_spec_set_event_handler(spec, &window_event_handler, this);
168
169 target_window = mir_create_window_sync(spec);
170 mir_window_spec_release(spec);
171
172 paint_window(target_window);
173 }
174
175 void invoke_window_event_handler(MirWindow* window, MirEvent const* event)
176 {
177 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
178 if (window == this->window) window_event_handler_(event);
179 if (window == target_window) target_window_event_handler_(event);
180 }
181
182 void invoke_window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event)
183 {
184 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
185 if (window == this->window) window_dnd_start_(event);
186 }
187
188 std::mutex window_event_handler_mutex;
189 std::function<void(MirDragAndDropEvent const* event)> window_dnd_start_ = [](MirDragAndDropEvent const*) {};
190 std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {};
191 std::function<void(MirEvent const* event)> target_window_event_handler_ = [](MirEvent const*) {};
192
193 static void window_event_handler(MirWindow* window, MirEvent const* event, void* context);
194 static void window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context);
195
196 MirConnection* another_connection{nullptr};
197 MirWindow* target_window{nullptr};
198};
199
200void DragAndDrop::set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler)
201{
202 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
203 if (window == this->window) window_event_handler_ = handler;
204 if (window == target_window) target_window_event_handler_ = handler;
205}
206
207void DragAndDrop::set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler)
208{
209 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
210 if (window == this->window) window_dnd_start_ = handler;
211}
212
213
214void DragAndDrop::reset_window_event_handler(MirWindow* window)
215{
216 if (window == this->window) window_event_handler_ = [](MirEvent const*) {};
217 if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {};
218}
219
220void DragAndDrop::paint_window(MirWindow* w)
221{
222 Signal have_focus;
223
224 set_window_event_handler(w, [&](MirEvent const* event)
225 {
226 if (mir_event_get_type(event) != mir_event_type_window)
227 return;
228
229 auto const window_event = mir_event_get_window_event(event);
230 if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus)
231 return;
232
233 if (mir_window_event_get_attribute_value(window_event))
234 have_focus.raise();
235 });
236
237 mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(w));
238
239 EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true));
240
241 reset_window_event_handler(w);
242}
243
244void DragAndDrop::center_mouse()
245{
246 Signal have_mouseover;
247
248 set_window_event_handler(window, [&](MirEvent const* event)
249 {
250 if (mir_event_get_type(event) != mir_event_type_input)
251 return;
252
253 auto const input_event = mir_event_get_input_event(event);
254
255 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
256 return;
257
258 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
259
260 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter)
261 return;
262
263 have_mouseover.raise();
264 });
265
266 move_mouse(0.5 * as_displacement(screen_geometry.size));
267
268// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20).
269// But it isn't essential for the test and we've probably waited long enough
270// for the mouse-down needed by the test to reach the window.
271// EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true));
272 have_mouseover.wait_for(receive_event_timeout);
273
274 reset_window_event_handler(window);
275}
276
277void DragAndDrop::window_event_handler(MirWindow* window, MirEvent const* event, void* context)
278{
279 static_cast<DragAndDrop*>(context)->invoke_window_event_handler(window, event);
280}
281
282void DragAndDrop::window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context)
283{
284 static_cast<DragAndDrop*>(context)->invoke_window_dnd_start_handler(window, event);
285}
286
287
288auto DragAndDrop::user_initiates_drag() -> Cookie
289{
290 Cookie cookie;
291 Signal have_cookie;
292
293 set_window_event_handler(window, [&](MirEvent const* event)
294 {
295 if (mir_event_get_type(event) != mir_event_type_input)
296 return;
297
298 auto const input_event = mir_event_get_input_event(event);
299
300 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
301 return;
302
303 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
304
305 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down)
306 return;
307
308 cookie = Cookie{mir_input_event_get_cookie(input_event)};
309 have_cookie.raise();
310 });
311
312 start_dragging_mouse();
313
314 EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true));
315
316 reset_window_event_handler(window);
317 return cookie;
318}
319
320auto DragAndDrop::client_requests_drag(Cookie const& cookie) -> Blob
321{
322 Blob blob;
323 Signal initiated;
324
325 set_window_dnd_start_handler(window, [&](MirDragAndDropEvent const* event)
326 {
327 if (dnd)
328 blob.reset(dnd->start_drag_and_drop(event));
329
330 if (blob)
331 initiated.raise();
332 });
333
334 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
335
336 if (dnd)
337 dnd->request_drag_and_drop(window, cookie);
338
339 EXPECT_TRUE(initiated.wait_for(receive_event_timeout));
340
341 reset_window_event_handler(window);
342 return blob;
343}
344
345auto DragAndDrop::handle_from_mouse_move() -> Blob
346{
347 Blob blob;
348 Signal have_blob;
349
350 set_window_event_handler(window, [&](MirEvent const* event)
351 {
352 if (mir_event_get_type(event) != mir_event_type_input)
353 return;
354
355 auto const input_event = mir_event_get_input_event(event);
356
357 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
358 return;
359
360 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
361
362 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
363
364 if (dnd)
365 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
366
367 if (blob)
368 have_blob.raise();
369 });
370
371 move_mouse({1,1});
372
373 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
374
375 reset_window_event_handler(window);
376 return blob;
377}
378
379auto DragAndDrop::handle_from_mouse_leave() -> Blob
380{
381 Blob blob;
382 Signal have_blob;
383
384 set_window_event_handler(window, [&](MirEvent const* event)
385 {
386 if (mir_event_get_type(event) != mir_event_type_input)
387 return;
388
389 auto const input_event = mir_event_get_input_event(event);
390
391 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
392 return;
393
394 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
395
396 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_leave)
397 return;
398
399 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
400
401 if (dnd)
402 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
403
404 if (blob)
405 have_blob.raise();
406 });
407
408 move_mouse({1,1});
409 move_mouse(0.5 * as_displacement(surface_size));
410
411 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
412
413 reset_window_event_handler(window);
414 return blob;
415}
416
417auto DragAndDrop::handle_from_mouse_enter() -> Blob
418{
419 Blob blob;
420 Signal have_blob;
421
422 set_window_event_handler(target_window, [&](MirEvent const* event)
423 {
424 if (mir_event_get_type(event) != mir_event_type_input)
425 return;
426
427 auto const input_event = mir_event_get_input_event(event);
428
429 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
430 return;
431
432 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
433
434 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter)
435 return;
436
437 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
438
439 if (dnd)
440 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
441
442 if (blob)
443 have_blob.raise();
444 });
445
446 move_mouse({1,1});
447 move_mouse(0.5 * as_displacement(surface_size));
448
449 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
450
451 reset_window_event_handler(target_window);
452 return blob;
453}
454
455auto DragAndDrop::handle_from_mouse_release() -> Blob
456{
457 Blob blob;
458 Signal have_blob;
459
460 set_window_event_handler(target_window, [&](MirEvent const* event)
461 {
462 if (mir_event_get_type(event) != mir_event_type_input)
463 return;
464
465 auto const input_event = mir_event_get_input_event(event);
466
467 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
468 return;
469
470 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
471
472 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_up)
473 return;
474
475 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
476
477 if (dnd)
478 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
479
480 if (blob)
481 have_blob.raise();
482 });
483
484 move_mouse({1,1});
485 move_mouse(0.5 * as_displacement(surface_size));
486 release_mouse();
487
488 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
489
490 reset_window_event_handler(target_window);
491 return blob;
492}
493
494auto DragAndDrop::count_of_handles_when_moving_mouse() -> int
495{
496 Signal have_3_events;
497 std::atomic<int> events{0};
498 std::atomic<int> handles{0};
499
500 auto counter = [&](MirEvent const* event)
501 {
502 if (mir_event_get_type(event) != mir_event_type_input)
503 return;
504
505 auto const input_event = mir_event_get_input_event(event);
506
507 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
508 return;
509
510 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
511
512 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
513
514 Blob blob;
515 if (dnd)
516 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
517
518 if (blob)
519 handles.fetch_add(1);
520
521 if (events.fetch_add(1) == 2)
522 have_3_events.raise();
523 };
524
525 set_window_event_handler(window, counter);
526 set_window_event_handler(target_window, counter);
527
528 start_dragging_mouse();
529 move_mouse({1,1});
530 release_mouse();
531
532 EXPECT_TRUE(have_3_events.wait_for(receive_event_timeout));
533
534 reset_window_event_handler(window);
535 reset_window_event_handler(target_window);
536 return handles;
537}
538
539MATCHER_P(BlobContentEq, p, "")
540{
541 if (!arg || !p)
542 return false;
543 if (mir_blob_size(arg) != mir_blob_size(p))
544 return false;
545 return !memcmp(mir_blob_data(arg), mir_blob_data(p), mir_blob_size(p));
546}
547}
548
549TEST_F(DragAndDrop, when_user_initiates_drag_client_receives_cookie)
550{
551 auto const cookie = user_initiates_drag();
552
553 EXPECT_THAT(cookie.get(), NotNull());
554}
555
556TEST_F(DragAndDrop, when_client_requests_drags_it_receives_handle)
557{
558 auto const cookie = user_initiates_drag();
559 ASSERT_THAT(cookie.get(), NotNull());
560
561 auto const handle = client_requests_drag(cookie);
562
563 EXPECT_THAT(handle.get(), NotNull());
564}
565
566TEST_F(DragAndDrop, during_drag_when_user_moves_mouse_client_receives_handle)
567{
568 auto const cookie = user_initiates_drag();
569 ASSERT_THAT(cookie.get(), NotNull());
570 auto const handle_from_request = client_requests_drag(cookie);
571
572 auto const handle = handle_from_mouse_move();
573
574 EXPECT_THAT(handle.get(), NotNull());
575 EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get()));
576}
577
578TEST_F(DragAndDrop, when_drag_moves_from_window_leave_event_contains_handle)
579{
580 auto const cookie = user_initiates_drag();
581 ASSERT_THAT(cookie.get(), NotNull());
582 auto const handle_from_request = client_requests_drag(cookie);
583
584 auto const handle = handle_from_mouse_leave();
585
586 EXPECT_THAT(handle.get(), NotNull());
587 EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get()));
588}
589
590TEST_F(DragAndDrop, when_drag_enters_target_window_enter_event_contains_handle)
591{
592 auto const cookie = user_initiates_drag();
593 ASSERT_THAT(cookie.get(), NotNull());
594 auto const handle_from_request = client_requests_drag(cookie);
595
596 auto const handle = handle_from_mouse_enter();
597
598 EXPECT_THAT(handle.get(), NotNull());
599 EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get()));
600}
601
602TEST_F(DragAndDrop, when_drag_releases_target_window_release_event_contains_handle)
603{
604 auto const cookie = user_initiates_drag();
605 ASSERT_THAT(cookie.get(), NotNull());
606 auto const handle_from_request = client_requests_drag(cookie);
607
608 auto const handle = handle_from_mouse_release();
609
610 EXPECT_THAT(handle.get(), NotNull());
611 EXPECT_THAT(handle.get(), BlobContentEq(handle_from_request.get()));
612}
613
614TEST_F(DragAndDrop, after_drag_finishes_pointer_events_no_longer_contain_handle)
615{
616 auto const cookie = user_initiates_drag();
617 ASSERT_THAT(cookie.get(), NotNull());
618 client_requests_drag(cookie);
619 handle_from_mouse_release();
620
621 server.the_shell()->clear_drag_and_drop_handle();
622
623 EXPECT_THAT(count_of_handles_when_moving_mouse(), Eq(0));
624}
0625
=== modified file 'tests/acceptance-tests/test_client_cursor_api.cpp'
--- tests/acceptance-tests/test_client_cursor_api.cpp 2017-02-28 08:53:57 +0000
+++ tests/acceptance-tests/test_client_cursor_api.cpp 2017-03-17 15:52:51 +0000
@@ -82,6 +82,7 @@
82 MOCK_METHOD0(cursor_image_removed, void());82 MOCK_METHOD0(cursor_image_removed, void());
83 MOCK_METHOD1(placed_relative, void(geom::Rectangle const& placement));83 MOCK_METHOD1(placed_relative, void(geom::Rectangle const& placement));
84 MOCK_METHOD1(input_consumed, void(MirEvent const*));84 MOCK_METHOD1(input_consumed, void(MirEvent const*));
85 MOCK_METHOD1(start_drag_and_drop, void(std::vector<uint8_t> const& handle));
85};86};
8687
8788
8889
=== modified file 'tests/include/mir/test/doubles/mock_input_targeter.h'
--- tests/include/mir/test/doubles/mock_input_targeter.h 2015-06-18 02:46:16 +0000
+++ tests/include/mir/test/doubles/mock_input_targeter.h 2017-03-17 15:52:51 +0000
@@ -35,6 +35,9 @@
35 virtual ~MockInputTargeter() noexcept(true) {}35 virtual ~MockInputTargeter() noexcept(true) {}
36 MOCK_METHOD1(set_focus, void(std::shared_ptr<input::Surface> const&));36 MOCK_METHOD1(set_focus, void(std::shared_ptr<input::Surface> const&));
37 MOCK_METHOD0(clear_focus, void());37 MOCK_METHOD0(clear_focus, void());
38
39 void set_drag_and_drop_handle(std::vector<uint8_t> const&) override {}
40 void clear_drag_and_drop_handle() override {}
38};41};
3942
40}43}
4144
=== modified file 'tests/include/mir/test/doubles/mock_shell.h'
--- tests/include/mir/test/doubles/mock_shell.h 2017-01-18 02:29:37 +0000
+++ tests/include/mir/test/doubles/mock_shell.h 2017-03-17 15:52:51 +0000
@@ -72,6 +72,9 @@
7272
73 MOCK_METHOD3(raise_surface, void(std::shared_ptr<frontend::Session> const& session,73 MOCK_METHOD3(raise_surface, void(std::shared_ptr<frontend::Session> const& session,
74 frontend::SurfaceId surface_id, uint64_t timestamp));74 frontend::SurfaceId surface_id, uint64_t timestamp));
75
76 MOCK_METHOD3(request_drag_and_drop, void(std::shared_ptr<frontend::Session> const& session,
77 frontend::SurfaceId surface_id, uint64_t timestamp));
75};78};
7679
77}80}
7881
=== modified file 'tests/include/mir/test/doubles/stub_display_server.h'
--- tests/include/mir/test/doubles/stub_display_server.h 2017-02-15 07:38:33 +0000
+++ tests/include/mir/test/doubles/stub_display_server.h 2017-03-17 15:52:51 +0000
@@ -158,6 +158,10 @@
158 mir::protobuf::RaiseRequest const* /*request*/,158 mir::protobuf::RaiseRequest const* /*request*/,
159 mir::protobuf::Void* /*response*/,159 mir::protobuf::Void* /*response*/,
160 google::protobuf::Closure* /*done*/) {}160 google::protobuf::Closure* /*done*/) {}
161 void request_drag_and_drop(
162 mir::protobuf::RequestAuthority const* /*request*/,
163 mir::protobuf::Void* /*response*/,
164 google::protobuf::Closure* /*done*/) {}
161 void apply_input_configuration(165 void apply_input_configuration(
162 mir::protobuf::InputConfigurationRequest const* /*request*/,166 mir::protobuf::InputConfigurationRequest const* /*request*/,
163 mir::protobuf::Void* /*response*/,167 mir::protobuf::Void* /*response*/,
164168
=== modified file 'tests/include/mir/test/doubles/stub_input_targeter.h'
--- tests/include/mir/test/doubles/stub_input_targeter.h 2015-06-18 02:46:16 +0000
+++ tests/include/mir/test/doubles/stub_input_targeter.h 2017-03-17 15:52:51 +0000
@@ -36,6 +36,9 @@
36 void clear_focus()36 void clear_focus()
37 {37 {
38 }38 }
39
40 void set_drag_and_drop_handle(std::vector<uint8_t> const&) override {}
41 void clear_drag_and_drop_handle() override {}
39};42};
4043
41}44}
4245
=== modified file 'tests/include/mir/test/doubles/stub_scene_surface.h'
--- tests/include/mir/test/doubles/stub_scene_surface.h 2017-02-15 14:45:41 +0000
+++ tests/include/mir/test/doubles/stub_scene_surface.h 2017-03-17 15:52:51 +0000
@@ -94,6 +94,7 @@
94 void set_confine_pointer_state(MirPointerConfinementState /*state*/) override {}94 void set_confine_pointer_state(MirPointerConfinementState /*state*/) override {}
95 MirPointerConfinementState confine_pointer_state() const override { return {}; }95 MirPointerConfinementState confine_pointer_state() const override { return {}; }
96 void placed_relative(geometry::Rectangle const& /*placement*/) override {}96 void placed_relative(geometry::Rectangle const& /*placement*/) override {}
97 void start_drag_and_drop(std::vector<uint8_t> const& /*handle*/) override {}
97};98};
9899
99}100}
100101
=== modified file 'tests/mir_test_framework/observant_shell.cpp'
--- tests/mir_test_framework/observant_shell.cpp 2017-01-20 00:01:50 +0000
+++ tests/mir_test_framework/observant_shell.cpp 2017-03-17 15:52:51 +0000
@@ -155,7 +155,26 @@
155void mtf::ObservantShell::raise_surface(155void mtf::ObservantShell::raise_surface(
156 std::shared_ptr<msc::Session> const& session,156 std::shared_ptr<msc::Session> const& session,
157 std::shared_ptr<msc::Surface> const& window,157 std::shared_ptr<msc::Surface> const& window,
158 uint64_t timestamp)
159{
160 return wrapped->raise_surface(session, window, timestamp);
161}
162
163void mtf::ObservantShell::request_drag_and_drop(
164 std::shared_ptr<msc::Session> const& session,
165 std::shared_ptr<msc::Surface> const& window,
158 uint64_t timestamp) 166 uint64_t timestamp)
159{167{
160 return wrapped->raise_surface(session, window, timestamp);168 return wrapped->request_drag_and_drop(session, window, timestamp);
161}169}
170
171void mtf::ObservantShell::set_drag_and_drop_handle(std::vector<uint8_t> const& handle)
172{
173 wrapped->set_drag_and_drop_handle(handle);
174}
175
176void mtf::ObservantShell::clear_drag_and_drop_handle()
177{
178 wrapped->clear_drag_and_drop_handle();
179}
180
162181
=== modified file 'tests/mir_test_framework/stub_surface.cpp'
--- tests/mir_test_framework/stub_surface.cpp 2017-02-15 14:45:41 +0000
+++ tests/mir_test_framework/stub_surface.cpp 2017-03-17 15:52:51 +0000
@@ -198,6 +198,10 @@
198{198{
199}199}
200200
201void mtd::StubSurface::start_drag_and_drop(std::vector<uint8_t> const& /*handle*/)
202{
203}
204
201namespace205namespace
202{206{
203// Ensure we don't accidentally have an abstract class207// Ensure we don't accidentally have an abstract class

Subscribers

People subscribed via source and target branches