2009年12月16日水曜日

Emacs (NTEmacs) 23.1 をWindows 7上で少し快適に使う - Part.2

さてPart.1「パッチを当てたEmacsをWindows上でコンパイルする」の続きを説明する。前回も述べたが、今回説明する「少し快適に使うためのセッティング」が少しの快適をWindows 7上で動作するEmacsにもたらすのだ、だからこっちの説明が重要。

さて、説明に入る前に前回コンパイルして出来たバイナリと、パッチの当たったソースファイルをダウンロード出来るようにしておいた。コンパイラの最適化オプションなどに興味のない人などはこのバイナリファイルをダウンロードすれば前回の手順をスキップできる。
(2010/03/12:配布用に一部コードを修正中。バイナリはしばらくお待ちください。)
(2010/03/14:再アップロードしました。)
    2. 少し快適に使うためのセッティング
    それでは本題に入ろう。前回、”少し快適”とは「Windows 7で導入された新しいタスクバーに対応すること」と一言で説明した。Windows 7ではまるでMac OS XのDockに似た、そして、さらにそれを使いやすくしたらしい今までとは全く異なる新しいタスクバーが導入されている。その中でもまず目につくのが、タスクバーにアプリケーションをピン留めすることができ(よく使うアプリケーションなどをタスクバーに登録することが出来る)、アプリケーションが起動中でも昔のようにタスクバーにアイコンが増えていくのではなく、ピン留めされたアイコンが変化する動作だ。
    詳しい説明は「Microsoft、Windows 7のタスクバーを解説 (ITmedia)」などを参照してほしい。

    さて前回ビルドしたEmacsでこの機能を使おうとすると以下の現象が発生する。

    まず runemacs.exe でEmacsを起動すると以下のようにタスクバーにEmacsアイコンが出現し、起動していることを示す。




    次回からEmacsをサクッと起動しようとピン留めしてみる(タスクバーに登録する)。Emacsアイコンを右クリックして、「タスクバーにこのプログラムを表示する」を選択。









    そしてEmacsを終了すると、タスクバーは以下の状態になる。




    ここまでは期待通りの動作をしている。そしてこのアイコンをクリックして再度Emacsを起動すると、、、
    ←2つEmacsが起動しているように表示され


    かつ、意味のないコマンドプロンプトが起動してしまいます。もうここまでくると、(NT)Emacsに詳しい方はお気づきかとは思いますが、タスクバーに登録されたアプリケーションは runemacs.exe ではなく、 emacs.exe なのです。
    そして emacs.exe は元々Windowsアプリケーションではなく、コンソールアプリケーションだからこうなってしまう。runemacs.exe はコンソールアプリケーションのEmacsをWindowsアプリケーションのように起動するためのアプリケーション(コマンドプロンプトが出ない)なのです。

    じゃあ、runemacs.exe をタスクバーに登録すればいいじゃんということになりますね。さっそく登録してみます。(その前に、タスクバーにある emacs.exe への登録は消しましょう、ややこしくなるので。右クリックして「タスクバーにこのプログラムを表示しない」でできます。)
    エクスプローラーから runemacs.exe を選択し右クリック、「タスクバーに表示する」で登録されます。














    そして、タスクバーのアイコンをクリックしてEmacsを起動してみましょう。すると、、、

    ←何か別に表示されてる



    せっかくのタスクバーの新機能がいかされず、起動アイコンと起動中アイコンが別々に表示されるという悲しい現象が発生します。

    これが今回私が訴えたかった快適ではなくなっている問題です。
    bug#1849 - Windows 7 Taskbar Support で指摘されていることもこれに関連することです。では、なぜこんなことが起きてしまうのか簡単に説明すると、Windows 7からはアプリケーションにアプリケーション ユーザー モデル ID (AppID)という識別子が導入されました。このIDが同じであると上記の問題は発生せずに1つのアイコンで表示されます。上記の例では、runemacs.exe を右クリックして登録した際にシステムが(暗黙に)定義したAppIDと emacs.exe が持っているAppIDが違うことにより発生しています、と推測しています。
    アプリケーションが明示的にAppIDを定義しないと、システムがある一定の法則にのっとって勝手にAppIDを作るようです。ちなみに、前回Emacsをコンパイルする際にこの問題に対応するEmacsのMAINブランチに入ったパッチを適用しました。そのコードによれば、Emacsは ”GNU.Emacs” というAppIDを明示的に定義しているようです。runemacs.exe や emacs.exe はこのAppIDをシステムに宣言しています。
    では、なぜ問題が発生するのか?ここからは推測ですが、まず、runemacs.exe を右クリックしてタスクバーに登録した場合は runemacs.exe が実行された際にシステムに宣言される "GNU.Emacs" AppIDが、このオペレーションでは適用されないということ。おそらくAppIDのない状態又はシステムが定義したAppIDでタスクバーに登録されているのでしょう。そして、次に runemacs.exe は emacs.exe を呼び出してすぐに終了してしまうために、runemacs.exe を実行してもタスクバーには runemacs.exe のプログラムが表示されず、結果的にユーザに右クリックして「タスクバーにこのプログラムを表示する」を選択する猶予を与えないためでしょう。
    もし、runemacs.exe がすぐに終了しないアプリケーションであれば、内部で "GNU.Emacs" AppIDを定義しているのでタスクバーにアイコンが表示されていれば、タスクバーに "GNU.Emacs" AppID をもったアプリと登録することができ、期待通りの動作をするはずです。(期待通りの動作="GNU.Emacs" AppIDをもった runemacs.exe をタスクバーに登録でき、かつそのアイコンで起動すると emacs.exe はそのアイコン上で起動中と表示されること)


    さて、ここまでは問題となる現象の説明であり「少し快適になる=この問題をなくす」セッティングの説明に入れていませんでした。さっそく(やっと?)、2. 少し快適に使うためのセッティングに入ります。

    MSDNのサイトをいろいろ調べたところ、ショートカットにAppIDを持たせることが出来ると判明。ということは runemacs.exe のショートカットを作って、そのショートカットに "GNU.Emacs" AppID を入れて、タスクバーに登録すればうまくいくんじゃね?という結論に至った。で、実際にごにょごにょすると確かに期待通りの動作が出来た!
    しかーし、ここで少し時間を食ってしまった。なぜならばショートカットに好きなAppIDを持たせる簡単な方法を見つけることが出来なかったため、自前でWindows アプリケーションを作るはめになったからである。まぁ、たいしたコード量じゃないんだが。

    では、まず次のアプリケーションをダウンロードして欲しい。
    「Shortcut AppID Changer by 俺 (ダウンロード先→ShortcutAppIDChanger.zip)」
    このアプリケーションはWindows 7上で動くもので、ショートカットに好きなAppIDを設定することができる。

    さてダウンロードが終わったら手順の説明に入る。
    1. runemacs.exeのショートカットを作る。
    Emacsのインストールフォルダのbinにある runemacs.exe を右クリックし、ショートカットの作成を選択する。すると、同じディレクトリにショートカットが出来るはずだ。

    2. ショートカットの名前を変える。
    これは飛ばしてもいい手順だが、、最終的にこのショートカットをタスクバーに登録すると、(右クリックで表示される)登録された名前はこのショートカットのファイル名となる。手順1で作ったショートカットファイルの名前はおそらく「runemacs.exe - ショートカット」となっているので、これを「emacs」とでも変えておこう。

    3. ショートカットにAppIDを埋め込む
    さて重要なステップにきた。作成したショートカットファイルに "GNU.Emacs" AppID を埋め込む。まず、ShortcutAppIDChanger.exe を起動して欲しい。すると以下のウィンドウが現れるはずだ。
    このウィンドウに先ほど作成したショートカットをドラッグ&ドロップする。すると、「Loaded file name: None」と表示されていたところが、作成したショートカットファイルの名前を表示するようになる。こうなれば、このアプリケーションは正しくショートカットファイルを認識している。
    そして次に、「PKEY_AppUserModel_ID 」と表示されている枠内にあるテキストボックスに設定するAppIDを入力する。今回はもちろん GNU.Emacs だ。以下のような表示になればOK。Loaded file nameのところは皆さんの環境によって違うだろう。
     
     そして、Saveボタンを押す。新しく保存してもよいし、読み込んだショートカットに上書き保存してもよい。保存したら "GNU.Emacs" AppID を持ったショートカットのできあがりである。このアプリケーションはExitボタンでも押して終了する。

    4. AppIDをもったショートカットをタスクバーに登録する
    前述の手順で作成したショートカットファイルを右クリックし、「タスクバーに表示する」を選択する。するとタスクバーにEmacsアイコンが現れる。

    以上で少し快適に使うセッティングは終了だ。
    タスクバーにあるEmacsアイコンをクリックしてEmacsを起動して欲しい。うまくいけば以下のように表示されるはずだ。
    そして、タスクバーはこの状態であり、コマンドプロンプトは表示されていないはずだ。

    これが今回説明したかった EmacsをWindows 7上で少し快適に使う方法 である。
    小さなことかもしれないが、Windows 7の新しいタスクバーに慣れてしまった僕にとっては、頻繁に使うEmacsはタスクバーに登録して使いたかったのだ!!
    へんてこりんな動作無しでね。

    さて、Emacsのブランチに入った変更は runemacs.exe / emacs.exe / emacsclientw.exe にAppIDを設定するコードを埋め込んだこと。今回のような問題はどう対処するのであろうか?それとも私が何か勘違いしているのだろうか?emacsclientを使うとまた違ってくるとか??
    もし、何かご存じの方がいらっしゃれば是非教えていただきたいm(_ _)m

    まぁ、いまのところ期待通りの動作をしているので個人的には満足している。
    次回は、「コンパイラに渡す最適化パラメータについて」又は「.emacsと最低限設定すべき環境変数」について何か書きたいと思っている。

    「Emacs (NTEmacs) 23.1 をWindows 7上で少し快適に使う」はPart.2でとりあえず完!
    では、また次回!!

    Emacs (NTEmacs) 23.1 をWindows 7上で少し快適に使う - Part.1

    Emacs 23.1 をWindows 7上で少し快適に使う方法を書いてみた。なにが少し快適なのかは一言で言えば「Windows 7で導入された新しいタスクバーに対応すること(詳細はPart2を参照)」である。
    ここでの説明は2つのステップに分かれている。
    1. パッチを当てたEmacsをWindows上でコンパイルする
    2. 少し快適に使うためのセッティング
    1.パッチを当てたEmacsをWindows上でコンパイルする
    基本的な手順はWindows 上での Emacs コンパイル - とりぷる ぷぅで親切に解説されている。様々な方法でコンパイルしてみたが、このサイトで書かれている手順が比較的容易でわかりやすいのでおすすめである。ここでは、このサイトの手順をベースに説明しよう。

    コンパイル環境は、XP Mode on Windows 7である。すなわちXP SP3環境。

    まず最初に必要ファイルをダウンロードする。
    1. Emacs 23.1 のソースファイルを本家サイトからダウンロード (emacs-23.1.tar.gz)
    2. Automated MinGW Installer (from Minimalist GNU for Windows) をダウンロード (MinGW-5.1.6.exe)
    3. MSYS Base System (from Minimalist GNU for Windows) をダウンロード (MSYS-1.0.11.exe)
    4. 画像表示のためにライブラリを GnuWin32 Packages からダウンロード
     (Xpm, LibPng, Zlib, LibUnGif, LibJpeg, LibTiff)
     実際にダウンロードしたファイルは以下である。
     (xpm-3.5.1-1.exe, xpm-3.5.1-1-src.exe, libpng-1.2.37-setup.exe, zlib-1.2.3.exe, libungif-4.1.4-1.exe, jpeg-6b-4.exe, tiff-3.8.2-1.exe)
     xpmについてsrcが必要になる理由は上記のサイトで解説されているように、「simx.hが必要であるためであり、simx.hはsrcに含まれているから」である。

    さて次に、2つのパッチをダウンロードする。
    5. NTEmacs JP Projectから日本語入力を利便性を向上するパッチをダウンロード (Emacs-23.1-IME.patch)
     このパッチがないと日本語のインライン入力などが出来なくて不便。
    6. 私のサイトからWindows 7用のパッチをダウンロード (win7appid.patch)
     このパッチは bug#1849 - Windows 7 Taskbar Support で指摘されたもので、詳細はこのリンクの文章を読んで欲しい。すでに対応はMAINブランチ上にあるが、Emacs 23.1 には取り込まれなかったので、私がこのBugに関連する修正だけを最新のソースツリーから取り出してパッチにしたものである。Jason Rumneyさんが対応されている。Thanks!!
    修正が入るファイルは、w32term.c, runemacs.c, emacsclient.c であり、コミット時のコメントは以下の通り。

    bug#1849 - Windows 7 Taskbar Support

    * w32term.c (w32_initialize): Use GetModuleHandle for library that is already loaded.
    Set user model ID if supported (bug#1849).

    * runemacs.c (set_user_model_id): New function.
    (WinMain): Use it.

    * emacsclient.c (w32_give_focus): Use GetModuleHandle for library that is already loaded.
    (w32_set_user_model_id): New function.
    (main): Use it to associate emacsclient with emacs (bug#1849).
    以上で、コンパイルするのに必要なファイルは全部そろった。

    次にMinGWなどのインストール手順を簡単に述べよう。
    1. MinGWはDownload & Installを選択し、Choose PackageはCurrent、Choose componentsはFullでインストールする。
    2. MSYS Base Systemは最後のPostステップでは、すべてYを選択し、MinGWのインストール先は、前述のMinGWインストール先をデフォルトでインストールしていれば、C:\MinGW」を入力してインストールする。
    3.  画像表示のためにライブラリ群をすべてインストールする。ここでの注意点はインストール先をMinGWのインストール先にすることである。つまり、MinGWのインストール先をデフォルトでインストールしていれば「C:\MinGW」をライブラリ群のインストール先として入力しなければならない。
     そして最後に、 (C:\)MinGW\src\xpm\3.5.1\libXpm-3.5.1-src\libにある simx.h を (C:\)MinGW\includeにコピーする。

    以上でEmacsのコンパイル環境は整った。

    さて、やっとコンパイルである。ここからは C:\work というフォルダにEmacsのソースと2つのパッチ (emacs-23.1.tar.gz, Emacs-23.1-IME.patch.gz, win7appid.patch) があると仮定して手順を説明する。
    1. スタートメニューからコマンドプロンプトの起動
    2. 以下のコマンドでカレントディレクトリを変更し、Cygwinなど他の実行ファイルが参照されないようにPATHを限定する。
    Microsoft Windows XP [Version 5.1.2600]
    (C) Copyright 1985-2001 Microsoft Corp.

    C:\Documents and Settings\XPMUser>cd c:\work

    C:\work>set PATH=C:\MinGW\bin;C:\msys\1.0\bin;C:\WINDOWS\system32
    3. EmacsのソースとIMEパッチの解凍を行う。
    C:\work>tar xvf emacs-23.1.tar.gz
    (中略)
    emacs-23.1/nextstep/AUTHORS
    emacs-23.1/nextstep/ChangeLog
    emacs-23.1/nextstep/DEV-NOTES
    emacs-23.1/nextstep/FOR-RELEASE
    emacs-23.1/nextstep/README
    emacs-23.1/nextstep/INSTALL
    emacs-23.1/COPYING

    C:\work>gzip -d Emacs-23.1-IME.patch.gz
    4. 2つのパッチを適用する。
    ここでそのままIMEパッチを適用してしまうと、emacs-23.1/nt/configure.bat への適用に失敗してしまう。これはconfigure.batの改行コードがCR+LFであるが、パッチの方はLFとなっているためである。そのために、configure.batの改行コードをLFにする必要がある。
    C:\work>bash
    bash-3.1$ tr -d "\r" < ./emacs-23.1/nt/configure.bat > configure.bat
    bash-3.1$ exit
    exit

    C:\work>mv configure.bat .\emacs-23.1\nt\configure.bat
    以上で configure.bat の改行コードはLF形式に変換された。さっそくパッチを適用する。
    C:\work>cd emacs-23.1

    C:\work\emacs-23.1>patch -p3 < ..\Emacs-23.1-IME.patch
    patching file lib-src/makefile.w32-in
    patching file lisp/loadup.el
    patching file nt/configure.bat
    patching file src/keyboard.c
    patching file src/w32.c
    patching file src/w32fns.c
    patching file src/w32term.c
    patching file src/w32term.h
    patching file src/window.c
    patching file lisp/international/w32-ime.el

    C:\work\emacs-23.1>patch -p1 < ..\win7appid.patch
    patching file lib-src/emacsclient.c
    patching file nt/runemacs.c
    patching file src/w32term.c
    Hunk #2 succeeded at 6395 (offset 55 lines).
    Hunk #4 succeeded at 6477 (offset 55 lines).
    5. パッチの適用は完了したので、Makefileの生成を行う。
    まずは configure.bat を実行し Makefile を生成する。なお、ここではインストール先として c:\work\emacs_bin を指定することとする。
    C:\work\emacs-23.1>cd nt

    C:\work\emacs-23.1\nt>configure.bat --with-gcc --no-cygwin --enable-w32-ime --cflags -D_UNICODE --cflags -DRECONVERSION --prefix c:/work/emacs_bin
    Checking for 'cp'...
    Checking for 'rm'...
    Checking for Windows Version ...
    Checking whether W32 API headers are too old...

    C:\work\emacs-23.1\nt>gcc -D_UNICODE -DRECONVERSION -DWINVER=0x0501 -mno-cygwin
    -c junk.c
    Using 'gcc'
    Checking for libpng...
    ...PNG header available, building with PNG support.
    Checking for jpeg-6b...
    ...JPEG header available, building with JPEG support.
    Checking for libgif...
    ...GIF header available, building with GIF support.
    Checking for tiff...
    ...TIFF header available, building with TIFF support.
    Checking for libXpm...
    ...XPM header available, building with XPM support.
    checking for RECONVERTSTRING...
    ...RECONVERTSTRING is defined.
    Generating makefiles
            1 個のファイルをコピーしました。
            1 個のファイルをコピーしました。
            1 個のファイルをコピーしました。

    (中略)

    config.settings
    gmake.defs
    ..\leim\makefile.w32-in
            1 個のファイルをコピーしました。
            1 個のファイルをコピーしました。

    Emacs successfully configured.
    Run `make' to build, then run `make install' to install.
    上記のような表示がでればOK。
    なお、当然であるが configure.bat の行は prefix指定まで 一行である。注意して欲しい。

    6. そしてコンパイル。
    この環境ではmakeコマンドは、make.exe ではなく mingw32-make.exe であることに注意すること。以下の例ではボールドの文字が実行しているコマンドである。
    C:\work\emacs-23.1\nt>mingw32-make.exe bootstrap
    [Please ignore a syntax error on the next line - it is intentional]
    /usr/bin/sh: -c: line 0: unexpected EOF while looking for matching `"'
    /usr/bin/sh: -c: line 1: syntax error: unexpected end of file

    (中略)

    Checking c:/work/emacs-23.1/leim/quail/4Corner.el ...
    Saving file c:/work/emacs-23.1/leim/leim-list.el...
    Wrote c:/work/emacs-23.1/leim/leim-list.el
    Updating c:/work/emacs-23.1/leim/leim-list.el ... done
    "./../src/oo-spd/i386/emacs.exe" -batch --no-init-file --no-site-file --multibyt
    e --eval '(w32-append-code-lines "leim-list.el" "./leim-ext.el")'
    Saving file c:/work/emacs-23.1/leim/leim-list.el...
    Wrote c:/work/emacs-23.1/leim/leim-list.el
    mingw32-make.exe[2]: Leaving directory `C:/work/emacs-23.1/leim'
    mingw32-make.exe[1]: Leaving directory `C:/work/emacs-23.1/nt'

    C:\work\emacs-23.1\nt>mingw32-make.exe info
    [Please ignore a syntax error on the next line - it is intentional]
    /usr/bin/sh: -c: line 0: unexpected EOF while looking for matching `"'
    /usr/bin/sh: -c: line 1: syntax error: unexpected end of file

    (中略)

    mingw32-make.exe[1]: Entering directory `C:/work/emacs-23.1/doc/lispintro'
    mingw32-make.exe[1]: Nothing to be done for `info'.
    mingw32-make.exe[1]: Leaving directory `C:/work/emacs-23.1/doc/lispintro'

    C:\work\emacs-23.1\nt>mingw32-make.exe
    [Please ignore a syntax error on the next line - it is intentional]
    /usr/bin/sh: -c: line 0: unexpected EOF while looking for matching `"'
    /usr/bin/sh: -c: line 1: syntax error: unexpected end of file

    (中略)

    mingw32-make.exe   -C ../leim all
    [Please ignore a syntax error on the next line - it is intentional]
    /usr/bin/sh: -c: line 0: unexpected EOF while looking for matching `"'
    /usr/bin/sh: -c: line 1: syntax error: unexpected end of file
    mingw32-make.exe[1]: Entering directory `C:/work/emacs-23.1/leim'
    mingw32-make.exe[1]: Nothing to be done for `all'.
    mingw32-make.exe[1]: Leaving directory `C:/work/emacs-23.1/leim'
    7. インストールを行う。
    インストール先は configure.bat の --prefix で指定した場所である。この例では c:\work\emacs_bin がインストール先となる。
    C:\work\emacs-23.1\nt>mingw32-make.exe install
    [Please ignore a syntax error on the next line - it is intentional]
    /usr/bin/sh: -c: line 0: unexpected EOF while looking for matching `"'
    /usr/bin/sh: -c: line 1: syntax error: unexpected end of file

    (中略)

    mkdir "c:/work/emacs_bin/info"
    mkdir "c:/work/emacs_bin/lock"
    mkdir "c:/work/emacs_bin/data"
    mkdir "c:/work/emacs_bin/site-lisp"
    mkdir "c:/work/emacs_bin/etc/icons"
    if [ ! -s ../same-dir.tst ] ; then cp -f ../site-lisp/subdirs.el c:/work/emacs_b
    in/site-lisp ; fi
    if [ ! -s ../same-dir.tst ] ; then cp -rf ../etc c:/work/emacs_bin ; fi
    cp -rf icons c:/work/emacs_bin/etc
    if [ ! -s ../same-dir.tst ] ; then cp -rf ../info c:/work/emacs_bin ; fi
    if [ ! -s ../same-dir.tst ] ; then cp -f ../COPYING c:/work/emacs_bin ; fi
    cp -f ../COPYING c:/work/emacs_bin/bin
    rm ../same-dir.tst
    rm: cannot lstat `../same-dir.tst': No such file or directory
    mingw32-make.exe: [install] Error 1 (ignored)
    rm c:/work/emacs_bin/same-dir.tst
    8. 最後に画像表示に必要なDLL群をコピーする。
    前述までのステップで C:\work\emacs_bin\bin\runemacs.exe を実行すると Emacs は起動するが、以下のように画像が表示されない状態となる。(XP Mode内で実行した例)
    画像を表示するためには必要なDLLはすべて C:\MinGW\bin にあり、C:\work\emacs_bin\bin フォルダーにコピーしなければならない。今回コピーするDLLは次の9個である。
    jpeg62.dll libimage.dll libpng3.dll libpng12.dll libpng13.dll libtiff3.dll libungif4.dll xpm4.dll zlib1.dll
    なお、libimage.dll や libpng3/12/13.dll のどれかは必要ないかもしれない。しかし、私はどれが必要ないのか判断できなかったためにすべてコピーすることにした。
    必要のないDLLをご存じの方は是非教えていただきたいm(_ _)m

    DLLをコピーした後に実行すると以下のように画像が表示される。


    さて、以上で1つの目のステップである「パッチを当てたEmacsをWindows上でコンパイルする」が終わった。お疲れ様です。

    さて、次に説明する2つ目のステップ「少し快適に使うためのセッティング」が今回の重要な”少し快適”を実現するポイントなのだが、次回に説明することとする。(ちょっと疲れたので別の日に書くw)

    ちなみに、今回のビルドはXP Mode上で行ったので、ゲストOSのXPからホストOSのWindows 7に、生成したバイナリをコピーしなければならない。XP Mode上ではホストのドライブが \\tsclient\C (最後がドライブレター) で見えるので、C:\work\emacs_bin フォルダーをホストのお好みの場所にコピーする。
    そして、runemacs.exe を実行すると以下のように起動するだろう。

    では、また次回!

    Emacs (NTEmacs) 23.1 をWindows 7上で少し快適に使う - Part.2」(続き)