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

如何使用X11库获取当前窗口的PID?

我之前也碰到过这种头疼的情况——不少轻量X11应用或者老旧程序根本不会设置_NET_WM_PID属性,靠直接读这个属性完全行不通。不过别慌,用X11库结合Linux的/proc文件系统,有几种可靠的办法能拿到窗口对应的PID:

方法1:通过/proc文件系统关联进程与X11窗口

这是Linux下最实用的方案,因为每个进程打开的X11套接字会在/proc/[pid]/fd目录里以符号链接的形式存在。步骤大概是:

  • 先用XGetInputFocus拿到当前焦点窗口的XID
  • 遍历系统中所有运行的进程,筛选出持有X11套接字的进程
  • 对每个符合条件的进程,枚举它创建的所有窗口,对比XID是否和目标窗口匹配

给你一段C语言的核心代码片段参考:

// 先获取目标窗口的XID
Display *display = XOpenDisplay(NULL);
Window focus_win;
int revert_to;
XGetInputFocus(display, &focus_win, &revert_to);

// 遍历/proc目录下的进程
DIR *proc_dir = opendir("/proc");
struct dirent *entry;
while ((entry = readdir(proc_dir)) != NULL) {
    // 跳过非数字命名的目录(只有进程PID是数字)
    if (!isdigit(entry->d_name[0])) continue;
    pid_t pid = atoi(entry->d_name);
    
    // 检查该进程是否持有X11套接字
    char fd_path[PATH_MAX];
    snprintf(fd_path, sizeof(fd_path), "/proc/%d/fd", pid);
    DIR *fd_dir = opendir(fd_path);
    struct dirent *fd_entry;
    int has_x11_socket = 0;
    while ((fd_entry = readdir(fd_dir)) != NULL) {
        char link_target[PATH_MAX];
        snprintf(link_target, sizeof(link_target), "%s/%s", fd_path, fd_entry->d_name);
        char target_buf[PATH_MAX];
        ssize_t len = readlink(link_target, target_buf, sizeof(target_buf)-1);
        if (len > 0) {
            target_buf[len] = '\0';
            // 匹配X11套接字的路径格式(比如/tmp/.X11-unix/X0)
            if (strstr(target_buf, "/tmp/.X11-unix/") != NULL) {
                has_x11_socket = 1;
                break;
            }
        }
    }
    closedir(fd_dir);
    if (!has_x11_socket) continue;
    
    // 递归枚举该进程的所有窗口,对比是否等于focus_win
    // 这里需要实现窗口树遍历逻辑(用XQueryTree),找到匹配的窗口后即可返回pid
}
closedir(proc_dir);
XCloseDisplay(display);
方法2:借助WM_CLASS属性兜底

有些窗口虽然没设置_NET_WM_PID,但会提供WM_CLASS属性,包含进程的名称信息。你可以:

  • 用XGetClassHint获取窗口的res_name和res_class
  • 结合/proc文件系统,查找cmdline包含该名称的进程,再验证进程的窗口是否对应目标XID

示例代码:

XClassHint class_hint;
if (XGetClassHint(display, focus_win, &class_hint)) {
    printf("窗口进程名: %s\n", class_hint.res_name);
    // 接下来遍历/proc,查找cmdline匹配res_name的进程,再验证窗口归属
    XFree(class_hint.res_name);
    XFree(class_hint.res_class);
}
方法3:追踪窗口创建事件(适合窗口管理器类应用)

如果你能提前监听X11的事件流,可以在窗口创建时就记录PID:

  • 监听CreateNotify事件
  • 对每个新创建的窗口,优先尝试读取_NET_WM_PID(有值直接记录)
  • 如果没有,再用方法1的逻辑关联进程
注意事项
  • 部分系统级窗口(比如窗口管理器自身的窗口)的PID就是窗口管理器的进程ID
  • 普通用户只能访问自己的/proc目录内容,root权限才能遍历所有进程

内容的提问来源于stack exchange,提问作者Răzvan Flavius Panda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:51:41