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
=== modified file 'debian/control'
--- debian/control 2017-09-13 04:15:28 +0000
+++ debian/control 2017-09-26 15:46:44 +0000
@@ -47,6 +47,7 @@
47 capnproto,47 capnproto,
48 libepoxy-dev,48 libepoxy-dev,
49 python3-pil:native,49 python3-pil:native,
50 linux-libc-dev,
50Standards-Version: 3.9.451Standards-Version: 3.9.4
51Homepage: https://launchpad.net/mir52Homepage: https://launchpad.net/mir
52# If you aren't a member of ~mir-team but need to upload packaging changes,53# If you aren't a member of ~mir-team but need to upload packaging changes,
5354
=== modified file 'src/protocol/wrapper_generator.cpp'
--- src/protocol/wrapper_generator.cpp 2017-09-07 00:32:52 +0000
+++ src/protocol/wrapper_generator.cpp 2017-09-26 15:46:44 +0000
@@ -373,6 +373,16 @@
373373
374 if (!methods.empty())374 if (!methods.empty())
375 {375 {
376 if (!is_global)
377 {
378 emit_indented_lines(out, " ", {
379 {"static void resource_destroyed_thunk(wl_resource* us)"},
380 {"{"},
381 {" delete static_cast<", generated_name, "*>(wl_resource_get_user_data(us));"},
382 {"}"}
383 });
384 }
385
376 emit_indented_lines(out, " ", {386 emit_indented_lines(out, " ", {
377 { "static struct ", wl_name, "_interface const vtable;" }387 { "static struct ", wl_name, "_interface const vtable;" }
378 });388 });
@@ -427,7 +437,7 @@
427 if (has_vtable)437 if (has_vtable)
428 {438 {
429 emit_indented_lines(out, indent + " ",439 emit_indented_lines(out, indent + " ",
430 {{ "wl_resource_set_implementation(resource, &vtable, this, nullptr);" }});440 {{ "wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);" }});
431 }441 }
432 emit_indented_lines(out, indent, {442 emit_indented_lines(out, indent, {
433 { "}" }443 { "}" }
434444
=== modified file 'src/server/frontend/wayland/core_generated_interfaces.h'
--- src/server/frontend/wayland/core_generated_interfaces.h 2017-09-07 00:33:43 +0000
+++ src/server/frontend/wayland/core_generated_interfaces.h 2017-09-26 15:46:44 +0000
@@ -108,7 +108,7 @@
108 wl_resource_post_no_memory(parent);108 wl_resource_post_no_memory(parent);
109 BOOST_THROW_EXCEPTION((std::bad_alloc{}));109 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
110 }110 }
111 wl_resource_set_implementation(resource, &vtable, this, nullptr);111 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
112 }112 }
113 virtual ~ShmPool() = default;113 virtual ~ShmPool() = default;
114114
@@ -138,6 +138,10 @@
138 me->resize(size);138 me->resize(size);
139 }139 }
140140
141 static void resource_destroyed_thunk(wl_resource* us)
142 {
143 delete static_cast<ShmPool*>(wl_resource_get_user_data(us));
144 }
141 static struct wl_shm_pool_interface const vtable;145 static struct wl_shm_pool_interface const vtable;
142};146};
143147
@@ -207,7 +211,7 @@
207 wl_resource_post_no_memory(parent);211 wl_resource_post_no_memory(parent);
208 BOOST_THROW_EXCEPTION((std::bad_alloc{}));212 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
209 }213 }
210 wl_resource_set_implementation(resource, &vtable, this, nullptr);214 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
211 }215 }
212 virtual ~Buffer() = default;216 virtual ~Buffer() = default;
213217
@@ -223,6 +227,10 @@
223 me->destroy();227 me->destroy();
224 }228 }
225229
230 static void resource_destroyed_thunk(wl_resource* us)
231 {
232 delete static_cast<Buffer*>(wl_resource_get_user_data(us));
233 }
226 static struct wl_buffer_interface const vtable;234 static struct wl_buffer_interface const vtable;
227};235};
228236
@@ -243,7 +251,7 @@
243 wl_resource_post_no_memory(parent);251 wl_resource_post_no_memory(parent);
244 BOOST_THROW_EXCEPTION((std::bad_alloc{}));252 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
245 }253 }
246 wl_resource_set_implementation(resource, &vtable, this, nullptr);254 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
247 }255 }
248 virtual ~DataOffer() = default;256 virtual ~DataOffer() = default;
249257
@@ -293,6 +301,10 @@
293 me->set_actions(dnd_actions, preferred_action);301 me->set_actions(dnd_actions, preferred_action);
294 }302 }
295303
304 static void resource_destroyed_thunk(wl_resource* us)
305 {
306 delete static_cast<DataOffer*>(wl_resource_get_user_data(us));
307 }
296 static struct wl_data_offer_interface const vtable;308 static struct wl_data_offer_interface const vtable;
297};309};
298310
@@ -317,7 +329,7 @@
317 wl_resource_post_no_memory(parent);329 wl_resource_post_no_memory(parent);
318 BOOST_THROW_EXCEPTION((std::bad_alloc{}));330 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
319 }331 }
320 wl_resource_set_implementation(resource, &vtable, this, nullptr);332 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
321 }333 }
322 virtual ~DataSource() = default;334 virtual ~DataSource() = default;
323335
@@ -347,6 +359,10 @@
347 me->set_actions(dnd_actions);359 me->set_actions(dnd_actions);
348 }360 }
349361
362 static void resource_destroyed_thunk(wl_resource* us)
363 {
364 delete static_cast<DataSource*>(wl_resource_get_user_data(us));
365 }
350 static struct wl_data_source_interface const vtable;366 static struct wl_data_source_interface const vtable;
351};367};
352368
@@ -369,7 +385,7 @@
369 wl_resource_post_no_memory(parent);385 wl_resource_post_no_memory(parent);
370 BOOST_THROW_EXCEPTION((std::bad_alloc{}));386 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
371 }387 }
372 wl_resource_set_implementation(resource, &vtable, this, nullptr);388 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
373 }389 }
374 virtual ~DataDevice() = default;390 virtual ~DataDevice() = default;
375391
@@ -414,6 +430,10 @@
414 me->release();430 me->release();
415 }431 }
416432
433 static void resource_destroyed_thunk(wl_resource* us)
434 {
435 delete static_cast<DataDevice*>(wl_resource_get_user_data(us));
436 }
417 static struct wl_data_device_interface const vtable;437 static struct wl_data_device_interface const vtable;
418};438};
419439
@@ -536,7 +556,7 @@
536 wl_resource_post_no_memory(parent);556 wl_resource_post_no_memory(parent);
537 BOOST_THROW_EXCEPTION((std::bad_alloc{}));557 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
538 }558 }
539 wl_resource_set_implementation(resource, &vtable, this, nullptr);559 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
540 }560 }
541 virtual ~ShellSurface() = default;561 virtual ~ShellSurface() = default;
542562
@@ -625,6 +645,10 @@
625 me->set_class(class_);645 me->set_class(class_);
626 }646 }
627647
648 static void resource_destroyed_thunk(wl_resource* us)
649 {
650 delete static_cast<ShellSurface*>(wl_resource_get_user_data(us));
651 }
628 static struct wl_shell_surface_interface const vtable;652 static struct wl_shell_surface_interface const vtable;
629};653};
630654
@@ -654,7 +678,7 @@
654 wl_resource_post_no_memory(parent);678 wl_resource_post_no_memory(parent);
655 BOOST_THROW_EXCEPTION((std::bad_alloc{}));679 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
656 }680 }
657 wl_resource_set_implementation(resource, &vtable, this, nullptr);681 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
658 }682 }
659 virtual ~Surface() = default;683 virtual ~Surface() = default;
660684
@@ -748,6 +772,10 @@
748 me->damage_buffer(x, y, width, height);772 me->damage_buffer(x, y, width, height);
749 }773 }
750774
775 static void resource_destroyed_thunk(wl_resource* us)
776 {
777 delete static_cast<Surface*>(wl_resource_get_user_data(us));
778 }
751 static struct wl_surface_interface const vtable;779 static struct wl_surface_interface const vtable;
752};780};
753781
@@ -847,7 +875,7 @@
847 wl_resource_post_no_memory(parent);875 wl_resource_post_no_memory(parent);
848 BOOST_THROW_EXCEPTION((std::bad_alloc{}));876 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
849 }877 }
850 wl_resource_set_implementation(resource, &vtable, this, nullptr);878 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
851 }879 }
852 virtual ~Pointer() = default;880 virtual ~Pointer() = default;
853881
@@ -875,6 +903,10 @@
875 me->release();903 me->release();
876 }904 }
877905
906 static void resource_destroyed_thunk(wl_resource* us)
907 {
908 delete static_cast<Pointer*>(wl_resource_get_user_data(us));
909 }
878 static struct wl_pointer_interface const vtable;910 static struct wl_pointer_interface const vtable;
879};911};
880912
@@ -896,7 +928,7 @@
896 wl_resource_post_no_memory(parent);928 wl_resource_post_no_memory(parent);
897 BOOST_THROW_EXCEPTION((std::bad_alloc{}));929 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
898 }930 }
899 wl_resource_set_implementation(resource, &vtable, this, nullptr);931 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
900 }932 }
901 virtual ~Keyboard() = default;933 virtual ~Keyboard() = default;
902934
@@ -912,6 +944,10 @@
912 me->release();944 me->release();
913 }945 }
914946
947 static void resource_destroyed_thunk(wl_resource* us)
948 {
949 delete static_cast<Keyboard*>(wl_resource_get_user_data(us));
950 }
915 static struct wl_keyboard_interface const vtable;951 static struct wl_keyboard_interface const vtable;
916};952};
917953
@@ -932,7 +968,7 @@
932 wl_resource_post_no_memory(parent);968 wl_resource_post_no_memory(parent);
933 BOOST_THROW_EXCEPTION((std::bad_alloc{}));969 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
934 }970 }
935 wl_resource_set_implementation(resource, &vtable, this, nullptr);971 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
936 }972 }
937 virtual ~Touch() = default;973 virtual ~Touch() = default;
938974
@@ -948,6 +984,10 @@
948 me->release();984 me->release();
949 }985 }
950986
987 static void resource_destroyed_thunk(wl_resource* us)
988 {
989 delete static_cast<Touch*>(wl_resource_get_user_data(us));
990 }
951 static struct wl_touch_interface const vtable;991 static struct wl_touch_interface const vtable;
952};992};
953993
@@ -1014,7 +1054,7 @@
1014 wl_resource_post_no_memory(parent);1054 wl_resource_post_no_memory(parent);
1015 BOOST_THROW_EXCEPTION((std::bad_alloc{}));1055 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1016 }1056 }
1017 wl_resource_set_implementation(resource, &vtable, this, nullptr);1057 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
1018 }1058 }
1019 virtual ~Region() = default;1059 virtual ~Region() = default;
10201060
@@ -1044,6 +1084,10 @@
1044 me->subtract(x, y, width, height);1084 me->subtract(x, y, width, height);
1045 }1085 }
10461086
1087 static void resource_destroyed_thunk(wl_resource* us)
1088 {
1089 delete static_cast<Region*>(wl_resource_get_user_data(us));
1090 }
1047 static struct wl_region_interface const vtable;1091 static struct wl_region_interface const vtable;
1048};1092};
10491093
@@ -1120,7 +1164,7 @@
1120 wl_resource_post_no_memory(parent);1164 wl_resource_post_no_memory(parent);
1121 BOOST_THROW_EXCEPTION((std::bad_alloc{}));1165 BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1122 }1166 }
1123 wl_resource_set_implementation(resource, &vtable, this, nullptr);1167 wl_resource_set_implementation(resource, &vtable, this, &resource_destroyed_thunk);
1124 }1168 }
1125 virtual ~Subsurface() = default;1169 virtual ~Subsurface() = default;
11261170
@@ -1171,6 +1215,10 @@
1171 me->set_desync();1215 me->set_desync();
1172 }1216 }
11731217
1218 static void resource_destroyed_thunk(wl_resource* us)
1219 {
1220 delete static_cast<Subsurface*>(wl_resource_get_user_data(us));
1221 }
1174 static struct wl_subsurface_interface const vtable;1222 static struct wl_subsurface_interface const vtable;
1175};1223};
11761224
11771225
=== modified file 'src/server/frontend/wayland/wayland_connector.cpp'
--- src/server/frontend/wayland/wayland_connector.cpp 2017-09-25 18:12:01 +0000
+++ src/server/frontend/wayland/wayland_connector.cpp 2017-09-26 15:46:44 +0000
@@ -41,6 +41,8 @@
4141
42#include "mir/executor.h"42#include "mir/executor.h"
4343
44#include "mir/client/event.h"
45
44#include <system_error>46#include <system_error>
45#include <sys/eventfd.h>47#include <sys/eventfd.h>
46#include <wayland-server-core.h>48#include <wayland-server-core.h>
@@ -51,6 +53,7 @@
51#include <functional>53#include <functional>
52#include <type_traits>54#include <type_traits>
5355
56#include <linux/input.h>
54#include <algorithm>57#include <algorithm>
55#include <iostream>58#include <iostream>
56#include <mir/log.h>59#include <mir/log.h>
@@ -69,6 +72,7 @@
69namespace mc = mir::compositor;72namespace mc = mir::compositor;
70namespace ms = mir::scene;73namespace ms = mir::scene;
71namespace geom = mir::geometry;74namespace geom = mir::geometry;
75namespace mcl = mir::client;
7276
73namespace mir77namespace mir
74{78{
@@ -154,8 +158,29 @@
154158
155struct ClientPrivate159struct ClientPrivate
156{160{
161 ClientPrivate(std::shared_ptr<mf::Session> const& session, mf::Shell& shell)
162 : session{session},
163 shell{&shell}
164 {
165 }
166
167 ~ClientPrivate()
168 {
169 shell->close_session(session);
170 /*
171 * This ensures that further calls to
172 * wl_client_get_destroy_listener(client, &cleanup_private)
173 * - and hence session_for_client(client) - return nullptr.
174 */
175 wl_list_remove(&destroy_listener.link);
176 }
177
157 wl_listener destroy_listener;178 wl_listener destroy_listener;
158 std::shared_ptr<mf::Session> session;179 std::shared_ptr<mf::Session> const session;
180 /*
181 * This shell is owned by the ClientSessionConstructor, which outlives all clients.
182 */
183 mf::Shell* const shell;
159};184};
160185
161static_assert(186static_assert(
@@ -178,9 +203,10 @@
178{203{
179 auto listener = wl_client_get_destroy_listener(client, &cleanup_private);204 auto listener = wl_client_get_destroy_listener(client, &cleanup_private);
180205
181 assert(listener && "Client session requested for malformed client");206 if (listener)
207 return private_from_listener(listener)->session;
182208
183 return private_from_listener(listener)->session;209 return nullptr;
184}210}
185211
186struct ClientSessionConstructor212struct ClientSessionConstructor
@@ -216,9 +242,8 @@
216 "",242 "",
217 std::make_shared<WaylandEventSink>([](auto){}));243 std::make_shared<WaylandEventSink>([](auto){}));
218244
219 auto client_context = new ClientPrivate;245 auto client_context = new ClientPrivate{session, *construction_context->shell};
220 client_context->destroy_listener.notify = &cleanup_private;246 client_context->destroy_listener.notify = &cleanup_private;
221 client_context->session = session;
222 wl_client_add_destroy_listener(client, &client_context->destroy_listener);247 wl_client_add_destroy_listener(client, &client_context->destroy_listener);
223}248}
224249
@@ -291,6 +316,19 @@
291316
292 return buffer;317 return buffer;
293}318}
319
320template<typename Callable>
321auto run_unless(std::shared_ptr<bool> const& condition, Callable&& callable)
322{
323 return
324 [callable = std::move(callable), condition]()
325 {
326 if (*condition)
327 return;
328
329 callable();
330 };
331}
294}332}
295333
296class WlShmBuffer :334class WlShmBuffer :
@@ -507,7 +545,8 @@
507 allocator{allocator},545 allocator{allocator},
508 executor{executor},546 executor{executor},
509 pending_buffer{nullptr},547 pending_buffer{nullptr},
510 pending_frames{std::make_shared<std::vector<wl_resource*>>()}548 pending_frames{std::make_shared<std::vector<wl_resource*>>()},
549 destroyed{std::make_shared<bool>(false)}
511 {550 {
512 auto session = session_for_client(client);551 auto session = session_for_client(client);
513 mg::BufferProperties const props{552 mg::BufferProperties const props{
@@ -523,6 +562,13 @@
523 stream->allow_framedropping(true);562 stream->allow_framedropping(true);
524 }563 }
525564
565 ~WlSurface()
566 {
567 *destroyed = true;
568 if (auto session = session_for_client(client))
569 session->destroy_buffer_stream(stream_id);
570 }
571
526 void set_resize_handler(std::function<void(geom::Size)> const& handler)572 void set_resize_handler(std::function<void(geom::Size)> const& handler)
527 {573 {
528 resize_handler = handler;574 resize_handler = handler;
@@ -544,6 +590,7 @@
544590
545 wl_resource* pending_buffer;591 wl_resource* pending_buffer;
546 std::shared_ptr<std::vector<wl_resource*>> const pending_frames;592 std::shared_ptr<std::vector<wl_resource*>> const pending_frames;
593 std::shared_ptr<bool> const destroyed;
547594
548 void destroy();595 void destroy();
549 void attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y);596 void attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y);
@@ -559,7 +606,7 @@
559606
560void WlSurface::destroy()607void WlSurface::destroy()
561{608{
562 delete this;609 wl_resource_destroy(resource);
563}610}
564611
565void WlSurface::attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y)612void WlSurface::attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y)
@@ -616,9 +663,10 @@
616 std::shared_ptr<mg::Buffer> mir_buffer;663 std::shared_ptr<mg::Buffer> mir_buffer;
617 auto shm_buffer = wl_shm_buffer_get(pending_buffer);664 auto shm_buffer = wl_shm_buffer_get(pending_buffer);
618 auto send_frame_notifications =665 auto send_frame_notifications =
619 [executor = executor, frames = pending_frames]()666 [executor = executor, frames = pending_frames, destroyed = destroyed]()
620 {667 {
621 executor->spawn(668 executor->spawn(run_unless(
669 destroyed,
622 [frames]()670 [frames]()
623 {671 {
624 /*672 /*
@@ -635,7 +683,7 @@
635 wl_resource_destroy(frame);683 wl_resource_destroy(frame);
636 }684 }
637 frames->clear();685 frames->clear();
638 });686 }));
639 };687 };
640688
641 if (shm_buffer)689 if (shm_buffer)
@@ -748,16 +796,29 @@
748 wl_client* client,796 wl_client* client,
749 wl_resource* parent,797 wl_resource* parent,
750 uint32_t id,798 uint32_t id,
799 std::function<void(WlKeyboard*)> const& on_destroy,
751 std::shared_ptr<mir::Executor> const& executor)800 std::shared_ptr<mir::Executor> const& executor)
752 : Keyboard(client, parent, id),801 : Keyboard(client, parent, id),
753 executor{executor}802 executor{executor},
754 {803 on_destroy{on_destroy},
804 destroyed{std::make_shared<bool>(false)}
805 {
806 }
807
808 ~WlKeyboard()
809 {
810 on_destroy(this);
811 *destroyed = true;
755 }812 }
756813
757 void handle_event(MirInputEvent const* event, wl_resource* /*target*/)814 void handle_event(MirInputEvent const* event, wl_resource* /*target*/)
758 {815 {
759 executor->spawn(816 executor->spawn(run_unless(
760 [ev = mir_event_ref(mir_input_event_get_event(event)), this] ()817 destroyed,
818 [
819 ev = mcl::Event{mir_event_ref(mir_input_event_get_event(event))},
820 this
821 ] ()
761 {822 {
762 int const serial = wl_display_next_serial(wl_client_get_display(client));823 int const serial = wl_display_next_serial(wl_client_get_display(client));
763 auto event = mir_event_get_input_event(ev);824 auto event = mir_event_get_input_event(ev);
@@ -782,18 +843,22 @@
782 default:843 default:
783 break;844 break;
784 }845 }
785 mir_event_unref(ev);846 }));
786 });
787 }847 }
788848
789 void handle_event(MirWindowEvent const* event, wl_resource* target)849 void handle_event(MirWindowEvent const* event, wl_resource* target)
790 {850 {
791 if (mir_window_event_get_attribute(event) == mir_window_attrib_focus)851 if (mir_window_event_get_attribute(event) == mir_window_attrib_focus)
792 {852 {
793 executor->spawn(853 executor->spawn(run_unless(
794 [resource = resource, serial = wl_display_next_serial(wl_client_get_display(client)),854 destroyed,
795 target = target, focussed = mir_window_event_get_attribute_value(event)]()855 [
856 target = target,
857 focussed = mir_window_event_get_attribute_value(event),
858 this
859 ]()
796 {860 {
861 auto const serial = wl_display_next_serial(wl_client_get_display(client));
797 if (focussed)862 if (focussed)
798 {863 {
799 wl_array key_state;864 wl_array key_state;
@@ -805,18 +870,21 @@
805 {870 {
806 wl_keyboard_send_leave(resource, serial, target);871 wl_keyboard_send_leave(resource, serial, target);
807 }872 }
808 });873 }));
809 }874 }
810 }875 }
811876
812private:877private:
813 std::shared_ptr<mir::Executor> const executor;878 std::shared_ptr<mir::Executor> const executor;
879 std::function<void(WlKeyboard*)> on_destroy;
880 std::shared_ptr<bool> const destroyed;
814881
815 void release() override;882 void release() override;
816};883};
817884
818void WlKeyboard::release()885void WlKeyboard::release()
819{886{
887 wl_resource_destroy(resource);
820}888}
821889
822class WlPointer : public wayland::Pointer890class WlPointer : public wayland::Pointer
@@ -827,17 +895,27 @@
827 wl_client* client,895 wl_client* client,
828 wl_resource* parent,896 wl_resource* parent,
829 uint32_t id,897 uint32_t id,
898 std::function<void(WlPointer*)> const& on_destroy,
830 std::shared_ptr<mir::Executor> const& executor)899 std::shared_ptr<mir::Executor> const& executor)
831 : Pointer(client, parent, id),900 : Pointer(client, parent, id),
832 display{wl_client_get_display(client)},901 display{wl_client_get_display(client)},
833 executor{executor}902 executor{executor},
834 {903 on_destroy{on_destroy},
904 destroyed{std::make_shared<bool>(false)}
905 {
906 }
907
908 ~WlPointer()
909 {
910 on_destroy(this);
911 *destroyed = true;
835 }912 }
836913
837 void handle_event(MirInputEvent const* event, wl_resource* target)914 void handle_event(MirInputEvent const* event, wl_resource* target)
838 {915 {
839 executor->spawn(916 executor->spawn(run_unless(
840 [ev = mir_event_ref(mir_input_event_get_event(event)), target, this]()917 destroyed,
918 [ev = mcl::Event{mir_input_event_get_event(event)}, target, this]()
841 {919 {
842 auto const serial = wl_display_next_serial(display);920 auto const serial = wl_display_next_serial(display);
843 auto const event = mir_event_get_input_event(ev);921 auto const event = mir_event_get_input_event(ev);
@@ -851,25 +929,27 @@
851 auto const current_set = mir_pointer_event_buttons(pointer_event);929 auto const current_set = mir_pointer_event_buttons(pointer_event);
852 auto const current_time = mir_input_event_get_event_time(event) / 1000;930 auto const current_time = mir_input_event_get_event_time(event) / 1000;
853931
854 auto button = 272; // No, I have *no* idea why GTK expects 272 to be the primary button.932 std::unordered_map<MirPointerButton, int> const button_mappings = {
855 // NB button is incremented in the loop and the order mir_pointer_button_XXX matters933 {mir_pointer_button_primary, BTN_LEFT},
856 for (auto mir_button :934 {mir_pointer_button_secondary, BTN_RIGHT},
857 {mir_pointer_button_primary, // 272935 {mir_pointer_button_tertiary, BTN_MIDDLE},
858 mir_pointer_button_tertiary, // 273936 {mir_pointer_button_back, BTN_BACK},
859 mir_pointer_button_secondary, // 274937 {mir_pointer_button_forward, BTN_FORWARD},
860 mir_pointer_button_back, // 275938 {mir_pointer_button_side, BTN_SIDE},
861 mir_pointer_button_forward}) // 276939 {mir_pointer_button_task, BTN_TASK},
940 {mir_pointer_button_extra, BTN_EXTRA}
941 };
942
943 for (auto mapping : button_mappings)
862 {944 {
863 if (mir_button & (current_set ^ last_set))945 if (mapping.first & (current_set ^ last_set))
864 {946 {
865 auto const action = (mir_button & current_set) ?947 auto const action = (mapping.first & current_set) ?
866 WL_POINTER_BUTTON_STATE_PRESSED :948 WL_POINTER_BUTTON_STATE_PRESSED :
867 WL_POINTER_BUTTON_STATE_RELEASED;949 WL_POINTER_BUTTON_STATE_RELEASED;
868950
869 wl_pointer_send_button(resource, serial, current_time, button, action);951 wl_pointer_send_button(resource, serial, current_time, mapping.second, action);
870 }952 }
871
872 ++button;
873 }953 }
874954
875 last_set = current_set;955 last_set = current_set;
@@ -934,7 +1014,7 @@
934 case mir_pointer_actions:1014 case mir_pointer_actions:
935 break;1015 break;
936 }1016 }
937 });1017 }));
938 }1018 }
9391019
940 // Pointer interface1020 // Pointer interface
@@ -942,6 +1022,9 @@
942 wl_display* const display;1022 wl_display* const display;
943 std::shared_ptr<mir::Executor> const executor;1023 std::shared_ptr<mir::Executor> const executor;
9441024
1025 std::function<void(WlPointer*)> on_destroy;
1026 std::shared_ptr<bool> const destroyed;
1027
945 MirPointerButtons last_set{0};1028 MirPointerButtons last_set{0};
946 float last_x, last_y, last_vscroll, last_hscroll;1029 float last_x, last_y, last_vscroll, last_hscroll;
9471030
@@ -959,7 +1042,7 @@
9591042
960void WlPointer::release()1043void WlPointer::release()
961{1044{
962 delete this;1045 wl_resource_destroy(resource);
963}1046}
9641047
965class WlTouch : public wayland::Touch1048class WlTouch : public wayland::Touch
@@ -969,9 +1052,18 @@
969 wl_client* client,1052 wl_client* client,
970 wl_resource* parent,1053 wl_resource* parent,
971 uint32_t id,1054 uint32_t id,
972 std::shared_ptr<mir::Executor> const& /*executor*/)1055 std::function<void(WlTouch*)> const& on_destroy,
973 : Touch(client, parent, id)1056 std::shared_ptr<mir::Executor> const& executor)
974 {1057 : Touch(client, parent, id),
1058 executor{executor},
1059 on_destroy{on_destroy}
1060 {
1061 }
1062
1063 ~WlTouch()
1064 {
1065 on_destroy(this);
1066 *destroyed = true;
975 }1067 }
9761068
977 void handle_event(MirInputEvent const* /*event*/, wl_resource* /*target*/)1069 void handle_event(MirInputEvent const* /*event*/, wl_resource* /*target*/)
@@ -980,11 +1072,16 @@
9801072
981 // Touch interface1073 // Touch interface
982private:1074private:
1075 std::shared_ptr<mir::Executor> const executor;
1076 std::function<void(WlTouch*)> on_destroy;
1077 std::shared_ptr<bool> const destroyed;
1078
983 void release() override;1079 void release() override;
984};1080};
9851081
986void WlTouch::release()1082void WlTouch::release()
987{1083{
1084 wl_resource_destroy(resource);
988}1085}
9891086
990template<class InputInterface>1087template<class InputInterface>
@@ -997,25 +1094,27 @@
997 InputCtx(InputCtx const&) = delete;1094 InputCtx(InputCtx const&) = delete;
998 InputCtx& operator=(InputCtx const&) = delete;1095 InputCtx& operator=(InputCtx const&) = delete;
9991096
1000 void register_listener(std::shared_ptr<InputInterface> const& listener)1097 void register_listener(InputInterface* listener)
1001 {1098 {
1099 std::lock_guard<std::mutex> lock{mutex};
1002 listeners.push_back(listener);1100 listeners.push_back(listener);
1003 }1101 }
10041102
1005 void unregister_listener(InputInterface const* listener)1103 void unregister_listener(InputInterface const* listener)
1006 {1104 {
1007 std::remove_if(1105 std::lock_guard<std::mutex> lock{mutex};
1008 listeners.begin(),1106 listeners.erase(
1009 listeners.end(),1107 std::remove(
1010 [listener](auto candidate)1108 listeners.begin(),
1011 {1109 listeners.end(),
1012 return candidate.get() == listener;1110 listener),
1013 });1111 listeners.end());
1014 }1112 }
10151113
1016 void handle_event(MirInputEvent const* event, wl_resource* target) const1114 void handle_event(MirInputEvent const* event, wl_resource* target) const
1017 {1115 {
1018 for (auto& listener : listeners)1116 std::lock_guard<std::mutex> lock{mutex};
1117 for (auto listener : listeners)
1019 {1118 {
1020 listener->handle_event(event, target);1119 listener->handle_event(event, target);
1021 }1120 }
@@ -1023,6 +1122,7 @@
10231122
1024 void handle_event(MirWindowEvent const* event, wl_resource* target) const1123 void handle_event(MirWindowEvent const* event, wl_resource* target) const
1025 {1124 {
1125 std::lock_guard<std::mutex> lock{mutex};
1026 for (auto& listener : listeners)1126 for (auto& listener : listeners)
1027 {1127 {
1028 listener->handle_event(event, target);1128 listener->handle_event(event, target);
@@ -1030,7 +1130,8 @@
1030 }1130 }
10311131
1032private:1132private:
1033 std::vector<std::shared_ptr<InputInterface>> listeners;1133 std::mutex mutable mutex;
1134 std::vector<InputInterface*> listeners;
1034};1135};
10351136
1036class WlSeat1137class WlSeat
@@ -1100,32 +1201,49 @@
1100 static void get_pointer(wl_client* client, wl_resource* resource, uint32_t id)1201 static void get_pointer(wl_client* client, wl_resource* resource, uint32_t id)
1101 {1202 {
1102 auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));1203 auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));
1103 me->pointer[client].register_listener(1204 auto& input_ctx = me->pointer[client];
1104 std::make_shared<WlPointer>(1205 input_ctx.register_listener(
1206 new WlPointer{
1105 client,1207 client,
1106 resource,1208 resource,
1107 id,1209 id,
1108 me->executor));1210 [&input_ctx](WlPointer* listener)
1211 {
1212 input_ctx.unregister_listener(listener);
1213 },
1214 me->executor});
1109 }1215 }
1110 static void get_keyboard(wl_client* client, wl_resource* resource, uint32_t id)1216 static void get_keyboard(wl_client* client, wl_resource* resource, uint32_t id)
1111 {1217 {
1112 auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));1218 auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));
1113 me->keyboard[client].register_listener(1219 auto& input_ctx = me->keyboard[client];
1114 std::make_shared<WlKeyboard>(1220
1221 input_ctx.register_listener(
1222 new WlKeyboard{
1115 client,1223 client,
1116 resource,1224 resource,
1117 id,1225 id,
1118 me->executor));1226 [&input_ctx](WlKeyboard* listener)
1227 {
1228 input_ctx.unregister_listener(listener);
1229 },
1230 me->executor});
1119 }1231 }
1120 static void get_touch(wl_client* client, wl_resource* resource, uint32_t id)1232 static void get_touch(wl_client* client, wl_resource* resource, uint32_t id)
1121 {1233 {
1122 auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));1234 auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));
1123 me->touch[client].register_listener(1235 auto& input_ctx = me->touch[client];
1124 std::make_shared<WlTouch>(1236
1237 input_ctx.register_listener(
1238 new WlTouch{
1125 client,1239 client,
1126 resource,1240 resource,
1127 id,1241 id,
1128 me->executor));1242 [&input_ctx](WlTouch* listener)
1243 {
1244 input_ctx.unregister_listener(listener);
1245 },
1246 me->executor});
1129 }1247 }
1130 static void release(struct wl_client* /*client*/, struct wl_resource* /*resource*/) {}1248 static void release(struct wl_client* /*client*/, struct wl_resource* /*resource*/) {}
11311249
@@ -1468,15 +1586,15 @@
1468 hide_spec.state = mir_window_state_hidden;1586 hide_spec.state = mir_window_state_hidden;
1469 shell->modify_surface(session, id, hide_spec);1587 shell->modify_surface(session, id, hide_spec);
1470 });1588 });
14711589 }
1472 auto shim = new DestructionShim{session, shell, surface_id};1590
1473 shim->destruction_listener.notify = &cleanup_surface;1591 ~WlShellSurface() override
1474 wl_resource_add_destroy_listener(1592 {
1475 resource,1593 if (auto session = session_for_client(client))
1476 &shim->destruction_listener);1594 {
1477 }1595 shell->destroy_surface(session, surface_id);
14781596 }
1479 ~WlShellSurface() override = default;1597 }
1480protected:1598protected:
1481 void pong(uint32_t /*serial*/) override1599 void pong(uint32_t /*serial*/) override
1482 {1600 {
@@ -1516,7 +1634,6 @@
15161634
1517 auto const session = session_for_client(client);1635 auto const session = session_for_client(client);
1518 shell->modify_surface(session, surface_id, mods);1636 shell->modify_surface(session, surface_id, mods);
1519
1520 }1637 }
15211638
1522 void set_popup(1639 void set_popup(
@@ -1549,38 +1666,6 @@
1549 {1666 {
1550 }1667 }
1551private:1668private:
1552 struct DestructionShim
1553 {
1554 DestructionShim(
1555 std::shared_ptr<mf::Session> const& session,
1556 std::shared_ptr<mf::Shell> const& shell,
1557 mf::SurfaceId id)
1558 : session{session},
1559 shell{shell},
1560 surface_id{id}
1561 {
1562 }
1563
1564 std::shared_ptr<mf::Session> const session;
1565 std::shared_ptr<mf::Shell> const shell;
1566 mf::SurfaceId const surface_id;
1567 wl_listener destruction_listener;
1568 };
1569
1570 static_assert(
1571 std::is_standard_layout<DestructionShim>::value,
1572 "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour");
1573
1574 static void cleanup_surface(wl_listener* listener, void*)
1575 {
1576 DestructionShim* shim;
1577 shim = wl_container_of(listener, shim, destruction_listener);
1578
1579 shim->shell->destroy_surface(shim->session, shim->surface_id);
1580
1581 delete shim;
1582 }
1583
1584 std::shared_ptr<mf::Shell> const shell;1669 std::shared_ptr<mf::Shell> const shell;
1585 mf::SurfaceId surface_id;1670 mf::SurfaceId surface_id;
1586};1671};

Subscribers

People subscribed via source and target branches