X resources を設定することのメモ

端末設定にも欠かせない X resources の設定や応用例について

xresources_magic.jpg

X 環境にはユーザの要望に応じて X クライアントアプリケーションを容易にカスタマイズできるよう、リソースの値を合理的に設定・格納する機能があり、 X resources とかリソースデータベースなどと呼ばれる。

主に端末エミュレータの配色や書体、カーソルテーマの設定などに利用され、これに触らず CLI の恩恵にあずかることはないと言えなくはないものである。

ネットには多くの設定例が掲げられており、私はよくそれらの記述例をコピペして自分の環境に適用している。それは世にも多く行われていることかと思う。

しかしこれの書き方や応用はどうなるかと思い man ページを眺めようとしたら、どこを読めばいいやらわからない。ちょっとググってみてもしっくりくる説明に出会えず、頼みの Arch Wiki も私には少々難しい記述がある。

そうなものだからこれはもっときちんと調べようと思い、やりはじめたら嵌った。意外に捉えどころがないような、なんというか複雑で曖昧なところがあると感じた。

そもそも X resources は X 環境を構築する一部なのだから、掘り下げれば X 全般に話が及んでしまう。また、歴史的経緯のうちに当初のコンベンションが変遷していったというようなこともあったのではなかろうか。そういったことが話を難しくしているのであろう。

ともかく、X resources ファイルの記述についてかようにまとめることにした。

xrdb か ~/.Xdefaults か

X resources によるユーザーレベルの設定は通常、 ~/.Xresources に書き込んだ設定を xrdb でリソースデータベースにロードしておくことによる。するとアプリが必要とする時にそこからリソースが渡されるようになる。

~/.Xresources というファイル名は規約上のもので、記述書式が同様ならばファイル名は問わないとされる(話をややこしくするようだが、xrdb でロードできるなら後述の ~/.Xdefaults という名前であっても構わないわけだ)。

ただしフル装備のデスクトップ環境では X の起動時に ~/.Xresources をロードするような xrdb コマンドの記述が X セッションのスタートアップスクリプトになっている(以下は ~/.xinitrc の例)。

# ~/.xinitrc

sysXresources=/etc/X11/xinit/.Xresources
userXresources=$HOME/.Xresources

if [ -f "$sysXresources" ]; then
    xrdb -merge "$sysXresources"
fi
if [ -f "$userXresources" ]; then
    xrdb -merge "$userXresources"
fi

かようにシステムは xrdb が ~/.Xresources をロードするよう構築されていることが多いようである。容易にインストール可能な充実したデスクトップ環境の利用が著しくなれば、この傾向は強まるものと思う。

そのことと別に、リソースマネージャが使われていない場合に、 ~/.Xdefaults を要求の都度読み込むという「古い」方法へとフォールバックするというのがある。

この ~/.Xdefaults に記述して都度読ませるという方法は今でも時々紹介される方法であり、ある条件下では思惑通りの結果をもたらしてくれるようである。

xrdb と違い、プログラム起動時(xlibが呼ばれるたび)に毎回ファイルを読み取るというのがミソで、これはつまり ~/.Xdefaults に設定を書き込んでその X アプリを起動すれば即反映されるということであり、一見扱いやすいように思えることだろう。しかし X クライアントを別のホストで実行する際には、リモートの ~/.Xdefaults を読んでしまうから都合が悪いということがある。

また、繰り返すようだが ~/.Xdefaults が読まれるのはリソースマネージャが使われていない場合である。そして前述のように多くのデスクトップ環境では xrdb が ~/.Xresources をロードしてリソースマネージャを利用しているわけだから、これを無理に利用しないような策を講じない限りは ~/.Xdefaults の出番はないはずである。

一方、 xrdb を使う方法のメリットは、リソース設定の内容は xrdb が一度だけロードすれば十分でありかつ無駄がないということ、そしてローカルかリモートであるかに拘らずアプリが必要とすれば適切なリソースが常に渡されるということである。

このようなことから X resources の設定については、 ~/.Xdefaults の利用法の確立や安定化を追究するよりは、 xrdb で設定をロードし、管理をリソースマネージャに任せたほうが良いと思われる。そして恒常的に反映させたい設定内容は ~/.Xresources に記述しておき、スタートアップスクリプトでこれをロードする道を確立しておく。シンプルでわかりやすいだろうし、このことを前提とするプログラムが多いということでもある。

だからここでは基本的に ~/.Xresources に記述したものを xrdb でロードしてリソースマネージャを使う方法について、記す。

X resources の構文

リソースの基本書式

リソースは1行単位で記す。各行は、いくつかのワード ― ここではコンポーネントと呼ぶ ― を . でつないで構成したリソース名と、そこへ格納したいリソース値を : で区切って記す。

instance.resource: value
class.resource: value

コンポーネントの大文字小文字は区別される。基本的には キャメルケース を用い、ロワーケース(最初の文字は小文字)によって表現する(例: xtermgeometryscrollBar )。

最初のコンポーネントは、リソースがどのアプリケーション設定かを示すための名前、つまりアプリケーション名である。アプリケーション名の表現はインスタンス(instance)か、あるいはクラス(class)で示すこととなる。

そしてドット区切りに続けてそのアプリケーションが持つリソース(resource)を記す。

リソースの持つ値、すなわちリソース値(value)として指定できるのは文字列、整数、ブーリアン( true / false )である。

インスタンス

インスタンスは、ほとんどの場合プログラム名(実行ファイル名)をもとにしたアプリケーション名である。

以下の例はインスタンス emacs というプログラムの cursorColordark green という値を適用したリソースを表している。Emacs のカーソル色をダークグリーンにするということだ。

emacs.cursorColor: dark green

インスタンスは前述のとおりプログラム名なので、これをリネームするならばインスタンスも同様に変わる。

このことを利用して以下のようなことができる。

例えば xterm の実行ファイル xtermxtermgreen などと言う名前でコピーし、リソースには xtermgreen.background: #002540 と書いてロードしておき xtermgreen を起動すると、背景が #002540 (緑色)になる、というような使い方ができる。

もっとも、 xterm の場合には -name オプションでインスタンスを指定できるから、無駄にコピーなどせず xterm -name xtermgreen というように起動すれば同じことである。 urxvt なども然り。

クラス

前述のとおりインスタンスは固定的とはいい難いが、クラスを用いた定義では意図せずインスタンスが変わってしまったとしても、確実にアプリケーションを指定できる。ネットでよく見かける設定例では、以下のようにクラスを用いた記述が多い。

Emacs.background: #002540
Emacs.foreground: azure3

このクラス名の表現に限っては、例えば EmacsXmessage のようにアッパーケース(最初の文字も大文字)を用いるのが慣例とされている。が、歴史的経緯からちょっとややこしくなっている。

例えば XTerm のように X 関連のクラス名は最初の2文字までを大文字にしていることが多く、他にも XClockXScreenSaver といったものがあるが、 Xfd などのように1文字目だけのものもある。また rxvt は Rxvt だが rxvt-unicode は URxvt である。さらに UXTerm というのもある。

URxvt.visualBell: true
URxvt.scrollBar: false

ともかく、クラスを使うには固有に決められているものを調べて正確に記述する配慮が必要だろう。

書式

リソースの表現はワイルドカード( ? * )での置き換えが可能で、 ? は1つの、 * は複数のリソースとみなすことができる。

例えば urxvt と xterm の背景色定義はそれぞれ URxvt.backgroundXTerm.vt100.background などと記すが、両方のアプリケーションプログラムが取りうる値とすべく、以下のように記述を1つにまとめることができる。

*background: #282828

Xresources では ! を記すと以降をコメントとみなす。よく開発言語ではスクリプトを書いた行内の後ろにコメントを付与できるが、 Xresources ではそういうのはうけつけないようなのでコメントは1行ずつにしておいた方がよさそうだ。

また行末に \ を置くことで行を分割できる。

!! ~/.Xresources

! Colors
URxvt.colorIT: #8ec07c
URxvt.colorBD: #fe8019

! Fonts - DejaVu with IPAGothic
URxvt.font: xft:DejaVuSansMono Nerd Font-9,\
            xft:IPAGothic

プリプロセッサに命令を渡す

ドットファイルとか rc ファイルは柔軟に設定できるほどに行数も増える。だからコメントをつけたりエディタのフォールド機能を使うとかで解りやすいよう工夫する向きも多い。そこではまたファイルの分割も有効な手段となり得るだろう。例えば *shrc では . コマンドでソースしたり、 ssh/config でも OpenSSH 7.3 あたりからは Include が使えるようになって、すっきりと見通しよく整理できる。

だから Xresources ファイルの記述でもこのようなことができるとありがたいと思うのだが、残念ながらそんな仕様ではないのだ。

ところが、 xrdb コマンドはファイルをロードして読み取る前にプリプロセッサを通す仕様となっているから、そのときに解釈させる命令が利用できるのだ。

デフォルトで利用されるのはCプリプロセッサ(CPP)だが、多くのシステムでこれが標準利用できるだろう。条件分岐や外部ファイルの読み込みができるのは柔軟な記述につながるはずだという、そういう目論見が持てる。

ここでは CPP の #include#define#ifdef について簡単に記す。

#include

#include で外部ファイルを差し込むことができる。例えばカラー定義だけを別のファイルにしたりできるから、テーマ切り替えを容易にする工夫ができそうだ。

#include "FILE"

パスはダブルクォーテーションで括って記すとカレントを基準にする。例えば以下のように ~/.Xresources に書いた場合、 ~/.Xresources.d ディレクトリの下にある theme_file というファイルを読み込むということになる。

#include ".Xresources.d/theme_file"

#define

#define はマクロ置き換え機能だが、シンボルの定義が便利で、よく使われることだろう。

#define IDENTIFIER [REPLACEMENT]

ワイルドカードによるプロパティ指定ができても、結局色や書体の指定を何度となく行うこともあるだろう。そういったものを #define でまとめておくと改変が楽になるかもしれない。

#ifdef / #ifndef

#if 〜 #endif で条件式が扱える。Cの式をまんま書くことができるが、 defined (否定は !defined )で定義の有無を判断できるのが便利である。この #if defined#if !defined#ifdef#ifndef という簡略文に置き換えられる。

#ifdef | #ifndef#elif#else#endif

xrdb コマンドは -D オプションでシンボル定義をプリプロセッサに渡せる(値も渡せる)ので、 #ifdef と組み合わせることでロード時に独自の値を渡して条件分岐させることも可能になる(記述例の項を参照)。

X resources のロード( xrdb コマンド)

リソースデータベースへの反映は xrdb で設定ファイルをロードすることによる。

既述のとおり xrdb コマンドがスタートアップスクリプトに書き込まれてあることが多いが、ユーザが設定内容の記述を書き換えた場合には明示的にロードする必要がある(でなければシステムを再起動するか)。

以下のようにファイル名を与えると、リソースデータベースをそのファイルの内容で書き換える。それまでの値は残らない( -load オプションと同じ)。なお、繰り返しになるがファイル名は ~/.Xresources である必要はない。

xrdb ~/.Xresources

前のリソースを残しつつ、一部のリソース値を刷新したり、新しいリソースを追加したりするには -merge オプションを用いる。スタートアップスクリプトではこの -merge オプションを記述してあることが多く、それまでにリソースデータベースへ登録されたものが失われないようにするためである。

xrdb -merge ~/.Xresources

また、 xrdb コマンドはパイプでテキストを渡すとリソースとして登録してくれる。 -merge オプションと組み合わせると一時的な改変などに便利である。

echo "URxvt.scrollBar: false" | xrdb -merge

-query オプションで設定した内容を一覧できる。

xrdb -query

様子をみながら設定調整することも多いかと思うが、多少なりとも見やすければ勘違いも減るかもしれない。 column コマンドは結構便利である。

xrdb -query | sort | column -t -s $'\t'

X resources ファイルの記述例

xterm と urxvt のリソースの共有

以下は xterm と urxvt でリソース名が同じで、よく使われるものを区切り子 * で指定したもの。ほかに termName や、色定義の color0 などもある。

urxvt が xterm よりも後の実装で同じリソース名を使っているのはこういう事を企図したものと思う。

!! ~/.Xresources

*geometry: 96x36
*saveLines: 1000
*visualBell: true
*scrollBar: true
*cursorBlink: true
*cursorUnderLine: true
*background: #FBF1C7
*foreground: #282828

外部ファイル

以下の例は色定義を別のファイル ~/.Xresources.d/theme_file にしたうえで、定数 DARK_THEME が定義されてあれば背景を黒にしてそうでなければ白にするもの。

!! ~/.Xresources

#include ".Xresources.d/theme_file"

*background: BG
*foreground: FG
!! ~/.Xresources.d/theme_file

#define colBlack #282828
#define colWhite #ebdbb2

#ifdef DARK_THEME
#define BG colBlack
#define FG colWhite
#else
#define BG colWhite
#define FG colBlack
#endif

上記2ファイルの構成で、以下のようにロードすると白っぽい背景になる。

$ xrdb ~/.Xresources

そして -D オプションで DARK_THEME を定義した場合には黒っぽい背景となる。

$ xrdb -DDARK_THEME ~/.Xresources

#include〜 より前のとこに #define DARK_THEME と書き込んどいて、都度コメントアウトしたりアンコメントするっていうやりかたもありだろう。

システムによって設定を変える

GitHub や Dropbox などを介して複数ホストでドットファイルを使い回す工夫はよく行われていることだろう。するとPCシステムの違いなどによってパラメータを変える工夫をしなければならないことも多いが、 X resources でもプリプロセッサの解釈を利用することでそれが可能である。

シンボルには #definexrdb -Dsymbol[=value] などで自前定義するものだけでなく、PC環境に則った内容が標準的に渡されるものもある( xrdb -symbols で一覧表示できる。詳細は XRDB(1) )。 hostname を格納した定数( HOST , SERVERHOST )もあるが、ここで至便なのは SRVR_ホスト名 で、これは hostname から生成されるシンボルである。

以下はシステムによってインストールされているフォントが違うことを条件分岐で補うもの。ホスト alicia では DejaVu と IPAゴシックの9ポを 、ホスト abigail.foo-bar.com では Inconsolata と Nasuフォント の11ポを、そしてそれ以外では monospace の9ポを使うというように、 xterm と urxvt の両方に設定してある。

!! ~/.Xresources

#ifdef SRVR_alicia
  #define  FONT       DejaVu Sans Mono
  #define  FONTW      IPAGothic
  #define  FONT_SIZE  9
#elif defined SRVR_abigail_foo_bar_com
  #define  FONT       Inconsolata
  #define  FONTW      NasuM
  #define  FONT_SIZE  11
#else
  #define  FONT       monospace:lang=en
  #define  FONTW      monospace:lang=ja
  #define  FONT_SIZE  9
#endif

XTerm*faceName:           FONT
XTerm*faceNameDoublesize: FONTW
XTerm*faceSize:           FONT_SIZE
URxvt.font:               xft:FONT-FONT_SIZE, xft:FONTW