[evolution-data-server] ESourceRegistryServer: Add a "tweak-key-file" signal.



commit ff97f680df9eaf24664dc24b43c397c6cae79d3a
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun Dec 23 23:37:25 2012 -0500

    ESourceRegistryServer: Add a "tweak-key-file" signal.
    
    This signal is emitted from e_source_registry_server_load_file() just
    prior to instantiating an EServerSideSource.  Signal handlers can tweak
    the GKeyFile content as necessary and return TRUE to write the modified
    content back to disk.
    
    For the purposes of tweaking, it's easier to deal with a plain GKeyFile
    than an ESource instance.  An ESource, for example, does not allow key
    file groups to be removed.
    
    The return value is cumulative.  If any signal handler returns TRUE,
    the GKeyFile content is written back to disk.
    
    Unfortunately this breaks the libebackend ABI because I forgot to add a
    pool of reserved pointers to the ESourceRegistryServerClass.  Do so now,
    since we have the opportunity.

 configure.ac                           |    2 +-
 libebackend/e-source-registry-server.c |  110 +++++++++++++++++++++++++++++++-
 libebackend/e-source-registry-server.h |    6 ++
 3 files changed, 114 insertions(+), 4 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 2cc7e96..4b9b4d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -125,7 +125,7 @@ LIBCAMEL_CURRENT=43
 LIBCAMEL_REVISION=0
 LIBCAMEL_AGE=0
 
-LIBEBACKEND_CURRENT=5
+LIBEBACKEND_CURRENT=6
 LIBEBACKEND_REVISION=0
 LIBEBACKEND_AGE=0
 
diff --git a/libebackend/e-source-registry-server.c b/libebackend/e-source-registry-server.c
index 202cfba..6b1ec69 100644
--- a/libebackend/e-source-registry-server.c
+++ b/libebackend/e-source-registry-server.c
@@ -105,6 +105,7 @@ enum {
 	FILES_LOADED,
 	SOURCE_ADDED,
 	SOURCE_REMOVED,
+	TWEAK_KEY_FILE,
 	LAST_SIGNAL
 };
 
@@ -1233,6 +1234,18 @@ source_registry_server_source_removed (ESourceRegistryServer *server,
 	g_object_unref (dbus_object);
 }
 
+static gboolean
+source_registry_server_any_true (GSignalInvocationHint *ihint,
+                                 GValue *return_accu,
+                                 const GValue *handler_return,
+                                 gpointer unused)
+{
+	if (g_value_get_boolean (handler_return))
+		g_value_set_boolean (return_accu, TRUE);
+
+	return TRUE;
+}
+
 static void
 e_source_registry_server_class_init (ESourceRegistryServerClass *class)
 {
@@ -1316,7 +1329,7 @@ e_source_registry_server_class_init (ESourceRegistryServerClass *class)
 
 	/**
 	 * ESourceRegistryServer::source-removed:
-	 * @server: the #ESourceRegistryServer when emitted the signal
+	 * @server: the #ESourceRegistryServer which emitted the signal
 	 * @source: the #EServerSideSource that got removed
 	 *
 	 * Emitted when an #EServerSideSource is removed from @server.
@@ -1330,6 +1343,39 @@ e_source_registry_server_class_init (ESourceRegistryServerClass *class)
 		g_cclosure_marshal_VOID__OBJECT,
 		G_TYPE_NONE, 1,
 		E_TYPE_SERVER_SIDE_SOURCE);
+
+	/**
+	 * ESourceRegistryServer::tweak-key-file:
+	 * @server: the #ESourceRegistryServer which emitted the signal
+	 * @key_file: a #GKeyFile
+	 * @uid: a unique identifier string for @key_file
+	 *
+	 * Emitted from e_source_registry_server_load_file() just prior
+	 * to instantiating an #EServerSideSource.  Signal handlers can
+	 * tweak the @key_file content as necessary and return %TRUE to
+	 * write the modified content back to disk.
+	 *
+	 * For the purposes of tweaking, it's easier to deal with a plain
+	 * #GKeyFile than an #ESource instance.  An #ESource, for example,
+	 * does not allow key file groups to be removed.
+	 *
+	 * The return value is cumulative.  If any signal handler returns
+	 * %TRUE, the @key_file content is written back to disk.
+	 *
+	 * Returns: %TRUE if @key_file was modified, %FALSE otherwise
+	 *
+	 * Since: 3.8
+	 **/
+	signals[TWEAK_KEY_FILE] = g_signal_new (
+		"tweak-key-file",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ESourceRegistryServerClass, tweak_key_file),
+		source_registry_server_any_true, NULL,
+		NULL,
+		G_TYPE_BOOLEAN, 2,
+		G_TYPE_KEY_FILE,
+		G_TYPE_STRING);
 }
 
 static void
@@ -1749,6 +1795,57 @@ e_source_registry_server_load_directory (ESourceRegistryServer *server,
 	return TRUE;
 }
 
+/* Helper for e_source_registry_server_load_file() */
+static gboolean
+source_registry_server_tweak_key_file (ESourceRegistryServer *server,
+                                       GFile *file,
+                                       const gchar *uid,
+                                       GError **error)
+{
+	GKeyFile *key_file;
+	gchar *contents = NULL;
+	gsize length;
+	gboolean handler_pending;
+	gboolean success = FALSE;
+	gboolean tweaked = FALSE;
+
+	/* Skip this if no one's listening. */
+	handler_pending = g_signal_has_handler_pending (
+		server, signals[TWEAK_KEY_FILE], 0, FALSE);
+	if (!handler_pending)
+		return TRUE;
+
+	key_file = g_key_file_new ();
+
+	g_file_load_contents (file, NULL, &contents, &length, NULL, error);
+
+	if (contents != NULL) {
+		success = g_key_file_load_from_data (
+			key_file, contents, length,
+			G_KEY_FILE_KEEP_COMMENTS |
+			G_KEY_FILE_KEEP_TRANSLATIONS,
+			error);
+		g_free (contents);
+	}
+
+	if (success)
+		g_signal_emit (
+			server, signals[TWEAK_KEY_FILE], 0,
+			key_file, uid, &tweaked);
+
+	if (tweaked) {
+		contents = g_key_file_to_data (key_file, &length, NULL);
+		success = g_file_replace_contents (
+			file, contents, length, NULL, FALSE,
+			G_FILE_CREATE_NONE, NULL, NULL, error);
+		g_free (contents);
+	}
+
+	g_key_file_free (key_file);
+
+	return success;
+}
+
 /**
  * e_source_registry_server_load_file:
  * @server: an #ESourceRegistryServer
@@ -1775,6 +1872,7 @@ e_source_registry_server_load_file (ESourceRegistryServer *server,
 	ESource *source;
 	gboolean writable;
 	gboolean removable;
+	gboolean success = TRUE;
 	gchar *uid;
 
 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
@@ -1791,11 +1889,17 @@ e_source_registry_server_load_file (ESourceRegistryServer *server,
 	/* Check if we already have this file loaded. */
 	source = e_source_registry_server_ref_source (server, uid);
 
-	g_free (uid);
+	/* If the source is to be removable then the key file can
+	 * be written back to disk, and can therefore be tweaked. */
+	if (source == NULL && removable)
+		success = source_registry_server_tweak_key_file (
+			server, file, uid, error);
 
-	if (source == NULL)
+	if (source == NULL && success)
 		source = e_server_side_source_new (server, file, error);
 
+	g_free (uid);
+
 	if (source == NULL)
 		return NULL;
 
diff --git a/libebackend/e-source-registry-server.h b/libebackend/e-source-registry-server.h
index e4007cb..f262485 100644
--- a/libebackend/e-source-registry-server.h
+++ b/libebackend/e-source-registry-server.h
@@ -91,6 +91,12 @@ struct _ESourceRegistryServerClass {
 						 ESource *source);
 	void		(*source_removed)	(ESourceRegistryServer *server,
 						 ESource *source);
+	gboolean	(*tweak_key_file)	(ESourceRegistryServer *server,
+						 GKeyFile *key_file,
+						 const gchar *uid);
+
+	/* Reserved slots. */
+	gpointer reserved[16];
 };
 
 GType		e_source_registry_server_get_type



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