# HG changeset patch # User František Kučera # Date 1617629848 -7200 # Node ID 039b3f8a344244750b2fff0477ac586be85b5677 # Parent 1b17b8cdbfc3c0dec1f73602050df6733edfc2f4 list windows: first version, --list-windows diff -r 1b17b8cdbfc3 -r 039b3f8a3442 bash-completion.sh --- a/bash-completion.sh Wed Apr 07 22:55:00 2021 +0200 +++ b/bash-completion.sh Mon Apr 05 15:37:28 2021 +0200 @@ -29,10 +29,12 @@ if [[ "$w1" == "--list-input-devices" ]]; then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0")) elif [[ "$w1" == "--list-input-events" ]]; then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0")) + elif [[ "$w1" == "--list-windows" ]]; then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0")) else OPTIONS=( "--list-input-devices" "--list-input-events" + "--list-windows" ) COMPREPLY=($(compgen -W "${OPTIONS[*]}" -- "$w0")) fi diff -r 1b17b8cdbfc3 -r 039b3f8a3442 src/CLIParser.h --- 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& 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"; } } diff -r 1b17b8cdbfc3 -r 039b3f8a3442 src/Configuration.h --- a/src/Configuration.h Wed Apr 07 22:55:00 2021 +0200 +++ b/src/Configuration.h Mon Apr 05 15:37:28 2021 +0200 @@ -30,6 +30,7 @@ public: bool listInputDevices = false; bool listInputEvents = false; + bool listWindows = false; virtual ~Configuration() { } 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."); }