ここではOSF/Motifを利用したXアプリケーション開発に関連する話題を集めています。
特に目次を設けずに随時追加していくつもりなので、 キリがつくまで読みにくいと思いますが了承下さい。
2001年1月現在、私の元で簡単に確認できる環境であるがゆえに 原則としてFreeBSD4.x向けに記述していますが、 環境依存な記述はなるべく少なくなるように注意を払いながら書いていくつもりです。
文書中でシェルからの操作の記述が含まれることがあります。 ここではbashを想定した記述になっています。 csh系のシェルを利用されている方は適宜置き換えてご利用下さい。
想定するMotifのライブラリのバージョンはopen Motifとして公開された 2.1.30です。 実際、私も自分でコンパイルしてopen Motifを利用しています。
ここででは読者が次の技術を持っていることを想定した書き方をしています。
皆さんご存知のとおり、UNIX版 Netscape NavigatorはMotif アプリケーションの代表作です。 もっとも最近のNavigatorは独自拡張のウィジェットを使いまくりなので、 Navigatorで実現されていることがすべて説明できるわけではありません。
CDE(Common Desktop Environment)を使ったことがない人でも 内容が把握できるようにしたいと思います。
標準設定では /usr/dt 以下にMotif関係のファイルが格納されているみたいですが、 複数のバージョンが格納されていることもあるので (もしかしたら互換ライブラリLesstifが入っているかも)、 どれでコンパイル/リンクされるのか きちんと把握しておくのは重要です。
例: $ locate libXm. /usr/dt/lib/libXm.a /usr/dt/lib/libXm.so /usr/dt/lib/libXm.so.2.1
当然ながら標準Xライブラリの場所も把握しておく必要があります。
☆
Motif関係のコンパイル済ライブラリとしては次のものがあります。
きちんと分類されているとはいえ、多いですね。
コンパイラ ドライバに与える順は
-lUil -lMrm -lXm -lXmu -lXt -lXp -lxpg4 -lXext -lX11 -lICE -lSMといったところでしょうか。
uilの解釈を内蔵させるアプリケーションはほとんどないと思うので、 一般には libUilが利用されることはないでしょう。
libxpg4はFreeBSD4.x以前の標準配布のライブラリで必要だったもので、 これを含めないと ロケール処理の関係でうまく日本語を扱えないことが知られています。
当面の慣れないうちは、盲目的にライブラリの指定をしてもよいでしょうけど、 頃合いを見て どのライブラリにどういうAPI(関数)が含まれているか確認しておくのも重要だと思います。 ライブラリのソースを直接 当たってもよいですが、nm(1)などを利用するのも手です。
例: $ for i in /usr/X11R6/lib/lib*.so /usr/dt/lib/lib*.so; \ do echo $i ; nm $i |grep " T "; done |more
Makefileにてライブラリ等のパスを指定してもよいのですが、 gccが利用できるFreeBSDでは、環境変数でこれを指示することもできます。 Makefileの記述が簡単になるので、私はこちらの方法をお勧めしたいと思います。
$HOME/.profile 等 シェルのスタートアップ スクリプトで設定しておくとよいでしょう。
例: XROOT=/usr/X11R6 DTROOT=/usr/dt C_INCLUDE_PATH=$XROOT/include:$DTROOT/include:/usr/local/include LIBRARY_PATH=$XROOT/lib:$DTROOT/lib:/usr/local/lib export C_INCLUDE_PATH LIBRARY_PATH
環境の確認ができたら、実際に簡単なプログラムをコンパイルしてみるとよいでしょう。
短いMotifプログラムを用意してみました。
#include <Xm/Text.h> #include <X11/Shell.h> main(int argc,char **argv) { XtAppContext app_context; /* 言語関係の初期化 */ XtSetLanguageProc(NULL,NULL,NULL); { /* 初期リソースの定義 */ static char *fallback_resources[] = { "*text_buffer.width: 300", "*text_buffer.height: 200", "*text_buffer.value: Welcome to Motif world!", "*fontList: k14;rk14:", NULL, }; /* トップレベルウィンドウの生成 */ Widget top_level_shell = XtVaOpenApplication(&app_context,"TextEditor",0,0,&argc,argv, fallback_resources,sessionShellWidgetClass,NULL); /* テキスト編集ウィジェット(複数行対応版)の生成 */ XtVaCreateManagedWidget("text_buffer",xmTextWidgetClass,top_level_shell, XmNeditMode, XmMULTI_LINE_EDIT, NULL); /* Xサーバ側のリソースの生成 */ XtRealizeWidget(top_level_shell); } /* イベント処理ループ */ XtAppMainLoop(app_context); }
ここではプログラムの意味は述べません。 とりあえずコメントから雰囲気でも掴んで下さい。
次に示すのは実際のコンパイルの様子です。
うまくコンパイルできたなら、ぜひ動かしてみて下さい。
ldd(1)を使って具体的にどのようなライブラリがリンクされているか確認してみるのもよいでしょう。
$ cat Makefile CFLAGS = -g -DNeedFunctionPrototypes=1 -DNeedWidePrototypes=0 \ $(XINCDIR) $(MOTIFINCDIR) XLIB = -lxpg4 -lXext -lX11 LIBXT = $(XLIBDIR) -lXmu -lXt -lXp $(XLIB) -lICE -lSM MOTIF = $(MOTIFLIBDIR) -lMrm -lXm welcome: welcome.o $(LINK.c) -o $@ welcome.o $(MOTIF) $(LIBXT) $(LDLIBS) $ make cc -g -DNeedFunctionPrototypes=1 -DNeedWidePrototypes=0 -c -o welcome.o welcome.c cc -g -DNeedFunctionPrototypes=1 -DNeedWidePrototypes=0 -o welcome welcome.o -lMrm -lXm -lXmu -lXt -lXp -lxpg4 -lXext -lX11 -lICE -lSM $ ./welcome & [1] 49602 $ ldd welcome welcome: libMrm.so => /usr/dt/lib/libMrm.so (0x28064000) libXm.so => /usr/dt/lib/libXm.so (0x28082000) libXmu.so.6 => /usr/X11R6/lib/libXmu.so.6 (0x2821d000) libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x2822e000) libXp.so.6 => /usr/X11R6/lib/libXp.so.6 (0x28271000) libxpg4.so.2 => /usr/lib/libxpg4.so.2 (0x28278000) libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x2827c000) libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x28287000) libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x28320000) libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x28334000) libc.so.4 => /usr/lib/libc.so.4 (0x2833c000) libXThrStub.so.6 => /usr/X11R6/lib/libXThrStub.so.6 (0x283c8000)
ここでFreeBSD 4.x固有のもう一つの事情を紹介しておく必要があるでしょう。 マクロ定義オプションである -DNeedFunctionPrototypes=1 -DNeedWidePrototypes=0 は 附属のXFree86のライブラリを利用する上で必要なものです。 代わりに -DFUNCPROTO=15 としても構いません。 その根拠は Imake.tmpl と FreeBSD.cf と Xfuncproto.h にあります。 興味のある人は参照してみて下さい。
MotifのGUIを構成する部品はウィジェット(Widget)と呼ばれます。 ウィジェットは大きく次のように分類できます。
トップレベル ウィンドウはウィンドウシステムにおいて それぞれが互いに干渉しないように独立して存在する窓(ウインドウ:Window)のことです。 感覚的にはルート ウィンドウの直の子ですが、 ウィンドウ マネージャが介入するのが一般的なので、 厳密には正しくありません。
シェルやダイアログがこの役を担当するウィジェットです。 これらは、一つだけしか子を持てません。 ほとんどの場合は何らかのマネージャが子になります。 非常に単純なものであればプリミティブを子にすることもあります。 (先のwelcome.cがそうです。)
プリミティブはいわゆる画面上のボタンや テキストの入力フィールド等のことです。 それぞれが特徴あるインタフェースを提供します。 隠蔽された内部事情はともかく、 一般には「イントリンシクス レベルでの子は存在しないもの」として扱います。
マネージャは通常プリミティブをそれぞれのルールに従って管理する機能があるものです。 例えば横に整列するとか、あるウィジェットを別のウィジェットの右や下に配置するとか 決めて配列するとかします。 メニューバーやポップアップ メニューがこれに該当します。
管理するウィジェットが決まっている場合もありますが、 (例えば、メニューバーにはカスケードボタンを配置することしか想定していない等) 直観的に考える範囲で有効そうなものは大抵、その管理下に置くことができます。
☆
ここで見てもらうのは タイミング的に少し高度な内容ですが (まだ説明していないものがいくつも含まれているという意味で)、 それぞれのウィジェットの関係の把握に役立つクラス継承図を次に示します。
図:コアクラスからの分岐
Motifアプリケーションを利用する際に意識するシェルは TopLevelShell, SessionShell, MenuShell, DialogShellですが、 Xtで利用できる全てのシェル関連ウィジェットの説明をしておきます。
参考までに、実際のコーディングにおいては、簡易生成関数やUILを使い出すと DialogShellやMenuShellの生成を直接指示することはありません。 (少なくとも現時点での著者のプログラミングにおいてはですが…) その存在と関連パラメータを意識しておく くらいでしょうか。
☆
シェルのクラス継承図を次に示します。
図:シェルクラス継承図
サブクラスはスーパークラスの特徴を踏まえた上で、 より細かい機能が実装されているものです。 例えば、セッション シェルは、 その継承元であるアプリケーション シェル、トップレベル …と同じリソースを保持しており、 全てが完全に同じ意味で利用できるわけではありませんが、 おおよそ同じ性質を持っています。
附属のリファレンスマニュアルを参照する時も、 必要に応じてですが、全てのスーパークラスのマニュアルも辿って読みます。