Я хочу контролировать все открытые окна под X11. В настоящее время я делаю это следующим образом:
- Первоначально обойдя все дерево, рекурсивно вызывая XQueryTree из корневого окна
- Прослушивание изменений подструктуры на всем рабочем столе:
XSelectInput( display, root_window, SubstructureNotifyMask | PropertyChangeMask )
- Обработка всех событий MapNotify, UnmapNotify и DestroyNotify, обновление моего собственного списка окон в процессе
Меня больше всего беспокоит пункт 1. Во время рекурсии XQueryTree будет вызываться несколько раз. Есть ли способ гарантировать, что дерево не изменится за это время? Другими словами, чтобы получить «снимок» всего дерева в один момент времени?
Кроме того, я заметил, что в некоторых системах X11 не все события поступают правильно. Например, при открытии нового окна на рабочем столе MapNotify для этого окна может никогда не попасть в мое приложение для мониторинга. Как это может быть? Возможно ли, чтобы его выбросили до прибытия?
Обновление:
Я написал небольшую программу, которая будет отслеживать события 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;
}