在 X11 上拦截 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 事件。 所以,这条路似乎也不是很好走。
I'd like to intercept the WM_DELETE_WINDOW
message that is posted to a certain selection of windows that an application I'm writing (AllTray), so that I can act on it instead of the application receiving it. I'm currently looking at trying this at the GDK level via gdk_display_add_client_message_filter
if possible, but I'd be happy with an Xlib solution if there is one as well; it seems to be possible, but I just don't seem to be understanding how I am to do it successfully.
Currently, I have two programs (written in C) that I am trying to use to get this figured out, the first one does nothing but create a window and register that it knows about WM_DELETE_WINDOW
, and the second one attempts to catch that message, but seems to fail in doing so; it appears to do precisely nothing. Am I understanding the documentation wrong on this, or is there something additional that I need to be doing (or do I need to avoid using GDK entirely for this)?
The background is this: Prior to my re-write of AllTray, the way it would do things appears to be to try to intercept a mouse-click on the X button itself. For some window managers, this worked properly, for others it didn't work at all, and for others, the user had to configure it manually and instruct AllTray where the button for closing the window was. What I am looking for is a solution that doesn't involve a LD_LIBRARY_PRELOAD
and will work for any window manager/application combination that conforms to the current standards and sends a WM_DELETE_WINDOW
ClientMessage when the window is closed.
UPDATE: I'm still looking for an answer. The route that I am taking at the moment is to try to reparent the window and manage it myself, but I just cannot make it work. Upon reparenting, I don't seem to be able to get it back in any way. I may be missing something very fundamental, but I can't figure out how to actually make it appear it my own window again, to bring it back on the screen.
UPDATE 2: Alright, so I've hit another brick wall. The X server documentation says to set the StructureNotifyMask on the window's event mask to receive both MapNotify and ReparentNotify events. I'd be interested in receiving either. My current thinking was to create a window that served just as an event receiver, and then when I get events for interesting things, act on them by creating and reparenting. However, this simply doesn't seem to be working. The only events I actually receive are PropertyNotify events. So, this route doesn't seem to be doing very much good, either.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不知道 X11,但我使用 "拦截
WM_DELETE_WINDOW
X11" 作为关键字。 找到 17k - MarkMail 和 Mplayer-commits r154 - trunk/libvo。 在这两种情况下,他们都在做同样的事情。在
static void x11_init()
内,然后在
static int x11_check_events()
内,请参阅 XInternAtom, XSetWMProtocols 和 XNextEvent。
写完上面的内容后,我发现在X11应用程序中处理窗口关闭:
I don't know X11, but I googled using "Intercept
WM_DELETE_WINDOW
X11" as keywords. Found 17k - MarkMail and Mplayer-commits r154 - trunk/libvo. In both cases they are doing the same thing.within
static void x11_init()
,then, within
static int x11_check_events()
,See XInternAtom, XSetWMProtocols and XNextEvent.
After I wrote the above, I found Handling window close in an X11 app:
不幸的是,这个问题的最佳答案是一系列非答案; 从技术上讲,有多种方法可以实现这一目标,但它们都有一些缺陷,使得它们极其不切实际:
LD_PRELOAD
库技巧。 这有几个缺点:LD_PRELOAD
,即使在类 UNIX 系统中也是如此。LD_PRELOAD
模块。LD_PRELOAD
的影响,即使它们在支持它的链接器下运行,因为它们可能不使用共享对象或 DLL 来进行通信与X; 例如,考虑一个使用 Java 本身编写的 X11 协议库的 Java 应用程序。LD_PRELOAD
库必须为 setuid/setgid。 当然,这是一个潜在的安全漏洞。最终,我通过使用完全独立的机制终于实现了我的目标; 任何感兴趣的人,请参阅 AllTray 0.7.5.1dev 及更高版本中的 Close-to-Tray 支持,包括 git master 分支在 github 上可用。
Unfortunately, the best answer to this question is a series of non-answers; there are technically ways to accomplish it, but they all have downfalls that make them extremely impractical:
LD_PRELOAD
library trick. This has several downsides:LD_PRELOAD
, even among UNIX-like systems.LD_PRELOAD
module for each of the libraries that an application might use to talk with X11.LD_PRELOAD
even if they ran under a linker that supported it, because they may not use a shared object or DLL in order to communicate with X; consider, for example, a Java application which uses an X11 protocol library written in Java itself.LD_PRELOAD
libraries must be setuid/setgid if they are to be used with setuid/setgid programs. This is, of course, a potential security vulnerability.Ultimately, I was able to finally accomplish my goal by using a completely separate mechanism; anyone who is interested, please see the Close-to-Tray support in AllTray 0.7.5.1dev and later, including the git master branch available on github.
好的,为了详细说明我之前的建议,您可能需要研究 XEmbed< /a>. 至少,这可能会给您一些尝试的想法。
如果做不到这一点,我会看看其他类似的软件如何工作(例如 wmdock,或 GtkPlug/GtkSocket 的实现方式),尽管我相信在这两种情况下,应用程序都需要明确的支持。
希望这更有帮助。
Ok, to elaborate on my earlier suggestion, you might want to investigate XEmbed. At the least, that might give you some ideas to try.
Failing that, I'd have a look at how other similar software might be working (e.g. wmdock, or how GtkPlug/GtkSocket is implemented), though I believe in both those cases explicit support is required in the applications.
Hope that is more helpful.
您应该阅读 ICCCM,它告诉您窗口管理器如何与客户端通信。 大多数 WM 都会通过重新设置父级来创建一个框架窗口来包含您的顶级窗口。 因此,如果您的父母可能会破坏 WM 和您的客户端窗口之间的关系。
You should read ICCCM that tells you how window manager communicates with client. Most of WM will create a frame window to contain your top-level window via reparenting. Thus, if your reparent may break the relationship known by WM and your client window.