Ubuntu 16.04无需轮询检测窗口打开事件并执行脚本或函数的方法
嘿,我之前在Ubuntu 16.04上折腾过类似的需求,太懂你不想用轮询的心情了——轮询不仅浪费系统资源,响应还不及时。下面给你几个事件驱动的靠谱方案,完美解决你的问题:
方案1:用libwnck(C/C++实现)
libwnck是GNOME生态下专门用于窗口管理的库,能直接监听窗口创建、关闭等事件,API非常友好,适合C/C++开发。
步骤:
- 先安装依赖库:
sudo apt-get install libwnck-3-dev
- 编写监听代码(示例):
#include <libwnck/libwnck.h> #include <string.h> // 窗口打开事件的回调函数 static void on_window_opened(WnckScreen *screen, WnckWindow *window, gpointer data) { // 获取窗口名称和窗口类名(类名更稳定,适合匹配目标窗口) const char *window_name = wnck_window_get_name(window); const char *window_class = wnck_window_get_class_group_name(window); // 替换成你的目标窗口标识(选名称或类名都可以) const char *TARGET_WINDOW_NAME = "你的目标窗口名"; const char *TARGET_WINDOW_CLASS = "你的目标窗口类"; if ((window_name && strcmp(window_name, TARGET_WINDOW_NAME) == 0) || (window_class && strcmp(window_class, TARGET_WINDOW_CLASS) == 0)) { // 执行你的Bash脚本 system("/path/to/your/script.sh"); // 或者直接调用你的C/C++函数 // your_custom_function(); } } int main(int argc, char **argv) { // 初始化GDK(libwnck依赖GDK) gdk_init(&argc, &argv); // 获取默认屏幕 WnckScreen *screen = wnck_screen_get_default(); // 绑定窗口打开事件的回调 g_signal_connect(screen, "window-opened", G_CALLBACK(on_window_opened), NULL); // 进入事件循环 gdk_main(); return 0; }
- 编译代码:
gcc -o window_monitor window_monitor.c $(pkg-config --cflags --libs libwnck-3.0)
- 运行编译后的程序即可持续监听窗口事件。
方案2:用DBus监听(纯Bash脚本)
如果你不想写代码,纯Bash就能搞定——Ubuntu 16.04的桌面环境(比如Unity)会通过DBus广播窗口相关的信号,我们可以直接监听这些信号来实现事件驱动。
示例脚本:
#!/bin/bash # 监听窗口添加事件(适配Unity/Compiz环境) dbus-monitor "interface='org.compiz.WindowManager',member='WindowAdded'" | while read -r line; do # 当捕获到窗口添加信号时,获取最新打开的窗口信息 if echo "$line" | grep -q "WindowAdded"; then # 用wmctrl获取最新窗口的名称(tail -n1取最后一行,即最新打开的窗口) latest_window_name=$(wmctrl -l | tail -n1 | awk '{sub(/^[^ ]+ [^ ]+ [^ ]+ /, ""); print}') # 替换成你的目标窗口名 TARGET_WINDOW="你的目标窗口名" if [[ "$latest_window_name" == *"$TARGET_WINDOW"* ]]; then # 执行你的脚本 /path/to/your/script.sh fi fi done
注意:
- 如果你的桌面是GNOME Shell,把监听的DBus接口改成
"interface='org.gnome.Shell',member='WindowAdded'"即可。 - 确保已经安装
wmctrl和dbus-x11:sudo apt-get install wmctrl dbus-x11
方案3:用XCB底层接口(C实现)
如果你需要更底层的X窗口系统控制,XCB是个不错的选择——它是Xlib的替代方案,更轻量,不需要依赖GNOME的库。
步骤:
- 安装依赖:
sudo apt-get install libxcb1-dev
- 编写监听代码:
#include <xcb/xcb.h> #include <string.h> #include <stdlib.h> int main() { // 连接到X服务器 xcb_connection_t *conn = xcb_connect(NULL, NULL); if (xcb_connection_has_error(conn)) { fprintf(stderr, "无法连接到X服务器\n"); return 1; } // 获取默认屏幕 xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; // 订阅根窗口的子结构通知事件(用于捕获窗口创建) uint32_t event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK, &event_mask); xcb_flush(conn); xcb_generic_event_t *event; while ((event = xcb_wait_for_event(conn))) { // 处理窗口创建事件 if (event->response_type == XCB_CREATE_NOTIFY) { xcb_create_notify_event_t *create_event = (xcb_create_notify_event_t *)event; // 获取窗口名称属性 xcb_get_property_cookie_t name_cookie = xcb_get_property( conn, 0, create_event->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1024); xcb_get_property_reply_t *name_reply = xcb_get_property_reply(conn, name_cookie, NULL); if (name_reply && name_reply->value_len > 0) { char *window_name = xcb_get_property_value(name_reply); // 替换成你的目标窗口名 if (strcmp(window_name, "你的目标窗口名") == 0) { system("/path/to/your/script.sh"); } free(name_reply); } } free(event); } xcb_disconnect(conn); return 0; }
- 编译代码:
gcc -o xcb_window_monitor xcb_window_monitor.c -lxcb
- 运行程序即可监听窗口创建事件。
这些方案都是完全基于事件驱动的,不会像轮询那样一直占用CPU,你可以根据自己的技术栈选择最适合的方式。
内容的提问来源于stack exchange,提问作者Christian Eriksson
相关产品推荐
相关产品推荐

