2009-07-29 31 views
12

私はX11セッションですべてのトップレベルデスクトップウィンドウのリストを取得しようとしています。基本的には、ウィンドウマネージャのアプリケーション切り替えUI(一般に、ユーザーがAlt + Tabキーを押したときに開く)に表示されるすべてのウィンドウのリストを取得したいと考えています。xlibを使ってトップレベルのX11ウィンドウを特定する方法は?

私の前に任意の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のプログラミングで見つけたすべてのリファレンスドキュメントは非常に乾燥しており、理解しづらいものです。おそらく、誰かがより良いリソースを指すことができるでしょうか?

答えて

11

私には解決策があります。

まあ、並べ替え。

ウィンドウマネージャが拡張ウィンドウマネージャのヒント(EWMH)を使用する場合は、 "_NET_CLIENT_LIST"アトムを使用してルートウィンドウを照会できます。このウィンドウマネージャが管理しているクライアントウィンドウのリストです。詳細については、hereを参照してください。

しかし、これにはいくつかの問題があります。まず、使用しているウィンドウマネージャが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); 
    } 
+0

このコードは正しくありませんが、 32ビット形式は、クライアントではなくサーバーで使用されるビット数を示します。クライアントは常にXID値を表すために「long」を使用します。あなたの配列はquint32ではなく 'long'の配列でなければなりません。 –

1

Xlibを使用する必要がない場合は、GDKのgdk_screen_get_window_stack()gdk_window_get_window_type()を使用すると、必要に応じて役立ちます。

6

は、以前のソリューションに展開するには:

// 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); 
+0

うん、情報ありがとう。 – Thomi

+0

'XFetchName'は成功するかもしれないが、' name = NULL'をセットすることに注意してください。この場合、あなたの例がクラッシュします。また、 'char * name = '\ 0';'は誤解を招くので、文字はポインタではないので定数は 'NULL'のように見えます。 – Ruslan

+0

NULL名を処理する固定コード。 – Ben

関連する問題