Quickshell デスクトップシェル
トップバー、サイドバー、コントロールセンター、通知などの「シェル」は Quickshell で実装しています。これは QML を使って Wayland デスクトップコンポーネントを記述できるツールです。私の環境は illogical-impulse (end-4 の dots、ディレクトリコード ii) をベースにしており、それを改変しています。
まず明確にしておきます:これは QML で7万行、900以上のファイルからなる巨大なコードベースで、その大半は私が書いたものではありません。したがって、私自身(そしてこの記事を読む人)にとって真に有用なのは、ファイルごとの解説ではなく、以下の2点です——「どのようにレイヤー構造が組まれているか」と「色がどこから来ているか」。この2つが分かれば、修正したいコンポーネントを順に追っていくことができます。
まず Quickshell 自体が提供する機能から説明します。Quickshell は QML (Qt の宣言的 UI 言語) を Wayland の layer-shell に接続します。これにより、「プロパティバインディング + シグナル」という宣言的な書き方で、トップバー、オーバーレイウィンドウ、ロック画面などのデスクトップレイヤーコンポーネントを記述できます。利点は反応性にあります——ある値が変化すると、それにバインドされた UI が自動的に再描画され、手動で更新ロジックを書く必要がありません。
その上で、ii の構造はデータを取得する services と UI を描画する modules の2層になっています。
- services はシステム状態を QML のシングルトンオブジェクトとしてカプセル化します。PipeWire(音量/デバイス)、NetworkManager(ネットワーク)、UPower(バッテリー)、MPRIS(再生中)などがそれぞれバインド可能なプロパティとして公開されます。
- modules はこれらの状態を宣言的にパネルやコントロールとして描画し、インタラクション(クリックやドラッグ)が発生すると service にコールバックを返します。
// 概要:システム音量に追従するスライダー
Slider {
value: Pipewire.defaultSink.volume // service のプロパティにバインド
onMoved: Pipewire.defaultSink.volume = value // インタラクションで値を書き戻す
}
したがって、トップバーに新しいウィジェットを追加する場合の手順は決まっています。modules 内で QML を記述し、対応する service からデータを取得してバインドするだけです。900以上のファイルの大半に触れる必要はありません。既存のコンポーネントを修正したい場合は、「どの service を参照しているか」を遡って調べればよいだけです。
色は Quickshell 自体で定義されておらず、matugen によって生成された ~/.local/state/quickshell/user/generated/colors.json を読み込みます。そのため、壁紙を変更すると、シェル全体が Ghostty やロック画面とともに色を変更します(matugen の記事を参照)。
Quickshell は Hyprland の起動時に自動的に起動され、常駐します。これはアップストリームの rice に追随する大規模なプロジェクトであるため、chezmoi に組み込むことはしていません。アップストリームの更新に合わせて、ローカルで数カ所を修正する方が、7万行のコードを自分で管理するよりも楽だからです。