タブをつくる
タブと聞くとあなたは、「4文字スペース空けるやつ」と、「GUIのウィンドウを構成するパーツで、FireFoxとかのタブブラウザみたいなもの」のどちらをイメージしますか?
私はどちらかというと「スペース空けるやつ」をイメージする側ですが、今日は、GUI側のお話です。
X WindowでGUIを構成するときに利用されるOpenMotifでもタブを使うことができます。
-----
$ man XmTabStack
XmTabStack(3X) XmTabStack(3X)
NAME
XmTabStack - The TabStack widget class
SYNOPSIS
#include <Xm/TabStack.h>
DESCRIPTION
The XmTabStack widget manages a group of widgets such that only one
widget in the group is visible at a time. Each child is associated
with a "tab" that displays a text label and/or a pixmap. By selecting
the "tab" the user interactively determines which child is displayed.
This widget exhibits behavior similar to the Microsoft Windows(TM) Tab
Control.
....
-----
といった形で説明があります。
普通の開発者の立場だと、このウィジェットを利用して、いろいろなGUIのコンポーネントを作成すると思います。
ですが、今日はちょっと視点を変えて、このタブがOpenMotifの中でどのように作られているのか見てみたいと思います。
タブを使うと、このようなGUIのウィンドウを作ることができます。
タブの表示に関わっているのは、OpenMotifのlib/Xm/TabStack.c、TabBox.cのあたりのソースです。
TabStack.cは、タブのパーツのうち、下半分の表示を担っています。
そして、今日のメインは、TabBox.cで、このソースが、タブの切り替えに使う上半分のタブの部分の処理を行っています。
X Windowでは、隠されていたウィンドウが前面に出されて表示されるとき、Exposeというイベントが発生します。
TabBox.cでは、それぞれのイベントが発生したときに呼び出される関数が定義されていますが、そのうちexposeイベントには、"Redisplay()"という関数が定義されています。
------
/* destroy */ NULL,
/* resize */ NULL,
/* expose */ Redisplay,
/* set_values */ NULL,
/* set values hook */ NULL,
-------
つまり、ウィンドウの再描画は、このRedisplay()で行われているということが分かりますので、Redisplay()を見ていくことにします。
で、早速、Redisplay()の動作をおおざっぱに書くと、
------
Redisplay()
-> Redisplaytabs()
-> DrawTab()
------
となっていることが分かります。
RedisplayTabs()の中を見てみると、次のようになっています。
-----
geom = XmTabBox__actual(tab);
for( i = 0; i < count; ++i )
{
if( XiRectInRegion(region, geom[i].x, geom[i].y, geom[i].width,
geom[i].height) )
{
info = _XmTabbedStackListGet(XmTabBox_tab_list(tab), i);
DrawTab(tab, info, &(geom[i]),
(Boolean)(XmTabBox__selected(tab) == i),
(Boolean)(XmTabBox__keyboard(tab) == i));
}
}
-----
countには、タブが何個あるか入っています。つまりfor文で、タブの数だけループをまわして、それぞれのタブに対して、DrawTab()を呼び出しているのです。
ただし注意点として、DrawTab()を呼び出す前に、XiRectInRegion()で、そのタブが、再描画の必要な領域にあるかどうか確認しています。
なので、もともと他のウィンドウに隠されていなかったタブに関しては、改めて再描画はされないということです。
次回は、実際のDrawTab()の処理を見てみたいと思います。


コメント