|  | 
○ はじめに
グラフィックスの描画において、グラフィックスコンテキスト( GC )は非常に重要です。GC とは、グラフィックスを描画するための情報(描画属性)を格納しておくためのものです( Windows GDI でのペンとブラシと同じで、これを指定しないと描画できません)。GC も X サーバのリソースとして管理されています。
Xlib を用いて描画する時は、まず X サーバ内のリソースとして GC を確保し、描画に必要な描画属性を GC に設定します。そして描画する時に、使いたい GC のリソース ID を指定して描画します。同じ描画属性を複数回使用するような場合は、その属性が設定されている GC のリソース ID のみを X サーバに指定すれば良いのでネットワーク伝送の効率が良いという利点があります。
ここでは
という順で説明していきます。
○ GC の生成と解放
GC の実体は XGCValues 構造体(<X11/Xlib.h>)として定義されています。
/* XGCValues 構造体 */
typedef struct
{
  int           function;           /* 表示関数 */
  unsigned long plane_mask;         /* プレーンマスク */
  unsigned long foreground;         /* フォアグラウンドカラー */
  unsigned long background;         /* バックグラウンドカラー */
  int           line_width;         /* 線幅 */
  int           line_style;         /* 線の形状 */
  int           cap_style;          /* 線の端点形状 */
  int           join_style;         /* 線の結合形状 */
  int           fill_style;         /* 塗りつぶしスタイル */
  int           fill_rule;          /* 塗りつぶし規則 */
  int           arc_mode;           /* 円弧の塗りつぶしモード */
  Pixmap        tile;               /* タイル用のピクスマップ */
  Pixmap        stipple;            /* スティップル用ビットマップ */
  int           ts_x_origin;        /* スティップルやタイルの原点 */
  int           ts_y_origin; 
  Font          font;               /* フォント */
  int           subwindow_mode;     /* 子ウィンドウへの描画モード */
  Bool          graphics_exposures; /* GraphicsExposeイベント用イベントマスク */
  int           clip_x_origin;      /* クリッピングの原点 */
  int           clip_y_origin; 
  Pixmap        clip_mask;          /* クリップマスク */
  int           dash_offset;        /* 破線の開始オフセット */
  char          dashes;             /* 破線のパターン */
} XGCValues;
(*)Bool型は <X11/Xlib.h> で次のように定義されています。
#define Bool   int
#define True   1
#define False  0
GC を生成するには XCreateGC()を使います。
GC XCreateGC( Display* display, Drawable d, unsigned long valuemask, XGCValues* values );
valuemask : GC のメンバのうち、設定、コピー、変更されるもの、
            あるいは値が返されるものをビットマスクで指定。
values    : valuemaskで指定したメンバの値を指定
この関数は valuemask、values で指定した属性値を持つ GC を新しく一つ生成します。valuemask に0、values に NULL を指定するとデフォルトの属性値を持つ GC が生成されます。各メンバに対応するデフォルトの属性値およびマスクは下表のようになっています。
| メンバ | デフォルト値 | マスク | 
|---|---|---|
| function | GXcopy | GCFunction | 
| plane_mask | 全プレーン(~0) | GCPlaneMask | 
| foreground | 0 | GCForeground | 
| background | 1 | GCBackground | 
| line_width | 0 | GCLineWidth | 
| line_style | LineSolid | GCLineStyle | 
| cap_style | CapButt | GCCapStyle | 
| join_style | JoinMiter | GCJoinStyle | 
| fill_style | FillSolid | GCFillStyle | 
| fill_rule | EvenOddRule | GCFillRule | 
| arc_mode | ArcPieSlice | GCArcMode | 
| tile | フォアグラウンドのピクセル値を持つピクスマップ | GCTile | 
| stipple | 全ビットが1のビットマップ | GCStipple | 
| ts_x_origin | 0 | GCTileStipXOrigin | 
| ts_y_origin | 0 | GCTileStipYOrigin | 
| font | fixed(サーバ依存) | GCFont | 
| subwindow_mode | ClipByChildren | GCSubwindowMode | 
| graphics_exposures | True | GCGraphicsExposures | 
| clip_x_origin | 0 | GCClipXOrigin | 
| clip_y_origin | 0 | GCClipYOrigin | 
| clip_mask | None | GCClipMask | 
| dash_offset | 0 | GCDashOffset | 
| dashes | 4(リスト[4, 4]) | GCDashList | 
必要なくなった GC を解放するためには XFreeGC() を使います。
XFreeGC( Display* dpy, GC gc );
○ GC のコピーと属性の変更
ある GC の内容を別の GC にコピーする場合は XCopyGC() を使います。
XCopyGC( Display* display, GC src, unsigned long valuemask, GC dest ); src, : コピー元 GC valuemask : コピーする属性を指定するマスク dest : コピー先 GC
この関数は src から dest に属性をコピーします。コピーしたい属性に対応するマスクを valuemask に設定しておきます。また、src と dest はあらかじめ作成しておかなければなりません(さらにはルートウィンドウと深さが同じでなければいけません)。
既に GC に設定されている属性値を変更する場合には XChangeGC() を使います。
XChangeGC( Display* display, GC gc, unsigned long valuemask, XGCValues* values ); valuemask : 変更する属性を指定するマスク values : 変更する属性の値を指定
valuemask で指定した GC の属性値が values の値に設定され、それ以外は変更されません。
○ GC に設定される描画属性
XGCValues 構造体のメンバを GC の描画属性として設定できます。各属性は、既に説明したように GC の生成時に設定できますが、各属性設定用の Xlib 関数を用いて設定することも可能です。ここでは GC の描画属性のうち
- 表示関数(function)
- 色(foreground, background)
- 線の属性
- 破線の属性
- 塗りつぶし/タイル/スティップル
- 塗りつぶしの規則/モード
- フォント(font)
- 子ウィンドウへの描画モード(subwindow_mode)
- GraphicsExpose/NoExpose イベント生成設定(graphics_exposures)
について説明します。ここで説明していないメンバのうち、clip_ で始まるメンバに関してはクリッピングという重要な概念があります。クリッピングは、描画量を抑えたり、透過色を持つ画像を扱う際に必須の内容で、LECTURE 7 Expose イベント にてあらためて説明します。その他について興味がある方は、Xlib のマニュアルなどのより詳細な文献を参照してください。
● 表示関数(function)
描画は、描画対象( dst )およびそこに描画するもの( src )の双方の対応するピクセル同士に論理演算を施すことで描画を行います。この描画時に施される論理演算として、X ウィンドウシステムでは 16 種類の演算が定義されています(下表参照)。デフォルトの表示関数は GXcopy です。
| 表示関数 | 論理演算 | 演算結果(src=0011、dst=0101) | 
|---|---|---|
| GXClear | 0 | 0000 | 
| GCand | src AND dst | 0001 | 
| GXandReverse | src AND (NOT dst) | 0010 | 
| GXcopy | src | 0011 | 
| GXandInverted | (NOT src) AND dst | 0100 | 
| GXnoop | dst | 0101 | 
| GXxor | src XOR dst | 0110 | 
| GXor | src OR dst | 0111 | 
| GXnor | (NOT src) AND (NOT dst) | 1000 | 
| GXequiv | (NOT src) XOR dst | 1001 | 
| GXinvert | NOT dst | 1010 | 
| GXorReverse | src OR (NOT dst) | 1011 | 
| GXcopyInverted | NOT src | 1100 | 
| GXorInverted | (NOT src) OR dst | 1101 | 
| GXnand | (NOT src) OR (NOT dst) | 1110 | 
| GXset | 1 | 1111 | 
排他的論理和( GXxor )はラバーバンドを描画するときに良く使用されます。表示関数に GXxor を設定した GC を用いて一度描画し、その上から同じ GC を用いてもう一度同じものを描画すると前に描画したものが消去されて元通りの画像が得られます。
表示関数の設定は、XCreateGC 時に function メンバを設定した XGCValues 構造体を用いる他に、 XSetFunction()を使って設定することが出来ます。
XSetFunction( Display* display, GC gc, int function ); function : 表示関数( GXcopy、GXxor、...)を指定する。
● 色(foreground, background)
描画時に使用するフォアグラウンドカラーおよびバックグラウンドカラーをピクセル値で指定します。XCreateGC 時に foreground/background メンバを設定した XGCValues 構造体を用いる他に、XSetForeground()、XSetBackground() を使って設定することが出来ます。
XSetForeground( Display* display, GC gc, unsigned long foreground ); foreground : フォアグラウンドカラーのピクセル値 XSetBackground( Display* display, GC gc, unsigned long background ); background : バックグラウンドカラーのピクセル値
● 線の属性
- 線幅 ( line_width )
  線の幅をピクセル数で指定します。 
- 線の形状 ( line_style )
  線の形状(実線/破線)を指定します。次のうちいずれかを指定します。 定数名 説明 LineSolid GC のフォアグラウンドカラーで実線を描画(デフォルト) LineOnOffDash GC のフォアグラウンドカラーで破線を描画(破線がオフの部分は描かれない) LineDoubleDash GC のフォアグラウンドカラーで破線を描画 (破線がオフの部分は GC のバックグラウンドカラー 
 
- 線の端点形状 ( cap_style )
  線の端点の形状を指定します。次のうちいずれかを指定します。 定数名 説明 CapNotLast 線幅が0および1の場合には終端のピクセルを描画しない以外は CapButt と同じ CapButt 終端が平らで突起がない。線端は垂直 CapRound 終端の中央を中心にした線幅の直径の半円 CapProjecting 線幅の半分だけ終端をはみ出す 
 
- 線の結合形状 ( join_style )
  2つの線の結合形状を指定します。次のうちいずれかを指定します。 定数名 説明 JoinMiter 2本の直線の外側のエッジが交わるまで伸ばす(デフォルト) JoinRound 接合点を中心にした線幅の直径の円弧 JoinBevel 終端は CapButt で、できた三角形の隙間を埋める 
以上の描画属性を GC に設定するには、XCreateGC において line_width/line_style/cap_style/join_style メンバを設定した XGCValues 構造体を用いる他に、XSetLineAttributes()を使って設定することが出来ます。
XSetLineAttributes( Display*     display, 
                    GC           gc, 
                    unsigned int line_width, 
                    int          line_style, 
                    int          cap_style,  
                    int          join_style 
                  );
line_width : 線幅 
line_style : 線のスタイル
cap_style  : 線の端点形状
join_style : 線の結合形状
● 破線の属性
破線の属性は、そのパターンと開始オフセットで指定します。
- 破線のパターン(dashes)
  破線とギャップの長さをピクセル単位で指定 
- 破線の開始オフセット(dash_offset)
  破線パターンの開始点までのオフセットをピクセル数で指定 
以上の属性は、XCreateGC 時に dashes/dash_offset メンバを設定した XGCValues 構造体を用いる他に、XSetDashes() を使って設定することが出来ます。
XSetDashes( Display* display, GC gc, int dash_offset, char dash_list[], int n ); dash_offset : 破線の開始オフセット n : dash_list の長さ dash_list[] : 破線のグラフィックスパターン
dash_list には、破線とギャップの長さをピクセル値で表した上で、破線とギャップのパターンを列挙したものを設定します。たとえば 3 ピクセルの線、2 ピクセルのギャップ、4 ピクセルの線、1 ピクセルのギャップ、以降はそのパターンの繰り返しという破線を設定するなら
char dash_list[] = { 3, 2, 4, 1 };
と設定します。dash_offset にはこのパターンの中の何ピクセル目から線を引き始めるかを設定します。
● 塗りつぶし/タイル/スティップル
塗りつぶしの方法には、FillSolid、FillTiled、FillStippled、そして FillOpaqueStippled の 4 種類があります。それぞれの内容は下表の通りです。
| 定数名 | 説明 | 
|---|---|
| FillSolid | GC のフォアグラウンドカラーで塗りつぶす(デフォルト) | 
| FillTiled | GC の tile で指定したピクスマップを敷きつめる(タイリング) | 
| FillStippled | GC の stipple で指定したビットマップでマスクした領域を GC のフォアグラウンドカラーで塗りつぶす(スティップル) | 
| FillOpaqueStippled | GC の stipple で指定したビットマップのビットが設定されている部分は GC のフォアグラウンドカラーで、ビットが設定されていない部分は GC のバックグラウンドカラーで塗りつぶす | 
上の塗りつぶしの方法を設定するには、XCreateGC 時に fill_style メンバを設定した XGCValues 構造体を用いる他に、XSetFillStyle() を使って設定することが出来ます。
XSetFillStyle( Display* display, GC gc, int fill_style ); fill_style : 塗りつぶしのスタイル
タイリングに使用するピクスマップ、およびスティップルに使用するビットマップはそれぞれ、XCreateGC 時に tile/stipple メンバを設定した XGCValues 構造体を用いる他に、XSetTile() および XSetStipple() を使って設定することが出来ます。
XSetTile( Display* display, GC gc, Pixmap tile ); tile : タイリング用ピクスマップID XSetStipple( Display* display, GC gc, Pixmap stipple ); stipple : スティップル用ビットマップのID
● 塗りつぶしの規則/モード
- 塗りつぶしの規則( fill_rule )
   ポリゴンを塗りつぶす場合の、塗りつぶし規則を指定します。次の2つが指定できます。 定数名 説明 WindingRule 重なっている領域はすべて塗りつぶす EvenOddRule 奇数回重なっている領域は塗りつぶさない 塗りつぶしの規則の指定には、XCreateGC 時に fill_rule メンバを設定した XGCValues 構造体を用いる他に、XSetFillRule() を使って設定することが出来ます。 XSetFillRule( Display* display, GC gc, int fill_rule ); fill_rule : WindingRule か EvenOddRuleを指定 
 
- 円弧の塗りつぶしモード( arc_mode )
   円弧を塗りつぶす場合の塗りつぶしモードを指定します。次の2つが指定可能です。 定数名 説明 ArcPieSlice 円弧の端点と円弧の中心を結んで閉じた領域を塗りつぶす ArcChord 円弧の端点同士を結んで閉じた領域を塗りつぶす 円弧の塗りつぶしモードの設定には、XCreateGC 時に arc_mode メンバを設定した XGCValues 構造体を用いる他に、XSetArcMode() を使って設定することが出来ます。 XSetArcMode( Display* dpy, GC gc, int arc_mode ); arc_mode : ArcPieSlice か ArcChordを指定 
● フォント(font)
文字列を描画する際に用いるフォントを指定します。フォントの設定は、XCreateGC 時に font メンバを設定した XGCValues 構造体を用いる他に、XSetFont() を使って設定することが出来ます。
XSetFont( Display* display, GC gc, Font font ); font : フォントID
ところで当たり前のことですが、フォントを設定する前にフォントをロードしなければなりません。フォントをロードするには XLoadQueryFont() を使います。
XFontStruct* XLoadQueryFont( Display* display, char* fontname ); fontname : フォント名 ( "-*-fixed-medium-r-normal--16-*-*-*" の様な形式 )
指定したフォントが見付からなかった場合、XLoadQueryFont() は NULL を返します。フォントが見付かった場合は、XFontStruct 構造体へのポインタが返って来ますが、XSetFont() に指定するフォント ID には XFontStruct のメンバである fid を指定します。
ところでこれらは半角英数字などの 1 バイト文字描画用の関数であり、日本語のようなマルチバイト文字の描画については以降の LECTURE で別途説明します。
● 子ウィンドウへの描画モード(subwindow_mode)
親ウィンドウ上の子ウィンドウ領域に対しても描画を行うかどうかを指定します。
| 定数名 | 説明 | 
|---|---|
| ClipByChildren | 子ウィンドウ領域には描画しない(デフォルト) | 
| IncludeInferiors | 子ウィンドウ領域に描画する | 
子ウィンドウへの描画モードの設定には、XCreateGC 時に subwindow_mode メンバを設定した XGCValues 構造体を用いる他に、XSetSubwindowMode() を使って設定することが出来ます。
XSetSubwindowMode( Display* display, GC gc, int subwindow_mode ); subwindow_mode : ClipByChildren かIncludeInferiors を指定
● GraphicsExpose/NoExpose イベント生成設定(graphics_exposures)
GC に対して明示的に指定しない限り、XCopyPlane/XCopyArea 実行時に GraphicsExpose/NoExpose イベントがクライアントに対して送られて来ます ( XSelectInput によるマスクの有無関係なしに )。これらのイベントを送らないでもらう様にするには、XCreateGC 時に graphis-exposures メンバを False に設定した XGCValues 構造体を用いて生成します ( 今の所、それ以外の方法が分かりません )。