From e487f5d6c8e6dcb04a94da593377ebada35ac2df Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 16 Apr 2014 20:39:11 +0100 Subject: [PATCH] TpPresenceMixin: redo the API to be introspectable TpPresenceStatusSpec and TpPresenceStatus are now opaque, refcounted structures, with accessors for everything. Functions that return them return a GList with (transfer full); this does lead to some irritating boilerplate in the CMs, unfortunately. --- .../telepathy-glib/telepathy-glib-sections.txt | 15 +- examples/cm/call/conn.c | 88 +++-- examples/cm/call/conn.h | 3 +- examples/cm/contactlist/conn.c | 40 +- examples/cm/contactlist/contact-list.c | 26 +- examples/cm/contactlist/contact-list.h | 3 +- telepathy-glib/base-protocol.c | 55 +-- telepathy-glib/base-protocol.h | 4 +- telepathy-glib/presence-mixin.c | 437 ++++++++++++--------- telepathy-glib/presence-mixin.h | 66 ++-- telepathy-glib/protocol.c | 2 +- telepathy-glib/versions/main-1.0.abi | 4 - tests/lib/contacts-conn.c | 88 ++++- tests/lib/contacts-conn.h | 3 +- 14 files changed, 520 insertions(+), 314 deletions(-) diff --git a/docs/reference/telepathy-glib/telepathy-glib-sections.txt b/docs/reference/telepathy-glib/telepathy-glib-sections.txt index 50f650c..e30a230 100644 --- a/docs/reference/telepathy-glib/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib/telepathy-glib-sections.txt @@ -1672,15 +1672,19 @@ tp_presence_status_spec_get_name tp_presence_status_spec_get_presence_type tp_presence_status_spec_has_message tp_presence_status_spec_new -tp_presence_status_spec_copy -tp_presence_status_spec_free +tp_presence_status_spec_get_id +tp_presence_status_spec_ref +tp_presence_status_spec_unref TpPresenceMixinStatusAvailableFunc -TpPresenceMixinGetContactStatusFunc +TpPresenceMixinDupContactStatusFunc TpPresenceMixinSetOwnStatusFunc TpPresenceMixinGetMaximumStatusMessageLengthFunc TpPresenceStatus tp_presence_status_new -tp_presence_status_free +tp_presence_status_ref +tp_presence_status_unref +tp_presence_status_get_spec +tp_presence_status_get_message TpPresenceMixin TpPresenceMixinInterface tp_presence_mixin_init @@ -1693,6 +1697,7 @@ TP_TYPE_PRESENCE_MIXIN TP_IS_PRESENCE_MIXIN TP_PRESENCE_MIXIN_GET_INTERFACE TpPresenceStatusSpecPrivate +tp_presence_status_get_type tp_presence_status_spec_get_type tp_presence_mixin_get_type @@ -4623,7 +4628,7 @@ TpBaseProtocol tp_base_protocol_get_name tp_base_protocol_get_immutable_properties tp_base_protocol_get_parameters -tp_base_protocol_get_statuses +tp_base_protocol_dup_statuses tp_base_protocol_new_connection TpBaseProtocolClass diff --git a/examples/cm/call/conn.c b/examples/cm/call/conn.c index 3dd0e0a..eb95cc2 100644 --- a/examples/cm/call/conn.c +++ b/examples/cm/call/conn.c @@ -59,16 +59,47 @@ struct _ExampleCallConnectionPrivate guint simulation_delay; gboolean away; gchar *presence_message; + GPtrArray *statuses; +}; + +/* Must be kept in sync with ExampleCallPresence enum in header */ +static const struct { + const gchar *name; + TpConnectionPresenceType type; + gboolean on_self; + gboolean has_message; +} presence_statuses[] = { + { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, FALSE }, + { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, FALSE }, + { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, FALSE }, + { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, TRUE }, + { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, TRUE }, + { NULL } }; static void example_call_connection_init (ExampleCallConnection *self) { + guint i; + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_CONNECTION, ExampleCallConnectionPrivate); self->priv->away = FALSE; self->priv->presence_message = g_strdup (""); + + self->priv->statuses = g_ptr_array_new_full (N_EXAMPLE_CALL_PRESENCES, + (GDestroyNotify) tp_presence_status_spec_unref); + + for (i = 0; i < N_EXAMPLE_CALL_PRESENCES; i++) + { + g_ptr_array_add (self->priv->statuses, + tp_presence_status_spec_new (presence_statuses[i].name, + presence_statuses[i].type, presence_statuses[i].on_self, + presence_statuses[i].has_message, i)); + } + + g_assert (presence_statuses[N_EXAMPLE_CALL_PRESENCES].name == NULL); } static void @@ -137,6 +168,7 @@ finalize (GObject *object) g_free (self->priv->account); g_free (self->priv->presence_message); + g_ptr_array_unref (self->priv->statuses); G_OBJECT_CLASS (example_call_connection_parent_class)->finalize (object); } @@ -224,13 +256,13 @@ shut_down (TpBaseConnection *conn) static gboolean status_available (TpPresenceMixin *mixin, - guint index_) + TpPresenceStatusSpec *spec) { return tp_base_connection_check_connected (TP_BASE_CONNECTION (mixin), NULL); } static TpPresenceStatus * -get_contact_status (TpPresenceMixin *mixin, +dup_contact_status (TpPresenceMixin *mixin, TpHandle contact) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (mixin); @@ -252,21 +284,24 @@ get_contact_status (TpPresenceMixin *mixin, message = NULL; } - return tp_presence_status_new (presence, message); + return tp_presence_status_new (g_ptr_array_index ( + self->priv->statuses, presence), message); } static gboolean set_own_status (TpPresenceMixin *mixin, - const TpPresenceStatus *status, + TpPresenceStatus *status, GError **error) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (mixin); TpBaseConnection *base = TP_BASE_CONNECTION (mixin); GHashTable *presences; + const gchar *message = tp_presence_status_get_message (status); - if (status->index == EXAMPLE_CALL_PRESENCE_AWAY) + if (tp_presence_status_spec_get_id (tp_presence_status_get_spec (status)) + == EXAMPLE_CALL_PRESENCE_AWAY) { - if (self->priv->away && !tp_strdiff (status->message, + if (self->priv->away && !tp_strdiff (message, self->priv->presence_message)) return TRUE; @@ -274,7 +309,7 @@ set_own_status (TpPresenceMixin *mixin, } else { - if (!self->priv->away && !tp_strdiff (status->message, + if (!self->priv->away && !tp_strdiff (message, self->priv->presence_message)) return TRUE; @@ -282,34 +317,26 @@ set_own_status (TpPresenceMixin *mixin, } g_free (self->priv->presence_message); - self->priv->presence_message = g_strdup (status->message); + self->priv->presence_message = g_strdup (message); presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); g_hash_table_insert (presences, GUINT_TO_POINTER (tp_base_connection_get_self_handle (base)), - (gpointer) status); - tp_presence_mixin_emit_presence_update (TP_PRESENCE_MIXIN (self), presences); + status); + tp_presence_mixin_emit_presence_update (TP_PRESENCE_MIXIN (self), + presences); g_hash_table_unref (presences); if (!self->priv->away) { - g_signal_emit (self, signals[SIGNAL_AVAILABLE], 0, status->message); + g_signal_emit (self, signals[SIGNAL_AVAILABLE], 0, + message); } return TRUE; } -/* Must be kept in sync with ExampleCallPresence enum in header */ -static const TpPresenceStatusSpec presence_statuses[] = { - { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, FALSE }, - { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, FALSE }, - { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, FALSE }, - { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, TRUE }, - { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, TRUE }, - { NULL } -}; - static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_PRESENCE1, NULL }; @@ -336,6 +363,21 @@ fill_contact_attributes (TpBaseConnection *conn, fill_contact_attributes (conn, dbus_interface, contact, attributes); } +static GList * +dup_statuses (TpPresenceMixin *mixin) +{ + ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (mixin); + GList *them = NULL; + guint i; + + for (i = 0; i < N_EXAMPLE_CALL_PRESENCES; i++) + them = g_list_prepend (them, + tp_presence_status_spec_ref ( + g_ptr_array_index (self->priv->statuses, i))); + + return them; +} + static void init_presence (gpointer g_iface, gpointer iface_data) @@ -343,9 +385,9 @@ init_presence (gpointer g_iface, TpPresenceMixinInterface *iface = g_iface; iface->status_available = status_available; - iface->get_contact_status = get_contact_status; + iface->dup_contact_status = dup_contact_status; iface->set_own_status = set_own_status; - iface->statuses = presence_statuses; + iface->dup_statuses = dup_statuses; } static void diff --git a/examples/cm/call/conn.h b/examples/cm/call/conn.h index bb2404d..f7694c1 100644 --- a/examples/cm/call/conn.h +++ b/examples/cm/call/conn.h @@ -61,7 +61,8 @@ typedef enum { EXAMPLE_CALL_PRESENCE_UNKNOWN, EXAMPLE_CALL_PRESENCE_ERROR, EXAMPLE_CALL_PRESENCE_AWAY, - EXAMPLE_CALL_PRESENCE_AVAILABLE + EXAMPLE_CALL_PRESENCE_AVAILABLE, + N_EXAMPLE_CALL_PRESENCES } ExampleCallPresence; const gchar * const *example_call_connection_get_possible_interfaces (void); diff --git a/examples/cm/contactlist/conn.c b/examples/cm/contactlist/conn.c index 20db31f..b599557 100644 --- a/examples/cm/contactlist/conn.c +++ b/examples/cm/contactlist/conn.c @@ -45,6 +45,7 @@ struct _ExampleContactListConnectionPrivate guint simulation_delay; ExampleContactList *contact_list; gboolean away; + GPtrArray *statuses; }; static void @@ -53,6 +54,7 @@ example_contact_list_connection_init (ExampleContactListConnection *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, ExampleContactListConnectionPrivate); + self->priv->statuses = example_contact_list_presence_statuses (); } static void @@ -111,6 +113,7 @@ finalize (GObject *object) EXAMPLE_CONTACT_LIST_CONNECTION (object); g_free (self->priv->account); + g_ptr_array_unref (self->priv->statuses); G_OBJECT_CLASS (example_contact_list_connection_parent_class)->finalize ( object); @@ -175,11 +178,12 @@ presence_updated_cb (ExampleContactList *contact_list, return; status = tp_presence_status_new ( - example_contact_list_get_presence (contact_list, contact), + g_ptr_array_index (self->priv->statuses, + example_contact_list_get_presence (contact_list, contact)), NULL); tp_presence_mixin_emit_one_presence_update (TP_PRESENCE_MIXIN (self), contact, status); - tp_presence_status_free (status); + tp_presence_status_unref (status); } static GPtrArray * @@ -287,13 +291,13 @@ constructed (GObject *object) static gboolean status_available (TpPresenceMixin *mixin, - guint index_) + TpPresenceStatusSpec *spec) { return tp_base_connection_check_connected (TP_BASE_CONNECTION (mixin), NULL); } static TpPresenceStatus * -get_contact_status (TpPresenceMixin *mixin, +dup_contact_status (TpPresenceMixin *mixin, TpHandle contact) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (mixin); @@ -313,19 +317,22 @@ get_contact_status (TpPresenceMixin *mixin, self->priv->contact_list, contact); } - return tp_presence_status_new (presence, ""); + return tp_presence_status_new ( + g_ptr_array_index (self->priv->statuses, presence), ""); } static gboolean set_own_status (TpPresenceMixin *mixin, - const TpPresenceStatus *status, + TpPresenceStatus *status, GError **error) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (mixin); TpBaseConnection *base = TP_BASE_CONNECTION (mixin); GHashTable *presences; - if (status->index == EXAMPLE_CONTACT_LIST_PRESENCE_AWAY) + if (tp_presence_status_spec_get_id ( + tp_presence_status_get_spec (status)) == + EXAMPLE_CONTACT_LIST_PRESENCE_AWAY) { if (self->priv->away) return TRUE; @@ -350,6 +357,21 @@ set_own_status (TpPresenceMixin *mixin, return TRUE; } +static GList * +dup_statuses (TpPresenceMixin *mixin) +{ + ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (mixin); + GList *them = NULL; + guint i; + + for (i = 0; i < self->priv->statuses->len; i++) + them = g_list_prepend (them, + tp_presence_status_spec_ref ( + g_ptr_array_index (self->priv->statuses, i))); + + return them; +} + static void init_presence (gpointer g_iface, gpointer iface_data) @@ -357,9 +379,9 @@ init_presence (gpointer g_iface, TpPresenceMixinInterface *iface = g_iface; iface->status_available = status_available; - iface->get_contact_status = get_contact_status; + iface->dup_contact_status = dup_contact_status; iface->set_own_status = set_own_status; - iface->statuses = example_contact_list_presence_statuses (); + iface->dup_statuses = dup_statuses; } diff --git a/examples/cm/contactlist/contact-list.c b/examples/cm/contactlist/contact-list.c index 3a5ca85..edb5863 100644 --- a/examples/cm/contactlist/contact-list.c +++ b/examples/cm/contactlist/contact-list.c @@ -21,19 +21,35 @@ /* this array must be kept in sync with the enum * ExampleContactListPresence in contact-list.h */ -static const TpPresenceStatusSpec _statuses[] = { +static const struct { + const gchar *name; + TpConnectionPresenceType type; + gboolean on_self; + gboolean has_message; +} _statuses[] = { { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, FALSE }, { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, FALSE }, { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, FALSE }, { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, FALSE }, - { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, FALSE }, - { NULL } + { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, FALSE } }; -const TpPresenceStatusSpec * +GPtrArray * example_contact_list_presence_statuses (void) { - return _statuses; + guint i; + GPtrArray *ret = g_ptr_array_new_full (G_N_ELEMENTS (_statuses), + (GDestroyNotify) tp_presence_status_spec_unref); + + for (i = 0; i < G_N_ELEMENTS (_statuses); i++) + { + g_ptr_array_add (ret, + tp_presence_status_spec_new (_statuses[i].name, + _statuses[i].type, _statuses[i].on_self, + _statuses[i].has_message, i)); + } + + return ret; } typedef struct { diff --git a/examples/cm/contactlist/contact-list.h b/examples/cm/contactlist/contact-list.h index fdd1175..dd3fa6e 100644 --- a/examples/cm/contactlist/contact-list.h +++ b/examples/cm/contactlist/contact-list.h @@ -60,8 +60,7 @@ typedef enum { EXAMPLE_CONTACT_LIST_PRESENCE_AVAILABLE } ExampleContactListPresence; -const TpPresenceStatusSpec *example_contact_list_presence_statuses ( - void); +GPtrArray *example_contact_list_presence_statuses (void); ExampleContactListPresence example_contact_list_get_presence ( ExampleContactList *self, TpHandle contact); diff --git a/telepathy-glib/base-protocol.c b/telepathy-glib/base-protocol.c index e18507d..5c831d0 100644 --- a/telepathy-glib/base-protocol.c +++ b/telepathy-glib/base-protocol.c @@ -513,7 +513,7 @@ tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, * @get_connection_details: a callback used to implement the Protocol D-Bus * properties that represent details of the connections provided by this * protocol - * @get_statuses: a callback used to implement the Protocol.Interface.Presence + * @dup_statuses: a callback used to implement the Protocol.Interface.Presence * interface's Statuses property. Since 0.13.5 * @get_avatar_details: a callback used to implement the * Protocol.Interface.Avatars interface's properties. Since 0.13.7 @@ -565,6 +565,8 @@ struct _TpBaseProtocolPrivate gchar *english_name; gchar *vcard_field; AvatarSpecs avatar_specs; + /* (element-type Tp.PresenceStatusSpec) (transfer full) */ + GList *statuses; }; enum @@ -698,10 +700,11 @@ tp_base_protocol_constructed (GObject *object) TP_TYPE_SVC_PROTOCOL_INTERFACE_AVATARS1); } - if (cls->get_statuses != NULL) + if (cls->dup_statuses != NULL) { object_skeleton_take_svc_interface (skel, TP_TYPE_SVC_PROTOCOL_INTERFACE_PRESENCE1); + self->priv->statuses = cls->dup_statuses (self); } if (TP_IS_PROTOCOL_ADDRESSING (self)) @@ -812,7 +815,7 @@ tp_base_protocol_get_immutable_properties (TpBaseProtocol *self) TP_IFACE_PROTOCOL_INTERFACE_ADDRESSING1, "AddressableURISchemes", NULL); - if (cls->get_statuses != NULL) + if (cls->dup_statuses != NULL) tp_dbus_properties_mixin_fill_properties_hash ((GObject *) self, table, TP_IFACE_PROTOCOL_INTERFACE_PRESENCE1, "Statuses", NULL); @@ -886,6 +889,9 @@ tp_base_protocol_finalize (GObject *object) g_boxed_free (TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, self->priv->requestable_channel_classes); + g_list_free_full (self->priv->statuses, + (GDestroyNotify) tp_presence_status_spec_unref); + if (finalize != NULL) finalize (object); } @@ -938,26 +944,25 @@ protocol_prop_presence_getter (GObject *object, { case PPP_STATUSES: { - const TpPresenceStatusSpec *status = - tp_base_protocol_get_statuses (self); + const GList *iter; GHashTable *ret = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) tp_value_array_free); - for (; status->name != NULL; status++) + for (iter = self->priv->statuses; iter != NULL; iter = iter->next) { + TpPresenceStatusSpec *status = iter->data; GValueArray *val = NULL; gchar *key = NULL; - gboolean settable = status->self; - gboolean message = (settable && status->has_message); - TpConnectionPresenceType type = status->presence_type; - key = g_strdup (status->name); + key = g_strdup (tp_presence_status_spec_get_name (status)); val = tp_value_array_build (3, - G_TYPE_UINT, type, - G_TYPE_BOOLEAN, settable, - G_TYPE_BOOLEAN, message, + G_TYPE_UINT, + tp_presence_status_spec_get_presence_type (status), + G_TYPE_BOOLEAN, + tp_presence_status_spec_can_set_on_self (status), + G_TYPE_BOOLEAN, tp_presence_status_spec_has_message (status), G_TYPE_INVALID); g_hash_table_insert (ret, key, val); @@ -1229,34 +1234,30 @@ tp_base_protocol_init (TpBaseProtocol *self) } /** - * tp_base_protocol_get_statuses: + * tp_base_protocol_dup_statuses: * @self: a Protocol object * * Get the statuses supported by this object. Subclasses implement this via - * the #TpBaseProtocolClass.get_statuses virtual method. + * the #TpBaseProtocolClass.dup_statuses virtual method. * * If the object does not implement the Protocol.Interface.Presences * interface, it need not implement this virtual method. * - * Returns: an array of #TpPresenceStatusSpec structs describing the - * standard statuses supported by this protocol, with a final element - * whose name element is guaranteed to be %NULL. The array must remain - * valid at least as long as @self does. - * - * Since: 0.13.5 + * Returns: (element-type Tp.PresenceStatusSpec): a list + * of #TpPresenceStatusSpec structs describing the + * standard statuses supported by this protocol. */ -const TpPresenceStatusSpec * -tp_base_protocol_get_statuses (TpBaseProtocol *self) +GList * +tp_base_protocol_dup_statuses (TpBaseProtocol *self) { - static const TpPresenceStatusSpec none[] = { { NULL } }; TpBaseProtocolClass *cls = TP_BASE_PROTOCOL_GET_CLASS (self); g_return_val_if_fail (cls != NULL, NULL); - if (cls->get_statuses != NULL) - return cls->get_statuses (self); + if (cls->dup_statuses != NULL) + return cls->dup_statuses (self); - return none; + return NULL; } /** diff --git a/telepathy-glib/base-protocol.h b/telepathy-glib/base-protocol.h index e77ea08..884254d 100644 --- a/telepathy-glib/base-protocol.h +++ b/telepathy-glib/base-protocol.h @@ -161,7 +161,7 @@ struct _TpBaseProtocolClass gchar **english_name, gchar **vcard_field); - const TpPresenceStatusSpec * (*get_statuses) (TpBaseProtocol *self); + GList *(*dup_statuses) (TpBaseProtocol *self); TpBaseProtocolGetAvatarDetailsFunc get_avatar_details; @@ -176,7 +176,7 @@ const gchar *tp_base_protocol_get_name (TpBaseProtocol *self); GHashTable *tp_base_protocol_get_immutable_properties (TpBaseProtocol *self); const TpCMParamSpec *tp_base_protocol_get_parameters (TpBaseProtocol *self); -const TpPresenceStatusSpec *tp_base_protocol_get_statuses (TpBaseProtocol *self); +GList *tp_base_protocol_dup_statuses (TpBaseProtocol *self); TpBaseConnection *tp_base_protocol_new_connection (TpBaseProtocol *self, GHashTable *asv, GError **error); diff --git a/telepathy-glib/presence-mixin.c b/telepathy-glib/presence-mixin.c index f16c91b..5c16505 100644 --- a/telepathy-glib/presence-mixin.c +++ b/telepathy-glib/presence-mixin.c @@ -31,43 +31,15 @@ */ /** - * TpPresenceStatusSpec: - * @name: String identifier of the presence status - * @presence_type: A type value, as specified by #TpConnectionPresenceType - * @self: Indicates if this status may be set on yourself - * @has_message: %TRUE if a human-readable message can accompany this status. - * - * Structure specifying a supported presence status. - * - * In addition to the fields documented here, there are some reserved fields - * which must currently be %NULL. A meaning may be defined for these in a - * future version of telepathy-glib. - */ - -/** - * TpPresenceStatus: - * @index: Index of the presence status in the provided supported presence - * statuses array - * @message: the non-%NULL human-readable status message - * - * Structure representing a presence status. - * - * In addition to the fields documented here, there are some gpointer fields - * which must currently be %NULL. A meaning may be defined for these in a - * future version of telepathy-glib. - */ - -/** * TpPresenceMixinStatusAvailableFunc: * @self: A #TpBaseConnection implementing #TpPresenceMixinInterface - * @which: An index into the array of #TpPresenceStatusSpec provided to - * tp_presence_mixin_class_init() + * @spec: A presence specification * * Signature of a callback to be used to determine if a given presence * status can be set on the connection. Most users of this interface do not need * to supply an implementation of this callback: the value of - * #TpPresenceStatusSpec.self is enough to determine whether this is a - * user-settable presence. + * tp_presence_status_spec_can_set_on_self() is enough to determine whether + * this is a user-settable presence. * * One place where this callback may be needed is on XMPP: not all server * implementation support the user becoming invisible. So an XMPP @@ -81,7 +53,7 @@ */ /** - * TpPresenceMixinGetContactStatusFunc: + * TpPresenceMixinDupContactStatusFunc: * @self: A #TpBaseConnection implementing #TpPresenceMixinInterface * @contact: A #TpHandle of type %TP_ENTITY_TYPE_CONTACT * @@ -93,17 +65,14 @@ /** * TpPresenceMixinSetOwnStatusFunc: * @self: A #TpBaseConnection implementing #TpPresenceMixinInterface - * @status: The status to set, or NULL for whatever the protocol defines as a - * "default" status + * @status: The status to set * @error: Used to return a Telepathy D-Bus error if %FALSE is returned * * Signature of the callback used to commit changes to the user's own presence - * status in SetStatuses. It is also used in ClearStatus and RemoveStatus to - * reset the user's own status back to the "default" one with a %NULL status - * argument. + * status. * - * The callback is responsible for emitting PresenceUpdate, if appropriate, - * by calling tp_presence_mixin_emit_presence_update(). + * The callback is responsible for emitting change-notification, if + * appropriate, by calling tp_presence_mixin_emit_presence_update(). * * Returns: %TRUE if the operation was successful, %FALSE if not. */ @@ -129,7 +98,7 @@ * status can be set on a particular connection. Should usually be %NULL, to * consider all statuses with #TpPresenceStatusSpec.self set to %TRUE to be * settable. - * @get_contact_status: A callback to be used get the current presence status + * @dup_contact_status: A callback to be used get the current presence status * for contacts. This is used in implementations of various D-Bus methods and * hence must be provided. * @set_own_status: A callback to be used to commit changes to the user's own @@ -137,8 +106,8 @@ * D-Bus methods and hence must be provided. * @get_maximum_status_message_length: The callback used to discover the * the limit for status messages length, if any. - * @statuses: An array of #TpPresenceStatusSpec structures representing all - * presence statuses supported by the protocol, terminated by a NULL name. + * @dup_statuses: Return a list of #TpPresenceStatusSpec structures + * representing all presence statuses supported by the protocol * * The interface vtable for a %TP_TYPE_PRESENCE_MIXIN. */ @@ -165,39 +134,74 @@ #include "debug-internal.h" #include "base-connection-internal.h" +/** + * TpPresenceStatusSpec: + * + * Structure specifying a supported presence status. All fields are + * private. + */ +struct _TpPresenceStatusSpec { + gsize refcount; + gchar *name; + TpConnectionPresenceType presence_type; + gboolean self; + gboolean has_message; + guint id; +}; + +/** + * TpPresenceStatus: + * + * Structure representing a presence status. All fields are private. + */ +struct _TpPresenceStatus { + gsize refcount; + TpPresenceStatusSpec *spec; + gchar *message; +}; + +typedef struct { + _TpGDBusConnectionInterfacePresence1 *presence_skeleton; + /* (transfer full) (element-type TpPresenceStatusSpec) */ + GList *statuses; +} TpPresenceMixinPrivate; + static GQuark -skeleton_quark (void) +private_quark (void) { static GQuark q = 0; if (q == 0) - q = g_quark_from_static_string ("TpPresenceMixin-skeleton"); + q = g_quark_from_static_string ("TpPresenceMixin-private"); return q; } -static GVariant *construct_presence_map ( - const TpPresenceStatusSpec *supported_statuses, - GHashTable *contact_statuses); +static GVariant *construct_presence_map (GHashTable *contact_statuses); /** - * tp_presence_status_new: (skip) - * @which: Index of the presence status in the provided supported presence - * statuses array + * tp_presence_status_new: + * @spec: Presence status specification describing the status * @message: (allow-none): a human-readable status message, or %NULL * * Construct a presence status structure. You should free the returned - * structure with #tp_presence_status_free. + * structure with tp_presence_status_unref(). * - * Returns: A pointer to the newly allocated presence status structure. + * Returns: (transfer full): A pointer to the newly allocated presence + * status structure. */ TpPresenceStatus * -tp_presence_status_new (guint which, +tp_presence_status_new (TpPresenceStatusSpec *spec, const gchar *message) { - TpPresenceStatus *status = g_slice_new (TpPresenceStatus); + TpPresenceStatus *status; - status->index = which; + g_return_val_if_fail (spec != NULL, NULL); + g_return_val_if_fail (spec->refcount > 0, NULL); + + status = g_slice_new (TpPresenceStatus); + status->refcount = 1; + status->spec = tp_presence_status_spec_ref (spec); if (message == NULL) message = ""; @@ -207,23 +211,78 @@ tp_presence_status_new (guint which, return status; } +/** + * tp_presence_status_ref: + * @status: (transfer none): a presence status + * + * Take a reference to @status. + * + * Returns: (transfer full): @status + */ +TpPresenceStatus * +tp_presence_status_ref (TpPresenceStatus *status) +{ + g_return_val_if_fail (status != NULL, NULL); + g_return_val_if_fail (status->refcount > 0, NULL); + + status->refcount++; + return status; +} /** - * tp_presence_status_free: (skip) - * @status: A pointer to the presence status structure to free. + * tp_presence_status_unref: + * @status: (transfer full): a presence status * - * Deallocate all resources associated with a presence status structure. + * Decrease the reference count of @status. */ void -tp_presence_status_free (TpPresenceStatus *status) +tp_presence_status_unref (TpPresenceStatus *status) { - if (!status) + g_return_if_fail (status != NULL); + g_return_if_fail (status->refcount > 0); + + if (--status->refcount > 0) return; g_free (status->message); g_slice_free (TpPresenceStatus, status); } +/** + * tp_presence_status_get_spec: + * @status: a presence status + * + * Return the status specification (presence type, etc.) for @status. + * + * Returns: (transfer none): the status specification, which is owned + * by @status and should not be freed + */ +TpPresenceStatusSpec * +tp_presence_status_get_spec (TpPresenceStatus *status) +{ + g_return_val_if_fail (status != NULL, NULL); + g_return_val_if_fail (status->refcount > 0, NULL); + + return status->spec; +} + +/** + * tp_presence_status_get_message: + * @status: a presence status + * + * Return the user-defined, human-readable message. + * + * Returns: the message + */ +const gchar * +tp_presence_status_get_message (TpPresenceStatus *status) +{ + g_return_val_if_fail (status != NULL, NULL); + g_return_val_if_fail (status->refcount > 0, NULL); + + return status->message; +} + G_DEFINE_INTERFACE (TpPresenceMixin, tp_presence_mixin, TP_TYPE_BASE_CONNECTION) static void update_statuses_property (TpPresenceMixin *self); @@ -255,6 +314,15 @@ connection_status_changed_cb (TpBaseConnection *base, } } +static void +private_free (gpointer p) +{ + TpPresenceMixinPrivate *priv = p; + + g_object_unref (priv->presence_skeleton); + g_slice_free (TpPresenceMixinPrivate, priv); +} + /** * tp_presence_mixin_init: * @self: a #TpBaseConnection that implements #TpPresenceMixinInterface @@ -266,28 +334,40 @@ connection_status_changed_cb (TpBaseConnection *base, void tp_presence_mixin_init (TpPresenceMixin *self) { - _TpGDBusConnectionInterfacePresence1 *presence_skeleton; TpPresenceMixinInterface *iface = TP_PRESENCE_MIXIN_GET_INTERFACE (self); - guint i; + TpPresenceMixinPrivate *priv; + const GList *iter; g_return_if_fail (TP_IS_BASE_CONNECTION (self)); g_return_if_fail (TP_IS_PRESENCE_MIXIN (self)); - g_return_if_fail (iface->get_contact_status != NULL); + g_return_if_fail (iface->dup_contact_status != NULL); + g_return_if_fail (iface->dup_statuses != NULL); g_return_if_fail (iface->set_own_status != NULL); - g_return_if_fail (iface->statuses != NULL); - for (i = 0; iface->statuses[i].name != NULL; i++) + priv = g_slice_new0 (TpPresenceMixinPrivate); + priv->presence_skeleton = + _tp_gdbus_connection_interface_presence1_skeleton_new (); + g_object_set_qdata_full (G_OBJECT (self), private_quark (), priv, + private_free); + + g_signal_connect_object (priv->presence_skeleton, "handle-set-presence", + G_CALLBACK (tp_presence_mixin_set_presence), self, 0); + + priv->statuses = iface->dup_statuses (self); + + for (iter = priv->statuses; iter != NULL; iter = iter->next) { - if (iface->statuses[i].self) + TpPresenceStatusSpec *spec = iter->data; + + if (spec->self) { - switch (iface->statuses[i].presence_type) + switch (spec->presence_type) { case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: case TP_CONNECTION_PRESENCE_TYPE_ERROR: WARNING ("Status \"%s\" of type %u should not be available " - "to set on yourself", iface->statuses[i].name, - iface->statuses[i].presence_type); + "to set on yourself", spec->name, spec->presence_type); break; default: @@ -296,13 +376,6 @@ tp_presence_mixin_init (TpPresenceMixin *self) } } - presence_skeleton = _tp_gdbus_connection_interface_presence1_skeleton_new (); - g_object_set_qdata_full (G_OBJECT (self), skeleton_quark (), - presence_skeleton, g_object_unref); - - g_signal_connect_object (presence_skeleton, "handle-set-presence", - G_CALLBACK (tp_presence_mixin_set_presence), self, 0); - /* Set the initial properties values, we'll update them once CONNECTED */ update_max_status_message_len_property (self); update_statuses_property (self); @@ -310,7 +383,7 @@ tp_presence_mixin_init (TpPresenceMixin *self) G_CALLBACK (connection_status_changed_cb), NULL); g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (self), - G_DBUS_INTERFACE_SKELETON (presence_skeleton)); + G_DBUS_INTERFACE_SKELETON (priv->presence_skeleton)); } /** @@ -327,17 +400,16 @@ void tp_presence_mixin_emit_presence_update (TpPresenceMixin *self, GHashTable *contact_statuses) { - TpPresenceMixinInterface *iface = TP_PRESENCE_MIXIN_GET_INTERFACE (self); - _TpGDBusConnectionInterfacePresence1 *presence_skeleton; + TpPresenceMixinPrivate *priv; DEBUG ("called."); - presence_skeleton = g_object_get_qdata (G_OBJECT (self), skeleton_quark ()); - g_return_if_fail (presence_skeleton != NULL); + priv = g_object_get_qdata (G_OBJECT (self), private_quark ()); + g_return_if_fail (priv != NULL); _tp_gdbus_connection_interface_presence1_emit_presences_changed ( - presence_skeleton, - construct_presence_map (iface->statuses, contact_statuses)); + priv->presence_skeleton, + construct_presence_map (contact_statuses)); } /** @@ -352,7 +424,7 @@ tp_presence_mixin_emit_presence_update (TpPresenceMixin *self, void tp_presence_mixin_emit_one_presence_update (TpPresenceMixin *self, TpHandle handle, - const TpPresenceStatus *status) + TpPresenceStatus *status) { GHashTable *contact_statuses; @@ -369,30 +441,30 @@ tp_presence_mixin_emit_one_presence_update (TpPresenceMixin *self, static gboolean check_status_available (TpPresenceMixin *self, TpPresenceMixinInterface *iface, - guint i, + TpPresenceStatusSpec *spec, GError **error, gboolean for_self) { if (for_self) { - if (!iface->statuses[i].self) + if (!spec->self) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "cannot set status '%s' on yourself", - iface->statuses[i].name); + spec->name); return FALSE; } /* never allow OFFLINE, UNKNOWN or ERROR - if the CM says they're * OK to set on yourself, then it's wrong */ - switch (iface->statuses[i].presence_type) + switch (spec->presence_type) { case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: case TP_CONNECTION_PRESENCE_TYPE_ERROR: g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "cannot set offline/unknown/error status '%s' on yourself", - iface->statuses[i].name); + spec->name); return FALSE; default: @@ -400,85 +472,90 @@ check_status_available (TpPresenceMixin *self, } } - if (iface->status_available != NULL && !iface->status_available (self, i)) + if (iface->status_available != NULL && !iface->status_available (self, spec)) { DEBUG ("requested status %s is not available", - iface->statuses[i].name); + spec->name); g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "requested status '%s' is not available on this connection", - iface->statuses[i].name); + spec->name); return FALSE; } return TRUE; } -static int +static TpPresenceStatusSpec * check_for_status (TpPresenceMixin *self, const gchar *status, GError **error) { TpPresenceMixinInterface *iface = TP_PRESENCE_MIXIN_GET_INTERFACE (self); - int i; + TpPresenceMixinPrivate *priv; + const GList *iter; + + priv = g_object_get_qdata (G_OBJECT (self), private_quark ()); + g_return_val_if_fail (priv != NULL, NULL); - for (i = 0; iface->statuses[i].name != NULL; i++) + for (iter = priv->statuses; iter != NULL; iter = iter->next) { - if (!tp_strdiff (iface->statuses[i].name, status)) + TpPresenceStatusSpec *spec = iter->data; + + if (!tp_strdiff (spec->name, status)) break; } - if (iface->statuses[i].name != NULL) + if (iter != NULL) { + TpPresenceStatusSpec *spec = iter->data; + DEBUG ("Found status \"%s\", checking if it's available...", - (const gchar *) status); + spec->name); - if (!check_status_available (self, iface, i, error, TRUE)) - return -1; + if (!check_status_available (self, iface, spec, error, TRUE)) + return NULL; } else { DEBUG ("got unknown status identifier %s", status); g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "unknown status identifier: %s", status); - return -1; + return NULL; } - return i; + return iter->data; } static void update_statuses_property (TpPresenceMixin *self) { TpPresenceMixinInterface *iface = TP_PRESENCE_MIXIN_GET_INTERFACE (self); - _TpGDBusConnectionInterfacePresence1 *presence_skeleton; + TpPresenceMixinPrivate *priv; GVariantBuilder builder; - int i; + const GList *iter; - presence_skeleton = g_object_get_qdata (G_OBJECT (self), skeleton_quark ()); - g_return_if_fail (presence_skeleton != NULL); + priv = g_object_get_qdata (G_OBJECT (self), private_quark ()); + g_return_if_fail (priv != NULL); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{s(ubb)}")); - for (i = 0; iface->statuses[i].name != NULL; i++) + for (iter = priv->statuses; iter != NULL; iter = iter->next) { - gboolean message; + TpPresenceStatusSpec *spec = iter->data; /* we include statuses here even if they're not available * to set on yourself */ - if (!check_status_available (self, iface, i, NULL, FALSE)) + if (!check_status_available (self, iface, spec, NULL, FALSE)) continue; - message = tp_presence_status_spec_has_message ( - &iface->statuses[i]); - g_variant_builder_add (&builder, "{s(ubb)}", - iface->statuses[i].name, - iface->statuses[i].presence_type, - iface->statuses[i].self, - message); + spec->name, + spec->presence_type, + spec->self, + spec->has_message); } _tp_gdbus_connection_interface_presence1_set_statuses ( - presence_skeleton, + priv->presence_skeleton, g_variant_builder_end (&builder)); } @@ -486,17 +563,17 @@ static void update_max_status_message_len_property (TpPresenceMixin *self) { TpPresenceMixinInterface *iface = TP_PRESENCE_MIXIN_GET_INTERFACE (self); - _TpGDBusConnectionInterfacePresence1 *presence_skeleton; + TpPresenceMixinPrivate *priv; guint max_status_message_length = 0; - presence_skeleton = g_object_get_qdata (G_OBJECT (self), skeleton_quark ()); - g_return_if_fail (presence_skeleton != NULL); + priv = g_object_get_qdata (G_OBJECT (self), private_quark ()); + g_return_if_fail (priv != NULL); if (iface->get_maximum_status_message_length != NULL) max_status_message_length = iface->get_maximum_status_message_length (self); _tp_gdbus_connection_interface_presence1_set_maximum_status_message_length ( - presence_skeleton, max_status_message_length); + priv->presence_skeleton, max_status_message_length); } static gboolean @@ -508,25 +585,22 @@ tp_presence_mixin_set_presence ( TpPresenceMixin *self) { TpPresenceMixinInterface *iface = TP_PRESENCE_MIXIN_GET_INTERFACE (self); - TpPresenceStatus status_to_set = { 0, }; - int s; + TpPresenceStatus *status_to_set; + TpPresenceStatusSpec *s; GError *error = NULL; DEBUG ("called."); s = check_for_status (self, status, &error); - if (s == -1) + if (s == NULL) goto out; if (message == NULL) message = ""; - status_to_set.index = s; - status_to_set.message = g_strdup (message); - - iface->set_own_status (self, &status_to_set, &error); - - g_free (status_to_set.message); + status_to_set = tp_presence_status_new (s, message); + iface->set_own_status (self, status_to_set, &error); + tp_presence_status_unref (status_to_set); out: if (error == NULL) @@ -544,27 +618,21 @@ out: } static GVariant * -construct_presence_variant (TpPresenceStatus *status, - const TpPresenceStatusSpec *supported_statuses) +construct_presence_variant (TpPresenceStatus *status) { - TpConnectionPresenceType status_type; - const gchar *status_name; const gchar *message = NULL; - status_name = supported_statuses[status->index].name; - status_type = supported_statuses[status->index].presence_type; - message = status->message; if (message == NULL) message = ""; - return g_variant_new ("(uss)", status_type, status_name, message); + return g_variant_new ("(uss)", status->spec->presence_type, + status->spec->name, message); } static GVariant * -construct_presence_map (const TpPresenceStatusSpec *supported_statuses, - GHashTable *contact_statuses) +construct_presence_map (GHashTable *contact_statuses) { GVariantBuilder builder; GHashTableIter iter; @@ -579,7 +647,7 @@ construct_presence_map (const TpPresenceStatusSpec *supported_statuses, TpHandle handle = GPOINTER_TO_UINT (key); GVariant *presence; - presence = construct_presence_variant (value, supported_statuses); + presence = construct_presence_variant (value); g_variant_builder_add (&builder, "{u@(uss)}", handle, presence); } @@ -633,27 +701,21 @@ tp_presence_mixin_fill_contact_attributes (TpPresenceMixin *self, if (tp_strdiff (dbus_interface, TP_IFACE_CONNECTION_INTERFACE_PRESENCE1)) return FALSE; - status = iface->get_contact_status (self, contact); + status = iface->dup_contact_status (self, contact); if (status == NULL) { - CRITICAL ("get_contact_status returned NULL"); + CRITICAL ("dup_contact_status returned NULL"); } else { g_variant_dict_insert_value (attributes, TP_TOKEN_CONNECTION_INTERFACE_PRESENCE1_PRESENCE, - construct_presence_variant (status, iface->statuses)); - tp_presence_status_free (status); + construct_presence_variant (status)); + tp_presence_status_unref (status); } - return TRUE; -} -/* For now, self->priv is just self if heap-allocated, NULL if not. */ -static gboolean -_tp_presence_status_spec_is_heap_allocated (const TpPresenceStatusSpec *self) -{ - return (self->priv == (TpPresenceStatusSpecPrivate *) self); + return TRUE; } /** @@ -668,7 +730,7 @@ _tp_presence_status_spec_is_heap_allocated (const TpPresenceStatusSpec *self) * Since: 0.99.5 */ TpConnectionPresenceType -tp_presence_status_spec_get_presence_type (const TpPresenceStatusSpec *self) +tp_presence_status_spec_get_presence_type (TpPresenceStatusSpec *self) { g_return_val_if_fail (self != NULL, TP_CONNECTION_PRESENCE_TYPE_UNSET); @@ -686,7 +748,7 @@ tp_presence_status_spec_get_presence_type (const TpPresenceStatusSpec *self) * Since: 0.99.5 */ const gchar * -tp_presence_status_spec_get_name (const TpPresenceStatusSpec *self) +tp_presence_status_spec_get_name (TpPresenceStatusSpec *self) { g_return_val_if_fail (self != NULL, NULL); @@ -706,7 +768,7 @@ tp_presence_status_spec_get_name (const TpPresenceStatusSpec *self) * Since: 0.99.5 */ gboolean -tp_presence_status_spec_can_set_on_self (const TpPresenceStatusSpec *self) +tp_presence_status_spec_can_set_on_self (TpPresenceStatusSpec *self) { g_return_val_if_fail (self != NULL, FALSE); @@ -724,7 +786,7 @@ tp_presence_status_spec_can_set_on_self (const TpPresenceStatusSpec *self) * Since: 0.99.5 */ gboolean -tp_presence_status_spec_has_message (const TpPresenceStatusSpec *self) +tp_presence_status_spec_has_message (TpPresenceStatusSpec *self) { g_return_val_if_fail (self != NULL, FALSE); @@ -732,6 +794,22 @@ tp_presence_status_spec_has_message (const TpPresenceStatusSpec *self) } /** + * tp_presence_status_spec_get_id: + * @self: a presence status specification + * + * + * + * Returns: the @id passed to tp_presence_status_spec_new() + */ +guint +tp_presence_status_spec_get_id (TpPresenceStatusSpec *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return self->id; +} + +/** * tp_presence_status_spec_new: * @name: the name of the new presence status * @type: the category into which this presence status falls @@ -739,6 +817,8 @@ tp_presence_status_spec_has_message (const TpPresenceStatusSpec *self) * on themselves * @has_message: %TRUE if this presence status is accompanied by an * optional human-readable message + * @id: not used for anything by Telepathy, but may be used by + * connection managers as an index into a list of statuses if desired * * * @@ -749,7 +829,8 @@ TpPresenceStatusSpec * tp_presence_status_spec_new (const gchar *name, TpConnectionPresenceType type, gboolean can_set_on_self, - gboolean has_message) + gboolean has_message, + guint id) { TpPresenceStatusSpec *ret; @@ -759,55 +840,55 @@ tp_presence_status_spec_new (const gchar *name, ret = g_slice_new0 (TpPresenceStatusSpec); + ret->refcount = 1; ret->name = g_strdup (name); ret->presence_type = type; ret->self = can_set_on_self; ret->has_message = has_message; - - /* dummy marker for "this is on the heap" rather than a real struct */ - ret->priv = (TpPresenceStatusSpecPrivate *) ret; + ret->id = id; return ret; } /** - * tp_presence_status_spec_copy: + * tp_presence_status_spec_ref: * @self: a presence status specification * - * Copy a presence status specification. + * Take a reference to a presence status specification. * - * Returns: (transfer full): a new #TpPresenceStatusSpec resembling @self - * Since: 0.99.5 + * Returns: (transfer full): @self */ TpPresenceStatusSpec * -tp_presence_status_spec_copy (const TpPresenceStatusSpec *self) +tp_presence_status_spec_ref (TpPresenceStatusSpec *self) { g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (self->refcount > 0, NULL); - return tp_presence_status_spec_new (self->name, self->presence_type, - self->self, tp_presence_status_spec_has_message (self)); + self->refcount++; + return self; } /** - * tp_presence_status_spec_free: + * tp_presence_status_spec_unref: * @self: (transfer full): a presence status specification * - * Free a presence status specification produced by - * tp_presence_status_spec_new() or tp_presence_status_spec_copy(). - * - * Since: 0.99.5 + * Release a reference to a presence status specification produced by + * tp_presence_status_spec_new() or tp_presence_status_spec_ref(). */ void -tp_presence_status_spec_free (TpPresenceStatusSpec *self) +tp_presence_status_spec_unref (TpPresenceStatusSpec *self) { - g_return_if_fail (_tp_presence_status_spec_is_heap_allocated (self)); + g_return_if_fail (self != NULL); + g_return_if_fail (self->refcount > 0); - /* This struct was designed to always be on the stack, so freeing this - * needs a non-const-correct cast */ - g_free ((gchar *) self->name); + if (--self->refcount > 0) + return; + g_free (self->name); g_slice_free (TpPresenceStatusSpec, self); } G_DEFINE_BOXED_TYPE (TpPresenceStatusSpec, tp_presence_status_spec, - tp_presence_status_spec_copy, tp_presence_status_spec_free) + tp_presence_status_spec_ref, tp_presence_status_spec_unref) +G_DEFINE_BOXED_TYPE (TpPresenceStatus, tp_presence_status, + tp_presence_status_ref, tp_presence_status_unref) diff --git a/telepathy-glib/presence-mixin.h b/telepathy-glib/presence-mixin.h index 4a7b549..f2726f9 100644 --- a/telepathy-glib/presence-mixin.h +++ b/telepathy-glib/presence-mixin.h @@ -35,67 +35,64 @@ G_BEGIN_DECLS /* -- TpPresenceStatusSpec -- */ typedef struct _TpPresenceStatusSpec TpPresenceStatusSpec; -typedef struct _TpPresenceStatusSpecPrivate TpPresenceStatusSpecPrivate; - -struct _TpPresenceStatusSpec { - const gchar *name; - TpConnectionPresenceType presence_type; - gboolean self; - gboolean has_message; - - /**/ - GCallback _future[10]; - TpPresenceStatusSpecPrivate *priv; -}; _TP_AVAILABLE_IN_1_0 TpConnectionPresenceType tp_presence_status_spec_get_presence_type ( - const TpPresenceStatusSpec *self); + TpPresenceStatusSpec *self); _TP_AVAILABLE_IN_1_0 const gchar *tp_presence_status_spec_get_name ( - const TpPresenceStatusSpec *self); + TpPresenceStatusSpec *self); _TP_AVAILABLE_IN_1_0 gboolean tp_presence_status_spec_can_set_on_self ( - const TpPresenceStatusSpec *self); + TpPresenceStatusSpec *self); _TP_AVAILABLE_IN_1_0 gboolean tp_presence_status_spec_has_message ( - const TpPresenceStatusSpec *self); + TpPresenceStatusSpec *self); _TP_AVAILABLE_IN_1_0 GType tp_presence_status_spec_get_type (void); _TP_AVAILABLE_IN_1_0 +guint tp_presence_status_spec_get_id (TpPresenceStatusSpec *self); + +_TP_AVAILABLE_IN_1_0 TpPresenceStatusSpec *tp_presence_status_spec_new (const gchar *name, TpConnectionPresenceType type, gboolean can_set_on_self, - gboolean has_message); + gboolean has_message, + guint id); _TP_AVAILABLE_IN_1_0 -TpPresenceStatusSpec *tp_presence_status_spec_copy ( - const TpPresenceStatusSpec *self); +TpPresenceStatusSpec *tp_presence_status_spec_ref (TpPresenceStatusSpec *self); _TP_AVAILABLE_IN_1_0 -void tp_presence_status_spec_free (TpPresenceStatusSpec *self); +void tp_presence_status_spec_unref (TpPresenceStatusSpec *self); /* -- TpPresenceStatus -- */ +_TP_AVAILABLE_IN_1_0 +GType tp_presence_status_get_type (void); typedef struct _TpPresenceStatus TpPresenceStatus; -struct _TpPresenceStatus { - guint index; - gchar *message; +_TP_AVAILABLE_IN_1_0 +TpPresenceStatusSpec *tp_presence_status_get_spec (TpPresenceStatus *status); - /**/ - gpointer _future[6]; -}; +_TP_AVAILABLE_IN_1_0 +const gchar *tp_presence_status_get_message (TpPresenceStatus *status); -TpPresenceStatus *tp_presence_status_new (guint which, +_TP_AVAILABLE_IN_1_0 +TpPresenceStatus *tp_presence_status_new (TpPresenceStatusSpec *spec, const gchar *message) G_GNUC_WARN_UNUSED_RESULT; -void tp_presence_status_free (TpPresenceStatus *status); + +_TP_AVAILABLE_IN_1_0 +TpPresenceStatus *tp_presence_status_ref (TpPresenceStatus *status); + +_TP_AVAILABLE_IN_1_0 +void tp_presence_status_unref (TpPresenceStatus *status); /* -- TpPresenceMixinInterface -- */ @@ -118,14 +115,14 @@ typedef struct _TpPresenceMixinInterface TpPresenceMixinInterface; typedef struct _TpPresenceMixin TpPresenceMixin; typedef gboolean (*TpPresenceMixinStatusAvailableFunc) (TpPresenceMixin *self, - guint which); + TpPresenceStatusSpec *spec); -typedef TpPresenceStatus *(*TpPresenceMixinGetContactStatusFunc) ( +typedef TpPresenceStatus *(*TpPresenceMixinDupContactStatusFunc) ( TpPresenceMixin *self, TpHandle contact); typedef gboolean (*TpPresenceMixinSetOwnStatusFunc) (TpPresenceMixin *self, - const TpPresenceStatus *status, + TpPresenceStatus *status, GError **error); typedef guint (*TpPresenceMixinGetMaximumStatusMessageLengthFunc) ( @@ -135,12 +132,11 @@ struct _TpPresenceMixinInterface { GTypeInterface parent; TpPresenceMixinStatusAvailableFunc status_available; - TpPresenceMixinGetContactStatusFunc get_contact_status; + TpPresenceMixinDupContactStatusFunc dup_contact_status; TpPresenceMixinSetOwnStatusFunc set_own_status; TpPresenceMixinGetMaximumStatusMessageLengthFunc get_maximum_status_message_length; - - const TpPresenceStatusSpec *statuses; + GList *(*dup_statuses) (TpPresenceMixin *self); }; GType tp_presence_mixin_get_type (void) G_GNUC_CONST; @@ -149,7 +145,7 @@ void tp_presence_mixin_emit_presence_update (TpPresenceMixin *self, GHashTable *contact_presences); void tp_presence_mixin_emit_one_presence_update (TpPresenceMixin *self, TpHandle handle, - const TpPresenceStatus *status); + TpPresenceStatus *status); void tp_presence_mixin_init (TpPresenceMixin *self); gboolean tp_presence_mixin_fill_contact_attributes (TpPresenceMixin *self, diff --git a/telepathy-glib/protocol.c b/telepathy-glib/protocol.c index 9d4fe1c..bb1c011 100644 --- a/telepathy-glib/protocol.c +++ b/telepathy-glib/protocol.c @@ -2308,7 +2308,7 @@ tp_protocol_dup_presence_statuses (TpProtocol *self) &message); l = g_list_prepend (l, tp_presence_status_spec_new (k, type, - on_self, message)); + on_self, message, 0)); } return g_list_reverse (l); diff --git a/telepathy-glib/versions/main-1.0.abi b/telepathy-glib/versions/main-1.0.abi index 6298933..42450f6 100644 --- a/telepathy-glib/versions/main-1.0.abi +++ b/telepathy-glib/versions/main-1.0.abi @@ -330,7 +330,6 @@ tp_base_password_channel_get_type tp_base_protocol_get_immutable_properties tp_base_protocol_get_name tp_base_protocol_get_parameters -tp_base_protocol_get_statuses tp_base_protocol_get_type tp_base_protocol_new_connection tp_base_room_config_dup_channel @@ -979,11 +978,8 @@ tp_observe_channel_context_is_recovering tp_presence_mixin_emit_one_presence_update tp_presence_mixin_emit_presence_update tp_presence_mixin_get_type -tp_presence_status_free tp_presence_status_new tp_presence_status_spec_can_set_on_self -tp_presence_status_spec_copy -tp_presence_status_spec_free tp_presence_status_spec_get_name tp_presence_status_spec_get_presence_type tp_presence_status_spec_get_type diff --git a/tests/lib/contacts-conn.c b/tests/lib/contacts-conn.c index a418cb7..54a2371 100644 --- a/tests/lib/contacts-conn.c +++ b/tests/lib/contacts-conn.c @@ -91,6 +91,8 @@ struct _TpTestsContactsConnectionPrivate GPtrArray *default_contact_info; TpTestsContactListManager *list_manager; + /* (element-type TpPresenceStatusSpec) */ + GPtrArray *statuses; }; typedef struct @@ -136,9 +138,27 @@ free_rcc_list (GPtrArray *rccs) g_boxed_free (TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, rccs); } +/* Must match TpTestsContactsConnectionPresenceStatusIndex in the .h */ +static const struct { + const gchar *name; + TpConnectionPresenceType type; + gboolean on_self; + gboolean has_message; +} my_statuses[] = { + { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, TRUE}, + { "busy", TP_CONNECTION_PRESENCE_TYPE_BUSY, TRUE, TRUE }, + { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, TRUE }, + { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, FALSE }, + { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, FALSE }, + { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, FALSE }, + { NULL } +}; + static void tp_tests_contacts_connection_init (TpTestsContactsConnection *self) { + guint i; + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_CONTACTS_CONNECTION, TpTestsContactsConnectionPrivate); self->priv->aliases = g_hash_table_new_full (g_direct_hash, g_direct_equal, @@ -155,6 +175,20 @@ tp_tests_contacts_connection_init (TpTestsContactsConnection *self) g_direct_equal, NULL, (GDestroyNotify) free_rcc_list); self->priv->contact_info = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_ptr_array_unref); + + self->priv->statuses = g_ptr_array_new_full ( + TP_TESTS_CONTACTS_CONNECTION_N_STATUSES, + (GDestroyNotify) tp_presence_status_spec_unref); + + for (i = 0; i < TP_TESTS_CONTACTS_CONNECTION_N_STATUSES; i++) + { + g_ptr_array_add (self->priv->statuses, + tp_presence_status_spec_new (my_statuses[i].name, + my_statuses[i].type, my_statuses[i].on_self, + my_statuses[i].has_message, i)); + } + + g_assert (my_statuses[TP_TESTS_CONTACTS_CONNECTION_N_STATUSES].name == NULL); } static void @@ -179,6 +213,7 @@ finalize (GObject *object) g_hash_table_unref (self->priv->locations); g_hash_table_unref (self->priv->capabilities); g_hash_table_unref (self->priv->contact_info); + g_ptr_array_unref (self->priv->statuses); if (self->priv->default_contact_info != NULL) g_ptr_array_unref (self->priv->default_contact_info); @@ -420,26 +455,15 @@ constructed (GObject *object) tp_presence_mixin_init (TP_PRESENCE_MIXIN (self)); } -/* Must match TpTestsContactsConnectionPresenceStatusIndex in the .h */ -static const TpPresenceStatusSpec my_statuses[] = { - { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, TRUE}, - { "busy", TP_CONNECTION_PRESENCE_TYPE_BUSY, TRUE, TRUE }, - { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, TRUE }, - { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, FALSE }, - { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, FALSE }, - { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, FALSE }, - { NULL } -}; - static gboolean my_status_available (TpPresenceMixin *mixin, - guint index) + TpPresenceStatusSpec *spec) { return tp_base_connection_check_connected (TP_BASE_CONNECTION (mixin), NULL); } static TpPresenceStatus * -my_get_contact_status (TpPresenceMixin *mixin, +my_dup_contact_status (TpPresenceMixin *mixin, TpHandle contact) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (mixin); @@ -452,19 +476,24 @@ my_get_contact_status (TpPresenceMixin *mixin, presence_message = g_hash_table_lookup ( self->priv->presence_messages, key); - return tp_presence_status_new (index, presence_message); + return tp_presence_status_new ( + g_ptr_array_index (self->priv->statuses, index), presence_message); } static gboolean my_set_own_status (TpPresenceMixin *mixin, - const TpPresenceStatus *status, + TpPresenceStatus *status, GError **error) { TpBaseConnection *base_conn = TP_BASE_CONNECTION (mixin); - TpTestsContactsConnectionPresenceStatusIndex index = status->index; - const gchar *message = status->message; + TpTestsContactsConnectionPresenceStatusIndex index; + const gchar *message; TpHandle self_handle; + index = tp_presence_status_spec_get_id ( + tp_presence_status_get_spec (status)); + message = tp_presence_status_get_message (status); + self_handle = tp_base_connection_get_self_handle (base_conn); tp_tests_contacts_connection_change_presences ( TP_TESTS_CONTACTS_CONNECTION (base_conn), @@ -479,6 +508,21 @@ my_get_maximum_status_message_length_cb (TpPresenceMixin *mixin G_GNUC_UNUSED) return 512; } +static GList * +my_dup_statuses (TpPresenceMixin *mixin) +{ + TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (mixin); + GList *them = NULL; + guint i; + + for (i = 0; i < TP_TESTS_CONTACTS_CONNECTION_N_STATUSES; i++) + them = g_list_prepend (them, + tp_presence_status_spec_ref ( + g_ptr_array_index (self->priv->statuses, i))); + + return them; +} + static void init_presence (gpointer g_iface, gpointer iface_data) @@ -486,9 +530,9 @@ init_presence (gpointer g_iface, TpPresenceMixinInterface *iface = g_iface; iface->status_available = my_status_available; - iface->get_contact_status = my_get_contact_status; + iface->dup_contact_status = my_dup_contact_status; iface->set_own_status = my_set_own_status; - iface->statuses = my_statuses; + iface->dup_statuses = my_dup_statuses; iface->get_maximum_status_message_length = my_get_maximum_status_message_length_cb; } @@ -614,7 +658,7 @@ tp_tests_contacts_connection_change_presences ( const gchar * const *messages) { GHashTable *presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) tp_presence_status_free); + NULL, (GDestroyNotify) tp_presence_status_unref); guint i; for (i = 0; i < n; i++) @@ -629,7 +673,9 @@ tp_tests_contacts_connection_change_presences ( g_hash_table_insert (self->priv->presence_messages, key, g_strdup (messages[i])); - g_hash_table_insert (presences, key, tp_presence_status_new (indexes[i], + g_hash_table_insert (presences, key, + tp_presence_status_new ( + g_ptr_array_index (self->priv->statuses, indexes[i]), messages[i])); } diff --git a/tests/lib/contacts-conn.h b/tests/lib/contacts-conn.h index 2814055..071d95e 100644 --- a/tests/lib/contacts-conn.h +++ b/tests/lib/contacts-conn.h @@ -46,7 +46,8 @@ typedef enum { TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY, TP_TESTS_CONTACTS_CONNECTION_STATUS_OFFLINE, TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN, - TP_TESTS_CONTACTS_CONNECTION_STATUS_ERROR + TP_TESTS_CONTACTS_CONNECTION_STATUS_ERROR, + TP_TESTS_CONTACTS_CONNECTION_N_STATUSES } TpTestsContactsConnectionPresenceStatusIndex; /* TYPE MACROS */ -- 1.9.2