Я хочу отслеживать все открытые окна под 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;
}