#include "gdkkeysyms.h"
+#include "xsettings-client.h"
+
#if HAVE_CONFIG_H
# include <config.h>
# if STDC_HEADERS
#include "gdkinputprivate.h"
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#include <X11/Xatom.h>
+
typedef struct _GdkIOClosure GdkIOClosure;
typedef struct _GdkEventPrivate GdkEventPrivate;
XPointer arg);
#endif
-static gboolean gdk_event_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout,
- gpointer user_data);
-static gboolean gdk_event_check (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data);
-static gboolean gdk_event_dispatch (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data);
+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);
+static void gdk_xsettings_watch_cb (Window window,
+ Bool is_start,
+ long mask,
+ void *cb_data);
+static void gdk_xsettings_notify_cb (const char *name,
+ XSettingsAction action,
+ XSettingsSetting *setting,
+ void *data);
+
/* Private variable declarations
*/
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;
+
+static XSettingsClient *xsettings_client;
/*********************************************
* 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));
- 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);
+ 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);
+
+ xsettings_client = xsettings_client_new (gdk_display, DefaultScreen (gdk_display),
+ gdk_xsettings_notify_cb,
+ gdk_xsettings_watch_cb,
+ NULL);
}
/*
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);
+ }
+}
+
+#define HAS_FOCUS(window_impl) \
+ ((window_impl)->has_focus || (window_impl)->has_pointer_focus)
+
+static void
+generate_focus_event (GdkWindow *window,
+ gboolean in)
+{
+ GdkEvent event;
+
+ event.type = GDK_FOCUS_CHANGE;
+ event.focus_change.window = window;
+ event.focus_change.send_event = FALSE;
+ event.focus_change.in = in;
+
+ gdk_event_put (&event);
+}
+
static gint
gdk_event_translate (GdkEvent *event,
XEvent *xevent,
GdkWindow *window;
GdkWindowObject *window_private;
+ GdkWindowImplX11 *window_impl = NULL;
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;
}
window = gdk_window_lookup (xevent->xany.window);
- /* FIXME: window might be a GdkPixmap!!! */
-
window_private = (GdkWindowObject *) window;
+
+ if (_gdk_moveresize_window &&
+ (xevent->xany.type == MotionNotify ||
+ xevent->xany.type == ButtonRelease))
+ {
+ _gdk_moveresize_handle_event (xevent);
+ gdk_window_unref (window);
+ return FALSE;
+ }
+
+ 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;
+ }
+ /* FIXME: window might be a GdkPixmap!!! */
if (window != NULL)
- gdk_window_ref (window);
-
+ {
+ window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+
+ if (xevent->xany.window != GDK_WINDOW_XID (window))
+ {
+ g_assert (xevent->xany.window == window_impl->focus_window);
+
+ switch (xevent->type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ xevent->xany.window = GDK_WINDOW_XID (window);
+ break;
+ default:
+ return False;
+ }
+ }
+
+ gdk_window_ref (window);
+ }
+
event->any.window = window;
event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
}
}
-#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
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 --;
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);
/* 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)
- {
+ switch (xevent->xbutton.button)
+ {
+ case 4: /* up */
+ case 5: /* down */
+ case 6: /* left */
+ case 7: /* right */
event->scroll.type = GDK_SCROLL;
- event->scroll.direction = (xevent->xbutton.button == 4) ?
- GDK_SCROLL_UP : GDK_SCROLL_DOWN;
+
+ if (xevent->xbutton.button == 4)
+ event->scroll.direction = GDK_SCROLL_UP;
+ else if (xevent->xbutton.button == 5)
+ event->scroll.direction = GDK_SCROLL_DOWN;
+ else if (xevent->xbutton.button == 6)
+ event->scroll.direction = GDK_SCROLL_LEFT;
+ else
+ event->scroll.direction = GDK_SCROLL_RIGHT;
+
event->scroll.window = window;
event->scroll.time = xevent->xbutton.x;
event->scroll.x = xevent->xbutton.x + xoffset;
event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
event->scroll.state = (GdkModifierType) xevent->xbutton.state;
event->scroll.device = gdk_core_pointer;
- }
- else
- {
+ break;
+
+ default:
event->button.type = GDK_BUTTON_PRESS;
event->button.window = window;
event->button.time = xevent->xbutton.time;
event->button.device = gdk_core_pointer;
gdk_event_button_generate (event);
+ break;
}
break;
}
/* We treat button presses as scroll wheel events, so ignore the release */
- if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
+ if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
+ xevent->xbutton.button == 6 || xevent->xbutton.button ==7)
{
return_val = FALSE;
break;
xevent->xcrossing.window,
xevent->xcrossing.detail,
xevent->xcrossing.subwindow));
-
+
+ /* Handle focusing (in the case where no window manager is running */
+ if (window &&
+ GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
+ xevent->xcrossing.detail != NotifyInferior &&
+ xevent->xcrossing.focus && !window_impl->has_focus)
+ {
+ gboolean had_focus = HAS_FOCUS (window_impl);
+
+ window_impl->has_pointer_focus = TRUE;
+
+ if (HAS_FOCUS (window_impl) != had_focus)
+ generate_focus_event (window, TRUE);
+ }
+
/* Tell XInput stuff about it if appropriate */
if (window_private &&
!GDK_WINDOW_DESTROYED (window) &&
xevent->xcrossing.window,
xevent->xcrossing.detail, xevent->xcrossing.subwindow));
+ /* Handle focusing (in the case where no window manager is running */
+ if (window &&
+ GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
+ xevent->xcrossing.detail != NotifyInferior &&
+ xevent->xcrossing.focus && !window_impl->has_focus)
+ {
+ gboolean had_focus = HAS_FOCUS (window_impl);
+
+ window_impl->has_pointer_focus = FALSE;
+
+ if (HAS_FOCUS (window_impl) != had_focus)
+ generate_focus_event (window, FALSE);
+ }
+
event->crossing.type = GDK_LEAVE_NOTIFY;
event->crossing.window = window;
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 FocusIn:
+ GDK_NOTE (EVENTS,
+ g_message ("focus in:\t\twindow: %ld", xevent->xfocus.window));
+
+ if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
{
- 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));
+ gboolean had_focus = HAS_FOCUS (window_impl);
+ switch (xevent->xfocus.detail)
+ {
+ case NotifyAncestor:
+ case NotifyNonlinear:
+ case NotifyVirtual:
+ case NotifyNonlinearVirtual:
+ window_impl->has_focus = TRUE;
+ break;
+ case NotifyPointer:
+ window_impl->has_pointer_focus = TRUE;
+ break;
+ case NotifyInferior:
+ case NotifyPointerRoot:
+ case NotifyDetailNone:
+ break;
+ }
+
+ if (HAS_FOCUS (window_impl) != had_focus)
+ generate_focus_event (window, TRUE);
+ }
+ break;
+ case FocusOut:
+ GDK_NOTE (EVENTS,
+ g_message ("focus out:\t\twindow: %ld", xevent->xfocus.window));
+
+ if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
+ {
+ gboolean had_focus = HAS_FOCUS (window_impl);
+
+ switch (xevent->xfocus.detail)
+ {
+ case NotifyAncestor:
+ case NotifyNonlinear:
+ case NotifyVirtual:
+ case NotifyNonlinearVirtual:
+ window_impl->has_focus = FALSE;
+ break;
+ case NotifyPointer:
+ window_impl->has_pointer_focus = FALSE;
+ break;
+ case NotifyInferior:
+ case NotifyPointerRoot:
+ case NotifyDetailNone:
+ break;
+ }
+
+ if (HAS_FOCUS (window_impl) != had_focus)
+ generate_focus_event (window, FALSE);
+ }
+ break;
+
+#if 0
/* 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);
+#endif
- break;
- default:
- return_val = FALSE;
- }
- break;
-
case KeymapNotify:
GDK_NOTE (EVENTS,
g_message ("keymap notify"));
{
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;
{
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;
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 (window && 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;
event->any.type = GDK_MAP;
event->any.window = window;
+
+ /* Unset iconified if it was set */
+ if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
+ gdk_synthesize_window_state (window,
+ GDK_WINDOW_STATE_ICONIFIED,
+ 0);
break;
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;
+ if (window_private->resize_count >= 1)
+ {
+ window_private->resize_count -= 1;
+
+ if (window_private->resize_count == 0 &&
+ window == _gdk_moveresize_window)
+ _gdk_moveresize_configure_done ();
+ }
}
break;
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;
/* 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) */
}
else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
{
+ GdkWindow *win = event->any.window;
+ Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
+
+ /* There is no way of knowing reliably whether we are viewable so we need
+ * to trap errors so we don't cause a BadMatch.
+ */
+ gdk_error_trap_push ();
+ XSetInputFocus (GDK_WINDOW_XDISPLAY (win),
+ focus_win,
+ RevertToParent,
+ xevent->xclient.data.l[1]);
+ XSync (GDK_WINDOW_XDISPLAY (win), False);
+ gdk_error_trap_pop ();
}
else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
{
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 ();
}
static gboolean
-gdk_event_prepare (gpointer source_data,
- GTimeVal *current_time,
- gint *timeout,
- gpointer user_data)
+gdk_event_prepare (GSource *source,
+ gint *timeout)
{
gboolean retval;
}
static gboolean
-gdk_event_check (gpointer source_data,
- GTimeVal *current_time,
- gpointer user_data)
+gdk_event_check (GSource *source)
{
gboolean retval;
}
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;
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);
+}
+
+static struct
+{
+ const char *xsettings_name;
+ const char *gdk_name;
+} settings_map[] = {
+ { "Net/DoubleClickTime", "gtk-double-click-timeout" },
+ { "Net/DragThreshold", "gtk-drag-threshold" },
+ { "Gtk/ColorPalette", "gtk-color-palette" },
+ { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
+ { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
+ { "Net/CursorBlink", "gtk-cursor-blink" },
+ { "Net/CursorBlinkTime", "gtk-cursor-blink-time" }
+};
+
+static void
+gdk_xsettings_notify_cb (const char *name,
+ XSettingsAction action,
+ XSettingsSetting *setting,
+ void *data)
+{
+ GdkEvent new_event;
+ int i;
+
+ new_event.type = GDK_SETTING;
+ new_event.setting.window = NULL;
+ 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)
+ {
+ new_event.setting.name = g_strdup (settings_map[i].gdk_name);
+ break;
+ }
+
+ if (!new_event.setting.name)
+ return;
+
+ switch (action)
+ {
+ case XSETTINGS_ACTION_NEW:
+ new_event.setting.action = GDK_SETTING_ACTION_NEW;
+ break;
+ case XSETTINGS_ACTION_CHANGED:
+ new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
+ break;
+ case XSETTINGS_ACTION_DELETED:
+ new_event.setting.action = GDK_SETTING_ACTION_DELETED;
+ break;
+ }
+
+ gdk_event_put (&new_event);
+}
+
+static gboolean
+check_transform (const gchar *xsettings_name,
+ GType src_type,
+ GType dest_type)
+{
+ if (!g_value_type_transformable (src_type, dest_type))
+ {
+ g_warning ("Cannot tranform xsetting %s of type %s to type %s\n",
+ xsettings_name,
+ g_type_name (src_type),
+ g_type_name (dest_type));
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+gboolean
+gdk_setting_get (const gchar *name,
+ GValue *value)
+{
+ const char *xsettings_name = NULL;
+ XSettingsResult result;
+ XSettingsSetting *setting;
+ gboolean success = FALSE;
+ gint i;
+ GValue tmp_val = { 0, };
+
+ for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
+ if (strcmp (settings_map[i].gdk_name, name) == 0)
+ {
+ xsettings_name = settings_map[i].xsettings_name;
+ break;
+ }
+
+ if (!xsettings_name)
+ return FALSE;
+
+ result = xsettings_client_get_setting (xsettings_client, xsettings_name, &setting);
+ if (result != XSETTINGS_SUCCESS)
+ return FALSE;
+
+ switch (setting->type)
+ {
+ case XSETTINGS_TYPE_INT:
+ if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
+ {
+ g_value_init (&tmp_val, G_TYPE_INT);
+ g_value_set_int (&tmp_val, setting->data.v_int);
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ case XSETTINGS_TYPE_STRING:
+ if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
+ {
+ g_value_init (&tmp_val, G_TYPE_STRING);
+ g_value_set_string (&tmp_val, setting->data.v_string);
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ case XSETTINGS_TYPE_COLOR:
+ if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
+ {
+ GdkColor color;
+
+ g_value_init (&tmp_val, GDK_TYPE_COLOR);
+
+ color.pixel = 0;
+ color.red = setting->data.v_color.red;
+ color.green = setting->data.v_color.green;
+ color.blue = setting->data.v_color.blue;
+
+ g_value_set_boxed (&tmp_val, &color);
+
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ }
+
+ g_value_unset (&tmp_val);
+
+ xsettings_setting_free (setting);
+
+ return success;
+}
+
+GdkFilterReturn
+gdk_xsettings_client_event_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ if (xsettings_client_process_event (xsettings_client, (XEvent *)xevent))
+ return GDK_FILTER_REMOVE;
+ else
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+gdk_xsettings_watch_cb (Window window,
+ Bool is_start,
+ long mask,
+ void *cb_data)
+{
+ GdkWindow *gdkwin;
+
+ gdkwin = gdk_window_lookup (window);
+ if (is_start)
+ gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
+ else
+ gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
+}