Mir

Merge lp:mir/0.20 into lp:mir/ubuntu

Proposed by Andreas Pokorny
Status: Merged
Approved by: Andreas Pokorny
Approved revision: 3333
Merged at revision: 1267
Proposed branch: lp:mir/0.20
Merge into: lp:mir/ubuntu
Diff against target: 455 lines (+231/-54)
8 files modified
CMakeLists.txt (+1/-1)
debian/changelog (+11/-0)
include/test/mir/test/doubles/mock_input_device_hub.h (+43/-0)
src/server/input/default_configuration.cpp (+37/-24)
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:mir/0.20
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Mir CI Bot continuous-integration Needs Fixing
Mir development team Pending
Review via email: mp+288248@code.launchpad.net

Commit message

Bug fix release 0.20.2

Description of the change

mir release 0.20.2

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

FAILED: Continuous integration, rev:3332
https://mir-jenkins.ubuntu.com/job/mir-ubuntu-ci/2/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/347/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/377
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/369
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/369
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/356/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/356
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/356/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/356/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/356/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/356/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/356
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/356/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3332
https://mir-jenkins.ubuntu.com/job/mir-ubuntu-ci/3/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/350/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/380
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/372
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/372
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/359/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/359
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/359/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/359/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/359/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/359
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/359/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/359
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/359/artifact/output/*zip*/output.zip

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

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

FAILED: Continuous integration, rev:3332
https://mir-jenkins.ubuntu.com/job/mir-ubuntu-ci/4/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/357/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/387
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/380
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/380
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/367/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/367
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/367/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/367/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/367/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/367
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/367/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/367
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/367/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
lp:mir/0.20 updated
3333. By Andreas Pokorny

bump library version

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

FAILED: Continuous integration, rev:3330
https://mir-jenkins.ubuntu.com/job/mir-ubuntu-ci/5/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/360/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/390
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/382
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/382
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/369/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/369/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/369/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/369/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/369
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/369/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/369
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/369/artifact/output/*zip*/output.zip

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

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

FAILED: Continuous integration, rev:3333
https://mir-jenkins.ubuntu.com/job/mir-ubuntu-ci/6/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/361/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/391
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/383
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/383
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/370/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/370
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/370/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/370/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/370/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/370
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/370/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/370
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/370/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:3333
http://jenkins.qa.ubuntu.com/job/mir-ubuntu-ci/157/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/6045
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4952
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/6001
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/484/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-ubuntu-xenial-amd64-ci/45
        deb: http://jenkins.qa.ubuntu.com/job/mir-ubuntu-xenial-amd64-ci/45/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-ubuntu-xenial-i386-ci/45
        deb: http://jenkins.qa.ubuntu.com/job/mir-ubuntu-xenial-i386-ci/45/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5998
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5998/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8364
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27986
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/480
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/480/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/332/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27987

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ubuntu-ci/157/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-02-24 13:35:43 +0000
3+++ CMakeLists.txt 2016-03-07 15:15:54 +0000
4@@ -29,7 +29,7 @@
5
6 set(MIR_VERSION_MAJOR 0)
7 set(MIR_VERSION_MINOR 20)
8-set(MIR_VERSION_PATCH 1)
9+set(MIR_VERSION_PATCH 2)
10
11 add_definitions(-DMIR_VERSION_MAJOR=${MIR_VERSION_MAJOR})
12 add_definitions(-DMIR_VERSION_MINOR=${MIR_VERSION_MINOR})
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2016-02-25 12:03:41 +0000
16+++ debian/changelog 2016-03-07 15:15:54 +0000
17@@ -1,3 +1,14 @@
18+mir (0.20.2) UNRELEASED; urgency=medium
19+
20+ * New upstream release 0.20.2 (https://launchpad.net/mir/+milestone/0.20.2)
21+ - ABI summary:
22+ . No ABI changes in any libraries. Bugfix release only.
23+ - Bug fixed:
24+ . On removal of USB and BT devices key repeat events of pressed keys
25+ are sent indefinitely. (LP:#1550050)
26+
27+ -- Andreas Pokorny <andreas.pokorny@canonical.com> Mon, 07 Mar 2016 10:03:45 +0100
28+
29 mir (0.20.1+16.04.20160225.1-0ubuntu1) xenial; urgency=medium
30
31 [ Kevin DuBois ]
32
33=== added file 'include/test/mir/test/doubles/mock_input_device_hub.h'
34--- include/test/mir/test/doubles/mock_input_device_hub.h 1970-01-01 00:00:00 +0000
35+++ include/test/mir/test/doubles/mock_input_device_hub.h 2016-03-07 15:15:54 +0000
36@@ -0,0 +1,43 @@
37+/*
38+ * Copyright © 2016 Canonical Ltd.
39+ *
40+ * This program is free software: you can redistribute it and/or modify it
41+ * under the terms of the GNU General Public License version 3,
42+ * as published by the Free Software Foundation.
43+ *
44+ * This program is distributed in the hope that it will be useful,
45+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
46+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47+ * GNU General Public License for more details.
48+ *
49+ * You should have received a copy of the GNU General Public License
50+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
51+ *
52+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
53+ */
54+
55+#ifndef MIR_TEST_DOUBLES_MOCK_INPUT_DEVICE_HUB_H_
56+#define MIR_TEST_DOUBLES_MOCK_INPUT_DEVICE_HUB_H_
57+
58+#include "mir/input/input_device_hub.h"
59+
60+namespace mir
61+{
62+namespace test
63+{
64+namespace doubles
65+{
66+
67+struct MockInputDeviceHub : input::InputDeviceHub
68+{
69+ MOCK_METHOD1(add_observer, void(std::shared_ptr<input::InputDeviceObserver> const&));
70+ MOCK_METHOD1(remove_observer, void(std::weak_ptr<input::InputDeviceObserver> const&));
71+ MOCK_METHOD1(for_each_input_device, void(std::function<void(std::shared_ptr<input::Device>const&)> const&));
72+
73+};
74+
75+}
76+}
77+}
78+
79+#endif
80
81=== modified file 'src/server/input/default_configuration.cpp'
82--- src/server/input/default_configuration.cpp 2016-02-12 10:51:29 +0000
83+++ src/server/input/default_configuration.cpp 2016-03-07 15:15:54 +0000
84@@ -270,33 +270,46 @@
85
86 std::shared_ptr<mi::InputDeviceRegistry> mir::DefaultServerConfiguration::the_input_device_registry()
87 {
88- return default_input_device_hub([this]()
89- {
90- return std::make_shared<mi::DefaultInputDeviceHub>(
91- std::make_shared<mi::BasicSeat>(
92- the_input_dispatcher(),
93- the_touch_visualizer(),
94- the_cursor_listener(),
95- the_input_region()),
96- the_input_reading_multiplexer(),
97- the_main_loop(),
98- the_cookie_authority());
99- });
100+ return default_input_device_hub(
101+ [this]()
102+ {
103+ auto input_dispatcher = the_input_dispatcher();
104+ auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher);
105+ auto hub = std::make_shared<mi::DefaultInputDeviceHub>(
106+ std::make_shared<mi::BasicSeat>(
107+ input_dispatcher,
108+ the_touch_visualizer(),
109+ the_cursor_listener(),
110+ the_input_region()),
111+ the_input_reading_multiplexer(),
112+ the_main_loop(),
113+ the_cookie_authority());
114+
115+ if (key_repeater)
116+ key_repeater->set_input_device_hub(hub);
117+ return hub;
118+ });
119 }
120
121 std::shared_ptr<mi::InputDeviceHub> mir::DefaultServerConfiguration::the_input_device_hub()
122 {
123- return default_input_device_hub([this]()
124- {
125- return std::make_shared<mi::DefaultInputDeviceHub>(
126-std::make_shared<mi::BasicSeat>(
127- the_input_dispatcher(),
128- the_touch_visualizer(),
129- the_cursor_listener(),
130- the_input_region()),
131+ return default_input_device_hub(
132+ [this]()
133+ {
134+ auto input_dispatcher = the_input_dispatcher();
135+ auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher);
136+ auto hub = std::make_shared<mi::DefaultInputDeviceHub>(
137+ std::make_shared<mi::BasicSeat>(
138+ input_dispatcher,
139+ the_touch_visualizer(),
140+ the_cursor_listener(),
141+ the_input_region()),
142+ the_input_reading_multiplexer(),
143+ the_main_loop(),
144+ the_cookie_authority());
145
146- the_input_reading_multiplexer(),
147- the_main_loop(),
148- the_cookie_authority());
149- });
150+ if (key_repeater)
151+ key_repeater->set_input_device_hub(hub);
152+ return hub;
153+ });
154 }
155
156=== modified file 'src/server/input/default_input_device_hub.cpp'
157--- src/server/input/default_input_device_hub.cpp 2016-01-29 15:55:17 +0000
158+++ src/server/input/default_input_device_hub.cpp 2016-03-07 15:15:54 +0000
159@@ -228,17 +228,23 @@
160
161 void mi::DefaultInputDeviceHub::remove_device_handle(MirInputDeviceId id)
162 {
163- auto handle_it = remove_if(begin(handles),
164- end(handles),
165- [&id](auto const& handle){return handle->id() == id;});
166+ auto handle_it = remove_if(
167+ begin(handles),
168+ end(handles),
169+ [this,&id](auto const& handle)
170+ {
171+ if (handle->id() != id)
172+ return false;
173+ for (auto const& observer : observers)
174+ {
175+ observer->device_removed(handle);
176+ observer->changes_complete();
177+ }
178+ return true;
179+ });
180
181 if (handle_it == end(handles))
182 return;
183- for (auto const& observer : observers)
184- {
185- observer->device_removed(*handle_it);
186- observer->changes_complete();
187- }
188
189 handles.erase(handle_it, end(handles));
190 }
191
192=== modified file 'src/server/input/key_repeat_dispatcher.cpp'
193--- src/server/input/key_repeat_dispatcher.cpp 2016-01-29 08:18:22 +0000
194+++ src/server/input/key_repeat_dispatcher.cpp 2016-03-07 15:15:54 +0000
195@@ -18,6 +18,8 @@
196
197 #include "key_repeat_dispatcher.h"
198
199+#include "mir/input/device.h"
200+#include "mir/input/input_device_hub.h"
201 #include "mir/time/alarm_factory.h"
202 #include "mir/time/alarm.h"
203 #include "mir/events/event_private.h"
204@@ -31,6 +33,34 @@
205
206 namespace mi = mir::input;
207
208+namespace
209+{
210+struct DeviceRemovalFilter : mi::InputDeviceObserver
211+{
212+ DeviceRemovalFilter(std::function<void(MirInputDeviceId)> const& on_removal)
213+ : on_removal(on_removal) {}
214+
215+ void device_added(std::shared_ptr<mi::Device> const&) override
216+ {
217+ }
218+
219+ void device_changed(std::shared_ptr<mi::Device> const&) override
220+ {
221+ }
222+
223+ void device_removed(std::shared_ptr<mi::Device> const& device) override
224+ {
225+ on_removal(device->id());
226+ }
227+
228+ void changes_complete() override
229+ {
230+ }
231+ std::function<void(MirInputDeviceId)> on_removal;
232+};
233+
234+}
235+
236 mi::KeyRepeatDispatcher::KeyRepeatDispatcher(
237 std::shared_ptr<mi::InputDispatcher> const& next_dispatcher,
238 std::shared_ptr<mir::time::AlarmFactory> const& factory,
239@@ -47,6 +77,17 @@
240 {
241 }
242
243+void mi::KeyRepeatDispatcher::set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub)
244+{
245+ hub->add_observer(std::make_shared<DeviceRemovalFilter>(
246+ [this](MirInputDeviceId id)
247+ {
248+ std::unique_lock<std::mutex> lock(repeat_state_mutex);
249+ repeat_state_by_device.erase(id); // destructor cancels alarms
250+ }
251+ ));
252+}
253+
254 mi::KeyRepeatDispatcher::KeyboardState& mi::KeyRepeatDispatcher::ensure_state_for_device_locked(std::lock_guard<std::mutex> const&, MirInputDeviceId id)
255 {
256 repeat_state_by_device.insert(std::make_pair(id, KeyboardState()));
257
258=== modified file 'src/server/input/key_repeat_dispatcher.h'
259--- src/server/input/key_repeat_dispatcher.h 2016-01-29 08:18:22 +0000
260+++ src/server/input/key_repeat_dispatcher.h 2016-03-07 15:15:54 +0000
261@@ -1,5 +1,5 @@
262 /*
263- * Copyright © 2015 Canonical Ltd.
264+ * Copyright © 2015-2016 Canonical Ltd.
265 *
266 * This program is free software: you can redistribute it and/or modify it
267 * under the terms of the GNU General Public License version 3,
268@@ -20,6 +20,7 @@
269 #define MIR_INPUT_KEY_REPEAT_DISPATCHER_H_
270
271 #include "mir/input/input_dispatcher.h"
272+#include "mir/input/input_device_observer.h"
273
274 #include <memory>
275 #include <chrono>
276@@ -39,8 +40,8 @@
277 }
278 namespace input
279 {
280-
281-class KeyRepeatDispatcher : public mir::input::InputDispatcher
282+class InputDeviceHub;
283+class KeyRepeatDispatcher : public InputDispatcher
284 {
285 public:
286 KeyRepeatDispatcher(std::shared_ptr<InputDispatcher> const& next_dispatcher,
287@@ -54,7 +55,9 @@
288 bool dispatch(MirEvent const& event) override;
289 void start() override;
290 void stop() override;
291-
292+
293+ void set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub);
294+
295 private:
296 std::mutex repeat_state_mutex;
297
298
299=== modified file 'tests/unit-tests/input/test_key_repeat_dispatcher.cpp'
300--- tests/unit-tests/input/test_key_repeat_dispatcher.cpp 2016-01-29 08:18:22 +0000
301+++ tests/unit-tests/input/test_key_repeat_dispatcher.cpp 2016-03-07 15:15:54 +0000
302@@ -23,9 +23,15 @@
303 #include "mir/time/alarm.h"
304 #include "mir/time/alarm_factory.h"
305 #include "mir/cookie/authority.h"
306+#include "mir/input/input_device_observer.h"
307+#include "mir/input/pointer_configuration.h"
308+#include "mir/input/touchpad_configuration.h"
309+#include "mir/input/device.h"
310
311+#include "mir/test/fake_shared.h"
312 #include "mir/test/event_matchers.h"
313 #include "mir/test/doubles/mock_input_dispatcher.h"
314+#include "mir/test/doubles/mock_input_device_hub.h"
315
316 #include <gtest/gtest.h>
317 #include <gmock/gmock.h>
318@@ -35,6 +41,8 @@
319 namespace mt = mir::test;
320 namespace mtd = mt::doubles;
321
322+using namespace ::testing;
323+
324 namespace
325 {
326 struct MockAlarm : public mir::time::Alarm
327@@ -43,6 +51,12 @@
328 MOCK_CONST_METHOD0(state, mir::time::Alarm::State());
329 MOCK_METHOD1(reschedule_in, bool(std::chrono::milliseconds));
330 MOCK_METHOD1(reschedule_for, bool(mir::time::Timestamp));
331+
332+ // destructor cancels the alarm
333+ ~MockAlarm()
334+ {
335+ cancel();
336+ }
337 };
338
339 struct MockAlarmFactory : public mir::time::AlarmFactory
340@@ -59,25 +73,60 @@
341 }
342 };
343
344+struct StubDevice : public mi::Device
345+{
346+ MirInputDeviceId device_id;
347+ StubDevice(MirInputDeviceId id) : device_id(id) {}
348+ MirInputDeviceId id() const { return device_id;}
349+ mi::DeviceCapabilities capabilities() const {return mi::DeviceCapability::keyboard;}
350+ std::string name() const {return {};}
351+ std::string unique_id() const {return {};}
352+
353+ mir::optional_value<mi::PointerConfiguration> pointer_configuration() const {return {};}
354+ void apply_pointer_configuration(mi::PointerConfiguration const&) {;}
355+ mir::optional_value<mi::TouchpadConfiguration> touchpad_configuration() const {return {};}
356+ void apply_touchpad_configuration(mi::TouchpadConfiguration const&) {}
357+};
358+
359 struct KeyRepeatDispatcher : public testing::Test
360 {
361 KeyRepeatDispatcher()
362 : dispatcher(mock_next_dispatcher, mock_alarm_factory, cookie_authority, true, repeat_time, repeat_delay)
363 {
364- }
365+ ON_CALL(hub,add_observer(_)).WillByDefault(SaveArg<0>(&observer));
366+ dispatcher.set_input_device_hub(mt::fake_shared(hub));
367+ }
368+ void simulate_device_removal()
369+ {
370+ StubDevice dev(test_device);
371+ observer->device_removed(mt::fake_shared(dev));
372+ observer->changes_complete();
373+ }
374+
375+ const MirInputDeviceId test_device = 123;
376 std::shared_ptr<mtd::MockInputDispatcher> mock_next_dispatcher = std::make_shared<mtd::MockInputDispatcher>();
377 std::shared_ptr<MockAlarmFactory> mock_alarm_factory = std::make_shared<MockAlarmFactory>();
378 std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create();
379 std::chrono::milliseconds const repeat_time{2};
380 std::chrono::milliseconds const repeat_delay{1};
381+ std::shared_ptr<mi::InputDeviceObserver> observer;
382+ NiceMock<mtd::MockInputDeviceHub> hub;
383 mi::KeyRepeatDispatcher dispatcher;
384+
385+ mir::EventUPtr a_key_down_event()
386+ {
387+ 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);
388+ }
389+
390+ mir::EventUPtr a_key_up_event()
391+ {
392+ 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);
393+ }
394 };
395 }
396
397 TEST_F(KeyRepeatDispatcher, forwards_start_stop)
398 {
399- using namespace ::testing;
400-
401 InSequence seq;
402 EXPECT_CALL(*mock_next_dispatcher, start()).Times(1);
403 EXPECT_CALL(*mock_next_dispatcher, stop()).Times(1);
404@@ -86,22 +135,8 @@
405 dispatcher.stop();
406 }
407
408-namespace
409-{
410-mir::EventUPtr a_key_down_event()
411-{
412- return mev::make_event(0, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_down, 0, 0, mir_input_event_modifier_alt);
413-}
414-mir::EventUPtr a_key_up_event()
415-{
416- return mev::make_event(0, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_up, 0, 0, mir_input_event_modifier_alt);
417-}
418-}
419-
420 TEST_F(KeyRepeatDispatcher, schedules_alarm_to_repeat_key_down)
421 {
422- using namespace ::testing;
423-
424 MockAlarm *mock_alarm = new MockAlarm; // deleted by AlarmFactory
425 std::function<void()> alarm_function;
426
427@@ -122,3 +157,28 @@
428 // Trigger the cancel
429 dispatcher.dispatch(*a_key_up_event());
430 }
431+
432+TEST_F(KeyRepeatDispatcher, stops_repeat_on_device_removal)
433+{
434+ MockAlarm *mock_alarm = new MockAlarm;
435+ std::function<void()> alarm_function;
436+ bool alarm_canceled = false;
437+
438+ InSequence seq;
439+ EXPECT_CALL(*mock_alarm_factory, create_alarm_adapter(_)).Times(1).
440+ WillOnce(DoAll(SaveArg<0>(&alarm_function), Return(mock_alarm)));
441+ // Once for initial down and again when invoked
442+ EXPECT_CALL(*mock_alarm, reschedule_in(repeat_time)).Times(1).WillOnce(Return(true));
443+ EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyDownEvent())).Times(1);
444+ EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyRepeatEvent())).Times(1);
445+ EXPECT_CALL(*mock_alarm, reschedule_in(repeat_delay)).Times(1).WillOnce(Return(true));
446+ ON_CALL(*mock_alarm, cancel()).WillByDefault(Invoke([&](){alarm_canceled = true; return true;}));
447+
448+ dispatcher.dispatch(*a_key_down_event());
449+
450+ alarm_function();
451+ Mock::VerifyAndClearExpectations(mock_alarm); // mock_alarm will be deleted after this
452+
453+ simulate_device_removal();
454+ EXPECT_THAT(alarm_canceled, Eq(true));
455+}

Subscribers

People subscribed via source and target branches

to all changes: