static void
load_wallpapers (gchar              *key,
                 CcBackgroundItem   *item,
                 BgWallpapersSource *source)
{
  BgWallpapersSourcePrivate *priv = source->priv;
  GtkTreeIter iter;
  GIcon *pixbuf;
  GtkListStore *store = bg_source_get_liststore (BG_SOURCE (source));
  gboolean deleted;

  g_object_get (G_OBJECT (item), "is-deleted", &deleted, NULL);

  if (deleted)
    return;

  gtk_list_store_append (store, &iter);

  pixbuf = cc_background_item_get_thumbnail (item, priv->thumb_factory,
					     THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);

  gtk_list_store_set (store, &iter,
                      0, pixbuf,
                      1, g_object_ref (item),
                      2, cc_background_item_get_name (item),
                      -1);

  if (pixbuf)
    g_object_unref (pixbuf);
}
Beispiel #2
0
static void
bg_source_constructed (GObject *object)
{
  G_OBJECT_CLASS (bg_source_parent_class)->constructed (object);

  bg_source_calculate_thumbnail_dimensions (BG_SOURCE (object));
}
static void
remove_button_clicked (GtkButton         *button,
		       CcBackgroundPanel *panel)
{
  CcBackgroundItem *item;
  GtkListStore *store;
  GtkTreePath *path;
  CcBackgroundPanelPrivate *priv;

  priv = panel->priv;

  item = get_selected_item (panel);
  if (item == NULL)
    g_assert_not_reached ();

  bg_pictures_source_remove (panel->priv->pictures_source, item);
  g_object_unref (item);

  /* Are there any items left in the pictures tree store? */
  store = bg_source_get_liststore (BG_SOURCE (panel->priv->pictures_source));
  if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL) == 0)
    gtk_combo_box_set_active (GTK_COMBO_BOX (WID ("sources-combobox")), SOURCE_WALLPAPERS);

  path = gtk_tree_path_new_from_string ("0");
  gtk_icon_view_select_path (GTK_ICON_VIEW (WID ("backgrounds-iconview")), path);
  gtk_tree_path_free (path);
}
static void
picture_scaled (GObject *source_object,
                GAsyncResult *res,
                gpointer user_data)
{
  BgPicturesSource *bg_source;
  CcBackgroundItem *item;
  GError *error = NULL;
  GdkPixbuf *pixbuf;
  const char *software;
  const char *uri;
  GtkTreeIter iter;
  GtkListStore *store;

  pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
  if (pixbuf == NULL)
    {
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        g_warning ("Failed to load image: %s", error->message);

      g_error_free (error);
      return;
    }

  /* since we were not cancelled, we can now cast user_data
   * back to BgPicturesSource.
   */
  bg_source = BG_PICTURES_SOURCE (user_data);
  store = bg_source_get_liststore (BG_SOURCE (bg_source));
  item = g_object_get_data (source_object, "item");
  uri = cc_background_item_get_uri (item);

  /* Ignore screenshots */
  software = gdk_pixbuf_get_option (pixbuf, "tEXt::Software");
  if (software != NULL &&
      g_str_equal (software, "gnome-screenshot"))
    {
      g_debug ("Ignored URL '%s' as it's a screenshot from gnome-screenshot",
               cc_background_item_get_uri (item));
      g_object_unref (pixbuf);
      g_object_unref (item);
      return;
    }

  cc_background_item_load (item, NULL);

  /* insert the item into the liststore */
  gtk_list_store_insert_with_values (store, &iter, -1,
                                     0, pixbuf,
                                     1, item,
                                     -1);

  g_hash_table_insert (bg_source->priv->known_items,
                       bg_pictures_source_get_unique_filename (uri),
                       GINT_TO_POINTER (TRUE));


  g_object_unref (pixbuf);
}
static void
picture_opened_for_read (GObject *source_object,
                         GAsyncResult *res,
                         gpointer user_data)
{
  BgPicturesSource *bg_source;
  CcBackgroundItem *item;
  GFileInputStream *stream;
  GError *error = NULL;
  gint thumbnail_height;
  gint thumbnail_width;

  item = g_object_get_data (source_object, "item");
  stream = g_file_read_finish (G_FILE (source_object), res, &error);
  if (stream == NULL)
    {
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        {
          char *filename = g_file_get_path (G_FILE (source_object));
          g_warning ("Failed to load picture '%s': %s", filename, error->message);
          remove_placeholder (BG_PICTURES_SOURCE (user_data), item);
          g_free (filename);
        }

      g_error_free (error);
      return;
    }

  /* since we were not cancelled, we can now cast user_data
   * back to BgPicturesSource.
   */
  bg_source = BG_PICTURES_SOURCE (user_data);

  thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (bg_source));
  thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (bg_source));
  g_object_set_data_full (G_OBJECT (stream), "item", g_object_ref (item), g_object_unref);
  gdk_pixbuf_new_from_stream_at_scale_async (G_INPUT_STREAM (stream),
                                             thumbnail_width, thumbnail_height,
                                             TRUE,
                                             bg_source->priv->cancellable,
                                             picture_scaled, bg_source);
  g_object_unref (stream);
}
Beispiel #6
0
static void
bg_source_dispose (GObject *object)
{
  BgSource *source = BG_SOURCE (object);
  BgSourcePrivate *priv = bg_source_get_instance_private (source);

  g_clear_object (&priv->store);

  G_OBJECT_CLASS (bg_source_parent_class)->dispose (object);
}
static void
bg_source_dispose (GObject *object)
{
    BgSourcePrivate *priv = BG_SOURCE (object)->priv;

    if (priv->store)
    {
        g_object_unref (priv->store);
        priv->store = NULL;
    }

    G_OBJECT_CLASS (bg_source_parent_class)->dispose (object);
}
gboolean
bg_colors_source_add (BgColorsSource       *self,
                      GdkRGBA              *rgba,
                      GtkTreeRowReference **ret_row_ref)
{
  GnomeDesktopThumbnailFactory *thumb_factory;
  GtkListStore *store;
  gchar *c;
  char **colors;
  gsize len;
  GKeyFile *keyfile;
  GError *error = NULL;
  char *path;

  c = g_strdup_printf ("#%02x%02x%02x",
                       (int)(255*rgba->red),
                       (int)(255*rgba->green),
                       (int)(255*rgba->blue));

  thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
  store = bg_source_get_liststore (BG_SOURCE (self));

  bg_colors_source_add_color (self, thumb_factory, store, c, ret_row_ref);

  g_object_unref (thumb_factory);

  /* Save to the keyfile */
  path = get_colors_dir ();
  g_mkdir_with_parents (path, 0700);
  g_free (path);

  path = get_colors_path ();
  colors = NULL;
  len = 0;

  keyfile = g_key_file_new ();
  if (g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL))
    colors = g_key_file_get_string_list (keyfile, "Colors", "custom-colors", &len, NULL);

  if (len == 0 && colors != NULL)
    {
      g_strfreev (colors);
      colors = NULL;
    }

  if (colors == NULL)
    {
      colors = g_new0 (char *, 2);
      colors[0] = c;
      len = 1;
    }
static void
bg_colors_source_init (BgColorsSource *self)
{
  GnomeDesktopThumbnailFactory *thumb_factory;
  guint i;
  GtkListStore *store;

  store = bg_source_get_liststore (BG_SOURCE (self));

  thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);

  for (i = 0; i < G_N_ELEMENTS (items); i++)
    {
      CcBackgroundItemFlags flags;
      CcBackgroundItem *item;
      GIcon *pixbuf;

      item = cc_background_item_new (NULL);
      flags = CC_BACKGROUND_ITEM_HAS_PCOLOR |
	      CC_BACKGROUND_ITEM_HAS_SCOLOR |
	      CC_BACKGROUND_ITEM_HAS_SHADING |
	      CC_BACKGROUND_ITEM_HAS_PLACEMENT |
	      CC_BACKGROUND_ITEM_HAS_URI;
      /* It does have a URI, it's "none" */

      g_object_set (G_OBJECT (item),
                    "uri", "file:///" DATADIR "/cinnamon-control-center/pixmaps/noise-texture-light.png",
		    "primary-color", items[i].pcolor,
		    "secondary-color", items[i].pcolor,
		    "shading", items[i].type,
		    "placement", G_DESKTOP_BACKGROUND_STYLE_WALLPAPER,
		    "flags", flags,
		    NULL);
      cc_background_item_load (item, NULL);

      /* insert the item into the liststore */
      pixbuf = cc_background_item_get_thumbnail (item,
						 thumb_factory,
						 THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
      gtk_list_store_insert_with_values (store, NULL, 0,
                                         0, pixbuf,
                                         1, item,
                                         -1);

      g_object_unref (pixbuf);
    }

  g_object_unref (thumb_factory);
}
static void
add_custom_wallpaper (CcBackgroundPanel *panel,
		      const char        *uri)
{
  GtkListStore *store;

  store = bg_source_get_liststore (BG_SOURCE (panel->priv->pictures_source));
  g_signal_connect (G_OBJECT (store), "row-inserted",
		    G_CALLBACK (row_inserted), panel);

  if (bg_pictures_source_add (panel->priv->pictures_source, uri) == FALSE) {
    g_signal_handlers_disconnect_by_func (G_OBJECT (store), G_CALLBACK (row_inserted), panel);
    return;
  }

  /* Wait for the item to get added */
}
static void
bg_source_get_property (GObject    *object,
                        guint       property_id,
                        GValue     *value,
                        GParamSpec *pspec)
{
    BgSource *source = BG_SOURCE (object);

    switch (property_id)
    {
    case PROP_LISTSTORE:
        g_value_set_object (value, bg_source_get_liststore (source));
        break;

    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}
Beispiel #12
0
static void
bg_source_set_property (GObject      *object,
                        guint         property_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
  BgSource *source = BG_SOURCE (object);
  BgSourcePrivate *priv = bg_source_get_instance_private (source);

  switch (property_id)
    {
    case PROP_WINDOW:
      priv->window = GTK_WIDGET (g_value_get_object (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}
static void
remove_placeholder (BgPicturesSource *bg_source, CcBackgroundItem *item)
{
  GtkListStore *store;
  GtkTreeIter iter;
  GtkTreePath *path;
  GtkTreeRowReference *row_ref;

  store = bg_source_get_liststore (BG_SOURCE (bg_source));
  row_ref = g_object_get_data (G_OBJECT (item), "row-ref");
  if (row_ref == NULL)
    return;

  path = gtk_tree_row_reference_get_path (row_ref);
  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
    return;

  gtk_list_store_remove (store, &iter);
}
gboolean
bg_pictures_source_remove (BgPicturesSource *bg_source,
			   CcBackgroundItem *item)
{
  GtkTreeModel *model;
  GtkTreeIter iter;
  gboolean cont;
  const char *uri;
  gboolean retval;

  retval = FALSE;
  model = GTK_TREE_MODEL (bg_source_get_liststore (BG_SOURCE (bg_source)));
  uri = cc_background_item_get_uri (item);

  cont = gtk_tree_model_get_iter_first (model, &iter);
  while (cont)
    {
      CcBackgroundItem *tmp_item;
      const char *tmp_uri;

      gtk_tree_model_get (model, &iter, 1, &tmp_item, -1);
      tmp_uri = cc_background_item_get_uri (tmp_item);
      if (g_str_equal (tmp_uri, uri))
        {
          GFile *file;
          char *uuid;

          file = g_file_new_for_uri (uri);
          uuid = g_file_get_basename (file);
          g_hash_table_insert (bg_source->priv->known_items,
			       uuid, NULL);

          gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
          retval = TRUE;
          g_file_trash (file, NULL, NULL);
          g_object_unref (file);
          break;
        }
      g_object_unref (tmp_item);
      cont = gtk_tree_model_iter_next (model, &iter);
    }
  return retval;
}
static void
row_inserted (GtkTreeModel      *tree_model,
	      GtkTreePath       *path,
	      GtkTreeIter       *iter,
	      CcBackgroundPanel *panel)
{
  GtkListStore *store;
  CcBackgroundPanelPrivate *priv;

  priv = panel->priv;

  store = bg_source_get_liststore (BG_SOURCE (panel->priv->pictures_source));
  g_signal_handlers_disconnect_by_func (G_OBJECT (store), G_CALLBACK (row_inserted), panel);

  /* Change source */
  gtk_combo_box_set_active (GTK_COMBO_BOX (WID ("sources-combobox")), SOURCE_PICTURES);

  /* And select the newly added item */
  gtk_icon_view_select_path (GTK_ICON_VIEW (WID ("backgrounds-iconview")), path);
}
static void
bg_colors_source_constructed (GObject *object)
{
  BgColorsSource *self = BG_COLORS_SOURCE (object);
  GnomeDesktopThumbnailFactory *thumb_factory;
  guint i;
  GtkListStore *store;
  GKeyFile *keyfile;
  char *path;

  G_OBJECT_CLASS (bg_colors_source_parent_class)->constructed (object);

  store = bg_source_get_liststore (BG_SOURCE (self));
  thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);

  for (i = 0; i < G_N_ELEMENTS (items); i++)
    {
      bg_colors_source_add_color (self, thumb_factory, store, items[i].pcolor, NULL);
    }

  keyfile = g_key_file_new ();
  path = get_colors_path ();
  if (g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL))
    {
      char **colors;

      colors = g_key_file_get_string_list (keyfile, "Colors", "custom-colors", NULL, NULL);
      for (i = 0; colors != NULL && colors[i] != NULL; i++)
        {
          bg_colors_source_add_color (self, thumb_factory, store, colors[i], NULL);
        }

      if (colors)
        g_strfreev (colors);
    }
  g_key_file_unref (keyfile);
  g_free (path);

  g_object_unref (thumb_factory);
}
static void
picture_scaled (GObject *source_object,
                GAsyncResult *res,
                gpointer user_data)
{
  BgPicturesSource *bg_source = BG_PICTURES_SOURCE (user_data);
  CcBackgroundItem *item;
  GError *error = NULL;
  GdkPixbuf *pixbuf;
  const char *source_url;

  GtkTreeIter iter;
  GtkListStore *store;

  store = bg_source_get_liststore (BG_SOURCE (bg_source));
  item = g_object_get_data (source_object, "item");

  pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
  if (pixbuf == NULL)
    {
      g_warning ("Failed to load image: %s", error->message);
      g_error_free (error);
      g_object_unref (item);
      return;
    }

  /* insert the item into the liststore */
  gtk_list_store_insert_with_values (store, &iter, 0,
                                     0, pixbuf,
                                     1, item,
                                     -1);
  source_url = cc_background_item_get_source_url (item);
  if (source_url != NULL)
    {
      g_hash_table_insert (bg_source->priv->known_items,
			   bg_pictures_source_get_unique_filename (source_url), GINT_TO_POINTER (TRUE));
    }
  else
    {
      char *cache_path;
      GFile *file, *parent, *dir;

      cache_path = bg_pictures_source_get_cache_path ();
      dir = g_file_new_for_path (cache_path);
      g_free (cache_path);

      file = g_file_new_for_uri (cc_background_item_get_uri (item));
      parent = g_file_get_parent (file);

      if (g_file_equal (parent, dir))
        {
          char *basename;
          basename = g_file_get_basename (file);
	  g_hash_table_insert (bg_source->priv->known_items,
			       basename, GINT_TO_POINTER (TRUE));
	}
      g_object_unref (file);
      g_object_unref (parent);
    }

  g_object_unref (pixbuf);
}
static void
bg_pictures_source_init (BgPicturesSource *self)
{
  const gchar *pictures_path;
  BgPicturesSourcePrivate *priv;
  GFile *dir;
  char *cache_path;
  GtkListStore *store;

  priv = self->priv = PICTURES_SOURCE_PRIVATE (self);

  priv->cancellable = g_cancellable_new ();
  priv->known_items = g_hash_table_new_full (g_str_hash,
					     g_str_equal,
					     (GDestroyNotify) g_free,
					     NULL);

  pictures_path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
  if (pictures_path == NULL)
    pictures_path = g_get_home_dir ();

  g_mkdir_with_parents (pictures_path, USER_DIR_MODE);

  dir = g_file_new_for_path (pictures_path);
  g_file_enumerate_children_async (dir,
				   ATTRIBUTES,
                                   G_FILE_QUERY_INFO_NONE,
                                   G_PRIORITY_LOW, priv->cancellable,
                                   dir_enum_async_ready, self);

  priv->picture_dir_monitor = g_file_monitor_directory (dir,
                                                        G_FILE_MONITOR_NONE,
                                                        priv->cancellable,
                                                        NULL);

  if (priv->picture_dir_monitor)
    g_signal_connect (priv->picture_dir_monitor,
                      "changed",
                      G_CALLBACK (files_changed_cb),
                      self);

  g_object_unref (dir);

  cache_path = bg_pictures_source_get_cache_path ();
  g_mkdir_with_parents (cache_path, USER_DIR_MODE);

  dir = g_file_new_for_path (cache_path);
  g_file_enumerate_children_async (dir,
				   ATTRIBUTES,
                                   G_FILE_QUERY_INFO_NONE,
                                   G_PRIORITY_LOW, priv->cancellable,
                                   dir_enum_async_ready, self);
  g_free (cache_path);

  priv->cache_dir_monitor = g_file_monitor_directory (dir,
                                                      G_FILE_MONITOR_NONE,
                                                      priv->cancellable,
                                                      NULL);
  if (priv->cache_dir_monitor)
    g_signal_connect (priv->cache_dir_monitor,
                      "changed",
                      G_CALLBACK (files_changed_cb),
                      self);

  g_object_unref (dir);

  priv->grl_miner = cc_background_grilo_miner_new ();
  g_signal_connect_swapped (priv->grl_miner, "media-found", G_CALLBACK (media_found_cb), self);
  cc_background_grilo_miner_start (priv->grl_miner);

  priv->thumb_factory =
    gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);

  store = bg_source_get_liststore (BG_SOURCE (self));

  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
                                   1,
                                   (GtkTreeIterCompareFunc)sort_func,
                                   self,
                                   NULL);

  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
                                        1,
                                        GTK_SORT_ASCENDING);
}
static gboolean
add_single_file (BgPicturesSource     *bg_source,
                 GFile                *file,
                 const gchar          *content_type,
                 guint64               mtime,
                 GtkTreeRowReference **ret_row_ref)
{
  CcBackgroundItem *item = NULL;
  CcBackgroundItemFlags flags = 0;
  GtkListStore *store;
  GtkTreeIter iter;
  GtkTreePath *path = NULL;
  GtkTreeRowReference *row_ref = NULL;
  cairo_surface_t *surface = NULL;
  char *source_uri = NULL;
  char *uri = NULL;
  gboolean needs_download;
  gboolean retval = FALSE;
  GFile *pictures_dir, *cache_dir;
  GrlMedia *media;

  /* find png and jpeg files */
  if (!content_type)
    goto out;
  if (!in_content_types (content_type))
    goto out;

  /* create a new CcBackgroundItem */
  uri = g_file_get_uri (file);

  pictures_dir = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
  cache_dir = bg_pictures_source_get_cache_file ();
  needs_download = !g_file_has_parent (file, pictures_dir) &&
          !g_file_has_parent (file, cache_dir);
  g_object_unref (pictures_dir);
  g_object_unref (cache_dir);

  if (!needs_download)
    {
      source_uri = g_strdup (uri);
      flags |= CC_BACKGROUND_ITEM_HAS_URI;
    }
  else
    {
      source_uri = uri;
      uri = NULL;
    }

  item = cc_background_item_new (uri);
  flags |= CC_BACKGROUND_ITEM_HAS_SHADING | CC_BACKGROUND_ITEM_HAS_PLACEMENT;
  g_object_set (G_OBJECT (item),
		"flags", flags,
		"shading", G_DESKTOP_BACKGROUND_SHADING_SOLID,
		"placement", G_DESKTOP_BACKGROUND_STYLE_ZOOM,
                "modified", mtime,
                "needs-download", needs_download,
                "source-url", source_uri,
		NULL);

  if (!ret_row_ref && in_screenshot_types (content_type))
    goto read_file;

  surface = get_content_loading_icon (BG_SOURCE (bg_source));
  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, surface,
                                     1, item,
                                     -1);

  path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
  row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
  g_object_set_data_full (G_OBJECT (item), "row-ref", row_ref, (GDestroyNotify) gtk_tree_row_reference_free);


 read_file:

  media = g_object_get_data (G_OBJECT (file), "grl-media");
  if (media == NULL)
    {
      g_object_set_data_full (G_OBJECT (file), "item", g_object_ref (item), g_object_unref);
      g_file_read_async (file, G_PRIORITY_DEFAULT,
                         bg_source->priv->cancellable,
                         picture_opened_for_read, bg_source);
    }
  else
    {
      GFile *native_file;
      GFile *thumbnail_file = NULL;
      gchar *native_dir;
      gchar *native_path;
      const gchar *title;
      const gchar *thumbnail_uri;

      title = grl_media_get_title (media);
      g_object_set (G_OBJECT (item), "name", title, NULL);

      thumbnail_uri = grl_media_get_thumbnail (media);
      thumbnail_file = g_file_new_for_uri (thumbnail_uri);

      native_path = gnome_desktop_thumbnail_path_for_uri (source_uri, GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
      native_file = g_file_new_for_path (native_path);

      native_dir = g_path_get_dirname (native_path);
      g_mkdir_with_parents (native_dir, USER_DIR_MODE);

      g_object_set_data_full (G_OBJECT (thumbnail_file), "item", g_object_ref (item), g_object_unref);
      g_object_set_data_full (G_OBJECT (thumbnail_file),
                              "native-file",
                              g_object_ref (native_file),
                              g_object_unref);
      g_file_copy_async (thumbnail_file,
                         native_file,
                         G_FILE_COPY_ALL_METADATA,
                         G_PRIORITY_DEFAULT,
                         bg_source->priv->cancellable,
                         NULL,
                         NULL,
                         picture_copied_for_read,
                         bg_source);

      g_clear_object (&thumbnail_file);
      g_object_unref (native_file);
      g_free (native_dir);
      g_free (native_path);
    }

  retval = TRUE;

 out:
  if (ret_row_ref)
    {
      if (row_ref && retval != FALSE)
        *ret_row_ref = gtk_tree_row_reference_copy (row_ref);
      else
        *ret_row_ref = NULL;
    }
  gtk_tree_path_free (path);
  g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
  g_clear_object (&item);
  g_object_unref (file);
  g_free (source_uri);
  g_free (uri);
  return retval;
}
static void
picture_scaled (GObject *source_object,
                GAsyncResult *res,
                gpointer user_data)
{
  BgPicturesSource *bg_source;
  CcBackgroundItem *item;
  GError *error = NULL;
  GdkPixbuf *pixbuf = NULL;
  const char *software;
  const char *uri;
  GtkTreeIter iter;
  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);
  if (pixbuf == NULL)
    {
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        {
          g_warning ("Failed to load image: %s", error->message);
          remove_placeholder (BG_PICTURES_SOURCE (user_data), item);
        }

      g_error_free (error);
      goto out;
    }

  /* since we were not cancelled, we can now cast user_data
   * back to BgPicturesSource.
   */
  bg_source = BG_PICTURES_SOURCE (user_data);
  store = bg_source_get_liststore (BG_SOURCE (bg_source));
  uri = cc_background_item_get_uri (item);
  if (uri == NULL)
    uri = cc_background_item_get_source_url (item);

  /* Ignore screenshots */
  software = gdk_pixbuf_get_option (pixbuf, "tEXt::Software");
  if (software != NULL &&
      g_str_equal (software, "gnome-screenshot"))
    {
      g_debug ("Ignored URL '%s' as it's a screenshot from gnome-screenshot", uri);
      remove_placeholder (BG_PICTURES_SOURCE (user_data), item);
      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");
  if (row_ref == NULL)
    {
      /* insert the item into the liststore if it did not exist */
      gtk_list_store_insert_with_values (store, NULL, -1,
                                         0, surface,
                                         1, item,
                                         -1);
    }
  else
    {
      path = gtk_tree_row_reference_get_path (row_ref);
      if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
        {
          /* otherwise update the thumbnail */
          gtk_list_store_set (store, &iter,
                              0, surface,
                              -1);
        }
    }

  g_hash_table_insert (bg_source->priv->known_items,
                       bg_pictures_source_get_unique_filename (uri),
                       GINT_TO_POINTER (TRUE));


 out:
  g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
  g_clear_object (&pixbuf);
}
static void
picture_scaled (GObject *source_object,
                GAsyncResult *res,
                gpointer user_data)
{
  BgPicturesSource *bg_source;
  CcBackgroundItem *item;
  GError *error = NULL;
  GdkPixbuf *pixbuf;
  const char *source_url;
  const char *software;
  GtkTreeIter iter;
  GtkListStore *store;

  pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
  if (pixbuf == NULL)
    {
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        g_warning ("Failed to load image: %s", error->message);

      g_error_free (error);
      return;
    }

  /* since we were not cancelled, we can now cast user_data
   * back to BgPicturesSource.
   */
  bg_source = BG_PICTURES_SOURCE (user_data);
  store = bg_source_get_liststore (BG_SOURCE (bg_source));
  item = g_object_get_data (source_object, "item");

  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
                                   1,
                                   (GtkTreeIterCompareFunc)sort_func,
                                   bg_source,
                                   NULL);

  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
                                        1,
                                        GTK_SORT_ASCENDING);

  /* Ignore screenshots */
  software = gdk_pixbuf_get_option (pixbuf, "tEXt::Software");
  if (software != NULL &&
      g_str_equal (software, "gnome-screenshot"))
    {
      g_debug ("Ignored URL '%s' as it's a screenshot from gnome-screenshot",
               cc_background_item_get_uri (item));
      g_object_unref (pixbuf);
      g_object_unref (item);
      return;
    }

  cc_background_item_load (item, NULL);

  /* insert the item into the liststore */
  gtk_list_store_insert_with_values (store, &iter, 0,
                                     0, pixbuf,
                                     1, item,
                                     -1);
  source_url = cc_background_item_get_source_url (item);
  if (source_url != NULL)
    {
      g_hash_table_insert (bg_source->priv->known_items,
			   bg_pictures_source_get_unique_filename (source_url), GINT_TO_POINTER (TRUE));
    }
  else
    {
      char *cache_path;
      GFile *file, *parent, *dir;

      cache_path = bg_pictures_source_get_cache_path ();
      dir = g_file_new_for_path (cache_path);
      g_free (cache_path);

      file = g_file_new_for_uri (cc_background_item_get_uri (item));
      parent = g_file_get_parent (file);

      if (g_file_equal (parent, dir))
        {
          char *basename;
          basename = g_file_get_basename (file);
	  g_hash_table_insert (bg_source->priv->known_items,
			       basename, GINT_TO_POINTER (TRUE));
	}
      g_object_unref (file);
      g_object_unref (parent);
    }

  g_object_unref (pixbuf);
}
static void
bg_colors_source_add_color (BgColorsSource               *self,
                            GnomeDesktopThumbnailFactory *thumb_factory,
                            GtkListStore                 *store,
                            const char                   *color,
                            GtkTreeRowReference         **ret_row_ref)
{
  CcBackgroundItemFlags flags;
  CcBackgroundItem *item;
  GdkPixbuf *pixbuf;
  cairo_surface_t *surface;
  int scale_factor;
  int thumbnail_height, thumbnail_width;
  GtkTreeIter iter;

  thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (self));
  thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (self));

  item = cc_background_item_new (NULL);
  flags = CC_BACKGROUND_ITEM_HAS_PCOLOR |
          CC_BACKGROUND_ITEM_HAS_SCOLOR |
          CC_BACKGROUND_ITEM_HAS_SHADING |
          CC_BACKGROUND_ITEM_HAS_PLACEMENT |
          CC_BACKGROUND_ITEM_HAS_URI;
  /* It does have a URI, it's "none" */

  g_object_set (G_OBJECT (item),
                "uri", "file:///" DATADIR "/gnome-control-center/pixmaps/noise-texture-light.png",
                "primary-color", color,
                "secondary-color", color,
                "shading", G_DESKTOP_BACKGROUND_SHADING_SOLID,
                "placement", G_DESKTOP_BACKGROUND_STYLE_WALLPAPER,
                "flags", flags,
                NULL);
  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,
                                             scale_factor);
  surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL);
  gtk_list_store_insert_with_values (store, &iter, 0,
                                     0, surface,
                                     1, item,
                                     -1);

  if (ret_row_ref)
    {
      GtkTreePath *path;

      path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
      *ret_row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
      gtk_tree_path_free (path);
    }

  cairo_surface_destroy (surface);
  g_object_unref (pixbuf);
  g_object_unref (item);
}