summaryrefslogtreecommitdiffstats
path: root/otherlibs/graph/events.c
blob: cd944045889889da6e74e83a0c3b19a77557967a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/***********************************************************************/
/*                                                                     */
/*                           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(c)
     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(eventlist)
     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;
}