Thu, 18 Jul 2019 03:45:06 +0000
Merged in default (pull request #521)
Convert buddy list UI ops into a derivable GObject instead
Approved-by: Gary Kramlich
| ChangeLog.API | file | annotate | diff | comparison | revisions | |
| libpurple/buddylist.h | file | annotate | diff | comparison | revisions |
--- a/ChangeLog.API Wed Jul 17 09:52:28 2019 +0000 +++ b/ChangeLog.API Thu Jul 18 03:45:06 2019 +0000 @@ -403,8 +403,10 @@ * purple_account_set_current_error * purple_account_set_ui_data * purple_base64_*. Use g_base64_* instead + * purple_blist_get_ui_data * purple_blist_load * purple_blist_new + * purple_blist_set_ui_data * purple_set_blist * purple_blist_update_buddy_icon * purple_buddy_get_local_alias
--- a/finch/finch.h Wed Jul 17 09:52:28 2019 +0000 +++ b/finch/finch.h Thu Jul 18 03:45:06 2019 +0000 @@ -34,9 +34,6 @@ #define FINCH_PREFS_ROOT "/finch" -#define FINCH_GET_DATA(obj) (obj)->ui_data -#define FINCH_SET_DATA(obj, data) (obj)->ui_data = data - /** * finch_start: *
--- a/finch/gntblist.c Wed Jul 17 09:52:28 2019 +0000 +++ b/finch/gntblist.c Thu Jul 18 03:45:06 2019 +0000 @@ -65,8 +65,9 @@ #define SHOW_EMPTY_GROUP_TIMEOUT 60 -typedef struct -{ +struct _FinchBuddyList { + PurpleBuddyList parent; + GntWidget *window; GntWidget *tree; @@ -96,7 +97,7 @@ guint new_group_timeout; FinchBlistManager *manager; -} FinchBlist; +}; typedef struct { @@ -122,23 +123,24 @@ } u; } StatusBoxItem; -static FinchBlist *ggblist; - -static void add_buddy(PurpleBuddy *buddy, FinchBlist *ggblist); -static void add_contact(PurpleContact *contact, FinchBlist *ggblist); -static void add_group(PurpleGroup *group, FinchBlist *ggblist); -static void add_chat(PurpleChat *chat, FinchBlist *ggblist); -static void add_node(PurpleBlistNode *node, FinchBlist *ggblist); +static FinchBuddyList *ggblist; + +static void add_buddy(PurpleBuddy *buddy, FinchBuddyList *ggblist); +static void add_contact(PurpleContact *contact, FinchBuddyList *ggblist); +static void add_group(PurpleGroup *group, FinchBuddyList *ggblist); +static void add_chat(PurpleChat *chat, FinchBuddyList *ggblist); +static void add_node(PurpleBlistNode *node, FinchBuddyList *ggblist); static void node_update(PurpleBuddyList *list, PurpleBlistNode *node); -static void draw_tooltip(FinchBlist *ggblist); +static void draw_tooltip(FinchBuddyList *ggblist); static void tooltip_for_buddy(PurpleBuddy *buddy, GString *str, gboolean full); static gboolean remove_typing_cb(gpointer null); -static void remove_peripherals(FinchBlist *ggblist); +static void remove_peripherals(FinchBuddyList *ggblist); static const char * get_display_name(PurpleBlistNode *node); static void savedstatus_changed(PurpleSavedStatus *now, PurpleSavedStatus *old); static void blist_show(PurpleBuddyList *list); -static void update_node_display(PurpleBlistNode *buddy, FinchBlist *ggblist); -static void update_buddy_display(PurpleBuddy *buddy, FinchBlist *ggblist); +static void update_node_display(PurpleBlistNode *buddy, + FinchBuddyList *ggblist); +static void update_buddy_display(PurpleBuddy *buddy, FinchBuddyList *ggblist); static gboolean account_autojoin_cb(PurpleConnection *pc, gpointer null); static void finch_request_add_buddy(PurpleBuddyList *list, PurpleAccount *account, @@ -372,7 +374,7 @@ } static GntTextFormatFlags -get_blist_node_flag(PurpleBlistNode *node) +get_blist_node_flag(FinchBuddyList *ggblist, PurpleBlistNode *node) { GntTextFormatFlags flag = 0; FinchBlistNode *fnode = purple_blist_node_get_ui_data(node); @@ -393,9 +395,10 @@ } static void -blist_update_row_flags(PurpleBlistNode *node) +blist_update_row_flags(FinchBuddyList *ggblist, PurpleBlistNode *node) { - gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), node, get_blist_node_flag(node)); + gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), node, + get_blist_node_flag(ggblist, node)); gnt_tree_set_row_color(GNT_TREE(ggblist->tree), node, get_display_color(node)); } @@ -405,7 +408,7 @@ } static void -add_node(PurpleBlistNode *node, FinchBlist *ggblist) +add_node(PurpleBlistNode *node, FinchBuddyList *ggblist) { if (purple_blist_node_get_ui_data(node)) return; @@ -431,7 +434,7 @@ } static void -remove_tooltip(FinchBlist *ggblist) +remove_tooltip(FinchBuddyList *ggblist) { gnt_widget_destroy(ggblist->tooltip); ggblist->tooltip = NULL; @@ -441,7 +444,7 @@ static void node_remove(PurpleBuddyList *list, PurpleBlistNode *node) { - FinchBlist *ggblist = FINCH_GET_DATA(list); + FinchBuddyList *ggblist = FINCH_BUDDY_LIST(list); PurpleBlistNode *parent; if (ggblist == NULL || purple_blist_node_get_ui_data(node) == NULL) @@ -474,14 +477,15 @@ static void node_update(PurpleBuddyList *list, PurpleBlistNode *node) { + FinchBuddyList *ggblist; + + g_return_if_fail(FINCH_IS_BUDDY_LIST(list)); /* It really looks like this should never happen ... but it does. This will at least emit a warning to the log when it happens, so maybe someone will figure it out. */ g_return_if_fail(node != NULL); - if (FINCH_GET_DATA(list)== NULL) - return; /* XXX: this is probably the place to auto-join chats */ - + ggblist = FINCH_BUDDY_LIST(list); if (ggblist->window == NULL) return; @@ -489,7 +493,7 @@ gnt_tree_change_text(GNT_TREE(ggblist->tree), node, 0, get_display_name(node)); gnt_tree_sort_row(GNT_TREE(ggblist->tree), node); - blist_update_row_flags(node); + blist_update_row_flags(ggblist, node); if (gnt_tree_get_parent_key(GNT_TREE(ggblist->tree), node) != ggblist->manager->find_parent(node)) node_remove(list, node); @@ -497,60 +501,36 @@ if (PURPLE_IS_BUDDY(node)) { PurpleBuddy *buddy = (PurpleBuddy*)node; - add_node((PurpleBlistNode*)buddy, FINCH_GET_DATA(list)); + add_node((PurpleBlistNode *)buddy, FINCH_BUDDY_LIST(list)); node_update(list, purple_blist_node_get_parent(node)); } else if (PURPLE_IS_CHAT(node)) { - add_node(node, FINCH_GET_DATA(list)); + add_node(node, FINCH_BUDDY_LIST(list)); } else if (PURPLE_IS_CONTACT(node)) { if (purple_blist_node_get_ui_data(node)== NULL) { /* The core seems to expect the UI to add the buddies. */ for (node = purple_blist_node_get_first_child(node); node; node = purple_blist_node_get_sibling_next(node)) - add_node(node, FINCH_GET_DATA(list)); + add_node(node, FINCH_BUDDY_LIST(list)); } } else if (PURPLE_IS_GROUP(node)) { if (!ggblist->manager->can_add_node(node)) node_remove(list, node); else - add_node(node, FINCH_GET_DATA(list)); + add_node(node, FINCH_BUDDY_LIST(list)); } if (ggblist->tnode == node) { draw_tooltip(ggblist); } } -static void -new_list(PurpleBuddyList *list) -{ - if (ggblist) - return; - - ggblist = g_new0(FinchBlist, 1); - FINCH_SET_DATA(list, ggblist); - ggblist->manager = finch_blist_manager_find(purple_prefs_get_string(PREF_ROOT "/grouping")); - if (!ggblist->manager) - ggblist->manager = &default_manager; -} - -static void destroy_list(PurpleBuddyList *list) -{ - if (ggblist == NULL) - return; - - gnt_widget_destroy(ggblist->window); - g_free(ggblist); - ggblist = NULL; -} - static gboolean remove_new_empty_group(gpointer data) { PurpleBuddyList *list; - - if (!ggblist) - return FALSE; + FinchBuddyList *ggblist; list = purple_blist_get_default(); g_return_val_if_fail(list, FALSE); + ggblist = FINCH_BUDDY_LIST(list); ggblist->new_group_timeout = 0; while (ggblist->new_group) { @@ -746,13 +726,14 @@ } static void -add_group_cb(gpointer null, const char *group) +add_group_cb(FinchBuddyList *ggblist, const char *group) { PurpleGroup *grp; if (!group || !*group) { purple_notify_error(NULL, _("Error"), _("Error adding group"), _("You must give a name for the group to add."), NULL); + g_object_unref(ggblist); return; } @@ -762,9 +743,6 @@ purple_blist_add_group(grp, NULL); } - if (!ggblist) - return; - /* Treat the group as a new group even if it had existed before. This should * make things easier to add buddies to empty groups (new or old) without having * to turn on 'show empty groups' setting */ @@ -781,35 +759,20 @@ add_node((PurpleBlistNode*)grp, ggblist); gnt_tree_set_selected(GNT_TREE(ggblist->tree), grp); } + + g_object_unref(ggblist); } static void finch_request_add_group(PurpleBuddyList *list) { - purple_request_input(NULL, _("Add Group"), NULL, _("Enter the name of the group"), - NULL, FALSE, FALSE, NULL, - _("Add"), G_CALLBACK(add_group_cb), _("Cancel"), NULL, - NULL, NULL); + purple_request_input(NULL, _("Add Group"), NULL, + _("Enter the name of the group"), NULL, FALSE, + FALSE, NULL, _("Add"), G_CALLBACK(add_group_cb), + _("Cancel"), G_CALLBACK(g_object_unref), NULL, + g_object_ref(list)); } -static PurpleBlistUiOps blist_ui_ops = -{ - new_list, - new_node, - blist_show, - node_update, - node_remove, - destroy_list, - NULL, - finch_request_add_buddy, - finch_request_add_chat, - finch_request_add_group, - NULL, - NULL, - NULL, - NULL, NULL, NULL, NULL -}; - static gpointer finch_blist_get_handle(void) { @@ -819,7 +782,7 @@ } static void -add_group(PurpleGroup *group, FinchBlist *ggblist) +add_group(PurpleGroup *group, FinchBuddyList *ggblist) { gpointer parent; PurpleBlistNode *node = (PurpleBlistNode *)group; @@ -892,7 +855,7 @@ } static void -add_chat(PurpleChat *chat, FinchBlist *ggblist) +add_chat(PurpleChat *chat, FinchBuddyList *ggblist) { gpointer parent; PurpleBlistNode *node = (PurpleBlistNode *)chat; @@ -909,7 +872,7 @@ } static void -add_contact(PurpleContact *contact, FinchBlist *ggblist) +add_contact(PurpleContact *contact, FinchBuddyList *ggblist) { gpointer parent; PurpleBlistNode *node = (PurpleBlistNode*)contact; @@ -932,7 +895,7 @@ } static void -add_buddy(PurpleBuddy *buddy, FinchBlist *ggblist) +add_buddy(PurpleBuddy *buddy, FinchBuddyList *ggblist) { gpointer parent; PurpleBlistNode *node = (PurpleBlistNode *)buddy; @@ -948,18 +911,14 @@ gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)), parent, NULL)); - blist_update_row_flags((PurpleBlistNode*)buddy); - if (buddy == purple_contact_get_priority_buddy(contact)) - blist_update_row_flags((PurpleBlistNode*)contact); -} - -PurpleBlistUiOps *finch_blist_get_ui_ops() -{ - return &blist_ui_ops; + blist_update_row_flags(ggblist, (PurpleBlistNode *)buddy); + if (buddy == purple_contact_get_priority_buddy(contact)) { + blist_update_row_flags(ggblist, (PurpleBlistNode *)contact); + } } static void -selection_activate(GntWidget *widget, FinchBlist *ggblist) +selection_activate(GntWidget *widget, FinchBuddyList *ggblist) { GntTree *tree = GNT_TREE(ggblist->tree); PurpleBlistNode *node = gnt_tree_get_selection_data(tree); @@ -1559,13 +1518,13 @@ } static void -context_menu_destroyed(GntWidget *widget, FinchBlist *ggblist) +context_menu_destroyed(GntWidget *widget, FinchBuddyList *ggblist) { ggblist->context = NULL; } static void -draw_context_menu(FinchBlist *ggblist) +draw_context_menu(FinchBuddyList *ggblist) { PurpleBlistNode *node = NULL; GntWidget *context = NULL; @@ -1720,7 +1679,7 @@ } static gboolean -draw_tooltip_real(FinchBlist *ggblist) +draw_tooltip_real(FinchBuddyList *ggblist) { PurpleBlistNode *node; int x, y, top, width, w, h; @@ -1790,7 +1749,7 @@ } static void -draw_tooltip(FinchBlist *ggblist) +draw_tooltip(FinchBuddyList *ggblist) { /* When an account has signed off, it removes one buddy at a time. * Drawing the tooltip after removing each buddy is expensive. On @@ -1803,21 +1762,22 @@ } static void -selection_changed(GntWidget *widget, gpointer old, gpointer current, FinchBlist *ggblist) +selection_changed(GntWidget *widget, gpointer old, gpointer current, + FinchBuddyList *ggblist) { remove_peripherals(ggblist); draw_tooltip(ggblist); } static gboolean -context_menu(GntWidget *widget, FinchBlist *ggblist) +context_menu(GntWidget *widget, FinchBuddyList *ggblist) { draw_context_menu(ggblist); return TRUE; } static gboolean -key_pressed(GntWidget *widget, const char *text, FinchBlist *ggblist) +key_pressed(GntWidget *widget, const char *text, FinchBuddyList *ggblist) { if (text[0] == 27 && text[1] == 0) { /* Escape was pressed */ @@ -1844,14 +1804,14 @@ } static void -update_node_display(PurpleBlistNode *node, FinchBlist *ggblist) +update_node_display(PurpleBlistNode *node, FinchBuddyList *ggblist) { - GntTextFormatFlags flag = get_blist_node_flag(node); + GntTextFormatFlags flag = get_blist_node_flag(ggblist, node); gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), node, flag); } static void -update_buddy_display(PurpleBuddy *buddy, FinchBlist *ggblist) +update_buddy_display(PurpleBuddy *buddy, FinchBuddyList *ggblist) { PurpleContact *contact; @@ -1860,28 +1820,31 @@ gnt_tree_change_text(GNT_TREE(ggblist->tree), buddy, 0, get_display_name((PurpleBlistNode*)buddy)); gnt_tree_change_text(GNT_TREE(ggblist->tree), contact, 0, get_display_name((PurpleBlistNode*)contact)); - blist_update_row_flags((PurpleBlistNode *)buddy); + blist_update_row_flags(ggblist, (PurpleBlistNode *)buddy); if (buddy == purple_contact_get_priority_buddy(contact)) - blist_update_row_flags((PurpleBlistNode *)contact); - - if (ggblist->tnode == (PurpleBlistNode*)buddy) + blist_update_row_flags(ggblist, (PurpleBlistNode *)contact); + + if (ggblist->tnode == (PurpleBlistNode *)buddy) { draw_tooltip(ggblist); + } } static void -buddy_status_changed(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *now, FinchBlist *ggblist) +buddy_status_changed(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *now, + FinchBuddyList *ggblist) { update_buddy_display(buddy, ggblist); } static void -buddy_idle_changed(PurpleBuddy *buddy, int old, int new, FinchBlist *ggblist) +buddy_idle_changed(PurpleBuddy *buddy, int old, int new, + FinchBuddyList *ggblist) { update_buddy_display(buddy, ggblist); } static void -remove_peripherals(FinchBlist *ggblist) +remove_peripherals(FinchBuddyList *ggblist) { if (ggblist->tooltip) remove_tooltip(ggblist); @@ -1910,7 +1873,6 @@ { PurpleBlistNode *node; purple_signals_disconnect_by_handle(finch_blist_get_handle()); - FINCH_SET_DATA(purple_blist_get_default(), NULL); node = purple_blist_get_default_root(); while (node) { @@ -1929,7 +1891,6 @@ if (ggblist->new_group) g_list_free(ggblist->new_group); - g_free(ggblist); ggblist = NULL; } @@ -3013,9 +2974,7 @@ static void blist_show(PurpleBuddyList *list) { - if (ggblist == NULL) - new_list(list); - else if (ggblist->window) { + if (ggblist->window) { gnt_window_present(ggblist->window); return; } @@ -3164,6 +3123,54 @@ } /************************************************************************** + * GObject code + **************************************************************************/ +G_DEFINE_TYPE(FinchBuddyList, finch_buddy_list, PURPLE_TYPE_BUDDY_LIST) + +static void +finch_buddy_list_init(FinchBuddyList *self) +{ + if (!ggblist) { + /* The first buddy list object becomes the default. */ + ggblist = self; + } + + self->manager = finch_blist_manager_find( + purple_prefs_get_string(PREF_ROOT "/grouping")); + if (!self->manager) { + self->manager = &default_manager; + } +} + +static void +finch_buddy_list_finalize(GObject *obj) +{ + FinchBuddyList *ggblist = FINCH_BUDDY_LIST(obj); + + gnt_widget_destroy(ggblist->window); + + G_OBJECT_CLASS(finch_buddy_list_parent_class)->finalize(obj); +} + +static void +finch_buddy_list_class_init(FinchBuddyListClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + PurpleBuddyListClass *purple_blist_class; + + obj_class->finalize = finch_buddy_list_finalize; + + purple_blist_class = PURPLE_BUDDY_LIST_CLASS(klass); + purple_blist_class->new_node = new_node; + purple_blist_class->show = blist_show; + purple_blist_class->update = node_update; + purple_blist_class->remove = node_remove; + purple_blist_class->request_add_buddy = finch_request_add_buddy; + purple_blist_class->request_add_chat = finch_request_add_chat; + purple_blist_class->request_add_group = finch_request_add_group; +} + +/************************************************************************** * GBoxed code **************************************************************************/ static FinchBlistManager *
--- a/finch/gntblist.h Wed Jul 17 09:52:28 2019 +0000 +++ b/finch/gntblist.h Thu Jul 18 03:45:06 2019 +0000 @@ -32,6 +32,7 @@ #include "gnt.h" #include "gnttree.h" +#define FINCH_TYPE_BUDDY_LIST (finch_buddy_list_get_type()) #define FINCH_TYPE_BLIST_MANAGER (finch_blist_manager_get_type()) /********************************************************************** @@ -74,14 +75,8 @@ */ GType finch_blist_manager_get_type(void); -/** - * finch_blist_get_ui_ops: - * - * Get the ui-functions. - * - * Returns: The PurpleBlistUiOps structure populated with the appropriate functions. - */ -PurpleBlistUiOps * finch_blist_get_ui_ops(void); +G_DECLARE_FINAL_TYPE(FinchBuddyList, finch_buddy_list, FINCH, BUDDY_LIST, + PurpleBuddyList) /** * finch_blist_init:
--- a/finch/gntui.c Wed Jul 17 09:52:28 2019 +0000 +++ b/finch/gntui.c Thu Jul 18 03:45:06 2019 +0000 @@ -65,7 +65,7 @@ /* Initialize the buddy list */ finch_blist_init(); - purple_blist_set_ui_ops(finch_blist_get_ui_ops()); + purple_blist_set_ui(FINCH_TYPE_BUDDY_LIST); /* Initialize sound */ purple_sound_set_ui_ops(finch_sound_get_ui_ops()); @@ -122,7 +122,7 @@ purple_connections_set_ui_ops(NULL); finch_connections_uninit(); - purple_blist_set_ui_ops(NULL); + purple_blist_set_ui(G_TYPE_INVALID); finch_blist_uninit(); purple_conversations_set_ui_ops(NULL);
--- a/libpurple/buddylist.c Wed Jul 17 09:52:28 2019 +0000 +++ b/libpurple/buddylist.c Thu Jul 18 03:45:06 2019 +0000 @@ -35,11 +35,11 @@ /* Private data for a buddy list. */ typedef struct { + PurpleBlistNode *root; GHashTable *buddies; /* Every buddy in this list */ } PurpleBuddyListPrivate; -static PurpleBlistUiOps *blist_ui_ops = NULL; - +static GType buddy_list_type = G_TYPE_INVALID; static PurpleBuddyList *purplebuddylist = NULL; G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddyList, purple_buddy_list, G_TYPE_OBJECT); @@ -454,11 +454,15 @@ void purple_blist_schedule_save() { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; + + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); + + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); /* Save everything */ - if (ops && ops->save_account) { - ops->save_account(purplebuddylist, NULL); + if (klass && klass->save_account) { + klass->save_account(purplebuddylist, NULL); } } @@ -609,8 +613,8 @@ PurpleXmlNode *cnode; group = purple_group_new(name); - purple_blist_add_group(group, - purple_blist_get_last_sibling(purplebuddylist->root)); + purple_blist_add_group(group, purple_blist_get_last_sibling( + purple_blist_get_default_root())); for (cnode = groupnode->child; cnode; cnode = cnode->next) { if (cnode->type != PURPLE_XMLNODE_TYPE_TAG) @@ -707,13 +711,18 @@ *****************************************************************************/ void +purple_blist_set_ui(GType type) +{ + g_return_if_fail(g_type_is_a(type, PURPLE_TYPE_BUDDY_LIST) || + type == G_TYPE_INVALID); + buddy_list_type = type; +} + +void purple_blist_boot(void) { - PurpleBlistUiOps *ui_ops; GList *account; - PurpleBuddyList *gbl = g_object_new(PURPLE_TYPE_BUDDY_LIST, NULL); - - ui_ops = purple_blist_get_ui_ops(); + PurpleBuddyList *gbl = g_object_new(buddy_list_type, NULL); buddies_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_destroy); @@ -727,9 +736,6 @@ purple_blist_buddies_cache_add_account(account->data); } - if (ui_ops != NULL && ui_ops->new_list != NULL) - ui_ops->new_list(gbl); - purplebuddylist = gbl; load_blist(); @@ -744,15 +750,23 @@ PurpleBlistNode * purple_blist_get_default_root(void) { - return purplebuddylist ? purplebuddylist->root : NULL; + if (purplebuddylist) { + PurpleBuddyListPrivate *priv = + purple_buddy_list_get_instance_private(purplebuddylist); + return priv->root; + } + return NULL; } PurpleBlistNode * purple_blist_get_root(PurpleBuddyList *list) { - g_return_val_if_fail(PURPLE_IS_BUDDY_LIST(list), NULL); + PurpleBuddyListPrivate *priv = NULL; - return list->root; + g_return_val_if_fail(PURPLE_IS_BUDDY_LIST(list), NULL); + priv = purple_buddy_list_get_instance_private(list); + + return priv->root; } static void @@ -776,32 +790,28 @@ return buddies; } -void * -purple_blist_get_ui_data() -{ - return purplebuddylist->ui_data; -} - -void -purple_blist_set_ui_data(void *ui_data) -{ - purplebuddylist->ui_data = ui_data; -} - void purple_blist_show() { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; - if (ops && ops->show) - ops->show(purplebuddylist); + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + + if (klass && klass->show) { + klass->show(purplebuddylist); + } } void purple_blist_set_visible(gboolean show) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; - if (ops && ops->set_visible) - ops->set_visible(purplebuddylist, show); + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + + if (klass && klass->set_visible) { + klass->set_visible(purplebuddylist, show); + } } void purple_blist_update_buddies_cache(PurpleBuddy *buddy, const char *new_name) @@ -853,10 +863,12 @@ void purple_blist_add_chat(PurpleChat *chat, PurpleGroup *group, PurpleBlistNode *node) { PurpleBlistNode *cnode = PURPLE_BLIST_NODE(chat); - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; PurpleCountingNode *group_counter; g_return_if_fail(PURPLE_IS_CHAT(chat)); + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); if (node == NULL) { if (group == NULL) @@ -894,12 +906,13 @@ if (cnode->parent->child == cnode) cnode->parent->child = cnode->next; - if (ops && ops->remove) - ops->remove(purplebuddylist, cnode); + if (klass && klass->remove) { + klass->remove(purplebuddylist, cnode); + } /* ops->remove() cleaned up the cnode's ui_data, so we need to * reinitialize it */ - if (ops && ops->new_node) { - ops->new_node(purplebuddylist, cnode); + if (klass && klass->new_node) { + klass->new_node(purplebuddylist, cnode); } } @@ -931,12 +944,14 @@ } } - if (ops) { - if (ops->save_node) { - ops->save_node(purplebuddylist, cnode); + if (klass) { + if (klass->save_node) { + klass->save_node(purplebuddylist, cnode); } - if (ops->update) - ops->update(purplebuddylist, PURPLE_BLIST_NODE(cnode)); + if (klass->update) { + klass->update(purplebuddylist, + PURPLE_BLIST_NODE(cnode)); + } } purple_signal_emit(purple_blist_get_handle(), "blist-node-added", @@ -945,19 +960,21 @@ void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node) { + PurpleBuddyListClass *klass = NULL; + PurpleBuddyListPrivate *priv = NULL; PurpleBlistNode *cnode, *bnode; PurpleCountingNode *contact_counter, *group_counter; PurpleGroup *g; PurpleContact *c; PurpleAccount *account; - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); struct _purple_hbuddy *hb, *hb2; GHashTable *account_buddies; - PurpleBuddyListPrivate *priv = - purple_buddy_list_get_instance_private(purplebuddylist); + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); g_return_if_fail(PURPLE_IS_BUDDY(buddy)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + priv = purple_buddy_list_get_instance_private(purplebuddylist); bnode = PURPLE_BLIST_NODE(buddy); account = purple_buddy_get_account(buddy); @@ -979,8 +996,8 @@ g = purple_blist_get_default_group(); /* Add group to blist if isn't already on it. Fixes #2752. */ if (!purple_blist_find_group(purple_group_get_name(g))) { - purple_blist_add_group(g, - purple_blist_get_last_sibling(purplebuddylist->root)); + purple_blist_add_group( + g, purple_blist_get_last_sibling(priv->root)); } c = purple_contact_new(); purple_blist_add_contact(c, g, @@ -1018,8 +1035,9 @@ if (bnode->parent->child == bnode) bnode->parent->child = bnode->next; - if (ops && ops->remove) - ops->remove(purplebuddylist, bnode); + if (klass && klass->remove) { + klass->remove(purplebuddylist, bnode); + } if (bnode->parent->parent != (PurpleBlistNode*)g) { struct _purple_hbuddy hb; @@ -1038,8 +1056,9 @@ } else { purple_contact_invalidate_priority_buddy((PurpleContact*)bnode->parent); - if (ops && ops->update) - ops->update(purplebuddylist, bnode->parent); + if (klass && klass->update) { + klass->update(purplebuddylist, bnode->parent); + } } } @@ -1092,13 +1111,15 @@ purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy)); - if (ops) { - if (ops->save_node) { - ops->save_node(purplebuddylist, - (PurpleBlistNode *)buddy); + if (klass) { + if (klass->save_node) { + klass->save_node(purplebuddylist, + (PurpleBlistNode *)buddy); } - if (ops->update) - ops->update(purplebuddylist, PURPLE_BLIST_NODE(buddy)); + if (klass->update) { + klass->update(purplebuddylist, + PURPLE_BLIST_NODE(buddy)); + } } /* Signal that the buddy has been added */ @@ -1108,18 +1129,21 @@ void purple_blist_add_contact(PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; + PurpleBuddyListPrivate *priv = NULL; PurpleGroup *g; PurpleBlistNode *gnode, *cnode, *bnode; PurpleCountingNode *contact_counter, *group_counter; - PurpleBuddyListPrivate *priv = - purple_buddy_list_get_instance_private(purplebuddylist); g_return_if_fail(PURPLE_IS_CONTACT(contact)); + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); if (PURPLE_BLIST_NODE(contact) == node) return; + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + priv = purple_buddy_list_get_instance_private(purplebuddylist); + if (node && (PURPLE_IS_CONTACT(node) || PURPLE_IS_CHAT(node))) g = PURPLE_GROUP(node->parent); @@ -1205,11 +1229,12 @@ purple_counting_node_change_current_size(group_counter, -1); purple_counting_node_change_total_size(group_counter, -1); - if (ops && ops->remove) - ops->remove(purplebuddylist, cnode); + if (klass && klass->remove) { + klass->remove(purplebuddylist, cnode); + } - if (ops && ops->remove_node) { - ops->remove_node(purplebuddylist, cnode); + if (klass && klass->remove_node) { + klass->remove_node(purplebuddylist, cnode); } } @@ -1239,52 +1264,59 @@ purple_counting_node_change_current_size(group_counter, +1); purple_counting_node_change_total_size(group_counter, +1); - if (ops && ops->save_node) - { + if (klass && klass->save_node) { if (cnode->child) { - ops->save_node(purplebuddylist, cnode); + klass->save_node(purplebuddylist, cnode); } for (bnode = cnode->child; bnode; bnode = bnode->next) { - ops->save_node(purplebuddylist, bnode); + klass->save_node(purplebuddylist, bnode); } } - if (ops && ops->update) - { - if (cnode->child) - ops->update(purplebuddylist, cnode); + if (klass && klass->update) { + if (cnode->child) { + klass->update(purplebuddylist, cnode); + } - for (bnode = cnode->child; bnode; bnode = bnode->next) - ops->update(purplebuddylist, bnode); + for (bnode = cnode->child; bnode; bnode = bnode->next) { + klass->update(purplebuddylist, bnode); + } } } void purple_blist_add_group(PurpleGroup *group, PurpleBlistNode *node) { - PurpleBlistUiOps *ops; + PurpleBuddyListClass *klass = NULL; + PurpleBuddyListPrivate *priv = NULL; PurpleBlistNode *gnode = (PurpleBlistNode*)group; gchar* key; + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); g_return_if_fail(PURPLE_IS_GROUP(group)); - ops = purple_blist_get_ui_ops(); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + priv = purple_buddy_list_get_instance_private(purplebuddylist); /* if we're moving to overtop of ourselves, do nothing */ if (gnode == node) { - if (!purplebuddylist->root) + if (!priv->root) { node = NULL; - else + } else { return; + } } if (purple_blist_find_group(purple_group_get_name(group))) { /* This is just being moved */ - if (ops && ops->remove) - ops->remove(purplebuddylist, (PurpleBlistNode *)group); + if (klass && klass->remove) { + klass->remove(purplebuddylist, + (PurpleBlistNode *)group); + } - if (gnode == purplebuddylist->root) - purplebuddylist->root = gnode->next; + if (gnode == priv->root) { + priv->root = gnode->next; + } if (gnode->prev) gnode->prev->next = gnode->next; if (gnode->next) @@ -1301,24 +1333,26 @@ node->next->prev = gnode; node->next = gnode; } else { - if (purplebuddylist->root) - purplebuddylist->root->prev = gnode; - gnode->next = purplebuddylist->root; + if (priv->root) { + priv->root->prev = gnode; + } + gnode->next = priv->root; gnode->prev = NULL; - purplebuddylist->root = gnode; + priv->root = gnode; } - if (ops && ops->save_node) { - ops->save_node(purplebuddylist, gnode); + if (klass && klass->save_node) { + klass->save_node(purplebuddylist, gnode); for (node = gnode->child; node; node = node->next) { - ops->save_node(purplebuddylist, node); + klass->save_node(purplebuddylist, node); } } - if (ops && ops->update) { - ops->update(purplebuddylist, gnode); - for (node = gnode->child; node; node = node->next) - ops->update(purplebuddylist, node); + if (klass && klass->update) { + klass->update(purplebuddylist, gnode); + for (node = gnode->child; node; node = node->next) { + klass->update(purplebuddylist, node); + } } purple_signal_emit(purple_blist_get_handle(), "blist-node-added", @@ -1327,12 +1361,14 @@ void purple_blist_remove_contact(PurpleContact *contact) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; PurpleBlistNode *node, *gnode; PurpleGroup *group; + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); g_return_if_fail(PURPLE_IS_CONTACT(contact)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); node = (PurpleBlistNode *)contact; gnode = node->parent; group = PURPLE_GROUP(gnode); @@ -1363,11 +1399,12 @@ purple_counting_node_change_total_size(PURPLE_COUNTING_NODE(group), -1); /* Update the UI */ - if (ops && ops->remove) - ops->remove(purplebuddylist, node); + if (klass && klass->remove) { + klass->remove(purplebuddylist, node); + } - if (ops && ops->remove_node) { - ops->remove_node(purplebuddylist, node); + if (klass && klass->remove_node) { + klass->remove_node(purplebuddylist, node); } purple_signal_emit(purple_blist_get_handle(), "blist-node-removed", @@ -1380,9 +1417,8 @@ void purple_blist_remove_buddy(PurpleBuddy *buddy) { - PurpleBuddyListPrivate *priv = - purple_buddy_list_get_instance_private(purplebuddylist); - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; + PurpleBuddyListPrivate *priv = NULL; PurpleBlistNode *node, *cnode, *gnode; PurpleCountingNode *contact_counter, *group_counter; PurpleContact *contact; @@ -1391,8 +1427,11 @@ GHashTable *account_buddies; PurpleAccount *account; + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); g_return_if_fail(PURPLE_IS_BUDDY(buddy)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + priv = purple_buddy_list_get_instance_private(purplebuddylist); account = purple_buddy_get_account(buddy); node = PURPLE_BLIST_NODE(buddy); cnode = node->parent; @@ -1429,8 +1468,9 @@ if (cnode->child && purple_contact_get_priority_buddy(contact) == buddy) { purple_contact_invalidate_priority_buddy(contact); - if (ops && ops->update) - ops->update(purplebuddylist, cnode); + if (klass && klass->update) { + klass->update(purplebuddylist, cnode); + } } } @@ -1444,11 +1484,12 @@ g_hash_table_remove(account_buddies, &hb); /* Update the UI */ - if (ops && ops->remove) - ops->remove(purplebuddylist, node); + if (klass && klass->remove) { + klass->remove(purplebuddylist, node); + } - if (ops && ops->remove_node) { - ops->remove_node(purplebuddylist, node); + if (klass && klass->remove_node) { + klass->remove_node(purplebuddylist, node); } /* Remove this buddy's pounces */ @@ -1467,13 +1508,15 @@ void purple_blist_remove_chat(PurpleChat *chat) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; PurpleBlistNode *node, *gnode; PurpleGroup *group; PurpleCountingNode *group_counter; + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); g_return_if_fail(PURPLE_IS_CHAT(chat)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); node = (PurpleBlistNode *)chat; gnode = node->parent; group = (PurpleGroup *)gnode; @@ -1498,11 +1541,12 @@ } /* Update the UI */ - if (ops && ops->remove) - ops->remove(purplebuddylist, node); + if (klass && klass->remove) { + klass->remove(purplebuddylist, node); + } - if (ops && ops->remove_node) { - ops->remove_node(purplebuddylist, node); + if (klass && klass->remove_node) { + klass->remove_node(purplebuddylist, node); } purple_signal_emit(purple_blist_get_handle(), "blist-node-removed", @@ -1514,16 +1558,20 @@ void purple_blist_remove_group(PurpleGroup *group) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; + PurpleBuddyListPrivate *priv = NULL; PurpleBlistNode *node; GList *l; gchar* key; + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); g_return_if_fail(PURPLE_IS_GROUP(group)); if (group == purple_blist_get_default_group()) purple_debug_warning("buddylist", "cannot remove default group"); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + priv = purple_buddy_list_get_instance_private(purplebuddylist); node = (PurpleBlistNode *)group; /* Make sure the group is empty */ @@ -1531,8 +1579,9 @@ return; /* Remove the node from its parent */ - if (purplebuddylist->root == node) - purplebuddylist->root = node->next; + if (priv->root == node) { + priv->root = node->next; + } if (node->prev) node->prev->next = node->next; if (node->next) @@ -1543,11 +1592,12 @@ g_free(key); /* Update the UI */ - if (ops && ops->remove) - ops->remove(purplebuddylist, node); + if (klass && klass->remove) { + klass->remove(purplebuddylist, node); + } - if (ops && ops->remove_node) { - ops->remove_node(purplebuddylist, node); + if (klass && klass->remove_node) { + klass->remove_node(purplebuddylist, node); } purple_signal_emit(purple_blist_get_handle(), "blist-node-removed", @@ -1581,7 +1631,7 @@ hb.account = account; hb.name = (gchar *)purple_normalize(account, name); - for (group = purplebuddylist->root; group; group = group->next) { + for (group = priv->root; group; group = group->next) { if (!group->child) continue; @@ -1637,7 +1687,7 @@ hb.name = (gchar *)purple_normalize(account, name); hb.account = account; - for (node = purplebuddylist->root; node != NULL; node = node->next) { + for (node = priv->root; node != NULL; node = node->next) { if (!node->child) continue; @@ -1748,14 +1798,16 @@ void purple_blist_add_account(PurpleAccount *account) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; PurpleBlistNode *gnode, *cnode, *bnode; PurpleCountingNode *contact_counter, *group_counter; g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); - if (!ops || !ops->update) + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + if (!klass || !klass->update) { return; + } for (gnode = purple_blist_get_default_root(); gnode; gnode = gnode->next) { @@ -1773,29 +1825,34 @@ purple_counting_node_change_current_size(contact_counter, +1); if (purple_counting_node_get_current_size(contact_counter) == 1) purple_counting_node_change_current_size(group_counter, +1); - ops->update(purplebuddylist, bnode); - } - } - if (recompute || - purple_blist_node_get_bool(cnode, "show_offline")) { - purple_contact_invalidate_priority_buddy((PurpleContact*)cnode); - ops->update(purplebuddylist, cnode); - } + klass->update( + purplebuddylist, + bnode); + } + } + if (recompute || + purple_blist_node_get_bool( + cnode, "show_offline")) { + purple_contact_invalidate_priority_buddy( + (PurpleContact *)cnode); + klass->update(purplebuddylist, + cnode); + } } else if (PURPLE_IS_CHAT(cnode) && purple_chat_get_account(PURPLE_CHAT(cnode)) == account) { group_counter = PURPLE_COUNTING_NODE(gnode); purple_counting_node_change_online_count(group_counter, +1); purple_counting_node_change_current_size(group_counter, +1); - ops->update(purplebuddylist, cnode); + klass->update(purplebuddylist, cnode); } } - ops->update(purplebuddylist, gnode); + klass->update(purplebuddylist, gnode); } } void purple_blist_remove_account(PurpleAccount *account) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); + PurpleBuddyListClass *klass = NULL; PurpleBlistNode *gnode, *cnode, *bnode; PurpleCountingNode *contact_counter, *group_counter; PurpleBuddy *buddy; @@ -1805,6 +1862,7 @@ GList *list = NULL, *iter = NULL; g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); for (gnode = purple_blist_get_default_root(); gnode; gnode = gnode->next) { @@ -1851,16 +1909,20 @@ else recompute = TRUE; - if (ops && ops->remove) { - ops->remove(purplebuddylist, bnode); + if (klass && klass->remove) { + klass->remove( + purplebuddylist, + bnode); } } } if (recompute) { purple_contact_invalidate_priority_buddy(contact); - if (ops && ops->update) - ops->update(purplebuddylist, cnode); + if (klass && klass->update) { + klass->update(purplebuddylist, + cnode); + } } } else if (PURPLE_IS_CHAT(cnode)) { chat = PURPLE_CHAT(cnode); @@ -1870,8 +1932,10 @@ purple_counting_node_change_current_size(group_counter, -1); purple_counting_node_change_online_count(group_counter, -1); - if (ops && ops->remove) - ops->remove(purplebuddylist, cnode); + if (klass && klass->remove) { + klass->remove(purplebuddylist, + cnode); + } } } } @@ -1924,13 +1988,14 @@ purple_blist_request_add_buddy(PurpleAccount *account, const char *username, const char *group, const char *alias) { - PurpleBlistUiOps *ui_ops; + PurpleBuddyListClass *klass = NULL; - ui_ops = purple_blist_get_ui_ops(); + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); - if (ui_ops != NULL && ui_ops->request_add_buddy != NULL) { - ui_ops->request_add_buddy(purplebuddylist, account, username, - group, alias); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + if (klass != NULL && klass->request_add_buddy != NULL) { + klass->request_add_buddy(purplebuddylist, account, username, + group, alias); } } @@ -1938,98 +2003,80 @@ purple_blist_request_add_chat(PurpleAccount *account, PurpleGroup *group, const char *alias, const char *name) { - PurpleBlistUiOps *ui_ops; + PurpleBuddyListClass *klass = NULL; - ui_ops = purple_blist_get_ui_ops(); + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); - if (ui_ops != NULL && ui_ops->request_add_chat != NULL) { - ui_ops->request_add_chat(purplebuddylist, account, group, alias, - name); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + if (klass != NULL && klass->request_add_chat != NULL) { + klass->request_add_chat(purplebuddylist, account, group, alias, + name); } } void purple_blist_request_add_group(void) { - PurpleBlistUiOps *ui_ops; + PurpleBuddyListClass *klass = NULL; + + g_return_if_fail(PURPLE_IS_BUDDY_LIST(purplebuddylist)); - ui_ops = purple_blist_get_ui_ops(); - - if (ui_ops != NULL && ui_ops->request_add_group != NULL) { - ui_ops->request_add_group(purplebuddylist); + klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist); + if (klass != NULL && klass->request_add_group != NULL) { + klass->request_add_group(purplebuddylist); } } void purple_blist_new_node(PurpleBuddyList *list, PurpleBlistNode *node) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - if (ops && ops->new_node) { - ops->new_node(list, node); + PurpleBuddyListClass *klass = NULL; + + g_return_if_fail(PURPLE_IS_BUDDY_LIST(list)); + + klass = PURPLE_BUDDY_LIST_GET_CLASS(list); + if (klass && klass->new_node) { + klass->new_node(list, node); } } void purple_blist_update_node(PurpleBuddyList *list, PurpleBlistNode *node) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - if (ops && ops->update) { - ops->update(list, node); + PurpleBuddyListClass *klass = NULL; + + g_return_if_fail(PURPLE_IS_BUDDY_LIST(list)); + + klass = PURPLE_BUDDY_LIST_GET_CLASS(list); + if (klass && klass->update) { + klass->update(list, node); } } void purple_blist_save_node(PurpleBuddyList *list, PurpleBlistNode *node) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - if (ops && ops->save_node) { - ops->save_node(list, node); + PurpleBuddyListClass *klass = NULL; + + g_return_if_fail(PURPLE_IS_BUDDY_LIST(list)); + + klass = PURPLE_BUDDY_LIST_GET_CLASS(list); + if (klass && klass->save_node) { + klass->save_node(list, node); } } void purple_blist_save_account(PurpleBuddyList *list, PurpleAccount *account) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - if (ops && ops->save_account) { - ops->save_account(list, account); - } -} + PurpleBuddyListClass *klass = NULL; + + g_return_if_fail(PURPLE_IS_BUDDY_LIST(list)); -void -purple_blist_set_ui_ops(PurpleBlistUiOps *ops) -{ - gboolean overrode = FALSE; - blist_ui_ops = ops; - - if (!ops) - return; - - if (!ops->save_node) { - ops->save_node = purple_blist_real_save_node; - overrode = TRUE; + klass = PURPLE_BUDDY_LIST_GET_CLASS(list); + if (klass && klass->save_account) { + klass->save_account(list, account); } - if (!ops->remove_node) { - ops->remove_node = purple_blist_real_save_node; - overrode = TRUE; - } - if (!ops->save_account) { - ops->save_account = purple_blist_real_save_account; - overrode = TRUE; - } - - if (overrode && (ops->save_node != purple_blist_real_save_node || - ops->remove_node != purple_blist_real_save_node || - ops->save_account != purple_blist_real_save_account)) { - purple_debug_warning("buddylist", "Only some of the blist saving UI ops " - "were overridden. This probably is not what you want!\n"); - } -} - -PurpleBlistUiOps * -purple_blist_get_ui_ops(void) -{ - return blist_ui_ops; } const gchar * @@ -2051,6 +2098,9 @@ { void *handle = purple_blist_get_handle(); + /* Set a default, which can't be done as a static initializer. */ + buddy_list_type = PURPLE_TYPE_BUDDY_LIST; + purple_signal_register(handle, "buddy-status-changed", purple_marshal_VOID__POINTER_POINTER_POINTER, G_TYPE_NONE, 3, PURPLE_TYPE_BUDDY, PURPLE_TYPE_STATUS, @@ -2119,16 +2169,15 @@ } static void -blist_node_destroy(PurpleBlistNode *node) +blist_node_destroy(PurpleBuddyListClass *klass, PurpleBuddyList *list, + PurpleBlistNode *node) { - PurpleBlistUiOps *ui_ops; PurpleBlistNode *child, *next_child; - ui_ops = purple_blist_get_ui_ops(); child = node->child; while (child) { next_child = child->next; - blist_node_destroy(child); + blist_node_destroy(klass, list, child); child = next_child; } @@ -2137,8 +2186,9 @@ node->child = NULL; node->next = NULL; node->prev = NULL; - if (ui_ops && ui_ops->remove) - ui_ops->remove(purplebuddylist, node); + if (klass && klass->remove) { + klass->remove(list, node); + } g_object_unref(node); } @@ -2146,9 +2196,6 @@ void purple_blist_uninit(void) { - PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - PurpleBlistNode *node, *next_node; - /* This happens if we quit before purple_set_blist is called. */ if (purplebuddylist == NULL) return; @@ -2161,25 +2208,13 @@ purple_debug(PURPLE_DEBUG_INFO, "buddylist", "Destroying\n"); - if (ops && ops->destroy) - ops->destroy(purplebuddylist); - - node = purple_blist_get_default_root(); - while (node) { - next_node = node->next; - blist_node_destroy(node); - node = next_node; - } - purplebuddylist->root = NULL; - g_hash_table_destroy(buddies_cache); g_hash_table_destroy(groups_cache); buddies_cache = NULL; groups_cache = NULL; - g_object_unref(purplebuddylist); - purplebuddylist = NULL; + g_clear_object(&purplebuddylist); g_free(localized_default_group_name); localized_default_group_name = NULL; @@ -2189,36 +2224,6 @@ } /************************************************************************** - * GBoxed code - **************************************************************************/ -static PurpleBlistUiOps * -purple_blist_ui_ops_copy(PurpleBlistUiOps *ops) -{ - PurpleBlistUiOps *ops_new; - - g_return_val_if_fail(ops != NULL, NULL); - - ops_new = g_new(PurpleBlistUiOps, 1); - *ops_new = *ops; - - return ops_new; -} - -GType -purple_blist_ui_ops_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - type = g_boxed_type_register_static("PurpleBlistUiOps", - (GBoxedCopyFunc)purple_blist_ui_ops_copy, - (GBoxedFreeFunc)g_free); - } - - return type; -} - -/************************************************************************** * GObject code **************************************************************************/ @@ -2239,10 +2244,22 @@ static void purple_buddy_list_finalize(GObject *object) { - PurpleBuddyListPrivate *priv = purple_buddy_list_get_instance_private( - PURPLE_BUDDY_LIST(object)); + PurpleBuddyList *list = PURPLE_BUDDY_LIST(object); + PurpleBuddyListClass *klass = PURPLE_BUDDY_LIST_GET_CLASS(list); + PurpleBuddyListPrivate *priv = + purple_buddy_list_get_instance_private(list); + PurpleBlistNode *node, *next_node; + g_hash_table_destroy(priv->buddies); + node = priv->root; + while (node) { + next_node = node->next; + blist_node_destroy(klass, list, node); + node = next_node; + } + priv->root = NULL; + G_OBJECT_CLASS(purple_buddy_list_parent_class)->finalize(object); } @@ -2252,5 +2269,8 @@ GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->finalize = purple_buddy_list_finalize; + + klass->save_node = purple_blist_real_save_node; + klass->remove_node = purple_blist_real_save_node; + klass->save_account = purple_blist_real_save_account; } -
--- a/libpurple/buddylist.h Wed Jul 17 09:52:28 2019 +0000 +++ b/libpurple/buddylist.h Thu Jul 18 03:45:06 2019 +0000 @@ -33,19 +33,8 @@ #include "buddy.h" -#define PURPLE_TYPE_BUDDY_LIST (purple_buddy_list_get_type()) -#define PURPLE_BUDDY_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_BUDDY_LIST, PurpleBuddyList)) -#define PURPLE_BUDDY_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_BUDDY_LIST, PurpleBuddyListClass)) -#define PURPLE_IS_BUDDY_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_BUDDY_LIST)) -#define PURPLE_IS_BUDDY_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_BUDDY_LIST)) -#define PURPLE_BUDDY_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_BUDDY_LIST, PurpleBuddyListClass)) - -typedef struct _PurpleBuddyList PurpleBuddyList; -typedef struct _PurpleBuddyListClass PurpleBuddyListClass; - -#define PURPLE_TYPE_BLIST_UI_OPS (purple_blist_ui_ops_get_type()) - -typedef struct _PurpleBlistUiOps PurpleBlistUiOps; +#define PURPLE_TYPE_BUDDY_LIST (purple_buddy_list_get_type()) +typedef struct _PurpleBuddyList PurpleBuddyList; #define PURPLE_BLIST_DEFAULT_GROUP_NAME _("Buddies") @@ -67,55 +56,32 @@ /**************************************************************************/ /** * PurpleBuddyList: - * @root: The first node in the buddy list - * @ui_data: The UI data associated with this buddy list. This is a convenience - * field provided to the UIs -- it is not used by the libpurple core. * * The Buddy List */ -struct _PurpleBuddyList { - GObject gparent; - - /*< public >*/ - PurpleBlistNode *root; - gpointer ui_data; -}; - -struct _PurpleBuddyListClass { - GObjectClass gparent_class; - - /*< private >*/ - void (*_purple_reserved1)(void); - void (*_purple_reserved2)(void); - void (*_purple_reserved3)(void); - void (*_purple_reserved4)(void); -}; - /** - * PurpleBlistUiOps: - * @new_list: Sets UI-specific data on a buddy list. + * PurpleBuddyListClass: * @new_node: Sets UI-specific data on a node. * @show: The core will call this when it's finished doing its core - * stuff + * stuff. * @update: This will update a node in the buddy list. * @remove: This removes a node from the list - * @destroy: When the list is destroyed, this is called to destroy the UI. - * @set_visible: Hides or unhides the buddy list + * @set_visible: Hides or unhides the buddy list. * @save_node: This is called when a node has been modified and should be * saved. - * <sbr/>Implementation of this UI op is + * <sbr/>Implementation of this method is * <emphasis>OPTIONAL</emphasis>. If not implemented, it will be * set to a fallback function that saves data to * <filename>blist.xml</filename> like in previous libpurple * versions. * <sbr/>@node: The node which has been modified. * @remove_node: Called when a node is about to be removed from the buddy list. - * The UI op should update the relevant data structures to remove - * this node (for example, removing a buddy from the group this - * node is in). - * <sbr/>Implementation of this UI op is - * <emphasis>OPTIONAL</emphasis>. If not implemented, - * it will be set to a fallback function that saves data to + * The method should update the relevant data structures to + * remove this node (for example, removing a buddy from the + * group this node is in). + * <sbr/>Implementation of this method is + * <emphasis>OPTIONAL</emphasis>. If not implemented, it will be + * set to a fallback function that saves data to * <filename>blist.xml</filename> like in previous libpurple * versions. * <sbr/>@node: The node which has been modified. @@ -123,7 +89,7 @@ * this, the callback must save the privacy and buddy list data * for an account. If the account is %NULL, save the data for all * accounts. - * <sbr/>Implementation of this UI op is + * <sbr/>Implementation of this method is * <emphasis>OPTIONAL</emphasis>. If not implemented, it will be * set to a fallback function that saves data to * <filename>blist.xml</filename> like in previous @@ -131,19 +97,19 @@ * <sbr/>@account: The account whose data to save. If %NULL, * save all data for all accounts. * - * Buddy list UI operations. + * Buddy list operations. * - * Any UI representing a buddy list must assign a filled-out PurpleBlistUiOps - * structure to the buddy list core. + * Any UI representing a buddy list must derive a filled-out + * @PurpleBuddyListClass and set the GType using purple_blist_set_ui() before a + * buddy list is created. */ -struct _PurpleBlistUiOps -{ - void (*new_list)(PurpleBuddyList *list); +struct _PurpleBuddyListClass { + GObjectClass gparent_class; + void (*new_node)(PurpleBuddyList *list, PurpleBlistNode *node); void (*show)(PurpleBuddyList *list); void (*update)(PurpleBuddyList *list, PurpleBlistNode *node); void (*remove)(PurpleBuddyList *list, PurpleBlistNode *node); - void (*destroy)(PurpleBuddyList *list); void (*set_visible)(PurpleBuddyList *list, gboolean show); void (*request_add_buddy)(PurpleBuddyList *list, PurpleAccount *account, @@ -162,10 +128,7 @@ void (*save_account)(PurpleBuddyList *list, PurpleAccount *account); /*< private >*/ - void (*_purple_reserved1)(void); - void (*_purple_reserved2)(void); - void (*_purple_reserved3)(void); - void (*_purple_reserved4)(void); + gpointer reserved[4]; }; G_BEGIN_DECLS @@ -179,7 +142,8 @@ * * Returns: The #GType for the #PurpleBuddyList object. */ -GType purple_buddy_list_get_type(void); +G_DECLARE_DERIVABLE_TYPE(PurpleBuddyList, purple_buddy_list, PURPLE, BUDDY_LIST, + GObject) /** * purple_blist_get_default: @@ -228,23 +192,6 @@ GSList *purple_blist_get_buddies(void); /** - * purple_blist_get_ui_data: - * - * Returns the UI data for the list. - * - * Returns: The UI data for the list. - */ -gpointer purple_blist_get_ui_data(void); - -/** - * purple_blist_set_ui_data: - * @ui_data: The UI data for the list. - * - * Sets the UI data for the list. - */ -void purple_blist_set_ui_data(gpointer ui_data); - -/** * purple_blist_show: * * Shows the buddy list, creating a new one if necessary. @@ -524,10 +471,6 @@ */ void purple_blist_request_add_group(void); -/**************************************************************************/ -/* Buddy list UI Functions */ -/**************************************************************************/ - /** * purple_blist_new_node: * @list: The list that contains the node. @@ -583,36 +526,21 @@ void purple_blist_save_account(PurpleBuddyList *list, PurpleAccount *account); /**************************************************************************/ -/* UI Registration Functions */ +/* Buddy List Subsystem */ /**************************************************************************/ /** - * purple_blist_ui_ops_get_type: + * purple_blist_set_ui: + * @type: The @GType of a derived UI implementation of @PurpleBuddyList. + * + * Set the UI implementation of the buddy list. * - * Returns: The #GType for the #PurpleBlistUiOps boxed structure. - */ -GType purple_blist_ui_ops_get_type(void); - -/** - * purple_blist_set_ui_ops: - * @ops: The ops struct. + * This must be called before the buddy list is created or you will get the + * default libpurple implementation. * - * Sets the UI operations structure to be used for the buddy list. + * Since: 3.0.0 */ -void purple_blist_set_ui_ops(PurpleBlistUiOps *ops); - -/** - * purple_blist_get_ui_ops: - * - * Returns the UI operations structure to be used for the buddy list. - * - * Returns: The UI operations structure. - */ -PurpleBlistUiOps *purple_blist_get_ui_ops(void); - -/**************************************************************************/ -/* Buddy List Subsystem */ -/**************************************************************************/ +void purple_blist_set_ui(GType type); /** * purple_blist_get_handle:
--- a/pidgin/gtkblist.c Wed Jul 17 09:52:28 2019 +0000 +++ b/pidgin/gtkblist.c Thu Jul 18 03:45:06 2019 +0000 @@ -129,8 +129,8 @@ } PidginBuddyListPrivate; -#define PIDGIN_BUDDY_LIST_GET_PRIVATE(list) \ - ((PidginBuddyListPrivate *)((list)->priv)) +G_DEFINE_TYPE_WITH_PRIVATE(PidginBuddyList, pidgin_buddy_list, + PURPLE_TYPE_BUDDY_LIST) #define PIDGIN_WINDOW_ICONIFIED(x) \ (gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(x))) & \ @@ -249,14 +249,14 @@ } static void -gtk_blist_hide_cb(GtkWidget *widget, gpointer data) +gtk_blist_hide_cb(GtkWidget *widget, PidginBuddyList *gtkblist) { purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-hiding", gtkblist); } static void -gtk_blist_show_cb(GtkWidget *widget, gpointer data) +gtk_blist_show_cb(GtkWidget *widget, PidginBuddyList *gtkblist) { purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-unhiding", gtkblist); @@ -407,6 +407,7 @@ gchar *path_str, gpointer user_data) { + PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(user_data); GtkTreeIter iter; GtkTreePath *path = NULL; PurpleBlistNode *node; @@ -548,6 +549,7 @@ static void gtk_blist_renderer_edited_cb(GtkCellRendererText *text_rend, char *arg1, char *arg2, PurpleBuddyList *list) { + PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(list); GtkTreeIter iter; GtkTreePath *path; PurpleBlistNode *node; @@ -974,7 +976,7 @@ img = gtk_image_new_from_icon_name("dialog-question", GTK_ICON_SIZE_DIALOG); - gtkblist = PIDGIN_BLIST(purple_blist_get_default()); + gtkblist = PIDGIN_BUDDY_LIST(purple_blist_get_default()); blist_window = gtkblist ? GTK_WINDOW(gtkblist->window) : NULL; data->window = gtk_dialog_new(); @@ -1152,6 +1154,7 @@ static void gtk_blist_row_expanded_cb(GtkTreeView *tv, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { + PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(user_data); PurpleBlistNode *node; gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), iter, NODE_COLUMN, &node, -1); @@ -1174,6 +1177,7 @@ static void gtk_blist_row_collapsed_cb(GtkTreeView *tv, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data) { + PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(user_data); PurpleBlistNode *node; gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), iter, NODE_COLUMN, &node, -1); @@ -1209,6 +1213,7 @@ } static void gtk_blist_row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { + PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(data); PurpleBlistNode *node; GtkTreeIter iter; @@ -4564,7 +4569,7 @@ static void sign_on_off_cb(PurpleConnection *gc, PurpleBuddyList *blist) { - PidginBuddyList *gtkblist = PIDGIN_BLIST(blist); + PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(blist); update_menu_bar(gtkblist); } @@ -4793,65 +4798,10 @@ } } -/************************************************************************** - * GTK Buddy list GBoxed code - **************************************************************************/ -static PidginBuddyList * -pidgin_buddy_list_ref(PidginBuddyList *gtkblist) -{ - PidginBuddyListPrivate *priv; - - g_return_val_if_fail(gtkblist != NULL, NULL); - - priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); - priv->box_count++; - - return gtkblist; -} - -static void -pidgin_buddy_list_unref(PidginBuddyList *gtkblist) -{ - PidginBuddyListPrivate *priv; - - g_return_if_fail(gtkblist != NULL); - - priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); - - g_return_if_fail(priv->box_count >= 0); - - if (!priv->box_count--) - purple_core_quit(); -} - -GType -pidgin_buddy_list_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - type = g_boxed_type_register_static("PidginBuddyList", - (GBoxedCopyFunc)pidgin_buddy_list_ref, - (GBoxedFreeFunc)pidgin_buddy_list_unref); - } - - return type; -} - /********************************************************************************** * Public API Functions * **********************************************************************************/ -static void pidgin_blist_new_list(PurpleBuddyList *blist) -{ - PidginBuddyList *gtkblist; - - gtkblist = g_new0(PidginBuddyList, 1); - gtkblist->priv = g_new0(PidginBuddyListPrivate, 1); - - blist->ui_data = gtkblist; -} - static void pidgin_blist_new_node(PurpleBuddyList *list, PurpleBlistNode *node) { @@ -4943,7 +4893,7 @@ GList *list = NULL; PidginBuddyListPrivate *priv; - priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + priv = pidgin_buddy_list_get_instance_private(gtkblist); priv->select_notebook_page_timeout = 0; @@ -4963,7 +4913,8 @@ static void pidgin_blist_select_notebook_page(PidginBuddyList *gtkblist) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); priv->select_notebook_page_timeout = g_timeout_add(0, pidgin_blist_select_notebook_page_cb, gtkblist); } @@ -5096,7 +5047,8 @@ add_error_dialog(PidginBuddyList *gtkblist, GtkWidget *dialog) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); gtk_container_add(GTK_CONTAINER(priv->error_scrollbook), dialog); } @@ -5213,7 +5165,8 @@ static void remove_generic_error_dialog(PurpleAccount *account) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); remove_child_widget_by_account( GTK_CONTAINER(priv->error_scrollbook), account); } @@ -5223,7 +5176,8 @@ update_generic_error_message(PurpleAccount *account, const char *description) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); GtkWidget *mini_dialog = find_child_widget_by_account( GTK_CONTAINER(priv->error_scrollbook), account); pidgin_mini_dialog_set_description(PIDGIN_MINI_DIALOG(mini_dialog), @@ -5281,7 +5235,8 @@ static void ensure_signed_on_elsewhere_minidialog(PidginBuddyList *gtkblist) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); PidginMiniDialog *mini_dialog; if(priv->signed_on_elsewhere) @@ -5309,7 +5264,8 @@ static void update_signed_on_elsewhere_minidialog_title(void) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); PidginMiniDialog *mini_dialog = priv->signed_on_elsewhere; guint accounts; char *title; @@ -5363,7 +5319,8 @@ static void add_to_signed_on_elsewhere(PurpleAccount *account) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); PidginMiniDialog *mini_dialog; GtkWidget *account_label; @@ -5383,7 +5340,8 @@ static void remove_from_signed_on_elsewhere(PurpleAccount *account) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); PidginMiniDialog *mini_dialog = priv->signed_on_elsewhere; if(mini_dialog == NULL) return; @@ -5398,7 +5356,8 @@ update_signed_on_elsewhere_tooltip(PurpleAccount *account, const char *description) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); GtkContainer *c = GTK_CONTAINER(priv->signed_on_elsewhere->contents); GtkWidget *label = find_child_widget_by_account(c, account); gtk_widget_set_tooltip_text(label, description); @@ -5625,7 +5584,10 @@ "cell-background-rgba", BGCOLOR_COLUMN, "markup", NAME_COLUMN, NULL); - g_signal_connect(G_OBJECT(rend), "editing-started", G_CALLBACK(gtk_blist_renderer_editing_started_cb), NULL); + g_signal_connect( + G_OBJECT(rend), "editing-started", + G_CALLBACK(gtk_blist_renderer_editing_started_cb), + list); g_signal_connect(G_OBJECT(rend), "editing-canceled", G_CALLBACK(gtk_blist_renderer_editing_cancelled_cb), list); g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), list); g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL); @@ -5750,8 +5712,8 @@ return; } - gtkblist = PIDGIN_BLIST(list); - priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + gtkblist = PIDGIN_BUDDY_LIST(list); + priv = pidgin_buddy_list_get_instance_private(gtkblist); if (priv->current_theme) g_object_unref(priv->current_theme); @@ -5777,9 +5739,9 @@ g_signal_connect(G_OBJECT(gtkblist->window), "delete_event", G_CALLBACK(gtk_blist_delete_cb), NULL); g_signal_connect(G_OBJECT(gtkblist->window), "hide", - G_CALLBACK(gtk_blist_hide_cb), NULL); + G_CALLBACK(gtk_blist_hide_cb), gtkblist); g_signal_connect(G_OBJECT(gtkblist->window), "show", - G_CALLBACK(gtk_blist_show_cb), NULL); + G_CALLBACK(gtk_blist_show_cb), gtkblist); g_signal_connect(G_OBJECT(gtkblist->window), "size-allocate", G_CALLBACK(gtk_blist_size_allocate_cb), NULL); g_signal_connect(G_OBJECT(gtkblist->window), "visibility_notify_event", G_CALLBACK(gtk_blist_visibility_cb), NULL); @@ -5957,9 +5919,12 @@ gtk_tree_view_append_column(GTK_TREE_VIEW(gtkblist->treeview), gtkblist->text_column); pidgin_blist_build_layout(list); - g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", G_CALLBACK(gtk_blist_row_activated_cb), NULL); - g_signal_connect(G_OBJECT(gtkblist->treeview), "row-expanded", G_CALLBACK(gtk_blist_row_expanded_cb), NULL); - g_signal_connect(G_OBJECT(gtkblist->treeview), "row-collapsed", G_CALLBACK(gtk_blist_row_collapsed_cb), NULL); + g_signal_connect(G_OBJECT(gtkblist->treeview), "row-activated", + G_CALLBACK(gtk_blist_row_activated_cb), gtkblist); + g_signal_connect(G_OBJECT(gtkblist->treeview), "row-expanded", + G_CALLBACK(gtk_blist_row_expanded_cb), gtkblist); + g_signal_connect(G_OBJECT(gtkblist->treeview), "row-collapsed", + G_CALLBACK(gtk_blist_row_collapsed_cb), gtkblist); g_signal_connect(G_OBJECT(gtkblist->treeview), "button-press-event", G_CALLBACK(gtk_blist_button_press_cb), NULL); g_signal_connect(G_OBJECT(gtkblist->treeview), "key-press-event", G_CALLBACK(gtk_blist_key_press_cb), NULL); g_signal_connect(G_OBJECT(gtkblist->treeview), "popup-menu", G_CALLBACK(pidgin_blist_popup_menu_cb), NULL); @@ -6113,7 +6078,7 @@ { PurpleBlistNode *node; - gtkblist = PIDGIN_BLIST(list); + gtkblist = PIDGIN_BUDDY_LIST(list); if(!gtkblist || !gtkblist->treeview) return; @@ -6150,7 +6115,7 @@ PidginBuddyList *gtkblist; blist = purple_blist_get_default(); - gtkblist = PIDGIN_BLIST(blist); + gtkblist = PIDGIN_BUDDY_LIST(blist); gtkblist->refresh_timer = g_timeout_add_seconds(30,(GSourceFunc)pidgin_blist_refresh_timer, blist); } @@ -6836,7 +6801,7 @@ static void pidgin_blist_update(PurpleBuddyList *list, PurpleBlistNode *node) { if (list) - gtkblist = PIDGIN_BLIST(list); + gtkblist = PIDGIN_BUDDY_LIST(list); if(!gtkblist || !gtkblist->treeview || !node) return; @@ -6853,51 +6818,6 @@ pidgin_blist_update_chat(list, node); } -static void pidgin_blist_destroy(PurpleBuddyList *list) -{ - PidginBuddyListPrivate *priv; - - if (!list || !list->ui_data) - return; - - g_return_if_fail(list->ui_data == gtkblist); - - purple_signals_disconnect_by_handle(gtkblist); - - gtk_widget_destroy(gtkblist->window); - - pidgin_blist_tooltip_destroy(); - - if (gtkblist->refresh_timer) - g_source_remove(gtkblist->refresh_timer); - if (gtkblist->timeout) - g_source_remove(gtkblist->timeout); - if (gtkblist->drag_timeout) - g_source_remove(gtkblist->drag_timeout); - - gtkblist->refresh_timer = 0; - gtkblist->timeout = 0; - gtkblist->drag_timeout = 0; - gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL; - g_object_unref(G_OBJECT(gtkblist->treemodel)); - gtkblist->treemodel = NULL; - g_object_unref(G_OBJECT(gtkblist->ui)); - g_object_unref(G_OBJECT(gtkblist->empty_avatar)); - - priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); - - if (priv->current_theme) - g_object_unref(priv->current_theme); - if (priv->select_notebook_page_timeout) - g_source_remove(priv->select_notebook_page_timeout); - g_free(priv); - - g_free(gtkblist); - accountmenu = NULL; - gtkblist = NULL; - purple_prefs_disconnect_by_handle(pidgin_blist_get_handle()); -} - static void pidgin_blist_set_visible(PurpleBuddyList *list, gboolean show) { if (!(gtkblist && gtkblist->window)) @@ -7382,31 +7302,6 @@ pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE); } -static PurpleBlistUiOps blist_ui_ops = -{ - pidgin_blist_new_list, - pidgin_blist_new_node, - pidgin_blist_show, - pidgin_blist_update, - pidgin_blist_remove, - pidgin_blist_destroy, - pidgin_blist_set_visible, - pidgin_blist_request_add_buddy, - pidgin_blist_request_add_chat, - pidgin_blist_request_add_group, - NULL, - NULL, - NULL, - NULL, NULL, NULL, NULL -}; - - -PurpleBlistUiOps * -pidgin_blist_get_ui_ops(void) -{ - return &blist_ui_ops; -} - PidginBuddyList *pidgin_blist_get_default_gtk_blist() { return gtkblist; @@ -7485,7 +7380,8 @@ void pidgin_blist_set_theme(PidginBlistTheme *theme) { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); PurpleBuddyList *list = purple_blist_get_default(); if (theme != NULL) @@ -7508,7 +7404,8 @@ PidginBlistTheme * pidgin_blist_get_theme() { - PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); return priv->current_theme; } @@ -7576,6 +7473,77 @@ purple_signals_unregister_by_instance(pidgin_blist_get_handle()); purple_signals_disconnect_by_handle(pidgin_blist_get_handle()); + + accountmenu = NULL; + gtkblist = NULL; +} + +/************************************************************************** + * GTK Buddy list GObject code + **************************************************************************/ +static void +pidgin_buddy_list_init(PidginBuddyList *self) +{ +} + +static void +pidgin_buddy_list_finalize(GObject *obj) +{ + PidginBuddyList *gtkblist = PIDGIN_BUDDY_LIST(obj); + PidginBuddyListPrivate *priv = + pidgin_buddy_list_get_instance_private(gtkblist); + + purple_signals_disconnect_by_handle(gtkblist); + + gtk_widget_destroy(gtkblist->window); + + pidgin_blist_tooltip_destroy(); + + if (gtkblist->refresh_timer) { + g_source_remove(gtkblist->refresh_timer); + gtkblist->refresh_timer = 0; + } + if (gtkblist->timeout) { + g_source_remove(gtkblist->timeout); + gtkblist->timeout = 0; + } + if (gtkblist->drag_timeout) { + g_source_remove(gtkblist->drag_timeout); + gtkblist->drag_timeout = 0; + } + + gtkblist->window = gtkblist->vbox = gtkblist->treeview = NULL; + g_clear_object(>kblist->treemodel); + g_object_unref(G_OBJECT(gtkblist->ui)); + g_object_unref(G_OBJECT(gtkblist->empty_avatar)); + + g_clear_object(&priv->current_theme); + if (priv->select_notebook_page_timeout) { + g_source_remove(priv->select_notebook_page_timeout); + } + + purple_prefs_disconnect_by_handle(pidgin_blist_get_handle()); + + G_OBJECT_CLASS(pidgin_buddy_list_parent_class)->finalize(obj); +} + +static void +pidgin_buddy_list_class_init(PidginBuddyListClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + PurpleBuddyListClass *purple_blist_class; + + obj_class->finalize = pidgin_buddy_list_finalize; + + purple_blist_class = PURPLE_BUDDY_LIST_CLASS(klass); + purple_blist_class->new_node = pidgin_blist_new_node; + purple_blist_class->show = pidgin_blist_show; + purple_blist_class->update = pidgin_blist_update; + purple_blist_class->remove = pidgin_blist_remove; + purple_blist_class->set_visible = pidgin_blist_set_visible; + purple_blist_class->request_add_buddy = pidgin_blist_request_add_buddy; + purple_blist_class->request_add_chat = pidgin_blist_request_add_chat; + purple_blist_class->request_add_group = pidgin_blist_request_add_group; } /*********************************************************************
--- a/pidgin/gtkblist.h Wed Jul 17 09:52:28 2019 +0000 +++ b/pidgin/gtkblist.h Thu Jul 18 03:45:06 2019 +0000 @@ -106,6 +106,8 @@ * Like, everything you need to know about the gtk buddy list */ struct _PidginBuddyList { + PurpleBuddyList parent; + GtkWidget *window; GtkWidget *notebook; GtkWidget *main_vbox; @@ -144,14 +146,8 @@ GtkWidget *statusbox; GdkPixbuf *empty_avatar; - - gpointer priv; }; -#define PIDGIN_BLIST(list) ((PidginBuddyList *)purple_blist_get_ui_data()) -#define PIDGIN_IS_PIDGIN_BLIST(list) \ - (purple_blist_get_ui_ops() == pidgin_blist_get_ui_ops()) - G_BEGIN_DECLS /************************************************************************** @@ -163,7 +159,8 @@ * * Returns: The #GType for the #PidginBuddyList boxed structure. */ -GType pidgin_buddy_list_get_type(void); +G_DECLARE_FINAL_TYPE(PidginBuddyList, pidgin_buddy_list, PIDGIN, BUDDY_LIST, + PurpleBuddyList) /** * pidgin_blist_get_handle: @@ -189,15 +186,6 @@ void pidgin_blist_uninit(void); /** - * pidgin_blist_get_ui_ops: - * - * Returns the UI operations structure for the buddy list. - * - * Returns: The GTK+ list operations structure. - */ -PurpleBlistUiOps *pidgin_blist_get_ui_ops(void); - -/** * pidgin_blist_get_default_gtk_blist: * * Returns the default gtk buddy list
--- a/pidgin/libpidgin.c Wed Jul 17 09:52:28 2019 +0000 +++ b/pidgin/libpidgin.c Thu Jul 18 03:45:06 2019 +0000 @@ -225,7 +225,7 @@ /* Set the UI operation structures. */ purple_accounts_set_ui_ops(pidgin_accounts_get_ui_ops()); purple_xfers_set_ui_ops(pidgin_xfers_get_ui_ops()); - purple_blist_set_ui_ops(pidgin_blist_get_ui_ops()); + purple_blist_set_ui(PIDGIN_TYPE_BUDDY_LIST); purple_notify_set_ui_ops(pidgin_notify_get_ui_ops()); purple_request_set_ui_ops(pidgin_request_get_ui_ops()); purple_sound_set_ui_ops(pidgin_sound_get_ui_ops());