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, &registry_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;
+}
+
+}