如何在XWindows中捕获窗口最小化、最大化事件?
问题根因
你使用的Ubuntu 20.04默认搭载Mutter窗口管理器,这类现代X11窗口管理器已经不完全遵循旧版ICCCM规范的最小化逻辑,不会在最小化时unmap窗口,而是通过EWMH标准的_NET_WM_STATE窗口属性标记所有窗口状态,所以你收不到UnmapNotify属于正常现象。
原有代码核心错误
- 你把
XCloseDisplay和return 0写在了事件循环内部,程序处理一次事件就会主动关闭X连接退出,自然收不到后续状态变化通知。 - 读取
_NET_WM_STATE时只请求了1个单位长度的返回值,而该属性实际是Atom类型的数组,可能同时包含多个状态标识,只取第一个自然读不全所有状态。
修改方案
你需要先初始化所有需要用到的状态Atom,再遍历读取到的属性数组判断当前窗口状态:
步骤1:新增状态Atom定义
在main函数开头新增以下变量:
Atom net_wm_state; Atom net_wm_state_hidden; // 对应最小化状态 Atom net_wm_state_max_vert; // 垂直最大化 Atom net_wm_state_max_horz; // 水平最大化 Atom net_wm_state_fullscreen; // 全屏状态
步骤2:初始化Atom
在XOpenDisplay调用成功后新增Atom初始化逻辑:
net_wm_state = XInternAtom(d, "_NET_WM_STATE", False); net_wm_state_hidden = XInternAtom(d, "_NET_WM_STATE_HIDDEN", False); net_wm_state_max_vert = XInternAtom(d, "_NET_WM_STATE_MAXIMIZED_VERT", False); net_wm_state_max_horz = XInternAtom(d, "_NET_WM_STATE_MAXIMIZED_HORZ", False); net_wm_state_fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", False);
步骤3:修改PropertyNotify事件处理逻辑
替换原有PropertyNotify分支的代码:
} else if (e.type == PropertyNotify) { // 直接匹配Atom,比转字符串比较效率更高 if (e.xproperty.atom == net_wm_state) { status = XGetWindowProperty(d, w, net_wm_state, 0L, 1024L, False, // 请求足够长的返回空间 AnyPropertyType, &type, &format, &length, &after, &dp); if (status == Success && type == XA_ATOM && format == 32) { int is_minimized = 0; int is_maximized = 0; int is_fullscreen = 0; Atom *states = (Atom *)dp; // 遍历所有状态标识 for (unsigned long i = 0; i < length; i++) { if (states[i] == net_wm_state_hidden) is_minimized = 1; if (states[i] == net_wm_state_max_vert) is_maximized += 1; if (states[i] == net_wm_state_max_horz) is_maximized += 1; if (states[i] == net_wm_state_fullscreen) is_fullscreen = 1; } // 同时存在水平+垂直最大化标识才是普通最大化 is_maximized = (is_maximized == 2) ? 1 : 0; printf("状态更新:最小化=%d,最大化=%d,全屏=%d\n", is_minimized, is_maximized, is_fullscreen); } // 必须释放XGetWindowProperty返回的内存,避免泄漏 if (dp) XFree(dp); } }
步骤4:修正资源释放逻辑
把循环内的XCloseDisplay(d);和return 0;移到while循环外部,程序才能正常监听后续事件。
补充说明
不需要再额外监听StructureNotify等不需要的事件,只要保留PropertyChangeMask就能收到_NET_WM_STATE的变化通知,所有逻辑完全兼容GNOME、KDE等主流桌面环境的窗口管理器。
内容的提问来源于stack exchange,提问作者Scott Franco
相关产品推荐
相关产品推荐

