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は、サブツリー全体ではなく直接サブウィンドウのイベントのみを送信しますか?
ちなみに、これは 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;
}