changeset 216:8a482049b968

dep/animia: win/wayland: add UNTESTED support for wlroots protocols
author Paper <mrpapersonic@gmail.com>
date Sun, 07 Jan 2024 12:42:10 -0500
parents 031a257ee019
children 47ddd6b638e3
files dep/animia/.clang-format dep/animia/CMakeLists.txt dep/animia/README.md dep/animia/src/win/wayland.cc
diffstat 4 files changed, 129 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/dep/animia/.clang-format	Sun Jan 07 11:44:40 2024 -0500
+++ b/dep/animia/.clang-format	Sun Jan 07 12:42:10 2024 -0500
@@ -5,10 +5,8 @@
 ColumnLimit: 120
 IndentWidth: 4
 TabWidth: 4
-AccessModifierOffset: 4
 
 IndentCaseLabels: true
-IndentAccessModifiers: true
 IndentPPDirectives: AfterHash
 
 BreakBeforeBraces: Attach
--- a/dep/animia/CMakeLists.txt	Sun Jan 07 11:44:40 2024 -0500
+++ b/dep/animia/CMakeLists.txt	Sun Jan 07 12:42:10 2024 -0500
@@ -138,6 +138,7 @@
 			list(APPEND SRC_FILES
 				src/win/wayland.cc
 				src/win/wayland/ext-foreign-toplevel-list-v1.c
+				src/win/wayland/wlr-foreign-toplevel-management-unstable-v1.c
 			)
 			list(APPEND INCLUDE_DIRS ${WAYLAND_INCLUDE_DIRS})
 			list(APPEND LIBRARIES ${WAYLAND_LINK_LIBRARIES})
--- a/dep/animia/README.md	Sun Jan 07 11:44:40 2024 -0500
+++ b/dep/animia/README.md	Sun Jan 07 12:42:10 2024 -0500
@@ -8,7 +8,8 @@
 ## Support
 Animia supports Windows, macOS, and Linux when dealing with file descriptors.
 When enumerating windows, it supports Windows, macOS (Quartz), X11, and
-Wayland (only via the `ext_foreign_toplevel_handle_v1` interface).
+Wayland (only via the `ext_foreign_toplevel_handle_v1` and
+`wlr_foreign_toplevel_management_unstable_v1` interfaces).
 
 Unlike Anisthesia, Animia currently does not support UI automation, i.e., most
 web browsers will not work properly, if at all.
@@ -36,8 +37,7 @@
 [unreliable](https://stackoverflow.com/a/49970271).
 
 ### Wayland
-Only Wayland servers that implement the `ext_foreign_toplevel_handle_v1`
-interface will work with Animia. As of 2 January 2024, this means there are no
-server implementations that will work. **However**, it is possible to implement
-support for the wlroots-specific `wlr_foreign_toplevel_management_unstable_v1`
-protocol, which will at least give support to window managers based off of it.
+Only Wayland servers that implement the `ext_foreign_toplevel_handle_v1` or
+`wlr_foreign_toplevel_management_unstable_v1` interfaces will work with Animia.
+Currently, both Sway and Mir support the latter. Maybe some day we'll have
+major compositor support for `ext_foreign_toplevel_handle_v1`.
--- a/dep/animia/src/win/wayland.cc	Sun Jan 07 11:44:40 2024 -0500
+++ b/dep/animia/src/win/wayland.cc	Sun Jan 07 12:42:10 2024 -0500
@@ -1,24 +1,90 @@
 #include "animia/win/wayland.h"
-#include "animia/win.h"
 #include "animia.h"
+#include "animia/win.h"
 
+#include <cstring>
 #include <iostream>
-#include <cstring>
 
 #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 {
 
-static void noop() {}
+/* 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;
+}
 
-/* 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) {
+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 ext_foreign_handle_handle_title(void* data, struct ext_foreign_toplevel_handle_v1* handle, const char* title) {
+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;
 }
@@ -28,18 +94,22 @@
 		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 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
+    .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) {
+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;
@@ -48,35 +118,49 @@
 	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 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
-};
+    .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;
+	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) {
+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);
+		if (!global->zwlr_toplevel_mgr || version < 3)
+			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)
+			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 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
-};
+static const struct wl_registry_listener registry_listener = {.global = registry_handle_global,
+                                                              .global_remove = registry_handle_global_remove};
 
 /* BAH! humbug... */
 struct sync_data {
@@ -89,20 +173,22 @@
 	struct wl_display* display = nullptr;
 };
 
-static void sync_handle_done (void* data, struct wl_callback* callback, uint32_t other_data);
+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,
+    .done = sync_handle_done,
 };
 
-static void sync_handle_done (void* data, struct wl_callback* callback, uint32_t other_data) {
+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;
+		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;
 		}
@@ -115,7 +201,7 @@
 		 * 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;
@@ -124,9 +210,7 @@
 
 /* here comes the actual function we can use */
 bool EnumerateWindows(window_proc_t window_proc) {
-	struct sync_data sync = {
-		.display = wl_display_connect(NULL)
-	};
+	struct sync_data sync = {.display = wl_display_connect(NULL)};
 
 	if (!sync.display) {
 		std::cerr << "animia/wayland: Can't connect to display" << std::endl;
@@ -152,4 +236,4 @@
 	return true;
 }
 
-}
+} // namespace animia::internal::wayland