diff dep/animia/src/win/x11.cc @ 156:cdf79282d647

dep/animia: add VERY early x11 window stuff
author Paper <mrpapersonic@gmail.com>
date Wed, 15 Nov 2023 18:04:04 -0500
parents
children 18c8eb5d1edc
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/animia/src/win/x11.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -0,0 +1,115 @@
+#include <X11/Xlib.h>
+
+/* The code for this is very fugly because X11 uses lots of generic type names
+   (i.e., Window, Display), so I have to use :: when defining vars to distinguish
+   between Animia's types and X11's types */
+
+namespace animia::internal::x11 {
+
+static bool GetWindowPropertyAsString(::Display* display, ::Window window, const char* atom, std::string& result, ::Atom reqtype = AnyPropertyType) {
+	int format;
+	unsigned long leftover_bytes, num_of_items;
+	::Atom type;
+	void* data;
+
+	if (!::XGetWindowProperty(display, root, ::XInternAtom(display, atom, true), 0L, (~0L), false, reqtype,
+	                            &type, &format, &num_of_items, &leftover_bytes, &data))
+		return false;
+
+	result = std::string(data, num_of_items);
+
+	::XFree(data);
+
+	return true;
+}
+
+static bool GetWindowPID(::Display* display, ::Window window, pid_t& result) {
+	int format;
+	unsigned long leftover_bytes, num_of_items;
+	::Atom type;
+	void* data;
+
+	if (!::XGetWindowProperty(display, root, ::XInternAtom(display, atom, true), 0L, (~0L), false, reqtype,
+	                            &type, &format, &num_of_items, &leftover_bytes, &data))
+		return false;
+
+	result = static_cast<pid_t>(*(uint32_t*)data);
+
+	::XFree(data);
+
+	return true;
+}
+
+static bool FetchName(::Display* display, ::Window window, std::string& result) {
+	/* TODO: Check if XInternAtom created None or not... */
+	if (GetWindowPropertyAsString(display, window, "_NET_WM_NAME", result, ::XInternAtom(display, "UTF8_STRING", false)))
+		return true;
+
+	/* Fallback to XGetWMName() */
+	XTextProperty text;
+
+	{
+		int status = ::XGetWMName(display, window, &text);
+		if (!status || !text_prop.value || !text_prop.nitems)
+			return false;
+	}
+
+	char** list;
+
+	{
+		int num;
+
+		int status = ::XmbTextPropertyToTextList(display, &text, &list, &num);
+		if (status < Success || !num || !*list)
+			return false;
+	}
+
+	::XFree(text.value);
+
+	result = *list;
+
+	::XFreeStringList(list);
+
+	return true;
+}
+
+bool X11WinTools::EnumerateWindows(window_proc_t window_proc) {
+	auto get_window_property = [&](Display* display, Window window, Atom atom, unsigned long& num_of_items, void*& data) -> int {
+		int format;
+		unsigned long leftover_bytes;
+		::Atom realtype;
+
+		return ::XGetWindowProperty(display, root, atom, 0L, (~0L), false, AnyPropertyType,
+		                            &realtype, &format, &num_of_items, &leftover_bytes, &data);
+	}
+
+	::Display* display = ::XOpenDisplay(nullptr);
+	::Window root = ::DefaultRootWindow(display);
+
+	unsigned long num_windows;
+	::Window* windows = nullptr;
+
+	int status = get_window_property(display, root, ::XInternAtom(display, "_NET_CLIENT_LIST", true), num_windows, (void*)windows);
+
+	if (status < Success)
+		return false;
+
+	for (long k = 0; k < num_windows; k++) {
+		const ::Window window = windows[k];
+
+		Window win;
+		win.id = (long)windows[k];
+		GetWindowPropertyAsString(display, window, "_NET_ACTIVE_WINDOW", win.class_name, ::XInternAtom(display, "STRING", false));
+		win.title = FetchName(display, windows[k]);
+
+		Process proc;
+		GetWindowPID(display, window, proc.pid);
+
+		if (!window_proc(proc, win))
+			return false;
+	}
+
+	return true;
+}
+
+}