我正在尝试找到一种方法来检测在 Ubuntu 16.04 中打开窗口(任何窗口)的事件
我希望能够检测到“窗口打开”事件并检查打开的窗口是否是我寻找的窗口,然后运行 bash 脚本或 C/C++ 函数。
到目前为止,我发现我可以使用wmctrl -l
它来查找已打开的窗口。我可以使用这个命令,也许grep
可以找到我寻找的窗口是否打开,然后根据这些信息采取行动。
我不想轮询,因为我不希望应用程序在窗口打开时处于空闲状态。该动作应尽可能“即时”。
有没有我可以听的事件或信号来实现这一目标?从内核、窗口管理器(Compiz)或者可能是一些更改的日志文件?
编辑: 澄清一下,我有一个应用程序(不在我的控制之下),它可能随时显示一个窗口,这个窗口没有标题,但它确实设置了 WM_CLASS(WM_CLASS 对于应用程序的所有窗口都是相同的)。我想在显示此窗口(或创建,以最好/更容易者为准)的情况下采取行动。
窗口似乎没有在主应用程序窗口“内”打开。使用xwininfo -children -id <window-id>
表明主应用程序和寻找的窗口位于不同的分支上,连接到“根窗口”。
分支看起来像这样,其中 R 是“根节点”;A 是主应用程序分支的根节点,Y 是寻找窗口 W 的分支的根:
R
/ \
A Y
/\ \
B C X
\ \
Q W
所以我希望我能找到YXW的独特结构
我不确定我是否必须听取所有窗口,但我假设我必须检查“根窗口”中发生的情况并尝试找到寻找的窗口。
我找到了两种解决这个问题的方法。
xprop -spy -root _NET_ACTIVE_WINDOW
中结合使用该命令。grep
我最终使用了替代方法 1,但我将在下面提供一些信息。
使用 xprop: 创建搜索窗口的应用程序总是将新窗口放在顶部并处于焦点位置。该
xprop -spy <window-id>
命令允许人们监听属性的变化,<window-id>
并且-root
是“根窗口”的 id(上面问题中的树中的 R)。要监听特定属性的变化,我们可以在这种情况下提供属性的名称,_NET_ACTIVE_WINDOW
它包含当前焦点窗口的 id,请参阅规范。然后我们得到这样的输出流:并且可以
grep
用来提取ID。要检查活动窗口是否是寻找的窗口,我们需要知道是什么使它独一无二,这可能对每个人都不同,但很可能第一个过滤器是WM_CLASS
属性,请参阅描述。这是一个小例子:Bash gist: 这是问题案例的要点,其中树是识别因素。
限制
xprop -spy
:这并不专门监听窗口打开,而是在窗口聚焦时。这意味着如果窗口保持打开状态,失去焦点然后再次聚焦,此脚本仍将报告此事件。Xlib 编程: 这更复杂但也更强大。一些很好的入门资源是:
为此,必须打开一个连接并注册为 X-server 的侦听器:
根据正在寻找的事件,应该选择一个EventMask 。
对于一个连续的应用程序(想要处理后续事件),可能需要设置一个错误处理函数,该函数应该返回 0(可能带有警告),以便执行顺利进行,如下所示:
在一个循环中,然后可以处理来自 X-server 的事件
要处理事件,
e
我们可以检查e
XEvent
结构包含不同类型结构中的信息,具体取决于事件类型。需要以下库:
并且应用程序应该使用
-lX11
标志编译以包含 Xlib 库。Xlib gists + Gotchas: 我创建了两个从 X-server 监听事件的 gists。请注意,我对用于识别的窗口树的结构感兴趣。其他人可能有其他属性来唯一标识窗口。
第一个监听
CreateNotify
事件以确定是否创建了具有正确 WM_CLASS 的窗口,称之为 W。此时该窗口可能不在正确的树结构中。例如,它可能被创建为根的子项,而不是由应用程序控制的窗口。因此,我们监听该ReparentNotify
事件以查看 W 是否有新的父级。不幸的是,我们也不能保证这里的树结构是正确的,因为稍后可能会将其他窗口添加到 W 的树中。但是如果 W 的树结构是唯一的并且它的形状不是具有相同类的另一个窗口的子树,我们至少可以通过检查找到这些窗口
ReparentNotify
(我们甚至可能不需要检查,CreateNotify
因为我们可以随时检查 WM_CLASS有一个窗口ID)。第二个监听
MapNotify
事件并检查窗口树的结构。然后它在树中寻找正确的 WM_CLASS。在此之后可以继续确定结构是否正确。同样,
MapNotify
我们不能保证“完成”的树结构。然而,似乎该结构通常在此事件后的短时间内“稳定”。为了合理地确保结构不会改变,我在收集树之前添加了一个短暂的暂停。为了不冒对我不知道的树进行其他更改的风险,这个暂停应该多长时间,500ms 似乎对我来说效果很好。杂项: X11 窗口可以用许多不同的语言创建,所以我想也可以用许多不同的语言来听它们。
一些调查窗口的工具:
xprop
xwininfo
特别是选项-tree
或-children
您还可以查看上述命令的源代码xprop和xwininfo,以获得一些指导和启发。
要在窗口打开而不使用 while 循环轮询的情况下执行命令,可以使用 xdotool :-
我不知道 xdotool 是否通过轮询在内部实现了此功能。
这个想法的所有功劳都归功于这个答案:https ://askubuntu.com/a/1187586