(拡張機能が Xinerama を認識できるようにする)
X.org Xinerama Task Force
Last Modified
20 May 2002
X.org Standards Process Status:
Stage 4: Public Review
Draft Version 0.8
Mark Vojkovich, The XFree86 Project, Inc.
Xinerama は X サーバの拡張である。この拡張では、複数のスクリーンを持つ X サーバが使用され、このサーバはクライアントから見ると「複数のモニターに跨る、単一のスクリーンを持つ X サーバ」のように見える(1つの大きなスクリーン)。DDX (Device Dependent X)から見ると、X サーバは従来型の複数スクリーンを持つ X サーバのように動作する。この仕組み(拡張)は DDX の関与無しに DIX の層で管理されており、理論的には、DDX 側では Xinerama の存在を知っている必要すら無い。DIX で実行される Xinerama 固有の仕事の大半は、ディスパッチの段階で行われる。各拡張機能は、それぞれ自分自身のディスパッチを行うことから、この仕組みに参加するために、あるいは少なくとも Xinerama の存在を認識できるようになるために、修正が必要である可能性がある。この文書では、他の拡張が手伝ったり認識したりする必要がある Xinerama の操作について、その様々な側面を概説する。
すでに Xinerama を認識できるようになっている X サーバ拡張があるので、それらを参照してほしい。例えば、MIT-SHM や Nonrectangular Window Shape Extension(SHAPE 拡張)などである。
ある種の Proc 関数では、Xinerama を認識できる拡張は、1つ1つのリクエストをそれぞれの物理スクリーンへ送る必要がある。これは通常、元となる Proc 関数を新たな関数で置き換えることによって実現される。この新たな関数は、各スクリーンに対して1回づつ元の Proc 関数を呼び出すものであり、その際には各スクリーンに合うようにプロトコル・データの修正が行われる(データの修正は各スクリーンへ同データを渡す前に行われる)。
基本的に、ウィンドウの占有のようなサーバ固有のリソースの場合、特別なことをする必要はない。けれども、ウィンドウ、ピクスマップ及び GC (グラフィクス・コンテクスト)のようなスクリーン固有のリソースの場合、通常は特別な処理が必要になる。Xinerama においては、クライアントがこうしたリソースを指定するために用いる XID (1つ)は、サーバ内部の(同種の)リソースの集合1つに対応しており、この集合の中の各リソースはそれぞれ対応するスクリーンを持っている。
サーバは、クライアントから XID を提示された場合、リソース1つを取り出すのではなく、リソースの集合を取り出す必要がある。これは、XineramaRes 構造体の中に、そのリソースの、スクリーンそれぞれのバージョンの XID を保持しておくことで実現される。
typedef struct { XID id ; } XineramaInfo;
typedef struct { XineramaInfo info[MAXSCREENS]; /* list of XIDs in the set */ RESTYPE type; /* RESTYPE of the set */ union { /* type specific data */ struct { char visibility; char class; } win; struct { Bool shared; } pix; char raw_data[4]; } u; } XineramaRes;
XineramaRes は、それ自身が1つのリソースであり、クライントが指定してくる XID と同一の XID を用いるものである。例えば、拡張にスクリーン固有のリソース「RT_FOO」が存在する場合、新たなリソース型「XRT_FOO」が作成される(訳註:上記の構造体の中にある RESTYPE 型の定数(のようなもの)として使用される。具体的には「XRT_WINDOW」「XRT_PIXMAP」「XRT_GC」「XRT_COLORMAP」などがある。「RT」はResource Type であろう)。クライアントが FOO 型のリソースを指定するためにある XID を使用したとすると、サーバは、それと同一の XID を使用してリソース型 XRT_FOO について検索を行い、各スクリーンのリソース RT_FOO の XID 群を保持する XineramaRes を取り出してくる。Xinerama がどのようにリソース作成を修正しているかを知るには、xineramaProcs.c でどのようにウィンドウ、ピクスマップ、グラフィクス・コンテクストが作成されているのかを見るとよい。(訳註:令和6年11月、xineramaProcs.c は今のところ存在せず、該当するコードは多分 panoramiXprocs.c (及びその周辺)にある。XineramaRes も現時点では存在せず、似た形の PanoramiXRes が使用されている。X11R7.7/xserver/xorg-server-1.12.2/Xext/panoramiXprocs.c 内の「stuff」は、X11R7.7/xserver/xorg-server-1.12.2/include/dix.h を参照。)
XineramaRes 構造体の info メンバは、一組の XID 群が入った配列である。配列の要素番号は、スクリーン番号である。この配列の中の最初の要素をクライアントが提示してきた XID とし、残りを FakeClientID(同クライアント用の偽物の ID)にすると便利である。クライアントがリソースを指定するために使う XID と、第1のスクリーンのリソースの XID とを同一にし、さらに XineramaRes のハッシュ検索にも同じ XID を使用するということである。これは、リソースを解放する段になって活きてくる。ディスパッチ層にてスクリーン番号の大きい方から順にリソースを解放していく場合、最後のスクリーン(先頭のスクリーン)のリソースが解放された時に XineramaRes は自動的に解放されることになるのだが、これは最後に解放されたリソースと同じ XID で XineramaRes がハッシュ検索されるようになっているからである。
Proc 関数の書き換えの特別な場合として、ウィンドウのようなドローアブルに描き込む関数による書き換えがある。この場合、サーバは、ドローアブルの XID と、描画操作を完了させるために必要な他のリソース(例えば GC)の XID とを調べることで、それらのリソースの各スクリーンに固有のバージョンを保有している XineramaRes 構造体を探し出す。Proc 関数の書き換えにおいては、その後、正しい XID (スクリーン固有リソースの XID)を代わりに与えて、元々の Proc 関数を各スクリーンに対して呼び出すことになる。
描き込みの対象がルート・ウィンドウの場合は、さらに特殊である。論理ルート・ウィンドウの子供の座標は、論理スクリーン空間にある。物理スクリーンの位置は通常、物理スクリーン同士で相対的なものであるから、スクリーン固有のウィンドウの座標も通常は異なる値をとることになる。しかし、ルート・ウィンドウはそうではない。なぜかというと、各物理スクリーンの内部におけるルート・ウィンドウの位置は、単一の論理ルート・ウィンドウを基準とした座標となるように変更することができないからである。これは次のことを意味する。即ち、ルート・ウィンドウに対するレンダリング操作では、論理ルート・ウィンドウを基準とした場合の当該物理スクリーンのルート・ウィンドウの相対的な位置に基いて、同操作の座標を修正する必要があることを意味する。また、GC のクリップ原点やタイルとスティプルの原点のような、各ドローアブル(の原点)を基準にした他の変数も、ルート・ウィンドウに対して使用する際には適切に配慮する必要がある。加えて、ルート・ウィンドウの背景も適切にずらす必要がある。
ディスパッチ層では単一の論理スクリーン宛てのリクエストを受け取って個々のスクリーンへ同リクエストを分配するが、イベントはしばしば個々のスクリーンからやって来て(単一の)論理スクリーン向けに変換されてからクライアントへ渡される。場合によっては、こうしたイベントが XID を参照していることがある。この種のイベントが 0 番のスクリーンから来たのでない場合、その XID は、従たるスクリーン群を使うために生成された FakeClientID (クライアント用の偽物の ID)の中の1つである可能性がある。その場合、同 XID の代わりに 0 番目のスクリーンの XID をクライアントへ渡せるようにするためには、逆の探索を行って先の XID が属する XineramaRes を入手する必要がある。この難しい探索を支援するために、新たな関数が追加されている。
XineramaRes * XineramaFindIDOnAnyScreen(RESTYPE type, XID id)
この関数は、id で指定された XID が属している XineramaRes を返す。
XineramaRes * XineramaFindIDByScrnum(RESTYPE type, XID id, int screen)
この関数は、XineramaFindIDOnAnyScreen とよく似ているが、XineramaRes の info メンバの配列の「screen」番目の要素しか調べない。このルーチンは上の関数より速いので、XID がどのスクリーンから来たのかわかっている場合(スクリーンの番号がわかっている場合)、こちらを使うべきである。