* Patch to test the composited windows, it requires a patch in gdkwindow offscreen-viewport
authorAlejandro G. Castro <alex@igalia.com>
Wed, 6 May 2009 16:25:51 +0000 (18:25 +0200)
committerAlejandro G. Castro <alex@igalia.com>
Wed, 6 May 2009 18:29:06 +0000 (20:29 +0200)
hildon/hildon-viewport.c

index 8a45139..bfe188c 100644 (file)
@@ -37,17 +37,17 @@ enum {
 
 static void hildon_viewport_finalize                 (GObject          *object);
 static void hildon_viewport_destroy                  (GtkObject        *object);
-static void hildon_viewport_set_property             (GObject         *object,
-                                                      guint            prop_id,
-                                                      const GValue    *value,
-                                                      GParamSpec      *pspec);
-static void hildon_viewport_get_property             (GObject         *object,
-                                                      guint            prop_id,
-                                                      GValue          *value,
-                                                      GParamSpec      *pspec);
-static void hildon_viewport_set_scroll_adjustments       (HildonViewport           *viewport,
-                                                           GtkAdjustment    *hadjustment,
-                                                           GtkAdjustment    *vadjustment);
+static void hildon_viewport_set_property             (GObject          *object,
+                                                      guint             prop_id,
+                                                      const GValue     *value,
+                                                      GParamSpec       *pspec);
+static void hildon_viewport_get_property             (GObject          *object,
+                                                      guint             prop_id,
+                                                      GValue           *value,
+                                                      GParamSpec       *pspec);
+static void hildon_viewport_set_scroll_adjustments   (HildonViewport   *viewport,
+                                                      GtkAdjustment    *hadjustment,
+                                                      GtkAdjustment    *vadjustment);
 static void hildon_viewport_realize                  (GtkWidget        *widget);
 static void hildon_viewport_unrealize                (GtkWidget        *widget);
 static void hildon_viewport_paint                    (GtkWidget        *widget,
@@ -62,8 +62,15 @@ static void hildon_viewport_size_allocate            (GtkWidget        *widget,
                                                       GtkAllocation    *allocation);
 static void hildon_viewport_adjustment_value_changed (GtkAdjustment    *adjustment,
                                                       gpointer          data);
-static void hildon_viewport_style_set                (GtkWidget *widget,
-                                                      GtkStyle  *previous_style);
+static void hildon_viewport_style_set                (GtkWidget        *widget,
+                                                      GtkStyle         *previous_style);
+static void hildon_viewport_paint_offscreen_children (cairo_t          *cr,
+                                                      GdkWindow        *window,
+                                                      GdkEventExpose   *event,
+                                                      gint              orig_x,
+                                                      gint              orig_y);
+static void hildon_viewport_expose_window            (GdkWindow        *window);
+
 
 G_DEFINE_TYPE (HildonViewport, hildon_viewport, GTK_TYPE_BIN)
 
@@ -561,6 +568,53 @@ hildon_viewport_get_shadow_type (HildonViewport *viewport)
   return viewport->shadow_type;
 }
 
+static void
+hildon_viewport_expose_window (GdkWindow *window)
+{
+  GList *l, *children;
+  gpointer user_data;
+  gboolean is_double_buffered;
+  GdkEvent event;
+
+  gdk_window_get_user_data (window, &user_data);
+
+  event.expose.type = GDK_EXPOSE;
+  event.expose.window = g_object_ref (window);
+  event.expose.send_event = FALSE;
+  event.expose.count = 0;
+  event.expose.area.x = 0;
+  event.expose.area.y = 0;
+  gdk_drawable_get_size (GDK_DRAWABLE (window),
+                        &event.expose.area.width,
+                        &event.expose.area.height);
+  event.expose.region = gdk_region_rectangle (&event.expose.area);
+
+  if (user_data)
+    is_double_buffered = GTK_WIDGET_DOUBLE_BUFFERED (GTK_WIDGET (user_data));
+  else
+    is_double_buffered = FALSE;
+
+  /* If this is not double buffered, force a double buffer so that
+     redirection works. */
+  if (!is_double_buffered)
+    gdk_window_begin_paint_region (window, event.expose.region);
+
+  gtk_main_do_event (&event);
+
+  if (!is_double_buffered)
+    gdk_window_end_paint (window);
+
+  children = gdk_window_peek_children (window);
+  for (l = children; l != NULL; l = l->next)
+    {
+      GdkWindow *child = l->data;
+
+      /* Don't expose input-only windows */
+      if (gdk_drawable_get_depth (GDK_DRAWABLE (child)) != 0)
+       hildon_viewport_expose_window (l->data);
+    }
+}
+
 void
 hildon_viewport_freeze (HildonViewport *viewport)
 {
@@ -569,6 +623,9 @@ hildon_viewport_freeze (HildonViewport *viewport)
   GtkBin *bin;
   GtkWidget *child;
   GtkWidget *widget;
+  gint w, h;
+  cairo_t *cr;
+  GdkEvent event;
 
   g_return_if_fail (GTK_WIDGET_REALIZED (viewport));
   g_return_if_fail (priv->pixmap == NULL);
@@ -577,27 +634,41 @@ hildon_viewport_freeze (HildonViewport *viewport)
   bin = GTK_BIN (viewport);
   child = gtk_bin_get_child (bin);
 
-  priv->pixmap = gtk_widget_get_snapshot (child, NULL);
+  gdk_drawable_get_size (viewport->bin_window, &w, &h);
 
-#if 0
-  {
-    GtkWidget *image;
-    GtkWidget *window, *sw;
+  event.expose.type = GDK_EXPOSE;
+  event.expose.window = g_object_ref (viewport->bin_window);
+  event.expose.send_event = FALSE;
+  event.expose.count = 0;
+  event.expose.area.x = 0;
+  event.expose.area.y = 0;
+  event.expose.area.width = w;
+  event.expose.area.height = h;
+  event.expose.region = gdk_region_rectangle (&event.expose.area);
 
-    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-    sw = gtk_scrolled_window_new (NULL, NULL);
+  /* ensure the children are drawn in their offscreen windows */
+  hildon_viewport_expose_window (viewport->bin_window);
 
-    gtk_widget_realize (window);
+  cr = gdk_cairo_create (viewport->bin_window);
 
-    image = gtk_image_new_from_pixmap (priv->pixmap, NULL);
+  /* blit the children to the bin window */
+  hildon_viewport_paint_offscreen_children (cr,
+                                            viewport->bin_window,
+                                            (GdkEventExpose *)&event,
+                                            0, 0);
 
-    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), image);
-    gtk_container_add (GTK_CONTAINER (window), sw);
-    gtk_widget_show_all (window);
+  g_object_unref (viewport->bin_window);
 
-    gtk_widget_show (image);
-  }
-#endif
+  cairo_destroy (cr);
+
+  priv->pixmap = gdk_pixmap_new (viewport->bin_window,
+                                 w, h, -1);
+
+  /* copy the bin window to a pixmap, consider XCompositeNameWindowPixmap */
+  gdk_draw_drawable (priv->pixmap,
+                     widget->style->bg_gc[GTK_STATE_NORMAL],
+                     viewport->bin_window,
+                     0, 0, 0, 0, w, h);
 
   gdk_window_hide (viewport->bin_window);
   gtk_widget_queue_draw (widget);
@@ -614,16 +685,17 @@ hildon_viewport_thaw (HildonViewport *viewport)
 
   widget = GTK_WIDGET (viewport);
 
-  /* leak? */
-  g_object_unref (priv->pixmap);
+  if (priv->pixmap) {
+    g_object_unref (priv->pixmap);
 
-  priv->pixmap = NULL;
+    priv->pixmap = NULL;
 
-  new_x = - hadjustment->value;
-  new_y = - vadjustment->value;
+    new_x = - hadjustment->value;
+    new_y = - vadjustment->value;
 
-  gdk_window_show (viewport->bin_window);
-  gdk_window_move (viewport->bin_window, new_x, new_y);
+    gdk_window_show (viewport->bin_window);
+    gdk_window_move (viewport->bin_window, new_x, new_y);
+  }
 }
 
 static void
@@ -696,6 +768,8 @@ hildon_viewport_realize (GtkWidget *widget)
                     NULL, widget, "viewportbin",
                     0, 0, -1, -1);
 
+  gdk_window_set_composited (viewport->bin_window, TRUE);
+
   gdk_window_show (viewport->bin_window);
   gdk_window_show (viewport->view_window);
 }
@@ -737,6 +811,54 @@ hildon_viewport_paint (GtkWidget    *widget,
     }
 }
 
+static void
+hildon_viewport_paint_offscreen_children (cairo_t        *cr,
+                                          GdkWindow      *window,
+                                          GdkEventExpose *event,
+                                          gint            orig_x,
+                                          gint            orig_y)
+{
+  GList *subwindow;
+
+  for (subwindow = gdk_window_peek_children (window);
+       subwindow;
+       subwindow = subwindow->next)
+    {
+      /* avoid input-only windows */
+      if (gdk_drawable_get_depth (GDK_DRAWABLE (subwindow->data)) != 0)
+        {
+          gint x, y, w, h;
+
+          gdk_window_get_position (subwindow->data,
+                                   &x, &y);
+
+          x += orig_x;
+          y += orig_y;
+
+          gdk_drawable_get_size (subwindow->data, &w, &h);
+
+          /* do not draw the widgets outside the event */
+          if ((x+w < event->area.x) ||
+              (y+h < event->area.y) ||
+              (x > event->area.x+event->area.width) ||
+              (y > event->area.y+event->area.height))
+            continue;
+
+          gdk_cairo_set_source_pixmap (cr, subwindow->data, x, y);
+
+          cairo_rectangle (cr, x, y, w, h);
+
+          cairo_fill (cr);
+
+
+          hildon_viewport_paint_offscreen_children (cr,
+                                                    subwindow->data,
+                                                    event,
+                                                    x, y);
+        }
+    }
+}
+
 static gint
 hildon_viewport_expose (GtkWidget      *widget,
                         GdkEventExpose *event)
@@ -748,31 +870,38 @@ hildon_viewport_expose (GtkWidget      *widget,
     {
       if (event->window == widget->window)
         hildon_viewport_paint (widget, &event->area);
-      else if ((event->window == viewport->bin_window) ||
-               (event->window == viewport->view_window))
+      else if ((event->window == viewport->bin_window))
         {
-          if (priv->pixmap)
-            {
-              GtkAdjustment *vadjustment = hildon_viewport_get_vadjustment (viewport);
-              GtkAdjustment *hadjustment = hildon_viewport_get_hadjustment (viewport);
-
-              gdk_draw_drawable (viewport->view_window,
-                                 widget->style->bg_gc[GTK_STATE_NORMAL], priv->pixmap,
-                                 hadjustment->value + event->area.x,
-                                 vadjustment->value + event->area.y,
-                                 event->area.x, event->area.y,
-                                 event->area.width, event->area.height);
-            }
-          else
-            {
-              gtk_paint_flat_box(widget->style,
-                                 viewport->bin_window,
-                                 GTK_STATE_NORMAL, GTK_SHADOW_NONE,
-                                 &event->area, widget, "viewportbin",
-                                 0, 0, -1, -1);
-            }
+          cairo_t *cr;
+
+          gtk_paint_flat_box(widget->style,
+                             viewport->bin_window,
+                             GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+                             &event->area, widget, "viewportbin",
+                             0, 0, -1, -1);
 
           (* GTK_WIDGET_CLASS (hildon_viewport_parent_class)->expose_event) (widget, event);
+
+          cr = gdk_cairo_create (viewport->bin_window);
+
+          hildon_viewport_paint_offscreen_children (cr,
+                                                    viewport->bin_window,
+                                                    event, 0, 0);
+
+          cairo_destroy (cr);
+        }
+      else if (event->window == viewport->view_window)
+        {
+          GtkAdjustment *vadjustment = hildon_viewport_get_vadjustment (viewport);
+          GtkAdjustment *hadjustment = hildon_viewport_get_hadjustment (viewport);
+
+          gdk_draw_drawable (viewport->view_window,
+                             widget->style->bg_gc[GTK_STATE_NORMAL],
+                             priv->pixmap ? priv->pixmap : viewport->bin_window,
+                             hadjustment->value + event->area.x,
+                             vadjustment->value + event->area.y,
+                             event->area.x, event->area.y,
+                             event->area.width, event->area.height);
         }
     }