diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/empathy-accounts-dialog.c | 2 | ||||
-rw-r--r-- | src/empathy-call-window.c | 494 | ||||
-rw-r--r-- | src/empathy-call-window.ui | 93 | ||||
-rw-r--r-- | src/empathy-chat-window.c | 95 | ||||
-rw-r--r-- | src/empathy-chatrooms-window.c | 15 | ||||
-rw-r--r-- | src/empathy-debug-window.c | 2 | ||||
-rw-r--r-- | src/empathy-event-manager.c | 4 |
7 files changed, 501 insertions, 204 deletions
diff --git a/src/empathy-accounts-dialog.c b/src/empathy-accounts-dialog.c index daae3d874..ec410050b 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -1224,7 +1224,7 @@ accounts_dialog_add_account (EmpathyAccountsDialog *dialog, accounts_dialog_connection_changed_cb (account, 0, status, - TP_CONNECTION_STATUS_DISCONNECTED, + TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED, NULL, NULL, dialog); diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index e1f8cd268..6cd437553 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -44,6 +44,9 @@ #include <libempathy-gtk/empathy-ui-utils.h> #include <libempathy-gtk/empathy-sound.h> +#define DEBUG_FLAG EMPATHY_DEBUG_VOIP +#include <libempathy/empathy-debug.h> + #include "empathy-call-window.h" #include "empathy-call-window-fullscreen.h" #include "empathy-sidebar.h" @@ -92,6 +95,12 @@ typedef enum { REDIALING } CallState; +typedef enum { + CAMERA_STATE_OFF = 0, + CAMERA_STATE_PREVIEW, + CAMERA_STATE_ON, +} CameraState; + /* private structure */ typedef struct _EmpathyCallWindowPriv EmpathyCallWindowPriv; @@ -116,13 +125,15 @@ struct _EmpathyCallWindowPriv GtkWidget *volume_button; GtkWidget *redial_button; GtkWidget *mic_button; - GtkWidget *camera_button; GtkWidget *toolbar; GtkWidget *pane; - GtkAction *show_preview; - GtkAction *send_video; GtkAction *redial; GtkAction *menu_fullscreen; + GtkAction *action_camera; + GtkAction *action_camera_preview; + GtkWidget *tool_button_camera_off; + GtkWidget *tool_button_camera_preview; + GtkWidget *tool_button_camera_on; /* The frames and boxes that contain self and remote avatar and video input/output. When we redial, we destroy and re-create the boxes */ @@ -173,6 +184,7 @@ struct _EmpathyCallWindowPriv GMutex *lock; gboolean call_started; gboolean sending_video; + CameraState camera_state; EmpathyCallWindowFullscreen *fullscreen; gboolean is_fullscreen; @@ -200,18 +212,9 @@ static gboolean empathy_call_window_state_event_cb (GtkWidget *widget, static void empathy_call_window_sidebar_toggled_cb (GtkToggleButton *toggle, EmpathyCallWindow *window); -static void empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle, - EmpathyCallWindow *window); - static void empathy_call_window_set_send_video (EmpathyCallWindow *window, gboolean send); -static void empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle, - EmpathyCallWindow *window); - -static void empathy_call_window_show_preview_toggled_cb ( - GtkToggleAction *toggle, EmpathyCallWindow *window); - static void empathy_call_window_mic_toggled_cb ( GtkToggleToolButton *toggle, EmpathyCallWindow *window); @@ -259,11 +262,32 @@ static void empathy_call_window_volume_changed_cb (GtkScaleButton *button, gdouble value, EmpathyCallWindow *window); +static void block_camera_control_signals (EmpathyCallWindow *self); +static void unblock_camera_control_signals (EmpathyCallWindow *self); + static void empathy_call_window_setup_toolbar (EmpathyCallWindow *self) { EmpathyCallWindowPriv *priv = GET_PRIV (self); GtkToolItem *tool_item; + GtkWidget *camera_off_icon; + GdkPixbuf *pixbuf, *modded_pixbuf; + + /* set the icon of the 'camera off' button by greying off the webcam icon */ + pixbuf = empathy_pixbuf_from_icon_name ("camera-web", + GTK_ICON_SIZE_SMALL_TOOLBAR); + + modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + + gdk_pixbuf_saturate_and_pixelate (pixbuf, modded_pixbuf, 1.0, TRUE); + g_object_unref (pixbuf); + + camera_off_icon = gtk_image_new_from_pixbuf (modded_pixbuf); + g_object_unref (modded_pixbuf); + gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON ( + priv->tool_button_camera_off), camera_off_icon); /* Add an empty expanded GtkToolItem so the volume button is at the end of * the toolbar. */ @@ -642,6 +666,7 @@ empathy_call_window_setup_video_preview (EmpathyCallWindow *window) return; } + DEBUG ("Create video preview"); g_assert (priv->video_tee == NULL); priv->video_tee = gst_element_factory_make ("tee", NULL); @@ -669,6 +694,33 @@ empathy_call_window_setup_video_preview (EmpathyCallWindow *window) } static void +display_video_preview (EmpathyCallWindow *self, + gboolean display) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + if (display) + { + /* Display the preview and hide the self avatar */ + DEBUG ("Show video preview"); + + if (priv->video_preview == NULL) + empathy_call_window_setup_video_preview (self); + gtk_widget_show (priv->video_preview); + gtk_widget_hide (priv->self_user_avatar_widget); + } + else + { + /* Display the self avatar and hide the preview */ + DEBUG ("Show self avatar"); + + if (priv->video_preview != NULL) + gtk_widget_hide (priv->video_preview); + gtk_widget_show (priv->self_user_avatar_widget); + } +} + +static void empathy_call_window_set_state_connecting (EmpathyCallWindow *window) { EmpathyCallWindowPriv *priv = GET_PRIV (window); @@ -682,6 +734,188 @@ empathy_call_window_set_state_connecting (EmpathyCallWindow *window) } static void +disable_camera (EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + if (priv->camera_state == CAMERA_STATE_OFF) + return; + + DEBUG ("Disable camera"); + + display_video_preview (self, FALSE); + + if (priv->camera_state == CAMERA_STATE_ON) + empathy_call_window_set_send_video (self, FALSE); + + block_camera_control_signals (self); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_on), FALSE); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_preview), FALSE); + + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_off), TRUE); + gtk_radio_action_set_current_value (GTK_RADIO_ACTION (priv->action_camera), + CAMERA_STATE_OFF); + unblock_camera_control_signals (self); + + priv->camera_state = CAMERA_STATE_OFF; +} + +static void +tool_button_camera_off_toggled_cb (GtkToggleToolButton *toggle, + EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + if (!gtk_toggle_tool_button_get_active (toggle)) + { + if (priv->camera_state == CAMERA_STATE_OFF) + { + /* We can't change the state by disabling the button */ + block_camera_control_signals (self); + gtk_toggle_tool_button_set_active (toggle, TRUE); + unblock_camera_control_signals (self); + } + + return; + } + + disable_camera (self); +} + +static void +enable_preview (EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + if (priv->camera_state == CAMERA_STATE_PREVIEW) + return; + + DEBUG ("Enable preview"); + + if (priv->camera_state == CAMERA_STATE_ON) + /* preview is already displayed so we just have to stop sending */ + empathy_call_window_set_send_video (self, FALSE); + + display_video_preview (self, TRUE); + + block_camera_control_signals (self); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_off), FALSE); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_on), FALSE); + + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_preview), TRUE); + gtk_radio_action_set_current_value (GTK_RADIO_ACTION (priv->action_camera), + CAMERA_STATE_PREVIEW); + unblock_camera_control_signals (self); + + priv->camera_state = CAMERA_STATE_PREVIEW; +} + +static void +tool_button_camera_preview_toggled_cb (GtkToggleToolButton *toggle, + EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + if (!gtk_toggle_tool_button_get_active (toggle)) + { + if (priv->camera_state == CAMERA_STATE_PREVIEW) + { + /* We can't change the state by disabling the button */ + block_camera_control_signals (self); + gtk_toggle_tool_button_set_active (toggle, TRUE); + unblock_camera_control_signals (self); + } + + return; + } + + enable_preview (self); +} + +static void +enable_camera (EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + if (priv->camera_state == CAMERA_STATE_ON) + return; + + DEBUG ("Enable camera"); + + empathy_call_window_set_send_video (self, TRUE); + + block_camera_control_signals (self); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_off), FALSE); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_preview), FALSE); + + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( + priv->tool_button_camera_on), TRUE); + gtk_radio_action_set_current_value (GTK_RADIO_ACTION (priv->action_camera), + CAMERA_STATE_ON); + unblock_camera_control_signals (self); + + priv->camera_state = CAMERA_STATE_ON; +} + +static void +tool_button_camera_on_toggled_cb (GtkToggleToolButton *toggle, + EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + if (!gtk_toggle_tool_button_get_active (toggle)) + { + if (priv->camera_state == CAMERA_STATE_ON) + { + /* We can't change the state by disabling the button */ + block_camera_control_signals (self); + gtk_toggle_tool_button_set_active (toggle, TRUE); + unblock_camera_control_signals (self); + } + + return; + } + + enable_camera (self); +} + +static void +action_camera_change_cb (GtkRadioAction *action, + GtkRadioAction *current, + EmpathyCallWindow *self) +{ + CameraState state; + + state = gtk_radio_action_get_current_value (current); + + switch (state) + { + case CAMERA_STATE_OFF: + disable_camera (self); + break; + + case CAMERA_STATE_PREVIEW: + enable_preview (self); + break; + + case CAMERA_STATE_ON: + enable_camera (self); + break; + + default: + g_assert_not_reached (); + } +} + +static void empathy_call_window_init (EmpathyCallWindow *self) { EmpathyCallWindowPriv *priv = GET_PRIV (self); @@ -703,13 +937,15 @@ empathy_call_window_init (EmpathyCallWindow *self) "statusbar", &priv->statusbar, "redial", &priv->redial_button, "microphone", &priv->mic_button, - "camera", &priv->camera_button, "toolbar", &priv->toolbar, - "send_video", &priv->send_video, "menuredial", &priv->redial, - "show_preview", &priv->show_preview, "ui_manager", &priv->ui_manager, "menufullscreen", &priv->menu_fullscreen, + "camera_off", &priv->tool_button_camera_off, + "camera_preview", &priv->tool_button_camera_preview, + "camera_on", &priv->tool_button_camera_on, + "action_camera_off", &priv->action_camera, + "action_camera_preview", &priv->action_camera_preview, NULL); g_free (filename); @@ -719,10 +955,11 @@ empathy_call_window_init (EmpathyCallWindow *self) "menuredial", "activate", empathy_call_window_redial_cb, "redial", "clicked", empathy_call_window_redial_cb, "microphone", "toggled", empathy_call_window_mic_toggled_cb, - "camera", "toggled", empathy_call_window_camera_toggled_cb, - "send_video", "toggled", empathy_call_window_send_video_toggled_cb, - "show_preview", "toggled", empathy_call_window_show_preview_toggled_cb, "menufullscreen", "activate", empathy_call_window_fullscreen_cb, + "camera_off", "toggled", tool_button_camera_off_toggled_cb, + "camera_preview", "toggled", tool_button_camera_preview_toggled_cb, + "camera_on", "toggled", tool_button_camera_on_toggled_cb, + "action_camera_off", "changed", action_camera_change_cb, NULL); priv->lock = g_mutex_new (); @@ -975,18 +1212,6 @@ empathy_call_window_setup_avatars (EmpathyCallWindow *self, } static void -empathy_call_window_setup_video_preview_visibility (EmpathyCallWindow *self, - EmpathyCallHandler *handler) -{ - EmpathyCallWindowPriv *priv = GET_PRIV (self); - gboolean initial_video = - empathy_call_handler_has_initial_video (priv->handler); - - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), - initial_video); -} - -static void empathy_call_window_constructed (GObject *object) { EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object); @@ -1001,8 +1226,21 @@ empathy_call_window_constructed (GObject *object) g_object_unref (call); empathy_call_window_setup_avatars (self, priv->handler); - empathy_call_window_setup_video_preview_visibility (self, priv->handler); empathy_call_window_set_state_connecting (self); + + if (empathy_call_handler_has_initial_video (priv->handler)) + { + /* Enable 'send video' buttons and display the preview */ + gtk_toggle_tool_button_set_active ( + GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_on), TRUE); + + display_video_preview (self, TRUE); + } + else + { + gtk_toggle_tool_button_set_active ( + GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_off), TRUE); + } } static void empathy_call_window_dispose (GObject *object); @@ -1069,6 +1307,7 @@ static void empathy_call_window_video_stream_changed_cb (EmpathyTpCall *call, GParamSpec *property, EmpathyCallWindow *self) { + DEBUG ("video stream changed"); empathy_call_window_update_avatars_visibility (call, self); } @@ -1282,8 +1521,6 @@ empathy_call_window_disconnected (EmpathyCallWindow *self) if (could_reset_pipeline) { - gboolean initial_video = empathy_call_handler_has_initial_video ( - priv->handler); g_mutex_lock (priv->lock); g_timer_stop (priv->timer); @@ -1301,19 +1538,19 @@ empathy_call_window_disconnected (EmpathyCallWindow *self) /* Reseting the send_video, camera_buton and mic_button to their initial state */ - gtk_widget_set_sensitive (priv->camera_button, FALSE); + gtk_widget_set_sensitive (priv->tool_button_camera_on, FALSE); gtk_widget_set_sensitive (priv->mic_button, FALSE); - gtk_action_set_sensitive (priv->send_video, FALSE); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), - initial_video); gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), initial_video); + GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_off), TRUE); gtk_toggle_tool_button_set_active ( GTK_TOGGLE_TOOL_BUTTON (priv->mic_button), TRUE); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), - FALSE); - gtk_action_set_sensitive (priv->show_preview, FALSE); + /* FIXME: This is to workaround the fact that the pipeline has been + * destroyed and so we can't display preview until a new call (and so a + * new pipeline) is created. We should fix this properly by refactoring + * the code managing the pipeline. This is bug #602937 */ + gtk_widget_set_sensitive (priv->tool_button_camera_preview, FALSE); + gtk_action_set_sensitive (priv->action_camera_preview, FALSE); gtk_progress_bar_set_fraction ( GTK_PROGRESS_BAR (priv->volume_progress_bar), 0); @@ -1325,6 +1562,9 @@ empathy_call_window_disconnected (EmpathyCallWindow *self) priv->call_started = FALSE; could_disconnect = TRUE; + + /* TODO: display the self avatar of the preview (depends if the "Always + * Show Video Preview" is enabled or not) */ } return could_disconnect; @@ -1674,24 +1914,21 @@ empathy_call_window_connected (gpointer user_data) priv->sending_video = can_send_video ? empathy_tp_call_is_sending_video (call) : FALSE; - gtk_action_set_sensitive (priv->show_preview, TRUE); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), - priv->sending_video - || gtk_toggle_action_get_active (GTK_TOGGLE_ACTION ( - priv->show_preview))); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), - priv->sending_video && priv->video_input != NULL); gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), + GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_on), priv->sending_video && priv->video_input != NULL); - gtk_widget_set_sensitive (priv->camera_button, can_send_video); - gtk_action_set_sensitive (priv->send_video, can_send_video); + gtk_widget_set_sensitive (priv->tool_button_camera_on, can_send_video); gtk_action_set_sensitive (priv->redial, FALSE); gtk_widget_set_sensitive (priv->redial_button, FALSE); gtk_widget_set_sensitive (priv->mic_button, TRUE); + /* FIXME: this should won't be needed once bug #602937 is fixed + * (see empathy_call_window_disconnected for details) */ + gtk_widget_set_sensitive (priv->tool_button_camera_preview, TRUE); + gtk_action_set_sensitive (priv->action_camera_preview, TRUE); + empathy_call_window_update_avatars_visibility (call, self); g_object_unref (call); @@ -1770,23 +2007,6 @@ empathy_call_window_sink_added_cb (EmpathyCallHandler *handler, case TP_MEDIA_STREAM_TYPE_VIDEO: if (priv->video_input != NULL) { - EmpathyTpCall *call; - g_object_get (priv->handler, "tp-call", &call, NULL); - - if (empathy_tp_call_is_sending_video (call)) - { - empathy_call_window_setup_video_preview (self); - - gtk_toggle_action_set_active ( - GTK_TOGGLE_ACTION (priv->show_preview), TRUE); - - if (priv->video_preview != NULL) - gtk_widget_show (priv->video_preview); - gtk_widget_hide (priv->self_user_avatar_widget); - } - - g_object_unref (call); - if (priv->video_tee != NULL) { pad = gst_element_get_request_pad (priv->video_tee, "src%d"); @@ -1806,6 +2026,7 @@ empathy_call_window_remove_video_input (EmpathyCallWindow *self) EmpathyCallWindowPriv *priv = GET_PRIV (self); GstElement *preview; + DEBUG ("remove video input"); preview = empathy_video_widget_get_element ( EMPATHY_VIDEO_WIDGET (priv->video_preview)); @@ -1823,11 +2044,9 @@ empathy_call_window_remove_video_input (EmpathyCallWindow *self) gtk_widget_destroy (priv->video_preview); priv->video_preview = NULL; - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), FALSE); gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), FALSE); - gtk_widget_set_sensitive (priv->camera_button, FALSE); - gtk_action_set_sensitive (priv->send_video, FALSE); + GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_on), FALSE); + gtk_widget_set_sensitive (priv->tool_button_camera_on, FALSE); gtk_widget_show (priv->self_user_avatar_widget); } @@ -1898,28 +2117,6 @@ empathy_call_window_bus_message (GstBus *bus, GstMessage *message, } static void -empathy_call_window_update_self_avatar_visibility (EmpathyCallWindow *window) -{ - EmpathyCallWindowPriv *priv = GET_PRIV (window); - - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (priv->show_preview))) - { - if (priv->video_preview != NULL) - { - gtk_widget_hide (priv->self_user_avatar_widget); - gtk_widget_show (priv->video_preview); - } - else - { - if (priv->video_preview != NULL) - gtk_widget_hide (priv->video_preview); - - gtk_widget_show (priv->self_user_avatar_widget); - } - } -} - -static void empathy_call_window_update_avatars_visibility (EmpathyTpCall *call, EmpathyCallWindow *window) { @@ -1935,8 +2132,6 @@ empathy_call_window_update_avatars_visibility (EmpathyTpCall *call, gtk_widget_hide (priv->video_output); gtk_widget_show (priv->remote_user_avatar_widget); } - - empathy_call_window_update_self_avatar_visibility (window); } static void @@ -2176,76 +2371,15 @@ empathy_call_window_set_send_video (EmpathyCallWindow *window, /* When we start sending video, we want to show the video preview by default. */ - if (send) - { - empathy_call_window_setup_video_preview (window); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), - TRUE); - } - - g_object_get (priv->handler, "tp-call", &call, NULL); - empathy_tp_call_request_video_stream_direction (call, send); - g_object_unref (call); -} - -static void -empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle, - EmpathyCallWindow *window) -{ - EmpathyCallWindowPriv *priv = GET_PRIV (window); - gboolean active; + display_video_preview (window, send); if (priv->call_state != CONNECTED) return; - active = (gtk_toggle_tool_button_get_active (toggle)); - - if (priv->sending_video == active) - return; - - empathy_call_window_set_send_video (window, active); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), active); -} - -static void -empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle, - EmpathyCallWindow *window) -{ - EmpathyCallWindowPriv *priv = GET_PRIV (window); - gboolean active; - - if (priv->call_state != CONNECTED) - return; - - active = (gtk_toggle_action_get_active (toggle)); - - if (priv->sending_video == active) - return; - - empathy_call_window_set_send_video (window, active); - gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), active); -} - -static void -empathy_call_window_show_preview_toggled_cb (GtkToggleAction *toggle, - EmpathyCallWindow *window) -{ - gboolean show_preview_toggled; - EmpathyCallWindowPriv *priv = GET_PRIV (window); - - show_preview_toggled = gtk_toggle_action_get_active (toggle); - - if (show_preview_toggled) - { - empathy_call_window_setup_video_preview (window); - gtk_widget_show (priv->self_user_output_frame); - empathy_call_window_update_self_avatar_visibility (window); - } - else - { - gtk_widget_hide (priv->self_user_output_frame); - } + g_object_get (priv->handler, "tp-call", &call, NULL); + DEBUG ("%s sending video", send ? "start": "stop"); + empathy_tp_call_request_video_stream_direction (call, send); + g_object_unref (call); } static void @@ -2336,9 +2470,6 @@ empathy_call_window_restart_call (EmpathyCallWindow *window) gtk_widget_show_all (priv->content_hbox); - if (!empathy_call_handler_has_initial_video (priv->handler)) - gtk_widget_hide (priv->self_user_output_frame); - priv->outgoing = TRUE; empathy_call_window_set_state_connecting (window); @@ -2474,3 +2605,36 @@ empathy_call_window_volume_changed_cb (GtkScaleButton *button, empathy_audio_sink_set_volume (EMPATHY_GST_AUDIO_SINK (priv->audio_output), value); } + +/* block all the signals related to camera control widgets. This is useful + * when we are manually updating the UI and so don't want to fire the + * callbacks */ +static void +block_camera_control_signals (EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + g_signal_handlers_block_by_func (priv->tool_button_camera_off, + tool_button_camera_off_toggled_cb, self); + g_signal_handlers_block_by_func (priv->tool_button_camera_preview, + tool_button_camera_preview_toggled_cb, self); + g_signal_handlers_block_by_func (priv->tool_button_camera_on, + tool_button_camera_on_toggled_cb, self); + g_signal_handlers_block_by_func (priv->action_camera, + tool_button_camera_on_toggled_cb, self); +} + +static void +unblock_camera_control_signals (EmpathyCallWindow *self) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + g_signal_handlers_unblock_by_func (priv->tool_button_camera_off, + tool_button_camera_off_toggled_cb, self); + g_signal_handlers_unblock_by_func (priv->tool_button_camera_preview, + tool_button_camera_preview_toggled_cb, self); + g_signal_handlers_unblock_by_func (priv->tool_button_camera_on, + tool_button_camera_on_toggled_cb, self); + g_signal_handlers_unblock_by_func (priv->action_camera, + tool_button_camera_on_toggled_cb, self); +} diff --git a/src/empathy-call-window.ui b/src/empathy-call-window.ui index 64e87e040..94d2fba83 100644 --- a/src/empathy-call-window.ui +++ b/src/empathy-call-window.ui @@ -11,13 +11,6 @@ </object> </child> <child> - <object class="GtkToggleAction" id="send_video"> - <property name="name">send_video</property> - <property name="label" translatable="yes">Send video</property> - <property name="sensitive">False</property> - </object> - </child> - <child> <object class="GtkAction" id="menuhangup"> <property name="icon_name">call-stop</property> <property name="name">menuhangup</property> @@ -33,16 +26,45 @@ </object> </child> <child> - <object class="GtkAction" id="view"> - <property name="name">view</property> - <property name="label" translatable="yes">_View</property> + <object class="GtkAction" id="camera"> + <property name="name">camera</property> + <property name="label" translatable="yes">V_ideo</property> + </object> + </child> + <child> + <object class="GtkRadioAction" id="action_camera_off"> + <property name="name">action_camera_off</property> + <property name="visible">True</property> + <property name="label" translatable="yes">Video Off</property> + <property name="draw_as_radio">True</property> + <property name="value">0</property> + <property name="current-value">0</property> </object> </child> <child> - <object class="GtkToggleAction" id="show_preview"> - <property name="name">show_preview</property> - <property name="label" translatable="yes">Video preview</property> - <property name="active">True</property> + <object class="GtkRadioAction" id="action_camera_preview"> + <property name="name">action_camera_preview</property> + <property name="visible">True</property> + <property name="label" translatable="yes">Video Preview</property> + <property name="draw_as_radio">True</property> + <property name="group">action_camera_off</property> + <property name="value">1</property> + </object> + </child> + <child> + <object class="GtkRadioAction" id="action_camera_on"> + <property name="name">action_camera_on</property> + <property name="visible">True</property> + <property name="label" translatable="yes">Video On</property> + <property name="draw_as_radio">True</property> + <property name="group">action_camera_off</property> + <property name="value">2</property> + </object> + </child> + <child> + <object class="GtkAction" id="view"> + <property name="name">view</property> + <property name="label" translatable="yes">_View</property> </object> </child> <child> @@ -57,12 +79,15 @@ <ui> <menubar name="menubar1"> <menu action="call"> - <menuitem action="send_video"/> <menuitem action="menuhangup"/> <menuitem action="menuredial"/> </menu> + <menu action="camera"> + <menuitem action="action_camera_off"/> + <menuitem action="action_camera_preview"/> + <menuitem action="action_camera_on"/> + </menu> <menu action="view"> - <menuitem action="show_preview"/> <menuitem action="menufullscreen"/> </menu> </menubar> @@ -127,11 +152,43 @@ </packing> </child> <child> - <object class="GtkToggleToolButton" id="camera"> + <object class="GtkSeparatorToolItem" id="camera_separator"> + <property name="visible">True</property> + </object> + <packing> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToggleToolButton" id="camera_off"> + <property name="visible">True</property> + <property name="label" translatable="yes">Camera Off</property> + <property name="sensitive">True</property> + <property name="tooltip_text" translatable="yes">Disable camera and stop sending video</property> + </object> + <packing> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToggleToolButton" id="camera_preview"> + <property name="visible">True</property> + <property name="label" translatable="yes">Preview</property> + <property name="icon_name">stock_person</property> + <property name="sensitive">True</property> + <property name="tooltip_text" translatable="yes">Enable camera but don't send video</property> + </object> + <packing> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToggleToolButton" id="camera_on"> <property name="visible">True</property> - <property name="label" translatable="yes">Send video</property> + <property name="label" translatable="yes">Camera On</property> <property name="icon_name">camera-web</property> <property name="sensitive">False</property> + <property name="tooltip_text" translatable="yes">Enable camera and send video</property> </object> <packing> <property name="homogeneous">True</property> diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index fb04e7c3e..ea63f29aa 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -369,16 +369,97 @@ chat_window_contact_menu_update (EmpathyChatWindowPriv *priv, } } +static guint +get_all_unread_messages (EmpathyChatWindowPriv *priv) +{ + GList *l; + guint nb = 0; + + for (l = priv->chats_new_msg; l != NULL; l = g_list_next (l)) { + EmpathyChat *chat = l->data; + + nb += empathy_chat_get_nb_unread_messages (chat); + } + + return nb; +} + +static gchar * +get_window_title_name (EmpathyChatWindowPriv *priv) +{ + const gchar *active_name; + guint nb_chats; + guint current_unread_msgs; + + nb_chats = g_list_length (priv->chats); + g_assert (nb_chats > 0); + + active_name = empathy_chat_get_name (priv->current_chat); + + current_unread_msgs = empathy_chat_get_nb_unread_messages ( + priv->current_chat); + + if (nb_chats == 1) { + /* only one tab */ + if (current_unread_msgs == 0) + return g_strdup (active_name); + else + return g_strdup_printf (ngettext ( + "%s (%d unread)", + "%s (%d unread)", current_unread_msgs), + active_name, current_unread_msgs); + } else { + guint nb_others = nb_chats - 1; + guint all_unread_msgs; + + all_unread_msgs = get_all_unread_messages (priv); + + if (all_unread_msgs == 0) { + /* no unread message */ + return g_strdup_printf (ngettext ( + "%s (and %u other)", + "%s (and %u others)", nb_others), + active_name, nb_others); + } + + else if (all_unread_msgs == current_unread_msgs) { + /* unread messages are in the current tab */ + return g_strdup_printf (ngettext ( + "%s (%d unread)", + "%s (%d unread)", current_unread_msgs), + active_name, current_unread_msgs); + } + + else if (current_unread_msgs == 0) { + /* unread messages are in other tabs */ + return g_strdup_printf (ngettext ( + "%s (%d unread from others)", + "%s (%d unread from others)", + all_unread_msgs), + active_name, all_unread_msgs); + } + + else { + /* unread messages are in all the tabs */ + return g_strdup_printf (ngettext ( + "%s (%d unread from all)", + "%s (%d unread from all)", + all_unread_msgs), + active_name, all_unread_msgs); + } + } +} + static void chat_window_title_update (EmpathyChatWindowPriv *priv) { - const gchar *name; - - name = empathy_chat_get_name (priv->current_chat); + gchar *name; DEBUG ("Update window : Title"); + name = get_window_title_name (priv); gtk_window_set_title (GTK_WINDOW (priv->dialog), name); + g_free (name); } static void @@ -1127,6 +1208,8 @@ chat_window_new_message_cb (EmpathyChat *chat, } if (has_focus && priv->current_chat == chat) { + /* window and tab are focused so consider the message to be read */ + empathy_chat_messages_read (chat); return; } @@ -1157,6 +1240,9 @@ chat_window_new_message_cb (EmpathyChat *chat, EMPATHY_SOUND_MESSAGE_INCOMING); chat_window_show_or_update_notification (window, message, chat); } + + /* update the number of unread messages */ + chat_window_title_update (priv); } static GtkNotebook * @@ -1213,6 +1299,7 @@ chat_window_page_switched_cb (GtkNotebook *notebook, priv->current_chat = chat; priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); + empathy_chat_messages_read (chat); chat_window_update_chat_tab (chat); } @@ -1304,6 +1391,7 @@ chat_window_page_removed_cb (GtkNotebook *notebook, /* Keep list of chats up to date */ priv->chats = g_list_remove (priv->chats, chat); priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); + empathy_chat_messages_read (chat); priv->chats_composing = g_list_remove (priv->chats_composing, chat); if (priv->chats == NULL) { @@ -1325,6 +1413,7 @@ chat_window_focus_in_event_cb (GtkWidget *widget, priv = GET_PRIV (window); priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat); + empathy_chat_messages_read (priv->current_chat); chat_window_set_urgency_hint (window, FALSE); diff --git a/src/empathy-chatrooms-window.c b/src/empathy-chatrooms-window.c index 6f2c8c24c..aae8aac32 100644 --- a/src/empathy-chatrooms-window.c +++ b/src/empathy-chatrooms-window.c @@ -52,8 +52,6 @@ typedef struct { GtkWidget *button_remove; GtkWidget *button_edit; GtkWidget *button_close; - - gint room_column; } EmpathyChatroomsWindow; static void chatrooms_window_destroy_cb (GtkWidget *widget, @@ -278,7 +276,6 @@ chatrooms_window_model_add_columns (EmpathyChatroomsWindow *window) NULL); count = gtk_tree_view_append_column (view, column); gtk_tree_view_column_set_sort_column_id (column, count - 1); - window->room_column = count - 1; /* Chatroom auto connect */ cell = gtk_cell_renderer_toggle_new (); @@ -306,7 +303,6 @@ chatrooms_window_model_refresh_data (EmpathyChatroomsWindow *window, GtkTreeModel *model; GtkListStore *store; GtkTreeIter iter; - GtkTreeViewColumn *column; EmpathyAccountChooser *account_chooser; TpAccount *account; GList *chatrooms, *l; @@ -322,17 +318,6 @@ chatrooms_window_model_refresh_data (EmpathyChatroomsWindow *window, chatrooms = empathy_chatroom_manager_get_chatrooms (window->manager, account); - /* Sort out columns, we only show the server column for - * selected protocol types, such as Jabber. - */ - if (account) { - column = gtk_tree_view_get_column (view, window->room_column); - gtk_tree_view_column_set_visible (column, TRUE); - } else { - column = gtk_tree_view_get_column (view, window->room_column); - gtk_tree_view_column_set_visible (column, FALSE); - } - /* Clean out the store */ gtk_list_store_clear (store); diff --git a/src/empathy-debug-window.c b/src/empathy-debug-window.c index e4c1445e6..4c34e6808 100644 --- a/src/empathy-debug-window.c +++ b/src/empathy-debug-window.c @@ -31,6 +31,7 @@ #include <libempathy/empathy-utils.h> #include <libempathy-gtk/empathy-account-chooser.h> +#include <libempathy-gtk/empathy-geometry.h> #include <telepathy-glib/dbus.h> #include <telepathy-glib/util.h> @@ -1163,6 +1164,7 @@ debug_window_constructor (GType type, gtk_window_set_title (GTK_WINDOW (object), _("Debug Window")); gtk_window_set_default_size (GTK_WINDOW (object), 800, 400); + empathy_geometry_bind (GTK_WINDOW (object), "debug-window"); g_signal_connect (object, "key-press-event", G_CALLBACK (debug_window_key_press_event_cb), NULL); diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c index 0992dd243..86956e7f9 100644 --- a/src/empathy-event-manager.c +++ b/src/empathy-event-manager.c @@ -944,7 +944,7 @@ event_manager_presence_changed_cb (EmpathyContactMonitor *monitor, empathy_contact_get_name (contact)); event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_PRESENCE, - GTK_STOCK_DIALOG_INFO, header, NULL, NULL, NULL, NULL); + "stock_person", header, NULL, NULL, NULL, NULL); } } else @@ -960,7 +960,7 @@ event_manager_presence_changed_cb (EmpathyContactMonitor *monitor, empathy_contact_get_name (contact)); event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_PRESENCE, - GTK_STOCK_DIALOG_INFO, header, NULL, NULL, NULL, NULL); + "stock_person", header, NULL, NULL, NULL, NULL); } } g_free (header); |