Mir

Merge lp:~robertcarr/mir/enable-pointer-touch-input into lp:~mir-team/mir/trunk

Proposed by Robert Carr
Status: Superseded
Proposed branch: lp:~robertcarr/mir/enable-pointer-touch-input
Merge into: lp:~mir-team/mir/trunk
Diff against target: 2645 lines (+1013/-387)
49 files modified
include/server/mir/default_server_configuration.h (+3/-3)
include/server/mir/input/input_manager.h (+0/-1)
include/server/mir/input/null_input_manager.h (+0/-5)
include/server/mir/input/null_input_target_listener.h (+26/-11)
include/server/mir/input/surface_target.h (+2/-0)
include/server/mir/shell/application_session.h (+4/-1)
include/server/mir/shell/input_focus_selector.h (+0/-52)
include/server/mir/shell/input_target_listener.h (+59/-0)
include/server/mir/shell/session_manager.h (+5/-2)
include/server/mir/shell/single_visibility_focus_mechanism.h (+1/-4)
include/server/mir/shell/surface.h (+1/-0)
include/test/mir_test/event_matchers.h (+64/-0)
include/test/mir_test/fake_event_hub_input_configuration.h (+2/-0)
include/test/mir_test_doubles/mock_event_filter.h (+0/-32)
include/test/mir_test_doubles/mock_input_focus_selector.h (+0/-40)
include/test/mir_test_doubles/mock_input_target_listener.h (+49/-0)
include/test/mir_test_doubles/stub_input_target_listener.h (+59/-0)
include/test/mir_test_doubles/stub_surface_target.h (+4/-0)
include/test/mir_test_framework/testing_server_configuration.h (+1/-1)
src/server/default_server_configuration.cpp (+8/-8)
src/server/display_server.cpp (+1/-1)
src/server/input/android/android_dispatcher_controller.cpp (+73/-23)
src/server/input/android/android_dispatcher_controller.h (+19/-6)
src/server/input/android/android_input_window_handle.cpp (+8/-2)
src/server/input/android/default_android_input_configuration.cpp (+6/-1)
src/server/input/android/default_android_input_configuration.h (+2/-0)
src/server/input/android/event_filter_dispatcher_policy.cpp (+6/-5)
src/server/input/android/event_filter_dispatcher_policy.h (+2/-1)
src/server/shell/application_session.cpp (+6/-2)
src/server/shell/session_manager.cpp (+27/-10)
src/server/shell/single_visibility_focus_mechanism.cpp (+2/-7)
src/server/shell/surface.cpp (+12/-0)
tests/acceptance-tests/test_client_input.cpp (+145/-35)
tests/acceptance-tests/test_focus_selection.cpp (+21/-21)
tests/death-tests/test_application_manager_death.cpp (+4/-3)
tests/integration-tests/input/android/test_android_input_manager.cpp (+71/-12)
tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp (+2/-1)
tests/integration-tests/shell/test_session_manager.cpp (+24/-17)
tests/mir_test_doubles/fake_event_hub.cpp (+2/-2)
tests/mir_test_framework/testing_server_options.cpp (+3/-11)
tests/unit-tests/input/android/test_android_dispatcher_controller.cpp (+138/-13)
tests/unit-tests/input/android/test_android_input_window_handle.cpp (+11/-0)
tests/unit-tests/input/android/test_event_filter_input_dispatcher_policy.cpp (+15/-2)
tests/unit-tests/shell/test_application_session.cpp (+11/-5)
tests/unit-tests/shell/test_registration_order_focus_sequence.cpp (+16/-11)
tests/unit-tests/shell/test_session_manager.cpp (+72/-8)
tests/unit-tests/shell/test_single_visibility_focus_mechanism.cpp (+1/-24)
tests/unit-tests/shell/test_surface.cpp (+18/-0)
tests/unit-tests/shell/test_the_session_container_implementation.cpp (+7/-4)
To merge this branch: bzr merge lp:~robertcarr/mir/enable-pointer-touch-input
Reviewer Review Type Date Requested Status
Mir development team Pending
Review via email: mp+160151@code.launchpad.net

This proposal has been superseded by a proposal from 2013-04-22.

Commit message

Enable motion events! (Pointer and touch input)

Description of the change

Enable motion events in the DispatcherPolicy and Window Handle. This branch is largely new acceptance tests! (small changes to event_filter_dispatcher_policy and android_input_window_handle)

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/default_server_configuration.h'
2--- include/server/mir/default_server_configuration.h 2013-04-19 15:59:41 +0000
3+++ include/server/mir/default_server_configuration.h 2013-04-22 16:32:37 +0000
4@@ -50,7 +50,7 @@
5 {
6 class SurfaceFactory;
7 class SurfaceBuilder;
8-class InputFocusSelector;
9+class InputTargetListener;
10 class SessionContainer;
11 class FocusSetter;
12 class FocusSequence;
13@@ -156,7 +156,6 @@
14 /** @name shell configuration - dependencies
15 * dependencies of shell on the rest of the Mir
16 * @{ */
17- virtual std::shared_ptr<shell::InputFocusSelector> the_input_focus_selector();
18 virtual std::shared_ptr<shell::SurfaceBuilder> the_surface_builder();
19 /** @} */
20
21@@ -178,6 +177,7 @@
22 * @{ */
23 virtual std::shared_ptr<input::android::InputConfiguration> the_input_configuration();
24 virtual std::initializer_list<std::shared_ptr<input::EventFilter> const> the_event_filters();
25+ virtual std::shared_ptr<shell::InputTargetListener> the_input_target_listener();
26 /** @} */
27
28 /** @name logging configuration - customization
29@@ -197,7 +197,7 @@
30 CachedPtr<frontend::Shell> session_manager;
31 std::shared_ptr<input::android::InputConfiguration> input_configuration;
32 CachedPtr<input::InputManager> input_manager;
33- CachedPtr<shell::InputFocusSelector> input_focus_selector;
34+ CachedPtr<shell::InputTargetListener> input_target_listener;
35 CachedPtr<graphics::Platform> graphics_platform;
36 CachedPtr<graphics::BufferInitializer> buffer_initializer;
37 CachedPtr<compositor::GraphicBufferAllocator> buffer_allocator;
38
39=== modified file 'include/server/mir/input/input_manager.h'
40--- include/server/mir/input/input_manager.h 2013-04-16 09:08:29 +0000
41+++ include/server/mir/input/input_manager.h 2013-04-22 16:32:37 +0000
42@@ -21,7 +21,6 @@
43 #define MIR_INPUT_INPUT_MANAGER_H_
44
45 #include "mir/input/input_channel_factory.h"
46-#include "mir/shell/input_focus_selector.h"
47
48 #include <memory>
49
50
51=== modified file 'include/server/mir/input/null_input_manager.h'
52--- include/server/mir/input/null_input_manager.h 2013-04-16 09:08:29 +0000
53+++ include/server/mir/input/null_input_manager.h 2013-04-22 16:32:37 +0000
54@@ -40,11 +40,6 @@
55 return std::shared_ptr<InputChannel>();
56 }
57
58- virtual void set_input_focus_to(std::shared_ptr<input::SessionTarget> const& /* session */,
59- std::shared_ptr<input::SurfaceTarget> const& /* surface */)
60- {
61- }
62-
63 protected:
64 NullInputManager(const NullInputManager&) = delete;
65 NullInputManager& operator=(const NullInputManager&) = delete;
66
67=== renamed file 'include/server/mir/input/null_input_focus_selector.h' => 'include/server/mir/input/null_input_target_listener.h'
68--- include/server/mir/input/null_input_focus_selector.h 2013-04-17 02:04:35 +0000
69+++ include/server/mir/input/null_input_target_listener.h 2013-04-22 16:32:37 +0000
70@@ -16,33 +16,48 @@
71 * Authored by: Robert Carr <robert.carr@canonical.com>
72 */
73
74-#ifndef MIR_INPUT_NULL_INPUT_FOCUS_SELECTOR_H_
75-#define MIR_INPUT_NULL_INPUT_FOCUS_SELECTOR_H_
76+#ifndef MIR_INPUT_NULL_INPUT_TARGET_LISTENER_H_
77+#define MIR_INPUT_NULL_INPUT_TARGET_LISTENER_H_
78
79-#include "mir/shell/input_focus_selector.h"
80+#include "mir/shell/input_target_listener.h"
81
82 namespace mir
83 {
84 namespace input
85 {
86
87-class NullInputFocusSelector : public shell::InputFocusSelector
88+class NullInputTargetListener : public shell::InputTargetListener
89 {
90 public:
91- NullInputFocusSelector() {};
92- virtual ~NullInputFocusSelector() {}
93+ NullInputTargetListener() {};
94+ virtual ~NullInputTargetListener() noexcept(true) {}
95
96- virtual void set_input_focus_to(std::shared_ptr<input::SessionTarget> const&,
97- std::shared_ptr<input::SurfaceTarget> const&)
98+ virtual void input_application_opened(std::shared_ptr<input::SessionTarget> const&)
99+ {
100+ }
101+ virtual void input_application_closed(std::shared_ptr<input::SessionTarget> const&)
102+ {
103+ }
104+ virtual void input_surface_opened(std::shared_ptr<input::SessionTarget> const&,
105+ std::shared_ptr<input::SurfaceTarget> const&)
106+ {
107+ }
108+ virtual void input_surface_closed(std::shared_ptr<input::SurfaceTarget> const&)
109+ {
110+ }
111+ virtual void focus_changed(std::shared_ptr<input::SurfaceTarget> const&)
112+ {
113+ }
114+ virtual void focus_cleared()
115 {
116 }
117
118 protected:
119- NullInputFocusSelector(const NullInputFocusSelector&) = delete;
120- NullInputFocusSelector& operator=(const NullInputFocusSelector&) = delete;
121+ NullInputTargetListener(const NullInputTargetListener&) = delete;
122+ NullInputTargetListener& operator=(const NullInputTargetListener&) = delete;
123 };
124
125 }
126 }
127
128-#endif // MIR_INPUT_NULL_INPUT_FOCUS_SELECTOR_H_
129+#endif // MIR_INPUT_NULL_INPUT_TARGET_LISTENER_H_
130
131=== modified file 'include/server/mir/input/surface_target.h'
132--- include/server/mir/input/surface_target.h 2013-04-16 09:08:29 +0000
133+++ include/server/mir/input/surface_target.h 2013-04-22 16:32:37 +0000
134@@ -20,6 +20,7 @@
135 #define MIR_INPUT_SURFACE_TARGET_H_
136
137 #include "mir/geometry/size.h"
138+#include "mir/geometry/point.h"
139
140 #include <string>
141
142@@ -33,6 +34,7 @@
143 public:
144 virtual ~SurfaceTarget() {}
145
146+ virtual geometry::Point top_left() const = 0;
147 virtual geometry::Size size() const = 0;
148 virtual std::string name() const = 0;
149
150
151=== modified file 'include/server/mir/shell/application_session.h'
152--- include/server/mir/shell/application_session.h 2013-04-16 17:42:26 +0000
153+++ include/server/mir/shell/application_session.h 2013-04-22 16:32:37 +0000
154@@ -30,11 +30,13 @@
155 {
156 class SurfaceFactory;
157 class Surface;
158+class InputTargetListener;
159
160 class ApplicationSession : public Session
161 {
162 public:
163- explicit ApplicationSession(std::shared_ptr<SurfaceFactory> const& surface_factory, std::string const& session_name);
164+ explicit ApplicationSession(std::shared_ptr<SurfaceFactory> const& surface_factory,
165+ std::shared_ptr<InputTargetListener> const& input_target_listener, std::string const& session_name);
166 ~ApplicationSession();
167
168 frontend::SurfaceId create_surface(frontend::SurfaceCreationParameters const& params);
169@@ -58,6 +60,7 @@
170
171 private:
172 std::shared_ptr<SurfaceFactory> const surface_factory;
173+ std::shared_ptr<InputTargetListener> const input_target_listener;
174 std::string const session_name;
175
176 frontend::SurfaceId next_id();
177
178=== removed file 'include/server/mir/shell/input_focus_selector.h'
179--- include/server/mir/shell/input_focus_selector.h 2013-04-16 09:08:29 +0000
180+++ include/server/mir/shell/input_focus_selector.h 1970-01-01 00:00:00 +0000
181@@ -1,52 +0,0 @@
182-/*
183- * Copyright © 2013 Canonical Ltd.
184- *
185- * This program is free software: you can redistribute it and/or modify it
186- * under the terms of the GNU General Public License version 3,
187- * as published by the Free Software Foundation.
188- *
189- * This program is distributed in the hope that it will be useful,
190- * but WITHOUT ANY WARRANTY; without even the implied warranty of
191- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
192- * GNU General Public License for more details.
193- *
194- * You should have received a copy of the GNU General Public License
195- * along with this program. If not, see <http://www.gnu.org/licenses/>.
196- *
197- * Authored by: Robert Carr <robert.carr@canonical.com>
198- */
199-
200-#ifndef MIR_SHELL_INPUT_FOCUS_SELECTOR_H_
201-#define MIR_SHELL_INPUT_FOCUS_SELECTOR_H_
202-
203-#include <memory>
204-
205-namespace mir
206-{
207-namespace input
208-{
209-class SessionTarget;
210-class SurfaceTarget;
211-}
212-
213-namespace shell
214-{
215-
216-class InputFocusSelector
217-{
218-public:
219- virtual ~InputFocusSelector() {}
220-
221- virtual void set_input_focus_to(std::shared_ptr<input::SessionTarget> const& focus_application,
222- std::shared_ptr<input::SurfaceTarget> const& focus_surface) = 0;
223-
224-protected:
225- InputFocusSelector() = default;
226- InputFocusSelector(InputFocusSelector const&) = delete;
227- InputFocusSelector& operator=(InputFocusSelector const&) = delete;
228-};
229-
230-}
231-} // namespace mir
232-
233-#endif // MIR_SHELL_INPUT_FOCUS_SELECTOR_H_
234
235=== added file 'include/server/mir/shell/input_target_listener.h'
236--- include/server/mir/shell/input_target_listener.h 1970-01-01 00:00:00 +0000
237+++ include/server/mir/shell/input_target_listener.h 2013-04-22 16:32:37 +0000
238@@ -0,0 +1,59 @@
239+/*
240+ * Copyright © 2013 Canonical Ltd.
241+ *
242+ * This program is free software: you can redistribute it and/or modify it
243+ * under the terms of the GNU General Public License version 3,
244+ * as published by the Free Software Foundation.
245+ *
246+ * This program is distributed in the hope that it will be useful,
247+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
248+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
249+ * GNU General Public License for more details.
250+ *
251+ * You should have received a copy of the GNU General Public License
252+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
253+ *
254+ * Authored by: Robert Carr <robert.carr@canonical.com>
255+ */
256+
257+#ifndef MIR_SHELL_INPUT_TARGET_LISTENER_H_
258+#define MIR_SHELL_INPUT_TARGET_LISTENER_H_
259+
260+#include <memory>
261+
262+namespace mir
263+{
264+namespace input
265+{
266+class SessionTarget;
267+class SurfaceTarget;
268+}
269+
270+namespace shell
271+{
272+
273+class InputTargetListener
274+{
275+public:
276+ virtual ~InputTargetListener() = default;
277+
278+ virtual void input_application_opened(std::shared_ptr<input::SessionTarget> const& application) = 0;
279+ virtual void input_application_closed(std::shared_ptr<input::SessionTarget> const& application) = 0;
280+
281+ virtual void input_surface_opened(std::shared_ptr<input::SessionTarget> const& application,
282+ std::shared_ptr<input::SurfaceTarget> const& opened_surface) = 0;
283+ virtual void input_surface_closed(std::shared_ptr<input::SurfaceTarget> const& closed_surface) = 0;
284+
285+ virtual void focus_changed(std::shared_ptr<input::SurfaceTarget> const& focus_surface) = 0;
286+ virtual void focus_cleared() = 0;
287+
288+protected:
289+ InputTargetListener() = default;
290+ InputTargetListener(InputTargetListener const&) = delete;
291+ InputTargetListener& operator=(InputTargetListener const&) = delete;
292+};
293+
294+}
295+} // namespace mir
296+
297+#endif // MIR_SHELL_INPUT_TARGET_LISTENER_H_
298
299=== modified file 'include/server/mir/shell/session_manager.h'
300--- include/server/mir/shell/session_manager.h 2013-04-19 09:15:31 +0000
301+++ include/server/mir/shell/session_manager.h 2013-04-22 16:32:37 +0000
302@@ -40,15 +40,17 @@
303 class SessionContainer;
304 class FocusSequence;
305 class FocusSetter;
306+class InputTargetListener;
307 class Session;
308
309 class SessionManager : public frontend::Shell
310 {
311 public:
312 explicit SessionManager(std::shared_ptr<SurfaceFactory> const& surface_factory,
313- std::shared_ptr<SessionContainer> const& session_container,
314+ std::shared_ptr<SessionContainer> const& app_container,
315 std::shared_ptr<FocusSequence> const& focus_sequence,
316- std::shared_ptr<FocusSetter> const& focus_setter);
317+ std::shared_ptr<FocusSetter> const& focus_setter,
318+ std::shared_ptr<InputTargetListener> const& input_target_listener);
319 virtual ~SessionManager();
320
321 virtual std::shared_ptr<frontend::Session> open_session(std::string const& name);
322@@ -71,6 +73,7 @@
323 std::shared_ptr<SessionContainer> const app_container;
324 std::shared_ptr<FocusSequence> const focus_sequence;
325 std::shared_ptr<FocusSetter> const focus_setter;
326+ std::shared_ptr<InputTargetListener> const input_target_listener;
327
328 std::mutex mutex;
329 std::weak_ptr<Session> focus_application;
330
331=== modified file 'include/server/mir/shell/single_visibility_focus_mechanism.h'
332--- include/server/mir/shell/single_visibility_focus_mechanism.h 2013-04-16 09:08:29 +0000
333+++ include/server/mir/shell/single_visibility_focus_mechanism.h 2013-04-22 16:32:37 +0000
334@@ -28,13 +28,11 @@
335 namespace shell
336 {
337 class SessionContainer;
338-class InputFocusSelector;
339
340 class SingleVisibilityFocusMechanism : public FocusSetter
341 {
342 public:
343- explicit SingleVisibilityFocusMechanism(std::shared_ptr<SessionContainer> const& app_container,
344- std::shared_ptr<shell::InputFocusSelector> const& input_selector);
345+ explicit SingleVisibilityFocusMechanism(std::shared_ptr<SessionContainer> const& app_container);
346 virtual ~SingleVisibilityFocusMechanism() {}
347
348 void set_focus_to(std::shared_ptr<shell::Session> const& new_focus);
349@@ -44,7 +42,6 @@
350 SingleVisibilityFocusMechanism& operator=(const SingleVisibilityFocusMechanism&) = delete;
351 private:
352 std::shared_ptr<SessionContainer> const app_container;
353- std::shared_ptr<shell::InputFocusSelector> const input_selector;
354 };
355
356 }
357
358=== modified file 'include/server/mir/shell/surface.h'
359--- include/server/mir/shell/surface.h 2013-04-16 17:42:26 +0000
360+++ include/server/mir/shell/surface.h 2013-04-22 16:32:37 +0000
361@@ -63,6 +63,7 @@
362 virtual std::string name() const;
363
364 virtual geometry::Size size() const;
365+ virtual geometry::Point top_left() const;
366
367 virtual geometry::PixelFormat pixel_format() const;
368
369
370=== added file 'include/test/mir_test/event_matchers.h'
371--- include/test/mir_test/event_matchers.h 1970-01-01 00:00:00 +0000
372+++ include/test/mir_test/event_matchers.h 2013-04-22 16:32:37 +0000
373@@ -0,0 +1,64 @@
374+/*
375+ * Copyright © 2013 Canonical Ltd.
376+ *
377+ * This program is free software: you can redistribute it and/or modify it
378+ * under the terms of the GNU General Public License version 3,
379+ * as published by the Free Software Foundation.
380+ *
381+ * This program is distributed in the hope that it will be useful,
382+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
383+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
384+ * GNU General Public License for more details.
385+ *
386+ * You should have received a copy of the GNU General Public License
387+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
388+ *
389+ * Authored by: Robert Carr <robert.carr@canonical.com>
390+ */
391+
392+#ifndef MIR_TEST_EVENT_MATCHERS_H_
393+#define MIR_TEST_EVENT_MATCHERS_H_
394+
395+#include <androidfw/Input.h>
396+
397+#include <gmock/gmock.h>
398+
399+namespace mir
400+{
401+namespace test
402+{
403+
404+MATCHER_P(IsKeyEventWithKey, key, "")
405+{
406+ if (arg.type != mir_event_type_key)
407+ return false;
408+
409+ return arg.key.key_code == key;
410+}
411+MATCHER(KeyDownEvent, "")
412+{
413+ if (arg.type != mir_event_type_key)
414+ return false;
415+
416+ return arg.key.action == AKEY_EVENT_ACTION_DOWN;
417+}
418+MATCHER(ButtonDownEvent, "")
419+{
420+ if (arg.type != mir_event_type_motion)
421+ return false;
422+ if (arg.motion.button_state == 0)
423+ return false;
424+ return arg.motion.action == AMOTION_EVENT_ACTION_DOWN;
425+}
426+MATCHER_P2(MotionEvent, dx, dy, "")
427+{
428+ if (arg.type != mir_event_type_motion)
429+ return false;
430+ auto coords = &arg.motion.pointer_coordinates[0];
431+ return (coords->x == dx) && (coords->y == dy);
432+}
433+
434+}
435+} // namespace mir
436+
437+#endif // MIR_TEST_EVENT_MATCHERS_H_
438
439=== modified file 'include/test/mir_test/fake_event_hub_input_configuration.h'
440--- include/test/mir_test/fake_event_hub_input_configuration.h 2013-04-16 09:08:29 +0000
441+++ include/test/mir_test/fake_event_hub_input_configuration.h 2013-04-22 16:32:37 +0000
442@@ -63,6 +63,8 @@
443
444 droidinput::sp<droidinput::EventHubInterface> the_event_hub();
445 input::android::FakeEventHub* the_fake_event_hub();
446+
447+ bool is_key_repeat_enabled() override { return false; }
448
449
450 protected:
451
452=== modified file 'include/test/mir_test_doubles/mock_event_filter.h'
453--- include/test/mir_test_doubles/mock_event_filter.h 2013-04-16 09:08:29 +0000
454+++ include/test/mir_test_doubles/mock_event_filter.h 2013-04-22 16:32:37 +0000
455@@ -21,8 +21,6 @@
456
457 #include "mir/input/event_filter.h"
458
459-#include <androidfw/Input.h>
460-
461 #include <gmock/gmock.h>
462
463 namespace mir
464@@ -36,36 +34,6 @@
465 MOCK_METHOD1(handles, bool(const MirEvent&));
466 };
467 }
468-
469-MATCHER_P(IsKeyEventWithKey, key, "")
470-{
471- if (arg.type != mir_event_type_key)
472- return false;
473-
474- return arg.key.key_code == key;
475-}
476-MATCHER(KeyDownEvent, "")
477-{
478- if (arg.type != mir_event_type_key)
479- return false;
480-
481- return arg.key.action == AKEY_EVENT_ACTION_DOWN;
482-}
483-MATCHER(ButtonDownEvent, "")
484-{
485- if (arg.type != mir_event_type_motion)
486- return false;
487- if (arg.motion.button_state == 0)
488- return false;
489- return arg.motion.action == AKEY_EVENT_ACTION_DOWN;
490-}
491-MATCHER_P2(MotionEvent, dx, dy, "")
492-{
493- if (arg.type != mir_event_type_motion)
494- return false;
495- auto coords = &arg.motion.pointer_coordinates[0];
496- return (coords->x == dx) && (coords->y == dy);
497-}
498 }
499 }
500
501
502=== removed file 'include/test/mir_test_doubles/mock_input_focus_selector.h'
503--- include/test/mir_test_doubles/mock_input_focus_selector.h 2013-04-16 09:08:29 +0000
504+++ include/test/mir_test_doubles/mock_input_focus_selector.h 1970-01-01 00:00:00 +0000
505@@ -1,40 +0,0 @@
506-/*
507- * Copyright © 2013 Canonical Ltd.
508- *
509- * This program is free software: you can redistribute it and/or modify it
510- * under the terms of the GNU General Public License version 3,
511- * as published by the Free Software Foundation.
512- *
513- * This program is distributed in the hope that it will be useful,
514- * but WITHOUT ANY WARRANTY; without even the implied warranty of
515- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
516- * GNU General Public License for more details.
517- *
518- * You should have received a copy of the GNU General Public License
519- * along with this program. If not, see <http://www.gnu.org/licenses/>.
520- *
521- * Authored by: Robert Carr <robert.carr@canonical.com>
522- */
523-
524-#ifndef MIR_TEST_DOUBLES_MOCK_INPUT_FOCUS_SELECTOR_H_
525-#define MIR_TEST_DOUBLES_MOCK_INPUT_FOCUS_SELECTOR_H_
526-
527-#include "mir/shell/input_focus_selector.h"
528-
529-namespace mir
530-{
531-namespace test
532-{
533-namespace doubles
534-{
535-
536-struct MockInputFocusSelector : public shell::InputFocusSelector
537-{
538- MOCK_METHOD2(set_input_focus_to, void(std::shared_ptr<input::SessionTarget> const&, std::shared_ptr<input::SurfaceTarget> const&));
539-};
540-
541-}
542-}
543-} // namespace mir
544-
545-#endif // MIR_TEST_DOUBLES_MOCK_INPUT_FOCUS_SELECTOR_H_
546
547=== added file 'include/test/mir_test_doubles/mock_input_target_listener.h'
548--- include/test/mir_test_doubles/mock_input_target_listener.h 1970-01-01 00:00:00 +0000
549+++ include/test/mir_test_doubles/mock_input_target_listener.h 2013-04-22 16:32:37 +0000
550@@ -0,0 +1,49 @@
551+/*
552+ * Copyright © 2013 Canonical Ltd.
553+ *
554+ * This program is free software: you can redistribute it and/or modify it
555+ * under the terms of the GNU General Public License version 3,
556+ * as published by the Free Software Foundation.
557+ *
558+ * This program is distributed in the hope that it will be useful,
559+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
560+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
561+ * GNU General Public License for more details.
562+ *
563+ * You should have received a copy of the GNU General Public License
564+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
565+ *
566+ * Authored by: Robert Carr <robert.carr@canonical.com>
567+ */
568+
569+#ifndef MIR_TEST_DOUBLES_MOCK_INPUT_TARGET_LISTENER_H_
570+#define MIR_TEST_DOUBLES_MOCK_INPUT_TARGET_LISTENER_H_
571+
572+#include "mir/shell/input_target_listener.h"
573+
574+#include <gmock/gmock.h>
575+
576+namespace mir
577+{
578+namespace test
579+{
580+namespace doubles
581+{
582+
583+struct MockInputTargetListener : public shell::InputTargetListener
584+{
585+ virtual ~MockInputTargetListener() noexcept(true) {}
586+ MOCK_METHOD1(input_application_opened, void(std::shared_ptr<input::SessionTarget> const& application));
587+ MOCK_METHOD1(input_application_closed, void(std::shared_ptr<input::SessionTarget> const& application));
588+ MOCK_METHOD2(input_surface_opened, void(std::shared_ptr<input::SessionTarget> const& application,
589+ std::shared_ptr<input::SurfaceTarget> const& opened_surface));
590+ MOCK_METHOD1(input_surface_closed, void(std::shared_ptr<input::SurfaceTarget> const& closed_surface));
591+ MOCK_METHOD1(focus_changed, void(std::shared_ptr<input::SurfaceTarget> const& focus_surface));
592+ MOCK_METHOD0(focus_cleared, void());
593+};
594+
595+}
596+}
597+} // namespace mir
598+
599+#endif // MIR_TEST_DOUBLES_MOCK_INPUT_TARGET_LISTENER_H_
600
601=== added file 'include/test/mir_test_doubles/stub_input_target_listener.h'
602--- include/test/mir_test_doubles/stub_input_target_listener.h 1970-01-01 00:00:00 +0000
603+++ include/test/mir_test_doubles/stub_input_target_listener.h 2013-04-22 16:32:37 +0000
604@@ -0,0 +1,59 @@
605+/*
606+ * Copyright © 2013 Canonical Ltd.
607+ *
608+ * This program is free software: you can redistribute it and/or modify it
609+ * under the terms of the GNU General Public License version 3,
610+ * as published by the Free Software Foundation.
611+ *
612+ * This program is distributed in the hope that it will be useful,
613+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
614+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
615+ * GNU General Public License for more details.
616+ *
617+ * You should have received a copy of the GNU General Public License
618+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
619+ *
620+ * Authored by: Robert Carr <robert.carr@canonical.com>
621+ */
622+
623+#ifndef MIR_TEST_DOUBLES_STUB_INPUT_LISTENER_H_
624+#define MIR_TEST_DOUBLES_STUB_INPUT_LISTENER_H_
625+
626+#include "mir/shell/input_target_listener.h"
627+
628+namespace mir
629+{
630+namespace test
631+{
632+namespace doubles
633+{
634+
635+struct StubInputTargetListener : public shell::InputTargetListener
636+{
637+ void input_application_opened(std::shared_ptr<input::SessionTarget> const&)
638+ {
639+ }
640+ void input_application_closed(std::shared_ptr<input::SessionTarget> const&)
641+ {
642+ }
643+ void input_surface_opened(std::shared_ptr<input::SessionTarget> const&,
644+ std::shared_ptr<input::SurfaceTarget> const&)
645+ {
646+ }
647+ void input_surface_closed(std::shared_ptr<input::SurfaceTarget> const&)
648+ {
649+ }
650+ void focus_changed(std::shared_ptr<input::SurfaceTarget> const&)
651+ {
652+ }
653+
654+ void focus_cleared()
655+ {
656+ }
657+};
658+
659+}
660+}
661+} // namespace mir
662+
663+#endif // MIR_TEST_DOUBLES_STUB_INPUT_LISTENER_H_
664
665=== modified file 'include/test/mir_test_doubles/stub_surface_target.h'
666--- include/test/mir_test_doubles/stub_surface_target.h 2013-04-16 09:08:29 +0000
667+++ include/test/mir_test_doubles/stub_surface_target.h 2013-04-22 16:32:37 +0000
668@@ -43,6 +43,10 @@
669 {
670 return geometry::Size();
671 }
672+ geometry::Point top_left() const override
673+ {
674+ return geometry::Point();
675+ }
676 std::string name() const override
677 {
678 return std::string();
679
680=== modified file 'include/test/mir_test_framework/testing_server_configuration.h'
681--- include/test/mir_test_framework/testing_server_configuration.h 2013-04-16 09:08:29 +0000
682+++ include/test/mir_test_framework/testing_server_configuration.h 2013-04-22 16:32:37 +0000
683@@ -49,7 +49,7 @@
684 // to avoid starting and stopping the full android input stack for tests
685 // which do not leverage input.
686 std::shared_ptr<input::InputManager> the_input_manager();
687- std::shared_ptr<shell::InputFocusSelector> the_input_focus_selector();
688+ std::shared_ptr<shell::InputTargetListener> the_input_target_listener();
689
690 virtual std::string the_socket_file() const;
691 using DefaultServerConfiguration::the_options;
692
693=== modified file 'src/server/default_server_configuration.cpp'
694--- src/server/default_server_configuration.cpp 2013-04-19 12:49:42 +0000
695+++ src/server/default_server_configuration.cpp 2013-04-22 16:32:37 +0000
696@@ -45,7 +45,7 @@
697 #include "mir/graphics/buffer_initializer.h"
698 #include "mir/graphics/null_display_report.h"
699 #include "mir/input/null_input_manager.h"
700-#include "mir/input/null_input_focus_selector.h"
701+#include "mir/input/null_input_target_listener.h"
702 #include "input/android/default_android_input_configuration.h"
703 #include "input/android/android_input_manager.h"
704 #include "input/android/android_dispatcher_controller.h"
705@@ -310,8 +310,7 @@
706 [this]
707 {
708 return std::make_shared<msh::SingleVisibilityFocusMechanism>(
709- the_shell_session_container(),
710- the_input_focus_selector());
711+ the_shell_session_container());
712 });
713 }
714
715@@ -347,7 +346,8 @@
716 the_shell_surface_factory(),
717 the_shell_session_container(),
718 the_shell_focus_sequence(),
719- the_shell_focus_setter());
720+ the_shell_focus_setter(),
721+ the_input_target_listener());
722 });
723 }
724
725@@ -562,15 +562,15 @@
726 return the_input_manager();
727 }
728
729-std::shared_ptr<msh::InputFocusSelector> mir::DefaultServerConfiguration::the_input_focus_selector()
730+std::shared_ptr<msh::InputTargetListener> mir::DefaultServerConfiguration::the_input_target_listener()
731 {
732- return input_focus_selector(
733- [&]() -> std::shared_ptr<msh::InputFocusSelector>
734+ return input_target_listener(
735+ [&]() -> std::shared_ptr<msh::InputTargetListener>
736 {
737 if (the_options()->get("enable-input", false))
738 return std::make_shared<mia::DispatcherController>(the_input_configuration());
739 else
740- return std::make_shared<mi::NullInputFocusSelector>();
741+ return std::make_shared<mi::NullInputTargetListener>();
742 });
743 }
744
745
746=== modified file 'src/server/display_server.cpp'
747--- src/server/display_server.cpp 2013-04-19 14:52:23 +0000
748+++ src/server/display_server.cpp 2013-04-22 16:32:37 +0000
749@@ -31,9 +31,9 @@
750
751 namespace mc = mir::compositor;
752 namespace mf = mir::frontend;
753-namespace msh = mir::shell;
754 namespace mg = mir::graphics;
755 namespace mi = mir::input;
756+namespace msh = mir::shell;
757
758 namespace
759 {
760
761=== modified file 'src/server/input/android/android_dispatcher_controller.cpp'
762--- src/server/input/android/android_dispatcher_controller.cpp 2013-04-11 23:06:12 +0000
763+++ src/server/input/android/android_dispatcher_controller.cpp 2013-04-22 16:32:37 +0000
764@@ -25,35 +25,85 @@
765
766 #include <InputDispatcher.h>
767
768+#include <boost/throw_exception.hpp>
769+
770+#include <stdexcept>
771+#include <mutex>
772+
773 namespace mi = mir::input;
774 namespace mia = mi::android;
775
776 mia::DispatcherController::DispatcherController(std::shared_ptr<mia::InputConfiguration> const& config) :
777- input_dispatcher(config->the_dispatcher()),
778- focused_window_handle(0),
779- focused_application_handle(0)
780-{
781-}
782-
783-void mia::DispatcherController::set_input_focus_to(std::shared_ptr<mi::SessionTarget> const& session,
784- std::shared_ptr<mi::SurfaceTarget> const& surface)
785-{
786- if (focused_window_handle.get())
787- {
788- input_dispatcher->unregisterInputChannel(focused_window_handle->getInfo()->inputChannel);
789- focused_window_handle.clear();
790- focused_application_handle.clear();
791- }
792+ input_dispatcher(config->the_dispatcher())
793+{
794+}
795+
796+void mia::DispatcherController::input_application_opened(std::shared_ptr<mi::SessionTarget> const& session)
797+{
798+ std::unique_lock<std::mutex> lock(handles_mutex);
799+ if (application_handles.find(session) != application_handles.end())
800+ BOOST_THROW_EXCEPTION(std::logic_error("An application was opened twice"));
801+ application_handles[session] = new mia::InputApplicationHandle(session);
802+}
803+
804+void mia::DispatcherController::input_application_closed(std::shared_ptr<mi::SessionTarget> const& session)
805+{
806+ std::unique_lock<std::mutex> lock(handles_mutex);
807+ if (application_handles.find(session) == application_handles.end())
808+ BOOST_THROW_EXCEPTION(std::logic_error("An application was closed twice"));
809+ application_handles.erase(session);
810+}
811+
812+void mia::DispatcherController::input_surface_opened(std::shared_ptr<mi::SessionTarget> const& session,
813+ std::shared_ptr<input::SurfaceTarget> const& opened_surface)
814+{
815+ std::unique_lock<std::mutex> lock(handles_mutex);
816+ auto application_handle = application_handles.find(session);
817+ if (application_handle == application_handles.end())
818+ BOOST_THROW_EXCEPTION(std::logic_error("A surface was opened for an unopened application"));
819+ if (window_handles.find(opened_surface) != window_handles.end())
820+ BOOST_THROW_EXCEPTION(std::logic_error("A surface was opened twice"));
821+
822+ droidinput::sp<droidinput::InputWindowHandle> window_handle = new mia::InputWindowHandle(application_handle->second, opened_surface);
823+ input_dispatcher->registerInputChannel(window_handle->getInfo()->inputChannel, window_handle, false);
824+
825+ window_handles[opened_surface] = window_handle;
826+}
827+
828+void mia::DispatcherController::input_surface_closed(std::shared_ptr<input::SurfaceTarget> const& closed_surface)
829+{
830+ std::unique_lock<std::mutex> lock(handles_mutex);
831+ auto it = window_handles.find(closed_surface);
832+ if (it == window_handles.end())
833+ BOOST_THROW_EXCEPTION(std::logic_error("A surface was closed twice"));
834+
835+ input_dispatcher->unregisterInputChannel(it->second->getInfo()->inputChannel);
836+ window_handles.erase(it);
837+}
838+
839+void mia::DispatcherController::focus_cleared()
840+{
841+ droidinput::Vector<droidinput::sp<droidinput::InputWindowHandle>> empty_windows;
842+ droidinput::sp<droidinput::InputApplicationHandle> null_application = nullptr;
843+
844+ input_dispatcher->setFocusedApplication(null_application);
845+ input_dispatcher->setInputWindows(empty_windows);
846+}
847+
848+void mia::DispatcherController::focus_changed(std::shared_ptr<mi::SurfaceTarget> const& surface)
849+{
850+ std::unique_lock<std::mutex> lock(handles_mutex);
851+
852+ auto window_handle = window_handles[surface];
853+
854+ if (!window_handle.get())
855+ BOOST_THROW_EXCEPTION(std::logic_error("Focus changed to an unopened surface"));
856+ auto application_handle = window_handle->inputApplicationHandle;
857+
858+ input_dispatcher->setFocusedApplication(application_handle);
859
860 droidinput::Vector<droidinput::sp<droidinput::InputWindowHandle>> windows;
861- if (surface)
862- {
863- focused_application_handle = new mia::InputApplicationHandle(session);
864- focused_window_handle = new mia::InputWindowHandle(focused_application_handle, surface);
865- input_dispatcher->setFocusedApplication(focused_application_handle);
866+ windows.push_back(window_handle);
867
868- input_dispatcher->registerInputChannel(focused_window_handle->getInfo()->inputChannel, focused_window_handle, false);
869- windows.push_back(focused_window_handle);
870- }
871 input_dispatcher->setInputWindows(windows);
872 }
873
874=== modified file 'src/server/input/android/android_dispatcher_controller.h'
875--- src/server/input/android/android_dispatcher_controller.h 2013-04-11 23:06:12 +0000
876+++ src/server/input/android/android_dispatcher_controller.h 2013-04-22 16:32:37 +0000
877@@ -19,10 +19,13 @@
878 #ifndef MIR_INPUT_ANDROID_DISPATCHER_CONTROLLER_H_
879 #define MIR_INPUT_ANDROID_DISPATCHER_CONTROLLER_H_
880
881-#include "mir/shell/input_focus_selector.h"
882+#include "mir/shell/input_target_listener.h"
883
884 #include <utils/StrongPointer.h>
885
886+#include <map>
887+#include <mutex>
888+
889 namespace android
890 {
891 class InputDispatcherInterface;
892@@ -40,13 +43,21 @@
893 {
894 class InputConfiguration;
895
896-class DispatcherController : public shell::InputFocusSelector
897+class DispatcherController : public shell::InputTargetListener
898 {
899 public:
900 explicit DispatcherController(std::shared_ptr<InputConfiguration> const& input_configuration);
901- virtual ~DispatcherController() = default;
902+ virtual ~DispatcherController() noexcept(true) {}
903
904- void set_input_focus_to(std::shared_ptr<input::SessionTarget> const& session, std::shared_ptr<input::SurfaceTarget> const& surface);
905+ void input_application_opened(std::shared_ptr<input::SessionTarget> const& application);
906+ void input_application_closed(std::shared_ptr<input::SessionTarget> const& application);
907+
908+ void input_surface_opened(std::shared_ptr<input::SessionTarget> const& application,
909+ std::shared_ptr<input::SurfaceTarget> const& opened_surface);
910+ void input_surface_closed(std::shared_ptr<input::SurfaceTarget> const& closed_surface);
911+
912+ void focus_changed(std::shared_ptr<input::SurfaceTarget> const& focus_surface);
913+ void focus_cleared();
914
915 protected:
916 DispatcherController(const DispatcherController&) = delete;
917@@ -55,8 +66,10 @@
918 private:
919 droidinput::sp<droidinput::InputDispatcherInterface> input_dispatcher;
920
921- droidinput::sp<droidinput::InputWindowHandle> focused_window_handle;
922- droidinput::sp<droidinput::InputApplicationHandle> focused_application_handle;
923+ std::map<std::shared_ptr<input::SessionTarget>, droidinput::sp<droidinput::InputApplicationHandle>> application_handles;
924+ std::map<std::shared_ptr<input::SurfaceTarget>, droidinput::sp<droidinput::InputWindowHandle>> window_handles;
925+
926+ std::mutex handles_mutex;
927 };
928
929 }
930
931=== modified file 'src/server/input/android/android_input_window_handle.cpp'
932--- src/server/input/android/android_input_window_handle.cpp 2013-03-29 16:51:35 +0000
933+++ src/server/input/android/android_input_window_handle.cpp 2013-04-22 16:32:37 +0000
934@@ -48,11 +48,17 @@
935 surface->server_input_fd());
936 }
937
938- mInfo->frameLeft = 0;
939- mInfo->frameTop = 0;
940+ auto surface_position = surface->top_left();
941+ mInfo->frameLeft = surface_position.x.as_uint32_t();
942+ mInfo->frameTop = surface_position.y.as_uint32_t();
943 auto surface_size = surface->size();
944 mInfo->frameRight = mInfo->frameLeft + surface_size.width.as_uint32_t();
945 mInfo->frameBottom = mInfo->frameTop + surface_size.height.as_uint32_t();
946+
947+ mInfo->touchableRegionLeft = mInfo->frameLeft;
948+ mInfo->touchableRegionTop = mInfo->frameTop;
949+ mInfo->touchableRegionRight = mInfo->frameRight;
950+ mInfo->touchableRegionBottom = mInfo->frameBottom;
951
952 mInfo->name = droidinput::String8(surface->name().c_str());
953 mInfo->layoutParamsFlags = droidinput::InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
954
955=== modified file 'src/server/input/android/default_android_input_configuration.cpp'
956--- src/server/input/android/default_android_input_configuration.cpp 2013-04-16 09:08:29 +0000
957+++ src/server/input/android/default_android_input_configuration.cpp 2013-04-22 16:32:37 +0000
958@@ -98,7 +98,7 @@
959 return dispatcher_policy(
960 [this]()
961 {
962- return new mia::EventFilterDispatcherPolicy(filter_chain);
963+ return new mia::EventFilterDispatcherPolicy(filter_chain, is_key_repeat_enabled());
964 });
965 }
966
967@@ -149,3 +149,8 @@
968 new droidinput::InputReaderThread(the_reader()));
969 });
970 }
971+
972+bool mia::DefaultInputConfiguration::is_key_repeat_enabled()
973+{
974+ return true;
975+}
976
977=== modified file 'src/server/input/android/default_android_input_configuration.h'
978--- src/server/input/android/default_android_input_configuration.h 2013-04-16 09:08:29 +0000
979+++ src/server/input/android/default_android_input_configuration.h 2013-04-22 16:32:37 +0000
980@@ -69,6 +69,8 @@
981
982 virtual droidinput::sp<droidinput::InputDispatcherPolicyInterface> the_dispatcher_policy();
983 virtual droidinput::sp<droidinput::InputReaderPolicyInterface> the_reader_policy();
984+
985+ virtual bool is_key_repeat_enabled();
986
987 protected:
988 DefaultInputConfiguration(DefaultInputConfiguration const&) = delete;
989
990=== modified file 'src/server/input/android/event_filter_dispatcher_policy.cpp'
991--- src/server/input/android/event_filter_dispatcher_policy.cpp 2013-04-16 09:27:00 +0000
992+++ src/server/input/android/event_filter_dispatcher_policy.cpp 2013-04-22 16:32:37 +0000
993@@ -21,8 +21,9 @@
994 namespace mi = mir::input;
995 namespace mia = mi::android;
996
997-mia::EventFilterDispatcherPolicy::EventFilterDispatcherPolicy(std::shared_ptr<mi::EventFilter> const& event_filter) :
998- event_filter(event_filter)
999+mia::EventFilterDispatcherPolicy::EventFilterDispatcherPolicy(std::shared_ptr<mi::EventFilter> const& event_filter, bool key_repeat_enabled) :
1000+ event_filter(event_filter),
1001+ key_repeat_enabled(key_repeat_enabled)
1002 {
1003 }
1004
1005@@ -46,7 +47,7 @@
1006
1007 bool mia::EventFilterDispatcherPolicy::isKeyRepeatEnabled()
1008 {
1009- return true;
1010+ return key_repeat_enabled;
1011 }
1012
1013 bool mia::EventFilterDispatcherPolicy::filterInputEvent(const droidinput::InputEvent* input_event, uint32_t /*policy_flags*/)
1014@@ -67,9 +68,9 @@
1015 policy_flags |= droidinput::POLICY_FLAG_PASS_TO_USER;
1016 }
1017
1018-void mia::EventFilterDispatcherPolicy::interceptMotionBeforeQueueing(nsecs_t /* when */, uint32_t& /* policyFlags */)
1019+void mia::EventFilterDispatcherPolicy::interceptMotionBeforeQueueing(nsecs_t /* when */, uint32_t& policy_flags)
1020 {
1021- // TODO: Implement for motion events to client.
1022+ policy_flags |= droidinput::POLICY_FLAG_PASS_TO_USER;
1023 }
1024
1025 nsecs_t mia::EventFilterDispatcherPolicy::interceptKeyBeforeDispatching(
1026
1027=== modified file 'src/server/input/android/event_filter_dispatcher_policy.h'
1028--- src/server/input/android/event_filter_dispatcher_policy.h 2013-04-16 09:08:29 +0000
1029+++ src/server/input/android/event_filter_dispatcher_policy.h 2013-04-22 16:32:37 +0000
1030@@ -40,7 +40,7 @@
1031 class EventFilterDispatcherPolicy : public droidinput::InputDispatcherPolicyInterface
1032 {
1033 public:
1034- EventFilterDispatcherPolicy(std::shared_ptr<EventFilter> const& event_filter);
1035+ EventFilterDispatcherPolicy(std::shared_ptr<EventFilter> const& event_filter, bool key_repeat_enabled);
1036 virtual ~EventFilterDispatcherPolicy() {}
1037
1038 void notifyConfigurationChanged(nsecs_t when);
1039@@ -71,6 +71,7 @@
1040 EventFilterDispatcherPolicy& operator=(const EventFilterDispatcherPolicy&) = delete;
1041 private:
1042 std::shared_ptr<EventFilter> event_filter;
1043+ bool key_repeat_enabled;
1044 };
1045
1046 }
1047
1048=== modified file 'src/server/shell/application_session.cpp'
1049--- src/server/shell/application_session.cpp 2013-04-16 17:42:26 +0000
1050+++ src/server/shell/application_session.cpp 2013-04-22 16:32:37 +0000
1051@@ -18,8 +18,8 @@
1052
1053 #include "mir/shell/application_session.h"
1054 #include "mir/shell/surface.h"
1055-
1056 #include "mir/shell/surface_factory.h"
1057+#include "mir/shell/input_target_listener.h"
1058
1059 #include <boost/throw_exception.hpp>
1060
1061@@ -32,9 +32,11 @@
1062 namespace msh = mir::shell;
1063
1064 msh::ApplicationSession::ApplicationSession(
1065- std::shared_ptr<SurfaceFactory> const& surface_factory,
1066+ std::shared_ptr<msh::SurfaceFactory> const& surface_factory,
1067+ std::shared_ptr<msh::InputTargetListener> const& input_target_listener,
1068 std::string const& session_name) :
1069 surface_factory(surface_factory),
1070+ input_target_listener(input_target_listener),
1071 session_name(session_name),
1072 next_surface_id(0)
1073 {
1074@@ -46,6 +48,7 @@
1075 std::unique_lock<std::mutex> lock(surfaces_mutex);
1076 for (auto const& pair_id_surface : surfaces)
1077 {
1078+ input_target_listener->input_surface_closed(pair_id_surface.second);
1079 pair_id_surface.second->destroy();
1080 }
1081 }
1082@@ -95,6 +98,7 @@
1083 std::unique_lock<std::mutex> lock(surfaces_mutex);
1084 auto p = checked_find(id);
1085
1086+ input_target_listener->input_surface_closed(p->second);
1087 p->second->destroy();
1088 surfaces.erase(p);
1089 }
1090
1091=== modified file 'src/server/shell/session_manager.cpp'
1092--- src/server/shell/session_manager.cpp 2013-04-19 09:15:31 +0000
1093+++ src/server/shell/session_manager.cpp 2013-04-22 16:32:37 +0000
1094@@ -23,6 +23,8 @@
1095 #include "mir/shell/focus_sequence.h"
1096 #include "mir/shell/focus_setter.h"
1097 #include "mir/shell/session.h"
1098+#include "mir/shell/surface.h"
1099+#include "mir/shell/input_target_listener.h"
1100
1101 #include <memory>
1102 #include <cassert>
1103@@ -31,20 +33,22 @@
1104 namespace mf = mir::frontend;
1105 namespace msh = mir::shell;
1106
1107-msh::SessionManager::SessionManager(
1108- std::shared_ptr<msh::SurfaceFactory> const& surface_factory,
1109+msh::SessionManager::SessionManager(std::shared_ptr<msh::SurfaceFactory> const& surface_factory,
1110 std::shared_ptr<msh::SessionContainer> const& container,
1111 std::shared_ptr<msh::FocusSequence> const& sequence,
1112- std::shared_ptr<msh::FocusSetter> const& focus_setter) :
1113+ std::shared_ptr<msh::FocusSetter> const& focus_setter,
1114+ std::shared_ptr<msh::InputTargetListener> const& input_target_listener) :
1115 surface_factory(surface_factory),
1116 app_container(container),
1117 focus_sequence(sequence),
1118- focus_setter(focus_setter)
1119+ focus_setter(focus_setter),
1120+ input_target_listener(input_target_listener)
1121 {
1122 assert(surface_factory);
1123 assert(sequence);
1124 assert(container);
1125 assert(focus_setter);
1126+ assert(input_target_listener);
1127 }
1128
1129 msh::SessionManager::~SessionManager()
1130@@ -53,25 +57,36 @@
1131
1132 std::shared_ptr<mf::Session> msh::SessionManager::open_session(std::string const& name)
1133 {
1134- auto new_session = std::make_shared<msh::ApplicationSession>(surface_factory, name);
1135+ auto new_session = std::make_shared<msh::ApplicationSession>(surface_factory, input_target_listener, name);
1136
1137 app_container->insert_session(new_session);
1138+
1139+ input_target_listener->input_application_opened(new_session);
1140
1141 set_focus_to_locked(std::unique_lock<std::mutex>(mutex), new_session);
1142
1143 return new_session;
1144 }
1145
1146-inline void msh::SessionManager::set_focus_to_locked(std::unique_lock<std::mutex> const&, std::shared_ptr<Session> const& next_focus)
1147+inline void msh::SessionManager::set_focus_to_locked(std::unique_lock<std::mutex> const&, std::shared_ptr<Session> const& shell_session)
1148 {
1149- focus_application = next_focus;
1150- focus_setter->set_focus_to(next_focus);
1151+ auto old_focus = focus_application.lock();
1152+
1153+ focus_application = shell_session;
1154+ focus_setter->set_focus_to(shell_session);
1155+
1156+ if (shell_session && shell_session->default_surface())
1157+ input_target_listener->focus_changed(shell_session->default_surface());
1158+ else if (shell_session == old_focus || !shell_session)
1159+ input_target_listener->focus_cleared();
1160 }
1161
1162 void msh::SessionManager::close_session(std::shared_ptr<mf::Session> const& session)
1163 {
1164 auto shell_session = std::dynamic_pointer_cast<Session>(session);
1165
1166+ input_target_listener->input_application_closed(shell_session);
1167+
1168 app_container->remove_session(shell_session);
1169
1170 std::unique_lock<std::mutex> lock(mutex);
1171@@ -133,9 +148,11 @@
1172 mf::SurfaceCreationParameters const& params)
1173 {
1174 auto shell_session = std::dynamic_pointer_cast<Session>(session);
1175- auto id = session->create_surface(params);
1176+ auto id = shell_session->create_surface(params);
1177+
1178+ input_target_listener->input_surface_opened(shell_session,
1179+ std::dynamic_pointer_cast<msh::Surface>(shell_session->get_surface(id)));
1180 set_focus_to_locked(std::unique_lock<std::mutex>(mutex), shell_session);
1181
1182 return id;
1183 }
1184-
1185
1186=== modified file 'src/server/shell/single_visibility_focus_mechanism.cpp'
1187--- src/server/shell/single_visibility_focus_mechanism.cpp 2013-04-18 22:57:01 +0000
1188+++ src/server/shell/single_visibility_focus_mechanism.cpp 2013-04-22 16:32:37 +0000
1189@@ -19,7 +19,6 @@
1190 #include "mir/shell/session_container.h"
1191 #include "mir/frontend/session.h"
1192 #include "mir/shell/single_visibility_focus_mechanism.h"
1193-#include "mir/shell/input_focus_selector.h"
1194
1195 #include "mir/shell/session.h"
1196 #include "mir/shell/surface.h"
1197@@ -27,10 +26,8 @@
1198 namespace mf = mir::frontend;
1199 namespace msh = mir::shell;
1200
1201-msh::SingleVisibilityFocusMechanism::SingleVisibilityFocusMechanism(std::shared_ptr<msh::SessionContainer> const& app_container,
1202- std::shared_ptr<msh::InputFocusSelector> const& input_selector)
1203- : app_container(app_container),
1204- input_selector(input_selector)
1205+msh::SingleVisibilityFocusMechanism::SingleVisibilityFocusMechanism(std::shared_ptr<msh::SessionContainer> const& app_container)
1206+ : app_container(app_container)
1207 {
1208 }
1209
1210@@ -41,8 +38,6 @@
1211 if (session == focus_session)
1212 {
1213 session->show();
1214-
1215- input_selector->set_input_focus_to(focus_session, focus_session->default_surface());
1216 }
1217 else
1218 {
1219
1220=== modified file 'src/server/shell/surface.cpp'
1221--- src/server/shell/surface.cpp 2013-04-16 17:42:26 +0000
1222+++ src/server/shell/surface.cpp 2013-04-22 16:32:37 +0000
1223@@ -88,6 +88,18 @@
1224 }
1225 }
1226
1227+mir::geometry::Point msh::Surface::top_left() const
1228+{
1229+ if (auto const& s = surface.lock())
1230+ {
1231+ return s->top_left();
1232+ }
1233+ else
1234+ {
1235+ BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface"));
1236+ }
1237+}
1238+
1239 std::string msh::Surface::name() const
1240 {
1241 if (auto const& s = surface.lock())
1242
1243=== modified file 'tests/acceptance-tests/test_client_input.cpp'
1244--- tests/acceptance-tests/test_client_input.cpp 2013-04-17 07:31:40 +0000
1245+++ tests/acceptance-tests/test_client_input.cpp 2013-04-22 16:32:37 +0000
1246@@ -65,10 +65,9 @@
1247
1248 }
1249
1250- void set_input_focus_to(
1251- std::shared_ptr<mi::SessionTarget> const& session, std::shared_ptr<mi::SurfaceTarget> const& surface) override
1252+ void focus_changed(std::shared_ptr<mi::SurfaceTarget> const& surface) override
1253 {
1254- DispatcherController::set_input_focus_to(session, surface);
1255+ DispatcherController::focus_changed(surface);
1256
1257 // We need a synchronization primitive inorder to halt test event injection
1258 // until after a surface has taken focus (lest the events be discarded).
1259@@ -96,6 +95,7 @@
1260 {
1261 on_focus_set.wait_for_at_most_seconds(10);
1262 fake_event_hub->synthesize_builtin_keyboard_added();
1263+ fake_event_hub->synthesize_builtin_cursor_added();
1264 fake_event_hub->synthesize_device_scan_complete();
1265 inject_input();
1266 });
1267@@ -122,10 +122,10 @@
1268 });
1269 }
1270
1271- std::shared_ptr<msh::InputFocusSelector>
1272- the_input_focus_selector() override
1273+ std::shared_ptr<msh::InputTargetListener>
1274+ the_input_target_listener() override
1275 {
1276- return input_focus_selector(
1277+ return input_target_listener(
1278 [this]()
1279 {
1280 return std::make_shared<FocusNotifyingDispatcherController>(mt::fake_shared(input_config), on_focus_set);
1281@@ -186,7 +186,7 @@
1282
1283 struct MockInputHandler
1284 {
1285- MOCK_METHOD1(handle_key_down, void(MirEvent const*));
1286+ MOCK_METHOD1(handle_input, bool(MirEvent const*));
1287 };
1288
1289 struct InputReceivingClient : ClientConfigCommon
1290@@ -201,9 +201,9 @@
1291 static void handle_input(MirSurface* /* surface */, MirEvent const* ev, void* context)
1292 {
1293 auto client = static_cast<InputReceivingClient *>(context);
1294- if (ev->key.action == 0)
1295+
1296+ if(client->handler->handle_input(ev))
1297 {
1298- client->handler->handle_key_down(ev);
1299 client->event_received[client->events_received].wake_up_everyone();
1300 client->events_received++;
1301 }
1302@@ -227,7 +227,7 @@
1303 MirSurfaceParameters const request_params =
1304 {
1305 __PRETTY_FUNCTION__,
1306- 640, 480,
1307+ surface_width, surface_height,
1308 mir_pixel_format_abgr_8888,
1309 mir_buffer_usage_hardware
1310 };
1311@@ -259,9 +259,66 @@
1312
1313 int events_to_receive;
1314 int events_received;
1315+
1316+ static int const surface_width = 100;
1317+ static int const surface_height = 100;
1318 };
1319
1320-}
1321+MATCHER(KeyDownEvent, "")
1322+{
1323+ if (arg->type != mir_event_type_key)
1324+ return false;
1325+ if (arg->key.action != 0) // Key down
1326+ return false;
1327+
1328+ return true;
1329+}
1330+MATCHER_P(KeyOfSymbol, keysym, "")
1331+{
1332+ if (static_cast<xkb_keysym_t>(arg->key.key_code) == (uint)keysym)
1333+ return true;
1334+ return false;
1335+}
1336+
1337+MATCHER(HoverEnterEvent, "")
1338+{
1339+ if (arg->type != mir_event_type_motion)
1340+ return false;
1341+ if (arg->motion.action != AMOTION_EVENT_ACTION_HOVER_ENTER)
1342+ return false;
1343+
1344+ return true;
1345+}
1346+
1347+MATCHER_P2(ButtonDownEvent, x, y, "")
1348+{
1349+ if (arg->type != mir_event_type_motion)
1350+ return false;
1351+ if (arg->motion.action != AMOTION_EVENT_ACTION_DOWN)
1352+ return false;
1353+ printf("action: %d \n", arg->motion.action);
1354+ if (arg->motion.button_state == 0)
1355+ return false;
1356+ if (arg->motion.pointer_coordinates[0].x != x)
1357+ return false;
1358+ if (arg->motion.pointer_coordinates[0].y != y)
1359+ return false;
1360+ return true;
1361+}
1362+
1363+MATCHER_P2(MotionEventWithPosition, x, y, "")
1364+{
1365+ if (arg->type != mir_event_type_motion)
1366+ return false;
1367+ if (arg->motion.pointer_coordinates[0].x != x)
1368+ return false;
1369+ if (arg->motion.pointer_coordinates[0].y != y)
1370+ return false;
1371+ return true;
1372+}
1373+
1374+}
1375+
1376
1377 using TestClientInput = BespokeDisplayServerTestFixture;
1378
1379@@ -290,22 +347,13 @@
1380 void expect_input()
1381 {
1382 using namespace ::testing;
1383- EXPECT_CALL(*handler, handle_key_down(_)).Times(num_events_produced);
1384+ EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(num_events_produced)
1385+ .WillRepeatedly(Return(true));
1386 }
1387 } client_config;
1388 launch_client_process(client_config);
1389 }
1390
1391-namespace
1392-{
1393-MATCHER_P(KeyOfSymbol, keysym, "")
1394-{
1395- if (static_cast<xkb_keysym_t>(arg->key.key_code) == (uint)keysym)
1396- return true;
1397- return false;
1398-}
1399-}
1400-
1401 TEST_F(TestClientInput, clients_receive_us_english_mapped_keys)
1402 {
1403 using namespace ::testing;
1404@@ -319,12 +367,6 @@
1405 fake_event_hub->synthesize_event(mis::a_key_down_event()
1406 .of_scancode(KEY_4));
1407
1408- // Release the keys so we don't get repeat events.
1409- fake_event_hub->synthesize_event(mis::a_key_up_event()
1410- .of_scancode(KEY_4));
1411- fake_event_hub->synthesize_event(mis::a_key_up_event()
1412- .of_scancode(KEY_LEFTSHIFT));
1413-
1414 }
1415 } server_config;
1416 launch_server_process(server_config);
1417@@ -338,10 +380,78 @@
1418 using namespace ::testing;
1419
1420 InSequence seq;
1421- EXPECT_CALL(*handler, handle_key_down(KeyOfSymbol(XKB_KEY_Shift_L))).Times(1);
1422- EXPECT_CALL(*handler, handle_key_down(KeyOfSymbol(XKB_KEY_dollar))).Times(1);
1423- }
1424- } client_config;
1425- launch_client_process(client_config);
1426-}
1427-
1428+ EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1)
1429+ .WillOnce(Return(true));
1430+ EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_dollar)))).Times(1)
1431+ .WillOnce(Return(true));
1432+ }
1433+ } client_config;
1434+ launch_client_process(client_config);
1435+}
1436+
1437+// TODO: This assumes that clients are placed by shell at 0,0. Which probably isn't quite safe!
1438+TEST_F(TestClientInput, clients_receive_motion_inside_window)
1439+{
1440+ using namespace ::testing;
1441+
1442+ struct InputProducingServerConfiguration : FakeInputServerConfiguration
1443+ {
1444+ void inject_input()
1445+ {
1446+ fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputReceivingClient::surface_width,
1447+ InputReceivingClient::surface_height));
1448+ fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2));
1449+ }
1450+ } server_config;
1451+ launch_server_process(server_config);
1452+
1453+ struct MotionReceivingClient : InputReceivingClient
1454+ {
1455+ MotionReceivingClient() : InputReceivingClient(2) {}
1456+
1457+ void expect_input()
1458+ {
1459+ using namespace ::testing;
1460+
1461+ InSequence seq;
1462+
1463+ // We should see the cursor enter
1464+ EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1).WillOnce(Return(true));
1465+ EXPECT_CALL(*handler, handle_input(
1466+ MotionEventWithPosition(InputReceivingClient::surface_width,
1467+ InputReceivingClient::surface_height))).Times(1).WillOnce(Return(true));
1468+ // But we should not receive an event for the second movement outside of our surface!
1469+ }
1470+ } client_config;
1471+ launch_client_process(client_config);
1472+}
1473+
1474+TEST_F(TestClientInput, clients_receive_button_events_inside_window)
1475+{
1476+ using namespace ::testing;
1477+
1478+ struct InputProducingServerConfiguration : FakeInputServerConfiguration
1479+ {
1480+ void inject_input()
1481+ {
1482+ fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
1483+ }
1484+ } server_config;
1485+ launch_server_process(server_config);
1486+
1487+ struct ButtonReceivingClient : InputReceivingClient
1488+ {
1489+ ButtonReceivingClient() : InputReceivingClient(1) {}
1490+
1491+ void expect_input()
1492+ {
1493+ using namespace ::testing;
1494+
1495+ InSequence seq;
1496+
1497+ // The cursor starts at (0, 0).
1498+ EXPECT_CALL(*handler, handle_input(ButtonDownEvent(0, 0))).Times(1).WillOnce(Return(true));
1499+ }
1500+ } client_config;
1501+ launch_client_process(client_config);
1502+}
1503
1504=== modified file 'tests/acceptance-tests/test_focus_selection.cpp'
1505--- tests/acceptance-tests/test_focus_selection.cpp 2013-04-18 02:52:30 +0000
1506+++ tests/acceptance-tests/test_focus_selection.cpp 2013-04-22 16:32:37 +0000
1507@@ -24,11 +24,11 @@
1508 #include "mir/shell/organising_surface_factory.h"
1509 #include "mir/shell/session_manager.h"
1510 #include "mir/graphics/display.h"
1511-#include "mir/shell/input_focus_selector.h"
1512+#include "mir/shell/input_target_listener.h"
1513
1514 #include "mir_test_framework/display_server_test_fixture.h"
1515 #include "mir_test_doubles/mock_focus_setter.h"
1516-#include "mir_test_doubles/mock_input_focus_selector.h"
1517+#include "mir_test_doubles/mock_input_target_listener.h"
1518
1519 #include <gtest/gtest.h>
1520 #include <gmock/gmock.h>
1521@@ -36,7 +36,8 @@
1522 namespace mf = mir::frontend;
1523 namespace msh = mir::shell;
1524 namespace mi = mir::input;
1525-namespace mtd = mir::test::doubles;
1526+namespace mt = mir::test;
1527+namespace mtd = mt::doubles;
1528 namespace mtf = mir_test_framework;
1529
1530 namespace
1531@@ -46,6 +47,7 @@
1532
1533 namespace
1534 {
1535+
1536 struct ClientConfigCommon : TestingClientConfiguration
1537 {
1538 ClientConfigCommon() :
1539@@ -121,18 +123,10 @@
1540 {
1541 return arg != std::shared_ptr<msh::Session>();
1542 }
1543-MATCHER(NonNullSessionTarget, "")
1544-{
1545- return arg != std::shared_ptr<mi::SessionTarget>();
1546-}
1547 MATCHER(NonNullSurfaceTarget, "")
1548 {
1549 return arg != std::shared_ptr<mi::SurfaceTarget>();
1550 }
1551-MATCHER(NullSurfaceTarget, "")
1552-{
1553- return arg == std::shared_ptr<mi::SurfaceTarget>();
1554-}
1555 }
1556
1557 TEST_F(BespokeDisplayServerTestFixture, sessions_creating_surface_receive_focus)
1558@@ -148,7 +142,6 @@
1559 using namespace ::testing;
1560
1561 auto focus_setter = std::make_shared<mtd::MockFocusSetter>();
1562-
1563 {
1564 InSequence seq;
1565 // Once on application registration and once on surface creation
1566@@ -174,30 +167,37 @@
1567 {
1568 struct ServerConfig : TestingServerConfiguration
1569 {
1570- std::shared_ptr<mtd::MockInputFocusSelector> focus_selector;
1571+ std::shared_ptr<mtd::MockInputTargetListener> target_listener;
1572 bool expected;
1573
1574 ServerConfig()
1575- : focus_selector(std::make_shared<mtd::MockInputFocusSelector>()),
1576+ : target_listener(std::make_shared<mtd::MockInputTargetListener>()),
1577 expected(false)
1578 {
1579 }
1580
1581- std::shared_ptr<msh::InputFocusSelector>
1582- the_input_focus_selector() override
1583+ std::shared_ptr<msh::InputTargetListener>
1584+ the_input_target_listener() override
1585 {
1586 using namespace ::testing;
1587
1588 if (!expected)
1589 {
1590- InSequence seq;
1591+
1592+ EXPECT_CALL(*target_listener, input_application_opened(_)).Times(AtLeast(0));
1593+ EXPECT_CALL(*target_listener, input_application_closed(_)).Times(AtLeast(0));
1594+ EXPECT_CALL(*target_listener, input_surface_opened(_,_)).Times(AtLeast(0));
1595+ EXPECT_CALL(*target_listener, input_surface_closed(_)).Times(AtLeast(0));
1596+ EXPECT_CALL(*target_listener, focus_cleared()).Times(AtLeast(0));
1597
1598- EXPECT_CALL(*focus_selector, set_input_focus_to(NonNullSessionTarget(), NullSurfaceTarget())).Times(1);
1599- EXPECT_CALL(*focus_selector, set_input_focus_to(NonNullSessionTarget(), NonNullSurfaceTarget())).Times(1);
1600- expected = true;
1601+ {
1602+ InSequence seq;
1603+ EXPECT_CALL(*target_listener, focus_changed(NonNullSurfaceTarget())).Times(1);
1604+ expected = true;
1605+ }
1606 }
1607
1608- return focus_selector;
1609+ return target_listener;
1610 }
1611 } server_config;
1612
1613
1614=== modified file 'tests/death-tests/test_application_manager_death.cpp'
1615--- tests/death-tests/test_application_manager_death.cpp 2013-03-21 03:32:59 +0000
1616+++ tests/death-tests/test_application_manager_death.cpp 2013-04-22 16:32:37 +0000
1617@@ -30,11 +30,12 @@
1618 // ::testing::FLAGS_gtest_death_test_style = "threadsafe";
1619 // leads to the test failing under valgrind
1620 EXPECT_EXIT(
1621- std::shared_ptr<msh::SurfaceFactory> factory;
1622- mir::shell::SessionManager app(factory,
1623+ std::shared_ptr<msh::SurfaceFactory> surface_factory;
1624+ mir::shell::SessionManager app(surface_factory,
1625 std::shared_ptr<msh::SessionContainer>(),
1626 std::shared_ptr<msh::FocusSequence>(),
1627- std::shared_ptr<msh::FocusSetter>()),
1628+ std::shared_ptr<msh::FocusSetter>(),
1629+ std::shared_ptr<msh::InputTargetListener>()),
1630 ::testing::KilledBySignal(SIGABRT),
1631 ".*");
1632 }
1633
1634=== modified file 'tests/integration-tests/input/android/test_android_input_manager.cpp'
1635--- tests/integration-tests/input/android/test_android_input_manager.cpp 2013-04-10 23:48:23 +0000
1636+++ tests/integration-tests/input/android/test_android_input_manager.cpp 2013-04-22 16:32:37 +0000
1637@@ -35,6 +35,7 @@
1638 #include "mir_test_doubles/stub_surface_target.h"
1639 #include "mir_test/wait_condition.h"
1640 #include "mir_test/event_factory.h"
1641+#include "mir_test/event_matchers.h"
1642
1643 #include <EventHub.h>
1644 #include <InputDispatcher.h>
1645@@ -171,7 +172,7 @@
1646 struct MockDispatcherPolicy : public mia::EventFilterDispatcherPolicy
1647 {
1648 MockDispatcherPolicy(std::shared_ptr<mi::EventFilter> const& filter)
1649- : EventFilterDispatcherPolicy(filter)
1650+ : EventFilterDispatcherPolicy(filter, false)
1651 {
1652 }
1653 MOCK_METHOD3(interceptKeyBeforeDispatching, nsecs_t(droidinput::sp<droidinput::InputWindowHandle> const&,
1654@@ -211,24 +212,31 @@
1655 ON_CALL(viewable_area, view_area())
1656 .WillByDefault(Return(default_view_area));
1657 input_manager = std::make_shared<mia::InputManager>(configuration);
1658- input_focus_selector = std::make_shared<mia::DispatcherController>(configuration);
1659+ input_target_listener = std::make_shared<mia::DispatcherController>(configuration);
1660
1661 dispatcher_policy = configuration->the_mock_dispatcher_policy();
1662
1663 }
1664
1665+ ~AndroidInputManagerDispatcherInterceptSetup()
1666+ {
1667+ input_manager->stop();
1668+ }
1669+
1670 // TODO: It would be nice if it were possible to mock the interface between
1671 // droidinput::InputChannel and droidinput::InputDispatcher rather than use
1672 // valid fds to allow non-throwing construction of a real input channel.
1673 void SetUp()
1674 {
1675- test_input_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1676 input_manager->start();
1677 }
1678- void TearDown()
1679+
1680+ int test_fd()
1681 {
1682- input_manager->stop();
1683- close(test_input_fd);
1684+ int fds[2];
1685+ // Closed by droidinput InputChannel on shutdown
1686+ socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds);
1687+ return fds[0];
1688 }
1689
1690 MockEventFilter event_filter;
1691@@ -238,9 +246,7 @@
1692 droidinput::sp<MockDispatcherPolicy> dispatcher_policy;
1693
1694 std::shared_ptr<mia::InputManager> input_manager;
1695- std::shared_ptr<msh::InputFocusSelector> input_focus_selector;
1696-
1697- int test_input_fd;
1698+ std::shared_ptr<msh::InputTargetListener> input_target_listener;
1699 };
1700
1701 MATCHER_P(WindowHandleWithInputFd, input_fd, "")
1702@@ -259,14 +265,18 @@
1703 mt::WaitCondition wait_condition;
1704
1705 mtd::StubSessionTarget session;
1706- mtd::StubSurfaceTarget surface(test_input_fd);
1707+
1708+ auto input_fd = test_fd();
1709+ mtd::StubSurfaceTarget surface(input_fd);
1710
1711 EXPECT_CALL(event_filter, handles(_)).Times(1).WillOnce(Return(false));
1712 // We return -1 here to skip publishing of the event (to an unconnected test socket!).
1713- EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(test_input_fd), _, _))
1714+ EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd), _, _))
1715 .Times(1).WillOnce(DoAll(mt::WakeUp(&wait_condition), Return(-1)));
1716
1717- input_focus_selector->set_input_focus_to(mt::fake_shared(session), mt::fake_shared(surface));
1718+ input_target_listener->input_application_opened(mt::fake_shared(session));
1719+ input_target_listener->input_surface_opened(mt::fake_shared(session), mt::fake_shared(surface));
1720+ input_target_listener->focus_changed(mt::fake_shared(surface));
1721
1722 fake_event_hub->synthesize_builtin_keyboard_added();
1723 fake_event_hub->synthesize_device_scan_complete();
1724@@ -275,3 +285,52 @@
1725
1726 wait_condition.wait_for_at_most_seconds(1);
1727 }
1728+
1729+TEST_F(AndroidInputManagerDispatcherInterceptSetup, changing_focus_changes_event_recipient)
1730+{
1731+ using namespace ::testing;
1732+
1733+ mt::WaitCondition wait1, wait2, wait3;
1734+
1735+ mtd::StubSessionTarget session;
1736+
1737+ auto input_fd_1 = test_fd();
1738+ mtd::StubSurfaceTarget surface1(input_fd_1);
1739+ auto input_fd_2 = test_fd();
1740+ mtd::StubSurfaceTarget surface2(input_fd_2);
1741+
1742+ input_target_listener->input_application_opened(mt::fake_shared(session));
1743+ input_target_listener->input_surface_opened(mt::fake_shared(session), mt::fake_shared(surface1));
1744+ input_target_listener->input_surface_opened(mt::fake_shared(session), mt::fake_shared(surface2));
1745+
1746+ EXPECT_CALL(event_filter, handles(_)).Times(3).WillRepeatedly(Return(false));
1747+
1748+ {
1749+ InSequence seq;
1750+
1751+ EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd_1), _, _))
1752+ .Times(1).WillOnce(DoAll(mt::WakeUp(&wait1), Return(-1)));
1753+ EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd_2), _, _))
1754+ .Times(1).WillOnce(DoAll(mt::WakeUp(&wait2), Return(-1)));
1755+ EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd_1), _, _))
1756+ .Times(1).WillOnce(DoAll(mt::WakeUp(&wait3), Return(-1)));
1757+ }
1758+
1759+ fake_event_hub->synthesize_builtin_keyboard_added();
1760+ fake_event_hub->synthesize_device_scan_complete();
1761+
1762+ input_target_listener->focus_changed(mt::fake_shared(surface1));
1763+ fake_event_hub->synthesize_event(mis::a_key_down_event()
1764+ .of_scancode(KEY_1));
1765+ wait1.wait_for_at_most_seconds(1);
1766+
1767+ input_target_listener->focus_changed(mt::fake_shared(surface2));
1768+ fake_event_hub->synthesize_event(mis::a_key_down_event()
1769+ .of_scancode(KEY_2));
1770+ wait2.wait_for_at_most_seconds(1);
1771+
1772+ input_target_listener->focus_changed(mt::fake_shared(surface1));
1773+ fake_event_hub->synthesize_event(mis::a_key_down_event()
1774+ .of_scancode(KEY_3));
1775+ wait3.wait_for_at_most_seconds(5);
1776+}
1777
1778=== modified file 'tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp'
1779--- tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp 2013-04-02 18:26:40 +0000
1780+++ tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp 2013-04-22 16:32:37 +0000
1781@@ -26,6 +26,7 @@
1782 #include "mir_test_doubles/mock_event_filter.h"
1783 #include "mir_test/wait_condition.h"
1784 #include "mir_test/event_factory.h"
1785+#include "mir_test/event_matchers.h"
1786
1787 #include <InputDispatcher.h>
1788 #include <InputReader.h>
1789@@ -56,7 +57,7 @@
1790 void SetUp()
1791 {
1792 event_hub = new mia::FakeEventHub();
1793- dispatcher_policy = new mia::EventFilterDispatcherPolicy(mt::fake_shared(event_filter));
1794+ dispatcher_policy = new mia::EventFilterDispatcherPolicy(mt::fake_shared(event_filter), false);
1795 reader_policy = new mia::RudimentaryInputReaderPolicy();
1796 dispatcher = new droidinput::InputDispatcher(dispatcher_policy);
1797 reader = new droidinput::InputReader(event_hub, reader_policy, dispatcher);
1798
1799=== modified file 'tests/integration-tests/shell/test_session_manager.cpp'
1800--- tests/integration-tests/shell/test_session_manager.cpp 2013-04-18 00:00:55 +0000
1801+++ tests/integration-tests/shell/test_session_manager.cpp 2013-04-22 16:32:37 +0000
1802@@ -33,6 +33,7 @@
1803 #include "mir_test/fake_shared.h"
1804 #include "mir_test_doubles/mock_surface_factory.h"
1805 #include "mir_test_doubles/mock_focus_setter.h"
1806+#include "mir_test_doubles/stub_input_target_listener.h"
1807
1808 namespace mc = mir::compositor;
1809 namespace mf = mir::frontend;
1810@@ -44,19 +45,22 @@
1811 TEST(TestSessionManagerAndFocusSelectionStrategy, cycle_focus)
1812 {
1813 using namespace ::testing;
1814+
1815 mtd::MockSurfaceFactory surface_factory;
1816 std::shared_ptr<msh::DefaultSessionContainer> container(new msh::DefaultSessionContainer());
1817 msh::RegistrationOrderFocusSequence sequence(container);
1818- mtd::MockFocusSetter focus_changer;
1819+ mtd::MockFocusSetter focus_setter;
1820 std::shared_ptr<mf::Session> new_session;
1821+ mtd::StubInputTargetListener input_target_listener;
1822
1823 msh::SessionManager session_manager(
1824 mt::fake_shared(surface_factory),
1825 container,
1826 mt::fake_shared(sequence),
1827- mt::fake_shared(focus_changer));
1828-
1829- EXPECT_CALL(focus_changer, set_focus_to(_)).Times(3);
1830+ mt::fake_shared(focus_setter),
1831+ mt::fake_shared(input_target_listener));
1832+
1833+ EXPECT_CALL(focus_setter, set_focus_to(_)).Times(3);
1834
1835 auto session1 = session_manager.open_session("Visual Basic Studio");
1836 auto session2 = session_manager.open_session("Microsoft Access");
1837@@ -64,9 +68,9 @@
1838
1839 {
1840 InSequence seq;
1841- EXPECT_CALL(focus_changer, set_focus_to(Eq(session1))).Times(1);
1842- EXPECT_CALL(focus_changer, set_focus_to(Eq(session2))).Times(1);
1843- EXPECT_CALL(focus_changer, set_focus_to(Eq(session3))).Times(1);
1844+ EXPECT_CALL(focus_setter, set_focus_to(Eq(session1))).Times(1);
1845+ EXPECT_CALL(focus_setter, set_focus_to(Eq(session2))).Times(1);
1846+ EXPECT_CALL(focus_setter, set_focus_to(Eq(session3))).Times(1);
1847 }
1848
1849 session_manager.focus_next();
1850@@ -77,19 +81,22 @@
1851 TEST(TestSessionManagerAndFocusSelectionStrategy, closing_applications_transfers_focus)
1852 {
1853 using namespace ::testing;
1854+
1855 mtd::MockSurfaceFactory surface_factory;
1856- std::shared_ptr<msh::DefaultSessionContainer> model(new msh::DefaultSessionContainer());
1857- msh::RegistrationOrderFocusSequence sequence(model);
1858- mtd::MockFocusSetter focus_changer;
1859+ std::shared_ptr<msh::DefaultSessionContainer> container(new msh::DefaultSessionContainer());
1860+ msh::RegistrationOrderFocusSequence sequence(container);
1861+ mtd::MockFocusSetter focus_setter;
1862 std::shared_ptr<mf::Session> new_session;
1863+ mtd::StubInputTargetListener input_target_listener;
1864
1865 msh::SessionManager session_manager(
1866- mt::fake_shared(surface_factory),
1867- model,
1868- mt::fake_shared(sequence),
1869- mt::fake_shared(focus_changer));
1870+ mt::fake_shared(surface_factory),
1871+ container,
1872+ mt::fake_shared(sequence),
1873+ mt::fake_shared(focus_setter),
1874+ mt::fake_shared(input_target_listener));
1875
1876- EXPECT_CALL(focus_changer, set_focus_to(_)).Times(3);
1877+ EXPECT_CALL(focus_setter, set_focus_to(_)).Times(3);
1878
1879 auto session1 = session_manager.open_session("Visual Basic Studio");
1880 auto session2 = session_manager.open_session("Microsoft Access");
1881@@ -97,8 +104,8 @@
1882
1883 {
1884 InSequence seq;
1885- EXPECT_CALL(focus_changer, set_focus_to(Eq(session2))).Times(1);
1886- EXPECT_CALL(focus_changer, set_focus_to(Eq(session1))).Times(1);
1887+ EXPECT_CALL(focus_setter, set_focus_to(Eq(session2))).Times(1);
1888+ EXPECT_CALL(focus_setter, set_focus_to(Eq(session1))).Times(1);
1889 }
1890
1891 session_manager.close_session(session3);
1892
1893=== modified file 'tests/mir_test_doubles/fake_event_hub.cpp'
1894--- tests/mir_test_doubles/fake_event_hub.cpp 2013-03-29 16:51:35 +0000
1895+++ tests/mir_test_doubles/fake_event_hub.cpp 2013-04-22 16:32:37 +0000
1896@@ -322,7 +322,7 @@
1897 void mia::FakeEventHub::synthesize_event(const mis::ButtonParameters &parameters)
1898 {
1899 RawEvent event;
1900- event.when = 0; // TODO: This may need a timestamp to go over the wire ~racarr
1901+ event.when = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
1902 event.type = EV_KEY;
1903 event.code = parameters.button;
1904
1905@@ -348,7 +348,7 @@
1906 void mia::FakeEventHub::synthesize_event(const mis::MotionParameters &parameters)
1907 {
1908 RawEvent event;
1909- event.when = 0;
1910+ event.when = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
1911 event.type = EV_REL;
1912 if (parameters.device_id)
1913 event.deviceId = parameters.device_id;
1914
1915=== modified file 'tests/mir_test_framework/testing_server_options.cpp'
1916--- tests/mir_test_framework/testing_server_options.cpp 2013-04-18 15:20:45 +0000
1917+++ tests/mir_test_framework/testing_server_options.cpp 2013-04-22 16:32:37 +0000
1918@@ -29,7 +29,7 @@
1919 #include "mir/compositor/graphic_buffer_allocator.h"
1920 #include "mir/input/input_channel.h"
1921 #include "mir/input/input_manager.h"
1922-#include "mir/shell/input_focus_selector.h"
1923+#include "mir/input/null_input_target_listener.h"
1924 #include "src/server/input/android/android_input_manager.h"
1925 #include "src/server/input/android/android_dispatcher_controller.h"
1926
1927@@ -159,14 +159,6 @@
1928 }
1929 };
1930
1931-class StubInputFocusSelector : public msh::InputFocusSelector
1932-{
1933-public:
1934- void set_input_focus_to(std::shared_ptr<mi::SessionTarget> const& /* session */, std::shared_ptr<mi::SurfaceTarget> const& /* surface */)
1935- {
1936- }
1937-};
1938-
1939 }
1940
1941 mtf::TestingServerConfiguration::TestingServerConfiguration() :
1942@@ -184,14 +176,14 @@
1943 return std::make_shared<StubInputManager>();
1944 }
1945
1946-std::shared_ptr<msh::InputFocusSelector> mtf::TestingServerConfiguration::the_input_focus_selector()
1947+std::shared_ptr<msh::InputTargetListener> mtf::TestingServerConfiguration::the_input_target_listener()
1948 {
1949 auto options = the_options();
1950
1951 if (options->get("tests-use-real-input", false))
1952 return std::make_shared<mia::DispatcherController>(the_input_configuration());
1953 else
1954- return std::make_shared<StubInputFocusSelector>();
1955+ return std::make_shared<mi::NullInputTargetListener>();
1956 }
1957
1958 std::shared_ptr<mg::Platform> mtf::TestingServerConfiguration::the_graphics_platform()
1959
1960=== modified file 'tests/unit-tests/input/android/test_android_dispatcher_controller.cpp'
1961--- tests/unit-tests/input/android/test_android_dispatcher_controller.cpp 2013-04-15 14:39:18 +0000
1962+++ tests/unit-tests/input/android/test_android_dispatcher_controller.cpp 2013-04-22 16:32:37 +0000
1963@@ -31,6 +31,8 @@
1964 #include <sys/types.h>
1965 #include <sys/socket.h>
1966
1967+#include <stdexcept>
1968+
1969 namespace mi = mir::input;
1970 namespace mia = mi::android;
1971 namespace mt = mir::test;
1972@@ -47,12 +49,16 @@
1973 void SetUp() override
1974 {
1975 test_input_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1976+
1977+ dispatcher = new mtd::MockInputDispatcher();
1978 }
1979 void TearDown() override
1980 {
1981 close(test_input_fd);
1982 }
1983 int test_input_fd;
1984+ droidinput::sp<mtd::MockInputDispatcher> dispatcher;
1985+ mtd::MockInputConfiguration config;
1986 };
1987
1988 static bool
1989@@ -104,12 +110,116 @@
1990
1991 }
1992
1993-TEST_F(AndroidDispatcherControllerFdSetup, set_input_focus)
1994-{
1995- using namespace ::testing;
1996-
1997- auto dispatcher = new mtd::MockInputDispatcher(); // We need droidinput::sp
1998- mtd::MockInputConfiguration config;
1999+TEST_F(AndroidDispatcherControllerFdSetup, input_application_opened_behavior)
2000+{
2001+ using namespace ::testing;
2002+
2003+ EXPECT_CALL(config, the_dispatcher()).Times(1)
2004+ .WillOnce(Return(dispatcher));
2005+ mia::DispatcherController controller(mt::fake_shared(config));
2006+
2007+ auto session = std::make_shared<mtd::StubSessionTarget>();
2008+ controller.input_application_opened(session);
2009+ EXPECT_THROW({
2010+ // An application can not be opened twice!
2011+ controller.input_application_opened(session);
2012+ }, std::logic_error);
2013+}
2014+
2015+TEST_F(AndroidDispatcherControllerFdSetup, input_application_closed_behavior)
2016+{
2017+ using namespace ::testing;
2018+
2019+ EXPECT_CALL(config, the_dispatcher()).Times(1)
2020+ .WillOnce(Return(dispatcher));
2021+ mia::DispatcherController controller(mt::fake_shared(config));
2022+
2023+ auto session = std::make_shared<mtd::StubSessionTarget>();
2024+ EXPECT_THROW({
2025+ // We can't close an application which is not open
2026+ controller.input_application_closed(session);
2027+ }, std::logic_error);
2028+ controller.input_application_opened(session);
2029+ controller.input_application_closed(session);
2030+ EXPECT_THROW({
2031+ // Nor can we close an application twice
2032+ controller.input_application_closed(session);
2033+ }, std::logic_error);
2034+}
2035+
2036+TEST_F(AndroidDispatcherControllerFdSetup, input_surface_opened_behavior)
2037+{
2038+ using namespace ::testing;
2039+
2040+ auto session = std::make_shared<mtd::StubSessionTarget>();
2041+ auto surface = std::make_shared<mtd::StubSurfaceTarget>(test_input_fd);
2042+
2043+ EXPECT_CALL(config, the_dispatcher()).Times(1)
2044+ .WillOnce(Return(dispatcher));
2045+ EXPECT_CALL(*dispatcher, registerInputChannel(_, WindowHandleFor(session, surface), false)).Times(1)
2046+ .WillOnce(Return(droidinput::OK));
2047+
2048+ mia::DispatcherController controller(mt::fake_shared(config));
2049+
2050+ EXPECT_THROW({
2051+ // We can't open a surface with an unopened session!
2052+ controller.input_surface_opened(session, surface);
2053+ }, std::logic_error);
2054+ controller.input_application_opened(session);
2055+ controller.input_surface_opened(session, surface);
2056+ EXPECT_THROW({
2057+ // We can't open a surface twice
2058+ controller.input_surface_opened(session, surface);
2059+ }, std::logic_error);
2060+}
2061+
2062+TEST_F(AndroidDispatcherControllerFdSetup, input_surface_closed_behavior)
2063+{
2064+ using namespace ::testing;
2065+
2066+ auto session = std::make_shared<mtd::StubSessionTarget>();
2067+ auto surface = std::make_shared<mtd::StubSurfaceTarget>(test_input_fd);
2068+
2069+ EXPECT_CALL(config, the_dispatcher()).Times(1)
2070+ .WillOnce(Return(dispatcher));
2071+ EXPECT_CALL(*dispatcher, registerInputChannel(_, WindowHandleFor(session, surface), false)).Times(1)
2072+ .WillOnce(Return(droidinput::OK));
2073+ EXPECT_CALL(*dispatcher, unregisterInputChannel(_)).Times(1);
2074+ mia::DispatcherController controller(mt::fake_shared(config));
2075+
2076+ controller.input_application_opened(session);
2077+
2078+ EXPECT_THROW({
2079+ // We can't close a surface which hasn't been opened
2080+ controller.input_surface_closed(surface);
2081+ }, std::logic_error);
2082+ controller.input_surface_opened(session, surface);
2083+ controller.input_surface_closed(surface);
2084+ EXPECT_THROW({
2085+ // Nor can we close a surface twice
2086+ controller.input_surface_closed(surface);
2087+ }, std::logic_error);
2088+}
2089+
2090+TEST_F(AndroidDispatcherControllerFdSetup, on_focus_cleared)
2091+{
2092+ using namespace ::testing;
2093+
2094+ EXPECT_CALL(config, the_dispatcher()).Times(1)
2095+ .WillOnce(Return(dispatcher));
2096+
2097+ EXPECT_CALL(*dispatcher, setFocusedApplication(droidinput::sp<droidinput::InputApplicationHandle>(0))).Times(1);
2098+ EXPECT_CALL(*dispatcher, setInputWindows(EmptyVector())).Times(1);
2099+
2100+ mia::DispatcherController controller(mt::fake_shared(config));
2101+
2102+ controller.focus_cleared();
2103+}
2104+
2105+TEST_F(AndroidDispatcherControllerFdSetup, on_focus_changed)
2106+{
2107+ using namespace ::testing;
2108+
2109 EXPECT_CALL(config, the_dispatcher()).Times(1)
2110 .WillOnce(Return(dispatcher));
2111
2112@@ -119,15 +229,30 @@
2113 {
2114 InSequence seq;
2115 EXPECT_CALL(*dispatcher, setFocusedApplication(ApplicationHandleFor(session))).Times(1);
2116- EXPECT_CALL(*dispatcher, registerInputChannel(_, WindowHandleFor(session, surface), false)).Times(1)
2117- .WillOnce(Return(droidinput::OK));
2118 EXPECT_CALL(*dispatcher, setInputWindows(VectorContainingWindowHandleFor(session, surface))).Times(1);
2119- EXPECT_CALL(*dispatcher, unregisterInputChannel(_)).Times(1);
2120- EXPECT_CALL(*dispatcher, setInputWindows(EmptyVector())).Times(1);
2121 }
2122
2123 mia::DispatcherController controller(mt::fake_shared(config));
2124-
2125- controller.set_input_focus_to(session, surface);
2126- controller.set_input_focus_to(session, std::shared_ptr<mi::SurfaceTarget>());
2127+
2128+ controller.input_application_opened(session);
2129+ controller.input_surface_opened(session, surface);
2130+
2131+ controller.focus_changed(surface);
2132+}
2133+
2134+TEST_F(AndroidDispatcherControllerFdSetup, on_focus_changed_throw_behavior)
2135+{
2136+ using namespace ::testing;
2137+
2138+ EXPECT_CALL(config, the_dispatcher()).Times(1)
2139+ .WillOnce(Return(dispatcher));
2140+
2141+ auto surface = std::make_shared<mtd::StubSurfaceTarget>(test_input_fd);
2142+
2143+ mia::DispatcherController controller(mt::fake_shared(config));
2144+
2145+ EXPECT_THROW({
2146+ // We can't focus surfaces which never opened
2147+ controller.focus_changed(surface);
2148+ }, std::logic_error);
2149 }
2150
2151=== modified file 'tests/unit-tests/input/android/test_android_input_window_handle.cpp'
2152--- tests/unit-tests/input/android/test_android_input_window_handle.cpp 2013-04-04 11:26:58 +0000
2153+++ tests/unit-tests/input/android/test_android_input_window_handle.cpp 2013-04-22 16:32:37 +0000
2154@@ -52,6 +52,7 @@
2155 struct MockSurfaceTarget : public mi::SurfaceTarget
2156 {
2157 MOCK_CONST_METHOD0(server_input_fd, int());
2158+ MOCK_CONST_METHOD0(top_left, geom::Point());
2159 MOCK_CONST_METHOD0(size, geom::Size());
2160 MOCK_CONST_METHOD0(name, std::string());
2161 };
2162@@ -64,6 +65,7 @@
2163
2164 geom::Size const default_surface_size = geom::Size{geom::Width{256},
2165 geom::Height{256}};
2166+ geom::Point const default_surface_top_left = geom::Point{geom::X{10}, geom::Y{10}};
2167 std::string const testing_surface_name = "Test";
2168
2169 // We need a real open fd, as InputWindowHandle's constructor will fcntl() it, and
2170@@ -81,6 +83,8 @@
2171 // for touch/pointer events we will need a position
2172 EXPECT_CALL(surface, size()).Times(1)
2173 .WillOnce(Return(default_surface_size));
2174+ EXPECT_CALL(surface, top_left()).Times(1)
2175+ .WillOnce(Return(default_surface_top_left));
2176 EXPECT_CALL(surface, name()).Times(1)
2177 .WillOnce(Return(testing_surface_name));
2178
2179@@ -93,8 +97,15 @@
2180
2181 EXPECT_EQ(testing_server_fd, info->inputChannel->getFd());
2182
2183+ EXPECT_EQ(default_surface_top_left.x.as_uint32_t(), (uint32_t)(info->frameLeft));
2184+ EXPECT_EQ(default_surface_top_left.y.as_uint32_t(), (uint32_t)(info->frameTop));
2185 EXPECT_EQ(default_surface_size.height.as_uint32_t(), (uint32_t)(info->frameRight - info->frameLeft));
2186 EXPECT_EQ(default_surface_size.height.as_uint32_t(), (uint32_t)(info->frameBottom - info->frameTop));
2187
2188+ EXPECT_EQ(info->frameLeft, info->touchableRegionLeft);
2189+ EXPECT_EQ(info->frameTop, info->touchableRegionTop);
2190+ EXPECT_EQ(info->frameRight, info->touchableRegionRight);
2191+ EXPECT_EQ(info->frameBottom, info->touchableRegionBottom);
2192+
2193 free(filename);
2194 }
2195
2196=== modified file 'tests/unit-tests/input/android/test_event_filter_input_dispatcher_policy.cpp'
2197--- tests/unit-tests/input/android/test_event_filter_input_dispatcher_policy.cpp 2013-03-22 16:41:59 +0000
2198+++ tests/unit-tests/input/android/test_event_filter_input_dispatcher_policy.cpp 2013-04-22 16:32:37 +0000
2199@@ -32,12 +32,12 @@
2200 namespace mt = mir::test;
2201 namespace mtd = mir::test::doubles;
2202
2203-TEST(EventFilterDispatcherPolicy, offers_events_to_filter)
2204+TEST(EventFilterDispatcherPolicy, offers_key_events_to_filter)
2205 {
2206 using namespace ::testing;
2207 droidinput::KeyEvent ev;
2208 mtd::MockEventFilter filter;
2209- mia::EventFilterDispatcherPolicy policy(mt::fake_shared(filter));
2210+ mia::EventFilterDispatcherPolicy policy(mt::fake_shared(filter), true);
2211 uint32_t policy_flags;
2212
2213 EXPECT_CALL(filter, handles(_)).Times(1).WillOnce(Return(false));
2214@@ -53,3 +53,16 @@
2215 EXPECT_TRUE(policy.filterInputEvent(&ev, 0));
2216 }
2217
2218+TEST(EventFilterDispatcherPolicy, motion_events_are_allowed_to_pass_to_clients)
2219+{
2220+ using namespace ::testing;
2221+
2222+ mtd::MockEventFilter filter;
2223+ mia::EventFilterDispatcherPolicy policy(mt::fake_shared(filter), true);
2224+
2225+ uint32_t policy_flags;
2226+ policy.interceptMotionBeforeQueueing(0, policy_flags);
2227+
2228+ // All motion events are allowed. Of course they could later be removed by the input filter.
2229+ EXPECT_TRUE(policy_flags & droidinput::POLICY_FLAG_PASS_TO_USER);
2230+}
2231
2232=== modified file 'tests/unit-tests/shell/test_application_session.cpp'
2233--- tests/unit-tests/shell/test_application_session.cpp 2013-04-17 18:18:31 +0000
2234+++ tests/unit-tests/shell/test_application_session.cpp 2013-04-22 16:32:37 +0000
2235@@ -22,6 +22,7 @@
2236 #include "mir_test/fake_shared.h"
2237 #include "mir_test_doubles/mock_surface_factory.h"
2238 #include "mir_test_doubles/mock_surface.h"
2239+#include "mir_test_doubles/stub_input_target_listener.h"
2240 #include "mir_test_doubles/stub_surface_builder.h"
2241 #include "mir_test_doubles/stub_surface.h"
2242
2243@@ -51,7 +52,8 @@
2244 EXPECT_CALL(surface_factory, create_surface(_));
2245 EXPECT_CALL(*mock_surface, destroy());
2246
2247- msh::ApplicationSession session(mt::fake_shared(surface_factory), "Foo");
2248+ mtd::StubInputTargetListener input_listener;
2249+ msh::ApplicationSession session(mt::fake_shared(surface_factory), mt::fake_shared(input_listener), "Foo");
2250
2251 mf::SurfaceCreationParameters params;
2252 auto surf = session.create_surface(params);
2253@@ -75,7 +77,8 @@
2254 .WillOnce(Return(std::make_shared<NiceMock<mtd::MockSurface>>(mt::fake_shared(surface_builder))));
2255 }
2256
2257- msh::ApplicationSession app_session(mt::fake_shared(surface_factory), "Foo");
2258+ mtd::StubInputTargetListener input_listener;
2259+ msh::ApplicationSession app_session(mt::fake_shared(surface_factory), mt::fake_shared(input_listener), "Foo");
2260
2261 mf::SurfaceCreationParameters params;
2262 auto id1 = app_session.create_surface(params);
2263@@ -105,7 +108,8 @@
2264 mtd::MockSurfaceFactory surface_factory;
2265 ON_CALL(surface_factory, create_surface(_)).WillByDefault(Return(mock_surface));
2266
2267- msh::ApplicationSession app_session(mt::fake_shared(surface_factory), "Foo");
2268+ mtd::StubInputTargetListener input_listener;
2269+ msh::ApplicationSession app_session(mt::fake_shared(surface_factory), mt::fake_shared(input_listener), "Foo");
2270
2271 EXPECT_CALL(surface_factory, create_surface(_));
2272
2273@@ -130,7 +134,8 @@
2274 using namespace ::testing;
2275
2276 mtd::MockSurfaceFactory surface_factory;
2277- msh::ApplicationSession app_session(mt::fake_shared(surface_factory), "Foo");
2278+ mtd::StubInputTargetListener input_listener;
2279+ msh::ApplicationSession app_session(mt::fake_shared(surface_factory), mt::fake_shared(input_listener), "Foo");
2280 mf::SurfaceId invalid_surface_id(1);
2281
2282 EXPECT_THROW({
2283@@ -143,7 +148,8 @@
2284 using namespace ::testing;
2285
2286 mtd::MockSurfaceFactory surface_factory;
2287- msh::ApplicationSession app_session(mt::fake_shared(surface_factory), "Foo");
2288+ mtd::StubInputTargetListener input_listener;
2289+ msh::ApplicationSession app_session(mt::fake_shared(surface_factory), mt::fake_shared(input_listener), "Foo");
2290 mf::SurfaceId invalid_surface_id(1);
2291
2292 EXPECT_THROW({
2293
2294=== modified file 'tests/unit-tests/shell/test_registration_order_focus_sequence.cpp'
2295--- tests/unit-tests/shell/test_registration_order_focus_sequence.cpp 2013-04-18 00:00:55 +0000
2296+++ tests/unit-tests/shell/test_registration_order_focus_sequence.cpp 2013-04-22 16:32:37 +0000
2297@@ -22,8 +22,11 @@
2298 #include "mir/shell/registration_order_focus_sequence.h"
2299 #include "mir/frontend/surface_creation_parameters.h"
2300 #include "mir/surfaces/surface.h"
2301+
2302 #include "mir_test_doubles/mock_buffer_bundle.h"
2303 #include "mir_test_doubles/mock_surface_factory.h"
2304+#include "mir_test_doubles/stub_input_target_listener.h"
2305+#include "mir_test/fake_shared.h"
2306
2307 #include <gmock/gmock.h>
2308 #include <gtest/gtest.h>
2309@@ -32,7 +35,8 @@
2310 namespace mc = mir::compositor;
2311 namespace msh = mir::shell;
2312 namespace ms = mir::surfaces;
2313-namespace mtd = mir::test::doubles;
2314+namespace mt = mir::test;
2315+namespace mtd = mt::doubles;
2316
2317 namespace
2318 {
2319@@ -45,6 +49,7 @@
2320 }
2321 std::shared_ptr<mtd::MockSurfaceFactory> factory;
2322 std::shared_ptr<msh::DefaultSessionContainer> container;
2323+ mtd::StubInputTargetListener input_listener;
2324
2325 static std::string const testing_app_name1;
2326 static std::string const testing_app_name2;
2327@@ -60,9 +65,9 @@
2328 {
2329 using namespace ::testing;
2330
2331- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
2332- auto app2 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name2);
2333- auto app3 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name3);
2334+ auto app1 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name1);
2335+ auto app2 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name2);
2336+ auto app3 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name3);
2337
2338 container->insert_session(app1);
2339 container->insert_session(app2);
2340@@ -78,9 +83,9 @@
2341 {
2342 using namespace ::testing;
2343
2344- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
2345- auto app2 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name2);
2346- auto app3 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name3);
2347+ auto app1 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name1);
2348+ auto app2 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name2);
2349+ auto app3 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name3);
2350 container->insert_session(app1);
2351 container->insert_session(app2);
2352 container->insert_session(app3);
2353@@ -95,7 +100,7 @@
2354 {
2355 using namespace ::testing;
2356
2357- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
2358+ auto app1 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name1);
2359 container->insert_session(app1);
2360
2361 msh::RegistrationOrderFocusSequence focus_sequence(container);
2362@@ -107,8 +112,8 @@
2363 {
2364 using namespace ::testing;
2365
2366- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
2367- auto app2 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name2);
2368+ auto app1 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name1);
2369+ auto app2 = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name2);
2370 auto null_session = std::shared_ptr<msh::ApplicationSession>();
2371
2372 msh::RegistrationOrderFocusSequence focus_sequence(container);
2373@@ -124,7 +129,7 @@
2374 {
2375 using namespace ::testing;
2376
2377- auto invalid_session = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
2378+ auto invalid_session = std::make_shared<msh::ApplicationSession>(factory, mt::fake_shared(input_listener), testing_app_name1);
2379 auto null_session = std::shared_ptr<msh::ApplicationSession>();
2380
2381 msh::RegistrationOrderFocusSequence focus_sequence(container);
2382
2383=== modified file 'tests/unit-tests/shell/test_session_manager.cpp'
2384--- tests/unit-tests/shell/test_session_manager.cpp 2013-04-18 22:29:24 +0000
2385+++ tests/unit-tests/shell/test_session_manager.cpp 2013-04-22 16:32:37 +0000
2386@@ -21,15 +21,19 @@
2387 #include "mir/shell/session_manager.h"
2388 #include "mir/shell/default_session_container.h"
2389 #include "mir/shell/session.h"
2390+#include "mir/shell/input_target_listener.h"
2391 #include "mir/frontend/surface_creation_parameters.h"
2392 #include "mir/surfaces/surface.h"
2393 #include "mir/input/input_channel.h"
2394+
2395+#include "mir_test/fake_shared.h"
2396 #include "mir_test_doubles/mock_buffer_bundle.h"
2397-#include "mir_test/fake_shared.h"
2398 #include "mir_test_doubles/mock_surface_factory.h"
2399 #include "mir_test_doubles/mock_focus_setter.h"
2400 #include "mir_test_doubles/null_buffer_bundle.h"
2401 #include "mir_test_doubles/stub_surface_builder.h"
2402+#include "mir_test_doubles/stub_input_target_listener.h"
2403+#include "mir_test_doubles/mock_input_target_listener.h"
2404
2405 #include "mir/shell/surface.h"
2406
2407@@ -56,7 +60,7 @@
2408 ~MockSessionContainer() noexcept {}
2409 };
2410
2411-struct MockFocusSequence: public msh::FocusSequence
2412+struct MockFocusSequence : public msh::FocusSequence
2413 {
2414 MOCK_CONST_METHOD1(successor_of, std::shared_ptr<msh::Session>(std::shared_ptr<msh::Session> const&));
2415 MOCK_CONST_METHOD1(predecessor_of, std::shared_ptr<msh::Session>(std::shared_ptr<msh::Session> const&));
2416@@ -68,16 +72,18 @@
2417 SessionManagerSetup()
2418 : session_manager(mt::fake_shared(surface_factory),
2419 mt::fake_shared(container),
2420- mt::fake_shared(sequence),
2421- mt::fake_shared(focus_setter))
2422+ mt::fake_shared(focus_sequence),
2423+ mt::fake_shared(focus_setter),
2424+ mt::fake_shared(input_target_listener))
2425 {
2426 }
2427
2428 mtd::StubSurfaceBuilder surface_builder;
2429 mtd::MockSurfaceFactory surface_factory;
2430 testing::NiceMock<MockSessionContainer> container; // Inelegant but some tests need a stub
2431- MockFocusSequence sequence;
2432+ MockFocusSequence focus_sequence;
2433 testing::NiceMock<mtd::MockFocusSetter> focus_setter; // Inelegant but some tests need a stub
2434+ mtd::StubInputTargetListener input_target_listener;
2435
2436 msh::SessionManager session_manager;
2437 };
2438@@ -93,7 +99,7 @@
2439 EXPECT_CALL(focus_setter, set_focus_to(_));
2440 EXPECT_CALL(focus_setter, set_focus_to(std::shared_ptr<msh::Session>())).Times(1);
2441
2442- EXPECT_CALL(sequence, default_focus()).WillOnce(Return((std::shared_ptr<msh::Session>())));
2443+ EXPECT_CALL(focus_sequence, default_focus()).WillOnce(Return((std::shared_ptr<msh::Session>())));
2444
2445 auto session = session_manager.open_session("Visual Basic Studio");
2446 session_manager.close_session(session);
2447@@ -118,7 +124,7 @@
2448 EXPECT_CALL(focus_setter, set_focus_to(_)).Times(1);
2449 EXPECT_CALL(focus_setter, set_focus_to(std::shared_ptr<msh::Session>())).Times(1);
2450
2451- EXPECT_CALL(sequence, default_focus()).WillOnce(Return((std::shared_ptr<msh::Session>())));
2452+ EXPECT_CALL(focus_sequence, default_focus()).WillOnce(Return((std::shared_ptr<msh::Session>())));
2453
2454 auto session = session_manager.open_session("Visual Basic Studio");
2455 session->create_surface(mf::a_surface().of_size(geom::Size{geom::Width{1024}, geom::Height{768}}));
2456@@ -164,7 +170,7 @@
2457 session_manager.tag_session_with_lightdm_id(session1, 1);
2458 session_manager.focus_session_with_lightdm_id(1);
2459
2460- EXPECT_CALL(sequence, default_focus()).WillOnce(Return(shell_session2));
2461+ EXPECT_CALL(focus_sequence, default_focus()).WillOnce(Return(shell_session2));
2462 EXPECT_CALL(focus_setter, set_focus_to(Eq(shell_session2)));
2463
2464 session_manager.close_session(session1);
2465@@ -193,3 +199,61 @@
2466 session_manager.create_surface_for(session1, mf::a_surface());
2467 }
2468
2469+namespace
2470+{
2471+
2472+struct SessionManagerInputTargetListenerSetup : public testing::Test
2473+{
2474+ SessionManagerInputTargetListenerSetup()
2475+ : session_manager(mt::fake_shared(surface_factory),
2476+ mt::fake_shared(container),
2477+ mt::fake_shared(focus_sequence),
2478+ mt::fake_shared(focus_setter),
2479+ mt::fake_shared(input_target_listener))
2480+ {
2481+ }
2482+
2483+ mtd::StubSurfaceBuilder surface_builder;
2484+ mtd::MockSurfaceFactory surface_factory;
2485+ testing::NiceMock<MockSessionContainer> container; // Inelegant but some tests need a stub
2486+ testing::NiceMock<MockFocusSequence> focus_sequence;
2487+ testing::NiceMock<mtd::MockFocusSetter> focus_setter; // Inelegant but some tests need a stub
2488+ mtd::MockInputTargetListener input_target_listener;
2489+
2490+ msh::SessionManager session_manager;
2491+};
2492+
2493+}
2494+
2495+TEST_F(SessionManagerInputTargetListenerSetup, listener_is_notified_of_session_and_surfacelifecycle)
2496+{
2497+ using namespace ::testing;
2498+
2499+ std::shared_ptr<mi::InputChannel> null_input_channel;
2500+ ON_CALL(surface_factory, create_surface(_)).WillByDefault(
2501+ Return(std::make_shared<msh::Surface>(
2502+ mt::fake_shared(surface_builder),
2503+ mf::a_surface(),
2504+ null_input_channel)));
2505+
2506+ EXPECT_CALL(focus_sequence, default_focus()).WillOnce(Return((std::shared_ptr<msh::Session>())));
2507+ {
2508+ InSequence seq;
2509+
2510+ EXPECT_CALL(input_target_listener, input_application_opened(_))
2511+ .Times(1);
2512+ EXPECT_CALL(input_target_listener, input_surface_opened(_, _)).Times(1);
2513+ EXPECT_CALL(input_target_listener, focus_changed(_)).Times(1);
2514+ EXPECT_CALL(input_target_listener, input_surface_closed(_)).Times(1);
2515+ EXPECT_CALL(input_target_listener, input_application_closed(_))
2516+ .Times(1);
2517+ EXPECT_CALL(input_target_listener, focus_cleared()).Times(1);
2518+ }
2519+
2520+ {
2521+ auto session = session_manager.open_session("test");
2522+ auto surf = session_manager.create_surface_for(session, mf::a_surface());
2523+ session->destroy_surface(surf);
2524+ session_manager.close_session(session);
2525+ }
2526+}
2527
2528=== modified file 'tests/unit-tests/shell/test_single_visibility_focus_mechanism.cpp'
2529--- tests/unit-tests/shell/test_single_visibility_focus_mechanism.cpp 2013-04-19 15:33:04 +0000
2530+++ tests/unit-tests/shell/test_single_visibility_focus_mechanism.cpp 2013-04-22 16:32:37 +0000
2531@@ -27,7 +27,6 @@
2532 #include "mir_test_doubles/mock_buffer_bundle.h"
2533 #include "mir_test/fake_shared.h"
2534 #include "mir_test_doubles/mock_surface_factory.h"
2535-#include "mir_test_doubles/mock_input_focus_selector.h"
2536 #include "mir_test_doubles/stub_surface.h"
2537 #include "mir_test_doubles/mock_surface.h"
2538 #include "mir_test_doubles/stub_surface_builder.h"
2539@@ -64,8 +63,6 @@
2540 {
2541 using namespace ::testing;
2542
2543- NiceMock<mtd::MockInputFocusSelector> input_focus_selector;
2544-
2545 NiceMock<MockShellSession> app1, app2, app3;
2546 msh::DefaultSessionContainer model;
2547
2548@@ -73,7 +70,7 @@
2549 ON_CALL(app2, default_surface()).WillByDefault(Return(std::shared_ptr<msh::Surface>()));
2550 ON_CALL(app3, default_surface()).WillByDefault(Return(std::shared_ptr<msh::Surface>()));
2551
2552- msh::SingleVisibilityFocusMechanism focus_mechanism(mt::fake_shared(model), mt::fake_shared(input_focus_selector));
2553+ msh::SingleVisibilityFocusMechanism focus_mechanism(mt::fake_shared(model));
2554
2555 EXPECT_CALL(app1, show()).Times(1);
2556 EXPECT_CALL(app2, hide()).Times(1);
2557@@ -89,23 +86,3 @@
2558
2559 focus_mechanism.set_focus_to(mt::fake_shared(app1));
2560 }
2561-
2562-TEST(SingleVisibilityFocusMechanism, mechanism_sets_input_focus_from_default_surface)
2563-{
2564- using namespace ::testing;
2565-
2566- mtd::MockInputFocusSelector input_focus_selector;
2567- msh::DefaultSessionContainer model;
2568- auto session = std::make_shared<NiceMock<MockShellSession>>();
2569- auto surface = std::make_shared<mtd::MockSurface>(std::make_shared<mtd::StubSurfaceBuilder>());
2570-
2571- msh::SingleVisibilityFocusMechanism focus_mechanism(mt::fake_shared(model), mt::fake_shared(input_focus_selector));
2572-
2573- EXPECT_CALL(*session, default_surface()).Times(1).WillOnce(Return(surface));
2574-
2575- EXPECT_CALL(input_focus_selector, set_input_focus_to(Eq(session), Eq(surface))).Times(1);
2576-
2577- model.insert_session(session);
2578- focus_mechanism.set_focus_to(session);
2579-}
2580-
2581
2582=== modified file 'tests/unit-tests/shell/test_surface.cpp'
2583--- tests/unit-tests/shell/test_surface.cpp 2013-04-16 17:42:26 +0000
2584+++ tests/unit-tests/shell/test_surface.cpp 2013-04-22 16:32:37 +0000
2585@@ -220,6 +220,24 @@
2586 }, std::runtime_error);
2587 }
2588
2589+TEST_F(ShellSurface, top_left_throw_behavior)
2590+{
2591+ msh::Surface test(
2592+ mt::fake_shared(surface_builder),
2593+ mf::a_surface(),
2594+ null_input_channel);
2595+
2596+ EXPECT_NO_THROW({
2597+ test.top_left();
2598+ });
2599+
2600+ surface_builder.reset_surface();
2601+
2602+ EXPECT_THROW({
2603+ test.top_left();
2604+ }, std::runtime_error);
2605+}
2606+
2607 TEST_F(ShellSurface, name_throw_behavior)
2608 {
2609 msh::Surface test(
2610
2611=== modified file 'tests/unit-tests/shell/test_the_session_container_implementation.cpp'
2612--- tests/unit-tests/shell/test_the_session_container_implementation.cpp 2013-04-18 00:00:55 +0000
2613+++ tests/unit-tests/shell/test_the_session_container_implementation.cpp 2013-04-22 16:32:37 +0000
2614@@ -22,6 +22,7 @@
2615 #include "mir/frontend/surface_creation_parameters.h"
2616 #include "mir/surfaces/surface.h"
2617 #include "mir_test_doubles/mock_buffer_bundle.h"
2618+#include "mir_test_doubles/stub_input_target_listener.h"
2619 #include "mir_test_doubles/mock_surface_factory.h"
2620
2621 #include <gmock/gmock.h>
2622@@ -38,8 +39,10 @@
2623 auto factory = std::make_shared<mtd::MockSurfaceFactory>();
2624 msh::DefaultSessionContainer container;
2625
2626- container.insert_session(std::make_shared<msh::ApplicationSession>(factory, "Visual Studio 7"));
2627- container.insert_session(std::make_shared<msh::ApplicationSession>(factory, "Visual Studio 8"));
2628+ container.insert_session(std::make_shared<msh::ApplicationSession>(factory, std::make_shared<mtd::StubInputTargetListener>(),
2629+ "Visual Studio 7"));
2630+ container.insert_session(std::make_shared<msh::ApplicationSession>(factory, std::make_shared<mtd::StubInputTargetListener>(),
2631+ "Visual Studio 8"));
2632
2633 struct local
2634 {
2635@@ -64,8 +67,8 @@
2636 auto factory = std::make_shared<mtd::MockSurfaceFactory>();
2637 msh::DefaultSessionContainer container;
2638
2639- auto session = std::make_shared<msh::ApplicationSession>(factory,
2640- "Visual Studio 7");
2641+ auto session = std::make_shared<msh::ApplicationSession>(factory, std::make_shared<mtd::StubInputTargetListener>(),
2642+ "Visual Studio 7");
2643 EXPECT_THROW({
2644 container.remove_session(session);
2645 }, std::logic_error);

Subscribers

People subscribed via source and target branches