Mercurial > minori
view dep/animia/src/win/wayland.cc @ 219:2f6d27fcdf7d
dep/animia: wayland: fixup wlroots code
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Sun, 07 Jan 2024 13:37:50 -0500 |
parents | 8a482049b968 |
children | 53211cb1e7f5 |
line wrap: on
line source
#include "animia/win/wayland.h" #include "animia.h" #include "animia/win.h" #include <cstring> #include <iostream> #include "animia/win/wayland/ext-foreign-toplevel-list-v1.h" #include "animia/win/wayland/wlr-foreign-toplevel-management-unstable-v1.h" #include <wayland-client.h> namespace animia::internal::wayland { /* zwlr-foreign-toplevel-management-v1 implementation */ static void zwlr_foreign_handle_handle_title(void* data, struct zwlr_foreign_toplevel_handle_v1* handle, const char* title) { if (title) reinterpret_cast<Window*>(data)->text = title; } static void zwlr_foreign_handle_handle_app_id(void* data, struct zwlr_foreign_toplevel_handle_v1* handle, const char* app_id) { if (app_id) reinterpret_cast<Window*>(data)->class_name = app_id; } static void zwlr_foreign_handle_handle_done(void* data, struct zwlr_foreign_toplevel_handle_v1* handle) { if (handle) zwlr_foreign_toplevel_handle_v1_destroy(handle); } static void zwlr_foreign_handle_handle_state(void* data, struct zwlr_foreign_toplevel_handle_v1* handle, struct wl_array*) { } static void zwlr_foreign_handle_handle_parent(void* data, struct zwlr_foreign_toplevel_handle_v1* handle, struct zwlr_foreign_toplevel_handle_v1*) { } static void zwlr_foreign_handle_handle_output_enter(void* data, struct zwlr_foreign_toplevel_handle_v1* handle, struct wl_output*) { } static void zwlr_foreign_handle_handle_output_leave(void* data, struct zwlr_foreign_toplevel_handle_v1* handle, struct wl_output*) { } static void zwlr_foreign_handle_handle_closed(void* data, struct zwlr_foreign_toplevel_handle_v1* handle) { } static const struct zwlr_foreign_toplevel_handle_v1_listener zwlr_handle_listener = { .title = zwlr_foreign_handle_handle_title, .app_id = zwlr_foreign_handle_handle_app_id, .output_enter = zwlr_foreign_handle_handle_output_enter, .output_leave = zwlr_foreign_handle_handle_output_leave, .state = zwlr_foreign_handle_handle_state, .done = zwlr_foreign_handle_handle_done, .closed = zwlr_foreign_handle_handle_closed, .parent = zwlr_foreign_handle_handle_parent}; static void zwlr_toplevel_manager_handle_toplevel(void* data, struct zwlr_foreign_toplevel_manager_v1* manager, struct zwlr_foreign_toplevel_handle_v1* handle) { std::vector<Window>* windows = reinterpret_cast<std::vector<Window>*>(data); if (!windows) return; windows->push_back({0}); zwlr_foreign_toplevel_handle_v1_add_listener(handle, &zwlr_handle_listener, &*windows->end()); } static void zwlr_toplevel_manager_handle_finished(void*, struct zwlr_foreign_toplevel_manager_v1*) { } static const struct zwlr_foreign_toplevel_manager_v1_listener zwlr_toplevel_manager_listener = { .toplevel = zwlr_toplevel_manager_handle_toplevel, .finished = zwlr_toplevel_manager_handle_finished, }; /* 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 = nullptr; struct zwlr_foreign_toplevel_manager_v1* zwlr_toplevel_mgr = nullptr; 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)) { if (global->zwlr_toplevel_mgr) return; // we don't need this then 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); } else if (!std::strcmp(interface, zwlr_foreign_toplevel_manager_v1_interface.name)) { if (global->ext_toplevel_list || version < 3) return; // we don't need this then global->zwlr_toplevel_mgr = reinterpret_cast<struct zwlr_foreign_toplevel_manager_v1*>( wl_registry_bind(registry, name, &zwlr_foreign_toplevel_manager_v1_interface, 1)); zwlr_foreign_toplevel_manager_v1_add_listener(global->zwlr_toplevel_mgr, &zwlr_toplevel_manager_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 && !sync->global.zwlr_toplevel_mgr) { std::cerr << "animia/wayland: Wayland server doesn't support ext-foreign-toplevel-list-v1 nor " "wlr-foreign-toplevel-management-unstable-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; } } // namespace animia::internal::wayland