X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fx11%2Fgdkevents-x11.c;h=f0e44e8b06db4f6b55209a2560d4c3148a67bc06;hb=329c090ec18cf162db9d09b98f007f8979238116;hp=a0302943aaef3126701cb8992e94a5c112f5ef5d;hpb=da562f4dc8db7722ffc89198d42eb9e2efbda62a;p=~andy%2Fgtk diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index a0302943a..f0e44e8b0 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -28,6 +28,8 @@ #include "gdkprivate-x11.h" #include "gdkinternals.h" #include "gdkx.h" +#include "gdkscreen-x11.h" +#include "gdkdisplay-x11.h" #include "gdkkeysyms.h" @@ -49,21 +51,13 @@ #include typedef struct _GdkIOClosure GdkIOClosure; -typedef struct _GdkEventPrivate GdkEventPrivate; +typedef struct _GdkDisplaySource GdkDisplaySource; #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; @@ -72,10 +66,12 @@ struct _GdkIOClosure gpointer data; }; -struct _GdkEventPrivate +struct _GdkDisplaySource { - GdkEvent event; - guint flags; + GSource source; + + GdkDisplay *display; + GPollFD event_poll_fd; }; /* @@ -85,14 +81,10 @@ struct _GdkEventPrivate 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_translate (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent, + gboolean return_exposes); static gboolean gdk_event_prepare (GSource *source, gint *timeout); @@ -101,9 +93,12 @@ static gboolean gdk_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data); -GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data); +static GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev, + GdkEvent *event, + 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, Bool is_start, @@ -117,13 +112,7 @@ static void gdk_xsettings_notify_cb (const char *name, /* 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 GList *display_sources; static GSourceFuncs event_funcs = { gdk_event_prepare, @@ -132,89 +121,123 @@ static GSourceFuncs event_funcs = { NULL }; -static GPollFD event_poll_fd; - -static Window wmspec_check_window = None; +static GSource * +gdk_display_source_new (GdkDisplay *display) +{ + GSource *source = g_source_new (&event_funcs, sizeof (GdkDisplaySource)); + GdkDisplaySource *display_source = (GdkDisplaySource *)source; + + display_source->display = display; + + return source; +} -static XSettingsClient *xsettings_client; +static gboolean +gdk_check_xpending (GdkDisplay *display) +{ + return XPending (GDK_DISPLAY_XDISPLAY (display)); +} /********************************************* * Functions for maintaining the event queue * *********************************************/ +void +_gdk_x11_events_init_screen (GdkScreen *screen) +{ + GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen); + + /* 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); + screen_x11->xsettings_in_init = FALSE; +} + +void +_gdk_x11_events_uninit_screen (GdkScreen *screen) +{ + GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen); + + xsettings_client_destroy (screen_x11->xsettings_client); + screen_x11->xsettings_client = NULL; +} + void -gdk_events_init (void) +_gdk_events_init (GdkDisplay *display) { GSource *source; + GdkDisplaySource *display_source; + GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display); - connection_number = ConnectionNumber (gdk_display); - GDK_NOTE (MISC, - g_message ("connection number: %d", connection_number)); + int connection_number = ConnectionNumber (display_x11->xdisplay); + GDK_NOTE (MISC, g_message ("connection number: %d", connection_number)); - source = g_source_new (&event_funcs, sizeof (GSource)); + source = display_x11->event_source = gdk_display_source_new (display); + display_source = (GdkDisplaySource*) source; g_source_set_priority (source, GDK_PRIORITY_EVENTS); - event_poll_fd.fd = connection_number; - event_poll_fd.events = G_IO_IN; + display_source->event_poll_fd.fd = connection_number; + display_source->event_poll_fd.events = G_IO_IN; - g_source_add_poll (source, &event_poll_fd); + g_source_add_poll (source, &display_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); + display_sources = g_list_prepend (display_sources,display_source); - xsettings_client = xsettings_client_new (gdk_display, DefaultScreen (gdk_display), - gdk_xsettings_notify_cb, - gdk_xsettings_watch_cb, - NULL); + gdk_display_add_client_message_filter ( + display, + gdk_atom_intern ("WM_PROTOCOLS", FALSE), + 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: - * - *-------------------------------------------------------------- - */ +/** + * gdk_events_pending: + * + * Checks if any events are ready to be processed for any display. + * + * Return value: %TRUE if any events are pending. + **/ gboolean gdk_events_pending (void) { - return (gdk_event_queue_find_first() || XPending (gdk_display)); -} + GList *tmp_list; -/* - *-------------------------------------------------------------- - * 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: - * - *-------------------------------------------------------------- */ + for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next) + { + GdkDisplaySource *tmp_source = tmp_list->data; + GdkDisplay *display = tmp_source->display; + + if (_gdk_event_queue_find_first (display)) + return TRUE; + } + + for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next) + { + GdkDisplaySource *tmp_source = tmp_list->data; + GdkDisplay *display = tmp_source->display; + + if (gdk_check_xpending (display)) + return TRUE; + } + + return FALSE; +} static Bool graphics_expose_predicate (Display *display, XEvent *xevent, XPointer arg) { - if (xevent->xany.window == GDK_DRAWABLE_XID (arg) && + if (xevent->xany.window == GDK_DRAWABLE_XID ((GdkDrawable *)arg) && (xevent->xany.type == GraphicsExpose || xevent->xany.type == NoExpose)) return True; @@ -222,6 +245,17 @@ graphics_expose_predicate (Display *display, return False; } +/** + * gdk_event_get_graphics_expose: + * @window: the #GdkWindow to wait for the events for. + * + * Waits for a GraphicsExpose or NoExpose event from the X server. + * This is used in the #GtkText and #GtkCList widgets in GTK+ to make sure any + * GraphicsExpose events are handled before the widget is scrolled. + * + * Return value: a #GdkEventExpose if a GraphicsExpose was received, or %NULL if a + * NoExpose event was received. + **/ GdkEvent* gdk_event_get_graphics_expose (GdkWindow *window) { @@ -230,13 +264,15 @@ gdk_event_get_graphics_expose (GdkWindow *window) g_return_val_if_fail (window != NULL, NULL); - XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window); + XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent, + graphics_expose_predicate, (XPointer) window); if (xevent.xany.type == GraphicsExpose) { - event = gdk_event_new (); + event = gdk_event_new (GDK_NOTHING); - if (gdk_event_translate (event, &xevent, TRUE)) + if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event, + &xevent, TRUE)) return event; else gdk_event_free (event); @@ -268,22 +304,57 @@ gdk_event_apply_filters (XEvent *xevent, return GDK_FILTER_CONTINUE; } +/** + * gdk_display_add_client_message_filter: + * @display: a #GdkDisplay for which this message filter applies + * @message_type: the type of ClientMessage events to receive. + * This will be checked against the @message_type field + * of the XClientMessage event struct. + * @func: the function to call to process the event. + * @data: user data to pass to @func. + * + * Adds a filter to be called when X ClientMessage events are received. + * + * Since: 2.2 + **/ void -gdk_add_client_message_filter (GdkAtom message_type, - GdkFilterFunc func, - gpointer data) +gdk_display_add_client_message_filter (GdkDisplay *display, + GdkAtom message_type, + GdkFilterFunc func, + gpointer data) { - GdkClientFilter *filter = g_new (GdkClientFilter, 1); + GdkClientFilter *filter; + g_return_if_fail (GDK_IS_DISPLAY (display)); + filter = g_new (GdkClientFilter, 1); filter->type = message_type; filter->function = func; filter->data = data; - client_filters = g_list_prepend (client_filters, filter); + GDK_DISPLAY_X11(display)->client_filters = + g_list_prepend (GDK_DISPLAY_X11 (display)->client_filters, + filter); } -static GdkAtom wm_state_atom = 0; -static GdkAtom wm_desktop_atom = 0; +/** + * gdk_add_client_message_filter: + * @message_type: the type of ClientMessage events to receive. This will be + * checked against the message_type field of the + * XClientMessage event struct. + * @func: the function to call to process the event. + * @data: user data to pass to @func. + * + * Adds a filter to the default display to be called when X ClientMessage events + * are received. See gdk_display_add_client_message_filter(). + **/ +void +gdk_add_client_message_filter (GdkAtom message_type, + GdkFilterFunc func, + gpointer data) +{ + gdk_display_add_client_message_filter (gdk_display_get_default (), + message_type, func, data); +} static void gdk_check_wm_state_changed (GdkWindow *window) @@ -292,39 +363,33 @@ gdk_check_wm_state_changed (GdkWindow *window) gint format; gulong nitems; gulong bytes_after; - GdkAtom *atoms = NULL; + Atom *atoms = NULL; gulong i; - GdkAtom sticky_atom; - GdkAtom maxvert_atom; - GdkAtom maxhorz_atom; - gboolean found_sticky, found_maxvert, found_maxhorz; + gboolean found_sticky, found_maxvert, found_maxhorz, found_fullscreen; GdkWindowState old_state; + GdkDisplay *display = GDK_WINDOW_DISPLAY (window); - if (GDK_WINDOW_DESTROYED (window)) + if (GDK_WINDOW_DESTROYED (window) || + gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL) 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); + found_sticky = FALSE; + found_maxvert = FALSE; + found_maxhorz = FALSE; + found_fullscreen = FALSE; XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), - wm_state_atom, 0, G_MAXLONG, - False, XA_ATOM, &type, &format, &nitems, + gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"), + 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; - + Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY"); + Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT"); + Atom maxhorz_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ"); + Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN"); + i = 0; while (i < nitems) { @@ -334,18 +399,14 @@ gdk_check_wm_state_changed (GdkWindow *window) found_maxvert = TRUE; else if (atoms[i] == maxhorz_atom) found_maxhorz = TRUE; - + else if (atoms[i] == fullscreen_atom) + found_fullscreen = 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 @@ -355,9 +416,12 @@ gdk_check_wm_state_changed (GdkWindow *window) { gulong *desktop; - XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), - wm_desktop_atom, 0, G_MAXLONG, - False, XA_CARDINAL, &type, &format, &nitems, + XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + gdk_x11_get_xatom_by_name_for_display + (display, "_NET_WM_DESKTOP"), + 0, G_MAXLONG, False, XA_CARDINAL, &type, + &format, &nitems, &bytes_after, (guchar **)&desktop); if (type != None) @@ -385,6 +449,21 @@ gdk_check_wm_state_changed (GdkWindow *window) GDK_WINDOW_STATE_STICKY); } + if (old_state & GDK_WINDOW_STATE_FULLSCREEN) + { + if (!found_fullscreen) + gdk_synthesize_window_state (window, + GDK_WINDOW_STATE_FULLSCREEN, + 0); + } + else + { + if (found_fullscreen) + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_FULLSCREEN); + } + /* Our "maximized" means both vertical and horizontal; if only one, * we don't expose that via GDK */ @@ -421,30 +500,228 @@ generate_focus_event (GdkWindow *window, gdk_event_put (&event); } -static gint -gdk_event_translate (GdkEvent *event, - XEvent *xevent, - gboolean return_exposes) +static void +set_screen_from_root (GdkDisplay *display, + GdkEvent *event, + Window xrootwin) +{ + GdkScreen *screen; + + screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin); + g_assert (screen); + + gdk_event_set_screen (event, screen); +} + +static void +translate_key_event (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent) +{ + GdkKeymap *keymap = gdk_keymap_get_for_display (display); + gunichar c = 0; + guchar buf[7]; + + event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE; + event->key.time = xevent->xkey.time; + + event->key.state = (GdkModifierType) xevent->xkey.state; + event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state); + event->key.hardware_keycode = xevent->xkey.keycode; + + event->key.keyval = GDK_VoidSymbol; + + gdk_keymap_translate_keyboard_state (keymap, + event->key.hardware_keycode, + event->key.state, + event->key.group, + &event->key.keyval, + NULL, NULL, NULL); + + /* Fill in event->string crudely, since various programs + * depend on it. + */ + event->key.string = NULL; + + if (event->key.keyval != GDK_VoidSymbol) + c = gdk_keyval_to_unicode (event->key.keyval); + + if (c) + { + gsize bytes_written; + gint len; + + /* Apply the control key - Taken from Xlib + */ + if (event->key.state & GDK_CONTROL_MASK) + { + if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F; + else if (c == '2') + { + event->key.string = g_memdup ("\0\0", 2); + event->key.length = 1; + buf[0] = '\0'; + goto out; + } + else if (c >= '3' && c <= '7') c -= ('3' - '\033'); + else if (c == '8') c = '\177'; + else if (c == '/') c = '_' & 0x1F; + } + + len = g_unichar_to_utf8 (c, buf); + buf[len] = '\0'; + + event->key.string = g_locale_from_utf8 (buf, len, + NULL, &bytes_written, + NULL); + if (event->key.string) + event->key.length = bytes_written; + } + else if (event->key.keyval == GDK_Escape) + { + event->key.length = 1; + event->key.string = g_strdup ("\033"); + } + else if (event->key.keyval == GDK_Return || + event->key.keyval == GDK_KP_Enter) + { + event->key.length = 1; + event->key.string = g_strdup ("\r"); + } + + if (!event->key.string) + { + event->key.length = 0; + event->key.string = g_strdup (""); + } + + out: +#ifdef G_ENABLE_DEBUG + if (_gdk_debug_flags & GDK_DEBUG_EVENTS) + { + g_message ("%s:\t\twindow: %ld key: %12s %d", + event->type == GDK_KEY_PRESS ? "key press " : "key release", + xevent->xkey.window, + event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)", + event->key.keyval); + + if (event->key.length > 0) + g_message ("\t\tlength: %4d string: \"%s\"", + event->key.length, buf); + } +#endif /* G_ENABLE_DEBUG */ +} + +/* Return the window this has to do with, if any, rather + * than the frame or root window that was selecting + * for substructure + */ +static Window +get_real_window (XEvent *event) +{ + switch (event->type) + { + case CreateNotify: + return event->xcreatewindow.window; + + case DestroyNotify: + return event->xdestroywindow.window; + + case UnmapNotify: + return event->xunmap.window; + + case MapNotify: + return event->xmap.window; + + case MapRequest: + return event->xmaprequest.window; + + case ReparentNotify: + return event->xreparent.window; + + case ConfigureNotify: + return event->xconfigure.window; + + case ConfigureRequest: + return event->xconfigurerequest.window; + + case GravityNotify: + return event->xgravity.window; + + case CirculateNotify: + return event->xcirculate.window; + + case CirculateRequest: + return event->xcirculaterequest.window; + + default: + return event->xany.window; + } +} + +#ifdef G_ENABLE_DEBUG +static const char notify_modes[][18] = { + "NotifyNormal", + "NotifyGrab", + "NotifyUngrab", + "NotifyWhileGrabbed" +}; + +static const char notify_details[][22] = { + "NotifyAncestor", + "NotifyVirtual", + "NotifyInferior", + "NotifyNonlinear", + "NotifyNonlinearVirtual", + "NotifyPointer", + "NotifyPointerRoot", + "NotifyDetailNone" +}; +#endif + +static gboolean +gdk_event_translate (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent, + gboolean return_exposes) { GdkWindow *window; GdkWindowObject *window_private; GdkWindowImplX11 *window_impl = NULL; - static XComposeStatus compose; - KeySym keysym; - int charcount; - char buf[16]; gint return_val; gint xoffset, yoffset; + GdkScreen *screen = NULL; + GdkScreenX11 *screen_x11 = NULL; + GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display); + Window xwindow; 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. - */ + + /* init these, since the done: block uses them */ + window = NULL; + window_private = NULL; + event->any.window = NULL; + + if (_gdk_default_filters) + { + /* Apply global filters */ + GdkFilterReturn result; + result = gdk_event_apply_filters (xevent, event, + _gdk_default_filters); + + if (result != GDK_FILTER_CONTINUE) + { + return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE; + goto done; + } + } + + /* We handle events with window=None + * specially - they are generated by XFree86's XInput under + * some circumstances. This handling for obvious reasons + * goes before we bother to lookup the event window. + */ if (xevent->xany.window == None) { @@ -455,53 +732,52 @@ gdk_event_translate (GdkEvent *event, else return_val = FALSE; } + + /* Find the GdkWindow that this event relates to. + * Basically this means substructure events + * are reported same as structure events + */ + xwindow = get_real_window (xevent); - window = gdk_window_lookup (xevent->xany.window); + window = gdk_window_lookup_for_display (display, xwindow); window_private = (GdkWindowObject *) window; - if (_gdk_moveresize_window && - (xevent->xany.type == MotionNotify || - xevent->xany.type == ButtonRelease)) + if (window) { - _gdk_moveresize_handle_event (xevent); - gdk_window_unref (window); - return FALSE; + screen = GDK_WINDOW_SCREEN (window); + screen_x11 = GDK_SCREEN_X11 (screen); } - 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) { - 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; - } - } + /* Window may be a pixmap, so check its type. + * (This check is probably too expensive unless + * GLib short-circuits an exact type match, + * which has been proposed) + */ + if (GDK_IS_WINDOW (window)) + { + window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl); + + /* Move key events on focus window to the real toplevel, and + * filter out all other events on focus window + */ + if (xwindow == window_impl->focus_window) + { + switch (xevent->type) + { + case KeyPress: + case KeyRelease: + xwindow = GDK_WINDOW_XID (window); + xevent->xany.window = xwindow; + break; + default: + return FALSE; + } + } + } - gdk_window_ref (window); + g_object_ref (window); } event->any.window = window; @@ -510,17 +786,17 @@ gdk_event_translate (GdkEvent *event, if (window_private && GDK_WINDOW_DESTROYED (window)) { if (xevent->type != DestroyNotify) - return FALSE; + { + return_val = FALSE; + goto done; + } } - else + else if (window_private) { - /* Check for filters for this window - */ + /* Apply per-window filters */ GdkFilterReturn result; result = gdk_event_apply_filters (xevent, event, - window_private - ?window_private->filters - :gdk_default_filters); + window_private->filters); if (result != GDK_FILTER_CONTINUE) { @@ -528,7 +804,41 @@ gdk_event_translate (GdkEvent *event, goto done; } } + + if (screen_x11 && screen_x11->wmspec_check_window != None && + xwindow == screen_x11->wmspec_check_window) + { + if (xevent->type == DestroyNotify) + { + screen_x11->wmspec_check_window = None; + g_free (screen_x11->window_manager_name); + screen_x11->window_manager_name = g_strdup ("unknown"); + + /* careful, reentrancy */ + _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11)); + } + + /* Eat events on this window unless someone had wrapped + * it as a foreign window + */ + if (window == NULL) + { + return_val = FALSE; + goto done; + } + } + if (window && + (xevent->xany.type == MotionNotify || + xevent->xany.type == ButtonRelease)) + { + if (_gdk_moveresize_handle_event (xevent)) + { + return_val = FALSE; + goto done; + } + } + /* 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 @@ -551,86 +861,42 @@ gdk_event_translate (GdkEvent *event, switch (xevent->type) { case KeyPress: - /* Lookup the string corresponding to the given keysym. - */ - - charcount = XLookupString (&xevent->xkey, buf, 16, - &keysym, &compose); - 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_SHIFT 13 -#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) >> KEYBOARD_GROUP_SHIFT; - + if (window_private == NULL) + { + return_val = FALSE; + break; + } + translate_key_event (display, event, xevent); break; - - case KeyRelease: - /* Lookup the string corresponding to the given keysym. - */ + case KeyRelease: + if (window_private == NULL) + { + return_val = FALSE; + break; + } + /* 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)) + if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display)) { XEvent next_event; - XPeekEvent (gdk_display, &next_event); + XPeekEvent (xevent->xkey.display, &next_event); if (next_event.type == KeyPress && next_event.xkey.keycode == xevent->xkey.keycode && next_event.xkey.time == xevent->xkey.time) - break; + { + return_val = FALSE; + break; + } } - - 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; - + + translate_key_event (display, event, xevent); break; case ButtonPress: @@ -640,9 +906,9 @@ gdk_event_translate (GdkEvent *event, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); - if (window_private && - (window_private->extension_events != 0) && - gdk_input_ignore_core) + if (window_private == NULL || + ((window_private->extension_events != 0) && + display_x11->input_ignore_core)) { return_val = FALSE; break; @@ -668,13 +934,16 @@ gdk_event_translate (GdkEvent *event, event->scroll.direction = GDK_SCROLL_RIGHT; event->scroll.window = window; - event->scroll.time = xevent->xbutton.x; + event->scroll.time = xevent->xbutton.time; 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; + event->scroll.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xbutton.root); + break; default: @@ -688,9 +957,11 @@ gdk_event_translate (GdkEvent *event, event->button.axes = NULL; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; - event->button.device = gdk_core_pointer; + event->button.device = display->core_pointer; - gdk_event_button_generate (event); + set_screen_from_root (display, event, xevent->xbutton.root); + + _gdk_event_button_generate (display, event); break; } @@ -703,9 +974,9 @@ gdk_event_translate (GdkEvent *event, xevent->xbutton.x, xevent->xbutton.y, xevent->xbutton.button)); - if (window_private && - (window_private->extension_events != 0) && - gdk_input_ignore_core) + if (window_private == NULL || + ((window_private->extension_events != 0) && + display_x11->input_ignore_core)) { return_val = FALSE; break; @@ -729,7 +1000,9 @@ gdk_event_translate (GdkEvent *event, event->button.axes = NULL; event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; - event->button.device = gdk_core_pointer; + event->button.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xbutton.root); break; @@ -740,9 +1013,9 @@ gdk_event_translate (GdkEvent *event, xevent->xmotion.x, xevent->xmotion.y, (xevent->xmotion.is_hint) ? "true" : "false")); - if (window_private && - (window_private->extension_events != 0) && - gdk_input_ignore_core) + if (window_private == NULL || + ((window_private->extension_events != 0) && + display_x11->input_ignore_core)) { return_val = FALSE; break; @@ -758,7 +1031,9 @@ gdk_event_translate (GdkEvent *event, 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; + event->motion.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xmotion.root); break; @@ -768,15 +1043,21 @@ gdk_event_translate (GdkEvent *event, xevent->xcrossing.window, xevent->xcrossing.detail, xevent->xcrossing.subwindow)); - + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + /* 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) + xevent->xcrossing.focus && !window_impl->has_focus_window) { gboolean had_focus = HAS_FOCUS (window_impl); - + window_impl->has_pointer_focus = TRUE; if (HAS_FOCUS (window_impl) != had_focus) @@ -796,7 +1077,7 @@ gdk_event_translate (GdkEvent *event, * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) - event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; @@ -806,6 +1087,8 @@ gdk_event_translate (GdkEvent *event, event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; + set_screen_from_root (display, event, xevent->xcrossing.root); + /* Translate the crossing mode into Gdk terms. */ switch (xevent->xcrossing.mode) @@ -855,17 +1138,23 @@ gdk_event_translate (GdkEvent *event, g_message ("leave notify:\t\twindow: %ld detail: %d subwin: %ld", xevent->xcrossing.window, xevent->xcrossing.detail, xevent->xcrossing.subwindow)); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } /* 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) + xevent->xcrossing.focus && !window_impl->has_focus_window) { 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); } @@ -877,7 +1166,7 @@ gdk_event_translate (GdkEvent *event, * lookup the corresponding GdkWindow. */ if (xevent->xcrossing.subwindow != None) - event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow); else event->crossing.subwindow = NULL; @@ -887,6 +1176,8 @@ gdk_event_translate (GdkEvent *event, event->crossing.x_root = xevent->xcrossing.x_root; event->crossing.y_root = xevent->xcrossing.y_root; + set_screen_from_root (display, event, xevent->xcrossing.root); + /* Translate the crossing mode into Gdk terms. */ switch (xevent->xcrossing.mode) @@ -936,7 +1227,10 @@ gdk_event_translate (GdkEvent *event, */ case FocusIn: GDK_NOTE (EVENTS, - g_message ("focus in:\t\twindow: %ld", xevent->xfocus.window)); + g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s", + xevent->xfocus.window, + notify_details[xevent->xfocus.detail], + notify_modes[xevent->xfocus.mode])); if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD) { @@ -948,10 +1242,21 @@ gdk_event_translate (GdkEvent *event, case NotifyNonlinear: case NotifyVirtual: case NotifyNonlinearVirtual: - window_impl->has_focus = TRUE; + window_impl->has_focus_window = TRUE; + /* We pretend that the focus moves to the grab + * window, so we pay attention to NotifyGrab + * NotifyUngrab, and ignore NotifyWhileGrabbed + */ + if (xevent->xfocus.mode != NotifyWhileGrabbed) + window_impl->has_focus = TRUE; break; case NotifyPointer: - window_impl->has_pointer_focus = TRUE; + /* The X server sends NotifyPointer/NotifyGrab, + * but the pointer focus is ignored while a + * grab is in effect + */ + if (xevent->xfocus.mode != NotifyGrab) + window_impl->has_pointer_focus = TRUE; break; case NotifyInferior: case NotifyPointerRoot: @@ -965,8 +1270,11 @@ gdk_event_translate (GdkEvent *event, break; case FocusOut: GDK_NOTE (EVENTS, - g_message ("focus out:\t\twindow: %ld", xevent->xfocus.window)); - + g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s", + xevent->xfocus.window, + notify_details[xevent->xfocus.detail], + notify_modes[xevent->xfocus.mode])); + if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD) { gboolean had_focus = HAS_FOCUS (window_impl); @@ -977,10 +1285,13 @@ gdk_event_translate (GdkEvent *event, case NotifyNonlinear: case NotifyVirtual: case NotifyNonlinearVirtual: - window_impl->has_focus = FALSE; + window_impl->has_focus_window = FALSE; + if (xevent->xfocus.mode != NotifyWhileGrabbed) + window_impl->has_focus = FALSE; break; case NotifyPointer: - window_impl->has_pointer_focus = FALSE; + if (xevent->xfocus.mode != NotifyUngrab) + window_impl->has_pointer_focus = FALSE; break; case NotifyInferior: case NotifyPointerRoot: @@ -1017,6 +1328,13 @@ gdk_event_translate (GdkEvent *event, xevent->xexpose.x, xevent->xexpose.y, xevent->xexpose.width, xevent->xexpose.height, event->any.send_event ? " (send)" : "")); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + { GdkRectangle expose_rect; @@ -1038,7 +1356,6 @@ gdk_event_translate (GdkEvent *event, else { _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect); - return_val = FALSE; } @@ -1054,7 +1371,13 @@ gdk_event_translate (GdkEvent *event, GDK_NOTE (EVENTS, g_message ("graphics expose:\tdrawable: %ld", xevent->xgraphicsexpose.drawable)); - + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + expose_rect.x = xevent->xgraphicsexpose.x + xoffset; expose_rect.y = xevent->xgraphicsexpose.y + yoffset; expose_rect.width = xevent->xgraphicsexpose.width; @@ -1092,7 +1415,7 @@ gdk_event_translate (GdkEvent *event, case VisibilityNotify: #ifdef G_ENABLE_DEBUG - if (gdk_debug_flags & GDK_DEBUG_EVENTS) + if (_gdk_debug_flags & GDK_DEBUG_EVENTS) switch (xevent->xvisibility.state) { case VisibilityFullyObscured: @@ -1110,6 +1433,12 @@ gdk_event_translate (GdkEvent *event, } #endif /* G_ENABLE_DEBUG */ + if (window_private == NULL) + { + return_val = FALSE; + break; + } + event->visibility.type = GDK_VISIBILITY_NOTIFY; event->visibility.window = window; @@ -1148,14 +1477,21 @@ gdk_event_translate (GdkEvent *event, GDK_NOTE (EVENTS, g_message ("destroy notify:\twindow: %ld", xevent->xdestroywindow.window)); + + /* Ignore DestroyNotify from SubstructureNotifyMask */ + if (xevent->xdestroywindow.window == xevent->xdestroywindow.event) + { + event->any.type = GDK_DESTROY; + event->any.window = window; + + return_val = window_private && !GDK_WINDOW_DESTROYED (window); + + if (window && GDK_WINDOW_XID (window) != screen_x11->xroot_window) + gdk_window_destroy_notify (window); + } + else + return_val = FALSE; - 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: @@ -1171,13 +1507,15 @@ gdk_event_translate (GdkEvent *event, * 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; + if (window) + { + if (GDK_WINDOW_IS_MAPPED (window)) + gdk_synthesize_window_state (window, + 0, + GDK_WINDOW_STATE_ICONIFIED); + + _gdk_xgrab_check_unmap (window, xevent->xany.serial); + } break; @@ -1225,13 +1563,22 @@ gdk_event_translate (GdkEvent *event, ? " (discarding)" : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ? " (discarding child)" + : xevent->xconfigure.event != xevent->xconfigure.window + ? " (discarding substructure)" : "")); + if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT) + _gdk_x11_screen_size_changed (screen, xevent); + if (window && + xevent->xconfigure.event == xevent->xconfigure.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) + if (!window || + xevent->xconfigure.event != xevent->xconfigure.window || + GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD || + GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT) return_val = FALSE; else { @@ -1240,8 +1587,7 @@ gdk_event_translate (GdkEvent *event, event->configure.width = xevent->xconfigure.width; event->configure.height = xevent->xconfigure.height; - if (!xevent->xconfigure.x && - !xevent->xconfigure.y && + if (!xevent->xconfigure.send_event && !GDK_WINDOW_DESTROYED (window)) { gint tx = 0; @@ -1251,7 +1597,7 @@ gdk_event_translate (GdkEvent *event, gdk_error_trap_push (); if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window), - gdk_root_window, + screen_x11->xroot_window, 0, 0, &tx, &ty, &child_window)) @@ -1278,44 +1624,45 @@ gdk_event_translate (GdkEvent *event, { window_private->resize_count -= 1; - if (window_private->resize_count == 0 && - window == _gdk_moveresize_window) - _gdk_moveresize_configure_done (); + if (window_private->resize_count == 0) + _gdk_moveresize_configure_done (display, window); } } 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; - - 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) + "\"", + gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom), + "\"")); + + if (window_private == NULL) + { + return_val = FALSE; + break; + } + + if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE") || + xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP")) { /* If window state changed, then synthesize those events. */ - gdk_check_wm_state_changed (event->property.window); + gdk_check_wm_state_changed (window); } + if (window_private->event_mask & GDK_PROPERTY_CHANGE_MASK) + { + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = gdk_x11_xatom_to_atom_for_display (display, xevent->xproperty.atom); + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + } + else + return_val = FALSE; + break; case SelectionClear: @@ -1327,7 +1674,7 @@ gdk_event_translate (GdkEvent *event, { event->selection.type = GDK_SELECTION_CLEAR; event->selection.window = window; - event->selection.selection = xevent->xselectionclear.selection; + event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection); event->selection.time = xevent->xselectionclear.time; } else @@ -1342,9 +1689,9 @@ gdk_event_translate (GdkEvent *event, 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.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection); + event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target); + event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property); event->selection.requestor = xevent->xselectionrequest.requestor; event->selection.time = xevent->xselectionrequest.time; @@ -1358,9 +1705,9 @@ gdk_event_translate (GdkEvent *event, 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.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); event->selection.time = xevent->xselection.time; break; @@ -1378,16 +1725,17 @@ gdk_event_translate (GdkEvent *event, { GList *tmp_list; GdkFilterReturn result = GDK_FILTER_CONTINUE; + GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type); GDK_NOTE (EVENTS, g_message ("client message:\twindow: %ld", xevent->xclient.window)); - tmp_list = client_filters; + tmp_list = display_x11->client_filters; while (tmp_list) { GdkClientFilter *filter = tmp_list->data; - if (filter->type == xevent->xclient.message_type) + if (filter->type == message_type) { result = (*filter->function) (xevent, event, filter->data); break; @@ -1406,13 +1754,21 @@ gdk_event_translate (GdkEvent *event, 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)); - } + if (window_private == NULL) + { + return_val = FALSE; + } + else + { + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + } + break; + } } break; @@ -1424,25 +1780,26 @@ gdk_event_translate (GdkEvent *event, /* Let XLib know that there is a new keyboard mapping. */ XRefreshKeyboardMapping (&xevent->xmapping); - ++_gdk_keymap_serial; + _gdk_keymap_keys_changed (display); return_val = FALSE; break; default: #ifdef HAVE_XKB - if (xevent->type == _gdk_xkb_event_type) + if (xevent->type == display_x11->xkb_event_type) { XkbEvent *xkb_event = (XkbEvent *)xevent; switch (xkb_event->any.xkb_type) { case XkbMapNotify: - ++_gdk_keymap_serial; + _gdk_keymap_keys_changed (display); + return_val = FALSE; break; case XkbStateNotify: - _gdk_keymap_state_changed (); + _gdk_keymap_state_changed (display); break; } } @@ -1466,11 +1823,11 @@ gdk_event_translate (GdkEvent *event, if (return_val) { if (event->any.window) - gdk_window_ref (event->any.window); + g_object_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); + g_object_ref (event->crossing.subwindow); } else { @@ -1480,19 +1837,21 @@ gdk_event_translate (GdkEvent *event, } if (window) - gdk_window_unref (window); + g_object_unref (window); return return_val; } -GdkFilterReturn +static GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev, GdkEvent *event, gpointer data) { XEvent *xevent = (XEvent *)xev; + GdkWindow *win = event->any.window; + GdkDisplay *display = GDK_WINDOW_DISPLAY (win); - if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) + if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW")) { /* The delete window request specifies a window * to delete. We don't actually destroy the @@ -1510,7 +1869,7 @@ gdk_wm_protocols_filter (GdkXEvent *xev, 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_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS")) { GdkWindow *win = event->any.window; Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window; @@ -1526,46 +1885,31 @@ gdk_wm_protocols_filter (GdkXEvent *xev, 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)) + else if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING")) { XEvent xev = *xevent; - xev.xclient.window = gdk_root_window; - XSendEvent (gdk_display, gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + xev.xclient.window = GDK_WINDOW_XROOTWIN (win); + XSendEvent (GDK_WINDOW_XDISPLAY (win), + xev.xclient.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) +_gdk_events_queue (GdkDisplay *display) { GList *node; GdkEvent *event; XEvent xevent; + Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); - while (!gdk_event_queue_find_first() && XPending (gdk_display)) + while (!_gdk_event_queue_find_first(display) && XPending (xdisplay)) { - XNextEvent (gdk_display, &xevent); + XNextEvent (xdisplay, &xevent); switch (xevent.type) { @@ -1577,24 +1921,22 @@ gdk_events_queue (void) continue; } - event = gdk_event_new (); + event = gdk_event_new (GDK_NOTHING); - 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; + node = _gdk_event_queue_append (display, event); - if (gdk_event_translate (event, &xevent, FALSE)) + if (gdk_event_translate (display, event, &xevent, FALSE)) { ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING; } else { - gdk_event_queue_remove_link (node); + _gdk_event_queue_remove_link (display, node); g_list_free_1 (node); gdk_event_free (event); } @@ -1605,28 +1947,31 @@ static gboolean gdk_event_prepare (GSource *source, gint *timeout) { + GdkDisplay *display = ((GdkDisplaySource*)source)->display; gboolean retval; GDK_THREADS_ENTER (); *timeout = -1; - - retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display); - + retval = (_gdk_event_queue_find_first (display) != NULL || + gdk_check_xpending (display)); + GDK_THREADS_LEAVE (); return retval; } static gboolean -gdk_event_check (GSource *source) +gdk_event_check (GSource *source) { + GdkDisplaySource *display_source = (GdkDisplaySource*)source; gboolean retval; - + GDK_THREADS_ENTER (); - if (event_poll_fd.revents & G_IO_IN) - retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display); + if (display_source->event_poll_fd.revents & G_IO_IN) + retval = (_gdk_event_queue_find_first (display_source->display) != NULL || + gdk_check_xpending (display_source->display)); else retval = FALSE; @@ -1640,17 +1985,18 @@ gdk_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { + GdkDisplay *display = ((GdkDisplaySource*)source)->display; GdkEvent *event; GDK_THREADS_ENTER (); - gdk_events_queue(); - event = gdk_event_unqueue(); + _gdk_events_queue (display); + event = _gdk_event_unqueue (display); if (event) { - if (gdk_event_func) - (*gdk_event_func) (event, gdk_event_data); + if (_gdk_event_func) + (*_gdk_event_func) (event, _gdk_event_data); gdk_event_free (event); } @@ -1660,58 +2006,69 @@ gdk_event_dispatch (GSource *source, return TRUE; } -/* Sends a ClientMessage to all toplevel client windows */ +/** + * gdk_event_send_client_message_for_display: + * @display: the #GdkDisplay for the window where the message is to be sent. + * @event: the #GdkEvent to send, which should be a #GdkEventClient. + * @winid: the window to send the X ClientMessage event to. + * + * Sends an X ClientMessage event to a given window. + * + * This could be used for communicating between different applications, + * though the amount of data is limited to 20 bytes. + * + * Returns: non-zero on success. + * + * Since: 2.2 + */ gboolean -gdk_event_send_client_message (GdkEvent *event, guint32 xid) +gdk_event_send_client_message_for_display (GdkDisplay *display, + GdkEvent *event, + GdkNativeWindow winid) { 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.display = GDK_DISPLAY_XDISPLAY (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; + sev.xclient.window = winid; + memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data)); + sev.xclient.message_type = gdk_x11_atom_to_xatom_for_display (display, event->client.message_type); - return gdk_send_xevent (xid, False, NoEventMask, &sev); + return _gdk_send_xevent (display, winid, 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) +gdk_event_send_client_message_to_all_recurse (GdkDisplay *display, + 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; + gboolean result = 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; - } - + + gdk_error_trap_push (); + + if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid, + gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"), + 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data) != Success) + goto out; + if (type) { send = TRUE; @@ -1720,17 +2077,13 @@ gdk_event_send_client_message_to_all_recurse (XEvent *xev, 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; - } + if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid, + &ret_root, &ret_parent, + &ret_children, &ret_nchildren)) + goto out; for(i = 0; i < ret_nchildren; i++) - if (gdk_event_send_client_message_to_all_recurse (xev, ret_children[i], level + 1)) + if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1)) found = TRUE; XFree (ret_children); @@ -1739,32 +2092,56 @@ gdk_event_send_client_message_to_all_recurse (XEvent *xev, if (send || (!found && (level == 1))) { xev->xclient.window = xid; - gdk_send_xevent (xid, False, NoEventMask, xev); + _gdk_send_xevent (display, xid, False, NoEventMask, xev); } - gdk_error_warnings = old_warnings; + result = send || found; - return (send || found); + out: + gdk_error_trap_pop (); + + return result; } +/** + * gdk_screen_broadcast_client_message: + * @screen: the #GdkScreen where the event will be broadcasted. + * @event: the #GdkEvent. + * + * Sends an X ClientMessage event to all toplevel windows on @screen. + * + * Toplevel windows are determined by checking for the WM_STATE property, + * as described in the Inter-Client Communication Conventions Manual (ICCCM). + * If no windows are found with the WM_STATE property set, the message is + * sent to all children of the root window. + * + * Since: 2.2 + */ + void -gdk_event_send_clientmessage_toall (GdkEvent *event) +gdk_screen_broadcast_client_message (GdkScreen *screen, + GdkEvent *event) { XEvent sev; - gint old_warnings = gdk_error_warnings; + GdkWindow *root_window; - g_return_if_fail(event != NULL); + g_return_if_fail (event != NULL); + + root_window = gdk_screen_get_root_window (screen); /* Set up our event to send, with the exception of its target window */ sev.xclient.type = ClientMessage; - sev.xclient.display = gdk_display; + sev.xclient.display = GDK_WINDOW_XDISPLAY (root_window); 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; + memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data)); + sev.xclient.message_type = + gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (root_window), + event->client.message_type); + + gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen), + &sev, + GDK_WINDOW_XID (root_window), + 0); } /* @@ -1788,21 +2165,27 @@ gdk_event_send_clientmessage_toall (GdkEvent *event) void gdk_flush (void) { - XSync (gdk_display, False); + GSList *tmp_list = _gdk_displays; + + while (tmp_list) + { + XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False); + tmp_list = tmp_list->next; + } } -static GdkAtom timestamp_prop_atom = 0; - static Bool timestamp_predicate (Display *display, XEvent *xevent, XPointer arg) { Window xwindow = GPOINTER_TO_UINT (arg); + GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display); if (xevent->type == PropertyNotify && xevent->xproperty.window == xwindow && - xevent->xproperty.atom == timestamp_prop_atom) + xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display + (gdk_display, "GDK_TIMESTAMP_PROP")) return True; return False; @@ -1825,18 +2208,19 @@ gdk_x11_get_server_time (GdkWindow *window) Window xwindow; guchar c = 'a'; XEvent xevent; + Atom timestamp_prop_atom; 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); + timestamp_prop_atom = + gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), + "GDK_TIMESTAMP_PROP"); - XChangeProperty (xdisplay, xwindow, - timestamp_prop_atom, timestamp_prop_atom, + XChangeProperty (xdisplay, xwindow, timestamp_prop_atom, + timestamp_prop_atom, 8, PropModeReplace, &c, 1); XIfEvent (xdisplay, &xevent, @@ -1845,43 +2229,16 @@ gdk_x11_get_server_time (GdkWindow *window) return xevent.xproperty.time; } - -gboolean -gdk_net_wm_supports (GdkAtom property) +static void +fetch_net_wm_check_window (GdkScreen *screen) { - static GdkAtom wmspec_check_atom = 0; - static GdkAtom wmspec_supported_atom = 0; - static GdkAtom *atoms = NULL; - static gulong n_atoms = 0; + GdkScreenX11 *screen_x11; + GdkDisplay *display; Atom type; gint format; - gulong nitems; + gulong n_items; 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 @@ -1891,47 +2248,216 @@ gdk_net_wm_supports (GdkAtom property) * _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); + screen_x11 = GDK_SCREEN_X11 (screen); + display = screen_x11->display; + + if (screen_x11->wmspec_check_window != None) + return; /* already have it */ + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window, + gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"), + 0, G_MAXLONG, False, XA_WINDOW, &type, &format, + &n_items, &bytes_after, (guchar **) & xwindow); - 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; + return; gdk_error_trap_push (); - + /* Find out if this WM goes away, so we can reset everything. */ - XSelectInput (gdk_display, *xwindow, - StructureNotifyMask); + XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask); + + screen_x11->wmspec_check_window = *xwindow; + XFree (xwindow); + + screen_x11->need_refetch_net_supported = TRUE; + screen_x11->need_refetch_wm_name = TRUE; - gdk_flush (); + /* Careful, reentrancy */ + _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11)); +} + +/** + * gdk_x11_screen_get_window_manager_name: + * @screen: a #GdkScreen + * + * Returns the name of the window manager for @screen. + * + * Return value: the name of the window manager screen @screen, or + * "unknown" if the window manager is unknown. The string is owned by GDK + * and should not be freed. + * + * Since: 2.2 + **/ +const char* +gdk_x11_screen_get_window_manager_name (GdkScreen *screen) +{ + GdkScreenX11 *screen_x11; + + screen_x11 = GDK_SCREEN_X11 (screen); - if (gdk_error_trap_pop ()) + fetch_net_wm_check_window (screen); + + if (screen_x11->need_refetch_wm_name) { - XFree (xwindow); - return FALSE; + /* Get the name of the window manager */ + screen_x11->need_refetch_wm_name = FALSE; + + g_free (screen_x11->window_manager_name); + screen_x11->window_manager_name = g_strdup ("unknown"); + + if (screen_x11->wmspec_check_window != None) + { + Atom type; + gint format; + gulong n_items; + gulong bytes_after; + guchar *name; + + name = NULL; + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display), + screen_x11->wmspec_check_window, + gdk_x11_get_xatom_by_name_for_display (screen_x11->display, + "_NET_WM_NAME"), + 0, G_MAXLONG, False, + gdk_x11_get_xatom_by_name_for_display (screen_x11->display, + "UTF8_STRING"), + &type, &format, + &n_items, &bytes_after, + (guchar **)&name); + + gdk_display_sync (screen_x11->display); + + gdk_error_trap_pop (); + + if (name != NULL) + { + g_free (screen_x11->window_manager_name); + screen_x11->window_manager_name = g_strdup (name); + XFree (name); + } + } } + + return GDK_SCREEN_X11 (screen)->window_manager_name; +} - XGetWindowProperty (gdk_display, gdk_root_window, - wmspec_supported_atom, 0, G_MAXLONG, - False, XA_ATOM, &type, &format, &n_atoms, - &bytes_after, (guchar **)&atoms); +typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms; + +struct _NetWmSupportedAtoms +{ + Atom *atoms; + gulong n_atoms; +}; + +/** + * gdk_x11_screen_supports_net_wm_hint: + * @screen: the relevant #GdkScreen. + * @property: a property atom. + * + * This function is specific to the X11 backend of GDK, and indicates + * whether the window manager supports a certain hint from the + * Extended Window Manager Hints Specification. You can find this + * specification on + * http://www.freedesktop.org. + * + * When using this function, keep in mind that the window manager + * can change over time; so you shouldn't use this function in + * a way that impacts persistent application state. A common bug + * is that your application can start up before the window manager + * does when the user logs in, and before the window manager starts + * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property. + * You can monitor the window_manager_changed signal on #GdkScreen to detect + * a window manager change. + * + * Return value: %TRUE if the window manager supports @property + * + * Since: 2.2 + **/ +gboolean +gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen, + GdkAtom property) +{ + gulong i; + GdkScreenX11 *screen_x11; + NetWmSupportedAtoms *supported_atoms; + GdkDisplay *display; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + + screen_x11 = GDK_SCREEN_X11 (screen); + display = screen_x11->display; + + 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); + } + + fetch_net_wm_check_window (screen); + + if (screen_x11->wmspec_check_window == None) + return FALSE; + + if (screen_x11->need_refetch_net_supported) + { + /* WM has changed since we last got the supported list, + * refetch it. + */ + Atom type; + gint format; + gulong bytes_after; + + screen_x11->need_refetch_net_supported = FALSE; + + if (supported_atoms->atoms) + XFree (supported_atoms->atoms); + + supported_atoms->atoms = NULL; + supported_atoms->n_atoms = 0; + + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window, + gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"), + 0, G_MAXLONG, False, XA_ATOM, &type, &format, + &supported_atoms->n_atoms, &bytes_after, + (guchar **)&supported_atoms->atoms); + + if (type != XA_ATOM) + return FALSE; + } - if (type != XA_ATOM) + if (supported_atoms->atoms == NULL) return FALSE; - wmspec_check_window = *xwindow; - XFree (xwindow); + i = 0; + while (i < supported_atoms->n_atoms) + { + if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property)) + return TRUE; + + ++i; + } - /* since wmspec_check_window != None this isn't infinite. ;-) */ - return gdk_net_wm_supports (property); + return FALSE; +} + +/** + * gdk_net_wm_supports: + * @property: a property atom. + * + * This function is specific to the X11 backend of GDK, and indicates + * whether the window manager for the default screen supports a certain + * hint from the Extended Window Manager Hints Specification. See + * gdk_x11_screen_supports_net_wm_hint() for complete details. + * + * Return value: %TRUE if the window manager supports @property + **/ +gboolean +gdk_net_wm_supports (GdkAtom property) +{ + return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property); } static struct @@ -1939,13 +2465,20 @@ static struct const char *xsettings_name; const char *gdk_name; } settings_map[] = { - { "Net/DoubleClickTime", "gtk-double-click-timeout" }, - { "Net/DragThreshold", "gtk-drag-threshold" }, + { "Net/DoubleClickTime", "gtk-double-click-time" }, + { "Net/DndDragThreshold", "gtk-dnd-drag-threshold" }, + { "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" }, { "Net/CursorBlink", "gtk-cursor-blink" }, - { "Net/CursorBlinkTime", "gtk-cursor-blink-time" } + { "Net/CursorBlinkTime", "gtk-cursor-blink-time" }, + { "Net/ThemeName", "gtk-theme-name" } }; static void @@ -1955,20 +2488,26 @@ gdk_xsettings_notify_cb (const char *name, void *data) { GdkEvent new_event; + GdkScreen *screen = data; + GdkScreenX11 *screen_x11 = data; int i; + if (screen_x11->xsettings_in_init) + return; + new_event.type = GDK_SETTING; - new_event.setting.window = NULL; + new_event.setting.window = gdk_screen_get_root_window (screen); 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); + new_event.setting.name = (char *)settings_map[i].gdk_name; break; } + if (!new_event.setting.name) return; @@ -2005,16 +2544,40 @@ check_transform (const gchar *xsettings_name, return TRUE; } +/** + * gdk_screen_get_setting: + * @screen: the #GdkScreen where the setting is located + * @name: the name of the setting + * @value: location to store the value of the setting + * + * Retrieves a desktop-wide setting such as double-click time + * for the #GdkScreen @screen. + * + * FIXME needs a list of valid settings here, or a link to + * more information. + * + * Returns: %TRUE if the setting existed and a value was stored + * in @value, %FALSE otherwise. + * + * Since: 2.2 + **/ gboolean -gdk_setting_get (const gchar *name, - GValue *value) +gdk_screen_get_setting (GdkScreen *screen, + const gchar *name, + GValue *value) { + const char *xsettings_name = NULL; XSettingsResult result; XSettingsSetting *setting; + GdkScreenX11 *screen_x11; gboolean success = FALSE; gint i; GValue tmp_val = { 0, }; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); + + 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) @@ -2026,7 +2589,8 @@ gdk_setting_get (const gchar *name, if (!xsettings_name) return FALSE; - result = xsettings_client_get_setting (xsettings_client, xsettings_name, &setting); + result = xsettings_client_get_setting (screen_x11->xsettings_client, + xsettings_name, &setting); if (result != XSETTINGS_SUCCESS) return FALSE; @@ -2080,28 +2644,43 @@ gdk_setting_get (const gchar *name, return success; } -GdkFilterReturn +static GdkFilterReturn gdk_xsettings_client_event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { - if (xsettings_client_process_event (xsettings_client, (XEvent *)xevent)) + GdkScreenX11 *screen = data; + + if (xsettings_client_process_event (screen->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) +gdk_xsettings_watch_cb (Window window, + Bool is_start, + long mask, + void *cb_data) { GdkWindow *gdkwin; + GdkScreen *screen = cb_data; + + gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window); - gdkwin = gdk_window_lookup (window); if (is_start) - gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, NULL); + { + if (!gdkwin) + gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window); + else + g_object_ref (gdkwin); + + gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen); + } else - gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, NULL); + { + g_assert (gdkwin); + gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen); + g_object_unref (gdkwin); + } }