前言

在 Linux 桌面环境中,窗口管理是 GUI 应用开发中的重要组成部分。X Window System(X11)作为 Linux 桌面环境的显示服务器协议,提供了丰富的窗口管理功能。
今天,我们将深入探讨如何使用 X11 监听窗口事件,实现窗口状态监控、自动化操作等高级功能。

X11 基础概念

1.1 X Window System 架构

X11 采用客户端-服务器架构:

  • X Server: 管理显示硬件和输入设备
  • X Client: 应用程序,通过 X 协议与服务器通信
  • Xlib/XCB: 客户端库,提供编程接口
1.2 窗口与事件模型

X11 中所有GUI元素都是窗口,采用树状结构组织。事件驱动机制是 X11 的核心,包括:

  • 键盘/鼠标输入事件
  • 窗口状态变更事件
  • 属性更改事件等

X11 窗口监听实现

2.1 建立连接
int main()
{
    Display *display = XOpenDisplay(NULL);
    if (!display) {
        fprintf(stderr, "无法打开 X 显示\n");
        return -1;
    }
    Window root = DefaultRootWindow(display);
    printf("成功连接到 X Server\n");
    printf("根窗口 ID: %lu\n", root_window);
    // ...

    XCloseDisplay(display);
    return 0;
}
2.2 监听窗口事件
// 监听窗口属性和子窗口结构变化
XSelectInput(display, root, PropertyChangeMask | SubstructureNotifyMask);
// 等待请求完成
XSync(display, False);
XEvent event;
while (1) {
    XNextEvent(display, &event);
    
    switch (event.type) {
        case PropertyNotify:
            break;
            
        case ConfigureNotify:
            break;
            
        default:
            break;
    }
}
2.3 获取窗口属性信息
void print_window_info(Display *display, Window window) {
    Atom atom_type;
    int format;
    unsigned long nitems, bytes_after;
    unsigned char *data = NULL;
    // 获取窗口标题
    Atom atom_name = XInternAtom(display, "_NET_WM_NAME", False);
    if (XGetWindowProperty(display, window, atom_name, 0, 1024,
                           False, AnyPropertyType, &atom_type,
                           &format, &nitems, &bytes_after,
                           &data) == Success && data) {
        printf("窗口标题: %s\n", data);
        XFree(data);
    }

    // 获取窗口进程
    Atom atom_pid = XInternAtom(display, "_NET_WM_PID", False);
    if (XGetWindowProperty(display, window, atom_pid, 0, 1024,
                           False, XA_CARDINAL, &atom_type,
                           &format, &nitems, &bytes_after,
                           &data) == Success && data) {
        printf("所属进程: %d\n", *((pid_t*)data););
        XFree(data);
    }

    // 获取窗口几何属性
    XWindowAttributes attr;
    if (XGetWindowAttributes(display, window, &attr)) {
        int x_abs, y_abs;
        Window child_return;
        // 将相对坐标转换为绝对坐标
        if (XTranslateCoordinates(
                display, window, DefaultRootWindow(display), 0, 0,
                &x_abs, &y_abs, &child_return)) {
            printf("位置: %dx%d 大小: %dx%d\n",
                   x_abs, y_abs, attr.width, attr.height);
        }
    }
}

高级监听功能

3.1 监听活动窗口
XSelectInput(display, root, PropertyChangeMask);

// 监听活动窗口ID
Atom active_window_atom =
    XInternAtom(display, "_NET_ACTIVE_WINDOW", False);

XEvent event;
while (1) {
    XNextEvent(display, &event);
    
    if (event.type == PropertyNotify &&
        event.xproperty.atom == active_window_atom) {
        // 获取当前活动窗口
        Atom type;
        int format;
        unsigned long nitems, bytes_after;
        unsigned char* data = NULL;
        // 从根窗口获取活动窗口属性
        int status =
            XGetWindowProperty(display, root, active_window_atom,
                            0,          // long_offset
                            1,          // long_length
                            False,      // delete
                            XA_WINDOW,  // req_type
                            &type, &format, &nitems, &bytes_after, &data);
        if (status == Success && data) {
            Window active_window = *((Window*)data);
            printf("活动窗口变更: %lu\n", active_window);
        }
        if (data) XFree(data);
    }
}
3.2 监听窗口属性变化
XSelectInput(display, root, SubstructureNotifyMask);

XEvent event;
while (1) {
    XNextEvent(display, &event);
    
    if (event.type == ConfigureNotify ) {
        // 这里event.xconfigure.window中的窗口并不指向当前活动窗口.
        // 因此,想要实时获取窗口大小需要调用print_window_info()
        printf("窗口大小/位置变化: ID=%lu, %dx%d @ %d,%d\n",
           event.xconfigure.window,
           event.xconfigure.width,
           event.xconfigure.height,
           event.xconfigure.x,
           event.xconfigure.y);
    }
}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐