Mir

Merge lp:~raof/mir/wayland-clients-close-their-sessions-on-quit into lp:mir

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
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.

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 };

Subscribers

People subscribed via source and target branches