Xt Intrinsicsではイベントはウィジェットに対する一般的なイベントとし ても処理できますし、例えばボタンが押されたとかメニューが選ばれたとかス ライダーが動かされたとかウィジェット固有の動作を定義しておいてそれが発 生したときに呼び出される関数を登録するコールバックという仕組みがありま す。
まず一般的なイベントの処理について見てみましょう。イベントを処理する ルーチンをイベントハンドラーと言います。イベントハンドラーは XtAddEventHandlerによって登録され、XtRemoveEventHandlerによって取り除 くことが出来ます。イベントハンドラーにはどのタイプのイベントを処理する かを教えてやらなければなりません。イベントには名前が付いています。
KeyPress キーボードキーが押された KeyRelease キーボードキーが放された ButtonPress マウスボタンが押された ButtonRelease マウスボタンが放された MotionNotify (マウス移動により)ポインターが移動した EnterNotify ポインターがウインドウ内に入ってきた LeaveNotify ポインターがウインドウから出ていった FocusIn キーボードフォーカスがそのウインドウに来た FocusOut キーボードフォーカスがそのウインドウから抜けた Expose ウィンドウが(他の影などから)晒された
それぞれのイベントに対応するイベントマスクというビットがあります。プロ グラム上はそれぞれのイベントの名前にMaskを付けてあらわします。 (EnterNotifyはEnterWindowMas k、LeaveNofityはLeaveWindowMask、Exposeは ExposureMask、FocusInとFocusOutはともにFocusChangeMaskなどは違いますが。)
では実際にイベントハンドラーを登録しましょう。イベントハンドラーとな る関数は次のような引数を受け付けます。
void user_event_handler( widget, client_data, event, continue_flag ) Widget widget; XtPointer client_data; XEvent *event; Boolean *continue_flag;
widgetはイベントの発生したウインドウを表わします。client_dataはユーザ が引き渡すよう登録したデータで、何でもOK、eventは実際に発生したイベン トをあらわす構造体へのポインター、continue_flagは同じタイプのイベント に対してこの関数以外に登録されたハンドラーも呼び出すかどうかを返りに知 らせるフラッグです。この関数の登録をするXtAddE ventHandlerは
void XtAddEventHandler( widget, event_mask, nonmaskable, proc, client_data ) Widget widget; EventMask event_mask; Boolean nonmaskable; XtEventHandler proc; XtPointer client_data;
widgetはイベント発生元となるウインドウを表わし、event_maskは上で説明し たイベントマスクです。nonmaskableはそれらのイベントとは別のイベントに 登録するときにTRUEとするもので、ここではFALSEと考えてください。procが 先に見た引数を持った関数、client_ dataはこの登録に関連を付けたい任意の データを登録します。数値データでもよいしポインターでも構いません。イベ ントハンドラー側でどう使うかを決めたらそれに従います。例を書くと、
XtAddEventHandler( toplevel, ButtonPressMask | ButtonReleaseMask, FALSE, user_event_handler, ( XtPointer ) NULL );
この例ではtoplevelにイベントハンドラーを登録します。処理したいイベント はボタンが押されたというものとボタンが離されたというもので、受け取る関 数はuser_event_handl erです。データにはNULLを与えています。
では各々のイベントの細かい情報はどうやって知ることが出来るのでしょう か。ユーザが定義したイベントハンドラーの3つめの引数を用います。XEvent 型の構造体へのポインターが渡されます。実はXEvent型というのは共用体 (union)で、起こったイベントによって使われ方が違います。マウスボタンが 押された場合はXButtonEvent構造体をeventが指します。次の例は上述した user_event_handlerの一部です。XEvent構造体へのポインターであるeventを XButtonEvnetへのポインターであるようにキャスト(読み換え)しています。
XButtonEvent *buttonevent; buttonevent = ( XButtonEvent * ) event; buttonevent -> x; /* ボタンが押された位置のx座標 */ buttonevent -> y; /* 同じくy座標 */
などとなります。これらの構造体はXlib.hの中で定義されています。詳しくは Xlib.hを参照してください。
イベントハンドラーは一般的なイベントを処理しますが、例えばボタンウイ ジェットはその上でマウスボタンがクリックされることを想定したウィジェッ トですからもっと簡単に、それが押されたときはこうしようという関数をウィ ジェットに登録することができます。コールバック関数と呼ばれます。コール バック関数もリソースの一種です。ウィジェットにコールバック関数を割り当 てるにはXtAddCallbackを、割当を解除するにはXtRemov eCallbackを呼びます。 コールバック関数は次のような形のものです。
void user_callback( widget, client_data, call_data ) Widget widget; XtPointer client_data; XtPointer call_data;
最初の引数でウィジェットを識別します。2つめの引数は登録時に与えられる ユーザのデータ、最後の引数はコールバックの型によって使われる追加情報を 与えるポインターです。登録をする関数XtAddCallbackは、
void XtAddCallback( widget, callback_name, callback, client_data ) Widget widget; String callback_name; XtCallbackProc callback; XtPointer client_data;
widgetにコールバックが割り当てられますが、リソースですので名前を付ける 必要があります(第2引数)。関数は上の例user_callbackで定義した関数の型を XtCallbackProcとtype defしてあります(第3引数)。最後の引数はユーザが自 由に使えるものです。どのようなときにコールバックが呼ばれるかはウィジェッ トごとに定義されます。次の例を見てください。
void activate_callback( widget, client_data, call_data ) Widget widget; XtPointer client_data; XtPointer call_data; { exit( 0 ); /* 先程のquitbuttonのコールバックのつもり*/ } ... /* ここからはメイン関数の中 pushbuttonウィジェットを宣言した後*/ XtAddCallback( pushbutton, XmNactivateCallback, ( XtCallbackProc ) activate_callback, NULL );
先程の例で作ったpurshbuttonにはいくつかのコールバックがリソースとして 与えられています。XmNactivateCallbackもそのリソースの一つで、 pushbuttonが押された(ポインターがこの図形の上に来てマウスの左ボタンが 押された)ときに呼び出されるコールバックです。ユーザの定義した activate_callbackを登録しています。この宣言の後pushbuttonが押されると activate_callbackが呼ばれることになります。
Xt Intrinsicsでは、様々なリソースを実行時に設定できるようになってい ます。キーボードやボタンを押すといった行動に手続きを割り当てることも実 行時に出来るようになっています。この仕組みはトランスレーションマネージャ と呼ばれます。当然ですが実行時にはプログラムとしては完成しているわけで すから、できることは適当な関数を用意してそれに名前を付けて登録し、アク ションが起こったときにどの関数を呼び出すかを実行時に決めることです。登 録されるべき関数は次のような形をしてなければなりません。
void user_action( widget, event, params, num_params ) Widget widget; XEvent *event; String *params; Cardinal *num_params;
つぎにこういった関数を実行時に参照するための名前を付ける仕組みが必要で す。XtActi onRec構造体を用いてXtAddActions関数によっておこないます。
static XtActionRec useractions[] = { { "useraction1", user_action_1 }, { "useraction2", user_action_2 } }; XtAddActions( useractions, 2 );
これで登録はされましたが、実際の行為(イベント)とは対応していません。イ ベントとアクションの対応をつけるのがトランスレーションです。アクション が定義されるとそのデフォルトトランスレーションを準備しなければなりませ ん。トランスレーションテーブルと呼ばれる文字列変数を用意し、実行時にプ ログラムの中でXtParseTranslationTable関数を用いてコンパイルして、その 結果を使ってXtAugmentTranslation関数もしくはXtOverri deTranslations関 数を用いてウィジェット毎にデフォルトを登録します。
String source = "<Btn1Down>:useraction1()\n\ <Btn2Down>:useraction2( )"; XtTranslations translations; translations = XtParseTranslationTable( source ); XtAugmentTranslations( widget1, translations ); XtOverrideTranslations( widget2, translations );
同じイベントにアクションが既に登録されている場合、XtAugmentTranslation ではもとのままですがXtOverrideTranslationsでは上書きされます。これでデ フォルトアクションは決まりました。ユーザが実行時にトランスレーションテー ブルを与える場合は次のようになります。リソースファイルの中でウィジェッ トにtranslationsというリソースに登録します。
*translations:#override \n\ <Btn1Down>: useraction1( aaa ) \n\ <Btn2Down>: useraction2( bbb, ccc )
任意のウィジェットのtranslationsリソースに対して、<Btn1Down>というイベ ントにuser action1アクションを対応付け、引数(先の例ではparamsと num_paramsで与えられる)に文字列"aaa"が渡されるように宣言します。
これらのイベントの処理はそれが発生したウィジェットに定義されたアクショ ンを呼び出すことになります。しかし実用的にはイベントの発生元にないアク ションを呼び出す手段が欲しくなります。アクセラレータと呼ばれます。例え ばどこのウインドウにいようとあるキーを押すと特定のメニューが出るように したいなどという場合です。
XtInstallAccelerators( destination, source ) Widget destination, source;
この関数を用いるとdestinationウィジェットのacceleratorsリソースに指定 されたイベントが発生するとsourceウィジェットに定義された該当するアクショ ンが起動されます。