Mir

Merge lp:~raof/mir/wayland-touch-support into lp:mir

Proposed by Chris Halse Rogers
Status: Superseded
Proposed branch: lp:~raof/mir/wayland-touch-support
Merge into: lp:mir
Diff against target: 317 lines (+138/-66)
1 file modified
src/server/frontend/wayland/wayland_connector.cpp (+138/-66)
To merge this branch: bzr merge lp:~raof/mir/wayland-touch-support
Reviewer Review Type Date Requested Status
Mir development team Pending
Review via email: mp+331367@code.launchpad.net

Commit message

Wayland: Implement touch support.

This is mostly complete - it does not support touchpoint shape/size, but we only expose wl_seat v5 (as that's the version supported by Xenial's wayland) and the size/shape protocol was added in v6 anyway.

Fixes: https://bugs.launchpad.net/mir/+bug/1718732

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 'src/server/frontend/wayland/wayland_connector.cpp'
2--- src/server/frontend/wayland/wayland_connector.cpp 2017-09-26 16:00:49 +0000
3+++ src/server/frontend/wayland/wayland_connector.cpp 2017-09-26 17:51:10 +0000
4@@ -158,8 +158,29 @@
5
6 struct ClientPrivate
7 {
8+ ClientPrivate(std::shared_ptr<mf::Session> const& session, mf::Shell& shell)
9+ : session{session},
10+ shell{&shell}
11+ {
12+ }
13+
14+ ~ClientPrivate()
15+ {
16+ shell->close_session(session);
17+ /*
18+ * This ensures that further calls to
19+ * wl_client_get_destroy_listener(client, &cleanup_private)
20+ * - and hence session_for_client(client) - return nullptr.
21+ */
22+ wl_list_remove(&destroy_listener.link);
23+ }
24+
25 wl_listener destroy_listener;
26- std::shared_ptr<mf::Session> session;
27+ std::shared_ptr<mf::Session> const session;
28+ /*
29+ * This shell is owned by the ClientSessionConstructor, which outlives all clients.
30+ */
31+ mf::Shell* const shell;
32 };
33
34 static_assert(
35@@ -182,9 +203,10 @@
36 {
37 auto listener = wl_client_get_destroy_listener(client, &cleanup_private);
38
39- assert(listener && "Client session requested for malformed client");
40+ if (listener)
41+ return private_from_listener(listener)->session;
42
43- return private_from_listener(listener)->session;
44+ return nullptr;
45 }
46
47 struct ClientSessionConstructor
48@@ -220,9 +242,8 @@
49 "",
50 std::make_shared<WaylandEventSink>([](auto){}));
51
52- auto client_context = new ClientPrivate;
53+ auto client_context = new ClientPrivate{session, *construction_context->shell};
54 client_context->destroy_listener.notify = &cleanup_private;
55- client_context->session = session;
56 wl_client_add_destroy_listener(client, &client_context->destroy_listener);
57 }
58
59@@ -295,6 +316,19 @@
60
61 return buffer;
62 }
63+
64+template<typename Callable>
65+auto run_unless(std::shared_ptr<bool> const& condition, Callable&& callable)
66+{
67+ return
68+ [callable = std::move(callable), condition]()
69+ {
70+ if (*condition)
71+ return;
72+
73+ callable();
74+ };
75+}
76 }
77
78 class WlShmBuffer :
79@@ -511,7 +545,8 @@
80 allocator{allocator},
81 executor{executor},
82 pending_buffer{nullptr},
83- pending_frames{std::make_shared<std::vector<wl_resource*>>()}
84+ pending_frames{std::make_shared<std::vector<wl_resource*>>()},
85+ destroyed{std::make_shared<bool>(false)}
86 {
87 auto session = session_for_client(client);
88 mg::BufferProperties const props{
89@@ -527,6 +562,13 @@
90 stream->allow_framedropping(true);
91 }
92
93+ ~WlSurface()
94+ {
95+ *destroyed = true;
96+ if (auto session = session_for_client(client))
97+ session->destroy_buffer_stream(stream_id);
98+ }
99+
100 void set_resize_handler(std::function<void(geom::Size)> const& handler)
101 {
102 resize_handler = handler;
103@@ -548,6 +590,7 @@
104
105 wl_resource* pending_buffer;
106 std::shared_ptr<std::vector<wl_resource*>> const pending_frames;
107+ std::shared_ptr<bool> const destroyed;
108
109 void destroy();
110 void attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y);
111@@ -620,9 +663,10 @@
112 std::shared_ptr<mg::Buffer> mir_buffer;
113 auto shm_buffer = wl_shm_buffer_get(pending_buffer);
114 auto send_frame_notifications =
115- [executor = executor, frames = pending_frames]()
116+ [executor = executor, frames = pending_frames, destroyed = destroyed]()
117 {
118- executor->spawn(
119+ executor->spawn(run_unless(
120+ destroyed,
121 [frames]()
122 {
123 /*
124@@ -639,7 +683,7 @@
125 wl_resource_destroy(frame);
126 }
127 frames->clear();
128- });
129+ }));
130 };
131
132 if (shm_buffer)
133@@ -745,19 +789,6 @@
134 class WlPointer;
135 class WlTouch;
136
137-template<typename Callable>
138-auto run_unless(std::shared_ptr<bool> const& condition, Callable&& callable)
139-{
140- return
141- [callable = std::move(callable), condition]()
142- {
143- if (*condition)
144- return;
145-
146- callable();
147- };
148-}
149-
150 class WlKeyboard : public wayland::Keyboard
151 {
152 public:
153@@ -1034,8 +1065,81 @@
154 *destroyed = true;
155 }
156
157- void handle_event(MirInputEvent const* /*event*/, wl_resource* /*target*/)
158+ void handle_event(MirInputEvent const* event, wl_resource* target)
159 {
160+ executor->spawn(run_unless(
161+ destroyed,
162+ [ev = mcl::Event{mir_input_event_get_event(event)}, target = target, this]()
163+ {
164+ auto const input_ev = mir_event_get_input_event(ev);
165+ auto const touch_ev = mir_input_event_get_touch_event(input_ev);
166+
167+ for (auto i = 0u; i < mir_touch_event_point_count(touch_ev); ++i)
168+ {
169+ auto const touch_id = mir_touch_event_id(touch_ev, i);
170+ auto const action = mir_touch_event_action(touch_ev, i);
171+ auto const x = mir_touch_event_axis_value(
172+ touch_ev,
173+ i,
174+ mir_touch_axis_x);
175+ auto const y = mir_touch_event_axis_value(
176+ touch_ev,
177+ i,
178+ mir_touch_axis_y);
179+
180+ switch (action)
181+ {
182+ case mir_touch_action_down:
183+ wl_touch_send_down(
184+ resource,
185+ wl_display_get_serial(wl_client_get_display(client)),
186+ mir_input_event_get_event_time(input_ev) / 1000,
187+ target,
188+ touch_id,
189+ wl_fixed_from_double(x),
190+ wl_fixed_from_double(y));
191+ break;
192+ case mir_touch_action_up:
193+ wl_touch_send_up(
194+ resource,
195+ wl_display_get_serial(wl_client_get_display(client)),
196+ mir_input_event_get_event_time(input_ev) / 1000,
197+ touch_id);
198+ break;
199+ case mir_touch_action_change:
200+ wl_touch_send_motion(
201+ resource,
202+ mir_input_event_get_event_time(input_ev) / 1000,
203+ touch_id,
204+ wl_fixed_from_double(x),
205+ wl_fixed_from_double(y));
206+ break;
207+ case mir_touch_actions:
208+ /*
209+ * We should never receive an event with this action set;
210+ * the only way would be if a *new* action has been added
211+ * to the enum, and this hasn't been updated.
212+ *
213+ * There's nothing to do here, but don't use default: so
214+ * that the compiler will warn if a new enum value is added.
215+ */
216+ break;
217+ }
218+ }
219+
220+ if (mir_touch_event_point_count(touch_ev) > 0)
221+ {
222+ /*
223+ * This is mostly paranoia; I assume we won't actually be called
224+ * with an empty touch event.
225+ *
226+ * Regardless, the Wayland protocol requires that there be at least
227+ * one event sent before we send the ending frame, so make that explicit.
228+ */
229+ wl_touch_send_frame(resource);
230+ }
231+ }
232+ ));
233 }
234
235 // Touch interface
236@@ -1158,7 +1262,8 @@
237 wl_seat_send_capabilities(
238 resource,
239 WL_SEAT_CAPABILITY_POINTER |
240- WL_SEAT_CAPABILITY_KEYBOARD);
241+ WL_SEAT_CAPABILITY_KEYBOARD |
242+ WL_SEAT_CAPABILITY_TOUCH);
243 wl_seat_send_name(
244 resource,
245 "seat0");
246@@ -1554,15 +1659,15 @@
247 hide_spec.state = mir_window_state_hidden;
248 shell->modify_surface(session, id, hide_spec);
249 });
250-
251- auto shim = new DestructionShim{session, shell, surface_id};
252- shim->destruction_listener.notify = &cleanup_surface;
253- wl_resource_add_destroy_listener(
254- resource,
255- &shim->destruction_listener);
256- }
257-
258- ~WlShellSurface() override = default;
259+ }
260+
261+ ~WlShellSurface() override
262+ {
263+ if (auto session = session_for_client(client))
264+ {
265+ shell->destroy_surface(session, surface_id);
266+ }
267+ }
268 protected:
269 void pong(uint32_t /*serial*/) override
270 {
271@@ -1602,7 +1707,6 @@
272
273 auto const session = session_for_client(client);
274 shell->modify_surface(session, surface_id, mods);
275-
276 }
277
278 void set_popup(
279@@ -1635,38 +1739,6 @@
280 {
281 }
282 private:
283- struct DestructionShim
284- {
285- DestructionShim(
286- std::shared_ptr<mf::Session> const& session,
287- std::shared_ptr<mf::Shell> const& shell,
288- mf::SurfaceId id)
289- : session{session},
290- shell{shell},
291- surface_id{id}
292- {
293- }
294-
295- std::shared_ptr<mf::Session> const session;
296- std::shared_ptr<mf::Shell> const shell;
297- mf::SurfaceId const surface_id;
298- wl_listener destruction_listener;
299- };
300-
301- static_assert(
302- std::is_standard_layout<DestructionShim>::value,
303- "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour");
304-
305- static void cleanup_surface(wl_listener* listener, void*)
306- {
307- DestructionShim* shim;
308- shim = wl_container_of(listener, shim, destruction_listener);
309-
310- shim->shell->destroy_surface(shim->session, shim->surface_id);
311-
312- delete shim;
313- }
314-
315 std::shared_ptr<mf::Shell> const shell;
316 mf::SurfaceId surface_id;
317 };

Subscribers

People subscribed via source and target branches