AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1010276
Accepted
Christian Eriksson
Christian Eriksson
Asked: 2018-02-28 04:55:26 +0800 CST2018-02-28 04:55:26 +0800 CST 2018-02-28 04:55:26 +0800 CST

我可以在没有轮询的情况下对窗口打开的事件采取行动吗?

  • 772

我正在尝试找到一种方法来检测在 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的独特结构

我不确定我是否必须听取所有窗口,但我假设我必须检查“根窗口”中发生的情况并尝试找到寻找的窗口。

bash events window c c++
  • 2 2 个回答
  • 3708 Views

2 个回答

  • Voted
  1. Best Answer
    Christian Eriksson
    2018-03-21T01:47:41+08:002018-03-21T01:47:41+08:00

    我找到了两种解决这个问题的方法。

    1. 在 bash 脚本xprop -spy -root _NET_ACTIVE_WINDOW中结合使用该命令。grep
    2. 使用 Xlib 库创建一个 C++(可能是 C 或 python,以及我的项目开始时使用 C++)应用程序来监听来自X-server的事件。

    我最终使用了替代方法 1,但我将在下面提供一些信息。

    使用 xprop: 创建搜索窗口的应用程序总是将新窗口放在顶部并处于焦点位置。该xprop -spy <window-id>命令允许人们监听属性的变化,<window-id>并且-root是“根窗口”的 id(上面问题中的树中的 R)。要监听特定属性的变化,我们可以在这种情况下提供属性的名称,_NET_ACTIVE_WINDOW它包含当前焦点窗口的 id,请参阅规范。然后我们得到这样的输出流:

    _NET_ACTIVE_WINDOW(WINDOW): window id # 0x3c00010
    

    并且可以grep用来提取ID。要检查活动窗口是否是寻找的窗口,我们需要知道是什么使它独一无二,这可能对每个人都不同,但很可能第一个过滤器是WM_CLASS属性,请参阅描述。这是一个小例子:

    #!/bin/bash
    class_name=$1
    
    # regex for extracting hex id's
    grep_id='0[xX][a-zA-Z0-9]\{7\}'
    
    xprop -spy -root _NET_ACTIVE_WINDOW | grep --line-buffered -o $grep_id |
    while read -r id; do
        class="`xprop -id $id WM_CLASS | grep $class_name`"
        if [ -n "$class" ]; then
            # Found a window with the correct WM_CLASS now what makes your
            # window unique?
        fi
    done
    

    Bash gist: 这是问题案例的要点,其中树是识别因素。

    限制xprop -spy:这并不专门监听窗口打开,而是在窗口聚焦时。这意味着如果窗口保持打开状态,失去焦点然后再次聚焦,此脚本仍将报告此事件。

    Xlib 编程: 这更复杂但也更强大。一些很好的入门资源是:

    • Christophe Tronche的 Xlib 手册和简短教程
    • Alan 的Xlib 教程。

    为此,必须打开一个连接并注册为 X-server 的侦听器:

    // Open connection to X server
    Display *dsp = XOpenDisplay(NIL);
    assert(dsp);
    
    // Start listening to root window
    XSelectInput(dsp, DefaultRootWindow(dsp), SubstructureNotifyMask);
    

    根据正在寻找的事件,应该选择一个EventMask 。

    对于一个连续的应用程序(想要处理后续事件),可能需要设置一个错误处理函数,该函数应该返回 0(可能带有警告),以便执行顺利进行,如下所示:

    XSetErrorHandler(bad_window_handler);
    

    在一个循环中,然后可以处理来自 X-server 的事件

    XEvent e;
    XNextEvent(dsp, &e); // blocks until next event from X-server
    

    要处理事件,e我们可以检查e

    e.type == CreateNotify    // A window was created
    e.type == ReparentNotify  // A window got a new parent
    e.type == MapNotify       // A window was drawn
    e.type == DestroyNotify   // A window was destroyed
    

    XEvent 结构包含不同类型结构中的信息,具体取决于事件类型。

    需要以下库:

    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    

    并且应用程序应该使用-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,以获得一些指导和启发。

    • 23
  2. justpeanuts
    2022-05-29T20:59:58+08:002022-05-29T20:59:58+08:00

    要在窗口打开而不使用 while 循环轮询的情况下执行命令,可以使用 xdotool :-

    <code_that_triggers_window_opening> & xdotool search --sync --onlyvisible --name 'window_name' && <command_to_excute_on_window_open_event>
    

    我不知道 xdotool 是否通过轮询在内部实现了此功能。

    这个想法的所有功劳都归功于这个答案:https ://askubuntu.com/a/1187586

    • 0

相关问题

  • 同时复制到两个位置

  • 如何在 shell 脚本中创建选择菜单?

  • 从 bash 迁移到 zsh [关闭]

  • bashrc 还是 bash_profile?

  • 备份 bash 脚本未压缩其 tarball

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve