/***********************************************************************/ /* */ /* Objective Caml */ /* */ /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ /* */ /* Copyright 1996 Institut National de Recherche en Informatique et */ /* en Automatique. All rights reserved. This file is distributed */ /* under the terms of the GNU Library General Public License. */ /* */ /***********************************************************************/ /* $Id$ */ #include #include "libgraph.h" #include 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 | Button2Mask | Button3Mask | Button4Mask | Button5Mask); 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 | Button2Mask | Button3Mask | Button4Mask | Button5Mask); 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_small(5, 0); 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; }