Merge lp:~mir-team/mir/add-keymap-change-support into lp:mir
- add-keymap-change-support
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2336 |
Proposed branch: | lp:~mir-team/mir/add-keymap-change-support |
Merge into: | lp:mir |
Diff against target: |
1134 lines (+381/-60) 37 files modified
include/common/mir/events/event_builders.h (+2/-0) include/common/mir/input/input_platform.h (+3/-1) include/common/mir_toolkit/events/event.h (+14/-1) include/common/mir_toolkit/events/event_deprecated.h (+12/-1) include/common/mir_toolkit/events/keymap_event.h (+48/-0) include/server/mir/scene/null_surface_observer.h (+1/-0) include/server/mir/scene/surface.h (+2/-0) include/server/mir/scene/surface_observer.h (+2/-0) src/client/mir_surface.cpp (+11/-3) src/client/mir_surface.h (+2/-0) src/client/rpc/mir_protobuf_rpc_channel.cpp (+3/-1) src/common/event.cpp (+14/-0) src/common/events/event_builders.cpp (+12/-0) src/common/input/CMakeLists.txt (+1/-1) src/common/input/android/android_input_platform.cpp (+2/-2) src/common/input/android/android_input_platform.h (+1/-1) src/common/input/android/android_input_receiver.cpp (+9/-6) src/common/input/android/android_input_receiver.h (+3/-2) src/common/input/xkb_mapper.cpp (+17/-4) src/common/symbols.map (+7/-0) src/include/common/mir/input/xkb_mapper.h (+6/-1) src/include/server/mir/scene/surface_event_source.h (+1/-0) src/server/input/cursor_controller.cpp (+2/-2) src/server/scene/basic_surface.cpp (+11/-0) src/server/scene/basic_surface.h (+3/-0) src/server/scene/legacy_surface_change_notification.cpp (+5/-0) src/server/scene/legacy_surface_change_notification.h (+1/-0) src/server/scene/null_surface_observer.cpp (+1/-0) src/server/scene/surface_event_source.cpp (+5/-0) tests/acceptance-tests/throwback/test_client_input.cpp (+80/-0) tests/include/mir_test/event_matchers.h (+22/-0) tests/include/mir_test_doubles/stub_scene_surface.h (+2/-0) tests/integration-tests/test_test_framework.cpp (+40/-12) tests/unit-tests/client/input/test_android_input_receiver.cpp (+18/-7) tests/unit-tests/client/input/test_android_input_receiver_thread.cpp (+2/-1) tests/unit-tests/client/input/test_xkb_mapper.cpp (+12/-10) tests/unit-tests/client/test_client_mir_surface.cpp (+4/-4) |
To merge this branch: | bzr merge lp:~mir-team/mir/add-keymap-change-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Andreas Pokorny (community) | Approve | ||
Kevin DuBois (community) | Approve | ||
Chris Halse Rogers | Approve | ||
Alan Griffiths | Approve | ||
Review via email: mp+248719@code.launchpad.net |
Commit message
Introduce ms::Surface:
Description of the change
Introduce an API for shells to set the keymap for a surface. Required to implement the keyboard indicator.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2291
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Chris Halse Rogers (raof) wrote : | # |
709 +void ms::NullSurface
710 + xkb_rule_names const& /* names */) {}
Strange carriage return?
Otherwise OK.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2292
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Robert Carr (robertcarr) wrote : | # |
Whitespace fixed. CI error unrelated timeout (bumped)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2294
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2295
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Robert Carr (robertcarr) wrote : | # |
Its not the timeouts :( its weird behavior due to the FD limit test based leak check test and the movement of where XKB rule files are opened in the surface creation sequence...should get time to check tomorrow
Robert Carr (robertcarr) wrote : | # |
Made the test pass via a different method of counting FDs...there are some weird questions...
1. Why did it ever pass? Wasn't there a connection FD too meaning the last surface should have failed to create (due to its input FD being past the limit).
2. Why did the introduction of an additional fd per surface (per keymap) cause the test to fail intermittently in amd64 valgrind and nowhere else? and NOT due to timeouts?
These are the questions of our age. Anyway I believe the test is more robust now...
see "surface_
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2297
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Andreas Pokorny (andreas-pokorny) wrote : | # |
I just tried my favorite layout us + intl variant, with some of the composed keys. It maps them to dead key key symbols, but does not yield any of the composed symbols. A different part of the xkb API is needed for that, and I guess some more extensions to MirEvent?
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2298
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2299
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Chris Halse Rogers (raof) wrote : | # |
Looks good to me now.
@Andreas: I think we've decided that dead keys, compose keys, etc are an input method (albeit a very simple one) and will treat them as such.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2300
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2301
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Andreas Pokorny (andreas-pokorny) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2302
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2303
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2304
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'include/common/mir/events/event_builders.h' |
2 | --- include/common/mir/events/event_builders.h 2015-02-13 06:12:34 +0000 |
3 | +++ include/common/mir/events/event_builders.h 2015-02-20 18:01:07 +0000 |
4 | @@ -46,6 +46,8 @@ |
5 | EventUPtr make_event(frontend::SurfaceId const& surface_id, MirSurfaceAttrib attribute, int value); |
6 | // Close surface event |
7 | EventUPtr make_event(frontend::SurfaceId const& surface_id); |
8 | +// Keymap event |
9 | +EventUPtr make_event(frontend::SurfaceId const& surface_id, xkb_rule_names const& names); |
10 | |
11 | // Key event |
12 | EventUPtr make_event(MirInputDeviceId device_id, int64_t timestamp, |
13 | |
14 | === modified file 'include/common/mir/input/input_platform.h' |
15 | --- include/common/mir/input/input_platform.h 2015-01-21 07:34:50 +0000 |
16 | +++ include/common/mir/input/input_platform.h 2015-02-20 18:01:07 +0000 |
17 | @@ -32,6 +32,7 @@ |
18 | { |
19 | class InputReceiverThread; |
20 | class InputReceiverReport; |
21 | +class XKBMapper; |
22 | |
23 | // Interface for MirSurface to construct input dispatcher threads. |
24 | class InputPlatform |
25 | @@ -39,7 +40,8 @@ |
26 | public: |
27 | virtual ~InputPlatform() {}; |
28 | |
29 | - virtual std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback) = 0; |
30 | + virtual std::shared_ptr<InputReceiverThread> create_input_thread( |
31 | + int fd, std::shared_ptr<XKBMapper> const& xkb_mapper, std::function<void(MirEvent *)> const& callback) = 0; |
32 | |
33 | static std::shared_ptr<InputPlatform> create(); |
34 | static std::shared_ptr<InputPlatform> create(std::shared_ptr<InputReceiverReport> const& report); |
35 | |
36 | === modified file 'include/common/mir_toolkit/events/event.h' |
37 | --- include/common/mir_toolkit/events/event.h 2015-02-13 06:12:34 +0000 |
38 | +++ include/common/mir_toolkit/events/event.h 2015-02-20 18:01:07 +0000 |
39 | @@ -42,7 +42,8 @@ |
40 | mir_event_type_close_surface, |
41 | /* Type for new style input event will be returned from mir_event_get_type |
42 | when old style event type was mir_event_type_key or mir_event_type_motion */ |
43 | - mir_event_type_input |
44 | + mir_event_type_input, |
45 | + mir_event_type_keymap |
46 | } MirEventType; |
47 | |
48 | typedef struct MirSurfaceEvent MirSurfaceEvent; |
49 | @@ -51,6 +52,7 @@ |
50 | typedef struct MirOrientationEvent MirOrientationEvent; |
51 | typedef struct MirCloseSurfaceEvent MirCloseSurfaceEvent; |
52 | typedef struct MirInputEvent MirInputEvent; |
53 | +typedef struct MirKeymapEvent MirKeymapEvent; |
54 | |
55 | typedef union MirEvent MirEvent; |
56 | |
57 | @@ -73,6 +75,7 @@ |
58 | #include "mir_toolkit/events/surface_event.h" |
59 | #include "mir_toolkit/events/orientation_event.h" |
60 | #include "mir_toolkit/events/prompt_session_event.h" |
61 | +#include "mir_toolkit/events/keymap_event.h" |
62 | |
63 | #ifdef __cplusplus |
64 | /** |
65 | @@ -153,6 +156,16 @@ |
66 | MirCloseSurfaceEvent const* mir_event_get_close_surface_event(MirEvent const* ev); |
67 | |
68 | /* |
69 | + * Retrieve the MirKeymapEvent associated with a MirEvent of |
70 | + * type mir_event_type_keymap. The event signifies that the keymap |
71 | + * applied for the relevant surface has changed. |
72 | + * |
73 | + * \param [in] event The event |
74 | + * \return The associated MirKeymapEvent |
75 | + */ |
76 | +MirKeymapEvent const* mir_event_get_keymap_event(MirEvent const* ev); |
77 | + |
78 | +/* |
79 | * |
80 | * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
81 | * _________________________ |
82 | |
83 | === modified file 'include/common/mir_toolkit/events/event_deprecated.h' |
84 | --- include/common/mir_toolkit/events/event_deprecated.h 2014-12-17 21:37:34 +0000 |
85 | +++ include/common/mir_toolkit/events/event_deprecated.h 2015-02-20 18:01:07 +0000 |
86 | @@ -29,6 +29,8 @@ |
87 | #include <stdint.h> |
88 | #include "mir_toolkit/common.h" |
89 | |
90 | +#include <xkbcommon/xkbcommon.h> |
91 | + |
92 | #ifdef __cplusplus |
93 | /** |
94 | * \addtogroup mir_toolkit |
95 | @@ -234,9 +236,17 @@ |
96 | int surface_id; |
97 | }; |
98 | |
99 | +struct MirKeymapEvent |
100 | +{ |
101 | + MirEventType type; |
102 | + |
103 | + int surface_id; |
104 | + struct xkb_rule_names rules; |
105 | +}; |
106 | + |
107 | +// Access to MirEvent is deprecated |
108 | union MirEvent |
109 | { |
110 | - // Direct access to the type member is deprecated. Instead use mir_event_get_type. |
111 | MirEventType type; |
112 | MirKeyEvent key; |
113 | MirMotionEvent motion; |
114 | @@ -245,6 +255,7 @@ |
115 | MirPromptSessionEvent prompt_session; |
116 | MirOrientationEvent orientation; |
117 | MirCloseSurfaceEvent close_surface; |
118 | + MirKeymapEvent keymap; |
119 | }; |
120 | |
121 | #ifdef __cplusplus |
122 | |
123 | === added file 'include/common/mir_toolkit/events/keymap_event.h' |
124 | --- include/common/mir_toolkit/events/keymap_event.h 1970-01-01 00:00:00 +0000 |
125 | +++ include/common/mir_toolkit/events/keymap_event.h 2015-02-20 18:01:07 +0000 |
126 | @@ -0,0 +1,48 @@ |
127 | +/* |
128 | + * Copyright © 2014 Canonical Ltd. |
129 | + * |
130 | + * This program is free software: you can redistribute it and/or modify it |
131 | + * under the terms of the GNU Lesser General Public License version 3, |
132 | + * as published by the Free Software Foundation. |
133 | + * |
134 | + * This program is distributed in the hope that it will be useful, |
135 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
136 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
137 | + * GNU Lesser General Public License for more details. |
138 | + * |
139 | + * You should have received a copy of the GNU Lesser General Public License |
140 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
141 | + * |
142 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
143 | + */ |
144 | + |
145 | +#ifndef MIR_TOOLKIT_EVENTS_KEYMAP_EVENT_H_ |
146 | +#define MIR_TOOLKIT_EVENTS_KEYMAP_EVENT_H_ |
147 | + |
148 | +#include <mir_toolkit/events/event.h> |
149 | + |
150 | +#include <xkbcommon/xkbcommon.h> |
151 | + |
152 | +#ifdef __cplusplus |
153 | +/** |
154 | + * \addtogroup mir_toolkit |
155 | + * @{ |
156 | + */ |
157 | +extern "C" { |
158 | +#endif |
159 | + |
160 | +/* |
161 | + * Retrieve the new keymap reported by this MirKeymapEvent |
162 | + * |
163 | + * \param[in] ev The keymap event |
164 | + * \param[out] rules XKB rules describing the new keymap. |
165 | + */ |
166 | +void mir_keymap_event_get_rules(MirKeymapEvent const* ev, |
167 | + struct xkb_rule_names* names); |
168 | + |
169 | +#ifdef __cplusplus |
170 | +} |
171 | +/**@}*/ |
172 | +#endif |
173 | + |
174 | +#endif /* MIR_TOOLKIT_KEYMAP_EVENT_H_ */ |
175 | |
176 | === modified file 'include/server/mir/scene/null_surface_observer.h' |
177 | --- include/server/mir/scene/null_surface_observer.h 2015-01-21 07:34:50 +0000 |
178 | +++ include/server/mir/scene/null_surface_observer.h 2015-02-20 18:01:07 +0000 |
179 | @@ -42,6 +42,7 @@ |
180 | void cursor_image_set_to(graphics::CursorImage const& image) override; |
181 | void reception_mode_set_to(input::InputReceptionMode mode) override; |
182 | void client_surface_close_requested() override; |
183 | + void keymap_changed(xkb_rule_names const& names) override; |
184 | |
185 | protected: |
186 | NullSurfaceObserver(NullSurfaceObserver const&) = delete; |
187 | |
188 | === modified file 'include/server/mir/scene/surface.h' |
189 | --- include/server/mir/scene/surface.h 2015-01-23 03:50:26 +0000 |
190 | +++ include/server/mir/scene/surface.h 2015-02-20 18:01:07 +0000 |
191 | @@ -105,6 +105,8 @@ |
192 | virtual int configure(MirSurfaceAttrib attrib, int value) = 0; |
193 | // TODO a legacy of old interactions and needs removing |
194 | virtual int query(MirSurfaceAttrib attrib) = 0; |
195 | + |
196 | + virtual void set_keymap(xkb_rule_names const& rules) = 0; |
197 | }; |
198 | } |
199 | } |
200 | |
201 | === modified file 'include/server/mir/scene/surface_observer.h' |
202 | --- include/server/mir/scene/surface_observer.h 2015-01-21 07:34:50 +0000 |
203 | +++ include/server/mir/scene/surface_observer.h 2015-02-20 18:01:07 +0000 |
204 | @@ -24,6 +24,7 @@ |
205 | #include "mir/input/input_reception_mode.h" |
206 | |
207 | #include <glm/glm.hpp> |
208 | +#include <xkbcommon/xkbcommon.h> |
209 | |
210 | namespace mir |
211 | { |
212 | @@ -53,6 +54,7 @@ |
213 | virtual void reception_mode_set_to(input::InputReceptionMode mode) = 0; |
214 | virtual void cursor_image_set_to(graphics::CursorImage const& image) = 0; |
215 | virtual void client_surface_close_requested() = 0; |
216 | + virtual void keymap_changed(xkb_rule_names const& names) = 0; |
217 | |
218 | protected: |
219 | SurfaceObserver() = default; |
220 | |
221 | === modified file 'src/client/mir_surface.cpp' |
222 | --- src/client/mir_surface.cpp 2015-02-13 06:12:34 +0000 |
223 | +++ src/client/mir_surface.cpp 2015-02-20 18:01:07 +0000 |
224 | @@ -25,6 +25,7 @@ |
225 | #include "mir_connection.h" |
226 | #include "mir/input/input_receiver_thread.h" |
227 | #include "mir/input/input_platform.h" |
228 | +#include "mir/input/xkb_mapper.h" |
229 | |
230 | #include <cassert> |
231 | #include <unistd.h> |
232 | @@ -118,7 +119,8 @@ |
233 | name{spec.surface_name.value()}, |
234 | connection(allocating_connection), |
235 | buffer_stream_factory(buffer_stream_factory), |
236 | - input_platform(input_platform) |
237 | + input_platform(input_platform), |
238 | + keymapper(std::make_shared<mircv::XKBMapper>()) |
239 | { |
240 | for (int i = 0; i < mir_surface_attribs; i++) |
241 | attrib_cache[i] = -1; |
242 | @@ -433,8 +435,7 @@ |
243 | |
244 | if (surface.fd_size() > 0 && handle_event_callback) |
245 | { |
246 | - input_thread = input_platform->create_input_thread(surface.fd(0), |
247 | - handle_event_callback); |
248 | + input_thread = input_platform->create_input_thread(surface.fd(0), keymapper, handle_event_callback); |
249 | input_thread->start(); |
250 | } |
251 | } |
252 | @@ -457,6 +458,13 @@ |
253 | case mir_event_type_orientation: |
254 | orientation = mir_orientation_event_get_direction(mir_event_get_orientation_event(&e)); |
255 | break; |
256 | + case mir_event_type_keymap: |
257 | + { |
258 | + xkb_rule_names names; |
259 | + mir_keymap_event_get_rules(mir_event_get_keymap_event(&e), &names); |
260 | + keymapper->set_rules(names); |
261 | + break; |
262 | + } |
263 | default: |
264 | break; |
265 | }; |
266 | |
267 | === modified file 'src/client/mir_surface.h' |
268 | --- src/client/mir_surface.h 2015-02-13 06:12:34 +0000 |
269 | +++ src/client/mir_surface.h 2015-02-20 18:01:07 +0000 |
270 | @@ -43,6 +43,7 @@ |
271 | { |
272 | class InputPlatform; |
273 | class InputReceiverThread; |
274 | +class XKBMapper; |
275 | } |
276 | } |
277 | namespace client |
278 | @@ -159,6 +160,7 @@ |
279 | std::shared_ptr<mir::client::ClientBufferStreamFactory> const buffer_stream_factory; |
280 | std::shared_ptr<mir::client::ClientBufferStream> buffer_stream; |
281 | std::shared_ptr<mir::input::receiver::InputPlatform> const input_platform; |
282 | + std::shared_ptr<mir::input::receiver::XKBMapper> const keymapper; |
283 | |
284 | mir::protobuf::SurfaceSetting configure_result; |
285 | |
286 | |
287 | === modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp' |
288 | --- src/client/rpc/mir_protobuf_rpc_channel.cpp 2015-02-13 06:12:34 +0000 |
289 | +++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2015-02-20 18:01:07 +0000 |
290 | @@ -283,7 +283,9 @@ |
291 | case mir_event_type_close_surface: |
292 | surface_map->with_surface_do(e.close_surface.surface_id, send_e); |
293 | break; |
294 | - |
295 | + case mir_event_type_keymap: |
296 | + surface_map->with_surface_do(e.keymap.surface_id, send_e); |
297 | + break; |
298 | default: |
299 | event_sink->handle_event(e); |
300 | } |
301 | |
302 | === modified file 'src/common/event.cpp' |
303 | --- src/common/event.cpp 2014-12-18 19:11:01 +0000 |
304 | +++ src/common/event.cpp 2015-02-20 18:01:07 +0000 |
305 | @@ -133,6 +133,13 @@ |
306 | return &ev->close_surface; |
307 | } |
308 | |
309 | +MirKeymapEvent const* mir_event_get_keymap_event(MirEvent const* ev) |
310 | +{ |
311 | + expect_event_type(ev, mir_event_type_keymap); |
312 | + |
313 | + return &ev->keymap; |
314 | +} |
315 | + |
316 | /* Surface event accessors */ |
317 | |
318 | MirSurfaceAttrib mir_surface_event_get_attribute(MirSurfaceEvent const* ev) |
319 | @@ -179,6 +186,13 @@ |
320 | return ev->direction; |
321 | } |
322 | |
323 | +/* Keymap event accessors */ |
324 | + |
325 | +void mir_keymap_event_get_rules(MirKeymapEvent const* ev, xkb_rule_names *out_names) |
326 | +{ |
327 | + expect_event_type(ev, mir_event_type_keymap); |
328 | + *out_names = ev->rules; |
329 | +} |
330 | |
331 | // TODO: Until we opaquify the MirEvent structure and add |
332 | // a ref count ref is implemented as copy. |
333 | |
334 | === modified file 'src/common/events/event_builders.cpp' |
335 | --- src/common/events/event_builders.cpp 2015-02-13 06:12:34 +0000 |
336 | +++ src/common/events/event_builders.cpp 2015-02-20 18:01:07 +0000 |
337 | @@ -352,3 +352,15 @@ |
338 | |
339 | return make_event_uptr(e); |
340 | } |
341 | + |
342 | +mir::EventUPtr mev::make_event(mf::SurfaceId const& surface_id, xkb_rule_names const& rules) |
343 | +{ |
344 | + MirEvent *e = new MirEvent; |
345 | + memset(e, 0, sizeof (MirEvent)); |
346 | + |
347 | + e->type = mir_event_type_keymap; |
348 | + e->keymap.surface_id = surface_id.as_value(); |
349 | + e->keymap.rules = rules; |
350 | + |
351 | + return make_event_uptr(e); |
352 | +} |
353 | |
354 | === modified file 'src/common/input/CMakeLists.txt' |
355 | --- src/common/input/CMakeLists.txt 2015-01-21 07:34:50 +0000 |
356 | +++ src/common/input/CMakeLists.txt 2015-02-20 18:01:07 +0000 |
357 | @@ -16,7 +16,6 @@ |
358 | |
359 | set( |
360 | ANDROID_SHARED_INPUT_SOURCES |
361 | - ${CMAKE_CURRENT_SOURCE_DIR}/xkb_mapper.cpp |
362 | ) |
363 | |
364 | include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) |
365 | @@ -28,6 +27,7 @@ |
366 | ${ANDROID_SHARED_INPUT_SOURCES} |
367 | udev_wrapper.cpp |
368 | input_event.cpp |
369 | + ${CMAKE_CURRENT_SOURCE_DIR}/xkb_mapper.cpp |
370 | ) |
371 | |
372 | list(APPEND MIR_COMMON_SOURCES |
373 | |
374 | === modified file 'src/common/input/android/android_input_platform.cpp' |
375 | --- src/common/input/android/android_input_platform.cpp 2014-03-06 06:05:17 +0000 |
376 | +++ src/common/input/android/android_input_platform.cpp 2015-02-20 18:01:07 +0000 |
377 | @@ -35,9 +35,9 @@ |
378 | } |
379 | |
380 | std::shared_ptr<mircv::InputReceiverThread> mircva::AndroidInputPlatform::create_input_thread( |
381 | - int fd, std::function<void(MirEvent*)> const& callback) |
382 | + int fd, std::shared_ptr<mircv::XKBMapper> const& keymaper, std::function<void(MirEvent*)> const& callback) |
383 | { |
384 | - auto receiver = std::make_shared<mircva::InputReceiver>(fd, report); |
385 | + auto receiver = std::make_shared<mircva::InputReceiver>(fd, keymaper, report); |
386 | return std::make_shared<mircva::InputReceiverThread>(receiver, callback); |
387 | } |
388 | |
389 | |
390 | === modified file 'src/common/input/android/android_input_platform.h' |
391 | --- src/common/input/android/android_input_platform.h 2014-03-06 06:05:17 +0000 |
392 | +++ src/common/input/android/android_input_platform.h 2015-02-20 18:01:07 +0000 |
393 | @@ -37,7 +37,7 @@ |
394 | AndroidInputPlatform(std::shared_ptr<InputReceiverReport> const& report); |
395 | virtual ~AndroidInputPlatform(); |
396 | |
397 | - std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback); |
398 | + std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::shared_ptr<XKBMapper> const& xkb_mapper, std::function<void(MirEvent *)> const& callback); |
399 | |
400 | protected: |
401 | AndroidInputPlatform(const AndroidInputPlatform&) = delete; |
402 | |
403 | === modified file 'src/common/input/android/android_input_receiver.cpp' |
404 | --- src/common/input/android/android_input_receiver.cpp 2015-02-13 06:12:34 +0000 |
405 | +++ src/common/input/android/android_input_receiver.cpp 2015-02-20 18:01:07 +0000 |
406 | @@ -16,8 +16,6 @@ |
407 | * Authored by: Robert Carr <robert.carr@canonical.com> |
408 | */ |
409 | |
410 | -#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER |
411 | - |
412 | #include "android_input_receiver.h" |
413 | |
414 | #include "mir/input/xkb_mapper.h" |
415 | @@ -33,27 +31,29 @@ |
416 | namespace mia = mir::input::android; |
417 | |
418 | mircva::InputReceiver::InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel, |
419 | + std::shared_ptr<mircv::XKBMapper> const& keymapper, |
420 | std::shared_ptr<mircv::InputReceiverReport> const& report, |
421 | AndroidClock clock) |
422 | : input_channel(input_channel), |
423 | + xkb_mapper(keymapper), |
424 | report(report), |
425 | input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)), |
426 | looper(new droidinput::Looper(true)), |
427 | fd_added(false), |
428 | - xkb_mapper(std::make_shared<mircv::XKBMapper>()), |
429 | android_clock(clock) |
430 | { |
431 | } |
432 | |
433 | mircva::InputReceiver::InputReceiver(int fd, |
434 | + std::shared_ptr<mircv::XKBMapper> const& keymapper, |
435 | std::shared_ptr<mircv::InputReceiverReport> const& report, |
436 | AndroidClock clock) |
437 | : input_channel(new droidinput::InputChannel(droidinput::String8(""), fd)), |
438 | + xkb_mapper(keymapper), |
439 | report(report), |
440 | input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)), |
441 | looper(new droidinput::Looper(true)), |
442 | fd_added(false), |
443 | - xkb_mapper(std::make_shared<mircv::XKBMapper>()), |
444 | android_clock(clock) |
445 | { |
446 | } |
447 | @@ -74,10 +74,13 @@ |
448 | { |
449 | // TODO: As XKBMapper is used to track modifier state we need to use a seperate instance |
450 | // of XKBMapper per device id (or modify XKBMapper semantics) |
451 | - if (ev.type != mir_event_type_key) |
452 | + if (mir_event_get_type(&ev) != mir_event_type_input) |
453 | + return; |
454 | + if (mir_input_event_get_type(mir_event_get_input_event(&ev)) != |
455 | + mir_input_event_type_key) |
456 | return; |
457 | |
458 | - xkb_mapper->update_state_and_map_event(ev.key); |
459 | + xkb_mapper->update_state_and_map_event(ev); |
460 | } |
461 | |
462 | } |
463 | |
464 | === modified file 'src/common/input/android/android_input_receiver.h' |
465 | --- src/common/input/android/android_input_receiver.h 2015-02-13 06:12:34 +0000 |
466 | +++ src/common/input/android/android_input_receiver.h 2015-02-20 18:01:07 +0000 |
467 | @@ -55,9 +55,11 @@ |
468 | typedef std::function<std::chrono::nanoseconds(int)> AndroidClock; |
469 | |
470 | InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel, |
471 | + std::shared_ptr<XKBMapper> const& keymapper, |
472 | std::shared_ptr<InputReceiverReport> const& report, |
473 | AndroidClock clock = systemTime); |
474 | InputReceiver(int fd, |
475 | + std::shared_ptr<XKBMapper> const& keymapper, |
476 | std::shared_ptr<InputReceiverReport> const& report, |
477 | AndroidClock clock = systemTime); |
478 | |
479 | @@ -78,6 +80,7 @@ |
480 | |
481 | private: |
482 | droidinput::sp<droidinput::InputChannel> input_channel; |
483 | + std::shared_ptr<XKBMapper> const xkb_mapper; |
484 | std::shared_ptr<InputReceiverReport> const report; |
485 | |
486 | std::shared_ptr<droidinput::InputConsumer> input_consumer; |
487 | @@ -86,8 +89,6 @@ |
488 | |
489 | bool fd_added; |
490 | |
491 | - std::shared_ptr<XKBMapper> xkb_mapper; |
492 | - |
493 | AndroidClock const android_clock; |
494 | |
495 | bool try_next_event(MirEvent &ev); |
496 | |
497 | === modified file 'src/common/input/xkb_mapper.cpp' |
498 | --- src/common/input/xkb_mapper.cpp 2014-03-06 06:05:17 +0000 |
499 | +++ src/common/input/xkb_mapper.cpp 2015-02-20 18:01:07 +0000 |
500 | @@ -16,6 +16,8 @@ |
501 | * Authored by: Robert Carr <robert.carr@canonical.com> |
502 | */ |
503 | |
504 | +#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER |
505 | + |
506 | #include "mir/input/xkb_mapper.h" |
507 | |
508 | #include <string.h> |
509 | @@ -56,9 +58,7 @@ |
510 | names.variant = ""; |
511 | names.options = ""; |
512 | |
513 | - context = std::shared_ptr<xkb_context>(xkb_context_new(xkb_context_flags(0)), XKBContextDeleter()); |
514 | - map = std::shared_ptr<xkb_keymap>(xkb_map_new_from_names(context.get(), &names, xkb_map_compile_flags(0)), XKBKeymapDeleter()); |
515 | - state = std::shared_ptr<xkb_state>(xkb_state_new(map.get()), XKBStateDeleter()); |
516 | + set_rules(names); |
517 | } |
518 | |
519 | namespace |
520 | @@ -85,8 +85,12 @@ |
521 | |
522 | } |
523 | |
524 | -void mircv::XKBMapper::update_state_and_map_event(MirKeyEvent &key_ev) |
525 | +void mircv::XKBMapper::update_state_and_map_event(MirEvent &ev) |
526 | { |
527 | + std::unique_lock<std::mutex> lg(guard); |
528 | + |
529 | + auto &key_ev = ev.key; |
530 | + |
531 | xkb_key_direction direction; |
532 | |
533 | bool update_state = true; |
534 | @@ -106,3 +110,12 @@ |
535 | |
536 | key_ev.key_code = keysym_for_scan_code(state.get(), xkb_scan_code); |
537 | } |
538 | + |
539 | +void mircv::XKBMapper::set_rules(xkb_rule_names const& names) |
540 | +{ |
541 | + std::unique_lock<std::mutex> lg(guard); |
542 | + |
543 | + context = std::shared_ptr<xkb_context>(xkb_context_new(xkb_context_flags(0)), XKBContextDeleter()); |
544 | + map = std::shared_ptr<xkb_keymap>(xkb_map_new_from_names(context.get(), &names, xkb_map_compile_flags(0)), XKBKeymapDeleter()); |
545 | + state = std::shared_ptr<xkb_state>(xkb_state_new(map.get()), XKBStateDeleter()); |
546 | +} |
547 | |
548 | === modified file 'src/common/symbols.map' |
549 | --- src/common/symbols.map 2015-02-18 04:25:26 +0000 |
550 | +++ src/common/symbols.map 2015-02-20 18:01:07 +0000 |
551 | @@ -222,6 +222,13 @@ |
552 | typeinfo?for?mir::dispatch::SimpleDispatchThread; |
553 | vtable?for?mir::dispatch::SimpleDispatchThread; |
554 | |
555 | + mir::events::*; |
556 | + mir::input::receiver::XKBMapper::XKBMapper*; |
557 | + mir::input::receiver::XKBMapper::XKBMapper*; |
558 | + mir::input::receiver::XKBMapper::set_rules*; |
559 | + typeinfo?for?mir::input::receiver::XKBMapper; |
560 | + vtable?for?mir::input::receiver::XKBMapper; |
561 | + |
562 | mir::dispatch::MultiplexingDispatchable::MultiplexingDispatchable*; |
563 | mir::dispatch::MultiplexingDispatchable::?MultiplexingDispatchable*; |
564 | mir::dispatch::MultiplexingDispatchable::watch_fd*; |
565 | |
566 | === modified file 'src/include/common/mir/input/xkb_mapper.h' |
567 | --- src/include/common/mir/input/xkb_mapper.h 2015-02-13 06:12:34 +0000 |
568 | +++ src/include/common/mir/input/xkb_mapper.h 2015-02-20 18:01:07 +0000 |
569 | @@ -26,6 +26,7 @@ |
570 | #include <xkbcommon/xkbcommon.h> |
571 | |
572 | #include <memory> |
573 | +#include <mutex> |
574 | |
575 | namespace mir |
576 | { |
577 | @@ -40,13 +41,17 @@ |
578 | XKBMapper(); |
579 | virtual ~XKBMapper() = default; |
580 | |
581 | - void update_state_and_map_event(MirKeyEvent& key_ev); |
582 | + void set_rules(xkb_rule_names const& names); |
583 | + |
584 | + void update_state_and_map_event(MirEvent& ev); |
585 | |
586 | protected: |
587 | XKBMapper(XKBMapper const&) = delete; |
588 | XKBMapper& operator=(XKBMapper const&) = delete; |
589 | |
590 | private: |
591 | + std::mutex guard; |
592 | + |
593 | std::shared_ptr<xkb_context> context; |
594 | std::shared_ptr<xkb_keymap> map; |
595 | std::shared_ptr<xkb_state> state; |
596 | |
597 | === modified file 'src/include/server/mir/scene/surface_event_source.h' |
598 | --- src/include/server/mir/scene/surface_event_source.h 2015-01-21 07:34:50 +0000 |
599 | +++ src/include/server/mir/scene/surface_event_source.h 2015-02-20 18:01:07 +0000 |
600 | @@ -40,6 +40,7 @@ |
601 | void resized_to(geometry::Size const& size) override; |
602 | void orientation_set_to(MirOrientation orientation) override; |
603 | void client_surface_close_requested() override; |
604 | + void keymap_changed(xkb_rule_names const& names) override; |
605 | |
606 | private: |
607 | frontend::SurfaceId const id; |
608 | |
609 | === modified file 'src/server/input/cursor_controller.cpp' |
610 | --- src/server/input/cursor_controller.cpp 2015-01-21 07:34:50 +0000 |
611 | +++ src/server/input/cursor_controller.cpp 2015-02-20 18:01:07 +0000 |
612 | @@ -22,7 +22,7 @@ |
613 | #include "mir/input/surface.h" |
614 | #include "mir/graphics/cursor.h" |
615 | #include "mir/scene/observer.h" |
616 | -#include "mir/scene/surface_observer.h" |
617 | +#include "mir/scene/null_surface_observer.h" |
618 | #include "mir/scene/surface.h" |
619 | |
620 | #include <functional> |
621 | @@ -39,7 +39,7 @@ |
622 | namespace |
623 | { |
624 | |
625 | -struct UpdateCursorOnSurfaceChanges : ms::SurfaceObserver |
626 | +struct UpdateCursorOnSurfaceChanges : ms::NullSurfaceObserver |
627 | { |
628 | UpdateCursorOnSurfaceChanges(mi::CursorController* cursor_controller) |
629 | : cursor_controller(cursor_controller) |
630 | |
631 | === modified file 'src/server/scene/basic_surface.cpp' |
632 | --- src/server/scene/basic_surface.cpp 2015-02-17 11:58:56 +0000 |
633 | +++ src/server/scene/basic_surface.cpp 2015-02-20 18:01:07 +0000 |
634 | @@ -106,6 +106,12 @@ |
635 | { observer->client_surface_close_requested(); }); |
636 | } |
637 | |
638 | +void ms::SurfaceObservers::keymap_changed(xkb_rule_names const& rules) |
639 | +{ |
640 | + for_each([&rules](std::shared_ptr<SurfaceObserver> const& observer) |
641 | + { observer->keymap_changed(rules); }); |
642 | +} |
643 | + |
644 | |
645 | ms::BasicSurface::BasicSurface( |
646 | std::string const& name, |
647 | @@ -742,3 +748,8 @@ |
648 | { |
649 | input_sender->send_event(event, server_input_channel); |
650 | } |
651 | + |
652 | +void ms::BasicSurface::set_keymap(xkb_rule_names const& rules) |
653 | +{ |
654 | + observers.keymap_changed(rules); |
655 | +} |
656 | |
657 | === modified file 'src/server/scene/basic_surface.h' |
658 | --- src/server/scene/basic_surface.h 2015-02-03 15:07:44 +0000 |
659 | +++ src/server/scene/basic_surface.h 2015-02-20 18:01:07 +0000 |
660 | @@ -72,6 +72,7 @@ |
661 | void reception_mode_set_to(input::InputReceptionMode mode) override; |
662 | void cursor_image_set_to(graphics::CursorImage const& image) override; |
663 | void client_surface_close_requested() override; |
664 | + void keymap_changed(xkb_rule_names const& names) override; |
665 | }; |
666 | |
667 | class BasicSurface : public Surface |
668 | @@ -162,6 +163,8 @@ |
669 | |
670 | int dpi() const; |
671 | |
672 | + void set_keymap(xkb_rule_names const& rules) override; |
673 | + |
674 | private: |
675 | bool visible(std::unique_lock<std::mutex>&) const; |
676 | MirSurfaceType set_type(MirSurfaceType t); // Use configure() to make public changes |
677 | |
678 | === modified file 'src/server/scene/legacy_surface_change_notification.cpp' |
679 | --- src/server/scene/legacy_surface_change_notification.cpp 2015-01-21 07:34:50 +0000 |
680 | +++ src/server/scene/legacy_surface_change_notification.cpp 2015-02-20 18:01:07 +0000 |
681 | @@ -85,3 +85,8 @@ |
682 | void ms::LegacySurfaceChangeNotification::client_surface_close_requested() |
683 | { |
684 | } |
685 | + |
686 | +// A keymap change is not enough to trigger recomposition |
687 | +void ms::LegacySurfaceChangeNotification::keymap_changed(xkb_rule_names const&) |
688 | +{ |
689 | +} |
690 | |
691 | === modified file 'src/server/scene/legacy_surface_change_notification.h' |
692 | --- src/server/scene/legacy_surface_change_notification.h 2015-01-21 07:34:50 +0000 |
693 | +++ src/server/scene/legacy_surface_change_notification.h 2015-02-20 18:01:07 +0000 |
694 | @@ -48,6 +48,7 @@ |
695 | void reception_mode_set_to(input::InputReceptionMode mode) override; |
696 | void cursor_image_set_to(graphics::CursorImage const& image) override; |
697 | void client_surface_close_requested() override; |
698 | + void keymap_changed(xkb_rule_names const& names) override; |
699 | |
700 | private: |
701 | std::function<void()> const notify_scene_change; |
702 | |
703 | === modified file 'src/server/scene/null_surface_observer.cpp' |
704 | --- src/server/scene/null_surface_observer.cpp 2015-01-21 07:34:50 +0000 |
705 | +++ src/server/scene/null_surface_observer.cpp 2015-02-20 18:01:07 +0000 |
706 | @@ -32,3 +32,4 @@ |
707 | void ms::NullSurfaceObserver::reception_mode_set_to(input::InputReceptionMode /*mode*/) {} |
708 | void ms::NullSurfaceObserver::cursor_image_set_to(mg::CursorImage const& /*image*/) {} |
709 | void ms::NullSurfaceObserver::client_surface_close_requested() {} |
710 | +void ms::NullSurfaceObserver::keymap_changed(xkb_rule_names const& /* names */) {} |
711 | |
712 | === modified file 'src/server/scene/surface_event_source.cpp' |
713 | --- src/server/scene/surface_event_source.cpp 2015-02-13 06:12:34 +0000 |
714 | +++ src/server/scene/surface_event_source.cpp 2015-02-20 18:01:07 +0000 |
715 | @@ -56,3 +56,8 @@ |
716 | { |
717 | event_sink->handle_event(*mev::make_event(id)); |
718 | } |
719 | + |
720 | +void ms::SurfaceEventSource::keymap_changed(xkb_rule_names const& names) |
721 | +{ |
722 | + event_sink->handle_event(*mev::make_event(id, names)); |
723 | +} |
724 | |
725 | === modified file 'tests/acceptance-tests/throwback/test_client_input.cpp' |
726 | --- tests/acceptance-tests/throwback/test_client_input.cpp 2015-02-17 17:49:21 +0000 |
727 | +++ tests/acceptance-tests/throwback/test_client_input.cpp 2015-02-20 18:01:07 +0000 |
728 | @@ -624,3 +624,83 @@ |
729 | session->default_surface()->consume(key_event); |
730 | }); |
731 | } |
732 | + |
733 | +TEST_F(TestClientInput, clients_receive_keymap_change_events) |
734 | +{ |
735 | + using namespace testing; |
736 | + |
737 | + mt::WaitCondition first_event_received; |
738 | + InputClient client{new_connection(), test_client_name_1}; |
739 | + |
740 | + xkb_rule_names names; |
741 | + names.rules = "evdev"; |
742 | + names.model = "pc105"; |
743 | + names.layout = "dvorak"; |
744 | + names.variant = ""; |
745 | + names.options = ""; |
746 | + |
747 | + InSequence seq; |
748 | + EXPECT_CALL(client.handler, handle_input( |
749 | + mt::KeymapEventWithRules(names))) |
750 | + .Times(1).WillOnce(mt::WakeUp(&client.all_events_received)); |
751 | + |
752 | + client.start(); |
753 | + |
754 | + server_config().the_session_container()->for_each( |
755 | + [names] (std::shared_ptr<ms::Session> const& session) -> void |
756 | + { |
757 | + session->default_surface()->set_keymap(names); |
758 | + }); |
759 | +} |
760 | + |
761 | + |
762 | +TEST_F(TestClientInput, keymap_changes_change_keycode_received) |
763 | +{ |
764 | + using namespace testing; |
765 | + |
766 | + xkb_rule_names names; |
767 | + names.rules = "evdev"; |
768 | + names.model = "pc105"; |
769 | + names.layout = "us"; |
770 | + names.variant = "dvorak"; |
771 | + names.options = ""; |
772 | + |
773 | + mt::WaitCondition first_event_received, |
774 | + client_sees_keymap_change; |
775 | + InputClient client{new_connection(), test_client_name_1}; |
776 | + |
777 | + InSequence seq; |
778 | + EXPECT_CALL(client.handler, handle_input(AllOf( |
779 | + mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_n)))).Times(1); |
780 | + EXPECT_CALL(client.handler, handle_input(mt::KeyUpEvent())) |
781 | + .Times(1).WillOnce(mt::WakeUp(&first_event_received)); |
782 | + EXPECT_CALL(client.handler, handle_input( |
783 | + mt::KeymapEventWithRules(names))) |
784 | + .Times(1).WillOnce(mt::WakeUp(&client_sees_keymap_change)); |
785 | + EXPECT_CALL(client.handler, handle_input(AllOf( |
786 | + mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_b)))).Times(1); |
787 | + EXPECT_CALL(client.handler, handle_input(mt::KeyUpEvent())) |
788 | + .Times(1).WillOnce(mt::WakeUp(&client.all_events_received)); |
789 | + |
790 | + client.start(); |
791 | + |
792 | + fake_event_hub()->synthesize_event( |
793 | + mis::a_key_down_event().of_scancode(KEY_N)); |
794 | + fake_event_hub()->synthesize_event( |
795 | + mis::a_key_up_event().of_scancode(KEY_N)); |
796 | + |
797 | + first_event_received.wait_for_at_most_seconds(60); |
798 | + |
799 | + server_config().the_session_container()->for_each( |
800 | + [&names] (std::shared_ptr<ms::Session> const& session) -> void |
801 | + { |
802 | + session->default_surface()->set_keymap(names); |
803 | + }); |
804 | + |
805 | + client_sees_keymap_change.wait_for_at_most_seconds(60); |
806 | + |
807 | + fake_event_hub()->synthesize_event( |
808 | + mis::a_key_down_event().of_scancode(KEY_N)); |
809 | + fake_event_hub()->synthesize_event( |
810 | + mis::a_key_up_event().of_scancode(KEY_N)); |
811 | +} |
812 | |
813 | === modified file 'tests/include/mir_test/event_matchers.h' |
814 | --- tests/include/mir_test/event_matchers.h 2015-02-13 06:12:34 +0000 |
815 | +++ tests/include/mir_test/event_matchers.h 2015-02-20 18:01:07 +0000 |
816 | @@ -340,6 +340,28 @@ |
817 | return true; |
818 | } |
819 | |
820 | +MATCHER_P(KeymapEventWithRules, expected_rules, "") |
821 | +{ |
822 | + auto as_address = to_address(arg); |
823 | + if (mir_event_get_type(as_address) != mir_event_type_keymap) |
824 | + return false; |
825 | + auto kmev = mir_event_get_keymap_event(as_address); |
826 | + xkb_rule_names received_rules; |
827 | + mir_keymap_event_get_rules(kmev, &received_rules); |
828 | + |
829 | + if (strcmp(received_rules.rules, expected_rules.rules) != 0) |
830 | + return false; |
831 | + if (strcmp(received_rules.layout, expected_rules.layout) != 0) |
832 | + return false; |
833 | + if (strcmp(received_rules.model, expected_rules.model) != 0) |
834 | + return false; |
835 | + if (strcmp(received_rules.variant, expected_rules.variant) != 0) |
836 | + return false; |
837 | + if (strcmp(received_rules.options, expected_rules.options) != 0) |
838 | + return false; |
839 | + return true; |
840 | +} |
841 | + |
842 | } |
843 | } |
844 | |
845 | |
846 | === modified file 'tests/include/mir_test_doubles/stub_scene_surface.h' |
847 | --- tests/include/mir_test_doubles/stub_scene_surface.h 2015-01-22 09:00:14 +0000 |
848 | +++ tests/include/mir_test_doubles/stub_scene_surface.h 2015-02-20 18:01:07 +0000 |
849 | @@ -104,6 +104,8 @@ |
850 | void with_most_recent_buffer_do(std::function<void(graphics::Buffer&)> const& ) override {} |
851 | |
852 | std::shared_ptr<mir::scene::Surface> parent() const override { return nullptr; } |
853 | + |
854 | + void set_keymap(xkb_rule_names const&) {} |
855 | }; |
856 | |
857 | } |
858 | |
859 | === modified file 'tests/integration-tests/test_test_framework.cpp' |
860 | --- tests/integration-tests/test_test_framework.cpp 2015-02-13 06:12:34 +0000 |
861 | +++ tests/integration-tests/test_test_framework.cpp 2015-02-20 18:01:07 +0000 |
862 | @@ -29,7 +29,8 @@ |
863 | |
864 | #include <thread> |
865 | #include <list> |
866 | -#include <sys/resource.h> |
867 | +#include <sys/types.h> |
868 | +#include <dirent.h> |
869 | |
870 | namespace mf = mir::frontend; |
871 | |
872 | @@ -93,25 +94,35 @@ |
873 | mir_connection_release(connection); |
874 | } |
875 | |
876 | +namespace |
877 | +{ |
878 | +unsigned count_fds() |
879 | +{ |
880 | + unsigned count = 0; |
881 | + DIR* dir; |
882 | + EXPECT_TRUE(dir = opendir("/proc/self/fd/")); |
883 | + while (readdir(dir) != nullptr) |
884 | + count++; |
885 | + closedir(dir); |
886 | + return count; |
887 | +} |
888 | +} |
889 | + |
890 | // Regression test for https://bugs.launchpad.net/mir/+bug/1395762 |
891 | TEST_F(DemoInProcessServerWithStubClientPlatform, surface_creation_does_not_leak_fds) |
892 | { |
893 | mir::test::Signal connection_released; |
894 | |
895 | + int fd_count_after_one_surface_lifetime = 0; |
896 | + |
897 | std::thread{ |
898 | [&] |
899 | { |
900 | auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); |
901 | EXPECT_TRUE(mir_connection_is_valid(connection)); |
902 | |
903 | - // Use the number of allowed open files to ensure we exercise the system properly |
904 | - struct rlimit rlim; |
905 | - getrlimit(RLIMIT_NOFILE, &rlim); |
906 | - rlim_t fd_limit = rlim.rlim_cur; |
907 | - if (fd_limit == RLIM_INFINITY) fd_limit = 1024; |
908 | - |
909 | - for (rlim_t i = 0; i < fd_limit; ++i) |
910 | - { |
911 | + for (int i = 0; i < 16; ++i) |
912 | + { |
913 | MirSurfaceParameters request_params = |
914 | { |
915 | __PRETTY_FUNCTION__, |
916 | @@ -122,13 +133,30 @@ |
917 | }; |
918 | |
919 | auto const surface = mir_connection_create_surface_sync(connection, &request_params); |
920 | + EXPECT_TRUE(mir_surface_is_valid(surface)); |
921 | mir_surface_release_sync(surface); |
922 | + |
923 | + if (i == 0) |
924 | + { |
925 | + fd_count_after_one_surface_lifetime = count_fds(); |
926 | + } |
927 | } |
928 | |
929 | mir_connection_release(connection); |
930 | + |
931 | connection_released.raise(); |
932 | + |
933 | }}.detach(); |
934 | - |
935 | - EXPECT_TRUE(connection_released.wait_for(std::chrono::seconds{60})) |
936 | - << "Client hung, possibly because of fd leaks" << std::endl; |
937 | + |
938 | + |
939 | + EXPECT_TRUE(connection_released.wait_for(std::chrono::seconds{480})) |
940 | + << "Client hung" << std::endl; |
941 | + |
942 | + // Investigation revealed we leak a differing number of fds (3, 0) on Mesa/Android over the |
943 | + // entire lifetime of the client library. So we verify here only that we don't leak any FDs beyond |
944 | + // those created up to the lifetime of the first surface. |
945 | + auto new_fd_count = count_fds(); |
946 | + |
947 | + EXPECT_LE(new_fd_count, fd_count_after_one_surface_lifetime); |
948 | + |
949 | } |
950 | |
951 | === modified file 'tests/unit-tests/client/input/test_android_input_receiver.cpp' |
952 | --- tests/unit-tests/client/input/test_android_input_receiver.cpp 2015-02-13 06:12:34 +0000 |
953 | +++ tests/unit-tests/client/input/test_android_input_receiver.cpp 2015-02-20 18:01:07 +0000 |
954 | @@ -20,6 +20,7 @@ |
955 | |
956 | #include "src/common/input/android/android_input_receiver.h" |
957 | #include "mir/input/null_input_receiver_report.h" |
958 | +#include "mir/input/xkb_mapper.h" |
959 | #include "mir_toolkit/event.h" |
960 | |
961 | #include <androidfw/InputTransport.h> |
962 | @@ -149,14 +150,15 @@ |
963 | |
964 | TEST_F(AndroidInputReceiverSetup, receiever_takes_channel_fd) |
965 | { |
966 | - mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>()); |
967 | + mircva::InputReceiver receiver(client_fd, |
968 | + std::make_shared<mircv::XKBMapper>(), std::make_shared<mircv::NullInputReceiverReport>()); |
969 | |
970 | EXPECT_EQ(client_fd, receiver.fd()); |
971 | } |
972 | |
973 | TEST_F(AndroidInputReceiverSetup, receiver_receives_key_events) |
974 | { |
975 | - mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>()); |
976 | + mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::XKBMapper>(), std::make_shared<mircv::NullInputReceiverReport>()); |
977 | TestingInputProducer producer(server_fd); |
978 | |
979 | producer.produce_a_key_event(); |
980 | @@ -172,7 +174,8 @@ |
981 | |
982 | TEST_F(AndroidInputReceiverSetup, receiver_handles_events) |
983 | { |
984 | - mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>()); |
985 | + mircva::InputReceiver receiver(client_fd, |
986 | + std::make_shared<mircv::XKBMapper>(), std::make_shared<mircv::NullInputReceiverReport>()); |
987 | TestingInputProducer producer(server_fd); |
988 | |
989 | producer.produce_a_key_event(); |
990 | @@ -188,7 +191,9 @@ |
991 | |
992 | TEST_F(AndroidInputReceiverSetup, receiver_consumes_batched_motion_events) |
993 | { |
994 | - mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>()); |
995 | + mircva::InputReceiver receiver(client_fd, |
996 | + std::make_shared<mircv::XKBMapper>(), |
997 | + std::make_shared<mircv::NullInputReceiverReport>()); |
998 | TestingInputProducer producer(server_fd); |
999 | |
1000 | // Produce 3 motion events before client handles any. |
1001 | @@ -213,7 +218,9 @@ |
1002 | std::chrono::nanoseconds t = std::chrono::nanoseconds(0); |
1003 | |
1004 | mircva::InputReceiver receiver( |
1005 | - client_fd, std::make_shared<mircv::NullInputReceiverReport>(), |
1006 | + client_fd, |
1007 | + std::make_shared<mircv::XKBMapper>(), |
1008 | + std::make_shared<mircv::NullInputReceiverReport>(), |
1009 | [&t](int) { return t; } |
1010 | ); |
1011 | TestingInputProducer producer(server_fd); |
1012 | @@ -261,7 +268,9 @@ |
1013 | std::chrono::nanoseconds t; |
1014 | |
1015 | mircva::InputReceiver receiver( |
1016 | - client_fd, std::make_shared<mircv::NullInputReceiverReport>(), |
1017 | + client_fd, |
1018 | + std::make_shared<mircv::XKBMapper>(), |
1019 | + std::make_shared<mircv::NullInputReceiverReport>(), |
1020 | [&t](int) { return t; } |
1021 | ); |
1022 | TestingInputProducer producer(server_fd); |
1023 | @@ -309,7 +318,9 @@ |
1024 | std::chrono::nanoseconds t; |
1025 | |
1026 | mircva::InputReceiver receiver( |
1027 | - client_fd, std::make_shared<mircv::NullInputReceiverReport>(), |
1028 | + client_fd, |
1029 | + std::make_shared<mircv::XKBMapper>(), |
1030 | + std::make_shared<mircv::NullInputReceiverReport>(), |
1031 | [&t](int) { return t; } |
1032 | ); |
1033 | TestingInputProducer producer(server_fd); |
1034 | |
1035 | === modified file 'tests/unit-tests/client/input/test_android_input_receiver_thread.cpp' |
1036 | --- tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2015-02-13 06:12:34 +0000 |
1037 | +++ tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2015-02-20 18:01:07 +0000 |
1038 | @@ -22,6 +22,7 @@ |
1039 | #include "src/common/input/android/android_input_receiver.h" |
1040 | |
1041 | #include "mir/input/null_input_receiver_report.h" |
1042 | +#include "mir/input/xkb_mapper.h" |
1043 | |
1044 | #include "mir_toolkit/mir_client_library.h" |
1045 | |
1046 | @@ -48,7 +49,7 @@ |
1047 | struct MockInputReceiver : public mircva::InputReceiver |
1048 | { |
1049 | MockInputReceiver(int fd) |
1050 | - : InputReceiver(fd, std::make_shared<mircv::NullInputReceiverReport>()) |
1051 | + : InputReceiver(fd, std::make_shared<mircv::XKBMapper>(), std::make_shared<mircv::NullInputReceiverReport>()) |
1052 | { |
1053 | } |
1054 | MOCK_METHOD1(next_event, bool(MirEvent &)); |
1055 | |
1056 | === modified file 'tests/unit-tests/client/input/test_xkb_mapper.cpp' |
1057 | --- tests/unit-tests/client/input/test_xkb_mapper.cpp 2014-03-06 06:05:17 +0000 |
1058 | +++ tests/unit-tests/client/input/test_xkb_mapper.cpp 2015-02-20 18:01:07 +0000 |
1059 | @@ -32,24 +32,26 @@ |
1060 | |
1061 | static int map_key(mircv::XKBMapper &mapper, MirKeyAction action, int scan_code) |
1062 | { |
1063 | - MirKeyEvent ev; |
1064 | - ev.action = action; |
1065 | - ev.scan_code = scan_code; |
1066 | - ev.repeat_count = 0; |
1067 | + MirEvent ev; |
1068 | + ev.type = mir_event_type_key; |
1069 | + ev.key.action = action; |
1070 | + ev.key.scan_code = scan_code; |
1071 | + ev.key.repeat_count = 0; |
1072 | |
1073 | mapper.update_state_and_map_event(ev); |
1074 | - return ev.key_code; |
1075 | + return ev.key.key_code; |
1076 | } |
1077 | |
1078 | static int map_repeated_key(mircv::XKBMapper &mapper, MirKeyAction action, int scan_code) |
1079 | { |
1080 | - MirKeyEvent ev; |
1081 | - ev.action = action; |
1082 | - ev.scan_code = scan_code; |
1083 | - ev.repeat_count = 1; |
1084 | + MirEvent ev; |
1085 | + ev.type = mir_event_type_key; |
1086 | + ev.key.action = action; |
1087 | + ev.key.scan_code = scan_code; |
1088 | + ev.key.repeat_count = 1; |
1089 | |
1090 | mapper.update_state_and_map_event(ev); |
1091 | - return ev.key_code; |
1092 | + return ev.key.key_code; |
1093 | } |
1094 | |
1095 | } |
1096 | |
1097 | === modified file 'tests/unit-tests/client/test_client_mir_surface.cpp' |
1098 | --- tests/unit-tests/client/test_client_mir_surface.cpp 2015-02-13 06:12:34 +0000 |
1099 | +++ tests/unit-tests/client/test_client_mir_surface.cpp 2015-02-20 18:01:07 +0000 |
1100 | @@ -248,7 +248,7 @@ |
1101 | |
1102 | struct StubClientInputPlatform : public mircv::InputPlatform |
1103 | { |
1104 | - std::shared_ptr<mircv::InputReceiverThread> create_input_thread(int /* fd */, std::function<void(MirEvent*)> const& /* callback */) |
1105 | + std::shared_ptr<mircv::InputReceiverThread> create_input_thread(int /* fd */, std::shared_ptr<mircv::XKBMapper> const&, std::function<void(MirEvent*)> const& /* callback */) |
1106 | { |
1107 | return std::shared_ptr<mircv::InputReceiverThread>(); |
1108 | } |
1109 | @@ -256,7 +256,7 @@ |
1110 | |
1111 | struct MockClientInputPlatform : public mircv::InputPlatform |
1112 | { |
1113 | - MOCK_METHOD2(create_input_thread, std::shared_ptr<mircv::InputReceiverThread>(int, std::function<void(MirEvent*)> const&)); |
1114 | + MOCK_METHOD3(create_input_thread, std::shared_ptr<mircv::InputReceiverThread>(int, std::shared_ptr<mircv::XKBMapper> const&, std::function<void(MirEvent*)> const&)); |
1115 | }; |
1116 | |
1117 | struct MockInputReceiverThread : public mircv::InputReceiverThread |
1118 | @@ -451,7 +451,7 @@ |
1119 | auto mock_input_thread = std::make_shared<NiceMock<MockInputReceiverThread>>(); |
1120 | MirEventDelegate delegate = {null_event_callback, nullptr}; |
1121 | |
1122 | - EXPECT_CALL(*mock_input_platform, create_input_thread(_, _)).Times(1) |
1123 | + EXPECT_CALL(*mock_input_platform, create_input_thread(_, _, _)).Times(1) |
1124 | .WillOnce(Return(mock_input_thread)); |
1125 | EXPECT_CALL(*mock_input_thread, start()).Times(1); |
1126 | EXPECT_CALL(*mock_input_thread, stop()).Times(1); |
1127 | @@ -470,7 +470,7 @@ |
1128 | auto mock_input_platform = std::make_shared<MockClientInputPlatform>(); |
1129 | auto mock_input_thread = std::make_shared<NiceMock<MockInputReceiverThread>>(); |
1130 | |
1131 | - EXPECT_CALL(*mock_input_platform, create_input_thread(_, _)).Times(0); |
1132 | + EXPECT_CALL(*mock_input_platform, create_input_thread(_, _, _)).Times(0); |
1133 | EXPECT_CALL(*mock_input_thread, start()).Times(0); |
1134 | EXPECT_CALL(*mock_input_thread, stop()).Times(0); |
1135 |
Looks OK.
But it reminds me to wonder what all this input code is doing in libmircommon (as AFAICS it isn't needed by graphics platforms).