diff -r 1b17b8cdbfc3 -r 039b3f8a3442 src/X11Command.h --- 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 #include +#include #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, std::function 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, std::function 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."); }