* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+/*
+ * Modified by the GTK+ Team and others 1997-2000. 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 "gdkprivate-x11.h"
+#include "gdkinternals.h"
#include "gdkx.h"
-#include "gdkprivate.h"
-#include "gdkinput.h"
+
#include "gdkkeysyms.h"
#if HAVE_CONFIG_H
# endif
#endif
+#include "gdkinputprivate.h"
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#include <X11/Xatom.h>
typedef struct _GdkIOClosure GdkIOClosure;
typedef struct _GdkEventPrivate GdkEventPrivate;
#define DOUBLE_CLICK_DIST 5
#define TRIPLE_CLICK_DIST 5
-typedef enum {
+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 {
+struct _GdkIOClosure
+{
GdkInputFunction function;
GdkInputCondition condition;
GdkDestroyNotify notify;
gpointer data;
};
-struct _GdkEventPrivate {
+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);
+ XEvent *xevent,
+ gboolean return_exposes);
#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 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 gboolean gdk_event_prepare (GSource *source,
+ gint *timeout);
+static gboolean gdk_event_check (GSource *source);
+static gboolean gdk_event_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data);
GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
GdkEvent *event,
* when events are pending by using
* the "select" system call.
*/
-static guint32 button_click_time[2]; /* The last 2 button click times. Used
- * to determine if the latest button click
- * is part of a double or triple click.
- */
-static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses.
- * Also used to determine if the latest button
- * click is part of a double or triple click.
- */
-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 GList *client_filters; /* Filters for client messages */
-
-/* FIFO's for event queue, and for events put back using
- * gdk_event_put().
- */
-static GList *queued_events = NULL;
-static GList *queued_tail = NULL;
+static GList *client_filters; /* Filters for client messages */
static GSourceFuncs event_funcs = {
gdk_event_prepare,
gdk_event_check,
gdk_event_dispatch,
- (GDestroyNotify)g_free
+ NULL
};
-GPollFD event_poll_fd;
+static GPollFD event_poll_fd;
+
+static Window wmspec_check_window = None;
/*********************************************
* 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)
{
+ GSource *source;
+
connection_number = ConnectionNumber (gdk_display);
GDK_NOTE (MISC,
g_message ("connection number: %d", connection_number));
- g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
+ source = g_source_new (&event_funcs, sizeof (GSource));
+ g_source_set_priority (source, GDK_PRIORITY_EVENTS);
+
event_poll_fd.fd = connection_number;
event_poll_fd.events = G_IO_IN;
- g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
-
- button_click_time[0] = 0;
- button_click_time[1] = 0;
- button_window[0] = NULL;
- button_window[1] = NULL;
- button_number[0] = -1;
- button_number[1] = -1;
+ g_source_add_poll (source, &event_poll_fd);
+ g_source_set_can_recurse (source, TRUE);
+ g_source_attach (source, NULL);
gdk_add_client_message_filter (gdk_wm_protocols,
gdk_wm_protocols_filter, NULL);
*-------------------------------------------------------------- */
static Bool
-graphics_expose_predicate (Display *display,
- XEvent *xevent,
- XPointer arg)
+graphics_expose_predicate (Display *display,
+ XEvent *xevent,
+ XPointer 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 == GDK_DRAWABLE_XID (arg) &&
+ (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)
{
event = gdk_event_new ();
- if (gdk_event_translate (event, &xevent))
+ if (gdk_event_translate (event, &xevent, TRUE))
return event;
else
gdk_event_free (event);
return NULL;
}
-/************************
- * Exposure compression *
- ************************/
-
-/*
- * The following implements simple exposure compression. It is
- * modelled after the way Xt does exposure compression - in
- * particular compress_expose = XtExposeCompressMultiple.
- * It compress consecutive sequences of exposure events,
- * but not sequences that cross other events. (This is because
- * if it crosses a ConfigureNotify, we could screw up and
- * mistakenly compress the exposures generated for the new
- * size - could we just check for ConfigureNotify?)
- *
- * Xt compresses to a region / bounding rectangle, we compress
- * to two rectangles, and try find the two rectangles of minimal
- * area for this - this is supposed to handle the typical
- * L-shaped regions generated by OpaqueMove.
- */
-
-/* Given three rectangles, find the two rectangles that cover
- * them with the smallest area.
- */
-static void
-gdk_add_rect_to_rects (GdkRectangle *rect1,
- GdkRectangle *rect2,
- GdkRectangle *new_rect)
-{
- GdkRectangle t1, t2, t3;
- gint size1, size2, size3;
-
- gdk_rectangle_union (rect1, rect2, &t1);
- gdk_rectangle_union (rect1, new_rect, &t2);
- gdk_rectangle_union (rect2, new_rect, &t3);
-
- size1 = t1.width * t1.height + new_rect->width * new_rect->height;
- size2 = t2.width * t2.height + rect2->width * rect2->height;
- size3 = t1.width * t1.height + rect1->width * rect1->height;
-
- if (size1 < size2)
- {
- if (size1 < size3)
- {
- *rect1 = t1;
- *rect2 = *new_rect;
- }
- else
- *rect2 = t3;
- }
- else
- {
- if (size2 < size3)
- *rect1 = t2;
- else
- *rect2 = t3;
- }
-}
-
-typedef struct _GdkExposeInfo GdkExposeInfo;
-
-struct _GdkExposeInfo {
- Window window;
- gboolean seen_nonmatching;
-};
-
-Bool
-expose_predicate (Display *display, XEvent *xevent, XPointer arg)
-{
- 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.type != Expose) ||
- (xevent->xany.window != info->window))
- return FALSE;
- else
- return TRUE;
-}
-
-void
-gdk_compress_exposures (XEvent *xevent, GdkWindow *window)
-{
- gint nrects = 1;
- gint count = 0;
- GdkRectangle rect1;
- GdkRectangle rect2;
- GdkRectangle tmp_rect;
- XEvent tmp_event;
- GdkFilterReturn result;
- GdkExposeInfo info;
- GdkEvent event;
-
- info.window = xevent->xany.window;
- info.seen_nonmatching = FALSE;
-
- rect1.x = xevent->xexpose.x;
- rect1.y = xevent->xexpose.y;
- rect1.width = xevent->xexpose.width;
- rect1.height = xevent->xexpose.height;
-
- while (1)
- {
- if (count == 0)
- {
- if (!XCheckIfEvent (gdk_display,
- &tmp_event,
- expose_predicate,
- (XPointer)&info))
- break;
- }
- else
- XIfEvent (gdk_display,
- &tmp_event,
- expose_predicate,
- (XPointer)&info);
-
- /* We apply filters here, and if it was filtered, completely
- * ignore the return
- */
- result = gdk_event_apply_filters (xevent, &event,
- window ?
- ((GdkWindowPrivate *)window)->filters
- : gdk_default_filters);
-
- if (result != GDK_FILTER_CONTINUE)
- {
- if (result == GDK_FILTER_TRANSLATE)
- gdk_event_put (&event);
- continue;
- }
-
- if (nrects == 1)
- {
- rect2.x = tmp_event.xexpose.x;
- rect2.y = tmp_event.xexpose.y;
- rect2.width = tmp_event.xexpose.width;
- rect2.height = tmp_event.xexpose.height;
-
- nrects++;
- }
- else
- {
- tmp_rect.x = tmp_event.xexpose.x;
- tmp_rect.y = tmp_event.xexpose.y;
- tmp_rect.width = tmp_event.xexpose.width;
- tmp_rect.height = tmp_event.xexpose.height;
-
- gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
- }
-
- count = tmp_event.xexpose.count;
- }
-
- if (nrects == 2)
- {
- gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
-
- if ((tmp_rect.width * tmp_rect.height) <
- 2 * (rect1.height * rect1.width +
- rect2.height * rect2.width))
- {
- rect1 = tmp_rect;
- nrects = 1;
- }
- }
-
- if (nrects == 2)
- {
- event.expose.type = GDK_EXPOSE;
- event.expose.window = window;
- event.expose.area.x = rect2.x;
- event.expose.area.y = rect2.y;
- event.expose.area.width = rect2.width;
- event.expose.area.height = rect2.height;
- event.expose.count = 0;
-
- gdk_event_put (&event);
- }
-
- xevent->xexpose.count = nrects - 1;
- xevent->xexpose.x = rect1.x;
- xevent->xexpose.y = rect1.y;
- xevent->xexpose.width = rect1.width;
- xevent->xexpose.height = rect1.height;
-}
-
-/*************************************************************
- * gdk_event_handler_set:
- *
- * arguments:
- * func: Callback function to be called for each event.
- * data: Data supplied to the function
- * notify: function called when function is no longer needed
- *
- * results:
- *************************************************************/
-
-void
-gdk_event_handler_set (GdkEventFunc func,
- gpointer data,
- GDestroyNotify notify)
-{
- if (event_func && event_notify)
- (*event_notify) (event_data);
-
- event_func = func;
- event_data = data;
- event_notify = notify;
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_get
- *
- * Gets the next event.
- *
- * Arguments:
- *
- * Results:
- * 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.
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-GdkEvent *
-gdk_event_get (void)
-{
- gdk_events_queue();
-
- 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;
-
- g_return_if_fail (event != NULL);
-
- new_event = gdk_event_copy (event);
-
- gdk_event_queue_append (new_event);
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_copy
- *
- * Copy a event structure into new storage.
- *
- * Arguments:
- * "event" is the event struct to copy.
- *
- * Results:
- * A new event structure. Free it with gdk_event_free.
- *
- * Side effects:
- * The reference count of the window in the event is increased.
- *
- *--------------------------------------------------------------
- */
-
-static GMemChunk *event_chunk;
-
-static GdkEvent*
-gdk_event_new (void)
-{
- GdkEventPrivate *new_event;
-
- if (event_chunk == NULL)
- event_chunk = g_mem_chunk_new ("events",
- sizeof (GdkEventPrivate),
- 4096,
- G_ALLOC_AND_FREE);
-
- new_event = g_chunk_new (GdkEventPrivate, event_chunk);
- new_event->flags = 0;
-
- return (GdkEvent *)new_event;
-}
-
-GdkEvent*
-gdk_event_copy (GdkEvent *event)
-{
- GdkEvent *new_event;
-
- g_return_val_if_fail (event != NULL, NULL);
-
- new_event = gdk_event_new ();
-
- *new_event = *event;
- gdk_window_ref (new_event->any.window);
-
- switch (event->any.type)
- {
- case GDK_KEY_PRESS:
- case GDK_KEY_RELEASE:
- new_event->key.string = g_strdup (event->key.string);
- break;
-
- case GDK_ENTER_NOTIFY:
- case GDK_LEAVE_NOTIFY:
- if (event->crossing.subwindow != NULL)
- gdk_window_ref (event->crossing.subwindow);
- break;
-
- case GDK_DRAG_ENTER:
- case GDK_DRAG_LEAVE:
- case GDK_DRAG_MOTION:
- case GDK_DRAG_STATUS:
- case GDK_DROP_START:
- case GDK_DROP_FINISHED:
- gdk_drag_context_ref (event->dnd.context);
- break;
-
-
- default:
- break;
- }
-
- return new_event;
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_free
- *
- * Free a event structure obtained from gdk_event_copy. Do not use
- * with other event structures.
- *
- * Arguments:
- * "event" is the event struct to free.
- *
- * Results:
- *
- * Side effects:
- * The reference count of the window in the event is decreased and
- * might be freed, too.
- *
- *-------------------------------------------------------------- */
-
-void
-gdk_event_free (GdkEvent *event)
-{
- g_assert (event_chunk != NULL);
- g_return_if_fail (event != NULL);
-
- if (event->any.window)
- gdk_window_unref (event->any.window);
-
- switch (event->any.type)
- {
- case GDK_KEY_PRESS:
- case GDK_KEY_RELEASE:
- g_free (event->key.string);
- break;
-
- case GDK_ENTER_NOTIFY:
- case GDK_LEAVE_NOTIFY:
- if (event->crossing.subwindow != NULL)
- gdk_window_unref (event->crossing.subwindow);
- break;
-
- case GDK_DRAG_ENTER:
- case GDK_DRAG_LEAVE:
- case GDK_DRAG_MOTION:
- case GDK_DRAG_STATUS:
- case GDK_DROP_START:
- case GDK_DROP_FINISHED:
- gdk_drag_context_unref (event->dnd.context);
- break;
-
-
- default:
- break;
- }
-
- g_mem_chunk_free (event_chunk, event);
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_event_get_time:
- * Get the timestamp from an event.
- * arguments:
- * event:
- * results:
- * The event's time stamp, if it has one, otherwise
- * GDK_CURRENT_TIME.
- *--------------------------------------------------------------
- */
-
-guint32
-gdk_event_get_time (GdkEvent *event)
-{
- if (event)
- switch (event->type)
- {
- case GDK_MOTION_NOTIFY:
- return event->motion.time;
- case GDK_BUTTON_PRESS:
- case GDK_2BUTTON_PRESS:
- case GDK_3BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- return event->button.time;
- case GDK_KEY_PRESS:
- case GDK_KEY_RELEASE:
- return event->key.time;
- case GDK_ENTER_NOTIFY:
- case GDK_LEAVE_NOTIFY:
- return event->crossing.time;
- case GDK_PROPERTY_NOTIFY:
- return event->property.time;
- case GDK_SELECTION_CLEAR:
- case GDK_SELECTION_REQUEST:
- case GDK_SELECTION_NOTIFY:
- return event->selection.time;
- case GDK_PROXIMITY_IN:
- case GDK_PROXIMITY_OUT:
- return event->proximity.time;
- case GDK_DRAG_ENTER:
- case GDK_DRAG_LEAVE:
- case GDK_DRAG_MOTION:
- case GDK_DRAG_STATUS:
- case GDK_DROP_START:
- case GDK_DROP_FINISHED:
- return event->dnd.time;
- default: /* use current time */
- break;
- }
-
- return GDK_CURRENT_TIME;
-}
-
-/*
- *--------------------------------------------------------------
- * gdk_set_show_events
- *
- * Turns on/off the showing of events.
- *
- * Arguments:
- * "show_events" is a boolean describing whether or
- * not to show the events gdk receives.
- *
- * Results:
- *
- * Side effects:
- * When "show_events" is TRUE, calls to "gdk_event_get"
- * will output debugging informatin regarding the event
- * received to stdout.
- *
- *--------------------------------------------------------------
- */
-
-void
-gdk_set_show_events (int show_events)
-{
- if (show_events)
- gdk_debug_flags |= GDK_DEBUG_EVENTS;
- else
- gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
-}
-
-gint
-gdk_get_show_events (void)
-{
- return gdk_debug_flags & GDK_DEBUG_EVENTS;
-}
-
-static void
-gdk_io_destroy (gpointer data)
-{
- GdkIOClosure *closure = data;
-
- if (closure->notify)
- closure->notify (closure->data);
-
- g_free (closure);
-}
-
-static gboolean
-gdk_io_invoke (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
-{
- GdkIOClosure *closure = data;
- GdkInputCondition gdk_cond = 0;
-
- if (condition & (G_IO_IN | G_IO_PRI))
- gdk_cond |= GDK_INPUT_READ;
- if (condition & G_IO_OUT)
- gdk_cond |= GDK_INPUT_WRITE;
- if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
- gdk_cond |= GDK_INPUT_EXCEPTION;
-
- if (closure->condition & gdk_cond)
- closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
-
- return TRUE;
-}
-
-gint
-gdk_input_add_full (gint source,
- GdkInputCondition condition,
- GdkInputFunction function,
- gpointer data,
- GdkDestroyNotify destroy)
-{
- guint result;
- GdkIOClosure *closure = g_new (GdkIOClosure, 1);
- GIOChannel *channel;
- GIOCondition cond = 0;
-
- closure->function = function;
- closure->condition = condition;
- closure->notify = destroy;
- closure->data = data;
-
- if (condition & GDK_INPUT_READ)
- cond |= (G_IO_IN | G_IO_PRI);
- if (condition & GDK_INPUT_WRITE)
- cond |= G_IO_OUT;
- if (condition & GDK_INPUT_EXCEPTION)
- cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
-
- channel = g_io_channel_unix_new (source);
- 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;
-}
-
-gint
-gdk_input_add (gint source,
- GdkInputCondition condition,
- GdkInputFunction function,
- gpointer data)
-{
- return gdk_input_add_full (source, condition, function, data, NULL);
-}
-
-void
-gdk_input_remove (gint tag)
-{
- g_source_remove (tag);
-}
-
static gint
gdk_event_apply_filters (XEvent *xevent,
GdkEvent *event,
GList *filters)
{
- GdkEventFilter *filter;
GList *tmp_list;
GdkFilterReturn result;
while (tmp_list)
{
- filter = (GdkEventFilter *)tmp_list->data;
+ GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
- result = (*filter->function)(xevent, event, filter->data);
+ tmp_list = tmp_list->next;
+ result = filter->function (xevent, event, filter->data);
if (result != GDK_FILTER_CONTINUE)
return result;
-
- tmp_list = tmp_list->next;
}
return GDK_FILTER_CONTINUE;
client_filters = g_list_prepend (client_filters, filter);
}
+static GdkAtom wm_state_atom = 0;
+static GdkAtom wm_desktop_atom = 0;
+
+static void
+gdk_check_wm_state_changed (GdkWindow *window)
+{
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ GdkAtom *atoms = NULL;
+ gulong i;
+ GdkAtom sticky_atom;
+ GdkAtom maxvert_atom;
+ GdkAtom maxhorz_atom;
+ gboolean found_sticky, found_maxvert, found_maxhorz;
+ GdkWindowState old_state;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (wm_state_atom == 0)
+ wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+
+ if (wm_desktop_atom == 0)
+ wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+ wm_state_atom, 0, G_MAXLONG,
+ False, XA_ATOM, &type, &format, &nitems,
+ &bytes_after, (guchar **)&atoms);
+
+ if (type != None)
+ {
+
+ sticky_atom = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
+ maxvert_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
+ maxhorz_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);
+
+ found_sticky = FALSE;
+ found_maxvert = FALSE;
+ found_maxhorz = FALSE;
+
+ i = 0;
+ while (i < nitems)
+ {
+ if (atoms[i] == sticky_atom)
+ found_sticky = TRUE;
+ else if (atoms[i] == maxvert_atom)
+ found_maxvert = TRUE;
+ else if (atoms[i] == maxhorz_atom)
+ found_maxhorz = TRUE;
+
+ ++i;
+ }
+
+ XFree (atoms);
+ }
+ else
+ {
+ found_sticky = FALSE;
+ found_maxvert = FALSE;
+ found_maxhorz = FALSE;
+ }
+
+ /* For found_sticky to remain TRUE, we have to also be on desktop
+ * 0xFFFFFFFF
+ */
+
+ if (found_sticky)
+ {
+ gulong *desktop;
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
+ wm_desktop_atom, 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, (guchar **)&desktop);
+
+ if (type != None)
+ {
+ if (*desktop != 0xFFFFFFFF)
+ found_sticky = FALSE;
+ XFree (desktop);
+ }
+ }
+
+ old_state = gdk_window_get_state (window);
+
+ if (old_state & GDK_WINDOW_STATE_STICKY)
+ {
+ if (!found_sticky)
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_STICKY,
+ 0);
+ }
+ else
+ {
+ if (found_sticky)
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_STICKY);
+ }
+
+ /* Our "maximized" means both vertical and horizontal; if only one,
+ * we don't expose that via GDK
+ */
+ if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
+ {
+ if (!(found_maxvert && found_maxhorz))
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_MAXIMIZED,
+ 0);
+ }
+ else
+ {
+ if (found_maxvert && found_maxhorz)
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_MAXIMIZED);
+ }
+}
+
static gint
gdk_event_translate (GdkEvent *event,
- XEvent *xevent)
+ XEvent *xevent,
+ gboolean return_exposes)
{
GdkWindow *window;
- GdkWindowPrivate *window_private;
+ GdkWindowObject *window_private;
static XComposeStatus compose;
KeySym keysym;
int charcount;
-#ifdef USE_XIM
- static gchar* buf = NULL;
- static gint buf_len= 0;
-#else
char buf[16];
-#endif
gint return_val;
+ gint xoffset, yoffset;
return_val = FALSE;
* some circumstances.
*/
- if ((xevent->xany.window == None) &&
- gdk_input_vtable.window_none_event)
+ if (xevent->xany.window == None)
{
- return_val = gdk_input_vtable.window_none_event (event,xevent);
+ return_val = _gdk_input_window_none_event (event, xevent);
if (return_val >= 0) /* was handled */
return return_val;
}
window = gdk_window_lookup (xevent->xany.window);
- window_private = (GdkWindowPrivate *) window;
+ /* FIXME: window might be a GdkPixmap!!! */
+
+ window_private = (GdkWindowObject *) window;
if (window != NULL)
gdk_window_ref (window);
+
+ if (wmspec_check_window != None &&
+ xevent->xany.window == wmspec_check_window)
+ {
+ if (xevent->type == DestroyNotify)
+ wmspec_check_window = None;
+
+ /* Eat events on this window unless someone had wrapped
+ * it as a foreign window
+ */
+ if (window == NULL)
+ return FALSE;
+ }
event->any.window = window;
- event->any.send_event = xevent->xany.send_event;
+ event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
- if (window_private && window_private->destroyed)
+ if (window_private && GDK_WINDOW_DESTROYED (window))
{
if (xevent->type != DestroyNotify)
- return FALSE;
+ return FALSE;
}
else
{
if (result != GDK_FILTER_CONTINUE)
{
- return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+ return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+ goto done;
}
}
-#ifdef USE_XIM
- if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
- !((GdkWindowPrivate *) gdk_xim_window)->destroyed)
- {
- /*
- * If user presses a key in Preedit or Status window, keypress event
- * is sometimes sent to these windows. These windows are not managed
- * by GDK, so we redirect KeyPress event to xim_window.
- *
- * If someone want to use the window whitch is not managed by GDK
- * and want to get KeyPress event, he/she must register the filter
- * function to gdk_default_filters to intercept the event.
- */
-
- GdkFilterReturn result;
-
- window = gdk_xim_window;
- window_private = (GdkWindowPrivate *) window;
- gdk_window_ref (window);
- event->any.window = window;
-
- GDK_NOTE (XIM,
- g_message ("KeyPress event is redirected to xim_window: %#lx",
- xevent->xany.window));
-
- result = gdk_event_apply_filters (xevent, event,
- window_private->filters);
- if (result != GDK_FILTER_CONTINUE)
- return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
- }
-#endif
-
- if (window == NULL)
- g_message ("Got event for unknown window: %#lx\n", xevent->xany.window);
-
/* We do a "manual" conversion of the XEvent to a
* GdkEvent. The structures are mostly the same so
* the conversion is fairly straightforward. We also
return_val = TRUE;
+ if (window)
+ {
+ _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
+ }
+ else
+ {
+ xoffset = 0;
+ yoffset = 0;
+ }
+
switch (xevent->type)
{
case KeyPress:
/* Lookup the string corresponding to the given keysym.
*/
-
-#ifdef USE_XIM
- if (buf_len == 0)
- {
- buf_len = 128;
- buf = g_new (gchar, buf_len);
- }
- keysym = GDK_VoidSymbol;
-
- if (gdk_xim_ic && gdk_xim_ic->xic)
- {
- Status status;
-
- /* Clear keyval. Depending on status, may not be set */
- charcount = XmbLookupString(gdk_xim_ic->xic,
- &xevent->xkey, buf, buf_len-1,
- &keysym, &status);
- if (status == XBufferOverflow)
- { /* retry */
- /* alloc adequate size of buffer */
- GDK_NOTE (XIM,
- g_message("XIM: overflow (required %i)", charcount));
-
- while (buf_len <= charcount)
- buf_len *= 2;
- buf = (gchar *) g_realloc (buf, buf_len);
-
- charcount = XmbLookupString (gdk_xim_ic->xic,
- &xevent->xkey, buf, buf_len-1,
- &keysym, &status);
- }
- if (status == XLookupNone)
- {
- return_val = FALSE;
- break;
- }
- }
- else
- charcount = XLookupString (&xevent->xkey, buf, buf_len,
- &keysym, &compose);
-#else
+
charcount = XLookupString (&xevent->xkey, buf, 16,
&keysym, &compose);
-#endif
event->key.keyval = keysym;
+ event->key.hardware_keycode = xevent->xkey.keycode;
if (charcount > 0 && buf[charcount-1] == '\0')
charcount --;
else
buf[charcount] = '\0';
- /* Print debugging info. */
-
#ifdef G_ENABLE_DEBUG
if (gdk_debug_flags & GDK_DEBUG_EVENTS)
{
charcount, buf);
}
#endif /* G_ENABLE_DEBUG */
+
+ /* bits 13 and 14 in the "state" field are the keyboard group */
+#define KEYBOARD_GROUP_SHIFT 13
+#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
event->key.type = GDK_KEY_PRESS;
event->key.window = window;
event->key.state = (GdkModifierType) xevent->xkey.state;
event->key.string = g_strdup (buf);
event->key.length = charcount;
+
+ event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;
break;
case KeyRelease:
/* Lookup the string corresponding to the given keysym.
*/
-#ifdef USE_XIM
- if (buf_len == 0)
+
+ /* Emulate detectable auto-repeat by checking to see
+ * if the next event is a key press with the same
+ * keycode and timestamp, and if so, ignoring the event.
+ */
+
+ if (!_gdk_have_xkb_autorepeat && XPending (gdk_display))
{
- buf_len = 128;
- buf = g_new (gchar, buf_len);
+ XEvent next_event;
+
+ XPeekEvent (gdk_display, &next_event);
+
+ if (next_event.type == KeyPress &&
+ next_event.xkey.keycode == xevent->xkey.keycode &&
+ next_event.xkey.time == xevent->xkey.time)
+ break;
}
-#endif
+
keysym = GDK_VoidSymbol;
charcount = XLookupString (&xevent->xkey, buf, 16,
&keysym, &compose);
event->key.keyval = keysym;
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("key release:\t\twindow: %ld key: %12s %d",
xevent->xkey.window,
break;
case ButtonPress:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d",
xevent->xbutton.window,
break;
}
- event->button.type = GDK_BUTTON_PRESS;
- event->button.window = window;
- event->button.time = xevent->xbutton.time;
- event->button.x = xevent->xbutton.x;
- event->button.y = xevent->xbutton.y;
- event->button.x_root = (gfloat)xevent->xbutton.x_root;
- event->button.y_root = (gfloat)xevent->xbutton.y_root;
- event->button.pressure = 0.5;
- event->button.xtilt = 0;
- event->button.ytilt = 0;
- event->button.state = (GdkModifierType) xevent->xbutton.state;
- event->button.button = xevent->xbutton.button;
- event->button.source = GDK_SOURCE_MOUSE;
- event->button.deviceid = GDK_CORE_POINTER;
-
- if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
- (event->button.window == button_window[1]) &&
- (event->button.button == button_number[1]))
- {
- gdk_synthesize_click (event, 3);
-
- button_click_time[1] = 0;
- button_click_time[0] = 0;
- button_window[1] = NULL;
- button_window[0] = 0;
- button_number[1] = -1;
- button_number[0] = -1;
- }
- else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
- (event->button.window == button_window[0]) &&
- (event->button.button == button_number[0]))
+ /* If we get a ButtonPress event where the button is 4 or 5,
+ it's a Scroll event */
+ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
{
- gdk_synthesize_click (event, 2);
-
- button_click_time[1] = button_click_time[0];
- button_click_time[0] = event->button.time;
- button_window[1] = button_window[0];
- button_window[0] = event->button.window;
- button_number[1] = button_number[0];
- button_number[0] = event->button.button;
+ event->scroll.type = GDK_SCROLL;
+ event->scroll.direction = (xevent->xbutton.button == 4) ?
+ GDK_SCROLL_UP : GDK_SCROLL_DOWN;
+ event->scroll.window = window;
+ event->scroll.time = xevent->xbutton.x;
+ event->scroll.x = xevent->xbutton.x + xoffset;
+ event->scroll.y = xevent->xbutton.y + yoffset;
+ event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
+ event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
+ event->scroll.state = (GdkModifierType) xevent->xbutton.state;
+ event->scroll.device = gdk_core_pointer;
}
else
{
- button_click_time[1] = 0;
- button_click_time[0] = event->button.time;
- button_window[1] = NULL;
- button_window[0] = event->button.window;
- button_number[1] = -1;
- button_number[0] = event->button.button;
+ event->button.type = GDK_BUTTON_PRESS;
+ event->button.window = window;
+ event->button.time = xevent->xbutton.time;
+ event->button.x = xevent->xbutton.x + xoffset;
+ event->button.y = xevent->xbutton.y + yoffset;
+ event->button.x_root = (gfloat)xevent->xbutton.x_root;
+ event->button.y_root = (gfloat)xevent->xbutton.y_root;
+ event->button.axes = NULL;
+ event->button.state = (GdkModifierType) xevent->xbutton.state;
+ event->button.button = xevent->xbutton.button;
+ event->button.device = gdk_core_pointer;
+
+ gdk_event_button_generate (event);
}
break;
case ButtonRelease:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("button release:\twindow: %ld x,y: %d %d button: %d",
xevent->xbutton.window,
break;
}
+ /* We treat button presses as scroll wheel events, so ignore the release */
+ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
+ {
+ return_val = FALSE;
+ break;
+ }
+
event->button.type = GDK_BUTTON_RELEASE;
event->button.window = window;
event->button.time = xevent->xbutton.time;
- event->button.x = xevent->xbutton.x;
- event->button.y = xevent->xbutton.y;
+ event->button.x = xevent->xbutton.x + xoffset;
+ event->button.y = xevent->xbutton.y + yoffset;
event->button.x_root = (gfloat)xevent->xbutton.x_root;
event->button.y_root = (gfloat)xevent->xbutton.y_root;
- event->button.pressure = 0.5;
- event->button.xtilt = 0;
- event->button.ytilt = 0;
+ event->button.axes = NULL;
event->button.state = (GdkModifierType) xevent->xbutton.state;
event->button.button = xevent->xbutton.button;
- event->button.source = GDK_SOURCE_MOUSE;
- event->button.deviceid = GDK_CORE_POINTER;
+ event->button.device = gdk_core_pointer;
break;
case MotionNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s",
xevent->xmotion.window,
event->motion.type = GDK_MOTION_NOTIFY;
event->motion.window = window;
event->motion.time = xevent->xmotion.time;
- event->motion.x = xevent->xmotion.x;
- event->motion.y = xevent->xmotion.y;
+ event->motion.x = xevent->xmotion.x + xoffset;
+ event->motion.y = xevent->xmotion.y + yoffset;
event->motion.x_root = (gfloat)xevent->xmotion.x_root;
event->motion.y_root = (gfloat)xevent->xmotion.y_root;
- event->motion.pressure = 0.5;
- event->motion.xtilt = 0;
- event->motion.ytilt = 0;
+ event->motion.axes = NULL;
event->motion.state = (GdkModifierType) xevent->xmotion.state;
event->motion.is_hint = xevent->xmotion.is_hint;
- event->motion.source = GDK_SOURCE_MOUSE;
- event->motion.deviceid = GDK_CORE_POINTER;
+ event->motion.device = gdk_core_pointer;
break;
case EnterNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld",
xevent->xcrossing.window,
/* Tell XInput stuff about it if appropriate */
if (window_private &&
- !window_private->destroyed &&
- (window_private->extension_events != 0) &&
- gdk_input_vtable.enter_event)
- gdk_input_vtable.enter_event (&xevent->xcrossing, window);
+ !GDK_WINDOW_DESTROYED (window) &&
+ window_private->extension_events != 0)
+ _gdk_input_enter_event (&xevent->xcrossing, window);
event->crossing.type = GDK_ENTER_NOTIFY;
event->crossing.window = window;
event->crossing.subwindow = NULL;
event->crossing.time = xevent->xcrossing.time;
- event->crossing.x = xevent->xcrossing.x;
- event->crossing.y = xevent->xcrossing.y;
+ event->crossing.x = xevent->xcrossing.x + xoffset;
+ event->crossing.y = xevent->xcrossing.y + yoffset;
event->crossing.x_root = xevent->xcrossing.x_root;
event->crossing.y_root = xevent->xcrossing.y_root;
break;
case LeaveNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld",
xevent->xcrossing.window,
event->crossing.subwindow = NULL;
event->crossing.time = xevent->xcrossing.time;
- event->crossing.x = xevent->xcrossing.x;
- event->crossing.y = xevent->xcrossing.y;
+ event->crossing.x = xevent->xcrossing.x + xoffset;
+ event->crossing.y = xevent->xcrossing.y + yoffset;
event->crossing.x_root = xevent->xcrossing.x_root;
event->crossing.y_root = xevent->xcrossing.y_root;
case NotifyAncestor:
case NotifyInferior:
case NotifyNonlinear:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("focus %s:\t\twindow: %ld",
(xevent->xany.type == FocusIn) ? "in" : "out",
break;
case KeymapNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("keymap notify"));
break;
case Expose:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
- g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d",
+ g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d%s",
xevent->xexpose.window, xevent->xexpose.count,
xevent->xexpose.x, xevent->xexpose.y,
- xevent->xexpose.width, xevent->xexpose.height));
- gdk_compress_exposures (xevent, window);
-
- event->expose.type = GDK_EXPOSE;
- event->expose.window = window;
- event->expose.area.x = xevent->xexpose.x;
- event->expose.area.y = xevent->xexpose.y;
- event->expose.area.width = xevent->xexpose.width;
- event->expose.area.height = xevent->xexpose.height;
- event->expose.count = xevent->xexpose.count;
-
+ xevent->xexpose.width, xevent->xexpose.height,
+ event->any.send_event ? " (send)" : ""));
+ {
+ GdkRectangle expose_rect;
+
+ expose_rect.x = xevent->xexpose.x + xoffset;
+ expose_rect.y = xevent->xexpose.y + yoffset;
+ expose_rect.width = xevent->xexpose.width;
+ expose_rect.height = xevent->xexpose.height;
+
+ if (return_exposes)
+ {
+ event->expose.type = GDK_EXPOSE;
+ event->expose.area = expose_rect;
+ event->expose.region = gdk_region_rectangle (&expose_rect);
+ event->expose.window = window;
+ event->expose.count = xevent->xexpose.count;
+
+ return_val = TRUE;
+ }
+ else
+ {
+ _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
+
+ return_val = FALSE;
+ }
+
+ return_val = FALSE;
+ }
+
break;
case GraphicsExpose:
- /* Print debugging info.
- */
- GDK_NOTE (EVENTS,
- g_message ("graphics expose:\tdrawable: %ld",
- xevent->xgraphicsexpose.drawable));
-
- event->expose.type = GDK_EXPOSE;
- event->expose.window = window;
- event->expose.area.x = xevent->xgraphicsexpose.x;
- event->expose.area.y = xevent->xgraphicsexpose.y;
- event->expose.area.width = xevent->xgraphicsexpose.width;
- event->expose.area.height = xevent->xgraphicsexpose.height;
- event->expose.count = xevent->xexpose.count;
-
+ {
+ GdkRectangle expose_rect;
+
+ GDK_NOTE (EVENTS,
+ g_message ("graphics expose:\tdrawable: %ld",
+ xevent->xgraphicsexpose.drawable));
+
+ expose_rect.x = xevent->xgraphicsexpose.x + xoffset;
+ expose_rect.y = xevent->xgraphicsexpose.y + yoffset;
+ expose_rect.width = xevent->xgraphicsexpose.width;
+ expose_rect.height = xevent->xgraphicsexpose.height;
+
+ if (return_exposes)
+ {
+ event->expose.type = GDK_EXPOSE;
+ event->expose.area = expose_rect;
+ event->expose.region = gdk_region_rectangle (&expose_rect);
+ event->expose.window = window;
+ event->expose.count = xevent->xgraphicsexpose.count;
+
+ return_val = TRUE;
+ }
+ else
+ {
+ _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
+
+ return_val = FALSE;
+ }
+
+ }
break;
case NoExpose:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("no expose:\t\tdrawable: %ld",
xevent->xnoexpose.drawable));
break;
case VisibilityNotify:
- /* Print debugging info.
- */
#ifdef G_ENABLE_DEBUG
if (gdk_debug_flags & GDK_DEBUG_EVENTS)
switch (xevent->xvisibility.state)
break;
case CreateNotify:
- /* Not currently handled */
+ GDK_NOTE (EVENTS,
+ g_message ("create notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d parent: %ld ovr: %d",
+ xevent->xcreatewindow.window,
+ xevent->xcreatewindow.x,
+ xevent->xcreatewindow.y,
+ xevent->xcreatewindow.width,
+ xevent->xcreatewindow.height,
+ xevent->xcreatewindow.border_width,
+ xevent->xcreatewindow.parent,
+ xevent->xcreatewindow.override_redirect));
+ /* not really handled */
break;
case DestroyNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("destroy notify:\twindow: %ld",
xevent->xdestroywindow.window));
event->any.type = GDK_DESTROY;
event->any.window = window;
- return_val = window_private && !window_private->destroyed;
+ return_val = window_private && !GDK_WINDOW_DESTROYED (window);
- if(window && window_private->xwindow != GDK_ROOT_WINDOW())
+ if (window && GDK_WINDOW_XID (window) != GDK_ROOT_WINDOW())
gdk_window_destroy_notify (window);
break;
case UnmapNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("unmap notify:\t\twindow: %ld",
xevent->xmap.window));
event->any.type = GDK_UNMAP;
- event->any.window = window;
+ event->any.window = window;
+
+ /* If we are shown (not withdrawn) and get an unmap, it means we
+ * were iconified in the X sense. If we are withdrawn, and get
+ * an unmap, it means we hid the window ourselves, so we
+ * will have already flipped the iconified bit off.
+ */
+ if (GDK_WINDOW_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_WINDOW_STATE_ICONIFIED);
if (gdk_xgrab_window == window_private)
gdk_xgrab_window = NULL;
break;
case MapNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("map notify:\t\twindow: %ld",
xevent->xmap.window));
event->any.type = GDK_MAP;
event->any.window = window;
+
+ /* Unset iconified if it was set */
+ if (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED)
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_ICONIFIED,
+ 0);
break;
case ReparentNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
- g_message ("reparent notify:\twindow: %ld",
- xevent->xreparent.window));
+ g_message ("reparent notify:\twindow: %ld x,y: %d %d parent: %ld ovr: %d",
+ xevent->xreparent.window,
+ xevent->xreparent.x,
+ xevent->xreparent.y,
+ xevent->xreparent.parent,
+ xevent->xreparent.override_redirect));
/* Not currently handled */
return_val = FALSE;
break;
case ConfigureNotify:
- /* Print debugging info.
- */
- while ((XPending (gdk_display) > 0) &&
- XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
- ConfigureNotify, xevent))
- {
- GdkFilterReturn result;
-
- GDK_NOTE (EVENTS,
- g_message ("configure notify discarded:\twindow: %ld",
- xevent->xconfigure.window));
-
- result = gdk_event_apply_filters (xevent, event,
- window_private
- ?window_private->filters
- :gdk_default_filters);
-
- /* If the result is GDK_FILTER_REMOVE, there will be
- * trouble, but anybody who filtering the Configure events
- * better know what they are doing
- */
- if (result != GDK_FILTER_CONTINUE)
- {
- return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
- }
-
- /*XSync (gdk_display, 0);*/
- }
-
-
GDK_NOTE (EVENTS,
- g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d",
+ g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d%s",
xevent->xconfigure.window,
xevent->xconfigure.x,
xevent->xconfigure.y,
xevent->xconfigure.height,
xevent->xconfigure.border_width,
xevent->xconfigure.above,
- xevent->xconfigure.override_redirect));
-
- if (!window_private->destroyed &&
- (window_private->extension_events != 0) &&
- gdk_input_vtable.configure_event)
- gdk_input_vtable.configure_event (&xevent->xconfigure, window);
-
- if (window_private->window_type == GDK_WINDOW_CHILD)
+ xevent->xconfigure.override_redirect,
+ !window
+ ? " (discarding)"
+ : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
+ ? " (discarding child)"
+ : ""));
+ if (window &&
+ !GDK_WINDOW_DESTROYED (window) &&
+ (window_private->extension_events != 0))
+ _gdk_input_configure_event (&xevent->xconfigure, window);
+
+ if (!window || GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
return_val = FALSE;
else
{
if (!xevent->xconfigure.x &&
!xevent->xconfigure.y &&
- !window_private->destroyed)
+ !GDK_WINDOW_DESTROYED (window))
{
gint tx = 0;
gint ty = 0;
Window child_window = 0;
-
- if (!XTranslateCoordinates (window_private->xdisplay,
- window_private->xwindow,
- gdk_root_window,
- 0, 0,
- &tx, &ty,
- &child_window))
- g_warning ("GdkWindow %ld doesn't share root windows display?",
- window_private->xwindow);
- event->configure.x = tx;
- event->configure.y = ty;
+
+ gdk_error_trap_push ();
+ if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
+ GDK_DRAWABLE_XID (window),
+ gdk_root_window,
+ 0, 0,
+ &tx, &ty,
+ &child_window))
+ {
+ if (!gdk_error_trap_pop ())
+ {
+ event->configure.x = tx;
+ event->configure.y = ty;
+ }
+ }
+ else
+ gdk_error_trap_pop ();
}
else
{
}
window_private->x = event->configure.x;
window_private->y = event->configure.y;
- window_private->width = xevent->xconfigure.width;
- window_private->height = xevent->xconfigure.height;
+ GDK_WINDOW_IMPL_X11 (window_private->impl)->width = xevent->xconfigure.width;
+ GDK_WINDOW_IMPL_X11 (window_private->impl)->height = xevent->xconfigure.height;
if (window_private->resize_count > 1)
window_private->resize_count -= 1;
}
break;
case PropertyNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
- g_message ("property notify:\twindow: %ld",
- xevent->xproperty.window));
+ gchar *atom = gdk_atom_name (xevent->xproperty.atom);
+ g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
+ xevent->xproperty.window,
+ xevent->xproperty.atom,
+ atom ? "\"" : "",
+ atom ? atom : "unknown",
+ atom ? "\"" : "");
+ g_free (atom);
+ );
event->property.type = GDK_PROPERTY_NOTIFY;
event->property.window = window;
event->property.atom = xevent->xproperty.atom;
event->property.time = xevent->xproperty.time;
event->property.state = xevent->xproperty.state;
+
+ if (wm_state_atom == 0)
+ wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
+
+ if (wm_desktop_atom == 0)
+ wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
+
+ if (event->property.atom == wm_state_atom ||
+ event->property.atom == wm_desktop_atom)
+ {
+ /* If window state changed, then synthesize those events. */
+ gdk_check_wm_state_changed (event->property.window);
+ }
break;
GDK_NOTE (EVENTS,
g_message ("selection clear:\twindow: %ld",
xevent->xproperty.window));
-
- event->selection.type = GDK_SELECTION_CLEAR;
- event->selection.window = window;
- event->selection.selection = xevent->xselectionclear.selection;
- event->selection.time = xevent->xselectionclear.time;
-
+
+ if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
+ {
+ event->selection.type = GDK_SELECTION_CLEAR;
+ event->selection.window = window;
+ event->selection.selection = xevent->xselectionclear.selection;
+ event->selection.time = xevent->xselectionclear.time;
+ }
+ else
+ return_val = FALSE;
+
break;
case SelectionRequest:
break;
case ColormapNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("colormap notify:\twindow: %ld",
xevent->xcolormap.window));
GList *tmp_list;
GdkFilterReturn result = GDK_FILTER_CONTINUE;
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("client message:\twindow: %ld",
xevent->xclient.window));
break;
case MappingNotify:
- /* Print debugging info.
- */
GDK_NOTE (EVENTS,
g_message ("mapping notify"));
/* Let XLib know that there is a new keyboard mapping.
*/
XRefreshKeyboardMapping (&xevent->xmapping);
+ ++_gdk_keymap_serial;
return_val = FALSE;
break;
+
+#ifdef HAVE_XKB
+ case XkbMapNotify:
+ ++_gdk_keymap_serial;
+ return_val = FALSE;
+ break;
+#endif
default:
/* something else - (e.g., a Xinput event) */
if (window_private &&
- !window_private->destroyed &&
- (window_private->extension_events != 0) &&
- gdk_input_vtable.other_event)
- return_val = gdk_input_vtable.other_event(event, xevent, window);
+ !GDK_WINDOW_DESTROYED (window_private) &&
+ (window_private->extension_events != 0))
+ return_val = _gdk_input_other_event(event, xevent, window);
else
return_val = FALSE;
break;
}
-
+
+ done:
if (return_val)
{
if (event->any.window)
GdkFilterReturn
gdk_wm_protocols_filter (GdkXEvent *xev,
- GdkEvent *event,
- gpointer data)
+ GdkEvent *event,
+ gpointer data)
{
XEvent *xevent = (XEvent *)xev;
else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
{
}
+ else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
+ {
+ XEvent xev = *xevent;
+
+ xev.xclient.window = gdk_root_window;
+ XSendEvent (gdk_display, gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ }
return GDK_FILTER_REMOVE;
}
GdkEvent event;
GdkPredicate *pred;
- if (gdk_event_translate (&event, xevent))
+ if (gdk_event_translate (&event, xevent, FALSE))
{
pred = (GdkPredicate*) arg;
return (* pred->func) (&event, pred->data);
}
#endif
-static void
+void
gdk_events_queue (void)
{
GList *node;
while (!gdk_event_queue_find_first() && XPending (gdk_display))
{
- #ifdef USE_XIM
- Window w = None;
-
- XNextEvent (gdk_display, &xevent);
- if (gdk_xim_window)
- switch (xevent.type)
- {
- case KeyPress:
- case KeyRelease:
- case ButtonPress:
- case ButtonRelease:
- w = GDK_WINDOW_XWINDOW (gdk_xim_window);
- break;
- }
-
- if (XFilterEvent (&xevent, w))
- continue;
-#else
XNextEvent (gdk_display, &xevent);
-#endif
+
+ switch (xevent.type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ break;
+ default:
+ if (XFilterEvent (&xevent, None))
+ continue;
+ }
event = gdk_event_new ();
event->any.type = GDK_NOTHING;
event->any.window = NULL;
- event->any.send_event = FALSE;
- event->any.send_event = xevent.xany.send_event;
+ event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
gdk_event_queue_append (event);
- node = queued_tail;
+ node = gdk_queued_tail;
- if (gdk_event_translate (event, &xevent))
+ if (gdk_event_translate (event, &xevent, FALSE))
{
((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
}
}
static gboolean
-gdk_event_prepare (gpointer source_data,
- GTimeVal *current_time,
+gdk_event_prepare (GSource *source,
gint *timeout)
{
gboolean retval;
}
static gboolean
-gdk_event_check (gpointer source_data,
- GTimeVal *current_time)
+gdk_event_check (GSource *source)
{
gboolean retval;
return retval;
}
-static GdkEvent *
-gdk_event_unqueue (void)
-{
- GdkEvent *event = NULL;
- GList *tmp_list;
-
- tmp_list = gdk_event_queue_find_first ();
-
- if (tmp_list)
- {
- event = tmp_list->data;
- gdk_event_queue_remove_link (tmp_list);
- g_list_free_1 (tmp_list);
- }
-
- return event;
-}
-
static gboolean
-gdk_event_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data)
+gdk_event_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
{
GdkEvent *event;
if (event)
{
- if (event_func)
- (*event_func) (event, event_data);
+ if (gdk_event_func)
+ (*gdk_event_func) (event, gdk_event_data);
gdk_event_free (event);
}
return TRUE;
}
-static void
-gdk_synthesize_click (GdkEvent *event,
- gint nclicks)
-{
- GdkEvent temp_event;
-
- g_return_if_fail (event != NULL);
-
- temp_event = *event;
- temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
-
- gdk_event_put (&temp_event);
-}
-
/* Sends a ClientMessage to all toplevel client windows */
gboolean
gdk_event_send_client_message (GdkEvent *event, guint32 xid)
guint level)
{
static GdkAtom wm_state_atom = GDK_NONE;
-
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char *data;
-
Window *ret_children, ret_root, ret_parent;
unsigned int ret_nchildren;
- int i;
-
+ gint old_warnings = gdk_error_warnings;
gboolean send = FALSE;
gboolean found = FALSE;
+ int i;
if (!wm_state_atom)
wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
+ gdk_error_warnings = FALSE;
gdk_error_code = 0;
XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
&type, &format, &nitems, &after, &data);
if (gdk_error_code)
{
- gdk_error_code = 0;
+ gdk_error_warnings = old_warnings;
+
return FALSE;
}
else
{
/* OK, we're all set, now let's find some windows to send this to */
- if (XQueryTree(gdk_display, xid, &ret_root, &ret_parent,
- &ret_children, &ret_nchildren) != True)
- return FALSE;
-
- if (gdk_error_code)
- return FALSE;
+ if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
+ &ret_children, &ret_nchildren) != True ||
+ gdk_error_code)
+ {
+ gdk_error_warnings = old_warnings;
+
+ return FALSE;
+ }
for(i = 0; i < ret_nchildren; i++)
- if (gdk_event_send_client_message_to_all_recurse(xev, ret_children[i], level + 1))
+ if (gdk_event_send_client_message_to_all_recurse (xev, ret_children[i], level + 1))
found = TRUE;
- XFree(ret_children);
+ XFree (ret_children);
}
if (send || (!found && (level == 1)))
gdk_send_xevent (xid, False, NoEventMask, xev);
}
+ gdk_error_warnings = old_warnings;
+
return (send || found);
}
*--------------------------------------------------------------
*/
-void gdk_flush (void)
+void
+gdk_flush (void)
{
XSync (gdk_display, False);
}
+static GdkAtom timestamp_prop_atom = 0;
+
+static Bool
+timestamp_predicate (Display *display,
+ XEvent *xevent,
+ XPointer arg)
+{
+ Window xwindow = GPOINTER_TO_UINT (arg);
+
+ if (xevent->type == PropertyNotify &&
+ xevent->xproperty.window == xwindow &&
+ xevent->xproperty.atom == timestamp_prop_atom)
+ return True;
+
+ return False;
+}
+
+/**
+ * gdk_x11_get_server_time:
+ * @window: a #GdkWindow, used for communication with the server.
+ * The window must have GDK_PROPERTY_CHANGE_MASK in its
+ * events mask or a hang will result.
+ *
+ * Routine to get the current X server time stamp.
+ *
+ * Return value: the time stamp.
+ **/
+guint32
+gdk_x11_get_server_time (GdkWindow *window)
+{
+ Display *xdisplay;
+ Window xwindow;
+ guchar c = 'a';
+ XEvent xevent;
+
+ g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
+ g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
+
+ if (!timestamp_prop_atom)
+ timestamp_prop_atom = gdk_atom_intern ("GDK_TIMESTAMP_PROP", FALSE);
+
+ xdisplay = GDK_WINDOW_XDISPLAY (window);
+ xwindow = GDK_WINDOW_XWINDOW (window);
+
+ XChangeProperty (xdisplay, xwindow,
+ timestamp_prop_atom, timestamp_prop_atom,
+ 8, PropModeReplace, &c, 1);
+
+ XIfEvent (xdisplay, &xevent,
+ timestamp_predicate, GUINT_TO_POINTER(xwindow));
+
+ return xevent.xproperty.time;
+}
+
+
+gboolean
+gdk_net_wm_supports (GdkAtom property)
+{
+ static GdkAtom wmspec_check_atom = 0;
+ static GdkAtom wmspec_supported_atom = 0;
+ static GdkAtom *atoms = NULL;
+ static gulong n_atoms = 0;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ Window *xwindow;
+ gulong i;
+
+ if (wmspec_check_window != None)
+ {
+ if (atoms == NULL)
+ return FALSE;
+
+ i = 0;
+ while (i < n_atoms)
+ {
+ if (atoms[i] == property)
+ return TRUE;
+
+ ++i;
+ }
+
+ return FALSE;
+ }
+
+ if (atoms)
+ XFree (atoms);
+
+ atoms = NULL;
+ n_atoms = 0;
+
+ /* This function is very slow on every call if you are not running a
+ * spec-supporting WM. For now not optimized, because it isn't in
+ * any critical code paths, but if you used it somewhere that had to
+ * be fast you want to avoid "GTK is slow with old WMs" complaints.
+ * Probably at that point the function should be changed to query
+ * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something.
+ */
+
+ if (wmspec_check_atom == 0)
+ wmspec_check_atom = gdk_atom_intern ("_NET_SUPPORTING_WM_CHECK", FALSE);
+
+ if (wmspec_supported_atom == 0)
+ wmspec_supported_atom = gdk_atom_intern ("_NET_SUPPORTED", FALSE);
+
+ XGetWindowProperty (gdk_display, gdk_root_window,
+ wmspec_check_atom, 0, G_MAXLONG,
+ False, XA_WINDOW, &type, &format, &nitems,
+ &bytes_after, (guchar **)&xwindow);
+
+ if (type != XA_WINDOW)
+ return FALSE;
+
+ gdk_error_trap_push ();
+
+ /* Find out if this WM goes away, so we can reset everything. */
+ XSelectInput (gdk_display, *xwindow,
+ StructureNotifyMask);
+
+ gdk_flush ();
+
+ if (gdk_error_trap_pop ())
+ {
+ XFree (xwindow);
+ return FALSE;
+ }
+
+ XGetWindowProperty (gdk_display, gdk_root_window,
+ wmspec_supported_atom, 0, G_MAXLONG,
+ False, XA_ATOM, &type, &format, &n_atoms,
+ &bytes_after, (guchar **)&atoms);
+
+ if (type != XA_ATOM)
+ return FALSE;
+
+ wmspec_check_window = *xwindow;
+ XFree (xwindow);
+
+ /* since wmspec_check_window != None this isn't infinite. ;-) */
+ return gdk_net_wm_supports (property);
+}
+
+