You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XQueryTree获取顶级窗口数量错误问题求助

问题原因与解决方案

问题原因

XQueryTree返回的是根窗口的全部直接子窗口,但GTK、Qt这类现代UI框架会为应用创建大量辅助窗口——比如托盘图标容器、工具提示窗口、客户端装饰组件、甚至隐藏的内部窗口——这些窗口都会直接作为根窗口的子节点存在,但它们并不是用户认知里的“顶级应用窗口”。以KeepassXC为例,它基于GTK开发,会在主窗口之外创建多个辅助窗口,导致XQueryTree返回的数量远多于实际可见的顶级窗口。

嵌套Xephyr环境本身可能会引入少量额外窗口节点,但这不是导致数值严重错误的核心原因。

解决方法

要得到真实的用户感知级顶级窗口数量,需要对XQueryTree返回的窗口列表进行过滤,基于EWMH(Extended Window Manager Hints)标准或X的基础属性筛选出符合条件的窗口。核心过滤逻辑包括:

  • 检查WM_STATE属性:标准顶级窗口都会设置该属性(用于标识窗口映射状态,如正常、最小化),辅助窗口通常不会设置。
  • 过滤窗口类型:通过_NET_WM_WINDOW_TYPE属性排除辅助窗口类型,比如托盘、提示框、通知类窗口。
  • 检查窗口可见性:通过XGetWindowAttributes确认窗口处于IsViewable状态(已映射且可见)。

代码示例

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

// 判断窗口是否为真实顶级窗口
int is_real_top_level_window(Display *display, Window win) {
    Atom wm_state = XInternAtom(display, "WM_STATE", False);
    Atom net_wm_type = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
    Atom net_wm_type_dock = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", False);
    Atom net_wm_type_tooltip = XInternAtom(display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
    Atom net_wm_type_notification = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);

    // 检查WM_STATE属性是否存在
    Atom actual_type;
    int actual_format;
    unsigned long nitems, bytes_after;
    unsigned char *data = NULL;
    int result = XGetWindowProperty(display, win, wm_state, 0, 2, False, AnyPropertyType,
                                    &actual_type, &actual_format, &nitems, &bytes_after, &data);
    if (result != Success || data == NULL) {
        if (data) XFree(data);
        return 0;
    }
    XFree(data);

    // 排除辅助窗口类型
    result = XGetWindowProperty(display, win, net_wm_type, 0, 10, False, AnyPropertyType,
                                &actual_type, &actual_format, &nitems, &bytes_after, &data);
    if (result == Success && data != NULL) {
        Atom *types = (Atom *)data;
        for (unsigned long i = 0; i < nitems; i++) {
            if (types[i] == net_wm_type_dock || types[i] == net_wm_type_tooltip || types[i] == net_wm_type_notification) {
                XFree(data);
                return 0;
            }
        }
        XFree(data);
    }

    // 检查窗口是否可见
    XWindowAttributes attrs;
    if (XGetWindowAttributes(display, win, &attrs) == 0) {
        return 0;
    }
    return attrs.map_state == IsViewable;
}

int main() {
    Display *display_ = XOpenDisplay(NULL);
    if (!display_) {
        fprintf(stderr, "无法打开显示器\n");
        return 1;
    }
    Window root_ = DefaultRootWindow(display_);

    Window returned_root, returned_parent;
    Window* top_level_windows;
    unsigned int num_top_level_windows;
    XQueryTree(
        display_,
        root_,
        &returned_root,
        &returned_parent,
        &top_level_windows,
        &num_top_level_windows);  

    // 过滤真实顶级窗口
    unsigned int real_count = 0;
    for (unsigned int i = 0; i < num_top_level_windows; i++) {
        if (is_real_top_level_window(display_, top_level_windows[i])) {
            real_count++;
        }
    }

    printf("真实顶级窗口数量: %u\n", real_count);

    // 释放XQueryTree分配的内存
    if (top_level_windows) {
        XFree(top_level_windows);
    }
    XCloseDisplay(display_);
    return 0;
}

额外注意事项

  • 编译时需链接X11库:gcc -o top_win_count top_win_count.c -lX11
  • 确保窗口管理器支持EWMH标准(绝大多数现代窗口管理器如Openbox、KWin、Mutter等均支持)
  • 若需要统计包括最小化在内的所有顶级窗口,可去掉窗口可见性的检查逻辑。

内容的提问来源于stack exchange,提问作者Kuglatec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:53:24