第 3章sawfish のカスタマイズ(2)

目次
rep コードによるカスタマイズ
sawfish 周辺のアプリケーション、ライブラリ

rep コードによるカスタマイズ

sawfish も着々と開発が進み、新しいバージョン v0.35(web 公開のための改訂時最新)がリリースされました。最近では sawfish のバージョンが上っていってもそれほど大きな変更がなされるということはありませんが数々のバグ修正がなされより安定して使えるようになっています。

ところで最近筆者は少し気分を変えたいこともあってホストによっては Blackbox[1]を使うようになっています。Blackbox も動作が軽くて必要十分な機能を備え、(GNOME や KDE といったデスクトップ環境を使わない[2]という条件付きとなりますが)おすすめのウィンドウマネージャの一つです。

さて今回ははじめに sawfish の rep コードによるカスタマイズについて、そして次に sawfish 周辺のアプリケーションについて簡単に触れたいと思います。

rep って何?

前回は主に sawfish-ui を使ったカスタマイズ方法について説明しました。そして sawfish-ui を使うことで GUI を使って簡単かつ柔軟にカスタマイズできることに驚いた方もいるかと思います。

しかし今では GNOME および KDE の二つのすぐれたデスクトップ環境が GNU/Linux のさまざまなディストリビューションの標準のデスクトップとして用意されていることが普通となりました。そして設定ファイルを直接エディタなどで編集してカスタマイズする必要のあった、fvwm や twm などが一般的だった頃とは違い GUI の設定ツールがウィンドウマネージャの機能の一つとして提供されていることもめずらしくありません。例えば筆者が使用経験のある、Window Maker、sawfish、Blackbox、IceWM などはすべて GUI による設定ツールを持っています。

実は sawfish の場合は他のウィンドウマネージャとは少し異なり GUI 設定ツールが書き出すファイルも sawfish 自身を記述しているのと同じ言語で記述されています。つまりカスタマイズするということは sawfish 本体を拡張するということと本質的に変わりません。そして GUI 設定ツールではできないことも直接その言語で記述することで非常に柔軟かつ広範囲の拡張が可能となります[3]

それでは前回のように設定ツールでカスタマイズを施した後の sawfish-ui が書き出したコードの例を見てみましょう。以下は筆者の環境での$HOME/.sawfish/customの冒頭部分の抜粋です。

    ;; sawfish user customization -- do not edit by hand!
    ;; sawfish version 0.31.1, written Tue Oct 17 16:10:28 2000
    
    (custom-set-typed-variable (quote customize-show-symbols) (quote ()) (quote boolean))
    (custom-set-keymap (quote global-keymap) (quote (keymap (cycle-windows . "M-TAB") (next-workspace . "M-C-Right") (previous-workspace . "M-C-Left") (xterm . "M-C-x"))))
   

何やら括弧がたくさん並んでいます。似たような記述を Emacs の設定ファイル ($HOME/.emacs など)で見たことがある、と気づく方もいらっしゃることでしょう。似ているのも当然で、これを記述しているのは Emacs Lisp の親戚ともいえる、rep という Lisp 言語の一種です。

実は rep は sawfish の作者の John Harper 自身が開発しています。そして彼は sawfish で使っている rep の Gtk+ バインディング(librep から GTK+ の機能を使うライブラリ)の他に rep 言語の ORBit(GNOME で使っている CORBA) や SQL (ただし MySQL のみサポート)バインディング、さらには rep を使った Emacs ライクなエディタ Jade も作っています:John Harper 作のソフトウェアの一覧ページ

rep コーディングによる sawfish カスタマイズのためのリソース

rep 自体の文法などについては librep の info マニュアルに詳細に書かれています。そして librep についても特に sawfish に特化した情報については sawfish の info マニュアルが利用できます([4])。

また実際のコードの例については sawfish software map (http://adraken.themes.org/map.php) にたくさんの実例があります。

さらに rep は Emacs Lisp ライクな言語なので Emacs Lisp のマニュアルもだいたいそのまま参考にできます。筆者も emacs-lisp-intro-ja および emacs-manual-ja の Info マニュアルのソース(texinfo ファイル)から texi2html (http://www.mathematik.uni-kl.de/~obachman/Texi2html/) で HTML ファイルを生成してブラウザで参照するようにしています。

実際にコードを書いてカスタマイズ

それでは実際に$HOME/.sawfishrcをカスタマイズしてみましょう。

sawfish-client について

以下の項目についてそれぞれを.sawfishrcに記述すると起動時に読み込まれて実行されます。しかし直接書いてしまうとデバッグが難しくなるので、最初は対話的に rep 式を評価[5]し、正しい動作を確認してから.sawfishrcに書き込むことをお勧めします。

前回も少し触れましたが、sawfish では端末上でsawfish-client -と入力するとシェルのようなものが起動し、rep 式を対話的に評価することが可能です。この sawfish シェルの中ではuser> ,helpと入力することでヘルプを参照できたり、シンボル名などを補完(completion)したりできます。sawfish-client の他の機能についてはsawfish-client--helpとすれば参照できます。オプションそれぞれについての概要を次の表に示します。

図 3-1. sawfish-client

表 3-1. sawfish-client のオプション

--display X

DISPLAY X のウィンドウマネージャ(当然 sawfish がそのDISPLAYで動作していなければなりません)に接続します

-q

冗長な情報を表示しません

-f FUNCTION

関数 FUNCTION を評価します(例 FUNCTION=restart)

-c COMMAND

コマンド COMMAND を実行します(例 COMMAND=toggle-window-shaded)

-r FEATURE

モジュール FEATURE を読み込みます(例 FEATURE=sawfish.gtk.widget)

-e FORM

形式 FORM を評価します(例 FORM='(system "gedit &")

-

EOF 入力まで式を読み込んで評価します

--

標準入力から EOF 入力まで式を読み込んで評価します

Lispの基本

rep のコードについて理解するにはどうしても Lisp の基本的な知識が必要となります。しかし紙面が限られているのと筆者自身もあまり Lisp はよく知らないので割愛します。詳細については前述の文書などを参照して下さい。

以後 Lisp の特殊な用語や括弧のあふれる表現式がつづきますが、それらについてはあまり気にせず、Lisp というのはそういうものだからしょうがないと思ってあきらめて下さい :-)

rep コードの実例

アニメーションモードが none 以外 (solid か wireframe) であるときにウィンドウがアイコン化する方向 (anim-outline-icon-cords) を画面中央に指定:

      (setq anim-outline-icon-cords
        (cons (quotient (screen-width) 2) (quotient (screen-height) 2) ) )
     

一つ一つ分解していきます。括弧部分は入れ子の内側にあるものから先に評価されます。

screen-width と screen-height はそれぞれ画面の幅と高さの値を返す関数です。そして quotient は第一引数を第二引数で割ったときの商を返す関数です。つまり (quotient (screen-width) 2) は画面の幅の半分の値を返します。また cons はコンスセル[6]をつくる関数で (cons ... )の部分の結果は (画面の幅 . 画面の高さ) というコンスセルになります[7]

anim-outline-icon-cords はアイコン化の方向の座標を示すシンボルです。座標の原点は画面左上隅です。そして関数 setq[8]によってこのシンボルの値として先のコンスセルを指定、つまりアイコン化の方向は画面中央に指定されます。

もう少し実用的なものもあげてみます。

ルートメニューの中のアプリケーションメニューを再定義し、Emacs、Rxvt、Sylpheed、Mozilla がメニューから起動できるようにする:

      (defvar my-menu
       `(("Emacs" (system "emacs &"))
       ("Rxvt" (system "krxvt &"))
       ("Sylpheed" (system "sylpheed &"))
       ("Mozilla" (system "mozilla &"))
      ))
     
      (setq apps-menu my-menu)
     

system 関数は C 言語の system 関数[9]と同じように、引数をシェルコマンドとして解釈、実行することができます。シンボル my-menu にメニューのリストを指定し、さらにシンボル apps-menu がシンボル my-menu を指すように再定義しています[10]

ワークスペースの移動後すぐに画面中央にそのワークスペース名を表示:

      (require 'rep.io.timers) 

      (defun display-ws-name ()
       (display-message (or (nth current-workspace workspace-names)
         (format nil (_ "Workspace %d") (1+ current-workspace))))
	   (set-timer enter-ws-timer 0 500))
      (setq enter-ws-timer (make-timer (lambda (x) (display-message nil))))

      (add-hook 'enter-workspace-hook display-ws-name)
     

これは先のリソースの節で触れた、sawfish software map に投稿されていた例です。

require を使って他のモジュールライブラリを読み込んで利用することができます。

defun は関数を定義する関数です。書式は "(defun 関数名シンボル 引数リスト関数本体)" となっていますが、この例の場合は関数に対する引数はなく引数リストの部分は空リスト[11]になっています。そしてその後関数本体部分の定義が続きます。

関数本体部分のシンボル enter-ws-timer は関数定義の直後に先の setq 関数を使って指定されています。

フック (*-hook) は特定の場面で実行される関数(のリスト)を値に持つ特殊なシンボルです。この場合はワークスペースに入ってから 500 秒後にdisplay-ws-name 関数が実行されるように enter-workspace-hook フックに追加しています。

lambda は手続きオブジェクトを生成する(というよりも実は Lisp での関数の定義そのもの)特殊なシンボルです。

自分で書いた rep コードが長くなる場合、すべて .sawfishrc に記述するのではなくいくつかのファイルに分割することも可能です。

.sawfishrc から $HOME/.sawfish/lisp/ 以下の自作ライブラリ(my-rep-lib.jl) を読み込む:

      (load "my-rep-lib")
     

sawfish/wm.jl 内では次のように各ユーザの rep ライブラリを探す検索するパスが指定されています:

      (setq load-path (cons (canonical-file-name "~/.sawfish/lisp") load-path))
     

従って my-rep-lib をフルバスで指定する必要はありませんし、また rep コードは習慣的に *.jl というファイル名にしますが、load の引数には .jl をつけないので注意して下さい。

バイトコンパイル

Emacs のユーザ定義のライブラリをバイトコンパイルしている方もたくさんいらっしゃるかと思いますが、librep でもバイトコンパイルが可能です。

    bash$ rep --batch --no-rc compiler -f compile-batch <目的の rep コード、*.jl>
   

ただし librep ライブラリの下位互換性の問題から新しいバージョンに上げるときに再コンパイルする必要があります。これは少し面倒ですので筆者の場合は一切バイトコンパイルはしていません。

sawfish.el

rep コードを書くときの支援ツールとしてsawfish.el(http://www.hagbard.demon.co.uk/archives/sawfish.el) という Emacs のメジャーモードがあります。筆者はどちらかというと vi 派なので実は一度も使ったことがありませんが、おそらく便利に使えることでしょう。

注意

[1]

blackbox オフィシャルサイトはhttp://blackbox.alug.org、この本家サイトを筆者が和訳したサイトはhttp://kino22-ap.eng.hokudai.ac.jp/~ss/bb/です。

[2]

blackbox は コンパイル時の configure オプション指定によって KDE に対応することはできるようですが残念ながらまだ GNOME 対応はなされていませんし、その予定もないようです。

[3]

sawfish では拡張したコードと本体とを明確に区別することはできず、実際にこれまでもいろいろなユーザの拡張機能をとりこんで発展してきています。ひょっとすると、あなたが自分のために拡張、カスタマイズした機能も本体にとりこまれて全世界の人が使う標準の機能となるかもしれません :-)

[4]

なおこの sawfish の info マニュアルについては筆者が日本語に訳したもの(texinfo および html 形式)があります - http://sawfish.gnome.gr.jp/documentation.html

[5]

lisp の世界では関数を実行することを"式を評価する"というように表現するようです。

[6]

コンスセルは二つのポインタからなり、アトムと並んで Lisp で扱われる基本的なオブジェクトです。またすべてのリストはこのコンスセルからなります。

[7]

例えば筆者がこの原稿を書いている ThinkPad 600x では画面の大きさを1024 x 768で利用しているので (512 . 384) というコンスセルに評価されます。

[8]

setq はシンボルに値を指定する関数です。デフォルトではシンボルanim-outline-icon-cords の値は sawfish の lisp ディレクトリ以下のsawfish/wm/animation/outline.jlで、カスタマイズ可能なシンボルの値を定義する defvar 関数を使って定義されています。

[9]

system 関数についてはman systemの結果等を参照して下さい。

[10]

メニューの定義の仕方などについてはsawfish/wm/menus.jlを参照して下さい。

[11]

空リスト () は実はシンボル nil と同等です。後半部分で(display-message nil) というようにdisplay-message の引数に nil を使っているのはそういうわけです。