]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkevents.c
Handle Control-digits specially.
[~andy/gtk] / gdk / gdkevents.c
index f473692a4eaa464170985184a446a9b103b43d8b..159e0ee9e5e2c0eab84517353ae90af0cb67c419 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
 #include "gdk.h"
 #include "gdkx.h"
 #include "gdkprivate.h"
 #include "gdkinput.h"
 #include "gdkkeysyms.h"
 
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <string.h>
+#  endif
+#endif
+
+
 typedef struct _GdkIOClosure GdkIOClosure;
+typedef struct _GdkEventPrivate GdkEventPrivate;
 
 #define DOUBLE_CLICK_TIME      250
 #define TRIPLE_CLICK_TIME      500
 #define DOUBLE_CLICK_DIST      5
 #define TRIPLE_CLICK_DIST      5
 
-struct _GdkIOClosure {
+typedef enum
+{
+  /* Following flag is set for events on the event queue during
+   * translation and cleared afterwards.
+   */
+  GDK_EVENT_PENDING = 1 << 0
+} GdkEventFlags;
+
+struct _GdkIOClosure
+{
   GdkInputFunction function;
   GdkInputCondition condition;
   GdkDestroyNotify notify;
   gpointer data;
 };
 
+struct _GdkEventPrivate
+{
+  GdkEvent event;
+  guint    flags;
+};
+
 /* 
  * Private function declarations
  */
 
 static GdkEvent *gdk_event_new         (void);
-static gint     gdk_event_apply_filters (XEvent *xevent,
+static gint     gdk_event_apply_filters (XEvent   *xevent,
                                          GdkEvent *event,
-                                         GList *filters);
+                                         GList    *filters);
 static gint     gdk_event_translate     (GdkEvent *event, 
                                          XEvent   *xevent);
 #if 0
-static Bool     gdk_event_get_type     (Display      *display, 
-                                        XEvent       *xevent, 
-                                        XPointer      arg);
+static Bool     gdk_event_get_type     (Display   *display, 
+                                        XEvent    *xevent, 
+                                        XPointer   arg);
 #endif
 static void      gdk_events_queue       (void);
-static GdkEvent *gdk_event_unqueue      (void);
+static GdkEventgdk_event_unqueue      (void);
 
-static gboolean  gdk_event_prepare      (gpointer  source_data, 
-                                        GTimeVal *current_time,
-                                        gint     *timeout);
-static gboolean  gdk_event_check        (gpointer  source_data,
-                                        GTimeVal *current_time);
-static gboolean  gdk_event_dispatch     (gpointer  source_data,
-                                        GTimeVal *current_time,
-                                        gpointer  user_data);
+static gboolean  gdk_event_prepare      (gpointer   source_data, 
+                                        GTimeVal  *current_time,
+                                        gint      *timeout);
+static gboolean  gdk_event_check        (gpointer   source_data,
+                                        GTimeVal  *current_time);
+static gboolean  gdk_event_dispatch     (gpointer   source_data,
+                                        GTimeVal  *current_time,
+                                        gpointer   user_data);
 
-static void     gdk_synthesize_click   (GdkEvent     *event, 
-                                        gint          nclicks);
+static void     gdk_synthesize_click   (GdkEvent  *event, 
+                                        gint       nclicks);
 
 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
                                         GdkEvent  *event,
@@ -90,21 +121,17 @@ static GdkWindow *button_window[2];            /* The last 2 windows to receive button
                                             */
 static guint button_number[2];             /* The last 2 buttons to be pressed.
                                             */
-static GdkEventFunc   event_func;          /* Callback for events */
-static gpointer       event_data;
-static GDestroyNotify event_notify;
+static GdkEventFunc   event_func = NULL;    /* Callback for events */
+static gpointer       event_data = NULL;
+static GDestroyNotify event_notify = NULL;
 
-static GList *client_filters;                      /* Filters for client messages */
+static GList *client_filters;              /* Filters for client messages */
 
 /* FIFO's for event queue, and for events put back using
- * gdk_event_put(). We keep separate queues so that
- * we can make the putback events both FIFO and preemptive
- * of pending events.
+ * gdk_event_put().
  */
 static GList *queued_events = NULL;
 static GList *queued_tail = NULL;
-static GList *putback_events = NULL;
-static GList *putback_tail = NULL;
 
 static GSourceFuncs event_funcs = {
   gdk_event_prepare,
@@ -115,6 +142,79 @@ static GSourceFuncs event_funcs = {
 
 GPollFD event_poll_fd;
 
+/*********************************************
+ * Functions for maintaining the event queue *
+ *********************************************/
+
+/*************************************************************
+ * gdk_event_queue_find_first:
+ *     Find the first event on the queue that is not still
+ *     being filled in.
+ *   arguments:
+ *     
+ *   results:
+ *     Pointer to the list node for that event, or NULL
+ *************************************************************/
+
+static GList*
+gdk_event_queue_find_first (void)
+{
+  GList *tmp_list = queued_events;
+
+  while (tmp_list)
+    {
+      GdkEventPrivate *event = tmp_list->data;
+      if (!(event->flags & GDK_EVENT_PENDING))
+       return tmp_list;
+
+      tmp_list = g_list_next (tmp_list);
+    }
+
+  return NULL;
+}
+
+/*************************************************************
+ * gdk_event_queue_remove_link:
+ *     Remove a specified list node from the event queue.
+ *   arguments:
+ *     node: Node to remove.
+ *   results:
+ *************************************************************/
+
+static void
+gdk_event_queue_remove_link (GList *node)
+{
+  if (node->prev)
+    node->prev->next = node->next;
+  else
+    queued_events = node->next;
+  
+  if (node->next)
+    node->next->prev = node->prev;
+  else
+    queued_tail = node->prev;
+  
+}
+
+/*************************************************************
+ * gdk_event_queue_append:
+ *     Append an event onto the tail of the event queue.
+ *   arguments:
+ *     event: Event to append.
+ *   results:
+ *************************************************************/
+
+static void
+gdk_event_queue_append (GdkEvent *event)
+{
+  queued_tail = g_list_append (queued_tail, event);
+  
+  if (!queued_events)
+    queued_events = queued_tail;
+  else
+    queued_tail = queued_tail->next;
+}
+
 void 
 gdk_events_init (void)
 {
@@ -122,17 +222,13 @@ gdk_events_init (void)
   GDK_NOTE (MISC,
            g_message ("connection number: %d", connection_number));
 
-  g_source_add (-10, TRUE, &event_funcs, NULL, NULL, NULL);
+  g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
 
   event_poll_fd.fd = connection_number;
   event_poll_fd.events = G_IO_IN;
   
-  g_main_add_poll (-10, &event_poll_fd);
+  g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
 
-  /* This is really crappy. We have to look into the display structure
-   *  to find the base resource id. This is only needed for recording
-   *  and playback of events.
-   */
   button_click_time[0] = 0;
   button_click_time[1] = 0;
   button_window[0] = NULL;
@@ -160,10 +256,10 @@ gdk_events_init (void)
  *--------------------------------------------------------------
  */
 
-gint
+gboolean
 gdk_events_pending (void)
 {
-  return g_main_pending();
+  return (gdk_event_queue_find_first() || XPending (gdk_display));
 }
 
 /*
@@ -183,23 +279,23 @@ gdk_events_pending (void)
  *-------------------------------------------------------------- */
 
 static Bool
-graphics_expose_predicate  (Display  *display,
-                           XEvent   *xevent,
-                           XPointer  arg)
+graphics_expose_predicate (Display  *display,
+                          XEvent   *xevent,
+                          XPointer  arg)
 {
-  GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
+  GdkWindowPrivate *private = (GdkWindowPrivate*) arg;
   
   g_return_val_if_fail (private != NULL, False);
   
-  if ((xevent->xany.window == private->xwindow) &&
-      ((xevent->xany.type == GraphicsExpose) ||
-       (xevent->xany.type == NoExpose)))
+  if (xevent->xany.window == private->xwindow &&
+      (xevent->xany.type == GraphicsExpose ||
+       xevent->xany.type == NoExpose))
     return True;
   else
     return False;
 }
 
-GdkEvent *
+GdkEvent*
 gdk_event_get_graphics_expose (GdkWindow *window)
 {
   XEvent xevent;
@@ -207,7 +303,7 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   
   g_return_val_if_fail (window != NULL, NULL);
   
-  XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window);
+  XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window);
   
   if (xevent.xany.type == GraphicsExpose)
     {
@@ -282,29 +378,43 @@ gdk_add_rect_to_rects (GdkRectangle *rect1,
 
 typedef struct _GdkExposeInfo GdkExposeInfo;
 
-struct _GdkExposeInfo {
+struct _GdkExposeInfo
+{
   Window window;
   gboolean seen_nonmatching;
 };
 
-Bool
-expose_predicate (Display *display, XEvent *xevent, XPointer arg)
+static Bool
+expose_predicate (Display *display,
+                 XEvent  *xevent,
+                 XPointer arg)
 {
-  GdkExposeInfo *info = (GdkExposeInfo *)arg;
-
-  if (xevent->xany.type != Expose)
+  GdkExposeInfo *info = (GdkExposeInfo*) arg;
+
+  /* Compressing across GravityNotify events is safe, because
+   * we completely ignore them, so they can't change what
+   * we are going to draw. Compressing across GravityNotify
+   * events is necessay because during window-unshading animation
+   * we'll get a whole bunch of them interspersed with
+   * expose events.
+   */
+  if (xevent->xany.type != Expose && 
+      xevent->xany.type != GravityNotify)
     {
       info->seen_nonmatching = TRUE;
     }
 
-  if (info->seen_nonmatching || (xevent->xany.window != info->window))
+  if (info->seen_nonmatching ||
+      xevent->xany.type != Expose ||
+      xevent->xany.window != info->window)
     return FALSE;
   else
     return TRUE;
 }
 
 void
-gdk_compress_exposures (XEvent *xevent, GdkWindow *window)
+gdk_compress_exposures (XEvent    *xevent,
+                       GdkWindow *window)
 {
   gint nrects = 1;
   gint count = 0;
@@ -426,7 +536,7 @@ gdk_event_handler_set (GdkEventFunc   func,
                       gpointer       data,
                       GDestroyNotify notify)
 {
-  if (event_func && event_notify)
+  if (event_notify)
     (*event_notify) (event_data);
 
   event_func = func;
@@ -443,47 +553,65 @@ gdk_event_handler_set (GdkEventFunc   func,
  * Arguments:
  *
  * Results:
- *   If an event was received that we care about, returns 
+ *   If an event is waiting that we care about, returns 
  *   a pointer to that event, to be freed with gdk_event_free.
- *   Otherwise, returns NULL. This function will also return
- *   before an event is received if the timeout interval
- *   runs out.
+ *   Otherwise, returns NULL.
  *
  * Side effects:
  *
  *--------------------------------------------------------------
  */
 
-GdkEvent *
+GdkEvent*
 gdk_event_get (void)
 {
-  gdk_events_queue();
+  gdk_events_queue ();
 
-  return gdk_event_unqueue();
+  return gdk_event_unqueue ();
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_peek
+ *
+ *   Gets the next event.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   If an event is waiting that we care about, returns 
+ *   a copy of that event, but does not remove it from
+ *   the queue. The pointer is to be freed with gdk_event_free.
+ *   Otherwise, returns NULL.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+GdkEvent*
+gdk_event_peek (void)
+{
+  GList *tmp_list;
+
+  tmp_list = gdk_event_queue_find_first ();
+  
+  if (tmp_list)
+    return gdk_event_copy (tmp_list->data);
+  else
+    return NULL;
 }
 
 void
 gdk_event_put (GdkEvent *event)
 {
   GdkEvent *new_event;
-  GList *tmp_list;
   
   g_return_if_fail (event != NULL);
   
   new_event = gdk_event_copy (event);
 
-  tmp_list = g_list_alloc();
-  tmp_list->prev = putback_tail;
-  tmp_list->next = NULL;
-  tmp_list->data = new_event;
-
-  if (!putback_events)
-    {
-      putback_events = tmp_list;
-      putback_tail = tmp_list;
-    }
-  else
-    putback_tail->next = tmp_list;
+  gdk_event_queue_append (new_event);
 }
 
 /*
@@ -504,22 +632,23 @@ gdk_event_put (GdkEvent *event)
  *--------------------------------------------------------------
  */
 
-static GMemChunk *event_chunk;
+static GMemChunk *event_chunk = NULL;
 
 static GdkEvent*
 gdk_event_new (void)
 {
-  GdkEvent *new_event;
+  GdkEventPrivate *new_event;
   
   if (event_chunk == NULL)
     event_chunk = g_mem_chunk_new ("events",
-                                  sizeof (GdkEvent),
+                                  sizeof (GdkEventPrivate),
                                   4096,
                                   G_ALLOC_AND_FREE);
   
-  new_event = g_chunk_new (GdkEvent, event_chunk);
+  new_event = g_chunk_new (GdkEventPrivate, event_chunk);
+  new_event->flags = 0;
   
-  return new_event;
+  return (GdkEvent*) new_event;
 }
 
 GdkEvent*
@@ -555,7 +684,6 @@ gdk_event_copy (GdkEvent *event)
     case GDK_DROP_FINISHED:
       gdk_drag_context_ref (event->dnd.context);
       break;
-
       
     default:
       break;
@@ -585,8 +713,9 @@ gdk_event_copy (GdkEvent *event)
 void
 gdk_event_free (GdkEvent *event)
 {
-  g_assert (event_chunk != NULL);
   g_return_if_fail (event != NULL);
+
+  g_assert (event_chunk != NULL); /* paranoid */
   
   if (event->any.window)
     gdk_window_unref (event->any.window);
@@ -612,7 +741,6 @@ gdk_event_free (GdkEvent *event)
     case GDK_DROP_FINISHED:
       gdk_drag_context_unref (event->dnd.context);
       break;
-
       
     default:
       break;
@@ -696,7 +824,7 @@ gdk_event_get_time (GdkEvent *event)
  */
 
 void
-gdk_set_show_events (int show_events)
+gdk_set_show_events (gint show_events)
 {
   if (show_events)
     gdk_debug_flags |= GDK_DEBUG_EVENTS;
@@ -767,8 +895,9 @@ gdk_input_add_full (gint          source,
     cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
 
   channel = g_io_channel_unix_new (source);
-  result = g_io_add_watch_full   (channel, 0, cond, gdk_io_invoke,
-                                 closure, gdk_io_destroy);
+  result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, 
+                               gdk_io_invoke,
+                               closure, gdk_io_destroy);
   g_io_channel_unref (channel);
 
   return result;
@@ -802,9 +931,9 @@ gdk_event_apply_filters (XEvent *xevent,
   
   while (tmp_list)
     {
-      filter = (GdkEventFilter *)tmp_list->data;
+      filter = (GdkEventFilter*) tmp_list->data;
       
-      result = (*filter->function)(xevent, event, filter->data);
+      result = (*filter->function) (xevent, event, filter->data);
       if (result !=  GDK_FILTER_CONTINUE)
        return result;
       
@@ -1833,12 +1962,13 @@ gdk_event_get_type (Display  *display,
 static void
 gdk_events_queue (void)
 {
+  GList *node;
   GdkEvent *event;
   XEvent xevent;
 
-  while (!(putback_events || queued_events) && XPending (gdk_display))
+  while (!gdk_event_queue_find_first() && XPending (gdk_display))
     {
-  #ifdef USE_XIM
+#ifdef USE_XIM
       Window w = None;
       
       XNextEvent (gdk_display, &xevent);
@@ -1865,24 +1995,22 @@ gdk_events_queue (void)
       event->any.window = NULL;
       event->any.send_event = FALSE;
       event->any.send_event = xevent.xany.send_event;
-      
+
+      ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
+
+      gdk_event_queue_append (event);
+      node = queued_tail;
+
       if (gdk_event_translate (event, &xevent))
        {
-         GList *tmp_list = g_list_alloc();
-         tmp_list->prev = queued_tail;
-         tmp_list->next = NULL;
-         tmp_list->data = event;
-
-         if (!queued_events)
-           {
-             queued_events = tmp_list;
-             queued_tail = queued_events;
-           }
-         else
-           queued_tail->next = tmp_list;
+         ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
        }
       else
-       gdk_event_free (event);
+       {
+         gdk_event_queue_remove_link (node);
+         g_list_free_1 (node);
+         gdk_event_free (event);
+       }
     }
 }
 
@@ -1897,8 +2025,7 @@ gdk_event_prepare (gpointer  source_data,
 
   *timeout = -1;
 
-  gdk_events_queue ();
-  retval = (queued_events || putback_events);
+  retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
 
   GDK_THREADS_LEAVE ();
 
@@ -1906,49 +2033,37 @@ gdk_event_prepare (gpointer  source_data,
 }
 
 static gboolean  
-gdk_event_check   (gpointer  source_data,
-                  GTimeVal *current_time)
+gdk_event_check (gpointer  source_data,
+                GTimeVal *current_time)
 {
   gboolean retval;
   
   GDK_THREADS_ENTER ();
 
   if (event_poll_fd.revents & G_IO_IN)
-      gdk_events_queue ();
-
-  retval = (queued_events || putback_events);
+    retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
+  else
+    retval = FALSE;
 
   GDK_THREADS_LEAVE ();
 
   return retval;
 }
 
-static GdkEvent *
+static GdkEvent*
 gdk_event_unqueue (void)
 {
-  GdkEvent *event;
-  GList *tmp_list, **head, **tail;
+  GdkEvent *event = NULL;
+  GList *tmp_list;
 
-  if (putback_events)
-    {
-      head = &putback_events;
-      tail = &putback_tail;
-    }
-  else if (queued_events)
+  tmp_list = gdk_event_queue_find_first ();
+
+  if (tmp_list)
     {
-      head = &queued_events;
-      tail = &queued_tail;
+      event = tmp_list->data;
+      gdk_event_queue_remove_link (tmp_list);
+      g_list_free_1 (tmp_list);
     }
-  else
-    return NULL;
-
-  if (*head == *tail)
-    *tail = NULL;
-    
-  tmp_list = *head;
-  event = tmp_list->data;
-  *head = g_list_remove_link (tmp_list, tmp_list);
-  g_list_free_1 (tmp_list);
 
   return event;
 }
@@ -1962,6 +2077,7 @@ gdk_event_dispatch (gpointer  source_data,
  
   GDK_THREADS_ENTER ();
 
+  gdk_events_queue();
   event = gdk_event_unqueue();
 
   if (event)
@@ -2112,7 +2228,8 @@ gdk_event_send_clientmessage_toall (GdkEvent *event)
  *--------------------------------------------------------------
  */
 
-void gdk_flush (void)
+void
+gdk_flush (void)
 {
   XSync (gdk_display, False);
 }