Emacs をすばやく使うために、みなさんemacsclientを活用されていることかと思います。いちいち Emacs を起動しなくてよいため非常にべんりですが、いつからか(最初からかも?)emacsclientを叩いた際にかってにフレームを前面にもってきてくれなくなっていて、つらい思いをする日々が続いていました。
ということでめんどくさがらずに、ちゃんとコードを書いて使いやすいようにしましたというお話です。
用意するもの
ここではwmctrlというツールを利用します。コマンドラインから X ウィンドウマネージャを制御するものです。Wayland 環境のみなさんはごめんなさいですが、今回の方法は使えないと思います。
(余談: 個人的に SKK ユーザということもあり、SandS を実現するためにxcapeを利用しているので、X11 を使いつづけています。Wayland 環境での SandS ベストプラクティス情報ほしいです……)
閑話休題、aptなりなんなりでインストールしましょう
# apt install wmctrl
Emacs の設定
Emacs のフレーム(一般的用語におけるウィンドウですね)を最小化するにはiconify-frame、ポップアップするにはraise-frameという関数が用意されている……のですが、raise-frameを使っても最小化された Emacs のフレームがポップアップされません。なぜだ。
ということで外部ツールを利用する必要があります。先ほど紹介したwmctrlですね。Elisp にはcall-processという関数があり、これで外部プログラムを実行できるため、この仕組みを利用します。
(defun raise-frame-with-wmctrl (&optional frame)
;; (call-process "wmctrl" nil nil nil "-s" "1") ;; 仮想デスクトップ使ってるときはこれも追加で必要
(call-process "wmctrl" nil nil nil "-i" "-R"
(frame-parameter (or frame (selected-frame)) 'outer-window-id)))
(advice-add 'raise-frame :after #'raise-frame-with-wmctrl)
(add-hook 'server-switch-hook #'raise-frame)
(add-hook 'server-done-hook #'iconify-frame)
上記のコードをinit.elに書いておきましょう。やっていることは単純で、現在のフレームの Window id を取得し、それをwmctrlに渡しているだけです。
最小化するiconify-frameについては、特に問題ない(と思う)ので、そのまま hook に追加しておくだけでよいでしょう。
これで、端末からemacsclientでファイルを開いた際に勝手にウィンドウがポップアップし、編集を終了すると勝手に最小化されるはずです。
追記(2019-08-29)
この設定だと Magit で commit メッセージを書いた後にも Emacs のフレームが最小化されてしまいます。これは commit メッセージ入力用のバッファを開く際に emacsclient が利用されているためです。このような仕組みになっている理由はこちらにまとめられていますが、なんにしてもこれではとてつもなく不便なので、この挙動を修正しましょう。
(defun suppress-iconify (&rest arg)
(remove-hook 'server-done-hook #'iconify-emacs-when-server-is-done))
(defun apply-iconify (&rest arg)
(add-hook 'server-done-hook #'iconify-emacs-when-server-is-done))
(advice-add 'magit-run-git-with-editor :before #'surpress-iconify)
(advice-add 'with-editor-finish :after #'apply-iconify)
commit メッセージ入力用のバッファを開く関数が magit-run-git-with-editor です。なのでこの関数が呼ばれる前に server-done-hook から最小化用の関数を外します。同様に編集を完了させる関数が with-editor-finish なので、この後に再度最小化用の関数をserver-done-hookに追加しています。1つの hook に同じ関数が2つ以上設定されることはないようになっているので、ふつうに emacsclient を使った場合でも問題はありません。