/pidgin/main: c3548438b3a8: Implement PurplePrefsUiOps.(dis)conn...

dx dx at dxzone.com.ar
Thu Jun 16 23:31:07 EDT 2016


Changeset: c3548438b3a816033e66723479569bb16e918eab
Author:	 dx <dx at dxzone.com.ar>
Date:	 2016-06-16 02:10 -0300
Branch:	 release-2.x.y
URL: https://hg.pidgin.im/pidgin/main/rev/c3548438b3a8

Description:

Implement PurplePrefsUiOps.(dis)connect_callback from instantbird

They were called observers in instantbird, but since that's a mozilla specific
term, I made it generic. Most of the code checks if connect_callback is defined
to call the functions that implement callback handling for the UI.

The main difference is that when the UI overrides the handling of the
preferences, find_pref() won't work, and the callbacks have to be stored
elsewhere.

diffstat:

 libpurple/prefs.c |  196 +++++++++++++++++++++++++++++++++++++++++++++++++----
 libpurple/prefs.h |   16 +++-
 2 files changed, 195 insertions(+), 17 deletions(-)

diffs (truncated from 336 to 300 lines):

diff --git a/libpurple/prefs.c b/libpurple/prefs.c
--- a/libpurple/prefs.c
+++ b/libpurple/prefs.c
@@ -42,11 +42,13 @@
 
 static PurplePrefsUiOps *prefs_ui_ops = NULL;
 
-struct pref_cb {
+struct _PurplePrefCallbackData {
 	PurplePrefCallback func;
 	gpointer data;
 	guint id;
 	void *handle;
+	void *ui_data;
+	char *name;
 };
 
 /* TODO: This should use PurpleValues? */
@@ -80,6 +82,7 @@ static struct purple_pref prefs = {
 static GHashTable *prefs_hash = NULL;
 static guint       save_timer = 0;
 static gboolean    prefs_loaded = FALSE;
+static GSList     *ui_callbacks = NULL;
 
 #define PURPLE_PREFS_UI_OP_CALL(member, ...) \
 	{ \
@@ -823,16 +826,51 @@ do_callbacks(const char* name, struct pu
 	struct purple_pref *cb_pref;
 	for(cb_pref = pref; cb_pref; cb_pref = cb_pref->parent) {
 		for(cbs = cb_pref->callbacks; cbs; cbs = cbs->next) {
-			struct pref_cb *cb = cbs->data;
+			PurplePrefCallbackData *cb = cbs->data;
 			cb->func(name, pref->type, pref->value.generic, cb->data);
 		}
 	}
 }
 
+static void
+do_ui_callbacks(const char *name)
+{
+	GSList *cbs;
+
+	purple_debug_misc("prefs", "trigger callback %s\n", name);
+
+	for (cbs = ui_callbacks; cbs; cbs = cbs->next) {
+		PurplePrefCallbackData *cb = cbs->data;
+		const char *cb_name = cb->name;
+		size_t len = strlen(cb_name);
+		if (!strncmp(cb_name, name, len) &&
+		    (name[len] == 0 || name[len] == '/' ||
+		     (len && name[len - 1] == '/'))) {
+			/* This test should behave like this:
+			 * name    = /toto/tata
+			 * cb_name = /toto/tata --> true
+			 * cb_name = /toto/tatatiti --> false
+			 * cb_name = / --> true
+			 * cb_name = /toto --> true
+			 * cb_name = /toto/ --> true
+			 */
+			purple_prefs_trigger_callback_object(cbs->data);
+		}
+	}
+}
+
 void
 purple_prefs_trigger_callback(const char *name)
 {
-	struct purple_pref *pref = find_pref(name);
+	struct purple_pref *pref;
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+
+	if (uiop && uiop->connect_callback) {
+		do_ui_callbacks(name);
+		return;
+	}
+
+	pref = find_pref(name);
 
 	if(!pref) {
 		purple_debug_error("prefs",
@@ -1355,31 +1393,103 @@ purple_prefs_rename_boolean_toggle(const
 guint
 purple_prefs_connect_callback(void *handle, const char *name, PurplePrefCallback func, gpointer data)
 {
-	struct purple_pref *pref;
-	struct pref_cb *cb;
+	struct purple_pref *pref = NULL;
+	PurplePrefCallbackData *cb;
 	static guint cb_id = 0;
+	PurplePrefsUiOps *uiop = NULL;
 
 	g_return_val_if_fail(name != NULL, 0);
 	g_return_val_if_fail(func != NULL, 0);
 
-	pref = find_pref(name);
-	if (pref == NULL) {
-		purple_debug_error("prefs", "purple_prefs_connect_callback: Unknown pref %s\n", name);
-		return 0;
+	uiop = purple_prefs_get_ui_ops();
+
+	if (!(uiop && uiop->connect_callback)) {
+		pref = find_pref(name);
+		if (pref == NULL) {
+			purple_debug_error("prefs", "purple_prefs_connect_callback: Unknown pref %s\n", name);
+			return 0;
+		}
 	}
 
-	cb = g_new0(struct pref_cb, 1);
+	cb = g_new0(PurplePrefCallbackData, 1);
 
 	cb->func = func;
 	cb->data = data;
 	cb->id = ++cb_id;
 	cb->handle = handle;
+	cb->name = g_strdup(name);
 
-	pref->callbacks = g_slist_append(pref->callbacks, cb);
+	if (uiop && uiop->connect_callback) {
+		cb->ui_data = uiop->connect_callback(name, cb);
+
+		if (cb->ui_data == NULL) {
+			purple_debug_error("prefs", "purple_prefs_connect_callback: connect failed for %s\n", name);
+			g_free(cb->name);
+			g_free(cb);
+			return 0;
+		}
+
+		ui_callbacks = g_slist_append(ui_callbacks, cb);
+	} else {
+		pref->callbacks = g_slist_append(pref->callbacks, cb);
+	}
 
 	return cb->id;
 }
 
+static void
+purple_prefs_trigger_ui_callback_object(PurplePrefCallbackData *cb)
+{
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+	gconstpointer value = NULL;
+	PurplePrefType type = PURPLE_PREF_NONE;
+
+	type = uiop->get_type(cb->name);
+
+	switch (type) {
+		case PURPLE_PREF_INT:
+			if (uiop->get_int) {
+				value = GINT_TO_POINTER(uiop->get_int(cb->name));
+			}
+			break;
+		case PURPLE_PREF_BOOLEAN:
+			if (uiop->get_bool) {
+				value = GINT_TO_POINTER(uiop->get_bool(cb->name));
+			}
+			break;
+		case PURPLE_PREF_STRING:
+		case PURPLE_PREF_PATH:
+			if (uiop->get_string) {
+				value = uiop->get_string(cb->name);
+			}
+			break;
+		case PURPLE_PREF_STRING_LIST:
+		case PURPLE_PREF_PATH_LIST:
+			if (uiop->get_string_list) {
+				value = uiop->get_string_list(cb->name);
+			}
+			break;
+		case PURPLE_PREF_NONE:
+			break;
+		default:
+			purple_debug_error("prefs", "Unexpected type = %i\n", type);
+	}
+
+	cb->func(cb->name, type, value, cb->data);
+}
+
+void
+purple_prefs_trigger_callback_object(PurplePrefCallbackData *cb)
+{
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+
+	if (uiop && uiop->connect_callback && uiop->get_type) {
+		purple_prefs_trigger_ui_callback_object(cb);
+	} else {
+		purple_prefs_trigger_callback(cb->name);
+	}
+}
+
 static gboolean
 disco_callback_helper(struct purple_pref *pref, guint callback_id)
 {
@@ -1390,9 +1500,10 @@ disco_callback_helper(struct purple_pref
 		return FALSE;
 
 	for(cbs = pref->callbacks; cbs; cbs = cbs->next) {
-		struct pref_cb *cb = cbs->data;
+		PurplePrefCallbackData *cb = cbs->data;
 		if(cb->id == callback_id) {
 			pref->callbacks = g_slist_delete_link(pref->callbacks, cbs);
+			g_free(cb->name);
 			g_free(cb);
 			return TRUE;
 		}
@@ -1406,10 +1517,35 @@ disco_callback_helper(struct purple_pref
 	return FALSE;
 }
 
+static void
+disco_ui_callback_helper(guint callback_id)
+{
+	GSList *cbs;
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+
+	for (cbs = ui_callbacks; cbs; cbs = cbs->next) {
+		PurplePrefCallbackData *cb = cbs->data;
+		if (cb->id == callback_id) {
+			uiop->disconnect_callback(cb->name, cb->ui_data);
+
+			ui_callbacks = g_slist_delete_link(ui_callbacks, cbs);
+			g_free(cb->name);
+			g_free(cb);
+			return;
+		}
+	}
+}
+
 void
 purple_prefs_disconnect_callback(guint callback_id)
 {
-	disco_callback_helper(&prefs, callback_id);
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+
+	if (uiop && uiop->disconnect_callback) {
+		disco_ui_callback_helper(callback_id);
+	} else {
+		disco_callback_helper(&prefs, callback_id);
+	}
 }
 
 static void
@@ -1423,9 +1559,10 @@ disco_callback_helper_handle(struct purp
 
 	cbs = pref->callbacks;
 	while (cbs != NULL) {
-		struct pref_cb *cb = cbs->data;
+		PurplePrefCallbackData *cb = cbs->data;
 		if(cb->handle == handle) {
 			pref->callbacks = g_slist_delete_link(pref->callbacks, cbs);
+			g_free(cb->name);
 			g_free(cb);
 			cbs = pref->callbacks;
 		} else
@@ -1436,12 +1573,41 @@ disco_callback_helper_handle(struct purp
 		disco_callback_helper_handle(child, handle);
 }
 
+static void
+disco_ui_callback_helper_handle(void *handle)
+{
+	GSList *cbs;
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+
+	cbs = ui_callbacks;
+	for (cbs = ui_callbacks; cbs; cbs = cbs->next) {
+		PurplePrefCallbackData *cb = cbs->data;
+		if (cb->handle != handle) {
+			cbs = cbs->next;
+			continue;
+		}
+
+		uiop->disconnect_callback(cb->name, cb->ui_data);
+
+		ui_callbacks = g_slist_delete_link(ui_callbacks, cbs);
+		g_free(cb->name);
+		g_free(cb);
+		cbs = ui_callbacks;
+	}
+}
+
 void
 purple_prefs_disconnect_by_handle(void *handle)
 {
+	PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops();
+
 	g_return_if_fail(handle != NULL);
 
-	disco_callback_helper_handle(&prefs, handle);
+	if (uiop && uiop->disconnect_callback) {
+		disco_ui_callback_helper_handle(handle);
+	} else {
+		disco_callback_helper_handle(&prefs, handle);
+	}
 }
 
 GList *
diff --git a/libpurple/prefs.h b/libpurple/prefs.h
--- a/libpurple/prefs.h
+++ b/libpurple/prefs.h
@@ -62,6 +62,11 @@ typedef enum _PurplePrefType



More information about the Commits mailing list