--- a/libpurple/prefs.c Wed Jun 15 04:59:21 2016 -0300
+++ b/libpurple/prefs.c Thu Jun 16 02:10:34 2016 -0300
@@ -42,11 +42,13 @@
static PurplePrefsUiOps *prefs_ui_ops = NULL;
+struct _PurplePrefCallbackData { /* TODO: This should use PurpleValues? */
@@ -80,6 +82,7 @@
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 @@
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);
+do_ui_callbacks(const char *name) + 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: + * cb_name = /toto/tata --> true + * cb_name = /toto/tatatiti --> false + * cb_name = /toto --> true + * cb_name = /toto/ --> true + purple_prefs_trigger_callback_object(cbs->data); 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) { + pref = find_pref(name); purple_debug_error("prefs",
@@ -1355,31 +1393,103 @@
purple_prefs_connect_callback(void *handle, const char *name, PurplePrefCallback func, gpointer data)
- struct purple_pref *pref;
+ struct purple_pref *pref = NULL; + PurplePrefCallbackData *cb; + PurplePrefsUiOps *uiop = NULL; g_return_val_if_fail(name != NULL, 0);
g_return_val_if_fail(func != NULL, 0);
- pref = find_pref(name);
- purple_debug_error("prefs", "purple_prefs_connect_callback: Unknown pref %s\n", name);
+ uiop = purple_prefs_get_ui_ops(); + if (!(uiop && uiop->connect_callback)) { + pref = find_pref(name); + purple_debug_error("prefs", "purple_prefs_connect_callback: Unknown pref %s\n", name); - cb = g_new0(struct pref_cb, 1);
+ cb = g_new0(PurplePrefCallbackData, 1); + 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); + ui_callbacks = g_slist_append(ui_callbacks, cb); + pref->callbacks = g_slist_append(pref->callbacks, cb); +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); + value = GINT_TO_POINTER(uiop->get_int(cb->name)); + case PURPLE_PREF_BOOLEAN: + value = GINT_TO_POINTER(uiop->get_bool(cb->name)); + case PURPLE_PREF_STRING: + if (uiop->get_string) { + value = uiop->get_string(cb->name); + case PURPLE_PREF_STRING_LIST: + case PURPLE_PREF_PATH_LIST: + if (uiop->get_string_list) { + value = uiop->get_string_list(cb->name); + purple_debug_error("prefs", "Unexpected type = %i\n", type); + cb->func(cb->name, type, value, cb->data); +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); + purple_prefs_trigger_callback(cb->name); disco_callback_helper(struct purple_pref *pref, guint callback_id)
@@ -1390,9 +1500,10 @@
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);
@@ -1406,10 +1517,35 @@
+disco_ui_callback_helper(guint callback_id) + 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); 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); + disco_callback_helper(&prefs, callback_id); @@ -1423,9 +1559,10 @@
- struct pref_cb *cb = cbs->data;
+ PurplePrefCallbackData *cb = cbs->data; if(cb->handle == handle) {
pref->callbacks = g_slist_delete_link(pref->callbacks, cbs);
@@ -1436,12 +1573,41 @@
disco_callback_helper_handle(child, handle);
+disco_ui_callback_helper_handle(void *handle) + PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops(); + for (cbs = ui_callbacks; cbs; cbs = cbs->next) { + PurplePrefCallbackData *cb = cbs->data; + if (cb->handle != handle) { + uiop->disconnect_callback(cb->name, cb->ui_data); + ui_callbacks = g_slist_delete_link(ui_callbacks, cbs); 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); + disco_callback_helper_handle(&prefs, handle); --- a/libpurple/prefs.h Wed Jun 15 04:59:21 2016 -0300
+++ b/libpurple/prefs.h Thu Jun 16 02:10:34 2016 -0300
@@ -62,6 +62,11 @@
typedef void (*PurplePrefCallback) (const char *name, PurplePrefType type,
gconstpointer val, gpointer data);
+ * Opaque type to carry callback information +typedef struct _PurplePrefCallbackData PurplePrefCallbackData; /** @copydoc _PurplePrefsUiOps */
typedef struct _PurplePrefsUiOps PurplePrefsUiOps;
@@ -100,8 +105,8 @@
void (*schedule_save)(void);
- void *(*add_observer)(const char *name, gpointer data);
- void (*remove_observer)(const char *name, void *observer);
+ void *(*connect_callback)(const char *name, PurplePrefCallbackData *data); + void (*disconnect_callback)(const char *name, void *ui_data); void (*_purple_reserved1)(void);
void (*_purple_reserved2)(void);
@@ -423,6 +428,13 @@
void purple_prefs_trigger_callback(const char *name);
+ * Trigger callbacks as if the pref changed, taking a #PurplePrefCallbackData +void purple_prefs_trigger_callback_object(PurplePrefCallbackData *data); gboolean purple_prefs_load(void);