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. Я эту ОС практически не знаю (да и нет ее у меня).

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

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

RSS RSS-рассылка

Популярное

Дешевый хостинг