Mir

Merge lp:~andreas-pokorny/mir/08-csdi-forward-input-device-configuration-in-nested-server into lp:mir

Proposed by Andreas Pokorny
Status: Work in progress
Proposed branch: lp:~andreas-pokorny/mir/08-csdi-forward-input-device-configuration-in-nested-server
Merge into: lp:mir
Prerequisite: lp:~andreas-pokorny/mir/07-csdi-rpc-for-setting-input-device-configurations
Diff against target: 1138 lines (+516/-61)
23 files modified
include/platform/mir/input/pointer_settings.h (+7/-0)
include/platform/mir/input/touchpad_settings.h (+8/-0)
include/test/mir/test/event_matchers.h (+45/-0)
include/test/mir_test_framework/fake_input_device.h (+9/-1)
src/client/event_printer.cpp (+3/-3)
src/client/logging/rpc_report.cpp (+1/-1)
src/server/graphics/nested/host_connection.h (+1/-0)
src/server/graphics/nested/input_platform.cpp (+105/-12)
src/server/graphics/nested/mir_client_host_connection.cpp (+5/-0)
src/server/graphics/nested/mir_client_host_connection.h (+1/-0)
src/server/input/surface_input_dispatcher.cpp (+44/-1)
src/server/scene/surface_stack.cpp (+0/-2)
src/server/shell/abstract_shell.cpp (+1/-0)
tests/acceptance-tests/test_client_cookie.cpp (+1/-2)
tests/acceptance-tests/test_client_input.cpp (+10/-17)
tests/acceptance-tests/test_confined_pointer.cpp (+4/-8)
tests/acceptance-tests/test_nested_input.cpp (+197/-4)
tests/include/mir/test/doubles/stub_host_connection.h (+5/-0)
tests/mir_test_doubles/fake_display.cpp (+1/-0)
tests/mir_test_framework/fake_input_device_impl.cpp (+12/-1)
tests/mir_test_framework/fake_input_device_impl.h (+3/-0)
tests/unit-tests/input/test_nested_input_platform.cpp (+50/-0)
tests/unit-tests/input/test_surface_input_dispatcher.cpp (+3/-9)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/08-csdi-forward-input-device-configuration-in-nested-server
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve
Mir development team Pending
Review via email: mp+310644@code.launchpad.net

Commit message

nested: Forward input device configuration changes

Description of the change

Add the necessary pieces to forward input device changes inside the nested platform.

This branch has two prerequisites, the other one can be found here:
lp:~andreas-pokorny/mir/fix-1639749

To post a comment you must log in.
3805. By Andreas Pokorny

merge prereq

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

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

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

review: Needs Fixing (continuous-integration)
3806. By Andreas Pokorny

merge prereq fixes

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

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

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

review: Approve (continuous-integration)
3807. By Andreas Pokorny

merge conflict resolution from prereq

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

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

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

review: Approve (continuous-integration)
3808. By Andreas Pokorny

merge fixes from prerequisite branch

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

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

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

review: Approve (continuous-integration)

Unmerged revisions

3808. By Andreas Pokorny

merge fixes from prerequisite branch

3807. By Andreas Pokorny

merge conflict resolution from prereq

3806. By Andreas Pokorny

merge prereq fixes

3805. By Andreas Pokorny

merge prereq

3804. By Andreas Pokorny

merge protobuf changes..

3803. By Andreas Pokorny

merge nested startup fixes

3802. By Andreas Pokorny

remove debug print statements

3801. By Andreas Pokorny

merge prereq

3800. By Andreas Pokorny

WIP to fix acceptance test

3799. By Andreas Pokorny

merge prereq

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/platform/mir/input/pointer_settings.h'
2--- include/platform/mir/input/pointer_settings.h 2016-01-29 08:18:22 +0000
3+++ include/platform/mir/input/pointer_settings.h 2016-11-18 09:53:54 +0000
4@@ -56,6 +56,13 @@
5 double vertical_scroll_scale{1.0};
6 };
7
8+inline bool operator==(PointerSettings const& lhs, PointerSettings const& rhs)
9+{
10+ return lhs.handedness == rhs.handedness && lhs.cursor_acceleration_bias == rhs.cursor_acceleration_bias &&
11+ lhs.acceleration == rhs.acceleration && lhs.horizontal_scroll_scale == rhs.horizontal_scroll_scale &&
12+ lhs.vertical_scroll_scale == rhs.vertical_scroll_scale;
13+}
14+
15 }
16 }
17
18
19=== modified file 'include/platform/mir/input/touchpad_settings.h'
20--- include/platform/mir/input/touchpad_settings.h 2015-10-23 09:53:17 +0000
21+++ include/platform/mir/input/touchpad_settings.h 2016-11-18 09:53:54 +0000
22@@ -40,6 +40,14 @@
23 bool middle_mouse_button_emulation{true};
24 };
25
26+inline bool operator==(TouchpadSettings const& lhs, TouchpadSettings const& rhs)
27+{
28+ return lhs.click_mode == rhs.click_mode && lhs.scroll_mode == rhs.scroll_mode &&
29+ lhs.button_down_scroll_button == rhs.button_down_scroll_button && lhs.tap_to_click == rhs.tap_to_click &&
30+ lhs.disable_while_typing == rhs.disable_while_typing && lhs.disable_with_mouse == rhs.disable_with_mouse &&
31+ lhs.middle_mouse_button_emulation == rhs.middle_mouse_button_emulation;
32+}
33+
34 }
35 }
36
37
38=== modified file 'include/test/mir/test/event_matchers.h'
39--- include/test/mir/test/event_matchers.h 2016-11-11 07:56:09 +0000
40+++ include/test/mir/test/event_matchers.h 2016-11-18 09:53:54 +0000
41@@ -377,6 +377,21 @@
42 return true;
43 }
44
45+MATCHER_P2(PointerEnterEventWithPosition, x, y, "")
46+{
47+ auto pev = maybe_pointer_event(to_address(arg));
48+ if (pev == nullptr)
49+ return false;
50+ if (mir_pointer_event_action(pev) != mir_pointer_action_enter)
51+ return false;
52+ if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != x)
53+ return false;
54+ if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != y)
55+ return false;
56+ return true;
57+}
58+
59+
60 MATCHER_P(PointerEventWithModifiers, modifiers, "")
61 {
62 auto pev = maybe_pointer_event(to_address(arg));
63@@ -404,6 +419,26 @@
64 return true;
65 }
66
67+MATCHER_P2(PointerEnterEventWithDiff, expect_dx, expect_dy, "")
68+{
69+ auto pev = maybe_pointer_event(to_address(arg));
70+ if (pev == nullptr)
71+ return false;
72+ if (mir_pointer_event_action(pev) != mir_pointer_action_enter)
73+ return false;
74+ auto const error = 0.00001f;
75+ auto const actual_dx = mir_pointer_event_axis_value(pev,
76+ mir_pointer_axis_relative_x);
77+ if (std::abs(expect_dx - actual_dx) > error)
78+ return false;
79+ auto const actual_dy = mir_pointer_event_axis_value(pev,
80+ mir_pointer_axis_relative_y);
81+ if (std::abs(expect_dy - actual_dy) > error)
82+ return false;
83+ return true;
84+}
85+
86+
87 MATCHER_P4(TouchEventInDirection, x0, y0, x1, y1, "")
88 {
89 auto tev = maybe_touch_event(to_address(arg));
90@@ -541,6 +576,16 @@
91 return false;
92 }
93
94+MATCHER_P2(DeviceStateWithPosition, x, y, "")
95+{
96+ auto as_address = to_address(arg);
97+ if (mir_event_get_type(as_address) != mir_event_type_input_device_state)
98+ return false;
99+ auto device_state = mir_event_get_input_device_state_event(as_address);
100+ return x == mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_x) &&
101+ y == mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_y);
102+}
103+
104 }
105 }
106
107
108=== modified file 'include/test/mir_test_framework/fake_input_device.h'
109--- include/test/mir_test_framework/fake_input_device.h 2016-10-31 02:37:31 +0000
110+++ include/test/mir_test_framework/fake_input_device.h 2016-11-18 09:53:54 +0000
111@@ -24,6 +24,13 @@
112 #include <chrono>
113 #include <functional>
114
115+namespace mir
116+{
117+namespace input
118+{
119+class InputDevice;
120+}
121+}
122 namespace mir_test_framework
123 {
124
125@@ -42,7 +49,6 @@
126 FakeInputDevice() = default;
127 virtual ~FakeInputDevice() = default;
128
129-
130 virtual void emit_device_removal() = 0;
131 virtual void emit_runtime_error() = 0;
132 virtual void emit_event(mir::input::synthesis::KeyParameters const& key) = 0;
133@@ -52,6 +58,8 @@
134 virtual void emit_touch_sequence(std::function<mir::input::synthesis::TouchParameters(int)> const& generate_parameters,
135 int count,
136 std::chrono::duration<double> delay) = 0;
137+ virtual void on_configuration_change(
138+ std::function<void(mir::input::InputDevice const&)> const& callback) = 0;
139
140 FakeInputDevice(FakeInputDevice const&) = delete;
141 FakeInputDevice& operator=(FakeInputDevice const&) = delete;
142
143=== modified file 'src/client/event_printer.cpp'
144--- src/client/event_printer.cpp 2016-11-11 06:59:42 +0000
145+++ src/client/event_printer.cpp 2016-11-18 09:53:54 +0000
146@@ -218,7 +218,7 @@
147 << mir_keyboard_event_action(key_event)
148 << ", code=" << mir_keyboard_event_key_code(key_event)
149 << ", scan=" << mir_keyboard_event_scan_code(key_event) << ", modifiers=" << std::hex
150- << mir_keyboard_event_modifiers(key_event) << std::dec << ')';
151+ << static_cast<MirInputEventModifier>(mir_keyboard_event_modifiers(key_event)) << std::dec << ')';
152 }
153 case mir_input_event_type_touch:
154 {
155@@ -236,7 +236,7 @@
156 << ", minor=" << mir_touch_event_axis_value(touch_event, index, mir_touch_axis_touch_minor)
157 << ", size=" << mir_touch_event_axis_value(touch_event, index, mir_touch_axis_size) << '}';
158
159- return out << ", modifiers=" << mir_touch_event_modifiers(touch_event) << ')';
160+ return out << ", modifiers=" << static_cast<MirInputEventModifier>(mir_touch_event_modifiers(touch_event)) << ')';
161 }
162 case mir_input_event_type_pointer:
163 {
164@@ -255,7 +255,7 @@
165 << ", dy=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y)
166 << ", vscroll=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll)
167 << ", hscroll=" << mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll)
168- << ", modifiers=" << mir_pointer_event_modifiers(pointer_event) << ')';
169+ << ", modifiers=" << static_cast<MirInputEventModifier>(mir_pointer_event_modifiers(pointer_event)) << ')';
170 }
171 default:
172 return out << "<INVALID>";
173
174=== modified file 'src/client/logging/rpc_report.cpp'
175--- src/client/logging/rpc_report.cpp 2016-11-18 09:53:53 +0000
176+++ src/client/logging/rpc_report.cpp 2016-11-18 09:53:54 +0000
177@@ -154,7 +154,7 @@
178 std::stringstream ss;
179 ss << "Input device information received: ";
180 for (auto info : event.device_info())
181- ss << info.id() << ":" << info.name() << " ";
182+ ss << info.id() << ":" << info.name() << "-" << info.unique_id() << " ";
183
184 logger->log(ml::Severity::debug, ss.str(), component);
185 }
186
187=== modified file 'src/server/graphics/nested/host_connection.h'
188--- src/server/graphics/nested/host_connection.h 2016-10-31 02:37:31 +0000
189+++ src/server/graphics/nested/host_connection.h 2016-11-18 09:53:54 +0000
190@@ -78,6 +78,7 @@
191 virtual void emit_input_event(MirEvent const& event, mir::geometry::Rectangle const& source_frame) = 0;
192 virtual std::shared_ptr<NativeBuffer> create_buffer(graphics::BufferProperties const&) = 0;
193 virtual bool supports_passthrough() = 0;
194+ virtual void apply_input_device_configuration(MirInputDevice const* device) = 0;
195
196 protected:
197 HostConnection() = default;
198
199=== modified file 'src/server/graphics/nested/input_platform.cpp'
200--- src/server/graphics/nested/input_platform.cpp 2016-11-11 06:59:42 +0000
201+++ src/server/graphics/nested/input_platform.cpp 2016-11-18 09:53:54 +0000
202@@ -39,6 +39,13 @@
203 namespace
204 {
205
206+auto filter_pointer_action(MirPointerAction action)
207+{
208+ return (action == mir_pointer_action_enter || action == mir_pointer_action_leave)
209+ ? mir_pointer_action_motion
210+ : action;
211+}
212+
213 mgn::UniqueInputConfig make_empty_config()
214 {
215 return mgn::UniqueInputConfig(nullptr, [](MirInputConfig const*){});
216@@ -49,7 +56,8 @@
217 struct mgn::InputPlatform::InputDevice : mi::InputDevice
218 {
219 public:
220- InputDevice(MirInputDevice const* dev)
221+ InputDevice(MirInputDevice* dev, std::function<void(MirInputDevice const* config)> config_change)
222+ : emit_device_change{config_change}
223 {
224 update(dev);
225 }
226@@ -59,12 +67,59 @@
227 return device_id;
228 }
229
230- void update(MirInputDevice const* dev)
231- {
232+ mir::optional_value<mi::PointerSettings> to_pointer_settings(MirInputDevice const* dev)
233+ {
234+ mir::optional_value<mi::PointerSettings> opt_settings;
235+
236+ auto conf = mir_input_device_get_pointer_configuration(dev);
237+
238+ if (conf)
239+ {
240+ mi::PointerSettings settings;
241+ settings.handedness = mir_pointer_configuration_get_handedness(conf);
242+ settings.acceleration = mir_pointer_configuration_get_acceleration(conf);
243+ settings.cursor_acceleration_bias = mir_pointer_configuration_get_acceleration_bias(conf);
244+ settings.horizontal_scroll_scale = mir_pointer_configuration_get_horizontal_scroll_scale(conf);
245+ settings.vertical_scroll_scale = mir_pointer_configuration_get_vertical_scroll_scale(conf);
246+
247+ opt_settings = settings;
248+ }
249+ return opt_settings;
250+ }
251+
252+ mir::optional_value<mi::TouchpadSettings> to_touchpad_settings(MirInputDevice const* dev)
253+ {
254+ mir::optional_value<mi::TouchpadSettings> opt_settings;
255+
256+ auto conf = mir_input_device_get_touchpad_configuration(dev);
257+
258+ if (conf)
259+ {
260+ mi::TouchpadSettings settings;
261+ settings.click_mode = mir_touchpad_configuration_get_click_modes(conf);
262+ settings.scroll_mode = mir_touchpad_configuration_get_scroll_modes(conf);
263+ settings.button_down_scroll_button = mir_touchpad_configuration_get_button_down_scroll_button(conf);
264+ settings.tap_to_click = mir_touchpad_configuration_get_tap_to_click(conf);
265+ settings.disable_while_typing = mir_touchpad_configuration_get_disable_while_typing(conf);
266+ settings.disable_with_mouse = mir_touchpad_configuration_get_disable_with_mouse(conf);
267+ settings.middle_mouse_button_emulation = mir_touchpad_configuration_get_middle_mouse_button_emulation(conf);
268+
269+ opt_settings = settings;
270+ }
271+ return opt_settings;
272+
273+ }
274+
275+ void update(MirInputDevice* dev)
276+ {
277+ device = dev;
278 device_id = mir_input_device_get_id(dev);
279 device_info.name = mir_input_device_get_name(dev);
280 device_info.unique_id = mir_input_device_get_unique_id(dev);
281+
282 device_info.capabilities = mi::DeviceCapabilities(mir_input_device_get_capabilities(dev));
283+ pointer_settings = to_pointer_settings(dev);
284+ touchpad_settings = to_touchpad_settings(dev);
285 }
286
287 void start(mi::InputSink* destination, mi::EventBuilder* builder) override
288@@ -122,7 +177,7 @@
289 auto y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
290 auto new_event = builder->pointer_event(
291 event_time,
292- mir_pointer_event_action(pointer_event),
293+ filter_pointer_action(mir_pointer_event_action(pointer_event)),
294 mir_pointer_event_buttons(pointer_event),
295 x + frame.top_left.x.as_int(),
296 y + frame.top_left.y.as_int(),
297@@ -156,9 +211,23 @@
298 return pointer_settings;
299 }
300
301- void apply_settings(mi::PointerSettings const&) override
302+ void apply_settings(mi::PointerSettings const& new_settings) override
303 {
304- // TODO no C API for that
305+ if (pointer_settings.is_set() && pointer_settings.value() == new_settings)
306+ return;
307+
308+ auto ptr_conf = mir_input_device_get_mutable_pointer_configuration(device);
309+
310+ if (ptr_conf)
311+ {
312+ mir_pointer_configuration_set_acceleration(ptr_conf, new_settings.acceleration);
313+ mir_pointer_configuration_set_acceleration_bias(ptr_conf, new_settings.cursor_acceleration_bias);
314+ mir_pointer_configuration_set_handedness(ptr_conf, new_settings.handedness);
315+ mir_pointer_configuration_set_vertical_scroll_scale(ptr_conf, new_settings.vertical_scroll_scale);
316+ mir_pointer_configuration_set_horizontal_scroll_scale(ptr_conf, new_settings.horizontal_scroll_scale);
317+
318+ emit_device_change(device);
319+ }
320 }
321
322 mir::optional_value<mi::TouchpadSettings> get_touchpad_settings() const override
323@@ -166,24 +235,45 @@
324 return touchpad_settings;
325 }
326
327- void apply_settings(mi::TouchpadSettings const&) override
328+ void apply_settings(mi::TouchpadSettings const& new_settings) override
329 {
330- // no c api for that
331+ if (touchpad_settings.is_set() && touchpad_settings.value() == new_settings)
332+ return;
333+
334+ auto tpd_conf = mir_input_device_get_mutable_touchpad_configuration(device);
335+
336+ if (tpd_conf)
337+ {
338+ mir_touchpad_configuration_set_click_modes(tpd_conf, new_settings.click_mode);
339+ mir_touchpad_configuration_set_scroll_modes(tpd_conf, new_settings.scroll_mode);
340+ mir_touchpad_configuration_set_button_down_scroll_button(tpd_conf, new_settings.button_down_scroll_button);
341+ mir_touchpad_configuration_set_tap_to_click(tpd_conf, new_settings.tap_to_click);
342+ mir_touchpad_configuration_set_disable_with_mouse(tpd_conf, new_settings.disable_with_mouse);
343+ mir_touchpad_configuration_set_disable_while_typing(tpd_conf, new_settings.disable_while_typing);
344+ mir_touchpad_configuration_set_middle_mouse_button_emulation(tpd_conf, new_settings.middle_mouse_button_emulation);
345+
346+ emit_device_change(device);
347+ }
348 }
349
350+ MirInputDevice* device;
351 MirInputDeviceId device_id;
352 mi::InputSink* destination{nullptr};
353 mi::EventBuilder* builder{nullptr};
354 mi::InputDeviceInfo device_info;
355 mir::optional_value<mi::PointerSettings> pointer_settings;
356 mir::optional_value<mi::TouchpadSettings> touchpad_settings;
357+ std::function<void(MirInputDevice const*)> emit_device_change;
358 };
359
360-
361 mgn::InputPlatform::InputPlatform(std::shared_ptr<HostConnection> const& connection,
362 std::shared_ptr<input::InputDeviceRegistry> const& input_device_registry,
363 std::shared_ptr<input::InputReport> const& report)
364- : connection{connection}, input_device_registry{input_device_registry}, report{report}, action_queue{std::make_shared<dispatch::ActionQueue>()}, input_config{make_empty_config()}
365+ : connection{connection},
366+ input_device_registry{input_device_registry},
367+ report{report},
368+ action_queue{std::make_shared<dispatch::ActionQueue>()},
369+ input_config{make_empty_config()}
370 {
371 }
372
373@@ -294,7 +384,7 @@
374 auto config_ptr = input_config.get();
375 for (size_t i = 0, e = mir_input_config_device_count(config_ptr); i!=e; ++i)
376 {
377- auto dev = mir_input_config_get_device(config_ptr, i);
378+ auto dev = mir_input_config_get_mutable_device(config_ptr, i);
379 auto const id = mir_input_device_get_id(dev);
380 auto it = deleted.find(id);
381 if (it != end(deleted))
382@@ -305,7 +395,10 @@
383 }
384 else
385 {
386- new_devs.emplace_back(std::make_shared<InputDevice>(dev), id);
387+ new_devs.emplace_back(
388+ std::make_shared<InputDevice>(
389+ dev, [this](MirInputDevice const* dev) { connection->apply_input_device_configuration(dev); }),
390+ id);
391 devices[id] = new_devs.back().first;
392 }
393 }
394
395=== modified file 'src/server/graphics/nested/mir_client_host_connection.cpp'
396--- src/server/graphics/nested/mir_client_host_connection.cpp 2016-11-16 14:27:15 +0000
397+++ src/server/graphics/nested/mir_client_host_connection.cpp 2016-11-18 09:53:54 +0000
398@@ -460,6 +460,11 @@
399 return make_input_config(mir_connection);
400 }
401
402+void mgn::MirClientHostConnection::apply_input_device_configuration(MirInputDevice const* device)
403+{
404+ mir_connection_apply_input_device_configuration(mir_connection, device);
405+}
406+
407 void mgn::MirClientHostConnection::set_input_device_change_callback(std::function<void(UniqueInputConfig)> const& cb)
408 {
409 RecursiveWriteLock lock{input_config_callback_mutex};
410
411=== modified file 'src/server/graphics/nested/mir_client_host_connection.h'
412--- src/server/graphics/nested/mir_client_host_connection.h 2016-11-16 13:24:41 +0000
413+++ src/server/graphics/nested/mir_client_host_connection.h 2016-11-18 09:53:54 +0000
414@@ -87,6 +87,7 @@
415 void emit_input_event(MirEvent const& cb, mir::geometry::Rectangle const& source_frame) override;
416 std::shared_ptr<NativeBuffer> create_buffer(graphics::BufferProperties const&) override;
417 bool supports_passthrough() override;
418+ void apply_input_device_configuration(MirInputDevice const* device) override;
419
420 private:
421 void update_input_config(UniqueInputConfig input_config);
422
423=== modified file 'src/server/input/surface_input_dispatcher.cpp'
424--- src/server/input/surface_input_dispatcher.cpp 2016-11-11 07:56:09 +0000
425+++ src/server/input/surface_input_dispatcher.cpp 2016-11-18 09:53:54 +0000
426@@ -23,6 +23,7 @@
427 #include "mir/scene/observer.h"
428 #include "mir/scene/surface.h"
429 #include "mir/events/event_builders.h"
430+#include "mir_toolkit/mir_cookie.h"
431
432 #include <string.h>
433
434@@ -69,6 +70,37 @@
435 std::function<void(ms::Surface*)> const on_removed;
436 };
437
438+void deliver_without_relative_motion(std::shared_ptr<mi::Surface> const& surface, MirEvent const* ev)
439+{
440+ auto const* input_ev = mir_event_get_input_event(ev);
441+ auto const* pev = mir_input_event_get_pointer_event(input_ev);
442+ std::vector<uint8_t> cookie_data;
443+ if (mir_input_event_has_cookie(input_ev))
444+ {
445+ auto cookie = mir_input_event_get_cookie(input_ev);
446+ cookie_data.resize(mir_cookie_buffer_size(cookie));
447+ mir_cookie_to_buffer(cookie, cookie_data.data(), mir_cookie_buffer_size(cookie));
448+ mir_cookie_release(cookie);
449+ }
450+ auto const& bounds = surface->input_bounds();
451+
452+ auto to_deliver = mev::make_event(mir_input_event_get_device_id(input_ev),
453+ std::chrono::nanoseconds{mir_input_event_get_event_time(input_ev)},
454+ cookie_data,
455+ mir_pointer_event_modifiers(pev),
456+ mir_pointer_event_action(pev),
457+ mir_pointer_event_buttons(pev),
458+ mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
459+ mir_pointer_event_axis_value(pev, mir_pointer_axis_y),
460+ 0.0f,
461+ 0.0f,
462+ 0.0f,
463+ 0.0f);
464+
465+ mev::transform_positions(*to_deliver, geom::Displacement{bounds.top_left.x.as_int(), bounds.top_left.y.as_int()});
466+ surface->consume(to_deliver.get());
467+}
468+
469 void deliver(std::shared_ptr<mi::Surface> const& surface, MirEvent const* ev)
470 {
471 auto to_deliver = mev::clone_event(*ev);
472@@ -282,12 +314,23 @@
473 sent_ev = true;
474 }
475 if (!target)
476+ {
477 return sent_ev;
478+ }
479 if (action == mir_pointer_action_button_down)
480 {
481 pointer_state.gesture_owner = target;
482 }
483- deliver(target, ev);
484+
485+ if (sent_ev)
486+ {
487+ if (action != mir_pointer_action_motion)
488+ deliver_without_relative_motion(target, ev);
489+ }
490+ else
491+ {
492+ deliver(target, ev);
493+ }
494 return true;
495 }
496 return false;
497
498=== modified file 'src/server/scene/surface_stack.cpp'
499--- src/server/scene/surface_stack.cpp 2016-07-18 07:38:38 +0000
500+++ src/server/scene/surface_stack.cpp 2016-11-18 09:53:54 +0000
501@@ -311,9 +311,7 @@
502 {
503 if (surface->query(mir_surface_attrib_visibility) ==
504 MirSurfaceVisibility::mir_surface_visibility_exposed)
505- {
506 callback(surface);
507- }
508 }
509 }
510
511
512=== modified file 'src/server/shell/abstract_shell.cpp'
513--- src/server/shell/abstract_shell.cpp 2016-11-09 02:30:14 +0000
514+++ src/server/shell/abstract_shell.cpp 2016-11-18 09:53:54 +0000
515@@ -26,6 +26,7 @@
516 #include "mir/scene/prompt_session_manager.h"
517 #include "mir/scene/null_surface_observer.h"
518 #include "mir/scene/session_coordinator.h"
519+#include "mir/scene/surface_creation_parameters.h"
520 #include "mir/scene/session.h"
521 #include "mir/scene/surface.h"
522 #include "mir/input/seat.h"
523
524=== modified file 'tests/acceptance-tests/test_client_cookie.cpp'
525--- tests/acceptance-tests/test_client_cookie.cpp 2016-07-18 07:38:38 +0000
526+++ tests/acceptance-tests/test_client_cookie.cpp 2016-11-18 09:53:54 +0000
527@@ -177,10 +177,9 @@
528
529 TEST_F(ClientCookies, pointer_motion_events_do_not_have_cookies)
530 {
531- // with movement generates 2 events
532 fake_pointer->emit_event(mis::a_pointer_event().with_movement(1, 1));
533
534- int events = 2;
535+ int events = 1;
536 if (wait_for_n_events(events, this))
537 {
538 std::lock_guard<std::mutex> lk(mutex);
539
540=== modified file 'tests/acceptance-tests/test_client_input.cpp'
541--- tests/acceptance-tests/test_client_input.cpp 2016-11-18 09:53:53 +0000
542+++ tests/acceptance-tests/test_client_input.cpp 2016-11-18 09:53:54 +0000
543@@ -316,8 +316,7 @@
544
545 // We should see the cursor enter
546 InSequence seq;
547- EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent()));
548- EXPECT_CALL(first_client, handle_input(mt::PointerEventWithPosition(surface_width - 1, surface_height - 1)));
549+ EXPECT_CALL(first_client, handle_input(mt::PointerEnterEventWithPosition(surface_width - 1, surface_height - 1)));
550 EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent()))
551 .WillOnce(mt::WakeUp(&first_client.all_events_received));
552 // But we should not receive an event for the second movement outside of our surface!
553@@ -336,8 +335,8 @@
554 Client first_client(new_connection(), first);
555
556 InSequence seq;
557- EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent()));
558- EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(1, 1), mt::PointerEventWithDiff(1, 1))));
559+ EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEnterEventWithPosition(1, 1),
560+ mt::PointerEnterEventWithDiff(1, 1))));
561 EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(2, 2), mt::PointerEventWithDiff(1, 1))));
562 EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(3, 3), mt::PointerEventWithDiff(1, 1))));
563 EXPECT_CALL(first_client, handle_input(AllOf(mt::PointerEventWithPosition(2, 2), mt::PointerEventWithDiff(-1, -1))));
564@@ -433,16 +432,14 @@
565
566 {
567 InSequence seq;
568- EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent()));
569- EXPECT_CALL(first_client, handle_input(mt::PointerEventWithPosition(client_width - 1, client_height - 1)));
570+ EXPECT_CALL(first_client, handle_input(mt::PointerEnterEventWithPosition(client_width - 1, client_height - 1)));
571 EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent()))
572 .WillOnce(mt::WakeUp(&first_client.all_events_received));
573 }
574
575 {
576 InSequence seq;
577- EXPECT_CALL(second_client, handle_input(mt::PointerEnterEvent()));
578- EXPECT_CALL(second_client, handle_input(mt::PointerEventWithPosition(client_width - 1, client_height - 1)))
579+ EXPECT_CALL(second_client, handle_input(mt::PointerEnterEventWithPosition(client_width - 1, client_height - 1)))
580 .WillOnce(mt::WakeUp(&second_client.all_events_received));
581 }
582
583@@ -555,14 +552,12 @@
584 Client first_client(new_connection(), first);
585 Client second_client(new_connection(), second);
586
587- EXPECT_CALL(second_client, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
588- EXPECT_CALL(second_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
589- EXPECT_CALL(second_client, handle_input(mt::PointerEventWithPosition(1, 1)))
590+ EXPECT_CALL(second_client, handle_input(mt::PointerEnterEventWithPosition(1, 1)))
591 .WillOnce(mt::WakeUp(&second_client.all_events_received));
592
593- EXPECT_CALL(first_client, handle_input(mt::PointerEnterEvent())).Times(AnyNumber());
594- EXPECT_CALL(first_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
595- EXPECT_CALL(first_client, handle_input(mt::PointerEventWithPosition(2, 2)))
596+ EXPECT_CALL(second_client, handle_input(mt::PointerLeaveEvent())).Times(AnyNumber());
597+
598+ EXPECT_CALL(first_client, handle_input(mt::PointerEnterEventWithPosition(2, 2)))
599 .WillOnce(mt::WakeUp(&first_client.all_events_received));
600
601 // We send one event and then hide the surface on top before sending the next.
602@@ -869,11 +864,9 @@
603 ASSERT_TRUE(shell->wait_for_modify_surface(5s));
604
605 // We verify that we don't receive the first shaped out button event.
606- EXPECT_CALL(client, handle_input(mt::PointerEnterEvent()));
607- EXPECT_CALL(client, handle_input(mt::PointerEventWithPosition(1, 1)));
608+ EXPECT_CALL(client, handle_input(mt::PointerEnterEventWithPosition(1, 1)));
609 EXPECT_CALL(client, handle_input(mt::ButtonDownEvent(1, 1)))
610 .WillOnce(mt::WakeUp(&client.all_events_received));
611-
612
613 fake_mouse->emit_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
614 fake_mouse->emit_event(mis::a_button_up_event().of_button(BTN_LEFT).with_action(mis::EventAction::Up));
615
616=== modified file 'tests/acceptance-tests/test_confined_pointer.cpp'
617--- tests/acceptance-tests/test_confined_pointer.cpp 2016-11-02 05:07:18 +0000
618+++ tests/acceptance-tests/test_confined_pointer.cpp 2016-11-18 09:53:54 +0000
619@@ -215,8 +215,7 @@
620 Client client(new_connection(), first);
621
622 InSequence seq;
623- EXPECT_CALL(client, handle_input(mt::PointerEnterEvent()));
624- EXPECT_CALL(client, handle_input(mt::PointerEventWithPosition(surface_width / 2, 0)));
625+ EXPECT_CALL(client, handle_input(mt::PointerEnterEventWithPosition(surface_width / 2, 0)));
626 EXPECT_CALL(client, handle_input(AllOf(mt::PointerEventWithPosition(surface_width - 1, 0),
627 mt::PointerEventWithDiff(surface_width * 2, 0))));
628 EXPECT_CALL(client, handle_input(AllOf(mt::PointerEventWithPosition(surface_width - 1, 0),
629@@ -236,8 +235,7 @@
630 Client client(new_connection(), first);
631
632 InSequence seq;
633- EXPECT_CALL(client, handle_input(mt::PointerEnterEvent()));
634- EXPECT_CALL(client, handle_input(mt::PointerEventWithPosition(surface_width - 1, 0)));
635+ EXPECT_CALL(client, handle_input(mt::PointerEnterEventWithPosition(surface_width - 1, 0)));
636 EXPECT_CALL(client, handle_input(AllOf(mt::PointerEventWithPosition(surface_width - 1, 0), mt::PointerEventWithDiff(10, 0))))
637 .WillOnce(mt::WakeUp(&client.all_events_received));
638
639@@ -265,8 +263,7 @@
640 resized_signaled.wait_for(1s);
641
642 InSequence seq;
643- EXPECT_CALL(client, handle_input(mt::PointerEnterEvent()));
644- EXPECT_CALL(client, handle_input(mt::PointerEventWithPosition(surface_width + 100 - 1, 0)));
645+ EXPECT_CALL(client, handle_input(mt::PointerEnterEventWithPosition(surface_width + 100 - 1, 0)));
646 EXPECT_CALL(client, handle_input(AllOf(mt::PointerEventWithPosition(surface_width + 100 - 1, 0), mt::PointerEventWithDiff(10, 0))))
647 .WillOnce(mt::WakeUp(&client.all_events_received));
648
649@@ -295,8 +292,7 @@
650 std::this_thread::sleep_for(1s);
651
652 InSequence seq;
653- EXPECT_CALL(client_2, handle_input(mt::PointerEnterEvent()));
654- EXPECT_CALL(client_2, handle_input(mt::PointerEventWithPosition(0, 0)));
655+ EXPECT_CALL(client_2, handle_input(mt::PointerEnterEventWithPosition(0, 0)));
656 EXPECT_CALL(client_2, handle_input(mt::PointerEventWithPosition(surface_width - 1, 0)))
657 .WillOnce(mt::WakeUp(&client_2.all_events_received));
658
659
660=== modified file 'tests/acceptance-tests/test_nested_input.cpp'
661--- tests/acceptance-tests/test_nested_input.cpp 2016-10-12 06:03:15 +0000
662+++ tests/acceptance-tests/test_nested_input.cpp 2016-11-18 09:53:54 +0000
663@@ -56,6 +56,23 @@
664
665 namespace
666 {
667+
668+size_t get_index_of(MirInputConfig const* config, std::string const& id)
669+{
670+ for (size_t i = 0, e = mir_input_config_device_count(config);i != e;++i)
671+ {
672+ auto const* device = mir_input_config_get_device(config, i);
673+ if (mir_input_device_get_unique_id(device) == id)
674+ return i;
675+ }
676+ return mir_input_config_device_count(config);
677+}
678+
679+bool contains(MirInputConfig const* config, std::string const& id)
680+{
681+ return mir_input_config_device_count(config) != get_index_of(config, id);
682+}
683+
684 struct MockEventFilter : public mi::EventFilter
685 {
686 // Work around GMock wanting to know how to construct MirEvent
687@@ -69,8 +86,7 @@
688
689 std::vector<mir::geometry::Rectangle> const display_geometry
690 {
691- {{ 0, 0}, { 640, 480}},
692- {{480, 0}, {1920, 1080}}
693+ {{ 0, 0}, {1920, 1080}}
694 };
695
696 struct NestedServerWithMockEventFilter : mtf::HeadlessNestedServerRunner
697@@ -118,9 +134,19 @@
698 std::make_shared<NiceMock<mtd::MockInputDeviceObserver>>()};
699 };
700
701+struct NestedInputWithMouse : NestedInput
702+{
703+ std::string const uid{"mouse-uid"};
704+ std::unique_ptr<mtf::FakeInputDevice> fake_mouse{
705+ mtf::add_fake_input_device(mi::InputDeviceInfo{"mouse", uid, mi::DeviceCapability::pointer})
706+ };
707+ MockEventFilter nested_event_filter;
708+};
709+
710 struct ExposedSurface
711 {
712 public:
713+ using UniqueInputConfig = std::unique_ptr<MirInputConfig, void(*)(MirInputConfig const*)>;
714 ExposedSurface(std::string const& connect_string)
715 {
716 // Ensure the nested server posts a frame
717@@ -128,6 +154,16 @@
718 surface = mtf::make_any_surface(connection);
719 mir_surface_set_event_handler(surface, handle_event, this);
720 mir_buffer_stream_swap_buffers_sync(mir_surface_get_buffer_stream(surface));
721+
722+ mir_connection_set_input_config_change_callback(
723+ connection,
724+ [](MirConnection*, void* context)
725+ {
726+ auto* surf = static_cast<ExposedSurface*>(context);
727+ auto config = surf->get_input_config();
728+ surf->input_config(config.get());
729+ },
730+ this);
731 }
732
733 MOCK_METHOD1(handle_input, void(MirEvent const*));
734@@ -148,6 +184,11 @@
735 if (exposed && focused)
736 ready_to_accept_events.raise();
737 }
738+ UniqueInputConfig get_input_config()
739+ {
740+ auto config = mir_connection_create_input_config(connection);
741+ return {config,&mir_input_config_destroy};
742+ }
743
744 static void handle_event(MirSurface*, MirEvent const* ev, void* context)
745 {
746@@ -163,6 +204,11 @@
747 client->handle_input(ev);
748 }
749
750+ void on_input_config(std::function<void(MirInputConfig const*)> const& handler)
751+ {
752+ input_config = handler;
753+ }
754+
755 static void null_event_handler(MirSurface*, MirEvent const*, void*) {};
756 ~ExposedSurface()
757 {
758@@ -171,16 +217,16 @@
759 mir_connection_release(connection);
760 }
761 mir::test::Signal ready_to_accept_events;
762-
763+ MirConnection *connection;
764 protected:
765 ExposedSurface(ExposedSurface const&) = delete;
766 ExposedSurface& operator=(ExposedSurface const&) = delete;
767
768 private:
769- MirConnection *connection;
770 MirSurface *surface;
771 bool exposed{false};
772 bool focused{false};
773+ std::function<void(MirInputConfig const* confg)> input_config;
774 };
775
776 }
777@@ -301,3 +347,150 @@
778 client_to_nested_event_received.wait_for(2s);
779 client_to_host_event_received.wait_for(2s);
780 }
781+
782+TEST_F(NestedInput, nested_clients_can_change_host_device_configurations)
783+{
784+ auto const acceleration_bias = 0.9;
785+ std::string const uid{"mouse-uid"};
786+
787+ mt::Signal fake_device_received;
788+ NestedServerWithMockEventFilter nested_mir{new_connection()};
789+ ExposedSurface client_to_nested(nested_mir.new_connection());
790+ client_to_nested.on_input_config(
791+ [&](MirInputConfig const* config)
792+ {
793+ if (contains(config, uid))
794+ fake_device_received.raise();
795+ });
796+ client_to_nested.ready_to_accept_events.wait_for(4s);
797+
798+ std::unique_ptr<mtf::FakeInputDevice> fake_mouse{
799+ mtf::add_fake_input_device(mi::InputDeviceInfo{"mouse", uid, mi::DeviceCapability::pointer})
800+ };
801+
802+ EXPECT_TRUE(fake_device_received.wait_for(4s));
803+
804+ auto device_config = client_to_nested.get_input_config();
805+ auto device = mir_input_config_get_mutable_device(device_config.get(), get_index_of(device_config.get(), uid));
806+ auto ptr_conf = mir_input_device_get_mutable_pointer_configuration(device);
807+ mir_pointer_configuration_set_acceleration_bias(ptr_conf, acceleration_bias);
808+ fake_device_received.reset();
809+ mir_connection_apply_input_device_configuration(client_to_nested.connection, device);
810+
811+ EXPECT_TRUE(fake_device_received.wait_for(2s));
812+
813+ device_config = client_to_nested.get_input_config();
814+ device = mir_input_config_get_mutable_device(device_config.get(), get_index_of(device_config.get(), uid));
815+ ptr_conf = mir_input_device_get_mutable_pointer_configuration(device);
816+
817+ EXPECT_THAT(mir_pointer_configuration_get_acceleration_bias(ptr_conf), acceleration_bias);
818+}
819+
820+TEST_F(NestedInputWithMouse, acceleration_change_affects_received_events)
821+{
822+ mt::Signal pointer_events_received;
823+ mt::Signal device_change_received;
824+ mt::Signal device_change_applied;
825+ auto const acceleration_bias = 1.0;
826+ auto const x = 10.0f;
827+ auto const y = 40.0f;
828+ fake_mouse->on_configuration_change([&device_change_applied](mi::InputDevice const&){device_change_applied.raise();});
829+
830+ NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
831+ ExposedSurface client_to_nested(nested_mir.new_connection());
832+ client_to_nested.on_input_config(
833+ [&](MirInputConfig const* config)
834+ {
835+ auto device = mir_input_config_get_device(config, get_index_of(config, uid));
836+ auto ptr_conf = mir_input_device_get_pointer_configuration(device);
837+ if (ptr_conf)
838+ {
839+ if (mir_pointer_configuration_get_acceleration_bias(ptr_conf) == acceleration_bias)
840+ device_change_received.raise();
841+ }
842+ });
843+ client_to_nested.ready_to_accept_events.wait_for(4s);
844+
845+ auto device_config = client_to_nested.get_input_config();
846+ auto device = mir_input_config_get_mutable_device(device_config.get(), get_index_of(device_config.get(), uid));
847+ auto ptr_conf = mir_input_device_get_mutable_pointer_configuration(device);
848+ mir_pointer_configuration_set_acceleration_bias(ptr_conf, acceleration_bias);
849+ mir_connection_apply_input_device_configuration(client_to_nested.connection, device);
850+
851+ EXPECT_TRUE(device_change_received.wait_for(4s));
852+ EXPECT_TRUE(device_change_applied.wait_for(4s));
853+ EXPECT_CALL(nested_event_filter, handle(mt::PointerEventWithDiff(x * 2.0f, y * 2.0f)))
854+ .WillOnce(DoAll(mt::WakeUp(&pointer_events_received), Return(true)));
855+
856+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(x, y));
857+
858+ EXPECT_TRUE(pointer_events_received.wait_for(4s));
859+}
860+
861+TEST_F(NestedInputWithMouse, mouse_pointer_coordinates_in_nested_server_are_accumulated)
862+{
863+ auto const initial_movement_x = 30;
864+ auto const initial_movement_y = 30;
865+ auto const second_movement_x = 5;
866+ auto const second_movement_y = -2;
867+
868+ mt::Signal devices_ready;
869+ mt::Signal event_received;
870+ EXPECT_CALL(nested_event_filter, handle(mt::InputDeviceStateEvent()))
871+ .WillOnce(DoAll(mt::WakeUp(&devices_ready), Return(true)));
872+
873+ EXPECT_CALL(nested_event_filter,
874+ handle(AllOf(mt::PointerEventWithPosition(initial_movement_x, initial_movement_y),
875+ mt::PointerEventWithDiff(initial_movement_x, initial_movement_y))))
876+ .WillOnce(DoAll(mt::WakeUp(&event_received), Return(true)));
877+
878+ NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
879+ ExposedSurface client_to_nested_mir(nested_mir.new_connection());
880+ client_to_nested_mir.ready_to_accept_events.wait_for(1s);
881+
882+ devices_ready.wait_for(2s);
883+
884+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(initial_movement_x, initial_movement_y));
885+ event_received.wait_for(2s);
886+
887+ event_received.reset();
888+
889+ EXPECT_CALL(nested_event_filter,
890+ handle(AllOf(mt::PointerEventWithPosition(initial_movement_x + second_movement_x, initial_movement_y + second_movement_y),
891+ mt::PointerEventWithDiff(second_movement_x, second_movement_y))))
892+ .WillOnce(DoAll(mt::WakeUp(&event_received), Return(true)));
893+
894+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(second_movement_x, second_movement_y));
895+ event_received.wait_for(2s);
896+}
897+
898+TEST_F(NestedInputWithMouse, mouse_pointer_position_is_in_sync_with_host_server)
899+{
900+ int const x[] = {30, -10, 10};
901+ int const y[] = {30, 100, 50};
902+ int const initial_x = x[0] + x[1];
903+ int const initial_y = y[0] + y[1];
904+ int const final_x = initial_x + x[2];
905+ int const final_y = initial_y + y[2];
906+
907+ mt::Signal devices_ready;
908+ mt::Signal event_received;
909+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(x[0], y[0]));
910+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(x[1], y[1]));
911+
912+ EXPECT_CALL(nested_event_filter, handle(
913+ mt::DeviceStateWithPosition(initial_x, initial_y)))
914+ .WillOnce(DoAll(mt::WakeUp(&devices_ready), Return(true)));
915+ EXPECT_CALL(nested_event_filter,
916+ handle(AllOf(mt::PointerEventWithPosition(final_x, final_y),
917+ mt::PointerEventWithDiff(x[2], y[2]))))
918+ .WillOnce(DoAll(mt::WakeUp(&event_received), Return(true)));
919+
920+ NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
921+ ExposedSurface client_to_nested_mir(nested_mir.new_connection());
922+ client_to_nested_mir.ready_to_accept_events.wait_for(1s);
923+ devices_ready.wait_for(2s);
924+
925+ fake_mouse->emit_event(mis::a_pointer_event().with_movement(x[2], y[2]));
926+ event_received.wait_for(2s);
927+}
928
929=== modified file 'tests/include/mir/test/doubles/stub_host_connection.h'
930--- tests/include/mir/test/doubles/stub_host_connection.h 2016-11-17 08:45:49 +0000
931+++ tests/include/mir/test/doubles/stub_host_connection.h 2016-11-18 09:53:54 +0000
932@@ -165,6 +165,9 @@
933 {
934 return true;
935 }
936+ void apply_input_device_configuration(MirInputDevice const* /*device*/) override
937+ {
938+ }
939 };
940
941 struct MockHostConnection : StubHostConnection
942@@ -177,6 +180,8 @@
943 (std::shared_ptr<graphics::nested::HostStream> const&, geometry::Displacement,
944 graphics::BufferProperties, char const*, uint32_t));
945
946+ MOCK_METHOD1(apply_input_device_configuration, void(MirInputDevice const*));
947+
948 void emit_input_event(MirEvent const& event, mir::geometry::Rectangle const& source_frame)
949 {
950 if (event_callback)
951
952=== modified file 'tests/mir_test_doubles/fake_display.cpp'
953--- tests/mir_test_doubles/fake_display.cpp 2016-11-15 02:23:00 +0000
954+++ tests/mir_test_doubles/fake_display.cpp 2016-11-18 09:53:54 +0000
955@@ -22,6 +22,7 @@
956
957 #include "mir/graphics/event_handler_register.h"
958
959+#include <iostream>
960 #include <system_error>
961 #include <boost/throw_exception.hpp>
962
963
964=== modified file 'tests/mir_test_framework/fake_input_device_impl.cpp'
965--- tests/mir_test_framework/fake_input_device_impl.cpp 2016-11-15 20:53:57 +0000
966+++ tests/mir_test_framework/fake_input_device_impl.cpp 2016-11-18 09:53:54 +0000
967@@ -113,7 +113,7 @@
968
969 mtf::FakeInputDeviceImpl::InputDevice::InputDevice(mi::InputDeviceInfo const& info,
970 std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable)
971- : info(info), queue{dispatchable}, buttons{0}
972+ : info(info), queue{dispatchable}, buttons{0}, settings_changed{[](mir::input::InputDevice const&){}}
973 {
974 // the default setup results in a direct mapping of input velocity to output velocity.
975 settings.acceleration = mir_pointer_acceleration_none;
976@@ -235,6 +235,8 @@
977 if (!contains(info.capabilities, mi::DeviceCapability::pointer))
978 return;
979 this->settings = settings;
980+
981+ settings_changed(*this);
982 }
983
984 mir::optional_value<mi::TouchpadSettings> mtf::FakeInputDeviceImpl::InputDevice::get_touchpad_settings() const
985@@ -276,3 +278,12 @@
986 builder = nullptr;
987 mtf::StubInputPlatform::unregister_dispatchable(queue);
988 }
989+
990+void mtf::FakeInputDeviceImpl::on_configuration_change(
991+ std::function<void(mir::input::InputDevice const&)> const& callback)
992+{
993+ queue->enqueue([this, callback]()
994+ {
995+ device->settings_changed = callback;
996+ });
997+}
998
999=== modified file 'tests/mir_test_framework/fake_input_device_impl.h'
1000--- tests/mir_test_framework/fake_input_device_impl.h 2016-10-31 02:37:31 +0000
1001+++ tests/mir_test_framework/fake_input_device_impl.h 2016-11-18 09:53:54 +0000
1002@@ -49,6 +49,7 @@
1003 void emit_touch_sequence(std::function<mir::input::synthesis::TouchParameters(int)> const& event_generator,
1004 int count,
1005 std::chrono::duration<double> delay) override;
1006+ void on_configuration_change(std::function<void(mir::input::InputDevice const&)> const& callback) override;
1007
1008 private:
1009 class InputDevice : public mir::input::InputDevice
1010@@ -86,6 +87,8 @@
1011 mir::geometry::Point pos, scroll;
1012 MirPointerButtons buttons;
1013 mir::input::PointerSettings settings;
1014+ std::function<void(mir::input::InputDevice const&)> settings_changed;
1015+ friend class FakeInputDeviceImpl;
1016 };
1017 std::shared_ptr<mir::dispatch::ActionQueue> queue;
1018 std::shared_ptr<InputDevice> device;
1019
1020=== modified file 'tests/unit-tests/input/test_nested_input_platform.cpp'
1021--- tests/unit-tests/input/test_nested_input_platform.cpp 2016-10-27 14:31:48 +0000
1022+++ tests/unit-tests/input/test_nested_input_platform.cpp 2016-11-18 09:53:54 +0000
1023@@ -24,6 +24,7 @@
1024 #include "mir/cookie/authority.h"
1025 #include "mir/input/device_capability.h"
1026 #include "mir/input/input_device.h"
1027+#include "mir/input/pointer_settings.h"
1028 #include "mir/input/input_device_info.h"
1029 #include "mir/input/input_report.h"
1030 #include "mir/events/event_builders.h"
1031@@ -72,6 +73,16 @@
1032 mp::InputDeviceInfo a_mouse{to_device_info(0, mir_input_device_capability_pointer, "rodent", "rodent-evdev1")};
1033 const mir::geometry::Rectangle source_surface{{0, 0}, {100, 100}};
1034
1035+ TestNestedInputPlatform()
1036+ {
1037+ auto pointer_conf = a_mouse.mutable_pointer_configuration();
1038+ pointer_conf->set_handedness(mir_pointer_handedness_right);
1039+ pointer_conf->set_acceleration(mir_pointer_acceleration_adaptive);
1040+ pointer_conf->set_acceleration_bias(0.0);
1041+ pointer_conf->set_horizontal_scroll_scale(1.0);
1042+ pointer_conf->set_vertical_scroll_scale(1.0);
1043+ }
1044+
1045 auto capture_input_device(mp::InputDeviceInfo& dev)
1046 {
1047 std::shared_ptr<mi::InputDevice> input_dev;
1048@@ -174,3 +185,42 @@
1049 mock_host_connection.event_callback(*mev::make_event(a_keyboard.id(), 141ns, cookie, mir_keyboard_action_down, 0,
1050 scan_code, mir_input_event_modifier_none), source_surface);
1051 }
1052+
1053+TEST_F(TestNestedInputPlatform, replaces_enter_events_as_motion_event)
1054+{
1055+ auto nested_input_device = capture_input_device(a_mouse);
1056+ NiceMock<mtd::MockInputSink> event_sink;
1057+ mi::DefaultEventBuilder builder(MirInputDeviceId{18}, mir::cookie::Authority::create(), mt::fake_shared(mock_seat));
1058+
1059+ ASSERT_THAT(nested_input_device, Ne(nullptr));
1060+ nested_input_device->start(&event_sink, &builder);
1061+
1062+ EXPECT_CALL(event_sink,
1063+ handle_input(AllOf(
1064+ mt::PointerEventWithPosition(60.0f, 35.0f), mt::PointerEventWithDiff(60.0f, 35.0f))));
1065+ std::vector<uint8_t> cookie;
1066+
1067+ auto event = mev::make_event(a_mouse.id(),
1068+ 141ns,
1069+ cookie,
1070+ mir_input_event_modifier_none,
1071+ mir_pointer_action_enter,
1072+ 0,
1073+ 60.0f, 35.0f,
1074+ 0, 0,
1075+ 60.0f, 35.0f);
1076+
1077+ mock_host_connection.event_callback(*event, source_surface);
1078+}
1079+
1080+TEST_F(TestNestedInputPlatform, device_configurations_are_forwarded_to_host_connection)
1081+{
1082+ auto nested_input_device = capture_input_device(a_mouse);
1083+
1084+ mi::PointerSettings left_handed = nested_input_device->get_pointer_settings().value();
1085+ left_handed.handedness = mir_pointer_handedness_left;
1086+
1087+ EXPECT_CALL(mock_host_connection, apply_input_device_configuration(_));
1088+
1089+ nested_input_device->apply_settings(left_handed);
1090+}
1091
1092=== modified file 'tests/unit-tests/input/test_surface_input_dispatcher.cpp'
1093--- tests/unit-tests/input/test_surface_input_dispatcher.cpp 2016-11-11 07:56:09 +0000
1094+++ tests/unit-tests/input/test_surface_input_dispatcher.cpp 2016-11-18 09:53:54 +0000
1095@@ -294,7 +294,6 @@
1096
1097 InSequence seq;
1098 EXPECT_CALL(*surface, consume(mt::PointerEnterEvent())).Times(1);
1099- EXPECT_CALL(*surface, consume(mt::PointerEventWithPosition(1, 0))).Times(1);
1100 EXPECT_CALL(*surface, consume(mt::PointerLeaveEvent())).Times(1);
1101
1102 dispatcher.start();
1103@@ -312,10 +311,8 @@
1104
1105 InSequence seq;
1106 EXPECT_CALL(*top_surface, consume(mt::PointerEnterEvent())).Times(1);
1107- EXPECT_CALL(*top_surface, consume(mt::PointerEventWithPosition(1, 0))).Times(1);
1108 EXPECT_CALL(*surface, consume(mt::PointerEnterEvent())).Times(1);
1109- EXPECT_CALL(*surface, consume(mt::PointerEventWithPosition(1, 0))).Times(1);
1110-
1111+
1112 dispatcher.start();
1113
1114 EXPECT_TRUE(dispatcher.dispatch(*pointer.move_to({1, 0})));
1115@@ -334,12 +331,10 @@
1116
1117 InSequence seq;
1118 EXPECT_CALL(*surface, consume(mt::PointerEnterEvent())).Times(1);
1119- EXPECT_CALL(*surface, consume(mt::PointerEventWithPosition(1, 1))).Times(1);
1120 EXPECT_CALL(*surface, consume(mt::PointerLeaveEvent())).Times(1);
1121 EXPECT_CALL(*another_surface, consume(mt::PointerEnterEvent())).Times(1);
1122- EXPECT_CALL(*another_surface, consume(mt::PointerEventWithPosition(1, 1))).Times(1);
1123 EXPECT_CALL(*another_surface, consume(mt::PointerLeaveEvent())).Times(1);
1124-
1125+
1126 dispatcher.start();
1127
1128 EXPECT_TRUE(dispatcher.dispatch(*pointer.move_to({1, 1})));
1129@@ -419,8 +414,7 @@
1130 EXPECT_CALL(*surface, consume(mt::PointerEnterEvent())).Times(1);
1131 EXPECT_CALL(*surface, consume(mt::ButtonDownEvent(0,0))).Times(1);
1132 EXPECT_CALL(*another_surface, consume(mt::PointerEnterEvent())).Times(1);
1133- EXPECT_CALL(*another_surface, consume(mt::PointerEventWithPosition(1,1))).Times(1);
1134-
1135+
1136 dispatcher.start();
1137
1138 EXPECT_TRUE(dispatcher.dispatch(*ev_1));

Subscribers

People subscribed via source and target branches