Merge lp:~mir-team/mir/wayland-fix-keymaps-re-attempt into lp:mir
- wayland-fix-keymaps-re-attempt
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 4284 |
Proposed branch: | lp:~mir-team/mir/wayland-fix-keymaps-re-attempt |
Merge into: | lp:mir |
Prerequisite: | lp:~raof/mir/fixish-wayland-keyboard |
Diff against target: |
599 lines (+302/-27) 12 files modified
include/core/mir/optional_value.h (+5/-0) include/server/mir/server_action_queue.h (+10/-0) src/include/server/mir/glib_main_loop.h (+5/-0) src/server/frontend/wayland/wayland_connector.cpp (+130/-18) src/server/frontend/wayland/wayland_connector.h (+5/-1) src/server/frontend/wayland/wayland_default_configuration.cpp (+1/-0) src/server/glib_main_loop.cpp (+55/-1) src/server/input/default_input_device_hub.cpp (+8/-7) tests/include/mir/test/doubles/triggered_main_loop.h (+1/-0) tests/mir_test_doubles/triggered_main_loop.cpp (+6/-0) tests/unit-tests/scene/test_mediating_display_changer.cpp (+6/-0) tests/unit-tests/test_glib_main_loop.cpp (+70/-0) |
To merge this branch: | bzr merge lp:~mir-team/mir/wayland-fix-keymaps-re-attempt |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Approve | ||
Mir CI Bot | continuous-integration | Approve | |
Review via email: mp+331793@code.launchpad.net |
Commit message
Wayland: Handle keymaps vaguely appropriately.
This will work for the common case of one system-wide keymap and no per-surface keymaps.
It does not handle having multiple keyboards with different keymaps, or per-surface keymaps. This is left as an exercise for the reader.
Description of the change
Re proposing https:/
Since it didnt want to update its diffs or anything.
Wayland: Handle keymaps vaguely appropriately.
This will work for the common case of one system-wide keymap and no per-surface keymaps.
It does not handle having multiple keyboards with different keymaps, or per-surface keymaps. This is left as an exercise for the reader.
Mir CI Bot (mir-ci-bot) wrote : | # |
MichaĆ Sawicz (saviq) wrote : | # |
I'm afraid CI is quite insistent on the test failures :/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:4292
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
ABORTED: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:4292
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4292
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Alan Griffiths (alan-griffiths) wrote : | # |
Nit:
+ void device_added (std::shared_
+ void device_changed (std::shared_
+ void device_removed (std::shared_
+ void changes_complete () override;
We don't leave a space before function call parentheses.
Otherwise looks plausible and works for me
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4283
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'include/core/mir/optional_value.h' | |||
2 | --- include/core/mir/optional_value.h 2017-07-28 17:00:43 +0000 | |||
3 | +++ include/core/mir/optional_value.h 2017-10-09 17:50:36 +0000 | |||
4 | @@ -59,6 +59,11 @@ | |||
5 | 59 | return std::move(value_); | 59 | return std::move(value_); |
6 | 60 | } | 60 | } |
7 | 61 | 61 | ||
8 | 62 | operator bool() const | ||
9 | 63 | { | ||
10 | 64 | return is_set(); | ||
11 | 65 | } | ||
12 | 66 | |||
13 | 62 | private: | 67 | private: |
14 | 63 | void die_if_unset() const | 68 | void die_if_unset() const |
15 | 64 | { | 69 | { |
16 | 65 | 70 | ||
17 | === modified file 'include/server/mir/server_action_queue.h' | |||
18 | --- include/server/mir/server_action_queue.h 2017-07-28 17:00:43 +0000 | |||
19 | +++ include/server/mir/server_action_queue.h 2017-10-09 17:50:36 +0000 | |||
20 | @@ -32,6 +32,16 @@ | |||
21 | 32 | virtual ~ServerActionQueue() = default; | 32 | virtual ~ServerActionQueue() = default; |
22 | 33 | 33 | ||
23 | 34 | virtual void enqueue(void const* owner, ServerAction const& action) = 0; | 34 | virtual void enqueue(void const* owner, ServerAction const& action) = 0; |
24 | 35 | /** | ||
25 | 36 | * Enqueue an action to be run, guaranteeing that it *will* be run. | ||
26 | 37 | * | ||
27 | 38 | * The action will be run even if the queue is not normally being drained | ||
28 | 39 | * (for example, if the main loop is suspended). If running on the queue is | ||
29 | 40 | * not possible, the action will be run on the caller's thread. | ||
30 | 41 | * | ||
31 | 42 | * \param [in] action Functor to invoke. | ||
32 | 43 | */ | ||
33 | 44 | virtual void enqueue_with_guaranteed_execution(ServerAction const& action) = 0; | ||
34 | 35 | virtual void pause_processing_for(void const* owner) = 0; | 45 | virtual void pause_processing_for(void const* owner) = 0; |
35 | 36 | virtual void resume_processing_for(void const* owner) = 0; | 46 | virtual void resume_processing_for(void const* owner) = 0; |
36 | 37 | 47 | ||
37 | 38 | 48 | ||
38 | === modified file 'src/include/server/mir/glib_main_loop.h' | |||
39 | --- src/include/server/mir/glib_main_loop.h 2017-07-28 17:00:43 +0000 | |||
40 | +++ src/include/server/mir/glib_main_loop.h 2017-10-09 17:50:36 +0000 | |||
41 | @@ -28,6 +28,7 @@ | |||
42 | 28 | #include <exception> | 28 | #include <exception> |
43 | 29 | 29 | ||
44 | 30 | #include <glib.h> | 30 | #include <glib.h> |
45 | 31 | #include <deque> | ||
46 | 31 | 32 | ||
47 | 32 | namespace mir | 33 | namespace mir |
48 | 33 | { | 34 | { |
49 | @@ -76,6 +77,8 @@ | |||
50 | 76 | void unregister_fd_handler(void const* owner) override; | 77 | void unregister_fd_handler(void const* owner) override; |
51 | 77 | 78 | ||
52 | 78 | void enqueue(void const* owner, ServerAction const& action) override; | 79 | void enqueue(void const* owner, ServerAction const& action) override; |
53 | 80 | void enqueue_with_guaranteed_execution(ServerAction const& action) override; | ||
54 | 81 | |||
55 | 79 | void pause_processing_for(void const* owner) override; | 82 | void pause_processing_for(void const* owner) override; |
56 | 80 | void resume_processing_for(void const* owner) override; | 83 | void resume_processing_for(void const* owner) override; |
57 | 81 | 84 | ||
58 | @@ -100,6 +103,8 @@ | |||
59 | 100 | detail::SignalSources signal_sources; | 103 | detail::SignalSources signal_sources; |
60 | 101 | std::mutex do_not_process_mutex; | 104 | std::mutex do_not_process_mutex; |
61 | 102 | std::vector<void const*> do_not_process; | 105 | std::vector<void const*> do_not_process; |
62 | 106 | std::mutex run_on_halt_mutex; | ||
63 | 107 | std::deque<ServerAction> run_on_halt_queue; | ||
64 | 103 | std::function<void()> before_iteration_hook; | 108 | std::function<void()> before_iteration_hook; |
65 | 104 | std::exception_ptr main_loop_exception; | 109 | std::exception_ptr main_loop_exception; |
66 | 105 | }; | 110 | }; |
67 | 106 | 111 | ||
68 | === modified file 'src/server/frontend/wayland/wayland_connector.cpp' | |||
69 | --- src/server/frontend/wayland/wayland_connector.cpp 2017-10-08 02:12:58 +0000 | |||
70 | +++ src/server/frontend/wayland/wayland_connector.cpp 2017-10-09 17:50:36 +0000 | |||
71 | @@ -43,6 +43,11 @@ | |||
72 | 43 | 43 | ||
73 | 44 | #include "mir/client/event.h" | 44 | #include "mir/client/event.h" |
74 | 45 | 45 | ||
75 | 46 | #include "mir/input/device.h" | ||
76 | 47 | #include "mir/input/mir_keyboard_config.h" | ||
77 | 48 | #include "mir/input/input_device_hub.h" | ||
78 | 49 | #include "mir/input/input_device_observer.h" | ||
79 | 50 | |||
80 | 46 | #include <system_error> | 51 | #include <system_error> |
81 | 47 | #include <sys/eventfd.h> | 52 | #include <sys/eventfd.h> |
82 | 48 | #include <wayland-server-core.h> | 53 | #include <wayland-server-core.h> |
83 | @@ -75,6 +80,7 @@ | |||
84 | 75 | namespace ms = mir::scene; | 80 | namespace ms = mir::scene; |
85 | 76 | namespace geom = mir::geometry; | 81 | namespace geom = mir::geometry; |
86 | 77 | namespace mcl = mir::client; | 82 | namespace mcl = mir::client; |
87 | 83 | namespace mi = mir::input; | ||
88 | 78 | 84 | ||
89 | 79 | namespace mir | 85 | namespace mir |
90 | 80 | { | 86 | { |
91 | @@ -798,6 +804,7 @@ | |||
92 | 798 | wl_client* client, | 804 | wl_client* client, |
93 | 799 | wl_resource* parent, | 805 | wl_resource* parent, |
94 | 800 | uint32_t id, | 806 | uint32_t id, |
95 | 807 | mir::input::Keymap const& initial_keymap, | ||
96 | 801 | std::function<void(WlKeyboard*)> const& on_destroy, | 808 | std::function<void(WlKeyboard*)> const& on_destroy, |
97 | 802 | std::shared_ptr<mir::Executor> const& executor) | 809 | std::shared_ptr<mir::Executor> const& executor) |
98 | 803 | : Keyboard(client, parent, id), | 810 | : Keyboard(client, parent, id), |
99 | @@ -811,19 +818,14 @@ | |||
100 | 811 | // TODO: We should really grab the keymap for the focused surface when | 818 | // TODO: We should really grab the keymap for the focused surface when |
101 | 812 | // we receive focus. | 819 | // we receive focus. |
102 | 813 | 820 | ||
116 | 814 | xkb_rule_names default_rules; | 821 | // TODO: Maintain per-device keymaps, and send the appropriate map before |
117 | 815 | memset(&default_rules, 0, sizeof(default_rules)); | 822 | // sending an event from a keyboard with a different map. |
118 | 816 | 823 | ||
119 | 817 | keymap = decltype(keymap){ | 824 | /* The wayland::Keyboard constructor has already run, creating the keyboard |
120 | 818 | xkb_keymap_new_from_names( | 825 | * resource. It is thus safe to send a keymap event to it; the client will receive |
121 | 819 | context.get(), | 826 | * the keyboard object before this event. |
122 | 820 | &default_rules, | 827 | */ |
123 | 821 | XKB_KEYMAP_COMPILE_NO_FLAGS), | 828 | set_keymap(initial_keymap); |
111 | 822 | &xkb_keymap_unref}; | ||
112 | 823 | |||
113 | 824 | state = decltype(state){ | ||
114 | 825 | xkb_state_new(keymap.get()), | ||
115 | 826 | &xkb_state_unref}; | ||
124 | 827 | } | 829 | } |
125 | 828 | 830 | ||
126 | 829 | ~WlKeyboard() | 831 | ~WlKeyboard() |
127 | @@ -966,6 +968,38 @@ | |||
128 | 966 | state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref); | 968 | state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref); |
129 | 967 | } | 969 | } |
130 | 968 | 970 | ||
131 | 971 | void set_keymap(mir::input::Keymap const& new_keymap) | ||
132 | 972 | { | ||
133 | 973 | xkb_rule_names const names = { | ||
134 | 974 | "evdev", | ||
135 | 975 | new_keymap.model.c_str(), | ||
136 | 976 | new_keymap.layout.c_str(), | ||
137 | 977 | new_keymap.variant.c_str(), | ||
138 | 978 | new_keymap.options.c_str() | ||
139 | 979 | }; | ||
140 | 980 | keymap = decltype(keymap){ | ||
141 | 981 | xkb_keymap_new_from_names( | ||
142 | 982 | context.get(), | ||
143 | 983 | &names, | ||
144 | 984 | XKB_KEYMAP_COMPILE_NO_FLAGS), | ||
145 | 985 | &xkb_keymap_unref}; | ||
146 | 986 | |||
147 | 987 | // TODO: We might need to copy across the existing depressed keys? | ||
148 | 988 | state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref); | ||
149 | 989 | |||
150 | 990 | auto buffer = xkb_keymap_get_as_string(keymap.get(), XKB_KEYMAP_FORMAT_TEXT_V1); | ||
151 | 991 | auto length = strlen(buffer); | ||
152 | 992 | |||
153 | 993 | mir::AnonymousShmFile shm_buffer{length}; | ||
154 | 994 | memcpy(shm_buffer.base_ptr(), buffer, length); | ||
155 | 995 | |||
156 | 996 | wl_keyboard_send_keymap( | ||
157 | 997 | resource, | ||
158 | 998 | WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, | ||
159 | 999 | shm_buffer.fd(), | ||
160 | 1000 | length); | ||
161 | 1001 | } | ||
162 | 1002 | |||
163 | 969 | private: | 1003 | private: |
164 | 970 | std::unique_ptr<xkb_keymap, decltype(&xkb_keymap_unref)> keymap; | 1004 | std::unique_ptr<xkb_keymap, decltype(&xkb_keymap_unref)> keymap; |
165 | 971 | std::unique_ptr<xkb_state, decltype(&xkb_state_unref)> state; | 1005 | std::unique_ptr<xkb_state, decltype(&xkb_state_unref)> state; |
166 | @@ -1320,8 +1354,20 @@ | |||
167 | 1320 | class WlSeat | 1354 | class WlSeat |
168 | 1321 | { | 1355 | { |
169 | 1322 | public: | 1356 | public: |
172 | 1323 | WlSeat(wl_display* display, std::shared_ptr<mir::Executor> const& executor) | 1357 | WlSeat( |
173 | 1324 | : executor{executor}, | 1358 | wl_display* display, |
174 | 1359 | std::shared_ptr<mi::InputDeviceHub> const& input_hub, | ||
175 | 1360 | std::shared_ptr<mir::Executor> const& executor) | ||
176 | 1361 | : config_observer{ | ||
177 | 1362 | std::make_shared<ConfigObserver>( | ||
178 | 1363 | keymap, | ||
179 | 1364 | [this](mir::input::Keymap const& new_keymap) | ||
180 | 1365 | { | ||
181 | 1366 | keymap = new_keymap; | ||
182 | 1367 | |||
183 | 1368 | })}, | ||
184 | 1369 | input_hub{input_hub}, | ||
185 | 1370 | executor{executor}, | ||
186 | 1325 | global{wl_global_create( | 1371 | global{wl_global_create( |
187 | 1326 | display, | 1372 | display, |
188 | 1327 | &wl_seat_interface, | 1373 | &wl_seat_interface, |
189 | @@ -1333,10 +1379,12 @@ | |||
190 | 1333 | { | 1379 | { |
191 | 1334 | BOOST_THROW_EXCEPTION(std::runtime_error("Failed to export wl_seat interface")); | 1380 | BOOST_THROW_EXCEPTION(std::runtime_error("Failed to export wl_seat interface")); |
192 | 1335 | } | 1381 | } |
193 | 1382 | input_hub->add_observer(config_observer); | ||
194 | 1336 | } | 1383 | } |
195 | 1337 | 1384 | ||
196 | 1338 | ~WlSeat() | 1385 | ~WlSeat() |
197 | 1339 | { | 1386 | { |
198 | 1387 | input_hub->remove_observer(config_observer); | ||
199 | 1340 | wl_global_destroy(global); | 1388 | wl_global_destroy(global); |
200 | 1341 | } | 1389 | } |
201 | 1342 | 1390 | ||
202 | @@ -1350,9 +1398,38 @@ | |||
203 | 1350 | } | 1398 | } |
204 | 1351 | 1399 | ||
205 | 1352 | private: | 1400 | private: |
206 | 1401 | class ConfigObserver : public mi::InputDeviceObserver | ||
207 | 1402 | { | ||
208 | 1403 | public: | ||
209 | 1404 | ConfigObserver( | ||
210 | 1405 | mir::input::Keymap const& keymap, | ||
211 | 1406 | std::function<void(mir::input::Keymap const&)> const& on_keymap_commit) | ||
212 | 1407 | : current_keymap{keymap}, | ||
213 | 1408 | on_keymap_commit{on_keymap_commit} | ||
214 | 1409 | { | ||
215 | 1410 | } | ||
216 | 1411 | |||
217 | 1412 | void device_added(std::shared_ptr<input::Device> const& device) override; | ||
218 | 1413 | void device_changed(std::shared_ptr<input::Device> const& device) override; | ||
219 | 1414 | void device_removed(std::shared_ptr<input::Device> const& device) override; | ||
220 | 1415 | void changes_complete() override; | ||
221 | 1416 | |||
222 | 1417 | private: | ||
223 | 1418 | mir::input::Keymap const& current_keymap; | ||
224 | 1419 | mir::input::Keymap pending_keymap; | ||
225 | 1420 | std::function<void(mir::input::Keymap const&)> const on_keymap_commit; | ||
226 | 1421 | }; | ||
227 | 1422 | |||
228 | 1423 | mir::input::Keymap keymap; | ||
229 | 1424 | std::shared_ptr<ConfigObserver> const config_observer; | ||
230 | 1425 | |||
231 | 1353 | std::unordered_map<wl_client*, InputCtx<WlPointer>> mutable pointer; | 1426 | std::unordered_map<wl_client*, InputCtx<WlPointer>> mutable pointer; |
232 | 1354 | std::unordered_map<wl_client*, InputCtx<WlKeyboard>> mutable keyboard; | 1427 | std::unordered_map<wl_client*, InputCtx<WlKeyboard>> mutable keyboard; |
233 | 1355 | std::unordered_map<wl_client*, InputCtx<WlTouch>> mutable touch; | 1428 | std::unordered_map<wl_client*, InputCtx<WlTouch>> mutable touch; |
234 | 1429 | |||
235 | 1430 | std::shared_ptr<mi::InputDeviceHub> const input_hub; | ||
236 | 1431 | |||
237 | 1432 | |||
238 | 1356 | std::shared_ptr<mir::Executor> const executor; | 1433 | std::shared_ptr<mir::Executor> const executor; |
239 | 1357 | 1434 | ||
240 | 1358 | static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id) | 1435 | static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id) |
241 | @@ -1413,6 +1490,7 @@ | |||
242 | 1413 | client, | 1490 | client, |
243 | 1414 | resource, | 1491 | resource, |
244 | 1415 | id, | 1492 | id, |
245 | 1493 | me->keymap, | ||
246 | 1416 | [&input_ctx](WlKeyboard* listener) | 1494 | [&input_ctx](WlKeyboard* listener) |
247 | 1417 | { | 1495 | { |
248 | 1418 | input_ctx.unregister_listener(listener); | 1496 | input_ctx.unregister_listener(listener); |
249 | @@ -1435,8 +1513,10 @@ | |||
250 | 1435 | }, | 1513 | }, |
251 | 1436 | me->executor}); | 1514 | me->executor}); |
252 | 1437 | } | 1515 | } |
255 | 1438 | static void release(struct wl_client* /*client*/, struct wl_resource* /*resource*/) {} | 1516 | static void release(struct wl_client* /*client*/, struct wl_resource* us) |
256 | 1439 | 1517 | { | |
257 | 1518 | wl_resource_destroy(us); | ||
258 | 1519 | } | ||
259 | 1440 | 1520 | ||
260 | 1441 | wl_global* const global; | 1521 | wl_global* const global; |
261 | 1442 | static struct wl_seat_interface const vtable; | 1522 | static struct wl_seat_interface const vtable; |
262 | @@ -1464,6 +1544,37 @@ | |||
263 | 1464 | return touch[client]; | 1544 | return touch[client]; |
264 | 1465 | } | 1545 | } |
265 | 1466 | 1546 | ||
266 | 1547 | void WlSeat::ConfigObserver::device_added(std::shared_ptr<input::Device> const& device) | ||
267 | 1548 | { | ||
268 | 1549 | if (auto keyboard_config = device->keyboard_configuration()) | ||
269 | 1550 | { | ||
270 | 1551 | if (current_keymap != keyboard_config.value().device_keymap()) | ||
271 | 1552 | { | ||
272 | 1553 | pending_keymap = keyboard_config.value().device_keymap(); | ||
273 | 1554 | } | ||
274 | 1555 | } | ||
275 | 1556 | } | ||
276 | 1557 | |||
277 | 1558 | void WlSeat::ConfigObserver::device_changed(std::shared_ptr<input::Device> const& device) | ||
278 | 1559 | { | ||
279 | 1560 | if (auto keyboard_config = device->keyboard_configuration()) | ||
280 | 1561 | { | ||
281 | 1562 | if (current_keymap != keyboard_config.value().device_keymap()) | ||
282 | 1563 | { | ||
283 | 1564 | pending_keymap = keyboard_config.value().device_keymap(); | ||
284 | 1565 | } | ||
285 | 1566 | } | ||
286 | 1567 | } | ||
287 | 1568 | |||
288 | 1569 | void WlSeat::ConfigObserver::device_removed(std::shared_ptr<input::Device> const& /*device*/) | ||
289 | 1570 | { | ||
290 | 1571 | } | ||
291 | 1572 | |||
292 | 1573 | void WlSeat::ConfigObserver::changes_complete() | ||
293 | 1574 | { | ||
294 | 1575 | on_keymap_commit(pending_keymap); | ||
295 | 1576 | } | ||
296 | 1577 | |||
297 | 1467 | void WaylandEventSink::send_buffer(BufferStreamId /*id*/, graphics::Buffer& /*buffer*/, graphics::BufferIpcMsgType) | 1578 | void WaylandEventSink::send_buffer(BufferStreamId /*id*/, graphics::Buffer& /*buffer*/, graphics::BufferIpcMsgType) |
298 | 1468 | { | 1579 | { |
299 | 1469 | } | 1580 | } |
300 | @@ -2055,6 +2166,7 @@ | |||
301 | 2055 | optional_value<std::string> const& display_name, | 2166 | optional_value<std::string> const& display_name, |
302 | 2056 | std::shared_ptr<mf::Shell> const& shell, | 2167 | std::shared_ptr<mf::Shell> const& shell, |
303 | 2057 | DisplayChanger& display_config, | 2168 | DisplayChanger& display_config, |
304 | 2169 | std::shared_ptr<mi::InputDeviceHub> const& input_hub, | ||
305 | 2058 | std::shared_ptr<mg::GraphicBufferAllocator> const& allocator, | 2170 | std::shared_ptr<mg::GraphicBufferAllocator> const& allocator, |
306 | 2059 | bool arw_socket) | 2171 | bool arw_socket) |
307 | 2060 | : display{wl_display_create(), &cleanup_display}, | 2172 | : display{wl_display_create(), &cleanup_display}, |
308 | @@ -2089,7 +2201,7 @@ | |||
309 | 2089 | display.get(), | 2201 | display.get(), |
310 | 2090 | executor, | 2202 | executor, |
311 | 2091 | this->allocator); | 2203 | this->allocator); |
313 | 2092 | seat_global = std::make_unique<mf::WlSeat>(display.get(), executor); | 2204 | seat_global = std::make_unique<mf::WlSeat>(display.get(), input_hub, executor); |
314 | 2093 | output_manager = std::make_unique<mf::OutputManager>( | 2205 | output_manager = std::make_unique<mf::OutputManager>( |
315 | 2094 | display.get(), | 2206 | display.get(), |
316 | 2095 | display_config); | 2207 | display_config); |
317 | 2096 | 2208 | ||
318 | === modified file 'src/server/frontend/wayland/wayland_connector.h' | |||
319 | --- src/server/frontend/wayland/wayland_connector.h 2017-09-15 16:34:13 +0000 | |||
320 | +++ src/server/frontend/wayland/wayland_connector.h 2017-10-09 17:50:36 +0000 | |||
321 | @@ -29,7 +29,10 @@ | |||
322 | 29 | namespace mir | 29 | namespace mir |
323 | 30 | { | 30 | { |
324 | 31 | 31 | ||
326 | 32 | 32 | namespace input | |
327 | 33 | { | ||
328 | 34 | class InputDeviceHub; | ||
329 | 35 | } | ||
330 | 33 | namespace graphics | 36 | namespace graphics |
331 | 34 | { | 37 | { |
332 | 35 | class GraphicBufferAllocator; | 38 | class GraphicBufferAllocator; |
333 | @@ -54,6 +57,7 @@ | |||
334 | 54 | optional_value<std::string> const& display_name, | 57 | optional_value<std::string> const& display_name, |
335 | 55 | std::shared_ptr<Shell> const& shell, | 58 | std::shared_ptr<Shell> const& shell, |
336 | 56 | DisplayChanger& display_config, | 59 | DisplayChanger& display_config, |
337 | 60 | std::shared_ptr<input::InputDeviceHub> const& input_hub, | ||
338 | 57 | std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator, | 61 | std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator, |
339 | 58 | bool arw_socket); | 62 | bool arw_socket); |
340 | 59 | 63 | ||
341 | 60 | 64 | ||
342 | === modified file 'src/server/frontend/wayland/wayland_default_configuration.cpp' | |||
343 | --- src/server/frontend/wayland/wayland_default_configuration.cpp 2017-09-15 16:34:13 +0000 | |||
344 | +++ src/server/frontend/wayland/wayland_default_configuration.cpp 2017-10-09 17:50:36 +0000 | |||
345 | @@ -42,6 +42,7 @@ | |||
346 | 42 | display_name, | 42 | display_name, |
347 | 43 | the_frontend_shell(), | 43 | the_frontend_shell(), |
348 | 44 | *the_frontend_display_changer(), | 44 | *the_frontend_display_changer(), |
349 | 45 | the_input_device_hub(), | ||
350 | 45 | the_buffer_allocator(), | 46 | the_buffer_allocator(), |
351 | 46 | arw_socket); | 47 | arw_socket); |
352 | 47 | }); | 48 | }); |
353 | 48 | 49 | ||
354 | === modified file 'src/server/glib_main_loop.cpp' | |||
355 | --- src/server/glib_main_loop.cpp 2017-07-28 17:00:43 +0000 | |||
356 | +++ src/server/glib_main_loop.cpp 2017-10-09 17:50:36 +0000 | |||
357 | @@ -154,7 +154,19 @@ | |||
358 | 154 | detail::add_idle_gsource(main_context, G_PRIORITY_HIGH, | 154 | detail::add_idle_gsource(main_context, G_PRIORITY_HIGH, |
359 | 155 | [this] | 155 | [this] |
360 | 156 | { | 156 | { |
362 | 157 | running = false; | 157 | { |
363 | 158 | std::lock_guard<std::mutex> lock{run_on_halt_mutex}; | ||
364 | 159 | running = false; | ||
365 | 160 | } | ||
366 | 161 | // We know any other thread sees running == false here, so don't need | ||
367 | 162 | // to lock run_on_halt_queue. | ||
368 | 163 | for (auto& action : run_on_halt_queue) | ||
369 | 164 | { | ||
370 | 165 | try { action(); } | ||
371 | 166 | catch (...) { handle_exception(std::current_exception()); } | ||
372 | 167 | } | ||
373 | 168 | run_on_halt_queue.clear(); | ||
374 | 169 | |||
375 | 158 | g_main_context_wakeup(main_context); | 170 | g_main_context_wakeup(main_context); |
376 | 159 | }); | 171 | }); |
377 | 160 | } | 172 | } |
378 | @@ -246,6 +258,48 @@ | |||
379 | 246 | }); | 258 | }); |
380 | 247 | } | 259 | } |
381 | 248 | 260 | ||
382 | 261 | |||
383 | 262 | void mir::GLibMainLoop::enqueue_with_guaranteed_execution(mir::ServerAction const& action) | ||
384 | 263 | { | ||
385 | 264 | auto const action_with_exception_handling = | ||
386 | 265 | [this] | ||
387 | 266 | { | ||
388 | 267 | try | ||
389 | 268 | { | ||
390 | 269 | mir::ServerAction action; | ||
391 | 270 | { | ||
392 | 271 | std::lock_guard<std::mutex> lock{run_on_halt_mutex}; | ||
393 | 272 | action = run_on_halt_queue.front(); | ||
394 | 273 | run_on_halt_queue.pop_front(); | ||
395 | 274 | } | ||
396 | 275 | action(); | ||
397 | 276 | } | ||
398 | 277 | catch (...) | ||
399 | 278 | { | ||
400 | 279 | handle_exception(std::current_exception()); | ||
401 | 280 | } | ||
402 | 281 | }; | ||
403 | 282 | |||
404 | 283 | { | ||
405 | 284 | std::lock_guard<std::mutex> lock{run_on_halt_mutex}; | ||
406 | 285 | |||
407 | 286 | if (!running) | ||
408 | 287 | { | ||
409 | 288 | action(); | ||
410 | 289 | return; | ||
411 | 290 | } | ||
412 | 291 | else | ||
413 | 292 | { | ||
414 | 293 | run_on_halt_queue.push_back(action); | ||
415 | 294 | } | ||
416 | 295 | } | ||
417 | 296 | |||
418 | 297 | detail::add_idle_gsource( | ||
419 | 298 | main_context, | ||
420 | 299 | G_PRIORITY_DEFAULT, | ||
421 | 300 | action_with_exception_handling); | ||
422 | 301 | } | ||
423 | 302 | |||
424 | 249 | void mir::GLibMainLoop::pause_processing_for(void const* owner) | 303 | void mir::GLibMainLoop::pause_processing_for(void const* owner) |
425 | 250 | { | 304 | { |
426 | 251 | std::lock_guard<std::mutex> lock{do_not_process_mutex}; | 305 | std::lock_guard<std::mutex> lock{do_not_process_mutex}; |
427 | 252 | 306 | ||
428 | === modified file 'src/server/input/default_input_device_hub.cpp' | |||
429 | --- src/server/input/default_input_device_hub.cpp 2017-07-28 17:00:43 +0000 | |||
430 | +++ src/server/input/default_input_device_hub.cpp 2017-10-09 17:50:36 +0000 | |||
431 | @@ -88,25 +88,26 @@ | |||
432 | 88 | auto observer = obs.lock(); | 88 | auto observer = obs.lock(); |
433 | 89 | if (observer) | 89 | if (observer) |
434 | 90 | { | 90 | { |
435 | 91 | std::mutex mutex; | ||
436 | 92 | std::condition_variable cv; | 91 | std::condition_variable cv; |
439 | 93 | std::unique_lock<decltype(mutex)> lock{mutex}; | 92 | std::atomic<bool> removed{false}; |
438 | 94 | bool removed{false}; | ||
440 | 95 | 93 | ||
443 | 96 | data->observer_queue->enqueue( | 94 | data->observer_queue->enqueue_with_guaranteed_execution( |
442 | 97 | data.get(), | ||
444 | 98 | [&,this] | 95 | [&,this] |
445 | 99 | { | 96 | { |
446 | 100 | // Unless remove() is on the same thread as add() external synchronization would be needed | 97 | // Unless remove() is on the same thread as add() external synchronization would be needed |
447 | 101 | data->observers.remove(observer); | 98 | data->observers.remove(observer); |
448 | 102 | 99 | ||
450 | 103 | std::lock_guard<decltype(mutex)> lock{mutex}; | 100 | // We do *not* take a lock and instead rely on removed being atomic, |
451 | 101 | // as enqueue_with_guaranteed_execution may run on our stack. | ||
452 | 104 | removed = true; | 102 | removed = true; |
453 | 105 | cv.notify_one(); | 103 | cv.notify_one(); |
454 | 106 | }); | 104 | }); |
455 | 107 | 105 | ||
456 | 106 | std::mutex mutex; | ||
457 | 107 | std::unique_lock<decltype(mutex)> lock{mutex}; | ||
458 | 108 | |||
459 | 108 | // Before returning wait for the remove - otherwise notifications can still happen | 109 | // Before returning wait for the remove - otherwise notifications can still happen |
461 | 109 | cv.wait(lock, [&] { return removed; }); | 110 | cv.wait(lock, [&] { return removed.load(); }); |
462 | 110 | } | 111 | } |
463 | 111 | } | 112 | } |
464 | 112 | 113 | ||
465 | 113 | 114 | ||
466 | === modified file 'tests/include/mir/test/doubles/triggered_main_loop.h' | |||
467 | --- tests/include/mir/test/doubles/triggered_main_loop.h 2017-07-28 17:00:43 +0000 | |||
468 | +++ tests/include/mir/test/doubles/triggered_main_loop.h 2017-10-09 17:50:36 +0000 | |||
469 | @@ -41,6 +41,7 @@ | |||
470 | 41 | void unregister_fd_handler(void const* owner) override; | 41 | void unregister_fd_handler(void const* owner) override; |
471 | 42 | std::unique_ptr<mir::time::Alarm> create_alarm(callback const& call) override; | 42 | std::unique_ptr<mir::time::Alarm> create_alarm(callback const& call) override; |
472 | 43 | void enqueue(void const* owner, ServerAction const& action) override; | 43 | void enqueue(void const* owner, ServerAction const& action) override; |
473 | 44 | void enqueue_with_guaranteed_execution(ServerAction const& action) override; | ||
474 | 44 | 45 | ||
475 | 45 | void spawn(std::function<void()>&& work) override; | 46 | void spawn(std::function<void()>&& work) override; |
476 | 46 | 47 | ||
477 | 47 | 48 | ||
478 | === modified file 'tests/mir_test_doubles/triggered_main_loop.cpp' | |||
479 | --- tests/mir_test_doubles/triggered_main_loop.cpp 2017-07-28 17:00:43 +0000 | |||
480 | +++ tests/mir_test_doubles/triggered_main_loop.cpp 2017-10-09 17:50:36 +0000 | |||
481 | @@ -81,6 +81,12 @@ | |||
482 | 81 | actions.push_back(action); | 81 | actions.push_back(action); |
483 | 82 | } | 82 | } |
484 | 83 | 83 | ||
485 | 84 | void mtd::TriggeredMainLoop::enqueue_with_guaranteed_execution(ServerAction const& action) | ||
486 | 85 | { | ||
487 | 86 | base::enqueue(nullptr, action); | ||
488 | 87 | actions.push_back(action); | ||
489 | 88 | } | ||
490 | 89 | |||
491 | 84 | void mtd::TriggeredMainLoop::trigger_server_actions() | 90 | void mtd::TriggeredMainLoop::trigger_server_actions() |
492 | 85 | { | 91 | { |
493 | 86 | for (auto const& action : actions) | 92 | for (auto const& action : actions) |
494 | 87 | 93 | ||
495 | === modified file 'tests/unit-tests/scene/test_mediating_display_changer.cpp' | |||
496 | --- tests/unit-tests/scene/test_mediating_display_changer.cpp 2017-08-09 11:30:59 +0000 | |||
497 | +++ tests/unit-tests/scene/test_mediating_display_changer.cpp 2017-10-09 17:50:36 +0000 | |||
498 | @@ -100,6 +100,10 @@ | |||
499 | 100 | { | 100 | { |
500 | 101 | action(); | 101 | action(); |
501 | 102 | } | 102 | } |
502 | 103 | void enqueue_with_guaranteed_execution(mir::ServerAction const& action) override | ||
503 | 104 | { | ||
504 | 105 | action(); | ||
505 | 106 | } | ||
506 | 103 | 107 | ||
507 | 104 | void pause_processing_for(void const* /*owner*/) override {} | 108 | void pause_processing_for(void const* /*owner*/) override {} |
508 | 105 | void resume_processing_for(void const* /*owner*/) override {} | 109 | void resume_processing_for(void const* /*owner*/) override {} |
509 | @@ -110,8 +114,10 @@ | |||
510 | 110 | MockServerActionQueue() | 114 | MockServerActionQueue() |
511 | 111 | { | 115 | { |
512 | 112 | ON_CALL(*this, enqueue(_, _)).WillByDefault(InvokeArgument<1>()); | 116 | ON_CALL(*this, enqueue(_, _)).WillByDefault(InvokeArgument<1>()); |
513 | 117 | ON_CALL(*this, enqueue_with_guaranteed_execution(_)).WillByDefault(InvokeArgument<0>()); | ||
514 | 113 | } | 118 | } |
515 | 114 | MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&)); | 119 | MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&)); |
516 | 120 | MOCK_METHOD1(enqueue_with_guaranteed_execution, void(mir::ServerAction const&)); | ||
517 | 115 | MOCK_METHOD1(pause_processing_for, void(void const*)); | 121 | MOCK_METHOD1(pause_processing_for, void(void const*)); |
518 | 116 | MOCK_METHOD1(resume_processing_for, void(void const*)); | 122 | MOCK_METHOD1(resume_processing_for, void(void const*)); |
519 | 117 | }; | 123 | }; |
520 | 118 | 124 | ||
521 | === modified file 'tests/unit-tests/test_glib_main_loop.cpp' | |||
522 | --- tests/unit-tests/test_glib_main_loop.cpp 2017-07-28 17:00:43 +0000 | |||
523 | +++ tests/unit-tests/test_glib_main_loop.cpp 2017-10-09 17:50:36 +0000 | |||
524 | @@ -833,6 +833,76 @@ | |||
525 | 833 | destroy_glib_main_loop); | 833 | destroy_glib_main_loop); |
526 | 834 | } | 834 | } |
527 | 835 | 835 | ||
528 | 836 | TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_before_run) | ||
529 | 837 | { | ||
530 | 838 | using namespace testing; | ||
531 | 839 | |||
532 | 840 | int num_actions{0}; | ||
533 | 841 | |||
534 | 842 | ml.enqueue_with_guaranteed_execution( | ||
535 | 843 | [&num_actions] | ||
536 | 844 | { | ||
537 | 845 | ++num_actions; | ||
538 | 846 | }); | ||
539 | 847 | |||
540 | 848 | EXPECT_THAT(num_actions, Eq(1)); | ||
541 | 849 | } | ||
542 | 850 | |||
543 | 851 | TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_after_stop) | ||
544 | 852 | { | ||
545 | 853 | using namespace testing; | ||
546 | 854 | |||
547 | 855 | int num_actions{0}; | ||
548 | 856 | |||
549 | 857 | ml.enqueue( | ||
550 | 858 | nullptr, | ||
551 | 859 | [this]() | ||
552 | 860 | { | ||
553 | 861 | ml.stop(); | ||
554 | 862 | }); | ||
555 | 863 | |||
556 | 864 | ml.run(); | ||
557 | 865 | |||
558 | 866 | ml.enqueue_with_guaranteed_execution( | ||
559 | 867 | [&num_actions] | ||
560 | 868 | { | ||
561 | 869 | ++num_actions; | ||
562 | 870 | }); | ||
563 | 871 | |||
564 | 872 | EXPECT_THAT(num_actions, Eq(1)); | ||
565 | 873 | } | ||
566 | 874 | |||
567 | 875 | TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_on_mainloop) | ||
568 | 876 | { | ||
569 | 877 | using namespace testing; | ||
570 | 878 | |||
571 | 879 | mt::Signal loop_running; | ||
572 | 880 | mt::Signal loop_finished; | ||
573 | 881 | |||
574 | 882 | ml.enqueue( | ||
575 | 883 | nullptr, | ||
576 | 884 | [&loop_running]() { loop_running.raise(); }); | ||
577 | 885 | |||
578 | 886 | mt::AutoJoinThread t{ | ||
579 | 887 | [&] | ||
580 | 888 | { | ||
581 | 889 | ml.run(); | ||
582 | 890 | loop_finished.raise(); | ||
583 | 891 | }}; | ||
584 | 892 | |||
585 | 893 | ASSERT_TRUE(loop_running.wait_for(std::chrono::seconds{5})); | ||
586 | 894 | |||
587 | 895 | ml.enqueue_with_guaranteed_execution( | ||
588 | 896 | [main_thread = std::this_thread::get_id()]() | ||
589 | 897 | { | ||
590 | 898 | EXPECT_THAT(std::this_thread::get_id(), Ne(main_thread)); | ||
591 | 899 | }); | ||
592 | 900 | |||
593 | 901 | ml.stop(); | ||
594 | 902 | |||
595 | 903 | EXPECT_TRUE(loop_finished.wait_for(std::chrono::seconds{30})); | ||
596 | 904 | } | ||
597 | 905 | |||
598 | 836 | namespace | 906 | namespace |
599 | 837 | { | 907 | { |
600 | 838 | 908 |
FAILED: Continuous integration, rev:4292 /mir-jenkins. ubuntu. com/job/ mir-ci/ 3714/ /mir-jenkins. ubuntu. com/job/ build-mir/ 5095/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/5333 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= artful/ 5320 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial/ 5320 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= zesty/5320 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= artful/ 5139/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= zesty/5139/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= artful/ 5139/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 5139/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= zesty/5139/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= artful/ 5139 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= artful/ 5139/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= zesty/5139 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= zesty/5139/ artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 5139/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 3714/rebuild
https:/