HP OpenVMS Systems Documentation |
[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ]
この章では次のトピックについて説明するとともに,プログラミング例も示します。
UILを使用してPrint,Help,Color Mixing,Compound String Text,SVN のいずれかのウィジェットを作成している場合,アプリケーション・ソース・ ファイルにはMrmInitializeの呼び出し後に,次の1行を追加しなければなりません。
DXmInitialize();
DXmInitializeルーチンは,DECが提供するすべてのウィジェットに対してMrmRegisterClass を呼び出します。DXmInitializeを呼び出さない場合, アプリケーションの実行時に次のようなエラーが発生します。
X Toolkit Warning: Urm__WCI_LookupClassDescriptor: Couldn't find class descriptor for class xxxxxxx - MrmNOT_FOUND
次以降の節で,XmFormウィジェットのプログラミング上のヒントについてさらに説明します。XmForm ウィジェットについて完全に知りたい場合には, 『OSF/Motifプログラマーズ・ リファレンス』を参照してください。
XmFormウィジェットの一般的な使用方法として,XmFormウィジェットのサイズが変わっても, 他のウィジェットの位置合わせが変わらないように, それらのウィジェトの行および列を確定することがあります。例 3-1 に示すUILは,このようなXmFormウィジェットを実現している例です。
. . . object form_main : XmForm{ arguments { XmNdialogTitle = compound_string("XmForm"); XmNwidth = 400; XmNheight = 400; }; 【1】controls { XmPushButton a_button; XmPushButton b_button; XmPushButton c_button; XmPushButton d_button; XmPushButton e_button; XmPushButton f_button; XmPushButton g_button; XmPushButton h_button; XmPushButton i_button; XmPushButton j_button; }; }; object 【2】a_button : XmPushButton { arguments { XmNlabelString = compound_string("a button"); XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 25; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object 【3】b_button : XmPushButton { arguments { XmNlabelString = compound_string("b button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = a_button; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object c_button : XmPushButton { arguments { XmNlabelString = compound_string("c button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = b_button; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object d_button : XmPushButton { arguments { XmNlabelString = compound_string("d button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = c_button; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object e_button : XmPushButton { arguments { XmNlabelString = compound_string("e button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = d_button; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object 【4】f_button : XmPushButton { arguments { XmNlabelString = compound_string("f button"); XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 25; XmNleftAttachment = XmATTACH_WIDGET; XmNleftOffset = 5; XmNleftWidget = a_button; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object 【5】g_button : XmPushButton { arguments { XmNlabelString = compound_string("g button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = f_button; XmNleftAttachment = XmATTACH_WIDGET; XmNleftOffset = 5; XmNleftWidget = b_button; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object h_button : XmPushButton { arguments { XmNlabelString = compound_string("h button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = g_button; XmNleftAttachment = XmATTACH_WIDGET; XmNleftOffset = 5; XmNleftWidget = c_button; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object i_button : XmPushButton { arguments { XmNlabelString = compound_string("i button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = h_button; XmNleftAttachment = XmATTACH_WIDGET; XmNleftOffset = 5; XmNleftWidget = d_button; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object j_button : XmPushButton { arguments { XmNlabelString = compound_string("j button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = i_button; XmNleftAttachment = XmATTACH_WIDGET; XmNleftOffset = 5; XmNleftWidget = e_button; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; . . .
これらのXmPushButtonは,XmATTACH_OPPOSITE_WIDGETを次のように使用して, ウィジェットの左側をa_buttonの左側に位置合わせすることもできます。
object b_button : XmPushButton { arguments { XmNlabelString = compound_string("b button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = a_button; XmNleftAttachment = XmATTACH_OPPOSITE_WIDGET; XmNleftWidget = a_button; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; }; object c_button : XmPushButton { arguments { XmNlabelString = compound_string("b button"); XmNtopAttachment = XmATTACH_WIDGET; XmNtopOffset = 5; XmNtopWidget = b_button; XmNleftAttachment = XmATTACH_OPPOSITE_WIDGET; XmNleftWidget = a_button; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; }; };
これらのXmPushButtonは,XmATTACH_OPPOSITE_WIDGETを使用して,左側をf_button の左側にアタッチすることもできます。
例 3-1に示している例はXmPushButtonの位置合わせを正しく行い,XmForm のサイズにかかわりなくこの関係を維持します。 ただし,各XmPushButtonウィジェットのサイズが異なる場合,この位置合わせは壊れることがあります。 たとえば,ボタンbのタイトルが長ければ, ボタンgを右に押します。
アプリケーションでさまざまなサイズのウィジェットの位置合わせをする必要がある場合は, 一番大きな子に合わせて拡大するXmRowColumnウィジェットにXmPushButton を置くことができます。そしてXmFormウィジェット内でXmRowColumn ウィジェットの位置合わせをします。
例 3-2に示すUILの例は,サイズが異なる子をもつXmForm ウィジェットを実現します。
. . . object form_main : XmForm{ arguments { XmNdialogTitle = compound_string("XmForm"); XmNwidth = 400; XmNheight = 400; }; 【1】controls { XmRowColumn align_a; XmRowColumn align_b; }; }; object align_a : XmRowColumn { arguments { XmNunitType = XmPIXELS; 【2】XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 25; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; XmNorientation = XmVERTICAL; XmNborderWidth = 0; }; controls { XmPushButton a_button; XmPushButton b_button; XmPushButton c_button; XmPushButton d_button; XmPushButton e_button; }; }; object a_button : XmPushButton { arguments { XmNlabelString = compound_string("a button"); }; }; object b_button : XmPushButton { arguments { XmNlabelString = compound_string("b button"); }; }; object c_button : XmPushButton { arguments { XmNlabelString = compound_string("Long Button Title"); }; }; object d_button : XmPushButton { arguments { XmNlabelString = compound_string("d button"); }; }; object e_button : XmPushButton { arguments { XmNlabelString = compound_string("Long Button Title"); }; }; object align_b : XmRowColumn { arguments { XmNunitType = XmPIXELS; XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 25; 【3】XmNleftAttachment = XmATTACH_WIDGET; XmNleftWidget = align_a; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; XmNorientation = XmVERTICAL; XmNborderWidth = 0; }; controls { XmPushButton f_button; XmPushButton g_button; XmPushButton h_button; XmPushButton i_button; XmPushButton j_button; }; }; object f_button : XmPushButton { arguments { XmNlabelString = compound_string("f button"); }; }; object g_button : XmPushButton { arguments { XmNlabelString = compound_string("g button"); }; }; object h_button : XmPushButton { arguments { XmNlabelString = compound_string("h button"); }; }; object i_button : XmPushButton { arguments { XmNlabelString = compound_string("i button"); }; }; object j_button : XmPushButton { arguments { XmNlabelString = compound_string("j button"); }; }; . . .
XmFormウィジェットを使用すると,ウィジェットの辺をXmFormウィジェット内の特定の位置へアタッチすることができます。x およびy座標を使用して位置を指定する代わりに,XmForm ウィジェットの総面積の一部として位置を指定します。 これを百分率位置指定といいます。
このようなアタッチメントの指定は,アタッチメント・タイプ属性の値としてアタッチメント・ タイプ定数XmNATTACH_POSITIONを,およびアタッチメント位置属性の値として分数位置の分子の値を渡すことによって行います。
たとえば,XmFormウィジェットの中間点は2辺間の距離の半分です。 子ウィジェットの左辺をXmFormウィジェットの中間点にアタッチするには, XmNleftAttachment 属性をXmNATTACH_POSITIONに設定し,XmNleftPosition 属性に分子の値50を指定します(省略時の分母は100) 。
XmNleftPosition引数は百分率として扱うこともできます。この場合50という値は50% を意味します。
ただし,これは子ウィジェットの左辺をXmFormウィジェットの中間点に位置合わせしますが, 子ウィジェットはセンタリングされないことに注意してください。 子ウィジェットを中間点にセンタリングするには,次の操作を行います。
例 3-3と例 3-4 は,オフセット値を使用して子ウィジェットをセンタリングする方法を示しています。MrmNcreateCallback ルーチンは,XmPushButton ウィジェットをそれぞれの位置にセンタリングする,幅と高さのオフセットを計算します。 この位置とオフセットの関係は,XmFormウィジェットでどのようなサイズ変更操作を実行しても維持されます。
. . . module form version = 'v1.0' names = case_sensitive procedure center_form (); object 【1】form_main : XmForm{ arguments { XmNdialogTitle = compound_string("XmForm"); XmNwidth = 400; XmNheight = 400; }; controls { XmPushButton a_arrow; XmPushButton b_arrow; XmPushButton c_arrow; }; }; object a_arrow : XmPushButton { 【2】arguments { XmNlabelString = compound_string("centered"); XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 50; XmNbottomAttachment = XmATTACH_NONE; XmNleftAttachment = XmATTACH_POSITION; XmNleftPosition = 25; XmNrightAttachment = XmATTACH_NONE; }; callbacks { 【3】MrmNcreateCallback = procedure center_form(); }; }; object b_arrow : XmPushButton { 【4】arguments { XmNlabelString = compound_string("centered"); XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 50; XmNbottomAttachment = XmATTACH_NONE; XmNleftAttachment = XmATTACH_POSITION; XmNleftPosition = 50; XmNrightAttachment = XmATTACH_NONE; }; callbacks { MrmNcreateCallback = procedure center_form(); }; }; object c_arrow : XmPushButton { 【5】arguments { XmNlabelString = compound_string("centered"); XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 50; XmNbottomAttachment = XmATTACH_NONE; XmNleftAttachment = XmATTACH_POSITION; XmNleftPosition = 75; XmNrightAttachment = XmATTACH_NONE; }; callbacks { MrmNcreateCallback = procedure center_form(); }; }; end module; . . .
. . . #include <stdio> #include <Mrm/MrmAppl.h> #include <DXm/DXmCSText.h> Widget toplevel, form_w; static MrmHierarchy s_MrmHierarchy; static MrmType *dummy_class; static char *db_filename_vec[] = {"center_form.uid" }; /* Forward declarations */ static void center_form(); /* The names and addresses of things that Mrm.has to bind. The names do * not have to be in alphabetical order. */ static MrmRegisterArg reglist[] = { {"center_form", (caddr_t) center_form} }; static int reglist_num = (sizeof reglist / sizeof reglist [0]); int main(argc, argv) unsigned int argc; char **argv; { XtAppContext app_context; MrmInitialize(); DXmInitialize(); toplevel = XtAppInitialize(&app_context, "example", NULL, 0, &argc, argv, NULL, NULL, 0); /* Open the UID files (the output of the UIL compiler) in the hierarchy*/ if (MrmOpenHierarchy(1, db_filename_vec, NULL, &s_MrmHierarchy) !=MrmSUCCESS) printf("can't open hierarchy"); MrmRegisterNames(reglist, reglist_num); if (MrmFetchWidget(s_MrmHierarchy, "form_main", toplevel, &form_w, &dummy_class) != MrmSUCCESS) printf("can't fetch widget"); XtManageChild(form_w); XtRealizeWidget(toplevel); XtAppMainLoop(app_context); } static void center_form(w, tag, reason) Widget w; int *tag; unsigned long *reason; { Arg arglist[10]; int ac; int calc_width = 0; int width_b = 0; int calc_height = 0; int height_b = 0; /* Get the button width and height*/ 【1】ac = 0; XtSetArg(arglist[ac], XmNwidth, &width_b); ac++; XtSetArg(arglist[ac], XmNheight, &height_b); ac++; XtGetValues(w, arglist, ac); /* Calculate the button width and height */ 【2】calc_width = width_b/2; calc_height = height_b/2; ac = 0; 【3】XtSetArg (arglist[ac], XmNleftOffset, -calc_width); ac++; 【4】XtSetArg (arglist[ac], XmNtopOffset, -calc_height); ac++; XtSetValues (w, arglist, ac); } . . .
ツールキットにはDXmFormSpaceButtonsEquallyというルーチンが含まれており, アプリケーションはこのルーチンを呼び出して,XmFormウィジェット内の不特定数のプッシュ・ ボタンを,間隔とサイズが等しくなるように設定することができます。DXmFormSpaceButtonsEqually はXmFormウィジェットの幅とXmPushButton の数を判断したのち,それに従ってXmPushButton の間隔とサイズを設定します。
プログラマはDXmFormSpaceButtonsEquallyに,XmPushButtonが入っているXmForm ウィジェットのウィジェットID,変更するXmPushButtonのウィジェットID の配列,ウィジェット配列内のXmPushButtonの数を渡します。
XmPushButtonのIDは,XmFormウィジェットに表示される順に,たとえば「了解」「適用」「リセット」「取消」のように指定しなければなりません。 また,XmPushButtonは左右のアタッチメントを持っていてはなりません。
次のDXmFormSpaceButtonsEquallyの例は,DECburgerサンプル・プログラムからの引用です。 この例はXmFormDialogウィジェット内で「了解」, 「適用」,「リセット」,「取消」の各プッシュ・ボタンのスペース設定を行っています。
. . . #define k_ok 6 /* NOTE: ok, apply, reset, cancel */ #define k_apply 7 /* must be sequential */ #define k_reset 8 #define k_cancel 9 . . . static void show_hide_proc(w, tag, reason) Widget w; int *tag; XmAnyCallbackStruct *reason; { if (XtIsManaged(widget_array[k_order_box])) XtUnmanageChild(widget_array[k_order_box]); else { start_watch(); XtManageChild(widget_array[k_order_box]); DXmFormSpaceButtonsEqually (widget_array[k_order_box], &widget_array[k_ok], 4); stop_watch(); } }
『OSF/Motifプログラマーズ・ ガイド』で説明しているように,アプリケーションはアプリケーション固有のデフォルト・ ファイルを使用して,CまたはUILモジュールに明示的に設定されてないリソースを指定できます。 アプリケーションの省略時の値が入っているファイルは次のように,XtAppInitialize ルーチンのapplication_class 引数で指定します。
toplevel = XtAppInitialize(&app_context, "example", NULL, 0, &argc, argv, NULL, NULL, 0);
application_class引数(この場合"example")は,DEC UNIXシステムおよびeXcursion for Windows NT システムではexample.dat,OpenVMSシステムではEXAMPLE.DAT という名前のデフォルト・ファイルを指定します。ファイル・ タイプは省略時の設定により.DATです。XtAppInitializeルーチンはデフォルト・ ファイルがある場合,自動的にそれを使用します。
次はデフォルト・ファイルの一例です。これはOpenVMSではDECW$USER_ DEFAULTS (ユーザのSYS$LOGINディレクトリ)にあります。UNIXおよびWindows NT システムでは,ユーザのホーム・ディレクトリにあります。
! example*allowShellResize: true example*borderWidth: 0 example*highlightThickness: 1 example*traversalOn: true example*fontList: fixed example*background: LightBlue !
デフォルト・ファイルでリソースがどのように使用されているかを判断するには, インクルード・ファイルでそのウィジェットを調べ,リソースがどのように定義されているかを確認してください。 たとえば, DXmSvnNfontListLevelのリソースはDXmSvn.h(UNIXとWindows NT)あるいはDXMSVN.H (OpenVMS)で次のように定義されています。
#define DXmSvnNfontListLevel0 "DXmfontListLevel0" #define DXmSvnNfontListLevel1 "DXmfontListLevel1" #define DXmSvnNfontListLevel2 "DXmfontListLevel2" #define DXmSvnNfontListLevel3 "DXmfontListLevel3"
DEC提供のウィジェットは,そのウィジェットに固有のリソースについて,DXmN というリソース名の先頭文字を持っています。SVNウィジェットの場合, 先頭文字はDXmSvnNです。
デフォルト・ファイルにおける値として,リソースの文字列の値(この場合はDXmfontListLevel0 ,DXmfontListLevel1など)を使用します。名前は大文字と小文字を区別することに注意してください。
example*main_svn.background: LightBlue example*DXmfontListLevel2: -ADOBE-ITC Avant Garde Gothic-Book-R-Normal--14-100-*-*-P-80-*
ほかのウィジェットと共通のリソースや,ウィジェットのスーパークラスの一部であるリソースは, 先頭文字としてXmNを使用します。リソース名はXm.h (UNIXおよびWindows NT)あるいはXM.H(OpenVMS)にあり,デフォルト・ ファイルで使用される文字列は,X_GBLSのあとに括弧で囲まれています。 たとえば,デフォルト・ファイルでXmNbackgroundを指定するには, backgroundという文字列の値を使用します。
#define XmNbackground X_GBLS(background)
多くのアプリケーションには,ユーザがアプリケーションの設定を変更し, あとでそのアプリケーションを起動するときのために,それらの設定を保管できるオプションがあります。 例 3-6と例 3-7 は,メイン・ウィンドウのXmNwidth およびXmNheightリソースをユーザが設定して保管できるアプリケーションを実現しています。
. . . module form version = 'v1.0' names = case_sensitive procedure save_create (); all_done (); object 【1】main_window : XmMainWindow { controls { XmMenuBar menu_bar; XmForm form_main; }; }; object menu_bar : XmMenuBar { arguments { XmNorientation = XmHORIZONTAL; XmNspacing = 15; }; controls { XmCascadeButton cust_entry; }; }; object 【2】cust_entry : XmCascadeButton { arguments { XmNlabelString = compound_string("Save Settings"); XmNmnemonic = keysym("S"); }; controls { XmPulldownMenu cust_menu; }; }; object cust_menu : XmPulldownMenu { controls { XmPushButton push_me; XmPushButton done; }; }; object 【3】push_me : XmPushButton { arguments { XmNlabelString = compound_string("Save Width and Height"); }; callbacks { XmNactivateCallback = procedure save_create (); }; }; object 【4】done : XmPushButton { arguments { XmNlabelString = compound_string("Exit"); }; callbacks { XmNactivateCallback = procedure all_done (); }; }; 【5】 object form_main : XmForm{ arguments { XmNdialogTitle = compound_string("XmForm"); XmNwidth = 300; XmNheight = 300; }; controls { XmRowColumn align_a; XmRowColumn align_b; }; }; object align_a : XmRowColumn { arguments { XmNunitType = XmPIXELS; XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 25; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; XmNorientation = XmVERTICAL; XmNborderWidth = 0; }; controls { XmPushButton a_button; XmPushButton b_button; XmPushButton c_button; XmPushButton d_button; XmPushButton e_button; }; }; object align_b : XmRowColumn { arguments { XmNunitType = XmPIXELS; XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 25; XmNleftAttachment = XmATTACH_WIDGET; XmNleftWidget = align_a; XmNleftOffset = 25; XmNbottomAttachment = XmATTACH_NONE; XmNrightAttachment = XmATTACH_NONE; XmNorientation = XmVERTICAL; XmNborderWidth = 0; }; controls { XmPushButton f_button; XmPushButton g_button; XmPushButton h_button; XmPushButton i_button; XmPushButton j_button; }; }; object a_button : XmPushButton { arguments { XmNlabelString = compound_string("a button"); }; }; object b_button : XmPushButton { arguments { XmNlabelString = compound_string("b button"); }; }; object c_button : XmPushButton { arguments { XmNlabelString = compound_string("Long Button Title"); }; }; object d_button : XmPushButton { arguments { XmNlabelString = compound_string("d button"); }; }; object e_button : XmPushButton { arguments { XmNlabelString = compound_string("Long Button Title"); }; }; object f_button : XmPushButton { arguments { XmNlabelString = compound_string("f button"); }; }; object g_button : XmPushButton { arguments { XmNlabelString = compound_string("g button"); }; }; object h_button : XmPushButton { arguments { XmNlabelString = compound_string("h button"); }; }; object i_button : XmPushButton { arguments { XmNlabelString = compound_string("i button"); }; }; object j_button : XmPushButton { arguments { XmNlabelString = compound_string("j button"); }; }; end module;
. . . /* The example uses these defaults: * example*main_window.width: 334 * example*main_window.height: 246 * example*allowShellResize: true * example*highlightThickness: 1 * example*borderWidth: 0 * example*background: LightBlue * example*fontList: fixed * example*traversalOn: true */ #include <stdio> #include <Mrm/MrmAppl.h> #include <DXm/DXmCSText.h> #include <X11/Xresource.h> Widget toplevel, main_win, form_w; XrmDatabase database = 0; int save_width; int save_height; 【1】 #define resourceFileName "decw$user_defaults:example.dat" static MrmHierarchy s_MrmHierarchy; static MrmType *dummy_class; static char *db_filename_vec[] = {"defaults_file.uid" }; /* Forward declarations */ static void save_create(); static void all_done(); static void update_database( ); /* The names and addresses of things that Mrm.has to bind. The names do * not have to be in alphabetical order. */ static MrmRegisterArg reglist[] = { {"save_create", (caddr_t) save_create}, {"all_done", (caddr_t) all_done} }; static int reglist_num = (sizeof reglist / sizeof reglist [0]); int main(argc, argv) unsigned int argc; char **argv; { XtAppContext app_context; MrmInitialize(); DXmInitialize(); 【2】toplevel = XtAppInitialize(&app_context, "example", "Example", 0, &argc, argv, NULL, NULL, 0); /* Open the UID files (the output of the UIL compiler) in the hierarchy*/ if (MrmOpenHierarchy(1, db_filename_vec, NULL, &s_MrmHierarchy) !=MrmSUCCESS) printf("can't open hierarchy"); MrmRegisterNames(reglist, reglist_num); if (MrmFetchWidget(s_MrmHierarchy, "main_window", toplevel, &main_win, &dummy_class) != MrmSUCCESS) printf("can't fetch widget"); XtManageChild(main_win); XtRealizeWidget(toplevel); XtAppMainLoop(app_context); } 【3】 static void save_create(w, tag, reason) Widget w; int *tag; unsigned long *reason; { Arg arglist[10]; int ac; 【4】if (!(database = XrmGetFileDatabase (resourceFileName))) printf("Resource Database Not found"); 【5】ac = 0; XtSetArg(arglist[ac], XmNwidth, &save_width); ac++; XtSetArg(arglist[ac], XmNheight, &save_height); ac++; XtGetValues(main_win, arglist, ac); 【6】update_database ("example*main_window.width", save_width); update_database ("example*main_window.height", save_height); 【7】XrmPutFileDatabase (database, resourceFileName); } static void update_database(resourceNameP, number) char *resourceNameP; int number; { XrmValue value; char valueA[256]; sprintf (valueA, "%d", number); value.addr = valueA; value.size = strlen (valueA) + 1; 【8】XrmPutResource (&database, resourceNameP, XtRString, &value); } static void all_done(w, tag, reason) Widget w; int *tag; unsigned long *reason; { exit(1); } . . .
リソースは『X Window System』に記述されているフォーマットに従って指定しなければなりません。 たとえば"example*main_window.width"のように指定します。
ツールキットを使用すると,アプリケーションは複数のディスプレイをオープンすることができます。 複数のディスプレイをオープンすることによって,1 つのアプリケーションの独立したインスタンスを複数のワークテーション上で実行したり, アプリケーションのインスタンスを相互に接続することができます。 複数のディスプレイをオープンするには,次のコマンド・ シーケンスを使用します。
複数のディスプレイ名をアプリケーション中にコーディングする必要はありません。SET DISPLAY コマンドを使用すると,アプリケーションに複数のディスプレイ名を設定できます。
$ SET DISPLAY DPY1/CREATE/NODE="DPY1" $ SET DISPLAY DPY2/CREATE/NODE="DPY2"
DPY1とDPY2は,ワークステーション装置に相当する論理名です。 XtOpenDisplayへの呼び出しでその論理名を渡します。
display = XtOpenDisplay(app_context, "dpy1", "two_heads", "demo", NULL, 0, &argc, argv); display_b = XtOpenDisplay(app_context, "dpy2", "two_heads", "demo", NULL, 0, &argc, argv);
UNIXシステムでは,複数のディスプレイを使用するための性能は,使用しているシェルに依存します。C シェルを使用している場合は,以下のsetenv コマンドを使用してください。
setenv dpy1 dpy1:0.0 setenv dpy2 dpy2:0.2
BourneシェルあるいはKornシェルを使用している場合は,以下のexportコマンドを使用してください。
export dpy1=dpy1:0.0 export dpy2=dpy2:0.1
つぎに,以下のコードをアプリケーションに組み込んでください。
char *dpy1; char *dpy2; dpy1=getenv("dpy1"); dpy2=getenv("dpy2"); display=XtOpenDisplay(app_context, dpy1, "two_heads", "demo", NULL, 0, &argc, argv); display_b=XtOpenDisplay(app_context, dpy2, "two_heads", "demo", NULL, 0, &argc, argv);
Windows NTシステムでは,ディスプレイの変数を設定するコマンドは以下のとおりです。
set dpy1=dpy1:0.0 set dpy2=dpy2:0.0
例 3-8と例 3-9 は,第3.2.3項に示したウィジェットのセンタリング例のバージョンを実現しています。 この例は2 つのディスプレイをオープンし,アプリケーションの独立したインスタンスを実行します。UIL ファイルが共用されていることに注意してください。
. . . module form version = 'v1.0' names = case_sensitive procedure center_form (); object form_main : XmForm{ arguments { XmNdialogTitle = compound_string("XmForm"); XmNwidth = 400; XmNheight = 400; }; controls { XmPushButton a_arrow; XmPushButton b_arrow; XmPushButton c_arrow; }; }; object a_arrow : XmPushButton { arguments { XmNlabelString = compound_string("centered"); XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 50; XmNbottomAttachment = XmATTACH_NONE; XmNleftAttachment = XmATTACH_POSITION; XmNleftPosition = 25; XmNrightAttachment = XmATTACH_NONE; }; callbacks { MrmNcreateCallback = procedure center_form(); }; }; object b_arrow : XmPushButton { arguments { XmNlabelString = compound_string("centered"); XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 50; XmNbottomAttachment = XmATTACH_NONE; XmNleftAttachment = XmATTACH_POSITION; XmNleftPosition = 50; XmNrightAttachment = XmATTACH_NONE; }; callbacks { MrmNcreateCallback = procedure center_form(); }; }; object c_arrow : XmPushButton { arguments { XmNlabelString = compound_string("centered"); XmNtopAttachment = XmATTACH_POSITION; XmNtopPosition = 50; XmNbottomAttachment = XmATTACH_NONE; XmNleftAttachment = XmATTACH_POSITION; XmNleftPosition = 75; XmNrightAttachment = XmATTACH_NONE; }; callbacks { MrmNcreateCallback = procedure center_form(); }; }; end module; . . .
. . . #include <stdio> #include <Mrm/MrmAppl.h> #include <DXm/DXmCSText.h> 【1】 Widget toplevel, toplevel_b, form_w, form_w_b; static MrmHierarchy s_MrmHierarchy; static MrmType *dummy_class; static char *db_filename_vec[] = 【2】 {"twin_form.uid" }; /* Forward declarations */ static void center_form(); /* The names and addresses of things that Mrm.has to bind. The names do * not have to be in alphabetical order. */ static MrmRegisterArg reglist[] = { {"center_form", (caddr_t) center_form} }; static int reglist_num = (sizeof reglist / sizeof reglist [0]); int main(argc, argv) unsigned int argc; char **argv; { XtAppContext app_context; 【3】Display *display, *display_b; MrmInitialize(); DXmInitialize(); 【4】XtToolkitInitialize(); 【5】app_context = XtCreateApplicationContext(); 【6】display = XtOpenDisplay(app_context, "dpy1", "two_heads", "demo", NULL, 0, &argc, argv); display_b = XtOpenDisplay(app_context, "dpy2", "two_heads", "demo", NULL, 0, &argc, argv); if (!display) { XtWarning ("Can't open display one...exiting"); exit(0); } if (!display_b) { XtWarning ("Can't open display two...exiting"); exit(0); } 【7】toplevel = XtAppCreateShell ("two_heads", NULL, applicationShellWidgetClass, display, NULL, 0); toplevel_b = XtAppCreateShell ("two_heads", NULL, applicationShellWidgetClass, display_b, NULL, 0); /* Open the UID files (the output of the UIL compiler) in the hierarchy*/ if (MrmOpenHierarchy(1, db_filename_vec, NULL, &s_MrmHierarchy) !=MrmSUCCESS) printf("can't open hierarchy"); MrmRegisterNames(reglist, reglist_num); 【8】if (MrmFetchWidget(s_MrmHierarchy, "form_main", toplevel, &form_w, &dummy_class) != MrmSUCCESS) printf("can't fetch widget"); if (MrmFetchWidget(s_MrmHierarchy, "form_main", toplevel_b, &form_w_b, &dummy_class) != MrmSUCCESS) printf("can't fetch widget"); 【9】XtManageChild(form_w); XtManageChild(form_w_b); 【10】XtRealizeWidget(toplevel); XtRealizeWidget(toplevel_b); 【11】XtAppMainLoop(app_context); } static void center_form(w, tag, reason) Widget w; int *tag; unsigned long *reason; { Arg arglist[10]; int ac; int calc_width = 0; int width_b = 0; int calc_height = 0; int height_b = 0; /* Calculate the button width */ ac = 0; XtSetArg(arglist[ac], XmNwidth, &width_b); XtGetValues(w, arglist, 1); calc_width = width_b/2; /* Calculate the button height */ ac = 0; XtSetArg(arglist[ac], XmNheight, &height_b); XtGetValues(w, arglist, 1); calc_height = height_b/2; ac = 0; XtSetArg (arglist[ac], XmNleftOffset, -calc_width); ac++; XtSetArg (arglist[ac], XmNtopOffset, -calc_height); ac++; XtSetValues (w, arglist, ac); } . . .
例 3-10は,2つのマルチラインCSTextウィジェットを相互に接続するアプリケーションを実現しています。 一方のウィジェットに入力されたテキストは,2 つのウィジェットが同じファイルを同時に編集しているかのように, 別のウィジェットにも反映されます。
. . . #include <stdio> #include <Mrm/MrmAppl.h> #include <DXm/DXmCSText.h> static void change_cs(); 【1】 static Widget toplevel, toplevel_b, text_shell, text_shell_b, text_w, text_w_b; static int ignoreValueChanged = 1; int main(argc, argv) unsigned int argc; char **argv; { XtAppContext app_context; Arg arglist[15]; int ac = 0; XtCallbackRec callback_arg[2]; 【2】Display *display, *display_b; 【3】XtToolkitInitialize(); 【4】app_context = XtCreateApplicationContext(); 【5】display = XtOpenDisplay(app_context, "dpy1", "two_heads", "demo", NULL, 0, &argc, argv); display_b = XtOpenDisplay(app_context, "dpy2", "two_heads", "demo", NULL, 0, &argc, argv); if (!display) { XtWarning ("Can't open display...exiting"); exit(0); } if (!display_b) { XtWarning ("Can't open display...exiting"); exit(0); } 【6】toplevel = XtAppCreateShell ("two_heads", NULL, applicationShellWidgetClass, display, NULL, 0); toplevel_b = XtAppCreateShell ("two_heads", NULL, applicationShellWidgetClass, display_b, NULL, 0); ac = 0; XtSetArg( arglist[ac], XmNdialogTitle, XmStringCreateLtoR("User Defined",""));ac++; XtSetArg( arglist[ac], XmNallowOverlap, TRUE);ac++; XtSetArg( arglist[ac], XmNheight, 300);ac++; XtSetArg( arglist[ac], XmNwidth, 300);ac++; XtSetArg( arglist[ac], XmNresizePolicy, XmRESIZE_GROW);ac++; 【7】text_shell = XmCreateBulletinBoard(toplevel, "CSText", arglist, ac ); text_shell_b = XmCreateBulletinBoard(toplevel_b, "CSText", arglist, ac ); callback_arg[0].callback = change_cs; callback_arg[0].closure = 0; callback_arg[1].callback = NULL; callback_arg[1].closure = NULL; ac = 0; XtSetArg( arglist[ac], XmNx, 40);ac++; XtSetArg( arglist[ac], XmNy, 50);ac++; XtSetArg( arglist[ac], XmNrows, 20 ); ac++; XtSetArg( arglist[ac], XmNcolumns, 45 ); ac++; XtSetArg( arglist[ac], XmNvalueChangedCallback, callback_arg);ac++; XtSetArg( arglist[ac], XmNscrollVertical, TRUE);ac++; XtSetArg( arglist[ac], XmNeditMode, XmMULTI_LINE_EDIT);ac++; 【8】text_w = DXmCreateScrolledCSText(text_shell, "textwidget", arglist, ac ); text_w_b = DXmCreateScrolledCSText(text_shell_b, "textwidget", arglist, ac ); 【9】XtManageChild(text_w); XtManageChild(text_w_b); 【10】XtManageChild(text_shell); XtManageChild(text_shell_b); 【11】XtRealizeWidget(toplevel); XtRealizeWidget(toplevel_b); 【12】ignoreValueChanged = 0; 【13】XtAppMainLoop(app_context); } /* The user entered something*/ 【14】 static void change_cs(w, tag, reason) Widget w; int *tag; unsigned long *reason; { XmString new_text; DXmCSTextPosition last_pos; Widget ww; 【15】if (ignoreValueChanged) return; 【16】ignoreValueChanged = 1; 【17】new_text = DXmCSTextGetString(w); 【18】last_pos = DXmCSTextGetLastPosition(text_w); 【19】if (w == text_w_b) ww = text_w; else ww = text_w_b; DXmCSTextSetString(ww, new_text); DXmCSTextSetInsertionPosition(ww, last_pos); DXmCSTextSetInsertionPosition(text_w_b, last_pos); XtFree(new_text); ignoreValueChanged = 0; } . . .
ツールキットにはDXmCreateCursorというルーチンがあり,これを呼び出すことによってアプリケーションのカーソルを作成できます。UNIX およびWindows NT システムでは,カーソルを識別するには,DECspecific.hインクルード・ ファイルに定義されているカーソル定数の1つを指定します。XDmCreateCursor ルーチンを使用するためには,アプリケーションにDECspecific.h およびdecwcursor.hインクルード・ファイルを取り込まなければなりません。OpenVMS システムでは,カーソルを識別するには, DECw$Cursor.hインクルード・ファイルに定義されているカーソル定数の1 つを指定します。XDmCreateCursorルーチンを使用するためには,アプリケーションにDECspecific.h およびDECw$Cursor.hインクルード・ファイルを取り込まなければなりません。
例 3-11は,DXmCreateCursorルーチンを使用して待機カーソルを作成し, そのカーソルをアプリケーションのウィンドウで使用するように定義した後, 親(もと)のカーソルを復元する方法を示しています。 カーソルは一度だけ作成する必要があり,その後は必要に応じてそのカーソルを定義したり, 定義を解除することができます。
. . . #include <DXm/DECspecific.h> #include <sys$library/DECw$Cursor.h> . . . Widget toplevel_widget, my_widget; Cursor cursor; cursor = DXmCreateCursor(toplevel_widget, decw$c_wait_cursor); XDefineCursor(XtDisplay(toplevel_widget), XtWindow(my_widget), cursor); . . . /* Perform some function */ XUndefineCursor(XtDisplay(toplevel_widget), XtWindow(my_widget));
『X Window System Toolkit』で説明されているように,XtAppAddInputルーチンを使用することにより, 入力の代替ソースをツールキットに登録することができます。 この代替ソースからの入力が利用できるようになると, Intrinsicsは提供されているコールバック・ルーチンを呼び出して,入力が利用できることを通知します。
XtAppAddInputルーチンには,オペレーティング・システムに依存する引数がいくつかあります。 『X Window System Toolkit』では,UNIXおよびWindows NTシステム上で使われるXtAppAddInputルーチンについて説明してあります。
OpenVMS環境において,XtAppAddInputルーチンの呼び出しに使用される引数は, 次のとおりです。
アプリケーションには,入力が利用できることを知らせるために,イベント・ フラグをセットする方法が必要です。イベント・フラグをセットするもっとも一般的な方法は,AST 終了ルーチンを使用することです。たとえば 例 3-13では,START_READルーチンが$QIO 読み込みを開始し,AST終了ルーチンとしてCompletionASTを指定します。CompletionAst はイベント・フラグをセットします。
例 3-12と例 3-13 はブロードキャスト・メッセージをトラップし,それらをXmScrolledList ウィジェットに表示するプログラムを実現しています。このプログラムはメールボックスを使用して, プロセス同士のやりとりを処理します。
AllocateAddInputRecルーチンは,割り当てられたスペース,アプリケーション( ウィジェット)コールバック,タグが入っているデータ構造体を割り当てて初期化します。 このデータ構造体はASTレベルでCompletionAstルーチンへ渡され, その後アプリケーションのXtInputCallbackProcルーチンへ渡されます。 このデータ構造体はアプリケーションの必要に応じて使用できます。
AllocateAddInputRecで割り当てられたデータ構造体を使用し,アプリケーションの要求に基づいてProcessMessageRec とAddInputCallbackルーチンを置き換えることにより, このコードを使用して$QIOをバッファに読み込み, 入力が利用できることをツールキットに通知するイベント・フラグをセットして, 別の$QIO読み込みを開始することができます。
次のコマンドを使用すると,このプログラムをコンパイルしてリンクすることができます。
$ UIL/MOTIF BTRAP.UIL $ CC/NOOPTIMIZE BTRAP $ LINK BTRAP,SYS$INPUT/OPT SYS$SHARE:DECW$DXMLIBSHR/SHARE,SYS$SHARE:DECW$XLIBSHR/SHARE
module BTrap names = case_sensitive procedure LabelCreateCallback (); QuitCallback (); object bTrapMain : XmMainWindow { arguments { XmNwidth = 650; XmNheight = 150; }; controls { XmForm btrap_form; }; }; object btrap_form : XmForm{ controls { XmScrolledList bTrapLabel; XmPushButton bTrapQuitButton; }; }; 【1】 object bTrapLabel : XmScrolledList { arguments { XmNvisibleItemCount = 5; XmNunitType = XmPIXELS; XmNlistSizePolicy = XmVARIABLE; XmNscrollBarDisplayPolicy = XmSTATIC; XmNleftAttachment = XmATTACH_FORM; XmNleftOffset = 0; XmNrightAttachment = XmATTACH_FORM; XmNrightOffset = 0; XmNtopAttachment = XmATTACH_FORM; XmNtopOffset = 3; XmNbottomAttachment = XmATTACH_NONE; }; callbacks { MrmNcreateCallback = procedure LabelCreateCallback(); }; }; object bTrapQuitButton : XmPushButton { arguments { XmNlabelString = compound_string("Quit"); XmNleftAttachment = XmATTACH_NONE; XmNtopAttachment = XmATTACH_NONE; XmNbottomAttachment = XmATTACH_FORM; XmNbottomOffset = 5; XmNrightAttachment = XmATTACH_FORM; XmNrightOffset = 10; }; callbacks { XmNactivateCallback = procedure QuitCallback(); }; }; end module; . . .
【1】 #include <Mrm/MrmAppl.h> #include <descrip.h> #include <jpidef.h> #include <ssdef.h> #include <iodef.h> #include <libdef.h> #include <dvidef.h> #include <psldef.h> #include <prcdef.h> #include <ttdef.h> #include <tt2def.h> #include <msgdef.h> /* * Global Data * */ static MrmHierarchy s_MrmHierarchy; /* MRM database hierarchy ID */ static MrmType *dummy_class; /* and class variable. */ static char *db_filename_vec[] = /* Mrm.heirachy file list. */ {"btrap.uid" /* There is only one UID file for */ }; /* this application. */ static int db_filename_num = (sizeof db_filename_vec / sizeof db_filename_vec [0]); 【2】 #define MISC_EFN 2 /* use for system service calls */ 【3】 typedef struct { unsigned short type; unsigned short unit; unsigned char controllerNameLen; char controllerNameA[15]; unsigned short messageLen; char messageA[256]; } VmsMailboxMessage; /* Define a control block to contain information about the mailbox message. * This control block will be passed to the I/O completion routine. */ 【4】 typedef struct _MessageRec { unsigned short iosbA[4]; VmsMailboxMessage mailboxMessage; } MessageRec; static MessageRec messageRec; static short devChan, mbChan; /* Definitions for AST routines */ #define LIB$_QUEWASEMP 1409772 【5】 #define ADD_INPUT_EFN 3 typedef struct { unsigned long queueEntryA[2]; /* must be first in struct */ char *mallocP; /* address actually malloc-ed */ void (*routineP)(); /* thread resumption routine */ Opaque closure; /* thread closure */ } AddInputRec; static _align(quadword) unsigned long addInputQueueHeaderA[2]; static int initialized; /* Application Context */ 【6】 XtAppContext app_context; /* Application Widgets */ static Widget appW, mainW, labelW; /* * Forward declarations */ static unsigned long StartReadQIO(); static void LabelCreateCallback(); static void QuitCallback(); static void AddInputCallback(); extern void CompletionAst(); extern Opaque AllocateAddInputRec(); /* The names and addresses of things that Mrm.has to bind. The names do * not have to be in alphabetical order. */ static MrmRegisterArg reglist[] = { {"LabelCreateCallback", (caddr_t) LabelCreateCallback}, {"QuitCallback", (caddr_t) QuitCallback} }; static int reglist_num = (sizeof reglist / sizeof reglist [0]); 【7】 static void ProcessMessageRec(messageRecP) MessageRec *messageRecP; { VmsMailboxMessage *mailboxMessageP = &messageRecP->mailboxMessage; int bell = 0; char c, bufA[256]; char *fromBufP = mailboxMessageP->messageA; int fromBufLen = mailboxMessageP->messageLen; char *toBufP; Arg al[1]; XmString labelP; /* If this is a non-null broadcast message, pass it to XmScrolledList. */ if ((mailboxMessageP->type == MSG$_TRMBRDCST) && fromBufLen) { if (fromBufP[fromBufLen-1] != '\n') fromBufP[fromBufLen++] = '\n'; while (fromBufLen) { toBufP = bufA; bell = 0; while (1) { c = *(fromBufP++); fromBufLen--; if (c == 7) bell++; else if (c == '\t') *(toBufP++) = ' '; else if (c == '\n') {*toBufP = 0; break;} else *(toBufP++) = c; } if (bufA[0]) { labelP = XmStringLtoRCreate(bufA,""); XmListAddItem(labelW, labelP, 0); XtFree (labelP); } while (bell--) XBell (XtDisplay (labelW), 0); } } /* Start another asynchronous read. */ StartReadQIO (messageRecP); } 【8】 static unsigned long StartReadQIO(messageRecP) MessageRec *messageRecP; { unsigned long status; status = sys$qio ( MISC_EFN, /* always use this EFN */ mbChan, /* mailbox channel */ IO$_READVBLK, /* function code */ 【9】messageRecP->iosbA, /* IOSB (in message control block) */ 【10】CompletionAst, /* always use this ASTADR */ 【11】AllocateAddInputRec(ProcessMessageRec, messageRecP), /* callback and its argument */ &messageRecP->mailboxMessage, /* buffer address */ sizeof(VmsMailboxMessage), /* buffer length */ 0, 0, 0, 0); /* unused QIO parameters */ return (status); } typedef struct { short bufferLength; short itemCode; char *bufP; unsigned short *bufLenP; } GetjpiItemList; static unsigned long masterPid; static GetjpiItemList masterPidItemListA[2] = { {4, JPI$_MASTER_PID, &masterPid, 0}, {0, 0, 0, 0}}; static char devNameBufA[64]; static unsigned short devNameLen; static GetjpiItemList devNameItemListA[2] = { {sizeof(devNameBufA)-1, JPI$_TERMINAL, devNameBufA, &devNameLen}, {0, 0, 0, 0}}; #define Check(s) if ((status = s) != SS$_NORMAL) return (status) 【12】 static unsigned long StartTrappingMessages() { unsigned long status; unsigned long modeBufA[3]; unsigned short dviBufA[2]; unsigned short iosbA[4]; /* Get the terminal name owned by the master process of our job tree. */ Check (sys$getjpiw (MISC_EFN, 0, 0, masterPidItemListA, iosbA, 0, 0)); Check (iosbA[0]); Check (sys$getjpiw (MISC_EFN, &masterPid, 0, devNameItemListA, iosbA, 0, 0)); Check (iosbA[0]); /* Assign a channel (with mailbox) to that terminal device, and enable * the mailbox so that messages will be sent to it. */ { struct dsc$descriptor_s devNameDsc = {devNameLen, DSC$K_DTYPE_T, DSC$K_CLASS_S, devNameBufA}; int maximumMessageSize = sizeof(VmsMailboxMessage); int bufferQuota = sizeof(VmsMailboxMessage)*32; Check (lib$asn_wth_mbx (&devNameDsc, &maximumMessageSize, &bufferQuota, &devChan, &mbChan)); } { char dummyBufA[4]; Check (sys$qiow (MISC_EFN, devChan, IO$_WRITEVBLK | IO$M_ENABLMBX, iosbA, 0, 0, dummyBufA, 0, 0, 0, 0, 0)); Check (iosbA[0]); } /* Set the terminal NOBROADCAST since messages will be displayed in * our window. */ Check (sys$qiow (MISC_EFN, devChan, IO$_SENSEMODE, iosbA, 0, 0, modeBufA, sizeof(modeBufA), 0, 0, 0, 0)); Check (iosbA[0]); { 【13】modeBufA[1] |= TT$M_NOBRDCST; modeBufA[2] |= TT2$M_BRDCSTMBX; Check (sys$qiow (MISC_EFN, devChan, IO$_SETMODE, iosbA, 0, 0, modeBufA, sizeof(modeBufA), 0, 0, 0, 0)); Check (iosbA[0]); } /* Start the first asynchronous mailbox read. */ 【14】Check (StartReadQIO (&messageRec)); printf("FYI - messages are being trapped\n"); return (SS$_NORMAL); } static int main(argc, argv) int argc; char **argv; { unsigned long status; MrmInitialize(); /* Initialize MRM before initializing /* the X Toolkit. */ /* Initialize the application. */ appW = XtAppInitialize(&app_context, /* App. context is returned */ "btrap$defaults", /* Root class name. */ NULL, /* No option list. */ 0, /* Number of options. */ &argc, /* Address of argc */ argv, /* argv */ NULL, /* No fallback resources */ NULL, /* No override resources */ 0); /* No override resources */ /* Open the UID files (the output of the UIL compiler) in the hierarchy*/ if (MrmOpenHierarchy(db_filename_num, /* Number of files. */ db_filename_vec, /* Array of file names. */ NULL, /* Default OS extenstion. */ &s_MrmHierarchy) /* Pointer to returned MRM ID */ !=MrmSUCCESS) printf("can't open hierarchy"); /* Register the items MRM needs to bind for us. */ MrmRegisterNames(reglist, reglist_num); /* Start to trap messages and do the $QIO read of the mailbox */ 【15】if ((status = StartTrappingMessages ()) != SS$_NORMAL) { printf ("BTrap - Unable to trap broadcast messages"); return (status); }; /* Go get the main part of the application. */ if (MrmFetchWidget(s_MrmHierarchy, "bTrapMain", appW, &mainW, &dummy_class) != MrmSUCCESS) printf("can't fetch main window"); XtManageChild (mainW); /* manage the main window */ XtRealizeWidget (appW); /* realize the widget tree */ XtAppMainLoop(app_context); /* and go to work */ } /* The routine you want to be invoked by XtAppAddInput. * AddInputCallback does not use the tag argument of XtAppAddInput. */ 【16】 static void AddInputCallback() { unsigned long status; AddInputRec *addInputRecP; sys$clref (ADD_INPUT_EFN); /* clear flag so we can be called again */ while (lib$remqhi (addInputQueueHeaderA, &addInputRecP, 0) != LIB$_QUEWASEMP) { (*addInputRecP->routineP) (addInputRecP->closure); XtFree (addInputRecP->mallocP); } } /* Use CompletionAst as the ASTADR parameter on asynchronous system service * calls. This routine must not be called directly from the application. * It adds an application callback to the pending callback list. */ void CompletionAst(addInputRecP) AddInputRec *addInputRecP; { lib$insqti (addInputRecP, addInputQueueHeaderA, 0); sys$setef (ADD_INPUT_EFN); } /* Use AllocateAddInputRec as the ASTPRM parameter on asynchronous system * service calls. Arguments to this routine are the application callback * routine to be called when the system service completes and the parameter * to be passed to that callback. AllocateAddInputRec allocates and * initializes an application callback record to be passed to the * CompletionAst routine at AST level when the system service completes. */ Opaque AllocateAddInputRec(routineP, closure) void (*routineP)(); Opaque closure; { char *mallocP; AddInputRec *addInputRecP; if (!initialized) XtAppAddInput (app_context, ADD_INPUT_EFN, 0, AddInputCallback, 0); mallocP = XtMalloc (sizeof (AddInputRec) + 7); addInputRecP = (AddInputRec *)(((int)(mallocP) + 7) & (-8)); addInputRecP->mallocP = mallocP; addInputRecP->routineP = routineP; addInputRecP->closure = closure; return ((Opaque)addInputRecP); } /* Callback Routines */ static void LabelCreateCallback(w, tag, reason) Widget w; int *tag; XmAnyCallbackStruct *reason; { labelW = w; } static void QuitCallback(w, tag, reason) Widget w; int *tag; XmAnyCallbackStruct *reason; { exit (1); }
MISC_EFNはXtAppAddInputへの呼び出しで指定されたフラグと同じではありません。 なぜなら,そのフラグは入力が保留中であることをツールキットが認識できるようにセットされたままでなければならず, また, 入力が保留中のときにだけXtAppAddInputを呼び出すほうが効率的だからです。
イベント・フラグ番号は,0から31までのイベント・フラグ番号が入っているクラスタ0 に制限されていることに注意してください。
この例では,ProcessMessageRecはブロードキャスト・メッセージのテキストを取得し, それをXmStringに変換してから, XmScrolledListウィジェットの項目リストの最後に追加します。 その後,ProcessMessageRecは別の$QIO読み込みを開始します。
CompletionAstはLIB$INSQTIルーチンを使用して,データ構造体をキューに挿入します(addInputQueueHeaderA) 。CompletionAstがADD_INPUT_ EFNイベント・フラグをセットすると,ツールキットはXtAppAddInput ルーチンを呼び出して,非ASTレベルでできるだけ早く実行します。
このコードは次のように実行されます。
このように実現すると,XtAddInput procの実行を待つことなく, ASTルーチンにいる間に次のQIO読み込み要求をキューに登録する。
{ modeBufA[1] |= TT2$M_BRDCSTMBX; Check (sys$qiow (MISC_EFN, devChan, IO$_SETMODE, iosbA, 0, 0, modeBufA, sizeof(modeBufA), 0, 0, 0, 0)); Check (iosbA[0]); }
ターミナルへのブロードキャスト・メッセージを禁止にする場合には, プログラムの終了時に次のコマンドを入力して,ターミナルへのブロードキャスト・ メッセージを使用できるようにしてください。
$ SET TERMINAL/BROADCAST/NOBRDCSTMBX
この例では,AddInputCallbackはフラグをクリアして,キューからデータ構造体を取り除きます。 *addInputRecP->routinePフィールドは, ウィジェットの呼び出すコールバック・ルーチンであり, addInputRecP->closureフィールドはそのコールバックの引数です。 いずれも使用されていません。
AddInputCallbackは実際にはメッセージ・データを処理せず, ProcessMessageRecルーチンがメッセージ・データをXmScrolledListウィジェットに追加します。
MrmFetchxxxxを使用してUILで割り当てたリソースをフェッチする場合には, 処理の終了後,それらのリソースに関連付けられたメモリを解放しなければなりません。
表 3-1は,UILの値のタイプと, 関連するリソースを解放するためにアプリケーションで使用するルーチンをリストしたものです。
UILの値 | Mrmの値 | 解放するルーチン |
---|---|---|
string_ table | MrmRtypeCStringVector | XtFree |
asciz_table | MrmRtypeChar8Vector | XtFree |
compound_string | MrmRtypeCString | XmStringFree |
string | MrmRtypeChar8 | XtFree |
integer_table | MrmRtypeIntegerVector | XtFree |
integer | MrmRtypeInteger | XtFree |
boolean | MrmRtypeBoolean | XtFree |
rgb | MrmRtypeColor | XFreeColors |
color | MrmRtypeColor | XFreeColors |
color_table | MrmRtypeColorTable | XFreeColors |
float | MrmRtypeFloat | XtFree |
single_float | MrmRtypeSingleFloat | XtFree |
font_table | MrmRtypeFontList | XmFontListFree |
font | MrmRtypeFont | XmFontListFree |
icon | MrmRtypeIconImage | XFreePixmap |
pixmap | MrmRtypeIconImage | XFreePixmap |
xbitmapfile | MrmRtypeXBitmapFile | XFreePixmap |
class_rec_ name | MrmRtypeClassRecName | 解放しない |
keysym | MrmRtypeKeysym | 解放しない |
translation_table | MrmRtypeTransTable | 適用なし |
identifier | MrmRtypeAddrName | 解放しない |
any | MrmRtypeAny | 使用法による |