changeset 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 d2bbb5773616
children 18c8eb5d1edc
files dep/animia/CMakeLists.txt dep/animia/include/animia.h dep/animia/include/animia/fd.h dep/animia/include/animia/fd/linux.h dep/animia/include/animia/fd/win32.h dep/animia/include/animia/fd/xnu.h dep/animia/include/animia/media.h dep/animia/include/animia/player.h dep/animia/include/animia/types.h dep/animia/include/animia/util.h dep/animia/include/animia/util/win32.h dep/animia/include/animia/win.h dep/animia/include/animia/win/quartz.h dep/animia/include/animia/win/win32.h dep/animia/include/animia/win/x11.h dep/animia/src/animia.cc dep/animia/src/fd.cc dep/animia/src/fd/linux.cc dep/animia/src/fd/win32.cc dep/animia/src/fd/xnu.cc dep/animia/src/player.cc dep/animia/src/strategist.cc dep/animia/src/util.cc dep/animia/src/util/win32.cc dep/animia/src/win.cc dep/animia/src/win/quartz.mm dep/animia/src/win/win32.cc dep/animia/src/win/x11.cc
diffstat 28 files changed, 321 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- a/dep/animia/CMakeLists.txt	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/CMakeLists.txt	Wed Nov 15 18:04:04 2023 -0500
@@ -12,18 +12,27 @@
 
 set(LIBRARIES)
 
+set(INCLUDE_DIRS
+	include
+)
+
+set(DEFINES)
+
 # FD
 if(LINUX)
+	list(APPEND DEFINES LINUX)
 	list(APPEND SRC_FILES
 		# linux
 		src/fd/linux.cc
 	)
 elseif(APPLE) # this won't run on Linux
+	list(APPEND DEFINES MACOSX)
 	list(APPEND SRC_FILES
 		# xnu stuff
 		src/fd/xnu.cc
 	)
 elseif(WIN32)
+	list(APPEND DEFINES WIN32)
 	list(APPEND SRC_FILES
 		# win32
 		src/fd/win32.cc
@@ -45,6 +54,20 @@
 	find_library(COREGRAPHICS_LIBRARY CoreGraphics)
 	find_library(APPKIT_LIBRARY AppKit)
 	list(APPEND LIBRARIES ${FOUNDATION_LIBRARY} ${COREGRAPHICS_LIBRARY} ${APPKIT_LIBRARY})
+else()
+	find_package(X11::X11)
+	if (X11_FOUND)
+		list(APPEND DEFINES X11)
+		list(APPEND SRC_FILES
+			src/win/x11.cc
+		)
+		list(APPEND INCLUDE_DIRS
+			${X11_INCLUDE_DIR}
+		)
+		list(APPEND LIBRARIES
+			${X11_LIBRARIES}
+		)
+	endif()
 endif()
 
 add_library(animia SHARED ${SRC_FILES})
--- a/dep/animia/include/animia.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia.h	Wed Nov 15 18:04:04 2023 -0500
@@ -13,22 +13,22 @@
 };
 
 struct Process {
-	internal::pid_t pid = 0;
-	std::string name;
+		internal::pid_t pid = 0;
+		std::string name;
 };
 
 struct Window {
-	unsigned int id = 0;
-	std::string class_name;
-	std::string text; // title bar text
+		unsigned int id = 0;
+		std::string class_name;
+		std::string text; // title bar text
 };
 
 struct Result {
-	ResultType type;
-	Player player;
-	Process process; // unused when using window_title. it's dumb, blame X11
-	Window window; // unused with file descriptors
-	std::vector<Media> media;
+		ResultType type;
+		Player player;
+		Process process; // unused when using window_title. it's dumb, blame X11
+		Window window;   // unused with file descriptors
+		std::vector<Media> media;
 };
 
 bool GetResults(const std::vector<Player>& players, std::vector<Result>& results);
--- a/dep/animia/include/animia/fd.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/fd.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,9 +1,9 @@
 #ifndef __animia__animia__fd_h
 #define __animia__animia__fd_h
 
+#include <functional>
 #include <set>
 #include <string>
-#include <functional>
 
 #include "animia/types.h"
 
@@ -14,8 +14,8 @@
 namespace internal {
 
 struct OpenFile {
-	pid_t pid = 0;
-	std::string path;
+		pid_t pid = 0;
+		std::string path;
 };
 
 using process_proc_t = std::function<bool(const Process&)>;
--- a/dep/animia/include/animia/fd/linux.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/fd/linux.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,15 +1,15 @@
 #ifndef __animia__animia__fd__linux_h
 #define __animia__animia__fd__linux_h
 
+#include <set>
 #include <string>
-#include <set>
 
+#include "animia/fd.h"
 #include "animia/types.h"
-#include "animia/fd.h"
 
 /* Russian warship, go fuck yourself */
 #ifdef linux
-#undef linux
+#	undef linux
 #endif
 
 namespace animia::internal::linux {
@@ -20,6 +20,6 @@
 		bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) override;
 };
 
-}
+} // namespace animia::internal::linux
 
 #endif // __animia__animia__fd__linux_h
--- a/dep/animia/include/animia/fd/win32.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/fd/win32.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,13 +1,13 @@
 #ifndef __animia__animia__fd__win32_h
 #define __animia__animia__fd__win32_h
 
+#include <set>
 #include <string>
-#include <set>
 
 #include <windows.h>
 
+#include "animia/fd.h"
 #include "animia/types.h"
-#include "animia/fd.h"
 
 namespace animia::internal::win32 {
 
@@ -17,6 +17,6 @@
 		bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) override;
 };
 
-}
+} // namespace animia::internal::win32
 
 #endif // __animia__animia__fd__win32_h
--- a/dep/animia/include/animia/fd/xnu.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/fd/xnu.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,11 +1,11 @@
 #ifndef __animia__animia__fd__xnu_h
 #define __animia__animia__fd__xnu_h
 
+#include <set>
 #include <string>
-#include <set>
 
+#include "animia/fd.h"
 #include "animia/types.h"
-#include "animia/fd.h"
 
 namespace animia::internal::xnu {
 
@@ -15,6 +15,6 @@
 		bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) override;
 };
 
-}
+} // namespace animia::internal::xnu
 
 #endif // __animia__animia__fd__xnu_h
--- a/dep/animia/include/animia/media.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/media.h	Wed Nov 15 18:04:04 2023 -0500
@@ -19,14 +19,14 @@
 };
 
 struct MediaInfo {
-	MediaInfoType type = MediaInfoType::Unknown;
-	std::string value;
+		MediaInfoType type = MediaInfoType::Unknown;
+		std::string value;
 };
 
 struct Media {
-	std::vector<MediaInfo> information;
+		std::vector<MediaInfo> information;
 };
 
-}  // namespace animia
+} // namespace animia
 
 #endif // __animia__animia__media_h
--- a/dep/animia/include/animia/player.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/player.h	Wed Nov 15 18:04:04 2023 -0500
@@ -18,12 +18,12 @@
 };
 
 struct Player {
-	PlayerType type = PlayerType::Default;
-	std::string name;
-	std::string window_title_format;
-	std::vector<std::string> windows;
-	std::vector<std::string> executables;
-	std::vector<Strategy> strategies;
+		PlayerType type = PlayerType::Default;
+		std::string name;
+		std::string window_title_format;
+		std::vector<std::string> windows;
+		std::vector<std::string> executables;
+		std::vector<Strategy> strategies;
 };
 
 bool ParsePlayersData(const std::string& data, std::vector<Player>& players);
--- a/dep/animia/include/animia/types.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/types.h	Wed Nov 15 18:04:04 2023 -0500
@@ -5,13 +5,13 @@
    don't force the user to include <windows.h> or <IntBase.h> */
 #ifdef _WIN32
 namespace animia::internal {
-	typedef unsigned long pid_t;
+typedef unsigned long pid_t;
 }
 #else
 /* <sys/types.h> shouldn't be that big, right? */
 #	include <sys/types.h>
 namespace animia::internal {
-	typedef ::pid_t pid_t;
+typedef ::pid_t pid_t;
 }
 #endif
 
--- a/dep/animia/include/animia/util.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/util.h	Wed Nov 15 18:04:04 2023 -0500
@@ -12,6 +12,6 @@
 bool TrimLeft(std::string& str, const char* chars);
 bool TrimRight(std::string& str, const char* chars);
 
-}
+} // namespace animia::internal::util
 
 #endif // __animia__animia__util_h
\ No newline at end of file
--- a/dep/animia/include/animia/util/win32.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/util/win32.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,14 +1,17 @@
+#ifndef __animia__animia__util__win32_h
+#define __animia__animia__util__win32_h
+
 #include <windows.h>
 #include <subauth.h>
 
+#include <memory>
 #include <string>
-#include <memory>
 
 namespace animia::internal::win32 {
 
 struct HandleDeconstructor {
-	using pointer = HANDLE;
-	void operator()(pointer t) const { ::CloseHandle(t); };
+		using pointer = HANDLE;
+		void operator()(pointer t) const { ::CloseHandle(t); };
 };
 
 using Handle = std::unique_ptr<HANDLE, HandleDeconstructor>;
@@ -25,4 +28,6 @@
 bool IsSystemDirectory(const std::string& path);
 bool IsSystemDirectory(std::wstring path);
 
-}
\ No newline at end of file
+} // namespace animia::internal::win32
+
+#endif // __animia__animia__util__win32_h
\ No newline at end of file
--- a/dep/animia/include/animia/win.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/win.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,8 +1,8 @@
 #ifndef __animia__animia__win_h
 #define __animia__animia__win_h
 
+#include <functional>
 #include <string>
-#include <functional>
 
 namespace animia {
 
@@ -15,7 +15,10 @@
 
 class BaseWinTools {
 	public:
-		virtual bool EnumerateWindows(window_proc_t window_proc) { return false; (void)window_proc; }
+		virtual bool EnumerateWindows(window_proc_t window_proc) {
+			return false;
+			(void)window_proc;
+		}
 };
 
 extern BaseWinTools& win;
--- a/dep/animia/include/animia/win/quartz.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/win/quartz.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,5 +1,5 @@
-#ifndef __animia__animia__fd__quartz_h
-#define __animia__animia__fd__quartz_h
+#ifndef __animia__animia__win__quartz_h
+#define __animia__animia__win__quartz_h
 
 #include "animia/win.h"
 
@@ -10,6 +10,6 @@
 		bool EnumerateWindows(window_proc_t window_proc) override;
 };
 
-}
+} // namespace animia::internal::quartz
 
-#endif // __animia__animia__fd__quartz_h
+#endif // __animia__animia__win__quartz_h
--- a/dep/animia/include/animia/win/win32.h	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/include/animia/win/win32.h	Wed Nov 15 18:04:04 2023 -0500
@@ -1,5 +1,5 @@
-#ifndef __animia__animia__fd__win32_h
-#define __animia__animia__fd__win32_h
+#ifndef __animia__animia__win__win32_h
+#define __animia__animia__win__win32_h
 
 #include "animia/win.h"
 
@@ -10,6 +10,6 @@
 		bool EnumerateWindows(window_proc_t window_proc) override;
 };
 
-}
+} // namespace animia::internal::win32
 
-#endif // __animia__animia__fd__win32_h
+#endif // __animia__animia__win__win32_h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/animia/include/animia/win/x11.h	Wed Nov 15 18:04:04 2023 -0500
@@ -0,0 +1,15 @@
+#ifndef __animia__animia__win__x11_h
+#define __animia__animia__win__x11_h
+
+#include "animia/win.h"
+
+namespace animia::internal::x11 {
+
+class X11WinTools final : public BaseWinTools {
+	public:
+		bool EnumerateWindows(window_proc_t window_proc) override;
+};
+
+} // namespace animia::internal::x11
+
+#endif // __animia__animia__win__x11_h
--- a/dep/animia/src/animia.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/animia.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -1,15 +1,13 @@
+#include "animia.h"
+#include "animia/fd.h"
+#include "animia/strategies.h"
+#include "animia/types.h"
+#include "animia/util.h"
+#include "animia/win.h"
+
+#include <set>
 #include <string>
 #include <vector>
-#include <set>
-
-#include "animia.h"
-#include "animia/util.h"
-#include "animia/strategies.h"
-#include "animia/types.h"
-#include "animia/fd.h"
-#include "animia/win.h"
-
-#include <iostream>
 
 namespace animia {
 
@@ -50,8 +48,6 @@
 bool GetResults(const std::vector<Player>& players, std::vector<Result>& results) {
 	/* Start out with file descriptors. */
 	auto process_proc = [&](const Process& process) -> bool {
-		std::cout << process.name << std::endl;
-
 		for (const auto& player : players) {
 			if (!internal::PlayerHasStrategy(player, Strategy::OpenFiles))
 				continue;
@@ -93,4 +89,4 @@
 	return internal::ApplyStrategies(results);
 }
 
-}
+} // namespace animia
--- a/dep/animia/src/fd.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/fd.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -22,4 +22,4 @@
 
 BaseFdTools& fd = os_fd;
 
-}
+} // namespace animia::internal
--- a/dep/animia/src/fd/linux.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/fd/linux.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -1,18 +1,18 @@
-#include "animia/util.h"
 #include "animia/fd/linux.h"
 #include "animia.h"
+#include "animia/util.h"
 
 #include <algorithm>
+#include <cstring>
 #include <filesystem>
 #include <fstream>
 #include <sstream>
 #include <string>
 #include <unordered_map>
 #include <vector>
-#include <cstring>
 
+#include <dirent.h>
 #include <fcntl.h>
-#include <dirent.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -58,7 +58,7 @@
 		if (!util::ReadFile(path, data))
 			return false;
 		buffer << data;
-	}	
+	}
 
 	int flags = 0;
 	for (std::string line; std::getline(buffer, line);) {
@@ -75,7 +75,7 @@
 static std::string GetFilenameFromFd(std::string link) {
 	/* gets around stupid linux limitation where /proc doesn't
 	   give actual filesize readings */
-	size_t  exe_size = 1024;
+	size_t exe_size = 1024;
 	ssize_t exe_used;
 	std::string ret;
 
--- a/dep/animia/src/fd/win32.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/fd/win32.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -85,7 +85,7 @@
 	/* we should really put a cap on this */
 	ULONG cb = 1 << 19;
 
-	for (NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH; status == STATUS_INFO_LENGTH_MISMATCH; ) {
+	for (NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH; status == STATUS_INFO_LENGTH_MISMATCH;) {
 		/* why are we doing this? */
 		status = STATUS_NO_MEMORY;
 
--- a/dep/animia/src/fd/xnu.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/fd/xnu.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -5,16 +5,16 @@
 #include "animia/fd/xnu.h"
 #include "animia.h"
 
+#include <cassert>
+#include <string>
 #include <unordered_map>
 #include <vector>
-#include <string>
-#include <cassert>
 
 #include <fcntl.h>
+#include <libproc.h>
 #include <sys/sysctl.h>
 #include <sys/types.h>
 #include <sys/user.h>
-#include <libproc.h>
 
 namespace animia::internal::xnu {
 
@@ -25,36 +25,21 @@
 	if (st != PROC_PIDTBSDINFO_SIZE)
 		return "";
 
-	return proc.pbi_name;
+	return (proc.pbi_name[0]) ? proc.pbi_name : proc.pbi_comm;
 }
 
-/* this is a cleaned up version of a function from... Apple?
-   ...anyway, what it essentially does is gets the size and stuff from
-   sysctl() and reserves the space in a vector to store the PIDs */
 bool XnuFdTools::EnumerateOpenProcesses(process_proc_t process_proc) {
-	struct kinfo_proc* result = NULL;
-	size_t length = 0;
-	static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
+	std::vector<pid_t> pids;
+	pids.reserve(1024);
 
-	/* get appropriate length from sysctl()
-	   note: the reason this isn't checked is actually because this will
-	   *always* return an error on OS X (or... maybe I'm doing it wrong :) ) */
-	sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);
-
-	result = (struct kinfo_proc*)malloc(length);
-	if (result == NULL)
-		return false;
-
-	/* TODO: this might actually return ENOMEM if the amount of file handles changes between the
-	   original sysctl() call and this one, which is technically possible */
-	if (sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, result, &length, NULL, 0) == ENOMEM) {
-		assert(result != NULL);
-		free(result);
-		return false;
+	for (int returned_size = pids.capacity(); pids.capacity() > returned_size; pids.reserve(pids.capacity() * 2)) {
+		returned_size = proc_listpids(PROC_ALL_PIDS, 0, pids.data(), pids.capacity() * sizeof(pid_t));
+		if (returned_size == -1)
+			return false;
 	}
 
-	for (int i = 0; i < length / sizeof(*result); i++) {
-		const pid_t pid = result[i].kp_proc.p_pid;
+	for (int i = 0; i < size / sizeof(*pids); i++) {
+		const pid_t pid = pids[i].kp_proc.p_pid;
 		if (!process_proc({pid, GetProcessName(pid)}))
 			return false;
 	}
@@ -81,13 +66,14 @@
 			if (info[i].proc_fdtype == PROX_FDTYPE_VNODE) {
 				struct vnode_fdinfowithpath vnodeInfo;
 
-				int sz = proc_pidfdinfo(pid, info[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE);
+				int sz = proc_pidfdinfo(pid, info[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo,
+				                        PROC_PIDFDVNODEPATHINFO_SIZE);
 				if (sz != PROC_PIDFDVNODEPATHINFO_SIZE)
 					return false;
 
 				/* this doesn't work!
 				if (vnodeInfo.pfi.fi_openflags & O_WRONLY || vnodeInfo.pfi.fi_openflags & O_RDWR)
-					continue;
+				    continue;
 				*/
 
 				if (!open_file_proc({pid, vnodeInfo.pvip.vip_path}))
@@ -99,4 +85,4 @@
 	return true;
 }
 
-} // namespace animia::internal::unix
+} // namespace animia::internal::xnu
--- a/dep/animia/src/player.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/player.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -1,11 +1,11 @@
+#include "animia/player.h"
+#include "animia/util.h"
+
 #include <map>
 #include <sstream>
 #include <string>
 #include <vector>
 
-#include "animia/player.h"
-#include "animia/util.h"
-
 namespace animia {
 
 namespace internal::parser {
@@ -24,34 +24,26 @@
 	return line.find_first_not_of('\t');
 }
 
-bool HandleIndentation(const size_t current,
-                       const std::vector<Player>& players,
-                       State& state) {
+bool HandleIndentation(const size_t current, const std::vector<Player>& players, State& state) {
 	// Each state has a definitive expected indentation
 	const auto expected = [&state]() -> size_t {
 		switch (state) {
 			default:
-			case State::ExpectPlayerName:
-				return 0;
-			case State::ExpectSection:
-				return 1;
+			case State::ExpectPlayerName: return 0;
+			case State::ExpectSection: return 1;
 			case State::ExpectWindow:
 			case State::ExpectExecutable:
 			case State::ExpectStrategy:
-			case State::ExpectType:
-				return 2;
-			case State::ExpectWindowTitle:
-				return 3;
+			case State::ExpectType: return 2;
+			case State::ExpectWindowTitle: return 3;
 		}
 	}();
 
 	if (current > expected)
-		return false;  // Disallow excessive indentation
+		return false; // Disallow excessive indentation
 
 	if (current < expected) {
-		auto fix_state = [&]() {
-			state = !current ? State::ExpectPlayerName : State::ExpectSection;
-		};
+		auto fix_state = [&]() { state = !current ? State::ExpectPlayerName : State::ExpectSection; };
 		switch (state) {
 			case State::ExpectWindow:
 				if (players.back().windows.empty())
@@ -68,11 +60,8 @@
 					return false;
 				fix_state();
 				break;
-			case State::ExpectType:
-				fix_state();
-				break;
-			case State::ExpectWindowTitle:
-				return false;
+			case State::ExpectType: fix_state(); break;
+			case State::ExpectWindowTitle: return false;
 		}
 	}
 
@@ -89,10 +78,10 @@
 
 		case State::ExpectSection: {
 			static const std::map<std::string, State> sections = {
-				{"windows", State::ExpectWindow},
-				{"executables", State::ExpectExecutable},
-				{"strategies", State::ExpectStrategy},
-				{"type", State::ExpectType},
+			    {"windows",     State::ExpectWindow    },
+			    {"executables", State::ExpectExecutable},
+			    {"strategies",  State::ExpectStrategy  },
+			    {"type",        State::ExpectType      },
 			};
 			util::TrimRight(line, ":");
 			const auto it = sections.find(line);
@@ -102,19 +91,15 @@
 			break;
 		}
 
-		case State::ExpectWindow:
-			players.back().windows.push_back(line);
-			break;
+		case State::ExpectWindow: players.back().windows.push_back(line); break;
 
-		case State::ExpectExecutable:
-			players.back().executables.push_back(line);
-			break;
+		case State::ExpectExecutable: players.back().executables.push_back(line); break;
 
 		case State::ExpectStrategy: {
 			static const std::map<std::string, Strategy> strategies = {
-				{"window_title", Strategy::WindowTitle},
-				{"open_files", Strategy::OpenFiles},
-				{"ui_automation", Strategy::UiAutomation},
+			    {"window_title",  Strategy::WindowTitle },
+			    {"open_files",    Strategy::OpenFiles   },
+			    {"ui_automation", Strategy::UiAutomation},
 			};
 			util::TrimRight(line, ":");
 			const auto it = strategies.find(line);
@@ -123,17 +108,15 @@
 			const auto strategy = it->second;
 			players.back().strategies.push_back(strategy);
 			switch (strategy) {
-				case Strategy::WindowTitle:
-					state = State::ExpectWindowTitle;
-					break;
+				case Strategy::WindowTitle: state = State::ExpectWindowTitle; break;
 			}
 			break;
 		}
 
 		case State::ExpectType: {
 			static const std::map<std::string, PlayerType> types = {
-				{"default", PlayerType::Default},
-				{"web_browser", PlayerType::WebBrowser},
+			    {"default",     PlayerType::Default   },
+			    {"web_browser", PlayerType::WebBrowser},
 			};
 			const auto it = types.find(line);
 			if (it == types.end())
@@ -151,7 +134,7 @@
 	return true;
 }
 
-}  // namespace internal::parser
+} // namespace internal::parser
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -166,7 +149,7 @@
 
 	while (std::getline(stream, line, '\n')) {
 		if (line.empty())
-			continue;  // Ignore empty lines
+			continue; // Ignore empty lines
 
 		indentation = internal::parser::GetIndentation(line);
 
@@ -174,7 +157,7 @@
 		internal::util::TrimRight(line, "\n\r");
 
 		if (line.empty() || line.front() == '#')
-			continue;  // Ignore empty lines and comments
+			continue; // Ignore empty lines and comments
 
 		if (!internal::parser::HandleIndentation(indentation, players, state))
 			return false;
@@ -195,4 +178,4 @@
 	return ParsePlayersData(data, players);
 }
 
-}  // namespace animia
+} // namespace animia
--- a/dep/animia/src/strategist.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/strategist.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -1,11 +1,9 @@
+#include <regex>
+
+#include "animia.h"
+#include "animia/fd.h"
 #include "animia/strategies.h"
 #include "animia/util.h"
-#include "animia/fd.h"
-#include "animia.h"
-
-#include <iostream>
-
-#include <regex>
 
 namespace animia::internal {
 
@@ -28,12 +26,8 @@
 	bool success = false;
 
 	switch (result_.type) {
-		case ResultType::Process:
-			success |= ApplyOpenFilesStrategy();
-			break;
-		case ResultType::Window:
-			success |= ApplyWindowTitleStrategy();
-			break;
+		case ResultType::Process: success |= ApplyOpenFilesStrategy(); break;
+		case ResultType::Window: success |= ApplyWindowTitleStrategy(); break;
 	}
 
 	return success;
@@ -80,8 +74,7 @@
 
 static MediaInfoType InferMediaInformationType(const std::string& str) {
 	const std::regex path_pattern(R"(^(?:[A-Za-z]:[/\\]|\\\\)[^<>:"/\\|?*]+)");
-	return (std::regex_search(str, path_pattern))
-		? MediaInfoType::File : MediaInfoType::Unknown;
+	return (std::regex_search(str, path_pattern)) ? MediaInfoType::File : MediaInfoType::Unknown;
 }
 
 bool Strategist::ApplyWindowTitleStrategy() {
@@ -119,4 +112,4 @@
 	return true;
 }
 
-}
+} // namespace animia::internal
--- a/dep/animia/src/util.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/util.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -1,10 +1,8 @@
 #include <algorithm>
 #include <fstream>
+#include <regex>
 #include <sstream>
 #include <string>
-#include <regex>
-
-#include <iostream>
 
 #include "animia/util.h"
 
@@ -28,13 +26,9 @@
 
 /* this assumes ASCII... which really should be the case for what we need, anyway */
 bool EqualStrings(const std::string& str1, const std::string& str2) {
-	auto tolower = [](const char c) -> char {
-		return ('A' <= c && c <= 'Z') ? c + ('a' - 'A') : c;
-	};
+	auto tolower = [](const char c) -> char { return ('A' <= c && c <= 'Z') ? c + ('a' - 'A') : c; };
 
-	auto equal_chars = [&tolower](const char c1, const char c2) -> bool {
-		return tolower(c1) == tolower(c2);
-	};
+	auto equal_chars = [&tolower](const char c1, const char c2) -> bool { return tolower(c1) == tolower(c2); };
 
 	return str1.length() == str2.length() && std::equal(str1.begin(), str1.end(), str2.begin(), equal_chars);
 }
@@ -90,4 +84,4 @@
 	return true;
 }
 
-} // namespace anisthesia::detail::util
+} // namespace animia::internal::util
--- a/dep/animia/src/util/win32.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/util/win32.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -1,8 +1,8 @@
 #include "animia/util/win32.h"
 
+#include <shlobj.h>  /* SHGetKnownFolderPath */
+#include <subauth.h> /* UNICODE_STRING */
 #include <windows.h>
-#include <shlobj.h> /* SHGetKnownFolderPath */
-#include <subauth.h> /* UNICODE_STRING */
 
 namespace animia::internal::win32 {
 
@@ -14,7 +14,6 @@
 	if (string.empty())
 		return std::string();
 
-
 	long size = ::WideCharToMultiByte(CP_UTF8, 0, string.c_str(), string.length(), nullptr, 0, nullptr, nullptr);
 	std::string ret = std::string(size, '\0');
 	::WideCharToMultiByte(CP_UTF8, 0, string.c_str(), string.length(), &ret.front(), ret.length(), nullptr, nullptr);
@@ -87,4 +86,4 @@
 	return path.find(windir) == 4;
 }
 
-}
+} // namespace animia::internal::win32
--- a/dep/animia/src/win.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/win.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -18,4 +18,4 @@
 
 BaseWinTools& win = os_win;
 
-}
+} // namespace animia::internal
--- a/dep/animia/src/win/quartz.mm	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/win/quartz.mm	Wed Nov 15 18:04:04 2023 -0500
@@ -11,36 +11,32 @@
 static bool IntegerFromNSNumber(NSNumber* num, T& result) {
 	if (!num)
 		return false;
+
 	result = [num intValue];
 	return true;
 }
 
+static bool StringFromNSString(NSString* string, std::string& result) {
+	if (!string)
+		return false;
+
+	result = [string UTF8String];
+	return true;
+}
+
 static bool GetWindowTitle(unsigned int wid, std::string& result) {
 	NSWindow* window = [NSApp windowWithWindowNumber: wid];
 	if (!window)
 		return false;
 
-	NSString* title = [window title];
-	if (!title)
-		return false;
-
-	result = [title UTF8String];
-
-	return true;
-}
-
-static bool StringFromNSString(NSString* string, std::string& result) {
-	if (!string)
-		return false;
-	result = [string UTF8String];
-	return true;
+	return StringFromNSString([window title], result);
 }
 
 bool QuartzWinTools::EnumerateWindows(window_proc_t window_proc) {
 	if (!window_proc)
 		return false;
 
-	NSMutableArray* windows = (NSMutableArray*)CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID);
+	NSMutableArray* windows = reinterpret_cast<NSMutableArray*>(CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID));
 	if (!windows)
 		return false;
 
--- a/dep/animia/src/win/win32.cc	Wed Nov 15 15:24:39 2023 -0500
+++ b/dep/animia/src/win/win32.cc	Wed Nov 15 18:04:04 2023 -0500
@@ -1,7 +1,7 @@
 #include "animia/win/win32.h"
+#include "animia.h"
 #include "animia/util/win32.h"
 #include "animia/win.h"
-#include "animia.h"
 
 #include <set>
 #include <string>
@@ -48,8 +48,7 @@
 	// Note that if we requested PROCESS_QUERY_INFORMATION access right instead
 	// of PROCESS_QUERY_LIMITED_INFORMATION, this function would fail when used
 	// to open an elevated process.
-	Handle process_handle(::OpenProcess(
-			PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id));
+	Handle process_handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id));
 
 	if (!process_handle)
 		return std::wstring();
@@ -72,12 +71,8 @@
 	const auto window_style = ::GetWindowLong(hwnd, GWL_STYLE);
 	const auto window_ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
 
-	auto has_style = [&window_style](DWORD style) {
-		return (window_style & style) != 0;
-	};
-	auto has_ex_style = [&window_ex_style](DWORD ex_style) {
-		return (window_ex_style & ex_style) != 0;
-	};
+	auto has_style = [&window_style](DWORD style) { return (window_style & style) != 0; };
+	auto has_ex_style = [&window_ex_style](DWORD ex_style) { return (window_ex_style & ex_style) != 0; };
 
 	// Toolbars, tooltips and similar topmost windows
 	if (has_style(WS_POPUP) && has_ex_style(WS_EX_TOOLWINDOW))
@@ -90,18 +85,18 @@
 
 static bool VerifyClassName(const std::wstring& name) {
 	static const std::set<std::wstring> invalid_names = {
-		// System classes
-		L"#32770",         // Dialog box
-		L"CabinetWClass",  // Windows Explorer
-		L"ComboLBox",
-		L"DDEMLEvent",
-		L"DDEMLMom",
-		L"DirectUIHWND",
-		L"GDI+ Hook Window Class",
-		L"IME",
-		L"Internet Explorer_Hidden",
-		L"MSCTFIME UI",
-		L"tooltips_class32",
+	    // System classes
+	    L"#32770",        // Dialog box
+	    L"CabinetWClass", // Windows Explorer
+	    L"ComboLBox",
+	    L"DDEMLEvent",
+	    L"DDEMLMom",
+	    L"DirectUIHWND",
+	    L"GDI+ Hook Window Class",
+	    L"IME",
+	    L"Internet Explorer_Hidden",
+	    L"MSCTFIME UI",
+	    L"tooltips_class32",
 	};
 
 	return !name.empty() && !invalid_names.count(name);
@@ -113,12 +108,12 @@
 
 static bool VerifyProcessFileName(const std::wstring& name) {
 	static const std::set<std::wstring> invalid_names = {
-		// System files
-		L"explorer",    // Windows Explorer
-		L"taskeng",     // Task Scheduler Engine
-		L"taskhost",    // Host Process for Windows Tasks
-		L"taskhostex",  // Host Process for Windows Tasks
-		L"Taskmgr",     // Task Manager
+	    // System files
+	    L"explorer",   // Windows Explorer
+	    L"taskeng",    // Task Scheduler Engine
+	    L"taskhost",   // Host Process for Windows Tasks
+	    L"taskhostex", // Host Process for Windows Tasks
+	    L"Taskmgr",    // Task Manager
 	};
 
 	return !name.empty() && !invalid_names.count(name);
@@ -176,4 +171,4 @@
 	return ::EnumWindows(EnumWindowsProc, param) != FALSE;
 }
 
-} // namespace animia::win::detail
\ No newline at end of file
+} // namespace animia::internal::win32
\ No newline at end of file
--- /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;
+}
+
+}