Mercurial > minori
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animia/src/win/wayland.cc Tue Jan 02 02:34:27 2024 -0500 @@ -0,0 +1,155 @@ +#include "animia/win/wayland.h" +#include "animia/win.h" +#include "animia.h" + +#include <iostream> +#include <cstring> + +#include "animia/win/wayland/ext-foreign-toplevel-list-v1.h" +#include <wayland-client.h> + +namespace animia::internal::wayland { + +static void noop() {} + +/* ext_foreign_handle stuff */ +static void ext_foreign_handle_handle_app_id(void* data, struct ext_foreign_toplevel_handle_v1* handle, const char* app_id) { + if (app_id) + reinterpret_cast<Window*>(data)->class_name = app_id; +} + +static void ext_foreign_handle_handle_title(void* data, struct ext_foreign_toplevel_handle_v1* handle, const char* title) { + if (title) + reinterpret_cast<Window*>(data)->text = title; +} + +static void ext_foreign_handle_handle_done(void* data, struct ext_foreign_toplevel_handle_v1* handle) { + if (handle) + ext_foreign_toplevel_handle_v1_destroy(handle); +} + +static void ext_foreign_handle_handle_closed(void*, struct ext_foreign_toplevel_handle_v1*) {} +static void ext_foreign_handle_handle_identifier(void*, ext_foreign_toplevel_handle_v1*, const char*) {} + +static const struct ext_foreign_toplevel_handle_v1_listener ext_handle_listener = { + .closed = ext_foreign_handle_handle_closed, + .done = ext_foreign_handle_handle_done, + .title = ext_foreign_handle_handle_title, + .app_id = ext_foreign_handle_handle_app_id, + .identifier = ext_foreign_handle_handle_identifier // for now +}; + +static void ext_toplevel_list_handle_toplevel(void* data, struct ext_foreign_toplevel_list_v1* list, struct ext_foreign_toplevel_handle_v1* handle) { + std::vector<Window>* windows = reinterpret_cast<std::vector<Window>*>(data); + if (!windows) + return; + + windows->push_back({0}); + ext_foreign_toplevel_handle_v1_add_listener(handle, &ext_handle_listener, &*windows->end()); +} + +static void ext_toplevel_list_handle_finished(void*, ext_foreign_toplevel_list_v1*) {} + +static const struct ext_foreign_toplevel_list_v1_listener ext_toplevel_list_listener = { + .toplevel = ext_toplevel_list_handle_toplevel, + .finished = ext_toplevel_list_handle_finished +}; + +/* -- Global data -- */ +struct global_data { + struct ext_foreign_toplevel_list_v1* ext_toplevel_list; + std::vector<Window> windows; +}; + +static void registry_handle_global(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { + struct global_data* global = reinterpret_cast<struct global_data*>(data); + + if (!std::strcmp(interface, ext_foreign_toplevel_list_v1_interface.name)) { + // bind to ext-foreign-toplevel-list-v1 + global->ext_toplevel_list = reinterpret_cast<struct ext_foreign_toplevel_list_v1*>(wl_registry_bind(registry, name, &ext_foreign_toplevel_list_v1_interface, 1)); + ext_foreign_toplevel_list_v1_add_listener(global->ext_toplevel_list, &ext_toplevel_list_listener, &global->windows); + } +} + +static void registry_handle_global_remove(void*, wl_registry*, uint32_t) {} + +static const struct wl_registry_listener registry_listener = { + .global = registry_handle_global, + .global_remove = registry_handle_global_remove +}; + +/* BAH! humbug... */ +struct sync_data { + bool loop = true; + int sync = 0; + + struct global_data global = {0}; + + struct wl_callback* callback = nullptr; + struct wl_display* display = nullptr; +}; + +static void sync_handle_done (void* data, struct wl_callback* callback, uint32_t other_data); +static const struct wl_callback_listener sync_callback_listener = { + .done = sync_handle_done, +}; + +static void sync_handle_done (void* data, struct wl_callback* callback, uint32_t other_data) { + struct sync_data* sync = reinterpret_cast<struct sync_data*>(data); + + wl_callback_destroy(callback); + sync->callback = nullptr; + + if (sync->sync == 0) { + if (!sync->global.ext_toplevel_list) { + std::cerr << "animia/wayland: Wayland server doesn't support ext-foreign-toplevel-list-v1!" << std::endl; + sync->loop = false; + return; + } + + sync->sync++; + sync->callback = wl_display_sync(sync->display); + wl_callback_add_listener(sync->callback, &sync_callback_listener, sync); + + /* we may need another sync here if there are protocol extensions for + * ext_foreign_toplevel_list. + * + * more info: https://git.sr.ht/~leon_plickat/lswt/tree/toplevel-info/item/lswt.c + */ + } else { + /* we've received everything we need! */ + sync->loop = false; + } +} + +/* here comes the actual function we can use */ +bool EnumerateWindows(window_proc_t window_proc) { + struct sync_data sync = { + .display = wl_display_connect(NULL) + }; + + if (!sync.display) { + std::cerr << "animia/wayland: Can't connect to display" << std::endl; + return false; + } + + struct global_data global; + + struct wl_registry* registry = wl_display_get_registry(sync.display); + wl_registry_add_listener(registry, ®istry_listener, &sync.global); + + sync.callback = wl_display_sync(sync.display); + wl_callback_add_listener(sync.callback, &sync_callback_listener, &sync); + + while (sync.loop && wl_display_dispatch(sync.display)); + + for (const auto& window : global.windows) + if (!window_proc({0}, window)) + return false; + + wl_display_disconnect(sync.display); + + return true; +} + +}