Linux 获取焦点 GUI 窗口更改的通知

2024-02-19

在Linux中,当当前聚焦的GUI应用程序发生变化时是否可以收到通知?我正在编写一个应用程序,用于跟踪用户在每个 GUI 应用程序上停留的时间(每个进程,而不是在一个进程内),并且需要某种方法来访问此信息。我正在用 c++ 做这个。


Here is what I have found so far:
xprop -id $(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $NF}') | awk '/_NET_WM_PID\(CARDINAL\)/{print $NF}'

这会打印出当前关注的应用程序的 pid,但需要我经常拉取。我宁愿不拉,但如果有必要的话我会拉。它还假设所有 GUI 都经过 x11,这可能不是一个不合理的假设,但并不完全可移植。

另一种方法是编写一个挂接到各种 gui 函数的共享对象,然后修改主机系统的 ld.so.preload 文件以在每个进程中加载​​该共享对象。这假设所有 GUI 应用程序都使用动态链接的图形库。我还必须为每个图形库编写挂钩以确保完全覆盖。在研究 GTK 时(我正在运行 Gnome 的系统上进行测试),我没有发现任何在窗口切换上调用的函数。不过我还没有仔细看。


Is there a way to get notifications through x11 for this sort of thing? Or other graphics libraries for that matter?

Edit:

好的,这是我到目前为止所拥有的,基于 @Andrey 的代码:

#include <X11/Xlib.h>
#include <cstring>
#include <iostream>
using namespace std;

pid_t get_window_pid( Display * d, Window& w );

int main()
{
    Display * d;
    Window w;
    XEvent e;

    d = XOpenDisplay( 0 );
    if ( !d ) {
        cerr << "Could not open display" << endl;
        return 1;
    }

    w = DefaultRootWindow( d );
    XSelectInput( d, w, PropertyChangeMask );

    pid_t window_pid;

    for ( ;; ) {
        XNextEvent( d, &e );
        if ( e.type == PropertyNotify ) {
            if ( !strcmp( XGetAtomName( d, e.xproperty.atom ), "_NET_ACTIVE_WINDOW" ) ) {
                window_pid = get_window_pid( d, w );
                cout << window_pid << endl;
            }
        }
    }

    return 0;
}

pid_t get_window_pid( Display * d, Window& w )
{
    Atom atom = XInternAtom( d, "_NET_WM_PID", true );

    Atom actual_type;
    int actual_format;
    unsigned long nitems;
    unsigned long bytes_after;
    unsigned char *prop;

    int status;
    status = XGetWindowProperty(
        d, w, atom, 0, 1024,
        false, AnyPropertyType,
        &actual_type,
        &actual_format, &nitems,
        &bytes_after,
        &prop
    );

    if ( status || !prop )
        return -1;

    return prop[1] * 256 + prop[0];
}

But get_window_pid总是返回 -1,即使使用xprop -id $(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $NF}') | awk '/_NET_WM_PID\(CARDINAL\)/{print $NF}'正确返回活动窗口的 pid。我究竟做错了什么?


JavaScript 中的示例使用node-x11 https://github.com/sidorares/node-x11:

var x11 = require('x11');
x11.createClient(function(err, display) {
  var X = display.client;
  X.ChangeWindowAttributes(display.screen[0].root, { eventMask: x11.eventMask.PropertyChange });
  X.on('event', function(ev) {
    if(ev.name == 'PropertyNotify') {
      X.GetAtomName(ev.atom, function(err, name) {
        if (name == '_NET_ACTIVE_WINDOW') {
          X.GetProperty(0, ev.window, ev.atom, X.atoms.WINDOW, 0, 4, function(err, prop) {
            console.log('New active window:' + prop.data.readUInt32LE(0));
          });
        }
      });
    }
  });
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux 获取焦点 GUI 窗口更改的通知 的相关文章

随机推荐