diff options
Diffstat (limited to 'panels/background/bg-pictures-source.c')
-rw-r--r-- | panels/background/bg-pictures-source.c | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/panels/background/bg-pictures-source.c b/panels/background/bg-pictures-source.c new file mode 100644 index 0000000..3a3027b --- /dev/null +++ b/panels/background/bg-pictures-source.c @@ -0,0 +1,855 @@ +/* bg-pictures-source.c */ +/* + * Copyright (C) 2010 Intel, Inc + * + * 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 of the License, 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, see <http://www.gnu.org/licenses/>. + * + * Author: Thomas Wood <thomas.wood@intel.com> + * + */ + +#include <config.h> + +#include "bg-pictures-source.h" + +#include "cc-background-grilo-miner.h" +#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> +#include <gdesktop-enums.h> + +#define ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_NAME "," \ + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \ + G_FILE_ATTRIBUTE_TIME_MODIFIED + +struct _BgPicturesSource +{ + BgSource parent_instance; + + GCancellable *cancellable; + + CcBackgroundGriloMiner *grl_miner; + + GFileMonitor *picture_dir_monitor; + GFileMonitor *cache_dir_monitor; + + GHashTable *known_items; +}; + +G_DEFINE_TYPE (BgPicturesSource, bg_pictures_source, BG_TYPE_SOURCE) + +const char * const content_types[] = { + "image/png", + "image/jp2", + "image/jpeg", + "image/bmp", + "image/svg+xml", + "image/x-portable-anymap", + NULL +}; + +const char * const screenshot_types[] = { + "image/png", + NULL +}; + +static char *bg_pictures_source_get_unique_filename (const char *uri); + +static void picture_opened_for_read (GObject *source_object, GAsyncResult *res, gpointer user_data); + +static void +bg_pictures_source_dispose (GObject *object) +{ + BgPicturesSource *source = BG_PICTURES_SOURCE (object); + + if (source->cancellable) + { + g_cancellable_cancel (source->cancellable); + g_clear_object (&source->cancellable); + } + + g_clear_object (&source->grl_miner); + + G_OBJECT_CLASS (bg_pictures_source_parent_class)->dispose (object); +} + +static void +bg_pictures_source_finalize (GObject *object) +{ + BgPicturesSource *bg_source = BG_PICTURES_SOURCE (object); + + g_clear_pointer (&bg_source->known_items, g_hash_table_destroy); + + g_clear_object (&bg_source->picture_dir_monitor); + g_clear_object (&bg_source->cache_dir_monitor); + + G_OBJECT_CLASS (bg_pictures_source_parent_class)->finalize (object); +} + +static void +bg_pictures_source_class_init (BgPicturesSourceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = bg_pictures_source_dispose; + object_class->finalize = bg_pictures_source_finalize; +} + +static void +remove_placeholder (BgPicturesSource *bg_source, + CcBackgroundItem *item) +{ + GListStore *store; + guint i; + + store = bg_source_get_liststore (BG_SOURCE (bg_source)); + + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++) + { + g_autoptr(CcBackgroundItem) item_n = NULL; + + item_n = g_list_model_get_item (G_LIST_MODEL (store), i); + + if (item_n == item) + { + g_list_store_remove (store, i); + break; + } + } +} + +static gboolean +picture_needs_rotation (GdkPixbuf *pixbuf) +{ + const gchar *str; + + str = gdk_pixbuf_get_option (pixbuf, "orientation"); + if (str == NULL) + return FALSE; + + if (*str == '5' || *str == '6' || *str == '7' || *str == '8') + return TRUE; + + return FALSE; +} + +static GdkPixbuf * +swap_rotated_pixbuf (GdkPixbuf *pixbuf) +{ + GdkPixbuf *tmp_pixbuf; + + tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf); + if (tmp_pixbuf == NULL) + return pixbuf; + + g_object_unref (pixbuf); + return tmp_pixbuf; +} + +static int +sort_func (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + CcBackgroundItem *item_a; + CcBackgroundItem *item_b; + guint64 modified_a; + guint64 modified_b; + int retval; + + item_a = (CcBackgroundItem *) a; + item_b = (CcBackgroundItem *) b; + modified_a = cc_background_item_get_modified (item_a); + modified_b = cc_background_item_get_modified (item_b); + + retval = modified_b - modified_a; + + return retval; +} + +static void +picture_scaled (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + CcBackgroundItem *item; + g_autoptr(GError) error = NULL; + g_autoptr(GdkPixbuf) pixbuf = NULL; + const char *software; + const char *uri; + GListStore *store; + cairo_surface_t *surface = NULL; + int scale_factor; + gboolean rotation_applied; + + 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); + } + + 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)); + 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); + return; + } + + /* Process embedded orientation */ + rotation_applied = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "rotation-applied")); + + if (!rotation_applied && picture_needs_rotation (pixbuf)) + { + /* the width and height of pixbuf we requested are wrong for EXIF + * orientations 5, 6, 7 and 8. the file has to be reloaded. */ + g_autoptr(GFile) file = NULL; + + file = g_file_new_for_uri (uri); + g_object_set_data (G_OBJECT (item), "needs-rotation", GINT_TO_POINTER (TRUE)); + g_object_set_data_full (G_OBJECT (file), "item", g_object_ref (item), g_object_unref); + g_file_read_async (G_FILE (file), G_PRIORITY_DEFAULT, + bg_source->cancellable, + picture_opened_for_read, bg_source); + return; + } + + pixbuf = swap_rotated_pixbuf (pixbuf); + + 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); + + /* insert the item into the liststore */ + g_list_store_insert_sorted (store, item, sort_func, bg_source); + + g_hash_table_insert (bg_source->known_items, + bg_pictures_source_get_unique_filename (uri), + GINT_TO_POINTER (TRUE)); + + g_clear_pointer (&surface, cairo_surface_destroy); +} + +static void +picture_opened_for_read (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + CcBackgroundItem *item; + g_autoptr(GFileInputStream) stream = NULL; + g_autoptr(GError) error = NULL; + gint thumbnail_height; + gint thumbnail_width; + gboolean needs_rotation; + + 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)) + { + g_autofree gchar *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); + } + + return; + } + + /* since we were not cancelled, we can now cast user_data + * back to BgPicturesSource. + */ + bg_source = BG_PICTURES_SOURCE (user_data); + + needs_rotation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "needs-rotation")); + if (needs_rotation) + { + /* swap width and height for EXIF orientations that need it */ + thumbnail_width = bg_source_get_thumbnail_height (BG_SOURCE (bg_source)); + thumbnail_height = bg_source_get_thumbnail_width (BG_SOURCE (bg_source)); + g_object_set_data (G_OBJECT (item), "rotation-applied", GINT_TO_POINTER (TRUE)); + } + else + { + thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (bg_source)); + thumbnail_height = bg_source_get_thumbnail_height (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->cancellable, + picture_scaled, bg_source); +} + +static void +picture_copied_for_read (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + CcBackgroundItem *item; + g_autoptr(GError) error = NULL; + GFile *thumbnail_file = G_FILE (source_object); + GFile *native_file; + + if (!g_file_copy_finish (thumbnail_file, res, &error)) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + { + g_autofree gchar *uri = NULL; + + uri = g_file_get_uri (thumbnail_file); + g_warning ("Failed to download '%s': %s", uri, error->message); + return; + } + } + + bg_source = BG_PICTURES_SOURCE (user_data); + + native_file = g_object_get_data (G_OBJECT (thumbnail_file), "native-file"); + item = g_object_get_data (G_OBJECT (thumbnail_file), "item"); + g_object_set_data_full (G_OBJECT (native_file), "item", g_object_ref (item), g_object_unref); + g_file_read_async (native_file, + G_PRIORITY_DEFAULT, + bg_source->cancellable, + picture_opened_for_read, + bg_source); +} + +static gboolean +in_content_types (const char *content_type) +{ + guint i; + for (i = 0; content_types[i]; i++) + if (g_str_equal (content_types[i], content_type)) + return TRUE; + return FALSE; +} + +static GFile * +bg_pictures_source_get_cache_file (void) +{ + g_autofree gchar *path = NULL; + GFile *file; + + path = bg_pictures_source_get_cache_path (); + file = g_file_new_for_path (path); + + return file; +} + +static gboolean +add_single_file (BgPicturesSource *bg_source, + GFile *file, + const gchar *content_type, + guint64 mtime) +{ + g_autoptr(CcBackgroundItem) item = NULL; + CcBackgroundItemFlags flags = 0; + g_autofree gchar *source_uri = NULL; + g_autofree gchar *uri = NULL; + gboolean needs_download; + gboolean retval = FALSE; + const gchar *pictures_path; + g_autoptr(GFile) pictures_dir = NULL; + g_autoptr(GFile) cache_dir = NULL; + 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_path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES); + if (pictures_path == NULL) + pictures_path = g_get_home_dir (); + pictures_dir = g_file_new_for_path (pictures_path); + cache_dir = bg_pictures_source_get_cache_file (); + needs_download = !g_file_has_parent (file, pictures_dir) && + !g_file_has_parent (file, cache_dir); + + if (!needs_download) + { + source_uri = g_strdup (uri); + flags |= CC_BACKGROUND_ITEM_HAS_URI; + } + else + { + source_uri = g_steal_pointer (&uri); + } + + 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); + + 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->cancellable, + picture_opened_for_read, bg_source); + } + else + { + g_autoptr(GFile) native_file = NULL; + g_autoptr(GFile) thumbnail_file = NULL; + g_autofree gchar *native_dir = NULL; + g_autofree gchar *native_path = NULL; + 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->cancellable, + NULL, + NULL, + picture_copied_for_read, + bg_source); + } + + retval = TRUE; + + out: + return retval; +} + +static gboolean +add_single_file_from_info (BgPicturesSource *bg_source, + GFile *file, + GFileInfo *info) +{ + const gchar *content_type; + guint64 mtime; + + content_type = g_file_info_get_content_type (info); + mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); + return add_single_file (bg_source, file, content_type, mtime); +} + +static gboolean +add_single_file_from_media (BgPicturesSource *bg_source, + GFile *file, + GrlMedia *media) +{ + GDateTime *mtime; + const gchar *content_type; + gint64 mtime_unix; + + content_type = grl_media_get_mime (media); + + /* only GRL_METADATA_KEY_CREATION_DATE is implemented in the Flickr + * plugin, GRL_METADATA_KEY_MODIFICATION_DATE is not + */ + mtime = grl_media_get_creation_date (media); + if (!mtime) + mtime = grl_media_get_modification_date (media); + if (mtime) + mtime_unix = g_date_time_to_unix (mtime); + else + mtime_unix = g_get_real_time () / G_USEC_PER_SEC; + + return add_single_file (bg_source, file, content_type, (guint64) mtime_unix); +} + +gboolean +bg_pictures_source_add (BgPicturesSource *bg_source, + const char *uri, + GtkTreeRowReference **ret_row_ref) +{ + g_autoptr(GFile) file = NULL; + GFileInfo *info; + gboolean retval; + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, ATTRIBUTES, G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (info == NULL) + return FALSE; + + retval = add_single_file_from_info (bg_source, file, info); + + return retval; +} + +gboolean +bg_pictures_source_remove (BgPicturesSource *bg_source, + const char *uri) +{ + GListStore *store; + gboolean retval; + guint i; + + retval = FALSE; + store = bg_source_get_liststore (BG_SOURCE (bg_source)); + + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++) + { + g_autoptr(CcBackgroundItem) tmp_item = NULL; + const char *tmp_uri; + + tmp_item = g_list_model_get_item (G_LIST_MODEL (store), i); + tmp_uri = cc_background_item_get_uri (tmp_item); + if (g_str_equal (tmp_uri, uri)) + { + char *uuid; + uuid = bg_pictures_source_get_unique_filename (uri); + g_hash_table_insert (bg_source->known_items, + uuid, NULL); + + g_list_store_remove (store, i); + retval = TRUE; + break; + } + } + return retval; +} + +static int +file_sort_func (gconstpointer a, + gconstpointer b) +{ + GFileInfo *file_a = G_FILE_INFO (a); + GFileInfo *file_b = G_FILE_INFO (b); + guint64 modified_a, modified_b; + + modified_a = g_file_info_get_attribute_uint64 (file_a, G_FILE_ATTRIBUTE_TIME_MODIFIED); + + modified_b = g_file_info_get_attribute_uint64 (file_b, G_FILE_ATTRIBUTE_TIME_MODIFIED); + + return modified_b - modified_a; +} + +static void +file_info_async_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *bg_source; + GList *files, *l; + g_autoptr(GError) err = NULL; + GFile *parent; + + files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source), + res, + &err); + if (err) + { + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Could not get pictures file information: %s", err->message); + + g_list_foreach (files, (GFunc) g_object_unref, NULL); + g_list_free (files); + return; + } + + bg_source = BG_PICTURES_SOURCE (user_data); + + parent = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source)); + + files = g_list_sort (files, file_sort_func); + + /* iterate over the available files */ + for (l = files; l; l = g_list_next (l)) + { + GFileInfo *info = l->data; + g_autoptr(GFile) file = NULL; + + file = g_file_get_child (parent, g_file_info_get_name (info)); + + add_single_file_from_info (bg_source, file, info); + } + + g_list_foreach (files, (GFunc) g_object_unref, NULL); + g_list_free (files); +} + +static void +dir_enum_async_ready (GObject *s, + GAsyncResult *res, + gpointer user_data) +{ + BgPicturesSource *source = (BgPicturesSource *) user_data; + g_autoptr(GFileEnumerator) enumerator = NULL; + g_autoptr(GError) err = NULL; + + enumerator = g_file_enumerate_children_finish (G_FILE (s), res, &err); + + if (err) + { + if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Could not fill pictures source: %s", err->message); + return; + } + + /* get the files */ + g_file_enumerator_next_files_async (enumerator, + G_MAXINT, + G_PRIORITY_LOW, + source->cancellable, + file_info_async_ready, + user_data); +} + +char * +bg_pictures_source_get_cache_path (void) +{ + return g_build_filename (g_get_user_cache_dir (), + "gnome-control-center", + "backgrounds", + NULL); +} + +static char * +bg_pictures_source_get_unique_filename (const char *uri) +{ + g_autoptr(GChecksum) csum = NULL; + char *ret; + + csum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (csum, (guchar *) uri, -1); + ret = g_strdup (g_checksum_get_string (csum)); + + return ret; +} + +char * +bg_pictures_source_get_unique_path (const char *uri) +{ + g_autoptr(GFile) parent = NULL; + g_autoptr(GFile) file = NULL; + g_autofree gchar *cache_path = NULL; + g_autofree gchar *filename = NULL; + + cache_path = bg_pictures_source_get_cache_path (); + parent = g_file_new_for_path (cache_path); + + filename = bg_pictures_source_get_unique_filename (uri); + file = g_file_get_child (parent, filename); + + return g_file_get_path (file); +} + +gboolean +bg_pictures_source_is_known (BgPicturesSource *bg_source, + const char *uri) +{ + g_autofree gchar *uuid = NULL; + + uuid = bg_pictures_source_get_unique_filename (uri); + + return GPOINTER_TO_INT (g_hash_table_lookup (bg_source->known_items, uuid)); +} + +static void +file_info_ready (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + GFileInfo *info; + GError *error = NULL; + GFile *file = G_FILE (object); + + info = g_file_query_info_finish (file, res, &error); + + if (!info) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Problem looking up file info: %s", error->message); + g_clear_error (&error); + return; + } + + add_single_file_from_info (BG_PICTURES_SOURCE (user_data), file, info); +} + +static void +file_added (GFile *file, + BgPicturesSource *self) +{ + g_autofree gchar *uri = NULL; + uri = g_file_get_uri (file); + + if (!bg_pictures_source_is_known (self, uri)) + { + g_file_query_info_async (file, + ATTRIBUTES, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_LOW, + NULL, + file_info_ready, + self); + } +} + +static void +files_changed_cb (BgPicturesSource *self, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type) +{ + g_autofree gchar *uri = NULL; + + switch (event_type) + { + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + file_added (file, self); + break; + + case G_FILE_MONITOR_EVENT_DELETED: + uri = g_file_get_uri (file); + bg_pictures_source_remove (self, uri); + break; + + default: + return; + } +} + +static GFileMonitor * +monitor_path (BgPicturesSource *self, + const char *path) +{ + GFileMonitor *monitor; + g_autoptr(GFile) dir = NULL; + + g_mkdir_with_parents (path, USER_DIR_MODE); + + dir = g_file_new_for_path (path); + g_file_enumerate_children_async (dir, + ATTRIBUTES, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_LOW, self->cancellable, + dir_enum_async_ready, self); + + monitor = g_file_monitor_directory (dir, + G_FILE_MONITOR_NONE, + self->cancellable, + NULL); + + if (monitor) + g_signal_connect_object (monitor, + "changed", + G_CALLBACK (files_changed_cb), + self, G_CONNECT_SWAPPED); + + return monitor; +} + +static void +media_found_cb (BgPicturesSource *self, GrlMedia *media) +{ + g_autoptr(GFile) file = NULL; + const gchar *uri; + + uri = grl_media_get_url (media); + file = g_file_new_for_uri (uri); + g_object_set_data_full (G_OBJECT (file), "grl-media", g_object_ref (media), g_object_unref); + add_single_file_from_media (self, file, media); +} + +static void +bg_pictures_source_init (BgPicturesSource *self) +{ + const gchar *pictures_path; + g_autofree gchar *cache_path = NULL; + + self->cancellable = g_cancellable_new (); + self->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 (); + + self->picture_dir_monitor = monitor_path (self, pictures_path); + + cache_path = bg_pictures_source_get_cache_path (); + self->cache_dir_monitor = monitor_path (self, cache_path); + + self->grl_miner = cc_background_grilo_miner_new (); + g_signal_connect_object (self->grl_miner, "media-found", G_CALLBACK (media_found_cb), self, G_CONNECT_SWAPPED); + cc_background_grilo_miner_start (self->grl_miner); +} + +BgPicturesSource * +bg_pictures_source_new (GtkWidget *widget) +{ + return g_object_new (BG_TYPE_PICTURES_SOURCE, "widget", widget, NULL); +} + +const char * const * +bg_pictures_get_support_content_types (void) +{ + return content_types; +} |