Make PurpleContact derivable

Wed, 23 Nov 2022 22:41:43 -0600

author
Gary Kramlich <grim@reaperworld.com>
date
Wed, 23 Nov 2022 22:41:43 -0600
changeset 41933
8ccd6fdc7ceb
parent 41932
0c3de459b1cc
child 41934
2bf330d7a6db

Make PurpleContact derivable

We want to make PurpleContact derivable so that we can subclass it with
PurpleAccount. This will make things easier for everyone as we start moving
everything to PurpleContact as an account will just be a contact.

Testing Done:
Ran the unit tests and built the docs.

Reviewed at https://reviews.imfreedom.org/r/2081/

libpurple/purplecontact.c file | annotate | diff | comparison | revisions
libpurple/purplecontact.h file | annotate | diff | comparison | revisions
--- a/libpurple/purplecontact.c	Wed Nov 23 01:29:41 2022 -0600
+++ b/libpurple/purplecontact.c	Wed Nov 23 22:41:43 2022 -0600
@@ -21,9 +21,7 @@
 #include "purpleenums.h"
 #include "util.h"
 
-struct _PurpleContact {
-	GObject parent;
-
+typedef struct  {
 	gchar *id;
 	PurpleAccount *account;
 
@@ -40,7 +38,7 @@
 	PurplePerson *person;
 
 	PurpleContactPermission permission;
-};
+} PurpleContactPrivate;
 
 enum {
 	PROP_0,
@@ -58,21 +56,36 @@
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
 
-G_DEFINE_TYPE(PurpleContact, purple_contact, G_TYPE_OBJECT)
+G_DEFINE_TYPE_WITH_PRIVATE(PurpleContact, purple_contact, G_TYPE_OBJECT)
 
 /******************************************************************************
  * Helpers
  *****************************************************************************/
 static void
 purple_contact_set_account(PurpleContact *contact, PurpleAccount *account) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
 
-	if(g_set_object(&contact->account, account)) {
+	priv = purple_contact_get_instance_private(contact);
+
+	if(g_set_object(&priv->account, account)) {
 		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ACCOUNT]);
 	}
 }
 
+static PurpleAccount *
+purple_contact_default_get_account(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
+
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->account;
+}
+
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
@@ -159,12 +172,13 @@
 static void
 purple_contact_dispose(GObject *obj) {
 	PurpleContact *contact = PURPLE_CONTACT(obj);
+	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
 
-	g_clear_object(&contact->account);
-	g_clear_object(&contact->avatar);
-	g_clear_object(&contact->presence);
-	g_clear_object(&contact->tags);
-	g_clear_object(&contact->person);
+	g_clear_object(&priv->account);
+	g_clear_object(&priv->avatar);
+	g_clear_object(&priv->presence);
+	g_clear_object(&priv->tags);
+	g_clear_object(&priv->person);
 
 	G_OBJECT_CLASS(purple_contact_parent_class)->dispose(obj);
 }
@@ -172,11 +186,12 @@
 static void
 purple_contact_finalize(GObject *obj) {
 	PurpleContact *contact = PURPLE_CONTACT(obj);
+	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
 
-	g_clear_pointer(&contact->id, g_free);
-	g_clear_pointer(&contact->username, g_free);
-	g_clear_pointer(&contact->display_name, g_free);
-	g_clear_pointer(&contact->alias, g_free);
+	g_clear_pointer(&priv->id, g_free);
+	g_clear_pointer(&priv->username, g_free);
+	g_clear_pointer(&priv->display_name, g_free);
+	g_clear_pointer(&priv->alias, g_free);
 
 	G_OBJECT_CLASS(purple_contact_parent_class)->finalize(obj);
 }
@@ -184,25 +199,32 @@
 static void
 purple_contact_constructed(GObject *obj) {
 	PurpleContact *contact = NULL;
+	PurpleContactPrivate *priv = NULL;
 
 	G_OBJECT_CLASS(purple_contact_parent_class)->constructed(obj);
 
 	contact = PURPLE_CONTACT(obj);
-	if(contact->id == NULL) {
+	priv = purple_contact_get_instance_private(contact);
+
+	if(priv->id == NULL) {
 		purple_contact_set_id(contact, NULL);
 	}
 }
 
 static void
 purple_contact_init(PurpleContact *contact) {
-	contact->tags = purple_tags_new();
-	contact->presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
+	PurpleContactPrivate *priv = purple_contact_get_instance_private(contact);
+
+	priv->tags = purple_tags_new();
+	priv->presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
 }
 
 static void
 purple_contact_class_init(PurpleContactClass *klass) {
 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
 
+	klass->get_account = purple_contact_default_get_account;
+
 	obj_class->constructed = purple_contact_constructed;
 	obj_class->dispose = purple_contact_dispose;
 	obj_class->finalize = purple_contact_finalize;
@@ -355,7 +377,8 @@
 purple_contact_new(PurpleAccount *account, const gchar *id) {
 	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
 
-	return g_object_new(PURPLE_TYPE_CONTACT,
+	return g_object_new(
+		PURPLE_TYPE_CONTACT,
 		"account", account,
 		"id", id,
 		NULL);
@@ -363,156 +386,231 @@
 
 PurpleAccount *
 purple_contact_get_account(PurpleContact *contact) {
+	PurpleContactClass *klass = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->account;
+	klass = PURPLE_CONTACT_GET_CLASS(contact);
+	if(klass != NULL && klass->get_account != NULL) {
+		return klass->get_account(contact);
+	}
+
+	return NULL;
 }
 
 const gchar *
 purple_contact_get_id(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->id;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->id;
 }
 
 void
 purple_contact_set_id(PurpleContact *contact, const gchar *id) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	g_free(contact->id);
-	contact->id = g_strdup(id);
+	priv = purple_contact_get_instance_private(contact);
+
+	g_free(priv->id);
+	priv->id = g_strdup(id);
 
 	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ID]);
 }
 
 const gchar *
 purple_contact_get_username(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->username;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->username;
 }
 
 void
 purple_contact_set_username(PurpleContact *contact, const gchar *username) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 	g_return_if_fail(username != NULL);
 
-	g_free(contact->username);
-	contact->username = g_strdup(username);
+	priv = purple_contact_get_instance_private(contact);
+
+	g_free(priv->username);
+	priv->username = g_strdup(username);
 
 	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_USERNAME]);
 }
 
 const gchar *
 purple_contact_get_display_name(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->display_name;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->display_name;
 }
 
 void
 purple_contact_set_display_name(PurpleContact *contact,
                                 const gchar *display_name)
 {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	g_free(contact->display_name);
-	contact->display_name = g_strdup(display_name);
+	priv = purple_contact_get_instance_private(contact);
+
+	g_free(priv->display_name);
+	priv->display_name = g_strdup(display_name);
 
 	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_DISPLAY_NAME]);
 }
 
 const gchar *
 purple_contact_get_alias(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->alias;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->alias;
 }
 
 void
 purple_contact_set_alias(PurpleContact *contact, const gchar *alias) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	g_free(contact->alias);
-	contact->alias = g_strdup(alias);
+	priv = purple_contact_get_instance_private(contact);
+
+	g_free(priv->alias);
+	priv->alias = g_strdup(alias);
 
 	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_ALIAS]);
 }
 
 GdkPixbuf *
 purple_contact_get_avatar(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->avatar;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->avatar;
 }
 
 void
 purple_contact_set_avatar(PurpleContact *contact, GdkPixbuf *avatar) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	if(g_set_object(&contact->avatar, avatar)) {
+	priv = purple_contact_get_instance_private(contact);
+
+	if(g_set_object(&priv->avatar, avatar)) {
 		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_AVATAR]);
 	}
 }
 
 PurplePresence *
 purple_contact_get_presence(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->presence;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->presence;
 }
 
 PurpleTags *
 purple_contact_get_tags(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->tags;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->tags;
 }
 
 void
 purple_contact_set_person(PurpleContact *contact, PurplePerson *person) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	if(g_set_object(&contact->person, person)) {
+	priv = purple_contact_get_instance_private(contact);
+
+	if(g_set_object(&priv->person, person)) {
 		g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PERSON]);
 	}
 }
 
 PurplePerson *
 purple_contact_get_person(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
-	return contact->person;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->person;
 }
 
 PurpleContactPermission
 purple_contact_get_permission(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact),
 	                     PURPLE_CONTACT_PERMISSION_UNSET);
 
-	return contact->permission;
+	priv = purple_contact_get_instance_private(contact);
+
+	return priv->permission;
 }
 
 void
 purple_contact_set_permission(PurpleContact *contact,
                               PurpleContactPermission permission)
 {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_if_fail(PURPLE_IS_CONTACT(contact));
 
-	contact->permission = permission;
+	priv = purple_contact_get_instance_private(contact);
+
+	priv->permission = permission;
 
 	g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PERMISSION]);
 }
 
 const char *
 purple_contact_get_name_for_display(PurpleContact *contact) {
+	PurpleContactPrivate *priv = NULL;
+
 	g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
 
+	priv = purple_contact_get_instance_private(contact);
+
 	/* If contact is associated with a PurplePerson that has an alias set,
 	 * return the alias of that PurplePerson.
 	 */
-	if(contact->person != NULL) {
-		const char *alias = purple_person_get_alias(contact->person);
+	if(priv->person != NULL) {
+		const char *alias = purple_person_get_alias(priv->person);
 
 		if(alias != NULL && alias[0] != '\0') {
 			return alias;
@@ -520,22 +618,22 @@
 	}
 
 	/* If the purple user set an alias for the contact, return that. */
-	if(contact->alias != NULL && contact->alias[0] != '\0') {
-		return contact->alias;
+	if(priv->alias != NULL && priv->alias[0] != '\0') {
+		return priv->alias;
 	}
 
 	/* If the contact has a display name set, return that. */
-	if(contact->display_name != NULL && contact->display_name[0] != '\0') {
-		return contact->display_name;
+	if(priv->display_name != NULL && priv->display_name[0] != '\0') {
+		return priv->display_name;
 	}
 
 	/* Fallback to the username if that is set. */
-	if(contact->username != NULL && contact->username[0] != '\0') {
-		return contact->username;
+	if(priv->username != NULL && priv->username[0] != '\0') {
+		return priv->username;
 	}
 
 	/* Finally, in a last ditch effort, return the id of the contact. */
-	return contact->id;
+	return priv->id;
 }
 
 int
--- a/libpurple/purplecontact.h	Wed Nov 23 01:29:41 2022 -0600
+++ b/libpurple/purplecontact.h	Wed Nov 23 22:41:43 2022 -0600
@@ -34,7 +34,8 @@
 G_BEGIN_DECLS
 
 #define PURPLE_TYPE_CONTACT (purple_contact_get_type())
-G_DECLARE_FINAL_TYPE(PurpleContact, purple_contact, PURPLE, CONTACT, GObject)
+G_DECLARE_DERIVABLE_TYPE(PurpleContact, purple_contact, PURPLE, CONTACT,
+                         GObject)
 
 /**
  * PurpleContactPermission:
@@ -59,6 +60,26 @@
 #include <libpurple/purpleperson.h>
 
 /**
+ * PurpleContactClass:
+ * @get_account: A virtual method whose sole purpose is to allow
+ *               [class@Purple.Account] to subclass [class@Purple.Contact].
+ *
+ * The class struct for [class@Purple.Contact].
+ *
+ * Since: 3.0.0
+ */
+struct _PurpleContactClass {
+	/*< private >*/
+	GObjectClass parent;
+
+	/*< public >*/
+	PurpleAccount *(*get_account)(PurpleContact *contact);
+
+	/*< private >*/
+	gpointer reserved[4];
+};
+
+/**
  * PurpleContact:
  *
  * A representation of a user. Contacts are used everywhere you need to refer to

mercurial