From: Xavier Claessens Date: Sun, 18 May 2008 14:27:44 +0000 (+0000) Subject: Improve dispatcher. Fixes bug #465928. X-Git-Url: https://git.0d.be/?p=empathy.git;a=commitdiff_plain;h=ec55d4f9308a0eb65c6ea5de7e9757e9d8b0b70f Improve dispatcher. Fixes bug #465928. svn path=/trunk/; revision=1108 --- diff --git a/libempathy-gtk/empathy-contact-list-view.c b/libempathy-gtk/empathy-contact-list-view.c index 90598d39..3c4d234b 100644 --- a/libempathy-gtk/empathy-contact-list-view.c +++ b/libempathy-gtk/empathy-contact-list-view.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "empathy-contact-list-view.h" @@ -462,7 +463,7 @@ contact_list_view_row_activated_cb (EmpathyContactListView *view, -1); if (contact) { - empathy_chat_with_contact (contact); + empathy_dispatcher_chat_with_contact (contact); g_object_unref (contact); } } @@ -491,7 +492,7 @@ contact_list_view_voip_activated_cb (EmpathyCellRendererActivatable *cell, -1); if (contact) { - empathy_call_with_contact (contact); + empathy_dispatcher_call_with_contact (contact); g_object_unref (contact); } } diff --git a/libempathy-gtk/empathy-contact-menu.c b/libempathy-gtk/empathy-contact-menu.c index 275729f9..81c94a6d 100644 --- a/libempathy-gtk/empathy-contact-menu.c +++ b/libempathy-gtk/empathy-contact-menu.c @@ -26,8 +26,9 @@ #include #include -#include #include +#include +#include #include "empathy-contact-menu.h" #include "empathy-images.h" @@ -112,7 +113,7 @@ empathy_contact_chat_menu_item_new (EmpathyContact *contact) gtk_widget_show (image); g_signal_connect_swapped (item, "activate", - G_CALLBACK (empathy_chat_with_contact), + G_CALLBACK (empathy_dispatcher_chat_with_contact), contact); return item; @@ -134,7 +135,7 @@ empathy_contact_call_menu_item_new (EmpathyContact *contact) gtk_widget_show (image); g_signal_connect_swapped (item, "activate", - G_CALLBACK (empathy_call_with_contact), + G_CALLBACK (empathy_dispatcher_call_with_contact), contact); return item; diff --git a/libempathy-gtk/empathy-new-message-dialog.c b/libempathy-gtk/empathy-new-message-dialog.c index b07f13e2..fc4c0f88 100644 --- a/libempathy-gtk/empathy-new-message-dialog.c +++ b/libempathy-gtk/empathy-new-message-dialog.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -67,10 +68,10 @@ new_message_dialog_response_cb (GtkWidget *widget, } if (response == 1) { - empathy_call_with_contact_id (account, id); + empathy_dispatcher_call_with_contact_id (account, id); } else if (response == 2) { - empathy_chat_with_contact_id (account, id); + empathy_dispatcher_chat_with_contact_id (account, id); } g_object_unref (account); diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 741b01db..1d2b9895 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -40,6 +40,7 @@ #include "empathy-utils.h" #include "empathy-tube-handler.h" #include "empathy-contact-factory.h" +#include "empathy-tp-group.h" #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER #include @@ -49,7 +50,7 @@ typedef struct { GHashTable *connections; gpointer token; MissionControl *mc; - GHashTable *tubes; + GSList *tubes; } EmpathyDispatcherPriv; G_DEFINE_TYPE (EmpathyDispatcher, empathy_dispatcher, G_TYPE_OBJECT); @@ -203,7 +204,6 @@ dispatcher_tubes_new_tube_cb (TpChannel *channel, gpointer user_data, GObject *dispatcher) { - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); static TpDBusDaemon *daemon = NULL; DispatcherTube *tube; McAccount *account; @@ -213,9 +213,8 @@ dispatcher_tubes_new_tube_cb (TpChannel *channel, GError *error = NULL; /* Increase tube count */ - number = GPOINTER_TO_UINT (g_hash_table_lookup (priv->tubes, channel)); - g_hash_table_replace (priv->tubes, g_object_ref (channel), - GUINT_TO_POINTER (++number)); + number = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (channel), "tube-count")); + g_object_set_data (G_OBJECT (channel), "tube-count", GUINT_TO_POINTER (++number)); DEBUG ("Increased tube count for channel %p: %d", channel, number); /* We dispatch only local pending tubes */ @@ -308,17 +307,18 @@ dispatcher_tubes_list_tubes_cb (TpChannel *channel, } static void -dispatcher_tubes_channel_invalidated_cb (TpProxy *proxy, - guint domain, - gint code, - gchar *message, +dispatcher_tubes_channel_invalidated_cb (TpProxy *proxy, + guint domain, + gint code, + gchar *message, EmpathyDispatcher *dispatcher) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - DEBUG ("Error: %s", message); + DEBUG ("%s", message); - g_hash_table_remove (priv->tubes, proxy); + priv->tubes = g_slist_remove (priv->tubes, proxy); + g_object_unref (proxy); } static void @@ -327,18 +327,16 @@ dispatcher_tubes_tube_closed_cb (TpChannel *channel, gpointer user_data, GObject *dispatcher) { - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - guint number; + guint number; - number = GPOINTER_TO_UINT (g_hash_table_lookup (priv->tubes, channel)); + number = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (channel), "tube-count")); if (number == 1) { DEBUG ("No more tube, closing channel"); tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); } else if (number > 1) { DEBUG ("Decrease tube count: %d", number); - g_hash_table_replace (priv->tubes, g_object_ref (channel), - GUINT_TO_POINTER (--number)); + g_object_set_data (G_OBJECT (channel), "tube-count", GUINT_TO_POINTER (--number)); } } @@ -348,15 +346,9 @@ dispatcher_tubes_handle_channel (EmpathyDispatcher *dispatcher, { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - if (g_hash_table_lookup (priv->tubes, channel)) { - return; - } - - DEBUG ("Handling new channel"); - - g_hash_table_insert (priv->tubes, g_object_ref (channel), - GUINT_TO_POINTER (0)); + DEBUG ("Called"); + priv->tubes = g_slist_prepend (priv->tubes, g_object_ref (channel)); g_signal_connect (channel, "invalidated", G_CALLBACK (dispatcher_tubes_channel_invalidated_cb), dispatcher); @@ -569,34 +561,24 @@ dispatcher_status_changed_cb (MissionControl *mc, g_object_unref (account); } -static guint -dispatcher_channel_hash (gconstpointer key) -{ - TpProxy *channel = TP_PROXY (key); - - return g_str_hash (channel->object_path); -} - -static gboolean -dispatcher_channel_equal (gconstpointer a, - gconstpointer b) -{ - TpProxy *channel_a = TP_PROXY (a); - TpProxy *channel_b = TP_PROXY (b); - - return g_str_equal (channel_a->object_path, channel_b->object_path); -} - static void dispatcher_finalize (GObject *object) { EmpathyDispatcherPriv *priv = GET_PRIV (object); + GSList *l; empathy_disconnect_account_status_changed (priv->token); g_object_unref (priv->mc); + for (l = priv->tubes; l; l = l->next) { + g_signal_handlers_disconnect_by_func (l->data, + dispatcher_tubes_channel_invalidated_cb, + object); + g_object_unref (l->data); + } + g_slist_free (priv->tubes); + g_hash_table_destroy (priv->connections); - g_hash_table_destroy (priv->tubes); } static void @@ -645,10 +627,6 @@ empathy_dispatcher_init (EmpathyDispatcher *dispatcher) EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherPriv); dispatcher->priv = priv; - priv->tubes = g_hash_table_new_full (dispatcher_channel_hash, - dispatcher_channel_equal, - g_object_unref, NULL); - priv->mc = empathy_mission_control_new (); priv->token = empathy_connect_to_account_status_changed (priv->mc, G_CALLBACK (dispatcher_status_changed_cb), @@ -679,3 +657,162 @@ empathy_dispatcher_new (void) return dispatcher; } +typedef struct { + const gchar *channel_type; + guint handle_type; + guint handle; +} DispatcherRequestData; + +static void +dispatcher_request_channel_cb (TpConnection *connection, + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + DispatcherRequestData *data = (DispatcherRequestData*) user_data; + + if (error) { + DEBUG ("Error: %s", error->message); + return; + } + + if (dispatcher) { + TpChannel *channel; + + channel = tp_channel_new (connection, object_path, + data->channel_type, + data->handle_type, + data->handle, NULL); + + g_signal_emit (dispatcher, signals[DISPATCH_CHANNEL], 0, channel); + } +} + +void +empathy_dispatcher_call_with_contact (EmpathyContact *contact) +{ + MissionControl *mc; + McAccount *account; + TpConnection *connection; + gchar *object_path; + TpChannel *channel; + EmpathyContactFactory *factory; + EmpathyTpGroup *group; + EmpathyContact *self_contact; + GError *error = NULL; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + mc = empathy_mission_control_new (); + account = empathy_contact_get_account (contact); + connection = mission_control_get_tpconnection (mc, account, NULL); + tp_connection_run_until_ready (connection, FALSE, NULL, NULL); + g_object_unref (mc); + + /* We abuse of suppress_handler, TRUE means OUTGOING. The channel + * will be catched in EmpathyFilter */ + if (!tp_cli_connection_run_request_channel (connection, -1, + TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, + TP_HANDLE_TYPE_NONE, + 0, + TRUE, + &object_path, + &error, + NULL)) { + DEBUG ("Couldn't request channel: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + g_object_unref (connection); + return; + } + + channel = tp_channel_new (connection, + object_path, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, + TP_HANDLE_TYPE_NONE, 0, NULL); + + group = empathy_tp_group_new (channel); + empathy_run_until_ready (group); + + factory = empathy_contact_factory_new (); + self_contact = empathy_contact_factory_get_user (factory, account); + empathy_contact_run_until_ready (self_contact, + EMPATHY_CONTACT_READY_HANDLE, + NULL); + + empathy_tp_group_add_member (group, contact, ""); + empathy_tp_group_add_member (group, self_contact, ""); + + g_object_unref (factory); + g_object_unref (self_contact); + g_object_unref (group); + g_object_unref (connection); + g_object_unref (channel); + g_free (object_path); +} + +void +empathy_dispatcher_call_with_contact_id (McAccount *account, const gchar *contact_id) +{ + EmpathyContactFactory *factory; + EmpathyContact *contact; + + factory = empathy_contact_factory_new (); + contact = empathy_contact_factory_get_from_id (factory, account, contact_id); + empathy_contact_run_until_ready (contact, EMPATHY_CONTACT_READY_HANDLE, NULL); + + empathy_dispatcher_call_with_contact (contact); + + g_object_unref (contact); + g_object_unref (factory); +} + +void +empathy_dispatcher_chat_with_contact (EmpathyContact *contact) +{ + MissionControl *mc; + McAccount *account; + TpConnection *connection; + DispatcherRequestData *data; + + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + + mc = empathy_mission_control_new (); + account = empathy_contact_get_account (contact); + connection = mission_control_get_tpconnection (mc, account, NULL); + tp_connection_run_until_ready (connection, FALSE, NULL, NULL); + g_object_unref (mc); + + /* We abuse of suppress_handler, TRUE means OUTGOING. */ + data = g_new (DispatcherRequestData, 1); + data->channel_type = TP_IFACE_CHANNEL_TYPE_TEXT; + data->handle_type = TP_HANDLE_TYPE_CONTACT; + data->handle = empathy_contact_get_handle (contact); + tp_cli_connection_call_request_channel (connection, -1, + data->channel_type, + data->handle_type, + data->handle, + TRUE, + dispatcher_request_channel_cb, + data, g_free, + NULL); + g_object_unref (connection); +} + +void +empathy_dispatcher_chat_with_contact_id (McAccount *account, + const gchar *contact_id) +{ + EmpathyContactFactory *factory; + EmpathyContact *contact; + + factory = empathy_contact_factory_new (); + contact = empathy_contact_factory_get_from_id (factory, account, contact_id); + empathy_contact_run_until_ready (contact, EMPATHY_CONTACT_READY_HANDLE, NULL); + + empathy_dispatcher_chat_with_contact (contact); + + g_object_unref (contact); + g_object_unref (factory); +} + diff --git a/libempathy/empathy-dispatcher.h b/libempathy/empathy-dispatcher.h index 0cc59c8b..b14a460e 100644 --- a/libempathy/empathy-dispatcher.h +++ b/libempathy/empathy-dispatcher.h @@ -57,15 +57,21 @@ typedef struct { gboolean activatable; } EmpathyDispatcherTube; -GType empathy_dispatcher_get_type (void) G_GNUC_CONST; -EmpathyDispatcher * empathy_dispatcher_new (void); -void empathy_dispatcher_channel_process(EmpathyDispatcher *dispatcher, - TpChannel *channel); -GType empathy_dispatcher_tube_get_type (void); -EmpathyDispatcherTube *empathy_dispatcher_tube_ref (EmpathyDispatcherTube *tube); -void empathy_dispatcher_tube_unref (EmpathyDispatcherTube *tube); -void empathy_dispatcher_tube_process (EmpathyDispatcher *dispatcher, - EmpathyDispatcherTube *tube); +GType empathy_dispatcher_get_type (void) G_GNUC_CONST; +EmpathyDispatcher * empathy_dispatcher_new (void); +void empathy_dispatcher_channel_process (EmpathyDispatcher *dispatcher, + TpChannel *channel); +GType empathy_dispatcher_tube_get_type (void); +EmpathyDispatcherTube *empathy_dispatcher_tube_ref (EmpathyDispatcherTube *tube); +void empathy_dispatcher_tube_unref (EmpathyDispatcherTube *tube); +void empathy_dispatcher_tube_process (EmpathyDispatcher *dispatcher, + EmpathyDispatcherTube *tube); +void empathy_dispatcher_call_with_contact (EmpathyContact *contact); +void empathy_dispatcher_call_with_contact_id (McAccount *account, + const gchar *contact_id); +void empathy_dispatcher_chat_with_contact_id (McAccount *account, + const gchar *contact_id); +void empathy_dispatcher_chat_with_contact (EmpathyContact *contact); G_END_DECLS diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c index fe6a787b..f62d28e4 100644 --- a/libempathy/empathy-utils.c +++ b/libempathy/empathy-utils.c @@ -338,126 +338,6 @@ empathy_mission_control_new (void) return mc; } -void -empathy_call_with_contact (EmpathyContact *contact) -{ - MissionControl *mc; - McAccount *account; - TpConnection *connection; - gchar *object_path; - TpChannel *channel; - EmpathyContactFactory *factory; - EmpathyTpGroup *group; - EmpathyContact *self_contact; - GError *error = NULL; - - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - mc = empathy_mission_control_new (); - account = empathy_contact_get_account (contact); - connection = mission_control_get_tpconnection (mc, account, NULL); - tp_connection_run_until_ready (connection, FALSE, NULL, NULL); - g_object_unref (mc); - - /* We abuse of suppress_handler, TRUE means OUTGOING. The channel - * will be catched in EmpathyFilter */ - if (!tp_cli_connection_run_request_channel (connection, -1, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - TP_HANDLE_TYPE_NONE, - 0, - TRUE, - &object_path, - &error, - NULL)) { - DEBUG ("Couldn't request channel: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - g_object_unref (connection); - return; - } - - channel = tp_channel_new (connection, - object_path, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - TP_HANDLE_TYPE_NONE, 0, NULL); - - group = empathy_tp_group_new (channel); - empathy_run_until_ready (group); - - factory = empathy_contact_factory_new (); - self_contact = empathy_contact_factory_get_user (factory, account); - empathy_contact_run_until_ready (self_contact, - EMPATHY_CONTACT_READY_HANDLE, - NULL); - - empathy_tp_group_add_member (group, contact, ""); - empathy_tp_group_add_member (group, self_contact, ""); - - g_object_unref (factory); - g_object_unref (self_contact); - g_object_unref (group); - g_object_unref (connection); - g_object_unref (channel); - g_free (object_path); -} - -void -empathy_call_with_contact_id (McAccount *account, const gchar *contact_id) -{ - EmpathyContactFactory *factory; - EmpathyContact *contact; - - factory = empathy_contact_factory_new (); - contact = empathy_contact_factory_get_from_id (factory, account, contact_id); - empathy_contact_run_until_ready (contact, EMPATHY_CONTACT_READY_HANDLE, NULL); - - empathy_call_with_contact (contact); - - g_object_unref (contact); - g_object_unref (factory); -} - -void -empathy_chat_with_contact (EmpathyContact *contact) -{ - MissionControl *mc; - McAccount *account; - TpConnection *connection; - - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); - - mc = empathy_mission_control_new (); - account = empathy_contact_get_account (contact); - connection = mission_control_get_tpconnection (mc, account, NULL); - tp_connection_run_until_ready (connection, FALSE, NULL, NULL); - g_object_unref (mc); - - /* We abuse of suppress_handler, TRUE means OUTGOING. The channel - * will be catched in EmpathyFilter */ - tp_cli_connection_call_request_channel (connection, -1, - TP_IFACE_CHANNEL_TYPE_TEXT, - TP_HANDLE_TYPE_CONTACT, - empathy_contact_get_handle (contact), - TRUE, - NULL, NULL, NULL, NULL); - g_object_unref (connection); -} - -void -empathy_chat_with_contact_id (McAccount *account, const gchar *contact_id) -{ - EmpathyContactFactory *factory; - EmpathyContact *contact; - - factory = empathy_contact_factory_new (); - contact = empathy_contact_factory_get_from_id (factory, account, contact_id); - empathy_contact_run_until_ready (contact, EMPATHY_CONTACT_READY_HANDLE, NULL); - - empathy_chat_with_contact (contact); - - g_object_unref (contact); - g_object_unref (factory); -} - const gchar * empathy_presence_get_default_message (McPresence presence) { @@ -747,3 +627,28 @@ empathy_disconnect_account_status_changed (gpointer token) data); } +guint +empathy_proxy_hash (gconstpointer key) +{ + TpProxy *proxy = TP_PROXY (key); + + g_return_val_if_fail (TP_IS_PROXY (proxy), 0); + + return g_str_hash (proxy->object_path) + + g_str_hash (proxy->bus_name); +} + +gboolean +empathy_proxy_equal (gconstpointer a, + gconstpointer b) +{ + TpProxy *proxy_a = TP_PROXY (a); + TpProxy *proxy_b = TP_PROXY (b); + + g_return_val_if_fail (TP_IS_PROXY (proxy_a), FALSE); + g_return_val_if_fail (TP_IS_PROXY (proxy_b), FALSE); + + return g_str_equal (proxy_a->object_path, proxy_b->object_path) && + g_str_equal (proxy_a->bus_name, proxy_b->bus_name); +} + diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h index 800f09d0..92ba44a9 100644 --- a/libempathy/empathy-utils.h +++ b/libempathy/empathy-utils.h @@ -83,12 +83,6 @@ guint empathy_account_hash (gconstpointer key); gboolean empathy_account_equal (gconstpointer a, gconstpointer b); MissionControl *empathy_mission_control_new (void); -void empathy_call_with_contact (EmpathyContact *contact); -void empathy_call_with_contact_id (McAccount *account, - const gchar *contact_id); -void empathy_chat_with_contact (EmpathyContact *contact); -void empathy_chat_with_contact_id (McAccount *account, - const gchar *contact_id); const gchar * empathy_presence_get_default_message (McPresence presence); const gchar * empathy_presence_to_str (McPresence presence); McPresence empathy_presence_from_str (const gchar *str); @@ -104,11 +98,16 @@ void empathy_run_until_ready_full (gpointer object, gpointer user_data, GMainLoop **loop); McAccount * empathy_channel_get_account (TpChannel *channel); -gpointer empathy_connect_to_account_status_changed (MissionControl *mc, +gpointer empathy_connect_to_account_status_changed (MissionControl *mc, GCallback handler, gpointer user_data, GClosureNotify free_func); -void empathy_disconnect_account_status_changed (gpointer token); +void empathy_disconnect_account_status_changed (gpointer token); +gboolean empathy_proxy_equal (gconstpointer a, + gconstpointer b); +guint empathy_proxy_hash (gconstpointer key); + + G_END_DECLS diff --git a/python/pyempathy/pyempathy.defs b/python/pyempathy/pyempathy.defs index cc9ef339..45e34717 100644 --- a/python/pyempathy/pyempathy.defs +++ b/python/pyempathy/pyempathy.defs @@ -498,40 +498,6 @@ (return-type "MissionControl*") ) -(define-function empathy_call_with_contact - (c-name "empathy_call_with_contact") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - ) -) - -(define-function empathy_call_with_contact_id - (c-name "empathy_call_with_contact_id") - (return-type "none") - (parameters - '("McAccount*" "account") - '("const-gchar*" "contact_id") - ) -) - -(define-function empathy_chat_with_contact - (c-name "empathy_chat_with_contact") - (return-type "none") - (parameters - '("EmpathyContact*" "contact") - ) -) - -(define-function empathy_chat_with_contact_id - (c-name "empathy_chat_with_contact_id") - (return-type "none") - (parameters - '("McAccount*" "account") - '("const-gchar*" "contact_id") - ) -) - (define-function empathy_presence_get_default_message (c-name "empathy_presence_get_default_message") (return-type "const-gchar*") @@ -612,6 +578,23 @@ ) ) +(define-function empathy_proxy_equal + (c-name "empathy_proxy_equal") + (return-type "gboolean") + (parameters + '("gconstpointer" "a") + '("gconstpointer" "b") + ) +) + +(define-function empathy_proxy_hash + (c-name "empathy_proxy_hash") + (return-type "guint") + (parameters + '("gconstpointer" "key") + ) +) + ;; From empathy-message.h @@ -2302,4 +2285,38 @@ ) ) +(define-function empathy_dispatcher_call_with_contact + (c-name "empathy_dispatcher_call_with_contact") + (return-type "none") + (parameters + '("EmpathyContact*" "contact") + ) +) + +(define-function empathy_dispatcher_call_with_contact_id + (c-name "empathy_dispatcher_call_with_contact_id") + (return-type "none") + (parameters + '("McAccount*" "account") + '("const-gchar*" "contact_id") + ) +) + +(define-function empathy_dispatcher_chat_with_contact_id + (c-name "empathy_dispatcher_chat_with_contact_id") + (return-type "none") + (parameters + '("McAccount*" "account") + '("const-gchar*" "contact_id") + ) +) + +(define-function empathy_dispatcher_chat_with_contact + (c-name "empathy_dispatcher_chat_with_contact") + (return-type "none") + (parameters + '("EmpathyContact*" "contact") + ) +) + diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index 2d52fcf7..54eb8a4c 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -38,7 +38,7 @@ #define DEBUG_FLAG EMPATHY_DEBUG_OTHER #include -typedef struct +typedef struct { EmpathyTpCall *call; GTimeVal start_time; @@ -61,6 +61,8 @@ typedef struct GtkWidget *keypad_expander; } EmpathyCallWindow; +static GSList *windows = NULL; + static gboolean call_window_update_timer (gpointer data) { @@ -269,8 +271,11 @@ call_window_destroy_cb (GtkWidget *widget, EmpathyCallWindow *window) { call_window_finalize (window); + g_object_unref (window->output_video_socket); g_object_unref (window->preview_video_socket); + + windows = g_slist_remove (windows, window); g_slice_free (EmpathyCallWindow, window); } @@ -461,17 +466,18 @@ call_window_dtmf_connect (GladeXML *glade, } GtkWidget * -empathy_call_window_new (EmpathyTpCall *call) +empathy_call_window_new (TpChannel *channel) { EmpathyCallWindow *window; GladeXML *glade; gchar *filename; const gchar *icons[] = {"audio-input-microphone", NULL}; - g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), NULL); + g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); window = g_slice_new0 (EmpathyCallWindow); - window->call = g_object_ref (call); + windows = g_slist_prepend (windows, window); + window->call = empathy_tp_call_new (channel); filename = empathy_file_lookup ("empathy-call-window.glade", "src"); glade = empathy_glade_get_file (filename, @@ -562,3 +568,52 @@ empathy_call_window_new (EmpathyTpCall *call) return window->window; } +GtkWidget * +empathy_call_window_find (TpChannel *channel) +{ + GSList *l; + + g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); + + for (l = windows; l; l = l->next) + { + EmpathyCallWindow *window = l->data; + TpChannel *this_channel = NULL; + + if (window->call) + g_object_get (window->call, "channel", &this_channel, NULL); + if (this_channel) + { + g_object_unref (this_channel); + if (empathy_proxy_equal (channel, this_channel)) + return window->window; + } + } + + return NULL; +} + +void +empathy_call_window_set_channel (GtkWidget *window, TpChannel *channel) +{ + GSList *l; + + g_return_if_fail (GTK_IS_WIDGET (window)); + g_return_if_fail (TP_IS_CHANNEL (channel)); + + for (l = windows; l; l = l->next) + { + EmpathyCallWindow *call_window = l->data; + + if (call_window->window == window) + { + if (!call_window->call) + { + call_window->call = empathy_tp_call_new (channel); + call_window_update (call_window); + } + break; + } + } +} + diff --git a/src/empathy-call-window.h b/src/empathy-call-window.h index eef1c9a9..782eda09 100644 --- a/src/empathy-call-window.h +++ b/src/empathy-call-window.h @@ -26,11 +26,14 @@ #include -#include +#include G_BEGIN_DECLS -GtkWidget *empathy_call_window_new (EmpathyTpCall *call); +GtkWidget *empathy_call_window_new (TpChannel *channel); +GtkWidget *empathy_call_window_find (TpChannel *channel); +void empathy_call_window_set_channel (GtkWidget *window, + TpChannel *channel); G_END_DECLS diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index a43e524c..1db873b5 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -977,7 +978,7 @@ chat_window_drag_data_received (GtkWidget *widget, chat = empathy_chat_window_find_chat (account, strv[1]); if (!chat) { - empathy_chat_with_contact_id (account, strv[2]); + empathy_dispatcher_chat_with_contact_id (account, strv[2]); g_object_unref (account); g_strfreev (strv); return; diff --git a/src/empathy-status-icon.c b/src/empathy-status-icon.c index 9d8a8c8c..50dfa1be 100644 --- a/src/empathy-status-icon.c +++ b/src/empathy-status-icon.c @@ -82,18 +82,180 @@ struct _StatusIconEvent { gchar *message; StatusIconEventFunc func; gpointer user_data; + TpChannel *channel; + EmpathyStatusIcon *icon; }; G_DEFINE_TYPE (EmpathyStatusIcon, empathy_status_icon, G_TYPE_OBJECT); +static void +status_icon_update_tooltip (EmpathyStatusIcon *icon) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + const gchar *tooltip = NULL; + + if (priv->events) { + tooltip = ((StatusIconEvent*)priv->events->data)->message; + } + + if (!tooltip) { + tooltip = empathy_idle_get_status (priv->idle); + } + + gtk_status_icon_set_tooltip (priv->icon, tooltip); +} + +static void +status_icon_update_icon (EmpathyStatusIcon *icon) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + const gchar *icon_name; + + if (priv->events && priv->showing_event_icon) { + icon_name = ((StatusIconEvent*)priv->events->data)->icon_name; + } else { + McPresence state; + + state = empathy_idle_get_state (priv->idle); + icon_name = empathy_icon_name_for_presence (state); + } + + gtk_status_icon_set_from_icon_name (priv->icon, icon_name); +} + +static gboolean +status_icon_blink_timeout_cb (EmpathyStatusIcon *icon) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + + priv->showing_event_icon = !priv->showing_event_icon; + status_icon_update_icon (icon); + + return TRUE; +} + +static void status_icon_channel_invalidated_cb (TpProxy *channel, guint domain, + gint code, gchar *message, + EmpathyStatusIcon *icon); + static void status_icon_event_free (StatusIconEvent *event) { g_free (event->icon_name); g_free (event->message); + if (event->channel) { + g_signal_handlers_disconnect_by_func (event->channel, + status_icon_channel_invalidated_cb, + event->icon); + g_object_unref (event->channel); + } g_slice_free (StatusIconEvent, event); } +static void +status_icon_event_remove (EmpathyStatusIcon *icon, + StatusIconEvent *event) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + GSList *l; + + if (!(l = g_slist_find (priv->events, event))) { + return; + } + + priv->events = g_slist_delete_link (priv->events, l); + status_icon_event_free (event); + status_icon_update_tooltip (icon); + status_icon_update_icon (icon); + + if (!priv->events && priv->blink_timeout) { + g_source_remove (priv->blink_timeout); + priv->blink_timeout = 0; + } +} + +static void +status_icon_event_remove_by_channel (EmpathyStatusIcon *icon, + TpChannel *channel) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + GSList *l; + + for (l = priv->events; l; l = l->next) { + StatusIconEvent *event = l->data; + + if (empathy_proxy_equal (event->channel, channel)) { + DEBUG ("Found event '%s'", event->message); + status_icon_event_remove (icon, event); + break; + } + } +} + +static void +status_icon_event_activate (EmpathyStatusIcon *icon, + StatusIconEvent *event) +{ + if (event->func) { + event->func (icon, event->user_data); + } + status_icon_event_remove (icon, event); +} + +static void +status_icon_event_add (EmpathyStatusIcon *icon, + const gchar *icon_name, + const gchar *message, + StatusIconEventFunc func, + gpointer user_data, + TpChannel *channel) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + StatusIconEvent *event; + gboolean had_events; + + DEBUG ("Adding event: %s", message); + + event = g_slice_new0 (StatusIconEvent); + event->icon_name = g_strdup (icon_name); + event->message = g_strdup (message); + event->func = func; + event->user_data = user_data; + event->icon = icon; + + if (channel) { + event->channel = g_object_ref (channel); + g_signal_connect (channel, "invalidated", + G_CALLBACK (status_icon_channel_invalidated_cb), + icon); + } + + had_events = (priv->events != NULL); + priv->events = g_slist_append (priv->events, event); + if (!had_events) { + priv->showing_event_icon = TRUE; + status_icon_update_icon (icon); + status_icon_update_tooltip (icon); + + if (!priv->blink_timeout) { + priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT, + (GSourceFunc) status_icon_blink_timeout_cb, + icon); + } + } +} + +static void +status_icon_channel_invalidated_cb (TpProxy *channel, + guint domain, + gint code, + gchar *message, + EmpathyStatusIcon *icon) +{ + DEBUG ("%s", message); + status_icon_event_remove_by_channel (icon, TP_CHANNEL (channel)); +} + static void status_icon_set_visibility (EmpathyStatusIcon *icon, gboolean visible, @@ -147,41 +309,6 @@ status_icon_toggle_visibility (EmpathyStatusIcon *icon) status_icon_set_visibility (icon, !visible, TRUE); } -static void -status_icon_update_tooltip (EmpathyStatusIcon *icon) -{ - EmpathyStatusIconPriv *priv = GET_PRIV (icon); - const gchar *tooltip = NULL; - - if (priv->events) { - tooltip = ((StatusIconEvent*)priv->events->data)->message; - } - - if (!tooltip) { - tooltip = empathy_idle_get_status (priv->idle); - } - - gtk_status_icon_set_tooltip (priv->icon, tooltip); -} - -static void -status_icon_update_icon (EmpathyStatusIcon *icon) -{ - EmpathyStatusIconPriv *priv = GET_PRIV (icon); - const gchar *icon_name; - - if (priv->events && priv->showing_event_icon) { - icon_name = ((StatusIconEvent*)priv->events->data)->icon_name; - } else { - McPresence state; - - state = empathy_idle_get_state (priv->idle); - icon_name = empathy_icon_name_for_presence (state); - } - - gtk_status_icon_set_from_icon_name (priv->icon, icon_name); -} - static void status_icon_idle_notify_cb (EmpathyStatusIcon *icon) { @@ -198,27 +325,6 @@ status_icon_delete_event_cb (GtkWidget *widget, return TRUE; } -static void -status_icon_event_activate (EmpathyStatusIcon *icon, - StatusIconEvent *event) -{ - EmpathyStatusIconPriv *priv = GET_PRIV (icon); - - if (event->func) { - event->func (icon, event->user_data); - } - - priv->events = g_slist_remove (priv->events, event); - status_icon_event_free (event); - status_icon_update_tooltip (icon); - status_icon_update_icon (icon); - - if (!priv->events && priv->blink_timeout) { - g_source_remove (priv->blink_timeout); - priv->blink_timeout = 0; - } -} - static void status_icon_activate_cb (GtkStatusIcon *status_icon, EmpathyStatusIcon *icon) @@ -319,51 +425,6 @@ status_icon_create_menu (EmpathyStatusIcon *icon) g_object_unref (glade); } -static gboolean -status_icon_blink_timeout_cb (EmpathyStatusIcon *icon) -{ - EmpathyStatusIconPriv *priv = GET_PRIV (icon); - - priv->showing_event_icon = !priv->showing_event_icon; - status_icon_update_icon (icon); - - return TRUE; -} - -static void -status_icon_event_add (EmpathyStatusIcon *icon, - const gchar *icon_name, - const gchar *message, - StatusIconEventFunc func, - gpointer user_data) -{ - EmpathyStatusIconPriv *priv = GET_PRIV (icon); - StatusIconEvent *event; - gboolean had_events; - - DEBUG ("Adding event: %s", message); - - event = g_slice_new (StatusIconEvent); - event->icon_name = g_strdup (icon_name); - event->message = g_strdup (message); - event->func = func; - event->user_data = user_data; - - had_events = (priv->events != NULL); - priv->events = g_slist_append (priv->events, event); - if (!had_events) { - priv->showing_event_icon = TRUE; - status_icon_update_icon (icon); - status_icon_update_tooltip (icon); - - if (!priv->blink_timeout) { - priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT, - (GSourceFunc) status_icon_blink_timeout_cb, - icon); - } - } -} - static void status_icon_channel_process (EmpathyStatusIcon *icon, gpointer user_data) @@ -372,7 +433,6 @@ status_icon_channel_process (EmpathyStatusIcon *icon, TpChannel *channel = TP_CHANNEL (user_data); empathy_dispatcher_channel_process (priv->dispatcher, channel); - g_object_unref (channel); } static gboolean @@ -404,7 +464,7 @@ status_icon_chat_message_received_cb (EmpathyTpChat *tp_chat, channel = empathy_tp_chat_get_channel (tp_chat); status_icon_event_add (icon, EMPATHY_IMAGE_NEW_MESSAGE, msg, status_icon_channel_process, - g_object_ref (channel)); + channel, channel); g_free (msg); } @@ -442,7 +502,7 @@ status_icon_filter_channel_cb (EmpathyDispatcher *dispatcher, status_icon_event_add (icon, EMPATHY_IMAGE_VOIP, msg, status_icon_channel_process, - g_object_ref (channel)); + channel, channel); g_free (msg); g_object_unref (contact); @@ -452,6 +512,14 @@ status_icon_filter_channel_cb (EmpathyDispatcher *dispatcher, g_free (channel_type); } +static void +status_icon_dispatch_channel_cb (EmpathyDispatcher *dispatcher, + TpChannel *channel, + EmpathyStatusIcon *icon) +{ + status_icon_event_remove_by_channel (icon, channel); +} + static void status_icon_tube_process (EmpathyStatusIcon *icon, gpointer user_data) @@ -512,7 +580,8 @@ status_icon_filter_tube_cb (EmpathyDispatcher *dispatcher, } status_icon_event_add (icon, icon_name, msg, status_icon_tube_process, - empathy_dispatcher_tube_ref (tube)); + empathy_dispatcher_tube_ref (tube), + tube->channel); g_free (msg); } @@ -558,7 +627,8 @@ status_icon_pendings_changed_cb (EmpathyContactList *list, status_icon_event_add (icon, GTK_STOCK_DIALOG_QUESTION, str->str, status_icon_pending_subscribe, - g_object_ref (contact)); + g_object_ref (contact), + NULL); g_string_free (str, TRUE); } @@ -650,6 +720,9 @@ empathy_status_icon_init (EmpathyStatusIcon *icon) g_signal_connect (priv->dispatcher, "filter-channel", G_CALLBACK (status_icon_filter_channel_cb), icon); + g_signal_connect (priv->dispatcher, "dispatch-channel", + G_CALLBACK (status_icon_dispatch_channel_cb), + icon); g_signal_connect (priv->dispatcher, "filter-tube", G_CALLBACK (status_icon_filter_tube_cb), icon); diff --git a/src/empathy.c b/src/empathy.c index 242f946a..19d9cb22 100644 --- a/src/empathy.c +++ b/src/empathy.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include @@ -98,11 +98,14 @@ dispatch_channel_cb (EmpathyDispatcher *dispatcher, g_object_unref (tp_chat); } else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) { - EmpathyTpCall *tp_call; + GtkWidget *window; - tp_call = empathy_tp_call_new (channel); - empathy_call_window_new (tp_call); - g_object_unref (tp_call); + window = empathy_call_window_find (channel); + if (window) { + gtk_window_present (GTK_WINDOW (window)); + } else { + empathy_call_window_new (channel); + } } }