如何使用Python在GNOME桌面中将窗口移动至桌面图标层下方
GNOME X11会话下用Python将窗口置于桌面图标层下方
本方案仅适用于Ubuntu GNOME的X11会话,Wayland会话下Xlib无全局窗口操作权限,无法实现该需求。登录时在登录界面点齿轮选择「GNOME on Xorg」即可切换到支持的会话,登录后执行echo $XDG_SESSION_TYPE返回x11即为环境符合要求。
核心实现逻辑
GNOME X11下窗口按栈顺序叠放,从最底层到最顶层顺序固定:
- 最底层:X根窗口,即系统绘制桌面壁纸的层
- 向上第二层:桌面图标容器窗口,Ubuntu默认桌面图标扩展、GNOME原生图标功能都运行在这层,窗口会携带标准的
_NET_WM_WINDOW_TYPE_DESKTOP类型标记 - 中间层:所有普通应用窗口
- 最顶层:置顶窗口、弹窗、通知等元素
要把目标窗口放到桌面图标层下方,本质就是操作X服务器的窗口栈,把目标窗口的层级调整到桌面图标容器窗口的紧邻下方即可。
前置依赖安装
执行以下命令安装所需的Python Xlib库,二选一即可:
# 系统源安装(推荐,兼容性更好) sudo apt update && sudo apt install python3-xlib # pip安装 pip install python3-xlib
完整实现代码
from Xlib import X, display, Xatom from Xlib.protocol import event # 初始化当前用户的X服务器连接 d = display.Display() root = d.screen().root # 预定义需要用到的X协议原子 NET_WM_WINDOW_TYPE = d.intern_atom('_NET_WM_WINDOW_TYPE') NET_WM_WINDOW_TYPE_DESKTOP = d.intern_atom('_NET_WM_WINDOW_TYPE_DESKTOP') NET_WM_NAME = d.intern_atom('_NET_WM_NAME') UTF8_STRING = d.intern_atom('UTF8_STRING') NET_WM_PID = d.intern_atom('_NET_WM_PID') def get_desktop_window(): """遍历所有顶层窗口,定位桌面图标所在的容器窗口""" raw_windows = root.query_tree().children for win in raw_windows: try: win_type_prop = win.get_full_property(NET_WM_WINDOW_TYPE, X.AnyPropertyType) if not win_type_prop: continue # 匹配标记为桌面类型的窗口 if win_type_prop.value[0] == NET_WM_WINDOW_TYPE_DESKTOP: return win except Exception: continue raise RuntimeError("未找到桌面图标层窗口,请确认当前运行在GNOME X11会话且已启用桌面图标功能") def get_target_window_by_title(title_keyword): """按标题关键词匹配需要调整层级的目标窗口""" raw_windows = root.query_tree().children for win in raw_windows: try: title_prop = win.get_full_property(NET_WM_NAME, UTF8_STRING) if not title_prop: continue win_title = title_prop.value.decode('utf8', errors='ignore') if title_keyword in win_title: return win except Exception: continue raise RuntimeError(f"未找到标题包含「{title_keyword}」的窗口") if __name__ == "__main__": # 1. 获取桌面图标层窗口对象 desktop_win = get_desktop_window() # 2. 替换为你要操作的窗口的标题关键词,比如要操作Firefox就传"Firefox" target_win = get_target_window_by_title("替换为你的目标窗口标题关键词") # 3. 核心操作:将目标窗口调整到桌面窗口的下方 target_win.configure( sibling=desktop_win, stack_mode=X.Below ) # === 可选配置开始 === # 如果需要窗口长期停留在图标层下方,不会被GNOME WM自动抬回普通层,可以取消下面这段注释 # 注意:加了这个属性后窗口不会出现在Alt+Tab切换列表,适合动态壁纸、桌面挂件类场景 # target_win.change_property( # NET_WM_WINDOW_TYPE, # Xatom.ATOM, # 32, # [NET_WM_WINDOW_TYPE_DESKTOP], # X.PropModeReplace # ) # === 可选配置结束 === # 将所有操作提交到X服务器生效 d.sync() print("窗口层级调整完成")
使用说明
- 把代码里
get_target_window_by_title的参数替换成目标窗口的标题关键词即可,比如要调整终端窗口就传"终端"或"Terminal"。 - 如果需要按进程PID匹配窗口,可以参考
get_target_window_by_title的逻辑,读取窗口的_NET_WM_PID属性做匹配即可。 - 不要用sudo运行脚本,否则会因为权限上下文不对找不到当前用户的X会话。
常见问题排查
- 调整完窗口过几秒自动跳回普通层:把代码里可选配置段的注释打开,给目标窗口打上桌面类型标记,GNOME窗口管理器就不会自动调整它的栈顺序。
- 找不到桌面窗口:如果用了第三方桌面图标扩展未按标准标记窗口类型,可以在终端执行
xwininfo -tree -root打印完整窗口树,手动找到承载图标的窗口ID,直接传入调整逻辑即可。 - 窗口被图标完全挡住:属于正常现象,因为窗口已经在图标层下方,如果需要交互可以暂时隐藏桌面图标,或者只给不需要点击的壁纸类窗口用这个层级。
内容的提问来源于stack exchange,提问作者Fido_de07
相关产品推荐
相关产品推荐

