mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-17 23:10:22 +00:00
a1a252ce46
Fri Feb 2 12:26:50 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkrc.c (gtk_rc_add_initial_default_files): Get rid of a bunch of g_strdup_printf("%s%s") in favor of g_strconcat(). * gtk/gtkrc.c Makefile.am: Use $(libdir), not $(exe_prefix), since some people set $(libdir) separately. (#1290, David Kaelbling) Thu Feb 1 18:25:46 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkfilesel.c: If PATH_MAX and MAXPATHLEN are not defined, define MAXPATHLEN to 2048. (The Hurd doesn't have MAXPATHLEN, but the code here depends on a fixed value.) (#4524) Wed Jan 31 22:01:04 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkhandlebox.c (gtk_handle_box_button_changed): Handle the case where child == NULL and handle_position == RIGHT or BOTTOM. (#8041g) Wed Jan 31 21:20:39 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkctree.c (real_tree_move): If the node being moved isn't viewable there is no way that moving the node will cause the focus row to become not viewable, so omit check on the visibility of new_sibling, which is irrelevant. (Fixes #8002, David Helder) Wed Jan 31 20:38:17 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkentry.c (gtk_entry_commit_cb): Delete the current selection before inserting new text. Wed Jan 31 18:49:33 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkoptionmenu.c (gtk_option_menu_item_state_changed_cb): Make the sensitivity of the reparented child track that of the original parent menu item. (#34218, David Hodson) * gtk/gtkoptionmenu.c (gtk_option_menu_item_destroy_cb): Handle the case where the current item is destroyed properly. * gtk/gtkoptionmenu.c: Some additional code cleanups and fix some edge cases with child-less menuitems. Wed Jan 31 17:16:13 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkcombo.c (gtk_combo_window_key_press): Make Return key pop down window. (#12074, Jon K Hellan) Wed Jan 31 16:21:42 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtklist.c (gtk_list_signal_item_toggle): Don't allow toggling of rows off in BROWSE or EXTENDED mode. (#12072, Jon K Hellan) The solution here isn't perfect - you get an extraneous emission of "toggle", which could conceivably confuse an app, but better than the current situation. LXR search seems to indicate that no apps in GNOME CVS connect to "toggle". Wed Jan 31 15:46:13 2001 Owen Taylor <otaylor@redhat.com> * gtk/Makefile.am (libgtkinclude_HEADERS): Move gtkcompat.h from gtk_public_h_sources to directly here to avoid warning when building srcdir != builddir. (#9656) Tue Jan 30 19:49:02 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkrange.c: Patch from Kipp Hickman to make the event handlers in gtkrange.c return the proper values (TRUE == handled) (#10316). This is just the tip of the iceberg, but gtkrange.c is the most common place where the propagation is problematical, and also a place where it is almost certainly safe to change this in the stable branch. (You don't want right click popups on a range control or anything...) Tue Jan 30 18:57:59 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtktext.c (clear_focus_area): We need to clear the focus area on focus out, even if a background pixmap isn't set. (#13941) Tue Jan 30 18:24:10 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtknotebook.c (gtk_notebook_set_shape): Fix from Sean Cunningham to deal with setting the shape properly when scrolling arrows are turned on, but not visible because there is sufficient space. (#13432) Tue Jan 30 16:39:25 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkitemfactory.c (gtk_item_factory_delete_item): For menu items with submenus, destroy the item along with the submenu. (#7841, Brian Masney(?)) Also, handle paths of the form '<foo>/abcd...' properly. * gtk/testgtk.c (menu_items): Add a dummy branch that we delete later. Tue Jan 30 15:51:25 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkwindow.c (gtk_window_real_set_focus): Fix a problem where the focus widget sometimes wasn't drawn with the default if there was no default widget. * gtk/gtkstyle.c (gtk_style_real_unrealize): free colors, unreference pixmaps. * gtk/gtkstyle.c (gtk_style_realize): Reference colormap for some extra safety. Mon Jan 29 19:00:01 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtk{ctree.c,clist.c} (set_cell_contents): Handle setting the text of a cell to the old pointer value better, by copying the new text before freeing the old text. Some code cleanup. (#8079, Karl Nelson) Mon Jan 29 16:50:19 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtklabel.[ch] gtk/gtkframe.[ch]: Make gtk_label_get_text() gtk_frame_get_label() non strdup'ing, and G_CONST_RETURN. Mon Jan 29 15:22:51 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmenu.c (gtk_menu_remove): When removing an item from a menu, check to see if it matches menu->old_active_menu_item, and if so, unref and clear old_active_menu_item (Patch from Pavel Cisler) * gtk/gtkmenushell.c (gtk_menu_shell_remove): Unset menu_shell->active_menu_item, if it is the child being removed. (Patch based on that of Gene Ragan, #50337)
1589 lines
40 KiB
C
1589 lines
40 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
* 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 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* 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 "gdkkeysyms.h"
|
|
|
|
#if HAVE_CONFIG_H
|
|
# include <config.h>
|
|
# if STDC_HEADERS
|
|
# include <string.h>
|
|
# endif
|
|
#endif
|
|
|
|
#include "gdkinputprivate.h"
|
|
|
|
#ifdef HAVE_XKB
|
|
#include <X11/XKBlib.h>
|
|
#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
|
|
|
|
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 gint gdk_event_apply_filters (XEvent *xevent,
|
|
GdkEvent *event,
|
|
GList *filters);
|
|
static gint gdk_event_translate (GdkEvent *event,
|
|
XEvent *xevent,
|
|
gboolean return_exposes);
|
|
#if 0
|
|
static Bool gdk_event_get_type (Display *display,
|
|
XEvent *xevent,
|
|
XPointer arg);
|
|
#endif
|
|
|
|
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,
|
|
gpointer data);
|
|
|
|
/* Private variable declarations
|
|
*/
|
|
|
|
static int connection_number = 0; /* The file descriptor number of our
|
|
* connection to the X server. This
|
|
* is used so that we may determine
|
|
* when events are pending by using
|
|
* the "select" system call.
|
|
*/
|
|
static GList *client_filters; /* Filters for client messages */
|
|
|
|
static GSourceFuncs event_funcs = {
|
|
gdk_event_prepare,
|
|
gdk_event_check,
|
|
gdk_event_dispatch,
|
|
NULL
|
|
};
|
|
|
|
GPollFD event_poll_fd;
|
|
|
|
/*********************************************
|
|
* Functions for maintaining the event queue *
|
|
*********************************************/
|
|
|
|
void
|
|
gdk_events_init (void)
|
|
{
|
|
GSource *source;
|
|
|
|
connection_number = ConnectionNumber (gdk_display);
|
|
GDK_NOTE (MISC,
|
|
g_message ("connection number: %d", connection_number));
|
|
|
|
|
|
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_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);
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
* gdk_events_pending
|
|
*
|
|
* Returns if events are pending on the queue.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Results:
|
|
* Returns TRUE if events are pending
|
|
*
|
|
* Side effects:
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
|
|
gboolean
|
|
gdk_events_pending (void)
|
|
{
|
|
return (gdk_event_queue_find_first() || XPending (gdk_display));
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
* gdk_event_get_graphics_expose
|
|
*
|
|
* Waits for a GraphicsExpose or NoExpose event
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Results:
|
|
* For GraphicsExpose events, returns a pointer to the event
|
|
* converted into a GdkEvent Otherwise, returns NULL.
|
|
*
|
|
* Side effects:
|
|
*
|
|
*-------------------------------------------------------------- */
|
|
|
|
static Bool
|
|
graphics_expose_predicate (Display *display,
|
|
XEvent *xevent,
|
|
XPointer arg)
|
|
{
|
|
if (xevent->xany.window == GDK_DRAWABLE_XID (arg) &&
|
|
(xevent->xany.type == GraphicsExpose ||
|
|
xevent->xany.type == NoExpose))
|
|
return True;
|
|
else
|
|
return False;
|
|
}
|
|
|
|
GdkEvent*
|
|
gdk_event_get_graphics_expose (GdkWindow *window)
|
|
{
|
|
XEvent xevent;
|
|
GdkEvent *event;
|
|
|
|
g_return_val_if_fail (window != NULL, NULL);
|
|
|
|
XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window);
|
|
|
|
if (xevent.xany.type == GraphicsExpose)
|
|
{
|
|
event = gdk_event_new ();
|
|
|
|
if (gdk_event_translate (event, &xevent, TRUE))
|
|
return event;
|
|
else
|
|
gdk_event_free (event);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static gint
|
|
gdk_event_apply_filters (XEvent *xevent,
|
|
GdkEvent *event,
|
|
GList *filters)
|
|
{
|
|
GList *tmp_list;
|
|
GdkFilterReturn result;
|
|
|
|
tmp_list = filters;
|
|
|
|
while (tmp_list)
|
|
{
|
|
GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
|
|
|
|
tmp_list = tmp_list->next;
|
|
result = filter->function (xevent, event, filter->data);
|
|
if (result != GDK_FILTER_CONTINUE)
|
|
return result;
|
|
}
|
|
|
|
return GDK_FILTER_CONTINUE;
|
|
}
|
|
|
|
void
|
|
gdk_add_client_message_filter (GdkAtom message_type,
|
|
GdkFilterFunc func,
|
|
gpointer data)
|
|
{
|
|
GdkClientFilter *filter = g_new (GdkClientFilter, 1);
|
|
|
|
filter->type = message_type;
|
|
filter->function = func;
|
|
filter->data = data;
|
|
|
|
client_filters = g_list_prepend (client_filters, filter);
|
|
}
|
|
|
|
static gint
|
|
gdk_event_translate (GdkEvent *event,
|
|
XEvent *xevent,
|
|
gboolean return_exposes)
|
|
{
|
|
|
|
GdkWindow *window;
|
|
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;
|
|
|
|
/* Find the GdkWindow that this event occurred in.
|
|
*
|
|
* We handle events with window=None
|
|
* specially - they are generated by XFree86's XInput under
|
|
* some circumstances.
|
|
*/
|
|
|
|
if (xevent->xany.window == None)
|
|
{
|
|
return_val = _gdk_input_window_none_event (event, xevent);
|
|
|
|
if (return_val >= 0) /* was handled */
|
|
return return_val;
|
|
else
|
|
return_val = FALSE;
|
|
}
|
|
|
|
window = gdk_window_lookup (xevent->xany.window);
|
|
/* FIXME: window might be a GdkPixmap!!! */
|
|
|
|
window_private = (GdkWindowObject *) window;
|
|
|
|
if (window != NULL)
|
|
gdk_window_ref (window);
|
|
|
|
event->any.window = window;
|
|
event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
|
|
|
|
if (window_private && GDK_WINDOW_DESTROYED (window))
|
|
{
|
|
if (xevent->type != DestroyNotify)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Check for filters for this window
|
|
*/
|
|
GdkFilterReturn result;
|
|
result = gdk_event_apply_filters (xevent, event,
|
|
window_private
|
|
?window_private->filters
|
|
:gdk_default_filters);
|
|
|
|
if (result != GDK_FILTER_CONTINUE)
|
|
{
|
|
return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
#ifdef USE_XIM
|
|
if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
|
|
!GDK_WINDOW_DESTROYED (gdk_xim_window))
|
|
{
|
|
/*
|
|
* 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 = (GdkWindowObject *) 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_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* 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
|
|
* optionally print debugging info regarding events
|
|
* received.
|
|
*/
|
|
|
|
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';
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
if (gdk_debug_flags & GDK_DEBUG_EVENTS)
|
|
{
|
|
g_message ("key press:\twindow: %ld key: %12s %d",
|
|
xevent->xkey.window,
|
|
event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
|
|
event->key.keyval);
|
|
if (charcount > 0)
|
|
g_message ("\t\tlength: %4d string: \"%s\"",
|
|
charcount, buf);
|
|
}
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
/* bits 13 and 14 in the "state" field are the keyboard group */
|
|
#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
|
|
|
|
event->key.type = GDK_KEY_PRESS;
|
|
event->key.window = window;
|
|
event->key.time = xevent->xkey.time;
|
|
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;
|
|
|
|
break;
|
|
|
|
case KeyRelease:
|
|
/* Lookup the string corresponding to the given keysym.
|
|
*/
|
|
#ifdef USE_XIM
|
|
if (buf_len == 0)
|
|
{
|
|
buf_len = 128;
|
|
buf = g_new (gchar, buf_len);
|
|
}
|
|
#endif
|
|
keysym = GDK_VoidSymbol;
|
|
charcount = XLookupString (&xevent->xkey, buf, 16,
|
|
&keysym, &compose);
|
|
event->key.keyval = keysym;
|
|
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("key release:\t\twindow: %ld key: %12s %d",
|
|
xevent->xkey.window,
|
|
XKeysymToString (event->key.keyval),
|
|
event->key.keyval));
|
|
|
|
event->key.type = GDK_KEY_RELEASE;
|
|
event->key.window = window;
|
|
event->key.time = xevent->xkey.time;
|
|
event->key.state = (GdkModifierType) xevent->xkey.state;
|
|
event->key.length = 0;
|
|
event->key.string = NULL;
|
|
|
|
break;
|
|
|
|
case ButtonPress:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("button press:\t\twindow: %ld x,y: %d %d button: %d",
|
|
xevent->xbutton.window,
|
|
xevent->xbutton.x, xevent->xbutton.y,
|
|
xevent->xbutton.button));
|
|
|
|
if (window_private &&
|
|
(window_private->extension_events != 0) &&
|
|
gdk_input_ignore_core)
|
|
{
|
|
return_val = FALSE;
|
|
break;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
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
|
|
{
|
|
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:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("button release:\twindow: %ld x,y: %d %d button: %d",
|
|
xevent->xbutton.window,
|
|
xevent->xbutton.x, xevent->xbutton.y,
|
|
xevent->xbutton.button));
|
|
|
|
if (window_private &&
|
|
(window_private->extension_events != 0) &&
|
|
gdk_input_ignore_core)
|
|
{
|
|
return_val = FALSE;
|
|
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 + 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;
|
|
|
|
break;
|
|
|
|
case MotionNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s",
|
|
xevent->xmotion.window,
|
|
xevent->xmotion.x, xevent->xmotion.y,
|
|
(xevent->xmotion.is_hint) ? "true" : "false"));
|
|
|
|
if (window_private &&
|
|
(window_private->extension_events != 0) &&
|
|
gdk_input_ignore_core)
|
|
{
|
|
return_val = FALSE;
|
|
break;
|
|
}
|
|
|
|
event->motion.type = GDK_MOTION_NOTIFY;
|
|
event->motion.window = window;
|
|
event->motion.time = xevent->xmotion.time;
|
|
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.axes = NULL;
|
|
event->motion.state = (GdkModifierType) xevent->xmotion.state;
|
|
event->motion.is_hint = xevent->xmotion.is_hint;
|
|
event->motion.device = gdk_core_pointer;
|
|
|
|
break;
|
|
|
|
case EnterNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("enter notify:\t\twindow: %ld detail: %d subwin: %ld",
|
|
xevent->xcrossing.window,
|
|
xevent->xcrossing.detail,
|
|
xevent->xcrossing.subwindow));
|
|
|
|
/* Tell XInput stuff about it if appropriate */
|
|
if (window_private &&
|
|
!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;
|
|
|
|
/* If the subwindow field of the XEvent is non-NULL, then
|
|
* lookup the corresponding GdkWindow.
|
|
*/
|
|
if (xevent->xcrossing.subwindow != None)
|
|
event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
|
|
else
|
|
event->crossing.subwindow = NULL;
|
|
|
|
event->crossing.time = xevent->xcrossing.time;
|
|
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;
|
|
|
|
/* Translate the crossing mode into Gdk terms.
|
|
*/
|
|
switch (xevent->xcrossing.mode)
|
|
{
|
|
case NotifyNormal:
|
|
event->crossing.mode = GDK_CROSSING_NORMAL;
|
|
break;
|
|
case NotifyGrab:
|
|
event->crossing.mode = GDK_CROSSING_GRAB;
|
|
break;
|
|
case NotifyUngrab:
|
|
event->crossing.mode = GDK_CROSSING_UNGRAB;
|
|
break;
|
|
};
|
|
|
|
/* Translate the crossing detail into Gdk terms.
|
|
*/
|
|
switch (xevent->xcrossing.detail)
|
|
{
|
|
case NotifyInferior:
|
|
event->crossing.detail = GDK_NOTIFY_INFERIOR;
|
|
break;
|
|
case NotifyAncestor:
|
|
event->crossing.detail = GDK_NOTIFY_ANCESTOR;
|
|
break;
|
|
case NotifyVirtual:
|
|
event->crossing.detail = GDK_NOTIFY_VIRTUAL;
|
|
break;
|
|
case NotifyNonlinear:
|
|
event->crossing.detail = GDK_NOTIFY_NONLINEAR;
|
|
break;
|
|
case NotifyNonlinearVirtual:
|
|
event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
|
|
break;
|
|
default:
|
|
event->crossing.detail = GDK_NOTIFY_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
event->crossing.focus = xevent->xcrossing.focus;
|
|
event->crossing.state = xevent->xcrossing.state;
|
|
|
|
break;
|
|
|
|
case LeaveNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld",
|
|
xevent->xcrossing.window,
|
|
xevent->xcrossing.detail, xevent->xcrossing.subwindow));
|
|
|
|
event->crossing.type = GDK_LEAVE_NOTIFY;
|
|
event->crossing.window = window;
|
|
|
|
/* If the subwindow field of the XEvent is non-NULL, then
|
|
* lookup the corresponding GdkWindow.
|
|
*/
|
|
if (xevent->xcrossing.subwindow != None)
|
|
event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
|
|
else
|
|
event->crossing.subwindow = NULL;
|
|
|
|
event->crossing.time = xevent->xcrossing.time;
|
|
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;
|
|
|
|
/* Translate the crossing mode into Gdk terms.
|
|
*/
|
|
switch (xevent->xcrossing.mode)
|
|
{
|
|
case NotifyNormal:
|
|
event->crossing.mode = GDK_CROSSING_NORMAL;
|
|
break;
|
|
case NotifyGrab:
|
|
event->crossing.mode = GDK_CROSSING_GRAB;
|
|
break;
|
|
case NotifyUngrab:
|
|
event->crossing.mode = GDK_CROSSING_UNGRAB;
|
|
break;
|
|
};
|
|
|
|
/* Translate the crossing detail into Gdk terms.
|
|
*/
|
|
switch (xevent->xcrossing.detail)
|
|
{
|
|
case NotifyInferior:
|
|
event->crossing.detail = GDK_NOTIFY_INFERIOR;
|
|
break;
|
|
case NotifyAncestor:
|
|
event->crossing.detail = GDK_NOTIFY_ANCESTOR;
|
|
break;
|
|
case NotifyVirtual:
|
|
event->crossing.detail = GDK_NOTIFY_VIRTUAL;
|
|
break;
|
|
case NotifyNonlinear:
|
|
event->crossing.detail = GDK_NOTIFY_NONLINEAR;
|
|
break;
|
|
case NotifyNonlinearVirtual:
|
|
event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
|
|
break;
|
|
default:
|
|
event->crossing.detail = GDK_NOTIFY_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
event->crossing.focus = xevent->xcrossing.focus;
|
|
event->crossing.state = xevent->xcrossing.state;
|
|
|
|
break;
|
|
|
|
case FocusIn:
|
|
case FocusOut:
|
|
/* We only care about focus events that indicate that _this_
|
|
* window (not a ancestor or child) got or lost the focus
|
|
*/
|
|
switch (xevent->xfocus.detail)
|
|
{
|
|
case NotifyAncestor:
|
|
case NotifyInferior:
|
|
case NotifyNonlinear:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("focus %s:\t\twindow: %ld",
|
|
(xevent->xany.type == FocusIn) ? "in" : "out",
|
|
xevent->xfocus.window));
|
|
|
|
/* gdk_keyboard_grab() causes following events. These events confuse
|
|
* the XIM focus, so ignore them.
|
|
*/
|
|
if (xevent->xfocus.mode == NotifyGrab ||
|
|
xevent->xfocus.mode == NotifyUngrab)
|
|
break;
|
|
|
|
event->focus_change.type = GDK_FOCUS_CHANGE;
|
|
event->focus_change.window = window;
|
|
event->focus_change.in = (xevent->xany.type == FocusIn);
|
|
|
|
break;
|
|
default:
|
|
return_val = FALSE;
|
|
}
|
|
break;
|
|
|
|
case KeymapNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("keymap notify"));
|
|
|
|
/* Not currently handled */
|
|
return_val = FALSE;
|
|
break;
|
|
|
|
case Expose:
|
|
GDK_NOTE (EVENTS,
|
|
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,
|
|
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.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:
|
|
{
|
|
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.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:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("no expose:\t\tdrawable: %ld",
|
|
xevent->xnoexpose.drawable));
|
|
|
|
event->no_expose.type = GDK_NO_EXPOSE;
|
|
event->no_expose.window = window;
|
|
|
|
break;
|
|
|
|
case VisibilityNotify:
|
|
#ifdef G_ENABLE_DEBUG
|
|
if (gdk_debug_flags & GDK_DEBUG_EVENTS)
|
|
switch (xevent->xvisibility.state)
|
|
{
|
|
case VisibilityFullyObscured:
|
|
g_message ("visibility notify:\twindow: %ld none",
|
|
xevent->xvisibility.window);
|
|
break;
|
|
case VisibilityPartiallyObscured:
|
|
g_message ("visibility notify:\twindow: %ld partial",
|
|
xevent->xvisibility.window);
|
|
break;
|
|
case VisibilityUnobscured:
|
|
g_message ("visibility notify:\twindow: %ld full",
|
|
xevent->xvisibility.window);
|
|
break;
|
|
}
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
event->visibility.type = GDK_VISIBILITY_NOTIFY;
|
|
event->visibility.window = window;
|
|
|
|
switch (xevent->xvisibility.state)
|
|
{
|
|
case VisibilityFullyObscured:
|
|
event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
|
|
break;
|
|
|
|
case VisibilityPartiallyObscured:
|
|
event->visibility.state = GDK_VISIBILITY_PARTIAL;
|
|
break;
|
|
|
|
case VisibilityUnobscured:
|
|
event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case CreateNotify:
|
|
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:
|
|
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 && !GDK_WINDOW_DESTROYED (window);
|
|
|
|
if (window && GDK_WINDOW_XID (window) != GDK_ROOT_WINDOW())
|
|
gdk_window_destroy_notify (window);
|
|
break;
|
|
|
|
case UnmapNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("unmap notify:\t\twindow: %ld",
|
|
xevent->xmap.window));
|
|
|
|
event->any.type = GDK_UNMAP;
|
|
event->any.window = window;
|
|
|
|
if (gdk_xgrab_window == window_private)
|
|
gdk_xgrab_window = NULL;
|
|
|
|
break;
|
|
|
|
case MapNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("map notify:\t\twindow: %ld",
|
|
xevent->xmap.window));
|
|
|
|
event->any.type = GDK_MAP;
|
|
event->any.window = window;
|
|
|
|
break;
|
|
|
|
case ReparentNotify:
|
|
GDK_NOTE (EVENTS,
|
|
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:
|
|
GDK_NOTE (EVENTS,
|
|
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.width,
|
|
xevent->xconfigure.height,
|
|
xevent->xconfigure.border_width,
|
|
xevent->xconfigure.above,
|
|
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
|
|
{
|
|
event->configure.type = GDK_CONFIGURE;
|
|
event->configure.window = window;
|
|
event->configure.width = xevent->xconfigure.width;
|
|
event->configure.height = xevent->xconfigure.height;
|
|
|
|
if (!xevent->xconfigure.x &&
|
|
!xevent->xconfigure.y &&
|
|
!GDK_WINDOW_DESTROYED (window))
|
|
{
|
|
gint tx = 0;
|
|
gint ty = 0;
|
|
Window child_window = 0;
|
|
|
|
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
|
|
{
|
|
event->configure.x = xevent->xconfigure.x;
|
|
event->configure.y = xevent->xconfigure.y;
|
|
}
|
|
window_private->x = event->configure.x;
|
|
window_private->y = event->configure.y;
|
|
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:
|
|
GDK_NOTE (EVENTS,
|
|
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;
|
|
|
|
break;
|
|
|
|
case SelectionClear:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("selection clear:\twindow: %ld",
|
|
xevent->xproperty.window));
|
|
|
|
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:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("selection request:\twindow: %ld",
|
|
xevent->xproperty.window));
|
|
|
|
event->selection.type = GDK_SELECTION_REQUEST;
|
|
event->selection.window = window;
|
|
event->selection.selection = xevent->xselectionrequest.selection;
|
|
event->selection.target = xevent->xselectionrequest.target;
|
|
event->selection.property = xevent->xselectionrequest.property;
|
|
event->selection.requestor = xevent->xselectionrequest.requestor;
|
|
event->selection.time = xevent->xselectionrequest.time;
|
|
|
|
break;
|
|
|
|
case SelectionNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("selection notify:\twindow: %ld",
|
|
xevent->xproperty.window));
|
|
|
|
|
|
event->selection.type = GDK_SELECTION_NOTIFY;
|
|
event->selection.window = window;
|
|
event->selection.selection = xevent->xselection.selection;
|
|
event->selection.target = xevent->xselection.target;
|
|
event->selection.property = xevent->xselection.property;
|
|
event->selection.time = xevent->xselection.time;
|
|
|
|
break;
|
|
|
|
case ColormapNotify:
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("colormap notify:\twindow: %ld",
|
|
xevent->xcolormap.window));
|
|
|
|
/* Not currently handled */
|
|
return_val = FALSE;
|
|
break;
|
|
|
|
case ClientMessage:
|
|
{
|
|
GList *tmp_list;
|
|
GdkFilterReturn result = GDK_FILTER_CONTINUE;
|
|
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("client message:\twindow: %ld",
|
|
xevent->xclient.window));
|
|
|
|
tmp_list = client_filters;
|
|
while (tmp_list)
|
|
{
|
|
GdkClientFilter *filter = tmp_list->data;
|
|
if (filter->type == xevent->xclient.message_type)
|
|
{
|
|
result = (*filter->function) (xevent, event, filter->data);
|
|
break;
|
|
}
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
|
|
switch (result)
|
|
{
|
|
case GDK_FILTER_REMOVE:
|
|
return_val = FALSE;
|
|
break;
|
|
case GDK_FILTER_TRANSLATE:
|
|
return_val = TRUE;
|
|
break;
|
|
case GDK_FILTER_CONTINUE:
|
|
/* Send unknown ClientMessage's on to Gtk for it to use */
|
|
event->client.type = GDK_CLIENT_EVENT;
|
|
event->client.window = window;
|
|
event->client.message_type = xevent->xclient.message_type;
|
|
event->client.data_format = xevent->xclient.format;
|
|
memcpy(&event->client.data, &xevent->xclient.data,
|
|
sizeof(event->client.data));
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case MappingNotify:
|
|
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 &&
|
|
!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)
|
|
gdk_window_ref (event->any.window);
|
|
if (((event->any.type == GDK_ENTER_NOTIFY) ||
|
|
(event->any.type == GDK_LEAVE_NOTIFY)) &&
|
|
(event->crossing.subwindow != NULL))
|
|
gdk_window_ref (event->crossing.subwindow);
|
|
}
|
|
else
|
|
{
|
|
/* Mark this event as having no resources to be freed */
|
|
event->any.window = NULL;
|
|
event->any.type = GDK_NOTHING;
|
|
}
|
|
|
|
if (window)
|
|
gdk_window_unref (window);
|
|
|
|
return return_val;
|
|
}
|
|
|
|
GdkFilterReturn
|
|
gdk_wm_protocols_filter (GdkXEvent *xev,
|
|
GdkEvent *event,
|
|
gpointer data)
|
|
{
|
|
XEvent *xevent = (XEvent *)xev;
|
|
|
|
if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
|
|
{
|
|
/* The delete window request specifies a window
|
|
* to delete. We don't actually destroy the
|
|
* window because "it is only a request". (The
|
|
* window might contain vital data that the
|
|
* program does not want destroyed). Instead
|
|
* the event is passed along to the program,
|
|
* which should then destroy the window.
|
|
*/
|
|
GDK_NOTE (EVENTS,
|
|
g_message ("delete window:\t\twindow: %ld",
|
|
xevent->xclient.window));
|
|
|
|
event->any.type = GDK_DELETE;
|
|
|
|
return GDK_FILTER_TRANSLATE;
|
|
}
|
|
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;
|
|
}
|
|
|
|
#if 0
|
|
static Bool
|
|
gdk_event_get_type (Display *display,
|
|
XEvent *xevent,
|
|
XPointer arg)
|
|
{
|
|
GdkEvent event;
|
|
GdkPredicate *pred;
|
|
|
|
if (gdk_event_translate (&event, xevent, FALSE))
|
|
{
|
|
pred = (GdkPredicate*) arg;
|
|
return (* pred->func) (&event, pred->data);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
gdk_events_queue (void)
|
|
{
|
|
GList *node;
|
|
GdkEvent *event;
|
|
XEvent xevent;
|
|
|
|
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 = xevent.xany.send_event ? TRUE : FALSE;
|
|
|
|
((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
|
|
|
|
gdk_event_queue_append (event);
|
|
node = gdk_queued_tail;
|
|
|
|
if (gdk_event_translate (event, &xevent, FALSE))
|
|
{
|
|
((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
|
|
}
|
|
else
|
|
{
|
|
gdk_event_queue_remove_link (node);
|
|
g_list_free_1 (node);
|
|
gdk_event_free (event);
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gdk_event_prepare (GSource *source,
|
|
gint *timeout)
|
|
{
|
|
gboolean retval;
|
|
|
|
GDK_THREADS_ENTER ();
|
|
|
|
*timeout = -1;
|
|
|
|
retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
|
|
|
|
GDK_THREADS_LEAVE ();
|
|
|
|
return retval;
|
|
}
|
|
|
|
static gboolean
|
|
gdk_event_check (GSource *source)
|
|
{
|
|
gboolean retval;
|
|
|
|
GDK_THREADS_ENTER ();
|
|
|
|
if (event_poll_fd.revents & G_IO_IN)
|
|
retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
|
|
else
|
|
retval = FALSE;
|
|
|
|
GDK_THREADS_LEAVE ();
|
|
|
|
return retval;
|
|
}
|
|
|
|
static gboolean
|
|
gdk_event_dispatch (GSource *source,
|
|
GSourceFunc callback,
|
|
gpointer user_data)
|
|
{
|
|
GdkEvent *event;
|
|
|
|
GDK_THREADS_ENTER ();
|
|
|
|
gdk_events_queue();
|
|
event = gdk_event_unqueue();
|
|
|
|
if (event)
|
|
{
|
|
if (gdk_event_func)
|
|
(*gdk_event_func) (event, gdk_event_data);
|
|
|
|
gdk_event_free (event);
|
|
}
|
|
|
|
GDK_THREADS_LEAVE ();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Sends a ClientMessage to all toplevel client windows */
|
|
gboolean
|
|
gdk_event_send_client_message (GdkEvent *event, guint32 xid)
|
|
{
|
|
XEvent sev;
|
|
|
|
g_return_val_if_fail(event != NULL, FALSE);
|
|
|
|
/* Set up our event to send, with the exception of its target window */
|
|
sev.xclient.type = ClientMessage;
|
|
sev.xclient.display = gdk_display;
|
|
sev.xclient.format = event->client.data_format;
|
|
sev.xclient.window = xid;
|
|
memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
|
|
sev.xclient.message_type = event->client.message_type;
|
|
|
|
return gdk_send_xevent (xid, False, NoEventMask, &sev);
|
|
}
|
|
|
|
/* Sends a ClientMessage to all toplevel client windows */
|
|
gboolean
|
|
gdk_event_send_client_message_to_all_recurse (XEvent *xev,
|
|
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;
|
|
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_warnings = old_warnings;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (type)
|
|
{
|
|
send = TRUE;
|
|
XFree (data);
|
|
}
|
|
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 ||
|
|
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))
|
|
found = TRUE;
|
|
|
|
XFree (ret_children);
|
|
}
|
|
|
|
if (send || (!found && (level == 1)))
|
|
{
|
|
xev->xclient.window = xid;
|
|
gdk_send_xevent (xid, False, NoEventMask, xev);
|
|
}
|
|
|
|
gdk_error_warnings = old_warnings;
|
|
|
|
return (send || found);
|
|
}
|
|
|
|
void
|
|
gdk_event_send_clientmessage_toall (GdkEvent *event)
|
|
{
|
|
XEvent sev;
|
|
gint old_warnings = gdk_error_warnings;
|
|
|
|
g_return_if_fail(event != NULL);
|
|
|
|
/* Set up our event to send, with the exception of its target window */
|
|
sev.xclient.type = ClientMessage;
|
|
sev.xclient.display = gdk_display;
|
|
sev.xclient.format = event->client.data_format;
|
|
memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
|
|
sev.xclient.message_type = event->client.message_type;
|
|
|
|
gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
|
|
|
|
gdk_error_warnings = old_warnings;
|
|
}
|
|
|
|
/*
|
|
*--------------------------------------------------------------
|
|
* gdk_flush
|
|
*
|
|
* Flushes the Xlib output buffer and then waits
|
|
* until all requests have been received and processed
|
|
* by the X server. The only real use for this function
|
|
* is in dealing with XShm.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Results:
|
|
*
|
|
* Side effects:
|
|
*
|
|
*--------------------------------------------------------------
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|