2009-06-19 6 views
13

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

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

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

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

Update:

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

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

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

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

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; 
} 

ответ

16

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

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

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

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

+1

Спасибо! Я взглянул на исходный код для xwininfo и, похоже, делает обход дерева так же, как и я: без защиты конструкций вокруг него. Поэтому, если есть вероятность изменения дерева между вызовами XQueryTree, xwininfo также будет затронута и не даст правильных результатов, я думаю ... – Marten

+1

@Marten, да. xwininfo - это моментальный снимок, но он даст вам иерархию. Затем вы можете открыть несколько окон и использовать их для запуска xprop -spy для проверки обновлений. Есть немало таких инструментов. Взгляните на список справочных страниц по адресу http://www.x.org/archive/X11R6.9.0/doc/html/manindex1.html –

3

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

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

+1

XGrabServer предоставит вам полное внимание, но также отключит всех других клиентов, что делает его бесполезно для этого –

+0

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

0

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

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