Mir

Merge lp:~alan-griffiths/mir/client-initiates-user-move-and-resize into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 4129
Proposed branch: lp:~alan-griffiths/mir/client-initiates-user-move-and-resize
Merge into: lp:mir
Prerequisite: lp:~alan-griffiths/mir/request-with-authority
Diff against target: 385 lines (+293/-0)
9 files modified
include/client/mir_toolkit/mir_window.h (+9/-0)
src/client/mir_surface.cpp (+5/-0)
src/client/mir_surface.h (+1/-0)
src/client/mir_surface_api.cpp (+14/-0)
src/client/symbols.map (+2/-0)
src/protobuf/mir_protobuf.proto (+1/-0)
tests/acceptance-tests/CMakeLists.txt (+1/-0)
tests/acceptance-tests/client_mediated_user_gestures.cpp (+259/-0)
tests/acceptance-tests/drag_and_drop.cpp (+1/-0)
To merge this branch: bzr merge lp:~alan-griffiths/mir/client-initiates-user-move-and-resize
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve
Gerry Boland (community) Abstain
Daniel van Vugt Abstain
Chris Halse Rogers Approve
Andreas Pokorny (community) Approve
Review via email: mp+320917@code.launchpad.net

Commit message

Client side and initial tests for a client initiating a user move gesture

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

PASSED: Continuous integration, rev:4112
https://mir-jenkins.ubuntu.com/job/mir-ci/3238/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4358
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4445
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4435
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4435
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4435
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4390
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4390/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/4390
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4390/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4390
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4390/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/4390
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4390/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4390
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4390/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/4390
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4390/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I've linked the 'move' bug 1420334.

But why write more code for client-initiated resizing? That already works :)

review: Needs Information
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

As an example of a self-resizing client, try 'tiled' which has a resize grip in the bottom right corner. It already works.

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

> I've linked the 'move' bug 1420334.
>
> But why write more code for client-initiated resizing? That already works :)

No it doesn't. ;)

I agree clients can resize, but they can't request the shell to initiate a resize gesture. There is no way to invoke the touch resize handles under U8, drag the left edge or top.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

That's true, but the feature you're talking about in Unity7 also does not have resize handles (right click titlebar and then Resize, or just Alt+F8).

So either the client initiates the resize, and that works perfectly already; or
the server initiates resize, and that works perfectly already too.

Even if you did want it to pop up the resize handles, that's still a shell operation since the window menu itself is part of the shell. Not part of the client.

I think this branch should be just about movement.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

There is a difference between submitting a buffer with a different size, and resizing a window. So if we want to support CSD, this change is necessary.

review: Approve
Revision history for this message
Gerry Boland (gerboland) wrote :

How is this API to be used by the client? I.e. where is the client specifying the new size/position?

Is it that the client gets a mouseDown event with a cookie that it decides should cause a resize/move, so calls the mir_window_request_user_resize with that cookie. Then
(a) shell intercepts all other input events, instead sending resize events to the client? Or
(b) shell keep sending the mouseMove events to the client, and client resizes its window/buffer as it pleases (WM can restrict those choices though)?
On resize completion, mouseUp event finally sent to client?

If a user wants to resize the top-left corner of a window, is that a move & resize? Should that be an atomic operation instead?

The only reason I see that Mir's current window resize api is insufficient for client-size-initiated-resize is the cursor - we want the cursor to be the shell-themed resize image, and to remain that image even if the cursor moves beyond the window borders.

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

> How is this API to be used by the client? I.e. where is the client specifying
> the new size/position?

The client isn't specifying the position or size. It is requesting the shell treats an input event as the beginning of a gesture.

> Is it that the client gets a mouseDown event with a cookie that it decides
> should cause a resize/move, so calls the mir_window_request_user_resize with
> that cookie. Then
> (a) shell intercepts all other input events, instead sending resize events to
> the client? Or
> (b) shell keep sending the mouseMove events to the client, and client resizes
> its window/buffer as it pleases (WM can restrict those choices though)?
> On resize completion, mouseUp event finally sent to client?

(a)

> If a user wants to resize the top-left corner of a window, is that a move &
> resize? Should that be an atomic operation instead?

That's an atomic operation in those shells that currently support it. Initiating the resize through a client API shouldn't change that.

> The only reason I see that Mir's current window resize api is insufficient for
> client-size-initiated-resize is the cursor - we want the cursor to be the
> shell-themed resize image, and to remain that image even if the cursor moves
> beyond the window borders.

Hmm, I can see it will be easier to reach consensus on the USER_MOVE codepath. Maybe I should split that out?

Revision history for this message
William Hua (attente) wrote :

Andreas is right, even if we can change the buffer size, this isn't the same as requesting a resize operation from an input event.

In gtk, we have this api we're expected to implement:

https://git.gnome.org/browse/gtk+/tree/gdk/gdkwindow.c#n8649

So for mir_window_request_user_resize(), I'd expect it to be able to at least accept a directional argument that allows us to do a fixed resize in a certain direction. I believe there should also be special semantics if the client doesn't specify any direction, where the server should decide that based on the initial mouse motion or initial arrow key press.

I wouldn't expect the client to get a mouse up event on completion of the resize, or any events other than resize ones during the client's resizing. So from Gerry's comment, (a) is the most sensible for us in gtk, especially from the api's point of view. If there's non-resizable windows, the server should already know that from the time the window was created, and just reject any resize operation in that case.

It also needs to be implemented so that the user can also resize using the keyboard arrow keys as well.

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

> Hmm, I can see it will be easier to reach consensus on the USER_MOVE codepath.
> Maybe I should split that out?

OK, I'm dropping the resize code from this MP as it clearly needs further consideration.

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

PASSED: Continuous integration, rev:4115
https://mir-jenkins.ubuntu.com/job/mir-ci/3253/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4381
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4470
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4460
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4460
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4460
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4413
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4413/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/4413
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4413/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4413
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4413/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/4413
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4413/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/4413
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4413/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/4413
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4413/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

This seems sensible to me.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

*shrug*

My request has been satisfied but I would hazard a guess this functionality may take us a few attempts to cover all the major use cases.

review: Abstain
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I'm fairly sure we need zero more work done on resizing. All the resizing use cases are covered by existing APIs.

On the topic of client-initiated movement though, please start thinking about the Chrome/Chromium use case too: You drag a tab out of the window, that then creates a new window where the cursor remains on the same relative tab coordinate in the new window. If it's not baked in to the drag action then we'll need to be able to create that new top-level window at a precise coordinate relative to the old window (which may be the parent but can also be closed leaving just the child open).

Revision history for this message
Gerry Boland (gerboland) wrote :

No objections here

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

FAILED: Autolanding.
More details in the following jenkins job:
https://mir-jenkins.ubuntu.com/job/mir-autolanding/1243/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4408/console
    None: https://mir-jenkins.ubuntu.com/job/generic-land-mp/1312/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4500/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4490/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4490/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4490/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4440/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4440/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4440/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4440/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4440/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4440/console

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

04:02:04 Text conflict in src/client/mir_surface.cpp
04:02:04 1 conflicts encountered.

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

PASSED: Continuous integration, rev:4116
https://mir-jenkins.ubuntu.com/job/mir-ci/3277/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4418
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4510
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4500
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4500
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4500
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4450/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/4450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4450/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4450/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/4450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4450/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/4450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4450/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/4450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4450/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/client/mir_toolkit/mir_window.h'
--- include/client/mir_toolkit/mir_window.h 2017-03-14 04:41:33 +0000
+++ include/client/mir_toolkit/mir_window.h 2017-03-29 08:37:58 +0000
@@ -738,6 +738,15 @@
738void mir_window_raise(MirWindow* window, MirCookie const* cookie);738void mir_window_raise(MirWindow* window, MirCookie const* cookie);
739739
740/**740/**
741 * Informs the window manager that the user is moving the window.
742 *
743 * \param [in] window The window to move
744 * \param [in] cookie A cookie instance obtained from an input event.
745 * An invalid cookie will terminate the client connection.
746 */
747void mir_window_request_user_move(MirWindow* window, MirCookie const* cookie);
748
749/**
741 * Get the type (purpose) of a window.750 * Get the type (purpose) of a window.
742 * \param [in] window The window to query751 * \param [in] window The window to query
743 * \return The type of the window752 * \return The type of the window
744753
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2017-03-28 14:28:26 +0000
+++ src/client/mir_surface.cpp 2017-03-29 08:37:58 +0000
@@ -588,6 +588,11 @@
588 request_operation(cookie, mp::RequestOperation::MAKE_ACTIVE);588 request_operation(cookie, mp::RequestOperation::MAKE_ACTIVE);
589}589}
590590
591void MirSurface::request_user_move(MirCookie const* cookie)
592{
593 request_operation(cookie, mp::RequestOperation::USER_MOVE);
594}
595
591void MirSurface::request_drag_and_drop(MirCookie const* cookie)596void MirSurface::request_drag_and_drop(MirCookie const* cookie)
592{597{
593 request_operation(cookie, mp::RequestOperation::START_DRAG_AND_DROP);598 request_operation(cookie, mp::RequestOperation::START_DRAG_AND_DROP);
594599
=== modified file 'src/client/mir_surface.h'
--- src/client/mir_surface.h 2017-03-28 14:28:26 +0000
+++ src/client/mir_surface.h 2017-03-29 08:37:58 +0000
@@ -200,6 +200,7 @@
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_user_move(MirCookie const* cookie);
203 void request_drag_and_drop(MirCookie const* cookie);204 void request_drag_and_drop(MirCookie const* cookie);
204 void set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback);205 void set_drag_and_drop_start_handler(std::function<void(MirWindowEvent const*)> const& callback);
205206
206207
=== modified file 'src/client/mir_surface_api.cpp'
--- src/client/mir_surface_api.cpp 2017-03-14 04:41:33 +0000
+++ src/client/mir_surface_api.cpp 2017-03-29 08:37:58 +0000
@@ -695,6 +695,20 @@
695 }695 }
696}696}
697697
698void mir_window_request_user_move(MirWindow* window, MirCookie const* cookie)
699{
700 mir::require(mir_window_is_valid(window));
701
702 try
703 {
704 window->request_user_move(cookie);
705 }
706 catch (std::exception const& ex)
707 {
708 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
709 }
710}
711
698MirWindowType mir_window_get_type(MirWindow* window)712MirWindowType mir_window_get_type(MirWindow* window)
699{713{
700 MirWindowType type = mir_window_type_normal;714 MirWindowType type = mir_window_type_normal;
701715
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2017-03-28 11:32:58 +0000
+++ src/client/symbols.map 2017-03-29 08:37:58 +0000
@@ -604,6 +604,8 @@
604 mir_keyboard_event_key_text;604 mir_keyboard_event_key_text;
605 mir_output_get_logical_height;605 mir_output_get_logical_height;
606 mir_output_get_logical_width;606 mir_output_get_logical_width;
607 mir_window_request_user_move;
608 mir_window_request_user_resize;
607 mir_touchscreen_config_get_mapping_mode;609 mir_touchscreen_config_get_mapping_mode;
608 mir_touchscreen_config_get_output_id;610 mir_touchscreen_config_get_output_id;
609 mir_touchscreen_config_set_mapping_mode;611 mir_touchscreen_config_set_mapping_mode;
610612
=== modified file 'src/protobuf/mir_protobuf.proto'
--- src/protobuf/mir_protobuf.proto 2017-03-23 15:00:37 +0000
+++ src/protobuf/mir_protobuf.proto 2017-03-29 08:37:58 +0000
@@ -443,6 +443,7 @@
443 UNKNOWN = 0;443 UNKNOWN = 0;
444 START_DRAG_AND_DROP = 1;444 START_DRAG_AND_DROP = 1;
445 MAKE_ACTIVE = 2;445 MAKE_ACTIVE = 2;
446 USER_MOVE = 3;
446}447}
447448
448message RequestWithAuthority {449message RequestWithAuthority {
449450
=== modified file 'tests/acceptance-tests/CMakeLists.txt'
--- tests/acceptance-tests/CMakeLists.txt 2017-03-15 09:30:18 +0000
+++ tests/acceptance-tests/CMakeLists.txt 2017-03-29 08:37:58 +0000
@@ -3,6 +3,7 @@
3set(3set(
4 SOURCES4 SOURCES
55
6 client_mediated_user_gestures.cpp
6 drag_and_drop.cpp7 drag_and_drop.cpp
78
8 # Catch double-free bugs by wrapping close() and abort()ing on EBADF9 # Catch double-free bugs by wrapping close() and abort()ing on EBADF
910
=== added file 'tests/acceptance-tests/client_mediated_user_gestures.cpp'
--- tests/acceptance-tests/client_mediated_user_gestures.cpp 1970-01-01 00:00:00 +0000
+++ tests/acceptance-tests/client_mediated_user_gestures.cpp 2017-03-29 08:37:58 +0000
@@ -0,0 +1,259 @@
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/mir_window.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 <atomic>
39
40using namespace std::chrono_literals;
41using namespace mir::geometry;
42using namespace testing;
43using mir::test::Signal;
44
45namespace
46{
47class Cookie
48{
49public:
50 Cookie() = default;
51
52 explicit Cookie(MirCookie const* cookie) : self{cookie, deleter} {}
53
54 operator MirCookie const*() const { return self.get(); }
55
56 auto get() const -> MirCookie const* { return self.get(); }
57
58 void reset() { self.reset(); }
59
60 void reset(MirCookie const* cookie) { self.reset(cookie, deleter); }
61
62private:
63 static void deleter(MirCookie const* cookie) { mir_cookie_release(cookie); }
64
65 std::shared_ptr<MirCookie const> self;
66};
67
68void mir_cookie_release(Cookie const&) = delete;
69
70struct MouseMoverAndFaker
71{
72 void start_dragging_mouse()
73 {
74 using namespace mir::input::synthesis;
75 fake_mouse->emit_event(a_button_down_event().of_button(BTN_LEFT));
76 }
77
78 void move_mouse(Displacement const& displacement)
79 {
80 using mir::input::synthesis::a_pointer_event;
81 fake_mouse->emit_event(a_pointer_event().with_movement(displacement.dx.as_int(), displacement.dy.as_int()));
82 }
83
84 void release_mouse()
85 {
86 using namespace mir::input::synthesis;
87 fake_mouse->emit_event(a_button_up_event().of_button(BTN_LEFT));
88 }
89
90private:
91 std::unique_ptr<mir_test_framework::FakeInputDevice> fake_mouse{
92 mir_test_framework::add_fake_input_device(
93 mir::input::InputDeviceInfo{"mouse", "mouse-uid", mir::input::DeviceCapability::pointer})
94 };
95};
96
97Rectangle const screen_geometry{{0, 0}, {800, 600}};
98auto const receive_event_timeout = 90s;
99
100struct ClientMediatedUserGestures : mir_test_framework::ConnectedClientWithAWindow,
101 MouseMoverAndFaker
102{
103 void SetUp() override
104 {
105 initial_display_layout({screen_geometry});
106 mir_test_framework::ConnectedClientWithAWindow::SetUp();
107 mir_window_set_event_handler(window, &window_event_handler, this);
108
109 paint_window();
110
111 center_mouse();
112 }
113
114 void TearDown() override
115 {
116 reset_window_event_handler();
117 mir_test_framework::ConnectedClientWithAWindow::TearDown();
118 }
119
120 auto user_initiates_gesture() -> Cookie;
121
122private:
123 void center_mouse();
124 void paint_window();
125 void set_window_event_handler(std::function<void(MirEvent const* event)> const& handler);
126 void reset_window_event_handler();
127 void invoke_window_event_handler(MirEvent const* event)
128 {
129 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
130 window_event_handler_(event);
131 }
132
133 std::mutex window_event_handler_mutex;
134 std::function<void(MirEvent const* event)> window_event_handler_ = [](MirEvent const*) {};
135
136 static void window_event_handler(MirWindow* window, MirEvent const* event, void* context);
137};
138
139void ClientMediatedUserGestures::set_window_event_handler(std::function<void(MirEvent const* event)> const& handler)
140{
141 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
142 window_event_handler_ = handler;
143}
144
145void ClientMediatedUserGestures::reset_window_event_handler()
146{
147 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
148 window_event_handler_ = [](MirEvent const*) {};
149}
150
151void ClientMediatedUserGestures::window_event_handler(MirWindow* /*window*/, MirEvent const* event, void* context)
152{
153 static_cast<ClientMediatedUserGestures*>(context)->invoke_window_event_handler(event);
154}
155
156void ClientMediatedUserGestures::paint_window()
157{
158 Signal have_focus;
159
160 set_window_event_handler([&](MirEvent const* event)
161 {
162 if (mir_event_get_type(event) != mir_event_type_window)
163 return;
164
165 auto const window_event = mir_event_get_window_event(event);
166 if (mir_window_event_get_attribute(window_event) != mir_window_attrib_focus)
167 return;
168
169 if (mir_window_event_get_attribute_value(window_event))
170 have_focus.raise();
171 });
172
173 mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(window));
174
175 EXPECT_THAT(have_focus.wait_for(receive_event_timeout), Eq(true));
176
177 reset_window_event_handler();
178}
179
180void ClientMediatedUserGestures::center_mouse()
181{
182 Signal have_mouseover;
183
184 set_window_event_handler([&](MirEvent const* event)
185 {
186 if (mir_event_get_type(event) != mir_event_type_input)
187 return;
188
189 auto const input_event = mir_event_get_input_event(event);
190
191 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
192 return;
193
194 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
195
196 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_enter)
197 return;
198
199 have_mouseover.raise();
200 });
201
202 move_mouse(0.5 * as_displacement(screen_geometry.size));
203
204// We miss the "mouseover" occasionally (with valgrind and heavy stress about 1/20).
205// But it isn't essential for the test and we've probably waited long enough
206// for the mouse-down needed by the test to reach the window.
207// EXPECT_THAT(have_mouseover.wait_for(receive_event_timeout), Eq(true));
208 have_mouseover.wait_for(receive_event_timeout);
209
210 reset_window_event_handler();
211}
212
213auto ClientMediatedUserGestures::user_initiates_gesture() -> Cookie
214{
215 Cookie cookie;
216 Signal have_cookie;
217
218 set_window_event_handler([&](MirEvent const* event)
219 {
220 if (mir_event_get_type(event) != mir_event_type_input)
221 return;
222
223 auto const input_event = mir_event_get_input_event(event);
224
225 if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer)
226 return;
227
228 auto const pointer_event = mir_input_event_get_pointer_event(input_event);
229
230 if (mir_pointer_event_action(pointer_event) != mir_pointer_action_button_down)
231 return;
232
233 cookie = Cookie{mir_input_event_get_cookie(input_event)};
234 have_cookie.raise();
235 });
236
237 start_dragging_mouse();
238
239 EXPECT_THAT(have_cookie.wait_for(receive_event_timeout), Eq(true));
240
241 reset_window_event_handler();
242 return cookie;
243}
244}
245
246TEST_F(ClientMediatedUserGestures, when_user_initiates_gesture_client_receives_cookie)
247{
248 auto const cookie = user_initiates_gesture();
249
250 EXPECT_THAT(cookie.get(), NotNull());
251}
252
253// TODO extend this test when server side implemented
254TEST_F(ClientMediatedUserGestures, when_client_initiates_move_nothing_bad_happens)
255{
256 auto const cookie = user_initiates_gesture();
257
258 mir_window_request_user_move(window, cookie);
259}
0260
=== modified file 'tests/acceptance-tests/drag_and_drop.cpp'
--- tests/acceptance-tests/drag_and_drop.cpp 2017-03-17 15:32:15 +0000
+++ tests/acceptance-tests/drag_and_drop.cpp 2017-03-29 08:37:58 +0000
@@ -213,6 +213,7 @@
213213
214void DragAndDrop::reset_window_event_handler(MirWindow* window)214void DragAndDrop::reset_window_event_handler(MirWindow* window)
215{215{
216 std::lock_guard<decltype(window_event_handler_mutex)> lock{window_event_handler_mutex};
216 if (window == this->window) window_event_handler_ = [](MirEvent const*) {};217 if (window == this->window) window_event_handler_ = [](MirEvent const*) {};
217 if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {};218 if (window == target_window) target_window_event_handler_ = [](MirEvent const*) {};
218}219}

Subscribers

People subscribed via source and target branches