diff --git a/ChangeLog b/ChangeLog index e53f1cfb10..cc8143eee3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,59 @@ +2006-05-25 Matthias Clasen + + Make GTK+ work as an untrusted X client. (#136571, + Ed Catmur) + + * gdk/x11/gdkdisplay-x11.h: + * gdk/x11/gdkdisplay-x11.c (gdk_display_open): When + opening a display, determine if we are untrusted. + + * gdk/x11/gdkdisplay-x11.c (gdk_notify_startup_complete): + Just bail out when we are untrusted. + + * gdk/x11/gdkwindow-x11.c (gdk_window_new): Work around + a bug in the Xorg XSECURITY implementation by coercing + toplevel InputOnly windows to InputOutput. + + * gdk/x11/gdkwindow-x11.c (_gdk_windowing_get_pointer): + (_gdk_windowing_window_get_pointer): + When untrusted, call XQueryPointer on an auxiliary + window, not on the root window. + + * gdk/x11/gdkwindow-x11.c (_gdk_windowing_window_at_pointer): + If untrusted, loop through all GDK-aware toplevels on all + screens in the hope we hit one containing the pointer; + then use that as the basis of the current XQueryPointer + child recursion. + + * gdk/x11/gdkmain-x11.c (gdk_pointer_grab): + (gdk_keyboard_grab): Ignore failed grabs when untrusted. + + * gdk/x11/gdkdnd-x11.c (gdk_window_cache_new): Only + cache our own toplevels when untrusted. + + * gdk/x11/gdkdnd-x11.c (motif_send_enter): Don't try + to do Motif DND as untrusted client. + + * gdk/x11/gdkevents-x11.c (fetch_net_wm_check_window): + (gdk_x11_screen_get_window_manager_name): + (gdk_x11_screen_supports_net_wm_hint): + Bail out early if untrusted. + + * gtk/gtkcolorsel.c (grab_color_at_mouse): If getting + the color under the pointer by screenshooting the root + window fails, it tries to get the color from our own + window. + + * gtk/gtkcolorsel.c (get_screen_color): Make the + dropper_grab_widget a child of the dialog, not a + toplevel. + + * gtk/gtkinvisible.c (gtk_invisible_realize): Respect + a parent window that has been set before realizing. + + * gtk/gtkwidget.c (gtk_widget_get_parent_window): + Always return a previously set parent window. + 2006-05-24 Matthias Clasen * gtk/gtkfontbutton.c (gtk_font_button_clicked): diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index e53f1cfb10..cc8143eee3 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,59 @@ +2006-05-25 Matthias Clasen + + Make GTK+ work as an untrusted X client. (#136571, + Ed Catmur) + + * gdk/x11/gdkdisplay-x11.h: + * gdk/x11/gdkdisplay-x11.c (gdk_display_open): When + opening a display, determine if we are untrusted. + + * gdk/x11/gdkdisplay-x11.c (gdk_notify_startup_complete): + Just bail out when we are untrusted. + + * gdk/x11/gdkwindow-x11.c (gdk_window_new): Work around + a bug in the Xorg XSECURITY implementation by coercing + toplevel InputOnly windows to InputOutput. + + * gdk/x11/gdkwindow-x11.c (_gdk_windowing_get_pointer): + (_gdk_windowing_window_get_pointer): + When untrusted, call XQueryPointer on an auxiliary + window, not on the root window. + + * gdk/x11/gdkwindow-x11.c (_gdk_windowing_window_at_pointer): + If untrusted, loop through all GDK-aware toplevels on all + screens in the hope we hit one containing the pointer; + then use that as the basis of the current XQueryPointer + child recursion. + + * gdk/x11/gdkmain-x11.c (gdk_pointer_grab): + (gdk_keyboard_grab): Ignore failed grabs when untrusted. + + * gdk/x11/gdkdnd-x11.c (gdk_window_cache_new): Only + cache our own toplevels when untrusted. + + * gdk/x11/gdkdnd-x11.c (motif_send_enter): Don't try + to do Motif DND as untrusted client. + + * gdk/x11/gdkevents-x11.c (fetch_net_wm_check_window): + (gdk_x11_screen_get_window_manager_name): + (gdk_x11_screen_supports_net_wm_hint): + Bail out early if untrusted. + + * gtk/gtkcolorsel.c (grab_color_at_mouse): If getting + the color under the pointer by screenshooting the root + window fails, it tries to get the color from our own + window. + + * gtk/gtkcolorsel.c (get_screen_color): Make the + dropper_grab_widget a child of the dialog, not a + toplevel. + + * gtk/gtkinvisible.c (gtk_invisible_realize): Respect + a parent window that has been set before realizing. + + * gtk/gtkwidget.c (gtk_widget_get_parent_window): + Always return a previously set parent window. + 2006-05-24 Matthias Clasen * gtk/gtkfontbutton.c (gtk_font_button_clicked): diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 1304a83125..af90587f76 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -219,6 +219,24 @@ gdk_display_open (const gchar *display_name) } #endif + display_x11->trusted_client = TRUE; + { + Window root, child; + int rootx, rooty, winx, winy; + unsigned int xmask; + + gdk_error_trap_push (); + XQueryPointer (display_x11->xdisplay, + GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window, + &root, &child, &rootx, &rooty, &winx, &winy, &xmask); + gdk_flush (); + if (G_UNLIKELY (gdk_error_trap_pop () == BadWindow)) + { + g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display)); + display_x11->trusted_client = FALSE; + } + } + if (_gdk_synchronize) XSynchronize (display_x11->xdisplay, True); @@ -1056,6 +1074,9 @@ gdk_notify_startup_complete (void) if (display_x11->startup_notification_id == NULL) return; + if (!G_LIKELY (display_x11->trusted_client)) + return; + escaped_id = escape_for_xmessage (display_x11->startup_notification_id); message = g_strdup_printf ("remove: ID=%s", escaped_id); g_free (escaped_id); diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index 36defc8d98..14b8fd5b29 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -81,6 +81,11 @@ struct _GdkDisplayX11 gboolean have_xfixes; gint xfixes_event_base; + /* If the SECURITY extension is in place, whether this client holds + * a trusted authorization and so is allowed to make various requests + * (grabs, properties etc.) Otherwise always TRUE. */ + gboolean trusted_client; + /* Information about current pointer and keyboard grabs held by this * client. If gdk_pointer_xgrab_window or gdk_keyboard_xgrab_window * window is NULL, then the other associated fields are ignored diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c index b4eb8e9d39..7e0961c771 100644 --- a/gdk/x11/gdkdnd-x11.c +++ b/gdk/x11/gdkdnd-x11.c @@ -460,6 +460,25 @@ gdk_window_cache_new (GdkScreen *screen) XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa); result->old_event_mask = xwa.your_event_mask; + + if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client)) + { + GList *toplevel_windows, *list; + GdkWindow *window; + gint x, y, width, height; + + toplevel_windows = gdk_screen_get_toplevel_windows (screen); + for (list = toplevel_windows; list; list = list->next) { + window = GDK_WINDOW (list->data); + gdk_window_get_geometry (window, &x, &y, &width, &height, NULL); + gdk_window_cache_add (result, GDK_WINDOW_XID (window), + x, y, width, height, + gdk_window_is_visible (window)); + } + g_list_free (toplevel_windows); + return result; + } + XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window), result->old_event_mask | SubstructureNotifyMask); gdk_window_add_filter (root_window, gdk_window_cache_filter, result); @@ -1287,6 +1306,9 @@ motif_send_enter (GdkDragContext *context, GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window); XEvent xev; + if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) + return; /* Motif Dnd requires getting properties on the root window */ + xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE"); xev.xclient.format = 8; diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 46cdd12857..d64925b9e5 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -2574,6 +2574,8 @@ fetch_net_wm_check_window (GdkScreen *screen) screen_x11 = GDK_SCREEN_X11 (screen); display = screen_x11->display; + + g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client); if (screen_x11->wmspec_check_window != None) return; /* already have it */ @@ -2631,6 +2633,9 @@ gdk_x11_screen_get_window_manager_name (GdkScreen *screen) screen_x11 = GDK_SCREEN_X11 (screen); + if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client)) + return screen_x11->window_manager_name; + fetch_net_wm_check_window (screen); if (screen_x11->need_refetch_wm_name) @@ -2726,6 +2731,9 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen, screen_x11 = GDK_SCREEN_X11 (screen); display = screen_x11->display; + if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) + return FALSE; + supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms"); if (!supported_atoms) { diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index 72f7339749..75e69479d3 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -191,6 +191,7 @@ gdk_pointer_grab (GdkWindow * window, { gint return_val; GdkCursorPrivate *cursor_private; + GdkDisplayX11 *display_x11; guint xevent_mask; Window xwindow; Window xconfine_to; @@ -202,6 +203,8 @@ gdk_pointer_grab (GdkWindow * window, g_return_val_if_fail (GDK_IS_WINDOW (window), 0); g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0); + display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); + cursor_private = (GdkCursorPrivate*) cursor; xwindow = GDK_WINDOW_XID (window); @@ -233,7 +236,8 @@ gdk_pointer_grab (GdkWindow * window, confine_to, time); - if (return_val == GrabSuccess) + if (return_val == GrabSuccess || + G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed)) { if (!GDK_WINDOW_DESTROYED (window)) { @@ -257,7 +261,6 @@ gdk_pointer_grab (GdkWindow * window, if (return_val == GrabSuccess) { - GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); if (display_x11->pointer_xgrab_window != NULL && display_x11->pointer_xgrab_window != (GdkWindowObject *)window) generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), @@ -338,10 +341,13 @@ gdk_keyboard_grab (GdkWindow * window, { gint return_val; unsigned long serial; + GdkDisplayX11 *display_x11; g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); + serial = NextRequest (GDK_WINDOW_XDISPLAY (window)); if (!GDK_WINDOW_DESTROYED (window)) @@ -356,13 +362,16 @@ gdk_keyboard_grab (GdkWindow * window, owner_events, GrabModeAsync, GrabModeAsync, time); + if (G_UNLIKELY (!display_x11->trusted_client && + return_val == AlreadyGrabbed)) + /* we can't grab the keyboard, but we can do a GTK-local grab */ + return_val = GrabSuccess; } else return_val = AlreadyGrabbed; if (return_val == GrabSuccess) { - GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window)); if (display_x11->keyboard_xgrab_window != NULL && display_x11->keyboard_xgrab_window != (GdkWindowObject *)window) generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index dd26bca996..55b153a9ba 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -88,6 +88,7 @@ static void gdk_window_add_colormap_windows (GdkWindow *window); static void set_wm_name (GdkDisplay *display, Window xwindow, const gchar *name); +static void move_to_current_desktop (GdkWindow *window); static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable); static void gdk_window_impl_x11_set_colormap (GdkDrawable *drawable, @@ -731,6 +732,17 @@ gdk_window_new (GdkWindow *parent, else private->window_type = attributes->window_type; + /* Work around a bug where Xorg refuses to map toplevel InputOnly windows + * from an untrusted client: http://bugs.freedesktop.org/show_bug.cgi?id=6988 + */ + if (attributes->wclass == GDK_INPUT_ONLY && + GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT && + !G_LIKELY (GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (parent))->trusted_client)) + { + g_warning ("Coercing GDK_INPUT_ONLY toplevel window to GDK_INPUT_OUTPUT to work around bug in Xorg server"); + attributes->wclass = GDK_INPUT_OUTPUT; + } + _gdk_window_init_position (GDK_WINDOW (private)); if (impl->position_info.big) private->guffaw_gravity = TRUE; @@ -2007,7 +2019,13 @@ gdk_x11_window_move_to_current_desktop (GdkWindow *window) if (toplevel->on_all_desktops) return; + + move_to_current_desktop (window); +} +static void +move_to_current_desktop (GdkWindow *window) +{ if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window), gdk_atom_intern_static_string ("_NET_WM_DESKTOP"))) { @@ -3428,6 +3446,8 @@ _gdk_windowing_get_pointer (GdkDisplay *display, GdkModifierType *mask) { GdkScreen *default_screen; + Display *xdisplay; + Window xwindow; Window root = None; Window child; int rootx, rooty; @@ -3439,10 +3459,27 @@ _gdk_windowing_get_pointer (GdkDisplay *display, return; default_screen = gdk_display_get_default_screen (display); + + xdisplay = GDK_SCREEN_XDISPLAY (default_screen); + xwindow = GDK_SCREEN_XROOTWIN (default_screen); - XQueryPointer (GDK_SCREEN_XDISPLAY (default_screen), - GDK_SCREEN_XROOTWIN (default_screen), - &root, &child, &rootx, &rooty, &winx, &winy, &xmask); + if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) + { + XQueryPointer (xdisplay, xwindow, + &root, &child, &rootx, &rooty, &winx, &winy, &xmask); + } + else + { + XSetWindowAttributes attributes; + Window w; + + w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0, + CopyFromParent, InputOnly, CopyFromParent, + 0, &attributes); + XQueryPointer (xdisplay, w, + &root, &child, &rootx, &rooty, &winx, &winy, &xmask); + XDestroyWindow (xdisplay, w); + } if (root != None) { @@ -3476,13 +3513,28 @@ _gdk_windowing_window_get_pointer (GdkDisplay *display, _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset); return_val = NULL; - if (!GDK_WINDOW_DESTROYED (window) && - XQueryPointer (GDK_WINDOW_XDISPLAY (window), - GDK_WINDOW_XID (window), - &root, &child, &rootx, &rooty, &winx, &winy, &xmask)) + if (!GDK_WINDOW_DESTROYED (window)) { - if (child) - return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child); + if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) + { + if (XQueryPointer (GDK_WINDOW_XDISPLAY (window), + GDK_WINDOW_XID (window), + &root, &child, &rootx, &rooty, &winx, &winy, &xmask)) + { + if (child) + return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child); + } + } + else + { + GdkScreen *screen; + int originx, originy; + _gdk_windowing_get_pointer (gdk_drawable_get_display (window), &screen, + &rootx, &rooty, &xmask); + gdk_window_get_origin (window, &originx, &originy); + winx = rootx - originx; + winy = rooty - originy; + } } *x = winx + xoffset; @@ -3555,24 +3607,89 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, * and the result. */ gdk_x11_display_grab (display); - XQueryPointer (xdisplay, xwindow, - &root, &child, &rootx, &rooty, &winx, &winy, &xmask); - - if (root == xwindow) - xwindow = child; - else - xwindow = root; - - while (xwindow) + if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) { - xwindow_last = xwindow; XQueryPointer (xdisplay, xwindow, - &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask); + &root, &child, &rootx, &rooty, &winx, &winy, &xmask); + if (root == xwindow) + xwindow = child; + else + xwindow = root; + + while (xwindow) + { + xwindow_last = xwindow; + XQueryPointer (xdisplay, xwindow, + &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask); + } + } + else + { + gint i, screens, width, height; + GList *toplevels, *list; + Window pointer_window; + + pointer_window = None; + screens = gdk_display_get_n_screens (display); + for (i = 0; i < screens; ++i) { + screen = gdk_display_get_screen (display, i); + toplevels = gdk_screen_get_toplevel_windows (screen); + for (list = toplevels; list != NULL; list = g_list_next (list)) { + window = GDK_WINDOW (list->data); + xwindow = GDK_WINDOW_XWINDOW (window); + gdk_error_trap_push (); + XQueryPointer (xdisplay, xwindow, + &root, &child, &rootx, &rooty, &winx, &winy, &xmask); + gdk_flush (); + if (gdk_error_trap_pop ()) + continue; + if (child != None) + { + pointer_window = child; + break; + } + gdk_window_get_geometry (window, NULL, NULL, &width, &height, NULL); + if (winx >= 0 && winy >= 0 && winx < width && winy < height) + { + /* A childless toplevel, or below another window? */ + XSetWindowAttributes attributes; + Window w; + + w = XCreateWindow (xdisplay, xwindow, winx, winy, 1, 1, 0, + CopyFromParent, InputOnly, CopyFromParent, + 0, &attributes); + XMapWindow (xdisplay, w); + XQueryPointer (xdisplay, xwindow, + &root, &child, &rootx, &rooty, &winx, &winy, &xmask); + XDestroyWindow (xdisplay, w); + if (child == w) + { + pointer_window = xwindow; + break; + } + } + } + g_list_free (toplevels); + if (pointer_window != None) + break; + } + xwindow = pointer_window; + + while (xwindow) + { + xwindow_last = xwindow; + gdk_error_trap_push (); + XQueryPointer (xdisplay, xwindow, + &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask); + gdk_flush (); + if (gdk_error_trap_pop ()) + break; + } } + gdk_x11_display_ungrab (display); - window = gdk_window_lookup_for_display (GDK_SCREEN_DISPLAY(screen), - xwindow_last); + window = gdk_window_lookup_for_display (display, xwindow_last); *win_x = window ? winx : -1; *win_y = window ? winy : -1; @@ -4480,52 +4597,12 @@ gdk_window_unstick (GdkWindow *window) if (GDK_WINDOW_IS_MAPPED (window)) { - XEvent xev; - Atom type; - gint format; - gulong nitems; - gulong bytes_after; - guchar *data; - gulong *current_desktop; - GdkDisplay *display = gdk_drawable_get_display (window); - /* Request unstick from viewport */ gdk_wmspec_change_state (FALSE, window, gdk_atom_intern_static_string ("_NET_WM_STATE_STICKY"), NULL); - /* Get current desktop, then set it; this is a race, but not - * one that matters much in practice. - */ - XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), - gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"), - 0, G_MAXLONG, - False, XA_CARDINAL, &type, &format, &nitems, - &bytes_after, &data); - - if (type == XA_CARDINAL) - { - current_desktop = (gulong *)data; - - xev.xclient.type = ClientMessage; - xev.xclient.serial = 0; - xev.xclient.send_event = True; - xev.xclient.window = GDK_WINDOW_XWINDOW (window); - xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"); - xev.xclient.format = 32; - - xev.xclient.data.l[0] = *current_desktop; - xev.xclient.data.l[1] = 0; - xev.xclient.data.l[2] = 0; - xev.xclient.data.l[3] = 0; - xev.xclient.data.l[4] = 0; - - XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False, - SubstructureRedirectMask | SubstructureNotifyMask, - &xev); - - XFree (current_desktop); - } + move_to_current_desktop (window); } else { diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c index 24eae26ba5..eec02636af 100644 --- a/gtk/gtkcolorsel.c +++ b/gtk/gtkcolorsel.c @@ -1224,6 +1224,17 @@ grab_color_at_mouse (GdkScreen *screen, priv = colorsel->private_data; image = gdk_drawable_get_image (root_window, x_root, y_root, 1, 1); + if (!image) + { + gint x, y; + GdkDisplay *display = gdk_screen_get_display (screen); + GdkWindow *window = gdk_display_get_window_at_pointer (display, &x, &y); + if (!window) + return; + image = gdk_drawable_get_image (window, x, y, 1, 1); + if (!image) + return; + } pixel = gdk_image_get_pixel (image, 0, 0); g_object_unref (image); @@ -1429,11 +1440,11 @@ get_screen_color (GtkWidget *button) gtk_widget_add_events (priv->dropper_grab_widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); + gtk_widget_set_parent_window (priv->dropper_grab_widget, + GTK_WIDGET (colorsel)->window); gtk_widget_show (priv->dropper_grab_widget); gdk_window_set_user_data (priv->dropper_grab_widget->window, colorsel); - gdk_window_reparent (priv->dropper_grab_widget->window, - GTK_WIDGET (colorsel)->window, 0, 0); } if (gdk_keyboard_grab (priv->dropper_grab_widget->window, diff --git a/gtk/gtkinvisible.c b/gtk/gtkinvisible.c index 3cf3a2ae9f..c944b770be 100644 --- a/gtk/gtkinvisible.c +++ b/gtk/gtkinvisible.c @@ -214,11 +214,16 @@ gtk_invisible_get_screen (GtkInvisible *invisible) static void gtk_invisible_realize (GtkWidget *widget) { + GdkWindow *parent; GdkWindowAttr attributes; gint attributes_mask; GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + parent = gtk_widget_get_parent_window (widget); + if (parent == NULL) + parent = gtk_widget_get_root_window (widget); + attributes.x = -100; attributes.y = -100; attributes.width = 10; @@ -230,8 +235,7 @@ gtk_invisible_realize (GtkWidget *widget) attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR; - widget->window = gdk_window_new (gtk_widget_get_root_window (widget), - &attributes, attributes_mask); + widget->window = gdk_window_new (parent, &attributes, attributes_mask); gdk_window_set_user_data (widget->window, widget); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index c43b35cd72..d9d3b53bd2 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -5822,11 +5822,11 @@ gtk_widget_get_parent_window (GtkWidget *widget) GdkWindow *parent_window; g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (widget->parent != NULL, NULL); parent_window = g_object_get_qdata (G_OBJECT (widget), quark_parent_window); - return (parent_window != NULL) ? parent_window : widget->parent->window; + return (parent_window != NULL) ? parent_window : + (widget->parent != NULL) ? widget->parent->window : NULL; } /**