1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Elliot Fairweather
4 * Copyright (C) 2007-2008 Collabora Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
21 * Xavier Claessens <xclaesse@gmail.com>
26 #include <glade/glade.h>
27 #include <glib/gi18n.h>
29 #include <telepathy-glib/enums.h>
31 #include <libempathy/empathy-contact.h>
32 #include <libempathy/empathy-tp-call.h>
33 #include <libempathy/empathy-utils.h>
34 #include <libempathy-gtk/empathy-ui-utils.h>
36 #include "empathy-call-window.h"
38 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
39 #include <libempathy/empathy-debug.h>
45 guint timeout_event_id;
51 GtkWidget *controls_vbox;
52 GtkWidget *volume_hbox;
53 GtkWidget *status_label;
54 GtkWidget *input_volume_button;
55 GtkWidget *output_volume_button;
56 GtkWidget *preview_video_socket;
57 GtkWidget *output_video_socket;
58 GtkWidget *video_button;
59 GtkWidget *hang_up_button;
60 GtkWidget *confirmation_dialog;
64 call_window_update_timer (gpointer data)
66 EmpathyCallWindow *window = data;
70 glong time, seconds, minutes, hours;
72 g_get_current_time (¤t);
75 then = (window->start_time).tv_sec;
86 str = g_strdup_printf ("Connected - %02ld : %02ld : %02ld", hours,
89 str = g_strdup_printf ("Connected - %02ld : %02ld", minutes, seconds);
91 gtk_label_set_text (GTK_LABEL (window->status_label), str);
99 call_window_stop_timeout (EmpathyCallWindow *window)
101 DEBUG ("Timer stopped");
103 if (window->timeout_event_id)
105 g_source_remove (window->timeout_event_id);
106 window->timeout_event_id = 0;
111 call_window_set_output_video_is_drawing (EmpathyCallWindow *window,
114 DEBUG ("Setting output video is drawing - %d", is_drawing);
116 if (is_drawing && !window->is_drawing)
118 gtk_window_set_resizable (GTK_WINDOW (window->window), TRUE);
119 gtk_box_pack_end (GTK_BOX (window->main_hbox),
120 window->output_video_socket, TRUE, TRUE, 0);
121 empathy_tp_call_add_output_video (window->call,
122 gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
124 if (!is_drawing && window->is_drawing)
126 gtk_window_set_resizable (GTK_WINDOW (window->window), FALSE);
127 empathy_tp_call_add_output_video (window->call, 0);
128 gtk_container_remove (GTK_CONTAINER (window->main_hbox),
129 window->output_video_socket);
132 window->is_drawing = is_drawing;
136 call_window_finalize (EmpathyCallWindow *window)
138 gtk_label_set_text (GTK_LABEL (window->status_label), _("Closed"));
139 gtk_widget_set_sensitive (window->hang_up_button, FALSE);
140 gtk_widget_set_sensitive (window->video_button, FALSE);
141 gtk_widget_set_sensitive (window->output_volume_button, FALSE);
142 gtk_widget_set_sensitive (window->input_volume_button, FALSE);
146 call_window_stop_timeout (window);
147 call_window_set_output_video_is_drawing (window, FALSE);
148 empathy_tp_call_remove_preview_video (window->call,
149 gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
150 g_object_unref (window->call);
154 if (window->confirmation_dialog)
155 gtk_widget_destroy (window->confirmation_dialog);
159 call_window_socket_realized_cb (GtkWidget *widget,
160 EmpathyCallWindow *window)
162 if (widget == window->preview_video_socket)
164 DEBUG ("Preview socket realized");
165 empathy_tp_call_add_preview_video (window->call,
166 gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
169 DEBUG ("Output socket realized");
173 call_window_video_button_toggled_cb (GtkWidget *button,
174 EmpathyCallWindow *window)
179 is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
181 DEBUG ("Send video toggled - %d", is_sending);
183 g_object_get (window->call, "status", &status, NULL);
184 if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
185 empathy_tp_call_request_video_stream_direction (window->call, is_sending);
189 call_window_hang_up_button_clicked_cb (GtkWidget *widget,
190 EmpathyCallWindow *window)
192 DEBUG ("Call clicked, end call");
193 call_window_finalize (window);
197 call_window_output_volume_changed_cb (GtkScaleButton *button,
199 EmpathyCallWindow *window)
205 empathy_tp_call_mute_output (window->call, TRUE);
208 empathy_tp_call_mute_output (window->call, FALSE);
209 empathy_tp_call_set_output_volume (window->call, value * 100);
214 call_window_input_volume_changed_cb (GtkScaleButton *button,
216 EmpathyCallWindow *window)
222 empathy_tp_call_mute_input (window->call, TRUE);
225 empathy_tp_call_mute_input (window->call, FALSE);
226 /* FIXME: Not implemented?
227 empathy_tp_call_set_input_volume (window->call, value * 100);*/
232 call_window_delete_event_cb (GtkWidget *widget,
234 EmpathyCallWindow *window)
238 guint status = EMPATHY_TP_CALL_STATUS_CLOSED;
240 DEBUG ("Delete event occurred");
243 g_object_get (window->call, "status", &status, NULL);
245 if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
247 dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
248 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
249 GTK_MESSAGE_WARNING, GTK_BUTTONS_CANCEL, _("End this call?"));
250 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
251 _("Closing this window will end the call in progress."));
252 gtk_dialog_add_button (GTK_DIALOG (dialog), _("_End Call"), GTK_RESPONSE_OK);
253 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
255 result = gtk_dialog_run (GTK_DIALOG (dialog));
256 gtk_widget_destroy (dialog);
258 if (result != GTK_RESPONSE_OK)
266 call_window_destroy_cb (GtkWidget *widget,
267 EmpathyCallWindow *window)
269 call_window_finalize (window);
270 g_object_unref (window->output_video_socket);
271 g_object_unref (window->preview_video_socket);
272 g_slice_free (EmpathyCallWindow, window);
276 call_window_confirmation_dialog_response_cb (GtkDialog *dialog,
278 EmpathyCallWindow *window)
280 if (response == GTK_RESPONSE_OK && window->call)
281 empathy_tp_call_accept_incoming_call (window->call);
283 call_window_finalize (window);
285 gtk_widget_destroy (window->confirmation_dialog);
286 window->confirmation_dialog = NULL;
290 call_window_show_confirmation_dialog (EmpathyCallWindow *window)
292 EmpathyContact *contact;
296 if (window->confirmation_dialog)
299 g_object_get (window->call, "contact", &contact, NULL);
301 window->confirmation_dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
302 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
303 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Incoming call"));
304 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (window->confirmation_dialog),
305 _("%s is calling you, do you want to answer?"),
306 empathy_contact_get_name (contact));
307 gtk_dialog_set_default_response (GTK_DIALOG (window->confirmation_dialog),
310 button = gtk_dialog_add_button (GTK_DIALOG (window->confirmation_dialog),
311 _("_Reject"), GTK_RESPONSE_CANCEL);
312 image = gtk_image_new_from_icon_name (GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
313 gtk_button_set_image (GTK_BUTTON (button), image);
315 button = gtk_dialog_add_button (GTK_DIALOG (window->confirmation_dialog),
316 _("_Answer"), GTK_RESPONSE_OK);
317 image = gtk_image_new_from_icon_name (GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON);
318 gtk_button_set_image (GTK_BUTTON (button), image);
320 g_signal_connect (window->confirmation_dialog, "response",
321 G_CALLBACK (call_window_confirmation_dialog_response_cb),
324 gtk_widget_show (window->confirmation_dialog);
325 g_object_unref (contact);
329 call_window_update (EmpathyCallWindow *window)
331 EmpathyContact *contact;
333 EmpathyTpCallStream *audio_stream;
334 EmpathyTpCallStream *video_stream;
335 gboolean is_incoming;
338 g_object_get (window->call,
339 "status", &window->status,
340 "audio-stream", &audio_stream,
341 "video-stream", &video_stream,
343 "is-incoming", &is_incoming,
346 if (video_stream->state > audio_stream->state)
347 stream_state = video_stream->state;
349 stream_state = audio_stream->state;
351 DEBUG ("Status changed - status: %d, stream state: %d, "
352 "is-incoming: %d video-stream direction: %d",
353 window->status, stream_state, is_incoming, video_stream->direction);
355 /* Depending on the status we have to set:
358 * - sensibility of all buttons
360 if (window->status == EMPATHY_TP_CALL_STATUS_READYING)
362 gtk_window_set_title (GTK_WINDOW (window->window), _("Empathy Call"));
363 gtk_label_set_text (GTK_LABEL (window->status_label), _("Readying"));
364 gtk_widget_set_sensitive (window->video_button, FALSE);
365 gtk_widget_set_sensitive (window->output_volume_button, FALSE);
366 gtk_widget_set_sensitive (window->input_volume_button, FALSE);
367 gtk_widget_set_sensitive (window->hang_up_button, FALSE);
369 else if (window->status == EMPATHY_TP_CALL_STATUS_PENDING)
371 title = g_strdup_printf (_("%s - Empathy Call"),
372 empathy_contact_get_name (contact));
374 gtk_window_set_title (GTK_WINDOW (window->window), title);
375 gtk_label_set_text (GTK_LABEL (window->status_label), _("Ringing"));
376 gtk_widget_set_sensitive (window->hang_up_button, TRUE);
378 call_window_show_confirmation_dialog (window);
380 else if (window->status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
382 gboolean receiving_video;
383 gboolean sending_video;
385 if (stream_state == TP_MEDIA_STREAM_STATE_DISCONNECTED)
386 gtk_label_set_text (GTK_LABEL (window->status_label), _("Disconnected"));
387 if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTING)
388 gtk_label_set_text (GTK_LABEL (window->status_label), _("Connecting"));
389 else if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTED &&
390 window->timeout_event_id == 0)
392 /* The call started, launch the timer */
393 g_get_current_time (&(window->start_time));
394 window->timeout_event_id = g_timeout_add_seconds (1,
395 call_window_update_timer, window);
396 call_window_update_timer (window);
399 receiving_video = video_stream->direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE;
400 sending_video = video_stream->direction & TP_MEDIA_STREAM_DIRECTION_SEND;
401 call_window_set_output_video_is_drawing (window, receiving_video);
402 g_signal_handlers_block_by_func (window->video_button,
403 call_window_video_button_toggled_cb, window);
404 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->video_button),
406 g_signal_handlers_unblock_by_func (window->video_button,
407 call_window_video_button_toggled_cb, window);
409 gtk_widget_set_sensitive (window->video_button, TRUE);
410 gtk_widget_set_sensitive (window->output_volume_button, TRUE);
411 gtk_widget_set_sensitive (window->input_volume_button, TRUE);
412 gtk_widget_set_sensitive (window->hang_up_button, TRUE);
414 else if (window->status == EMPATHY_TP_CALL_STATUS_CLOSED)
415 call_window_finalize (window);
418 g_object_unref (contact);
422 empathy_call_window_new (EmpathyTpCall *call)
424 EmpathyCallWindow *window;
427 const gchar *icons[] = {"audio-input-microphone", NULL};
429 g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), NULL);
431 window = g_slice_new0 (EmpathyCallWindow);
432 window->call = g_object_ref (call);
434 filename = empathy_file_lookup ("empathy-call-window.glade", "src");
435 glade = empathy_glade_get_file (filename,
438 "window", &window->window,
439 "main_hbox", &window->main_hbox,
440 "controls_vbox", &window->controls_vbox,
441 "volume_hbox", &window->volume_hbox,
442 "status_label", &window->status_label,
443 "video_button", &window->video_button,
444 "hang_up_button", &window->hang_up_button,
448 empathy_glade_connect (glade,
450 "window", "destroy", call_window_destroy_cb,
451 "window", "delete_event", call_window_delete_event_cb,
452 "hang_up_button", "clicked", call_window_hang_up_button_clicked_cb,
453 "video_button", "toggled", call_window_video_button_toggled_cb,
456 g_object_unref (glade);
458 /* Output volume button */
459 window->output_volume_button = gtk_volume_button_new ();
460 gtk_scale_button_set_value (GTK_SCALE_BUTTON (window->output_volume_button), 1);
461 gtk_box_pack_start (GTK_BOX (window->volume_hbox),
462 window->output_volume_button, FALSE, FALSE, 0);
463 gtk_widget_show (window->output_volume_button);
464 g_signal_connect (window->output_volume_button, "value-changed",
465 G_CALLBACK (call_window_output_volume_changed_cb), window);
467 /* Input volume button */
468 window->input_volume_button = gtk_volume_button_new ();
469 gtk_scale_button_set_icons (GTK_SCALE_BUTTON (window->input_volume_button),
471 gtk_scale_button_set_value (GTK_SCALE_BUTTON (window->input_volume_button), 1);
472 gtk_box_pack_start (GTK_BOX (window->volume_hbox),
473 window->input_volume_button, FALSE, FALSE, 0);
474 gtk_widget_show (window->input_volume_button);
475 g_signal_connect (window->input_volume_button, "value-changed",
476 G_CALLBACK (call_window_input_volume_changed_cb), window);
478 /* Output video socket */
479 window->output_video_socket = g_object_ref (gtk_socket_new ());
480 gtk_widget_set_size_request (window->output_video_socket, 400, 300);
481 g_signal_connect (GTK_OBJECT (window->output_video_socket), "realize",
482 G_CALLBACK (call_window_socket_realized_cb), window);
483 gtk_widget_show (window->output_video_socket);
485 /* Preview video socket */
486 window->preview_video_socket = g_object_ref (gtk_socket_new ());
487 gtk_widget_set_size_request (window->preview_video_socket, 176, 144);
488 g_signal_connect (GTK_OBJECT (window->preview_video_socket), "realize",
489 G_CALLBACK (call_window_socket_realized_cb), window);
490 gtk_box_pack_start (GTK_BOX (window->controls_vbox),
491 window->preview_video_socket, TRUE, TRUE, 0);
492 gtk_box_reorder_child (GTK_BOX (window->controls_vbox),
493 window->preview_video_socket, 0);
494 gtk_widget_show (window->preview_video_socket);
496 g_signal_connect_swapped (G_OBJECT (window->call), "notify",
497 G_CALLBACK (call_window_update),
500 call_window_update (window);
501 gtk_widget_show (window->window);
503 return window->window;