[nautilus] Refactor the load/save code for the list.



commit b80bfe38ac1cc4fd3561961d7f6f8b43ec786f20
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Mon Apr 12 15:04:35 2010 +0200

    Refactor the load/save code for the list.
    
    Don't use sync i/o anymore. This should also fix bug #532911.

 src/nautilus-bookmark-list.c |  255 ++++++++++++++++++++++++++----------------
 src/nautilus-bookmark-list.h |    2 +-
 2 files changed, 162 insertions(+), 95 deletions(-)
---
diff --git a/src/nautilus-bookmark-list.c b/src/nautilus-bookmark-list.c
index 0e57768..f7e1b7c 100644
--- a/src/nautilus-bookmark-list.c
+++ b/src/nautilus-bookmark-list.c
@@ -36,6 +36,8 @@
 #include <gio/gio.h>
 
 #define MAX_BOOKMARK_LENGTH 80
+#define LOAD_JOB 1
+#define SAVE_JOB 2
 
 enum {
 	CONTENTS_CHANGED,
@@ -165,6 +167,8 @@ do_finalize (GObject *object)
 		NAUTILUS_BOOKMARK_LIST (object)->monitor = NULL;
 	}
 
+	g_queue_free (NAUTILUS_BOOKMARK_LIST (object)->pending_ops);
+
 	clear (NAUTILUS_BOOKMARK_LIST (object));
 
 	G_OBJECT_CLASS (nautilus_bookmark_list_parent_class)->finalize (object);
@@ -199,7 +203,6 @@ bookmark_monitor_changed_cb (GFileMonitor      *monitor,
 	    eflags == G_FILE_MONITOR_EVENT_CREATED) {
 		g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (NAUTILUS_BOOKMARK_LIST (user_data)));
 		nautilus_bookmark_list_load_file (NAUTILUS_BOOKMARK_LIST (user_data));
-		g_signal_emit (user_data, signals[CONTENTS_CHANGED], 0);
 	}
 }
 
@@ -208,6 +211,8 @@ nautilus_bookmark_list_init (NautilusBookmarkList *bookmarks)
 {
 	GFile *file;
 
+	bookmarks->pending_ops = g_queue_new ();
+
 	nautilus_bookmark_list_load_file (bookmarks);
 
 	file = nautilus_bookmark_list_get_file ();
@@ -249,7 +254,7 @@ nautilus_bookmark_list_append (NautilusBookmarkList *bookmarks,
 				  nautilus_bookmark_copy (bookmark), 
 				  -1);
 
-	nautilus_bookmark_list_contents_changed (bookmarks);
+	nautilus_bookmark_list_save_file (bookmarks);
 }
 
 /**
@@ -275,21 +280,6 @@ nautilus_bookmark_list_contains (NautilusBookmarkList *bookmarks,
 }
 
 /**
- * nautilus_bookmark_list_contents_changed:
- * 
- * Save the bookmark list to disk, and emit the contents_changed signal.
- * @bookmarks: NautilusBookmarkList whose contents have been modified.
- **/ 
-void
-nautilus_bookmark_list_contents_changed (NautilusBookmarkList *bookmarks)
-{
-	g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
-
-	nautilus_bookmark_list_save_file (bookmarks);
-	g_signal_emit (bookmarks, signals[CONTENTS_CHANGED], 0);
-}
-
-/**
  * nautilus_bookmark_list_delete_item_at:
  * 
  * Delete the bookmark at the specified position.
@@ -314,7 +304,7 @@ nautilus_bookmark_list_delete_item_at (NautilusBookmarkList *bookmarks,
 
 	g_list_free_1 (doomed);
 
-	nautilus_bookmark_list_contents_changed (bookmarks);
+	nautilus_bookmark_list_save_file (bookmarks);
 }
 
 /**
@@ -349,7 +339,7 @@ nautilus_bookmark_list_move_item (NautilusBookmarkList *bookmarks,
 						 destination);
 	}
 
-	nautilus_bookmark_list_contents_changed (bookmarks);
+	nautilus_bookmark_list_save_file (bookmarks);
 }
 
 /**
@@ -386,7 +376,7 @@ nautilus_bookmark_list_delete_items_with_uri (NautilusBookmarkList *bookmarks,
 	}
 
 	if (list_changed) {
-		nautilus_bookmark_list_contents_changed (bookmarks);
+		nautilus_bookmark_list_save_file (bookmarks);
 	}
 }
 
@@ -426,7 +416,7 @@ nautilus_bookmark_list_insert_item (NautilusBookmarkList *bookmarks,
 				  nautilus_bookmark_copy (new_bookmark), 
 				  index);
 
-	nautilus_bookmark_list_contents_changed (bookmarks);
+	nautilus_bookmark_list_save_file (bookmarks);
 }
 
 /**
@@ -463,25 +453,18 @@ nautilus_bookmark_list_length (NautilusBookmarkList *bookmarks)
 	return g_list_length (bookmarks->list);
 }
 
-/**
- * nautilus_bookmark_list_load_file:
- * 
- * Reads bookmarks from file, clobbering contents in memory.
- * @bookmarks: the list of bookmarks to fill with file contents.
- **/
 static void
-nautilus_bookmark_list_load_file (NautilusBookmarkList *bookmarks)
+load_file_finish (NautilusBookmarkList *bookmarks,
+		  GObject *source,
+		  GAsyncResult *res)
 {
-	GFile *file;
-	char *contents;
 	GError *error = NULL;
+	gchar *contents = NULL;
 
-	file = nautilus_bookmark_list_get_file ();
-
-	/* Wipe out old list. */
-	clear (bookmarks);
+	g_file_load_contents_finish (G_FILE (source),
+				     res, &contents, NULL, NULL, &error);
 
-	if (g_file_load_contents (file, NULL, &contents, NULL, NULL, &error)) {
+	if (error == NULL) {
         	char **lines;
       		int i;
 
@@ -508,45 +491,67 @@ nautilus_bookmark_list_load_file (NautilusBookmarkList *bookmarks)
 		}
       		g_free (contents);
        		g_strfreev (lines);
-	}
-	else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+
+		g_signal_emit (bookmarks, signals[CONTENTS_CHANGED], 0);
+	} else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
 		g_warning ("Could not load bookmark file: %s\n", error->message);
 		g_error_free (error);
 	}
+}
+
+static void
+load_file_async (NautilusBookmarkList *self,
+		 GAsyncReadyCallback callback)
+{
+	GFile *file;
+
+	file = nautilus_bookmark_list_get_file ();
+
+	/* Wipe out old list. */
+	clear (self);
+
+	/* keep the bookmark list alive */
+	g_object_ref (self);
+	g_file_load_contents_async (file, NULL, callback, self);
 
 	g_object_unref (file);
 }
 
-/**
- * nautilus_bookmark_list_new:
- * 
- * Create a new bookmark_list, with contents read from disk.
- * 
- * Return value: A pointer to the new widget.
- **/
-NautilusBookmarkList *
-nautilus_bookmark_list_new (void)
+static void
+save_file_finish (NautilusBookmarkList *bookmarks,
+		  GObject *source,
+		  GAsyncResult *res)
 {
-	NautilusBookmarkList *list;
+	GError *error = NULL;
+	GFile *file;
 
-	list = NAUTILUS_BOOKMARK_LIST (g_object_new (NAUTILUS_TYPE_BOOKMARK_LIST, NULL));
+	g_file_replace_contents_finish (G_FILE (source),
+					res, NULL, &error);
 
-	return g_object_ref_sink (list);
+	if (error != NULL) {
+		g_warning ("Unable to replace contents of the bookmarks file: %s",
+			   error->message);
+		g_error_free (error);
+	}
+
+	file = nautilus_bookmark_list_get_file ();
+
+	/* re-enable bookmark file monitoring */
+	bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL);
+	g_file_monitor_set_rate_limit (bookmarks->monitor, 1000);
+	g_signal_connect (bookmarks->monitor, "changed",
+			  G_CALLBACK (bookmark_monitor_changed_cb), bookmarks);
+
+	g_object_unref (file);
 }
 
-/**
- * nautilus_bookmark_list_save_file:
- * 
- * Save bookmarks to disk.
- * @bookmarks: the list of bookmarks to save.
- **/
 static void
-nautilus_bookmark_list_save_file (NautilusBookmarkList *bookmarks)
+save_file_async (NautilusBookmarkList *bookmarks,
+		 GAsyncReadyCallback callback)
 {
 	GFile *file;
-	GOutputStream *out;
-	GError *error = NULL;
 	GList *l;
+	GString *bookmark_string;
 
 	/* temporarily disable bookmark file monitoring when writing file */
 	if (bookmarks->monitor != NULL) {
@@ -555,16 +560,10 @@ nautilus_bookmark_list_save_file (NautilusBookmarkList *bookmarks)
 	}
 
 	file = nautilus_bookmark_list_get_file ();
+	bookmark_string = g_string_new (NULL);
 
-	out = (GOutputStream *)g_file_replace (file, NULL, FALSE, 0, NULL, &error);
-	if (out == NULL) {
-		g_message ("Opening bookmark file failed: %s\n", error->message);
-		goto error;
-	}
-
-      	for (l = bookmarks->list; l; l = l->next) {
+	for (l = bookmarks->list; l; l = l->next) {
 		NautilusBookmark *bookmark;
-		char *bookmark_string;
 
 		bookmark = NAUTILUS_BOOKMARK (l->data);
 
@@ -573,50 +572,118 @@ nautilus_bookmark_list_save_file (NautilusBookmarkList *bookmarks)
 			char *label, *uri;
 			label = nautilus_bookmark_get_name (bookmark);
 			uri = nautilus_bookmark_get_uri (bookmark);
-			bookmark_string = g_strconcat (uri, " ", label, "\n", NULL);
+			g_string_append_printf (bookmark_string,
+						"%s %s\n", uri, label);
 			g_free (uri);
 			g_free (label);
 		} else {
 			char *uri;
 			uri = nautilus_bookmark_get_uri (bookmark);
-			bookmark_string = g_strconcat (uri, "\n", NULL);
+			g_string_append_printf (bookmark_string, "%s\n", uri);
 			g_free (uri);
 		}
+	}
 
-		if (!g_output_stream_write_all (out,
-						bookmark_string,
-						strlen (bookmark_string),
-						NULL, NULL,
-						&error)) {
-			g_warning ("writing %s to bookmark file failed: %s\n",
-				   bookmark_string, error->message); 
-			g_free (bookmark_string);
-    			goto error;
-		}
+	/* keep the bookmark list alive */
+	g_object_ref (bookmarks);
+	g_file_replace_contents_async (file, bookmark_string->str,
+				       bookmark_string->len, NULL,
+				       FALSE, 0, NULL, callback,
+				       bookmarks);
+
+	g_object_unref (file);
+}
+
+static void
+process_next_op (NautilusBookmarkList *bookmarks);
+
+static void
+op_processed_cb (GObject *source,
+		 GAsyncResult *res,
+		 gpointer user_data)
+{
+	NautilusBookmarkList *self = user_data;
+	int op;
+
+	op = GPOINTER_TO_INT (g_queue_pop_tail (self->pending_ops));
 
-		g_free (bookmark_string);
+	if (op == LOAD_JOB) {
+		load_file_finish (self, source, res);
+	} else {
+		save_file_finish (self, source, res);
 	}
 
-	if (!g_output_stream_close (out, NULL, &error)) {
-		g_warning ("Closing bookmark file failed: %s\n", error->message);
+	if (!g_queue_is_empty (self->pending_ops)) {
+		process_next_op (self);
 	}
 
-error:
-	if (error)
-		g_error_free (error);
+	/* release the reference acquired during the _async method */
+	g_object_unref (self);
+}
+
+static void
+process_next_op (NautilusBookmarkList *bookmarks)
+{
+	gint op;
 
-	if (out)
-		g_object_unref (out);
+	op = GPOINTER_TO_INT (g_queue_peek_tail (bookmarks->pending_ops));
 
-	/* re-enable bookmark file monitoring */
-	bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL);
-	g_file_monitor_set_rate_limit (bookmarks->monitor, 1000);
-	g_signal_connect (bookmarks->monitor, "changed",
-			  G_CALLBACK (bookmark_monitor_changed_cb), bookmarks);
+	if (op == LOAD_JOB) {
+		load_file_async (bookmarks, op_processed_cb);
+	} else {
+		save_file_async (bookmarks, op_processed_cb);
+	}
+}
 
-	if (out)
-		g_object_unref (out);
-	g_object_unref (file);
+/**
+ * nautilus_bookmark_list_load_file:
+ * 
+ * Reads bookmarks from file, clobbering contents in memory.
+ * @bookmarks: the list of bookmarks to fill with file contents.
+ **/
+static void
+nautilus_bookmark_list_load_file (NautilusBookmarkList *bookmarks)
+{
+	g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (LOAD_JOB));
+
+	if (g_queue_get_length (bookmarks->pending_ops) == 1) {
+		process_next_op (bookmarks);
+	}
+}
+
+/**
+ * nautilus_bookmark_list_save_file:
+ * 
+ * Save bookmarks to disk.
+ * @bookmarks: the list of bookmarks to save.
+ **/
+static void
+nautilus_bookmark_list_save_file (NautilusBookmarkList *bookmarks)
+{
+	g_signal_emit (bookmarks, signals[CONTENTS_CHANGED], 0);
+
+	g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (SAVE_JOB));
+
+	if (g_queue_get_length (bookmarks->pending_ops) == 1) {
+		process_next_op (bookmarks);
+	}
+}
+
+/**
+ * nautilus_bookmark_list_new:
+ * 
+ * Create a new bookmark_list, with contents read from disk.
+ * 
+ * Return value: A pointer to the new widget.
+ **/
+NautilusBookmarkList *
+nautilus_bookmark_list_new (void)
+{
+	NautilusBookmarkList *list;
+
+	list = NAUTILUS_BOOKMARK_LIST (g_object_new (NAUTILUS_TYPE_BOOKMARK_LIST, NULL));
+
+	return g_object_ref_sink (list);
 }
 
 /**
diff --git a/src/nautilus-bookmark-list.h b/src/nautilus-bookmark-list.h
index 231b50e..dfb4e5e 100644
--- a/src/nautilus-bookmark-list.h
+++ b/src/nautilus-bookmark-list.h
@@ -51,6 +51,7 @@ struct NautilusBookmarkList {
 
 	GList *list; 
 	GFileMonitor *monitor;
+	GQueue *pending_ops;
 };
 
 struct NautilusBookmarkListClass {
@@ -64,7 +65,6 @@ void                    nautilus_bookmark_list_append              (NautilusBook
 								    NautilusBookmark *bookmark);
 gboolean                nautilus_bookmark_list_contains            (NautilusBookmarkList   *bookmarks,
 								    NautilusBookmark *bookmark);
-void                    nautilus_bookmark_list_contents_changed    (NautilusBookmarkList   *bookmarks);
 void                    nautilus_bookmark_list_delete_item_at      (NautilusBookmarkList   *bookmarks,
 								    guint                   index);
 void                    nautilus_bookmark_list_delete_items_with_uri (NautilusBookmarkList *bookmarks,



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