emacsclientでフォーカスを移す
追記 xfce4だとフォーカスを勝手に移してくれます.
最近プログラム関係は Macではなく Ubuntuばっかりなんですが、
emacsclientの使い心地が Macとなにか違う。考えてみると、
フォーカスが移動しないじゃんってことで、なんとかできない
ものかと思い書いてみた。
一応 EmacsWiki: Emacs Clientに書いているんですが、
Emacsのタイトルバーは elscreenのタブ名が表示するようにしているし、
複数立ち上げていることもあるし、端末でもサーバを起動するかもしれないし、
ということで、そのあたりもカバーすることを目標としました。
フォーカスの移動は wmctrlというプログラムを利用します。 Ubuntuの場合
aptからインストールしてください。
% sudo aptitude install wmctrl
サーバが起動する Emacsの特定
サーバが起動する Emacsを特定するために以下のコードを .emacsに加えました.
defadviceでサーバ起動後に後述の emacs_serverstart.plに起動させます。
引数はその Emacsのプロセス IDと GUI版で起動しているか否かを示すフラグ
です。
(when (string-equal system-type "gnu/linux") (defadvice server-start (after server-start-after-write-window-id ()) (call-process "emacs_serverstart.pl" nil nil nil (number-to-string (emacs-pid)) (if window-system "x" "nox"))) (ad-activate 'server-start))
サーバ起動した Emacsの情報を記録する
私の方法は以下のとおりです
これを実現するために以下の Perlスクリプトを書きました。これを PATHの
通ったディレクトリに置き、実行権限を与えます。
#!/usr/bin/env perl use strict; use warnings; use Fcntl qw(:flock); use File::Which qw(which); unless (which("wmctrl")) { exit 1; } my ($emacs_pid, $has_window) = @ARGV[0,1]; unless ($emacs_pid && $has_window) { die "Usage $0 emacs_pid [x or nox]\n" } my $server_wid_file = $ENV{HOME} . '/.emacs.d/server_wid'; if ($has_window eq 'x') { server_is_x($emacs_pid); } else { server_is_nox(); } sub server_is_x { my $pid = shift; my $emacs_window_id; open my $fh, "-|", qw/wmctrl -p -l/ or die "Can't open wmctrl process\n"; while (my $line = <$fh>) { chomp $line; my ($wid, $pid) = (split ' ', $line)[0,2]; if ($emacs_pid eq $pid) { $emacs_window_id = $wid; last; } } close $fh; open my $wfh, ">", $server_wid_file or die "Can't open write file\n"; flock $wfh, LOCK_EX; print $wfh $emacs_window_id; close $wfh; } sub server_is_nox { my $server_window_name = 'emacsserver_run'; unlink $server_wid_file if -e $server_wid_file; open my $fh, "-|", qw/wmctrl -l/ or die "Can't open wmctrl process\n"; while (my $line = <$fh>) { chomp $line; my $window_title = (split ' ', $line)[3]; if ($window_title eq $server_window_name) { # rename old server run terminal my @cmd = (qw/wmctrl -F -r/, $server_window_name, qw/-T Terminal/); system(); last; } } close $fh; # change current terminal window my @cmd = (qw/wmctrl -r :ACTIVE: -T/, $server_window_name); system(@cmd); }
GUI版では、初めに引数として与えられたプロセス IDから Window IDを特定して
います。得られた Window IDを ~/.emacs.d/server_widというファイルに
書きだしています。複数開かれたことを考えて、ロックをしています。
一方非 GUI版では GUI版で記録した Window IDを削除します。このファイルの
有無で GUI版か非 GUI版のいずれで server-startが実行されたかを判断します。
次にすでに名前が変えられた端末エミュレータがないか調べます。もし一致する
ものがあれば、それを 'Terminal'に変更します。そして最後に現在アクティブ
なウィンドウの名前をサーバが起動していることを示す名前に変更します。
これでフォーカスを移すための情報が揃いました。
フォーカスを切り替える emacsclient
フォーカルを切り替えるために以下のシェルスクリプトを書きました。
これも PATHの通ったディレクトリに置き、実行権限を与えます。
#!/bin/sh if ! which wmctrl > /dev/null 2>&1 then echo "Please install wmctrl" exit 1 fi # get current window id CURRENT_WID=`wmctrl -a :ACTIVE: -v 2>&1 | \ perl -wln -e 'm{Using window: (\w+)$} and print $1'` 2> /dev/null if [ "$CURRENT_WID" = "" ] then echo "Faild getting current window id" exit 1 fi WID_FILE=${HOME}/.emacs.d/server_wid if [ -e $WID_FILE ] then # server is running on GUI Emacs WID=`cat $WID_FILE` # forcus emacs server window wmctrl -i -a $WID else # server is running emacs in terminal SERVER_TERM_TITLE='emacsserver_run' wmctrl -F -a $SERVER_TERM_TITLE fi emacsclient $@ # return to origin window wmctrl -i -a $CURRENT_WID
初めに編集が終わった後にフォーカスを元に戻すために、現在の WindowIDを
取得しています。そして次に切り替えですが、GUI版用のファイルがあれば
GUI版、なければ非GUI版としています。フォーカスの切り替えは '-a'
オプションです。なお'-i'は WindowIDで指定するためのオプション、
'-F'は厳密にタイトルバーと一致させるためのオプションです。
フォーカスが終わったら emacsclientを起動して、編集が終われば
元のウィンドウに戻ります。
使い方は emacsclientから上記のシェルスクリプトに変更するだけです。
% emacsclient.sh ファイル名
これで目標が達成できました。手元のテストでは GUI版でも端末版でも
動きました。問題があればご指摘いただけると助かります。
最後に
休みになったらもうちょっと確認して githubに上げます。