[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ]

# 3 DECwindowsアプリケーションを作成するための有益なヒント

この章では次のトピックについて説明するとともに，プログラミング例も示します。

- DECが提供するウィジェットのUILからの使用

- XmFormウィジェットの使用

- デフォルト・ファイルの使用

- 複数のディスプレイの使用

- カーソルの作成

- XtAddInputルーチンの使用

- UILで割り当てたリソースの解放

# 3.1 DECが提供するウィジェットのUILからの使用

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

# 3.2 XmFormウィジェットについてのヒント

次以降の節で，XmFormウィジェットのプログラミング上のヒントについてさらに説明します。XmForm ウィジェットについて完全に知りたい場合には， 『OSF/Motifプログラマーズ・ リファレンス』を参照してください。

## 3.2.1 子を持つフォーム・ダイアログ・ボックスの作成

XmFormウィジェットの一般的な使用方法として，XmFormウィジェットのサイズが変わっても， 他のウィジェットの位置合わせが変わらないように， それらのウィジェトの行および列を確定することがあります。例 3-1 に示すUILは，このようなXmFormウィジェットを実現している例です。

### 例 3-1 子を持つXmFormダイアログ- UILモジュール

       .
       .
       .
    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;
                };
        };

       .
       .
       .

1. XmFormウィジェットは10個のXmPushButtonウィジェットを制御します。

2. 一番上のXmPushButtonウィジェットはオフセットの25を使用して， 上部と左側をXmFormウィジェットにアタッチします。

3. それ以降のXmPushButtonウィジェットは，すぐ上にあるXmPushButton ウィジェットの底部と左にあるXmFormウィジェットにアタッチします。

   これらの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;
                        };
                };

4. ボタン"f"も"a"と同様，上部をXmFormにアタッチしますが，左側を左にあるXmPushButton にアタッチします。

5. それ以降のXmPushButtonウィジェットは，すぐ上にあるXmPushButton ウィジェットの底部，および左にあるXmPushButton にアタッチします。

   これらのXmPushButtonは，XmATTACH_OPPOSITE_WIDGETを使用して，左側をf_button の左側にアタッチすることもできます。

## 3.2.2 サイズが異なる子の位置合わせ

例 3-1に示している例はXmPushButtonの位置合わせを正しく行い，XmForm のサイズにかかわりなくこの関係を維持します。 ただし，各XmPushButtonウィジェットのサイズが異なる場合，この位置合わせは壊れることがあります。 たとえば，ボタンbのタイトルが長ければ， ボタンgを右に押します。

アプリケーションでさまざまなサイズのウィジェットの位置合わせをする必要がある場合は， 一番大きな子に合わせて拡大するXmRowColumnウィジェットにXmPushButton を置くことができます。そしてXmFormウィジェット内でXmRowColumn ウィジェットの位置合わせをします。

例 3-2に示すUILの例は，サイズが異なる子をもつXmForm ウィジェットを実現します。

### 例 3-2 サイズが異なる子の位置合わせ

       .
       .
       .
    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");
                };
        };
       .
       .
       .

1. XmFormウィジェットは2つのXmRowColumnウィジェットを制御します。

2. XmRowColumnウィジェットのalign_aは，XmFormの上部および左側に位置合わせされます。 このウィジェットはXmPushButtonのaからe までを制御します。境界は表示しません。

3. XmRowColumnウィジェットのalign_bは，XmFormの上部およびalign_a ウィジェットの右側に位置合わせされます。このウィジェットはXmPushButton のfからjまでを制御します。境界は表示しません。

## 3.2.3 XmFormウィジェット内のウィジェットのセンタリング

XmFormウィジェットを使用すると，ウィジェットの辺をXmFormウィジェット内の特定の位置へアタッチすることができます。x およびy座標を使用して位置を指定する代わりに，XmForm ウィジェットの総面積の一部として位置を指定します。 これを百分率位置指定といいます。

このようなアタッチメントの指定は，アタッチメント・タイプ属性の値としてアタッチメント・ タイプ定数XmNATTACH_POSITIONを，およびアタッチメント位置属性の値として分数位置の分子の値を渡すことによって行います。

たとえば，XmFormウィジェットの中間点は2辺間の距離の半分です。 子ウィジェットの左辺をXmFormウィジェットの中間点にアタッチするには， XmNleftAttachment 属性をXmNATTACH_POSITIONに設定し，XmNleftPosition 属性に分子の値50を指定します(省略時の分母は100) 。

XmNleftPosition引数は百分率として扱うこともできます。この場合50という値は50% を意味します。

ただし，これは子ウィジェットの左辺をXmFormウィジェットの中間点に位置合わせしますが， 子ウィジェットはセンタリングされないことに注意してください。 子ウィジェットを中間点にセンタリングするには，次の操作を行います。

- 子ウィジェットの幅と高さを取得する。

- XmNleftPositionとXmNtopPosition属性に値50を指定する。

- 子ウィジェットのサイズの半分に等しい負のオフセットを指定する。

例 3_3と例 3-4 は，オフセット値を使用して子ウィジェットをセンタリングする方法を示しています。MrmNcreateCallback ルーチンは，XmPushButton ウィジェットをそれぞれの位置にセンタリングする，幅と高さのオフセットを計算します。 この位置とオフセットの関係は，XmFormウィジェットでどのようなサイズ変更操作を実行しても維持されます。

### 例 3-3 XmForm内の子ウィジェットのセンタリング- UIL モジュール

       .
       .
       .

    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;
       .
       .
       .

1. XmPushButtonを制御するXmFormウィジェットのインスタンスを作成します。

2. このXmPushButtonはXmFormウィジェットの全体幅の25%，高さの50% でセンタリングされます。

3. XmPushButtonウィジェットが作成されると，center_formプロシージャが呼び出されます。 ウィジェットはフェッチされるときに作成されます。

4. このXmPushButtonはXmFormウィジェットの全体幅の50%，高さの50% でセンタリングされます。

5. このXmPushButtonはXmFormウィジェットの全体幅の75%，高さの50% でセンタリングされます。

### 例 3-4 XmForm内の子ウィジェットの作成- Cモジュール

       .
       .
       .
    #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);

    }
       .
       .
       .

1. XmPushButtonの幅と高さを取得します。

2. 使用するオフセットを計算します。XmPushButtonウィジェットを幅と高さのそれぞれ半分に等しい値でオフセットします。

3. XmPushButtonを左へシフトさせるため，負のXmNleftOffset値としてcalc_width を指定します。

4. XmPushButtonを上へシフトさせるため，負のXmNtopOffset値としてcalc_height を指定します。

## 3.2.4 XmFormウィジェットにおけるXmPushButton の配置

ツールキットにはDXmFormSpaceButtonsEquallyというルーチンが含まれており， アプリケーションはこのルーチンを呼び出して，XmFormウィジェット内の不特定数のプッシュ・ ボタンを，間隔とサイズが等しくなるように設定することができます。DXmFormSpaceButtonsEqually はXmFormウィジェットの幅とXmPushButton の数を判断したのち，それに従ってXmPushButton の間隔とサイズを設定します。

プログラマはDXmFormSpaceButtonsEquallyに，XmPushButtonが入っているXmForm ウィジェットのウィジェットID，変更するXmPushButtonのウィジェットID の配列，ウィジェット配列内のXmPushButtonの数を渡します。

XmPushButtonのIDは，XmFormウィジェットに表示される順に，たとえば「了解」「適用」「リセット」「取消」のように指定しなければなりません。 また，XmPushButtonは左右のアタッチメントを持っていてはなりません。

次のDXmFormSpaceButtonsEquallyの例は，DECburgerサンプル・プログラムからの引用です。 この例はXmFormDialogウィジェット内で「了解」， 「適用」，「リセット」，「取消」の各プッシュ・ボタンのスペース設定を行っています。

### 例 3-5 DXmFormSpaceButtonsEquallyルーチンの呼び出し

       .
       .
       .
    #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();
        }
    }

# 3.3 デフォルト・ファイルの使用

『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.4 変更した設定を保管するためのデフォルト・ ファイルの使用

多くのアプリケーションには，ユーザがアプリケーションの設定を変更し， あとでそのアプリケーションを起動するときのために，それらの設定を保管できるオプションがあります。 例 3_6と例 3-7 は，メイン・ウィンドウのXmNwidth およびXmNheightリソースをユーザが設定して保管できるアプリケーションを実現しています。

### 例 3-6 アプリケーションの省略時の値の保管- UILモジュール

       .
       .
       .
    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;

1. この例はユーザにXmNwidthおよびXmNheightの省略時の値を決定させるため，XmNwidth とXmNheightの値はこのモジュール中にコーディングされていません。

2. "Save Settings"のXmCascadeButtonを宣言します。

3. "Save Width and Height"のXmPushButtonを宣言します。このプッシュ・ ボタンのアクティベート・コールバックは，省略時の値を保管するルーチンを呼び出します。

4. "Exit"のXmPushButtonを宣言します。このプッシュ・ボタンのアクティベート・ コールバックは，終了ルーチンを呼び出します。

5. XmForm，XmRowColumn，XmPushButtonウィジェットを宣言して， アプリケーションを終了します。

### 例 3-7 アプリケーションの省略時の値の保管- C モジュール

       .
       .
       .

    /* 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);
    }
       .
       .
       .

1. Xrmリソース・マネージャ・ルーチンへの呼び出しにおいて， デフォルト・ファイル名を指定するための定数を定義します。

2. application_class引数(この場合"example")は，"example"という名前のデフォルト・ ファイルを指定します。ファイル・タイプは省略時の設定により.dat です。XtAppInitializeルーチンはアプリケーションの実行時， デフォルト・ファイルがあれば自動的にそれを使用します。

3. push_meプッシュ・ボタンのコールバックによって呼び出される， 省略時の値の保管ルーチン。

4. ディスクからデフォルト・ファイルを取得します。

5. XmNwidthおよびXmNheightの現在値を取得します。

6. update_databaseルーチンを呼び出して，save_heightおよびsave_width の整数値を文字列に変換し，それらの文字列をXrmValueデータ構造体に格納します。 このデータ構造体はXrmPutResourceルーチンが必要とするフォーマットです。

   リソースは『X Window System』に記述されているフォーマットに従って指定しなければなりません。 たとえば"example*main_window.width"のように指定します。

7. デフォルト・ファイルをディスクに格納します。

8. XrmValueデータ構造体は文字列およびその長さで初期化されます。 その後XrmValueデータ構造体のアドレスが，引数としてXrmPutResource ルーチンへ渡されます。

# 3.5 複数のディスプレイの使用

ツールキットを使用すると，アプリケーションは複数のディスプレイをオープンすることができます。 複数のディスプレイをオープンすることによって，1 つのアプリケーションの独立したインスタンスを複数のワークテーション上で実行したり， アプリケーションのインスタンスを相互に接続することができます。 複数のディスプレイをオープンするには，次のコマンド・ シーケンスを使用します。

1. XtToolkitInitialize (1回)

2. XtCreateApplicationContext (1回)

3. XtOpenDisplay (複数回)

4. XtAppCreateShell (複数回)

5. XtAppMainLoop (1回)

6. MrmFetchWidget (複数のMainウィジェットをフェッチするために複数回)

7. XtManageChild (複数のMainウィジェットを管理するために複数回)

8. XtRealizeWidget (複数のアプリケーション・シェルについて複数回)

複数のディスプレイ名をアプリケーション中にコーディングする必要はありません。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.5.1 複数の独立したディスプレイの使用

例 3_8と例 3-9 は，第3.2.3項に示したウィジェットのセンタリング例のバージョンを実現しています。 この例は2 つのディスプレイをオープンし，アプリケーションの独立したインスタンスを実行します。UIL ファイルが共用されていることに注意してください。

### 例 3-8 複数の独立したディスプレイの使用- 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;
       .
       .
       .

### 例 3-9 複数の独立したディスプレイの使用- Cモジュール

       .
       .
       .
    #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);

    }
       .
       .
       .

1. この例は2つのアプリケーション・シェルと，2つのXmFormウィジェットを必要とします。

2. 1つのUIDファイルがアプリケーションのインスタンス間で共有されています。

3. オープンする各ディスプレイについて，1つのDisplayデータ構造体を宣言します。

4. ツールキットを一度だけ初期化する必要があります。

5. アプリケーション・コンテキストを1つだけ作成する必要があります。

6. オープンしたい各ディスプレイについてXtOpenDisplayを呼び出します。

7. アプリケーションの各インスタンスについて最上位のシェルを作成します。

8. アプリケーションの各インスタンスについて，ウィジェット階層のインスタンスをフェッチします。

9. アプリケーションの各インスタンスについてMainウィジェットを管理します。

10. アプリケーションの各インスタンスについて最上位のシェルを実現します。

11. アプリケーション・コンテキストは1つだけなので， XtAppMainLoopを一度だけ呼び出す必要があります。

## 3.5.2 相互に接続された複数ディスプレイの使用

例 3-10は，2つのマルチラインCSTextウィジェットを相互に接続するアプリケーションを実現しています。 一方のウィジェットに入力されたテキストは，2 つのウィジェットが同じファイルを同時に編集しているかのように， 別のウィジェットにも反映されます。

### 例 3-10 相互に接続された複数ディスプレイの使用

       .
       .
       .
    #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;
    }
       .
       .
       .

1. この例は，アプリケーション・シェルとすべてのウィジェットの複数のインスタンスを使用します。

2. オープンする各ディスプレイについて，1つのDisplayデータ構造体を宣言します。

3. ツールキットを一度だけ初期化する必要があります。

4. アプリケーション・コンテキストを1つだけ作成する必要があります。

5. オープンしたい各ディスプレイについてXtOpenDisplayを呼び出します。 アプリケーションはSET DISPLAYコマンドへの最後の呼び出しと， アプリケーション中にコーディングされているディスプレイ名で識別されるディスプレイをオープンします。

6. アプリケーションの各インスタンスについて最上位のシェルを作成します。

7. アプリケーションの各インスタンスについてXmBulletinBoard ウィジェットを作成します。引数リストは共有されます。

8. アプリケーションの各インスタンスについて，スクロールするCSText ウィジェットを作成します。呼び出すXmNvalueChangedCallback ルーチンを含め，引数リストは共有されます。

9. 両方のCSTextウィジェットを管理します。

10. 両方のXmBulletinBoardウィジェットを管理します。

11. 両方の最上位のシェルを実現します。

12. すべてが実現されるまで，value changedコールバックが呼び出されないようにします。

13. アプリケーション・コンテキストは1つだけなので， XtAppMainLoopを一度だけ呼び出す必要があります。

14. ユーザがテキストを入力すると，このコールバック・ルーチンが呼び出されます。

15. 最上位のシェルが実現されるまで，このコールバックが呼び出されないようにします。

16. このコールバック・ルーチンの呼び出しが完了するまで，コールバック・ ルーチンが呼び出されないようにします。

17. ユーザが新たに入力したテキストを取得します。

18. 文字列の最後の文字位置を取得します。

19. 2つのCSTextウィジェットのうちのどちらがコールバックを生成して， もう一方のウィジェットのテキストと挿入位置を設定したかを判別します。

# 3.6 カーソルの作成

ツールキットには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ルーチンを使用して待機カーソルを作成し， そのカーソルをアプリケーションのウィンドウで使用するように定義した後， 親(もと)のカーソルを復元する方法を示しています。 カーソルは一度だけ作成する必要があり，その後は必要に応じてそのカーソルを定義したり， 定義を解除することができます。

### 例 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));

# 3.7 XtAppAddInputルーチンの使用

『X Window System Toolkit』で説明されているように，XtAppAddInputルーチンを使用することにより， 入力の代替ソースをツールキットに登録することができます。 この代替ソースからの入力が利用できるようになると， Intrinsicsは提供されているコールバック・ルーチンを呼び出して，入力が利用できることを通知します。

XtAppAddInputルーチンには，オペレーティング・システムに依存する引数がいくつかあります。 『X Window System Toolkit』では，UNIXおよびWindows NTシステム上で使われるXtAppAddInputルーチンについて説明してあります。

注意
  本節は，OpenVMSシステムにのみ， 適用されます。

OpenVMS環境において，XtAppAddInputルーチンの呼び出しに使用される引数は， 次のとおりです。

1. アプリケーション・コンテキスト。

2. モニタするイベント・フラグ。Intrinsicsはこのフラグがセットされていることを認めると， プログラマが指定するXtInputCallbackProc ルーチンを呼び出す。イベント・フラグの番号は，0 から31までのイベント・フラグ番号を含むクラスタ0に制限されている。 詳しい説明は『OpenVMS System Services Reference Manual』を参照。イベント・フラグ0はXtAddInputイベント・フラグとして使用できない。

3. 状態戻りコードの入出力状態バイト(IOSB)。この引数は0でもよい。

4. 入力が利用できるとき，つまりイベント・フラグがセットされているときに呼び出したいXtInputCallbackProc ルーチン。

5. XtInputCallbackProcルーチンへ渡すデータ。

アプリケーションには，入力が利用できることを知らせるために，イベント・ フラグをセットする方法が必要です。イベント・フラグをセットするもっとも一般的な方法は，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

注意
  このプログラムをテストする方法として， プログラムを漢字端末エミュレータのウィンドウから実行し， そのウィンドウに入力フォーカスを与え，Ctrl/Tを押してトラップさせるブロードキャスト・ メッセージを生成する方法があります。

### 例 3-12 XtAppAddInputルーチンの使用- UIL モジュール

    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. ブロードキャスト・メッセージを受信するためのXmScrolledList ウィジェットを作成し，それをXmFormウィジェットにアタッチします。

### 例 3-13 XtAppAddInputルーチンの使用- Cモジュール

    【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);
    }

1. ツールキットのウィジェット定義を取り込みます。メールボックスを設定してメッセージをトラップするために， 追加のインクルード・ ファイルが必要です。

2. このイベント・フラグは$QIOシステム・サービス・ルーチンへ渡され，XtAppAddInput への呼び出しで指定されたイベント・フラグから区別されます。$QIO システム・サービス・ルーチンは，実行を開始するとフラグをクリアし， 成功か不成功かにかかわらず入出力が終了するとフラグをセットします。

   MISC_EFNはXtAppAddInputへの呼び出しで指定されたフラグと同じではありません。 なぜなら，そのフラグは入力が保留中であることをツールキットが認識できるようにセットされたままでなければならず， また， 入力が保留中のときにだけXtAppAddInputを呼び出すほうが効率的だからです。

   イベント・フラグ番号は，0から31までのイベント・フラグ番号が入っているクラスタ0 に制限されていることに注意してください。

3. メールボックスのメッセージを格納するために使用される構造体。

4. メールボックス・メッセージの構造体に関する情報が入っている制御ブロック。 この制御ブロックは，メッセージの文字列の値を取得するために， 入出力終了ルーチンへ渡されます。

5. このイベント・フラグはXtAppAddInputへの呼び出しで指定されます。AST 終了ルーチン(CompletionAst)は，呼び出されるたびにこのフラグをセットします。 このフラグは入力が保留中であることをツールキットが認識できるようにセットされなければならないため， XtAppAddInputへの呼び出しで指定されるフラグと同じです。

6. アプリケーション・コンテキストを宣言します。

7. AllocateAddInputRecは非同期システム・サービス呼び出しにおけるASTPRM パラメータです。AllocateAddInputRecの引数には， アプリケーション固有の呼び出されるコールバック・ルーチン(ProcessMessageRec) と，そのコールバックへ渡されるパラメータ(メールボックス・ メッセージ)があります。

   この例では，ProcessMessageRecはブロードキャスト・メッセージのテキストを取得し， それをXmStringに変換してから， XmScrolledListウィジェットの項目リストの最後に追加します。 その後，ProcessMessageRecは別の$QIO読み込みを開始します。

8. ブロードキャスト・メールボックスに関する非同期の読み込みを開始します。 このルーチンはMrmFetchWidgetへの呼び出しの前に， StartTrappingMessagesルーチンによって呼び出されます。

9. IOSBが，読み込み終了ルーチンで利用できるように，メッセージ制御ブロックに埋め込まれます。IOSB は$QIO読み込みの状態を反映します。

10. AST読み込み終了ルーチン。CompletionAstは通知の目的のみに使用され， 読み込みによって返されるデータは処理しません。 CompletionAstは1つの引数，つまりAllocateAddInputRecによって返されるaddInputRecP データ構造体を指定して呼び出されます。このデータ構造体にはアプリケーション( ウィジェット)コールバックとタグが入ります。

    CompletionAstはLIB$INSQTIルーチンを使用して，データ構造体をキューに挿入します(addInputQueueHeaderA) 。CompletionAstがADD_INPUT_ EFNイベント・フラグをセットすると，ツールキットはXtAppAddInput ルーチンを呼び出して，非ASTレベルでできるだけ早く実行します。

11. AllocateAddInputRecはASTPRMパラメータとして使用されます。 これは$QIOシステム・サービスであって，$QIOWではないことに注意してください。AllocateAddInputRec は$QIO読み込みが終了したのちに呼び出されますが，CompletionAst AST 読み込み終了ルーチンが呼び出される前です。

    このコードは次のように実行されます。

    1. AllocateAddInputRecがXtAppAddInputによって呼び出されるルーチンを設定する。

    2. AllocateAddInputRecが，割り当てられたスペース，アプリケーション( ウィジェット)コールバック，およびタグを含み，AST レベルでCompletionAstルーチンへ渡されるデータ構造体を割り当てて初期化する。 このデータ構造体は，アプリケーションの必要に応じて使用できる。

    3. ProcessMessageRecルーチンが，メッセージ・データを引数として呼び出される。ProcessMessageRec はシステム・サービスの終了時にも呼び出されるが，CompletionAst AST 読み込み終了ルーチンが呼び出される前であることに注意する。 このため， CompletionAstが呼び出されるまでには，ProcessMessageRecはすでにそのデータを処理し， 別の$QIO読み込みを開始している。

       このように実現すると，XtAddInput procの実行を待つことなく， ASTルーチンにいる間に次のQIO読み込み要求をキューに登録する。

12. メールボックスを設定してメッセージをトラップします。

13. この例はターミナルへのブロードキャスト・メッセージが使用できないことに注意してください。 ターミナルへのブロードキャスト・ メッセージを禁止にしたくない場合は，メールボックスへのブロードキャストだけを使用できるようにコードを変更することもできます。

              {
              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

14. ブロードキャスト・メールボックスに関して最初の非同期読み込みを開始します。

15. MrmFetchWidgetへの呼び出しの前に，StartTrappingMessages が呼び出されます。

16. ツールキットはADD_INPUT_EFNフラグがセットされていることを認め，XtAppAddInput で指定されたルーチン(この場合はAddInputCallback ) を呼び出します。AddInputCallbackルーチンのアプリケーションのバージョンでは， アプリケーション固有の機能が実行できます。

    この例では，AddInputCallbackはフラグをクリアして，キューからデータ構造体を取り除きます。 *addInputRecP->routinePフィールドは， ウィジェットの呼び出すコールバック・ルーチンであり， addInputRecP->closureフィールドはそのコールバックの引数です。 いずれも使用されていません。

    AddInputCallbackは実際にはメッセージ・データを処理せず， ProcessMessageRecルーチンがメッセージ・データをXmScrolledListウィジェットに追加します。

# 3.8 UILで割り当てられたリソースの解放

MrmFetchxxxxを使用してUILで割り当てたリソースをフェッチする場合には， 処理の終了後，それらのリソースに関連付けられたメモリを解放しなければなりません。

表 3-1は，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 | 使用法による

[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ]