跳转至

07 · Quickshell 运行时

Omarchy Shell 不是一组每次点击才启动的 QML 小程序,而是一个长时间运行的 Quickshell 进程。bar、panel、overlay、menu、通知和后台 service 都是它内部的插件。

为什么需要常驻宿主

桌面 UI 有大量需要共享的状态:应用索引、插件注册表、主题 token、当前 panel、通知历史、托盘和媒体状态。如果每个界面都独立启动,会重复扫描、出现多个 D-Bus owner,并很难保持互斥关系。

flowchart TD
    Root[shell.qml / ShellRoot]
    Root --> PR[PluginRegistry]
    Root --> BR[BarWidgetRegistry]
    Root --> AL[AppLibrary]
    Root --> Bar[Active Bar]
    Root --> Service[Service Loaders]
    Root --> Surface[Panel / Overlay / Menu Loaders]
    CLI[omarchy-shell IPC] --> Root
    PR --> Bar
    PR --> Service
    PR --> Surface
    AL --> Bar
    AL --> Surface

shell.qml 显式创建共享 registry 和 AppLibrary,再通过 property 注入下游。这样可避免 QML 相对 import 造成“看似 singleton、实际不同实例”的问题。

启动与重启

Hyprland autostart 调用 omarchy-launch-shell,后者启动 Quickshell 主文件。omarchy-restart-shell 使用锁和等待逻辑,避免旧进程未退出就拉起第二个实例。

IPC wrapper omarchy-shell 只向已运行实例转发调用,并受超时控制。它不会自动启动 Shell:

  • 正常调用失败能真实反映桌面运行时缺失;
  • -q 可用于 quiet best-effort 场景;
  • 启动责任仍集中在会话 autostart,而不是散到任意命令。

这防止一个 headless SSH 命令意外启动整套图形桌面。

配置加载链

Shell 有三层配置输入:

  1. shell.qml 内置一个可启动的 fallback 对象;
  2. 读取 $OMARCHY_PATH/config/omarchy/shell.json 的发行初始配置;
  3. 若 ~/.config/omarchy/shell.json 存在且合法,则整体替换。

default 和 user 文件都由 FileView 监视,改动触发重新解析。用户配置是 canonical object,不做 deep merge;这避免新默认字段在用户不知情时改变已定制桌面。

插件何时加载

类型 时机 理由
active full bar 启动时 桌面持续可见
first-party service 启动时 通知、锁屏等基础设施
third-party service 被 shell.json 启用时 不默认执行外部代码
panel / overlay / menu summon 时 降低常驻开销
keepLoaded surface 首次 summon 后保留 插件声明保留状态/性能

若选中的第三方 full bar 加载失败,宿主回退到内置 omarchy.bar,保证桌面仍有基本控制面。

延迟 surface 的两次召唤问题

panel 第一次 summon 时 Loader 还没完成。如果第二个 payload 很快到达,简单实现会覆盖或丢失事件。Shell 保存 pending payload,待组件 ready 后再调用 open(payloadJson)。

sequenceDiagram
    participant C as CLI
    participant H as Shell host
    participant L as Loader
    participant P as Plugin panel
    C->>H: summon(id, payload A)
    H->>L: active = true
    C->>H: summon(id, payload B)
    H->>H: 保存 pending payload
    L-->>H: item ready
    H->>P: 注入依赖
    H->>P: open(latest queued payload)

宿主还维护当前 open panel ID,使常规 panel 互斥;bar widget 对应的 panel 则路由给正在使用的 bar 实例,因为位置和 anchor 由 bar 掌握。

IPC 是稳定边界

Shell 暴露一个 shell target,并允许插件注册自己的 target。核心方法包括:

  • ping:健康检查;
  • summon / hide / toggle:surface 生命周期;
  • call:调用已加载插件方法;
  • rescanPlugins:重新发现与热加载;
  • reloadConfig:重读 shell.json;
  • applyTheme:推送颜色和 shell token;
  • bar widget 的 put/move/set 与调试接口。

命令行、Hyprland binding 和其他脚本都走 IPC,而不是直接操作 QML 对象。这让 UI 内部可以重构,只要 IPC 契约保持。

主题如何进入常驻进程

主题切换先在文件系统生成 colors.toml / shell.toml,随后把 base64 编码的 payload 经 applyTheme 推入 Shell。机器级 ~/.config/omarchy/shell.toml 另由 FileView 实时监视,并覆盖活动主题的对应 token,使文字大小等本机偏好跨主题保留。

QML 通过共享 singleton 使用:

  • Color:基础 palette 与各 surface 角色;
  • Style:间距、字号、圆角与 bar 尺寸;
  • Border:支持渐变/分边宽度的边框规范。

故障隔离策略

故障 宿主行为
用户 shell.json 无效 保持可启动 fallback/default
自定义 bar 加载失败 回退内置 bar
panel 尚未实例化 排队 payload 后延迟 open
Shell 不在运行 IPC 明确失败,不偷偷启动
插件目录变化 rescan / inotify 热加载用户代码
主题切换 先原子更新文件,再向运行时推送

关键源码索引

下一章专门拆常驻宿主最重要的扩展边界:08 · 插件系统。