Mir

Merge lp:~andreas-pokorny/mir/fix-1536279 into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 4121
Proposed branch: lp:~andreas-pokorny/mir/fix-1536279
Merge into: lp:mir
Prerequisite: lp:~andreas-pokorny/mir/store-device-config
Diff against target: 716 lines (+254/-38)
15 files modified
src/client/buffer_vault.cpp (+1/-1)
src/client/connection_surface_map.cpp (+7/-0)
src/client/connection_surface_map.h (+2/-1)
src/client/default_connection_configuration.cpp (+2/-2)
src/client/input/input_devices.cpp (+39/-1)
src/client/mir_surface.cpp (+5/-0)
src/client/mir_surface.h (+1/-0)
src/client/rpc/mir_protobuf_rpc_channel.cpp (+1/-1)
src/include/client/mir/client/surface_map.h (+2/-1)
src/include/client/mir/input/input_devices.h (+3/-1)
tests/acceptance-tests/test_nested_input.cpp (+163/-17)
tests/include/mir/test/test_protobuf_client.h (+6/-1)
tests/mir_test_doubles/test_protobuf_client.cpp (+3/-2)
tests/unit-tests/client/test_protobuf_rpc_channel.cpp (+15/-8)
tests/unit-tests/frontend/stress_protobuf_communicator.cpp (+4/-2)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/fix-1536279
Reviewer Review Type Date Requested Status
Alan Griffiths Abstain
Cemil Azizoglu (community) Approve
Kevin DuBois (community) Approve
Mir CI Bot continuous-integration Approve
Andreas Pokorny (community) Abstain
Review via email: mp+319438@code.launchpad.net

Commit message

Clear keystate and keymap on device removal (LP: #1536279)

  A client window may have a "default" keymap configured. So a keystate will be tracked for each keyboard device individually. Switching away from the vt of the mirserver will trigger a removal of all devices, switching back to the server will make those devices reappear.

 If the keystate is not cleared on removal any pressed key will be stuck during a vt switch.

Description of the change

This makes the keymapper in the client behave like the server on device removal.

The keystate gets cleared and when the device reappears and will be used again the default keymap will be used to create a clean keystate again.

Majority of the change is about constructing the test to have a mirserver with a nested server a focused window with a keymap configured followed by a vt switch and key presses..

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

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

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

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

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

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

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

^ the new test fails, the client does not receive the keymap in the time frame.

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

should be fine now..

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

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

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

review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

+ static void for_each_window(std::function<void(MirSurface &surf)> const& fun);

could we use ConnectionSurfaceMap here? (In the future, I think it would be good to remove the system of checking valid surfaces in favor of using the connection-saved map).

Alright by me otherwise.

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

> + static void for_each_window(std::function<void(MirSurface &surf)> const&
> fun);
>
> could we use ConnectionSurfaceMap here? (In the future, I think it would be
> good to remove the system of checking valid surfaces in favor of using the
> connection-saved map).

ok

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

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

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

review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

thanks, lgtm

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

SurfaceTrackingShell looks familiar. Is the duplication useful or accidental?

review: Needs Information
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

LGTM

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

> SurfaceTrackingShell looks familiar. Is the duplication useful or accidental?

I am not sure it can be classified as accidental. And only useful until we discover a general problem...

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

> > SurfaceTrackingShell looks familiar. Is the duplication useful or
> accidental?
>
> I am not sure it can be classified as accidental. And only useful until we
> discover a general problem...

/shrug. But I will block a third copy.

review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/client/buffer_vault.cpp'
2--- src/client/buffer_vault.cpp 2017-01-30 08:13:20 +0000
3+++ src/client/buffer_vault.cpp 2017-03-23 16:39:46 +0000
4@@ -18,10 +18,10 @@
5
6 #include "mir/client_buffer_factory.h"
7 #include "mir/client_buffer.h"
8+#include "mir/client/surface_map.h"
9 #include "buffer_vault.h"
10 #include "buffer.h"
11 #include "buffer_factory.h"
12-#include "surface_map.h"
13 #include "mir_protobuf.pb.h"
14 #include "protobuf_to_native_buffer.h"
15 #include "connection_surface_map.h"
16
17=== modified file 'src/client/connection_surface_map.cpp'
18--- src/client/connection_surface_map.cpp 2017-03-14 04:41:33 +0000
19+++ src/client/connection_surface_map.cpp 2017-03-23 16:39:46 +0000
20@@ -136,3 +136,10 @@
21 BOOST_THROW_EXCEPTION(std::runtime_error("could not find render surface"));
22 }
23 #pragma GCC diagnostic pop
24+
25+void mcl::ConnectionSurfaceMap::with_all_windows_do(std::function<void(MirWindow*)> const& fn) const
26+{
27+ std::shared_lock<decltype(stream_guard)> lk(guard);
28+ for(auto const& window : surfaces)
29+ fn(window.second.get());
30+}
31
32=== modified file 'src/client/connection_surface_map.h'
33--- src/client/connection_surface_map.h 2017-03-14 04:41:33 +0000
34+++ src/client/connection_surface_map.h 2017-03-23 16:39:46 +0000
35@@ -19,7 +19,7 @@
36 #ifndef MIR_CLIENT_CONNECTION_SURFACE_MAP_H_
37 #define MIR_CLIENT_CONNECTION_SURFACE_MAP_H_
38
39-#include "surface_map.h"
40+#include "mir/client/surface_map.h"
41
42 #include <shared_mutex>
43 #include <unordered_map>
44@@ -56,6 +56,7 @@
45 void insert(void* render_surface_key, std::shared_ptr<MirRenderSurface> const& render_surface);
46 std::shared_ptr<MirRenderSurface> render_surface(void* render_surface_key) const;
47 #pragma GCC diagnostic pop
48+ void with_all_windows_do(std::function<void(MirWindow*)> const&) const override;
49 private:
50 std::shared_timed_mutex mutable guard;
51 std::unordered_map<frontend::SurfaceId, std::shared_ptr<MirWindow>> surfaces;
52
53=== modified file 'src/client/default_connection_configuration.cpp'
54--- src/client/default_connection_configuration.cpp 2017-02-15 14:45:41 +0000
55+++ src/client/default_connection_configuration.cpp 2017-03-23 16:39:46 +0000
56@@ -118,9 +118,9 @@
57 mcl::DefaultConnectionConfiguration::the_input_devices()
58 {
59 return input_devices(
60- []
61+ [this]
62 {
63- return std::make_shared<mir::input::InputDevices>();
64+ return std::make_shared<mir::input::InputDevices>(the_surface_map());
65 });
66 }
67
68
69=== modified file 'src/client/input/input_devices.cpp'
70--- src/client/input/input_devices.cpp 2017-01-18 02:29:37 +0000
71+++ src/client/input/input_devices.cpp 2017-03-23 16:39:46 +0000
72@@ -18,19 +18,57 @@
73
74 #include "mir/input/input_devices.h"
75 #include "mir/input/mir_input_config_serialization.h"
76+#include "mir/input/mir_input_config_serialization.h"
77+#include "mir/input/xkb_mapper.h"
78+#include "../mir_surface.h"
79+
80+#include <unordered_set>
81
82 namespace mi = mir::input;
83
84+namespace
85+{
86+std::unordered_set<MirInputDeviceId> get_removed_devices(MirInputConfig const& old_config, MirInputConfig const& new_config)
87+{
88+ std::unordered_set<MirInputDeviceId> removed;
89+ old_config.for_each(
90+ [&new_config, &removed](MirInputDevice const& dev)
91+ {
92+ if (nullptr == new_config.get_device_config_by_id(dev.id()))
93+ removed.insert(dev.id());
94+ });
95+ return removed;
96+}
97+}
98+
99+mi::InputDevices::InputDevices(std::shared_ptr<client::SurfaceMap> const& windows)
100+ : windows{windows}
101+{
102+}
103+
104 void mi::InputDevices::update_devices(std::string const& config_buffer)
105 {
106 std::function<void()> stored_callback;
107
108+ std::unordered_set<MirInputDeviceId> ids;
109 {
110+ auto new_configuration = mi::deserialize_input_config(config_buffer);
111 std::unique_lock<std::mutex> lock(devices_access);
112- configuration = mi::deserialize_input_config(config_buffer);
113+ ids = get_removed_devices(new_configuration, configuration);
114+ configuration = new_configuration;
115 stored_callback = callback;
116 }
117
118+ auto window_map = windows.lock();
119+ if (window_map)
120+ window_map->with_all_windows_do(
121+ [&ids](MirWindow* window)
122+ {
123+ auto keymapper = window->get_keymapper();
124+ for (auto const& id : ids)
125+ keymapper->clear_keymap_for_device(id);
126+ });
127+
128 if (stored_callback)
129 stored_callback();
130 }
131
132=== modified file 'src/client/mir_surface.cpp'
133--- src/client/mir_surface.cpp 2017-03-17 15:32:15 +0000
134+++ src/client/mir_surface.cpp 2017-03-23 16:39:46 +0000
135@@ -838,4 +838,9 @@
136 return frame_clock;
137 }
138
139+std::shared_ptr<mir::input::receiver::XKBMapper> MirSurface::get_keymapper() const
140+{
141+ return keymapper;
142+}
143+
144 #pragma GCC diagnostic pop
145
146=== modified file 'src/client/mir_surface.h'
147--- src/client/mir_surface.h 2017-03-17 15:32:15 +0000
148+++ src/client/mir_surface.h 2017-03-23 16:39:46 +0000
149@@ -221,6 +221,7 @@
150 MirConnection* connection() const;
151
152 std::shared_ptr<mir::client::FrameClock> get_frame_clock() const;
153+ std::shared_ptr<mir::input::receiver::XKBMapper> get_keymapper() const;
154
155 private:
156 std::mutex mutable mutex; // Protects all members of *this
157
158=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp'
159--- src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-17 17:20:09 +0000
160+++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-03-23 16:39:46 +0000
161@@ -19,7 +19,7 @@
162 #include "mir_protobuf_rpc_channel.h"
163 #include "rpc_report.h"
164
165-#include "../surface_map.h"
166+#include "mir/client/surface_map.h"
167 #include "../buffer.h"
168 #include "../presentation_chain.h"
169 #include "../buffer_factory.h"
170
171=== renamed file 'src/client/surface_map.h' => 'src/include/client/mir/client/surface_map.h'
172--- src/client/surface_map.h 2017-01-18 04:43:15 +0000
173+++ src/include/client/mir/client/surface_map.h 2017-03-23 16:39:46 +0000
174@@ -43,7 +43,8 @@
175 virtual void with_all_streams_do(std::function<void(MirBufferStream*)> const&) const = 0;
176 virtual std::shared_ptr<MirBuffer> buffer(int buffer_id) const = 0;
177 virtual void insert(int buffer_id, std::shared_ptr<MirBuffer> const& buffer) = 0;
178- virtual void erase(int buffer_id) = 0;
179+ virtual void erase(int buffer_id) = 0;
180+ virtual void with_all_windows_do(std::function<void(MirWindow*)> const&) const = 0;
181
182 protected:
183 virtual ~SurfaceMap() = default;
184
185=== modified file 'src/include/client/mir/input/input_devices.h'
186--- src/include/client/mir/input/input_devices.h 2017-01-18 02:29:37 +0000
187+++ src/include/client/mir/input/input_devices.h 2017-03-23 16:39:46 +0000
188@@ -20,6 +20,7 @@
189 #define MIR_INPUT_INPUT_DEVICES_H_
190
191 #include "mir/input/mir_input_config.h"
192+#include "mir/client/surface_map.h"
193
194 #include <mutex>
195 #include <string>
196@@ -32,11 +33,12 @@
197 class InputDevices
198 {
199 public:
200- InputDevices() = default;
201+ InputDevices(std::shared_ptr<client::SurfaceMap> const& windows);
202 void update_devices(std::string const& device_buffer);
203 MirInputConfig devices();
204 void set_change_callback(std::function<void()> const& callback);
205 private:
206+ std::weak_ptr<client::SurfaceMap> const windows;
207 std::mutex devices_access;
208 MirInputConfig configuration;
209 std::function<void()> callback;
210
211=== modified file 'tests/acceptance-tests/test_nested_input.cpp'
212--- tests/acceptance-tests/test_nested_input.cpp 2017-03-23 16:39:46 +0000
213+++ tests/acceptance-tests/test_nested_input.cpp 2017-03-23 16:39:46 +0000
214@@ -22,6 +22,10 @@
215 #include "mir/input/event_filter.h"
216 #include "mir/input/composite_event_filter.h"
217 #include "mir/input/mir_input_config.h"
218+#include "mir/shell/shell_wrapper.h"
219+#include "mir/scene/session.h"
220+#include "mir/scene/surface.h"
221+#include "mir/graphics/event_handler_register.h"
222
223 #include "mir_test_framework/fake_input_device.h"
224 #include "mir_test_framework/stub_server_platform_factory.h"
225@@ -30,6 +34,7 @@
226 #include "mir_test_framework/any_surface.h"
227 #include "mir/test/doubles/nested_mock_egl.h"
228 #include "mir/test/doubles/mock_input_device_observer.h"
229+#include "mir/test/doubles/fake_display.h"
230 #include "mir/test/event_factory.h"
231 #include "mir/test/event_matchers.h"
232 #include "mir/test/fake_shared.h"
233@@ -48,6 +53,7 @@
234 namespace mis = mi::synthesis;
235
236 namespace mt = mir::test;
237+namespace mg = mir::graphics;
238 namespace mtd = mt::doubles;
239 namespace mtf = mir_test_framework;
240
241@@ -56,6 +62,71 @@
242
243 namespace
244 {
245+
246+struct SurfaceTrackingShell : mir::shell::ShellWrapper
247+{
248+ SurfaceTrackingShell(
249+ std::shared_ptr<mir::shell::Shell> wrapped_shell)
250+ : ShellWrapper{wrapped_shell}, wrapped_shell{wrapped_shell}
251+ {}
252+
253+ mir::frontend::SurfaceId create_surface(
254+ std::shared_ptr<mir::scene::Session> const& session,
255+ mir::scene::SurfaceCreationParameters const& params,
256+ std::shared_ptr<mir::frontend::EventSink> const& sink) override
257+ {
258+ auto surface_id = wrapped_shell->create_surface(session, params, sink);
259+
260+ tracked_surfaces[session->name()] = TrackedSurface{session, surface_id};
261+
262+ return surface_id;
263+ }
264+
265+ std::shared_ptr<mir::scene::Surface> get_surface(std::string const& session_name)
266+ {
267+ if (end(tracked_surfaces) == tracked_surfaces.find(session_name))
268+ return nullptr;
269+ TrackedSurface & tracked_surface = tracked_surfaces[session_name];
270+ auto session = tracked_surface.session.lock();
271+ if (!session)
272+ return nullptr;
273+ return session->surface(tracked_surface.surface);
274+ }
275+
276+ struct TrackedSurface
277+ {
278+ std::weak_ptr<mir::scene::Session> session;
279+ mir::frontend::SurfaceId surface;
280+ };
281+ std::unordered_map<std::string, TrackedSurface> tracked_surfaces;
282+ std::shared_ptr<mir::shell::Shell> wrapped_shell;
283+};
284+
285+struct Display : mtd::FakeDisplay
286+{
287+ using mtd::FakeDisplay::FakeDisplay;
288+
289+ void register_pause_resume_handlers(
290+ mg::EventHandlerRegister&,
291+ mg::DisplayPauseHandler const& pause_handler,
292+ mg::DisplayResumeHandler const& resume_handler) override
293+ {
294+ pause_function = pause_handler;
295+ resume_function = resume_handler;
296+ }
297+
298+ void trigger_pause()
299+ {
300+ pause_function();
301+ }
302+ void trigger_resume()
303+ {
304+ resume_function();
305+ }
306+ std::function<bool()> pause_function{[](){return false;}};
307+ std::function<bool()> resume_function{[](){return false;}};
308+};
309+
310 size_t get_index_of(MirInputConfig const* config, std::string const& id)
311 {
312 for (size_t i = 0, e = mir_input_config_device_count(config);i != e;++i)
313@@ -75,11 +146,11 @@
314 struct MockEventFilter : public mi::EventFilter
315 {
316 // Work around GMock wanting to know how to construct MirEvent
317- MOCK_METHOD1(handle, bool(MirEvent const*));
318+ MOCK_METHOD1(handle, void(MirEvent const*));
319 bool handle(MirEvent const& ev)
320 {
321 handle(&ev);
322- return true;
323+ return false;
324 }
325 };
326
327@@ -94,7 +165,15 @@
328 std::shared_ptr<MockEventFilter> const& event_filter)
329 : mtf::HeadlessNestedServerRunner(connection_string), mock_event_filter{event_filter}
330 {
331- server.the_composite_event_filter()->append(mock_event_filter);
332+ server.the_composite_event_filter()->prepend(mock_event_filter);
333+ server.wrap_shell(
334+ [this](std::shared_ptr<mir::shell::Shell> const& wrapped)
335+ {
336+ surfaces = std::make_shared<SurfaceTrackingShell>(wrapped);
337+ return surfaces;
338+ });
339+
340+
341 start_server();
342 }
343 NestedServerWithMockEventFilter(std::string const& connection_string)
344@@ -107,14 +186,24 @@
345 stop_server();
346 }
347
348+ std::shared_ptr<mir::scene::Surface> get_surface(std::string const& name)
349+ {
350+ return surfaces->get_surface(name);
351+ }
352+ std::shared_ptr<SurfaceTrackingShell> surfaces;
353 std::shared_ptr<MockEventFilter> const mock_event_filter;
354 };
355
356 struct NestedInput : public mtf::HeadlessInProcessServer
357 {
358+ Display display{display_geometry};
359+ NestedInput()
360+ {
361+ preset_display(mt::fake_shared(display));
362+ }
363+
364 void SetUp()
365 {
366- initial_display_layout(display_geometry);
367 mtf::HeadlessInProcessServer::SetUp();
368 }
369
370@@ -143,10 +232,10 @@
371 {
372 public:
373 using UniqueInputConfig = std::unique_ptr<MirInputConfig , void(*)(MirInputConfig const*)>;
374- ExposedSurface(std::string const& connect_string)
375+ ExposedSurface(std::string const& connect_string, std::string const& session_name = "ExposedSurface")
376 {
377 // Ensure the nested server posts a frame
378- connection = mir_connect_sync(connect_string.c_str(), __PRETTY_FUNCTION__);
379+ connection = mir_connect_sync(connect_string.c_str(), session_name.c_str());
380
381 mir_connection_set_input_config_change_callback(
382 connection,
383@@ -163,6 +252,8 @@
384 }
385
386 MOCK_METHOD1(handle_input, void(MirEvent const*));
387+ MOCK_METHOD1(handle_device_state, void(MirEvent const*));
388+ MOCK_METHOD0(handle_keymap, void());
389
390 void handle_window_event(MirWindowEvent const* event)
391 {
392@@ -177,7 +268,12 @@
393 mir_window_focus_state_focused == value)
394 focused = true;
395
396- if (exposed && focused)
397+ test_and_raise();
398+ }
399+
400+ void test_and_raise()
401+ {
402+ if (exposed && focused && input_device_state_received)
403 ready_to_accept_events.raise();
404 }
405
406@@ -207,8 +303,17 @@
407 client->handle_window_event(window_event);
408
409 }
410+ if (type == mir_event_type_keymap)
411+ client->handle_keymap();
412 if (type == mir_event_type_input)
413 client->handle_input(ev);
414+ if (type == mir_event_type_input_device_state)
415+ {
416+ client->input_device_state_received = true;
417+ client->test_and_raise();
418+ client->handle_device_state(ev);
419+ }
420+
421 }
422
423 static void null_event_handler(MirWindow*, MirEvent const*, void*) {};
424@@ -229,6 +334,7 @@
425 MirWindow *window;
426 bool exposed{false};
427 bool focused{false};
428+ bool input_device_state_received = false;
429 std::function<void(MirInputConfig const* confg)> input_config{[](MirInputConfig const*){}};
430 };
431
432@@ -243,15 +349,14 @@
433
434 InSequence seq;
435 EXPECT_CALL(nested_event_filter, handle(mt::InputDeviceStateEvent()))
436- .WillOnce(DoAll(mt::WakeUp(&devices_ready), Return(true)));
437+ .WillOnce(mt::WakeUp(&devices_ready));
438 EXPECT_CALL(nested_event_filter, handle(mt::KeyOfScanCode(KEY_A))).
439 Times(AtLeast(1)).
440- WillRepeatedly(DoAll(InvokeWithoutArgs(increase_key_a_events), Return(true)));
441+ WillRepeatedly(InvokeWithoutArgs(increase_key_a_events));
442
443 EXPECT_CALL(nested_event_filter, handle(mt::KeyOfScanCode(KEY_RIGHTSHIFT))).
444 Times(2).
445- WillOnce(Return(true)).
446- WillOnce(DoAll(mt::WakeUp(&all_events_received), Return(true)));
447+ WillOnce(mt::WakeUp(&all_events_received));
448
449 NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
450 ExposedSurface client(nested_mir.new_connection());
451@@ -348,7 +453,7 @@
452 .WillOnce(mt::WakeUp(&client_to_host_event_received));
453 EXPECT_CALL(nested_event_filter,
454 handle(mt::DeviceStateWithPressedKeys(std::vector<uint32_t>({KEY_LEFTALT, KEY_TAB}))))
455- .WillOnce(DoAll(mt::WakeUp(&client_to_nested_event_received), Return(true)));
456+ .WillOnce(mt::WakeUp(&client_to_nested_event_received));
457
458 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_LEFTALT));
459 fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_TAB));
460@@ -367,12 +472,12 @@
461 mt::Signal devices_ready;
462 mt::Signal event_received;
463 EXPECT_CALL(nested_event_filter, handle(mt::InputDeviceStateEvent()))
464- .WillOnce(DoAll(mt::WakeUp(&devices_ready), Return(true)));
465+ .WillOnce(mt::WakeUp(&devices_ready));
466
467 EXPECT_CALL(nested_event_filter,
468 handle(AllOf(mt::PointerEventWithPosition(initial_movement_x, initial_movement_y),
469 mt::PointerEventWithDiff(initial_movement_x, initial_movement_y))))
470- .WillOnce(DoAll(mt::WakeUp(&event_received), Return(true)));
471+ .WillOnce(mt::WakeUp(&event_received));
472
473 NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
474 ExposedSurface client_to_nested_mir(nested_mir.new_connection());
475@@ -388,7 +493,7 @@
476 EXPECT_CALL(nested_event_filter,
477 handle(AllOf(mt::PointerEventWithPosition(initial_movement_x + second_movement_x, initial_movement_y + second_movement_y),
478 mt::PointerEventWithDiff(second_movement_x, second_movement_y))))
479- .WillOnce(DoAll(mt::WakeUp(&event_received), Return(true)));
480+ .WillOnce(mt::WakeUp(&event_received));
481
482 fake_mouse->emit_event(mis::a_pointer_event().with_movement(second_movement_x, second_movement_y));
483 ASSERT_TRUE(event_received.wait_for(60s));
484@@ -410,11 +515,11 @@
485
486 EXPECT_CALL(nested_event_filter, handle(
487 mt::DeviceStateWithPosition(initial_x, initial_y)))
488- .WillOnce(DoAll(mt::WakeUp(&devices_ready), Return(true)));
489+ .WillOnce(mt::WakeUp(&devices_ready));
490 EXPECT_CALL(nested_event_filter,
491 handle(AllOf(mt::PointerEventWithPosition(final_x, final_y),
492 mt::PointerEventWithDiff(x[2], y[2]))))
493- .WillOnce(DoAll(mt::WakeUp(&event_received), Return(true)));
494+ .WillOnce(mt::WakeUp(&event_received));
495
496 NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
497 ExposedSurface client_to_nested_mir(nested_mir.new_connection());
498@@ -464,3 +569,44 @@
499 EXPECT_THAT(mir_pointer_config_get_acceleration_bias(ptr_conf), acceleration_bias);
500 }
501
502+TEST_F(NestedInput, pressed_keys_on_vt_switch_are_forgotten)
503+{
504+ mt::Signal keymap_received;
505+ mt::Signal devices_ready;
506+ mt::Signal initial_keys_received;
507+ mt::Signal keys_without_modifier_received;
508+ NiceMock<MockEventFilter> nested_event_filter;
509+ ON_CALL(nested_event_filter, handle(
510+ mt::InputDeviceStateEvent()))
511+ .WillByDefault(mt::WakeUp(&devices_ready));
512+
513+ NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
514+ ExposedSurface client_to_nested(nested_mir.new_connection(), "with_keymap");
515+
516+ ASSERT_TRUE(devices_ready.wait_for(10s));
517+ EXPECT_CALL(client_to_nested, handle_keymap())
518+ .WillOnce(mt::WakeUp(&keymap_received));
519+ EXPECT_CALL(client_to_nested, handle_input(mt::KeyOfScanCode(KEY_RIGHTALT)));
520+ EXPECT_CALL(client_to_nested, handle_input(mt::KeyOfScanCode(KEY_RIGHTCTRL)))
521+ .WillOnce(mt::WakeUp(&initial_keys_received));
522+
523+ nested_mir.get_surface("with_keymap")->set_keymap(MirInputDeviceId{0}, "pc105", "de", "", "");
524+
525+ ASSERT_TRUE(client_to_nested.ready_to_accept_events.wait_for(10s));
526+ EXPECT_TRUE(keymap_received.wait_for(10s));
527+
528+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_RIGHTALT));
529+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_RIGHTCTRL));
530+
531+ EXPECT_TRUE(initial_keys_received.wait_for(10s));
532+
533+ display.trigger_pause();
534+ display.trigger_resume();
535+
536+ EXPECT_CALL(client_to_nested,
537+ handle_input(AllOf(mt::KeyOfScanCode(KEY_A), mt::KeyWithModifiers(mir_input_event_modifier_none))))
538+ .WillOnce(mt::WakeUp(&keys_without_modifier_received));
539+
540+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_A));
541+ EXPECT_TRUE(keys_without_modifier_received.wait_for(10s));
542+}
543
544=== modified file 'tests/include/mir/test/test_protobuf_client.h'
545--- tests/include/mir/test/test_protobuf_client.h 2017-01-18 02:29:37 +0000
546+++ tests/include/mir/test/test_protobuf_client.h 2017-03-23 16:39:46 +0000
547@@ -33,7 +33,11 @@
548
549 namespace mir
550 {
551-namespace client { namespace rpc {class MirBasicRpcChannel;}}
552+namespace client
553+{
554+class SurfaceMap;
555+namespace rpc {class MirBasicRpcChannel;}
556+}
557 namespace dispatch
558 {
559 class ThreadedDispatcher;
560@@ -49,6 +53,7 @@
561 TestProtobufClient(std::string socket_file, int timeout_ms);
562
563 std::shared_ptr<doubles::MockRpcReport> rpc_report;
564+ std::shared_ptr<mir::client::SurfaceMap> surface_map;
565 std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> channel;
566 std::shared_ptr<dispatch::ThreadedDispatcher> eventloop;
567 mir::client::rpc::DisplayServer display_server;
568
569=== modified file 'tests/mir_test_doubles/test_protobuf_client.cpp'
570--- tests/mir_test_doubles/test_protobuf_client.cpp 2017-01-18 02:29:37 +0000
571+++ tests/mir_test_doubles/test_protobuf_client.cpp 2017-03-23 16:39:46 +0000
572@@ -42,12 +42,13 @@
573
574 mir::test::TestProtobufClient::TestProtobufClient(std::string socket_file, int timeout_ms) :
575 rpc_report(std::make_shared<testing::NiceMock<doubles::MockRpcReport>>()),
576+ surface_map{std::make_shared<mir::client::ConnectionSurfaceMap>()},
577 channel(mclr::make_rpc_channel(
578 socket_file,
579- std::make_shared<mir::client::ConnectionSurfaceMap>(),
580+ surface_map,
581 std::make_shared<mir::client::BufferFactory>(),
582 std::make_shared<mir::client::DisplayConfiguration>(),
583- std::make_shared<mir::input::InputDevices>(),
584+ std::make_shared<mir::input::InputDevices>(surface_map),
585 rpc_report,
586 std::make_shared<mir::client::LifecycleControl>(),
587 std::make_shared<mir::client::AtomicCallback<int32_t>>(),
588
589=== modified file 'tests/unit-tests/client/test_protobuf_rpc_channel.cpp'
590--- tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2017-03-10 19:47:57 +0000
591+++ tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2017-03-23 16:39:46 +0000
592@@ -19,7 +19,6 @@
593 #include "src/client/rpc/mir_protobuf_rpc_channel.h"
594 #include "src/client/rpc/stream_transport.h"
595 #include "src/client/rpc/mir_display_server.h"
596-#include "src/client/surface_map.h"
597 #include "src/client/display_configuration.h"
598 #include "src/client/rpc/null_rpc_report.h"
599 #include "src/client/lifecycle_control.h"
600@@ -29,6 +28,7 @@
601 #include "mir/variable_length_array.h"
602 #include "mir_protobuf.pb.h"
603 #include "mir_protobuf_wire.pb.h"
604+#include "mir/client/surface_map.h"
605 #include "mir/input/input_devices.h"
606
607 #include "mir/test/doubles/null_client_event_sink.h"
608@@ -67,7 +67,9 @@
609 MOCK_METHOD2(insert, void(int, std::shared_ptr<mcl::MirBuffer> const&));
610 MOCK_METHOD2(insert, void(mir::frontend::BufferStreamId, std::shared_ptr<MirPresentationChain> const&));
611 MOCK_METHOD1(erase, void(int));
612-};
613+ MOCK_CONST_METHOD1(with_all_windows_do,
614+ void(std::function<void(MirWindow*)> const&));
615+};
616
617 class StubSurfaceMap : public mcl::SurfaceMap
618 {
619@@ -96,6 +98,9 @@
620 void erase(int) override
621 {
622 }
623+ void with_all_windows_do(std::function<void(MirWindow*)> const&) const override
624+ {
625+ }
626 };
627
628 class MockStreamTransport : public mclr::StreamTransport
629@@ -235,12 +240,13 @@
630 MirProtobufRpcChannelTest()
631 : transport{new testing::NiceMock<MockStreamTransport>},
632 lifecycle{std::make_shared<mcl::LifecycleControl>()},
633+ surface_map{std::make_shared<StubSurfaceMap>()},
634 channel{new mclr::MirProtobufRpcChannel{
635 std::unique_ptr<MockStreamTransport>{transport},
636- std::make_shared<StubSurfaceMap>(),
637+ surface_map,
638 std::make_shared<mcl::BufferFactory>(),
639 std::make_shared<mcl::DisplayConfiguration>(),
640- std::make_shared<mir::input::InputDevices>(),
641+ std::make_shared<mir::input::InputDevices>(surface_map),
642 std::make_shared<mclr::NullRpcReport>(),
643 lifecycle,
644 std::make_shared<mir::client::PingHandler>(),
645@@ -251,6 +257,7 @@
646
647 MockStreamTransport* transport;
648 std::shared_ptr<mcl::LifecycleControl> lifecycle;
649+ std::shared_ptr<mcl::SurfaceMap> surface_map;
650 std::shared_ptr<mclr::MirProtobufRpcChannel> channel;
651 mtd::MockMirBufferStream stream;
652 };
653@@ -395,7 +402,7 @@
654 stream_map,
655 std::make_shared<mcl::BufferFactory>(),
656 std::make_shared<mcl::DisplayConfiguration>(),
657- std::make_shared<mir::input::InputDevices>(),
658+ std::make_shared<mir::input::InputDevices>(stream_map),
659 std::make_shared<mclr::NullRpcReport>(),
660 lifecycle,
661 std::make_shared<mir::client::PingHandler>(),
662@@ -745,7 +752,7 @@
663 stream_map,
664 mock_buffer_factory,
665 std::make_shared<mcl::DisplayConfiguration>(),
666- std::make_shared<mir::input::InputDevices>(),
667+ std::make_shared<mir::input::InputDevices>(stream_map),
668 std::make_shared<mclr::NullRpcReport>(),
669 lifecycle,
670 std::make_shared<mir::client::PingHandler>(),
671@@ -780,7 +787,7 @@
672 stream_map,
673 mock_buffer_factory,
674 std::make_shared<mcl::DisplayConfiguration>(),
675- std::make_shared<mir::input::InputDevices>(),
676+ std::make_shared<mir::input::InputDevices>(stream_map),
677 std::make_shared<mclr::NullRpcReport>(),
678 lifecycle,
679 std::make_shared<mir::client::PingHandler>(),
680@@ -813,7 +820,7 @@
681 stream_map,
682 mock_buffer_factory,
683 std::make_shared<mcl::DisplayConfiguration>(),
684- std::make_shared<mir::input::InputDevices>(),
685+ std::make_shared<mir::input::InputDevices>(stream_map),
686 std::make_shared<mclr::NullRpcReport>(),
687 lifecycle,
688 std::make_shared<mir::client::PingHandler>(),
689
690=== modified file 'tests/unit-tests/frontend/stress_protobuf_communicator.cpp'
691--- tests/unit-tests/frontend/stress_protobuf_communicator.cpp 2017-03-20 12:08:08 +0000
692+++ tests/unit-tests/frontend/stress_protobuf_communicator.cpp 2017-03-23 16:39:46 +0000
693@@ -59,6 +59,7 @@
694 StubProtobufClient(std::string socket_file, int timeout_ms);
695
696 std::shared_ptr<mir::client::rpc::RpcReport> rpc_report;
697+ std::shared_ptr<mir::client::SurfaceMap> surface_map;
698 std::shared_ptr<mir::client::rpc::MirBasicRpcChannel> channel;
699 mir::client::rpc::DisplayServer display_server;
700 mir::protobuf::ConnectParameters connect_parameters;
701@@ -162,12 +163,13 @@
702 std::string socket_file,
703 int timeout_ms) :
704 rpc_report(std::make_shared<mir::client::rpc::NullRpcReport>()),
705+ surface_map(std::make_shared<mir::client::ConnectionSurfaceMap>()),
706 channel(mir::client::rpc::make_rpc_channel(
707 socket_file,
708- std::make_shared<mir::client::ConnectionSurfaceMap>(),
709+ surface_map,
710 std::make_shared<mir::client::BufferFactory>(),
711 std::make_shared<mir::client::DisplayConfiguration>(),
712- std::make_shared<mir::input::InputDevices>(),
713+ std::make_shared<mir::input::InputDevices>(surface_map),
714 rpc_report,
715 std::make_shared<mir::client::LifecycleControl>(),
716 std::make_shared<mir::client::PingHandler>(),

Subscribers

People subscribed via source and target branches