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 | 使用法による |