pidgin/pidgin

Parents 8f7b46f497c6
Children e795355c3165
Add "new-status" properties to PurplePresence with fallbacks were applicable

This adds the new `emoji` and `mobile` properties to `PurplePresence`. It also makes `message` read/write and it fallsback to the active status's message if the internal message is false. Additionally the primitive property was moved `PurpleStatusPrimitive` to `PurplePresencePrimitive`.

Testing Done:
Ran the updated unit tests and connected a demo account and verified that the expected status messages were displayed.

Reviewed at https://reviews.imfreedom.org/r/2372/
--- a/libpurple/purplepresence.c Tue Mar 21 02:07:16 2023 -0500
+++ b/libpurple/purplepresence.c Tue Mar 21 02:36:13 2023 -0500
@@ -36,6 +36,11 @@
GHashTable *status_table;
PurpleStatus *active_status;
+
+ PurplePresencePrimitive primitive;
+ char *message;
+ char *emoji;
+ gboolean mobile;
} PurplePresencePrivate;
enum {
@@ -46,6 +51,8 @@
PROP_ACTIVE_STATUS,
PROP_PRIMITIVE,
PROP_MESSAGE,
+ PROP_EMOJI,
+ PROP_MOBILE,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES];
@@ -98,6 +105,18 @@
purple_presence_set_active_status(presence,
g_value_get_object(value));
break;
+ case PROP_PRIMITIVE:
+ purple_presence_set_primitive(presence, g_value_get_enum(value));
+ break;
+ case PROP_MESSAGE:
+ purple_presence_set_message(presence, g_value_get_string(value));
+ break;
+ case PROP_EMOJI:
+ purple_presence_set_emoji(presence, g_value_get_string(value));
+ break;
+ case PROP_MOBILE:
+ purple_presence_set_mobile(presence, g_value_get_boolean(value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
@@ -129,6 +148,12 @@
case PROP_MESSAGE:
g_value_set_string(value, purple_presence_get_message(presence));
break;
+ case PROP_EMOJI:
+ g_value_set_string(value, purple_presence_get_emoji(presence));
+ break;
+ case PROP_MOBILE:
+ g_value_set_boolean(value, purple_presence_get_mobile(presence));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
@@ -157,6 +182,9 @@
g_clear_pointer(&priv->idle_time, g_date_time_unref);
g_clear_pointer(&priv->login_time, g_date_time_unref);
+ g_clear_pointer(&priv->message, g_free);
+ g_clear_pointer(&priv->emoji, g_free);
+
G_OBJECT_CLASS(purple_presence_parent_class)->finalize(obj);
}
@@ -219,9 +247,9 @@
properties[PROP_PRIMITIVE] = g_param_spec_enum(
"primitive", "primitive",
"The primitive for the presence",
- PURPLE_TYPE_STATUS_PRIMITIVE,
- PURPLE_STATUS_UNSET,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ PURPLE_TYPE_PRESENCE_PRIMITIVE,
+ PURPLE_PRESENCE_PRIMITIVE_OFFLINE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
* PurplePresence:message:
@@ -234,7 +262,33 @@
"message", "message",
"The status message",
NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurplePresence:emoji:
+ *
+ * The emoji or mood of the presence.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_EMOJI] = g_param_spec_string(
+ "emoji", "emoji",
+ "The emoji for the presence.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * PurplePresence:mobile:
+ *
+ * Whether or not the presence is on a mobile device.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_MOBILE] = g_param_spec_boolean(
+ "mobile", "mobile",
+ "Whether or not the presence is on a mobile device.",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
}
@@ -557,21 +611,34 @@
return 0;
}
-PurpleStatusPrimitive
+PurplePresencePrimitive
purple_presence_get_primitive(PurplePresence *presence) {
PurplePresencePrivate *priv = NULL;
- PurpleStatusType *type = NULL;
- g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), PURPLE_STATUS_UNSET);
+ g_return_val_if_fail(PURPLE_IS_PRESENCE(presence),
+ PURPLE_PRESENCE_PRIMITIVE_OFFLINE);
priv = purple_presence_get_instance_private(presence);
- type = purple_status_get_status_type(priv->active_status);
- if(type != NULL) {
- return purple_status_type_get_primitive(type);
+ return priv->primitive;
+}
+
+void
+purple_presence_set_primitive(PurplePresence *presence,
+ PurplePresencePrimitive primitive)
+{
+ PurplePresencePrivate *priv = NULL;
+
+ g_return_if_fail(PURPLE_IS_PRESENCE(presence));
+
+ priv = purple_presence_get_instance_private(presence);
+
+ if(priv->primitive != primitive) {
+ priv->primitive = primitive;
+
+ g_object_notify_by_pspec(G_OBJECT(presence),
+ properties[PROP_PRIMITIVE]);
}
-
- return PURPLE_STATUS_UNSET;
}
const char *
@@ -582,9 +649,82 @@
priv = purple_presence_get_instance_private(presence);
+ if(priv->message != NULL) {
+ return priv->message;
+ }
+
return purple_status_get_attr_string(priv->active_status, "message");
}
+void
+purple_presence_set_message(PurplePresence *presence, const char *message) {
+ PurplePresencePrivate *priv = NULL;
+
+ g_return_if_fail(PURPLE_IS_PRESENCE(presence));
+
+ priv = purple_presence_get_instance_private(presence);
+
+ if(!purple_strequal(priv->message, message)) {
+ g_free(priv->message);
+ priv->message = g_strdup(message);
+
+ g_object_notify_by_pspec(G_OBJECT(presence), properties[PROP_MESSAGE]);
+ }
+}
+
+const char *
+purple_presence_get_emoji(PurplePresence *presence) {
+ PurplePresencePrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL);
+
+ priv = purple_presence_get_instance_private(presence);
+
+ return priv->emoji;
+}
+
+void
+purple_presence_set_emoji(PurplePresence *presence, const char *emoji) {
+ PurplePresencePrivate *priv = NULL;
+
+ g_return_if_fail(PURPLE_IS_PRESENCE(presence));
+
+ priv = purple_presence_get_instance_private(presence);
+
+ if(!purple_strequal(priv->emoji, emoji)) {
+ g_free(priv->emoji);
+ priv->emoji = g_strdup(emoji);
+
+ g_object_notify_by_pspec(G_OBJECT(presence), properties[PROP_EMOJI]);
+ }
+}
+
+gboolean
+purple_presence_get_mobile(PurplePresence *presence) {
+ PurplePresencePrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
+
+ priv = purple_presence_get_instance_private(presence);
+
+ return priv->mobile;
+}
+
+void
+purple_presence_set_mobile(PurplePresence *presence, gboolean mobile) {
+ PurplePresencePrivate *priv = NULL;
+
+ g_return_if_fail(PURPLE_IS_PRESENCE(presence));
+
+ priv = purple_presence_get_instance_private(presence);
+
+ if(priv->mobile != mobile) {
+ priv->mobile = mobile;
+
+ g_object_notify_by_pspec(G_OBJECT(presence), properties[PROP_MOBILE]);
+ }
+}
+
const char *
purple_presence_primitive_to_string(PurplePresencePrimitive primitive) {
switch(primitive) {
--- a/libpurple/purplepresence.h Tue Mar 21 02:07:16 2023 -0500
+++ b/libpurple/purplepresence.h Tue Mar 21 02:36:13 2023 -0500
@@ -298,13 +298,24 @@
* purple_presence_get_primitive:
* @presence: The instance.
*
- * Gets the [enum@Purple.StatusPrimitive] for @presence.
+ * Gets the [enum@Purple.PresencePrimitive] for @presence.
*
* Returns: The current primitive.
*
* Since: 3.0.0
*/
-PurpleStatusPrimitive purple_presence_get_primitive(PurplePresence *presence);
+PurplePresencePrimitive purple_presence_get_primitive(PurplePresence *presence);
+
+/**
+ * purple_presence_set_primitive:
+ * @presence: The instance.
+ * @primitive: The new primitive.
+ *
+ * Sets the [enum@Purple.StatusPrimitive] for @presence to @primitive.
+ *
+ * Since: 3.0.0
+ */
+void purple_presence_set_primitive(PurplePresence *presence, PurplePresencePrimitive primitive);
/**
* purple_presence_get_message:
@@ -319,6 +330,64 @@
const char *purple_presence_get_message(PurplePresence *presence);
/**
+ * purple_presence_set_message:
+ * @presence: The instance.
+ * @message: (nullable): The new message.
+ *
+ * Sets the status message of @presence to @message.
+ *
+ * Since: 3.0.0
+ */
+void purple_presence_set_message(PurplePresence *presence, const char *message);
+
+/**
+ * purple_presence_get_emoji:
+ * @presence: The instance.
+ *
+ * Gets the current emoji, sometimes referred to as a mood, of @presence.
+ *
+ * Returns: The current emoji or %NULL if none is set.
+ *
+ * Since: 3.0.0
+ */
+const char *purple_presence_get_emoji(PurplePresence *presence);
+
+/**
+ * purple_presence_set_emoji:
+ * @presence: The instance.
+ * @emoji: (nullable): The new emoji to set.
+ *
+ * Sets the current emoji, sometimes referred to as a mood, of @presence to
+ * @emoji.
+ *
+ * Since: 3.0.0
+ */
+void purple_presence_set_emoji(PurplePresence *presence, const char *emoji);
+
+/**
+ * purple_presence_get_mobile:
+ * @presence: The instance.
+ *
+ * Gets whether or not @presence is on a mobile device.
+ *
+ * Returns: %TRUE if @presence is on a mobile device, otherwise %FALSE.
+ *
+ * Since: 3.0.0
+ */
+gboolean purple_presence_get_mobile(PurplePresence *presence);
+
+/**
+ * purple_presence_set_mobile:
+ * @presence: The instance.
+ * @mobile: The new mobile status.
+ *
+ * Sets whether or not @presence is on a mobile device.
+ *
+ * Since: 3.0.0
+ */
+void purple_presence_set_mobile(PurplePresence *presence, gboolean mobile);
+
+/**
* purple_presence_primitive_to_string:
* @primitive: The [enum@Purple.PresencePrimitive] value.
*
--- a/libpurple/tests/test_presence.c Tue Mar 21 02:07:16 2023 -0500
+++ b/libpurple/tests/test_presence.c Tue Mar 21 02:36:13 2023 -0500
@@ -24,65 +24,79 @@
* Main
*****************************************************************************/
static void
-test_purple_presence_migrate_online_without_message(void) {
+test_purple_presence_new(void) {
PurplePresence *presence = NULL;
- PurpleStatus *status = NULL;
- PurpleStatusType *type = NULL;
- type = purple_status_type_new(PURPLE_STATUS_AVAILABLE,
- "online", "online", TRUE);
presence = purple_presence_new();
- status = purple_status_new(type, presence);
-
- purple_status_set_active(status, TRUE);
-
- /* Now verify that the presence returns the correct values for the
- * properties.
- */
- g_assert_cmpint(purple_presence_get_primitive(presence), ==,
- PURPLE_STATUS_AVAILABLE);
- g_assert_null(purple_presence_get_message(presence));
+ g_assert_true(PURPLE_IS_PRESENCE(presence));
/* Cleanup. */
g_clear_object(&presence);
- g_clear_object(&status);
- g_clear_pointer(&type, purple_status_type_destroy);
}
static void
-test_purple_presence_migrate_online_with_message(void) {
+test_purple_presence_properties(void) {
PurplePresence *presence = NULL;
- PurpleStatus *status = NULL;
- PurpleStatusType *type = NULL;
- GHashTable *attrs = NULL;
+ PurplePresencePrimitive primitive = PURPLE_PRESENCE_PRIMITIVE_OFFLINE;
+ GDateTime *now = NULL;
+ GDateTime *login = NULL;
+ GDateTime *login1 = NULL;
+ GDateTime *idle = NULL;
+ GDateTime *idle1 = NULL;
+ char *message = NULL;
+ char *emoji = NULL;
+ gboolean mobile = FALSE;
- type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
- "online", "online",
- FALSE, TRUE, TRUE,
- "message", "message",
- purple_value_new(G_TYPE_STRING),
- NULL);
- presence = purple_presence_new();
+ /* Create the login and idle times. */
+ now = g_date_time_new_now_utc();
+ login = g_date_time_add_hours(now, -1);
+ idle = g_date_time_add_minutes(now, -10);
+ g_clear_pointer(&now, g_date_time_unref);
- status = purple_status_new(type, presence);
-
- attrs = g_hash_table_new(g_str_hash, g_str_equal);
- g_hash_table_insert(attrs, "message", "Greetings Programs!");
- purple_status_set_active_with_attributes(status, TRUE, attrs);
- g_hash_table_destroy(attrs);
+ /* Create the presence using g_object_new to make sure set_property is
+ * wired up correctly.
+ */
+ presence = g_object_new(
+ PURPLE_TYPE_PRESENCE,
+ "primitive", PURPLE_PRESENCE_PRIMITIVE_AVAILABLE,
+ "message", "I'll be back!",
+ "emoji", "🤖",
+ "login-time", login,
+ "idle-time", idle,
+ "mobile", TRUE,
+ NULL);
- /* Now verify that the presence returns the correct values for the
- * properties.
+ /* Grab the values via g_object_get to make sure get_property is wired up
+ * correctly.
*/
- g_assert_cmpint(purple_presence_get_primitive(presence), ==,
- PURPLE_STATUS_AVAILABLE);
- g_assert_cmpstr(purple_presence_get_message(presence), ==,
- "Greetings Programs!");
+ g_object_get(
+ presence,
+ "primitive", &primitive,
+ "message", &message,
+ "emoji", &emoji,
+ "login-time", &login1,
+ "idle-time", &idle1,
+ "mobile", &mobile,
+ NULL);
+
+ /* Validate! */
+ g_assert_cmpint(primitive, ==, PURPLE_PRESENCE_PRIMITIVE_AVAILABLE);
+ g_assert_cmpstr(message, ==, "I'll be back!");
+ g_assert_cmpstr(emoji, ==, "🤖");
+ g_assert_nonnull(login1);
+ g_assert_true(g_date_time_equal(login, login1));
+ g_assert_nonnull(idle1);
+ g_assert_true(g_date_time_equal(idle, idle1));
+ g_assert_true(mobile);
/* Cleanup. */
+ g_clear_pointer(&message, g_free);
+ g_clear_pointer(&emoji, g_free);
+ g_clear_pointer(&login, g_date_time_unref);
+ g_clear_pointer(&login1, g_date_time_unref);
+ g_clear_pointer(&idle, g_date_time_unref);
+ g_clear_pointer(&idle1, g_date_time_unref);
g_clear_object(&presence);
- g_clear_object(&status);
- g_clear_pointer(&type, purple_status_type_destroy);
}
/******************************************************************************
@@ -92,14 +106,8 @@
main(gint argc, gchar *argv[]) {
g_test_init(&argc, &argv, NULL);
- /* This tests verify that PurplePresence is properly notifying of property
- * changes with the 2.x.y and earlier status back end. When PurplePresence
- * has replaced that back end, these tests should be removed as well.
- */
- g_test_add_func("/presence/migrate/online-without-message",
- test_purple_presence_migrate_online_without_message);
- g_test_add_func("/presence/migrate/online-with-message",
- test_purple_presence_migrate_online_with_message);
+ g_test_add_func("/presence/new", test_purple_presence_new);
+ g_test_add_func("/presence/properties", test_purple_presence_properties);
return g_test_run();
}