/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
+ * Josh MacDonald, Ryan Lortie
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*/
/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * Modified by the GTK+ Team and others 1997-2007. 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 <config.h>
+#include "config.h"
#include "gdk.h"
#include "gdkprivate-x11.h"
#include <string.h>
#include "gdkinputprivate.h"
-
+#include "gdksettings.c"
#include "gdkalias.h"
+
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
#include <X11/extensions/Xfixes.h>
#endif
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
#include <X11/Xatom.h>
typedef struct _GdkIOClosure GdkIOClosure;
{
GdkInputFunction function;
GdkInputCondition condition;
- GdkDestroyNotify notify;
+ GDestroyNotify notify;
gpointer data;
};
static GSource *gdk_display_source_new (GdkDisplay *display);
static gboolean gdk_check_xpending (GdkDisplay *display);
-static void gdk_xsettings_watch_cb (Window window,
+static Bool gdk_xsettings_watch_cb (Window window,
Bool is_start,
long mask,
void *cb_data);
/* Keep a flag to avoid extra notifies that we don't need
*/
screen_x11->xsettings_in_init = TRUE;
- screen_x11->xsettings_client = xsettings_client_new (screen_x11->xdisplay,
- screen_x11->screen_num,
- gdk_xsettings_notify_cb,
- gdk_xsettings_watch_cb,
- screen);
- xsettings_client_set_grab_func (screen_x11->xsettings_client,
- refcounted_grab_server);
- xsettings_client_set_ungrab_func (screen_x11->xsettings_client,
- refcounted_ungrab_server);
+ screen_x11->xsettings_client = xsettings_client_new_with_grab_funcs (screen_x11->xdisplay,
+ screen_x11->screen_num,
+ gdk_xsettings_notify_cb,
+ gdk_xsettings_watch_cb,
+ screen,
+ refcounted_grab_server,
+ refcounted_ungrab_server);
screen_x11->xsettings_in_init = FALSE;
}
{
GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
- xsettings_client_destroy (screen_x11->xsettings_client);
- screen_x11->xsettings_client = NULL;
+ if (screen_x11->xsettings_client)
+ {
+ xsettings_client_destroy (screen_x11->xsettings_client);
+ screen_x11->xsettings_client = NULL;
+ }
}
void
display_sources = g_list_prepend (display_sources,display_source);
gdk_display_add_client_message_filter (display,
- gdk_atom_intern ("WM_PROTOCOLS", FALSE),
+ gdk_atom_intern_static_string ("WM_PROTOCOLS"),
gdk_wm_protocols_filter,
NULL);
}
+void
+_gdk_events_uninit (GdkDisplay *display)
+{
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+ if (display_x11->event_source)
+ {
+ display_sources = g_list_remove (display_sources,
+ display_x11->event_source);
+ g_source_destroy (display_x11->event_source);
+ g_source_unref (display_x11->event_source);
+ display_x11->event_source = NULL;
+ }
+}
/**
* gdk_events_pending:
GdkEvent *event;
g_return_val_if_fail (window != NULL, NULL);
-
+
XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent,
graphics_expose_predicate, (XPointer) window);
* @data: user data to pass to @func.
*
* Adds a filter to be called when X ClientMessage events are received.
+ * See gdk_window_add_filter() if you are interested in filtering other
+ * types of events.
*
* Since: 2.2
**/
{
GdkKeymap *keymap = gdk_keymap_get_for_display (display);
gunichar c = 0;
- guchar buf[7];
+ gchar buf[7];
event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
event->key.time = xevent->xkey.time;
&event->key.keyval,
NULL, NULL, NULL);
+ _gdk_keymap_add_virtual_modifiers (keymap, &event->key.state);
+ event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
+
/* Fill in event->string crudely, since various programs
* depend on it.
*/
gdk_event_get_time (event));
}
+static gboolean
+is_parent_of (GdkWindow *parent,
+ GdkWindow *child)
+{
+ GdkWindow *w;
+
+ w = child;
+ while (w != NULL)
+ {
+ if (w == parent)
+ return TRUE;
+
+ w = gdk_window_get_parent (w);
+ }
+
+ return FALSE;
+}
+
static gboolean
gdk_event_translate (GdkDisplay *display,
GdkEvent *event,
GdkWindow *filter_window;
GdkWindowImplX11 *window_impl = NULL;
gboolean return_val;
- gint xoffset, yoffset;
GdkScreen *screen = NULL;
GdkScreenX11 *screen_x11 = NULL;
GdkToplevelX11 *toplevel = NULL;
if (window != NULL)
{
+ /* Apply keyboard grabs to non-native windows */
+ if (/* Is key event */
+ (xevent->type == KeyPress || xevent->type == KeyRelease) &&
+ /* And we have a grab */
+ display->keyboard_grab.window != NULL &&
+ (
+ /* The window is not a descendant of the grabbed window */
+ !is_parent_of ((GdkWindow *)display->keyboard_grab.window, window) ||
+ /* Or owner event is false */
+ !display->keyboard_grab.owner_events
+ )
+ )
+ {
+ /* Report key event against grab window */
+ window = display->keyboard_grab.window;;
+ window_private = (GdkWindowObject *) window;
+ }
+
window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
/* Move key events on focus window to the real toplevel, and
return_val = TRUE;
- if (window)
- {
- _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
- }
- else
- {
- xoffset = 0;
- yoffset = 0;
- }
-
switch (xevent->type)
{
case KeyPress:
event->scroll.window = window;
event->scroll.time = xevent->xbutton.time;
- event->scroll.x = xevent->xbutton.x + xoffset;
- event->scroll.y = xevent->xbutton.y + yoffset;
+ event->scroll.x = xevent->xbutton.x;
+ event->scroll.y = xevent->xbutton.y;
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->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 = 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.axes = NULL;
return_val = FALSE;
break;
}
-
- _gdk_event_button_generate (display, event);
break;
}
set_user_time (window, event);
- _gdk_xgrab_check_button_event (window, xevent);
break;
case ButtonRelease:
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 = 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.axes = NULL;
event->button.device = display->core_pointer;
if (!set_screen_from_root (display, event, xevent->xbutton.root))
- {
- return_val = FALSE;
- break;
- }
-
- _gdk_xgrab_check_button_event (window, xevent);
+ return_val = FALSE;
+
break;
case MotionNotify:
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 = xevent->xmotion.x;
+ event->motion.y = xevent->xmotion.y;
event->motion.x_root = (gfloat)xevent->xmotion.x_root;
event->motion.y_root = (gfloat)xevent->xmotion.y_root;
event->motion.axes = NULL;
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 = xevent->xcrossing.x;
+ event->crossing.y = xevent->xcrossing.y;
event->crossing.x_root = xevent->xcrossing.x_root;
event->crossing.y_root = xevent->xcrossing.y_root;
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 = xevent->xcrossing.x;
+ event->crossing.y = xevent->xcrossing.y;
event->crossing.x_root = xevent->xcrossing.x_root;
event->crossing.y_root = xevent->xcrossing.y_root;
{
GdkRectangle expose_rect;
- expose_rect.x = xevent->xexpose.x + xoffset;
- expose_rect.y = xevent->xexpose.y + yoffset;
+ expose_rect.x = xevent->xexpose.x;
+ expose_rect.y = xevent->xexpose.y;
expose_rect.width = xevent->xexpose.width;
expose_rect.height = xevent->xexpose.height;
break;
}
- expose_rect.x = xevent->xgraphicsexpose.x + xoffset;
- expose_rect.y = xevent->xgraphicsexpose.y + yoffset;
+ expose_rect.x = xevent->xgraphicsexpose.x;
+ expose_rect.y = xevent->xgraphicsexpose.y;
expose_rect.width = xevent->xgraphicsexpose.width;
expose_rect.height = xevent->xgraphicsexpose.height;
? " (discarding substructure)"
: ""));
if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
- _gdk_x11_screen_size_changed (screen, xevent);
+ {
+ window_private->width = xevent->xconfigure.width;
+ window_private->height = xevent->xconfigure.height;
+
+ _gdk_x11_drawable_update_size (window_private->impl);
+ _gdk_x11_screen_size_changed (screen, xevent);
+ }
if (window &&
xevent->xconfigure.event == xevent->xconfigure.window &&
}
#endif
- if (!window ||
+ if (!window ||
xevent->xconfigure.event != xevent->xconfigure.window ||
GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
}
window_private->x = event->configure.x;
window_private->y = event->configure.y;
- window_impl->width = xevent->xconfigure.width;
- window_impl->height = xevent->xconfigure.height;
+ window_private->width = xevent->xconfigure.width;
+ window_private->height = xevent->xconfigure.height;
+ _gdk_window_update_size (window);
_gdk_x11_drawable_update_size (window_private->impl);
if (window_private->resize_count >= 1)
event->selection.window = window;
event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
- event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
+ if (xevent->xselection.property == None)
+ event->selection.property = GDK_NONE;
+ else
+ event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
event->selection.time = xevent->xselection.time;
break;
break;
case XkbStateNotify:
- _gdk_keymap_state_changed (display);
+ _gdk_keymap_state_changed (display, xevent);
break;
}
}
if (xevent->type - display_x11->xfixes_event_base == XFixesSelectionNotify)
{
XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent;
+
+ _gdk_x11_screen_process_owner_change (screen, xevent);
+
event->owner_change.type = GDK_OWNER_CHANGE;
event->owner_change.window = window;
event->owner_change.owner = selection_notify->owner;
selection_notify->selection);
event->owner_change.time = selection_notify->timestamp;
event->owner_change.selection_time = selection_notify->selection_timestamp;
+
+ return_val = TRUE;
+ }
+ else
+#endif
+#ifdef HAVE_RANDR
+ if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
+ xevent->type - display_x11->xrandr_event_base == RRNotify)
+ {
+ if (screen)
+ _gdk_x11_screen_size_changed (screen, xevent);
+ }
+ else
+#endif
+#if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+ if (display_x11->have_xdamage && window_private && window_private->composited &&
+ xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
+ ((XDamageNotifyEvent *) xevent)->damage == window_impl->damage)
+ {
+ XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
+ XserverRegion repair;
+ GdkRectangle rect;
+
+ rect.x = window_private->x + damage_event->area.x;
+ rect.y = window_private->y + damage_event->area.y;
+ rect.width = damage_event->area.width;
+ rect.height = damage_event->area.height;
+
+ repair = XFixesCreateRegion (display_x11->xdisplay,
+ &damage_event->area, 1);
+ XDamageSubtract (display_x11->xdisplay,
+ window_impl->damage,
+ repair, None);
+ XFixesDestroyRegion (display_x11->xdisplay, repair);
+
+ if (window_private->parent != NULL)
+ _gdk_window_process_expose (GDK_WINDOW (window_private->parent),
+ damage_event->serial, &rect);
return_val = TRUE;
}
if (window)
g_object_unref (window);
-
+
return return_val;
}
!_gdk_x11_display_is_root_window (display,
xevent->xclient.window))
{
- XEvent xev = *xevent;
+ XClientMessageEvent xclient = xevent->xclient;
- xev.xclient.window = GDK_WINDOW_XROOTWIN (win);
+ xclient.window = GDK_WINDOW_XROOTWIN (win);
XSendEvent (GDK_WINDOW_XDISPLAY (win),
- xev.xclient.window,
+ xclient.window,
False,
- SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
return GDK_FILTER_REMOVE;
}
if (gdk_event_translate (display, event, &xevent, FALSE))
{
((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
+ _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
}
else
{
gulong bytes_after;
guchar *data;
Window *xwindow;
-
- /* 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.
- */
+ GTimeVal tv;
screen_x11 = GDK_SCREEN_X11 (screen);
display = screen_x11->display;
+
+ g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
- if (screen_x11->wmspec_check_window != None)
- return; /* already have it */
-
+ g_get_current_time (&tv);
+
+ if (ABS (tv.tv_sec - screen_x11->last_wmspec_check_time) < 15)
+ return; /* we've checked recently */
+
+ screen_x11->last_wmspec_check_time = tv.tv_sec;
+
data = NULL;
XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
xwindow = (Window *)data;
+ if (screen_x11->wmspec_check_window == *xwindow)
+ {
+ XFree (xwindow);
+ return;
+ }
+
gdk_error_trap_push ();
/* Find out if this WM goes away, so we can reset everything. */
screen_x11 = GDK_SCREEN_X11 (screen);
+ if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
+ return screen_x11->window_manager_name;
+
fetch_net_wm_check_window (screen);
if (screen_x11->need_refetch_wm_name)
gint format;
gulong n_items;
gulong bytes_after;
- guchar *name;
+ gchar *name;
name = NULL;
gulong n_atoms;
};
+static void
+cleanup_atoms(gpointer data)
+{
+ NetWmSupportedAtoms *supported_atoms = data;
+ if (supported_atoms->atoms)
+ XFree (supported_atoms->atoms);
+ g_free (supported_atoms);
+}
+
/**
* gdk_x11_screen_supports_net_wm_hint:
* @screen: the relevant #GdkScreen.
screen_x11 = GDK_SCREEN_X11 (screen);
display = screen_x11->display;
+ if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+ return FALSE;
+
supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
if (!supported_atoms)
{
supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
- g_object_set_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms);
+ g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
}
fetch_net_wm_check_window (screen);
return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
}
-static const struct
-{
- const char *xsettings_name;
- const char *gdk_name;
-} settings_map[] = {
- { "Net/DoubleClickTime", "gtk-double-click-time" },
- { "Net/DoubleClickDistance", "gtk-double-click-distance" },
- { "Net/DndDragThreshold", "gtk-dnd-drag-threshold" },
- { "Net/CursorBlink", "gtk-cursor-blink" },
- { "Net/CursorBlinkTime", "gtk-cursor-blink-time" },
- { "Net/ThemeName", "gtk-theme-name" },
- { "Net/IconThemeName", "gtk-icon-theme-name" },
- { "Gtk/CanChangeAccels", "gtk-can-change-accels" },
- { "Gtk/ColorPalette", "gtk-color-palette" },
- { "Gtk/FontName", "gtk-font-name" },
- { "Gtk/IconSizes", "gtk-icon-sizes" },
- { "Gtk/KeyThemeName", "gtk-key-theme-name" },
- { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
- { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
- { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" },
- { "Gtk/IMStatusStyle", "gtk-im-status-style" },
- { "Gtk/Modules", "gtk-modules" },
- { "Gtk/FileChooserBackend", "gtk-file-chooser-backend" },
- { "Gtk/ButtonImages", "gtk-button-images" },
- { "Gtk/MenuImages", "gtk-menu-images" },
- { "Gtk/MenuBarAccel", "gtk-menu-bar-accel" },
- { "Gtk/CursorThemeName", "gtk-cursor-theme-name" },
- { "Gtk/CursorThemeSize", "gtk-cursor-theme-size" },
- { "Xft/Antialias", "gtk-xft-antialias" },
- { "Xft/Hinting", "gtk-xft-hinting" },
- { "Xft/HintStyle", "gtk-xft-hintstyle" },
- { "Xft/RGBA", "gtk-xft-rgba" },
- { "Xft/DPI", "gtk-xft-dpi" },
-};
static void
gdk_xsettings_notify_cb (const char *name,
new_event.setting.send_event = FALSE;
new_event.setting.name = NULL;
- for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
- if (strcmp (settings_map[i].xsettings_name, name) == 0)
+ for (i = 0; i < GDK_SETTINGS_N_ELEMENTS() ; i++)
+ if (strcmp (GDK_SETTINGS_X_NAME (i), name) == 0)
{
- new_event.setting.name = (char *)settings_map[i].gdk_name;
+ new_event.setting.name = (char*) GDK_SETTINGS_GDK_NAME (i);
break;
}
{
if (!g_value_type_transformable (src_type, dest_type))
{
- g_warning ("Cannot tranform xsetting %s of type %s to type %s\n",
+ g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
xsettings_name,
g_type_name (src_type),
g_type_name (dest_type));
screen_x11 = GDK_SCREEN_X11 (screen);
- for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
- if (strcmp (settings_map[i].gdk_name, name) == 0)
+ for (i = 0; i < GDK_SETTINGS_N_ELEMENTS(); i++)
+ if (strcmp (GDK_SETTINGS_GDK_NAME (i), name) == 0)
{
- xsettings_name = settings_map[i].xsettings_name;
+ xsettings_name = GDK_SETTINGS_X_NAME (i);
break;
}
return GDK_FILTER_CONTINUE;
}
-static void
+static Bool
gdk_xsettings_watch_cb (Window window,
Bool is_start,
long mask,
if (is_start)
{
- if (!gdkwin)
- gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
- else
+ if (gdkwin)
g_object_ref (gdkwin);
-
+ else
+ {
+ gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
+
+ /* gdk_window_foreign_new_for_display() can fail and return NULL if the
+ * window has already been destroyed.
+ */
+ if (!gdkwin)
+ return False;
+ }
+
gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
}
else
{
- g_assert (gdkwin);
+ if (!gdkwin)
+ {
+ /* gdkwin should not be NULL here, since if starting the watch succeeded
+ * we have a reference on the window. It might mean that the caller didn't
+ * remove the watch when it got a DestroyNotify event. Or maybe the
+ * caller ignored the return value when starting the watch failed.
+ */
+ g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
+ return False;
+ }
+
gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
g_object_unref (gdkwin);
}
+
+ return True;
+}
+
+void
+_gdk_windowing_event_data_copy (const GdkEvent *src,
+ GdkEvent *dst)
+{
+}
+
+void
+_gdk_windowing_event_data_free (GdkEvent *event)
+{
}
#define __GDK_EVENTS_X11_C__