summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2014-04-16 20:39:11 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2014-04-17 14:24:35 +0100
commite487f5d6c8e6dcb04a94da593377ebada35ac2df (patch)
tree69feb5c0d290f2d77628d4b69b9adb14c08c4492
parent49fe3c0ac98e28ed62c937a0588605748e088f53 (diff)
TpPresenceMixin: redo the API to be introspectablewip-presence-mixin
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.
-rw-r--r--docs/reference/telepathy-glib/telepathy-glib-sections.txt15
-rw-r--r--examples/cm/call/conn.c88
-rw-r--r--examples/cm/call/conn.h3
-rw-r--r--examples/cm/contactlist/conn.c40
-rw-r--r--examples/cm/contactlist/contact-list.c26
-rw-r--r--examples/cm/contactlist/contact-list.h3
-rw-r--r--telepathy-glib/base-protocol.c55
-rw-r--r--telepathy-glib/base-protocol.h4
-rw-r--r--telepathy-glib/presence-mixin.c437
-rw-r--r--telepathy-glib/presence-mixin.h66
-rw-r--r--telepathy-glib/protocol.c2
-rw-r--r--telepathy-glib/versions/main-1.0.abi4
-rw-r--r--tests/lib/contacts-conn.c88
-rw-r--r--tests/lib/contacts-conn.h3
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 50f650ccd..e30a23075 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
<TITLE>TpPresenceMixin</TITLE>
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
</SECTION>
@@ -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
<SUBSECTION>
TpBaseProtocolClass
diff --git a/examples/cm/call/conn.c b/examples/cm/call/conn.c
index 3dd0e0a40..eb95cc2cc 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 bb2404df8..f7694c1e7 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 20db31f90..b599557c6 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 3a5ca8501..edb5863fe 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 fdd1175fd..dd3fa6e0f 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 e18507d78..5c831d0d6 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 e77ea0809..884254def 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 f16c91bef..5c165052f 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 4a7b54995..f2726f92d 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;
-
- /*<private>*/
- 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);
- /*<private>*/
- 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 9d4fe1c90..bb1c01159 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 629893388..42450f68d 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 a418cb7ce..54a237170 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 28140550d..071d95ea4 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 */