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
を使う必要がある。とりあえずターミナルをホスト側で動かせば、コンテナはほぼ意識しないで済む。