Merge lp:~andreas-pokorny/mir/rebase-fix-1550050 into lp:mir
- rebase-fix-1550050
- Merge into development-branch
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Daniel van Vugt | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 3397 | ||||
Proposed branch: | lp:~andreas-pokorny/mir/rebase-fix-1550050 | ||||
Merge into: | lp:mir | ||||
Diff against target: |
343 lines (+153/-31) 5 files modified
src/server/input/default_configuration.cpp (+14/-2) src/server/input/default_input_device_hub.cpp (+14/-8) src/server/input/key_repeat_dispatcher.cpp (+41/-0) src/server/input/key_repeat_dispatcher.h (+7/-4) tests/unit-tests/input/test_key_repeat_dispatcher.cpp (+77/-17) |
||||
To merge this branch: | bzr merge lp:~andreas-pokorny/mir/rebase-fix-1550050 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Approve | ||
Mir CI Bot | continuous-integration | Needs Fixing | |
Andreas Pokorny (community) | Needs Information | ||
Daniel van Vugt | Abstain | ||
Cemil Azizoglu (community) | Approve | ||
Review via email:
|
Commit message
Fixes the potential endless repeat on unplugged devices (LP: #1550050)
The key repeat dispatcher now reacts on the removal of input devices by resetting potentially still active repeat alarms. The integration here is a bit clumsy, since the input device hub needs the input dispatcher to forward device events. While the input dispatcher needs it to register at the input device hub as an observer.
Description of the change
This fix registers for device changes and then stops sending repeat events for removed devices.
A different approach to this one which requires adding a two step initialization will be proposed soon, but requires an ABI change in the input platform interface.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Mir CI Bot (mir-ci-bot) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Daniel van Vugt (vanvugt) wrote : | # |
The version is incorrect. Should be 0.21.0 in lp:mir
Also the changelog is incorrect for the same reason.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Daniel van Vugt (vanvugt) wrote : | # |
Separate MPs are up to fix the above issues. You can just remove your version changes here...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andreas Pokorny (andreas-pokorny) wrote : | # |
ok removed the 'unreleased' changelog entry.
My understanding was that we will make another 0.20.3 release using what is currently in lp:mir - since there are no ABI breaks yet.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3387
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Daniel van Vugt (vanvugt) wrote : | # |
lp:mir is series 0.21, which is clear in the launchpad config:
https:/
So lp:mir should always call itself series 0.21 until such time as that's released and we're working on series 0.22.
If you want to release a 0.20.3 then that must occur in lp:mir/0.20.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andreas Pokorny (andreas-pokorny) wrote : | # |
Agreed. Depending on where we release from we do not need this MP!
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alan Griffiths (alan-griffiths) wrote : | # |
We probably don't need this on trunk. Either we:
1. release 0.20.x from mir/0.20 - which already has this fix;
2. release a better solution (which I understand will break ABI) as 0.21; or,
3. we release 0.21 with this solution and apply the better solution in 0.22
I think we intend to release 0.20.3 and don't need this (yet).
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3387
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alan Griffiths (alan-griffiths) wrote : | # |
> We probably don't need this on trunk. Either we:
>
> 1. release 0.20.x from mir/0.20 - which already has this fix;
> 2. release a better solution (which I understand will break ABI) as 0.21; or,
> 3. we release 0.21 with this solution and apply the better solution in 0.22
>
> I think we intend to release 0.20.3 and don't need this (yet).
...we went for option 3
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Daniel van Vugt (vanvugt) wrote : | # |
The failure is due to more random display configuration API failures. We've had a lot of them lately.
Preview Diff
1 | === modified file 'src/server/input/default_configuration.cpp' | |||
2 | --- src/server/input/default_configuration.cpp 2016-03-09 11:19:15 +0000 | |||
3 | +++ src/server/input/default_configuration.cpp 2016-03-15 07:45:18 +0000 | |||
4 | @@ -295,12 +295,18 @@ | |||
5 | 295 | return default_input_device_hub( | 295 | return default_input_device_hub( |
6 | 296 | [this]() | 296 | [this]() |
7 | 297 | { | 297 | { |
9 | 298 | return std::make_shared<mi::DefaultInputDeviceHub>( | 298 | auto input_dispatcher = the_input_dispatcher(); |
10 | 299 | auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher); | ||
11 | 300 | auto hub = std::make_shared<mi::DefaultInputDeviceHub>( | ||
12 | 299 | the_global_event_sink(), | 301 | the_global_event_sink(), |
13 | 300 | the_seat(), | 302 | the_seat(), |
14 | 301 | the_input_reading_multiplexer(), | 303 | the_input_reading_multiplexer(), |
15 | 302 | the_main_loop(), | 304 | the_main_loop(), |
16 | 303 | the_cookie_authority()); | 305 | the_cookie_authority()); |
17 | 306 | |||
18 | 307 | if (key_repeater) | ||
19 | 308 | key_repeater->set_input_device_hub(hub); | ||
20 | 309 | return hub; | ||
21 | 304 | }); | 310 | }); |
22 | 305 | } | 311 | } |
23 | 306 | 312 | ||
24 | @@ -309,11 +315,17 @@ | |||
25 | 309 | return default_input_device_hub( | 315 | return default_input_device_hub( |
26 | 310 | [this]() | 316 | [this]() |
27 | 311 | { | 317 | { |
29 | 312 | return std::make_shared<mi::DefaultInputDeviceHub>( | 318 | auto input_dispatcher = the_input_dispatcher(); |
30 | 319 | auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher); | ||
31 | 320 | auto hub = std::make_shared<mi::DefaultInputDeviceHub>( | ||
32 | 313 | the_global_event_sink(), | 321 | the_global_event_sink(), |
33 | 314 | the_seat(), | 322 | the_seat(), |
34 | 315 | the_input_reading_multiplexer(), | 323 | the_input_reading_multiplexer(), |
35 | 316 | the_main_loop(), | 324 | the_main_loop(), |
36 | 317 | the_cookie_authority()); | 325 | the_cookie_authority()); |
37 | 326 | |||
38 | 327 | if (key_repeater) | ||
39 | 328 | key_repeater->set_input_device_hub(hub); | ||
40 | 329 | return hub; | ||
41 | 318 | }); | 330 | }); |
42 | 319 | } | 331 | } |
43 | 320 | 332 | ||
44 | === modified file 'src/server/input/default_input_device_hub.cpp' | |||
45 | --- src/server/input/default_input_device_hub.cpp 2016-03-08 20:43:41 +0000 | |||
46 | +++ src/server/input/default_input_device_hub.cpp 2016-03-15 07:45:18 +0000 | |||
47 | @@ -244,17 +244,23 @@ | |||
48 | 244 | void mi::DefaultInputDeviceHub::remove_device_handle(MirInputDeviceId id) | 244 | void mi::DefaultInputDeviceHub::remove_device_handle(MirInputDeviceId id) |
49 | 245 | { | 245 | { |
50 | 246 | std::unique_lock<std::mutex> lock(observer_guard); | 246 | std::unique_lock<std::mutex> lock(observer_guard); |
54 | 247 | auto handle_it = remove_if(begin(handles), | 247 | auto handle_it = remove_if( |
55 | 248 | end(handles), | 248 | begin(handles), |
56 | 249 | [&id](auto const& handle){return handle->id() == id;}); | 249 | end(handles), |
57 | 250 | [this,&id](auto const& handle) | ||
58 | 251 | { | ||
59 | 252 | if (handle->id() != id) | ||
60 | 253 | return false; | ||
61 | 254 | for (auto const& observer : observers) | ||
62 | 255 | { | ||
63 | 256 | observer->device_removed(handle); | ||
64 | 257 | observer->changes_complete(); | ||
65 | 258 | } | ||
66 | 259 | return true; | ||
67 | 260 | }); | ||
68 | 250 | 261 | ||
69 | 251 | if (handle_it == end(handles)) | 262 | if (handle_it == end(handles)) |
70 | 252 | return; | 263 | return; |
71 | 253 | for (auto const& observer : observers) | ||
72 | 254 | { | ||
73 | 255 | observer->device_removed(*handle_it); | ||
74 | 256 | observer->changes_complete(); | ||
75 | 257 | } | ||
76 | 258 | 264 | ||
77 | 259 | handles.erase(handle_it, end(handles)); | 265 | handles.erase(handle_it, end(handles)); |
78 | 260 | sink->handle_input_device_change(handles); | 266 | sink->handle_input_device_change(handles); |
79 | 261 | 267 | ||
80 | === modified file 'src/server/input/key_repeat_dispatcher.cpp' | |||
81 | --- src/server/input/key_repeat_dispatcher.cpp 2016-01-29 08:18:22 +0000 | |||
82 | +++ src/server/input/key_repeat_dispatcher.cpp 2016-03-15 07:45:18 +0000 | |||
83 | @@ -18,6 +18,8 @@ | |||
84 | 18 | 18 | ||
85 | 19 | #include "key_repeat_dispatcher.h" | 19 | #include "key_repeat_dispatcher.h" |
86 | 20 | 20 | ||
87 | 21 | #include "mir/input/device.h" | ||
88 | 22 | #include "mir/input/input_device_hub.h" | ||
89 | 21 | #include "mir/time/alarm_factory.h" | 23 | #include "mir/time/alarm_factory.h" |
90 | 22 | #include "mir/time/alarm.h" | 24 | #include "mir/time/alarm.h" |
91 | 23 | #include "mir/events/event_private.h" | 25 | #include "mir/events/event_private.h" |
92 | @@ -31,6 +33,34 @@ | |||
93 | 31 | 33 | ||
94 | 32 | namespace mi = mir::input; | 34 | namespace mi = mir::input; |
95 | 33 | 35 | ||
96 | 36 | namespace | ||
97 | 37 | { | ||
98 | 38 | struct DeviceRemovalFilter : mi::InputDeviceObserver | ||
99 | 39 | { | ||
100 | 40 | DeviceRemovalFilter(std::function<void(MirInputDeviceId)> const& on_removal) | ||
101 | 41 | : on_removal(on_removal) {} | ||
102 | 42 | |||
103 | 43 | void device_added(std::shared_ptr<mi::Device> const&) override | ||
104 | 44 | { | ||
105 | 45 | } | ||
106 | 46 | |||
107 | 47 | void device_changed(std::shared_ptr<mi::Device> const&) override | ||
108 | 48 | { | ||
109 | 49 | } | ||
110 | 50 | |||
111 | 51 | void device_removed(std::shared_ptr<mi::Device> const& device) override | ||
112 | 52 | { | ||
113 | 53 | on_removal(device->id()); | ||
114 | 54 | } | ||
115 | 55 | |||
116 | 56 | void changes_complete() override | ||
117 | 57 | { | ||
118 | 58 | } | ||
119 | 59 | std::function<void(MirInputDeviceId)> on_removal; | ||
120 | 60 | }; | ||
121 | 61 | |||
122 | 62 | } | ||
123 | 63 | |||
124 | 34 | mi::KeyRepeatDispatcher::KeyRepeatDispatcher( | 64 | mi::KeyRepeatDispatcher::KeyRepeatDispatcher( |
125 | 35 | std::shared_ptr<mi::InputDispatcher> const& next_dispatcher, | 65 | std::shared_ptr<mi::InputDispatcher> const& next_dispatcher, |
126 | 36 | std::shared_ptr<mir::time::AlarmFactory> const& factory, | 66 | std::shared_ptr<mir::time::AlarmFactory> const& factory, |
127 | @@ -47,6 +77,17 @@ | |||
128 | 47 | { | 77 | { |
129 | 48 | } | 78 | } |
130 | 49 | 79 | ||
131 | 80 | void mi::KeyRepeatDispatcher::set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub) | ||
132 | 81 | { | ||
133 | 82 | hub->add_observer(std::make_shared<DeviceRemovalFilter>( | ||
134 | 83 | [this](MirInputDeviceId id) | ||
135 | 84 | { | ||
136 | 85 | std::unique_lock<std::mutex> lock(repeat_state_mutex); | ||
137 | 86 | repeat_state_by_device.erase(id); // destructor cancels alarms | ||
138 | 87 | } | ||
139 | 88 | )); | ||
140 | 89 | } | ||
141 | 90 | |||
142 | 50 | mi::KeyRepeatDispatcher::KeyboardState& mi::KeyRepeatDispatcher::ensure_state_for_device_locked(std::lock_guard<std::mutex> const&, MirInputDeviceId id) | 91 | mi::KeyRepeatDispatcher::KeyboardState& mi::KeyRepeatDispatcher::ensure_state_for_device_locked(std::lock_guard<std::mutex> const&, MirInputDeviceId id) |
143 | 51 | { | 92 | { |
144 | 52 | repeat_state_by_device.insert(std::make_pair(id, KeyboardState())); | 93 | repeat_state_by_device.insert(std::make_pair(id, KeyboardState())); |
145 | 53 | 94 | ||
146 | === modified file 'src/server/input/key_repeat_dispatcher.h' | |||
147 | --- src/server/input/key_repeat_dispatcher.h 2016-01-29 08:18:22 +0000 | |||
148 | +++ src/server/input/key_repeat_dispatcher.h 2016-03-15 07:45:18 +0000 | |||
149 | @@ -1,5 +1,5 @@ | |||
150 | 1 | /* | 1 | /* |
152 | 2 | * Copyright © 2015 Canonical Ltd. | 2 | * Copyright © 2015-2016 Canonical Ltd. |
153 | 3 | * | 3 | * |
154 | 4 | * This program is free software: you can redistribute it and/or modify it | 4 | * This program is free software: you can redistribute it and/or modify it |
155 | 5 | * under the terms of the GNU General Public License version 3, | 5 | * under the terms of the GNU General Public License version 3, |
156 | @@ -20,6 +20,7 @@ | |||
157 | 20 | #define MIR_INPUT_KEY_REPEAT_DISPATCHER_H_ | 20 | #define MIR_INPUT_KEY_REPEAT_DISPATCHER_H_ |
158 | 21 | 21 | ||
159 | 22 | #include "mir/input/input_dispatcher.h" | 22 | #include "mir/input/input_dispatcher.h" |
160 | 23 | #include "mir/input/input_device_observer.h" | ||
161 | 23 | 24 | ||
162 | 24 | #include <memory> | 25 | #include <memory> |
163 | 25 | #include <chrono> | 26 | #include <chrono> |
164 | @@ -39,8 +40,8 @@ | |||
165 | 39 | } | 40 | } |
166 | 40 | namespace input | 41 | namespace input |
167 | 41 | { | 42 | { |
170 | 42 | 43 | class InputDeviceHub; | |
171 | 43 | class KeyRepeatDispatcher : public mir::input::InputDispatcher | 44 | class KeyRepeatDispatcher : public InputDispatcher |
172 | 44 | { | 45 | { |
173 | 45 | public: | 46 | public: |
174 | 46 | KeyRepeatDispatcher(std::shared_ptr<InputDispatcher> const& next_dispatcher, | 47 | KeyRepeatDispatcher(std::shared_ptr<InputDispatcher> const& next_dispatcher, |
175 | @@ -54,7 +55,9 @@ | |||
176 | 54 | bool dispatch(MirEvent const& event) override; | 55 | bool dispatch(MirEvent const& event) override; |
177 | 55 | void start() override; | 56 | void start() override; |
178 | 56 | void stop() override; | 57 | void stop() override; |
180 | 57 | 58 | ||
181 | 59 | void set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub); | ||
182 | 60 | |||
183 | 58 | private: | 61 | private: |
184 | 59 | std::mutex repeat_state_mutex; | 62 | std::mutex repeat_state_mutex; |
185 | 60 | 63 | ||
186 | 61 | 64 | ||
187 | === modified file 'tests/unit-tests/input/test_key_repeat_dispatcher.cpp' | |||
188 | --- tests/unit-tests/input/test_key_repeat_dispatcher.cpp 2016-01-29 08:18:22 +0000 | |||
189 | +++ tests/unit-tests/input/test_key_repeat_dispatcher.cpp 2016-03-15 07:45:18 +0000 | |||
190 | @@ -23,9 +23,15 @@ | |||
191 | 23 | #include "mir/time/alarm.h" | 23 | #include "mir/time/alarm.h" |
192 | 24 | #include "mir/time/alarm_factory.h" | 24 | #include "mir/time/alarm_factory.h" |
193 | 25 | #include "mir/cookie/authority.h" | 25 | #include "mir/cookie/authority.h" |
194 | 26 | #include "mir/input/input_device_observer.h" | ||
195 | 27 | #include "mir/input/pointer_configuration.h" | ||
196 | 28 | #include "mir/input/touchpad_configuration.h" | ||
197 | 29 | #include "mir/input/device.h" | ||
198 | 26 | 30 | ||
199 | 31 | #include "mir/test/fake_shared.h" | ||
200 | 27 | #include "mir/test/event_matchers.h" | 32 | #include "mir/test/event_matchers.h" |
201 | 28 | #include "mir/test/doubles/mock_input_dispatcher.h" | 33 | #include "mir/test/doubles/mock_input_dispatcher.h" |
202 | 34 | #include "mir/test/doubles/mock_input_device_hub.h" | ||
203 | 29 | 35 | ||
204 | 30 | #include <gtest/gtest.h> | 36 | #include <gtest/gtest.h> |
205 | 31 | #include <gmock/gmock.h> | 37 | #include <gmock/gmock.h> |
206 | @@ -35,6 +41,8 @@ | |||
207 | 35 | namespace mt = mir::test; | 41 | namespace mt = mir::test; |
208 | 36 | namespace mtd = mt::doubles; | 42 | namespace mtd = mt::doubles; |
209 | 37 | 43 | ||
210 | 44 | using namespace ::testing; | ||
211 | 45 | |||
212 | 38 | namespace | 46 | namespace |
213 | 39 | { | 47 | { |
214 | 40 | struct MockAlarm : public mir::time::Alarm | 48 | struct MockAlarm : public mir::time::Alarm |
215 | @@ -43,6 +51,12 @@ | |||
216 | 43 | MOCK_CONST_METHOD0(state, mir::time::Alarm::State()); | 51 | MOCK_CONST_METHOD0(state, mir::time::Alarm::State()); |
217 | 44 | MOCK_METHOD1(reschedule_in, bool(std::chrono::milliseconds)); | 52 | MOCK_METHOD1(reschedule_in, bool(std::chrono::milliseconds)); |
218 | 45 | MOCK_METHOD1(reschedule_for, bool(mir::time::Timestamp)); | 53 | MOCK_METHOD1(reschedule_for, bool(mir::time::Timestamp)); |
219 | 54 | |||
220 | 55 | // destructor cancels the alarm | ||
221 | 56 | ~MockAlarm() | ||
222 | 57 | { | ||
223 | 58 | cancel(); | ||
224 | 59 | } | ||
225 | 46 | }; | 60 | }; |
226 | 47 | 61 | ||
227 | 48 | struct MockAlarmFactory : public mir::time::AlarmFactory | 62 | struct MockAlarmFactory : public mir::time::AlarmFactory |
228 | @@ -59,25 +73,60 @@ | |||
229 | 59 | } | 73 | } |
230 | 60 | }; | 74 | }; |
231 | 61 | 75 | ||
232 | 76 | struct StubDevice : public mi::Device | ||
233 | 77 | { | ||
234 | 78 | MirInputDeviceId device_id; | ||
235 | 79 | StubDevice(MirInputDeviceId id) : device_id(id) {} | ||
236 | 80 | MirInputDeviceId id() const { return device_id;} | ||
237 | 81 | mi::DeviceCapabilities capabilities() const {return mi::DeviceCapability::keyboard;} | ||
238 | 82 | std::string name() const {return {};} | ||
239 | 83 | std::string unique_id() const {return {};} | ||
240 | 84 | |||
241 | 85 | mir::optional_value<mi::PointerConfiguration> pointer_configuration() const {return {};} | ||
242 | 86 | void apply_pointer_configuration(mi::PointerConfiguration const&) {;} | ||
243 | 87 | mir::optional_value<mi::TouchpadConfiguration> touchpad_configuration() const {return {};} | ||
244 | 88 | void apply_touchpad_configuration(mi::TouchpadConfiguration const&) {} | ||
245 | 89 | }; | ||
246 | 90 | |||
247 | 62 | struct KeyRepeatDispatcher : public testing::Test | 91 | struct KeyRepeatDispatcher : public testing::Test |
248 | 63 | { | 92 | { |
249 | 64 | KeyRepeatDispatcher() | 93 | KeyRepeatDispatcher() |
250 | 65 | : dispatcher(mock_next_dispatcher, mock_alarm_factory, cookie_authority, true, repeat_time, repeat_delay) | 94 | : dispatcher(mock_next_dispatcher, mock_alarm_factory, cookie_authority, true, repeat_time, repeat_delay) |
251 | 66 | { | 95 | { |
253 | 67 | } | 96 | ON_CALL(hub,add_observer(_)).WillByDefault(SaveArg<0>(&observer)); |
254 | 97 | dispatcher.set_input_device_hub(mt::fake_shared(hub)); | ||
255 | 98 | } | ||
256 | 99 | void simulate_device_removal() | ||
257 | 100 | { | ||
258 | 101 | StubDevice dev(test_device); | ||
259 | 102 | observer->device_removed(mt::fake_shared(dev)); | ||
260 | 103 | observer->changes_complete(); | ||
261 | 104 | } | ||
262 | 105 | |||
263 | 106 | const MirInputDeviceId test_device = 123; | ||
264 | 68 | std::shared_ptr<mtd::MockInputDispatcher> mock_next_dispatcher = std::make_shared<mtd::MockInputDispatcher>(); | 107 | std::shared_ptr<mtd::MockInputDispatcher> mock_next_dispatcher = std::make_shared<mtd::MockInputDispatcher>(); |
265 | 69 | std::shared_ptr<MockAlarmFactory> mock_alarm_factory = std::make_shared<MockAlarmFactory>(); | 108 | std::shared_ptr<MockAlarmFactory> mock_alarm_factory = std::make_shared<MockAlarmFactory>(); |
266 | 70 | std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create(); | 109 | std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create(); |
267 | 71 | std::chrono::milliseconds const repeat_time{2}; | 110 | std::chrono::milliseconds const repeat_time{2}; |
268 | 72 | std::chrono::milliseconds const repeat_delay{1}; | 111 | std::chrono::milliseconds const repeat_delay{1}; |
269 | 112 | std::shared_ptr<mi::InputDeviceObserver> observer; | ||
270 | 113 | NiceMock<mtd::MockInputDeviceHub> hub; | ||
271 | 73 | mi::KeyRepeatDispatcher dispatcher; | 114 | mi::KeyRepeatDispatcher dispatcher; |
272 | 115 | |||
273 | 116 | mir::EventUPtr a_key_down_event() | ||
274 | 117 | { | ||
275 | 118 | return mev::make_event(test_device, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_down, 0, 0, mir_input_event_modifier_alt); | ||
276 | 119 | } | ||
277 | 120 | |||
278 | 121 | mir::EventUPtr a_key_up_event() | ||
279 | 122 | { | ||
280 | 123 | return mev::make_event(test_device, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_up, 0, 0, mir_input_event_modifier_alt); | ||
281 | 124 | } | ||
282 | 74 | }; | 125 | }; |
283 | 75 | } | 126 | } |
284 | 76 | 127 | ||
285 | 77 | TEST_F(KeyRepeatDispatcher, forwards_start_stop) | 128 | TEST_F(KeyRepeatDispatcher, forwards_start_stop) |
286 | 78 | { | 129 | { |
287 | 79 | using namespace ::testing; | ||
288 | 80 | |||
289 | 81 | InSequence seq; | 130 | InSequence seq; |
290 | 82 | EXPECT_CALL(*mock_next_dispatcher, start()).Times(1); | 131 | EXPECT_CALL(*mock_next_dispatcher, start()).Times(1); |
291 | 83 | EXPECT_CALL(*mock_next_dispatcher, stop()).Times(1); | 132 | EXPECT_CALL(*mock_next_dispatcher, stop()).Times(1); |
292 | @@ -86,22 +135,8 @@ | |||
293 | 86 | dispatcher.stop(); | 135 | dispatcher.stop(); |
294 | 87 | } | 136 | } |
295 | 88 | 137 | ||
296 | 89 | namespace | ||
297 | 90 | { | ||
298 | 91 | mir::EventUPtr a_key_down_event() | ||
299 | 92 | { | ||
300 | 93 | return mev::make_event(0, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_down, 0, 0, mir_input_event_modifier_alt); | ||
301 | 94 | } | ||
302 | 95 | mir::EventUPtr a_key_up_event() | ||
303 | 96 | { | ||
304 | 97 | return mev::make_event(0, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_up, 0, 0, mir_input_event_modifier_alt); | ||
305 | 98 | } | ||
306 | 99 | } | ||
307 | 100 | |||
308 | 101 | TEST_F(KeyRepeatDispatcher, schedules_alarm_to_repeat_key_down) | 138 | TEST_F(KeyRepeatDispatcher, schedules_alarm_to_repeat_key_down) |
309 | 102 | { | 139 | { |
310 | 103 | using namespace ::testing; | ||
311 | 104 | |||
312 | 105 | MockAlarm *mock_alarm = new MockAlarm; // deleted by AlarmFactory | 140 | MockAlarm *mock_alarm = new MockAlarm; // deleted by AlarmFactory |
313 | 106 | std::function<void()> alarm_function; | 141 | std::function<void()> alarm_function; |
314 | 107 | 142 | ||
315 | @@ -122,3 +157,28 @@ | |||
316 | 122 | // Trigger the cancel | 157 | // Trigger the cancel |
317 | 123 | dispatcher.dispatch(*a_key_up_event()); | 158 | dispatcher.dispatch(*a_key_up_event()); |
318 | 124 | } | 159 | } |
319 | 160 | |||
320 | 161 | TEST_F(KeyRepeatDispatcher, stops_repeat_on_device_removal) | ||
321 | 162 | { | ||
322 | 163 | MockAlarm *mock_alarm = new MockAlarm; | ||
323 | 164 | std::function<void()> alarm_function; | ||
324 | 165 | bool alarm_canceled = false; | ||
325 | 166 | |||
326 | 167 | InSequence seq; | ||
327 | 168 | EXPECT_CALL(*mock_alarm_factory, create_alarm_adapter(_)).Times(1). | ||
328 | 169 | WillOnce(DoAll(SaveArg<0>(&alarm_function), Return(mock_alarm))); | ||
329 | 170 | // Once for initial down and again when invoked | ||
330 | 171 | EXPECT_CALL(*mock_alarm, reschedule_in(repeat_time)).Times(1).WillOnce(Return(true)); | ||
331 | 172 | EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyDownEvent())).Times(1); | ||
332 | 173 | EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyRepeatEvent())).Times(1); | ||
333 | 174 | EXPECT_CALL(*mock_alarm, reschedule_in(repeat_delay)).Times(1).WillOnce(Return(true)); | ||
334 | 175 | ON_CALL(*mock_alarm, cancel()).WillByDefault(Invoke([&](){alarm_canceled = true; return true;})); | ||
335 | 176 | |||
336 | 177 | dispatcher.dispatch(*a_key_down_event()); | ||
337 | 178 | |||
338 | 179 | alarm_function(); | ||
339 | 180 | Mock::VerifyAndClearExpectations(mock_alarm); // mock_alarm will be deleted after this | ||
340 | 181 | |||
341 | 182 | simulate_device_removal(); | ||
342 | 183 | EXPECT_THAT(alarm_canceled, Eq(true)); | ||
343 | 184 | } |
PASSED: Continuous integration, rev:3386 /mir-jenkins. ubuntu. com/job/ mir-ci/ 560/ /mir-jenkins. ubuntu. com/job/ build-mir/ 448 /mir-jenkins. ubuntu. com/job/ build-0- fetch/478 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 470 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial/ 470 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 457 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 457/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 457 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 457/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 457 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 457/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 457 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 457/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 457 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 457/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
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:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 560/rebuild
https:/