From f30cfd729a99f4d2a8b69f94a96b9385835ad59e Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 11 Aug 2009 11:30:55 +0200 Subject: [PATCH] Show/Hide native window when updating viewable This moves the native show/hide calls to the generic code for calculating viewable rather than in its own separate code called from gdk_window_show/hide. This simplifies the code a bit, but most significantly it means things are correctly shown when they become viewable for other reasons than a show/hide call. For instance, this fixes bug 590442 (gvim embedding) where the toplevel GtkPlug is mapped by the embedder and we didn't previously pick up that the native children became viewable and should be shown. --- gdk/gdkinternals.h | 2 +- gdk/gdkwindow.c | 129 ++++++++++++++++++++++----------------------- 2 files changed, 65 insertions(+), 66 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index ec29042b75..75eb068856 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -386,7 +386,7 @@ void _gdk_window_destroy (GdkWindow *window, gboolean foreign_destroy); void _gdk_window_clear_update_area (GdkWindow *window); void _gdk_window_update_size (GdkWindow *window); -void _gdk_window_update_viewable (GdkWindow *window); +gboolean _gdk_window_update_viewable (GdkWindow *window); void _gdk_window_process_updates_recurse (GdkWindow *window, GdkRegion *expose_region); diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 63e5d7d85b..2b773c2d85 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -5818,38 +5818,17 @@ gdk_window_raise_internal (GdkWindow *window) } } -/* Showing a non-native parent may cause children to become visible, - we need to handle this by manually showing them then. To simplify - things we hide them all when they are not visible. */ -static void -show_all_visible_impls (GdkWindowObject *private, gboolean already_mapped) -{ - GdkWindowObject *child; - GList *l; - - for (l = private->children; l != NULL; l = l->next) - { - child = l->data; - - /* For foreign windows, only show if if was - explicitly hidden, otherwise we might cause - suprising things to happen to the other client. */ - if (GDK_WINDOW_IS_MAPPED (child) && - child->window_type != GDK_WINDOW_FOREIGN) - show_all_visible_impls (child, FALSE); - } - - if (gdk_window_has_impl (private)) - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private, already_mapped); -} - -static void +/* Returns TRUE If the native window was mapped or unmapped */ +static gboolean set_viewable (GdkWindowObject *w, gboolean val) { GdkWindowObject *child; GList *l; + if (w->viewable == val) + return FALSE; + w->viewable = val; if (val) @@ -5863,9 +5842,48 @@ set_viewable (GdkWindowObject *w, child->window_type != GDK_WINDOW_FOREIGN) set_viewable (child, val); } + + if (gdk_window_has_impl (w) && + w->window_type != GDK_WINDOW_FOREIGN && + w->parent != NULL && + w->parent->window_type != GDK_WINDOW_ROOT) + { + /* For most native windows we show/hide them not when they are + * mapped/unmapped, because that may not produce the correct results. + * For instance, if a native window have a non-native parent which is + * hidden, but its native parent is viewable then showing the window + * would make it viewable to X but its not viewable wrt the non-native + * hierarchy. In order to handle this we track the gdk side viewability + * and only map really viewable windows. + * + * There are two exceptions though: + * + * For foreign windows we don't want ever change the mapped state + * except when explicitly done via gdk_window_show/hide, as this may + * cause problems for client owning the foreign window when its window + * is suddenly mapped or unmapped. + * + * For toplevel windows embedded in a foreign window (e.g. a plug) + * we sometimes synthesize a map of a window, but the native + * window is really shown by the embedder, so we don't want to + * do the show ourselves. We can't really tell this case from the normal + * toplevel show as such toplevels are seen by gdk as parents of the + * root window, so we make an exception for all toplevels. + */ + + if (val) + GDK_WINDOW_IMPL_GET_IFACE (w->impl)->show ((GdkWindow *)w, FALSE); + else + GDK_WINDOW_IMPL_GET_IFACE (w->impl)->hide ((GdkWindow *)w); + + return TRUE; + } + + return FALSE; } -void +/* Returns TRUE If the native window was mapped or unmapped */ +gboolean _gdk_window_update_viewable (GdkWindow *window) { GdkWindowObject *priv = (GdkWindowObject *)window; @@ -5881,15 +5899,15 @@ _gdk_window_update_viewable (GdkWindow *window) else viewable = FALSE; - if (priv->viewable != viewable) - set_viewable (priv, viewable); + return set_viewable (priv, viewable); } static void gdk_window_show_internal (GdkWindow *window, gboolean raise) { GdkWindowObject *private; - gboolean was_mapped; + gboolean was_mapped, was_viewable; + gboolean did_show; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -5898,6 +5916,7 @@ gdk_window_show_internal (GdkWindow *window, gboolean raise) return; was_mapped = GDK_WINDOW_IS_MAPPED (window); + was_viewable = private->viewable; if (raise) /* Keep children in (reverse) stacking order */ @@ -5915,10 +5934,17 @@ gdk_window_show_internal (GdkWindow *window, gboolean raise) private->state = 0; } - _gdk_window_update_viewable (window); + did_show = _gdk_window_update_viewable (window); - if (gdk_window_is_viewable (window)) - show_all_visible_impls (private, was_mapped); + /* If it was already viewable the backend show op won't be called, call it + again to ensure things happen right if the mapped tracking was not right + for e.g. a foreign window. + Dunno if this is strictly needed but its what happened pre-csw. + Also show if not done by gdk_window_update_viewable. */ + if (gdk_window_has_impl (private) && (was_viewable || !did_show)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->show ((GdkWindow *)private, + !did_show ? + was_mapped : TRUE); if (!was_mapped && !gdk_window_has_impl (private)) { @@ -6146,33 +6172,6 @@ gdk_window_show (GdkWindow *window) gdk_window_show_internal (window, TRUE); } -/* Hiding a non-native parent may cause parents to become non-visible, - even if their parent native window is visible. We need to handle this - by manually hiding them then. To simplify things we hide them all - when they are not visible. */ -static void -hide_all_visible_impls (GdkWindowObject *private) -{ - GdkWindowObject *child; - GList *l; - - for (l = private->children; l != NULL; l = l->next) - { - child = l->data; - - /* For foreign windows, only hide if if was - explicitly hidden, otherwise we might cause - suprising things to happen to the other client. */ - if (GDK_WINDOW_IS_MAPPED (child) && - child->window_type != GDK_WINDOW_FOREIGN) - hide_all_visible_impls (child); - } - - if (gdk_window_has_impl (private)) - GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide ((GdkWindow *)private); -} - - /** * gdk_window_hide: * @window: a #GdkWindow @@ -6186,7 +6185,7 @@ void gdk_window_hide (GdkWindow *window) { GdkWindowObject *private; - gboolean was_mapped, was_viewable; + gboolean was_mapped, did_hide; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -6195,7 +6194,6 @@ gdk_window_hide (GdkWindow *window) return; was_mapped = GDK_WINDOW_IS_MAPPED (private); - was_viewable = gdk_window_is_viewable (window); if (gdk_window_has_impl (private)) { @@ -6234,10 +6232,11 @@ gdk_window_hide (GdkWindow *window) private->state = GDK_WINDOW_STATE_WITHDRAWN; } - _gdk_window_update_viewable (window); + did_hide = _gdk_window_update_viewable (window); - if (was_viewable) - hide_all_visible_impls (private); + /* Hide foreign window as those are not handled by update_viewable. */ + if (gdk_window_has_impl (private) && (!did_hide)) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->hide ((GdkWindow *)private); recompute_visible_regions (private, TRUE, FALSE);