]> www.fi.muni.cz Git - evince.git/commitdiff
Add thumbnail support.
authorAnders Carlsson <andersca@gnome.org>
Wed, 22 Dec 2004 20:54:22 +0000 (20:54 +0000)
committerAnders Carlsson <andersca@src.gnome.org>
Wed, 22 Dec 2004 20:54:22 +0000 (20:54 +0000)
2004-12-22  Anders Carlsson  <andersca@gnome.org>

* backend/Makefile.am:
* backend/ev-document-thumbnails.c:
(ev_document_thumbnails_get_type),
(ev_document_thumbnails_get_thumbnail):
* backend/ev-document-thumbnails.h:
* pixbuf/pixbuf-document.c: (G_DEFINE_TYPE_WITH_CODE),
(pixbuf_document_thumbnails_get_thumbnail),
(pixbuf_document_document_thumbnails_iface_init):
* shell/Makefile.am:
* shell/ev-sidebar-thumbnails.c: (ev_sidebar_thumbnails_destroy),
(ev_sidebar_thumbnails_class_init), (ev_sidebar_thumbnails_init),
(populate_thumbnails), (ev_sidebar_thumbnails_set_document):
* shell/ev-sidebar-thumbnails.h:
* shell/ev-sidebar.c: (ev_sidebar_init), (ev_sidebar_add_page),
(ev_sidebar_set_document):
* shell/ev-utils.c: (gaussian), (create_blur_filter),
(create_shadow), (ev_pixbuf_add_shadow):
* shell/ev-utils.h:
Add thumbnail support.

backend/Makefile.am
backend/ev-document-thumbnails.c [new file with mode: 0644]
backend/ev-document-thumbnails.h [new file with mode: 0644]
pixbuf/pixbuf-document.c
shell/Makefile.am
shell/ev-sidebar-thumbnails.c
shell/ev-sidebar-thumbnails.h
shell/ev-sidebar.c
shell/ev-utils.c [new file with mode: 0644]
shell/ev-utils.h [new file with mode: 0644]

index 445029795ec959d2b8d3264e13672c8fb7a565d1..2f54157cef0eb330d5282ac7da1828fb45b28727 100644 (file)
@@ -13,6 +13,8 @@ libevbackend_la_SOURCES=                      \
        ev-backend-marshal.c                    \
        ev-document.c                           \
        ev-document.h                           \
+       ev-document-thumbnails.c                \
+       ev-document-thumbnails.h                \
        ev-document-bookmarks.c                 \
        ev-document-bookmarks.h                 \
        $(NULL)
diff --git a/backend/ev-document-thumbnails.c b/backend/ev-document-thumbnails.c
new file mode 100644 (file)
index 0000000..e9c53ab
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ *  Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "ev-document-thumbnails.h"
+
+GType
+ev_document_thumbnails_get_type (void)
+{
+       static GType type = 0;
+
+       if (G_UNLIKELY (type == 0))
+       {
+               static const GTypeInfo our_info =
+               {
+                       sizeof (EvDocumentThumbnailsIface),
+                       NULL,
+                       NULL,
+               };
+
+               type = g_type_register_static (G_TYPE_INTERFACE,
+                                              "EvDocumentThumbnails",
+                                              &our_info, (GTypeFlags)0);
+       }
+
+       return type;
+}
+
+GdkPixbuf *
+ev_document_thumbnails_get_thumbnail (EvDocumentThumbnails   *document,
+                                     gint                    page,
+                                     gint                    width)
+{
+       EvDocumentThumbnailsIface *iface = EV_DOCUMENT_THUMBNAILS_GET_IFACE (document);
+       
+       return iface->get_thumbnail (document, page, width);
+}
diff --git a/backend/ev-document-thumbnails.h b/backend/ev-document-thumbnails.h
new file mode 100644 (file)
index 0000000..fdc1e80
--- /dev/null
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ *  Copyright (C) 2004 Anders Carlsson
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef EV_DOCUMENT_THUMBNAILS_H
+#define EV_DOCUMENT_THUMBNAILS_H
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_DOCUMENT_THUMBNAILS        (ev_document_thumbnails_get_type ())
+#define EV_DOCUMENT_THUMBNAILS(o)                  (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_THUMBNAILS, EvDocumentThumbnails))
+#define EV_DOCUMENT_THUMBNAILS_IFACE(k)            (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_THUMBNAILS, EvDocumentThumbnailsIface))
+#define EV_IS_DOCUMENT_THUMBNAILS(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_DOCUMENT_THUMBNAILS))
+#define EV_IS_DOCUMENT_THUMBNAILS_IFACE(k)         (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT_THUMBNAILS))
+#define EV_DOCUMENT_THUMBNAILS_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_DOCUMENT_THUMBNAILS, EvDocumentThumbnailsIface))
+
+typedef struct _EvDocumentThumbnails   EvDocumentThumbnails;
+typedef struct _EvDocumentThumbnailsIface      EvDocumentThumbnailsIface;
+
+struct _EvDocumentThumbnailsIface
+{
+       GTypeInterface base_iface;
+
+       /* Methods  */
+       GdkPixbuf *  (* get_thumbnail) (EvDocumentThumbnails   *document,
+                                       gint                    page,
+                                       gint                    width);
+};
+
+GType ev_document_thumbnails_get_type (void);
+
+GdkPixbuf *ev_document_thumbnails_get_thumbnail (EvDocumentThumbnails   *document,
+                                                gint                    page,
+                                                gint                    width);
+
+G_END_DECLS
+
+#endif
index c8efd2d9588d21039dfbb7b60b978ab06b7ab9c8..7eeb8fdaf986e699b568151e8775e536976818f6 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
-/* pixbuf-document.h: Implementation of EvDocument for PIXBUF
+/*
  * Copyright (C) 2004, Anders Carlsson <andersca@gnome.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,7 @@
  */
 
 #include "pixbuf-document.h"
+#include "ev-document-thumbnails.h"
 
 struct _PixbufDocumentClass
 {
@@ -38,10 +39,14 @@ struct _PixbufDocument
 typedef struct _PixbufDocumentClass PixbufDocumentClass;
 
 static void pixbuf_document_document_iface_init (EvDocumentIface *iface);
+static void pixbuf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (PixbufDocument, pixbuf_document, G_TYPE_OBJECT,
                          { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
-                                                 pixbuf_document_document_iface_init) });
+                                                 pixbuf_document_document_iface_init);
+                        G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
+                                               pixbuf_document_document_thumbnails_iface_init)                            
+                                  });
 
 static GObjectClass *parent_class;
 
@@ -219,6 +224,34 @@ pixbuf_document_document_iface_init (EvDocumentIface *iface)
         iface->end_find = pixbuf_document_end_find;
 }
 
+static GdkPixbuf *
+pixbuf_document_thumbnails_get_thumbnail (EvDocumentThumbnails   *document,
+                                         gint                   page,
+                                         gint                   width)
+{
+       PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
+       GdkPixbuf *pixbuf;
+       gdouble scale_factor;
+       gint height;
+       
+       scale_factor = (gdouble)width / gdk_pixbuf_get_width (pixbuf_document->pixbuf);
+
+       height = gdk_pixbuf_get_height (pixbuf_document->pixbuf) * scale_factor;
+       
+       pixbuf = gdk_pixbuf_scale_simple (pixbuf_document->pixbuf, width, height,
+                                         GDK_INTERP_BILINEAR);
+       
+       return pixbuf;
+}
+
+
+static void
+pixbuf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
+{
+       iface->get_thumbnail = pixbuf_document_thumbnails_get_thumbnail;
+}
+
+
 static void
 pixbuf_document_init (PixbufDocument *pixbuf_document)
 {
index a36511ae51980819b43dd8170e2b06f4e4103431..4740485202543da039d814cd98349a1396e36cf1 100644 (file)
@@ -35,6 +35,8 @@ evince_SOURCES=                               \
        ev-sidebar-thumbnails.h         \
        ev-stock-icons.c                \
        ev-stock-icons.h                \
+       ev-utils.c                      \
+       ev-utils.h                      \
        main.c                          \
        $(NULL)
 
index a2f5d76ff4081ba96ce8dfd9365d69490b6ebc4c..c727abff04f08ecc16bdc0230ed70bcc188807da 100644 (file)
@@ -1,9 +1,11 @@
 /* this file is part of evince, a gnome document viewer
  *
  *  Copyright (C) 2004 Red Hat, Inc.
+ *  Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
  *
- *  Author:
+ *  Authors:
  *    Jonathan Blandford <jrb@alum.mit.edu>
+ *    Anders Carlsson <andersca@gnome.org>
  *
  * Evince is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
 #include <gtk/gtk.h>
 
 #include "ev-sidebar-thumbnails.h"
+#include "ev-document-thumbnails.h"
+#include "ev-utils.h"
+
+#define THUMBNAIL_WIDTH 96
 
 struct _EvSidebarThumbnailsPrivate {
-       int dummy;
+       GtkWidget *tree_view;
+       GtkListStore *list_store;
+       EvDocument *document;
+       
+       guint idle_id;
+       gint current_page, n_pages;
+};
+
+enum {
+       COLUMN_PAGE_STRING,
+       COLUMN_PIXBUF,
+       NUM_COLUMNS
 };
 
-G_DEFINE_TYPE (EvSidebarThumbnails, ev_sidebar_thumbnails, GTK_TYPE_VBOX)
+static GtkVBoxClass *parent_class;
+
+G_DEFINE_TYPE (EvSidebarThumbnails, ev_sidebar_thumbnails, GTK_TYPE_VBOX);
 
 #define EV_SIDEBAR_THUMBNAILS_GET_PRIVATE(object) \
-       (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsPrivate))
+       (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsPrivate));
+
+static void
+ev_sidebar_thumbnails_destroy (GtkObject *object)
+{
+       EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (object);
+       EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
+       
+       if (priv->idle_id != 0) {
+               g_source_remove (priv->idle_id);
+
+               priv->idle_id = 0;
+       }
+       
+       GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
 
 static void
 ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnails_class)
 {
        GObjectClass *g_object_class;
-
+       GtkObjectClass *gtk_object_class;
+       
        g_object_class = G_OBJECT_CLASS (ev_sidebar_thumbnails_class);
+       gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_thumbnails_class);
 
+       parent_class = g_type_class_peek_parent (ev_sidebar_thumbnails_class);
+       
+       gtk_object_class->destroy = ev_sidebar_thumbnails_destroy;
+       
        g_type_class_add_private (g_object_class, sizeof (EvSidebarThumbnailsPrivate));
 
 }
@@ -52,14 +92,34 @@ ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnail
 static void
 ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails)
 {
-       GtkWidget *label;
+       GtkWidget *swindow;
+       EvSidebarThumbnailsPrivate *priv;
+
+       priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
 
-       ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
+       priv->list_store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF);
+       priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->list_store));
+
+       gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
+       gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
+                                                    NULL, gtk_cell_renderer_pixbuf_new (),
+                                                    "pixbuf", 1, NULL);
+       gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
+                                                    NULL, gtk_cell_renderer_text_new (),
+                                                    "text", 0, NULL);
        
-       label = gtk_label_new ("Thumbnails!");
-       gtk_box_pack_start (GTK_BOX (ev_sidebar_thumbnails), label,
-                           TRUE, TRUE, 0);
-       gtk_widget_show (label);
+       g_object_unref (priv->list_store);
+
+       swindow = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
+                                       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+       gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
+                                            GTK_SHADOW_IN);
+
+       gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view);
+       gtk_box_pack_start (GTK_BOX (ev_sidebar_thumbnails), swindow, TRUE, TRUE, 0);
+       
+       gtk_widget_show_all (swindow);
 }
 
 GtkWidget *
@@ -71,3 +131,82 @@ ev_sidebar_thumbnails_new (void)
 
        return ev_sidebar_thumbnails;
 }
+
+static gboolean
+populate_thumbnails (gpointer data)
+{
+       EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (data);
+       EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
+       GdkPixbuf *tmp, *pixbuf;
+       GtkTreePath *path;
+       GtkTreeIter iter;
+       
+       tmp = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (priv->document),
+                                                      priv->current_page, THUMBNAIL_WIDTH);
+
+
+       /* Add shadow */
+       pixbuf = ev_pixbuf_add_shadow (tmp, 5, 0, 0, 0.5);
+       
+       path = gtk_tree_path_new_from_indices (priv->current_page, -1);
+       gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store), &iter, path);
+       gtk_tree_path_free (path);
+
+       gtk_list_store_set (priv->list_store, &iter,
+                           COLUMN_PIXBUF, pixbuf,
+                           -1);
+
+       g_object_unref (tmp);
+       g_object_unref (pixbuf);
+       
+       priv->current_page++;
+       
+       if (priv->current_page == priv->n_pages)
+               return FALSE;
+       else
+               return TRUE;
+}
+
+void
+ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails,
+                                   EvDocument          *document)
+{
+       GtkIconTheme *theme;
+       GdkPixbuf *loading_icon;
+       gint i, n_pages;
+       EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
+       
+       g_return_if_fail (EV_IS_DOCUMENT_THUMBNAILS (document));
+
+       if (priv->idle_id != 0) {
+               g_source_remove (priv->idle_id);
+       }
+       
+       theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (sidebar_thumbnails)));
+
+       loading_icon = gtk_icon_theme_load_icon (theme, "gnome-fs-loading-icon",
+                                                THUMBNAIL_WIDTH, 0, NULL);
+
+       n_pages = ev_document_get_n_pages (document);
+       
+       for (i = 0; i < n_pages; i++) {
+               GtkTreeIter iter;
+               gchar *page;
+
+               page = g_strdup_printf ("Page %d", i + 1);
+               gtk_list_store_append (sidebar_thumbnails->priv->list_store,
+                                      &iter);
+               gtk_list_store_set (sidebar_thumbnails->priv->list_store,
+                                   &iter,
+                                   COLUMN_PAGE_STRING, page,
+                                   COLUMN_PIXBUF, loading_icon,
+                                   -1);
+               g_free (page);
+       }
+
+       priv->document = document;
+       priv->idle_id = g_idle_add (populate_thumbnails, sidebar_thumbnails);
+       priv->n_pages = n_pages;
+       priv->current_page = 0;
+}
+
index e0ccccfc49cfabac74ccd311dbdc2136f02289df..45f68fce2c69a3504ca33bae4293930d8c3ac2d3 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <gtk/gtkvbox.h>
 
+#include "ev-document.h"
+
 G_BEGIN_DECLS
 
 typedef struct _EvSidebarThumbnails EvSidebarThumbnails;
@@ -52,6 +54,9 @@ struct _EvSidebarThumbnailsClass {
 GType      ev_sidebar_thumbnails_get_type (void);
 GtkWidget *ev_sidebar_thumbnails_new      (void);
 
+void ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails,
+                                        EvDocument          *document);
+
 G_END_DECLS
 
 #endif /* __EV_SIDEBAR_THUMBNAILS_H__ */
index 780f9f6a73811371777b39450d5b483c4e116411..98beaa502078e9b15619bf9b2ce9e1c5058fd149 100644 (file)
@@ -28,7 +28,9 @@
 #include <gtk/gtk.h>
 
 #include "ev-sidebar.h"
+#include "ev-document-thumbnails.h"
 #include "ev-sidebar-bookmarks.h"
+#include "ev-sidebar-thumbnails.h"
 
 typedef struct
 {
@@ -77,7 +79,7 @@ ev_sidebar_init (EvSidebar *ev_sidebar)
 {
        GtkWidget *hbox;
        GtkCellRenderer *renderer;
-
+       
        ev_sidebar->priv = EV_SIDEBAR_GET_PRIVATE (ev_sidebar);
        gtk_box_set_spacing (GTK_BOX (ev_sidebar), 6);
 
@@ -100,6 +102,7 @@ ev_sidebar_init (EvSidebar *ev_sidebar)
        gtk_box_pack_start (GTK_BOX (hbox),
                            ev_sidebar->priv->option_menu,
                            FALSE, FALSE, 0);
+       
        renderer = gtk_cell_renderer_text_new ();
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ev_sidebar->priv->option_menu),
                                    renderer, TRUE);
@@ -172,6 +175,10 @@ ev_sidebar_add_page (EvSidebar   *ev_sidebar,
                                           PAGE_COLUMN_MAIN_WIDGET, main_widget,
                                           PAGE_COLUMN_NOTEBOOK_INDEX, index,
                                           -1);
+
+       /* Set the first item added as active */
+       if (gtk_combo_box_get_active (GTK_COMBO_BOX (ev_sidebar->priv->option_menu)))
+               gtk_combo_box_set_active (GTK_COMBO_BOX (ev_sidebar->priv->option_menu), 0);
 }
 
 void
@@ -204,7 +211,13 @@ ev_sidebar_set_document (EvSidebar   *sidebar,
                           && ev_bookmarks_has_bookmarks (document)... */
                        ev_sidebar_bookmarks_set_document (EV_SIDEBAR_BOOKMARKS (widget),
                                                           document);
-               /* else if EV_IS_SIDEBAR_THUMBNAILS... */
+               else if (EV_IS_SIDEBAR_THUMBNAILS (widget) &&
+                        EV_IS_DOCUMENT_THUMBNAILS (document))
+                       ev_sidebar_thumbnails_set_document (EV_SIDEBAR_THUMBNAILS (widget),
+                                                           document);
+                               
+
+                 
        }
        
 
diff --git a/shell/ev-utils.c b/shell/ev-utils.c
new file mode 100644 (file)
index 0000000..cf8a67c
--- /dev/null
@@ -0,0 +1,179 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ *  Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "ev-utils.h"
+#include <math.h>
+
+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 blur_radius,
+              int x_offset, int y_offset, double opacity)
+{
+  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);
+
+  if (x_offset < 0)
+         x_offset = (blur_radius * 4) / 5;
+  
+  if (y_offset < 0)
+         y_offset = (blur_radius * 4) / 5;
+
+  
+  width = gdk_pixbuf_get_width (src) + blur_radius * 2 + x_offset;
+  height = gdk_pixbuf_get_height (src) + blur_radius * 2 + y_offset;
+
+  dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), TRUE,
+                        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 + x_offset) + y - (filter->size >> 1) + i;
+                 src_x = -(blur_radius + y_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];
+                 else
+                         suma += 0xff;
+                   
+               }
+           }
+
+         if (dest_bpp == 4)
+           dest_pixels [y * dest_rowstride +
+                        x * dest_bpp + 3] = (suma * opacity) / (filter->size * filter->size);
+
+       }
+    }
+  
+  return dest;
+}
+
+GdkPixbuf *
+ev_pixbuf_add_shadow (GdkPixbuf *src, int size,
+                     int x_offset, int y_offset, double opacity)
+{
+  GdkPixbuf *dest;
+  
+  dest = create_shadow (src, size, x_offset, y_offset, opacity);
+
+  gdk_pixbuf_composite (src, dest,
+                       size, size,
+                       gdk_pixbuf_get_width (src),
+                       gdk_pixbuf_get_height (src),
+                       size, size,
+                       1.0, 1.0,
+                       GDK_INTERP_NEAREST, 255);
+
+  return dest;
+}
+
+
diff --git a/shell/ev-utils.h b/shell/ev-utils.h
new file mode 100644 (file)
index 0000000..084a285
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/*
+ *  Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __EV_UTILS_H__
+#define __EV_UTILS_H__
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+GdkPixbuf *ev_pixbuf_add_shadow (GdkPixbuf *src, int size,
+                                int x_offset, int y_offset, double opacity);
+
+G_END_DECLS
+
+#endif /* __EV_VIEW_H__ */