Mercurial > minori
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, ®istry_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 } |
