comparison dep/animia/src/win/wayland.cc @ 199:9f3534f6b8c4

dep/animia: initial Wayland support, drop non-working kvm fd plugin
author Paper <mrpapersonic@gmail.com>
date Tue, 02 Jan 2024 02:34:27 -0500
parents
children 8a482049b968
comparison
equal deleted inserted replaced
198:bc1ae1810855 199:9f3534f6b8c4
1 #include "animia/win/wayland.h"
2 #include "animia/win.h"
3 #include "animia.h"
4
5 #include <iostream>
6 #include <cstring>
7
8 #include "animia/win/wayland/ext-foreign-toplevel-list-v1.h"
9 #include <wayland-client.h>
10
11 namespace animia::internal::wayland {
12
13 static void noop() {}
14
15 /* ext_foreign_handle stuff */
16 static void ext_foreign_handle_handle_app_id(void* data, struct ext_foreign_toplevel_handle_v1* handle, const char* app_id) {
17 if (app_id)
18 reinterpret_cast<Window*>(data)->class_name = app_id;
19 }
20
21 static void ext_foreign_handle_handle_title(void* data, struct ext_foreign_toplevel_handle_v1* handle, const char* title) {
22 if (title)
23 reinterpret_cast<Window*>(data)->text = title;
24 }
25
26 static void ext_foreign_handle_handle_done(void* data, struct ext_foreign_toplevel_handle_v1* handle) {
27 if (handle)
28 ext_foreign_toplevel_handle_v1_destroy(handle);
29 }
30
31 static void ext_foreign_handle_handle_closed(void*, struct ext_foreign_toplevel_handle_v1*) {}
32 static void ext_foreign_handle_handle_identifier(void*, ext_foreign_toplevel_handle_v1*, const char*) {}
33
34 static const struct ext_foreign_toplevel_handle_v1_listener ext_handle_listener = {
35 .closed = ext_foreign_handle_handle_closed,
36 .done = ext_foreign_handle_handle_done,
37 .title = ext_foreign_handle_handle_title,
38 .app_id = ext_foreign_handle_handle_app_id,
39 .identifier = ext_foreign_handle_handle_identifier // for now
40 };
41
42 static void ext_toplevel_list_handle_toplevel(void* data, struct ext_foreign_toplevel_list_v1* list, struct ext_foreign_toplevel_handle_v1* handle) {
43 std::vector<Window>* windows = reinterpret_cast<std::vector<Window>*>(data);
44 if (!windows)
45 return;
46
47 windows->push_back({0});
48 ext_foreign_toplevel_handle_v1_add_listener(handle, &ext_handle_listener, &*windows->end());
49 }
50
51 static void ext_toplevel_list_handle_finished(void*, ext_foreign_toplevel_list_v1*) {}
52
53 static const struct ext_foreign_toplevel_list_v1_listener ext_toplevel_list_listener = {
54 .toplevel = ext_toplevel_list_handle_toplevel,
55 .finished = ext_toplevel_list_handle_finished
56 };
57
58 /* -- Global data -- */
59 struct global_data {
60 struct ext_foreign_toplevel_list_v1* ext_toplevel_list;
61 std::vector<Window> windows;
62 };
63
64 static void registry_handle_global(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
65 struct global_data* global = reinterpret_cast<struct global_data*>(data);
66
67 if (!std::strcmp(interface, ext_foreign_toplevel_list_v1_interface.name)) {
68 // bind to ext-foreign-toplevel-list-v1
69 global->ext_toplevel_list = reinterpret_cast<struct ext_foreign_toplevel_list_v1*>(wl_registry_bind(registry, name, &ext_foreign_toplevel_list_v1_interface, 1));
70 ext_foreign_toplevel_list_v1_add_listener(global->ext_toplevel_list, &ext_toplevel_list_listener, &global->windows);
71 }
72 }
73
74 static void registry_handle_global_remove(void*, wl_registry*, uint32_t) {}
75
76 static const struct wl_registry_listener registry_listener = {
77 .global = registry_handle_global,
78 .global_remove = registry_handle_global_remove
79 };
80
81 /* BAH! humbug... */
82 struct sync_data {
83 bool loop = true;
84 int sync = 0;
85
86 struct global_data global = {0};
87
88 struct wl_callback* callback = nullptr;
89 struct wl_display* display = nullptr;
90 };
91
92 static void sync_handle_done (void* data, struct wl_callback* callback, uint32_t other_data);
93 static const struct wl_callback_listener sync_callback_listener = {
94 .done = sync_handle_done,
95 };
96
97 static void sync_handle_done (void* data, struct wl_callback* callback, uint32_t other_data) {
98 struct sync_data* sync = reinterpret_cast<struct sync_data*>(data);
99
100 wl_callback_destroy(callback);
101 sync->callback = nullptr;
102
103 if (sync->sync == 0) {
104 if (!sync->global.ext_toplevel_list) {
105 std::cerr << "animia/wayland: Wayland server doesn't support ext-foreign-toplevel-list-v1!" << std::endl;
106 sync->loop = false;
107 return;
108 }
109
110 sync->sync++;
111 sync->callback = wl_display_sync(sync->display);
112 wl_callback_add_listener(sync->callback, &sync_callback_listener, sync);
113
114 /* we may need another sync here if there are protocol extensions for
115 * ext_foreign_toplevel_list.
116 *
117 * more info: https://git.sr.ht/~leon_plickat/lswt/tree/toplevel-info/item/lswt.c
118 */
119 } else {
120 /* we've received everything we need! */
121 sync->loop = false;
122 }
123 }
124
125 /* here comes the actual function we can use */
126 bool EnumerateWindows(window_proc_t window_proc) {
127 struct sync_data sync = {
128 .display = wl_display_connect(NULL)
129 };
130
131 if (!sync.display) {
132 std::cerr << "animia/wayland: Can't connect to display" << std::endl;
133 return false;
134 }
135
136 struct global_data global;
137
138 struct wl_registry* registry = wl_display_get_registry(sync.display);
139 wl_registry_add_listener(registry, &registry_listener, &sync.global);
140
141 sync.callback = wl_display_sync(sync.display);
142 wl_callback_add_listener(sync.callback, &sync_callback_listener, &sync);
143
144 while (sync.loop && wl_display_dispatch(sync.display));
145
146 for (const auto& window : global.windows)
147 if (!window_proc({0}, window))
148 return false;
149
150 wl_display_disconnect(sync.display);
151
152 return true;
153 }
154
155 }