WSLでemacsclientをGUIで使えるようにする(その2)


前回から続きます。

フレームサイズとフォントセットの問題

今の設定だとemacsはシェル上でdaemonモードで動かしているわけです。当然ながらバックグラウンドで動いているからフレーム自体が作成されていないため、

(setq initial-frame-alist
      (append (list
           '(width . 120)
           '(height . 45)
           '(top . 0)
           '(left . 0)
           '(font . "VL Gothic-11")
           )
          initial-frame-alist))
(setq default-frame-alist initial-frame-alist)

のような設定をしていても、起動時に変数が読み込まれないみたいなんですね。

それでいろいろと探してみたところ、見つかったのがこのブログ記事。で、参照先のelファイルを参考にして設定してみました。

;; initial frame parameters
(let ((frame-alist
       `((vertical-scroll-bars . nil)
         (width . 85)
         (top . 0)
         (left . 800)
         (height . 47))))
  (setq-default initial-frame-alist (append frame-alist initial-frame-alist)
                default-frame-alist (append frame-alist default-frame-alist)))

;; font settings
(defconst default-fontset-name "geneigothic")
(defconst default-base-font-name "GenEi Gothic M SemiBold")
(defconst default-base-font-size 12)
(defconst default-ja-font-name "GenEi Gothic M SemiBold")
(defconst default-ja-font-pat "Hiragino.*")
(defconst default-ja-font-scale 1.3)

(defun setup-window-system-configuration (&optional frame)
  "Initialize configurations for window system.
Configurations, which require X (there exists a frame), are
placed in this function.

When Emacs is started as a GUI application, just running this
function initializes the configurations.

When Emacs is started as a daemon, this function should be called
just after the first frame is created by a client.  For this,
this function is added to `after-make-frame-functions' and
removed from them after the first call."
  (with-selected-frame (or frame (selected-frame))
    (when window-system
      (let* ((fontset-name default-fontset-name)
             (base default-base-font-name) (size default-base-font-size)
             (ja default-ja-font-name) (ja-pat default-ja-font-pat)
             (scale default-ja-font-scale)
             (base-font (format "%s-%d" base size))
             (ja-font (font-spec :family ja))
             (fsn (concat "fontset-" fontset-name))
             (elt (list (cons 'font fsn))))
        ;; create font
        (create-fontset-from-ascii-font base-font nil fontset-name)
        (set-fontset-font fsn 'unicode ja-font nil 'append)
        (add-to-list 'face-font-rescale-alist (cons ja-pat scale))
        ;; default
        (set-frame-font fsn)
        (setq-default initial-frame-alist (append elt initial-frame-alist)
                      default-frame-alist (append elt default-frame-alist))
        ;; current frame
        (set-frame-parameter (selected-frame) 'font fsn)
        ;; call once
        (remove-hook 'after-init-hook #'setup-window-system-configuration)
        (remove-hook 'after-make-frame-functions
                    #'setup-window-system-configuration)))))

(when window-system
  (if after-init-time
      ;; already initialized
      (setup-window-system-configuration)
    (add-hook 'after-init-hook #'setup-window-system-configuration)))
(add-hook 'after-make-frame-functions #'setup-window-system-configuration)

(defun close-frame-display (frame)
  "Close FRAME's X connection."
  (let* ((get-display #'(lambda (f)
                          (and (eq (framep f) 'x)
                               (terminal-name (frame-terminal f)))))
         (display (funcall get-display frame))
         (frames (remq frame (frame-list)))
         (displays (and display (mapcar get-display frames)))
         (hook (and (boundp 'delete-frame-functions)
                    (memq 'close-frame-display delete-frame-functions))))
    (when (and display (not (member display displays)))
      (remove-hook 'delete-frame-functions #'close-frame-display)
      (delete-frame frame)
      (x-close-connection display) ; causes segfault in Emacs <= 24.3.50 + GTK3
      (when hook (add-hook 'delete-frame-functions #'close-frame-display)))))
;; close frame display when the frame is deleted (we need this to
;; ensure that an emacs daemon without X window has no X connection)
(add-hook 'delete-frame-functions #'close-frame-display)

自分の好みのフォントサイズ、フレームサイズを設定したのと、元の設定だとフレームの高さは自動設定のような仕組みもあったんですが、その辺は削除しています。

カーソル・背景の色

上記の設定で、フレームサイズとフォントに関しては十分満足できる表示が得られるようになりました。

しかし、まだ直接GUIで起動した場合と異なる点が残ってまして、それがカーソルと背景の色でした。背景に関しては、damonモードだとテーマファイルが反映されないようです(ちなみに、hc-zenburnというのを利用しています。package.elから導入できます)。また、カーソルの色に関しては、SKKでモードごとにカーソルの色が変わるという機能を愛用しているので、それが出来ないのが困るという話です(モードライン見ればいいんですけどね)。

解決策

この辺を参考にして、以下のようなコードを入れてみました。

;; theme
(if (daemonp)
    (add-hook 'after-make-frame-functions
        (lambda (frame)
            (select-frame frame)
            (load-theme 'hc-zenburn t)
        (transient-mark-mode t)
        (set-face-background 'hl-line "dark slate gray")
        (set-face-background 'region "cadet blue")))
    (load-theme 'hc-zenburn t))

一応、これで望んだ通りに背景とカーソルの色がつくようになりました。ただし、カーソル色の方は、最初にフレームを開いてSKKを起動したときは色が変わらず、2回目以降から反映されるようになっています。これも1度目はSKKのFace関係の設定が読み込まれてないってことなんでしょうね。

ま、フレーム自体は一瞬で開くので、ひとまずはこれで行こうかと思います。

今後の課題

  • 最初のフレームでカーソルの色が変わるようにしたい
  • GUI (emacsclient -c) とTTY (emacsclient -t) でテーマを切り替えられるようにしたい(GUI:テーマ使用、TTY:テーマ不使用)。
    • daemonp と window-system の条件分岐で何とかなりそうな気がするんだけどうまくいってない。