ocaml/otherlibs/graph/events.c

140 lines
4.3 KiB
C

/***********************************************************************/
/* */
/* Objective Caml */
/* */
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
/* */
/* Copyright 1996 Institut National de Recherche en Informatique et */
/* Automatique. Distributed only by permission. */
/* */
/***********************************************************************/
/* $Id$ */
#include <signal.h>
#include "libgraph.h"
#include <alloc.h>
static unsigned char gr_queue[SIZE_QUEUE];
static int gr_head = 0; /* position of next read */
static int gr_tail = 0; /* position of next write */
#define QueueIsEmpty (gr_head == gr_tail)
#define QueueIsFull (gr_head == gr_tail + 1)
void gr_enqueue_char(unsigned char c)
{
if (QueueIsFull) return;
gr_queue[gr_tail] = c;
gr_tail++;
if (gr_tail >= SIZE_QUEUE) gr_tail = 0;
}
value gr_wait_event(value eventlist)
{
value res;
int mask;
Bool poll;
int mouse_x, mouse_y, button, key;
Window rootwin, childwin;
int root_x, root_y, win_x, win_y;
unsigned int modifiers;
#ifdef POSIX_SIGNALS
struct sigaction sigact, oldsig;
#else
void (*oldsig)();
#endif
XEvent event;
gr_check_open();
mask = 0;
poll = False;
while (eventlist != Val_int(0)) {
switch (Int_val(Field(eventlist, 0))) {
case 0: /* Button_down */
mask |= ButtonPressMask | OwnerGrabButtonMask; break;
case 1: /* Button_up */
mask |= ButtonReleaseMask | OwnerGrabButtonMask; break;
case 2: /* Key_pressed */
mask |= KeyPressMask; break;
case 3: /* Mouse_motion */
mask |= PointerMotionMask; break;
case 4: /* Poll */
poll = True; break;
}
eventlist = Field(eventlist, 1);
}
mouse_x = -1;
mouse_y = -1;
button = 0;
key = 0x100;
if (poll) {
if (XQueryPointer(grdisplay, grwindow.win,
&rootwin, &childwin,
&root_x, &root_y, &win_x, &win_y,
&modifiers)) {
mouse_x = win_x;
mouse_y = win_y;
}
button = modifiers & Button1Mask;
if (!QueueIsEmpty) key = gr_queue[gr_head];
} else {
if ((mask & KeyPressMask) && !QueueIsEmpty) {
key = gr_queue[gr_head];
gr_head++;
if (gr_head >= SIZE_QUEUE) gr_head = 0;
} else {
#ifdef POSIX_SIGNALS
sigact.sa_handler = SIG_IGN;
sigaction(EVENT_SIGNAL, &sigact, &oldsig);
#else
oldsig = signal(EVENT_SIGNAL, SIG_IGN);
#endif
XSelectInput(grdisplay, grwindow.win, DEFAULT_EVENT_MASK | mask);
again:
XNextEvent(grdisplay, &event);
switch(event.type) {
case ButtonPress:
case ButtonRelease:
mouse_x = event.xbutton.x;
mouse_y = event.xbutton.y;
button = event.type == ButtonPress;
break;
case MotionNotify:
mouse_x = event.xmotion.x;
mouse_y = event.xmotion.y;
button = event.xmotion.state & Button1Mask;
break;
case KeyPress:
gr_handle_simple_event(&event);
/* Some KeyPress events do not enqueue any characters (e.g. pressing
Ctrl), because they expand via XLookupString to the empty string.
Therefore we need to check again whether the char queue is empty. */
if ((mask & KeyPressMask) == 0 || QueueIsEmpty) goto again;
key = gr_queue[gr_head];
gr_head++;
if (gr_head >= SIZE_QUEUE) gr_head = 0;
break;
default:
gr_handle_simple_event(&event);
goto again;
}
#ifdef POSIX_SIGNALS
sigaction(EVENT_SIGNAL, &oldsig, NULL);
#else
signal(EVENT_SIGNAL, oldsig);
#endif
XSelectInput(grdisplay, grwindow.win, DEFAULT_EVENT_MASK);
XFlush(grdisplay);
}
}
res = alloc_tuple(5);
Field(res, 0) = Val_int(mouse_x);
Field(res, 1) = Val_int(mouse_y == -1 ? -1 : Wcvt(mouse_y));
Field(res, 2) = Val_bool(button);
Field(res, 3) = Val_bool(key != 0x100);
Field(res, 4) = Val_int(key & 0xFF);
return res;
}