libpurple/buddylist.c

changeset 39693
86f5c1fef140
parent 39692
6e8ebbefba1e
child 39694
4aed5fad4da9
--- a/libpurple/buddylist.c	Wed Jul 03 04:02:46 2019 -0400
+++ b/libpurple/buddylist.c	Wed Jul 03 20:09:04 2019 -0400
@@ -40,8 +40,7 @@
 	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);
@@ -456,11 +455,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);
 	}
 }
 
@@ -709,13 +712,19 @@
  *****************************************************************************/
 
 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);
+	PurpleBuddyListClass *klass = PURPLE_BUDDY_LIST_GET_CLASS(gbl);
 
 	buddies_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal,
 					 NULL, (GDestroyNotify)g_hash_table_destroy);
@@ -729,10 +738,11 @@
 		purple_blist_buddies_cache_add_account(account->data);
 	}
 
-	if (ui_ops != NULL && ui_ops->new_list != NULL)
-		ui_ops->new_list(gbl);
+	purplebuddylist = gbl;
 
-	purplebuddylist = gbl;
+	if (klass && klass->new_list) {
+		klass->new_list(gbl);
+	}
 
 	load_blist();
 }
@@ -812,18 +822,26 @@
 
 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)
@@ -875,10 +893,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)
@@ -916,12 +936,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);
 		}
 	}
 
@@ -953,12 +974,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",
@@ -967,19 +990,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);
 
@@ -1040,8 +1065,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;
@@ -1060,8 +1086,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);
+			}
 		}
 	}
 
@@ -1114,13 +1141,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 */
@@ -1130,18 +1159,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);
@@ -1227,11 +1259,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);
 		}
 	}
 
@@ -1261,36 +1294,37 @@
 		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)
 {
+	PurpleBuddyListClass *klass = NULL;
 	PurpleBuddyListPrivate *priv = NULL;
-	PurpleBlistUiOps *ops;
 	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 */
@@ -1305,8 +1339,10 @@
 	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 == priv->root) {
 			priv->root = gnode->next;
@@ -1335,17 +1371,18 @@
 		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",
@@ -1354,12 +1391,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);
@@ -1390,11 +1429,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",
@@ -1407,9 +1447,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;
@@ -1418,8 +1457,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;
@@ -1456,8 +1498,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);
+			}
 		}
 	}
 
@@ -1471,11 +1514,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 */
@@ -1494,13 +1538,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;
@@ -1525,11 +1571,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",
@@ -1541,18 +1588,20 @@
 
 void purple_blist_remove_group(PurpleGroup *group)
 {
-	PurpleBuddyListPrivate *priv =
-	        purple_buddy_list_get_instance_private(purplebuddylist);
-	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 */
@@ -1573,11 +1622,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",
@@ -1778,14 +1828,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) {
@@ -1803,29 +1855,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;
@@ -1835,6 +1892,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) {
@@ -1881,16 +1939,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);
@@ -1900,8 +1962,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);
+					}
 				}
 			}
 		}
@@ -1954,13 +2018,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);
 	}
 }
 
@@ -1968,98 +2033,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 *
@@ -2081,6 +2128,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, 
@@ -2151,10 +2201,10 @@
 static void
 blist_node_destroy(PurpleBlistNode *node)
 {
-	PurpleBlistUiOps *ui_ops;
+	PurpleBuddyListClass *klass = NULL;
 	PurpleBlistNode *child, *next_child;
 
-	ui_ops = purple_blist_get_ui_ops();
+	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
 	child = node->child;
 	while (child) {
 		next_child = child->next;
@@ -2167,8 +2217,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(purplebuddylist, node);
+	}
 
 	g_object_unref(node);
 }
@@ -2176,14 +2227,15 @@
 void
 purple_blist_uninit(void)
 {
+	PurpleBuddyListClass *klass = NULL;
 	PurpleBuddyListPrivate *priv = NULL;
-	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;
 
+	klass = PURPLE_BUDDY_LIST_GET_CLASS(purplebuddylist);
 	priv = purple_buddy_list_get_instance_private(purplebuddylist);
 
 	if (save_timer != 0) {
@@ -2194,8 +2246,9 @@
 
 	purple_debug(PURPLE_DEBUG_INFO, "buddylist", "Destroying\n");
 
-	if (ops && ops->destroy)
-		ops->destroy(purplebuddylist);
+	if (klass && klass->destroy) {
+		klass->destroy(purplebuddylist);
+	}
 
 	node = priv->root;
 	while (node) {
@@ -2222,36 +2275,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
  **************************************************************************/
 
@@ -2285,5 +2308,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;
 }
-

mercurial