X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fx11%2Fgdkevents-x11.c;h=f0e44e8b06db4f6b55209a2560d4c3148a67bc06;hb=329c090ec18cf162db9d09b98f007f8979238116;hp=9fbca311c30121c2a3b0313b6ffb5503cb40ae94;hpb=44e2b53f83f6c6b8467aec4c367700c89986e938;p=~andy%2Fgtk diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 9fbca311c..f0e44e8b0 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -146,12 +146,16 @@ 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 @@ -265,7 +269,7 @@ gdk_event_get_graphics_expose (GdkWindow *window) if (xevent.xany.type == GraphicsExpose) { - event = _gdk_event_new (); + event = gdk_event_new (GDK_NOTHING); if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event, &xevent, TRUE)) @@ -311,6 +315,7 @@ gdk_event_apply_filters (XEvent *xevent, * * Adds a filter to be called when X ClientMessage events are received. * + * Since: 2.2 **/ void gdk_display_add_client_message_filter (GdkDisplay *display, @@ -360,7 +365,7 @@ gdk_check_wm_state_changed (GdkWindow *window) gulong bytes_after; Atom *atoms = NULL; gulong i; - 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); @@ -371,6 +376,7 @@ gdk_check_wm_state_changed (GdkWindow *window) found_sticky = FALSE; found_maxvert = FALSE; found_maxhorz = FALSE; + found_fullscreen = FALSE; XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window), gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"), @@ -382,7 +388,8 @@ gdk_check_wm_state_changed (GdkWindow *window) 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) { @@ -392,7 +399,9 @@ 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; } @@ -440,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 */ @@ -476,6 +500,185 @@ generate_focus_event (GdkWindow *window, gdk_event_put (&event); } +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, @@ -486,15 +689,12 @@ gdk_event_translate (GdkDisplay *display, 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; @@ -533,9 +733,13 @@ gdk_event_translate (GdkDisplay *display, return_val = FALSE; } - /* Find the GdkWindow that this event occurred in. */ + /* 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_for_display (display, xevent->xany.window); + window = gdk_window_lookup_for_display (display, xwindow); window_private = (GdkWindowObject *) window; if (window) @@ -554,16 +758,18 @@ gdk_event_translate (GdkDisplay *display, if (GDK_IS_WINDOW (window)) { window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl); - - if (xevent->xany.window != GDK_WINDOW_XID (window)) + + /* 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) { - g_assert (xevent->xany.window == window_impl->focus_window); - switch (xevent->type) { case KeyPress: case KeyRelease: - xevent->xany.window = GDK_WINDOW_XID (window); + xwindow = GDK_WINDOW_XID (window); + xevent->xany.window = xwindow; break; default: return FALSE; @@ -571,7 +777,7 @@ gdk_event_translate (GdkDisplay *display, } } - g_object_ref (G_OBJECT (window)); + g_object_ref (window); } event->any.window = window; @@ -600,10 +806,17 @@ gdk_event_translate (GdkDisplay *display, } if (screen_x11 && screen_x11->wmspec_check_window != None && - xevent->xany.window == screen_x11->wmspec_check_window) + xwindow == screen_x11->wmspec_check_window) { if (xevent->type == DestroyNotify) - screen_x11->wmspec_check_window = None; + { + 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 @@ -653,48 +866,9 @@ gdk_event_translate (GdkDisplay *display, return_val = FALSE; break; } - - /* 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 */ - - 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; - - /* 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.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state); - + translate_key_event (display, event, xevent); break; - + case KeyRelease: if (window_private == NULL) { @@ -702,9 +876,6 @@ gdk_event_translate (GdkDisplay *display, break; } - /* Lookup the string corresponding to the given keysym. - */ - /* 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. @@ -719,30 +890,13 @@ gdk_event_translate (GdkDisplay *display, 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; - event->key.hardware_keycode = xevent->xkey.keycode; - - 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; - - event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT; + translate_key_event (display, event, xevent); break; case ButtonPress: @@ -787,6 +941,9 @@ gdk_event_translate (GdkDisplay *display, event->scroll.y_root = (gfloat)xevent->xbutton.y_root; event->scroll.state = (GdkModifierType) xevent->xbutton.state; event->scroll.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xbutton.root); + break; default: @@ -802,6 +959,8 @@ gdk_event_translate (GdkDisplay *display, event->button.button = xevent->xbutton.button; event->button.device = display->core_pointer; + set_screen_from_root (display, event, xevent->xbutton.root); + _gdk_event_button_generate (display, event); break; } @@ -842,6 +1001,8 @@ gdk_event_translate (GdkDisplay *display, event->button.state = (GdkModifierType) xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.device = display->core_pointer; + + set_screen_from_root (display, event, xevent->xbutton.root); break; @@ -872,6 +1033,8 @@ gdk_event_translate (GdkDisplay *display, event->motion.is_hint = xevent->xmotion.is_hint; event->motion.device = display->core_pointer; + set_screen_from_root (display, event, xevent->xmotion.root); + break; case EnterNotify: @@ -891,10 +1054,10 @@ gdk_event_translate (GdkDisplay *display, 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) @@ -924,6 +1087,8 @@ gdk_event_translate (GdkDisplay *display, 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) @@ -984,12 +1149,12 @@ gdk_event_translate (GdkDisplay *display, 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); } @@ -1011,6 +1176,8 @@ gdk_event_translate (GdkDisplay *display, 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) @@ -1060,7 +1227,10 @@ gdk_event_translate (GdkDisplay *display, */ 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) { @@ -1072,6 +1242,7 @@ gdk_event_translate (GdkDisplay *display, case NotifyNonlinear: case NotifyVirtual: case NotifyNonlinearVirtual: + 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 @@ -1099,8 +1270,11 @@ gdk_event_translate (GdkDisplay *display, 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); @@ -1111,6 +1285,7 @@ gdk_event_translate (GdkDisplay *display, case NotifyNonlinear: case NotifyVirtual: case NotifyNonlinearVirtual: + window_impl->has_focus_window = FALSE; if (xevent->xfocus.mode != NotifyWhileGrabbed) window_impl->has_focus = FALSE; break; @@ -1391,6 +1566,9 @@ gdk_event_translate (GdkDisplay *display, : 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) && @@ -1602,7 +1780,7 @@ gdk_event_translate (GdkDisplay *display, /* Let XLib know that there is a new keyboard mapping. */ XRefreshKeyboardMapping (&xevent->xmapping); - ++display_x11->keymap_serial; + _gdk_keymap_keys_changed (display); return_val = FALSE; break; @@ -1615,7 +1793,7 @@ gdk_event_translate (GdkDisplay *display, switch (xkb_event->any.xkb_type) { case XkbMapNotify: - ++display_x11->keymap_serial; + _gdk_keymap_keys_changed (display); return_val = FALSE; break; @@ -1645,11 +1823,11 @@ gdk_event_translate (GdkDisplay *display, 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 { @@ -1659,7 +1837,7 @@ gdk_event_translate (GdkDisplay *display, } if (window) - gdk_window_unref (window); + g_object_unref (window); return return_val; } @@ -1743,9 +1921,8 @@ _gdk_events_queue (GdkDisplay *display) 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; @@ -1830,22 +2007,24 @@ gdk_event_dispatch (GSource *source, } /** - * 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. - * @xid : the X window to send the X ClientMessage event to. + * 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. + * Returns: non-zero on success. + * + * Since: 2.2 */ gboolean -gdk_event_send_client_message_for_display (GdkDisplay *display, - GdkEvent *event, - guint32 xid) +gdk_event_send_client_message_for_display (GdkDisplay *display, + GdkEvent *event, + GdkNativeWindow winid) { XEvent sev; @@ -1855,11 +2034,11 @@ gdk_event_send_client_message_for_display (GdkDisplay *display, sev.xclient.type = ClientMessage; sev.xclient.display = GDK_DISPLAY_XDISPLAY (display); sev.xclient.format = event->client.data_format; - sev.xclient.window = xid; + 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 (display, xid, False, NoEventMask, &sev); + return _gdk_send_xevent (display, winid, False, NoEventMask, &sev); } @@ -1926,8 +2105,8 @@ gdk_event_send_client_message_to_all_recurse (GdkDisplay *display, /** * gdk_screen_broadcast_client_message: - * @screen : the #GdkScreen where the event will be broadcasted. - * @event : the #GdkEvent. + * @screen: the #GdkScreen where the event will be broadcasted. + * @event: the #GdkEvent. * * Sends an X ClientMessage event to all toplevel windows on @screen. * @@ -1935,6 +2114,8 @@ gdk_event_send_client_message_to_all_recurse (GdkDisplay *display, * 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 @@ -2048,6 +2229,120 @@ gdk_x11_get_server_time (GdkWindow *window) return xevent.xproperty.time; } +static void +fetch_net_wm_check_window (GdkScreen *screen) +{ + GdkScreenX11 *screen_x11; + GdkDisplay *display; + Atom type; + gint format; + gulong n_items; + gulong bytes_after; + Window *xwindow; + + /* This function is very slow on every call if you are not running a + * spec-supporting WM. For now not optimized, because it isn't in + * any critical code paths, but if you used it somewhere that had to + * be fast you want to avoid "GTK is slow with old WMs" complaints. + * Probably at that point the function should be changed to query + * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something. + */ + + 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); + + if (type != XA_WINDOW) + return; + + gdk_error_trap_push (); + + /* Find out if this WM goes away, so we can reset everything. */ + 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; + + /* 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); + + fetch_net_wm_check_window (screen); + + if (screen_x11->need_refetch_wm_name) + { + /* 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; +} + typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms; struct _NetWmSupportedAtoms @@ -2058,13 +2353,14 @@ struct _NetWmSupportedAtoms /** * gdk_x11_screen_supports_net_wm_hint: - * @screen : the relevant #GdkScreen. + * @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. + * 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 @@ -2072,18 +2368,17 @@ struct _NetWmSupportedAtoms * 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) { - Atom type; - gint format; - gulong nitems; - gulong bytes_after; - Window *xwindow; gulong i; GdkScreenX11 *screen_x11; NetWmSupportedAtoms *supported_atoms; @@ -2101,72 +2396,51 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen, g_object_set_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms); } - if (screen_x11->wmspec_check_window != None) + fetch_net_wm_check_window (screen); + + if (screen_x11->wmspec_check_window == None) + return FALSE; + + if (screen_x11->need_refetch_net_supported) { - if (supported_atoms->atoms == NULL) - return FALSE; + /* 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; - 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; - } + if (supported_atoms->atoms) + XFree (supported_atoms->atoms); - return FALSE; + 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 (supported_atoms->atoms) - XFree (supported_atoms->atoms); - - supported_atoms->atoms = NULL; - supported_atoms->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. - */ - 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, - &nitems, &bytes_after, (guchar **) & xwindow); - - if (type != XA_WINDOW) + if (supported_atoms->atoms == NULL) return FALSE; - - gdk_error_trap_push (); - - /* Find out if this WM goes away, so we can reset everything. */ - XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask); - - gdk_display_sync (screen_x11->display); - if (gdk_error_trap_pop ()) + i = 0; + while (i < supported_atoms->n_atoms) { - XFree (xwindow); - return FALSE; + if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property)) + return TRUE; + + ++i; } - 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; - - screen_x11->wmspec_check_window = *xwindow; - XFree (xwindow); - - /* since wmspec_check_window != None this isn't infinite. ;-) */ - return gdk_x11_screen_supports_net_wm_hint (screen, property); + return FALSE; } /** @@ -2196,9 +2470,12 @@ static struct { "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/ThemeName", "gtk-theme-name" } @@ -2212,8 +2489,12 @@ gdk_xsettings_notify_cb (const char *name, { 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 = gdk_screen_get_root_window (screen); new_event.setting.send_event = FALSE; @@ -2226,6 +2507,7 @@ gdk_xsettings_notify_cb (const char *name, break; } + if (!new_event.setting.name) return; @@ -2274,8 +2556,10 @@ check_transform (const gchar *xsettings_name, * 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 + * Returns: %TRUE if the setting existed and a value was stored * in @value, %FALSE otherwise. + * + * Since: 2.2 **/ gboolean gdk_screen_get_setting (GdkScreen *screen, @@ -2381,7 +2665,6 @@ gdk_xsettings_watch_cb (Window window, { GdkWindow *gdkwin; GdkScreen *screen = cb_data; - GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen); gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);