--- a/libpurple/prefs.c Thu Jun 16 22:29:37 2016 -0500
+++ b/libpurple/prefs.c Thu Jun 16 22:30:49 2016 -0500
@@ -40,11 +40,15 @@
+static PurplePrefsUiOps *prefs_ui_ops = NULL; +struct _PurplePrefCallbackData { /* TODO: This should use PurpleValues? */
@@ -78,6 +82,24 @@
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, ...) \ + PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops(); \ + if (uiop && uiop->member) { \ + uiop->member(__VA_ARGS__); \ +#define PURPLE_PREFS_UI_OP_CALL_RETURN(member, ...) \ + PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops(); \ + if (uiop && uiop->member) { \ + return uiop->member(__VA_ARGS__); \ /*********************************************************************
@@ -207,6 +229,8 @@
+ PURPLE_PREFS_UI_OP_CALL(save); node = prefs_to_xmlnode();
data = xmlnode_to_formatted_str(node, NULL);
purple_util_write_data_to_file("prefs.xml", data, -1);
@@ -225,6 +249,8 @@
schedule_prefs_save(void)
+ PURPLE_PREFS_UI_OP_CALL(schedule_save); save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
@@ -376,12 +402,21 @@
- gchar *filename = g_build_filename(purple_user_dir(), "prefs.xml", NULL);
GMarkupParseContext *context;
+ PurplePrefsUiOps *uiop = purple_prefs_get_ui_ops(); + if (uiop && uiop->load) { + filename = g_build_filename(purple_user_dir(), "prefs.xml", NULL); @@ -605,13 +640,19 @@
purple_prefs_add_none(const char *name)
+ PURPLE_PREFS_UI_OP_CALL(add_none, name); add_pref(PURPLE_PREF_NONE, name);
purple_prefs_add_bool(const char *name, gboolean value)
- struct purple_pref *pref = add_pref(PURPLE_PREF_BOOLEAN, name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(add_bool, name, value); + pref = add_pref(PURPLE_PREF_BOOLEAN, name); @@ -622,7 +663,11 @@
purple_prefs_add_int(const char *name, int value)
- struct purple_pref *pref = add_pref(PURPLE_PREF_INT, name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(add_int, name, value); + pref = add_pref(PURPLE_PREF_INT, name); @@ -640,6 +685,8 @@
+ PURPLE_PREFS_UI_OP_CALL(add_string, name, value); pref = add_pref(PURPLE_PREF_STRING, name);
@@ -651,9 +698,13 @@
purple_prefs_add_string_list(const char *name, GList *value)
- struct purple_pref *pref = add_pref(PURPLE_PREF_STRING_LIST, name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(add_string_list, name, value); + pref = add_pref(PURPLE_PREF_STRING_LIST, name); @@ -670,7 +721,12 @@
purple_prefs_add_path(const char *name, const char *value)
- struct purple_pref *pref = add_pref(PURPLE_PREF_PATH, name);
+ struct purple_pref *pref; + /* re-use the string UI OP */ + PURPLE_PREFS_UI_OP_CALL(add_string, name, value); + pref = add_pref(PURPLE_PREF_PATH, name); @@ -681,9 +737,14 @@
purple_prefs_add_path_list(const char *name, GList *value)
- struct purple_pref *pref = add_pref(PURPLE_PREF_PATH_LIST, name);
+ struct purple_pref *pref; + /* re-use the string list UI OP */ + PURPLE_PREFS_UI_OP_CALL(add_string_list, name, value); + pref = add_pref(PURPLE_PREF_PATH_LIST, name); @@ -740,7 +801,11 @@
purple_prefs_remove(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(remove, name); + pref = find_pref(name); @@ -761,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",
@@ -781,6 +881,7 @@
do_callbacks(name, pref);
+/* this function is deprecated, so it doesn't get the new UI ops */ purple_prefs_set_generic(const char *name, gpointer value)
@@ -799,7 +900,11 @@
purple_prefs_set_bool(const char *name, gboolean value)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(set_bool, name, value); + pref = find_pref(name); if(pref->type != PURPLE_PREF_BOOLEAN) {
@@ -820,7 +925,11 @@
purple_prefs_set_int(const char *name, int value)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(set_int, name, value); + pref = find_pref(name); if(pref->type != PURPLE_PREF_INT) {
@@ -841,13 +950,17 @@
purple_prefs_set_string(const char *name, const char *value)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; if(value != NULL && !g_utf8_validate(value, -1, NULL)) {
purple_debug_error("prefs", "purple_prefs_set_string: Cannot store invalid UTF8 for string pref %s\n", name);
+ PURPLE_PREFS_UI_OP_CALL(set_string, name, value); + pref = find_pref(name); if(pref->type != PURPLE_PREF_STRING && pref->type != PURPLE_PREF_PATH) {
purple_debug_error("prefs",
@@ -868,7 +981,12 @@
purple_prefs_set_string_list(const char *name, GList *value)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(set_string_list, name, value); + pref = find_pref(name); @@ -903,7 +1021,11 @@
purple_prefs_set_path(const char *name, const char *value)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(set_string, name, value); + pref = find_pref(name); if(pref->type != PURPLE_PREF_PATH) {
@@ -925,7 +1047,12 @@
purple_prefs_set_path_list(const char *name, GList *value)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL(set_string_list, name, value); + pref = find_pref(name); @@ -956,7 +1083,11 @@
purple_prefs_exists(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(exists, name); + pref = find_pref(name); @@ -967,7 +1098,11 @@
purple_prefs_get_type(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_type, name); + pref = find_pref(name); @@ -978,7 +1113,11 @@
purple_prefs_get_bool(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_bool, name); + pref = find_pref(name); purple_debug_error("prefs",
@@ -996,7 +1135,11 @@
purple_prefs_get_int(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_int, name); + pref = find_pref(name); purple_debug_error("prefs",
@@ -1014,7 +1157,11 @@
purple_prefs_get_string(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_string, name); + pref = find_pref(name); purple_debug_error("prefs",
@@ -1032,9 +1179,13 @@
purple_prefs_get_string_list(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_string_list, name); + pref = find_pref(name); purple_debug_error("prefs",
"purple_prefs_get_string_list: Unknown pref %s\n", name);
@@ -1055,7 +1206,11 @@
purple_prefs_get_path(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_string, name); + pref = find_pref(name); purple_debug_error("prefs",
@@ -1073,9 +1228,13 @@
purple_prefs_get_path_list(const char *name)
- struct purple_pref *pref = find_pref(name);
+ struct purple_pref *pref; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_string_list, name); + pref = find_pref(name); purple_debug_error("prefs",
"purple_prefs_get_path_list: Unknown pref %s\n", name);
@@ -1166,6 +1325,8 @@
struct purple_pref *oldpref, *newpref;
+ PURPLE_PREFS_UI_OP_CALL(rename, oldname, newname); oldpref = find_pref(oldname);
/* it's already been renamed, call off the dogs */
@@ -1188,6 +1349,8 @@
struct purple_pref *oldpref, *newpref;
+ PURPLE_PREFS_UI_OP_CALL(rename_boolean_toggle, oldname, newname); oldpref = find_pref(oldname);
/* it's already been renamed, call off the cats */
@@ -1230,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)
@@ -1265,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);
@@ -1281,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); @@ -1298,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);
@@ -1311,21 +1573,54 @@
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); purple_prefs_get_children_names(const char *name)
- struct purple_pref *pref = find_pref(name), *child;
+ struct purple_pref *pref, *child; + PURPLE_PREFS_UI_OP_CALL_RETURN(get_children_names, name); + pref = find_pref(name); @@ -1451,8 +1746,7 @@
purple_timeout_remove(save_timer);
purple_prefs_disconnect_by_handle(purple_prefs_get_handle());
@@ -1463,3 +1757,15 @@
+purple_prefs_set_ui_ops(PurplePrefsUiOps *ops) +purple_prefs_get_ui_ops(void)