Linux环境下用C++获取活动窗口可执行文件名及监听焦点变化
C++实现活动窗口进程检测方案
方案1:X11原生实现(通用跨桌面)
这个方案直接基于X11协议,无需依赖外部命令,兼容性覆盖绝大多数X11桌面环境(GNOME、KDE、Xfce等)。
步骤1:获取活动窗口的PID
通过X11 API读取根窗口的_NET_ACTIVE_WINDOW属性拿到当前焦点窗口ID,再读取该窗口的_NET_WM_PID属性获取进程ID:
#include <X11/Xlib.h> #include <X11/Xatom.h> #include <stdio.h> #include <stdlib.h> #include <string.h> pid_t get_active_window_pid(Display *display) { Window root = DefaultRootWindow(display); Atom net_active_window = XInternAtom(display, "_NET_ACTIVE_WINDOW", False); Atom net_wm_pid = XInternAtom(display, "_NET_WM_PID", False); // 获取活动窗口ID Atom actual_type; int format; unsigned long nitems, bytes_after; unsigned char *data = NULL; Window active_win = None; if (XGetWindowProperty(display, root, net_active_window, 0, 1, False, AnyPropertyType, &actual_type, &format, &nitems, &bytes_after, &data) == Success && data) { active_win = *(Window*)data; XFree(data); } if (active_win == None) return -1; // 获取窗口对应的PID pid_t pid = -1; if (XGetWindowProperty(display, active_win, net_wm_pid, 0, 1, False, XA_CARDINAL, &actual_type, &format, &nitems, &bytes_after, &data) == Success && data) { pid = *(pid_t*)data; XFree(data); } return pid; }
步骤2:通过PID读取可执行文件名
利用Linux的/proc文件系统,直接读取/proc/[pid]/comm(短进程名)或/proc/[pid]/exe(完整可执行路径,符号链接):
bool get_process_name(pid_t pid, char *buf, size_t buf_size) { char comm_path[64]; snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", pid); FILE *fp = fopen(comm_path, "r"); if (!fp) return false; if (fgets(buf, buf_size, fp)) { // 去掉换行符 buf[strcspn(buf, "\n")] = '\0'; fclose(fp); return true; } fclose(fp); return false; }
步骤3:监听窗口焦点变化
通过X11的事件监听机制,订阅根窗口的PropertyChange事件,当_NET_ACTIVE_WINDOW属性变化时触发检测:
int main() { Display *display = XOpenDisplay(NULL); if (!display) { fprintf(stderr, "Failed to open X display\n"); return 1; } Window root = DefaultRootWindow(display); Atom net_active_window = XInternAtom(display, "_NET_ACTIVE_WINDOW", False); // 订阅根窗口的属性变化事件 XSelectInput(display, root, PropertyChangeMask); XEvent event; char proc_name[256]; pid_t last_pid = -1; while (1) { XNextEvent(display, &event); if (event.type == PropertyNotify && event.xproperty.atom == net_active_window) { pid_t current_pid = get_active_window_pid(display); if (current_pid != -1 && current_pid != last_pid) { if (get_process_name(current_pid, proc_name, sizeof(proc_name))) { printf("Active window process changed: %s (PID: %d)\n", proc_name, current_pid); // 在这里执行你的自定义功能 // custom_function(proc_name); } last_pid = current_pid; } } } XCloseDisplay(display); return 0; }
编译时需要链接X11库:g++ your_code.cpp -o window_monitor -lX11
方案2:D-Bus实现(桌面环境特定)
如果目标环境是GNOME/KDE等遵循Freedesktop规范的桌面,D-Bus方案代码更简洁,但接口依赖具体桌面环境:
获取活动窗口PID(GNOME示例)
#include <dbus/dbus.h> #include <stdio.h> #include <stdlib.h> pid_t get_gnome_active_pid() { DBusError err; dbus_error_init(&err); DBusConnection *conn = dbus_bus_get(DBUS_BUS_SESSION, &err); if (dbus_error_is_set(&err)) { fprintf(stderr, "DBus connection error: %s\n", err.message); dbus_error_free(&err); return -1; } // 调用GNOME Shell接口获取活动窗口关联的应用信息 DBusMessage *msg = dbus_message_new_method_call( "org.gnome.Shell", "/org/gnome/Shell/WindowTracker", "org.gnome.Shell.WindowTracker", "GetWindowApp" ); if (!msg) { fprintf(stderr, "Failed to create DBus message\n"); dbus_connection_unref(conn); return -1; } // 先获取活动窗口ID(可复用X11逻辑或调用GNOME接口) Display *display = XOpenDisplay(NULL); Window active_win = DefaultRootWindow(display); // 此处省略X11获取活动窗口ID的代码,直接传入示例值 dbus_message_append_args(msg, DBUS_TYPE_UINT32, &active_win, DBUS_TYPE_INVALID); XCloseDisplay(display); DBusMessage *reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); dbus_message_unref(msg); if (dbus_error_is_set(&err)) { fprintf(stderr, "DBus reply error: %s\n", err.message); dbus_error_free(&err); dbus_connection_unref(conn); return -1; } // 解析回复获取应用PID pid_t pid = -1; DBusMessageIter iter; dbus_message_iter_init(reply, &iter); dbus_message_iter_recurse(&iter, &iter); dbus_message_iter_get_basic(&iter, &pid); dbus_message_unref(reply); dbus_connection_unref(conn); return pid; }
监听焦点变化
通过订阅D-Bus的PropertiesChanged信号实现,例如监听org.gnome.Shell.WindowTracker的属性变化,触发重新检测。
方案对比
- X11方案:通用性强,几乎支持所有X11桌面,无需额外依赖(仅需X11开发库),代码稍繁琐但稳定。
- D-Bus方案:代码更简洁,但依赖具体桌面环境的D-Bus接口,兼容性不如X11方案。
内容的提问来源于stack exchange,提问作者InnerBushman
相关产品推荐
相关产品推荐

