TSG部報 196号・クリスマスコンパ号


XToolkit intrinsics

GANA

1. XToolkit って一体...

The UNIX Super Text (下) より
 widget という概念を導入することによって, クライアントの作成を容易にす ることを図ったライブラリです. widget とは, 押しボタンやメニューといっ たクライアントのユーザーインターフェースを構成する部品のようなものと考 えてください. XToolkit を用いる場合, この部品を組合せ, その動作を調整 することにより, クライアントを作成していきます.

 XToolkit の中にはそのまま利用できる widget は入っていません. XToolkit を用いてクライアントを作成する場合には, XToolkit とは別に Widget セッ トのライブラリをリンクする必要があります.

 X ウィンドウシステムでは標準的な widget セットライブラリとして, Athena widget セットを用意しています.

(略)
 widget はオブジェクト指向の考え方から設計されたもので, クラスという概 念と継承という概念が導入されています.  (略)  Xtoolkit を使ってクライアントを作成する場合, 必要な部品のクラスのイン スタンスを生成し, そのインスタンスを組み合わせてクライアントとしま す. ちょうど, タイヤというクラスのインスタンスであるフロントタイヤ, リ アタイヤを作り, これらを組み合わせてバイクを作ると言ったようなものです.

 だそうですが, 以下の説明では widget セットは利用しません. Athena Widget や Motif や OPEN LOOK を使うことが目的ではないのです. 又, widget のクラスを自分で作成したりもしません. 継承も考えません. これか らやろうとしていることは, 「あくまで Xlib がメイン. でも XToolkit の便 利な所だけは利用してしまえ〜」 ということなのです. よって, XToolkit の 一番基本的な部分である XToolkit intrinsics と, 基本的な 3 つの widget class しか使わないことになります.

2. よいところ

などです.

コマンドラインの自動解析は説明するまでもありませんね. 自分で解析するの は結構面倒ですから. それから, -geometry-iconic-fg-bg などなどのオプションをディフォルトで解釈して くれるようになります.

リソースの利用については, 例えば, ~/.Xresources (人によっては ~/.Xdefaults かもしれません)に次のような記述をしたとしましょう.

*Foreground: White
*Background: Red

すると, XToolkit を利用していれば, window の背景色が赤になり, 前景 色が白になります. 又, キーカスタマイズも非常に簡単に設定できるようにな ります.

イベントドリブンのプログラムが書き易くなるのは, あるイベントが起こった 時に XToolkit がそれを処理する関数を直接呼んでくれる為です. Xlib だけ を利用していたとしたら, イベントごとに switch などで自分で振り 分けなければなりません.

そうそう, XToolkit とは関係ありませんが shape window の作り方について も少しだけ説明することにします. shape window とは, oclock や, xeyes で使用されている矩形でないウィンドウのことです.

3. リソースって何だ?

widget はそれぞれの widget class に応じて色々な属性を持っています. 例 えば, button と書いてあるボタンの widget では背景色が黄色で文字 の色 (前景色) が紫で文字列が button でフォントが -*-courier-*-16* であるとか, oclock の widget は長針の色 が赤で短針の色が柿色で, 縁の色が黒であるとか, mule のフォントは -*-marumoji-*--16-*-jisx0208.1983-0 であるとかです.

これらの属性をリソースといいます. そして, そのリソースを参照するために 使用される名前をリソース名といいます. widget と同じようにリソースもそ れぞれのリソースクラスに属しています.

さて, kterm はスクロールバーを使用していなければ, 普通 2 つの widget からできています. インスタンス名 (クラス名) です.

kterm(KTerm)
  |
  +--vt100(VT100)

kterm という widget の上を vt100 という widget が覆っ ています. 例えば次のようにして, ktermvt100forground というリソースの値を青にできます.

% xrdb
kterm.vt100.foreground: Blue
^D

xrdb はリソースを X Server にロードするためのコマンドで す. ~/.Xresources なども xrdb を使ってロードされます.

kterm では文字は vt100 widget の window に表示されますの で, 文字が青くなります.

さて, XToolkit を使用していれば -name オプションでインスタンス 名が変更できます. kterm -name console を実行してみて下さい. 文 字は青くありませんね. これを青くするためには,

console.vt100.foreground: Blue

としなければなりません.

ところが, 普通はインスタンス名にこだわらず, kterm の文字の色を 一括して指定したいと思うでしょう. そういう時はクラス名を指定します.

KTerm.vt100.foreground: Blue

こうしておけば, kterm の文字の色はいつも青くなります. ただし, 次のように,

login.vt100.foreground: Red

としておいて, kterm -name login とすれば文字の色は赤となり ます. リソースを決定する時はより詳しく指定されている方が採用されるので す.

また, リソース名 foreground をクラス名 Foreground で書く こともできます.

さて, 基本的にはこれでいいのですが, リソース名, インスタンス名, クラス 名はワイルドカードにより省略ができます. 例えば,

kterm.?.foreground: Red

とか,

kterm*foreground: Red

とかです. 意味は分かりますね. さて, この時どうなるのでしょう ? 実 は kterm は vt100 端末のエミュレーション機能だけでなく, tektronix 端末のエミュレーション機能ももっています. tek4014 端末をエミュ レートしている時は,

kterm(KTerm)
  |
  +--tek4014(Tek4014)

となっています. kterm.vt100.foreground では, vt100 の方の色しか指定されていませんが, kterm.?.foregroundkterm*foreground では当然ワイルドカードに tek4014 もマッ チしてしまいますので, 線の色が赤になります.

そして, 省略が極端になると,

*Foreground: Green

などという指定もでてきます, これは, Foreground クラスに属す るリソースの値を緑にするという指定です. 例えば, oclock の短針と 長針の色はそれぞれ, oclock.clock.houroclock.clock.minute で指定されますが, どちらもクラスは Clock.Clock.Foreground なので緑色になってしまいます.

4. さて具体的には

次の xtsample.cc を利用して説明することにします. C++ プログラム ですが, C++ の機能で利用しているのは, // によるコメントと, 構造 体の前にいちいち struct を付ける必要がないこと, ローカル変数は ブロックの先頭でなくても宣言できることだけですから, C しか知らない人で も大丈夫だと思います.

実際に利用してみるとリソースの利用の仕方などが良く分かりますので, 駒場 のアカウントがある人は, ~g440604/c/xtsample/ の下の xtsample を実行してみて下さい.

とりあえす, 実行すると日の丸と右上にアメリカの国旗がでるはずです. リソー スで変な設定をしている人は, 色が変かもしれません. 大きい旗の上では [space] で旗の模様が変わり, 小さい旗の上では j, a, f で大きい旗の種類を直接していできます. q[ESC] か, Window Manager の close(fvwm), delete(twm) で正常終了 します.

つぎにリソースを書いてみます.

% xrdb
xtsample*translations: #override \n\
        <Key>q:        change()resize()redraw(ALL)\n\
        <Key>space:    quit()
xtsample*foreground:   Orange
^D

どうでしょう ? さっきとは, [space] と, q の機能が入れ替 わっていますね. 又, 日の丸の色がオレンジになっています. 同じことが,

% xtsample -fg Orange -xrm 'xtsample*translations:#override\n<Key>q:
                              change()resize()redraw(ALL)\n<Key>space:quit()'

でも指定できます.

xtsample では, widget tree は次のようになっています.

xtsample(XTsample)
  |
  +--flag(Composite)
       |
       +--miniFlag(Core)

Composite という widget class は子 widget を複数持てる widget の一番基本のものです. Core という widget class は widget の最も 基本なものです. (全ての widget は Core から派生しています)

では, ソースを見ていきましょう.

xtsample.cc

001 //
002 // Xt Sample - GANA
003 // xtsample.cc
004 //
005 
006 
007 #include <X11/IntrinsicP.h>       // ふつうはいらない
008 #include <X11/Intrinsic.h>        // X toolkit insrinsics
009 #include <X11/StringDefs.h>       // リソース名の定義
010 #include <X11/Shell.h>            // shell widget
011 #include <X11/Composite.h>        // composite widget
012 #include <X11/Core.h>             // core widget
013 #include <X11/extensions/shape.h> // shape window
014 #include <stdlib.h>
015 #include <stdio.h>
016 
017 
018 #include "icon.xbm"
019 #include "mask.xbm"

この二つはアイコンを表示するためのデータです. このソースの後ろに載して おきます.

020 
021 
022 // ディフォルトリソース
023 static String default_resources[]=
024 {
025   "XTsample.Title:       Xt Sample",
026   "XTsample.Geometry:    11x7",
030   "XTsample*BorderWidth: 0",
031   NULL,
032 };

ここでこれらのリソースが最初から設定されているために, タイトルバーに ``Xt Sample'' と表示されたり, 日の丸が赤色だったりします.

033 
034 
035 // オプションの指定
036 static XrmOptionDescRec options[]=
037 {
038   //{ "-option", "resource", Xrmoption*,      (XPointer)value },
039 {"--help",       ".help",    XrmoptionNoArg,  (XPointer)"True"},
040 {"-help",        ".help",    XrmoptionNoArg,  (XPointer)"True"},
041 {"-h",           ".help",    XrmoptionNoArg,  (XPointer)"True"},
042 {"-f",           ".flag",    XrmoptionSepArg, (XPointer)NULL},
043 {"-flag",        ".flag",    XrmoptionSepArg, (XPointer)NULL},
044 {"-blue",        ".blue",    XrmoptionSepArg, (XPointer)NULL},
045 };

ここは, コマンドラインの自動解析に関するデータを指定しています. 例えば, --help が引数に指定されると, xtsample.help のリソースが "True" に設定されます. 又, -flag 1 と指定されれば, xtsample.flag のリソースが "1" に設定されます. 3 番目の 定数 XrmOption... によって, オプションの解析方法が変わってきま す.

XrmOptionDescRec options[x]                          コマンドライン   xtsample.option に
                                                                      設定されるリソース
{"-option", ".option", XrmoptionNoArg,     "True"}   -option          "True"            
{"-option", ".option", XrmoptionIsArg,     NULL}     -option          "option"          
{"-opt",    ".option", XrmoptionStickyArg, NULL}     -option          "ion"             
{"-option", ".option", XrmoptionSepArg,    NULL}     -option this     "this"            
{"-option", ".option", XrmoptionResArg,    NULL}     -option "*a:b"   名称 a の全リソースに "b"
{"-option", ".option", XrmoptionSkipArg,   NULL}     -option skip     この 2 つを無視
{"-option", ".option", XrmoptionSkipLine,  NULL}     -option ignore   この先全てを無視

XrmOptionDescRec は以下のように定義されています.

typedef struct {
    char            *option;    /* Option abbreviation in argv        */
    char            *specifier; /* Resource specifier                 */
    XrmOptionKind   argKind;    /* Which style of option it is        */
    XPointer        value;      /* Value to provide if XrmoptionNoArg */
} XrmOptionDescRec, *XrmOptionDescList;

046 
047 
048 // shell widget のリソースの内容が読み込まれる構造体
049 static struct ShellAppData
050 {
051   Bool   help;
052   String foreground;
053   String background;
054   String blue;
055   int    flag;
056   int    base_size;
057   int    inc_size;
058 }shell_app_data;
059 
060 
061 // 前出の構造体のどのメンバにどのリソースを読み込むか
062 static XtResource shell_resources[]=
063 {
064 { "help",       "Help",       XtRBoolean, sizeof(Boolean),  
         XtOffset(ShellAppData*, help),       XtRImmediate, (XtPointer)False},
065 { "foreground", "Foreground", XtRString,  sizeof(String),   
         XtOffset(ShellAppData*, foreground), XtRString,    (XtPointer)"Red"},
066 { "background", "Background", XtRString,  sizeof(String),   
         XtOffset(ShellAppData*, background), XtRString,  (XtPointer)"White"},
067 { "blue",       "Blue",       XtRString,  sizeof(String),   
         XtOffset(ShellAppData*, blue),       XtRString,   (XtPointer)"Blue"},
068 { "flag",       "Flag",       XtRInt,     sizeof(int),      
         XtOffset(ShellAppData*, flag),       XtRImmediate, (XtPointer)0},
069 { "baseSize",   "BaseSize",   XtRInt,     sizeof(int),      
         XtOffset(ShellAppData*, base_size),  XtRImmediate, (XtPointer)200},
070 { "incSize",    "IncSize",    XtRInt,     sizeof(int),      
         XtOffset(ShellAppData*, inc_size),   XtRImmediate, (XtPointer)32},
071 };

333 行で, ShellAppData 構造体にリソースを読み込みますが, その時 どのリソースをどの変数に読み込むかを指定するものです. リソースのディフォ ルトの値は, default_resources で設定できるだけでなくここでも設 定できます.

XtResource は以下のように定義されています.

typedef struct _XtResource {
    String    resource_name;   /* Resource name                            */
    String    resource_class;  /* Resource class                           */
    String    resource_type;   /* Representation type desired              */
    Cardinal  resource_size;   /* Size in bytes of representation          */
    Cardinal  resource_offset; /* Offset from base to put resource value   */
    String    default_type;    /* representation type of specified default */
    XtPointer default_addr;    /* Address of default resource              */
} XtResource, *XtResourceList;

072 
073 static Widget shell;          // shell widget
074 static Window shell_w=0;      // shell widget の window ID

shell widget というのは, 自分の作るアプリケーションのウィンドウの中で 最も親となるべき widget です. つまり, window になった時にタイトルバー がついたりする widget です. インスタンス名は xtsample でクラス 名は Shell ではなくて, XTsample となります.

075 
076 static Widget composite;      // composite widget
077 static Window composite_w=0;  // composite widget の window ID
078 static GC     composite_gc=0; // composite widget の GC
079 
080 static Widget core;           // core widget
081 static Window core_w=0;       // core widget の window ID
082 static GC     core_gc=0;      // core widget の GC
083 
084 static Pixmap shape_pxm=0;    // shape の pixmap の ID
085 static GC     shape_gc=0;     // shape の GC
086 static int    can_use_shape=True; // shape extension は使用可能?

この shape_pxm で, ウィンドウにマスクをかけて, 矩形でないウィン ドウを作ります. 又, shape extension 機能が使えない X Server も存在しま す.

087 
088 static XtAppContext acr;      // なんでしょ?これ。
089 static Display      *d=NULL;  // display 構造体
090 
091 static Pixmap icon, mask;     // icon の絵の白黒 pixmap ID
092 static XColor fore, back, blue; // それぞれの色のパレット番号
093 static Atom   atom_wm_protocols, atom_wm_delete_window;

この Atom は, Window Manager が送ってくるメッセージのうち, WM_DELETE_WINDOW の Atom です. (ある X Server の中では, 色々な 定数や文字列が色々な用途に使用されていますが, それらを一意に識別するた めに, それらに唯一の数を与えています. Atom とは, その数のことです. )

094 
095 
096 static void get_window_size
           (const Window w, unsigned int *width, unsigned int *height)
097 {
098   Window root;
099   int x, y;
100   unsigned int border, depth;
101   XGetGeometry(d, w, &root, &x, &y, width, height, &border, &depth);
102 }
103 
104 
105 static void japan(Window w, GC gc)
106 {
107   unsigned int width, height;
108   get_window_size(w, &width, &height);
109   int r=((width

この辺りが shape extension による window のくりぬき処理で す. shell_pxm に絵を書いて, それをマスクとして window (shell_w) にセットしています. この辺は oclock のソースか らの見よう見まねなので何が行なわれているのかいまいちよく分かっていませ ん. X の man page も, ``This manual pages needs a lot more work.'' と 言ってほとんど何も書いてありません.

void XShapeCombineMask (
    Display*, /* display   */
    Window,   /* dest      */
    int,      /* dest_kind */
    int,      /* x_off     */
    int,      /* y_off     */
    Pixmap,   /* src       */
    int       /* op        */
);

215 
216 
217 static void core_redraw(void)
218 {
219   switch (shell_app_data.flag)
220   {
221   case 0:
222     america(core_w, core_gc); break;
223   case 1:
224     france (core_w, core_gc); break;
225   case 2:
226     japan  (core_w, core_gc); break;
227   }
228 }
229 
230 
231 static void change_flag
           (Widget widget, XEvent *e, String *params, Cardinal *num_params)
232 {
233   if (*num_params>0) shell_app_data.flag=atoi(params[0])%3;
234   else               shell_app_data.flag=(shell_app_data.flag+1)%3;
235   fprintf(stderr, "flag changed to %d\n", shell_app_data.flag);
236 }
237 
238 
239 static void quit
           (Widget widget, XEvent *e, String *params, Cardinal *num_params)
240 {
241   fprintf(stderr, "quit\n");
242   exit(0);
243 }
244 
245 
246 static void redraw
           (Widget widget, XEvent *e, String *params, Cardinal *num_params)
247 {
248   fprintf(stderr, "redraw\n");
249   if (*num_params>0)
250   {
251     composite_redraw();
252     core_redraw();
253   }
254   else if (widget==composite) composite_redraw();
255   else if (widget==core) core_redraw();
256   XFlush(d);
257 }
258 
259 
260 static void resize
           (Widget widget, XEvent *e, String *params, Cardinal *num_params)
261 {
262   fprintf(stderr, "resize\n");
263   shell_resize();
264 }
265 
266 
267 static void close_window
           (Widget widget, XEvent *e, String *params, Cardinal *num_params)
268      // window manager からの delete window メッセージ
269      // (fvwm なら close 、twm なら delete) を受けとった
270 {
271   if (e->type==ClientMessage &&
272       e->xclient.message_type==atom_wm_protocols &&
273       e->xclient.data.l[0]==atom_wm_delete_window)
274   {
275     fprintf(stderr, "close\n");
276     exit(0);
277   }
278 }

ここで, 93 行目の Atom を使用しています.

279 
280 
281 static XtActionsRec actions[]=
282 {
283 {"quit",   quit},
284 {"change", change_flag},
285 {"redraw", redraw},
286 {"resize", resize},
287 {"close",  close_window},
288 };

ここで, 実際の関数と, リソースで設定される関数名を対応させています.

typedef struct _XtActionsRec{
    String	 string;
    XtActionProc proc;
} XtActionsRec;

typedef void (*XtActionProc)(
    Widget,   /* widget     */
    XEvent*,  /* event      */
    String*,  /* params     */
    Cardinal* /* num_params */
);

289 
290 
291 static String shell_translation=
292 "<ClientMessage>:   close()\n"
293 "<ConfigureNotify>: resize()redraw(ALL)\n";
294 
295 
296 static String composite_translation=
297 "<Key>space:        change()resize()redraw(ALL)\n"
298 "<Key>q:            quit()\n"
299 "<Key>Escape:       quit()\n"
300 "<Expose>:          redraw()\n";
301 
302 
303 static String core_translation=
304 "<Key>j:            change(0)resize()redraw(ALL)\n"
305 "<Key>a:            change(1)resize()redraw(ALL)\n"
306 "<Key>f:            change(2)resize()redraw(ALL)\n"
307 "<Key>q:            quit()\n"
308 "<Key>Escape:       quit()\n"
309 "<Expose>:          redraw()\n";

イベントが起こった時, どの関数がどんな引数でどういう順番に呼ばれるかを 指定します.

translation に指定するもの     X Event            どういうイベントか 
BtnDown, Btn1Down, Btn2Down... ButtonPress        マウスのボタンが押された 
BtnUp, Btn1Up, Btn2Up ...      ButtonRelease      マウスのボタンが離された 
Motion, PtrMoved, MouseMoved   MotionNotify       マウスが移動した 
Enter, EnterWindow             EnterNotify        マウスがウィンドウ内に入った 
Leave, LeaveWindow             LeaveNotify        マウスがウィンドウから出た 
Key, KeyDown                   KeyPress           キーが押された 
KeyUp                          KeyRelease         キーが離された 
FocusIn                        FocusIn            フォーカスを得た 
FocusOut                       FocusOut           フォーカスを失った 
KeyMap                         KeymapNotify       全キーの状態を検知した 
Mapping                        MappingNotify      キーボードのマップ状態が変わった 
Expose                         Expose             最描画要求 
GrExp                          GraohicExpose      
NoExp                          NoExpose           
Visible                        VisibilityNotify   可視/不可視状態の変化 
Clrmap                         ColormapNotify     
Message                        ClientMessage      WM からのメッセージなど 
Prop                           PropertyNotify     
SelClr                         SelectionClear     
Select                         SelectionNotify    
Circ                           CirculateNotify    ウィンドウの重なり方の変化 
Configure                      ConfigureNotify    リサイズされた, など 
Create                         CreateNotify       ウィンドウが生成された 
Destroy                        DestroyNotify      ウィンドウが消滅した 
Map                            MapNotify          ウィンドウがマップされた 
Unmap                          UnmapNotify        ウィンドウがアンマップされた 
Grav                           GravityNotify      
Reparent                       ReparentNotify     親ウィンドウの変更 
CircReq                        CirculateRequest   
ConfigureReq                   ConfigureRequest   
MapReq                         MapRequest         マップ要求 
ResizeReq                      ResizeRequest      リサイズ要求 

表記例            意味 
        ボタン 1 を押した 
Shift   シフトを押しながらボタン 1 を押した 
Ctrl      コントロールを押しながらボタン 1 を離した 
(2)     ダブルクリック 
(2+)    ダブルクリック以上 
a            a キーを押した (大文字・小文字関係なし) 
"Try"             Try と入力した 
!CtrlA       コントロールのみを押しながら a キーを押した 
Button1a     ボタン 1 を押しながら a キーを押した 
Shifta       シフトを押しながら a キーを押した 
                  Ctrl, Shift, Lock, Meta, Alt, Mod1, Button1 などが使える 

310 
311 
312 int main(int argc, char *argv[])
313 {
314   // widgets
315   shell=XtVaAppInitialize
316     (&acr, "XTsample",
317      options, XtNumber(options),
318      &argc, argv,
319      default_resources, NULL);

まず, shell widget を作成します. クラス名を XTsample とし, イン スタンス名はコマンドラインから自動的にせっていされます (大抵, xtsample となりますが, -name オプションなどが指定されれ ば別です). argc, argv を指定することによりコマンドライン の解析が行なわれ, 解析されたコマンドライン引数は argc, argv からとりのぞかれます. 又, X Server との接続を確立し, リソー スを読み込みます. ただし, この時点では shell widget の window は作成さ れていません.

Widget XtVaAppInitialize(
    XtAppContext*,     /* app_context_return */
    _Xconst _XtString, /* application_class  */
    XrmOptionDescList, /* options            */
    Cardinal,          /* num_options        */
    int*,              /* argc_in_out        */
    String*,           /* argv_in_out        */
    String*,           /* fallback_resources */
    ...
);

320   composite=XtVaCreateManagedWidget
321     ("flag", compositeWidgetClass,
322      shell,
323      NULL);
324   core=XtVaCreateManagedWidget
325     ("miniFlag", coreWidgetClass,
326      composite,
327      XtNwidth,  40,
328      XtNheight, 30,
329      NULL);

flagminiFlag を作成します. インスタンス名は, miniFlag のように, 先頭を子文字にすることが推奨されてます.

Widget XtVaCreateManagedWidget(
    _Xconst _XtString,  /* name         */
    WidgetClass,        /* widget_class */
    Widget,             /* parent       */
    ...
);

330   
331   XtAppAddActions(acr, actions, XtNumber(actions));

ここで, 実際の関数と, リソースで設定される関数名の対応を登録しています. (281〜288 行目参照)

void XtAppAddActions(
    XtAppContext, /* app_context */
    XtActionList, /* actions     */
    Cardinal      /* num_actions */
);

332   d=XtDisplay(shell);
333   XtGetApplicationResources
334     (shell,
335      XtPointer(&shell_app_data),
336      shell_resources, XtNumber(shell_resources),
337      NULL, 0);

ここで, 61〜71 行で設定した情報に基づいてリソースの値を app_data 構造体に代入しています.

void XtGetApplicationResources(
    Widget,         /* widget        */
    XtPointer,      /* base          */
    XtResourceList, /* resources     */
    Cardinal,       /* num_resources */
    ArgList,        /* args          */
    Cardinal        /* num_args      */
);

338   if (shell_app_data.help || argc>1)
339   {
340     fprintf(stderr,
341             "usage: xtsample [options ...]\n"
342             "       -h, -help, -flag <n>, -blue <color>, ...\n");
343     return 1;
344   }
345   
346   // translations
347   XtAugmentTranslations(shell,     
                             XtParseTranslationTable(shell_translation));
348   XtAugmentTranslations(composite, 
                             XtParseTranslationTable(composite_translation));
349   XtAugmentTranslations(core,      
                             XtParseTranslationTable(core_translation));

291〜309 行目で設定したディフォルトの translation を登録します. ただし, 同じ translation が既に設定されていたら, それは登録しま せん.

void XtAugmentTranslations(
    Widget,        /*  widget      */
    XtTranslations /* translations */
);

350   
351   // shape
352   int shape_event_base, shape_error_datas;
353   can_use_shape=XShapeQueryExtension(d, &shape_event_base, 
                                                     &shape_error_datas);

shape extension が使用可能かどうかの問い合わせをします.

Bool XShapeQueryExtension (
    Display*, /* display    */
    int*,     /* event_base */
    int*      /* error_base */
);

354   
355   // icon
356   icon=XCreateBitmapFromData(d, RootWindow(d, 0), 
                                (char *)icon_bits, icon_width, icon_height);
357   mask=XCreateBitmapFromData(d, RootWindow(d, 0), 
                                (char *)mask_bits, mask_width, mask_height);
358   XtVaSetValues(shell, XtNiconPixmap, icon, XtNiconMask, mask, NULL);

shell widget のリソースとしてアイコンを登録します. このリソースは Window Manager によってアイコンとして利用されます.

void XtVaSetValues(
    Widget, /* widget */
    ...
);

359   
360   // color
361   XColor dummy;
362   XAllocNamedColor(d, DefaultColormap(d, 0), 
                                 shell_app_data.foreground, &fore, &dummy);
363   XAllocNamedColor(d, DefaultColormap(d, 0), 
                                 shell_app_data.background, &back, &dummy);
364   XAllocNamedColor(d, DefaultColormap(d, 0), 
                                 shell_app_data.blue,       &blue, &dummy);

リソースで指定された色の名前から, その色のパレット番号と, rgb の値を取 得します.

365   
366   // resources
367   XtVaSetValues
368     (shell,
369      // XtNwidth,     0,
370      // XtNheight,    0,
371      // XtNmaxWidth,  0,
372      // XtNmaxHeight, 0,
373      // XtNminWidth,  0,
374      // XtNminHeight, 0,
375      XtNbaseWidth,    shell_app_data.base_size,
376      XtNbaseHeight,   shell_app_data.base_size,
377      XtNwidthInc,     shell_app_data.inc_size,
378      XtNheightInc,    shell_app_data.inc_size,
379      XtNinput,        True,
380      NULL);

shell widget にさらに大きさなどのリソースを設定します. まず, base サイ ズは, これ以上ちじまない大きさで, inc サイズ単位で大きくなることができ ます. kterm のようなサイズの変更が可能になると考えて下さい.

コメントアウトされている, max と min を指定すればウィンドウの最大と最 小の大きさが指定できます. base, inc との併用はできないようです.

XtNwidthXtNheight はウィンドウが生成された時の大きさ ですが, これは, 26 行目で既に設定してあるのでここでは設定しません.

XtNinput はマウスがウィンドウ内に入った時フォーカスを渡すように Window Manager に指示しています. こうしておかないと, Window Manager は フォーカスを渡してくれません.

381   XtRealizeWidget(shell);

ここでやっと 3 つの widget の window が実際に生成されます.

void XtRealizeWidget(
    Widget /* widget */
);

382   
383   shell_w     =XtWindow(shell);
384   composite_w =XtWindow(composite);
385   composite_gc=XCreateGC(d, composite_w, 0, 0);
386   core_w      =XtWindow(core);
387   core_gc     =XCreateGC(d, core_w, 0, 0);
388   
389   // close
390   atom_wm_protocols    =XInternAtom(d, "WM_PROTOCOLS",     False);
391   atom_wm_delete_window=XInternAtom(d, "WM_DELETE_WINDOW", False);
392   XSetWMProtocols(d, shell_w, &atom_wm_delete_window, 1);

Window Manager に, WM_DELETE_WINDOW メッセージを送るように指示 しています. (93, 267〜278 行目参照)

393   
394   XtAppMainLoop(acr);

イベント待ちループに入ります. この関数は制御を返しません. だから, 395 行目に到達することは決してないのです.

395 }

次の icon.xbmmask.xbmbitmap で生成しまし た. xv などでも生成可能です.

icon.xbm

001 #define icon_width 49
002 #define icon_height 25
003 static unsigned char icon_bits[] = {
004    0x00, 0x7c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x0a, 0x0f,
005    0x00, 0x00, 0x00, 0x10, 0x01, 0x85, 0x08, 0x00, 0x00, 0x00, 0x20, 0x82,
006    0xe2, 0x38, 0x00, 0x00, 0x00, 0x40, 0x44, 0x21, 0x20, 0x00, 0x00, 0x00,
007    0x80, 0xa8, 0xe0, 0x38, 0x00, 0x00, 0x00, 0x00, 0x55, 0x80, 0x08, 0x00,
008    0x00, 0x00, 0x80, 0x8a, 0x80, 0x08, 0x00, 0x00, 0x00, 0x40, 0x11, 0x81,
009    0x08, 0x00, 0x00, 0x00, 0xa0, 0x20, 0x82, 0x08, 0x00, 0x00, 0x00, 0x50,
010    0x40, 0x84, 0x30, 0x00, 0x00, 0x00, 0x28, 0x80, 0x08, 0x21, 0x00, 0x00,
011    0x00, 0x1c, 0x00, 0x1f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
012    0x00, 0x00, 0x7e, 0x3e, 0xee, 0xfc, 0x3c, 0xfc, 0x01, 0x41, 0x41, 0x11,
013    0x05, 0x25, 0x04, 0x01, 0x79, 0x49, 0x11, 0x25, 0x25, 0xe4, 0x01, 0x09,
014    0x49, 0x11, 0x25, 0x25, 0x24, 0x00, 0x39, 0x49, 0x11, 0x25, 0x25, 0xe4,
015    0x00, 0x41, 0x41, 0x01, 0x05, 0x25, 0x84, 0x00, 0x4e, 0x49, 0x29, 0xe5,
016    0x24, 0xe4, 0x00, 0x48, 0x49, 0x29, 0x25, 0x24, 0x24, 0x00, 0x4f, 0x49,
017    0x29, 0x25, 0xe4, 0xe5, 0x01, 0x41, 0x49, 0x29, 0x25, 0x04, 0x05, 0x01,
018    0x3f, 0x7f, 0xff, 0x3d, 0xfc, 0xfd, 0x01};

mask.xbm

001 #define mask_width 49
002 #define mask_height 25
003 static unsigned char mask_bits[] = {
004    0x00, 0x7c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x0e, 0x0f,
005    0x00, 0x00, 0x00, 0xf0, 0x01, 0x87, 0x0f, 0x00, 0x00, 0x00, 0xe0, 0x83,
006    0xe3, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xc7, 0xe1, 0x3f, 0x00, 0x00, 0x00,
007    0x80, 0xef, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x0f, 0x00,
008    0x00, 0x00, 0x80, 0xfb, 0x80, 0x0f, 0x00, 0x00, 0x00, 0xc0, 0xf1, 0x81,
009    0x0f, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0x83, 0x0f, 0x00, 0x00, 0x00, 0x70,
010    0xc0, 0x87, 0x3f, 0x00, 0x00, 0x00, 0x38, 0x80, 0x0f, 0x3f, 0x00, 0x00,
011    0x00, 0x1c, 0x00, 0x1f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
012    0x00, 0x00, 0x7e, 0x3e, 0xee, 0xfc, 0x3c, 0xfc, 0x01, 0x7f, 0x7f, 0xff,
013    0xfd, 0x3d, 0xfc, 0x01, 0x7f, 0x7f, 0xff, 0xfd, 0x3d, 0xfc, 0x01, 0x0f,
014    0x7f, 0xff, 0xfd, 0x3d, 0x3c, 0x00, 0x3f, 0x7f, 0xff, 0xfd, 0x3d, 0xfc,
015    0x00, 0x7f, 0x7f, 0xff, 0xfd, 0x3d, 0xfc, 0x00, 0x7e, 0x7f, 0xff, 0xfd,
016    0x3c, 0xfc, 0x00, 0x78, 0x7f, 0xff, 0x3d, 0x3c, 0x3c, 0x00, 0x7f, 0x7f,
017    0xff, 0x3d, 0xfc, 0xfd, 0x01, 0x7f, 0x7f, 0xff, 0x3d, 0xfc, 0xfd, 0x01,
018    0x3f, 0x7f, 0xff, 0x3d, 0xfc, 0xfd, 0x01};

さて, プログラムを作ったならば, 次はコンパイルです. しかし, X のライブ ラリは ld (リンカ) のサーチパスから外れていたり, socket のライ ブラリを要求したりと, 機種によって様々でいろいろ面倒です. そこで, うま くコンパイルできるように Imakefile というものを使います.

Imakefile

001 LOCAL_LIBRARIES	= $(XLIB) $(XTOOLLIB)
002 DEPLIBS		= $(DEPXLIB) $(DEPXTOOLLIB)
003 OBJS		= xtsample.o
004 SRCS		= xtsample.cc
005 
006 ComplexProgramTarget(xtsample)

これを作ってから

% xmkmf
% make depend
% make

とします (このプログラムの場合は depend の必要はありませんが). す ると, xmkmf により, 適当なライブラリがリンクされるような Makefile が生成され, make によりコンパイル, リンクされま す.

ふぅ. 結構しんどいですね.

5. XToolkit を使いたくなったでしょう?

なんかすごく面倒そうに見えますが, Xlib だけで作った時よりはソフトウェ アの使い勝手がかなり良くなると思います. Xlib しか使ったことのない人は ぜひ XToolkit を使ってみましょう.

でわ〜


[戻る]

g541119@komaba.ecc.u-tokyo.ac.jp