基于Xlib的自定义X11窗口管理器如何处理弹出窗口与对话框?
核心适配方案:区分普通窗口与弹窗
一、ICCCM 基础属性检查(优先实现)
WM_TRANSIENT_FOR属性:这是最基础的弹窗标识。如果窗口的该属性指向另一个已存在的窗口,说明它是父窗口的子弹窗(如对话框、悬浮提示),直接跳过平铺逻辑,让其自由浮动或跟随父窗口位置。- 实现:调用
XGetTransientForHint函数获取父窗口ID,若返回值不为None,则标记为非平铺窗口。
- 实现:调用
WM_STATE属性:检查窗口状态是否为WithdrawnState或IconicState,这类状态的窗口无需参与平铺。WM_HINTS属性:查看input字段,若窗口不需要接收输入(如纯装饰悬浮窗),同样跳过平铺。
二、EWMH 扩展属性补充(次优先)
_NET_WM_WINDOW_TYPE属性:该属性更细致地定义窗口类型,直接区分各类非平铺窗口:- 需要跳过平铺的典型类型:
_NET_WM_WINDOW_TYPE_DIALOG、_NET_WM_WINDOW_TYPE_UTILITY、_NET_WM_WINDOW_TYPE_TOOLTIP、_NET_WM_WINDOW_TYPE_NOTIFICATION - 实现:用
XGetWindowProperty获取属性值,对比对应的原子值,匹配上述类型则标记为浮动窗口。
- 需要跳过平铺的典型类型:
_NET_WM_STATE属性:若窗口带有_NET_WM_STATE_SKIP_TASKBAR或_NET_WM_STATE_SKIP_PAGER状态,说明它无需出现在任务栏/分页器中,通常属于弹窗类,可跳过平铺。
三、核心处理逻辑
- 窗口映射事件(
MapRequest)触发时,先执行上述属性检查。 - 标记为弹窗的窗口:不加入平铺布局队列,保留其自身的大小和位置设置,或根据父窗口位置做简单调整。
- 普通窗口:按原有主/栈平铺逻辑处理。
四、Xlib 代码示例片段
// 检查 WM_TRANSIENT_FOR Window transient_for; XGetTransientForHint(dpy, win, &transient_for); if (transient_for != None) { mark_as_floating(win); // 自定义函数:标记窗口为浮动 return; } // 检查 _NET_WM_WINDOW_TYPE Atom net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); Atom *window_types; int n_types; if (XGetWindowProperty(dpy, win, net_wm_window_type, 0, 10, False, XA_ATOM, NULL, NULL, &n_types, NULL, (unsigned char**)&window_types) == Success) { Atom dialog_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); Atom tooltip_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False); for (int i = 0; i < n_types; i++) { if (window_types[i] == dialog_type || window_types[i] == tooltip_type) { mark_as_floating(win); XFree(window_types); return; } } XFree(window_types); }
内容的提问来源于stack exchange,提问作者Moosa
相关产品推荐
相关产品推荐

