Emacsのフォントサイズをディスプレイ解像度によって変えてWSLgの場合でも正しく動作させる
複数のディスプレイ解像度に対応するEmacsのフォントサイズ設定
去年、楽天リーベイツのLenovoの還元日に備えた新しいラップトップPCを買うための検討メモ - ncaq に書いたようにラップトップPCを新調しました。
その際に前回ラップトップPCを買った時の状況と異なりフルリモートで働ける状態になっていたので、このPCを使う頻度はかなり低いと予想して、ディスプレイの解像度を4KやWQUXGAにするのではなく、お金をケチってフルHDに収めました。
その場合Emacsに設定するフォントサイズは、デスクトップPCで使う4Kのモニターと同じにしておくと、フルHDのディスプレイでは小さすぎるため、それぞれ振り分ける必要があります。
そのためピクセルサイズでフォントサイズを分岐するようにしました。
(defun font-setup ()
(set-face-attribute
'default
nil
:family "HackGen Console NF"
;; 2画面分割でだいたい横120文字を表示できるフォントサイズにする。
;; フルHDと4Kを想定。
:height (if (<= (frame-pixel-width) 1920) 108 130))
(set-fontset-font t 'unicode (font-spec :name "HackGen Console NF") nil 'append)
(unless (eq system-type 'darwin)
(set-fontset-font t '(#x1F000 . #x1FAFF) (font-spec :name "Noto Color Emoji") nil 'append)))
(frame-pixel-width)
を見て横の画素数が1920ピクセル以下なら小さいフォントサイズが使われるようにしました。
起動時にこの関数を実行します。
フォントファミリーは各自の好きなものに変更してください。
WSL2のWSLgでは実行タイミングが合わないことがある
ネイティブLinux環境ではデスクトップでもラップトップでもこれで問題なく動作しました。しかしWindows 11のWSL2のWSLg環境でこれを実行すると、
after-init-hook
のタイミングでも画面のピクセルサイズを正しく取得できないことがあるため、
4Kモニタにふさわしくない小さいフォントサイズが使われてしまうことがありました。
確実な再現性は無かったのですが、最初にEmacsを起動する時に問題が発生しやすかったので、 WestonやXWaylandの初期化に問題があるのかもしれません。
window-setup-hook
を使って解決
起動時のhook実行の種類を調べて、
after-init-hook
ではなくwindow-setup-hook
を使うことで、ウィンドウとフレームが作成された後に適切に初期化関数を実行することが出来て、問題が解決しました。
今の設定全体は以下のようになっています。
(leaf *font
:init
(defun font-setup ()
(set-face-attribute
'default
nil
:family "HackGen Console NF"
;; 2画面分割でだいたい横120文字を表示できるフォントサイズにする。
;; フルHDと4Kを想定。
:height (if (<= (frame-pixel-width) 1920) 108 130))
(set-fontset-font t 'unicode (font-spec :name "HackGen Console NF") nil 'append)
(unless (eq system-type 'darwin)
(set-fontset-font t '(#x1F000 . #x1FAFF) (font-spec :name "Noto Color Emoji") nil 'append)))
;; `frame-pixel-width'がフレーム作成後でないと実用的な値を返さないので、
;; 初期化後にフォントサイズを設定します。
:hook (window-setup-hook . font-setup))
備考
今のEmacsはネイティブのpure GTKによるネイティブのWayland対応が行われているため、 XWaylandを経由せずに直接Waylandで動作させれば、そもそもHi DPIにも自動的に対応していて私のような設定は不要かもしれません。
ただ私はまだXMonadから離れられないし、 Windowsで設定する時もWaylandだと小回りが効かないなあと思ったので、前にセットアップするときはX11を経由する方法を選択しました。次回セットアップするときはWindowsのWSL2ではWaylandを直接使ってみるかもしれません。