メインコンテンツまでスキップ

ShojiWMのアーキテクチャ

一言でいうと、ShojiWM は「速さが必要な部分を Rust で、見た目や挙動を TypeScript/TSX で書ける」Wayland コンポジターです。

このページでは、ShojiWM に興味を持った方に向けて、内部がどう動いているかを 順を追って解説します。専門用語はそのつど補足するので、Wayland やコンポジターを 初めて聞く方でも読み進められます。

そもそも「コンポジター」とは?

GUI のデスクトップでは、たくさんのアプリ(ブラウザ、ターミナル、ゲームなど)が それぞれ自分の絵(ウィンドウ)を描きます。これらをひとつの画面に 重ね合わせて(composite して) 最終的な映像を作り、ディスプレイに表示する 役割を持つソフトウェアが コンポジター です。

Wayland の世界では、このコンポジターが同時に「ウィンドウマネージャ (どのウィンドウをどこに、どんな大きさで置くか)」の役割も兼ねます。 ShojiWM はこの両方を担当します。

ヒント

Wayland 自体については Waylandとは を先に読むと理解がスムーズです。

全体像

ShojiWM は大きく4つの登場人物で成り立っています。

  • アプリ は標準の Wayland プロトコルを通じて ShojiWM と会話します。 アプリ側は「相手が ShojiWM である」ことを意識する必要はありません。
  • Rust コア は、入力・ウィンドウ・描画といった「速くて壊れてはいけない」 部分を担当します。
  • 設定ランタイム(TypeScript) は、ウィンドウの見た目や挙動を決めます。 RustyScript を通してコンポジター内へ組み込まれた Deno/V8 上で動作します。 あなたが書くのはこの部分です。
  • 最終的な映像は GPU で合成され、ディスプレイに出力されます。

2つの世界 ― なぜ Rust と TypeScript に分かれているのか

ShojiWM の最大の特徴は、1つのプロセスの中で役割を 2つの層 に分けていることです。

実行環境担当すること
コアRust + SmithayWayland プロトコル、入力処理、レイアウト計算、GPU 描画
設定組み込み Deno/V8 上の TypeScript/TSXウィンドウの装飾、配置ルール、エフェクト、キーバインド

なぜ分けるのでしょうか?

  • コア(Rust) は毎フレーム動く心臓部です。1秒間に何十回も実行されるため、 速度とメモリ安全性が重要です。そこで Rust と、Wayland コンポジター用ライブラリ Smithay を使っています。
  • 設定(TypeScript) は「見た目や好み」を表現する部分です。ここは書きやすさと 柔軟さが大切なので、Web 開発でおなじみの TypeScript/TSX で書けるようにして います。React に似た書き心地で、ウィンドウの枠やボタンを組み立てられます。

この2つは別プロセスではありません。RustyScript が Deno/V8 エンジンを shoji_wm プロセス内へ組み込み、TypeScript は専用のランタイムスレッドと V8 isolate 上で動作します。

注記

設定(TypeScript)を書き換えると、組み込みランタイムが設定を読み直します。 Rust コアを別プロセスとして落とす必要はないため、セッションを維持したまま 見た目や挙動を反復開発できます。

ShojiWM の実行に Node.js は必要ありません。Node.js/npm を使うのは、単独の TypeScript 型チェックや Docusaurus ドキュメントのビルドといった、リポジトリの 補助ツールを使う場合だけです。

SSD(サーバーサイド・デコレーション)の流れ

ウィンドウの「枠・タイトルバー・影」などの装飾を 誰が描くか には2つの流儀が あります。

  • クライアントサイド装飾 (CSD): アプリ自身が枠を描く
  • サーバーサイド装飾 (SSD): コンポジター(=サーバー)側が枠を描く

ShojiWM は SSD を採用し、しかもその「どう描くか」を あなたの TypeScript コードに任せます。流れを時系列で見てみましょう。

  1. アプリのウィンドウに変化が起きます(例:タイトルが変わった、フォーカスされた)。
  2. コアがそのウィンドウのスナップショット(現在の状態の写し)を TS ランタイムへ 送ります。
  3. TS ランタイムが、あなたの書いた 合成関数 composition(window) を実行し、 「このウィンドウをどう飾るか」を TSX で組み立てます。
  4. 結果のコンポジションツリーをコアへ返します。シグナルによる更新では、可能な限り 変更されたノードや uniform だけを差分として送ります。
  5. コアがそれを受け取り、レイアウトを計算して GPU で描画します。

つまり、あなたが TSX で <WindowBorder><Button> を書くと、組み込み ランタイムがそのツリーを評価してコアへ渡し、実際の画面の枠やボタンになります。

リアクティブな仕組み(シグナル)

「タイトルが変わったら枠の表示も自動で変わってほしい」――こうした自動更新を 支えているのが シグナル (signal) という仕組みです。

ポイントは「変化に関係する部分だけを再計算する」ことです。画面全体を毎回 作り直すのではなく、必要な部分だけを更新するので効率的です。React の状態管理を 触ったことがある方なら、感覚は近いはずです。

まとめ

  • ShojiWM は Rust の高速なコアTypeScript の柔軟な設定層の2層構造。
  • TypeScript は RustyScript/Deno/V8 として同じプロセスへ組み込まれ、 Rust コアとは native bridge でやり取りする。
  • ウィンドウの装飾は SSDで行い、その「描き方」を あなたの TSX コードが決める。
  • シグナルにより、状態の変化に応じて必要な部分だけが自動で再合成される。

次に進むなら、設定の概要 で実際のコードの書き方を 見てみてください。