☰
Qtile 窗口命令 API 全指南:在命令图中控制浮动、全屏、透明度与 Z 轴图层
2026/10/6 2:42:01 网站建设 项目流程
  • 桌面应用
  • 操作系统

【免费下载链接】qtile

:cookie: A full-featured, hackable tiling window manager written and configured in Python (X11 + Wayland)

项目地址:https://gitcode.com/gh_mirrors/qt/qtile
点击查看免费下载

导读

在 Qtile 中,窗口的尺寸与位置通常由当前布局(layout)决定,但窗口自身仍可通过一组丰富的命令改变外观与行为:切换浮动状态、进入全屏、调节透明度、调整 Z 轴图层次序、跨组/跨屏移动等。本文以 docs/manual/commands/api/windows.rst 为骨架,结合 libqtile/backend/base/window.py、X11/Wayland 双后端实现与对应测试,系统梳理窗口对象暴露的全部命令及其底层原理。读完本文,你将能够在键位绑定、鼠标回调、qtile shell、qtile cmd-obj 以及 Python 脚本(CommandClient / InteractiveCommandClient)中熟练调用这些窗口命令,并理解 X11 与 Wayland 后端在实现上的差异。

窗口对象与命令图

Qtile 将窗口管理器拆解为八类基本对象,构成一棵命令图(command graph):layouts、windows、groups、bars、widgets、screens、core,以及一个特殊的root节点。图形结构见 docs/manual/commands/command_graph.rst,每一条边都表示"持有对某对象的引用"。

窗口节点正是这八类节点之一。如 windows.rst 所述:

  • 窗口的尺寸与位置由当前布局决定;
  • 但窗口仍可以多种方式改变自身外观,例如切换浮动状态、全屏、调节透明度;
  • 窗口还可以访问与其显示相关的对象,即它所在的屏幕(screen)、所属的工作组(group)和当前布局(layout)。

这种连通性使得在某个对象上触发的回调中,可以轻易"顺藤摸瓜"地访问到相关对象。

文档自动生成机制

windows.rst 本身是一份由 Sphinx 指令生成的 API 页面:它通过qtile_commands指令,以libqtile.backend.base.Window为基类,将代码中所有用@expose_command()装饰的方法自动展开为命令文档。对应的指令实现位于 docs/qtile_docs/commands.py:它反射类成员,检查_cmd标记,收集全部公开命令,并同时生成lazy.window.<command>()与qtile cmd-obj -o window -f <command>两种调用语法的示例。因此,只要源码中新增了@expose_command()方法,本页 API 文档就会自动同步更新,这保证了文档与实现始终一致。

访问窗口命令的多种接口

命令图中的命令可通过五种接口调用,详见 docs/manual/commands/interfaces.rst。以窗口命令为例,同一操作在五种接口中的写法分别为:

# 1. lazy 接口(用于配置脚本中的键位与鼠标回调) lazy.window.toggle_floating() # 2. qtile shell(将命令图映射为虚拟文件系统) > cd window window > toggle_floating() # 3. qtile cmd-obj(适合 shell 脚本) qtile cmd-obj -o window -f toggle_floating # 4. CommandClient(低级 Python 接口) >>> from libqtile.command.client import CommandClient >>> c = CommandClient() >>> c.navigate("window", None).call("toggle_floating") # 5. InteractiveCommandClient(高级 Python 接口,语法模仿 lazy) >>> from libqtile.command.client import InteractiveCommandClient >>> c = InteractiveCommandClient() >>> c.window.toggle_floating()

需要注意:从根节点出发时,当前window、group、layout、screen都可以省略选择器而直接访问"当前对象";而widget与bar节点必须携带选择器。若某条路径解析不到对象(例如访问一个未显示在屏幕上的组所关联的 screen),会抛出CommandError: No object screen in path ...异常。

窗口对象的类层次:Window / Internal / Static

在 libqtile/backend/base/window.py 中,窗口对象被划分为三个抽象子类,均继承自_Window(CommandObject的子类),由各后端分别实现:

  • Window:普通客户端窗口,由布局管理。它持有qtile引用、float_x/float_y浮动偏移、bordercolor边框颜色与_float_state浮动状态等关键属性。repr形如Window(name='...', wid=...)。
  • Internal:Qtile 自身拥有的内部窗口(典型如 bar)。它需要实现create_drawer()来绘制内容,并处理按键、指针进入/离开/移动、按钮点击等事件。
  • Static:绑定到屏幕而非工作组的窗口,info()命令返回name、wm_class、x、y、width、height、id、opacity等字段。

此外,窗口还有若干只读属性供命令与布局使用,例如has_fixed_ratio()(客户端要求固定宽高比,对应 X11 的PAspect提示)、has_fixed_size()(固定尺寸)与urgent(紧急请求焦点,X11 下对应_NET_WM_STATE_DEMANDS_ATTENTION)。

布局定尺寸,窗口定状态:浮动 / 全屏 / 最大化 / 最小化

窗口的几何行为由浮动状态机统一管理。状态定义见 libqtile/backend/base/float_states.py:

class FloatStates(enum.Enum): NOT_FLOATING = 1 # 平铺 FLOATING = 2 # 浮动 MAXIMIZED = 3 # 最大化 FULLSCREEN = 4 # 全屏 TOP = 5 # 置顶 MINIMIZED = 6 # 最小化

基类的Window.maximized、fullscreen、minimized属性均直接以_float_state为准。进入/退出全屏的核心逻辑在_set_fullscreen()(window.py#L305-L323):进入全屏时先调用save_float_state()记录当前几何与状态,然后按屏幕全尺寸(扣除fullscreen_border_width)重排浮动几何;退出时调用restore_float_state()恢复。最大化(maximizedsetter)与之对称,使用max_border_width作为边框扣除。save_float_state()与restore_float_state()(window.py#L340-L361)把base_x/base_y/base_width/base_height作为"退出全屏/最大化后恢复"的锚点。

状态切换命令

基类Window声明了一组成对的抽象命令(均由具体后端实现):

命令作用
toggle_floating()/enable_floating()/disable_floating()切换/强制进入/强制退出浮动
toggle_maximize()/toggle_minimize()切换最大化 / 最小化
toggle_fullscreen()/enable_fullscreen()/disable_fullscreen()切换/进入/退出全屏

在 Wayland 后端(libqtile/backend/wayland/window.py#L864-L893)中,这些命令实现得非常直接:toggle_floating()即self.floating = not self.floating,toggle_fullscreen()即self.fullscreen = not self.fullscreen,fullscreen与maximized的 setter 进一步触发_update_fullscreen()/_update_maximized()向合成器同步状态。进入浮动时若配置了floats_kept_above=True,窗口会被自动放入 keep-above 图层(见get_new_layer(),wayland/window.py#L634-L641)。

X11 后端在info()中(x11/window.py#L668-L694)额外返回float_info(浮动时的 x/y/width/height)与floating/maximized/minimized/fullscreen布尔字段。测试 test/backend/x11/test_window.py#L195-L203 验证了窗口从浮动(10×10)切换为平铺(398×578)再切换为全屏(800×600)的几何变化。

透明度控制

基类Window提供三组透明度命令(window.py#L533-L551):

  • set_opacity(opacity):设置透明度,取值范围0.1~1.0(小于 0.1 被钳制到 0.1,大于 1 被钳制到 1);
  • up_opacity()/down_opacity():以 0.1 为步长递增/递减;
  • 只读属性opacity(0 表示全透明,1 表示不透明)。

在 X11 后端,透明度读写映射到 EWMH 的_NET_WM_WINDOW_OPACITY属性(x11/window.py#L705-L722):写入时将 0.0~1.0 的浮点值按0xFFFFFFFF缩放为整数,读取时再换算回两位小数。测试 test/backend/wayland/test_window.py#L122-L159 完整覆盖了边界行为:set_opacity(5.0)被钳到 1.0、set_opacity(-1.0)被钳到 0.1、连按down_opacity()十次后停在 0.1、连按up_opacity()十五次后停在 1.0——这也验证了"基类的 IPC 命令在 0.1 处钳制而非 0.0"这一细节。

Z 轴图层:置顶、置底与堆叠次序

窗口堆叠遵循 EWMH 的分层规则(desktop 层 → below 层 → 普通层 → above/dock 层 → 聚焦的全屏层),Qtile 还额外增加了一个"scratchpad 永远在最上"的图层。基类定义了五组图层命令(window.py#L153-L215):

命令语义
keep_above(enable=None)保持窗口在其它窗口之上;不传参时翻转当前状态
keep_below(enable=None)保持窗口在其它窗口之下;不传参时翻转当前状态
move_up(force=False)沿 Z 轴向上移动一个位置;普通窗口不会被提升到 keep_above 窗口之上
move_down(force=False)沿 Z 轴向下移动一个位置;普通窗口不会被压到 keep_below 窗口之下
move_to_top()移动到当前图层的顶部(例如三个 keep_above 窗口中,调用者排第一)
move_to_bottom()移动到当前图层的底部
bring_to_front()无视所有分层规则直接置顶;窗口失去焦点后按规则重新入栈

force=True的语义:move_up(force=True)允许把 keep_below 的窗口提升上去(同时清除其 keep_below 状态),move_down(force=True)同理允许压过 keep_above 窗口。keep_above/keep_below在 X11 后端通过读写_NET_WM_STATE中的_NET_WM_STATE_ABOVE/_NET_WM_STATE_BELOW原子实现(x11/window.py#L1394-L1484),随后调用change_layer()依据get_layering_information()(x11/window.py#L910-L971)重排堆叠。

Wayland 后端则直接映射到 wlr 合成器的图层:keep_above将视图 reparent 到LAYER_KEEPABOVE,keep_below到LAYER_KEEPBELOW,bring_to_front到LAYER_BRINGTOFRONT并调用qw_view_raise_to_top(wayland/window.py#L80-L121)。对应测试 test/backend/wayland/test_window.py#L88-L98 验证了bring_to_front()会把窗口从LAYER_LAYOUT移到LAYER_BRINGTOFRONT。

位置与尺寸:浮动几何的精细控制

基类抽象定义了以下几何命令,全部由后端实现:

命令作用
place(x, y, width, height, borderwidth, bordercolor, above=False, margin=None, respect_hints=False)把窗口放到指定位置并设置尺寸(布局调度的底层通道)
get_position()返回(x, y)
get_size()返回(width, height)
move_floating(dx, dy)浮动窗口相对位移
resize_floating(dw, dh)浮动窗口增减尺寸
set_position_floating(x, y)浮动窗口移动到绝对坐标
set_size_floating(w, h)浮动窗口设置为指定尺寸
set_position(x, y)浮动窗口移动;平铺窗口则与指针下的窗口交换位置
center()将浮动窗口在屏幕上居中

place()是布局调度窗口的底层通道。X11 实现(x11/window.py#L804-L908)展示了它的完整细节:

  • margin接受单个 int(四边等距)或[N, E, S, W]列表,并据此收缩目标几何;
  • respect_hints=True时会尊重客户端的 WM_SIZE_HINTS:受PMinSize/PMaxSize钳制、按PAspect校正宽高比、按base_width/width_inc与base_height/height_inc对齐增量;
  • 会保存float_x/float_y屏幕相对偏移,调用configure()下发 X 协议,随后paint_borders()绘制边框并发送合成ConfigureNotify。

Wayland 的place()(wayland/window.py#L178-L258)同样处理 margin,并把边框颜色列表转换为 C 层的qw_border数组后调用合成器接口;其set_position()在窗口为平铺状态时会遍历同组窗口,与指针所在窗口调用group.layout.swap()交换(wayland/window.py#L840-L857)。

center()命令是基类默认实现(window.py#L569-L592):仅对浮动窗口生效,且要求窗口已属于某个显示中的屏幕,然后按(screen.width - self.width) // 2计算居中坐标并调用place(..., above=True, respect_hints=True)。

在鼠标回调中的典型用法

窗口几何命令最常见的实战场景是鼠标拖拽与调整大小,参考 docs/manual/config/mouse.rst:

from libqtile.config import Click, Drag mouse = [ # 用 mod+左键拖动浮动窗口 Drag([mod], "Button1", lazy.window.set_position_floating(), start=lazy.window.get_position()), # 用 mod+右键调整浮动窗口大小 Drag([mod], "Button3", lazy.window.set_size_floating(), start=lazy.window.get_size()), # 用 mod+中键置顶窗口 Click([mod], "Button2", lazy.window.bring_to_front()) ]

其中start=提供了拖拽的起始几何快照,Drag会在指针移动时把增量传入绑定命令。

跨组与跨屏移动:togroup 与 toscreen

togroup(group_name=None, switch_group=False, toggle=False)(基类文档位于 window.py#L480-L505)把窗口移动到指定工作组:

# 移动到当前组(无实际效果) togroup() # 移动到名为 "a" 的组 togroup("a") # 移动到组 "a",并切换到该组 togroup("a", switch_group=True) # 若组 "a" 已在屏幕显示,则改用上一个使用过的组 togroup("a", toggle=True)

toscreen(index=None)则把窗口移动到指定屏幕——本质上是把窗口移交到该屏幕当前显示的组(window.py#L507-L531):

# 移动到当前屏幕 toscreen() # 移动到屏幕 0 toscreen(0)

索引越界会抛出CommandError: No such screen: ...。Wayland 的togroup()实现(wayland/window.py#L526-L559)还会先hide()再移交,并在组未配置persist=True时清理空组。

静态窗口:从布局中解放

static(screen=None, x=None, y=None, width=None, height=None)把普通窗口转换为静态窗口——它不再属于任何工作组,而是直接绑定屏幕,几何由用户指定,其余未指定的值沿用窗口当前状态。转换时窗口对象的defunct标记被置为 True(表示不再作为普通窗口被管理),并触发client_managedhook(Wayland 实现见 wayland/window.py#L469-L523)。测试 test/backend/wayland/test_window.py#L40-L58 验证了 XDG shell 窗口调用static()后仍可从info()["shell"]读到"XDG",而 layer shell 窗口的 shell 字段为"layer"。

关闭、聚焦与信息查询

kill

kill()关闭窗口。X11 实现遵循 ICCCM:若窗口声明了WM_DELETE_WINDOW协议,则发送ClientMessage礼貌请求关闭;否则直接KillClient(x11/window.py#L724-L747)。Wayland 实现直接调用合成器视图的kill()(wayland/window.py#L167-L168)。典型键位绑定:Key(["mod1"], "F4", lazy.window.kill())。

focus 与焦点机制

focus(warp=True)聚焦窗口并可选地将指针移动到窗口中心。X11 实现(x11/window.py#L1289-L1333)展示了一套完整的 ICCCM 聚焦协商流程:

  1. 若WM_HINTS的InputHint为真,直接SetInputFocus;
  2. 否则若窗口声明了WM_TAKE_FOCUS协议,发送携带合法时间戳的ClientMessage(时间戳不能是CurrentTime);
  3. 聚焦成功后同步_NET_WM_STATE_FOCUSED状态、清除 urgent 标记、更新_NET_ACTIVE_WINDOW、重抓/解除旧窗口的按钮事件,并触发client_focushook。

此外还有两个与焦点相关的辅助属性:can_steal_focus决定窗口是否可以抢走焦点(X11 下类型为notification的窗口默认不允许);activate_by_config()则依据配置项focus_on_window_activation(取值focus/smart/urgent/never,也可为可调用对象)决定窗口请求激活时的行为——smart模式下若窗口在别的屏幕,会置为 urgent 并触发client_urgent_hint_changedhook(window.py#L611-L632)。

info 与 inspect

  • info()返回窗口的元信息。基类文档要求至少包含name、x、y、width、height、group、id、wm_class(window.py#L136-L151);X11 与 Wayland 实现在此基础上追加floating、maximized、minimized、fullscreen、float_info等字段,Wayland 还额外提供shell与opacity(wayland/window.py#L657-L684)。
  • get_hints()(仅 X11)返回 WM_HINTS / WM_SIZE_HINTS 解析结果。
  • inspect()(仅 X11)返回"关于窗口的一切":X 属性(backing_store、map_state、事件掩码等)、属性列表、协议、normal hints、state 与 float_info(x11/window.py#L1340-L1392),对应测试 test/backend/x11/test_window.py#L759 的test_inspect_window。

空闲抑制:add_idle_inhibitor 与 remove_idle_inhibitor

为了在播放视频、全屏展示等场景下阻止系统进入空闲/睡眠,基类暴露了空闲抑制命令(window.py#L639-L652):

  • add_idle_inhibitor(inhibitor_type="open"):为窗口创建抑制规则,inhibitor_type可选"open"、"focus"、"fullscreen"、"visible",默认"open";
  • remove_idle_inhibitor():移除该窗口的抑制规则。

两者最终都交由qtile.core.idle_inhibitor_manager统一管理(对应 X11 的_NET_WM_IDLE_INHIBIT与 Wayland 的 idle inhibit 协议,见 libqtile/backend/x11/idle_notify.py 与 libqtile/backend/wayland/idle_inhibit.py)。配置中还可以通过idle_inhibitors规则批量声明"哪些窗口、在什么条件下自动添加抑制"(window.py#L634-L637)。

在键位配置中的综合实战

把上述命令组装成一套常见的窗口快捷键配置,参考 docs/manual/config/keys.rst:

from libqtile.config import Key, Match from libqtile.lazy import lazy keys = [ # 关闭窗口 Key([mod], "c", lazy.window.kill()), # 切换浮动 Key([mod], "space", lazy.window.toggle_floating()), # 切换全屏(可配合 .when() 限定条件,例如仅在窗口浮动时生效) Key([mod], "f", lazy.window.toggle_fullscreen().when(when_floating=True)), # 仅对特定 wm_class 生效 Key([mod], "x", lazy.window.toggle_fullscreen().when(focused=Match(wm_class="yourclasshere"))), # Z 轴调整 Key([mod], "k", lazy.window.move_up()), Key([mod], "j", lazy.window.move_down()), Key([mod, "shift"], "k", lazy.window.keep_above()), Key([mod, "shift"], "j", lazy.window.keep_below()), Key([mod, "control"], "k", lazy.window.bring_to_front()), # 跨组移动:把窗口移到组 "2" 并切换过去 Key([mod, "shift"], "2", lazy.window.togroup("2", switch_group=True)), # 透明度微调 Key([mod], "equal", lazy.window.up_opacity()), Key([mod], "minus", lazy.window.down_opacity()), ]

其中lazy.window.<command>()创建的是对命令的引用而非立即调用——这正是它能与键位/鼠标回调绑定的前提(详见 docs/manual/config/lazy.rst 中的 Window functions 一节与 docs/manual/commands/interfaces.rst 的说明)。togroup的可选参数switch_group、toggle也都在 lazy.rst 中有对应描述。

后端差异小结与测试佐证

能力X11 后端实现Wayland 后端实现
置顶/置底EWMH_NET_WM_STATE原子 +ConfigureWindow堆叠wlr layer-shell 图层 reparent
透明度_NET_WM_WINDOW_OPACITY属性合成器直接支持
焦点ICCCMWM_TAKE_FOCUS/ InputHint 协商qw_server_active_view+focus_window()
几何提示完整尊重WM_SIZE_HINTSrespect_hints暂标注为 TODO(wayland/window.py#L214)
专属命令get_hints()、inspect()is_visible()直接查询合成器可见性

所有窗口命令均被 test/backend/x11/test_window.py 与 test/backend/wayland/test_window.py 覆盖验证,例如 X11 侧的浮动/全屏几何切换(test_window.py#L195-L203)、大小/宽高比提示(test_min_size_hint等)、多色边框(test_multiple_borders),以及 Wayland 侧的透明度边界、图层切换与info()的 shell 字段。

结语

窗口命令 API 是 Qtile"可破解(hackable)"特性的重要一环:布局决定几何,而窗口自身的浮动、全屏、透明度与图层状态完全交给用户通过命令图控制。无论是编写键位配置、实现鼠标手势,还是通过 IPC 编写外部脚本,掌握 windows.rst 中列出的这组命令,就等于掌握了 Qtile 窗口层全部的用户可编程能力。想进一步了解其余对象的命令,可继续阅读 docs/manual/commands/api/index.rst 中的 root、layouts、groups、bars、widgets、screens 与 backend 各页。

  • 桌面应用
  • 操作系统

【免费下载链接】qtile

:cookie: A full-featured, hackable tiling window manager written and configured in Python (X11 + Wayland)

项目地址:https://gitcode.com/gh_mirrors/qt/qtile
点击查看免费下载
上一篇:minimal-mistakes 文本对齐实战:用 Kramdown 属性列表控制段落排版
下一篇:Apache Pulsar C++ 客户端源码构建全指南:多平台编译、测试与配置详解

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询