* 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 GdkEvent* gdk_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,
*/
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,
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)
{
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;
*--------------------------------------------------------------
*/
-gint
+gboolean
gdk_events_pending (void)
{
- return g_main_pending();
+ return (gdk_event_queue_find_first() || XPending (gdk_display));
}
/*
*-------------------------------------------------------------- */
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;
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)
{
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;
gpointer data,
GDestroyNotify notify)
{
- if (event_func && event_notify)
+ if (event_notify)
(*event_notify) (event_data);
event_func = 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);
}
/*
*--------------------------------------------------------------
*/
-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*
case GDK_DROP_FINISHED:
gdk_drag_context_ref (event->dnd.context);
break;
-
default:
break;
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);
case GDK_DROP_FINISHED:
gdk_drag_context_unref (event->dnd.context);
break;
-
default:
break;
*/
void
-gdk_set_show_events (int show_events)
+gdk_set_show_events (gint show_events)
{
if (show_events)
gdk_debug_flags |= GDK_DEBUG_EVENTS;
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;
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;
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);
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);
+ }
}
}
*timeout = -1;
- gdk_events_queue ();
- retval = (queued_events || putback_events);
+ retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
GDK_THREADS_LEAVE ();
}
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;
}
GDK_THREADS_ENTER ();
+ gdk_events_queue();
event = gdk_event_unqueue();
if (event)
*--------------------------------------------------------------
*/
-void gdk_flush (void)
+void
+gdk_flush (void)
{
XSync (gdk_display, False);
}