Mir

Merge lp:~andreas-pokorny/mir/nested-input-platform into lp:mir

Proposed by Andreas Pokorny
Status: Superseded
Proposed branch: lp:~andreas-pokorny/mir/nested-input-platform
Merge into: lp:mir
Prerequisite: lp:~andreas-pokorny/mir/fix-accumulation-of-relative-axis-when-resampling
Diff against target: 1295 lines (+622/-301)
18 files modified
src/include/server/mir/default_server_configuration.h (+1/-0)
src/server/graphics/default_configuration.cpp (+2/-6)
src/server/graphics/nested/CMakeLists.txt (+1/-0)
src/server/graphics/nested/display.cpp (+3/-9)
src/server/graphics/nested/display.h (+1/-10)
src/server/graphics/nested/display_buffer.cpp (+5/-37)
src/server/graphics/nested/display_buffer.h (+4/-9)
src/server/graphics/nested/host_connection.h (+7/-0)
src/server/graphics/nested/input_platform.cpp (+269/-0)
src/server/graphics/nested/input_platform.h (+71/-0)
src/server/graphics/nested/mir_client_host_connection.cpp (+22/-167)
src/server/graphics/nested/mir_client_host_connection.h (+8/-17)
src/server/input/default_configuration.cpp (+31/-43)
src/server/input/seat_input_device_tracker.cpp (+3/-1)
tests/include/mir/test/doubles/stub_host_connection.h (+10/-0)
tests/unit-tests/graphics/nested/test_nested_display.cpp (+1/-2)
tests/unit-tests/input/CMakeLists.txt (+1/-0)
tests/unit-tests/input/test_nested_input_platform.cpp (+182/-0)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/nested-input-platform
Reviewer Review Type Date Requested Status
Alan Griffiths Needs Information
Chris Halse Rogers Approve
Mir CI Bot continuous-integration Needs Fixing
Review via email: mp+293834@code.launchpad.net

This proposal has been superseded by a proposal from 2016-05-20.

Commit message

Nested Input Platform

Convert the input setup code for a nested server into a platform. The platform is not dynamically loaded. Still part of the server, but only uses the HostConnection interface and the APIs use by other input platforms. As a result there is now the same InputDeviceRegistry and the same input::Seat like on the host server.

Description of the change

A nested input platform built into the server.

This change adds input state tracking to nested servers.

The MP has two unrelated prerequisite branches
* lp:~andreas-pokorny/mir/mediate-nested-cursor-configuration-on-construction
* lp:~andreas-pokorny/mir/fix-accumulation-of-relative-axis-when-resampling

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

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

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

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

Unrelated failure: (lp:1570698)

22:06:59 11: Expected: to be called between 50 and 150 times
22:06:59 11: Actual: called 167 times - over-saturated and active
22:06:59 11: /��BUILDDIR��/mir-0.23.0+xenial1042bzr3496/tests/acceptance-tests/test_client_input.cpp:648: Failure
22:06:59 11: Value of: client_input_events_per_frame
22:06:59 11: Expected: is < 1.5
22:06:59 11: Actual: 1.5 (of type float)
22:06:59 11: [2016-05-04 22:06:58.560725] mirserver: Stopping
22:06:59 11: [ FAILED ] TestClientInput.receives_one_touch_event_per_frame (6775 ms)

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

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

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

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

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

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

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

Seems sensible on a first pass. Does our discussion regarding the intricacies of per-surface keymaps and modifier state require any alteration?

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

> Seems sensible on a first pass. Does our discussion regarding the intricacies
> of per-surface keymaps and modifier state require any alteration?

Not really - instead this helps with the per device keymaps, and helps with figuring out the actual modifiers according to the keymap configured. The alteration necessary is inside the mir::input::Seat implementation details. It needs to keep track of key states, instead of modifier states. Additionally to allow servers to properly implement key bindings I will add the per device keymapping to a related class there..

Revision history for this message
Chris Halse Rogers (raof) wrote :

I'm happy with this.

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

One of the prerequisite branches appears to have been rejected. Is this still relevant?

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

> One of the prerequisite branches appears to have been rejected. Is this still
> relevant?

the issue is very relevant - but I had to recject the MP. CI successfully merged the branch but then failed to remove the MP itself.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/include/server/mir/default_server_configuration.h'
2--- src/include/server/mir/default_server_configuration.h 2016-05-10 05:13:30 +0000
3+++ src/include/server/mir/default_server_configuration.h 2016-05-20 13:09:42 +0000
4@@ -335,6 +335,7 @@
5 protected:
6 std::shared_ptr<options::Option> the_options() const;
7 std::shared_ptr<graphics::nested::MirClientHostConnection> the_mir_client_host_connection();
8+ std::shared_ptr<input::DefaultInputDeviceHub> the_default_input_device_hub();
9
10 virtual std::shared_ptr<input::InputChannelFactory> the_input_channel_factory();
11 virtual std::shared_ptr<scene::MediatingDisplayChanger> the_mediating_display_changer();
12
13=== modified file 'src/server/graphics/default_configuration.cpp'
14--- src/server/graphics/default_configuration.cpp 2016-03-29 07:30:50 +0000
15+++ src/server/graphics/default_configuration.cpp 2016-05-20 13:09:42 +0000
16@@ -162,11 +162,9 @@
17 return std::make_shared<mgn::Display>(
18 the_graphics_platform(),
19 the_host_connection(),
20- the_input_dispatcher(),
21 the_display_report(),
22 the_display_configuration_policy(),
23- the_gl_config(),
24- the_cursor_listener());
25+ the_gl_config());
26 }
27 {
28 return the_graphics_platform()->create_display(
29@@ -254,9 +252,7 @@
30 return std::make_shared<graphics::nested::MirClientHostConnection>(
31 host_socket,
32 my_name,
33- the_host_lifecycle_event_listener(),
34- the_global_event_sink(),
35- the_main_loop()
36+ the_host_lifecycle_event_listener()
37 );
38 });
39 }
40
41=== modified file 'src/server/graphics/nested/CMakeLists.txt'
42--- src/server/graphics/nested/CMakeLists.txt 2016-01-29 08:18:22 +0000
43+++ src/server/graphics/nested/CMakeLists.txt 2016-05-20 13:09:42 +0000
44@@ -6,6 +6,7 @@
45 mirnestedgraphics OBJECT
46
47 display.cpp
48+ input_platform.cpp
49 nested_display_configuration.cpp
50 display_buffer.cpp
51 mir_client_host_connection.cpp
52
53=== modified file 'src/server/graphics/nested/display.cpp'
54--- src/server/graphics/nested/display.cpp 2016-05-13 07:15:29 +0000
55+++ src/server/graphics/nested/display.cpp 2016-05-20 13:09:42 +0000
56@@ -37,7 +37,6 @@
57 #include <stdexcept>
58 #include <sstream>
59
60-namespace mi = mir::input;
61 namespace mg = mir::graphics;
62 namespace mgn = mir::graphics::nested;
63 namespace geom = mir::geometry;
64@@ -179,17 +178,13 @@
65 mgn::Display::Display(
66 std::shared_ptr<mg::Platform> const& platform,
67 std::shared_ptr<HostConnection> const& connection,
68- std::shared_ptr<input::InputDispatcher> const& dispatcher,
69 std::shared_ptr<mg::DisplayReport> const& display_report,
70 std::shared_ptr<mg::DisplayConfigurationPolicy> const& initial_conf_policy,
71- std::shared_ptr<mg::GLConfig> const& gl_config,
72- std::shared_ptr<mi::CursorListener> const& cursor_listener) :
73+ std::shared_ptr<mg::GLConfig> const& gl_config) :
74 platform{platform},
75 connection{connection},
76- dispatcher{dispatcher},
77 display_report{display_report},
78 egl_display{connection->egl_native_display(), gl_config},
79- cursor_listener{cursor_listener},
80 outputs{},
81 current_configuration(std::make_unique<NestedDisplayConfiguration>(connection->create_display_config()))
82 {
83@@ -321,9 +316,8 @@
84 egl_display,
85 host_surface,
86 extents,
87- dispatcher,
88- cursor_listener,
89- best_output.current_format));
90+ best_output.current_format,
91+ connection));
92 }
93 });
94
95
96=== modified file 'src/server/graphics/nested/display.h'
97--- src/server/graphics/nested/display.h 2016-05-12 08:01:23 +0000
98+++ src/server/graphics/nested/display.h 2016-05-20 13:09:42 +0000
99@@ -33,11 +33,6 @@
100
101 namespace mir
102 {
103-namespace input
104-{
105-class InputDispatcher;
106-class CursorListener;
107-}
108 namespace geometry
109 {
110 struct Rectangle;
111@@ -120,11 +115,9 @@
112 Display(
113 std::shared_ptr<Platform> const& platform,
114 std::shared_ptr<HostConnection> const& connection,
115- std::shared_ptr<input::InputDispatcher> const& dispatcher,
116 std::shared_ptr<DisplayReport> const& display_report,
117 std::shared_ptr<DisplayConfigurationPolicy> const& conf_policy,
118- std::shared_ptr<GLConfig> const& gl_config,
119- std::shared_ptr<input::CursorListener> const& cursor_listener);
120+ std::shared_ptr<GLConfig> const& gl_config);
121
122 ~Display() noexcept;
123
124@@ -152,10 +145,8 @@
125 private:
126 std::shared_ptr<Platform> const platform;
127 std::shared_ptr<HostConnection> const connection;
128- std::shared_ptr<input::InputDispatcher> const dispatcher;
129 std::shared_ptr<DisplayReport> const display_report;
130 detail::EGLDisplayHandle egl_display;
131- std::shared_ptr<input::CursorListener> const cursor_listener;
132
133 std::mutex outputs_mutex;
134 std::unordered_map<DisplayConfigurationOutputId, std::shared_ptr<detail::DisplaySyncGroup>> outputs;
135
136=== modified file 'src/server/graphics/nested/display_buffer.cpp'
137--- src/server/graphics/nested/display_buffer.cpp 2016-05-12 08:01:23 +0000
138+++ src/server/graphics/nested/display_buffer.cpp 2016-05-20 13:09:42 +0000
139@@ -19,16 +19,13 @@
140 #include "display_buffer.h"
141
142 #include "host_connection.h"
143-#include "mir/input/input_dispatcher.h"
144 #include "mir/graphics/pixel_format_utils.h"
145-#include "mir/input/cursor_listener.h"
146 #include "mir/graphics/egl_error.h"
147 #include "mir/events/event_private.h"
148
149 #include <boost/throw_exception.hpp>
150 #include <stdexcept>
151
152-namespace mi = mir::input;
153 namespace mg = mir::graphics;
154 namespace mgn = mir::graphics::nested;
155 namespace geom = mir::geometry;
156@@ -37,16 +34,15 @@
157 EGLDisplayHandle const& egl_display,
158 std::shared_ptr<HostSurface> const& host_surface,
159 geometry::Rectangle const& area,
160- std::shared_ptr<input::InputDispatcher> const& dispatcher,
161- std::shared_ptr<mi::CursorListener> const& cursor_listener,
162- MirPixelFormat preferred_format) :
163+ MirPixelFormat preferred_format,
164+ std::shared_ptr<HostConnection> const& host_connection
165+ ) :
166 egl_display(egl_display),
167 host_surface{host_surface},
168+ host_connection{host_connection},
169 egl_config{egl_display.choose_windowed_config(preferred_format)},
170 egl_context{egl_display, eglCreateContext(egl_display, egl_config, egl_display.egl_context(), nested_egl_context_attribs)},
171 area{area.top_left, area.size},
172- dispatcher{dispatcher},
173- cursor_listener{cursor_listener},
174 egl_surface{egl_display, host_surface->egl_native_window(), egl_config}
175 {
176 host_surface->set_event_handler(event_thunk, this);
177@@ -118,35 +114,7 @@
178 if (mir_event_get_type(&event) != mir_event_type_input)
179 return;
180
181- if (event.type() == mir_event_type_motion)
182- {
183- MirMotionEvent my_event = *event.to_input()->to_motion();
184- auto iev = mir_event_get_input_event(&my_event);
185-
186- if (mir_input_event_get_type(iev) == mir_input_event_type_pointer)
187- {
188- auto motion = my_event.to_input()->to_motion();
189-
190- for (size_t i = 0; i != motion->pointer_count(); ++i)
191- {
192- auto x = motion->x(i);
193- auto y = motion->y(i);
194- motion->set_x(i, x + area.top_left.x.as_float());
195- motion->set_y(i, y + area.top_left.y.as_float());
196- }
197-
198- auto pev = mir_input_event_get_pointer_event(iev);
199- auto x = mir_pointer_event_axis_value(pev, mir_pointer_axis_x);
200- auto y = mir_pointer_event_axis_value(pev, mir_pointer_axis_y);
201- cursor_listener->cursor_moved_to(x, y);
202- }
203-
204- dispatcher->dispatch(my_event);
205- }
206- else
207- {
208- dispatcher->dispatch(event);
209- }
210+ host_connection->emit_input_event(event, area);
211 }
212
213 mg::NativeDisplayBuffer* mgn::detail::DisplayBuffer::native_display_buffer()
214
215=== modified file 'src/server/graphics/nested/display_buffer.h'
216--- src/server/graphics/nested/display_buffer.h 2016-05-03 04:36:33 +0000
217+++ src/server/graphics/nested/display_buffer.h 2016-05-20 13:09:42 +0000
218@@ -28,10 +28,6 @@
219
220 namespace mir
221 {
222-namespace input
223-{
224-class CursorListener;
225-}
226 namespace graphics
227 {
228 namespace nested
229@@ -50,9 +46,9 @@
230 EGLDisplayHandle const& egl_display,
231 std::shared_ptr<HostSurface> const& host_surface,
232 geometry::Rectangle const& area,
233- std::shared_ptr<input::InputDispatcher> const& input_dispatcher,
234- std::shared_ptr<input::CursorListener> const& cursor,
235- MirPixelFormat preferred_format);
236+ MirPixelFormat preferred_format,
237+ std::shared_ptr<HostConnection> const& host_connection
238+ );
239
240 ~DisplayBuffer() noexcept;
241
242@@ -73,11 +69,10 @@
243 private:
244 EGLDisplayHandle const& egl_display;
245 std::shared_ptr<HostSurface> const host_surface;
246+ std::shared_ptr<HostConnection> const host_connection;
247 EGLConfig const egl_config;
248 EGLContextStore const egl_context;
249 geometry::Rectangle const area;
250- std::shared_ptr<input::InputDispatcher> const dispatcher;
251- std::shared_ptr<input::CursorListener> const cursor_listener;
252 EGLSurfaceHandle const egl_surface;
253
254 static void event_thunk(MirSurface* surface, MirEvent const* event, void* context);
255
256=== modified file 'src/server/graphics/nested/host_connection.h'
257--- src/server/graphics/nested/host_connection.h 2016-03-29 07:30:50 +0000
258+++ src/server/graphics/nested/host_connection.h 2016-05-20 13:09:42 +0000
259@@ -21,6 +21,7 @@
260
261 #include "mir_toolkit/client_types.h"
262 #include "mir/graphics/nested_context.h"
263+#include "mir/geometry/rectangle.h"
264
265 #include <memory>
266 #include <vector>
267@@ -36,6 +37,8 @@
268
269 namespace nested
270 {
271+using UniqueInputConfig = std::unique_ptr<MirInputConfig, void(*)(MirInputConfig const*)>;
272+
273 class HostSurface;
274 class HostConnection : public NestedContext
275 {
276@@ -54,6 +57,10 @@
277 virtual void hide_cursor() = 0;
278 virtual auto graphics_platform_library() -> std::string = 0;
279
280+ virtual void set_input_device_change_callback(std::function<void(UniqueInputConfig)> const& cb) = 0;
281+ virtual void set_input_event_callback(std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const& cb) = 0;
282+ virtual void emit_input_event(MirEvent const& event, mir::geometry::Rectangle const& source_frame) = 0;
283+
284 protected:
285 HostConnection() = default;
286 HostConnection(HostConnection const&) = delete;
287
288=== added file 'src/server/graphics/nested/input_platform.cpp'
289--- src/server/graphics/nested/input_platform.cpp 1970-01-01 00:00:00 +0000
290+++ src/server/graphics/nested/input_platform.cpp 2016-05-20 13:09:42 +0000
291@@ -0,0 +1,269 @@
292+/*
293+ * Copyright © 2016 Canonical Ltd.
294+ *
295+ * This program is free software: you can redistribute it and/or modify it
296+ * under the terms of the GNU General Public License version 3,
297+ * as published by the Free Software Foundation.
298+ *
299+ * This program is distributed in the hope that it will be useful,
300+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
301+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
302+ * GNU General Public License for more details.
303+ *
304+ * You should have received a copy of the GNU General Public License
305+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
306+ *
307+ * Authored by:
308+ * Andreas Pokorny <andreas.pokorny@canonical.com>
309+ */
310+
311+#include "input_platform.h"
312+#include "host_connection.h"
313+
314+#include "mir/input/input_device_registry.h"
315+#include "mir/input/input_device_info.h"
316+#include "mir/input/input_device.h"
317+#include "mir/input/input_sink.h"
318+#include "mir/input/event_builder.h"
319+#include "mir/input/pointer_settings.h"
320+#include "mir/input/touchpad_settings.h"
321+#include "mir/input/device_capability.h"
322+#include "mir/dispatch/action_queue.h"
323+#include "mir/events/event_builders.h"
324+#include "mir/events/event_private.h"
325+
326+#include <chrono>
327+
328+namespace mi = mir::input;
329+namespace mgn = mir::graphics::nested;
330+
331+namespace
332+{
333+
334+mgn::UniqueInputConfig make_empty_config()
335+{
336+ return mgn::UniqueInputConfig(nullptr, [](MirInputConfig const*){});
337+}
338+
339+}
340+
341+struct mgn::InputPlatform::InputDevice : mi::InputDevice
342+{
343+public:
344+ InputDevice(MirInputDevice const* dev)
345+ {
346+ update(dev);
347+ }
348+
349+ MirInputDeviceId id() const
350+ {
351+ return device_id;
352+ }
353+
354+ void update(MirInputDevice const* dev)
355+ {
356+ device_id = mir_input_device_get_id(dev);
357+ device_info.name = mir_input_device_get_name(dev);
358+ device_info.unique_id = mir_input_device_get_unique_id(dev);
359+ device_info.capabilities = mi::DeviceCapabilities(mir_input_device_get_capabilities(dev));
360+ }
361+
362+ void start(mi::InputSink* destination, mi::EventBuilder* builder) override
363+ {
364+ this->destination = destination;
365+ this->builder = builder;
366+ }
367+
368+ void emit_event(MirInputEvent const* event, mir::geometry::Rectangle const& frame)
369+ {
370+ auto const type = mir_input_event_get_type(event);
371+ auto const event_time = std::chrono::nanoseconds{mir_input_event_get_event_time(event)};
372+
373+ // TODO move the coordinate transformation over here
374+ switch(type)
375+ {
376+ case mir_input_event_type_touch:
377+ {
378+ auto const* touch_event = mir_input_event_get_touch_event(event);
379+ auto new_event = builder->touch_event(event_time);
380+
381+ for (int i = 0, point_count = mir_touch_event_point_count(touch_event); i != point_count; ++i)
382+ {
383+ builder->add_touch(
384+ *new_event,
385+ mir_touch_event_id(touch_event, i),
386+ mir_touch_event_action(touch_event, i),
387+ mir_touch_event_tooltype(touch_event, i),
388+ mir_touch_event_axis_value(touch_event, i, mir_touch_axis_x),
389+ mir_touch_event_axis_value(touch_event, i, mir_touch_axis_y),
390+ mir_touch_event_axis_value(touch_event, i, mir_touch_axis_pressure),
391+ mir_touch_event_axis_value(touch_event, i, mir_touch_axis_touch_major),
392+ mir_touch_event_axis_value(touch_event, i, mir_touch_axis_touch_minor),
393+ mir_touch_event_axis_value(touch_event, i, mir_touch_axis_size));
394+ }
395+ destination->handle_input(*new_event);
396+ break;
397+ }
398+ case mir_input_event_type_key:
399+ {
400+ auto const* key_event = mir_input_event_get_keyboard_event(event);
401+ destination->handle_input(*builder->key_event(
402+ event_time,
403+ mir_keyboard_event_action(key_event),
404+ mir_keyboard_event_key_code(key_event),
405+ mir_keyboard_event_scan_code(key_event)
406+ ));
407+
408+ break;
409+ }
410+ case mir_input_event_type_pointer:
411+ {
412+ auto const* pointer_event = mir_input_event_get_pointer_event(event);
413+ auto new_event = builder->pointer_event(
414+ event_time,
415+ mir_pointer_event_action(pointer_event),
416+ mir_pointer_event_buttons(pointer_event),
417+ mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll),
418+ mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll),
419+ mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x),
420+ mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y)
421+ );
422+
423+ auto x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
424+ auto y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
425+ new_event->to_input()->to_motion()->set_x(0, x + frame.top_left.x.as_float());
426+ new_event->to_input()->to_motion()->set_y(0, y + frame.top_left.y.as_float());
427+ destination->handle_input(*new_event);
428+ break;
429+ }
430+ default:
431+ break;
432+ }
433+ }
434+
435+ void stop() override
436+ {
437+ this->destination = nullptr;
438+ this->builder = nullptr;
439+ }
440+
441+ mi::InputDeviceInfo get_device_info() override
442+ {
443+ return device_info;
444+ }
445+
446+ mir::optional_value<mi::PointerSettings> get_pointer_settings() const override
447+ {
448+ return pointer_settings;
449+ }
450+
451+ void apply_settings(mi::PointerSettings const&) override
452+ {
453+ // TODO no C API for that
454+ }
455+
456+ mir::optional_value<mi::TouchpadSettings> get_touchpad_settings() const override
457+ {
458+ return touchpad_settings;
459+ }
460+
461+ void apply_settings(mi::TouchpadSettings const&) override
462+ {
463+ // no c api for that
464+ }
465+
466+ MirInputDeviceId device_id;
467+ mi::InputSink* destination{nullptr};
468+ mi::EventBuilder* builder{nullptr};
469+ mi::InputDeviceInfo device_info;
470+ mir::optional_value<mi::PointerSettings> pointer_settings;
471+ mir::optional_value<mi::TouchpadSettings> touchpad_settings;
472+};
473+
474+
475+mgn::InputPlatform::InputPlatform(std::shared_ptr<HostConnection> const& connection,
476+ std::shared_ptr<input::InputDeviceRegistry> const& input_device_registry,
477+ std::shared_ptr<input::InputReport> const& report)
478+ : connection{connection}, input_device_registry{input_device_registry}, report{report}, action_queue{std::make_shared<dispatch::ActionQueue>()}, input_config{make_empty_config()}
479+{
480+}
481+
482+std::shared_ptr<mir::dispatch::Dispatchable> mgn::InputPlatform::dispatchable()
483+{
484+ return action_queue;
485+}
486+
487+void mgn::InputPlatform::start()
488+{
489+ connection->set_input_device_change_callback(
490+ [this](mgn::UniqueInputConfig new_config)
491+ {
492+ std::lock_guard<std::mutex> lock(devices_guard);
493+ input_config = std::move(new_config);
494+ update_devices_locked();
495+ });
496+
497+ connection->set_input_device_change_callback(
498+ [this](mgn::UniqueInputConfig new_config)
499+ {
500+ std::lock_guard<std::mutex> lock(devices_guard);
501+ input_config = std::move(new_config);
502+ action_queue->enqueue([this]{update_devices();});
503+ });
504+
505+ connection->set_input_event_callback(
506+ [this](MirEvent const& event, mir::geometry::Rectangle const& area)
507+ {
508+ auto const* input_ev = mir_event_get_input_event(&event);
509+ auto const id = mir_input_event_get_device_id(input_ev);
510+ auto it = devices.find(id);
511+ if (it != end(devices))
512+ it->second->emit_event(input_ev, area);
513+ });
514+}
515+
516+void mgn::InputPlatform::stop()
517+{
518+ std::function<void(mgn::UniqueInputConfig)> reset;
519+ connection->set_input_device_change_callback(reset);
520+
521+ for(auto const& device : devices)
522+ input_device_registry->remove_device(device.second);
523+
524+ devices.clear();
525+}
526+
527+void mgn::InputPlatform::update_devices()
528+{
529+ std::lock_guard<std::mutex> lock(devices_guard);
530+ update_devices_locked();
531+}
532+
533+void mgn::InputPlatform::update_devices_locked()
534+{
535+ auto deleted = std::move(devices);
536+ std::vector<std::shared_ptr<mgn::InputPlatform::InputDevice>> new_devs;
537+ auto config_ptr = input_config.get();
538+ for (size_t i = 0, e = mir_input_config_device_count(config_ptr); i!=e; ++i)
539+ {
540+ auto dev = mir_input_config_get_device(config_ptr, i);
541+ auto const id = mir_input_device_get_id(dev);
542+ auto it = deleted.find(id);
543+ if (it != end(deleted))
544+ {
545+ it->second->update(dev);
546+ devices[id] = it->second;
547+ deleted.erase(it);
548+ }
549+ else
550+ {
551+ new_devs.push_back(std::make_shared<InputDevice>(dev));
552+ devices[id] = new_devs.back();
553+ }
554+ }
555+
556+ for (auto const& deleted_dev : deleted)
557+ input_device_registry->remove_device(deleted_dev.second);
558+ for (auto new_dev : new_devs)
559+ input_device_registry->add_device(new_dev);
560+}
561
562=== added file 'src/server/graphics/nested/input_platform.h'
563--- src/server/graphics/nested/input_platform.h 1970-01-01 00:00:00 +0000
564+++ src/server/graphics/nested/input_platform.h 2016-05-20 13:09:42 +0000
565@@ -0,0 +1,71 @@
566+/*
567+ * Copyright © 2016 Canonical Ltd.
568+ *
569+ * This program is free software: you can redistribute it and/or modify it
570+ * under the terms of the GNU General Public License version 3,
571+ * as published by the Free Software Foundation.
572+ *
573+ * This program is distributed in the hope that it will be useful,
574+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
575+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
576+ * GNU General Public License for more details.
577+ *
578+ * You should have received a copy of the GNU General Public License
579+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
580+ *
581+ * Authored by:
582+ * Andreas Pokorny <andreas.pokorny@canonical.com>
583+ */
584+
585+#ifndef MIR_GRAPHICS_NESTED_INPUT_PLATFORM_H_
586+#define MIR_GRAPHICS_NESTED_INPUT_PLATFORM_H_
587+
588+#include "host_connection.h"
589+#include "mir/input/platform.h"
590+#include "mir/dispatch/dispatchable.h"
591+#include "mir/dispatch/action_queue.h"
592+
593+#include <memory>
594+#include <unordered_map>
595+#include <mutex>
596+
597+namespace mir
598+{
599+namespace input
600+{
601+class InputDevice;
602+class InputDeviceRegistry;
603+class InputReport;
604+}
605+namespace graphics
606+{
607+namespace nested
608+{
609+class HostConnection;
610+class InputPlatform : public input::Platform
611+{
612+public:
613+ InputPlatform(std::shared_ptr<HostConnection> const& connection,
614+ std::shared_ptr<input::InputDeviceRegistry> const& input_device_registry,
615+ std::shared_ptr<input::InputReport> const& report);
616+ std::shared_ptr<mir::dispatch::Dispatchable> dispatchable() override;
617+ void start() override;
618+ void stop() override;
619+
620+private:
621+ void update_devices();
622+ void update_devices_locked();
623+ struct InputDevice;
624+ std::shared_ptr<HostConnection> const connection;
625+ std::shared_ptr<input::InputDeviceRegistry> const input_device_registry;
626+ std::shared_ptr<input::InputReport> const report;
627+ std::shared_ptr<dispatch::ActionQueue> const action_queue;
628+ std::mutex devices_guard;
629+ UniqueInputConfig input_config;
630+ std::unordered_map<MirInputDeviceId, std::shared_ptr<InputDevice>> devices;
631+};
632+}
633+}
634+}
635+
636+#endif
637
638=== modified file 'src/server/graphics/nested/mir_client_host_connection.cpp'
639--- src/server/graphics/nested/mir_client_host_connection.cpp 2016-05-20 11:11:28 +0000
640+++ src/server/graphics/nested/mir_client_host_connection.cpp 2016-05-20 13:09:42 +0000
641@@ -19,6 +19,7 @@
642 #include "mir_client_host_connection.h"
643 #include "host_surface.h"
644 #include "mir_toolkit/mir_client_library.h"
645+
646 #include "mir/raii.h"
647 #include "mir/graphics/platform_operation_message.h"
648 #include "mir/graphics/cursor_image.h"
649@@ -45,79 +46,11 @@
650
651 namespace
652 {
653-
654-mgn::UniqueInputConfig make_empty_config()
655-{
656- return mgn::UniqueInputConfig(nullptr, [](MirInputConfig const*){});
657-}
658-
659 mgn::UniqueInputConfig make_input_config(MirConnection* con)
660 {
661 return mgn::UniqueInputConfig(mir_connection_create_input_config(con), mir_input_config_destroy);
662 }
663
664-class NestedDevice : public mi::Device
665-{
666-public:
667- NestedDevice(MirInputDevice const* dev)
668- {
669- update(dev);
670- }
671-
672- void update(MirInputDevice const* dev)
673- {
674- device_id = mir_input_device_get_id(dev);
675- device_name = mir_input_device_get_name(dev);
676- unique_device_id = mir_input_device_get_unique_id(dev);
677- caps = mi::DeviceCapabilities(mir_input_device_get_capabilities(dev));
678- }
679-
680- MirInputDeviceId id() const
681- {
682- return device_id;
683- }
684-
685- mi::DeviceCapabilities capabilities() const
686- {
687- return caps;
688- }
689-
690- std::string name() const
691- {
692- return device_name;
693- }
694- std::string unique_id() const
695- {
696- return unique_device_id;
697- }
698-
699- mir::optional_value<mi::PointerConfiguration> pointer_configuration() const
700- {
701- return pointer_conf;
702- }
703- void apply_pointer_configuration(mi::PointerConfiguration const&)
704- {
705- // TODO requires c api support
706- }
707-
708- mir::optional_value<mi::TouchpadConfiguration> touchpad_configuration() const
709- {
710- return touchpad_conf;
711- }
712- void apply_touchpad_configuration(mi::TouchpadConfiguration const&)
713- {
714- // TODO requires c api support
715- }
716-private:
717- MirInputDeviceId device_id;
718- std::string device_name;
719- std::string unique_device_id;
720- mi::DeviceCapabilities caps;
721- mir::optional_value<mi::PointerConfiguration> pointer_conf;
722- mir::optional_value<mi::TouchpadConfiguration> touchpad_conf;
723-};
724-
725-
726 void display_config_callback_thunk(MirConnection* /*connection*/, void* context)
727 {
728 (*static_cast<std::function<void()>*>(context))();
729@@ -292,15 +225,10 @@
730 mgn::MirClientHostConnection::MirClientHostConnection(
731 std::string const& host_socket,
732 std::string const& name,
733- std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener,
734- std::shared_ptr<mf::EventSink> const& sink,
735- std::shared_ptr<mir::ServerActionQueue> const& input_observer_queue)
736+ std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener)
737 : mir_connection{mir_connect_sync(host_socket.c_str(), name.c_str())},
738 conf_change_callback{[]{}},
739- host_lifecycle_event_listener{host_lifecycle_event_listener},
740- sink{sink},
741- observer_queue{input_observer_queue},
742- config{make_empty_config()}
743+ host_lifecycle_event_listener{host_lifecycle_event_listener}
744 {
745 if (!mir_connection_is_valid(mir_connection))
746 {
747@@ -318,14 +246,13 @@
748
749 mir_connection_set_input_config_change_callback(
750 mir_connection,
751- [](MirConnection*, void* context)
752+ [](MirConnection* connection, void* context)
753 {
754 auto obj = static_cast<MirClientHostConnection*>(context);
755- obj->update_input_devices();
756+ if (obj->input_config_callback)
757+ obj->input_config_callback(make_input_config(connection));
758 },
759 this);
760-
761- update_input_devices();
762 }
763
764 mgn::MirClientHostConnection::~MirClientHostConnection()
765@@ -466,92 +393,20 @@
766 return properties.filename;
767 }
768
769-void mgn::MirClientHostConnection::update_input_devices()
770-{
771- std::lock_guard<std::mutex> lock(devices_guard);
772- config = make_input_config(mir_connection);
773-
774- auto deleted = std::move(devices);
775- std::vector<std::shared_ptr<mi::Device>> new_devs;
776- auto config_ptr = config.get();
777- for (size_t i = 0, e = mir_input_config_device_count(config_ptr); i!=e; ++i)
778- {
779- auto dev = mir_input_config_get_device(config_ptr, i);
780- auto it = std::find_if(
781- begin(deleted),
782- end(deleted),
783- [id = mir_input_device_get_id(dev)](auto const& dev)
784- {
785- return id == dev->id();
786- });
787- if (it != end(deleted))
788- {
789- std::static_pointer_cast<NestedDevice>(*it)->update(dev);
790- devices.push_back(*it);
791- deleted.erase(it);
792- }
793- else
794- {
795- devices.push_back(std::make_shared<NestedDevice>(dev));
796- new_devs.push_back(devices.back());
797- }
798- }
799-
800- sink->handle_input_device_change(devices);
801-
802- if ((deleted.empty() && new_devs.empty()) || observers.empty())
803- return;
804-
805- observer_queue->enqueue(
806- this,
807- [this, new_devs = std::move(new_devs), deleted = std::move(deleted)]
808- {
809- std::lock_guard<std::mutex> lock(devices_guard);
810- for (auto const observer : observers)
811- {
812- for (auto const& item : new_devs)
813- observer->device_added(item);
814- for (auto const& item : deleted)
815- observer->device_removed(item);
816- observer->changes_complete();
817- }
818- });
819-}
820-
821-void mgn::MirClientHostConnection::add_observer(std::shared_ptr<mi::InputDeviceObserver> const& observer)
822-{
823- observer_queue->enqueue(
824- this,
825- [observer,this]
826- {
827- std::lock_guard<std::mutex> lock(devices_guard);
828- observers.push_back(observer);
829- for (auto const& item : devices)
830- {
831- observer->device_added(item);
832- }
833- observer->changes_complete();
834- }
835- );
836-}
837-
838-void mgn::MirClientHostConnection::remove_observer(std::weak_ptr<mi::InputDeviceObserver> const& element)
839-{
840- auto observer = element.lock();
841-
842- observer_queue->enqueue(this,
843- [observer, this]
844- {
845- observers.erase(remove(begin(observers), end(observers), observer), end(observers));
846- });
847-}
848-
849-void mgn::MirClientHostConnection::for_each_input_device(std::function<void(mi::Device const& device)> const& callback)
850-{
851- std::lock_guard<std::mutex> lock(devices_guard);
852- for (auto const& item : devices)
853- {
854- callback(*item);
855- }
856-
857+void mgn::MirClientHostConnection::set_input_device_change_callback(std::function<void(UniqueInputConfig)> const& cb)
858+{
859+ input_config_callback = cb;
860+ if (input_config_callback)
861+ input_config_callback(make_input_config(mir_connection));
862+}
863+
864+void mgn::MirClientHostConnection::set_input_event_callback(std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const& cb)
865+{
866+ event_callback = cb;
867+}
868+
869+void mgn::MirClientHostConnection::emit_input_event(MirEvent const& event, mir::geometry::Rectangle const& source_frame)
870+{
871+ if (event_callback)
872+ event_callback(event, source_frame);
873 }
874
875=== modified file 'src/server/graphics/nested/mir_client_host_connection.h'
876--- src/server/graphics/nested/mir_client_host_connection.h 2016-05-20 11:11:28 +0000
877+++ src/server/graphics/nested/mir_client_host_connection.h 2016-05-20 13:09:42 +0000
878@@ -51,16 +51,12 @@
879 namespace nested
880 {
881
882-using UniqueInputConfig = std::unique_ptr<MirInputConfig, void(*)(MirInputConfig const*)>;
883-
884-class MirClientHostConnection : public HostConnection, public input::InputDeviceHub
885+class MirClientHostConnection : public HostConnection
886 {
887 public:
888 MirClientHostConnection(std::string const& host_socket,
889 std::string const& name,
890- std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener,
891- std::shared_ptr<frontend::EventSink> const& sink,
892- std::shared_ptr<ServerActionQueue> const& observer_queue);
893+ std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener);
894 ~MirClientHostConnection();
895
896 std::vector<int> platform_fd_items() override;
897@@ -79,13 +75,12 @@
898 virtual PlatformOperationMessage platform_operation(
899 unsigned int op, PlatformOperationMessage const& request) override;
900
901- // InputDeviceHub
902- void add_observer(std::shared_ptr<input::InputDeviceObserver> const&) override;
903- void remove_observer(std::weak_ptr<input::InputDeviceObserver> const&) override;
904- void for_each_input_device(std::function<void(input::Device const& device)> const& callback) override;
905+ void set_input_device_change_callback(std::function<void(UniqueInputConfig)> const& cb) override;
906+ void set_input_event_callback(std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const& cb) override;
907+ void emit_input_event(MirEvent const& cb, mir::geometry::Rectangle const& source_frame) override;
908
909 private:
910- void update_input_devices();
911+ void update_input_config(UniqueInputConfig input_config);
912 std::mutex surfaces_mutex;
913
914 MirConnection* const mir_connection;
915@@ -94,12 +89,8 @@
916
917 std::vector<HostSurface*> surfaces;
918
919- std::shared_ptr<frontend::EventSink> const sink;
920- std::shared_ptr<mir::ServerActionQueue> const observer_queue;
921- std::vector<std::shared_ptr<input::InputDeviceObserver>> observers;
922- std::mutex devices_guard;
923- std::vector<std::shared_ptr<input::Device>> devices;
924- UniqueInputConfig config;
925+ std::function<void(UniqueInputConfig)> input_config_callback;
926+ std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> event_callback;
927
928 struct NestedCursorImage : graphics::CursorImage
929 {
930
931=== modified file 'src/server/input/default_configuration.cpp'
932--- src/server/input/default_configuration.cpp 2016-05-03 04:36:33 +0000
933+++ src/server/input/default_configuration.cpp 2016-05-20 13:09:42 +0000
934@@ -34,7 +34,7 @@
935 #include "default_input_manager.h"
936 #include "surface_input_dispatcher.h"
937 #include "basic_seat.h"
938-#include "../graphics/nested/mir_client_host_connection.h"
939+#include "../graphics/nested/input_platform.h"
940
941 #include "mir/input/touch_visualizer.h"
942 #include "mir/input/input_probe.h"
943@@ -58,6 +58,7 @@
944 namespace mr = mir::report;
945 namespace ms = mir::scene;
946 namespace mg = mir::graphics;
947+namespace mgn = mg::nested;
948 namespace msh = mir::shell;
949 namespace md = mir::dispatch;
950
951@@ -277,8 +278,13 @@
952 }
953 else if (options->is_set(options::host_socket_opt))
954 {
955- // TODO nested input handling (== host_socket) should fold into a platform
956- return std::make_shared<mi::NullInputManager>();
957+ auto const device_registry = the_input_device_registry();
958+ auto const input_report = the_input_report();
959+
960+ // TODO: move this into a nested graphics platform
961+ auto platform = std::make_shared<mgn::InputPlatform>(the_host_connection(), device_registry, input_report);
962+
963+ return std::make_shared<mi::DefaultInputManager>(the_input_reading_multiplexer(), std::move(platform));
964 }
965 else
966 {
967@@ -330,48 +336,30 @@
968
969 std::shared_ptr<mi::InputDeviceRegistry> mir::DefaultServerConfiguration::the_input_device_registry()
970 {
971- return default_input_device_hub(
972- [this]()
973- {
974- auto input_dispatcher = the_input_dispatcher();
975- auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher);
976- auto hub = std::make_shared<mi::DefaultInputDeviceHub>(
977- the_global_event_sink(),
978- the_seat(),
979- the_input_reading_multiplexer(),
980- the_main_loop(),
981- the_cookie_authority());
982-
983- if (key_repeater)
984- key_repeater->set_input_device_hub(hub);
985- return hub;
986- });
987+ return the_default_input_device_hub();
988 }
989
990 std::shared_ptr<mi::InputDeviceHub> mir::DefaultServerConfiguration::the_input_device_hub()
991 {
992- auto options = the_options();
993- if (options->is_set(options::host_socket_opt))
994- {
995- return the_mir_client_host_connection();
996- }
997- else
998- {
999- return default_input_device_hub(
1000- [this]()
1001- {
1002- auto input_dispatcher = the_input_dispatcher();
1003- auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher);
1004- auto hub = std::make_shared<mi::DefaultInputDeviceHub>(
1005- the_global_event_sink(),
1006- the_seat(),
1007- the_input_reading_multiplexer(),
1008- the_main_loop(),
1009- the_cookie_authority());
1010-
1011- if (key_repeater)
1012- key_repeater->set_input_device_hub(hub);
1013- return hub;
1014- });
1015- }
1016+ return the_default_input_device_hub();
1017+}
1018+
1019+std::shared_ptr<mi::DefaultInputDeviceHub> mir::DefaultServerConfiguration::the_default_input_device_hub()
1020+{
1021+ return default_input_device_hub(
1022+ [this]()
1023+ {
1024+ auto input_dispatcher = the_input_dispatcher();
1025+ auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher);
1026+ auto hub = std::make_shared<mi::DefaultInputDeviceHub>(
1027+ the_global_event_sink(),
1028+ the_seat(),
1029+ the_input_reading_multiplexer(),
1030+ the_main_loop(),
1031+ the_cookie_authority());
1032+
1033+ if (key_repeater && !the_options()->is_set(options::host_socket_opt))
1034+ key_repeater->set_input_device_hub(hub);
1035+ return hub;
1036+ });
1037 }
1038
1039=== modified file 'src/server/input/seat_input_device_tracker.cpp'
1040--- src/server/input/seat_input_device_tracker.cpp 2016-05-03 04:36:33 +0000
1041+++ src/server/input/seat_input_device_tracker.cpp 2016-05-20 13:09:42 +0000
1042@@ -24,6 +24,7 @@
1043 #include "mir/input/input_dispatcher.h"
1044 #include "mir/geometry/displacement.h"
1045 #include "mir/events/event_builders.h"
1046+#include "mir/events/event_private.h"
1047
1048 #include "input_modifier_utils.h"
1049
1050@@ -82,7 +83,8 @@
1051
1052 if (mir_input_event_type_pointer == mir_input_event_get_type(input_event))
1053 {
1054- mev::set_cursor_position(event, cursor_position());
1055+ event.to_input()->to_motion()->set_x(0, cursor_x);
1056+ event.to_input()->to_motion()->set_y(0, cursor_y);
1057 mev::set_button_state(event, button_state());
1058 }
1059
1060
1061=== modified file 'tests/include/mir/test/doubles/stub_host_connection.h'
1062--- tests/include/mir/test/doubles/stub_host_connection.h 2016-03-29 07:30:50 +0000
1063+++ tests/include/mir/test/doubles/stub_host_connection.h 2016-05-20 13:09:42 +0000
1064@@ -78,6 +78,16 @@
1065 }
1066
1067 auto graphics_platform_library() -> std::string { return {}; }
1068+
1069+ void set_input_device_change_callback(std::function<void(graphics::nested::UniqueInputConfig)> const&) override
1070+ {
1071+ }
1072+ void set_input_event_callback(std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const&) override
1073+ {
1074+ }
1075+ void emit_input_event(MirEvent const&, mir::geometry::Rectangle const&) override
1076+ {
1077+ }
1078 };
1079
1080
1081
1082=== modified file 'tests/unit-tests/graphics/nested/test_nested_display.cpp'
1083--- tests/unit-tests/graphics/nested/test_nested_display.cpp 2016-01-28 22:27:36 +0000
1084+++ tests/unit-tests/graphics/nested/test_nested_display.cpp 2016-05-20 13:09:42 +0000
1085@@ -68,10 +68,9 @@
1086 auto nested_display_raw = new mgn::Display{
1087 platform,
1088 std::make_shared<SingleDisplayHostConnection>(),
1089- mt::fake_shared(null_input_dispatcher),
1090 mt::fake_shared(null_display_report),
1091 mt::fake_shared(default_conf_policy),
1092- gl_config, std::make_shared<mtd::StubCursorListener>()};
1093+ gl_config};
1094
1095 return std::unique_ptr<mgn::Display>{nested_display_raw};
1096 }
1097
1098=== modified file 'tests/unit-tests/input/CMakeLists.txt'
1099--- tests/unit-tests/input/CMakeLists.txt 2016-05-03 04:36:33 +0000
1100+++ tests/unit-tests/input/CMakeLists.txt 2016-05-20 13:09:42 +0000
1101@@ -17,6 +17,7 @@
1102 ${CMAKE_CURRENT_SOURCE_DIR}/test_seat_input_device_tracker.cpp
1103 ${CMAKE_CURRENT_SOURCE_DIR}/test_key_repeat_dispatcher.cpp
1104 ${CMAKE_CURRENT_SOURCE_DIR}/test_validator.cpp
1105+ ${CMAKE_CURRENT_SOURCE_DIR}/test_nested_input_platform.cpp
1106 )
1107
1108 list(APPEND UMOCK_UNIT_TEST_SOURCES
1109
1110=== added file 'tests/unit-tests/input/test_nested_input_platform.cpp'
1111--- tests/unit-tests/input/test_nested_input_platform.cpp 1970-01-01 00:00:00 +0000
1112+++ tests/unit-tests/input/test_nested_input_platform.cpp 2016-05-20 13:09:42 +0000
1113@@ -0,0 +1,182 @@
1114+/*
1115+ * Copyright © 2016 Canonical Ltd.
1116+ *
1117+ * This program is free software: you can redistribute it and/or modify
1118+ * it under the terms of the GNU General Public License version 3 as
1119+ * published by the Free Software Foundation.
1120+ *
1121+ * This program is distributed in the hope that it will be useful,
1122+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1123+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1124+ * GNU General Public License for more details.
1125+ *
1126+ * You should have received a copy of the GNU General Public License
1127+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1128+ *
1129+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
1130+ */
1131+
1132+#include "src/server/graphics/nested/input_platform.h"
1133+#include "src/server/report/null_report_factory.h"
1134+#include "src/include/client/mir/input/input_devices.h"
1135+#include "src/server/input/default_event_builder.h"
1136+
1137+#include "mir/cookie/authority.h"
1138+#include "mir/input/device_capability.h"
1139+#include "mir/input/input_device.h"
1140+#include "mir/input/input_device_info.h"
1141+#include "mir/input/input_report.h"
1142+#include "mir/events/event_builders.h"
1143+#include "mir_toolkit/mir_connection.h"
1144+
1145+#include "mir/test/doubles/mock_input_device_registry.h"
1146+#include "mir/test/doubles/mock_input_sink.h"
1147+#include "mir/test/doubles/stub_host_connection.h"
1148+#include "mir/test/fake_shared.h"
1149+#include "mir/test/event_matchers.h"
1150+
1151+
1152+namespace mi = mir::input;
1153+namespace mt = mir::test;
1154+namespace mr = mir::report;
1155+namespace mev = mir::events;
1156+namespace mtd = mir::test::doubles;
1157+namespace mgn = mir::graphics::nested;
1158+using namespace std::chrono_literals;
1159+using namespace testing;
1160+namespace
1161+{
1162+
1163+struct MockHostConnection : mtd::StubHostConnection
1164+{
1165+ MOCK_METHOD1(set_input_device_change_callback, void (std::function<void(mgn::UniqueInputConfig)> const&));
1166+ MOCK_METHOD1(set_input_event_callback, void (std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const&));
1167+ void emit_input_event(MirEvent const& event, mir::geometry::Rectangle const& source_frame)
1168+ {
1169+ if (event_callback)
1170+ event_callback(event, source_frame);
1171+ }
1172+
1173+ MockHostConnection()
1174+ {
1175+ ON_CALL(*this, set_input_device_change_callback(_))
1176+ .WillByDefault(SaveArg<0>(&device_change_callback));
1177+ ON_CALL(*this, set_input_event_callback(_))
1178+ .WillByDefault(SaveArg<0>(&event_callback));
1179+ }
1180+
1181+ std::function<void(mgn::UniqueInputConfig)> device_change_callback;
1182+ std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> event_callback;
1183+};
1184+
1185+struct TestNestedInputPlatform : Test
1186+{
1187+ NiceMock<mtd::MockInputDeviceRegistry> mock_input_device_registry;
1188+ NiceMock<MockHostConnection> mock_host_connection;
1189+ mgn::InputPlatform platform{mt::fake_shared(mock_host_connection), mt::fake_shared(mock_input_device_registry),
1190+ mr::null_input_report()};
1191+ mi::DeviceData a_keyboard{1, mir_input_device_capability_keyboard, "keys" , "keys-evdev2"};
1192+ mi::DeviceData a_mouse{0, mir_input_device_capability_pointer, "rodent", "rodent-evdev1"};
1193+ const mir::geometry::Rectangle source_surface{{0, 0}, {100, 100}};
1194+
1195+
1196+ auto capture_input_device(mi::DeviceData& dev)
1197+ {
1198+ std::shared_ptr<mi::InputDevice> input_dev;
1199+ ON_CALL(mock_input_device_registry, add_device(_))
1200+ .WillByDefault(SaveArg<0>(&input_dev));
1201+ platform.start();
1202+ mgn::UniqueInputConfig input_config(
1203+ reinterpret_cast<MirInputConfig*>(
1204+ new std::vector<mir::input::DeviceData>{dev}),
1205+ mir_input_config_destroy);
1206+ mock_host_connection.device_change_callback(std::move(input_config));
1207+
1208+ platform.dispatchable()->dispatch(mir::dispatch::readable);
1209+
1210+ return input_dev;
1211+ }
1212+};
1213+
1214+}
1215+
1216+TEST_F(TestNestedInputPlatform, registers_to_host_connection)
1217+{
1218+ EXPECT_CALL(mock_host_connection, set_input_device_change_callback(_)).Times(2);
1219+ EXPECT_CALL(mock_host_connection, set_input_event_callback(_));
1220+
1221+ platform.start();
1222+}
1223+
1224+MATCHER_P(MatchesDeviceData, device_data, "")
1225+{
1226+ mi::InputDevice& dev = *arg;
1227+ auto dev_info = dev.get_device_info();
1228+
1229+ if (dev_info.name != device_data.name)
1230+ return false;
1231+ if (dev_info.unique_id != device_data.unique_id)
1232+ return false;
1233+ if (dev_info.capabilities.value() != device_data.caps)
1234+ return false;
1235+
1236+ return true;
1237+}
1238+
1239+TEST_F(TestNestedInputPlatform, registers_devices)
1240+{
1241+ EXPECT_CALL(mock_input_device_registry, add_device(MatchesDeviceData(a_keyboard)));
1242+ EXPECT_CALL(mock_input_device_registry, add_device(MatchesDeviceData(a_mouse)));
1243+
1244+ platform.start();
1245+ mi::InputDevices devices;
1246+ mgn::UniqueInputConfig input_config(
1247+ reinterpret_cast<MirInputConfig*>(
1248+ new std::vector<mir::input::DeviceData>{a_keyboard, a_mouse}),
1249+ mir_input_config_destroy);
1250+ mock_host_connection.device_change_callback(std::move(input_config));
1251+
1252+ platform.dispatchable()->dispatch(mir::dispatch::readable);
1253+}
1254+
1255+TEST_F(TestNestedInputPlatform, devices_forward_input_events)
1256+{
1257+ auto nested_input_device = capture_input_device(a_mouse);
1258+ NiceMock<mtd::MockInputSink> event_sink;
1259+ mi::DefaultEventBuilder builder(MirInputDeviceId{12}, mir::cookie::Authority::create());
1260+
1261+ ASSERT_THAT(nested_input_device, Ne(nullptr));
1262+ nested_input_device->start(&event_sink, &builder);
1263+
1264+ EXPECT_CALL(event_sink, handle_input(
1265+ AllOf(mt::PointerAxisChange(mir_pointer_axis_relative_x, 12),
1266+ mt::PointerAxisChange(mir_pointer_axis_relative_y, 10),
1267+ mt::InputDeviceIdMatches(MirInputDeviceId{12})
1268+ ))
1269+ );
1270+
1271+ std::vector<uint8_t> cookie;
1272+
1273+ mock_host_connection.event_callback(*mev::make_event(a_mouse.id, 12ns, cookie, mir_input_event_modifier_none,
1274+ mir_pointer_action_motion, mir_pointer_button_primary, 23, 42,
1275+ 0, 0, 12, 10), source_surface);
1276+}
1277+
1278+TEST_F(TestNestedInputPlatform, devices_forward_key_events)
1279+{
1280+ auto nested_input_device = capture_input_device(a_keyboard);
1281+ auto const scan_code = 45;
1282+ NiceMock<mtd::MockInputSink> event_sink;
1283+ mi::DefaultEventBuilder builder(MirInputDeviceId{18}, mir::cookie::Authority::create());
1284+
1285+ ASSERT_THAT(nested_input_device, Ne(nullptr));
1286+ nested_input_device->start(&event_sink, &builder);
1287+
1288+ EXPECT_CALL(event_sink,
1289+ handle_input(AllOf(
1290+ mt::KeyDownEvent(), mt::KeyOfScanCode(scan_code), mt::InputDeviceIdMatches(MirInputDeviceId{18}))));
1291+ std::vector<uint8_t> cookie;
1292+
1293+ mock_host_connection.event_callback(*mev::make_event(a_keyboard.id, 141ns, cookie, mir_keyboard_action_down, 0,
1294+ scan_code, mir_input_event_modifier_none), source_surface);
1295+}

Subscribers

People subscribed via source and target branches