在X11上拦截WM_DELETE_WINDOW?

Mic*_*sch 13 c linux x11 events intercept

我想拦截WM_DELETE_WINDOW发布到我正在编写的应用程序(AllTray)的某些窗口选择的消息,以便我可以对其进行操作而不是接收它的应用程序.目前,我看着在GDK级别尝试此通过gdk_display_add_client_message_filter,如果有可能,但我很高兴与Xlib的解决方案,如果有一个为好; 这似乎是可能的,但我似乎并不理解我是如何成功地做到的.

目前,我有两个程序(用C编写),我试图用它来解决这个问题,第一个程序除了创建一个它知道的窗口和寄存器之外什么也没做WM_DELETE_WINDOW,第二个试图捕获该消息,但是似乎没有这样做; 它似乎没有做任何事情.我是否理解文档错误,或者我需要做些什么(或者我是否需要完全避免使用GDK)?

背景是这样的:在我重新编写AllTray之前,它的工作方式似乎是试图拦截鼠标点击X按钮本身.对于某些窗口管理器,这种方法正常工作,对于其他窗口管理器根本不起作用,而对于其他窗口管理器,用户必须手动配置它并指示AllTray关闭窗口的按钮所在的位置.我正在寻找的是一个不涉及的解决方案,LD_LIBRARY_PRELOAD它将适用于任何符合当前标准的窗口管理器/应用程序组合,并WM_DELETE_WINDOW在窗口关闭时发送ClientMessage.

更新:我还在寻找答案.我现在采取的路线是尝试重新调整窗口并自行管理,但我无法使其工作.重新定位后,我似乎无法以任何方式取回它.我可能会遗漏一些非常基本的东西,但我无法弄清楚如何让它再次出现在我自己的窗口,将它带回屏幕.

更新2:好的,所以我打了另一个砖墙.X服务器文档说在窗口的事件掩码上设置StructureNotifyMask以接收MapNotify和ReparentNotify事件.我有兴趣接收任何一个.我目前的想法是创建一个窗口,作为事件接收器,然后当我获得有趣事件的事件时,通过创建和重新创建来对它们进行操作.但是,这根本不起作用.我实际收到的唯一事件是PropertyNotify事件.因此,这条路线似乎也没有做得很好.

Eug*_*ota 13

我不知道X11,但我使用"Intercept WM_DELETE_WINDOWX11"作为关键词进行了Google搜索.找到17k - MarkMailMplayer-提交r154 - trunk/libvo.在这两种情况下,他们都在做同样的事情.

 /* This is used to intercept window closing requests.  */
 static Atom wm_delete_window;
Run Code Online (Sandbox Code Playgroud)

static void x11_init(),内

XMapWindow(display, win);
wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, win, &wm_delete_window, 1);
Run Code Online (Sandbox Code Playgroud)

在内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 */
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅XInternAtom,XSetWMProtocolsXNextEvent.

在我写完上面的内容之后,我在X11应用程序中找到了关闭处理窗口:

当用户点击[x]X11应用程序上的关闭按钮时 ,我们希望它弹出一个对话框,询问"你真的想要退出吗?".这是一个简单的X应用程序.这里没有花哨的GTK或QT小部件.那么如何抓住"窗口正在关闭"的消息呢?

答案是通过调用XSetWMProtocols并注册WM_DELETE_WINDOW消息来告诉Window Manager我们对这些事件感兴趣.然后,如果有人试图关闭窗口,我们将从窗口管理器获取客户端消息,并且它不会关闭它,它会让我们接受我们.这是一个例子......

// 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;
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*sch 5

不幸的是,这个问题的最佳答案是一系列的非答案;有技术上的方法来实现它,但它们都有使它们非常不切实际的缺点:

  1. 为应用程序创建一个 X11 代理,在应用程序和 X 服务器之间来回传递所有 X11 协议消息。然后代理将过滤掉任何有趣的消息。这样做的缺点是,对于一个很小的功能来说,这是一个非常大的开销,而且 X11 协议很复杂。也可能会产生意想不到的后果,这使得这成为一个更没有吸引力的选择。
  2. 作为标准应用程序启动,充当窗口管理器和“有趣的”客户端应用程序之间的中介。这会破坏一些东西,例如 XDnD。实际上,它与第一个选项没有什么不同,只是代理处于 Window 级别而不是 X11 协议级别。
  3. 使用不可移植的LD_PRELOAD库技巧。这有几个缺点:
    1. 它在动态链接器之间是不可移植的:并非所有动态链接器都支持LD_PRELOAD,即使在类 UNIX 系统中也是如此。
    2. 它不可跨操作系统移植:并非所有操作系统都支持功能强大的动态链接器。
    3. 它打破了网络透明性:共享对象/动态链接库必须作为正在执行的子进程驻留在主机上。
    4. 并非所有 X11 应用程序都使用 Xlib;有必要为LD_PRELOAD应用程序可能用来与 X11 通信的每个库编写一个模块。
    5. 除了最后一点,并非所有应用程序都会受到影响,LD_PRELOAD即使它们在支持它的链接器下运行,因为它们可能不使用共享对象或 DLL 来与 X 通信;例如,考虑一个使用 Java 本身编写的 X11 协议库的 Java 应用程序。
    6. 在某些类 UNIX 操作系统上,LD_PRELOAD如果要与 setuid/setgid 程序一起使用,库必须是 setuid/setgid。当然,这是一个潜在的安全漏洞。
    7. 我很确定还有更多我想不到的缺点。
  4. 实现对 X Window 系统的扩展。在 X11 实现中不可移植,复杂且令人费解,完全不可能。
  5. 实现窗口管理器的扩展或插件。窗口管理器的数量与对窗口管理器的意见一样多,因此这是完全不可行的。

最终,我能够通过使用完全独立的机制最终实现我的目标;任何有兴趣的人,请参阅 AllTray 0.7.5.1dev 及更高版本中的 Close-to-Tray 支持,包括github 上提供的 git master 分支