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_WINDOW
X11"作为关键词进行了Google搜索.找到17k - MarkMail和Mplayer-提交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,XSetWMProtocols和XNextEvent.
在我写完上面的内容之后,我在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)
不幸的是,这个问题的最佳答案是一系列的非答案;有技术上的方法来实现它,但它们都有使它们非常不切实际的缺点:
LD_PRELOAD
库技巧。这有几个缺点:
LD_PRELOAD
,即使在类 UNIX 系统中也是如此。LD_PRELOAD
应用程序可能用来与 X11 通信的每个库编写一个模块。LD_PRELOAD
即使它们在支持它的链接器下运行,因为它们可能不使用共享对象或 DLL 来与 X 通信;例如,考虑一个使用 Java 本身编写的 X11 协议库的 Java 应用程序。LD_PRELOAD
如果要与 setuid/setgid 程序一起使用,库必须是 setuid/setgid。当然,这是一个潜在的安全漏洞。最终,我能够通过使用完全独立的机制最终实现我的目标;任何有兴趣的人,请参阅 AllTray 0.7.5.1dev 及更高版本中的 Close-to-Tray 支持,包括github 上提供的 git master 分支。
归档时间: |
|
查看次数: |
10690 次 |
最近记录: |