16

私が書いているアプリケーション ( AllTrayWM_DELETE_WINDOW )の特定の選択されたウィンドウに投稿されたメッセージを傍受して、アプリケーションがそれを受信する代わりにそれに基づいて行動できるようにしたいと思います。私は現在、可能であれば GDK レベルでこれを試すことを検討していますが、Xlib ソリューションもあれば満足しています。それは可能であるように思われますが、私はそれを成功させる方法を理解していないようです.gdk_display_add_client_message_filter

現在、これを理解するために使用しようとしている 2 つのプログラム (C で記述)あります。そうすることに失敗しているようです。正確には何もしていないようです。これに関するドキュメントが間違っていることを理解していますか、それとも何か追加する必要がありますか (または、このために GDK を完全に使用しないようにする必要がありますか)?WM_DELETE_WINDOW

背景は次のとおりです。AllTray を書き直す前は、X ボタン自体のマウス クリックをインターセプトしようとする方法があったようです。一部のウィンドウ マネージャーでは、これは適切に機能し、他のウィンドウ マネージャーではまったく機能しませんでした。その他のウィンドウ マネージャーでは、ユーザーが手動で構成し、ウィンドウを閉じるボタンの場所を AllTray に指示する必要がありました。私が探しているのは、を含まず、現在の標準に準拠し、ウィンドウが閉じられたときに ClientMessageLD_LIBRARY_PRELOADを送信するウィンドウマネージャー/アプリケーションの組み合わせで機能するソリューションです。WM_DELETE_WINDOW

更新:私はまだ答えを探しています。私が現在取っているルートは、ウィンドウの親を変更して自分で管理しようとすることですが、うまく機能させることができません。再親化すると、それを元に戻すことはできないようです。非常に基本的なものが欠けている可能性がありますが、実際に自分のウィンドウに再び表示させて画面に戻す方法がわかりません。

更新 2 : わかりました、別のレンガの壁にぶつかりました。X サーバーのドキュメントには、ウィンドウのイベント マスクに StructureNotifyMask を設定して、MapNotify イベントと ReparentNotify イベントの両方を受け取るように記載されています。私はどちらかを受け取ることに興味があります。私が現在考えているのは、イベント レシーバーとして機能するウィンドウを作成し、興味深いことのイベントを取得したら、それらを作成して再ペアレント化することです。ただし、これは単に機能していないようです。実際に受け取るイベントは PropertyNotify イベントだけです。そのため、このルートもあまりうまくいっていないようです。

4

4 に答える 4

21

X11のことはわかりませんが、「Intercept WM_DELETE_WINDOWX11」をキーワードにググってみました。17kが見つかりました- MarkMailとMplayer-commits r154 - trunk/libvo。どちらの場合も、彼らは同じことをしています。

 /* This is used to intercept window closing requests.  */
 static Atom wm_delete_window;

以内static void x11_init()

XMapWindow(display, win);
wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, win, &wm_delete_window, 1);

その後、以内static int x11_check_events()に、

XEvent Event;
while (XPending(display)) {
    XNextEvent(display, &Event);
    if (Event.type == ClientMessage) {
        if ((Atom)Event.xclient.data.l[0] == wm_delete_window) {
            /* your code here */
        }
    }
}

XInternAtomXSetWMProtocols、およびXNextEventを参照してください。

上記を書いた後、X11アプリでウィンドウを閉じる処理を見つけました:

ユーザーが X11 アプリケーションの閉じるボタン [x]をクリックすると、「本当に終了しますか?」というダイアログが表示されるようにします。これはプレーンな X アプリです。ここには派手な GTK または QT ウィジェットはありません。では、「ウィンドウが閉じられています」というメッセージをキャッチするにはどうすればよいでしょうか。

答えは、メッセージを呼び出しXSetWMProtocolsて登録することにより、これらのイベントに関心があることを Window Manager に伝えることです。WM_DELETE_WINDOW次に、誰かがウィンドウを閉じようとすると、ウィンドウ マネージャーからクライアント メッセージが表示されますが、ウィンドウは閉じられず、私たちに任せます。これが例です…。

// example.cpp
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>

int main()
{
   Display* display = XOpenDisplay(NULL);
   Window window = XCreateSimpleWindow(display,
                                       DefaultRootWindow(display),
                                       0, 0,
                                       500, 400,
                                       0,
                                       0, 0);

   // register interest in the delete window message
   Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
   XSetWMProtocols(display, window, &wmDeleteMessage, 1);

   std::cout << "Starting up..." << std::endl;
   XMapWindow(display, window);

   while (true) {
      XEvent event;
      XNextEvent(display, &event);

      if (event.type == ClientMessage &&
          event.xclient.data.l[0] == wmDeleteMessage) {
         std::cout << "Shutting down now!!!" << std::endl;
         break;
      }
   }

   XCloseDisplay(display);
   return 0;
}
于 2009-07-27T05:26:19.497 に答える
5

残念ながら、この質問に対する最良の答えは、一連の無回答です。技術的にはそれを達成する方法がありますが、それらにはすべて欠点があり、非常に実用的ではありません。

  1. アプリケーション用の X11 プロキシを作成し、すべての X11 プロトコル メッセージをアプリケーションと X サーバーの間でやり取りします。次に、プロキシは興味深いメッセージをフィルターで除外します。これの欠点は、1 つの小さな小さな機能のオーバーヘッドが非常に大きく、X11 プロトコルが複雑であることです。意図しない結果が生じる可能性もあるため、これはさらに魅力のない選択肢となります。
  2. ウィンドウ マネージャと「興味深い」クライアント アプリケーションの間の仲介役として機能する標準アプリケーションとして起動します。これにより、XDnD などの一部が機能しなくなります。実際には、プロキシが X11 プロトコル レベルではなくウィンドウ レベルであることを除いて、最初のオプションと同じです。
  3. 非ポータブルLD_PRELOADライブラリ トリックを使用します。これにはいくつかの欠点があります。
    1. LD_PRELOADダイナミック リンカー間での移植性はありません。UNIX ライクなシステム間であっても、すべてのダイナミック リンカーが をサポートしているわけではありません。
    2. オペレーティング システム間での移植性はありません。すべてのオペレーティング システムが機能的な動的リンカーをサポートしているわけではありません。
    3. ネットワークの透過性が損なわれます。共有オブジェクト/ダイナミック リンク ライブラリは、実行中の子プロセスとしてホスト上に存在する必要があります。
    4. すべての X11 アプリケーションが Xlib を使用しているわけではありません。LD_PRELOADアプリケーションが X11 と対話するために使用するライブラリごとに、1 つのモジュールを作成する必要があります。
    5. 最後の点に加えて、アプリケーションがLD_PRELOADX と通信するために共有オブジェクトまたは DLL を使用しない可能性があるため、それをサポートするリンカーの下で実行されたとしても、すべてのアプリケーションが影響を受けるわけではありません。たとえば、Java 自体で記述された X11 プロトコル ライブラリを使用する Java アプリケーションを考えてみましょう。
    6. 一部の UNIX ライクなオペレーティング システムでは、LD_PRELOADライブラリを setuid/setgid プログラムで使用する場合、ライブラリを setuid/setgid にする必要があります。もちろん、これは潜在的なセキュリティの脆弱性です。
    7. 私が考えられないより多くの欠点があると確信しています。
  4. X Window システムへの拡張機能を実装します。X11 実装間での移植性はなく、すべてが複雑で複雑になり、まったく問題外です。
  5. ウィンドウ マネージャーに拡張機能またはプラグインを実装します。ウィンドウ マネージャーに関する意見と同じ数のウィンドウ マネージャーが存在するため、これはまったく実行不可能です。

最終的に、完全に別のメカニズムを使用して、最終的に目標を達成することができました。興味のある方は、 github で利用可能な git master ブランチを含む、AllTray 0.7.5.1dev 以降の Close-to-Tray サポートを参照してください。

于 2011-07-29T02:42:47.293 に答える
0

ウィンドウマネージャーがクライアントと通信する方法を説明する ICCCM を読む必要があります。WM のほとんどは、再ペアレント化によってトップレベル ウィンドウを含むフレーム ウィンドウを作成します。したがって、再親が WM とクライアント ウィンドウで認識されている関係を壊す可能性がある場合。

于 2011-06-25T12:53:42.117 に答える
0

わかりました、私の以前の提案を詳しく説明するには、XEmbedを調査することをお勧めします。少なくとも、試してみるべきいくつかのアイデアが得られるかもしれません。

それができない場合は、他の同様のソフトウェアがどのように機能するか (wmdock や GtkPlug/GtkSocket の実装方法など) を調べますが、どちらの場合もアプリケーションで明示的なサポートが必要であると思います。

それがより役立つことを願っています。

于 2009-07-30T21:26:12.550 に答える