[gnome-control-center] background: Composite the emblems ourselves



commit 7f606870a3f26b50cda1c6c6f54ee242167f42ca
Author: Debarshi Ray <debarshir gnome org>
Date:   Mon Jun 30 15:47:24 2014 +0200

    background: Composite the emblems ourselves
    
    We were assuming that setting stock-size would affect the emblems in
    GEmblemedIcons, but not the icons themselves. This is a bit weird.
    GtkCellRendererPixbuf:gicon is meant to work with
    GtkCellRendererPixbuf:stock-size, and this was only working so far
    because GTK_ICON_LOOKUP_FORCE_SIZE was not being used when loading
    the icon.
    
    Let's composite the emblems ourselves so that we don't have to depend
    on this quirky interpretation of stock-size.
    
    Unfortunately, we can not directly use the pixbufs because they are
    unaware of the scale factor and GTK+ will scale them on HiDpi
    displays. Since our pixbufs already have enough pixels to work well
    with such devices, scaling them further will lead to giant, fuzzy
    thumbnails. Hence, we use GtkCellRendererPixbuf:surface with the
    scale factor codified in it.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=732375

 configure.ac                                     |    2 +-
 panels/background/bg-colors-source.c             |   11 +++-
 panels/background/bg-pictures-source.c           |   17 ++++-
 panels/background/bg-source.c                    |   12 +++-
 panels/background/bg-source.h                    |    2 +
 panels/background/bg-wallpapers-source.c         |   14 +++-
 panels/background/cc-background-chooser-dialog.c |    8 +--
 panels/background/cc-background-item.c           |   80 ++++++++++++++++++----
 panels/background/cc-background-item.h           |    4 +-
 panels/background/cc-background-panel.c          |    3 +
 10 files changed, 121 insertions(+), 32 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 9efe923..c95c64f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -119,7 +119,7 @@ LIBGD_INIT([_view-common notification static])
 PKG_CHECK_MODULES(LIBLANGUAGE, $COMMON_MODULES gnome-desktop-3.0 fontconfig)
 PKG_CHECK_MODULES(LIBSHORTCUTS, $COMMON_MODULES x11)
 PKG_CHECK_MODULES(SHELL, $COMMON_MODULES x11 polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION)
-PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES libxml-2.0 gnome-desktop-3.0
+PKG_CHECK_MODULES(BACKGROUND_PANEL, $COMMON_MODULES cairo-gobject libxml-2.0 gnome-desktop-3.0
                   gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION
                   goa-1.0 >= $GOA_REQUIRED_VERSION
                   grilo-0.2 >= $GRILO_REQUIRED_VERSION)
diff --git a/panels/background/bg-colors-source.c b/panels/background/bg-colors-source.c
index dd9ba97..3a589f5 100644
--- a/panels/background/bg-colors-source.c
+++ b/panels/background/bg-colors-source.c
@@ -24,6 +24,7 @@
 
 #include "cc-background-item.h"
 
+#include <cairo-gobject.h>
 #include <glib/gi18n-lib.h>
 #include <gdesktop-enums.h>
 
@@ -76,6 +77,8 @@ bg_colors_source_constructed (GObject *object)
       CcBackgroundItemFlags flags;
       CcBackgroundItem *item;
       GIcon *pixbuf;
+      cairo_surface_t *surface;
+      int scale_factor;
 
       item = cc_background_item_new (NULL);
       flags = CC_BACKGROUND_ITEM_HAS_PCOLOR |
@@ -96,14 +99,18 @@ bg_colors_source_constructed (GObject *object)
       cc_background_item_load (item, NULL);
 
       /* insert the item into the liststore */
+      scale_factor = bg_source_get_scale_factor (BG_SOURCE (self));
       pixbuf = cc_background_item_get_thumbnail (item,
                                                 thumb_factory,
-                                                thumbnail_width, thumbnail_height);
+                                                thumbnail_width, thumbnail_height,
+                                                scale_factor);
+      surface = gdk_cairo_surface_create_from_pixbuf (GDK_PIXBUF (pixbuf), scale_factor, NULL);
       gtk_list_store_insert_with_values (store, NULL, 0,
-                                         0, pixbuf,
+                                         0, surface,
                                          1, item,
                                          -1);
 
+      cairo_surface_destroy (surface);
       g_object_unref (pixbuf);
       g_object_unref (item);
     }
diff --git a/panels/background/bg-pictures-source.c b/panels/background/bg-pictures-source.c
index 0c5c6c0..3d0607f 100644
--- a/panels/background/bg-pictures-source.c
+++ b/panels/background/bg-pictures-source.c
@@ -27,6 +27,7 @@
 #include "cc-background-item.h"
 
 #include <string.h>
+#include <cairo-gobject.h>
 #include <gio/gio.h>
 #include <grilo.h>
 #include <libgnome-desktop/gnome-desktop-thumbnail.h>
@@ -150,6 +151,8 @@ picture_scaled (GObject *source_object,
   GtkTreePath *path;
   GtkTreeRowReference *row_ref;
   GtkListStore *store;
+  cairo_surface_t *surface = NULL;
+  int scale_factor;
 
   item = g_object_get_data (source_object, "item");
   pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
@@ -183,6 +186,8 @@ picture_scaled (GObject *source_object,
       goto out;
     }
 
+  scale_factor = bg_source_get_scale_factor (BG_SOURCE (bg_source));
+  surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL);
   cc_background_item_load (item, NULL);
 
   row_ref = g_object_get_data (G_OBJECT (item), "row-ref");
@@ -190,7 +195,7 @@ picture_scaled (GObject *source_object,
     {
       /* insert the item into the liststore if it did not exist */
       gtk_list_store_insert_with_values (store, NULL, -1,
-                                         0, pixbuf,
+                                         0, surface,
                                          1, item,
                                          -1);
     }
@@ -201,7 +206,7 @@ picture_scaled (GObject *source_object,
         {
           /* otherwise update the thumbnail */
           gtk_list_store_set (store, &iter,
-                              0, pixbuf,
+                              0, surface,
                               -1);
         }
     }
@@ -212,6 +217,7 @@ picture_scaled (GObject *source_object,
 
 
  out:
+  g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
   g_clear_object (&pixbuf);
 }
 
@@ -336,10 +342,12 @@ add_single_file (BgPicturesSource *bg_source,
   GtkTreeIter iter;
   GtkTreePath *path = NULL;
   GtkTreeRowReference *row_ref;
+  cairo_surface_t *surface = NULL;
   char *source_uri = NULL;
   char *uri = NULL;
   gboolean is_native;
   gboolean retval = FALSE;
+  int scale_factor;
 
   /* find png and jpeg files */
   if (!content_type)
@@ -395,11 +403,13 @@ add_single_file (BgPicturesSource *bg_source,
       goto read_file;
     }
 
+  scale_factor = bg_source_get_scale_factor (BG_SOURCE (bg_source));
+  surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL);
   store = bg_source_get_liststore (BG_SOURCE (bg_source));
 
   /* insert the item into the liststore */
   gtk_list_store_insert_with_values (store, &iter, -1,
-                                     0, pixbuf,
+                                     0, surface,
                                      1, item,
                                      -1);
 
@@ -470,6 +480,7 @@ add_single_file (BgPicturesSource *bg_source,
 
  out:
   gtk_tree_path_free (path);
+  g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
   g_clear_object (&pixbuf);
   g_clear_object (&icon_info);
   g_clear_object (&item);
diff --git a/panels/background/bg-source.c b/panels/background/bg-source.c
index dee3ab2..b0127f9 100644
--- a/panels/background/bg-source.c
+++ b/panels/background/bg-source.c
@@ -21,6 +21,8 @@
 #include "bg-source.h"
 #include "cc-background-item.h"
 
+#include <cairo-gobject.h>
+
 #define THUMBNAIL_WIDTH 256
 #define THUMBNAIL_HEIGHT (THUMBNAIL_WIDTH * 3 / 4)
 
@@ -155,7 +157,7 @@ bg_source_init (BgSource *self)
 
   priv = self->priv = SOURCE_PRIVATE (self);
 
-  priv->store = gtk_list_store_new (3, G_TYPE_ICON, G_TYPE_OBJECT, G_TYPE_STRING);
+  priv->store = gtk_list_store_new (3, CAIRO_GOBJECT_TYPE_SURFACE, G_TYPE_OBJECT, G_TYPE_STRING);
 }
 
 GtkListStore*
@@ -167,6 +169,14 @@ bg_source_get_liststore (BgSource *source)
 }
 
 gint
+bg_source_get_scale_factor (BgSource *source)
+{
+  g_return_val_if_fail (BG_IS_SOURCE (source), 1);
+
+  return gtk_widget_get_scale_factor (source->priv->window);
+}
+
+gint
 bg_source_get_thumbnail_height (BgSource *source)
 {
   g_return_val_if_fail (BG_IS_SOURCE (source), THUMBNAIL_HEIGHT);
diff --git a/panels/background/bg-source.h b/panels/background/bg-source.h
index bb6f9d4..5719247 100644
--- a/panels/background/bg-source.h
+++ b/panels/background/bg-source.h
@@ -67,6 +67,8 @@ GType bg_source_get_type (void) G_GNUC_CONST;
 
 GtkListStore* bg_source_get_liststore (BgSource *source);
 
+gint bg_source_get_scale_factor (BgSource *source);
+
 gint bg_source_get_thumbnail_height (BgSource *source);
 
 gint bg_source_get_thumbnail_width (BgSource *source);
diff --git a/panels/background/bg-wallpapers-source.c b/panels/background/bg-wallpapers-source.c
index d817ba0..e4bced5 100644
--- a/panels/background/bg-wallpapers-source.c
+++ b/panels/background/bg-wallpapers-source.c
@@ -25,6 +25,7 @@
 #include "cc-background-item.h"
 #include "cc-background-xml.h"
 
+#include <cairo-gobject.h>
 #include <libgnome-desktop/gnome-desktop-thumbnail.h>
 #include <gio/gio.h>
 
@@ -49,7 +50,9 @@ load_wallpapers (gchar              *key,
   GtkTreeIter iter;
   GIcon *pixbuf;
   GtkListStore *store = bg_source_get_liststore (BG_SOURCE (source));
+  cairo_surface_t *surface = NULL;
   gboolean deleted;
+  gint scale_factor;
   gint thumbnail_height;
   gint thumbnail_width;
 
@@ -60,17 +63,24 @@ load_wallpapers (gchar              *key,
 
   gtk_list_store_append (store, &iter);
 
+  scale_factor = bg_source_get_scale_factor (BG_SOURCE (source));
   thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (source));
   thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (source));
   pixbuf = cc_background_item_get_thumbnail (item, priv->thumb_factory,
-                                            thumbnail_width, thumbnail_height);
+                                            thumbnail_width, thumbnail_height,
+                                            scale_factor);
+  if (pixbuf == NULL)
+    goto out;
 
+  surface = gdk_cairo_surface_create_from_pixbuf (GDK_PIXBUF (pixbuf), scale_factor, NULL);
   gtk_list_store_set (store, &iter,
-                      0, pixbuf,
+                      0, surface,
                       1, item,
                       2, cc_background_item_get_name (item),
                       -1);
 
+ out:
+  g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
   if (pixbuf)
     g_object_unref (pixbuf);
 }
diff --git a/panels/background/cc-background-chooser-dialog.c 
b/panels/background/cc-background-chooser-dialog.c
index 2c087a8..79b39a2 100644
--- a/panels/background/cc-background-chooser-dialog.c
+++ b/panels/background/cc-background-chooser-dialog.c
@@ -413,18 +413,12 @@ cc_background_chooser_dialog_init (CcBackgroundChooserDialog *chooser)
   g_signal_connect (priv->icon_view, "item-activated", G_CALLBACK (on_item_activated), chooser);
 
   renderer = gtk_cell_renderer_pixbuf_new ();
-  /* set stock size to 32px so that emblems render at 16px. see:
-   * https://bugzilla.gnome.org/show_bug.cgi?id=682123#c4
-   */
-  g_object_set (renderer,
-                "stock-size", GTK_ICON_SIZE_DND,
-                NULL);
   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->icon_view),
                               renderer,
                               FALSE);
   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (priv->icon_view),
                                   renderer,
-                                  "gicon", 0,
+                                  "surface", 0,
                                   NULL);
 
   gtk_dialog_add_button (GTK_DIALOG (chooser), _("_Cancel"), GTK_RESPONSE_CANCEL);
diff --git a/panels/background/cc-background-item.c b/panels/background/cc-background-item.c
index 3548771..b4b8a4b 100644
--- a/panels/background/cc-background-item.c
+++ b/panels/background/cc-background-item.c
@@ -25,6 +25,7 @@
 #include <gtk/gtk.h>
 #include <gio/gio.h>
 #include <glib/gi18n-lib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 
 #include <libgnome-desktop/gnome-bg.h>
 #include <gdesktop-enums.h>
@@ -52,6 +53,7 @@ struct CcBackgroundItemPrivate
         guint64          modified;
 
         /* internal */
+        GdkPixbuf       *slideshow_emblem;
         GnomeBG         *bg;
         char            *mime_type;
         int              width;
@@ -81,15 +83,63 @@ static void     cc_background_item_finalize       (GObject               *object
 
 G_DEFINE_TYPE (CcBackgroundItem, cc_background_item, G_TYPE_OBJECT)
 
-static GEmblem *
-get_slideshow_icon (void)
+static GdkPixbuf *slideshow_emblem = NULL;
+
+static GIcon *
+get_emblemed_pixbuf (CcBackgroundItem *item, GdkPixbuf *pixbuf, gint scale_factor)
 {
-       GIcon *themed;
-       GEmblem *emblem;
-       themed = g_themed_icon_new ("slideshow-emblem");
-       emblem = g_emblem_new_with_origin (themed, G_EMBLEM_ORIGIN_DEVICE);
-       g_object_unref (themed);
-       return emblem;
+        GIcon *icon = NULL;
+        GIcon *retval;
+        GtkIconInfo *icon_info = NULL;
+        int eh;
+        int ew;
+        int h;
+        int w;
+        int x;
+        int y;
+
+        retval = g_object_ref (pixbuf);
+
+        if (item->priv->slideshow_emblem == NULL) {
+                if (slideshow_emblem == NULL) {
+                        GError *error = NULL;
+                        GtkIconTheme *theme;
+
+                        icon = g_themed_icon_new ("slideshow-emblem");
+                        theme = gtk_icon_theme_get_default ();
+                        icon_info = gtk_icon_theme_lookup_by_gicon_for_scale (theme,
+                                                                              icon,
+                                                                              16,
+                                                                              scale_factor,
+                                                                              GTK_ICON_LOOKUP_FORCE_SIZE |
+                                                                              GTK_ICON_LOOKUP_USE_BUILTIN);
+                        slideshow_emblem = gtk_icon_info_load_icon (icon_info, &error);
+                        if (slideshow_emblem == NULL) {
+                                g_warning ("Failed to load slideshow emblem: %s", error->message);
+                                g_error_free (error);
+                                goto out;
+                        }
+
+                        g_object_add_weak_pointer (G_OBJECT (slideshow_emblem), (gpointer *) 
(&slideshow_emblem));
+                        item->priv->slideshow_emblem = slideshow_emblem;
+                } else {
+                        item->priv->slideshow_emblem = g_object_ref (slideshow_emblem);
+                }
+        }
+
+        eh = gdk_pixbuf_get_height (slideshow_emblem);
+        ew = gdk_pixbuf_get_width (slideshow_emblem);
+        h = gdk_pixbuf_get_height (pixbuf);
+        w = gdk_pixbuf_get_width (pixbuf);
+        x = w - ew;
+        y = h - eh;
+
+        gdk_pixbuf_composite (slideshow_emblem, pixbuf, x, y, ew, eh, x, y, 1.0, 1.0, GDK_INTERP_BILINEAR, 
255);
+
+ out:
+        g_clear_object (&icon_info);
+        g_clear_object (&icon);
+        return retval;
 }
 
 static void
@@ -174,6 +224,7 @@ cc_background_item_get_frame_thumbnail (CcBackgroundItem             *item,
                                         GnomeDesktopThumbnailFactory *thumbs,
                                         int                           width,
                                         int                           height,
+                                        int                           scale_factor,
                                         int                           frame,
                                         gboolean                      force_size)
 {
@@ -214,11 +265,7 @@ cc_background_item_get_frame_thumbnail (CcBackgroundItem             *item,
         if (pixbuf != NULL
             && frame != -2
             && gnome_bg_changes_with_time (item->priv->bg)) {
-                GEmblem *emblem;
-
-                emblem = get_slideshow_icon ();
-                icon = g_emblemed_icon_new (G_ICON (pixbuf), emblem);
-                g_object_unref (emblem);
+                icon = get_emblemed_pixbuf (item, pixbuf, scale_factor);
                 g_object_unref (pixbuf);
         } else {
                 icon = G_ICON (pixbuf);
@@ -241,9 +288,10 @@ GIcon *
 cc_background_item_get_thumbnail (CcBackgroundItem             *item,
                                   GnomeDesktopThumbnailFactory *thumbs,
                                   int                           width,
-                                  int                           height)
+                                  int                           height,
+                                  int                           scale_factor)
 {
-        return cc_background_item_get_frame_thumbnail (item, thumbs, width, height, -1, FALSE);
+        return cc_background_item_get_frame_thumbnail (item, thumbs, width, height, scale_factor, -1, FALSE);
 }
 
 static void
@@ -801,6 +849,8 @@ cc_background_item_finalize (GObject *object)
         if (item->priv->bg != NULL)
                 g_object_unref (item->priv->bg);
 
+        g_clear_object (&item->priv->slideshow_emblem);
+
         G_OBJECT_CLASS (cc_background_item_parent_class)->finalize (object);
 }
 
diff --git a/panels/background/cc-background-item.h b/panels/background/cc-background-item.h
index 401ad8a..633a719 100644
--- a/panels/background/cc-background-item.h
+++ b/panels/background/cc-background-item.h
@@ -73,11 +73,13 @@ gboolean           cc_background_item_changes_with_time   (CcBackgroundItem
 GIcon     *        cc_background_item_get_thumbnail       (CcBackgroundItem             *item,
                                                            GnomeDesktopThumbnailFactory *thumbs,
                                                            int                           width,
-                                                           int                           height);
+                                                           int                           height,
+                                                           int                           scale_factor);
 GIcon     *        cc_background_item_get_frame_thumbnail (CcBackgroundItem             *item,
                                                            GnomeDesktopThumbnailFactory *thumbs,
                                                            int                           width,
                                                            int                           height,
+                                                           int                           scale_factor,
                                                            int                           frame,
                                                            gboolean                      force_size);
 
diff --git a/panels/background/cc-background-panel.c b/panels/background/cc-background-panel.c
index 95eca6b..77c623d 100644
--- a/panels/background/cc-background-panel.c
+++ b/panels/background/cc-background-panel.c
@@ -213,6 +213,7 @@ update_display_preview (CcBackgroundPanel *panel,
   GtkAllocation allocation;
   const gint preview_width = 309;
   const gint preview_height = 168;
+  gint scale_factor;
   GdkPixbuf *pixbuf;
   GIcon *icon;
   cairo_t *cr;
@@ -222,10 +223,12 @@ update_display_preview (CcBackgroundPanel *panel,
   if (!current_background)
     return;
 
+  scale_factor = gtk_widget_get_scale_factor (widget);
   icon = cc_background_item_get_frame_thumbnail (current_background,
                                                  priv->thumb_factory,
                                                  preview_width,
                                                  preview_height,
+                                                 scale_factor,
                                                  -2, TRUE);
   pixbuf = GDK_PIXBUF (icon);
 


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