From ec55d4f9308a0eb65c6ea5de7e9757e9d8b0b70f Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sun, 18 May 2008 14:27:44 +0000 Subject: Improve dispatcher. Fixes bug #465928. svn path=/trunk/; revision=1108 --- src/empathy-call-window.c | 63 +++++++++- src/empathy-call-window.h | 7 +- src/empathy-chat-window.c | 3 +- src/empathy-status-icon.c | 285 +++++++++++++++++++++++++++++----------------- src/empathy.c | 13 ++- 5 files changed, 253 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index 2d52fcf7c..54eb8a4cd 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 eef1c9a99..782eda09c 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 a43e524cd..1db873b5a 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 9d8a8c8c2..50dfa1be0 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 242f946a1..19d9cb220 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); + } } } -- cgit v1.2.3