Поставим задачу: создать Linux-приложение, которое находит все окна графической оболочки и выводит для них заголовки, координаты (положение на экране) и размер (высоту и ширину).
Решение: используем возможности библиотеки XLib, а именно ее функции: XGetWindowProperty() и XGetWindowAttributes().
План действий:
- Открываем экран по умолчанию;
- Находим идентификаторы всех окон с помощью XGetWindowProperty() (создадим вспомогательную функцию findWindows();
- Для каждого окна определяем заголовок с помощью той же функции XGetWindowProperty() (создаем функцию getWindowName()). Дополнительно запрашиваем атрибуты окна (координаты и размер) с помощью XGetWindowAttributes().
Пример вывода для окна браузера Chromium:
1 2 |
58720257: TECH GEEK – Chromium > Rect: [0, 36, 1920x1009] |
Реализация
Файл main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
#include <QCoreApplication> #include <X11/Xlib.h> #include <X11/Xatom.h> #include <iostream> Window* findWindows( Display* display, ulong* winCount ) { Atom actualType; int format; ulong bytesAfter; uchar* list = NULL; Status status = XGetWindowProperty( display, DefaultRootWindow( display ), XInternAtom( display, "_NET_CLIENT_LIST", False ), 0L, ~0L, False, XA_WINDOW, &actualType, &format, winCount, &bytesAfter, &list ); if( status != Success ) { *winCount = 0; return NULL; } return reinterpret_cast< Window* >( list ); } char* getWindowName( Display* display, Window win ) { Atom actualType; int format; ulong count, bytesAfter; uchar* name = NULL; Status status = XGetWindowProperty( display, win, XInternAtom( display, "_NET_WM_NAME", False ), 0L, ~0L, False, XInternAtom( display, "UTF8_STRING", False ), &actualType, &format, &count, &bytesAfter, &name ); if( status != Success ) { return NULL; } if( name == NULL ) { Status status = XGetWindowProperty( display, win, XInternAtom( display, "WM_NAME", False ), 0L, ~0L, False, AnyPropertyType, &actualType, &format, &count, &bytesAfter, &name ); if( status != Success ) { return NULL; } } return reinterpret_cast< char* >( name ); } int main() { setlocale( LC_ALL, "" ); if( Display* display = XOpenDisplay( NULL ) ) { ulong count = 0; Window* wins = findWindows( display, &count ); for( ulong i = 0; i < count; ++i ) { Window w = wins[ i ]; std::wcout << w; if( char* name = getWindowName( display, w ) ) { std::wcout << ": " << QString::fromUtf8( name ).toStdWString(); XFree( name ); } std::wcout << std::endl; XWindowAttributes attrs; if( XGetWindowAttributes( display, w, &attrs ) ) { Window child; if( XTranslateCoordinates( display, w, attrs.root, 0, 0, &attrs.x, &attrs.y, &child ) ) { std::wcout << QString( " > Rect: [%1, %2, %3x%4]" ). arg( attrs.x ).arg( attrs.y ). arg( attrs.width ).arg( attrs.height ). toStdWString(); std::wcout << std::endl; } } } if( wins ) { XFree( wins ); } XCloseDisplay( display ); } return 0; } |
Несколько замечаний по реализации:
- Для успешной сборки проекта необходимо подключить библиотеку X11: LIBS += -lX11;
- Не все окна выдают свое имя в формате UTF-8, поэтому в качестве запасного варианта мы запрашиваем хоть какой-то идентифицирующий окно текст, вызывая XGetWindowProperty() с параметром WM_NAME;
- Для вывода текста в формате UTF-8 на консоль Linux не забываем настроить кодировку приложения setlocale( LC_ALL, "" );
- Координаты левого верхнего угла окна (без учета рамки), которые возвращает XGetWindowAttributes(), отложены в системе координат самого этого окна, но нас интересуют абсолютные координаты окна на экране. Поэтому мы выполняем преобразование точки (x; y) в систему координат родительского окна с помощью XTranslateCoordinates().