xlibを使用して最上位のX11ウィンドウを識別する方法
質問
X11セッションですべてのトップレベルのデスクトップウィンドウのリストを取得しようとしています。基本的に、ウィンドウマネージャーのアプリケーション切り替えUIに表示されるすべてのウィンドウの一覧を取得します(ユーザーがAlt + Tabキーを押すと一般的に開きます)。
X11プログラミングを行ったことは一度もありませんが、これまでのところ、次のようなコードでウィンドウリスト全体を列挙することができました。
void CSoftwareInfoLinux::enumerateWindows(Display *display, Window rootWindow)
{
Window parent;
Window *children;
Window *child;
quint32 nNumChildren;
XTextProperty wmName;
XTextProperty wmCommand;
int status = XGetWMName(display, rootWindow, &wmName);
if (status && wmName.value && wmName.nitems)
{
int i;
char **list;
status = XmbTextPropertyToTextList(display, &wmName, &list, &i);
if (status >= Success && i && *list)
{
qDebug() << "Found window with name:" << (char*) *list;
}
status = XGetCommand(display, rootWindow, &list, &i);
if (status >= Success && i && *list)
{
qDebug() << "... and Command:" << i << (char*) *list;
}
Window tf;
status = XGetTransientForHint(display, rootWindow, &tf);
if (status >= Success && tf)
{
qDebug() << "TF set!";
}
XWMHints *pHints = XGetWMHints(display, rootWindow);
if (pHints)
{
qDebug() << "Flags:" << pHints->flags
<< "Window group:" << pHints->window_group;
}
}
status = XQueryTree(display, rootWindow, &rootWindow, &parent, &children, &nNumChildren);
if (status == 0)
{
// Could not query window tree further, aborting
return;
}
if (nNumChildren == 0)
{
// No more children found. Aborting
return;
}
for (int i = 0; i < nNumChildren; i++)
{
enumerateWindows(display, children[i]);
}
XFree((char*) children);
}
enumerateWindows()
は、最初にルートウィンドウで呼び出されます。
これは、何百ものウィンドウに関する情報を出力する限り、動作します-必要なのは、特定の Window
がトップレベルであるかどうかを判断するために問い合わせることができるプロパティを調べることですデスクトップアプリケーションウィンドウ(公式用語がわからない)またはそうでない。
これについて誰かが光を当てることはできますか? X11プログラミング用に見つけたすべてのリファレンスドキュメントはひどくドライで理解しにくいものです。おそらく誰かがより良いリソースを指すことができますか?
解決
解決策があります!
まあ、ちょっと。
ウィンドウマネージャーが拡張ウィンドウマネージャーヒント(EWMH)を使用している場合、&quot; _NET_CLIENT_LIST
&quot;を使用してルートウィンドウを照会できます。原子。この戻り値は、ウィンドウマネージャーが管理しているクライアントウィンドウのリストです。詳細については、こちらをご覧ください。
ただし、これにはいくつかの問題があります。開始するには、使用中のウィンドウマネージャがEWMHをサポートする必要があります。 KDEとGNOMEも同様であり、他の一部も同様であると確信しています。しかし、そうではないものがたくさんあると確信しています。また、KDEにいくつかの問題があることに気付きました。基本的に、一部の非KDEアプリケーションはリストに含まれません。たとえば、KDEでxcalcを実行すると、このリストには表示されません。
この方法の改善を提供できる人がいれば、喜んで聞きます。参考までに、使用しているコードを以下に示します。
Atom a = XInternAtom(m_pDisplay, "_NET_CLIENT_LIST" , true);
Atom actualType;
int format;
unsigned long numItems, bytesAfter;
unsigned char *data =0;
int status = XGetWindowProperty(m_pDisplay,
rootWindow,
a,
0L,
(~0L),
false,
AnyPropertyType,
&actualType,
&format,
&numItems,
&bytesAfter,
&data);
if (status >= Success && numItems)
{
// success - we have data: Format should always be 32:
Q_ASSERT(format == 32);
// cast to proper format, and iterate through values:
quint32 *array = (quint32*) data;
for (quint32 k = 0; k < numItems; k++)
{
// get window Id:
Window w = (Window) array[k];
qDebug() << "Scanned client window:" << w;
}
XFree(data);
}
他のヒント
ウィンドウ名を取得したい場合、前のソリューションを展開するには:
// get window Id:
Window w = (Window) array[k];
char* name = '\0';
status = XFetchName(display, w, &name);
if (status >= Success)
{
if (name == NULL)
printf("Found: %ul NULL\n", w);
else
printf("Found: %ul %s\n", w, name);
}
XFree(name);
Xlibを使用する必要がない場合、GDKの gdk_screen_get_window_stack()
および gdk_window_get_window_type()
を使用すると、ニーズに対応できます。