Mercurial > minori
view 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 source
#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; } }