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

Proposed by Alan Griffiths
Status: Merged
Approved by: Brandon Schaefer
Approved revision: 558
Merged at revision: 549
Proposed branch: lp:~alan-griffiths/miral/drag-and-drop
Merge into: lp:miral
Prerequisite: lp:~alan-griffiths/miral/1.3
Diff against target: 1092 lines (+850/-11)
16 files modified
CMakeLists.txt (+2/-2)
debian/changelog (+13/-2)
debian/libmiral2.symbols (+4/-0)
include/miral/window_management_policy_addendum2.h (+61/-0)
include/miral/window_manager_tools.h (+12/-0)
miral/CMakeLists.txt (+1/-0)
miral/basic_window_manager.cpp (+42/-5)
miral/basic_window_manager.h (+4/-0)
miral/symbols.map (+21/-0)
miral/window_management_trace.cpp (+18/-0)
miral/window_management_trace.h (+2/-0)
miral/window_manager_tools.cpp (+6/-0)
miral/window_manager_tools_implementation.h (+3/-0)
scripts/process_doxygen_xml.py (+12/-1)
test/CMakeLists.txt (+10/-1)
test/drag_and_drop.cpp (+639/-0)
To merge this branch: bzr merge lp:~alan-griffiths/miral/drag-and-drop
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve
Brandon Schaefer (community) Approve
Albert Astals Cid Pending
Review via email: mp+321593@code.launchpad.net

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

Commit message

[libmiral] Support for Drag and Drop messages

To post a comment you must log in.
Revision history for this message
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

By just reading the documentation i would not know on what to pass as std::vector<uint8_t> const& handle in start_drag_and_drop, is it "whatever i want"?

I guess it is since it's a randomly generated uuid in the example.

But what is this parameter for? I mean as a miral user, you pass it in, but do you ever get it back? It seems not, so maybe miral can constrcut the uuid itself?

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

> By just reading the documentation i would not know on what to pass as
> std::vector<uint8_t> const& handle in start_drag_and_drop, is it "whatever i
> want"?
>
> I guess it is since it's a randomly generated uuid in the example.
>
> But what is this parameter for? I mean as a miral user, you pass it in, but do
> you ever get it back? It seems not, so maybe miral can constrcut the uuid
> itself?

OK, so the documentation needs to state that "the handle will be passed to the client which can then use it to talk to the whatever service is being used to support drag and drop (e.g. on Ubuntu the content hub)".

Revision history for this message
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

> > By just reading the documentation i would not know on what to pass as
> > std::vector<uint8_t> const& handle in start_drag_and_drop, is it "whatever i
> > want"?
> >
> > I guess it is since it's a randomly generated uuid in the example.
> >
> > But what is this parameter for? I mean as a miral user, you pass it in, but
> do
> > you ever get it back? It seems not, so maybe miral can constrcut the uuid
> > itself?
>
> OK, so the documentation needs to state that "the handle will be passed to the
> client which can then use it to talk to the whatever service is being used to
> support drag and drop (e.g. on Ubuntu the content hub)".

That looks good to me :)

Revision history for this message
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

Looks good to me

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

PASSED: Continuous integration, rev:556
https://mir-jenkins.ubuntu.com/job/miral-ci/3/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-miral/4
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4542
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4532
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4532
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4532
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/6
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/6/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/6
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/6/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/6
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/6/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/6
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/6/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/miral-ci/3/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:556
https://mir-jenkins.ubuntu.com/job/miral-ci/6/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-miral/8
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4546
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4536
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4536
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4536
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4536
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial/13
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial/13/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/13
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/13/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/13
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/13/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial/13
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial/13/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/13
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/13/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/13
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/13/artifact/output/*zip*/output.zip

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

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

PASSED: Continuous integration, rev:557
https://mir-jenkins.ubuntu.com/job/miral-ci/7/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-miral/9
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4547
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4537
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4537
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4537
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4537
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial/14
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial/14/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/14
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/14/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/14
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/14/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial/14
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial/14/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/14
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/14/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/14
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/14/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
558. By Alan Griffiths

1.3.2 release changelog

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

PASSED: Continuous integration, rev:558
https://mir-jenkins.ubuntu.com/job/miral-ci/9/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-miral/13
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4593
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4582
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4582
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4582
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4582
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial/18
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial/18/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/18
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=xenial+overlay/18/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/18
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=amd64,release=zesty/18/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial/18
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial/18/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/18
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=xenial+overlay/18/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/18
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-miral/arch=i386,release=zesty/18/artifact/output/*zip*/output.zip

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

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

lgtm

review: Approve
Revision history for this message
Mir CI Bot (mir-ci-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2017-04-05 08:25:21 +0000
+++ CMakeLists.txt 2017-04-05 08:25:21 +0000
@@ -41,8 +41,8 @@
41include_directories(include SYSTEM ${MIRCLIENT_INCLUDE_DIRS})41include_directories(include SYSTEM ${MIRCLIENT_INCLUDE_DIRS})
4242
43set(MIRAL_VERSION_MAJOR 1)43set(MIRAL_VERSION_MAJOR 1)
44set(MIRAL_VERSION_MINOR 3)44set(MIRAL_VERSION_MINOR 4)
45set(MIRAL_VERSION_PATCH 2)45set(MIRAL_VERSION_PATCH 0)
4646
47set(MIRAL_VERSION ${MIRAL_VERSION_MAJOR}.${MIRAL_VERSION_MINOR}.${MIRAL_VERSION_PATCH})47set(MIRAL_VERSION ${MIRAL_VERSION_MAJOR}.${MIRAL_VERSION_MINOR}.${MIRAL_VERSION_PATCH})
4848
4949
=== modified file 'debian/changelog'
--- debian/changelog 2017-04-05 08:25:21 +0000
+++ debian/changelog 2017-04-05 08:25:21 +0000
@@ -1,3 +1,14 @@
1miral (1.4.0) UNRELEASED; urgency=medium
2
3 * New upstream release 1.4.0 (https://launchpad.net/miral/+milestone/1.4.0)
4 - ABI summary:
5 . miral ABI unchanged at 2
6 - Enhancements:
7 . Support for passing messages to enable Drag & Drop
8 - Bugs fixed:
9
10 -- Alan Griffiths <alan@Octopull-X1c3> Tue, 21 Mar 2017 17:57:20 +0000
11
1miral (1.3.2+17.04.20170330.5-0ubuntu1) zesty; urgency=medium12miral (1.3.2+17.04.20170330.5-0ubuntu1) zesty; urgency=medium
213
3 * New upstream release 1.3.2 (https://launchpad.net/miral/+milestone/1.3.2)14 * New upstream release 1.3.2 (https://launchpad.net/miral/+milestone/1.3.2)
@@ -74,11 +85,11 @@
74 . Chrome-less shell hint does not work any more (LP: #1658117)85 . Chrome-less shell hint does not work any more (LP: #1658117)
75 . WindowSpec::set_state() wrapper for mir_window_spec_set_state()86 . WindowSpec::set_state() wrapper for mir_window_spec_set_state()
76 (LP: #1661256)87 (LP: #1661256)
77 . "$ miral-app -kiosk" fails with "Unknown command line options: 88 . "$ miral-app -kiosk" fails with "Unknown command line options:
78 --desktop_file_hint=miral-shell.desktop" (LP: #1660933)89 --desktop_file_hint=miral-shell.desktop" (LP: #1660933)
79 . libmiral] Fix focus and movement rules for Input Method and Satellite90 . libmiral] Fix focus and movement rules for Input Method and Satellite
80 windows. (LP: #1660691)91 windows. (LP: #1660691)
81 92
8293
83 -- Alan Griffiths <alan.griffiths@canonical.com> Wed, 15 Feb 2017 14:05:46 +000094 -- Alan Griffiths <alan.griffiths@canonical.com> Wed, 15 Feb 2017 14:05:46 +0000
8495
8596
=== modified file 'debian/libmiral2.symbols'
--- debian/libmiral2.symbols 2017-03-15 17:44:36 +0000
+++ debian/libmiral2.symbols 2017-04-05 08:25:21 +0000
@@ -389,3 +389,7 @@
389 (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.3.1389 (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.3.1
390 (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.3.1390 (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.3.1
391 (c++)"miral::SetWindowManagementPolicy::operator()(mir::Server&) const@MIRAL_1.3.1" 1.3.1391 (c++)"miral::SetWindowManagementPolicy::operator()(mir::Server&) const@MIRAL_1.3.1" 1.3.1
392 MIRAL_1.4.0@MIRAL_1.4.0 1.4.0
393 (c++)"miral::WindowManagerTools::end_drag_and_drop()@MIRAL_1.4.0" 1.4.0
394 (c++)"miral::WindowManagerTools::start_drag_and_drop(miral::WindowInfo&, std::vector<unsigned char, std::allocator<unsigned char> > const&)@MIRAL_1.4.0" 1.4.0
395 (c++)"typeinfo for miral::WindowManagementPolicyAddendum2@MIRAL_1.4.0" 1.4.0
392396
=== added file 'include/miral/window_management_policy_addendum2.h'
--- include/miral/window_management_policy_addendum2.h 1970-01-01 00:00:00 +0000
+++ include/miral/window_management_policy_addendum2.h 2017-04-05 08:25:21 +0000
@@ -0,0 +1,61 @@
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#ifndef MIRAL_WINDOW_MANAGEMENT_ADDENDUM2_H
20#define MIRAL_WINDOW_MANAGEMENT_ADDENDUM2_H
21
22#include <mir/version.h>
23
24namespace miral
25{
26struct WindowInfo;
27
28/**
29 * Handle additional client requests.
30 *
31 * \note This interface is intended to be implemented by a WindowManagementPolicy
32 * implementation, we can't add these functions directly to that interface without
33 * breaking ABI (the vtab could be incompatible).
34 * When initializing the window manager this interface will be detected by
35 * dynamic_cast and registered accordingly.
36 */
37class WindowManagementPolicyAddendum2
38{
39public:
40/** @name handle requests originating from the client
41 * The policy is expected to update the model as appropriate
42 * @{ */
43 /** request from client to initiate drag and drop
44 * \note the request has already been validated against the requesting event
45 *
46 * @param window_info the window
47 */
48 virtual void handle_request_drag_and_drop(WindowInfo& window_info) = 0;
49/** @} */
50
51 virtual ~WindowManagementPolicyAddendum2() = default;
52 WindowManagementPolicyAddendum2() = default;
53 WindowManagementPolicyAddendum2(WindowManagementPolicyAddendum2 const&) = delete;
54 WindowManagementPolicyAddendum2& operator=(WindowManagementPolicyAddendum2 const&) = delete;
55};
56#if MIRAL_VERSION >= MIR_VERSION_NUMBER(2, 0, 0)
57#error "We've presumably broken ABI - please roll this interface into WindowManagementPolicy"
58#endif
59}
60
61#endif //MIRAL_WINDOW_MANAGEMENT_ADDENDUM2_H
062
=== modified file 'include/miral/window_manager_tools.h'
--- include/miral/window_manager_tools.h 2017-03-02 14:29:04 +0000
+++ include/miral/window_manager_tools.h 2017-04-05 08:25:21 +0000
@@ -166,6 +166,18 @@
166 /// Raise window and all its children166 /// Raise window and all its children
167 void raise_tree(Window const& root);167 void raise_tree(Window const& root);
168168
169 /** Start drag and drop. The handle will be passed to the client which can
170 * then use it to talk to the whatever service is being used to support drag
171 * and drop (e.g. on Ubuntu the content hub).
172 *
173 * @param window_info source window
174 * @param handle drag handle
175 */
176 void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle);
177
178 /// End drag and drop
179 void end_drag_and_drop();
180
169 /// Apply modifications to a window181 /// Apply modifications to a window
170 void modify_window(WindowInfo& window_info, WindowSpecification const& modifications);182 void modify_window(WindowInfo& window_info, WindowSpecification const& modifications);
171183
172184
=== modified file 'miral/CMakeLists.txt'
--- miral/CMakeLists.txt 2017-03-20 12:28:06 +0000
+++ miral/CMakeLists.txt 2017-04-05 08:25:21 +0000
@@ -61,6 +61,7 @@
61 ${CMAKE_SOURCE_DIR}/include/mir/client/display_config.h61 ${CMAKE_SOURCE_DIR}/include/mir/client/display_config.h
62 ${CMAKE_SOURCE_DIR}/include/mir/client/window.h62 ${CMAKE_SOURCE_DIR}/include/mir/client/window.h
63 ${CMAKE_SOURCE_DIR}/include/mir/client/detail/mir_forward_compatibility.h63 ${CMAKE_SOURCE_DIR}/include/mir/client/detail/mir_forward_compatibility.h
64 ${CMAKE_SOURCE_DIR}/include/miral/window_management_policy_addendum2.h
64)65)
6566
66target_link_libraries(miral67target_link_libraries(miral
6768
=== modified file 'miral/basic_window_manager.cpp'
--- miral/basic_window_manager.cpp 2017-03-21 12:30:42 +0000
+++ miral/basic_window_manager.cpp 2017-04-05 08:25:21 +0000
@@ -19,6 +19,7 @@
19#include "basic_window_manager.h"19#include "basic_window_manager.h"
20#include "miral/window_manager_tools.h"20#include "miral/window_manager_tools.h"
21#include "miral/workspace_policy.h"21#include "miral/workspace_policy.h"
22#include "miral/window_management_policy_addendum2.h"
2223
23#include <mir/scene/session.h>24#include <mir/scene/session.h>
24#include <mir/scene/surface.h>25#include <mir/scene/surface.h>
@@ -70,7 +71,6 @@
7071
71namespace72namespace
72{73{
73
74auto find_workspace_policy(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WorkspacePolicy*74auto find_workspace_policy(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WorkspacePolicy*
75{75{
76 miral::WorkspacePolicy* result = dynamic_cast<miral::WorkspacePolicy*>(policy.get());76 miral::WorkspacePolicy* result = dynamic_cast<miral::WorkspacePolicy*>(policy.get());
@@ -82,6 +82,22 @@
8282
83 return &null_workspace_policy;83 return &null_workspace_policy;
84}84}
85
86auto find_policy_addendum2(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WindowManagementPolicyAddendum2*
87{
88 miral::WindowManagementPolicyAddendum2* result = dynamic_cast<miral::WindowManagementPolicyAddendum2*>(policy.get());
89
90 if (result)
91 return result;
92
93 struct NullWindowManagementPolicyAddendum2 : miral::WindowManagementPolicyAddendum2
94 {
95 void handle_request_drag_and_drop(miral::WindowInfo&) override {}
96 };
97 static NullWindowManagementPolicyAddendum2 null_workspace_policy;
98
99 return &null_workspace_policy;
100}
85}101}
86102
87103
@@ -94,7 +110,8 @@
94 display_layout(display_layout),110 display_layout(display_layout),
95 persistent_surface_store{persistent_surface_store},111 persistent_surface_store{persistent_surface_store},
96 policy(build(WindowManagerTools{this})),112 policy(build(WindowManagerTools{this})),
97 workspace_policy{find_workspace_policy(policy)}113 workspace_policy{find_workspace_policy(policy)},
114 policy2{find_policy_addendum2(policy)}
98{115{
99}116}
100117
@@ -362,10 +379,12 @@
362#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0)379#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0)
363void miral::BasicWindowManager::handle_request_drag_and_drop(380void miral::BasicWindowManager::handle_request_drag_and_drop(
364 std::shared_ptr<mir::scene::Session> const& /*session*/,381 std::shared_ptr<mir::scene::Session> const& /*session*/,
365 std::shared_ptr<mir::scene::Surface> const& /*surface*/,382 std::shared_ptr<mir::scene::Surface> const& surface,
366 uint64_t /*timestamp*/)383 uint64_t timestamp)
367{384{
368 // TODO385 Locker lock{this};
386 if (timestamp >= last_input_event_timestamp)
387 policy2->handle_request_drag_and_drop(info_for(surface));
369}388}
370#endif389#endif
371390
@@ -741,6 +760,24 @@
741 focus_controller->raise({begin(windows), end(windows)});760 focus_controller->raise({begin(windows), end(windows)});
742}761}
743762
763void miral::BasicWindowManager::start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle)
764{
765#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0)
766 std::shared_ptr<scene::Surface>(window_info.window())->start_drag_and_drop(handle);
767 focus_controller->set_drag_and_drop_handle(handle);
768#else
769 (void)window_info;
770 (void)handle;
771#endif
772}
773
774void miral::BasicWindowManager::end_drag_and_drop()
775{
776#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 27, 0)
777 focus_controller->clear_drag_and_drop_handle();
778#endif
779}
780
744void miral::BasicWindowManager::move_tree(miral::WindowInfo& root, mir::geometry::Displacement movement)781void miral::BasicWindowManager::move_tree(miral::WindowInfo& root, mir::geometry::Displacement movement)
745{782{
746 if (movement == mir::geometry::Displacement{})783 if (movement == mir::geometry::Displacement{})
747784
=== modified file 'miral/basic_window_manager.h'
--- miral/basic_window_manager.h 2017-03-21 12:30:42 +0000
+++ miral/basic_window_manager.h 2017-04-05 08:25:21 +0000
@@ -46,6 +46,7 @@
46namespace miral46namespace miral
47{47{
48class WorkspacePolicy;48class WorkspacePolicy;
49class WindowManagementPolicyAddendum2;
49using mir::shell::SurfaceSet;50using mir::shell::SurfaceSet;
50using WindowManagementPolicyBuilder =51using WindowManagementPolicyBuilder =
51 std::function<std::unique_ptr<miral::WindowManagementPolicy>(miral::WindowManagerTools const& tools)>;52 std::function<std::unique_ptr<miral::WindowManagementPolicy>(miral::WindowManagerTools const& tools)>;
@@ -161,6 +162,8 @@
161 auto active_display() -> mir::geometry::Rectangle const override;162 auto active_display() -> mir::geometry::Rectangle const override;
162163
163 void raise_tree(Window const& root) override;164 void raise_tree(Window const& root) override;
165 void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) override;
166 void end_drag_and_drop() override;
164167
165 void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override;168 void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override;
166169
@@ -190,6 +193,7 @@
190193
191 std::unique_ptr<WindowManagementPolicy> const policy;194 std::unique_ptr<WindowManagementPolicy> const policy;
192 WorkspacePolicy* const workspace_policy;195 WorkspacePolicy* const workspace_policy;
196 WindowManagementPolicyAddendum2* const policy2;
193197
194 std::mutex mutex;198 std::mutex mutex;
195 SessionInfoMap app_info;199 SessionInfoMap app_info;
196200
=== modified file 'miral/symbols.map'
--- miral/symbols.map 2017-03-15 17:44:36 +0000
+++ miral/symbols.map 2017-04-05 08:25:21 +0000
@@ -401,3 +401,24 @@
401 vtable?for?miral::SetWindowManagementPolicy;401 vtable?for?miral::SetWindowManagementPolicy;
402 };402 };
403} MIRAL_1.3;403} MIRAL_1.3;
404
405MIRAL_1.4.0 {
406global:
407 extern "C++" {
408 miral::WindowManagementPolicyAddendum2::?WindowManagementPolicyAddendum2*;
409 miral::WindowManagementPolicyAddendum2::WindowManagementPolicyAddendum2*;
410 miral::WindowManagementPolicyAddendum2::operator*;
411 miral::WindowManagerTools::end_drag_and_drop*;
412 miral::WindowManagerTools::start_drag_and_drop*;
413 miral::toolkit::Window::Window*;
414 non-virtual?thunk?to?miral::WindowManagementPolicyAddendum2::?WindowManagementPolicyAddendum2*;
415 typeinfo?for?miral::WindowManagementPolicyAddendum2;
416 typeinfo?for?miral::toolkit::Window;
417 typeinfo?for?miral::toolkit::WindowId;
418 typeinfo?for?miral::toolkit::WindowSpec;
419 vtable?for?miral::WindowManagementPolicyAddendum2;
420 vtable?for?miral::toolkit::Window;
421 vtable?for?miral::toolkit::WindowId;
422 vtable?for?miral::toolkit::WindowSpec;
423 };
424} MIRAL_1.3.1;
404425
=== modified file 'miral/window_management_trace.cpp'
--- miral/window_management_trace.cpp 2017-03-03 10:06:02 +0000
+++ miral/window_management_trace.cpp 2017-04-05 08:25:21 +0000
@@ -547,6 +547,24 @@
547}547}
548MIRAL_TRACE_EXCEPTION548MIRAL_TRACE_EXCEPTION
549549
550void miral::WindowManagementTrace::start_drag_and_drop(miral::WindowInfo& window_info, std::vector<uint8_t> const& handle)
551try {
552 log_input();
553 mir::log_info("%s window_info=%s", __func__, dump_of(window_info).c_str());
554 trace_count++;
555 wrapped.start_drag_and_drop(window_info, handle);
556}
557MIRAL_TRACE_EXCEPTION
558
559void miral::WindowManagementTrace::end_drag_and_drop()
560try {
561 log_input();
562 mir::log_info("%s window_info=%s", __func__);
563 trace_count++;
564 wrapped.end_drag_and_drop();
565}
566MIRAL_TRACE_EXCEPTION
567
550void miral::WindowManagementTrace::modify_window(568void miral::WindowManagementTrace::modify_window(
551 miral::WindowInfo& window_info, miral::WindowSpecification const& modifications)569 miral::WindowInfo& window_info, miral::WindowSpecification const& modifications)
552try {570try {
553571
=== modified file 'miral/window_management_trace.h'
--- miral/window_management_trace.h 2017-03-02 14:29:04 +0000
+++ miral/window_management_trace.h 2017-04-05 08:25:21 +0000
@@ -69,6 +69,8 @@
69 virtual void focus_prev_within_application() override;69 virtual void focus_prev_within_application() override;
7070
71 virtual void raise_tree(Window const& root) override;71 virtual void raise_tree(Window const& root) override;
72 virtual void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) override;
73 virtual void end_drag_and_drop() override;
7274
73 virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override;75 virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) override;
7476
7577
=== modified file 'miral/window_manager_tools.cpp'
--- miral/window_manager_tools.cpp 2017-03-02 14:29:04 +0000
+++ miral/window_manager_tools.cpp 2017-04-05 08:25:21 +0000
@@ -83,6 +83,12 @@
83void miral::WindowManagerTools::raise_tree(Window const& root)83void miral::WindowManagerTools::raise_tree(Window const& root)
84{ tools->raise_tree(root); }84{ tools->raise_tree(root); }
8585
86void miral::WindowManagerTools::start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle)
87{ tools->start_drag_and_drop(window_info, handle); }
88
89void miral::WindowManagerTools::end_drag_and_drop()
90{ tools->end_drag_and_drop(); }
91
86void miral::WindowManagerTools::modify_window(WindowInfo& window_info, WindowSpecification const& modifications)92void miral::WindowManagerTools::modify_window(WindowInfo& window_info, WindowSpecification const& modifications)
87{ tools->modify_window(window_info,modifications); }93{ tools->modify_window(window_info,modifications); }
8894
8995
=== modified file 'miral/window_manager_tools_implementation.h'
--- miral/window_manager_tools_implementation.h 2017-03-02 14:29:04 +0000
+++ miral/window_manager_tools_implementation.h 2017-04-05 08:25:21 +0000
@@ -26,6 +26,7 @@
2626
27#include <functional>27#include <functional>
28#include <memory>28#include <memory>
29#include <vector>
2930
30namespace mir { namespace scene { class Surface; } }31namespace mir { namespace scene { class Surface; } }
3132
@@ -66,6 +67,8 @@
66 virtual auto window_at(mir::geometry::Point cursor) const -> Window = 0;67 virtual auto window_at(mir::geometry::Point cursor) const -> Window = 0;
67 virtual auto active_display() -> mir::geometry::Rectangle const = 0;68 virtual auto active_display() -> mir::geometry::Rectangle const = 0;
68 virtual void raise_tree(Window const& root) = 0;69 virtual void raise_tree(Window const& root) = 0;
70 virtual void start_drag_and_drop(WindowInfo& window_info, std::vector<uint8_t> const& handle) = 0;
71 virtual void end_drag_and_drop() = 0;
69 virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) = 0;72 virtual void modify_window(WindowInfo& window_info, WindowSpecification const& modifications) = 0;
70 virtual auto info_for_window_id(std::string const& id) const -> WindowInfo& = 0;73 virtual auto info_for_window_id(std::string const& id) const -> WindowInfo& = 0;
71 virtual auto id_for_window(Window const& window) const -> std::string = 0;74 virtual auto id_for_window(Window const& window) const -> std::string = 0;
7275
=== modified file 'scripts/process_doxygen_xml.py'
--- scripts/process_doxygen_xml.py 2017-03-15 17:44:36 +0000
+++ scripts/process_doxygen_xml.py 2017-04-05 08:25:21 +0000
@@ -476,10 +476,21 @@
476476
477MIRAL_1.3.1 {477MIRAL_1.3.1 {
478global:478global:
479 extern "C++" {
480 miral::SetWindowManagementPolicy::?SetWindowManagementPolicy*;
481 miral::SetWindowManagementPolicy::SetWindowManagementPolicy*;
482 miral::SetWindowManagementPolicy::operator*;
483 typeinfo?for?miral::SetWindowManagementPolicy;
484 vtable?for?miral::SetWindowManagementPolicy;
485 };
486} MIRAL_1.3;
487
488MIRAL_1.4.0 {
489global:
479 extern "C++" {'''490 extern "C++" {'''
480491
481END_NEW_STANZA = ''' };492END_NEW_STANZA = ''' };
482} MIRAL_1.3;'''493} MIRAL_1.3.1;'''
483494
484def _print_report():495def _print_report():
485 print OLD_STANZAS496 print OLD_STANZAS
486497
=== modified file 'test/CMakeLists.txt'
--- test/CMakeLists.txt 2017-02-13 16:23:29 +0000
+++ test/CMakeLists.txt 2017-04-05 08:25:21 +0000
@@ -39,6 +39,13 @@
39 ${GTEST_INCLUDE_DIR}39 ${GTEST_INCLUDE_DIR}
40)40)
4141
42# MIRAL_TEST_MODERN_FEATURES lists test sourcefiles that require a recent version of Mir
43if (MIRTEST_VERSION VERSION_LESS 0.27)
44 set(MIRAL_TEST_MODERN_FEATURES)
45else()
46 set(MIRAL_TEST_MODERN_FEATURES drag_and_drop.cpp)
47endif()
48
42add_executable(miral-test49add_executable(miral-test
43 mru_window_list.cpp50 mru_window_list.cpp
44 active_outputs.cpp51 active_outputs.cpp
@@ -56,7 +63,9 @@
56 display_reconfiguration.cpp63 display_reconfiguration.cpp
57 active_window.cpp64 active_window.cpp
58 raise_tree.cpp65 raise_tree.cpp
59 workspaces.cpp)66 workspaces.cpp
67 ${MIRAL_TEST_MODERN_FEATURES}
68)
6069
61target_link_libraries(miral-test70target_link_libraries(miral-test
62 ${MIRTEST_LDFLAGS}71 ${MIRTEST_LDFLAGS}
6372
=== added file 'test/drag_and_drop.cpp'
--- test/drag_and_drop.cpp 1970-01-01 00:00:00 +0000
+++ test/drag_and_drop.cpp 2017-04-05 08:25:21 +0000
@@ -0,0 +1,639 @@
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 <miral/window_management_policy_addendum2.h>
20
21#include <mir/client/blob.h>
22#include <mir/client/cookie.h>
23#include <mir/client/window.h>
24#include <mir/client/window_spec.h>
25#include <mir_toolkit/mir_buffer_stream.h>
26#include <mir_toolkit/extensions/drag_and_drop.h>
27
28#include <mir/geometry/displacement.h>
29#include <mir/input/input_device_info.h>
30#include <mir/input/device_capability.h>
31#include <mir/shell/shell.h>
32
33#include "test_server.h"
34#include <mir_test_framework/fake_input_device.h>
35#include <mir_test_framework/stub_server_platform_factory.h>
36#include <mir/test/event_factory.h>
37#include <mir/test/signal.h>
38
39#include <gmock/gmock.h>
40#include <gtest/gtest.h>
41
42#include <linux/input.h>
43#include <uuid/uuid.h>
44
45#include <boost/throw_exception.hpp>
46#include <atomic>
47
48using namespace std::chrono_literals;
49using namespace mir::client;
50using namespace mir::geometry;
51using namespace testing;
52using mir::test::Signal;
53
54namespace
55{
56struct MouseMoverAndFaker
57{
58 void start_dragging_mouse()
59 {
60 using namespace mir::input::synthesis;
61 fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT));
62 }
63
64 void move_mouse(Displacement const& displacement)
65 {
66 using mir::input::synthesis::a_pointer_event;
67 fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int()));
68 }
69
70 void release_mouse()
71 {
72 using namespace mir::input::synthesis;
73 fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT));
74 }
75
76private:
77 std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{
78 mir_test_framework::add_fake_input_device(
79 mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer})};
80};
81
82Rectangle const screen_geometry{{0,0}, {800,600}};
83auto const receive_event_timeout = 1s; //90s;
84
85struct ConnectedClientWithAWindow : miral::TestServer
86{
87 Connection connection;
88 Window window;
89
90 void SetUp() override
91 {
92 miral::TestServer::SetUp();
93 connection = connect_client(__func__);
94 window = WindowSpec::for_normal_window(connection, surface_size.width.as_int(), surface_size.height.as_int())
95 .set_pixel_format(mir_pixel_format_abgr_8888)
96 .set_name("ConnectedClientWithAWindow")
97 .set_buffer_usage(mir_buffer_usage_hardware)
98 .create_window();
99 }
100
101 void TearDown() override
102 {
103 window.reset();
104 connection.reset();
105 miral::TestServer::TearDown();
106 }
107
108 mir::geometry::Size const surface_size {640, 480};
109};
110
111struct DragAndDrop : ConnectedClientWithAWindow,
112 MouseMoverAndFaker
113{
114 MirDragAndDropV1 const* dnd = nullptr;
115
116 void SetUp() override
117 {
118 mir_test_framework::set_next_display_rects(std::unique_ptr<std::vector<Rectangle>>(new std::vector<Rectangle>({screen_geometry})));
119
120 ConnectedClientWithAWindow::SetUp();
121 dnd = mir_drag_and_drop_v1(connection);
122 mir_window_set_event_handler(window, &window_event_handler, this);
123 if (dnd) dnd->set_start_drag_and_drop_callback(window, &window_dnd_start_handler, this);
124
125 create_target_window();
126
127 paint_window(window);
128
129 center_mouse();
130 }
131
132 void TearDown() override
133 {
134 reset_window_event_handler(target_window);
135 reset_window_event_handler(window);
136 target_window.reset();
137 another_connection.reset();
138 ConnectedClientWithAWindow::TearDown();
139 }
140
141 auto user_initiates_drag() -> Cookie;
142 auto client_requests_drag(Cookie const& cookie) -> Blob;
143 auto handle_from_mouse_move() -> Blob;
144 auto handle_from_mouse_leave() -> Blob;
145 auto handle_from_mouse_enter() -> Blob;
146 auto handle_from_mouse_release() -> Blob;
147 auto count_of_handles_when_moving_mouse() -> int;
148
149private:
150 auto build_window_manager_policy(miral::WindowManagerTools const& tools) -> std::unique_ptr<TestWindowManagerPolicy> override;
151 void center_mouse();
152 void paint_window(MirWindow* w);
153 void set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler);
154 void set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler);
155 void reset_window_event_handler(MirWindow* window);
156
157 void create_target_window()
158 {
159 another_connection = connect_client("another_connection");
160 target_window = WindowSpec::
161 for_normal_window(connection, screen_geometry.size.width.as_int(), screen_geometry.size.height.as_int())
162 .set_pixel_format(mir_pixel_format_abgr_8888)
163 .set_name("target_window")
164 .set_buffer_usage(mir_buffer_usage_hardware)
165 .set_event_handler(&window_event_handler, this)
166 .create_window();
167
168 paint_window(target_window);
169 }
170
171 void invoke_window_event_handler(MirWindow* window, MirEvent const* event)
172 {
173 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
174 if (window == this->window) window_event_handler_(event);
175 if (window == target_window) target_window_event_handler_(event);
176 }
177
178 void invoke_window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event)
179 {
180 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
181 if (window == this->window) window_dnd_start_(event);
182 }
183
184 std::mutex window_event_handler_mutex;
185 std::function<void(MirDragAndDropEvent const* event)> window_dnd_start_ = [](MirDragAndDropEvent const*) {};
186 std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {};
187 std::function<void(MirEvent const* event)> target_window_event_handler_ = [](MirEvent const*) {};
188
189 static void window_event_handler(MirWindow* window, MirEvent const* event, void* context);
190 static void window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context);
191
192 Connection another_connection;
193 Window target_window;
194};
195
196void DragAndDrop::set_window_event_handler(MirWindow* window, std::function<void(MirEvent const* event)> const& handler)
197{
198 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
199 if (window == this->window) window_event_handler_ = handler;
200 if (window == target_window) target_window_event_handler_ = handler;
201}
202
203void DragAndDrop::set_window_dnd_start_handler(MirWindow* window, std::function<void(MirDragAndDropEvent const*)> const& handler)
204{
205std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
206if (window == this->window) window_dnd_start_ = handler;
207}
208
209
210void DragAndDrop::reset_window_event_handler(MirWindow* window)
211{
212 if (window == this->window) window_event_handler_ = [](MirEvent const*) {};
213 if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {};
214}
215
216void DragAndDrop::paint_window(MirWindow* w)
217{
218 Signal have_focus;
219
220 set_window_event_handler(w, [&](MirEvent const* event)
221 {
222 if (mir_event_get_type(event) != mir_event_type_window)
223 return;
224
225 auto const window_event = mir_event_get_window_event(event);
226 if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus)
227 return;
228
229 if (mir_window_event_get_attribute_value(window_event))
230 have_focus.raise();
231 });
232
233 mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(w));
234
235 EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true));
236
237 reset_window_event_handler(w);
238}
239
240void DragAndDrop::center_mouse()
241{
242 Signal have_mouseover;
243
244 set_window_event_handler(window, [&](MirEvent const* event)
245 {
246 if (mir_event_get_type(event) != mir_event_type_input)
247 return;
248
249 auto const input_event = mir_event_get_input_event(event);
250
251 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
252 return;
253
254 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
255
256 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter)
257 return;
258
259 have_mouseover.raise();
260 });
261
262 move_mouse(0.5 * as_displacement(screen_geometry.size));
263
264// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20).
265// But it isn't essential for the test and we've probably waited long enough
266// for the mouse-down needed by the test to reach the window.
267// EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true));
268 have_mouseover.wait_for(receive_event_timeout);
269
270 reset_window_event_handler(window);
271}
272
273void DragAndDrop::window_event_handler(MirWindow* window, MirEvent const* event, void* context)
274{
275 static_cast<DragAndDrop*>(context)->invoke_window_event_handler(window, event);
276}
277
278void DragAndDrop::window_dnd_start_handler(MirWindow* window, MirDragAndDropEvent const* event, void* context)
279{
280 static_cast<DragAndDrop*>(context)->invoke_window_dnd_start_handler(window, event);
281}
282
283
284auto DragAndDrop::user_initiates_drag() -> Cookie
285{
286 Cookie cookie;
287 Signal have_cookie;
288
289 set_window_event_handler(window, [&](MirEvent const* event)
290 {
291 if (mir_event_get_type(event) != mir_event_type_input)
292 return;
293
294 auto const input_event = mir_event_get_input_event(event);
295
296 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
297 return;
298
299 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
300
301 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down)
302 return;
303
304 cookie = Cookie{mir_input_event_get_cookie(input_event)};
305 have_cookie.raise();
306 });
307
308 start_dragging_mouse();
309
310 EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true));
311
312 reset_window_event_handler(window);
313 return cookie;
314}
315
316auto DragAndDrop::client_requests_drag(Cookie const& cookie) -> Blob
317{
318 Blob blob;
319 Signal initiated;
320
321 set_window_dnd_start_handler(window, [&](MirDragAndDropEvent const* event)
322 {
323 if (dnd)
324 blob.reset(dnd->start_drag_and_drop(event));
325
326 if (blob)
327 initiated.raise();
328 });
329
330 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
331
332 if (dnd)
333 dnd->request_drag_and_drop(window, cookie);
334
335 EXPECT_TRUE(initiated.wait_for(receive_event_timeout));
336
337 reset_window_event_handler(window);
338 return blob;
339}
340
341auto DragAndDrop::handle_from_mouse_move() -> Blob
342{
343 Blob blob;
344 Signal have_blob;
345
346 set_window_event_handler(window, [&](MirEvent const* event)
347 {
348 if (mir_event_get_type(event) != mir_event_type_input)
349 return;
350
351 auto const input_event = mir_event_get_input_event(event);
352
353 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
354 return;
355
356 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
357
358 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
359
360 if (dnd)
361 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
362
363 if (blob)
364 have_blob.raise();
365 });
366
367 move_mouse({1,1});
368
369 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
370
371 reset_window_event_handler(window);
372 return blob;
373}
374
375auto DragAndDrop::handle_from_mouse_leave() -> Blob
376{
377 Blob blob;
378 Signal have_blob;
379
380 set_window_event_handler(window, [&](MirEvent const* event)
381 {
382 if (mir_event_get_type(event) != mir_event_type_input)
383 return;
384
385 auto const input_event = mir_event_get_input_event(event);
386
387 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
388 return;
389
390 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
391
392 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_leave)
393 return;
394
395 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
396
397 if (dnd)
398 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
399
400 if (blob)
401 have_blob.raise();
402 });
403
404 move_mouse({1,1});
405 move_mouse(0.5 * as_displacement(surface_size));
406
407 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
408
409 reset_window_event_handler(window);
410 return blob;
411}
412
413auto DragAndDrop::handle_from_mouse_enter() -> Blob
414{
415 Blob blob;
416 Signal have_blob;
417
418 set_window_event_handler(target_window, [&](MirEvent const* event)
419 {
420 if (mir_event_get_type(event) != mir_event_type_input)
421 return;
422
423 auto const input_event = mir_event_get_input_event(event);
424
425 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
426 return;
427
428 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
429
430 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter)
431 return;
432
433 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
434
435 if (dnd)
436 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
437
438 if (blob)
439 have_blob.raise();
440 });
441
442 move_mouse({1,1});
443 move_mouse(0.5 * as_displacement(surface_size));
444
445 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
446
447 reset_window_event_handler(target_window);
448 return blob;
449}
450
451auto DragAndDrop::handle_from_mouse_release() -> Blob
452{
453 Blob blob;
454 Signal have_blob;
455
456 set_window_event_handler(target_window, [&](MirEvent const* event)
457 {
458 if (mir_event_get_type(event) != mir_event_type_input)
459 return;
460
461 auto const input_event = mir_event_get_input_event(event);
462
463 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
464 return;
465
466 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
467
468 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_up)
469 return;
470
471 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
472
473 if (dnd)
474 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
475
476 if (blob)
477 have_blob.raise();
478 });
479
480 move_mouse({1,1});
481 move_mouse(0.5 * as_displacement(surface_size));
482 release_mouse();
483
484 EXPECT_TRUE(have_blob.wait_for(receive_event_timeout));
485
486 reset_window_event_handler(target_window);
487 return blob;
488}
489
490auto DragAndDrop::count_of_handles_when_moving_mouse() -> int
491{
492 Signal have_3_events;
493 std::atomic<int> events{0};
494 std::atomic<int> handles{0};
495
496 auto counter = [&](MirEvent const* event)
497 {
498 if (mir_event_get_type(event) != mir_event_type_input)
499 return;
500
501 auto const input_event = mir_event_get_input_event(event);
502
503 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
504 return;
505
506 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
507
508 EXPECT_THAT(dnd, Ne(nullptr)) << "No Drag and Drop extension";
509
510 Blob blob;
511 if (dnd)
512 blob.reset(dnd->pointer_drag_and_drop(pointer_event));
513
514 if (blob)
515 handles.fetch_add(1);
516
517 if (events.fetch_add(1) == 2)
518 have_3_events.raise();
519 };
520
521 set_window_event_handler(window, counter);
522 set_window_event_handler(target_window, counter);
523
524 start_dragging_mouse();
525 move_mouse({1,1});
526 release_mouse();
527
528 EXPECT_TRUE(have_3_events.wait_for(receive_event_timeout));
529
530 reset_window_event_handler(window);
531 reset_window_event_handler(target_window);
532 return handles;
533}
534
535auto DragAndDrop::build_window_manager_policy(miral::WindowManagerTools const& tools) -> std::unique_ptr<TestWindowManagerPolicy>
536{
537 struct DnDWindowManagerPolicy : miral::TestServer::TestWindowManagerPolicy, miral::WindowManagementPolicyAddendum2
538 {
539 using miral::TestServer::TestWindowManagerPolicy::TestWindowManagerPolicy;
540
541 void handle_request_drag_and_drop(miral::WindowInfo& window_info) override
542 {
543 uuid_t uuid;
544 uuid_generate(uuid);
545 std::vector<uint8_t> const handle{std::begin(uuid), std::end(uuid)};
546
547 tools.start_drag_and_drop(window_info, handle);
548 }
549 };
550
551 return std::make_unique<DnDWindowManagerPolicy>(tools, *this);
552}
553
554MATCHER_P(BlobContentEq, p, "")
555{
556 if (!arg || !p)
557 return false;
558 if (mir_blob_size(arg) != mir_blob_size(p))
559 return false;
560 return !memcmp(mir_blob_data(arg), mir_blob_data(p), mir_blob_size(p));
561}
562}
563
564TEST_F(DragAndDrop, when_user_initiates_drag_client_receives_cookie)
565{
566 auto const cookie = user_initiates_drag();
567
568 EXPECT_THAT(cookie, NotNull());
569}
570
571TEST_F(DragAndDrop, when_client_requests_drags_it_receives_handle)
572{
573 auto const cookie = user_initiates_drag();
574 ASSERT_THAT(cookie, NotNull());
575
576 auto const handle = client_requests_drag(cookie);
577
578 EXPECT_THAT(handle, NotNull());
579}
580
581TEST_F(DragAndDrop, during_drag_when_user_moves_mouse_client_receives_handle)
582{
583 auto const cookie = user_initiates_drag();
584 ASSERT_THAT(cookie, NotNull());
585 auto const handle_from_request = client_requests_drag(cookie);
586
587 auto const handle = handle_from_mouse_move();
588
589 EXPECT_THAT(handle, NotNull());
590 EXPECT_THAT(handle, BlobContentEq(handle_from_request));
591}
592
593TEST_F(DragAndDrop, when_drag_moves_from_window_leave_event_contains_handle)
594{
595 auto const cookie = user_initiates_drag();
596 ASSERT_THAT(cookie, NotNull());
597 auto const handle_from_request = client_requests_drag(cookie);
598
599 auto const handle = handle_from_mouse_leave();
600
601 EXPECT_THAT(handle, NotNull());
602 EXPECT_THAT(handle, BlobContentEq(handle_from_request));
603}
604
605TEST_F(DragAndDrop, when_drag_enters_target_window_enter_event_contains_handle)
606{
607 auto const cookie = user_initiates_drag();
608 ASSERT_THAT(cookie, NotNull());
609 auto const handle_from_request = client_requests_drag(cookie);
610
611 auto const handle = handle_from_mouse_enter();
612
613 EXPECT_THAT(handle, NotNull());
614 EXPECT_THAT(handle, BlobContentEq(handle_from_request));
615}
616
617TEST_F(DragAndDrop, when_drag_releases_target_window_release_event_contains_handle)
618{
619 auto const cookie = user_initiates_drag();
620 ASSERT_THAT(cookie, NotNull());
621 auto const handle_from_request = client_requests_drag(cookie);
622
623 auto const handle = handle_from_mouse_release();
624
625 EXPECT_THAT(handle, NotNull());
626 EXPECT_THAT(handle, BlobContentEq(handle_from_request));
627}
628
629TEST_F(DragAndDrop, after_drag_finishes_pointer_events_no_longer_contain_handle)
630{
631 auto const cookie = user_initiates_drag();
632 ASSERT_THAT(cookie, NotNull());
633 client_requests_drag(cookie);
634 handle_from_mouse_release();
635
636 invoke_tools([](miral::WindowManagerTools& tools) { tools.end_drag_and_drop(); });
637
638 EXPECT_THAT(count_of_handles_when_moving_mouse(), Eq(0));
639}

Subscribers

People subscribed via source and target branches