第2章で窓を開くときに、窓が本当に開いたかを確認するため、Xserverから 送られてくるExposeイベントを取り込んでいました。イベントにはこの他にも たくさんの種類があり、端末で起こるさまざまな状況の変化がイベントとして Xclientに伝えられます。本章ではこのさまざまなイベントのうち、マウスの 状況の変化に関するイベントを受信してマウスで操作できるプログラムの 作り方を解説します。
マウスの状況の変化で発生するイベントは次の3種類です。
Xserverが送信するイベントはイベントキューと呼ばれるバッファに順次格納されます。 格納された順にXclientがそれを受け取っていくことになるのですが、受け取ってくれる Xclientがないと、そのイベントは自然消滅します。
Xserverは実にさまざまなイベントを発生しますが、Xclientが必要としている イベントはそのうちわずかです。Xclientは必要とするイベントの種類を あらかじめ XSelectInput()関数で明示することにより、それらのイベントを 受けとることができます。明示されていないイベントは無視されます。
Prototype
XSelectInput( Display* display, Window window, long event_mask );
event_maskにその窓が受けとるイベントの種類を指定します。 マウス関連でここで指定することができるものは以下の7種類があります。
イベントキューにはその窓に対して、Xserverから送られてくるイベントのうち XSelectInput() で指定した種類のイベントが貯められます。そのイベントをプログラム(Xclient)が受けとるには そのイベントを種々の関数を用いてキューから取り込まなければなりません。 取り込まれたイベントはXEvent型の構造体に格納されます。
イベントを取り込むための関数の一部を紹介します。
Prototype
void XNextEvent( Display* display, XEvent* event );
Bool XCheckMaskEvent( Display* display, long event_mask, XEvent* event );
XNextEvent()関数はイベントキューになにかイベントが入るまで待ちます。 イベントがキューに入るとそれをキューから取り出して、引数で指定した アドレスにあるXEvent型構造体に格納します。
XCheckMaskEvent()関数は指定のイベントマスクの種のイベントが キューに入っていなければ待たずに Falseを返します。あればそのイベントを キューから取り出して、引数で指定したアドレスにあるXEvent型構造体に 格納します。
両方の関数とも、この関数を呼ぶとXFlush()関数も自動的に 呼び出されます。そのため、この関数を連発して呼ぶとマシンへの 負荷が激しく重くなるので、連発しないように工夫してください。
XEvent型のイベント構造体にはイベントの種類の応じてさまざまな種類の情報が格納 されます。ここではマウスに関連するイベントのみについてその内容を紹介します。
例えばevというXEvent型構造体にイベントを取り込んだとしましょう。
ev.typeには取り込んだイベントの種類が記録されています。
例えばButtonPress,ButtonRelease,MotionNotifyなどの値です。
ev.type が ButtonPress または ButtonReleaseの場合には次の変数が利用可能です。
ev.type が MotionNotifyの場合には次の変数が利用可能です。
マウスのイベントを利用して、ボタンを押すたびに直線を描くプログラムを示します。 マウス操作の理解を深めて下さい。
名前はmtest.ccです。是非おためしください。mtest.ccの内容
/* mtest.cc */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
unsigned long GetColor( Display* dis, char* color_name )
{
Colormap cmap;
XColor near_color, true_color;
cmap = DefaultColormap( dis, 0 );
XAllocNamedColor( dis, cmap, color_name, &near_color, &true_color );
return( near_color.pixel );
}
int main( void )
{
Display* dis;
Window win;
XSetWindowAttributes att;
GC gc;
XEvent ev;
dis = XOpenDisplay( NULL );
win = XCreateSimpleWindow( dis, RootWindow(dis,0), 100, 100,
256, 256, 5, WhitePixel(dis,0), BlackPixel(dis,0) );
att.backing_store = WhenMapped;
XChangeWindowAttributes( dis, win, CWBackingStore, &att );
XSelectInput( dis, win, ExposureMask|ButtonPressMask );
XMapWindow( dis, win );
do{
XNextEvent( dis, &ev);
}while( ev.type != Expose );
gc = XCreateGC( dis, DefaultRootWindow(dis), 0, 0 );
XSetForeground( dis, gc, GetColor( dis, "yellow") );
int ox=0,oy=0;
while(1){
XNextEvent( dis, &ev );
if( ev.type != ButtonPress ) continue;
if( ev.xbutton.button == 1 ){
XDrawLine( dis, win, gc, ox, oy, ev.xbutton.x, ev.xbutton.y );
ox = ev.xbutton.x;
oy = ev.xbutton.y;
XFlush( dis );
continue;
}
if( ev.xbutton.button == 3 ){
break;
}
}
XDestroyWindow( dis , win );
XCloseDisplay( dis );
return(0);
}
これで左ボタンで次々に線が引けます。右ボタンでプログラム終了です。