Merge lp:~raof/mir/wayland-clients-close-their-sessions-on-quit into lp:mir
- wayland-clients-close-their-sessions-on-quit
- Merge into development-branch
Proposed by
Chris Halse Rogers
Status: | Superseded |
---|---|
Proposed branch: | lp:~raof/mir/wayland-clients-close-their-sessions-on-quit |
Merge into: | lp:mir |
Diff against target: |
863 lines (+260/-116) 4 files modified
debian/control (+1/-0) src/protocol/wrapper_generator.cpp (+11/-1) src/server/frontend/wayland/core_generated_interfaces.h (+60/-12) src/server/frontend/wayland/wayland_connector.cpp (+188/-103) |
To merge this branch: | bzr merge lp:~raof/mir/wayland-clients-close-their-sessions-on-quit |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir development team | Pending | ||
Review via email: mp+331357@code.launchpad.net |
Commit message
Wayland: Close the Mir session on client quit.
Fixes phantom sessions hanging around after client quit.
Description of the change
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 'debian/control' |
2 | --- debian/control 2017-09-13 04:15:28 +0000 |
3 | +++ debian/control 2017-09-26 15:46:44 +0000 |
4 | @@ -47,6 +47,7 @@ |
5 | capnproto, |
6 | libepoxy-dev, |
7 | python3-pil:native, |
8 | + linux-libc-dev, |
9 | Standards-Version: 3.9.4 |
10 | Homepage: https://launchpad.net/mir |
11 | # If you aren't a member of ~mir-team but need to upload packaging changes, |
12 | |
13 | === modified file 'src/protocol/wrapper_generator.cpp' |
14 | --- src/protocol/wrapper_generator.cpp 2017-09-07 00:32:52 +0000 |
15 | +++ src/protocol/wrapper_generator.cpp 2017-09-26 15:46:44 +0000 |
16 | @@ -373,6 +373,16 @@ |
17 | |
18 | if (!methods.empty()) |
19 | { |
20 | + if (!is_global) |
21 | + { |
22 | + emit_indented_lines(out, " ", { |
23 | + {"static void resource_destroyed_thunk(wl_resource* us)"}, |
24 | + {"{"}, |
25 | + {" delete static_cast<", generated_name, "*>(wl_resource_get_user_data(us));"}, |
26 | + {"}"} |
27 | + }); |
28 | + } |
29 | + |
30 | emit_indented_lines(out, " ", { |
31 | { "static struct ", wl_name, "_interface const vtable;" } |
32 | }); |
33 | @@ -427,7 +437,7 @@ |
34 | if (has_vtable) |
35 | { |
36 | emit_indented_lines(out, indent + " ", |
37 | - {{ "wl_resource_set_implementation(resource, &vtable, this, nullptr);" }}); |
38 | + {{ "wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);" }}); |
39 | } |
40 | emit_indented_lines(out, indent, { |
41 | { "}" } |
42 | |
43 | === modified file 'src/server/frontend/wayland/core_generated_interfaces.h' |
44 | --- src/server/frontend/wayland/core_generated_interfaces.h 2017-09-07 00:33:43 +0000 |
45 | +++ src/server/frontend/wayland/core_generated_interfaces.h 2017-09-26 15:46:44 +0000 |
46 | @@ -108,7 +108,7 @@ |
47 | wl_resource_post_no_memory(parent); |
48 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
49 | } |
50 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
51 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
52 | } |
53 | virtual ~ShmPool() = default; |
54 | |
55 | @@ -138,6 +138,10 @@ |
56 | me->resize(size); |
57 | } |
58 | |
59 | + static void resource_destroyed_thunk(wl_resource* us) |
60 | + { |
61 | + delete static_cast<ShmPool*>(wl_resource_get_user_data(us)); |
62 | + } |
63 | static struct wl_shm_pool_interface const vtable; |
64 | }; |
65 | |
66 | @@ -207,7 +211,7 @@ |
67 | wl_resource_post_no_memory(parent); |
68 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
69 | } |
70 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
71 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
72 | } |
73 | virtual ~Buffer() = default; |
74 | |
75 | @@ -223,6 +227,10 @@ |
76 | me->destroy(); |
77 | } |
78 | |
79 | + static void resource_destroyed_thunk(wl_resource* us) |
80 | + { |
81 | + delete static_cast<Buffer*>(wl_resource_get_user_data(us)); |
82 | + } |
83 | static struct wl_buffer_interface const vtable; |
84 | }; |
85 | |
86 | @@ -243,7 +251,7 @@ |
87 | wl_resource_post_no_memory(parent); |
88 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
89 | } |
90 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
91 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
92 | } |
93 | virtual ~DataOffer() = default; |
94 | |
95 | @@ -293,6 +301,10 @@ |
96 | me->set_actions(dnd_actions, preferred_action); |
97 | } |
98 | |
99 | + static void resource_destroyed_thunk(wl_resource* us) |
100 | + { |
101 | + delete static_cast<DataOffer*>(wl_resource_get_user_data(us)); |
102 | + } |
103 | static struct wl_data_offer_interface const vtable; |
104 | }; |
105 | |
106 | @@ -317,7 +329,7 @@ |
107 | wl_resource_post_no_memory(parent); |
108 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
109 | } |
110 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
111 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
112 | } |
113 | virtual ~DataSource() = default; |
114 | |
115 | @@ -347,6 +359,10 @@ |
116 | me->set_actions(dnd_actions); |
117 | } |
118 | |
119 | + static void resource_destroyed_thunk(wl_resource* us) |
120 | + { |
121 | + delete static_cast<DataSource*>(wl_resource_get_user_data(us)); |
122 | + } |
123 | static struct wl_data_source_interface const vtable; |
124 | }; |
125 | |
126 | @@ -369,7 +385,7 @@ |
127 | wl_resource_post_no_memory(parent); |
128 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
129 | } |
130 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
131 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
132 | } |
133 | virtual ~DataDevice() = default; |
134 | |
135 | @@ -414,6 +430,10 @@ |
136 | me->release(); |
137 | } |
138 | |
139 | + static void resource_destroyed_thunk(wl_resource* us) |
140 | + { |
141 | + delete static_cast<DataDevice*>(wl_resource_get_user_data(us)); |
142 | + } |
143 | static struct wl_data_device_interface const vtable; |
144 | }; |
145 | |
146 | @@ -536,7 +556,7 @@ |
147 | wl_resource_post_no_memory(parent); |
148 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
149 | } |
150 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
151 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
152 | } |
153 | virtual ~ShellSurface() = default; |
154 | |
155 | @@ -625,6 +645,10 @@ |
156 | me->set_class(class_); |
157 | } |
158 | |
159 | + static void resource_destroyed_thunk(wl_resource* us) |
160 | + { |
161 | + delete static_cast<ShellSurface*>(wl_resource_get_user_data(us)); |
162 | + } |
163 | static struct wl_shell_surface_interface const vtable; |
164 | }; |
165 | |
166 | @@ -654,7 +678,7 @@ |
167 | wl_resource_post_no_memory(parent); |
168 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
169 | } |
170 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
171 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
172 | } |
173 | virtual ~Surface() = default; |
174 | |
175 | @@ -748,6 +772,10 @@ |
176 | me->damage_buffer(x, y, width, height); |
177 | } |
178 | |
179 | + static void resource_destroyed_thunk(wl_resource* us) |
180 | + { |
181 | + delete static_cast<Surface*>(wl_resource_get_user_data(us)); |
182 | + } |
183 | static struct wl_surface_interface const vtable; |
184 | }; |
185 | |
186 | @@ -847,7 +875,7 @@ |
187 | wl_resource_post_no_memory(parent); |
188 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
189 | } |
190 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
191 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
192 | } |
193 | virtual ~Pointer() = default; |
194 | |
195 | @@ -875,6 +903,10 @@ |
196 | me->release(); |
197 | } |
198 | |
199 | + static void resource_destroyed_thunk(wl_resource* us) |
200 | + { |
201 | + delete static_cast<Pointer*>(wl_resource_get_user_data(us)); |
202 | + } |
203 | static struct wl_pointer_interface const vtable; |
204 | }; |
205 | |
206 | @@ -896,7 +928,7 @@ |
207 | wl_resource_post_no_memory(parent); |
208 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
209 | } |
210 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
211 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
212 | } |
213 | virtual ~Keyboard() = default; |
214 | |
215 | @@ -912,6 +944,10 @@ |
216 | me->release(); |
217 | } |
218 | |
219 | + static void resource_destroyed_thunk(wl_resource* us) |
220 | + { |
221 | + delete static_cast<Keyboard*>(wl_resource_get_user_data(us)); |
222 | + } |
223 | static struct wl_keyboard_interface const vtable; |
224 | }; |
225 | |
226 | @@ -932,7 +968,7 @@ |
227 | wl_resource_post_no_memory(parent); |
228 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
229 | } |
230 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
231 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
232 | } |
233 | virtual ~Touch() = default; |
234 | |
235 | @@ -948,6 +984,10 @@ |
236 | me->release(); |
237 | } |
238 | |
239 | + static void resource_destroyed_thunk(wl_resource* us) |
240 | + { |
241 | + delete static_cast<Touch*>(wl_resource_get_user_data(us)); |
242 | + } |
243 | static struct wl_touch_interface const vtable; |
244 | }; |
245 | |
246 | @@ -1014,7 +1054,7 @@ |
247 | wl_resource_post_no_memory(parent); |
248 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
249 | } |
250 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
251 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
252 | } |
253 | virtual ~Region() = default; |
254 | |
255 | @@ -1044,6 +1084,10 @@ |
256 | me->subtract(x, y, width, height); |
257 | } |
258 | |
259 | + static void resource_destroyed_thunk(wl_resource* us) |
260 | + { |
261 | + delete static_cast<Region*>(wl_resource_get_user_data(us)); |
262 | + } |
263 | static struct wl_region_interface const vtable; |
264 | }; |
265 | |
266 | @@ -1120,7 +1164,7 @@ |
267 | wl_resource_post_no_memory(parent); |
268 | BOOST_THROW_EXCEPTION((std::bad_alloc{})); |
269 | } |
270 | - wl_resource_set_implementation(resource, &vtable, this, nullptr); |
271 | + wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk); |
272 | } |
273 | virtual ~Subsurface() = default; |
274 | |
275 | @@ -1171,6 +1215,10 @@ |
276 | me->set_desync(); |
277 | } |
278 | |
279 | + static void resource_destroyed_thunk(wl_resource* us) |
280 | + { |
281 | + delete static_cast<Subsurface*>(wl_resource_get_user_data(us)); |
282 | + } |
283 | static struct wl_subsurface_interface const vtable; |
284 | }; |
285 | |
286 | |
287 | === modified file 'src/server/frontend/wayland/wayland_connector.cpp' |
288 | --- src/server/frontend/wayland/wayland_connector.cpp 2017-09-25 18:12:01 +0000 |
289 | +++ src/server/frontend/wayland/wayland_connector.cpp 2017-09-26 15:46:44 +0000 |
290 | @@ -41,6 +41,8 @@ |
291 | |
292 | #include "mir/executor.h" |
293 | |
294 | +#include "mir/client/event.h" |
295 | + |
296 | #include <system_error> |
297 | #include <sys/eventfd.h> |
298 | #include <wayland-server-core.h> |
299 | @@ -51,6 +53,7 @@ |
300 | #include <functional> |
301 | #include <type_traits> |
302 | |
303 | +#include <linux/input.h> |
304 | #include <algorithm> |
305 | #include <iostream> |
306 | #include <mir/log.h> |
307 | @@ -69,6 +72,7 @@ |
308 | namespace mc = mir::compositor; |
309 | namespace ms = mir::scene; |
310 | namespace geom = mir::geometry; |
311 | +namespace mcl = mir::client; |
312 | |
313 | namespace mir |
314 | { |
315 | @@ -154,8 +158,29 @@ |
316 | |
317 | struct ClientPrivate |
318 | { |
319 | + ClientPrivate(std::shared_ptr<mf::Session> const& session, mf::Shell& shell) |
320 | + : session{session}, |
321 | + shell{&shell} |
322 | + { |
323 | + } |
324 | + |
325 | + ~ClientPrivate() |
326 | + { |
327 | + shell->close_session(session); |
328 | + /* |
329 | + * This ensures that further calls to |
330 | + * wl_client_get_destroy_listener(client, &cleanup_private) |
331 | + * - and hence session_for_client(client) - return nullptr. |
332 | + */ |
333 | + wl_list_remove(&destroy_listener.link); |
334 | + } |
335 | + |
336 | wl_listener destroy_listener; |
337 | - std::shared_ptr<mf::Session> session; |
338 | + std::shared_ptr<mf::Session> const session; |
339 | + /* |
340 | + * This shell is owned by the ClientSessionConstructor, which outlives all clients. |
341 | + */ |
342 | + mf::Shell* const shell; |
343 | }; |
344 | |
345 | static_assert( |
346 | @@ -178,9 +203,10 @@ |
347 | { |
348 | auto listener = wl_client_get_destroy_listener(client, &cleanup_private); |
349 | |
350 | - assert(listener && "Client session requested for malformed client"); |
351 | + if (listener) |
352 | + return private_from_listener(listener)->session; |
353 | |
354 | - return private_from_listener(listener)->session; |
355 | + return nullptr; |
356 | } |
357 | |
358 | struct ClientSessionConstructor |
359 | @@ -216,9 +242,8 @@ |
360 | "", |
361 | std::make_shared<WaylandEventSink>([](auto){})); |
362 | |
363 | - auto client_context = new ClientPrivate; |
364 | + auto client_context = new ClientPrivate{session, *construction_context->shell}; |
365 | client_context->destroy_listener.notify = &cleanup_private; |
366 | - client_context->session = session; |
367 | wl_client_add_destroy_listener(client, &client_context->destroy_listener); |
368 | } |
369 | |
370 | @@ -291,6 +316,19 @@ |
371 | |
372 | return buffer; |
373 | } |
374 | + |
375 | +template<typename Callable> |
376 | +auto run_unless(std::shared_ptr<bool> const& condition, Callable&& callable) |
377 | +{ |
378 | + return |
379 | + [callable = std::move(callable), condition]() |
380 | + { |
381 | + if (*condition) |
382 | + return; |
383 | + |
384 | + callable(); |
385 | + }; |
386 | +} |
387 | } |
388 | |
389 | class WlShmBuffer : |
390 | @@ -507,7 +545,8 @@ |
391 | allocator{allocator}, |
392 | executor{executor}, |
393 | pending_buffer{nullptr}, |
394 | - pending_frames{std::make_shared<std::vector<wl_resource*>>()} |
395 | + pending_frames{std::make_shared<std::vector<wl_resource*>>()}, |
396 | + destroyed{std::make_shared<bool>(false)} |
397 | { |
398 | auto session = session_for_client(client); |
399 | mg::BufferProperties const props{ |
400 | @@ -523,6 +562,13 @@ |
401 | stream->allow_framedropping(true); |
402 | } |
403 | |
404 | + ~WlSurface() |
405 | + { |
406 | + *destroyed = true; |
407 | + if (auto session = session_for_client(client)) |
408 | + session->destroy_buffer_stream(stream_id); |
409 | + } |
410 | + |
411 | void set_resize_handler(std::function<void(geom::Size)> const& handler) |
412 | { |
413 | resize_handler = handler; |
414 | @@ -544,6 +590,7 @@ |
415 | |
416 | wl_resource* pending_buffer; |
417 | std::shared_ptr<std::vector<wl_resource*>> const pending_frames; |
418 | + std::shared_ptr<bool> const destroyed; |
419 | |
420 | void destroy(); |
421 | void attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y); |
422 | @@ -559,7 +606,7 @@ |
423 | |
424 | void WlSurface::destroy() |
425 | { |
426 | - delete this; |
427 | + wl_resource_destroy(resource); |
428 | } |
429 | |
430 | void WlSurface::attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y) |
431 | @@ -616,9 +663,10 @@ |
432 | std::shared_ptr<mg::Buffer> mir_buffer; |
433 | auto shm_buffer = wl_shm_buffer_get(pending_buffer); |
434 | auto send_frame_notifications = |
435 | - [executor = executor, frames = pending_frames]() |
436 | + [executor = executor, frames = pending_frames, destroyed = destroyed]() |
437 | { |
438 | - executor->spawn( |
439 | + executor->spawn(run_unless( |
440 | + destroyed, |
441 | [frames]() |
442 | { |
443 | /* |
444 | @@ -635,7 +683,7 @@ |
445 | wl_resource_destroy(frame); |
446 | } |
447 | frames->clear(); |
448 | - }); |
449 | + })); |
450 | }; |
451 | |
452 | if (shm_buffer) |
453 | @@ -748,16 +796,29 @@ |
454 | wl_client* client, |
455 | wl_resource* parent, |
456 | uint32_t id, |
457 | + std::function<void(WlKeyboard*)> const& on_destroy, |
458 | std::shared_ptr<mir::Executor> const& executor) |
459 | : Keyboard(client, parent, id), |
460 | - executor{executor} |
461 | - { |
462 | + executor{executor}, |
463 | + on_destroy{on_destroy}, |
464 | + destroyed{std::make_shared<bool>(false)} |
465 | + { |
466 | + } |
467 | + |
468 | + ~WlKeyboard() |
469 | + { |
470 | + on_destroy(this); |
471 | + *destroyed = true; |
472 | } |
473 | |
474 | void handle_event(MirInputEvent const* event, wl_resource* /*target*/) |
475 | { |
476 | - executor->spawn( |
477 | - [ev = mir_event_ref(mir_input_event_get_event(event)), this] () |
478 | + executor->spawn(run_unless( |
479 | + destroyed, |
480 | + [ |
481 | + ev = mcl::Event{mir_event_ref(mir_input_event_get_event(event))}, |
482 | + this |
483 | + ] () |
484 | { |
485 | int const serial = wl_display_next_serial(wl_client_get_display(client)); |
486 | auto event = mir_event_get_input_event(ev); |
487 | @@ -782,18 +843,22 @@ |
488 | default: |
489 | break; |
490 | } |
491 | - mir_event_unref(ev); |
492 | - }); |
493 | + })); |
494 | } |
495 | |
496 | void handle_event(MirWindowEvent const* event, wl_resource* target) |
497 | { |
498 | if (mir_window_event_get_attribute(event) == mir_window_attrib_focus) |
499 | { |
500 | - executor->spawn( |
501 | - [resource = resource, serial = wl_display_next_serial(wl_client_get_display(client)), |
502 | - target = target, focussed = mir_window_event_get_attribute_value(event)]() |
503 | + executor->spawn(run_unless( |
504 | + destroyed, |
505 | + [ |
506 | + target = target, |
507 | + focussed = mir_window_event_get_attribute_value(event), |
508 | + this |
509 | + ]() |
510 | { |
511 | + auto const serial = wl_display_next_serial(wl_client_get_display(client)); |
512 | if (focussed) |
513 | { |
514 | wl_array key_state; |
515 | @@ -805,18 +870,21 @@ |
516 | { |
517 | wl_keyboard_send_leave(resource, serial, target); |
518 | } |
519 | - }); |
520 | + })); |
521 | } |
522 | } |
523 | |
524 | private: |
525 | std::shared_ptr<mir::Executor> const executor; |
526 | + std::function<void(WlKeyboard*)> on_destroy; |
527 | + std::shared_ptr<bool> const destroyed; |
528 | |
529 | void release() override; |
530 | }; |
531 | |
532 | void WlKeyboard::release() |
533 | { |
534 | + wl_resource_destroy(resource); |
535 | } |
536 | |
537 | class WlPointer : public wayland::Pointer |
538 | @@ -827,17 +895,27 @@ |
539 | wl_client* client, |
540 | wl_resource* parent, |
541 | uint32_t id, |
542 | + std::function<void(WlPointer*)> const& on_destroy, |
543 | std::shared_ptr<mir::Executor> const& executor) |
544 | : Pointer(client, parent, id), |
545 | display{wl_client_get_display(client)}, |
546 | - executor{executor} |
547 | - { |
548 | + executor{executor}, |
549 | + on_destroy{on_destroy}, |
550 | + destroyed{std::make_shared<bool>(false)} |
551 | + { |
552 | + } |
553 | + |
554 | + ~WlPointer() |
555 | + { |
556 | + on_destroy(this); |
557 | + *destroyed = true; |
558 | } |
559 | |
560 | void handle_event(MirInputEvent const* event, wl_resource* target) |
561 | { |
562 | - executor->spawn( |
563 | - [ev = mir_event_ref(mir_input_event_get_event(event)), target, this]() |
564 | + executor->spawn(run_unless( |
565 | + destroyed, |
566 | + [ev = mcl::Event{mir_input_event_get_event(event)}, target, this]() |
567 | { |
568 | auto const serial = wl_display_next_serial(display); |
569 | auto const event = mir_event_get_input_event(ev); |
570 | @@ -851,25 +929,27 @@ |
571 | auto const current_set = mir_pointer_event_buttons(pointer_event); |
572 | auto const current_time = mir_input_event_get_event_time(event) / 1000; |
573 | |
574 | - auto button = 272; // No, I have *no* idea why GTK expects 272 to be the primary button. |
575 | - // NB button is incremented in the loop and the order mir_pointer_button_XXX matters |
576 | - for (auto mir_button : |
577 | - {mir_pointer_button_primary, // 272 |
578 | - mir_pointer_button_tertiary, // 273 |
579 | - mir_pointer_button_secondary, // 274 |
580 | - mir_pointer_button_back, // 275 |
581 | - mir_pointer_button_forward}) // 276 |
582 | + std::unordered_map<MirPointerButton, int> const button_mappings = { |
583 | + {mir_pointer_button_primary, BTN_LEFT}, |
584 | + {mir_pointer_button_secondary, BTN_RIGHT}, |
585 | + {mir_pointer_button_tertiary, BTN_MIDDLE}, |
586 | + {mir_pointer_button_back, BTN_BACK}, |
587 | + {mir_pointer_button_forward, BTN_FORWARD}, |
588 | + {mir_pointer_button_side, BTN_SIDE}, |
589 | + {mir_pointer_button_task, BTN_TASK}, |
590 | + {mir_pointer_button_extra, BTN_EXTRA} |
591 | + }; |
592 | + |
593 | + for (auto mapping : button_mappings) |
594 | { |
595 | - if (mir_button & (current_set ^ last_set)) |
596 | + if (mapping.first & (current_set ^ last_set)) |
597 | { |
598 | - auto const action = (mir_button & current_set) ? |
599 | + auto const action = (mapping.first & current_set) ? |
600 | WL_POINTER_BUTTON_STATE_PRESSED : |
601 | WL_POINTER_BUTTON_STATE_RELEASED; |
602 | |
603 | - wl_pointer_send_button(resource, serial, current_time, button, action); |
604 | + wl_pointer_send_button(resource, serial, current_time, mapping.second, action); |
605 | } |
606 | - |
607 | - ++button; |
608 | } |
609 | |
610 | last_set = current_set; |
611 | @@ -934,7 +1014,7 @@ |
612 | case mir_pointer_actions: |
613 | break; |
614 | } |
615 | - }); |
616 | + })); |
617 | } |
618 | |
619 | // Pointer interface |
620 | @@ -942,6 +1022,9 @@ |
621 | wl_display* const display; |
622 | std::shared_ptr<mir::Executor> const executor; |
623 | |
624 | + std::function<void(WlPointer*)> on_destroy; |
625 | + std::shared_ptr<bool> const destroyed; |
626 | + |
627 | MirPointerButtons last_set{0}; |
628 | float last_x, last_y, last_vscroll, last_hscroll; |
629 | |
630 | @@ -959,7 +1042,7 @@ |
631 | |
632 | void WlPointer::release() |
633 | { |
634 | - delete this; |
635 | + wl_resource_destroy(resource); |
636 | } |
637 | |
638 | class WlTouch : public wayland::Touch |
639 | @@ -969,9 +1052,18 @@ |
640 | wl_client* client, |
641 | wl_resource* parent, |
642 | uint32_t id, |
643 | - std::shared_ptr<mir::Executor> const& /*executor*/) |
644 | - : Touch(client, parent, id) |
645 | - { |
646 | + std::function<void(WlTouch*)> const& on_destroy, |
647 | + std::shared_ptr<mir::Executor> const& executor) |
648 | + : Touch(client, parent, id), |
649 | + executor{executor}, |
650 | + on_destroy{on_destroy} |
651 | + { |
652 | + } |
653 | + |
654 | + ~WlTouch() |
655 | + { |
656 | + on_destroy(this); |
657 | + *destroyed = true; |
658 | } |
659 | |
660 | void handle_event(MirInputEvent const* /*event*/, wl_resource* /*target*/) |
661 | @@ -980,11 +1072,16 @@ |
662 | |
663 | // Touch interface |
664 | private: |
665 | + std::shared_ptr<mir::Executor> const executor; |
666 | + std::function<void(WlTouch*)> on_destroy; |
667 | + std::shared_ptr<bool> const destroyed; |
668 | + |
669 | void release() override; |
670 | }; |
671 | |
672 | void WlTouch::release() |
673 | { |
674 | + wl_resource_destroy(resource); |
675 | } |
676 | |
677 | template<class InputInterface> |
678 | @@ -997,25 +1094,27 @@ |
679 | InputCtx(InputCtx const&) = delete; |
680 | InputCtx& operator=(InputCtx const&) = delete; |
681 | |
682 | - void register_listener(std::shared_ptr<InputInterface> const& listener) |
683 | + void register_listener(InputInterface* listener) |
684 | { |
685 | + std::lock_guard<std::mutex> lock{mutex}; |
686 | listeners.push_back(listener); |
687 | } |
688 | |
689 | void unregister_listener(InputInterface const* listener) |
690 | { |
691 | - std::remove_if( |
692 | - listeners.begin(), |
693 | - listeners.end(), |
694 | - [listener](auto candidate) |
695 | - { |
696 | - return candidate.get() == listener; |
697 | - }); |
698 | + std::lock_guard<std::mutex> lock{mutex}; |
699 | + listeners.erase( |
700 | + std::remove( |
701 | + listeners.begin(), |
702 | + listeners.end(), |
703 | + listener), |
704 | + listeners.end()); |
705 | } |
706 | |
707 | void handle_event(MirInputEvent const* event, wl_resource* target) const |
708 | { |
709 | - for (auto& listener : listeners) |
710 | + std::lock_guard<std::mutex> lock{mutex}; |
711 | + for (auto listener : listeners) |
712 | { |
713 | listener->handle_event(event, target); |
714 | } |
715 | @@ -1023,6 +1122,7 @@ |
716 | |
717 | void handle_event(MirWindowEvent const* event, wl_resource* target) const |
718 | { |
719 | + std::lock_guard<std::mutex> lock{mutex}; |
720 | for (auto& listener : listeners) |
721 | { |
722 | listener->handle_event(event, target); |
723 | @@ -1030,7 +1130,8 @@ |
724 | } |
725 | |
726 | private: |
727 | - std::vector<std::shared_ptr<InputInterface>> listeners; |
728 | + std::mutex mutable mutex; |
729 | + std::vector<InputInterface*> listeners; |
730 | }; |
731 | |
732 | class WlSeat |
733 | @@ -1100,32 +1201,49 @@ |
734 | static void get_pointer(wl_client* client, wl_resource* resource, uint32_t id) |
735 | { |
736 | auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource)); |
737 | - me->pointer[client].register_listener( |
738 | - std::make_shared<WlPointer>( |
739 | + auto& input_ctx = me->pointer[client]; |
740 | + input_ctx.register_listener( |
741 | + new WlPointer{ |
742 | client, |
743 | resource, |
744 | id, |
745 | - me->executor)); |
746 | + [&input_ctx](WlPointer* listener) |
747 | + { |
748 | + input_ctx.unregister_listener(listener); |
749 | + }, |
750 | + me->executor}); |
751 | } |
752 | static void get_keyboard(wl_client* client, wl_resource* resource, uint32_t id) |
753 | { |
754 | auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource)); |
755 | - me->keyboard[client].register_listener( |
756 | - std::make_shared<WlKeyboard>( |
757 | + auto& input_ctx = me->keyboard[client]; |
758 | + |
759 | + input_ctx.register_listener( |
760 | + new WlKeyboard{ |
761 | client, |
762 | resource, |
763 | id, |
764 | - me->executor)); |
765 | + [&input_ctx](WlKeyboard* listener) |
766 | + { |
767 | + input_ctx.unregister_listener(listener); |
768 | + }, |
769 | + me->executor}); |
770 | } |
771 | static void get_touch(wl_client* client, wl_resource* resource, uint32_t id) |
772 | { |
773 | auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource)); |
774 | - me->touch[client].register_listener( |
775 | - std::make_shared<WlTouch>( |
776 | + auto& input_ctx = me->touch[client]; |
777 | + |
778 | + input_ctx.register_listener( |
779 | + new WlTouch{ |
780 | client, |
781 | resource, |
782 | id, |
783 | - me->executor)); |
784 | + [&input_ctx](WlTouch* listener) |
785 | + { |
786 | + input_ctx.unregister_listener(listener); |
787 | + }, |
788 | + me->executor}); |
789 | } |
790 | static void release(struct wl_client* /*client*/, struct wl_resource* /*resource*/) {} |
791 | |
792 | @@ -1468,15 +1586,15 @@ |
793 | hide_spec.state = mir_window_state_hidden; |
794 | shell->modify_surface(session, id, hide_spec); |
795 | }); |
796 | - |
797 | - auto shim = new DestructionShim{session, shell, surface_id}; |
798 | - shim->destruction_listener.notify = &cleanup_surface; |
799 | - wl_resource_add_destroy_listener( |
800 | - resource, |
801 | - &shim->destruction_listener); |
802 | - } |
803 | - |
804 | - ~WlShellSurface() override = default; |
805 | + } |
806 | + |
807 | + ~WlShellSurface() override |
808 | + { |
809 | + if (auto session = session_for_client(client)) |
810 | + { |
811 | + shell->destroy_surface(session, surface_id); |
812 | + } |
813 | + } |
814 | protected: |
815 | void pong(uint32_t /*serial*/) override |
816 | { |
817 | @@ -1516,7 +1634,6 @@ |
818 | |
819 | auto const session = session_for_client(client); |
820 | shell->modify_surface(session, surface_id, mods); |
821 | - |
822 | } |
823 | |
824 | void set_popup( |
825 | @@ -1549,38 +1666,6 @@ |
826 | { |
827 | } |
828 | private: |
829 | - struct DestructionShim |
830 | - { |
831 | - DestructionShim( |
832 | - std::shared_ptr<mf::Session> const& session, |
833 | - std::shared_ptr<mf::Shell> const& shell, |
834 | - mf::SurfaceId id) |
835 | - : session{session}, |
836 | - shell{shell}, |
837 | - surface_id{id} |
838 | - { |
839 | - } |
840 | - |
841 | - std::shared_ptr<mf::Session> const session; |
842 | - std::shared_ptr<mf::Shell> const shell; |
843 | - mf::SurfaceId const surface_id; |
844 | - wl_listener destruction_listener; |
845 | - }; |
846 | - |
847 | - static_assert( |
848 | - std::is_standard_layout<DestructionShim>::value, |
849 | - "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour"); |
850 | - |
851 | - static void cleanup_surface(wl_listener* listener, void*) |
852 | - { |
853 | - DestructionShim* shim; |
854 | - shim = wl_container_of(listener, shim, destruction_listener); |
855 | - |
856 | - shim->shell->destroy_surface(shim->session, shim->surface_id); |
857 | - |
858 | - delete shim; |
859 | - } |
860 | - |
861 | std::shared_ptr<mf::Shell> const shell; |
862 | mf::SurfaceId surface_id; |
863 | }; |