src/X11Command.h
branchv_0
changeset 7 039b3f8a3442
parent 5 7afa994c98f0
child 8 b498160cc2ab
--- a/src/X11Command.h	Wed Apr 07 22:55:00 2021 +0200
+++ b/src/X11Command.h	Mon Apr 05 15:37:28 2021 +0200
@@ -23,6 +23,7 @@
 #include <stdexcept>
 
 #include <X11/extensions/XInput.h>
+#include <X11/Xutil.h>
 
 #include "Configuration.h"
 
@@ -262,6 +263,79 @@
 		}
 	}
 
+	relpipe::common::type::StringX fetchWindowName(const Display& display, Window window) {
+		relpipe::common::type::StringX name;
+		// TODO: this does not work → use XGetWMName(), XmbTextPropertyToTextList(), XFreeStringList() instead of XFetchName()
+		// char* rawName = nullptr;
+		// if (XFetchName(display.display, window, &rawName) && rawName) 
+		// name = convertor.from_bytes(rawName); // bad encoding, std::range_error – wstring_convert::from_bytes
+		// std::cout << "\n\n\n>>> " << rawName << " <<<\n\n\n"; // bad encoding, not UTF-8
+		//XFree(rawName);
+		return name;
+	}
+
+	void listWindow(const Display& display, Window window, relpipe::common::type::Integer level, Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer, std::function<void() > relationalWriterFlush) {
+		Window rootWindow;
+		Window parentWindow;
+		unsigned int childrenCount;
+		Window* childrenList;
+		if (!XQueryTree(display.display, window, &rootWindow, &parentWindow, &childrenList, &childrenCount))
+			throw std::invalid_argument("Unable to query the tree for window: " + std::to_string(window));
+
+		XWindowAttributes windowAttributes;
+		if (!XGetWindowAttributes(display.display, window, &windowAttributes))
+			throw std::invalid_argument("Unable to get attributes for window: " + std::to_string(window));
+
+		XClassHint classHint;
+		relpipe::common::type::StringX resClass;
+		relpipe::common::type::StringX resName;
+		if (XGetClassHint(display.display, window, &classHint)) {
+			if (classHint.res_class) resClass = convertor.from_bytes(classHint.res_class);
+			if (classHint.res_name) resName = convertor.from_bytes(classHint.res_name);
+			XFree(classHint.res_class);
+			XFree(classHint.res_name);
+		}
+
+		writer->writeAttribute(std::to_wstring(window));
+		// writer->writeAttribute(std::to_wstring(screen?));
+		// writer->writeAttribute(std::to_wstring(root_win));
+		writer->writeAttribute(std::to_wstring(parentWindow));
+		writer->writeAttribute(&level, typeid (level));
+		writer->writeAttribute(fetchWindowName(display, window));
+		writer->writeAttribute(resClass);
+		writer->writeAttribute(resName);
+		writer->writeAttribute(std::to_wstring(windowAttributes.x));
+		writer->writeAttribute(std::to_wstring(windowAttributes.y));
+		writer->writeAttribute(std::to_wstring(windowAttributes.width));
+		writer->writeAttribute(std::to_wstring(windowAttributes.height));
+
+		for (unsigned int i = 0; i < childrenCount; i++) listWindow(display, childrenList[i], level + 1, configuration, writer, relationalWriterFlush);
+
+		XFree(childrenList);
+	}
+
+	void listWindows(const Display& display, Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer, std::function<void() > relationalWriterFlush) {
+		writer->startRelation(L"x11_window",{
+			{L"id", relpipe::writer::TypeId::INTEGER},
+			// {L"screen", relpipe::writer::TypeId::INTEGER},
+			// {L"root", relpipe::writer::TypeId::INTEGER},
+			{L"parent", relpipe::writer::TypeId::INTEGER},
+			{L"level", relpipe::writer::TypeId::INTEGER},
+			{L"name", relpipe::writer::TypeId::STRING},
+			{L"res_class", relpipe::writer::TypeId::STRING},
+			{L"res_name", relpipe::writer::TypeId::STRING},
+			{L"x", relpipe::writer::TypeId::INTEGER},
+			{L"y", relpipe::writer::TypeId::INTEGER},
+			{L"width", relpipe::writer::TypeId::INTEGER},
+			{L"height", relpipe::writer::TypeId::INTEGER},
+		}, true);
+
+		int screen = DefaultScreen(display.display);
+		Window window = RootWindow(display.display, screen);
+
+		listWindow(display, window, 0, configuration, writer, relationalWriterFlush);
+	}
+
 	static int handleXError(::Display* display, XErrorEvent* errorEvent) {
 		std::wcerr << L"X11 error:"
 				<< L" display=" << errorEvent->display
@@ -287,6 +361,8 @@
 		if (display.display) {
 			if (configuration.listInputDevices) listInputDevices(display, configuration, writer, relationalWriterFlush);
 			if (configuration.listInputEvents) listInputEvents(display, configuration, writer, relationalWriterFlush);
+			if (configuration.listWindows) listWindows(display, configuration, writer, relationalWriterFlush);
+			// TODO: list screens
 		} else {
 			throw std::invalid_argument("Unable to open display. Please check the $DISPLAY variable.");
 		}