diff --git a/libpurple/purpleperson.h b/libpurple/purpleperson.h
--- a/libpurple/purpleperson.h
+++ b/libpurple/purpleperson.h
@@ -141,6 +141,19 @@
 PurpleTags *purple_person_get_tags(PurplePerson *person);
 
 /**
+ * purple_person_get_name_for_display:
+ * @person: The instance.
+ *
+ * Gets the name that should be displayed for @person. See
+ * [property@Purple.Person:name-for-display] for more information.
+ *
+ * Returns: (transfer none): The name to display for @person.
+ *
+ * Since: 3.0.0
+ */
+const char *purple_person_get_name_for_display(PurplePerson *person);
+
+/**
  * purple_person_add_contact:
  * @person: The instance.
  * @info: The [class@Purple.ContactInfo] to add.
# HG changeset patch
# Node ID 8b0c144ae27e
# Parent  5ac6db2b8c2d
diff --git a/libpurple/purpleperson.c b/libpurple/purpleperson.c
--- a/libpurple/purpleperson.c
+++ b/libpurple/purpleperson.c
@@ -18,6 +18,8 @@
 
 #include "purpleperson.h"
 
+#include "util.h"
+
 struct _PurplePerson {
 	GObject parent;
 
@@ -36,6 +38,7 @@
 	PROP_ALIAS,
 	PROP_AVATAR,
 	PROP_TAGS,
+	PROP_NAME_FOR_DISPLAY,
 	PROP_PRIORITY_CONTACT_INFO,
 	N_PROPERTIES
 };
@@ -79,8 +82,12 @@
 	guint n_items = person->contacts->len;
 
 	if(n_items <= 1) {
-		g_object_notify_by_pspec(G_OBJECT(person),
-		                         properties[PROP_PRIORITY_CONTACT_INFO]);
+		GObject *obj = G_OBJECT(person);
+
+		g_object_freeze_notify(obj);
+		g_object_notify_by_pspec(obj, properties[PROP_NAME_FOR_DISPLAY]);
+		g_object_notify_by_pspec(obj, properties[PROP_PRIORITY_CONTACT_INFO]);
+		g_object_thaw_notify(obj);
 
 		g_list_model_items_changed(G_LIST_MODEL(person), 0, n_items, n_items);
 
@@ -97,8 +104,12 @@
 	/* See if the priority contact changed. */
 	new_priority = g_ptr_array_index(person->contacts, 0);
 	if(original_priority != new_priority) {
-		g_object_notify_by_pspec(G_OBJECT(person),
-		                         properties[PROP_PRIORITY_CONTACT_INFO]);
+		GObject *obj = G_OBJECT(person);
+
+		g_object_freeze_notify(obj);
+		g_object_notify_by_pspec(obj, properties[PROP_NAME_FOR_DISPLAY]);
+		g_object_notify_by_pspec(obj, properties[PROP_PRIORITY_CONTACT_INFO]);
+		g_object_thaw_notify(obj);
 	}
 }
 
@@ -174,6 +185,10 @@
 		case PROP_TAGS:
 			g_value_set_object(value, purple_person_get_tags(person));
 			break;
+		case PROP_NAME_FOR_DISPLAY:
+			g_value_set_string(value,
+			                   purple_person_get_name_for_display(person));
+			break;
 		case PROP_PRIORITY_CONTACT_INFO:
 			g_value_set_object(value,
 			                   purple_person_get_priority_contact_info(person));
@@ -313,6 +328,25 @@
 		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
 	/**
+	 * PurplePerson:name-for-display:
+	 *
+	 * The name that should be displayed for this person.
+	 *
+	 * If [property@Purple.Person:alias] is set that will be returned. If not
+	 * the value of [method@Purple.ContactInfo.get_name_for_display] for
+	 * [property@Purple.Person:priority-contact-info] will be used. If
+	 * [property@Purple.Person:priority-contact-info] is %NULL, then %NULL will
+	 * be returned.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_NAME_FOR_DISPLAY] = g_param_spec_string(
+		"name-for-display", "name-for-display",
+		"The name that should be displayed for the person",
+		NULL,
+		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+	/**
 	 * PurplePerson:priority-contact-info:
 	 *
 	 * The [class@Purple.ContactInfo] that currently has the highest priority.
@@ -357,10 +391,17 @@
 purple_person_set_alias(PurplePerson *person, const gchar *alias) {
 	g_return_if_fail(PURPLE_IS_PERSON(person));
 
-	g_free(person->alias);
-	person->alias = g_strdup(alias);
+	if(!purple_strequal(person->alias, alias)) {
+		GObject *obj = G_OBJECT(person);
+
+		g_free(person->alias);
+		person->alias = g_strdup(alias);
 
-	g_object_notify_by_pspec(G_OBJECT(person), properties[PROP_ALIAS]);
+		g_object_freeze_notify(obj);
+		g_object_notify_by_pspec(obj, properties[PROP_ALIAS]);
+		g_object_notify_by_pspec(obj, properties[PROP_NAME_FOR_DISPLAY]);
+		g_object_thaw_notify(obj);
+	}
 }
 
 GdkPixbuf *
@@ -386,6 +427,24 @@
 	return person->tags;
 }
 
+const char *
+purple_person_get_name_for_display(PurplePerson *person) {
+	PurpleContactInfo *priority = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PERSON(person), NULL);
+
+	if(!purple_strempty(person->alias)) {
+		return person->alias;
+	}
+
+	priority = purple_person_get_priority_contact_info(person);
+	if(PURPLE_IS_CONTACT_INFO(priority)) {
+		return purple_contact_info_get_name_for_display(priority);
+	}
+
+	return NULL;
+}
+
 void
 purple_person_add_contact_info(PurplePerson *person,
                                PurpleContactInfo *info)
diff --git a/libpurple/tests/test_person.c b/libpurple/tests/test_person.c
--- a/libpurple/tests/test_person.c
+++ b/libpurple/tests/test_person.c
@@ -67,8 +67,9 @@
 	PurpleTags *tags = NULL;
 	GdkPixbuf *avatar = NULL;
 	GdkPixbuf *avatar1 = NULL;
-	gchar *id = NULL;
-	gchar *alias = NULL;
+	char *id = NULL;
+	char *alias = NULL;
+	char *name_for_display = NULL;
 
 	/* Create our avatar for testing. */
 	avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
@@ -88,6 +89,7 @@
 		"id", &id,
 		"alias", &alias,
 		"avatar", &avatar1,
+		"name-for-display", &name_for_display,
 		"tags", &tags,
 		NULL);
 
@@ -95,12 +97,14 @@
 	g_assert_nonnull(id);
 	g_assert_cmpstr(alias, ==, "alias");
 	g_assert_true(avatar1 == avatar);
+	g_assert_cmpstr(name_for_display, ==, "alias");
 	g_assert_nonnull(tags);
 
 	/* Free/unref all the things. */
 	g_clear_pointer(&id, g_free);
 	g_clear_pointer(&alias, g_free);
 	g_clear_object(&avatar1);
+	g_clear_pointer(&name_for_display, g_free);
 	g_clear_object(&tags);
 
 	g_clear_object(&avatar);
@@ -108,6 +112,44 @@
 }
 
 static void
+test_purple_person_name_for_display_person(void) {
+	PurpleContactInfo *info = NULL;
+	PurplePerson *person = NULL;
+
+	person = purple_person_new();
+	purple_person_set_alias(person, "person-alias");
+
+	info = purple_contact_info_new("id");
+	purple_person_add_contact_info(person, info);
+
+	/* Make sure the person's alias is overriding the contact info. */
+	g_assert_cmpstr(purple_person_get_name_for_display(person), ==,
+	                "person-alias");
+
+	g_clear_object(&info);
+	g_clear_object(&person);
+}
+
+static void
+test_purple_person_name_for_display_contact(void) {
+	PurpleContactInfo *info = NULL;
+	PurplePerson *person = NULL;
+
+	person = purple_person_new();
+
+	info = purple_contact_info_new("id");
+	purple_person_add_contact_info(person, info);
+
+	/* Make sure the contact info's name for display is called when the
+	 * person's alias is unset.
+	 */
+	g_assert_cmpstr(purple_person_get_name_for_display(person), ==, "id");
+
+	g_clear_object(&info);
+	g_clear_object(&person);
+}
+
+static void
 test_purple_person_contacts_single(void) {
 	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
@@ -367,6 +409,12 @@
 	                test_purple_person_new);
 	g_test_add_func("/person/properties",
 	                test_purple_person_properties);
+
+	g_test_add_func("/person/name-for-display/person",
+	                test_purple_person_name_for_display_person);
+	g_test_add_func("/person/name-for-display/contact",
+	                test_purple_person_name_for_display_contact);
+
 	g_test_add_func("/person/contacts/single",
 	                test_purple_person_contacts_single);
 	g_test_add_func("/person/contacts/multiple",
diff --git a/pidgin/resources/ContactList/widget.ui b/pidgin/resources/ContactList/widget.ui
--- a/pidgin/resources/ContactList/widget.ui
+++ b/pidgin/resources/ContactList/widget.ui
@@ -54,10 +54,8 @@
             <property name="xalign">0</property>
             <property name="use-markup">1</property>
             <binding name="label">
-              <lookup name="name-for-display" type="PurpleContactInfo">
-                <lookup name="priority-contact-info" type="PurplePerson">
-                  <lookup name="item">GtkListItem</lookup>
-                </lookup>
+              <lookup name="name-for-display" type="PurplePerson">
+                <lookup name="item">GtkListItem</lookup>
               </lookup>
             </binding>
           </object>
