diff dep/animone/src/win/x11.cc @ 301:b1f625b0227c

*: convert all files CRLF -> LF some files were in DOS format, others were in unix. now everything (that at least is under our control) should all be the same format
author Paper <paper@paper.us.eu.org>
date Mon, 13 May 2024 15:04:51 -0400
parents 969a3e8c79c5
children a4257370de16
line wrap: on
line diff
--- a/dep/animone/src/win/x11.cc	Mon May 13 14:56:37 2024 -0400
+++ b/dep/animone/src/win/x11.cc	Mon May 13 15:04:51 2024 -0400
@@ -1,256 +1,256 @@
-#include "animone/win/x11.h"
-#include "animone.h"
-#include "animone/fd.h" /* GetProcessName() */
-#include "animone/win.h"
-
-#include <xcb/res.h>
-#include <xcb/xcb.h>
-
-#include <climits>
-#include <cstdint>
-#include <cstring>
-#include <set>
-#include <string>
-#include <memory>
-
-#include <chrono>
-
-#include <iostream>
-
-/* This uses XCB (and it uses it *right*), so it should be plenty fast */
-
-static size_t str_nlen(const char* s, size_t len) {
-	size_t i = 0;
-	for (; i < len && s[i]; i++)
-		;
-	return i;
-}
-
-namespace animone::internal::x11 {
-
-static bool GetAllTopLevelWindowsEWMH(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots,
-                                      std::set<xcb_window_t>& result) {
-	const xcb_atom_t Atom__NET_CLIENT_LIST = [connection] {
-		static constexpr std::string_view name = "_NET_CLIENT_LIST";
-		xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data());
-		std::unique_ptr<xcb_intern_atom_reply_t> reply(::xcb_intern_atom_reply(connection, cookie, NULL));
-
-		xcb_atom_t atom = reply->atom;
-
-		return atom;
-	}();
-	if (Atom__NET_CLIENT_LIST == XCB_ATOM_NONE)
-		return false; // BTFO
-
-	bool success = false;
-
-	std::vector<xcb_get_property_cookie_t> cookies;
-	cookies.reserve(roots.size());
-
-	for (const auto& root : roots)
-		cookies.push_back(::xcb_get_property(connection, 0, root, Atom__NET_CLIENT_LIST, XCB_ATOM_ANY, 0L, UINT_MAX));
-
-	for (const auto& cookie : cookies) {
-		std::unique_ptr<xcb_get_property_reply_t> reply(::xcb_get_property_reply(connection, cookie, NULL));
-
-		if (reply) {
-			xcb_window_t* value = reinterpret_cast<xcb_window_t*>(::xcb_get_property_value(reply.get()));
-			int len = ::xcb_get_property_value_length(reply.get());
-
-			for (size_t i = 0; i < len; i++)
-				result.insert(value[i]);
-
-			success |= true;
-		}
-	}
-
-	return success;
-}
-
-/* This is called on every window. What this does is:
- * 1. Gets the tree of children
- * 2. Searches all children recursively for a WM_STATE property
- * 3. If that failed... return the original window
- */
-static bool WalkWindows(xcb_connection_t* connection, int depth, xcb_atom_t Atom_WM_STATE, const xcb_window_t* windows,
-                        int windows_len, std::set<xcb_window_t>& result) {
-	/* The depth we should start returning at. */
-	static constexpr int CUTOFF = 1;
-
-	bool success = false;
-
-	std::vector<xcb_query_tree_cookie_t> cookies;
-	cookies.reserve(windows_len);
-
-	for (int i = 0; i < windows_len; i++)
-		cookies.push_back(::xcb_query_tree(connection, windows[i]));
-
-	for (const auto& cookie : cookies) {
-		std::unique_ptr<xcb_query_tree_reply_t> query_tree_reply(::xcb_query_tree_reply(connection, cookie, NULL));
-
-		xcb_window_t* tree_children = ::xcb_query_tree_children(query_tree_reply.get());
-		int tree_children_len = ::xcb_query_tree_children_length(query_tree_reply.get());
-
-		std::vector<xcb_get_property_cookie_t> state_property_cookies;
-		state_property_cookies.reserve(tree_children_len);
-
-		for (int i = 0; i < tree_children_len; i++)
-			state_property_cookies.push_back(
-			    ::xcb_get_property(connection, 0, tree_children[i], Atom_WM_STATE, Atom_WM_STATE, 0, 0));
-
-		for (int i = 0; i < tree_children_len; i++) {
-			std::unique_ptr<xcb_get_property_reply_t> get_property_reply(
-			    ::xcb_get_property_reply(connection, state_property_cookies[i], NULL));
-
-			/* X11 is unfriendly here. what this means is "did the property exist?" */
-			if (get_property_reply->format || get_property_reply->type || get_property_reply->length) {
-				result.insert(tree_children[i]);
-				if (depth >= CUTOFF)
-					return true;
-
-				success |= true;
-				continue;
-			}
-		}
-
-		if (WalkWindows(connection, depth + 1, Atom_WM_STATE, tree_children, tree_children_len, result)) {
-			success |= true;
-			if (depth >= CUTOFF)
-				return true;
-			continue;
-		}
-	}
-
-	return success;
-}
-
-static bool GetAllTopLevelWindowsICCCM(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots,
-                                       std::set<xcb_window_t>& result) {
-	bool success = false;
-
-	xcb_atom_t Atom_WM_STATE = [connection] {
-		static constexpr std::string_view name = "WM_STATE";
-		xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data());
-		xcb_intern_atom_reply_t* reply = ::xcb_intern_atom_reply(connection, cookie, NULL);
-
-		xcb_atom_t atom = reply->atom;
-		free(reply);
-		return atom;
-	}();
-	if (Atom_WM_STATE == XCB_ATOM_NONE)
-		return success;
-
-	std::vector<xcb_query_tree_cookie_t> cookies;
-	cookies.reserve(roots.size());
-
-	for (const auto& root : roots)
-		cookies.push_back(::xcb_query_tree(connection, root));
-
-	for (const auto& cookie : cookies)
-		success |= WalkWindows(connection, 0, Atom_WM_STATE, roots.data(), roots.size(), result);
-
-	return success;
-}
-
-bool EnumerateWindows(window_proc_t window_proc) {
-	if (!window_proc)
-		return false;
-
-	xcb_connection_t* connection = ::xcb_connect(NULL, NULL);
-	if (xcb_connection_has_error(connection))
-		return false;
-
-	std::set<xcb_window_t> windows;
-	{
-		std::vector<xcb_window_t> roots;
-		{
-			xcb_screen_iterator_t iter = ::xcb_setup_roots_iterator(::xcb_get_setup(connection));
-			for (; iter.rem; ::xcb_screen_next(&iter))
-				roots.push_back(iter.data->root);
-		}
-
-		if (!GetAllTopLevelWindowsEWMH(connection, roots, windows))
-			GetAllTopLevelWindowsICCCM(connection, roots, windows);
-	}
-
-	struct WindowCookies {
-		xcb_window_t window;
-		xcb_get_property_cookie_t class_property_cookie;
-		xcb_get_property_cookie_t name_property_cookie;
-		xcb_res_query_client_ids_cookie_t pid_property_cookie;
-	};
-
-	std::vector<WindowCookies> window_cookies;
-	window_cookies.reserve(windows.size());
-
-	for (const auto& window : windows) {
-		xcb_res_client_id_spec_t spec = {.client = window, .mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID};
-
-		WindowCookies window_cookie = {
-		    window, ::xcb_get_property(connection, 0, window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0L, 2048L),
-		    ::xcb_get_property(connection, 0, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0L, UINT_MAX),
-		    ::xcb_res_query_client_ids(connection, 1, &spec)};
-
-		window_cookies.push_back(window_cookie);
-	}
-
-	for (const auto& window_cookie : window_cookies) {
-		Window win = {0};
-		win.id = window_cookie.window;
-		{
-			/* Class name */
-			std::unique_ptr<xcb_get_property_reply_t> reply(
-			    ::xcb_get_property_reply(connection, window_cookie.class_property_cookie, NULL));
-
-			if (reply && reply->format == 8) {
-				const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get()));
-				const int data_len = ::xcb_get_property_value_length(reply.get());
-
-				int instance_len = str_nlen(data, data_len);
-				const char* class_name = data + instance_len + 1;
-
-				win.class_name = std::string(class_name, str_nlen(class_name, data_len - (instance_len + 1)));
-			}
-		}
-		{
-			/* Title text */
-			std::unique_ptr<xcb_get_property_reply_t> reply(
-			    ::xcb_get_property_reply(connection, window_cookie.name_property_cookie, NULL));
-
-			if (reply) {
-				const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get()));
-				int len = ::xcb_get_property_value_length(reply.get());
-
-				win.text = std::string(data, len);
-			}
-		}
-		Process proc = {0};
-		{
-			/* PID */
-			std::unique_ptr<xcb_res_query_client_ids_reply_t> reply(
-			    ::xcb_res_query_client_ids_reply(connection, window_cookie.pid_property_cookie, NULL));
-
-			if (reply) {
-				xcb_res_client_id_value_iterator_t it = ::xcb_res_query_client_ids_ids_iterator(reply.get());
-				for (; it.rem; ::xcb_res_client_id_value_next(&it)) {
-					if (it.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
-						proc.pid = *::xcb_res_client_id_value_value(it.data);
-						GetProcessName(proc.pid, proc.name); /* fill this in if we can */
-						break;
-					}
-				}
-			}
-		}
-
-		if (!window_proc(proc, win)) {
-			::xcb_disconnect(connection);
-			return false;
-		}
-	}
-
-	::xcb_disconnect(connection);
-
-	return true;
-}
-
-} // namespace animone::internal::x11
+#include "animone/win/x11.h"
+#include "animone.h"
+#include "animone/fd.h" /* GetProcessName() */
+#include "animone/win.h"
+
+#include <xcb/res.h>
+#include <xcb/xcb.h>
+
+#include <climits>
+#include <cstdint>
+#include <cstring>
+#include <set>
+#include <string>
+#include <memory>
+
+#include <chrono>
+
+#include <iostream>
+
+/* This uses XCB (and it uses it *right*), so it should be plenty fast */
+
+static size_t str_nlen(const char* s, size_t len) {
+	size_t i = 0;
+	for (; i < len && s[i]; i++)
+		;
+	return i;
+}
+
+namespace animone::internal::x11 {
+
+static bool GetAllTopLevelWindowsEWMH(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots,
+                                      std::set<xcb_window_t>& result) {
+	const xcb_atom_t Atom__NET_CLIENT_LIST = [connection] {
+		static constexpr std::string_view name = "_NET_CLIENT_LIST";
+		xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data());
+		std::unique_ptr<xcb_intern_atom_reply_t> reply(::xcb_intern_atom_reply(connection, cookie, NULL));
+
+		xcb_atom_t atom = reply->atom;
+
+		return atom;
+	}();
+	if (Atom__NET_CLIENT_LIST == XCB_ATOM_NONE)
+		return false; // BTFO
+
+	bool success = false;
+
+	std::vector<xcb_get_property_cookie_t> cookies;
+	cookies.reserve(roots.size());
+
+	for (const auto& root : roots)
+		cookies.push_back(::xcb_get_property(connection, 0, root, Atom__NET_CLIENT_LIST, XCB_ATOM_ANY, 0L, UINT_MAX));
+
+	for (const auto& cookie : cookies) {
+		std::unique_ptr<xcb_get_property_reply_t> reply(::xcb_get_property_reply(connection, cookie, NULL));
+
+		if (reply) {
+			xcb_window_t* value = reinterpret_cast<xcb_window_t*>(::xcb_get_property_value(reply.get()));
+			int len = ::xcb_get_property_value_length(reply.get());
+
+			for (size_t i = 0; i < len; i++)
+				result.insert(value[i]);
+
+			success |= true;
+		}
+	}
+
+	return success;
+}
+
+/* This is called on every window. What this does is:
+ * 1. Gets the tree of children
+ * 2. Searches all children recursively for a WM_STATE property
+ * 3. If that failed... return the original window
+ */
+static bool WalkWindows(xcb_connection_t* connection, int depth, xcb_atom_t Atom_WM_STATE, const xcb_window_t* windows,
+                        int windows_len, std::set<xcb_window_t>& result) {
+	/* The depth we should start returning at. */
+	static constexpr int CUTOFF = 1;
+
+	bool success = false;
+
+	std::vector<xcb_query_tree_cookie_t> cookies;
+	cookies.reserve(windows_len);
+
+	for (int i = 0; i < windows_len; i++)
+		cookies.push_back(::xcb_query_tree(connection, windows[i]));
+
+	for (const auto& cookie : cookies) {
+		std::unique_ptr<xcb_query_tree_reply_t> query_tree_reply(::xcb_query_tree_reply(connection, cookie, NULL));
+
+		xcb_window_t* tree_children = ::xcb_query_tree_children(query_tree_reply.get());
+		int tree_children_len = ::xcb_query_tree_children_length(query_tree_reply.get());
+
+		std::vector<xcb_get_property_cookie_t> state_property_cookies;
+		state_property_cookies.reserve(tree_children_len);
+
+		for (int i = 0; i < tree_children_len; i++)
+			state_property_cookies.push_back(
+			    ::xcb_get_property(connection, 0, tree_children[i], Atom_WM_STATE, Atom_WM_STATE, 0, 0));
+
+		for (int i = 0; i < tree_children_len; i++) {
+			std::unique_ptr<xcb_get_property_reply_t> get_property_reply(
+			    ::xcb_get_property_reply(connection, state_property_cookies[i], NULL));
+
+			/* X11 is unfriendly here. what this means is "did the property exist?" */
+			if (get_property_reply->format || get_property_reply->type || get_property_reply->length) {
+				result.insert(tree_children[i]);
+				if (depth >= CUTOFF)
+					return true;
+
+				success |= true;
+				continue;
+			}
+		}
+
+		if (WalkWindows(connection, depth + 1, Atom_WM_STATE, tree_children, tree_children_len, result)) {
+			success |= true;
+			if (depth >= CUTOFF)
+				return true;
+			continue;
+		}
+	}
+
+	return success;
+}
+
+static bool GetAllTopLevelWindowsICCCM(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots,
+                                       std::set<xcb_window_t>& result) {
+	bool success = false;
+
+	xcb_atom_t Atom_WM_STATE = [connection] {
+		static constexpr std::string_view name = "WM_STATE";
+		xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data());
+		xcb_intern_atom_reply_t* reply = ::xcb_intern_atom_reply(connection, cookie, NULL);
+
+		xcb_atom_t atom = reply->atom;
+		free(reply);
+		return atom;
+	}();
+	if (Atom_WM_STATE == XCB_ATOM_NONE)
+		return success;
+
+	std::vector<xcb_query_tree_cookie_t> cookies;
+	cookies.reserve(roots.size());
+
+	for (const auto& root : roots)
+		cookies.push_back(::xcb_query_tree(connection, root));
+
+	for (const auto& cookie : cookies)
+		success |= WalkWindows(connection, 0, Atom_WM_STATE, roots.data(), roots.size(), result);
+
+	return success;
+}
+
+bool EnumerateWindows(window_proc_t window_proc) {
+	if (!window_proc)
+		return false;
+
+	xcb_connection_t* connection = ::xcb_connect(NULL, NULL);
+	if (xcb_connection_has_error(connection))
+		return false;
+
+	std::set<xcb_window_t> windows;
+	{
+		std::vector<xcb_window_t> roots;
+		{
+			xcb_screen_iterator_t iter = ::xcb_setup_roots_iterator(::xcb_get_setup(connection));
+			for (; iter.rem; ::xcb_screen_next(&iter))
+				roots.push_back(iter.data->root);
+		}
+
+		if (!GetAllTopLevelWindowsEWMH(connection, roots, windows))
+			GetAllTopLevelWindowsICCCM(connection, roots, windows);
+	}
+
+	struct WindowCookies {
+		xcb_window_t window;
+		xcb_get_property_cookie_t class_property_cookie;
+		xcb_get_property_cookie_t name_property_cookie;
+		xcb_res_query_client_ids_cookie_t pid_property_cookie;
+	};
+
+	std::vector<WindowCookies> window_cookies;
+	window_cookies.reserve(windows.size());
+
+	for (const auto& window : windows) {
+		xcb_res_client_id_spec_t spec = {.client = window, .mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID};
+
+		WindowCookies window_cookie = {
+		    window, ::xcb_get_property(connection, 0, window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0L, 2048L),
+		    ::xcb_get_property(connection, 0, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0L, UINT_MAX),
+		    ::xcb_res_query_client_ids(connection, 1, &spec)};
+
+		window_cookies.push_back(window_cookie);
+	}
+
+	for (const auto& window_cookie : window_cookies) {
+		Window win = {0};
+		win.id = window_cookie.window;
+		{
+			/* Class name */
+			std::unique_ptr<xcb_get_property_reply_t> reply(
+			    ::xcb_get_property_reply(connection, window_cookie.class_property_cookie, NULL));
+
+			if (reply && reply->format == 8) {
+				const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get()));
+				const int data_len = ::xcb_get_property_value_length(reply.get());
+
+				int instance_len = str_nlen(data, data_len);
+				const char* class_name = data + instance_len + 1;
+
+				win.class_name = std::string(class_name, str_nlen(class_name, data_len - (instance_len + 1)));
+			}
+		}
+		{
+			/* Title text */
+			std::unique_ptr<xcb_get_property_reply_t> reply(
+			    ::xcb_get_property_reply(connection, window_cookie.name_property_cookie, NULL));
+
+			if (reply) {
+				const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get()));
+				int len = ::xcb_get_property_value_length(reply.get());
+
+				win.text = std::string(data, len);
+			}
+		}
+		Process proc = {0};
+		{
+			/* PID */
+			std::unique_ptr<xcb_res_query_client_ids_reply_t> reply(
+			    ::xcb_res_query_client_ids_reply(connection, window_cookie.pid_property_cookie, NULL));
+
+			if (reply) {
+				xcb_res_client_id_value_iterator_t it = ::xcb_res_query_client_ids_ids_iterator(reply.get());
+				for (; it.rem; ::xcb_res_client_id_value_next(&it)) {
+					if (it.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
+						proc.pid = *::xcb_res_client_id_value_value(it.data);
+						GetProcessName(proc.pid, proc.name); /* fill this in if we can */
+						break;
+					}
+				}
+			}
+		}
+
+		if (!window_proc(proc, win)) {
+			::xcb_disconnect(connection);
+			return false;
+		}
+	}
+
+	::xcb_disconnect(connection);
+
+	return true;
+}
+
+} // namespace animone::internal::x11