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

13

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

Initially walking the whole tree by recursively calling XQueryTree from the root window Listening for substructure changes on the whole desktop: XSelectInput( display, root_window, SubstructureNotifyMask | PropertyChangeMask ) Handling all MapNotify, UnmapNotify and DestroyNotify events, updating my own list of windows in the process

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

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

Update:

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

<code>Reparented: 0x4a0005b to 0x1001e40
Mapped    : 0x1001e40
Destroyed : 0x1001e40
</code>

Вот и все.I'm never notified of the real window (0x4a0005b) being destroyed. Not even of it being mapped! Может кто-нибудь сказать мне, почему нет? SubStructureNotifyMask вызывает только событияdirect Подокна будут отправлены вместо целого поддерева?

Кстати, этого, очевидно, не происходит, когда Compiz работает. Тогда никакое перевоспитание не сделано:

<code>Mapped    : 0x4a0005b
Mapped    : 0x4e00233
Destroyed : 0x4a0005b
Destroyed : 0x4e00233
</code>

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

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

Ваш Ответ

3   ответа
0

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

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

3

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

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

XGrabServer уделит вам полное внимание, но он также отключает все другие клиенты, что делает его бесполезным для этого
XGrabServer не закрывает соединения других клиентов, он просто останавливает X-сервер от обработки любых запросов к ним, замораживая их все до тех пор, пока вы не освободите захват. Если ваш код когда-либо зависает во время захвата, вы, по сути, заморозили сеанс пользователей, оставив их очень расстроенными из-за вас.
16

Посмотри наxwininfo.

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

Update: Ага. Попробуйте использоватьxwininfo а также-root либо с-tree или же-children чтобы включить все окна.

И изменения могут быть отслежены сxprop -spy.

Спасибо! Я взглянул на исходный код для xwininfo, и он, похоже, выполняет обход дерева так же, как и я: без защиты конструкций вокруг него. Так что, если существует возможность изменения дерева между вызовами XQueryTree, xwininfo также будет затронут и не даст правильных результатов, я думаю ... Marten
@ Мартен, да. xwininfo - это снимок, но он даст вам иерархию. Затем вы можете открыть несколько окон и использовать их для запуска xprop -spy для проверки обновлений. Существует довольно много таких инструментов. Посмотрите список страниц справочника наx.org/archive/X11R6.9.0/doc/html/manindex1.html

Похожие вопросы