changeset 158:80d6b28eb29f

dep/animia: fix most X11 stuff it looks like _NET_WM_PID isn't supported by MOST clients, or my code is wrong... core/filesystem: fix Linux config path handling on *nix
author Paper <mrpapersonic@gmail.com>
date Fri, 17 Nov 2023 02:07:33 -0500
parents 18c8eb5d1edc
children 36feb332b7c7
files dep/animia/CMakeLists.txt dep/animia/README.md dep/animia/src/animia.cc dep/animia/src/util.cc dep/animia/src/win.cc dep/animia/src/win/x11.cc src/core/filesystem.cc
diffstat 7 files changed, 101 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/dep/animia/CMakeLists.txt	Thu Nov 16 16:51:34 2023 -0500
+++ b/dep/animia/CMakeLists.txt	Fri Nov 17 02:07:33 2023 -0500
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.16)
 project(animia LANGUAGES CXX)
 set(SRC_FILES
 	# any non-platform-specific files go here
@@ -11,64 +11,79 @@
 )
 
 set(LIBRARIES)
-
-set(INCLUDE_DIRS
-	include
-)
-
+set(INCLUDE_DIRS)
 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
+if(APPLE)
 	list(APPEND DEFINES MACOSX)
 	list(APPEND SRC_FILES
 		# xnu stuff
 		src/fd/xnu.cc
 	)
+	check_language(OBJCXX)
+	if(CMAKE_OBJCXX_COMPILER)
+		enable_language(OBJCXX)
+		list(APPEND SRC_FILES
+			src/win/quartz.mm
+		)
+		find_library(FOUNDATION_LIBRARY Foundation)
+		find_library(COREGRAPHICS_LIBRARY CoreGraphics)
+		find_library(APPKIT_LIBRARY AppKit)
+		list(APPEND LIBRARIES ${FOUNDATION_LIBRARY} ${COREGRAPHICS_LIBRARY} ${APPKIT_LIBRARY})
+	else() # NOT CMAKE_OBJCXX_COMPILER
+		message(WARNING "An Objective-C++ compiler couldn't be found! Window enumeration support will not be compiled.")
+	endif() # CMAKE_OBJCXX_COMPILER
 elseif(WIN32)
 	list(APPEND DEFINES WIN32)
 	list(APPEND SRC_FILES
 		# win32
 		src/fd/win32.cc
-	)
-endif()
-
-# Windows
-if(WIN32)
-	list(APPEND SRC_FILES
 		src/win/win32.cc
 		src/util/win32.cc
 	)
-elseif(APPLE)
-	enable_language(OBJCXX)
-	list(APPEND SRC_FILES
-		src/win/quartz.mm
-	)
-	find_library(FOUNDATION_LIBRARY Foundation)
-	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)
+else() # NOT WIN32 AND NOT APPLE
+	if(LINUX)
+		list(APPEND DEFINES LINUX)
+		list(APPEND SRC_FILES
+			# linux
+			src/fd/linux.cc
+		)
+	endif() # LINUX
+
+	# X11
+	find_package(X11 COMPONENTS X11)
+	if(X11_FOUND)
 		list(APPEND DEFINES X11)
 		list(APPEND SRC_FILES
 			src/win/x11.cc
 		)
 		list(APPEND INCLUDE_DIRS
-			${X11_INCLUDE_DIR}
+			${X11_INCLUDE_DIRS}
 		)
 		list(APPEND LIBRARIES
 			${X11_LIBRARIES}
 		)
-	endif()
-endif()
+	else() # NOT X11_FOUND
+		# For some systems, i.e. Debian, FindX11 fails to find X11, so we have
+		# to use pkg_config as a fallback
+		find_package(PkgConfig)
+		if(PKG_CONFIG_FOUND)
+			pkg_check_modules(X11 x11)
+			if(X11_FOUND)
+				list(APPEND DEFINES X11)
+				list(APPEND SRC_FILES
+					src/win/x11.cc
+				)
+				list(APPEND INCLUDE_DIRS
+					${X11_INCLUDE_DIRS}
+				)
+				list(APPEND LIBRARIES
+					${X11_LIBRARIES}
+				)
+			endif() # X11_FOUND
+		endif() # PKG_CONFIG_FOUND
+	endif() # X11_FOUND
+endif() # WIN32 AND APPLE
 
 add_library(animia SHARED ${SRC_FILES})
 set_target_properties(animia PROPERTIES
@@ -76,16 +91,6 @@
 	CXX_STANDARD 17
 )
 
-if(WIN32)
-	target_compile_definitions(animia PUBLIC WIN32)
-elseif(LINUX)
-	target_compile_definitions(animia PUBLIC LINUX)
-elseif(UNIX)
-	if(APPLE)
-		target_compile_definitions(animia PUBLIC MACOSX)
-	endif()
-	target_compile_definitions(animia PUBLIC UNIX)
-endif()
-
-target_include_directories(animia PRIVATE include)
+target_compile_definitions(animia PUBLIC ${DEFINES})
+target_include_directories(animia PRIVATE include PUBLIC ${INCLUDE_DIRS})
 target_link_libraries(animia PUBLIC ${LIBRARIES})
--- a/dep/animia/README.md	Thu Nov 16 16:51:34 2023 -0500
+++ b/dep/animia/README.md	Fri Nov 17 02:07:33 2023 -0500
@@ -2,3 +2,7 @@
 Animia is a work-in-progress cross-platform hard fork of Anisthesia and part of Minori.
 
 Most (if not all) Anisthesia configs should also work in this library as well (at least on Windows).
+
+## Support
+Animia supports Windows, macOS, and Linux when dealing with file descriptors. When enumerating windows, it supports Windows, macOS (Quartz), X11. I'd love to be able to support Wayland, but there's nothing I can do to provide an API that literally does not exist.
+
--- a/dep/animia/src/animia.cc	Thu Nov 16 16:51:34 2023 -0500
+++ b/dep/animia/src/animia.cc	Fri Nov 17 02:07:33 2023 -0500
@@ -9,6 +9,8 @@
 #include <string>
 #include <vector>
 
+#include <iostream>
+
 namespace animia {
 
 namespace internal {
@@ -70,6 +72,11 @@
 	         We should set the PID of the process if we can get it, but that'll be for when
 	         I can actually be arsed to implement the X11 backend. */
 	auto window_proc = [&](const Process& process, const Window& window) -> bool {
+		std::cout << "Window ID: " << window.id << "\n"
+			<< "\tClass name: " << window.class_name << "\n"
+			<< "\tTitle text: " << window.text << "\n"
+			<< "\tProcess info: " << "\n"
+			<< "\t\tPID: " << process.pid << "\n";
 		for (const auto& player : players) {
 			if (!internal::PlayerHasStrategy(player, Strategy::WindowTitle))
 				continue;
--- a/dep/animia/src/util.cc	Thu Nov 16 16:51:34 2023 -0500
+++ b/dep/animia/src/util.cc	Fri Nov 17 02:07:33 2023 -0500
@@ -10,16 +10,14 @@
 
 bool ReadFile(const std::string& path, std::string& data) {
 	std::ifstream file(path.c_str(), std::ios::in | std::ios::binary);
-
 	if (!file)
 		return false;
 
-	file.seekg(0, std::ios::end);
-	data.resize(static_cast<size_t>(file.tellg()));
-	file.seekg(0, std::ios::beg);
+	std::ostringstream string;
+	string << file.rdbuf();
+	file.close();
 
-	file.read(&data.front(), data.size());
-	file.close();
+	data = string.str();
 
 	return true;
 }
--- a/dep/animia/src/win.cc	Thu Nov 16 16:51:34 2023 -0500
+++ b/dep/animia/src/win.cc	Fri Nov 17 02:07:33 2023 -0500
@@ -4,6 +4,8 @@
 #	include "animia/win/win32.h"
 #elif MACOSX
 #	include "animia/win/quartz.h"
+#elif X11
+#	include "animia/win/x11.h"
 #endif
 
 namespace animia::internal {
--- a/dep/animia/src/win/x11.cc	Thu Nov 16 16:51:34 2023 -0500
+++ b/dep/animia/src/win/x11.cc	Fri Nov 17 02:07:33 2023 -0500
@@ -5,8 +5,11 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h> // XA_*
+
 #include <cstdint>
 #include <string>
+#include <memory>
+#include <set>
 
 /* 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
@@ -15,20 +18,17 @@
 namespace animia::internal::x11 {
 
 /* should return UTF8_STRING or STRING */
-static bool GetWindowPropertyAsString(::Display* display, ::Window window, const char* atom, std::string& result, ::Atom reqtype = AnyPropertyType) {
+static bool GetWindowPropertyAsString(::Display* display, ::Window window, ::Atom atom, std::string& result, ::Atom reqtype = AnyPropertyType) {
 	int format;
 	unsigned long leftover_bytes, num_of_items;
 	::Atom type;
 	unsigned char* data;
-
-	if (!::XGetWindowProperty(display, window, ::XInternAtom(display, atom, False), 0L, (~0L), False, reqtype,
-	                            &type, &format, &num_of_items, &leftover_bytes, &data))
+	if (!::XGetWindowProperty(display, window, atom, 0L, (~0L), False, reqtype,
+	                       &type, &format, &num_of_items, &leftover_bytes, &data))
 		return false;
 
 	result = std::string((char*)data, num_of_items);
 
-	::XFree(data);
-
 	return true;
 }
 
@@ -36,24 +36,22 @@
 static bool GetWindowPID(::Display* display, ::Window window, pid_t& result) {
 	int format;
 	unsigned long leftover_bytes, num_of_items;
-	::Atom reqtype = XA_CARDINAL, atom = ::XInternAtom(display, "_NET_WM_PID", False), type;
+	::Atom atom = ::XInternAtom(display, "_NET_WM_PID", False), type;
 	unsigned char* data;
 
-	/* TODO: check the type for this */
-	if (!::XGetWindowProperty(display, window, atom, 0L, (~0L), False, reqtype,
-	                          &type, &format, &num_of_items, &leftover_bytes, &data))
+	if (!::XGetWindowProperty(display, window, atom, 0L, (~0L), False, XA_CARDINAL,
+	                       &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)))
+	if (GetWindowPropertyAsString(display, window, ::XInternAtom(display, "_NET_WM_NAME", False),
+		                           result, ::XInternAtom(display, "UTF8_STRING", False)))
 		return true;
 
 	/* Fallback to XGetWMName() */
@@ -85,31 +83,29 @@
 }
 
 bool X11WinTools::EnumerateWindows(window_proc_t window_proc) {
-	auto get_window_property = [&](::Display* display, ::Window window, ::Atom atom, unsigned long& num_of_items, unsigned char** data) -> int {
-		int format;
-		unsigned long leftover_bytes;
-		::Atom realtype;
-
-		return ::XGetWindowProperty(display, window, atom, 0L, (~0L), false, AnyPropertyType,
-		                            &realtype, &format, &num_of_items, &leftover_bytes, data);
-	};
+	if (!window_proc)
+		return false;
 
 	::Display* display = ::XOpenDisplay(nullptr);
 	::Window root = DefaultRootWindow(display);
 
-	unsigned long num_windows;
+	unsigned int num_windows = 0;
 	::Window* windows = nullptr;
 
-	int status = get_window_property(display, root, ::XInternAtom(display, "_NET_CLIENT_LIST", true), num_windows, (unsigned char**)&windows);
+	{
+		::Window root_return;
+		::Window parent_return;
 
-	if (status < Success)
-		return false;
+		int status = ::XQueryTree(display, root, &root_return, &parent_return, &windows, &num_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];
+		win.id = window;
 		{
 			::XClassHint* hint = ::XAllocClassHint();
 			if (::XGetClassHint(display, window, hint)) {
@@ -126,6 +122,8 @@
 			return false;
 	}
 
+	::XFree(windows);
+
 	return true;
 }
 
--- a/src/core/filesystem.cc	Thu Nov 16 16:51:34 2023 -0500
+++ b/src/core/filesystem.cc	Fri Nov 17 02:07:33 2023 -0500
@@ -27,7 +27,12 @@
 /* this runs fs::create_directories() on the
    PARENT directory. */
 void CreateDirectories(const std::filesystem::path& path) {
-	std::filesystem::create_directories(path.parent_path());
+	if (path.empty())
+		return;
+
+	const auto& parent = path.parent_path();
+	if (!std::filesystem::exists(parent))
+		std::filesystem::create_directories(parent);
 }
 
 std::filesystem::path GetDotPath() {
@@ -49,8 +54,8 @@
 	if (!home)
 		home = getpwuid(getuid())->pw_dir;
 #	endif // __linux__
-	if (!home)
-		return std::filesystem::path(home) / ".config";
+	if (home)
+		return std::filesystem::path(home) / ".config" / CONFIG_DIR;
 	else
 		return std::filesystem::path();
 #endif     // !WIN32 && !MACOSX