[epiphany/mcatanzaro/#336] Make ephy_bookmarks_manager_save_to_file_async() actually async



commit 45d107037783707619c28dc789fa408fa97e660c
Author: Michael Catanzaro <mcatanzaro igalia com>
Date:   Thu Jun 20 17:17:05 2019 -0500

    Make ephy_bookmarks_manager_save_to_file_async() actually async
    
    Currently it looks like an asynchronous function, but it actually does
    sync I/O, which is bad.
    
    This also requires also making ephy_bookmarks_export() async, as
    well as gvdb_table_write_contents(). I'll attempt to upstream the GVDB
    changes separately.
    
    It also requires adding GCancellable parameters where required, to avoid
    introducing new crashes. This means we need a way for external code to
    access the EphyBookmarkManager's cancellable or we would need to get rid
    of the warn_on_error convenience callback.
    
    Also, remove ephy_bookmarks_manager_load_from_file(), since it's only
    one line long and only used in one place.
    
    Finally, rename the functions according to Carlos's feedback.
    
    Fixes #336

 lib/contrib/gvdb/README.epiphany              |   1 +
 lib/contrib/gvdb/gvdb-builder.c               |  93 ++++++++++++
 lib/contrib/gvdb/gvdb-builder.h               |  50 ++++---
 src/bookmarks/ephy-add-bookmark-popover.c     |  14 +-
 src/bookmarks/ephy-bookmark-properties-grid.c |   7 +-
 src/bookmarks/ephy-bookmarks-export.c         |  50 +++++--
 src/bookmarks/ephy-bookmarks-export.h         |  11 +-
 src/bookmarks/ephy-bookmarks-import.c         |   7 +-
 src/bookmarks/ephy-bookmarks-manager.c        | 196 ++++++++++++++++++--------
 src/bookmarks/ephy-bookmarks-manager.h        |  66 ++++-----
 src/profile-migrator/ephy-profile-migrator.c  |   9 +-
 src/window-commands.c                         |  41 ++++--
 12 files changed, 392 insertions(+), 153 deletions(-)
---
diff --git a/lib/contrib/gvdb/README.epiphany b/lib/contrib/gvdb/README.epiphany
index 4347db97c..7c85ce670 100644
--- a/lib/contrib/gvdb/README.epiphany
+++ b/lib/contrib/gvdb/README.epiphany
@@ -3,3 +3,4 @@ GVariant Database
  * Copied from https://git.gnome.org/browse/gvdb
  * Removed G_GNUC_INTERNAL
  * Fixed -Wsign-compare
+ * Added gvdb_table_write_contents_async()
diff --git a/lib/contrib/gvdb/gvdb-builder.c b/lib/contrib/gvdb/gvdb-builder.c
index 16a5283dd..66568cf42 100644
--- a/lib/contrib/gvdb/gvdb-builder.c
+++ b/lib/contrib/gvdb/gvdb-builder.c
@@ -512,6 +512,9 @@ gvdb_table_write_contents (GHashTable   *table,
   FileBuilder *fb;
   GString *str;
 
+  g_return_val_if_fail (table != NULL, FALSE);
+  g_return_val_if_fail (filename != NULL, FALSE);
+
   fb = file_builder_new (byteswap);
   file_builder_add_hash (fb, table, &root);
   str = file_builder_serialise (fb, root);
@@ -521,3 +524,93 @@ gvdb_table_write_contents (GHashTable   *table,
 
   return status;
 }
+
+typedef struct {
+  GString *contents;
+  GFile *file;
+} WriteContentsData;
+
+static WriteContentsData *
+write_contents_data_new (GString    *contents,
+                         GFile      *file)
+{
+  WriteContentsData *data;
+
+  data = g_slice_new (WriteContentsData);
+  data->contents = contents;
+  data->file = file;
+
+  return data;
+}
+
+static void
+write_contents_data_free (WriteContentsData *data)
+{
+  g_string_free (data->contents, TRUE);
+  g_object_unref (data->file);
+  g_slice_free (WriteContentsData, data);
+}
+
+static void
+replace_contents_cb (GObject      *source_object,
+                     GAsyncResult *result,
+                     gpointer      user_data)
+{
+  GTask *task = user_data;
+  WriteContentsData *data = g_task_get_task_data (task);
+  GError *error = NULL;
+
+  if (!g_file_replace_contents_finish (data->file, result, NULL, &error))
+    {
+      g_task_return_error (task, error);
+      g_object_unref (task);
+      return;
+    }
+
+  g_task_return_boolean (task, TRUE);
+  g_object_unref (task);
+}
+
+void
+gvdb_table_write_contents_async (GHashTable          *table,
+                                 const gchar         *filename,
+                                 gboolean             byteswap,
+                                 GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+  struct gvdb_pointer root;
+  FileBuilder *fb;
+  WriteContentsData *data;
+  GString *str;
+  GFile *file;
+  GTask *task;
+
+  g_return_if_fail (table != NULL);
+  g_return_if_fail (filename != NULL);
+
+  fb = file_builder_new (byteswap);
+  file_builder_add_hash (fb, table, &root);
+  str = file_builder_serialise (fb, root);
+
+  file = g_file_new_for_path (filename);
+  data = write_contents_data_new (str, file);
+
+  task = g_task_new (NULL, cancellable, callback, user_data);
+  g_task_set_task_data (task, data, (GDestroyNotify)write_contents_data_free);
+
+  g_file_replace_contents_async (file, str->str, str->len,
+                                 NULL, FALSE,
+                                 G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION,
+                                 cancellable, replace_contents_cb, task);
+}
+
+gboolean
+gvdb_table_write_contents_finish (GHashTable    *table,
+                                  GAsyncResult  *result,
+                                  GError       **error)
+{
+  g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/lib/contrib/gvdb/gvdb-builder.h b/lib/contrib/gvdb/gvdb-builder.h
index 8e32e144b..6dff57b09 100644
--- a/lib/contrib/gvdb/gvdb-builder.h
+++ b/lib/contrib/gvdb/gvdb-builder.h
@@ -26,25 +26,35 @@
 
 typedef struct _GvdbItem GvdbItem;
 
-GHashTable *            gvdb_hash_table_new                             (GHashTable    *parent,
-                                                                         const gchar   *key);
-
-GvdbItem *              gvdb_hash_table_insert                          (GHashTable    *table,
-                                                                         const gchar   *key);
-void                    gvdb_hash_table_insert_string                   (GHashTable    *table,
-                                                                         const gchar   *key,
-                                                                         const gchar   *value);
-
-void                    gvdb_item_set_value                             (GvdbItem      *item,
-                                                                         GVariant      *value);
-void                    gvdb_item_set_hash_table                        (GvdbItem      *item,
-                                                                         GHashTable    *table);
-void                    gvdb_item_set_parent                            (GvdbItem      *item,
-                                                                         GvdbItem      *parent);
-
-gboolean                gvdb_table_write_contents                       (GHashTable     *table,
-                                                                         const gchar    *filename,
-                                                                         gboolean        byteswap,
-                                                                         GError        **error);
+GHashTable *            gvdb_hash_table_new                             (GHashTable          *parent,
+                                                                         const gchar         *key);
+
+GvdbItem *              gvdb_hash_table_insert                          (GHashTable          *table,
+                                                                         const gchar         *key);
+void                    gvdb_hash_table_insert_string                   (GHashTable          *table,
+                                                                         const gchar         *key,
+                                                                         const gchar         *value);
+
+void                    gvdb_item_set_value                             (GvdbItem            *item,
+                                                                         GVariant            *value);
+void                    gvdb_item_set_hash_table                        (GvdbItem            *item,
+                                                                         GHashTable          *table);
+void                    gvdb_item_set_parent                            (GvdbItem            *item,
+                                                                         GvdbItem            *parent);
+
+gboolean                gvdb_table_write_contents                       (GHashTable          *table,
+                                                                         const gchar         *filename,
+                                                                         gboolean             byteswap,
+                                                                         GError             **error);
+
+void                    gvdb_table_write_contents_async                 (GHashTable          *table,
+                                                                         const gchar         *filename,
+                                                                         gboolean             byteswap,
+                                                                         GCancellable        *cancellable,
+                                                                         GAsyncReadyCallback  callback,
+                                                                         gpointer             user_data);
+gboolean                gvdb_table_write_contents_finish                (GHashTable          *table,
+                                                                         GAsyncResult        *result,
+                                                                         GError             **error);
 
 #endif /* __gvdb_builder_h__ */
diff --git a/src/bookmarks/ephy-add-bookmark-popover.c b/src/bookmarks/ephy-add-bookmark-popover.c
index 0ba8159eb..bb331f039 100644
--- a/src/bookmarks/ephy-add-bookmark-popover.c
+++ b/src/bookmarks/ephy-add-bookmark-popover.c
@@ -123,9 +123,10 @@ ephy_add_bookmark_popover_closed_cb (GtkPopover *popover,
   self = EPHY_ADD_BOOKMARK_POPOVER (popover);
   manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
 
-  ephy_bookmarks_manager_save_to_file_async (manager, NULL,
-                                             ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (manager,
+                               ephy_bookmarks_manager_save_warn_on_error_cancellable (manager),
+                               ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
 
   g_clear_pointer (&self->address, g_free);
   g_clear_pointer (&self->grid, gtk_widget_destroy);
@@ -184,9 +185,10 @@ ephy_add_bookmark_popover_update_bookmarked_status_cb (EphyAddBookmarkPopover *s
                                                  EPHY_LOCATION_ENTRY_BOOKMARK_ICON_EMPTY);
   }
 
-  ephy_bookmarks_manager_save_to_file_async (manager, NULL,
-                                             ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (manager,
+                               ephy_bookmarks_manager_save_warn_on_error_cancellable (manager),
+                               ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
 
   gtk_widget_hide (GTK_WIDGET (self));
 }
diff --git a/src/bookmarks/ephy-bookmark-properties-grid.c b/src/bookmarks/ephy-bookmark-properties-grid.c
index 63899ff05..9703f93b5 100644
--- a/src/bookmarks/ephy-bookmark-properties-grid.c
+++ b/src/bookmarks/ephy-bookmark-properties-grid.c
@@ -421,9 +421,10 @@ ephy_bookmark_properties_grid_finalize (GObject *object)
   if (self->bookmark_is_modified && !self->bookmark_is_removed)
     g_signal_emit_by_name (self->manager, "synchronizable-modified", self->bookmark, FALSE);
 
-  ephy_bookmarks_manager_save_to_file_async (self->manager, NULL,
-                                             ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (self->manager,
+                               ephy_bookmarks_manager_save_warn_on_error_cancellable (self->manager),
+                               ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
 
   G_OBJECT_CLASS (ephy_bookmark_properties_grid_parent_class)->finalize (object);
 }
diff --git a/src/bookmarks/ephy-bookmarks-export.c b/src/bookmarks/ephy-bookmarks-export.c
index 47f55d785..cbe7babf6 100644
--- a/src/bookmarks/ephy-bookmarks-export.c
+++ b/src/bookmarks/ephy-bookmarks-export.c
@@ -63,7 +63,8 @@ build_variant (EphyBookmark *bookmark)
 }
 
 static void
-add_bookmark_to_table (EphyBookmark *bookmark, GHashTable *table)
+add_bookmark_to_table (EphyBookmark *bookmark,
+                       GHashTable   *table)
 {
   gvdb_hash_table_insert_variant (table,
                                   ephy_bookmark_get_url (bookmark),
@@ -71,19 +72,41 @@ add_bookmark_to_table (EphyBookmark *bookmark, GHashTable *table)
 }
 
 static void
-add_tag_to_table (const char *tag, GHashTable *table)
+add_tag_to_table (const char *tag,
+                  GHashTable *table)
 {
   gvdb_hash_table_insert (table, tag);
 }
 
-gboolean
+static void
+write_contents_cb (GObject      *source_object,
+                   GAsyncResult *result,
+                   gpointer      user_data)
+{
+  g_autoptr(GTask) task = user_data;
+  GHashTable *root_table;
+  GError *error = NULL;
+
+  root_table = g_task_get_task_data (task);
+
+  if (!gvdb_table_write_contents_finish (root_table, result, &error)) {
+    g_task_return_error (task, error);
+    return;
+  }
+
+  g_task_return_boolean (task, TRUE);
+}
+
+void
 ephy_bookmarks_export (EphyBookmarksManager  *manager,
                        const char            *filename,
-                       GError               **error)
+                       GCancellable          *cancellable,
+                       GAsyncReadyCallback    callback,
+                       gpointer               user_data)
 {
   GHashTable *root_table;
   GHashTable *table;
-  gboolean result;
+  GTask *task;
 
   root_table = gvdb_hash_table_new (NULL, NULL);
 
@@ -95,8 +118,19 @@ ephy_bookmarks_export (EphyBookmarksManager  *manager,
   g_sequence_foreach (ephy_bookmarks_manager_get_bookmarks (manager), (GFunc)add_bookmark_to_table, table);
   g_hash_table_unref (table);
 
-  result = gvdb_table_write_contents (root_table, filename, FALSE, error);
-  g_hash_table_unref (root_table);
+  task = g_task_new (manager, cancellable, callback, user_data);
+  g_task_set_task_data (task, root_table, (GDestroyNotify)g_hash_table_unref);
+
+  gvdb_table_write_contents_async (root_table, filename, FALSE,
+                                   cancellable, write_contents_cb, task);
+}
+
+gboolean
+ephy_bookmarks_export_finish (EphyBookmarksManager  *manager,
+                              GAsyncResult          *result,
+                              GError               **error)
+{
+  g_assert (g_task_is_valid (result, manager));
 
-  return result;
+  return g_task_propagate_boolean (G_TASK (result), error);
 }
diff --git a/src/bookmarks/ephy-bookmarks-export.h b/src/bookmarks/ephy-bookmarks-export.h
index bd36b0e12..8bc087f48 100644
--- a/src/bookmarks/ephy-bookmarks-export.h
+++ b/src/bookmarks/ephy-bookmarks-export.h
@@ -24,8 +24,13 @@
 
 G_BEGIN_DECLS
 
-gboolean        ephy_bookmarks_export       (EphyBookmarksManager  *manager,
-                                             const char            *filename,
-                                             GError               **error);
+void            ephy_bookmarks_export        (EphyBookmarksManager  *manager,
+                                              const char            *filename,
+                                              GCancellable          *cancellable,
+                                              GAsyncReadyCallback    callback,
+                                              gpointer               user_data);
+gboolean        ephy_bookmarks_export_finish (EphyBookmarksManager  *manager,
+                                              GAsyncResult          *result,
+                                              GError               **error);
 
 G_END_DECLS
diff --git a/src/bookmarks/ephy-bookmarks-import.c b/src/bookmarks/ephy-bookmarks-import.c
index c942ab323..ffc9039a7 100644
--- a/src/bookmarks/ephy-bookmarks-import.c
+++ b/src/bookmarks/ephy-bookmarks-import.c
@@ -105,7 +105,12 @@ ephy_bookmarks_import (EphyBookmarksManager  *manager,
   int length;
   int i;
 
-  /* Create a new table to hold data stored in file. */
+  /* Create a new table to hold data stored in file.
+   *
+   * FIXME: This uses mmap so it's doing sync I/O, which is not cool. It's
+   * not straightforward to fix, but it would be nice to have an async
+   * constructor in GVDB. Then we could make ephy_bookmarks_import() async.
+   */
   root_table = gvdb_table_new (filename, TRUE, error);
   if (!root_table) {
     res = FALSE;
diff --git a/src/bookmarks/ephy-bookmarks-manager.c b/src/bookmarks/ephy-bookmarks-manager.c
index 4860997f2..bc26019be 100644
--- a/src/bookmarks/ephy-bookmarks-manager.c
+++ b/src/bookmarks/ephy-bookmarks-manager.c
@@ -34,12 +34,14 @@
 #define EPHY_BOOKMARKS_FILE "bookmarks.gvdb"
 
 struct _EphyBookmarksManager {
-  GObject     parent_instance;
+  GObject       parent_instance;
 
-  GSequence  *bookmarks;
-  GSequence  *tags;
+  GCancellable *cancellable;
 
-  gchar      *gvdb_filename;
+  GSequence    *bookmarks;
+  GSequence    *tags;
+
+  gchar        *gvdb_filename;
 };
 
 static void list_model_iface_init     (GListModelInterface *iface);
@@ -65,17 +67,6 @@ enum {
 
 static guint       signals[LAST_SIGNAL];
 
-static void
-ephy_bookmarks_manager_save_to_file (EphyBookmarksManager *self, GTask *task)
-{
-  gboolean result;
-
-  result = ephy_bookmarks_export (self, self->gvdb_filename, NULL);
-
-  if (task)
-    g_task_return_boolean (task, result);
-}
-
 static void
 ephy_bookmarks_manager_copy_tags_from_bookmark (EphyBookmarksManager *self,
                                                 EphyBookmark         *dest,
@@ -106,6 +97,19 @@ ephy_bookmarks_manager_create_tags_from_bookmark (EphyBookmarksManager *self,
     ephy_bookmarks_manager_create_tag (self, g_sequence_get (iter));
 }
 
+static void
+ephy_bookmarks_manager_dispose (GObject *object)
+{
+  EphyBookmarksManager *self = EPHY_BOOKMARKS_MANAGER (object);
+
+  if (self->cancellable) {
+    g_cancellable_cancel (self->cancellable);
+    g_clear_object (&self->cancellable);
+  }
+
+  G_OBJECT_CLASS (ephy_bookmarks_manager_parent_class)->dispose (object);
+}
+
 static void
 ephy_bookmarks_manager_finalize (GObject *object)
 {
@@ -124,6 +128,7 @@ ephy_bookmarks_manager_class_init (EphyBookmarksManagerClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->dispose  = ephy_bookmarks_manager_dispose;
   object_class->finalize = ephy_bookmarks_manager_finalize;
 
   signals[BOOKMARK_ADDED] =
@@ -205,6 +210,10 @@ ephy_bookmarks_manager_class_init (EphyBookmarksManagerClass *klass)
 static void
 ephy_bookmarks_manager_init (EphyBookmarksManager *self)
 {
+  g_autoptr(GError) error = NULL;
+
+  self->cancellable = g_cancellable_new ();
+
   self->gvdb_filename = g_build_filename (ephy_profile_dir (),
                                           EPHY_BOOKMARKS_FILE,
                                           NULL);
@@ -218,10 +227,12 @@ ephy_bookmarks_manager_init (EphyBookmarksManager *self)
                             NULL);
 
   /* Create DB file if it doesn't already exists */
-  if (!g_file_test (self->gvdb_filename, G_FILE_TEST_EXISTS))
-    ephy_bookmarks_manager_save_to_file (self, NULL);
+  if (!g_file_test (self->gvdb_filename, G_FILE_TEST_EXISTS)) {
+    if (!ephy_bookmarks_manager_save_sync (self, &error))
+      g_warning ("Failed to save bookmarks: %s", error->message);
+  }
 
-  ephy_bookmarks_manager_load_from_file (self);
+  ephy_bookmarks_import (self, self->gvdb_filename, NULL);
 }
 
 static void
@@ -329,9 +340,9 @@ ephy_bookmarks_manager_add_bookmark_internal (EphyBookmarksManager *self,
   }
 
   if (should_save)
-    ephy_bookmarks_manager_save_to_file_async (self, NULL,
-                                               
(GAsyncReadyCallback)ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                               NULL);
+    ephy_bookmarks_manager_save (self, self->cancellable,
+                                 (GAsyncReadyCallback)ephy_bookmarks_manager_save_warn_on_error_cb,
+                                 NULL);
 }
 
 void
@@ -362,9 +373,9 @@ ephy_bookmarks_manager_add_bookmarks (EphyBookmarksManager *self,
     g_signal_emit_by_name (self, "synchronizable-modified", bookmark, FALSE);
   }
 
-  ephy_bookmarks_manager_save_to_file_async (self, NULL,
-                                             
(GAsyncReadyCallback)ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (self, self->cancellable,
+                               (GAsyncReadyCallback)ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
 }
 
 static void
@@ -396,9 +407,9 @@ ephy_bookmarks_manager_remove_bookmark_internal (EphyBookmarksManager *self,
   g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
   g_signal_emit (self, signals[BOOKMARK_REMOVED], 0, bookmark);
 
-  ephy_bookmarks_manager_save_to_file_async (self, NULL,
-                                             
(GAsyncReadyCallback)ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (self, self->cancellable,
+                               (GAsyncReadyCallback)ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
 
   ephy_bookmarks_manager_unwatch_bookmark (self, bookmark);
   g_object_unref (bookmark);
@@ -580,50 +591,113 @@ ephy_bookmarks_manager_get_tags (EphyBookmarksManager *self)
 }
 
 void
-ephy_bookmarks_manager_save_to_file_async (EphyBookmarksManager *self,
-                                           GCancellable         *cancellable,
-                                           GAsyncReadyCallback   callback,
-                                           gpointer              user_data)
+ephy_bookmarks_manager_save_warn_on_error_cb (GObject      *object,
+                                              GAsyncResult *result,
+                                              gpointer      user_data)
+{
+  EphyBookmarksManager *self = EPHY_BOOKMARKS_MANAGER (object);
+  gboolean ret;
+  GError *error;
+
+  ret = ephy_bookmarks_manager_save_finish (self, result, &error);
+  if (ret == FALSE) {
+    g_warning ("%s", error->message);
+    g_error_free (error);
+  }
+}
+
+GCancellable *
+ephy_bookmarks_manager_save_warn_on_error_cancellable (EphyBookmarksManager *self)
+{
+  g_assert (EPHY_IS_BOOKMARKS_MANAGER (self));
+
+  return self->cancellable;
+}
+
+static void
+bookmarks_export_cb (GObject      *source_object,
+                     GAsyncResult *result,
+                     gpointer      user_data)
+{
+  EphyBookmarksManager *self = EPHY_BOOKMARKS_MANAGER (source_object);
+  g_autoptr(GTask) task = user_data;
+  GError *error;
+
+  if (!ephy_bookmarks_export_finish (self, result, &error)) {
+    g_task_return_error (task, error);
+    return;
+  }
+
+  g_task_return_boolean (task, TRUE);
+}
+
+void
+ephy_bookmarks_manager_save (EphyBookmarksManager *self,
+                             GCancellable         *cancellable,
+                             GAsyncReadyCallback   callback,
+                             gpointer              user_data)
 {
   GTask *task;
 
   task = g_task_new (self, cancellable, callback, user_data);
 
-  ephy_bookmarks_manager_save_to_file (self, task);
-
-  g_object_unref (task);
+  ephy_bookmarks_export (self, self->gvdb_filename,
+                         cancellable, bookmarks_export_cb, task);
 }
 
 gboolean
-ephy_bookmarks_manager_save_to_file_finish (EphyBookmarksManager *self,
-                                            GAsyncResult         *result,
-                                            GError              **error)
+ephy_bookmarks_manager_save_finish (EphyBookmarksManager *self,
+                                    GAsyncResult         *result,
+                                    GError              **error)
 {
   g_assert (g_task_is_valid (result, self));
 
   return g_task_propagate_boolean (G_TASK (result), error);
 }
 
-void
-ephy_bookmarks_manager_load_from_file (EphyBookmarksManager *self)
+typedef struct {
+  GMainLoop *main_loop;
+  gboolean   result;
+  GError    *error;
+} SaveToFileData;
+
+static void
+save_to_file_cb (GObject      *source_object,
+                 GAsyncResult *result,
+                 gpointer      user_data)
 {
-  ephy_bookmarks_import (self, self->gvdb_filename, NULL);
+  EphyBookmarksManager *self = EPHY_BOOKMARKS_MANAGER (source_object);
+  SaveToFileData *data = user_data;
+
+  data->result = ephy_bookmarks_manager_save_finish (self, result, &data->error);
+
+  g_main_loop_quit (data->main_loop);
 }
 
-void
-ephy_bookmarks_manager_save_to_file_warn_on_error_cb (GObject      *object,
-                                                      GAsyncResult *result,
-                                                      gpointer      user_data)
+gboolean
+ephy_bookmarks_manager_save_sync (EphyBookmarksManager  *self,
+                                  GError               **error)
 {
-  EphyBookmarksManager *self = EPHY_BOOKMARKS_MANAGER (object);
-  gboolean ret;
-  GError *error;
+  g_autoptr(GMainContext) context = NULL;
+  SaveToFileData *data;
+  gboolean result;
 
-  ret = ephy_bookmarks_manager_save_to_file_finish (self, result, &error);
-  if (ret == FALSE) {
-    g_warning ("%s", error->message);
-    g_error_free (error);
-  }
+  context = g_main_context_new ();
+  data = g_new (SaveToFileData, 1);
+  data->main_loop = g_main_loop_new (context, FALSE);
+
+  g_main_context_push_thread_default (context);
+  ephy_bookmarks_manager_save (self, NULL, save_to_file_cb, data);
+  g_main_loop_run (data->main_loop);
+  g_main_context_pop_thread_default (context);
+
+  result = data->result;
+  g_propagate_error (error, data->error);
+
+  g_main_loop_unref (data->main_loop);
+  g_free (data);
+
+  return result;
 }
 
 static GType
@@ -725,9 +799,9 @@ synchronizable_manager_save (EphySynchronizableManager *manager,
 {
   EphyBookmarksManager *self = EPHY_BOOKMARKS_MANAGER (manager);
 
-  ephy_bookmarks_manager_save_to_file_async (self, NULL,
-                                             
(GAsyncReadyCallback)ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (self, self->cancellable,
+                               (GAsyncReadyCallback)ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
 }
 
 static GPtrArray *
@@ -815,9 +889,9 @@ next:
   }
 
   /* Commit changes to file. */
-  ephy_bookmarks_manager_save_to_file_async (self, NULL,
-                                             
(GAsyncReadyCallback)ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (self, self->cancellable,
+                               (GAsyncReadyCallback)ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
   g_hash_table_unref (dont_upload);
 
   return to_upload;
@@ -893,9 +967,9 @@ next:
   }
 
   /* Commit changes to file. */
-  ephy_bookmarks_manager_save_to_file_async (self, NULL,
-                                             
(GAsyncReadyCallback)ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  ephy_bookmarks_manager_save (self, self->cancellable,
+                               (GAsyncReadyCallback)ephy_bookmarks_manager_save_warn_on_error_cb,
+                               NULL);
 
   return to_upload;
 }
diff --git a/src/bookmarks/ephy-bookmarks-manager.h b/src/bookmarks/ephy-bookmarks-manager.h
index 797187335..fa70e8094 100644
--- a/src/bookmarks/ephy-bookmarks-manager.h
+++ b/src/bookmarks/ephy-bookmarks-manager.h
@@ -35,42 +35,44 @@ G_DECLARE_FINAL_TYPE (EphyBookmarksManager, ephy_bookmarks_manager, EPHY, BOOKMA
 #define EPHY_BOOKMARKS_MOBILE_TAG       N_("Mobile")
 #define FIREFOX_BOOKMARKS_MOBILE_FOLDER "Mobile Bookmarks"
 
-EphyBookmarksManager *ephy_bookmarks_manager_new                  (void);
+EphyBookmarksManager *ephy_bookmarks_manager_new                    (void);
 
-void         ephy_bookmarks_manager_add_bookmark                  (EphyBookmarksManager *self,
-                                                                   EphyBookmark         *bookmark);
-void         ephy_bookmarks_manager_add_bookmarks                 (EphyBookmarksManager *self,
-                                                                   GSequence            *bookmarks);
-void         ephy_bookmarks_manager_remove_bookmark               (EphyBookmarksManager *self,
-                                                                   EphyBookmark         *bookmark);
-EphyBookmark *ephy_bookmarks_manager_get_bookmark_by_url          (EphyBookmarksManager *self,
-                                                                   const char           *url);
-EphyBookmark *ephy_bookmarks_manager_get_bookmark_by_id           (EphyBookmarksManager *self,
-                                                                   const char           *id);
+void         ephy_bookmarks_manager_add_bookmark                    (EphyBookmarksManager *self,
+                                                                     EphyBookmark         *bookmark);
+void         ephy_bookmarks_manager_add_bookmarks                   (EphyBookmarksManager *self,
+                                                                     GSequence            *bookmarks);
+void         ephy_bookmarks_manager_remove_bookmark                 (EphyBookmarksManager *self,
+                                                                     EphyBookmark         *bookmark);
+EphyBookmark *ephy_bookmarks_manager_get_bookmark_by_url            (EphyBookmarksManager *self,
+                                                                     const char           *url);
+EphyBookmark *ephy_bookmarks_manager_get_bookmark_by_id             (EphyBookmarksManager *self,
+                                                                     const char           *id);
 
-void         ephy_bookmarks_manager_create_tag                    (EphyBookmarksManager *self,
-                                                                   const char           *tag);
-void         ephy_bookmarks_manager_delete_tag                    (EphyBookmarksManager *self,
-                                                                   const char           *tag);
-gboolean     ephy_bookmarks_manager_tag_exists                    (EphyBookmarksManager *self,
-                                                                   const char           *tag);
+void         ephy_bookmarks_manager_create_tag                      (EphyBookmarksManager *self,
+                                                                     const char           *tag);
+void         ephy_bookmarks_manager_delete_tag                      (EphyBookmarksManager *self,
+                                                                     const char           *tag);
+gboolean     ephy_bookmarks_manager_tag_exists                      (EphyBookmarksManager *self,
+                                                                     const char           *tag);
 
-GSequence   *ephy_bookmarks_manager_get_bookmarks                 (EphyBookmarksManager *self);
-GSequence   *ephy_bookmarks_manager_get_bookmarks_with_tag        (EphyBookmarksManager *self,
-                                                                   const char           *tag);
-GSequence   *ephy_bookmarks_manager_get_tags                      (EphyBookmarksManager *self);
+GSequence   *ephy_bookmarks_manager_get_bookmarks                   (EphyBookmarksManager *self);
+GSequence   *ephy_bookmarks_manager_get_bookmarks_with_tag          (EphyBookmarksManager *self,
+                                                                     const char           *tag);
+GSequence   *ephy_bookmarks_manager_get_tags                        (EphyBookmarksManager *self);
 
-void        ephy_bookmarks_manager_save_to_file_async             (EphyBookmarksManager *self,
-                                                                   GCancellable         *cancellable,
-                                                                   GAsyncReadyCallback   callback,
-                                                                   gpointer              user_data);
-gboolean     ephy_bookmarks_manager_save_to_file_finish           (EphyBookmarksManager *self,
-                                                                   GAsyncResult         *result,
-                                                                   GError              **error);
-void         ephy_bookmarks_manager_load_from_file                (EphyBookmarksManager *self);
+gboolean     ephy_bookmarks_manager_save_sync                       (EphyBookmarksManager  *self,
+                                                                     GError               **error);
+void         ephy_bookmarks_manager_save                            (EphyBookmarksManager  *self,
+                                                                     GCancellable          *cancellable,
+                                                                     GAsyncReadyCallback    callback,
+                                                                     gpointer               user_data);
+gboolean     ephy_bookmarks_manager_save_finish                     (EphyBookmarksManager  *self,
+                                                                     GAsyncResult          *result,
+                                                                     GError               **error);
 
-void         ephy_bookmarks_manager_save_to_file_warn_on_error_cb (GObject      *object,
-                                                                   GAsyncResult *result,
-                                                                   gpointer      user_data);
+void          ephy_bookmarks_manager_save_warn_on_error_cb          (GObject               *object,
+                                                                     GAsyncResult          *result,
+                                                                     gpointer               user_data);
+GCancellable *ephy_bookmarks_manager_save_warn_on_error_cancellable (EphyBookmarksManager  *self);
 
 G_END_DECLS
diff --git a/src/profile-migrator/ephy-profile-migrator.c b/src/profile-migrator/ephy-profile-migrator.c
index 7a3dda466..3a5ae4fdd 100644
--- a/src/profile-migrator/ephy-profile-migrator.c
+++ b/src/profile-migrator/ephy-profile-migrator.c
@@ -353,6 +353,7 @@ migrate_bookmarks (void)
   xmlDocPtr doc;
   xmlNodePtr child;
   xmlNodePtr root;
+  GError *error;
 
   filename = g_build_filename (legacy_profile_dir (),
                                EPHY_BOOKMARKS_FILE,
@@ -385,10 +386,10 @@ migrate_bookmarks (void)
     child = child->next;
   }
 
-  /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=772668 */
-  ephy_bookmarks_manager_save_to_file_async (manager, NULL,
-                                             ephy_bookmarks_manager_save_to_file_warn_on_error_cb,
-                                             NULL);
+  if (!ephy_bookmarks_manager_save_sync (manager, &error)) {
+    g_warning ("Failed to save bookmarks: %s", error->message);
+    g_error_free (error);
+  }
 
   xmlFreeDoc (doc);
   g_object_unref (manager);
diff --git a/src/window-commands.c b/src/window-commands.c
index ddb886055..e8c4f2d79 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -435,6 +435,29 @@ window_cmd_import_bookmarks (GSimpleAction *action,
   gtk_widget_show_all (dialog);
 }
 
+static void
+bookmarks_export_cb (GObject      *source_object,
+                     GAsyncResult *result,
+                     gpointer      user_data)
+{
+  EphyBookmarksManager *manager = EPHY_BOOKMARKS_MANAGER (source_object);
+  GtkWidget *export_info_dialog;
+  gboolean exported;
+  g_autoptr(GError) error = NULL;
+
+  exported = ephy_bookmarks_export_finish (manager, result, &error);
+
+  export_info_dialog = gtk_message_dialog_new (GTK_WINDOW (user_data),
+                                               GTK_DIALOG_MODAL,
+                                               exported ? GTK_MESSAGE_INFO : GTK_MESSAGE_WARNING,
+                                               GTK_BUTTONS_OK,
+                                               "%s",
+                                               exported ? _("Bookmarks successfully exported!") :
+                                                          error->message);
+  gtk_dialog_run (GTK_DIALOG (export_info_dialog));
+  gtk_widget_destroy (export_info_dialog);
+}
+
 void
 window_cmd_export_bookmarks (GSimpleAction *action,
                              GVariant      *parameter,
@@ -442,13 +465,12 @@ window_cmd_export_bookmarks (GSimpleAction *action,
 {
   EphyBookmarksManager *manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
   GtkFileChooser *dialog;
-  GtkWidget *export_info_dialog;
   int chooser_response;
-  gboolean exported;
   GtkFileFilter *filter;
+  GtkWindow *window = user_data;
 
   dialog = GTK_FILE_CHOOSER (gtk_file_chooser_native_new (_("Choose File"),
-                                                          GTK_WINDOW (user_data),
+                                                          window,
                                                           GTK_FILE_CHOOSER_ACTION_SAVE,
                                                           _("_Save"),
                                                           _("_Cancel")));
@@ -463,24 +485,13 @@ window_cmd_export_bookmarks (GSimpleAction *action,
 
   chooser_response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
   if (chooser_response == GTK_RESPONSE_ACCEPT) {
-    GError *error = NULL;
     char *filename;
 
     gtk_native_dialog_hide (GTK_NATIVE_DIALOG (dialog));
 
     filename = gtk_file_chooser_get_filename (dialog);
-    exported = ephy_bookmarks_export (manager, filename, &error);
+    ephy_bookmarks_export (manager, filename, NULL, bookmarks_export_cb, window);
     g_free (filename);
-
-    export_info_dialog = gtk_message_dialog_new (GTK_WINDOW (user_data),
-                                                 GTK_DIALOG_MODAL,
-                                                 exported ? GTK_MESSAGE_INFO : GTK_MESSAGE_WARNING,
-                                                 GTK_BUTTONS_OK,
-                                                 "%s",
-                                                 exported ? _("Bookmarks successfully exported!") :
-                                                            error->message);
-    gtk_dialog_run (GTK_DIALOG (export_info_dialog));
-    gtk_widget_destroy (export_info_dialog);
   }
 
   g_object_unref (dialog);



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