--- a/src/CLIParser.h Wed Apr 07 22:55:00 2021 +0200
+++ b/src/CLIParser.h Mon Apr 05 15:37:28 2021 +0200
@@ -50,6 +50,7 @@
static const relpipe::common::type::StringX OPTION_LIST_INPUT_DEVICES;
static const relpipe::common::type::StringX OPTION_LIST_INPUT_EVENTS;
+ static const relpipe::common::type::StringX OPTION_LIST_WINDOWS;
Configuration parse(const std::vector<relpipe::common::type::StringX>& arguments) {
Configuration c;
@@ -63,6 +64,8 @@
c.listInputDevices = parseBoolean(readNext(arguments, i));
} else if (option == OPTION_LIST_INPUT_EVENTS) {
c.listInputEvents = parseBoolean(readNext(arguments, i));
+ } else if (option == OPTION_LIST_WINDOWS) {
+ c.listWindows = parseBoolean(readNext(arguments, i));
} else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
}
@@ -75,6 +78,7 @@
const relpipe::common::type::StringX CLIParser::OPTION_LIST_INPUT_DEVICES = L"--list-input-devices";
const relpipe::common::type::StringX CLIParser::OPTION_LIST_INPUT_EVENTS = L"--list-input-events";
+const relpipe::common::type::StringX CLIParser::OPTION_LIST_WINDOWS = L"--list-windows";
}
}
--- 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.");
}