X Window System コアプロトコル
プロパティの名前、データ型、値は全て文字列である。より正確に言えば、これらは全てアトムであり、サーバに格納されている文字列に対応していて、クライアントからはその識別子でアクセス可能である。クライアントはあるプロパティに対して、その名前を格納したアトムの識別子を使ってアクセスする。
プロパティは主にクライアント間通信に使われる。例えば、WM_NAME という名前のプロパティ(正確には、"WM_NAME" という文字列に対応したアトムをプロパティ名とするプロパティ)にはウィンドウの名前が格納される。ウィンドウマネージャは、一般にこのプロパティを読み、タイトルバーにウィンドウ名を表示する。
クライアント間通信には、ルートウィンドウのプロパティを使ったものもある。例えば、freedesktop.org のウィンドウマネージャ仕様によれば、ウィンドウマネージャは現在のアクティブウィンドウの識別子をルートウィンドウの _NET_ACTIVE_WINDOW というプロパティに格納するべきとしている。プログラムのパラメータを含むXリソースもルートウィンドウのプロパティとして格納される。そうすることで、(別のコンピュータ上で動作していても)全てのクライアントがそれらにアクセスできる。
xprop プログラムは指定されたウィンドウのプロパティ一覧を表示する。xprop -root とすれば、ルートウィンドウの各プロパティの名前、型、値を表示する。
X Window System では、全ての個々の物理キー(キーボードのキー)に 8 から 255 の数が割り当てられていて、これを keycode と呼ぶ。keycode はキーを特定するだけであり、そのキーに印字されている特定の文字や用語(例えば "Page Up")の識別はできない。それら文字や用語は keysym で識別される。keycode は実際の1つのキーに対応しているが、keysym は、例えばシフトキーなどの修飾キーが同時に押されたかどうかに対応して決定される。
キーが押下されたり、解放されたとき、サーバは KeyPress イベントあるいは KeyRelease イベントを適当なクライアントに送信する。これらのイベントには以下の情報が含まれる。
押下されたキーの keycode
現在の修飾状態(シフト、コントロールなど)とマウスボタンの状態
つまりサーバは、keycode と修飾状態を特定の文字に変換せずに送信する。この変換をするのは、クライアントの役割である。例えば、クライアントがあるキーとシフト修飾キーが押下されていることをイベントで通知されたとする。通常このキーが "a" という文字を生成するなら、クライアントは、このイベントによって文字 "A" を得る。
keycode から keysym へのクライアントでの変換には、サーバが用意した対応表を使う。この表をどこか全クライアントから参照可能なところに置けばよい。典型的なクライアントは、このマッピングを要求し、キーイベントの内容(keycode と修飾状態)から keysym への変換を行う。ただし、クライアントはこのマッピングを自由に変更できる。
修飾キーは、押下されると他のキーの解釈を変化させる。シフトキーは、一般に "a" のような小文字を "A" のような大文字に変化させる。他の修飾キーとしては、「コントロールキー」、「Altキー」、「Metaキー」などがある。
Xサーバは、最大8種類の修飾キーを扱える。ただし、各修飾キーは必ずしも1つの物理キーに対応したものとは限らない。キーボードには、同じ修飾キーが複数個存在する場合があるからである。例えば、多くのキーボードには2つのシフトキーがある(左端と右端)。これらの keycode は異なるが、Xサーバはどちらもシフト修飾キーと認識する。
8個の修飾キーについて、Xサーバはその修飾キーと認識される keycode の一覧を持っている。例えば、第一修飾キー(シフト)の keycode 一覧で 0x37 が記載されている場合、その keycode 0x37 に対応したキーをXサーバがシフト修飾キーであると認識する
修飾キーと解釈されるキーのマッピングはXサーバが管理するが、任意のクライアントが変更できる。例えば、クライアントからF1キーをシフト修飾キーとして解釈されるキー一覧に追加することができる。このような修正を加えると、F1キーが第3のシフトキーとして機能するようになる。しかし、F1キーを押下した場合の keycode はそのままである。したがって、F1キーを従来通りに解釈することもできるし(例えば、F1キー押下でヘルプウィンドウを開くなど)、同時にシフトキーとしても機能する("a" キーを押下したときにF1キーが押下されていると "A" と解釈される)。
Xサーバは、マウスボタンについてもマッピングを管理し、使用する。ただし、ボタンはボタン同士での入れ替えだけが可能となっている。これは、左利きのユーザ向けに左端のボタンと右端のボタンを入れ替えるのに便利である。
xmodmap プログラムは、キー/修飾キー/マウスボタンのマッピングを表示・変更する。
グラブ(grab)とは、キーボードとマウスの全イベントを1つのクライアントに送信する状態である。クライアントは、キーボードのグラブ、マウスのグラブ、あるいは両方のグラブを要求できる。サーバがその要求を満たす場合、全キーボード/マウス・イベントはグラブしたクライアントに(グラブをやめるまで)送られる。その間、他のクライアントはそれらイベントを受け取れない。
グラブ要求時、クライアントはグラブウィンドウを指定する。全イベントはグラブしているクライアントがグラブウィンドウに関連しているかのように送信される。しかし、他のクライアントはたとえグラブウィンドウを選択していてもイベントを受け取れない。グラブには、以下の2種類がある。
アクティブ : グラブは即座に効力を発揮する。
パッシブ : グラブは事前に指定されたキーまたはマウスボタンが押下されたときのみ効力を発揮し、解放された時点で終了する。
クライアントはキーボードかマウスポインタ、あるいは両方についてグラブ状態を確立できる。グラブ要求にはキーボードやマウスポインタのフリーズ要求を含めることもできる。グラブとフリーズの違いは、グラブがイベント受信者を変更するのに対して、フリーズはイベントの配信そのものを停止する点である。デバイスがフリーズされると、それが生成するイベントはキューに格納され、通常はフリーズ状態が解除されたときに溜めておいたイベント群が送信される。
マウスポインタのイベントの場合、イベント配信に影響を与える別の要素として、イベントマスクがある。これは、イベントの種類ごとに配信するか捨てるかを指定するものである。
グラブ要求には、グラブが確立していない状態でグラブしようとしているクライアントにイベントが送られようとしたとき、どうすべきかを指定するフィールドもある。特に、クライアントはそのようなイベントを普通に送信してもらうか、グラブに従って送信してもらうかを指定できる。これらの状況は見た目にも異なる結果となる。例えば、クライアントが通常状態では第一ウィンドウでキーボードイベントを受け取っていて、第二ウィンドウによるキーボードのグラブを要求したとする。イベントを第一ウィンドウに送信するかグラブウィンドウ(第二ウィンドウ)に送信するかはグラブ要求のパラメータに依存する。
クライアントはサーバ全体のグラブを要求することもできる。この場合、グラブクライアントからの要求以外は受け付けなくなる。
他にもXコアプロトコルには要求やイベントが存在する。まず、ウィンドウ間の親子関係に関する要求がある。クライアントは、ウィンドウの親の変更要求が可能である。また、ウィンドウの親子関係に関する情報を要求することもできる。他にセレクションに関する要求があるが、これは主に他のプロトコルで扱われる。入力フォーカスやカーソル形状についての要求もある。クライアントは、特定のリソース(ウィンドウ、ピクスマップなど)の所有者を終了させる要求もでき、サーバはそのコネクションを終了させる。また、クライアントはサーバにNOP要求を送信することもできる。
X Window System コアプロトコルは、拡張性を考慮して設計された。Xコアプロトコルには、利用可能な拡張や、拡張の要求/応答/イベント/エラーパケットをどう作ればよいかを問い合わせる機構を備えている。
特に、特定の拡張に対応したデータについて利用可能な拡張の一覧を要求できる。拡張のパケットは、Xコアプロトコルのパケットとよく似ている。Xコアプロトコルでは、要求/応答/イベント/エラーパケット内にそのパケットのタイプを示す整数が含まれている。例えば、新たなウィンドウの生成要求は 1 である。この整数の一部範囲が拡張用に予約されている。
クライアントがサーバとのコネクションを確立しようとした時、サーバのとりうる応答としては、受理するか、拒否するか、認証を要求するかのいずれかである。認証要求には、使用する認証手法の名称が含まれる。Xコアプロトコルでは認証プロセスは規定されておらず、使っている認証の種類に依存する。さもなくば、サーバは単に受理パケットか拒否パケットを送るだけである。
通常のクライアントとサーバのやり取りで認証に関わる要求は「ホストによるアクセス制御; host-based access method」だけである。クライアントは、この認証手法を有効にする要求ができ、接続を認可されているホスト(クライアント)の一覧を読んだり変更したりできる。一般のアプリケーションはこれらの要求を使うことはない。これらを使うプログラムとして xhost があり、ユーザやシェルスクリプトがアクセス可能ホスト一覧を読み書きできるようにする。ホストによるアクセス制御は、安全ではないと言われている。
多くのクライアントプログラムは、Xlibというクライアントライブラリを通してXサーバと通信する。クライアントは一般に Xaw、Motif、GTK、Qt といったライブラリを使うが、これらもXサーバとの通信には Xlib を使っている。Xlib を使うことで、以下のようになる。
Xlib を使うと、クライアントは応答とイベントの観点で同期的に動作可能となる。
Xlib では、要求を送信すると適当な応答があるまでブロックする。言い換えれば、Xlib を使っていないクライアントがあったとしたら、要求パケット送信後に応答を待つ間に他の処理が可能である。ただし、クライアントがマルチスレッド化されている場合は、Xlib を使っていても同様のことが可能である。
Xサーバは非同期にイベントを送信するが、Xlib はイベントをクライアント内のキューに蓄積する。クライアントは、明示的にライブラリ関数を呼び出したときだけそのキュー上のイベントにアクセスする。言い換えれば、クライアントがあるイベントを待っている場合、強制的にブロックまたはビジーウェイトとなる。
Xlib では要求をサーバに即座に送信せず、output buffer というキューに蓄積する。その内容が実際に送信されるのは、以下のタイミングである。
XFlashなどのライブラリ関数を使って明示的に送信を要求したとき。
Xサーバからの応答を待つ必要のあるライブラリ関数を呼び出したとき(例えば、XGetWindowAttributes)。
イベントキューにイベントがあるか問い合わせたとき(例えば、XNextEvent 呼び出し)で、かつブロックするような呼び出しをしたとき(例えば、XNextEvent はキューが空だとブロックする)。
Xtのような上位ライブラリ(さらに上位として Xaw や Motif がある)では、イベントに対応したコールバック関数を使うことができる。つまり、上位ライブラリがイベントキューを常時監視し、必要に応じて適切なコールバック関数を呼び出す。また、ウィンドウの再描画が必要となるようなイベントは Xt 内部で処理される。
XCB などの下位レベルのライブラリはプロトコルへの非同期アクセスを提供し、レイテンシ隠蔽効果が大きい。
X Window System コアプロトコルでは、クライアント間通信は規定されておらず、ウィンドウを使ってGUIに一般的に存在する視覚的要素(ボタンやメニューなど)をどう実現するかも規定していない。GUI要素は、ウィジェット・ツールキットと呼ばれるクライアントライブラリで実装される。クライアント間通信は、ICCCM や freedesktop.org の仕様など他の標準でカバーされている。
クライアント間通信は、セレクション、カットバッファ、ドラッグ・アンド・ドロップと関係がある。これらはユーザが利用するウィンドウ間のデータ転送手法である。ウィンドウが他のプログラムに制御されている場合もあるため、データ交換のためのプロトコルは必須である。クライアント間通信はXウィンドウマネージャとも関係がある。ウィンドウマネージャはウィンドウ群の見た目を制御し、GUIとしてのルック・アンド・フィール全般を制御する。他にもクライアント間通信に関わる問題として、Xセッションマネージャが関与する部分がある。
ユーザセッションの開始方法もXコアプロトコルではカバーされていない。通常、Xディスプレイマネージャが自動的に行う。しかし、ユーザが xinit や startx プログラムを手動で起動してセッションを開始することもできる。