From cde4022a6a6d15be2f1ef917815cadd438ce3a80 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 27 Apr 2012 14:32:10 +0200 Subject: [PATCH] Move ChatState to TpTextChannel API on TpChannel is now deprecated but still used to implement the corresponding API on TpTextChannel. https://bugs.freedesktop.org/show_bug.cgi?id=49215 --- docs/reference/telepathy-glib-sections.txt | 5 ++ telepathy-glib/channel.c | 3 + telepathy-glib/channel.h | 2 +- telepathy-glib/text-channel.c | 118 ++++++++++++++++++++++++++++ telepathy-glib/text-channel.h | 6 ++ 5 files changed, 133 insertions(+), 1 deletion(-) diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt index 02f6c41..1a68f78 100644 --- a/docs/reference/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib-sections.txt @@ -6528,11 +6528,15 @@ tp_text_channel_ack_all_pending_messages_finish tp_text_channel_set_chat_state_async tp_text_channel_set_chat_state_finish tp_text_channel_supports_message_type + TP_TEXT_CHANNEL_FEATURE_SMS tp_text_channel_is_sms_channel tp_text_channel_get_sms_flash tp_text_channel_get_sms_length_async tp_text_channel_get_sms_length_finish + +TP_TEXT_CHANNEL_FEATURE_CHAT_STATES +tp_text_channel_get_chat_state TP_IS_TEXT_CHANNEL TP_IS_TEXT_CHANNEL_CLASS @@ -6545,6 +6549,7 @@ TpTextChannelPrivate tp_text_channel_get_feature_quark_incoming_messages tp_text_channel_get_feature_quark_sms +tp_text_channel_get_feature_quark_chat_states
diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c index 41f016a..012e232 100644 --- a/telepathy-glib/channel.c +++ b/telepathy-glib/channel.c @@ -227,6 +227,7 @@ tp_channel_get_feature_quark_contacts (void) * tp_proxy_prepare_async() function, and waiting for it to callback. * * Since: 0.11.3 + * Deprecated: Use TP_TEXT_CHANNEL_FEATURE_CHAT_STATES instead. */ GQuark @@ -516,6 +517,7 @@ tp_channel_get_property (GObject *object, * Returns: the chat state for @contact, or %TP_CHANNEL_CHAT_STATE_INACTIVE * if their chat state is not known * Since: 0.11.3 + * Deprecated: Use tp_text_channel_get_chat_state() instead. */ TpChannelChatState tp_channel_get_chat_state (TpChannel *self, @@ -1863,6 +1865,7 @@ tp_channel_class_init (TpChannelClass *klass) * has finished preparing the feature %TP_CHANNEL_FEATURE_CHAT_STATES. * * Since: 0.11.3 + * Deprecated: Use #TpTextChannel::contact-chat-state-changed instead */ signals[SIGNAL_CHAT_STATE_CHANGED] = g_signal_new ("chat-state-changed", G_OBJECT_CLASS_TYPE (klass), diff --git a/telepathy-glib/channel.h b/telepathy-glib/channel.h index cf31db6..f66528b 100644 --- a/telepathy-glib/channel.h +++ b/telepathy-glib/channel.h @@ -159,7 +159,7 @@ TpContact *tp_channel_group_get_contact_owner (TpChannel *self, tp_channel_get_feature_quark_chat_states () GQuark tp_channel_get_feature_quark_chat_states (void) G_GNUC_CONST; TpChannelChatState tp_channel_get_chat_state (TpChannel *self, - TpHandle contact); + TpHandle contact) _TP_GNUC_DEPRECATED_FOR (tp_text_channel_get_chat_state); void tp_channel_join_async (TpChannel *self, const gchar *message, diff --git a/telepathy-glib/text-channel.c b/telepathy-glib/text-channel.c index e56664b..796bbe4 100644 --- a/telepathy-glib/text-channel.c +++ b/telepathy-glib/text-channel.c @@ -103,6 +103,7 @@ enum /* signals */ SIG_MESSAGE_RECEIVED, SIG_PENDING_MESSAGE_REMOVED, SIG_MESSAGE_SENT, + SIG_CONTACT_CHAT_STATE_CHANGED, LAST_SIGNAL }; @@ -359,6 +360,42 @@ message_sent_cb (TpChannel *channel, } static void +chat_state_changed_cb (TpTextChannel *self, + TpHandle handle, + TpChannelChatState state) +{ + TpConnection *conn; + TpContact *contact; + + /* We have only an handle, but since we guarantee "contact-chat-state-changed" + * to be emitted only if TP_CHANNEL_FEATURE_GROUP and + * TP_CHANNEL_FEATURE_CONTACTS has been prepared, we should already have its + * TpContact. If the TpContact does not exist, telling its chat state is + * useless anyway. */ + conn = tp_channel_borrow_connection ((TpChannel *) self); + contact = tp_connection_dup_contact_if_possible (conn, handle, NULL); + if (contact == NULL) + return; + + g_signal_emit (self, signals[SIG_CONTACT_CHAT_STATE_CHANGED], 0, + contact, state); + + g_object_unref (contact); +} + +static void +tp_text_channel_prepare_chat_states_async (TpProxy *proxy, + const TpProxyFeature *feature, + GAsyncReadyCallback callback, + gpointer user_data) +{ + /* This feature depends on TP_CHANNEL_FEATURE_CHAT_STATES so it's already + * prepared. */ + tp_simple_async_report_success_in_idle ((GObject *) proxy, + callback, user_data, tp_text_channel_prepare_chat_states_async); +} + +static void tp_text_channel_constructed (GObject *obj) { TpTextChannel *self = (TpTextChannel *) obj; @@ -399,6 +436,11 @@ tp_text_channel_constructed (GObject *obj) } + /* Forward TpChannel::chat-state-changed as + * TpTextChannel::contact-chat-state-changed */ + g_signal_connect (self, "chat-state-changed", + G_CALLBACK (chat_state_changed_cb), NULL); + props = tp_channel_borrow_immutable_properties (TP_CHANNEL (self)); self->priv->supported_content_types = (GStrv) tp_asv_get_strv (props, @@ -802,6 +844,7 @@ tp_text_channel_prepare_sms_async (TpProxy *proxy, enum { FEAT_PENDING_MESSAGES, FEAT_SMS, + FEAT_CHAT_STATES, N_FEAT }; @@ -810,6 +853,7 @@ tp_text_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED) { static TpProxyFeature features[N_FEAT + 1] = { { 0 } }; static GQuark need_sms[2] = {0, 0}; + static GQuark depends_chat_state[2] = {0, 0}; if (G_LIKELY (features[0].name != 0)) return features; @@ -826,6 +870,13 @@ tp_text_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED) need_sms[0] = TP_IFACE_QUARK_CHANNEL_INTERFACE_SMS; features[FEAT_SMS].interfaces_needed = need_sms; + features[FEAT_CHAT_STATES].name = + TP_TEXT_CHANNEL_FEATURE_CHAT_STATES; + features[FEAT_CHAT_STATES].prepare_async = + tp_text_channel_prepare_chat_states_async; + depends_chat_state[0] = TP_CHANNEL_FEATURE_CHAT_STATES; + features[FEAT_CHAT_STATES].depends_on = depends_chat_state; + /* assert that the terminator at the end is there */ g_assert (features[N_FEAT].name == 0); @@ -1025,6 +1076,26 @@ tp_text_channel_class_init (TpTextChannelClass *klass) 3, TP_TYPE_SIGNALLED_MESSAGE, G_TYPE_UINT, G_TYPE_STRING); g_type_class_add_private (gobject_class, sizeof (TpTextChannelPrivate)); + + /** + * TpTextChannel::contact-chat-state-changed: + * @self: a channel + * @contact: a #TpContact for the local user or another contact + * @state: the new #TpChannelChatState for the contact + * + * Emitted when a contact's chat state changes after tp_proxy_prepare_async() + * has finished preparing features %TP_TEXT_CHANNEL_FEATURE_CHAT_STATES, + * %TP_CHANNEL_FEATURE_GROUP and %TP_CHANNEL_FEATURE_CONTACTS. + * + * Since: 0.UNRELEASED + */ + signals[SIG_CONTACT_CHAT_STATE_CHANGED] = g_signal_new ( + "contact-chat-state-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, TP_TYPE_CONTACT, G_TYPE_UINT); } static void @@ -1494,6 +1565,53 @@ tp_text_channel_ack_message_finish (TpTextChannel *self, _tp_implement_finish_void (self, tp_text_channel_ack_message_async) } +/** + * TP_TEXT_CHANNEL_FEATURE_CHAT_STATES: + * + * Expands to a call to a function that returns a quark representing the + * chat states feature on a #TpTextChannel. + * + * When this feature is prepared, tp_text_channel_get_chat_state() and the + * #TpTextChannel::contact-chat-state-changed signal become useful. + * + * One can ask for a feature to be prepared using the + * tp_proxy_prepare_async() function, and waiting for it to callback. + * + * Since: 0.UNRELEASED + */ + +GQuark +tp_text_channel_get_feature_quark_chat_states (void) +{ + return g_quark_from_static_string ("tp-text-channel-feature-chat-states"); +} + +/** + * tp_text_channel_get_chat_state: + * @self: a channel + * @contact: a #TpContact + * + * Return the chat state for the given contact. If tp_proxy_is_prepared() + * would return %FALSE for the feature %TP_TEXT_CHANNEL_FEATURE_CHAT_STATES, + * the result will always be %TP_CHANNEL_CHAT_STATE_INACTIVE. + * + * Returns: the chat state for @contact, or %TP_CHANNEL_CHAT_STATE_INACTIVE + * if their chat state is not known + * Since: 0.UNRELEASED + */ +TpChannelChatState +tp_text_channel_get_chat_state (TpTextChannel *self, + TpContact *contact) +{ + g_return_val_if_fail (TP_IS_TEXT_CHANNEL (self), 0); + + /* Use the deprecated function internally to avoid duplicated introspection */ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + return tp_channel_get_chat_state ((TpChannel *) self, + tp_contact_get_handle (contact)); + G_GNUC_END_IGNORE_DEPRECATIONS +} + static void set_chat_state_cb (TpChannel *proxy, const GError *error, diff --git a/telepathy-glib/text-channel.h b/telepathy-glib/text-channel.h index 4d9fec5..62f6588 100644 --- a/telepathy-glib/text-channel.h +++ b/telepathy-glib/text-channel.h @@ -118,6 +118,12 @@ gboolean tp_text_channel_ack_all_pending_messages_finish (TpTextChannel *self, GAsyncResult *result, GError **error); +#define TP_TEXT_CHANNEL_FEATURE_CHAT_STATES \ + tp_text_channel_get_feature_quark_chat_states () +GQuark tp_text_channel_get_feature_quark_chat_states (void) G_GNUC_CONST; +TpChannelChatState tp_text_channel_get_chat_state (TpTextChannel *self, + TpContact *contact); + void tp_text_channel_set_chat_state_async (TpTextChannel *self, TpChannelChatState state, GAsyncReadyCallback callback, -- 1.7.9.5