BazitteはImmutable OSなので基本的にシステム領域は変更できない。よって、DistroboxコンテナにCompositorをインストールして利用する。ここではHyprlandを例に手順の記載する。

コンテナを作る

[hyprland]
image=quay.io/toolbx/arch-toolbox
volume=/run/dbus/system_bus_socket:/run/dbus/system_bus_socket
volume=/run/udev:/run/udev
volume=${XDG_RUNTIME_DIR}/X11-unix:/tmp/.X11-unix
additional_packages="hyprland"
exported_bins="/usr/bin/Hyprland /usr/bin/hyprctl"
  • dbusをマウントしてホストのlogindからseatを取得できるようにする。
  • udevをマウントしてデバイスのホットプラグを検知できるようにする。
  • Xwaylandをコンテナ内で実行可能にするために後述の.X11-unixの調整が必要になる。

distrobox assemble create --file hyprland.iniでコンテナを作成できる。ホストからHyprlandが実行できてセッション初期化に失敗することは確認しておこう。

X11ソケットをコンテナから作成可能にする

コンテナ内でXwaylandを起動すると標準の/tmp/.X11-unixにソケットを作成ようとするが、ホストではroot所有になっているディレクトリがコンテナ内ではnobodyにマッピングされており権限チェックに失敗する。色々試したがrootlessコンテナでホストのディレクトリをrootもしくは自身に見せかけるのは不可能だと結論づけた。

よって、コンテナは別のディレクトリにソケットを作成し、それをホストと同期する形にする。まずはsystemdのパス監視でソケットの作成を検知する。

[Unit]
Description=Watch %t/X11-unix for create/delete
 
[Path]
PathChanged=%t/X11-unix
Unit=x11-unix-link.service
 
[Install]
WantedBy=default.target

ソケットが作成されたらホストの/tmp/.X11-unixにシンボリックリンクする。

[Unit]
Description=Link %t/X11-unix/X* to /tmp/.X11-unix/X*
 
[Service]
Type=oneshot
ExecStart=/bin/sh -ec "rundir='%t/X11-unix'; out='/tmp/.X11-unix'; find \"$rundir\" -maxdepth 1 -type s -name 'X*' -print0 2>/dev/null | while IFS= read -r -d '' s; do ln -sfn \"$s\" \"$out/$(basename \"$s\")\"; done; for l in \"$out\"/X*; do [ -L \"$l\" ] || continue; target=$(readlink -f \"$l\" || true); case \"$target\" in \"$rundir\"/X*) [ -e \"$target\" ] || rm -f \"$l\";; esac; done"

最後に有効化する。

mkdir $XDG_RUNTIME_DIR/X11-unix
systemctl --user daemon-reload
systemctl --user enable --now x11-unix-link.path

これでコンテナ内でXwaylandが起動したらホストにソケットが現れる。なおホスト側でソケットを作っているとソケット/tmp/.X11-unix/X0のインデックスが重複する問題になるので注意。今のところホストでX11サーバーを起動することがないので無視している。

ディスプレイマネージャに登録する

sudo mkdir /usr/local/share/wayland-sessions
"[Desktop Entry]
Name=Hyprland
Comment=Hyprland
Exec=/home/atty/.local/bin/wayland-session-exec /home/atty/.local/bin/Hyprland
Type=Application
DesktopNames=Hyprland
X-GDM-SessionRegisters=true
X-GDM-SessionType=wayland
NoDisplay=false
" | sudo tee /usr/local/share/wayland-sessions/hyprland.desktop

ディスプレイマネージャの実行時はまだユーザーが確定していないので、/usr/localに設定を書くのがいいと思う。これでSDDMはセッションを認識してくれた。

Compositorの設定

Compositorはコンテナ内で動いているので、ホスト側のアプリを起動するにはdistrobox-host-execを使う必要がある。とりあえずターミナルをホスト側で動かせば、コンテナはほぼ意識しないで済む。