/* * This file is part of the Main Menu. * * Copyright (c) 2007 Novell, Inc. * * The Main Menu 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. * * The Main Menu 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 * the Main Menu; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "bookmark-agent.h" #ifdef HAVE_CONFIG_H # include #else # define PACKAGE "mate-main-menu" #endif #include #include #include #include #include #include #include "libslab-utils.h" #define USER_APPS_STORE_FILE_NAME "applications.xbel" #define USER_DOCS_STORE_FILE_NAME "documents.xbel" #define USER_DIRS_STORE_FILE_NAME "places.xbel" #define SYSTEM_STORE_FILE_NAME "system-items.xbel" #define CALC_TEMPLATE_FILE_NAME "empty.ots" #define WRITER_TEMPLATE_FILE_NAME "empty.ott" #define GTK_BOOKMARKS_FILE "bookmarks" #define TYPE_IS_RECENT(type) ((type) == BOOKMARK_STORE_RECENT_APPS || (type) == BOOKMARK_STORE_RECENT_DOCS) typedef struct { BookmarkStoreType type; BookmarkItem **items; gint n_items; BookmarkStoreStatus status; GBookmarkFile *store; gboolean needs_sync; gchar *store_path; gchar *user_store_path; gboolean user_modifiable; gboolean reorderable; const gchar *store_filename; GFileMonitor *store_monitor; GFileMonitor *user_store_monitor; void (* update_path) (BookmarkAgent *); void (* load_store) (BookmarkAgent *); void (* save_store) (BookmarkAgent *); void (* create_item) (BookmarkAgent *, const gchar *); gchar *gtk_store_path; GFileMonitor *gtk_store_monitor; } BookmarkAgentPrivate; enum { PROP_0, PROP_ITEMS, PROP_STATUS }; static BookmarkAgent *instances [BOOKMARK_STORE_N_TYPES]; static BookmarkAgentClass *bookmark_agent_parent_class = NULL; static void bookmark_agent_base_init (BookmarkAgentClass *); static void bookmark_agent_class_init (BookmarkAgentClass *); static void bookmark_agent_init (BookmarkAgent *); static BookmarkAgent *bookmark_agent_new (BookmarkStoreType ); static void get_property (GObject *, guint, GValue *, GParamSpec *); static void set_property (GObject *, guint, const GValue *, GParamSpec *); static void finalize (GObject *); static void update_agent (BookmarkAgent *); static void update_items (BookmarkAgent *); static void save_store (BookmarkAgent *); static gint get_rank (BookmarkAgent *, const gchar *); static void set_rank (BookmarkAgent *, const gchar *, gint); static void load_xbel_store (BookmarkAgent *); static void load_places_store (BookmarkAgent *); static void update_user_spec_path (BookmarkAgent *); static void save_xbel_store (BookmarkAgent *); static void create_app_item (BookmarkAgent *, const gchar *); static void create_doc_item (BookmarkAgent *, const gchar *); static void create_dir_item (BookmarkAgent *, const gchar *); static void store_monitor_cb (GFileMonitor *, GFile *, GFile *, GFileMonitorEvent, gpointer); static void weak_destroy_cb (gpointer, GObject *); static gint recent_item_mru_comp_func (gconstpointer a, gconstpointer b); static gchar *find_package_data_file (const gchar *filename); static gint BookmarkAgent_private_offset; static inline gpointer bookmark_agent_get_instance_private (BookmarkAgent *this) { return (G_STRUCT_MEMBER_P (this, BookmarkAgent_private_offset)); } GType bookmark_agent_get_type () { static GType g_define_type_id = 0; if (G_UNLIKELY (g_define_type_id == 0)) { static const GTypeInfo info = { sizeof (BookmarkAgentClass), (GBaseInitFunc) bookmark_agent_base_init, NULL, (GClassInitFunc) bookmark_agent_class_init, NULL, NULL, sizeof (BookmarkAgent), 0, (GInstanceInitFunc) bookmark_agent_init, NULL }; g_define_type_id = g_type_register_static ( G_TYPE_OBJECT, "BookmarkAgent", & info, 0); G_ADD_PRIVATE (BookmarkAgent); } return g_define_type_id; } BookmarkAgent * bookmark_agent_get_instance (BookmarkStoreType type) { g_return_val_if_fail (0 <= type, NULL); g_return_val_if_fail (type < BOOKMARK_STORE_N_TYPES, NULL); if (! instances [type]) { instances [type] = bookmark_agent_new (type); g_object_weak_ref (G_OBJECT (instances [type]), weak_destroy_cb, GINT_TO_POINTER (type)); } else g_object_ref (G_OBJECT (instances [type])); return instances [type]; } gboolean bookmark_agent_has_item (BookmarkAgent *this, const gchar *uri) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); return g_bookmark_file_has_item (priv->store, uri); } void bookmark_agent_add_item (BookmarkAgent *this, const BookmarkItem *item) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); if (! item) return; g_return_if_fail (priv->user_modifiable); g_return_if_fail (item->uri); g_return_if_fail (item->mime_type); g_bookmark_file_set_mime_type (priv->store, item->uri, item->mime_type); if (item->mtime) g_bookmark_file_set_modified (priv->store, item->uri, item->mtime); if (item->title) g_bookmark_file_set_title (priv->store, item->uri, item->title); g_bookmark_file_add_application (priv->store, item->uri, item->app_name, item->app_exec); set_rank (this, item->uri, g_bookmark_file_get_size (priv->store) - 1); save_store (this); } void bookmark_agent_move_item (BookmarkAgent *this, const gchar *uri, const gchar *uri_new) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); GError *error = NULL; if (! TYPE_IS_RECENT (priv->type)) return; gtk_recent_manager_move_item (gtk_recent_manager_get_default (), uri, uri_new, &error); if (error) { g_warning ("Unable to update %s with renamed file, [%s] -> [%s]: %s", priv->store_path, uri, uri_new, error->message); g_error_free (error); } } void bookmark_agent_purge_items (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); GError *error = NULL; gchar **uris = NULL; gsize uris_len; gint i; g_return_if_fail (priv->user_modifiable); uris = g_bookmark_file_get_uris (priv->store, &uris_len); if (TYPE_IS_RECENT (priv->type)) { for (i = 0; i < uris_len; i++) { gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uris [i], &error); if (error) { g_warning ("Unable to remove [%s] from %s: %s", priv->store_path, uris [i], error->message); g_error_free (error); } } } else { for (i = 0; i < uris_len; i++) { g_bookmark_file_remove_item (priv->store, uris [i], NULL); } save_store (this); } g_strfreev (uris); } void bookmark_agent_remove_item (BookmarkAgent *this, const gchar *uri) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gint rank; GError *error = NULL; gchar **uris = NULL; gint rank_i; gint i; g_return_if_fail (priv->user_modifiable); if (! bookmark_agent_has_item (this, uri)) return; if (TYPE_IS_RECENT (priv->type)) { gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, &error); if (error) { g_warning ("Unable to remove [%s] from %s: %s", priv->store_path, uri, error->message); g_error_free (error); } } else { rank = get_rank (this, uri); g_bookmark_file_remove_item (priv->store, uri, NULL); if (rank >= 0) { uris = g_bookmark_file_get_uris (priv->store, NULL); for (i = 0; uris && uris [i]; ++i) { rank_i = get_rank (this, uris [i]); if (rank_i > rank) set_rank (this, uris [i], rank_i - 1); } g_strfreev (uris); } save_store (this); } } void bookmark_agent_reorder_items (BookmarkAgent *this, const gchar **uris) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gint i; g_return_if_fail (priv->reorderable); for (i = 0; uris && uris [i]; ++i) set_rank (this, uris [i], i); save_store (this); } static GList * make_items_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar **uris; gint i; GList *items_ordered; if (!store) return NULL; uris = g_bookmark_file_get_uris (store, NULL); items_ordered = NULL; for (i = 0; uris && uris [i]; ++i) { gboolean include; if (priv->type == BOOKMARK_STORE_RECENT_APPS) include = g_bookmark_file_has_group (store, uris [i], "recently-used-apps", NULL); else include = ! g_bookmark_file_get_is_private (store, uris [i], NULL); if (include) { BookmarkItem *item; item = g_new0 (BookmarkItem, 1); item->uri = g_strdup (uris [i]); item->mime_type = g_bookmark_file_get_mime_type (store, uris [i], NULL); item->mtime = g_bookmark_file_get_modified (store, uris [i], NULL); items_ordered = g_list_prepend (items_ordered, item); } } items_ordered = g_list_sort (items_ordered, recent_item_mru_comp_func); g_strfreev (uris); return items_ordered; } void bookmark_agent_update_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store) { BookmarkAgentPrivate *priv; GList *items_ordered; GList *node; g_return_if_fail (IS_BOOKMARK_AGENT (this)); priv = bookmark_agent_get_instance_private (this); items_ordered = make_items_from_bookmark_file (this, store); g_bookmark_file_free (priv->store); priv->store = g_bookmark_file_new (); for (node = items_ordered; node; node = node->next) { BookmarkItem *item; item = (BookmarkItem *) node->data; g_bookmark_file_set_mime_type (priv->store, item->uri, item->mime_type); g_bookmark_file_set_modified (priv->store, item->uri, item->mtime); bookmark_item_free (item); } g_list_free (items_ordered); update_items (this); } void bookmark_item_free (BookmarkItem *item) { if (! item) return; g_free (item->uri); g_free (item->title); g_free (item->mime_type); g_free (item->icon); g_free (item->app_name); g_free (item->app_exec); g_free (item); } static void bookmark_agent_base_init (BookmarkAgentClass *this_class) { gint i; for (i = 0; i < BOOKMARK_STORE_N_TYPES; ++i) instances [i] = NULL; } static void bookmark_agent_class_init (BookmarkAgentClass *this_class) { GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); GParamSpec *items_pspec; GParamSpec *status_pspec; if (BookmarkAgent_private_offset != 0) g_type_class_adjust_private_offset (this_class, &BookmarkAgent_private_offset); g_obj_class->get_property = get_property; g_obj_class->set_property = set_property; g_obj_class->finalize = finalize; items_pspec = g_param_spec_pointer ( BOOKMARK_AGENT_ITEMS_PROP, BOOKMARK_AGENT_ITEMS_PROP, "the null-terminated list which contains the bookmark items in this store", G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); status_pspec = g_param_spec_int ( BOOKMARK_AGENT_STORE_STATUS_PROP, BOOKMARK_AGENT_STORE_STATUS_PROP, "the status of the store", BOOKMARK_STORE_DEFAULT_ONLY, BOOKMARK_STORE_USER, BOOKMARK_STORE_DEFAULT, G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (g_obj_class, PROP_ITEMS, items_pspec); g_object_class_install_property (g_obj_class, PROP_STATUS, status_pspec); bookmark_agent_parent_class = g_type_class_peek_parent (this_class); } static void bookmark_agent_init (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); priv->type = -1; priv->items = NULL; priv->n_items = 0; priv->status = BOOKMARK_STORE_ABSENT; priv->store = NULL; priv->needs_sync = FALSE; priv->store_path = NULL; priv->user_store_path = NULL; priv->user_modifiable = FALSE; priv->reorderable = FALSE; priv->store_filename = NULL; priv->store_monitor = NULL; priv->user_store_monitor = NULL; priv->update_path = NULL; priv->load_store = NULL; priv->save_store = NULL; priv->create_item = NULL; priv->gtk_store_path = NULL; priv->gtk_store_monitor = NULL; } static BookmarkAgent * bookmark_agent_new (BookmarkStoreType type) { BookmarkAgent *this; BookmarkAgentPrivate *priv; GFile *gtk_store_file; this = g_object_new (BOOKMARK_AGENT_TYPE, NULL); priv = bookmark_agent_get_instance_private (this); priv->type = type; priv->store = g_bookmark_file_new (); switch (type) { case BOOKMARK_STORE_USER_APPS: priv->store_filename = USER_APPS_STORE_FILE_NAME; priv->create_item = create_app_item; break; case BOOKMARK_STORE_USER_DOCS: priv->store_filename = USER_DOCS_STORE_FILE_NAME; priv->create_item = create_doc_item; break; case BOOKMARK_STORE_USER_DIRS: priv->store_filename = USER_DIRS_STORE_FILE_NAME; priv->create_item = create_dir_item; priv->user_modifiable = TRUE; priv->reorderable = FALSE; priv->load_store = load_places_store; priv->gtk_store_path = g_build_filename (g_get_user_config_dir (), "gtk-3.0", GTK_BOOKMARKS_FILE, NULL); gtk_store_file = g_file_new_for_path (priv->gtk_store_path); priv->gtk_store_monitor = g_file_monitor_file (gtk_store_file, 0, NULL, NULL); if (priv->gtk_store_monitor) { g_signal_connect (priv->gtk_store_monitor, "changed", G_CALLBACK (store_monitor_cb), this); } g_object_unref (gtk_store_file); break; case BOOKMARK_STORE_RECENT_APPS: case BOOKMARK_STORE_RECENT_DOCS: priv->user_modifiable = TRUE; priv->reorderable = FALSE; priv->store_path = g_build_filename (g_get_user_data_dir (), "recently-used.xbel", NULL); break; case BOOKMARK_STORE_SYSTEM: priv->store_filename = SYSTEM_STORE_FILE_NAME; priv->create_item = create_app_item; break; default: break; } if ( type == BOOKMARK_STORE_USER_APPS || type == BOOKMARK_STORE_USER_DOCS || type == BOOKMARK_STORE_USER_DIRS || type == BOOKMARK_STORE_SYSTEM) { priv->user_modifiable = TRUE; priv->user_store_path = g_build_filename ( g_get_user_data_dir (), PACKAGE, priv->store_filename, NULL); priv->update_path = update_user_spec_path; } if (type == BOOKMARK_STORE_USER_APPS || type == BOOKMARK_STORE_USER_DOCS || type == BOOKMARK_STORE_SYSTEM) { priv->reorderable = TRUE; priv->load_store = load_xbel_store; priv->save_store = save_xbel_store; } update_agent (this); return this; } static void get_property (GObject *g_obj, guint prop_id, GValue *value, GParamSpec *pspec) { BookmarkAgent *this = BOOKMARK_AGENT (g_obj); BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); switch (prop_id) { case PROP_ITEMS: g_value_set_pointer (value, priv->items); break; case PROP_STATUS: g_value_set_int (value, priv->status); break; } } static void set_property (GObject *g_obj, guint prop_id, const GValue *value, GParamSpec *pspec) { /* no writeable properties */ } static void finalize (GObject *g_obj) { BookmarkAgent *this = BOOKMARK_AGENT (g_obj); BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gint i; for (i = 0; priv->items && priv->items [i]; ++i) bookmark_item_free (priv->items [i]); g_free (priv->items); g_free (priv->store_path); g_free (priv->user_store_path); g_free (priv->gtk_store_path); if (priv->store_monitor) { g_signal_handlers_disconnect_by_func (priv->store_monitor, store_monitor_cb, this); g_file_monitor_cancel (priv->store_monitor); g_object_unref (priv->store_monitor); } if (priv->user_store_monitor) { g_signal_handlers_disconnect_by_func (priv->user_store_monitor, store_monitor_cb, this); g_file_monitor_cancel (priv->user_store_monitor); g_object_unref (priv->user_store_monitor); } if (priv->gtk_store_monitor) { g_signal_handlers_disconnect_by_func (priv->gtk_store_monitor, store_monitor_cb, this); g_file_monitor_cancel (priv->gtk_store_monitor); g_object_unref (priv->gtk_store_monitor); } g_bookmark_file_free (priv->store); G_OBJECT_CLASS (bookmark_agent_parent_class)->finalize (g_obj); } static void update_agent (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); if (priv->update_path) priv->update_path (this); if (priv->load_store) priv->load_store (this); update_items (this); } static void update_items (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar **uris = NULL; gchar **uris_ordered = NULL; gsize n_uris = 0; gint rank = -1; gint rank_corr = -1; gboolean needs_update = FALSE; gboolean store_corrupted = FALSE; gchar *new_title, *old_title; gint i; uris = g_bookmark_file_get_uris (priv->store, & n_uris); uris_ordered = g_new0 (gchar *, n_uris + 1); uris_ordered [n_uris] = NULL; for (i = 0; uris && uris [i]; ++i) { rank = get_rank (this, uris [i]); if (rank < 0 || rank >= n_uris) rank = i; if (uris_ordered [rank]) { store_corrupted = TRUE; rank_corr = rank; for (rank = 0; rank < n_uris; ++rank) if (! uris_ordered [rank]) break; g_warning ( "store corruption [%s] - multiple uris with same rank (%d): [%s] [%s], moving latter to %d", priv->store_path, rank_corr, uris_ordered [rank_corr], uris [i], rank); } set_rank (this, uris [i], rank); uris_ordered [rank] = uris [i]; } if (priv->n_items != n_uris) needs_update = TRUE; for (i = 0; ! needs_update && uris_ordered && uris_ordered [i]; ++i) { if (priv->type == BOOKMARK_STORE_USER_DIRS) { new_title = g_bookmark_file_get_title (priv->store, uris_ordered [i], NULL); old_title = priv->items [i]->title; if (!new_title && !old_title) { if (strcmp (priv->items [i]->uri, uris_ordered [i])) needs_update = TRUE; } else if ((new_title && !old_title) || (!new_title && old_title)) needs_update = TRUE; else if (strcmp (old_title, new_title)) needs_update = TRUE; g_free (new_title); } else if (strcmp (priv->items [i]->uri, uris_ordered [i])) needs_update = TRUE; } if (needs_update) { for (i = 0; priv->items && priv->items [i]; ++i) bookmark_item_free (priv->items [i]); g_free (priv->items); priv->n_items = n_uris; priv->items = g_new0 (BookmarkItem *, priv->n_items + 1); for (i = 0; uris_ordered && uris_ordered [i]; ++i) { priv->items [i] = g_new0 (BookmarkItem, 1); priv->items [i]->uri = g_strdup (uris_ordered [i]); priv->items [i]->title = g_bookmark_file_get_title (priv->store, uris_ordered [i], NULL); priv->items [i]->mime_type = g_bookmark_file_get_mime_type (priv->store, uris_ordered [i], NULL); priv->items [i]->mtime = g_bookmark_file_get_modified (priv->store, uris_ordered [i], NULL); priv->items [i]->app_name = NULL; priv->items [i]->app_exec = NULL; g_bookmark_file_get_icon (priv->store, uris_ordered [i], & priv->items [i]->icon, NULL, NULL); } /* Since the bookmark store for recently-used items is updated by the caller of BookmarkAgent, * we don't emit notifications in that case. The caller will know when to update itself. */ if (!TYPE_IS_RECENT (priv->type)) g_object_notify (G_OBJECT (this), BOOKMARK_AGENT_ITEMS_PROP); } if (store_corrupted) save_store (this); g_strfreev (uris); g_free (uris_ordered); } static void save_store (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar *dir; g_return_if_fail (priv->user_modifiable); priv->needs_sync = TRUE; priv->update_path (this); dir = g_path_get_dirname (priv->store_path); g_mkdir_with_parents (dir, 0700); g_free (dir); priv->save_store (this); update_items (this); } static gint get_rank (BookmarkAgent *this, const gchar *uri) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar **groups; gint rank; gint i; if (! priv->reorderable) return -1; groups = g_bookmark_file_get_groups (priv->store, uri, NULL, NULL); rank = -1; for (i = 0; groups && groups [i]; ++i) { if (g_str_has_prefix (groups [i], "rank-")) { if (rank >= 0) g_warning ( "store corruption - multiple ranks for same uri: [%s] [%s]", priv->store_path, uri); rank = atoi (& groups [i] [5]); } } g_strfreev (groups); return rank; } static void set_rank (BookmarkAgent *this, const gchar *uri, gint rank) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar **groups; gchar *group; gint i; if (! (priv->reorderable && bookmark_agent_has_item (this, uri))) return; groups = g_bookmark_file_get_groups (priv->store, uri, NULL, NULL); for (i = 0; groups && groups [i]; ++i) if (g_str_has_prefix (groups [i], "rank-")) g_bookmark_file_remove_group (priv->store, uri, groups [i], NULL); g_strfreev (groups); group = g_strdup_printf ("rank-%d", rank); g_bookmark_file_add_group (priv->store, uri, group); g_free (group); } static void load_xbel_store (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar **uris = NULL; GError *error = NULL; gint i; gboolean success; if (!priv->store_path) success = FALSE; else { success = g_bookmark_file_load_from_file (priv->store, priv->store_path, & error); } if (!success) { g_bookmark_file_free (priv->store); priv->store = g_bookmark_file_new (); if (error) { g_debug ("Couldn't load bookmark file [%s]: %s", priv->store_path, error->message); g_error_free (error); } else { g_debug ("Couldn't load bookmark file [NULL]"); } return; } uris = g_bookmark_file_get_uris (priv->store, NULL); for (i = 0; uris && uris [i]; ++i) priv->create_item (this, uris [i]); g_strfreev (uris); } static void load_places_store (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar **uris; gchar **groups; gchar **bookmarks = NULL; gchar *buf, *label, *uri; gint i, j, bookmark_len; load_xbel_store (this); uris = g_bookmark_file_get_uris (priv->store, NULL); for (i = 0; uris && uris [i]; ++i) { groups = g_bookmark_file_get_groups (priv->store, uris [i], NULL, NULL); for (j = 0; groups && groups [j]; ++j) { if (! strcmp (groups [j], "gtk-bookmarks")) { g_bookmark_file_remove_item (priv->store, uris [i], NULL); break; } } g_strfreev (groups); } g_strfreev (uris); g_file_get_contents (priv->gtk_store_path, & buf, NULL, NULL); if (buf) { bookmarks = g_strsplit (buf, "\n", -1); g_free (buf); } for (i = 0; bookmarks && bookmarks [i]; ++i) { bookmark_len = strlen (bookmarks [i]); if (bookmark_len > 0) { label = strstr (bookmarks[i], " "); if (label != NULL) uri = g_strndup (bookmarks [i], bookmark_len - strlen (label)); else uri = bookmarks [i]; g_bookmark_file_add_group (priv->store, uri, "gtk-bookmarks"); priv->create_item (this, uri); if (label != NULL) { label++; if (strlen (label) > 0) g_bookmark_file_set_title (priv->store, uri, label); g_free (uri); } } } g_strfreev (bookmarks); } static gchar * find_package_data_file (const gchar *filename) { const gchar * const *dirs = NULL; gchar *path = NULL; gint i; dirs = g_get_system_data_dirs (); for (i = 0; ! path && dirs && dirs [i]; ++i) { path = g_build_filename (dirs [i], PACKAGE, filename, NULL); if (! g_file_test (path, G_FILE_TEST_EXISTS)) { g_free (path); path = NULL; } } return path; } static void update_user_spec_path (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gboolean use_user_path; gchar *path = NULL; BookmarkStoreStatus status; use_user_path = priv->user_modifiable && (priv->needs_sync || g_file_test (priv->user_store_path, G_FILE_TEST_EXISTS)); if (use_user_path) path = g_strdup (priv->user_store_path); else path = find_package_data_file (priv->store_filename); if (use_user_path) status = BOOKMARK_STORE_USER; else if (path && priv->user_modifiable) status = BOOKMARK_STORE_DEFAULT; else if (path) status = BOOKMARK_STORE_DEFAULT_ONLY; else status = BOOKMARK_STORE_ABSENT; if (priv->status != status) { priv->status = status; g_object_notify (G_OBJECT (this), BOOKMARK_AGENT_STORE_STATUS_PROP); if (priv->user_store_monitor) { g_file_monitor_cancel (priv->user_store_monitor); g_object_unref (priv->user_store_monitor); priv->user_store_monitor = NULL; } if (priv->status == BOOKMARK_STORE_DEFAULT) { GFile *user_store_file; user_store_file = g_file_new_for_path (priv->user_store_path); priv->user_store_monitor = g_file_monitor_file (user_store_file, 0, NULL, NULL); if (priv->user_store_monitor) { g_signal_connect (priv->user_store_monitor, "changed", G_CALLBACK (store_monitor_cb), this); } g_object_unref (user_store_file); } } if (g_strcmp0 (priv->store_path, path)) { g_free (priv->store_path); priv->store_path = path; if (priv->store_monitor) { g_file_monitor_cancel (priv->store_monitor); g_object_unref (priv->store_monitor); } if (priv->store_path) { GFile *store_file; store_file = g_file_new_for_path (priv->store_path); priv->store_monitor = g_file_monitor_file (store_file, 0, NULL, NULL); if (priv->store_monitor) { g_signal_connect (priv->store_monitor, "changed", G_CALLBACK (store_monitor_cb), this); } g_object_unref (store_file); } } else g_free (path); } static void save_xbel_store (BookmarkAgent *this) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); GError *error = NULL; if (g_bookmark_file_to_file (priv->store, priv->store_path, &error)) return; if (error) { g_warning ("Couldn't save bookmark file [%s]: %s", priv->store_path, error->message); g_error_free (error); } else { g_warning ("Couldn't save bookmark file [%s]", priv->store_path); } } static void create_app_item (BookmarkAgent *this, const gchar *uri) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); MateDesktopItem *ditem; gchar *uri_new = NULL; ditem = libslab_mate_desktop_item_new_from_unknown_id (uri); if (ditem) { uri_new = g_strdup (mate_desktop_item_get_location (ditem)); mate_desktop_item_unref (ditem); } if (! uri_new) return; if (g_strcmp0 (uri, uri_new)) g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); g_free (uri_new); } static void create_doc_item (BookmarkAgent *this, const gchar *uri) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar *uri_new = NULL; if ((strcmp (uri, "BLANK_SPREADSHEET") == 0) || (strcmp (uri, "BLANK_DOCUMENT") == 0)) { gchar *template = NULL; gchar *file; gchar *dir = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); if (!dir) dir = g_build_filename (g_get_home_dir (), "Documents", NULL); if (strcmp (uri, "BLANK_SPREADSHEET") == 0) { g_bookmark_file_set_title (priv->store, uri, "BLANK_SPREADSHEET"); file = g_strconcat (_("New Spreadsheet"), ".ots", NULL); template = find_package_data_file (CALC_TEMPLATE_FILE_NAME); } else { g_bookmark_file_set_title (priv->store, uri, "BLANK_DOCUMENT"); file = g_strconcat (_("New Document"), ".ott", NULL); template = find_package_data_file (WRITER_TEMPLATE_FILE_NAME); } gchar *path = g_build_filename (dir, file, NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) { g_mkdir_with_parents (dir, 0700); if (template != NULL) { gchar *contents; gsize length; if (g_file_get_contents (template, &contents, &length, NULL)) g_file_set_contents (path, contents, length, NULL); g_free (contents); } else { fclose (g_fopen (path, "w")); } } uri_new = g_filename_to_uri (path, NULL, NULL); g_free (dir); g_free (file); g_free (path); g_free (template); } if (!uri_new) return; if (g_strcmp0 (uri, uri_new)) g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); g_free (uri_new); } static void create_dir_item (BookmarkAgent *this, const gchar *uri) { BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); gchar *uri_new = NULL; gchar *path = NULL; gchar *name = NULL; gchar *icon = NULL; gchar *search_string = NULL; gboolean gotta_free_name = FALSE; if (strcmp (uri, "HOME") == 0) { uri_new = g_filename_to_uri (g_get_home_dir (), NULL, NULL); name = g_strdup (C_("Home folder", "Home")); gotta_free_name = TRUE; icon = "user-home"; } else if (strcmp (uri, "DOCUMENTS") == 0) { path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); if (!path) path = g_build_filename (g_get_home_dir (), "Documents", NULL); name = _("Documents"); uri_new = g_filename_to_uri (path, NULL, NULL); } else if (strcmp (uri, "DESKTOP") == 0) { path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)); if (!path) path = g_build_filename (g_get_home_dir (), "Desktop", NULL); name = _("Desktop"); uri_new = g_filename_to_uri (path, NULL, NULL); icon = "user-desktop"; } else if (strcmp (uri, "file:///") == 0) { icon = "drive-harddisk"; name = _("File System"); } else if (strcmp (uri, "network:") == 0) { icon = "network-workgroup"; name = _("Network Servers"); } else if (g_str_has_prefix (uri, "x-caja-search")) { icon = "system-search"; path = g_build_filename (g_get_user_data_dir (), "caja", "searches", & uri [21], NULL); if (g_file_test (path, G_FILE_TEST_EXISTS)) { gchar *buf = NULL; g_file_get_contents (path, &buf, NULL, NULL); gchar *tag_open_ptr = NULL; gchar *tag_close_ptr = NULL; if (buf) { tag_open_ptr = strstr (buf, ""); tag_close_ptr = strstr (buf, ""); } if (tag_open_ptr && tag_close_ptr) { tag_close_ptr [0] = '\0'; tag_close_ptr [0] = 'a'; search_string = g_strdup_printf ("\"%s\"", &tag_open_ptr[6]); } g_free (buf); } if (search_string) { name = search_string; gotta_free_name = TRUE; } else { name = _("Search"); } } if (icon) g_bookmark_file_set_icon (priv->store, uri, icon, "image/png"); if (name) g_bookmark_file_set_title (priv->store, uri, name); if (uri_new && g_strcmp0 (uri, uri_new)) g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); if (gotta_free_name) { g_free (name); } g_free (path); g_free (uri_new); } static void store_monitor_cb (GFileMonitor *mon, GFile *f1, GFile *f2, GFileMonitorEvent event_type, gpointer user_data) { update_agent (BOOKMARK_AGENT (user_data)); } static void weak_destroy_cb (gpointer data, GObject *g_obj) { instances [GPOINTER_TO_INT (data)] = NULL; } static gint recent_item_mru_comp_func (gconstpointer a, gconstpointer b) { return ((BookmarkItem *) b)->mtime - ((BookmarkItem *) a)->mtime; }