如何使用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
相关产品推荐
相关产品推荐

