[gtk+] Revert "shooter: Use the reftests code for taking screenshots"



commit 671b3181b0882a12cc695d0b0f091bbe70a8f2ba
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Sep 29 21:59:22 2013 -0400

    Revert "shooter: Use the reftests code for taking screenshots"
    
    This reverts commit 5c926ca6bb1259d5ad152dda13e43b2a8536150f.
    
    This commit just dropped the nice shadow that we used to have
    around these shots, without a justification.

 docs/tools/Makefile.am |    2 +
 docs/tools/shadow.c    |  149 +++++++++++++++++++++++++++
 docs/tools/shadow.h    |    8 ++
 docs/tools/shooter.c   |  264 +++++++++++++++++++++++++++++++++--------------
 4 files changed, 344 insertions(+), 79 deletions(-)
---
diff --git a/docs/tools/Makefile.am b/docs/tools/Makefile.am
index 80ddcf2..e3b2966 100644
--- a/docs/tools/Makefile.am
+++ b/docs/tools/Makefile.am
@@ -26,6 +26,8 @@ endif
 doc_shooter_DEPENDENCIES = $(DEPS)
 doc_shooter_LDADD = $(LDADDS)
 doc_shooter_SOURCES=   \
+       shadow.c        \
+       shadow.h        \
        shooter.c       \
        widgets.c       \
        widgets.h
diff --git a/docs/tools/shadow.c b/docs/tools/shadow.c
new file mode 100644
index 0000000..67c31fe
--- /dev/null
+++ b/docs/tools/shadow.c
@@ -0,0 +1,149 @@
+#include "shadow.h"
+#include <math.h>
+
+#define BLUR_RADIUS 5
+#define SHADOW_OFFSET (BLUR_RADIUS * 4 / 5)
+#define SHADOW_OPACITY 0.75
+
+typedef struct {
+  int size;
+  double *data;
+} ConvFilter;
+
+static double
+gaussian (double x, double y, double r)
+{
+    return ((1 / (2 * M_PI * r)) *
+           exp ((- (x * x + y * y)) / (2 * r * r)));
+}
+
+static ConvFilter *
+create_blur_filter (int radius)
+{
+  ConvFilter *filter;
+  int x, y;
+  double sum;
+  
+  filter = g_new0 (ConvFilter, 1);
+  filter->size = radius * 2 + 1;
+  filter->data = g_new (double, filter->size * filter->size);
+
+  sum = 0.0;
+  
+  for (y = 0 ; y < filter->size; y++)
+    {
+      for (x = 0 ; x < filter->size; x++)
+       {
+         sum += filter->data[y * filter->size + x] = gaussian (x - (filter->size >> 1),
+                                                               y - (filter->size >> 1),
+                                                               radius);
+       }
+    }
+
+  for (y = 0; y < filter->size; y++)
+    {
+      for (x = 0; x < filter->size; x++)
+       {
+         filter->data[y * filter->size + x] /= sum;
+       }
+    }
+
+  return filter;
+  
+}
+
+static GdkPixbuf *
+create_shadow (GdkPixbuf *src)
+{
+  int x, y, i, j;
+  int width, height;
+  GdkPixbuf *dest;
+  static ConvFilter *filter = NULL;
+  int src_rowstride, dest_rowstride;
+  int src_bpp, dest_bpp;
+  
+  guchar *src_pixels, *dest_pixels;
+
+  if (!filter)
+    filter = create_blur_filter (BLUR_RADIUS);
+  
+  width = gdk_pixbuf_get_width (src) + BLUR_RADIUS * 2 + SHADOW_OFFSET;
+  height = gdk_pixbuf_get_height (src) + BLUR_RADIUS * 2 + SHADOW_OFFSET;
+
+  dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
+                        gdk_pixbuf_get_has_alpha (src),
+                        gdk_pixbuf_get_bits_per_sample (src),
+                        width, height);
+  gdk_pixbuf_fill (dest, 0);  
+  src_pixels = gdk_pixbuf_get_pixels (src);
+  src_rowstride = gdk_pixbuf_get_rowstride (src);
+  src_bpp = gdk_pixbuf_get_has_alpha (src) ? 4 : 3;
+  
+  dest_pixels = gdk_pixbuf_get_pixels (dest);
+  dest_rowstride = gdk_pixbuf_get_rowstride (dest);
+  dest_bpp = gdk_pixbuf_get_has_alpha (dest) ? 4 : 3;
+  
+  for (y = 0; y < height; y++)
+    {
+      for (x = 0; x < width; x++)
+       {
+         int sumr = 0, sumg = 0, sumb = 0, suma = 0;
+
+         for (i = 0; i < filter->size; i++)
+           {
+             for (j = 0; j < filter->size; j++)
+               {
+                 int src_x, src_y;
+
+                 src_y = -(BLUR_RADIUS + SHADOW_OFFSET) + y - (filter->size >> 1) + i;
+                 src_x = -(BLUR_RADIUS + SHADOW_OFFSET) + x - (filter->size >> 1) + j;
+
+                 if (src_y < 0 || src_y > gdk_pixbuf_get_height (src) ||
+                     src_x < 0 || src_x > gdk_pixbuf_get_width (src))
+                   continue;
+
+                 sumr += src_pixels [src_y * src_rowstride +
+                                     src_x * src_bpp + 0] *
+                   filter->data [i * filter->size + j];
+                 sumg += src_pixels [src_y * src_rowstride +
+                                     src_x * src_bpp + 1] * 
+                   filter->data [i * filter->size + j];
+
+                 sumb += src_pixels [src_y * src_rowstride +
+                                     src_x * src_bpp + 2] * 
+                   filter->data [i * filter->size + j];
+                 
+                 if (src_bpp == 4)
+                   suma += src_pixels [src_y * src_rowstride +
+                                       src_x * src_bpp + 3] *
+                   filter->data [i * filter->size + j];
+
+                   
+               }
+           }
+
+         if (dest_bpp == 4)
+           dest_pixels [y * dest_rowstride +
+                        x * dest_bpp + 3] = suma * SHADOW_OPACITY;
+
+       }
+    }
+  
+  return dest;
+}
+
+GdkPixbuf *
+create_shadowed_pixbuf (GdkPixbuf *src)
+{
+  GdkPixbuf *dest;
+  
+  dest = create_shadow (src);
+
+  gdk_pixbuf_composite (src, dest,
+                       BLUR_RADIUS, BLUR_RADIUS,
+                       gdk_pixbuf_get_width (src),
+                       gdk_pixbuf_get_height (src),
+                       BLUR_RADIUS, BLUR_RADIUS, 1.0, 1.0,
+                       GDK_INTERP_NEAREST, 255);
+  return dest;
+}
diff --git a/docs/tools/shadow.h b/docs/tools/shadow.h
new file mode 100644
index 0000000..2f569cc
--- /dev/null
+++ b/docs/tools/shadow.h
@@ -0,0 +1,8 @@
+#ifndef __SHADOW_H__
+#define __SHADOW_H__
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+GdkPixbuf *create_shadowed_pixbuf (GdkPixbuf *src);
+
+#endif /* __SHADOW_H__ */
diff --git a/docs/tools/shooter.c b/docs/tools/shooter.c
index 84c993e..1d3eeb2 100644
--- a/docs/tools/shooter.c
+++ b/docs/tools/shooter.c
@@ -1,101 +1,184 @@
-
+#include <gdk/gdk.h>
 #include <gtk/gtk.h>
+#include <gdkx.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <X11/extensions/shape.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <locale.h>
 #include "widgets.h"
+#include "shadow.h"
+
+#define MAXIMUM_WM_REPARENTING_DEPTH 4
+#ifndef _
+#define _(x) (x)
+#endif
+
+static Window
+find_toplevel_window (Window xid)
+{
+  Window root, parent, *children;
+  guint nchildren;
+
+  do
+    {
+      if (XQueryTree (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xid, &root,
+                     &parent, &children, &nchildren) == 0)
+       {
+         g_warning ("Couldn't find window manager window");
+         return 0;
+       }
+
+      if (root == parent)
+       return xid;
 
-typedef enum {
-  SNAPSHOT_WINDOW,
-  SNAPSHOT_DRAW
-} SnapshotMode;
+      xid = parent;
+    }
+  while (TRUE);
+}
 
-static gboolean
-quit_when_idle (gpointer loop)
+static GdkPixbuf *
+add_border_to_shot (GdkPixbuf *pixbuf)
 {
-  g_main_loop_quit (loop);
+  GdkPixbuf *retval;
+
+  retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+                          gdk_pixbuf_get_width (pixbuf) + 2,
+                          gdk_pixbuf_get_height (pixbuf) + 2);
+
+  /* Fill with solid black */
+  gdk_pixbuf_fill (retval, 0xFF);
+  gdk_pixbuf_copy_area (pixbuf,
+                       0, 0,
+                       gdk_pixbuf_get_width (pixbuf),
+                       gdk_pixbuf_get_height (pixbuf),
+                       retval, 1, 1);
 
-  return G_SOURCE_REMOVE;
+  return retval;
 }
 
-static void
-check_for_draw (GdkEvent *event, gpointer loop)
+static GdkPixbuf *
+remove_shaped_area (GdkPixbuf *pixbuf,
+                   Window     window)
 {
-  if (event->type == GDK_EXPOSE)
+  GdkPixbuf *retval;
+  XRectangle *rectangles;
+  int rectangle_count, rectangle_order;
+  int i;
+
+  retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+                          gdk_pixbuf_get_width (pixbuf),
+                          gdk_pixbuf_get_height (pixbuf));
+  
+  gdk_pixbuf_fill (retval, 0);
+  rectangles = XShapeGetRectangles (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), window,
+                                   ShapeBounding, &rectangle_count, &rectangle_order);
+
+  for (i = 0; i < rectangle_count; i++)
     {
-      g_idle_add (quit_when_idle, loop);
-      gdk_event_handler_set ((GdkEventFunc) gtk_main_do_event, NULL, NULL);
+      int y, x;
+
+      for (y = rectangles[i].y; y < rectangles[i].y + rectangles[i].height; y++)
+       {
+         guchar *src_pixels, *dest_pixels;
+
+         src_pixels = gdk_pixbuf_get_pixels (pixbuf) +
+           y * gdk_pixbuf_get_rowstride (pixbuf) +
+           rectangles[i].x * (gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3);
+         dest_pixels = gdk_pixbuf_get_pixels (retval) +
+           y * gdk_pixbuf_get_rowstride (retval) +
+           rectangles[i].x * 4;
+
+         for (x = rectangles[i].x; x < rectangles[i].x + rectangles[i].width; x++)
+           {
+             *dest_pixels++ = *src_pixels ++;
+             *dest_pixels++ = *src_pixels ++;
+             *dest_pixels++ = *src_pixels ++;
+             *dest_pixels++ = 255;
+
+             if (gdk_pixbuf_get_has_alpha (pixbuf))
+               src_pixels++;
+           }
+       }
     }
 
-  gtk_main_do_event (event);
+  return retval;
 }
 
-static cairo_surface_t *
-snapshot_widget (GtkWidget *widget, SnapshotMode mode)
+static GdkPixbuf *
+take_window_shot (Window   child,
+                 gboolean include_decoration)
 {
-  cairo_surface_t *surface;
-  cairo_pattern_t *bg;
-  GMainLoop *loop;
-  cairo_t *cr;
-
-  g_assert (gtk_widget_get_realized (widget));
-
-  surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
-                                               CAIRO_CONTENT_COLOR,
-                                               gtk_widget_get_allocated_width (widget),
-                                               gtk_widget_get_allocated_height (widget));
-
-  loop = g_main_loop_new (NULL, FALSE);
-  /* We wait until the widget is drawn for the first time.
-   * We can not wait for a GtkWidget::draw event, because that might not
-   * happen if the window is fully obscured by windowed child widgets.
-   * Alternatively, we could wait for an expose event on widget's window.
-   * Both of these are rather hairy, not sure what's best. */
-  gdk_event_handler_set (check_for_draw, loop, NULL);
-  g_main_loop_run (loop);
-
-  cr = cairo_create (surface);
-
-  switch (mode)
+  GdkWindow *window;
+  Window xid;
+  gint x_orig, y_orig;
+  gint x = 0, y = 0;
+  gint width, height;
+
+  GdkPixbuf *tmp, *tmp2;
+  GdkPixbuf *retval;
+
+  if (include_decoration)
+    xid = find_toplevel_window (child);
+  else
+    xid = child;
+
+  window = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), xid);
+
+  width = gdk_window_get_width (window);
+  height = gdk_window_get_height (window);
+  gdk_window_get_origin (window, &x_orig, &y_orig);
+
+  if (x_orig < 0)
     {
-    case SNAPSHOT_WINDOW:
-      {
-        GdkWindow *window = gtk_widget_get_window (widget);
-        if (gdk_window_get_window_type (window) == GDK_WINDOW_TOPLEVEL ||
-            gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
-          {
-            /* give the WM/server some time to sync. They need it.
-             * Also, do use popups instead of toplevls in your tests
-             * whenever you can. */
-            gdk_display_sync (gdk_window_get_display (window));
-            g_timeout_add (500, quit_when_idle, loop);
-            g_main_loop_run (loop);
-          }
-        gdk_cairo_set_source_window (cr, window, 0, 0);
-        cairo_paint (cr);
-      }
-      break;
-    case SNAPSHOT_DRAW:
-      bg = gdk_window_get_background_pattern (gtk_widget_get_window (widget));
-      if (bg)
-        {
-          cairo_set_source (cr, bg);
-          cairo_paint (cr);
-        }
-      gtk_widget_draw (widget, cr);
-      break;
-    default:
-      g_assert_not_reached();
-      break;
+      x = - x_orig;
+      width = width + x_orig;
+      x_orig = 0;
     }
 
-  cairo_destroy (cr);
-  g_main_loop_unref (loop);
-  gtk_widget_destroy (widget);
+  if (y_orig < 0)
+    {
+      y = - y_orig;
+      height = height + y_orig;
+      y_orig = 0;
+    }
+
+  if (x_orig + width > gdk_screen_width ())
+    width = gdk_screen_width () - x_orig;
+
+  if (y_orig + height > gdk_screen_height ())
+    height = gdk_screen_height () - y_orig;
+
+  tmp = gdk_pixbuf_get_from_window (window,
+                                   x, y, width, height);
 
-  return surface;
+  if (include_decoration)
+    tmp2 = remove_shaped_area (tmp, xid);
+  else
+    tmp2 = add_border_to_shot (tmp);
+
+  retval = create_shadowed_pixbuf (tmp2);
+  g_object_unref (tmp);
+  g_object_unref (tmp2);
+
+  return retval;
 }
 
 int main (int argc, char **argv)
 {
   GList *toplevels;
+  GdkPixbuf *screenshot = NULL;
   GList *node;
 
   /* If there's no DISPLAY, we silently error out.  We don't want to break
@@ -107,19 +190,42 @@ int main (int argc, char **argv)
 
   for (node = toplevels; node; node = g_list_next (node))
     {
+      GtkAllocation allocation;
+      GdkWindow *window;
       WidgetInfo *info;
+      XID id;
       char *filename;
-      cairo_surface_t *surface;
 
       info = node->data;
 
       gtk_widget_show (info->window);
 
-      surface = snapshot_widget (info->window,
-                                 info->include_decorations ? SNAPSHOT_WINDOW : SNAPSHOT_DRAW);
+      window = gtk_widget_get_window (info->window);
+      gtk_widget_get_allocation (info->window, &allocation);
+
+      gtk_widget_show_now (info->window);
+      gtk_widget_queue_draw_area (info->window,
+                                  allocation.x, allocation.y,
+                                  allocation.width, allocation.height);
+      gdk_window_process_updates (window, TRUE);
+
+      while (gtk_events_pending ())
+       {
+         gtk_main_iteration ();
+       }
+      sleep (1);
+
+      while (gtk_events_pending ())
+       {
+         gtk_main_iteration ();
+       }
+
+      id = gdk_x11_window_get_xid (window);
+      screenshot = take_window_shot (id, info->include_decorations);
       filename = g_strdup_printf ("./%s.png", info->name);
-      g_assert (cairo_surface_write_to_png (surface, filename) == CAIRO_STATUS_SUCCESS);
-      g_free (filename);
+      gdk_pixbuf_save (screenshot, filename, "png", NULL, NULL);
+      g_free(filename);
+      gtk_widget_hide (info->window);
     }
 
   return 0;


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