[gtk+] Show/Hide native window when updating viewable



commit f30cfd729a99f4d2a8b69f94a96b9385835ad59e
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Aug 11 11:30:55 2009 +0200

    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 ec29042..75eb068 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 63e5d7d..2b773c2 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);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]