[gtk+] GtkContainer: Propagate draws in GdkWindow order



commit c3973e8468ae4009fb309568463aea5e7856e4b7
Author: Alexander Larsson <alexl redhat com>
Date:   Wed May 15 12:39:21 2013 +0200

    GtkContainer: Propagate draws in GdkWindow order
    
    Now that we're not drawing the GdkWindows by themeselves we need to
    propagate into children in the same order as the windows were painted
    otherwise apps can't rely on stacking order to overlay children.
    
    This is still not 100% the same as the old behaviour, because we're
    treating all windows that are part of a window at the same time (to allow
    e.g. opacity groups), and we're only looking at order for the main
    windows of a widget. However, this fixes at least the ordering
    of the gnome-boxes fullscreen overlay toolbar.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=699970

 gtk/gtkcontainer.c |  127 +++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 95 insertions(+), 32 deletions(-)
---
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index dc81530..49bd093 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -346,6 +346,9 @@ static void    gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
                                                        const gchar  *tagname,
                                                        gpointer     *data);
 
+static gboolean gtk_container_should_propagate_draw (GtkContainer   *container,
+                                                     GtkWidget      *child,
+                                                     cairo_t        *cr);
 
 /* --- variables --- */
 static const gchar           vadjustment_key[] = "gtk-vadjustment";
@@ -3261,36 +3264,82 @@ gtk_container_show_all (GtkWidget *widget)
   gtk_widget_show (widget);
 }
 
+typedef struct {
+  GtkWidget *child;
+  int window_depth;
+} ChildOrderInfo;
+
 static void
-gtk_container_draw_child (GtkWidget *child,
-                          gpointer   client_data)
+gtk_container_draw_forall (GtkWidget *widget,
+                           gpointer   client_data)
 {
   struct {
-    GtkWidget *container;
+    GtkContainer *container;
+    GArray *child_infos;
     cairo_t *cr;
   } *data = client_data;
+  ChildOrderInfo info;
+  GList *siblings;
+  GdkWindow *window;
 
-  gtk_container_propagate_draw (GTK_CONTAINER (data->container),
-                                child,
-                                data->cr);
+  if (gtk_container_should_propagate_draw (data->container, widget, data->cr))
+    {
+      info.child = widget;
+      info.window_depth = G_MAXINT;
+      if (gtk_widget_get_has_window (widget))
+        {
+          window = gtk_widget_get_window (widget);
+          siblings = gdk_window_peek_children (gdk_window_get_parent (window));
+          info.window_depth = g_list_index (siblings, window);
+        }
+      g_array_append_val (data->child_infos, info);
+    }
+}
+
+static gint
+compare_children_for_draw (gconstpointer  _a,
+                           gconstpointer  _b)
+{
+  const ChildOrderInfo *a = _a;
+  const ChildOrderInfo *b = _b;
+
+  return b->window_depth - a->window_depth;
 }
 
 static gint
 gtk_container_draw (GtkWidget *widget,
                     cairo_t   *cr)
 {
+  GtkContainer *container = GTK_CONTAINER (widget);
+  GArray *child_infos;
+  int i;
+  ChildOrderInfo *child_info;
   struct {
-    GtkWidget *container;
+    GtkContainer *container;
+    GArray *child_infos;
     cairo_t *cr;
   } data;
 
-  data.container = widget;
-  data.cr = cr;
+  child_infos = g_array_new (FALSE, TRUE, sizeof (ChildOrderInfo));
 
-  gtk_container_forall (GTK_CONTAINER (widget),
-                        gtk_container_draw_child,
+  data.container = container;
+  data.cr = cr;
+  data.child_infos = child_infos;
+  gtk_container_forall (container,
+                        gtk_container_draw_forall,
                         &data);
 
+  g_array_sort (child_infos, compare_children_for_draw);
+
+  for (i = 0; i < child_infos->len; i++)
+    {
+      child_info = &g_array_index (child_infos, ChildOrderInfo, i);
+      gtk_container_propagate_draw (container,
+                                    child_info->child, cr);
+    }
+
+  g_array_free (child_infos, TRUE);
+
   return FALSE;
 }
 
@@ -3335,6 +3384,39 @@ gtk_container_unmap (GtkWidget *widget)
                         NULL);
 }
 
+static gboolean
+gtk_container_should_propagate_draw (GtkContainer   *container,
+                                     GtkWidget      *child,
+                                     cairo_t        *cr)
+{
+  GdkEventExpose *event;
+  GdkWindow *event_window, *child_in_window;
+
+  if (!gtk_widget_is_drawable (child))
+    return FALSE;
+
+  /* Only propagate to native child window if we're not handling
+     an expose (i.e. in a pure gtk_widget_draw() call */
+  event = _gtk_cairo_get_event (cr);
+  if (event &&
+      (gtk_widget_get_has_window (child) &&
+       gdk_window_has_native (gtk_widget_get_window (child))))
+    return FALSE;
+
+  /* Never propagate to a child window when exposing a window
+     that is not the one the child widget is in. */
+  event_window = _gtk_cairo_get_event_window (cr);
+  if (gtk_widget_get_has_window (child))
+    child_in_window = gdk_window_get_parent (gtk_widget_get_window (child));
+  else
+    child_in_window = gtk_widget_get_window (child);
+  if (event_window != NULL && child_in_window != event_window)
+    return FALSE;
+
+  return TRUE;
+}
+
+
 /**
  * gtk_container_propagate_draw:
  * @container: a #GtkContainer
@@ -3364,9 +3446,8 @@ gtk_container_propagate_draw (GtkContainer   *container,
                               GtkWidget      *child,
                               cairo_t        *cr)
 {
-  GdkEventExpose *event;
   GtkAllocation allocation;
-  GdkWindow *window, *w, *event_window, *child_in_window;
+  GdkWindow *window, *w;
   int x, y;
 
   g_return_if_fail (GTK_IS_CONTAINER (container));
@@ -3375,25 +3456,7 @@ gtk_container_propagate_draw (GtkContainer   *container,
 
   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (container));
 
-  if (!gtk_widget_is_drawable (child))
-    return;
-
-  /* Only propagate to native child window if we're not handling
-     an expose (i.e. in a pure gtk_widget_draw() call */
-  event = _gtk_cairo_get_event (cr);
-  if (event &&
-      (gtk_widget_get_has_window (child) &&
-       gdk_window_has_native (gtk_widget_get_window (child))))
-    return;
-
-  /* Never propagate to a child window when exposing a window
-     that is not the one the child widget is in. */
-  event_window = _gtk_cairo_get_event_window (cr);
-  if (gtk_widget_get_has_window (child))
-    child_in_window = gdk_window_get_parent (gtk_widget_get_window (child));
-  else
-    child_in_window = gtk_widget_get_window (child);
-  if (event_window != NULL && child_in_window != event_window)
+  if (!gtk_container_should_propagate_draw (container, child, cr))
     return;
 
   cairo_save (cr);


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