WSLg(WSL2 の GUI サポート)で Chrome や Obsidian を動かす話です。そもそも Windows ネイティブ版があるのに、なぜ WSL 側で動かすのか。理由は2つです。
- Windows 版 Obsidian は、WSL ファイルシステム内の vault を開けません。WSL 側で書いているノートをそのまま Obsidian で扱うには、WSL 側の Obsidian が要ります。
- WSL 内のアプリが URL を開くとき、既定ブラウザを WSL 側の Chrome にしておくと連携が楽です。
ところが WSLg で Chrome や Obsidian などの Chromium / Electron 製アプリを HiDPI ディスプレイで使うと、たいてい次で詰まります。
- 文字が小さい、もしくはぼやける(解決)
- ウィンドウの端をドラッグしてリサイズできない(解決)
- アプリのアイコンが Linux のペンギンのまま(スタートメニューは解決・タスクバーは未解決)
この記事では 1 と 2 を同時に解決する設定を中心に紹介します。3 のうちスタートメニューのアイコンは直せますが、起動中ウィンドウのタスクバーアイコンは WSLg 側のバグで現状直りません(後述)。検証環境は デュアル4Kディスプレイ + WSL2(Ubuntu 24.04)+ WSLg 1.0.73 で、Google Chrome と Obsidian の両方で「くっきり表示」かつ「端をドラッグしてリサイズ可能」を確認しました。
執筆について: この記事は Claude Code が執筆し、Gemini と筆者がレビューしました。
結論(コピペ用)
アプリを次のフラグで起動します。
--ozone-platform=wayland \
--enable-features=WaylandWindowDecorations,WaylandFractionalScaleV1 \
--force-device-scale-factor=2
加えて、Windows のディスプレイ拡大率を「整数」スケール(例: 200%)にし、--force-device-scale-factor をそのスケールに合わせます(200% なら 2)。表示サイズは好みで微調整してよく、たとえば 100% のまま文字を大きくしたいなら 1.5 にもできます。これだけで文字はくっきり、端はドラッグでリサイズできるようになります。楽勝です。
ポイントは「端をドラッグできるかどうかは、スケールではなく表示バックエンド(X11 か Wayland か)で決まる」ことです。
問題1: 文字が小さい → そしてぼやける
小さい
WSLg は Windows の拡大率に応じて GDK_DPI_SCALE / QT_SCALE_FACTOR を設定します(例: 150% なら 1.5)が、これは GTK / Qt アプリ向けです。Chromium / Electron 製アプリはこれらを無視するので、--force-device-scale-factor を明示的に渡す必要があります。
ぼやける(こっちが厄介)
Windows のディスプレイ拡大率が 150% のような「分数」スケールだと、WSLg / Weston は一度 2 倍で描画してから 1.5 倍へリサンプル(縮小)します。この縮小処理が、にじみ・ぼやけの正体です。アプリ側のフラグでは消せません。
対策は「整数」スケールを使うことです。拡大率ごとの挙動は次のとおり。
- Windows 100% → Weston は
scale:1(整数) → くっきり(--force-device-scale-factor=1.5) - Windows 150% → Weston は
clientScale:1.5(分数) → ぼやける(2倍描画→縮小) - Windows 200% → Weston は
scale:2(整数) → くっきり(--force-device-scale-factor=2)
現在のスケールは次で確認できます。
grep -i scale /mnt/wslg/weston.log
# 例: scale:2, clientScale:2.000000 なら整数スケールでくっきり
問題2: ウィンドウの端をドラッグできない
ここが一番ハマります。原因はスケールではなく表示バックエンドです。
- X11 / XWayland(
--ozone-platform=x11)の場合、ウィンドウ枠とリサイズは WSLg の RAIL シェルがサーバーサイドで処理しますが、ローカルでの移動・リサイズは実装されていません(microsoft/wslg#633)。リサイズの当たり判定がずれていて、小さな点でしか効かず、リサイズのたびにズレが増えるという挙動になります(microsoft/wslg#1008)。これが「たまにドラッグできて、たまにできない」の正体です。 - ネイティブ Wayland(
--ozone-platform=wayland+WaylandWindowDecorations)の場合、アプリが自分でウィンドウ枠を描画します(クライアントサイド装飾)。端のドラッグもアプリ自身が検知し、xdg_toplevel.resizeでコンポジターにリサイズを要求します。枠とドラッグ判定がアプリ側にあるので、普通の Linux ウィンドウと同じように端をドラッグできます。
つまり、端をドラッグできるようにする決め手は「ネイティブ Wayland + クライアントサイド装飾でアプリを起動する」ことです。くっきり表示は WaylandFractionalScaleV1 と、整数スケールに合わせた --force-device-scale-factor で保てます。
試したけどダメだった説(時間節約のため)
デバッグ中に「それっぽいけど違った」仮説です。同じ沼にハマらないように残しておきます。
- スケール値が原因では? → 違う。X11 では
1.5も2もドラッグ不可。Wayland ではどちらもくっきり&ドラッグ可。 - マルチモニタのオフセットが原因では?(プライマリ=原点のモニタだけ効く) → 違う。プライマリでも効かない。
- Chrome の「システムのタイトルバーと枠を使用する」をオフにすれば? → X11 では効果なし。
端のドラッグ可否を切り替える唯一の変数は X11 か Wayland か、でした。
恒久設定(2つの起動経路をカバーする)
アプリはシェルからもスタートメニューからも起動されるので、両方に同じフラグを効かせます。
シェルからの起動:~/.local/bin/ にラッパー
~/.local/bin は PATH の先頭にあるので、ここに同名のラッパーを置くと優先されます。
#!/bin/sh
exec /usr/bin/google-chrome-stable --class=google-chrome-wsl --ozone-platform=wayland \
--enable-features=WaylandWindowDecorations,WaylandFractionalScaleV1 \
--force-device-scale-factor=2 "$@"
--class=google-chrome-wsl は Wayland の app_id を固定します(タスクバーアイコンで使用。後述)。Chromium はこの --class を app_id として尊重します。~/.local/bin/obsidian-app(バイナリは /opt/Obsidian/obsidian)も同様に作りますが、Obsidian(Electron)は --class を Wayland の app_id には反映せず、常に obsidian を名乗ります(後述)。なお Obsidian 用のラッパー名は obsidian-app にしておくこと。~/.local/bin/obsidian は Obsidian 公式の CLI バイナリ(実行ファイル)なので、こちらは上書きせず残してください。
作ったラッパーには実行権限を付けます(chmod +x ~/.local/bin/google-chrome ~/.local/bin/obsidian-app)。~/.local/bin を新規に作った場合、PATH に載るのは次回ログイン以降なので、すぐ使うなら source ~/.profile しておくこと。
スタートメニューからの起動:Windows ショートカットを手で作る
WSLg は本来、/usr/share/applications/ の .desktop を読んで、スタートメニュー(Windows 側の「Ubuntu-24.04」フォルダ)にショートカットを自動生成します。ところがこの自動生成のアプリ一覧は、一度できると凍結されがちです。あとから入れたアプリは、/usr/share/applications/ に正しい .desktop があっても、NoDisplay を外しても、別名にしても、wsl --shutdown で distro を再起動しても、一覧に出てこないことがあります。
実際、手元では最初から入っていた8個(LibreOffice Writer / Calc / Impress、xpdf、gv、Zutty など)だけが毎回再生成され、あとから入れた Chrome・Obsidian は出てきませんでした。さらに、同じ LibreOffice パッケージの Draw すら出ません(Writer は出るのに)。WSLg のプラグインキャッシュ %LOCALAPPDATA%\Temp\WSLDVCPlugin\<distro名>\ を見ると、この8個分の .ico しか無く、distro 起動のたびにその8個だけが焼き直されていました。.desktop の内容で選んでいるのではなく、凍結した一覧を再生成しているだけ、という挙動です。
なので自動生成に頼らず、Windows のショートカットを自分で作ります。WSLg のショートカットは結局 wslg.exe を起動しているだけなので、同じ形を手で再現します(自動生成された LibreOffice のショートカットは C:\Program Files\WSL\wslg.exe -d <distro名> --cd "~" -- <コマンド> という形でした)。
まずアイコンを用意します。.lnk のアイコンは .ico 形式が要るので、アプリの PNG を .ico に変換します。ImageMagick などが無くても、PNG をそのまま埋めた単一画像 .ico を Python だけで作れます(Windows は PNG 圧縮の .ico を読めます)。
import struct
def png2ico(src, dst):
d = open(src, "rb").read()
w, h = struct.unpack(">II", d[16:24]) # PNG の IHDR から幅・高さ
hdr = struct.pack("<HHH", 0, 1, 1)
ent = struct.pack("<BBBBHHII", w % 256, h % 256, 0, 0, 1, 32, len(d), 22)
open(dst, "wb").write(hdr + ent + d) # 256 以上は w%256=0 となり「256」を意味する
base = "/mnt/c/Users/<Windowsユーザー名>/AppData/Local/WSLApps"
png2ico("/usr/share/icons/hicolor/256x256/apps/google-chrome.png", base + "/google-chrome-wsl.ico")
png2ico("/opt/Obsidian/resources/icon.png", base + "/obsidian-wsl.ico")
事前に mkdir -p /mnt/c/Users/<Windowsユーザー名>/AppData/Local/WSLApps でフォルダを作っておきます。Temp ではなくここに置くのは、WSLDVCPlugin のキャッシュと違って消えないようにするためです。
次にショートカットを作ります。distro名 は wsl -l -q で確認してください。
$ws=New-Object -ComObject WScript.Shell
$distro='Ubuntu-24.04' # wsl -l -q で確認した distro 名
$prog=[Environment]::GetFolderPath('Programs')
$ico=$env:LOCALAPPDATA+'\WSLApps'
function New-WslLnk($name,$cmd,$icon){
$s=$ws.CreateShortcut("$prog\$name.lnk")
$s.TargetPath='C:\Program Files\WSL\wslg.exe'
$s.Arguments='-d '+$distro+' --cd "~" -- '+$cmd
$s.IconLocation="$ico\$icon"
$s.Save()
}
New-WslLnk 'Google Chrome (WSL)' '/home/<ユーザー名>/.local/bin/google-chrome' 'google-chrome-wsl.ico'
New-WslLnk 'Obsidian (WSL)' '/home/<ユーザー名>/.local/bin/obsidian-app' 'obsidian-wsl.ico'
ショートカットはトップレベルの Programs(スタートメニュー\プログラム)に置きます。WSLg が再生成する「Ubuntu-24.04」フォルダの中に置くと、自動生成のタイミングで消される恐れがあるためです。表示名を (WSL) 付きにしているのは、Windows ネイティブの Chrome / Obsidian と区別するためです。これでスタートメニューに、アプリのアイコン付きで両方が出ます。wsl --shutdown も不要です。
なおショートカットのコマンドをラッパー(前節)に向けているので、起動フラグはラッパー1か所で管理できます。
起動中ウィンドウのタスクバーアイコン(ペンギンが残ることがある)
スタートメニューのアイコンは上の .ico で直りますが、起動中ウィンドウのタスクバーアイコンは別系統です。WSLg はウィンドウの Wayland app_id を /usr/share/applications/ の .desktop(StartupWMClass 一致)に対応づけてアイコンを決めます。対応が取れないと、WSLg 既定のペンギンになります。
まずラッパー側で --class=<app_id> を渡して app_id を固定します。Chrome は --class=google-chrome-wsl を Wayland の app_id として尊重するので、StartupWMClass=google-chrome-wsl の .desktop を /usr/share/applications/ に置けば対応づけの土台ができます(このディレクトリへの書き込みには sudo が要ります)。
[Desktop Entry]
Type=Application
Name=Google Chrome (WSL)
Exec=/home/<ユーザー名>/.local/bin/google-chrome %U
Icon=/usr/share/icons/hicolor/256x256/apps/google-chrome.png
StartupWMClass=google-chrome-wsl
Categories=Network;WebBrowser;
一方 Obsidian(Electron)は --class を Wayland の app_id に反映せず、常に obsidian を名乗ります。ps では --class=obsidian-wsl が渡っていても、weston.log の appId: は obsidian のままです。なので Obsidian 用に obsidian-wsl.desktop を作っても永遠に一致しません。Obsidian については、標準で入っている obsidian.desktop(Icon=obsidian が既存のテーマ PNG に解決される)が対応相手になります。--class で名前を分けることに意味があるのは、Chrome 側の app_id を Obsidian と衝突させないためです(これをやらないと両方が同じ app_id に合流し、タスクバーで1つのペンギンにまとまってしまいます)。
ここまでで「Chrome と Obsidian が同じペンギンに合流する」状態は解消し、2つは別々のタスクバーグループに分かれます。ただし、app_id と .desktop を正しく揃えても、起動中アイコンがアプリ本来のものにならない環境があります。手元(Ubuntu-24.04 + 2024年春ビルドの WSLg)がまさにそれで、Chrome はペンギン、Obsidian はノートのアイコンのまま直りませんでした(Obsidian 側は標準で入っている obsidian.desktop が後述の名前空間破綻より前に読まれているとみられ、あとから足した Chrome 用 .desktop は読まれずペンギンのまま、という非対称です)。
原因は .desktop でもアイコンファイルでもなく、WSLg 側のバグです。/mnt/wslg/weston.log を見ると、システムディストロ(WSLg 本体が動く側)がユーザーディストロのマウント名前空間に入って .desktop/アイコンを読みに行く処理が、attach_app_list_namespace failed Invalid argument で繰り返し失敗していました(起動直後の最初の数個を読んだあと破綻し、以降はオンデマンドのアイコン読み込みでも毎回失敗)。この状態だと、.desktop やアイコンをどれだけ正しく置いても WSLg がそもそも読めないため、アイコンは載りません。スタートメニュー側を Windows ショートカット(前節)で手作りしたのは、まさにこの読み取りに依存しないためです。
切り分けは /mnt/wslg/weston.log の attach_app_list_namespace failed の有無で付きます。出ていれば .desktop/アイコン側の修正では直らないので、Windows 側で wsl --update を試してください(新しい WSLg で名前空間アタッチが直る可能性があります)。更新後、同じログにこの行が出なくなったかで確認できます。
なお --ozone-platform=x11 で起動すると、ウィンドウが _NET_WM_ICON を自前で持つためタスクバーアイコンは正しく出ます。ただし本記事の主目的である「端をドラッグできるリサイズ」が X11/RAIL のバグで壊れるので、ここでは採れないトレードオフです。
ハマりどころ
- Wayland のウィンドウが出ない(タスクバーのアイコンだけ)。なお Chrome の
SingletonLockを死んだプロセスが掴んでいるか、Weston / RAIL の状態が壊れています。アプリを終了し、rm -f ~/.config/google-chrome/Singleton*してから Windows 側でwsl --shutdownしてください。その後はネイティブ Wayland も正常に表示されます。(この初回失敗が「WSLg で Wayland は無理」という誤解の元になりがちですが、ちゃんと動きます。) -
TMPDIRを差し替えるシェルから起動すると、二度と窓が出なくなる。Chromium / Electron はSingletonSocketをTMPDIR配下に作ります。サンドボックス環境(bwrap系のサンドボックスや、TMPDIRを一時ディレクトリへ向けるエージェント実行環境など)から一度起動すると、そのディレクトリが消えた後もSingletonLockが死んだソケットを指し続け、以降の起動は無言で既存(幽霊)インスタンスへ委譲して窓を出しません。バイナリ自体は正常です。なお対策は、起動ラッパーに「プロセスが無ければSingleton*を消してから起動する」自己修復を入れること(例:pgrep -x <app> >/dev/null || rm -f ~/.config/<app>/Singleton*)。wsl --shutdownは不要になります。 -
pkill -f <パターン>で自分のシェルごと死にます。パターン文字列がシェル自身のコマンドラインに一致するためです。pkill -x <名前>か PID 指定を使いましょう。 - モニタの X11 名・座標(
rdp-0/rdp-2やオフセット)はwsl --shutdownで変わります。毎回xrandr --listmonitorsで確認し、ハードコードしないこと。 -
.wslgconfigの分数スケール設定ではくっきりになりません。WESTON_RDP_FRACTIONAL_HI_DPI_SCALING=trueは公式設定ですが、分数スケールは原理的にぼやけます。直すのは「整数スケール+一致した--force-device-scale-factor」であって、このファイルではありません。
設定の要点
- 文字がぼやける → 整数のディスプレイ拡大率(200% など)+一致した
--force-device-scale-factor。 - 端をドラッグできない → ネイティブ Wayland +
WaylandWindowDecorations(X11/RAIL のサーバーサイドリサイズのバグを回避)。 - 両方をまとめた起動フラグ:
--ozone-platform=wayland --enable-features=WaylandWindowDecorations,WaylandFractionalScaleV1 --force-device-scale-factor=2
参考
- microsoft/wslg#633 — ローカル移動・リサイズ未対応(2022年から open)
- microsoft/wslg#1008 — ウィンドウが小さな点でしかリサイズできない
- microsoft/wslg#288 — 非プライマリモニタでのポインタ座標のずれ
-
WSLg Configuration Options for Debugging —
WESTON_RDP_FRACTIONAL_HI_DPI_SCALINGほか.wslgconfigの設定一覧