イベントハンドラ

X アプリケーションでは、通常、プログラムはウィジェットに登録されたコールバックを介してイベントに応答します。

一般的にコールバックは X ツールキットから直接起動されます。各ウィジェットにはアクションテーブルと呼ばれる一連の手続きが組み込まれており、既知のタイプのイベントに対して間接的にコールバックを呼び出します。

アクションテーブルもまた間接的に呼び出されます。イベントが到着すると、イベントはウィジェットのトランスレーションテーブルと照合され、特定のイベントシーケンスに対応して呼び出されるアクションが決定されます。

この方法はきわめて間接的であり、しかも、ユーザーがリソースファイルを変更してウィジェットのトランスレーションテーブルを修正してしまう可能性があるため、あまりよい方法ではありません。結果としてイベントに対するウィジェットの応答方法が変更されてしまう可能性があります。

さらに、ウィジェットによっては、組み込みアクションテーブルの内容が豊富でない場合もあります。したがって、用途によっては、組み込み動作の内容が不十分なこともあります。

この問題を回避するには、1 つ以上のイベントハンドラをウィジェットに登録し、特定のイベントタイプに対してはユーザーの手続きを呼び出すよう、X ツールキットに直接要求してください。この方法では、ウィジェットのトランスレーションテーブル機構とアクションテーブル機構は使用されません。

イベントハンドラは、次の手続きによってツールキットに登録されます。

        XtAddEventHandler(Widget      widget,
                          EventMask   mask,
                          Boolean     non_maskable,
                          XtEventProc event_handler,
                          XtPointer   client_data)
このような手続きは次の形式になります。
        void MyEventHandler(Widget    widget,
                            XtPointer client_data,
                            XEvent   *event,
                            Boolean  *continue_to_dispatch)
イベントマスク

イベントマスクは、ユーザーが関心のあるイベントの種類を指定します。一般的なイベントマスクは、ButtonPressMaskButtonReleaseMaskKeyPressMaskEnterWindowMask です。ハンドラで複数の種類のイベントを処理したい場合には、これらの論理和をとることができます。

マスク不可イベント

たとえば、GraphicsExposeClientMessageSelectionNotify など、明示的にフィルタするためのマスクを持たないイベントもあります。ハンドラでこれらのイベントも受け取りたい場合には、ハンドラを登録するときに、non_maskable フラグを「true」に設定してください。

例題

Motif の描画領域には、組み込みコールバックやアクションがほとんどありません。マウスボタン 3 を押すと、描画領域にポップアップメニューが表示されるようにすることがよくあります。

この動作が行われるようにするには、ボタンの押下イベントのイベントハンドラを追加し、イベントを受け取ったときにカーソル位置にメニューをポップアップさせます。この処理は、以下のコードで行います。

        #include <Xm/Xm.h>

        /* (1) マウスボタンの押下イベントを処理するハンドラを作成 */

        void menu_popup_handler(drawing_area,client_data,event)
                Widget               drawing_area ;
                XtPointer            client_data ;
                XButtonPressedEvent *event ;
        {
                extern Widget create_or_pick_some_menu(/* ... */) ;

                Widget popup_menu ;
	/* マウスボタン 3 に対してだけメニューをポップアップします  */
        /* また、マウスボタン 2 にはまったく異なるメニューを割り    */
        /* 当てることができます。メニューの割り当ては、even->button */
	/* により行います。参考: XmMenuPost リソース         */


                if (event-button != Button3) {
                            return ;
                }

 	/* 表示したいメニューを取得します。これは client_data として */
	/* 適切にキャストして渡せます。 			     */

 	/* なお、X-Designer で描画領域メニューを作成した場合には、   */
	/* メニュー階層の作成用に生成された関数が存在します (デフォ */
	/* ルトの場合)。それをここで呼び出すことができます。         */

                popup_menu = create_or_pick_some_menu(/* ... */) ;

                if (popup_menu != (Widget) 0) {
                        /* メニューをカーソル位置に置きます */

                        XmMenuPosition(popup_menu,event) ;

                        /* メニューを表示します */

                        XtManageChild(popup_menu) ;
                }
        }

        /* (2) この描画領域のハンドラをインストールします             */
        /* この操作は、描画領域の作成時に 1 回だけ行う必要があります  */

        void drawing_area_menus_init(drawing_area)
                Widget drawing_area ;
        {
                XtAddEventHandler(drawing_area,
                                  ButtonPressMask,
                                  False,
                                  menu_popup_handler,
                                  NULL) ;  /* または、表示するメニューなど */
        }
X イベントハンドラとマスクの詳細については、X マニュアルを参照してください。

関連項目: