X Window System コアプロトコル

X Window System コアプロトコル: X Window System core protocol[1][2][3]とは、X Window Systemの基本プロトコルである。X Window System はビットマップ・ディスプレイのためのネットワーク型ウィンドウシステムであり、UNIX系などのオペレーティングシステムグラフィカルユーザインタフェースの基盤となっている。X Window System はクライアントサーバモデルに基づき、サーバディスプレイキーボード/マウスといった入出力ハードウェアを制御する。アプリケーションプログラムは全てクライアントとして動作し、サーバ経由でユーザーや他のクライアントとやり取りする。このやり取りを規定するのが X Window System コアプロトコルである。他にも X Window System に関連したプロトコルはあるが、それらには X Window System コアプロトコル上に構築されたものと全く別個のものがある。Xコアプロトコルと呼ばれることもある。

X Window System ロゴ

X Window System コアプロトコルでは、パケットは要求(Request)、応答(Reply)、イベント(Event)、エラー(Error)の4種類しかなく、非同期にネットワーク上を転送される。要求パケットはクライアントからサーバに何らかの操作を依頼し(例えば、新たなウィンドウの生成)、結果としてデータを返してもらうものである。応答パケットは、そのようなデータをサーバからクライアントに返すためにある。イベントパケットは、サーバからクライアントにユーザーの操作やその他の事象の発生を知らせる。エラーパケットは、サーバからクライアントに対して、要求パケットの内容を処理しているときにエラーが発生したことを知らせる。要求パケットによって、応答パケット、イベントパケット、エラーパケットが生成される可能性がある。しかし、それ以外ではプロトコル上はパケットの送受信の順序は指定されていない。コアプロトコルへの拡張がいくつか存在し、それぞれに固有の要求/応答/イベント/エラーパケットが定義されている。

X は1984年、マサチューセッツ工科大学(MIT)で生まれた(2006年現在のリリース X11 は 1987年9月に登場)。設計者 Bob Scheifler と Jim Gettys は設計にあたっての原則として、コアプロトコルは「機構を生成するものであって、ポリシーを生成するものではない」とした。結果として、コアプロトコルにはクライアント間やクライアントとユーザー間のやり取りが具体的には示されていない。これらのやり取りに関する規定は別途行う必要があり[4]ICCCMfreedesktop.org の仕様が作成された。また、特定のウィジェット・ツールキットを使うことで必然的にやり取りが規定される。

概要

編集

サーバとクライアント間の通信は、伝送路上でパケットを交換することでなされる。コネクションはクライアントが確立する(クライアントの起動についてはプロトコル上規定されていない)。クライアントは最初のパケットを送信する。これには、使用するエンディアン、プロトコルのバージョン、クライアントがサーバに期待する認証方式が指定されている。サーバは、コネクションを受け付けるか否かを示した応答パケットを送り返すか、認証のためのパケットを送る。コネクションが受け付けられる場合、その後のやり取りでクライアントが使うべきデータを格納したパケットが送られる。

 
クライアントとサーバのやり取りの例

コネクションが確立すると、クライアントとサーバ間で以下の四種類のパケットが交換される。

  1. 要求(Request): クライアントがサーバから情報を要求するか、サーバに何らかの実行を要求する。
  2. 応答(Reply): サーバへの要求に対する応答。全ての要求パケットに対して応答パケットが生成されるわけではない。
  3. イベント(Event): サーバがクライアントに対して、キーボードやマウスからの入力、ウィンドウの移動、リサイズ、前面への露出などのイベントを知らせる。
  4. エラー(Error): 要求が不正だった場合、サーバはエラーパケットを送る。要求はキューイングされるので、要求に対するエラーは即座に返ってくるとは限らない。

要求パケットと応答パケットは様々な長さのものがあるが、イベントパケットとエラーパケットは32バイトで固定されている。

要求パケットにはサーバ側で受信した時点で逐次的な番号が振られる。あるクライアントからの最初の要求パケットには 1、2番目のパケットには 2 といったようになる。この番号の最下位ビットから16ビットぶんが応答パケットやエラーパケットに格納され、どの要求に対するものかを示すようになっている。また、イベントパケットにも同様の情報が格納されており、イベント発生時に処理中(あるいは直前まで処理していた)の要求パケットの番号が示されている。

ウィンドウ

編集

一般にグラフィカルユーザインタフェースで「ウィンドウ」と呼ぶものを、X Window System では「トップレベルウィンドウ」と呼ぶ。いわゆる「親ウィンドウ」の「サブウィンドウ」と呼ばれるウィンドウ内ウィンドウも「ウィンドウ」と呼ぶ。ボタンメニューアイコンなどのグラフィカルな構成要素は、実際にはサブウィンドウとして認識されている。

 
ウィンドウの配置の組合せ。1 はルートウィンドウでありスクリーン全体に対応する。2 と 3 はトップレベル・ウィンドウ。4 と 5 は 2 のサブウィンドウ。親ウィンドウからはみ出ている部分は表示されない。

クライアントはウィンドウ生成を要求できる。より正確に言えば、既存のウィンドウのサブウィンドウの生成を要求できる。結果として、クライアントが生成するウィンドウ群は一種の(階層)を形成する。この木の根をルートウィンドウと呼び、サーバが起動したときに自動的に生成される特殊なウィンドウである。他の全ウィンドウはルートウィンドウの直接的または間接的なサブウィンドウである。トップレベルウィンドウは、ルートウィンドウの直接のサブウィンドウである。見た目で言えば、ルートウィンドウは画面全体と同じ大きさであり、他のウィンドウ群の一番背後にある。

ウィンドウの内容は常に保持されるとは限らない。特に、ウィンドウが移動されたり、リサイズされたり、他のウィンドウの影に隠れたり、完全に(あるいは部分的に)見えなくなったりすると、ウィンドウの内容は破壊される可能性がある。Xサーバが、ウィンドウの内容の「バッキングストア」を管理していない場合はウィンドウの内容は失われる。クライアントはバッキングストアの保持を要求することができるが、サーバが必ずそうするという保証はない。従って、クライアントはバッキングストアを当てにしてはいけない。見える状態のウィンドウの中身が不明の場合、そのクライアントに対してイベントが送られ、内容の再描画が行われる。

ウィンドウには、一連の「属性」があり、ウィンドウの大きさと位置、背景画像、バッキングストア要否などの情報が格納されている。これら属性を調べたり、変更したりする要求パケットが存在する。

ウィンドウは InputOutputInputOnly のどちらかである。画面に表示され、何らかの内容が描画されるものは前者である。後者のウィンドウは画面には現れず、入力を受け取るためだけに存在する。

ウィンドウの外枠とタイトルバー(ボタンも含むことがある)はウィンドウマネージャが作成するものであって、そのウィンドウを作成したクライアントは関知しない。ウィンドウマネージャは、それらの部分についての入力も受け取り、ウィンドウのリサイズなどに対応する。クライアントは一般にウィンドウマネージャによるウィンドウの変化は関知しない。しかし、最近のウィンドウマネージャの多くはトップレベルウィンドウの親ウィンドウをルートウィンドウ以外に設定変更することが多く、この変更をクライアントが無視することはできない。Xコアプロトコルの観点では、ウィンドウマネージャもクライアントの一種であり、他のアプリケーションと何ら違いはない。

ウィンドウに関する情報は xwininfo プログラムを実行することで得られる。引数に -tree を付与すると、ウィンドウの親子関係をツリー形式で表示し、それぞれの識別子や位置データも表示する。

ピクスマップと描画領域

編集

ピクスマップとは、描画に使われるメモリ領域である。ピクスマップの内容がそのままウィンドウとして表示されるわけではなく、ピクスマップの内容(の一部)がウィンドウに転送されたり、逆にウィンドウからピクスマップに内容が転送されたりする。これによりダブルバッファリングなどの技法が可能となっている。ウィンドウ上で可能なグラフィカルな操作の多くは、ピクスマップ上でも可能である。

ウィンドウとピクスマップを総称して「描画領域; drawables」と呼ぶ。描画領域の内容データはサーバ側に置かれる。クライアントはサーバに対して描画領域の内容を転送してもらうこともできるし、逆に内容をサーバに送ることもできる。

グラフィックコンテキストとフォント

編集

クライアントはいくつかのグラフィック操作を要求できる。例えば、領域の生成、領域のコピー、点/直線/多角形/テキストの描画などである。これらの操作は全て、任意の描画領域(ウィンドウもピクスマップも)に対して実施可能である。

グラフィック操作要求の多くは、「グラフィックコンテキスト」を含む。これは、グラフィック操作のパラメータを格納した構造体である。グラフィックコンテキストには、前景色、背景色、テキストのフォント、その他のグラフィックパラメータが含まれる。グラフィック操作を要求する場合、クライアントはグラフィックコンテキストを作成しなければならない。グラフィックコンテキストの全パラメータがグラフィック操作に影響するわけではない。例えば、直線描画要求では、フォント指定は影響しない。

Xコアプロトコルでは、サーバ側のフォントの使用を扱う[5]。その場合のフォントはファイルとして格納されており、サーバはローカルなファイルシステムに直接アクセスする場合もあるし、「フォントサーバ」と呼ばれるプログラムにネットワーク経由でアクセスする場合もある。クライアントは、そのサーバで利用可能なフォント一覧を要求でき、フォントのロード(まだロードされていない場合)やアンロード(他のクライアントが使っていない場合)を要求できる。クライアントはフォントについての汎用情報を要求でき、特定のテキストを特定のフォントで描画するときに必要なスペースを問い合わせることもできる。

フォント名はXコアプロトコルのレベルでは任意の文字列に過ぎない。X Logical Font Description Conventions[6] により、フォントの属性に対応した命名規則が規定されている。この命名規則では、オプション的な属性も考慮するようになっている。

xlsfonts プログラムは、サーバが格納しているフォントの一覧を表示する。xfontsel プログラムは、フォントの字体を表示し、フォント名をコピー・アンド・ペーストで別のウィンドウに入力できる。

近年では、クライアント側でフォントを用意することが多くなり、サーバ側フォントの使用が廃れつつある[7]。クライアント側フォントは、クライアント側でレンダリングするもので、XftCairoライブラリを使ったり、XRender拡張を使ったりする。Xコアプロトコルにはクライアント側フォントに関する規定は存在しない。

リソースと識別子

編集

ウィンドウ、ピクスマップ、フォントなどに関するデータは全てサーバに格納されている。クライアントはそれらオブジェクトの識別子を知っており、サーバにそれらについて要求する際に名前として使用する。例えば、クライアントがウィンドウを生成したいとき、サーバに対して識別子を指定してウィンドウ生成を要求する。その識別子は後で、例えばウィンドウの描画時などクライアントからの要求で使用される。以下のオブジェクトはサーバ側にあり、識別子を使ってクライアントから指定される。

  • Window(ウィンドウ)
  • Pixmap(ピクスマップ)
  • Font(フォント)
  • Colormap (色表、後述)
  • Graphic context(グラフィックコンテキスト)

これらのオブジェクトを「リソース; resources」と呼ぶ。クライアントがこのようなリソースの生成を要求する場合、その識別子を常に指定する。例えば、新しいウィンドウを生成する場合、クライアントはそのウィンドウの属性(親、幅、高さなど)とウィンドウに関連付ける識別子を指定する。

識別子は32ビット整数であり、最上位ビットから3ビットは常にゼロとされる。クライアントごとに識別子の集合を持ち、新しいリソース生成時に使用する。この集合はサーバがコネクションの受理を知らせるパケット内で、2つの整数としてクライアントに通知される。クライアントは指定された範囲から、重ならないように識別子を選択して使う。ウィンドウ、ピクスマップ、フォント、カラーマップ、グラフィックコンテキストについて、2つのオブジェクトが同じ識別子を持つことはできない。

あるリソースが生成されると、その識別子をクライアントが使い、サーバに対してそのリソースに関する何らかの操作を要求するときに指定する。操作には、リソースを変化させるもの(例えば、ウィンドウを移動させる要求)と、サーバからそのリソースに関するデータを得るもの(例えば、ウィンドウの属性を要求する場合)がある。

識別子はクライアント内だけでなく、サーバ内で一意である。例えば、2つのウィンドウがそれぞれ別のクライアントが生成したものであっても、同じ識別子を持つことはない。クライアントは識別子さえ指定できれば、任意のオブジェクトにアクセスでき、例えば別のクライアントが生成したリソースも識別子が分かっていればアクセスできる(サーバから与えられた範囲外の識別子をサーバへの要求パケットに指定可能である)。

結果として、同じサーバに接続された2つのクライアントがあるとき、識別子によって一意にリソースが指定される。例えば、あるクライアントが識別子 0x1e00021 のウィンドウを生成し、その番号 0x1e00021 を別のアプリケーションに渡したとする(手段は何でも良い。例えば、ファイルに番号を書き込み、それを別のアプリケーションが読むという方法でもよい)。すると、その別のアプリケーションが同じウィンドウに対して操作可能となる。これは例えば Ghostviewの X 版で利用されている。Ghostview はサブウィンドウを生成し、その識別子を環境変数にセットして Ghostscript を呼び出す。Ghostscript は PostScript ファイルの内容をそのウィンドウに描画する[8]

リソースは、それを生成したクライアントがサーバとのコネクションをクローズしたときに正常に削除(破壊)される。ただし、コネクションをクローズする前にクライアントから破壊を要求することもできる。

イベント

編集

イベントとは、サーバからクライアントに送信されるパケットであり、クライアントが興味を持ちそうな事象が発生したことを通知するのに使われる。例えば、ユーザがキーを押下したり、マウスのボタンをクリックしたなどの事象である。イベントはユーザの入力だけではない。例えば、新たなサブウィンドウが生成された場合などにもイベントパケットが送信される。

イベントは常にいずれかのウィンドウに関連付けられている。例えば、マウスカーソルがあるウィンドウ上にあるときにクリックした場合、そのイベントはそのウィンドウと関連付けられる。イベントパケットにはそのウィンドウの識別子も含まれる。

クライアントはサーバに対してイベントパケットを他のクライアントに送るよう要求できる。これはクライアント間の通信に利用される。例えばマウスクリックで選択されたテキストをクライアントが要求する場合に、そのようなイベントが使われる。そのイベントは、その選択を保持しているウィンドウを制御しているクライアントに送られる。

Expose イベントは、ウィンドウの一部の内容が破壊された領域が画面上見えるようになったとき送信される。ウィンドウの内容はいくつかの条件が重なると破壊される。例えば、ウィンドウが別のウィンドウに隠され、サーバがバッキングストアを保持していなかった場合などである。サーバが Expose をクライアントに送信すると、クライアントはその部分を再描画しなければならない。

 
イベントの例: あるウィンドウ内でキーが押下されると、イベントが生成され、クライアントのイベントマスクの設定によってはクライアントに送信される。イベントマスクはクライアントが変更可能。

多くのイベントは、クライアントがそれについて興味があることを事前に表明していないと送信されない。これは、クライアントが必ずしも全てのイベントを必要としないためである。例えば、キーボード入力は受け付けるが、マウス関連のイベントは受け付けないといった状況が考えられる。イベントには、クライアントが明示的に要求していなくても必ず送信されるものもある。

クライアントは、ウィンドウの属性としてどのイベントを受け付けるかを設定できる。例えば、Expose イベントはウィンドウの再描画が必要な場合に送られるが、クライアント側でこれを受け付けない状態にすることもできる。これは、ウィンドウのイベントマスク属性を適切に設定することでなされる。

複数のクライアントが同じウィンドウのイベントを要求することもできる。その場合クライアント毎に異なるイベントマスクを設定できる。例えば、あるクライアントはキーボードのイベントだけを受け付け、別のクライアントがマウスのイベントだけを受け付けるといったことが可能である。サーバは各ウィンドウについてクライアント毎のイベントマスクを保持できるようになっている。ただし、ウィンドウ毎に1つのクライアントにしか送信できないイベントも存在する(特にマウスクリックについてのイベントやウィンドウ管理に関連した変化を知らせるイベント)。

xev プログラムは、ウィンドウに対応したイベントを表示する。特に xev -id WID とすれば、指定した識別子 WID に関わるイベントを全て表示する。

以下は、黒い四角形が描画されたウィンドウを生成し、キー押下で終了するクライアントとサーバ間のやり取りを例示したものである。この例では、クライアントの要求が応答を必要とするものではないため、サーバ側から応答パケットは送信されない。ただし、エラーパケットが生成される可能性はある。

  1. クライアントがサーバとのコネクションを開き、使用するバイトオーダー(エンディアン)を指定した初期パケットを送信する。
  2. サーバがコネクションを受理し(この例では認証は省略されている)、適切なパケットで応答する。このパケットにはルートウィンドウの識別子(例えば 0x0000002b)とこのクライアントが使える識別子の範囲などの情報が格納されている。
  3. クライアントが識別子 0x00200000 でデフォルトのグラフィックコンテキスト生成を要求する(この要求パケットでは、この例に出てくる他の要求パケットと同じように、応答パケットは返信されない)。
  4. クライアントがトップレベルウィンドウ(すなわち、親ウィンドウとしてルートウィンドウ 0x0000002b を指定)の生成を要求する。このとき、識別子 0x00200001、サイズ 200×200、位置 (10,10) などを指定。
  5. クライアントがウィンドウ 0x00200001 の属性変更を要求し、興味のあるイベントとして ExposeKeyPress を受け付けることを宣言する。
  6. クライアントがウィンドウ 0x00200001 の画面表示を要求する。
  7. ウィンドウが画面に表示され、内容を描画しなければならなくなると、サーバはクライアントに Expose イベントを送信する。
  8. このイベントを受けて、クライアントはウィンドウ 0x00200001 とグラフィックコンテキスト 0x00200000 を指定して PolyFillRectangle 要求を送信し、四角形の描画を要求する。

このウィンドウが別のウィンドウに覆われ、再び前面に戻った場合、バッキングストアをサーバが保持していないと、次のようになる。

  1. サーバがクライアントに Expose イベントを送り、ウィンドウを再描画する必要があることを知らせる。
  2. クライアントは PolyFillRectangle 要求を再度送信することでウィンドウを再描画する。

キーが押下されると、次のようになる。

  1. サーバはクライアントに KeyPress イベントを送り、ユーザーがキーを押下したことを知らせる。
  2. クライアントは、それに適切に対応する(この例の場合、終了する)。

プロトコルレベルでは、色は32ビットの符号なし整数で表され、ピクセル値(pixelvalue)と呼ばれる。以下のような要素から色の表現が影響を受ける。

  1. 色深度
  2. カラーマップ(colormap)- 色を赤、緑、青 (RGB) の強さで表したテーブル
  3. visual type - 上記テーブルを使ってどう色を表現するかを指定したもの

最も容易な場合、カラーマップは各行にRGBの値が格納されたテーブルとなる。ピクセル値 x は、そのテーブルのx-行目の色を意味する。クライアントがカラーマップの内容を変更できる場合、この表現方法は PseudoColor visual class である。StaticColor visual class では、クライアントがカラーマップの内容を変更できない。

visual class は全部で6種類存在する。それぞれ、RGB値とピクセル値の対応付け方法が異なる。そのうち、2つが上述の PseudoColorStaticColor である。他に GrayScaleStaticGray があり、これらは白、黒、灰色のみが表示可能である(前者ではクライアントによるカラーマップ変更が可能)。

残る2種類の visual class はこれらとは異なり、ピクセル値がそのままRGB値に対応している。この場合のピクセル値からRGB値への変換は次の通り。

  1. ピクセル値をビット列としてみる。
  2. このビット列を3つの部分に分割する。
  3. それら3つの部分がそれぞれ整数として認識され、それぞれ異なる3つのテーブルのインデックス値として使われる。

この場合、カラーマップは赤/緑/青の光の三原色それぞれに対応した3つのテーブルで構成される。結果として得られるのは三原色それぞれの強さである。このような表現を使う visual class として DirectColorTrueColor があり、前者はクライアントがカラーマップを変更でき、後者は変更できない。

いずれの機構でも、色をピクセル値で表現するには追加のパラメータが必要である。それらパラメータが visual type として集約されており、visual class の種類、その他のパラメータが格納されている。Xサーバには利用可能な visual type が固定個存在し、それぞれに識別子が割り当てられている。その識別子は32ビットの符号なし整数だが、リソースやアトムの識別子と重なっていても構わない。

クライアントからのコネクションを受理したとき、サーバが送信する受理パケットには、一連のブロックが含まれ、各ブロックは1つの画面(スクリーン)に対応している。各画面に対応したブロックは、さらにその画面でサポートしている色深度ごとのブロックに分かれている。色深度ごとのブロックは可能な visual type のリストを含む。まとめると、各画面には複数の色深度が対応し、その色深度ごとに複数の visual type が対応する。ある visual type は異なる色深度の複数の画面で使える場合もある。

それぞれの visual type について、受理パケットには識別子と実際のパラメータ(visual class その他)が格納されている。後でこの情報を要求できないので、クライアントはこの情報を格納しておく。さらに言えば、クライアントは visual type を変更したり、新たに生成したりできない。新たなウィンドウ生成の要求時、そのウィンドウの色を表現するのに使う色深度と visual type の識別子を指定する。

カラーマップは、その画面を制御するハードウェア(例えばビデオカード)がカラーパレットを使っているかどうかとは無関係に使われる。ハードウェアがパレットを使う場合は、常に制限されたカラーマップがインストールされ、無制限にピクセル値とRGB値の対応付けを増やすことはできない。クライアントはサーバに対してカラーマップのインストールを要求できるが、その場合、別のカラーマップのアンインストールが必要となる。これは、画面を見たとき、アンインストールされたカラーマップを使っていたウィンドウの色が変に表示されるという結果をもたらす(この現象を color flashing あるいは technicolor と呼ぶ)。この問題は標準カラーマップ(standard colormap)を使うことで解決する。標準カラーマップはピクセル値と色の事前に決められた対応付けをする。このため、異なるアプリケーション間で標準カラーマップを共用することが可能となっている。

カラーマップ生成はICCCMで規定されている。標準カラーマップは ICCCM でも規定されているし、Xlib 仕様にも定義されている。

アトム

編集

アトム(Atom)とは、文字列を表す32ビット整数である。文字列が任意の長さであるのに対してアトムは常に32ビット整数であり、プロトコル設計者は文字列を短い固定サイズで表すためにアトムを導入した[9]。アトムは短いため、同じ文字列をパケットとして何度も送信するような場合に利用される。これによってネットワークの利用効率が向上する。アトムはまた、イベントパケットのような固定サイズのパケットで利用される。

正確には、アトムはサーバが保持する文字列の識別子である。リソース(ウィンドウやピクスマップ)の識別子に似ているが、2つの点で異なる。まず第一に、アトムの識別子はサーバが設定するのであって、クライアントは指定できない。つまり、クライアントが新たなアトム生成を要求するときは、サーバに文字列を送信するだけであり、識別子は指定しない。サーバはその文字列に識別子を割り当て、クライアントへの応答パケットでそれを返す。第二に、アトムは特定のクライアントとは関連しない。アトムは、生成されるとクライアントが終了しても存続し、サーバが終了するまで残る(リソースのデフォルトの振る舞いはそれとは異なる)。

アトムは識別子であるから、一意である。しかし、アトムとリソースの識別子は同じになることがある。アトムに対応した文字列は「アトム名; atom name」と呼ばれる。アトム名は生成後に変更することはできないし、二つのアトムが同じアトム名となることもない。従って、アトム名はアトムを指すのにも使える。「アトム ABCD」と言った場合、正確には「文字列 ABCD に対応するアトム」あるいは「名前が ABCD のアトム」を意味する。クライアントは、新たなアトム生成を要求することもできるし、ある文字列のアトム(識別子)を要求することもできる(これらは同じ意味である)。事前定義されたアトムもある(特定の識別子と文字列でサーバが生成する)。

アトムは様々な用途で使われ、主に同じサーバに接続した複数のクライアント間の通信でよく使われる。特に、後述するウィンドウのプロパティに関連して使われる。

サーバ内に保持されている全アトムの一覧は xlsatoms プログラムを使って表示できる。特に、このプログラムはそれぞれのアトム(識別番号)とその名前(対応する文字列)を表示できる。

プロパティ

編集

各ウィンドウには、事前定義された属性群とプロパティ群があり、サーバに全て格納され、クライアントからは適当な要求でアクセスできる。属性はウィンドウに関するデータであり、サイズ、位置、背景色などがある。プロパティはウィンドウにアタッチされた任意のデータである。属性とは対照的に、プロパティはXコアプロトコルのレベルでは何の意味もない。クライアントはウィンドウのプロパティとして任意のデータを格納できる。

プロパティには、名前、データ型、値がある。プロパティは命令型プログラミングにおける変数に似ていて、クライアントが名前とデータ型を指定して生成でき、任意の値を格納できる。プロパティはウィンドウに対応しているため、同じプロパティ名を複数のウィンドウそれぞれで使い、それぞれ異なる型の異なる値を格納できる。

プロパティの名前、データ型、値は全て文字列である。より正確に言えば、これらは全てアトムであり、サーバに格納されている文字列に対応していて、クライアントからはその識別子でアクセス可能である。クライアントはあるプロパティに対して、その名前を格納したアトムの識別子を使ってアクセスする。

プロパティは主にクライアント間通信に使われる。例えば、WM_NAME という名前のプロパティ(正確には、"WM_NAME" という文字列に対応したアトムをプロパティ名とするプロパティ)にはウィンドウの名前が格納される。ウィンドウマネージャは、一般にこのプロパティを読み、タイトルバーにウィンドウ名を表示する。

クライアント間通信には、ルートウィンドウのプロパティを使ったものもある。例えば、freedesktop.org のウィンドウマネージャ仕様によれば[10]、ウィンドウマネージャは現在のアクティブウィンドウの識別子をルートウィンドウの _NET_ACTIVE_WINDOW というプロパティに格納するべきとしている。プログラムのパラメータを含むXリソースもルートウィンドウのプロパティとして格納される。そうすることで、(別のコンピュータ上で動作していても)全てのクライアントがそれらにアクセスできる。

xprop プログラムは指定されたウィンドウのプロパティ一覧を表示する。xprop -root とすれば、ルートウィンドウの各プロパティの名前、型、値を表示する。

キー・マッピング

編集
 
このキーが生成する keycode は常に同じだが、keysyms が異なる3つのシンボル /, 7, { が対応している。

X Window System では、全ての個々の物理キー(キーボードのキー)に 8 から 255 の数が割り当てられていて、これを keycode と呼ぶ。keycode はキーを特定するだけであり、そのキーに印字されている特定の文字や用語(例えば "Page Up")の識別はできない。それら文字や用語は keysym で識別される。keycode は実際の1つのキーに対応しているが、keysym は、例えばシフトキーなどの修飾キーが同時に押されたかどうかに対応して決定される。

キーが押下されたり、解放されたとき、サーバは KeyPress イベントあるいは KeyRelease イベントを適当なクライアントに送信する。これらのイベントには以下の情報が含まれる。

  1. 押下されたキーの keycode
  2. 現在の修飾状態(シフト、コントロールなど)とマウスボタンの状態
 
keycode が keysym に変換される様子

つまりサーバは、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要求を送信することもできる。

拡張

編集
 
shape extensionによって丸いウィンドウ(oclock)も生成できる。

X Window System コアプロトコルは、拡張性を考慮して設計された。Xコアプロトコルには、利用可能な拡張や、拡張の要求/応答/イベント/エラーパケットをどう作ればよいかを問い合わせる機構を備えている。

特に、特定の拡張に対応したデータについて利用可能な拡張の一覧を要求できる。拡張のパケットは、Xコアプロトコルのパケットとよく似ている。Xコアプロトコルでは、要求/応答/イベント/エラーパケット内にそのパケットのタイプを示す整数が含まれている。例えば、新たなウィンドウの生成要求は 1 である。この整数の一部範囲が拡張用に予約されている。

認可

編集

クライアントがサーバとのコネクションを確立しようとした時、サーバのとりうる応答としては、受理するか、拒否するか、認証を要求するかのいずれかである。認証要求には、使用する認証手法の名称が含まれる。Xコアプロトコルでは認証プロセスは規定されておらず、使っている認証の種類に依存する。さもなくば、サーバは単に受理パケットか拒否パケットを送るだけである。

通常のクライアントとサーバのやり取りで認証に関わる要求は「ホストによるアクセス制御; host-based access method」だけである。クライアントは、この認証手法を有効にする要求ができ、接続を認可されているホスト(クライアント)の一覧を読んだり変更したりできる。一般のアプリケーションはこれらの要求を使うことはない。これらを使うプログラムとして xhost があり、ユーザやシェルスクリプトがアクセス可能ホスト一覧を読み書きできるようにする。ホストによるアクセス制御は、安全ではないと言われている。

Xlib その他のクライアント・ライブラリ

編集

多くのクライアントプログラムは、Xlibというクライアントライブラリを通してXサーバと通信する。クライアントは一般に XawMotifGTKQt といったライブラリを使うが、これらもXサーバとの通信には Xlib を使っている。Xlib を使うことで、以下のようになる。

  1. Xlib を使うと、クライアントは応答とイベントの観点で同期的に動作可能となる。
    1. Xlib では、要求を送信すると適当な応答があるまでブロックする。言い換えれば、Xlib を使っていないクライアントがあったとしたら、要求パケット送信後に応答を待つ間に他の処理が可能である。ただし、クライアントがマルチスレッド化されている場合は、Xlib を使っていても同様のことが可能である。
    2. Xサーバは非同期にイベントを送信するが、Xlib はイベントをクライアント内のキューに蓄積する。クライアントは、明示的にライブラリ関数を呼び出したときだけそのキュー上のイベントにアクセスする。言い換えれば、クライアントがあるイベントを待っている場合、強制的にブロックまたはビジーウェイトとなる。
  2. Xlib では要求をサーバに即座に送信せず、output buffer というキューに蓄積する。その内容が実際に送信されるのは、以下のタイミングである。
    1. XFlashなどのライブラリ関数を使って明示的に送信を要求したとき。
    2. Xサーバからの応答を待つ必要のあるライブラリ関数を呼び出したとき(例えば、XGetWindowAttributes)。
    3. イベントキューにイベントがあるか問い合わせたとき(例えば、XNextEvent 呼び出し)で、かつブロックするような呼び出しをしたとき(例えば、XNextEvent はキューが空だとブロックする)。

Xtのような上位ライブラリ(さらに上位として XawMotif がある)では、イベントに対応したコールバック関数を使うことができる。つまり、上位ライブラリがイベントキューを常時監視し、必要に応じて適切なコールバック関数を呼び出す。また、ウィンドウの再描画が必要となるようなイベントは Xt 内部で処理される。

XCB などの下位レベルのライブラリはプロトコルへの非同期アクセスを提供し、レイテンシ隠蔽効果が大きい。

X Window System コアプロトコルで指定されないこと

編集

X Window System コアプロトコルでは、クライアント間通信は規定されておらず、ウィンドウを使ってGUIに一般的に存在する視覚的要素(ボタンメニューなど)をどう実現するかも規定していない。GUI要素は、ウィジェット・ツールキットと呼ばれるクライアントライブラリで実装される。クライアント間通信は、ICCCMfreedesktop.org の仕様[10]など他の標準でカバーされている。

クライアント間通信は、セレクション、カットバッファ、ドラッグ・アンド・ドロップと関係がある。これらはユーザが利用するウィンドウ間のデータ転送手法である。ウィンドウが他のプログラムに制御されている場合もあるため、データ交換のためのプロトコルは必須である。クライアント間通信はXウィンドウマネージャとも関係がある。ウィンドウマネージャはウィンドウ群の見た目を制御し、GUIとしてのルック・アンド・フィール全般を制御する。他にもクライアント間通信に関わる問題として、Xセッションマネージャが関与する部分がある。

ユーザセッションの開始方法もXコアプロトコルではカバーされていない。通常、Xディスプレイマネージャが自動的に行う。しかし、ユーザが xinitstartx プログラムを手動で起動してセッションを開始することもできる。

脚注・出典

編集
  1. ^ Robert W. Scheifler and James Gettys: X Window System: Core and extension protocols, X version 11, releases 6 and 6.1, Digital Press 1996, ISBN 1-55558-148-X
  2. ^ RFC 1013
  3. ^ Grant Edwards. An Introduction to X11 User Interfaces
  4. ^ Jim Gettys. Open Source Desktop Technology Road Map
  5. ^ comp.fonts FAQ: X11 Info
  6. ^ X Logical Font Description Conventions
  7. ^ Matthieu Herrb and Matthias Hopf. New Evolutions in the X Window System.
  8. ^ Ghostview: Interface with ghostscript
  9. ^ David Rosenthal. Inter-Client Communication Conventions Manual. MIT X Consortium Standard, 1989
  10. ^ a b Freedesktop window manager specification

関連項目

編集

外部リンク

編集