Подтвердить что ты не робот

Как получить и синхронизировать полный список всех окон X11?

Я хочу отслеживать все открытые окна под X11. В настоящее время я делаю это следующим образом:

  • Изначально проецирование всего дерева путем рекурсивного вызова XQueryTree из корневого окна
  • Прослушивание изменений подструктуры на всем рабочем столе: XSelectInput( display, root_window, SubstructureNotifyMask | PropertyChangeMask )
  • Обработка всех событий MapNotify, UnmapNotify и DestroyNotify, обновление моего собственного списка окон в процессе

В основном я беспокоюсь о точке 1. Во время рекурсии XQueryTree будет вызываться несколько раз. Есть ли способ гарантировать, что дерево не изменится тем временем? Другими словами, чтобы получить "снимок" всего дерева в один момент времени?

Кроме того, я заметил, что в некоторых системах X11 не все события поступают правильно. Например, при открытии нового окна на рабочем столе MapNotify для этого окна может никогда не появиться в моем приложении мониторинга. Как это может быть? Возможно ли, что он выброшен до прибытия?

Update:

Я написал небольшую программу, которая будет отслеживать события X в корневом окне (см. ниже). Теперь, когда я запускаю эту программу и запускаю и завершаю xcalc, я получаю следующий вывод:

Reparented: 0x4a0005b to 0x1001e40
Mapped    : 0x1001e40
Destroyed : 0x1001e40

Что это. Я никогда не уведомляю об уничтожении реального окна (0x4a0005b). Даже при этом не отображается! Может ли кто-нибудь сказать мне, почему бы и нет? Подструктура SubStructureNotifyMask вызывает только сообщения подкадров direct вместо всего поддерева?

Кстати, это, похоже, не происходит, когда работает Compiz. Затем никакого повторного убора не производится:

Mapped    : 0x4a0005b
Mapped    : 0x4e00233
Destroyed : 0x4a0005b
Destroyed : 0x4e00233

Источник программы мониторинга:

#include <X11/Xlib.h>
#include <cstdio>

int main()
{
    Display *display;
    Window rootwin;

    display = XOpenDisplay( NULL );
    rootwin = DefaultRootWindow( display );
    XSelectInput( display, rootwin, SubstructureNotifyMask );

    XEvent event;

    while ( 1 ) {
        XNextEvent( display, &event );
        if ( event.type == MapNotify ) {
            XMapEvent *mapevent = (XMapEvent *)&event;
            printf( "Mapped    : 0x%x\n", (unsigned int)(mapevent->window) );
        }
        if ( event.type == DestroyNotify ) {
            XDestroyWindowEvent *destroywindowevent = (XDestroyWindowEvent *)&event;
            printf( "Destroyed : 0x%x\n", (unsigned int)(destroywindowevent->window) );
        }
        if ( event.type == ReparentNotify ) {
            XReparentEvent *reparentevent = (XReparentEvent *)&event;
            printf( "Reparented: 0x%x to 0x%x\n", (unsigned int)(reparentevent->window), (unsigned int)(reparentevent->parent) );
        }
    }

    return 0;
}
4b9b3361

Ответ 1

Посмотрите xwininfo.

Вам также могут понравиться xprop и xspy для получения дополнительной информации.

Обновление: Да. Попробуйте использовать xwininfo и -root с помощью -tree или -children, чтобы задействовать все окна.

И изменения можно отслеживать с помощью xprop -spy.

Ответ 2

Я считаю, что захват X-сервера (XGrabServer (3)) предотвратит изменения в иерархии окон. Это немного тяжело, хотя, возможно, вы должны делать это только в том случае, если вам это действительно нужно.

Для примера кода, который просматривает иерархию окон, создает дерево, использует события окна, чтобы поддерживать его в актуальном состоянии, и игнорирует ошибки протокола X, которые неизбежны из-за рас, см. файл src/VBox/Additions/x11/VBoxClient/seamless-x11.cpp в исходном коде для VirtualBox.

Ответ 3

X11 - это удаленный протокол. Это означает, что когда вы запрашиваете X-сервер для получения какой-либо информации, вы всегда получаете свою собственную копию. Ваша копия никогда не изменяется, когда X-сервер обновляет свои внутренние структуры данных.

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