IT Notes

XLib: Собираем информацию об окнах в Linux

Поставим задачу: создать Linux-приложение, которое находит все окна графической оболочки и выводит для них заголовки, координаты (положение на экране) и размер (высоту и ширину).

Решение: используем возможности библиотеки XLib, а именно ее функции: XGetWindowProperty() и XGetWindowAttributes().

План действий:

  1. Открываем экран по умолчанию;
  2. Находим идентификаторы всех окон с помощью XGetWindowProperty() (создадим вспомогательную функцию findWindows();
  3. Для каждого окна определяем заголовок с помощью той же функции XGetWindowProperty() (создаем функцию getWindowName()). Дополнительно запрашиваем атрибуты окна (координаты и размер) с помощью XGetWindowAttributes().

Пример вывода для окна браузера Chromium:

58720257: Блог об информационных технологиях - IT Notes — Chromium
  > Rect: [0, 36, 1920x1009]

Реализация

Файл main.cpp:

#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;
}

Несколько замечаний по реализации:

  1. Для успешной сборки проекта необходимо подключить библиотеку X11: LIBS += -lX11;
  2. Не все окна выдают свое имя в формате UTF-8, поэтому в качестве запасного варианта мы запрашиваем хоть какой-то идентифицирующий окно текст, вызывая XGetWindowProperty() с параметром WM_NAME;
  3. Для вывода текста в формате UTF-8 на консоль Linux не забываем настроить кодировку приложения setlocale( LC_ALL, "" );
  4. Координаты левого верхнего угла окна (без учета рамки), которые возвращает XGetWindowAttributes(), отложены в системе координат самого этого окна, но нас интересуют абсолютные координаты окна на экране. Поэтому мы выполняем преобразование точки (x; y) в систему координат родительского окна с помощью XTranslateCoordinates().

Исходники

 Скачать пример использования XLib для поиска заголовков, координат и размеров окон графической оболочки

Похожие публикации

Комментарии

Спасибо за ваши старания! Как всегда полезные статьи, как-то можно подписаться на обновления на сайте? чтобы каждый день не заходить с проверкой))

Anonymous:

Спасибо за ваши старания! Как всегда полезные статьи, как-то можно подписаться на обновления на сайте? чтобы каждый день не заходить с проверкой))

Спасибо за комментарий =)

На сайте доступна RSS-рассылка

Большое спасибо за оперативность! (qprocess)

Anonymous:

Большое спасибо за оперативность! (qprocess)

Пожалуйста =)

Давно хотел спросить: а вы никогда не занимались OpenCV? Интересует связка OpenCV и Qt в linux.

Anonymous:

Давно хотел спросить: а вы никогда не занимались OpenCV? Интересует связка OpenCV и Qt в linux.

OpenCV - достаточно крупная библиотека. Сталкивался с ней при работе с Web-камерами, а также при решении некоторых прикладных задач обработки изображений.

А что именно интересует Вас?

Для начала хотя бы подружить эту библиотеку с Qt и собрать простейший проект. Примеры в интернете либо очень старые, либо поголовно под windows. Я эту ОС практически не знаю (да и нет ее у меня).

А интересует распознавание картинок. Точнее, распознавание наличия некоего шаблона на большом изображении. Возможно, потребуются нейронные сети, но пока хотя бы просто собрать проект.

Anonymous:

Для начала хотя бы подружить эту библиотеку с Qt и собрать простейший проект. Примеры в интернете либо очень старые, либо поголовно под windows. Я эту ОС практически не знаю (да и нет ее у меня).

А интересует распознавание картинок. Точнее, распознавание наличия некоего шаблона на большом изображении. Возможно, потребуются нейронные сети, но пока хотя бы просто собрать проект.

Хорошо. Запланировал выпуск статьи на эту тему.