2 * Copyright (C) 2007 Elliot Fairweather
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
23 #include <glade/glade.h>
24 #include <glib/gi18n.h>
26 #include <telepathy-glib/enums.h>
28 #include <libempathy/empathy-contact.h>
29 #include <libempathy/empathy-tp-call.h>
30 #include <libempathy/empathy-debug.h>
31 #include <libempathy/empathy-utils.h>
32 #include <libempathy-gtk/empathy-ui-utils.h>
34 #include "empathy-call-window.h"
36 #define DEBUG_DOMAIN "CallWindow"
41 GtkWidget *status_label;
42 GtkWidget *start_call_button;
43 GtkWidget *end_call_button;
44 GtkWidget *input_volume_scale;
45 GtkWidget *output_volume_scale;
46 GtkWidget *input_mute_button;
47 GtkWidget *output_mute_button;
48 GtkWidget *preview_video_frame;
49 GtkWidget *output_video_frame;
50 GtkWidget *preview_video_socket;
51 GtkWidget *output_video_socket;
52 GtkWidget *video_button;
53 GtkWidget *output_video_label;
58 guint timeout_event_id;
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 empathy_debug (DEBUG_DOMAIN, "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,
116 child = gtk_bin_get_child (GTK_BIN (window->output_video_frame));
118 empathy_debug (DEBUG_DOMAIN,
119 "Setting output video is drawing - %d", is_drawing);
121 if (is_drawing && !window->is_drawing)
124 gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
126 gtk_container_add (GTK_CONTAINER (window->output_video_frame),
127 window->output_video_socket);
128 gtk_widget_show (window->output_video_socket);
129 empathy_tp_call_add_output_video (window->call,
130 gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
132 if (!is_drawing && window->is_drawing)
134 empathy_tp_call_add_output_video (window->call, 0);
136 gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
138 gtk_container_add (GTK_CONTAINER (window->output_video_frame),
139 window->output_video_label);
140 gtk_widget_show (window->output_video_label);
143 window->is_drawing = is_drawing;
147 call_window_finalize (EmpathyCallWindow *window)
151 call_window_stop_timeout (window);
152 call_window_set_output_video_is_drawing (window, FALSE);
153 empathy_tp_call_remove_preview_video (window->call,
154 gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
155 g_object_unref (window->call);
161 call_window_socket_realized_cb (GtkWidget *widget,
162 EmpathyCallWindow *window)
164 if (widget == window->preview_video_socket)
166 empathy_debug (DEBUG_DOMAIN, "Preview socket realized");
167 empathy_tp_call_add_preview_video (window->call,
168 gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
171 empathy_debug (DEBUG_DOMAIN, "Output socket realized");
175 call_window_video_button_toggled_cb (GtkWidget *button,
176 EmpathyCallWindow *window)
180 is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
182 empathy_debug (DEBUG_DOMAIN, "Send video toggled - %d", is_sending);
184 empathy_tp_call_request_video_stream_direction (window->call, is_sending);
188 call_window_start_call_button_clicked_cb (GtkWidget *widget,
189 EmpathyCallWindow *window)
191 empathy_debug (DEBUG_DOMAIN, "Start call clicked");
193 gtk_widget_set_sensitive (window->start_call_button, FALSE);
194 empathy_tp_call_accept_incoming_call (window->call);
198 call_window_end_call_button_clicked_cb (GtkWidget *widget,
199 EmpathyCallWindow *window)
201 empathy_debug (DEBUG_DOMAIN, "End call clicked");
203 gtk_widget_set_sensitive (window->end_call_button, FALSE);
204 call_window_finalize (window);
208 call_window_output_volume_changed_cb (GtkWidget *scale,
209 EmpathyCallWindow *window)
213 volume = (guint) gtk_range_get_value (GTK_RANGE (scale));
215 empathy_debug (DEBUG_DOMAIN, "Output volume changed - %u", volume);
217 empathy_tp_call_set_output_volume (window->call, volume);
221 call_window_output_mute_button_toggled_cb (GtkWidget *button,
222 EmpathyCallWindow *window)
226 is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
228 empathy_debug (DEBUG_DOMAIN, "Mute output toggled - %d", is_muted);
230 empathy_tp_call_mute_output (window->call, is_muted);
234 call_window_input_mute_button_toggled_cb (GtkWidget *button,
235 EmpathyCallWindow *window)
239 is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
241 empathy_debug (DEBUG_DOMAIN, "Mute input toggled - %d", is_muted);
243 empathy_tp_call_mute_input (window->call, is_muted);
247 call_window_delete_event_cb (GtkWidget *widget,
249 EmpathyCallWindow *window)
255 empathy_debug (DEBUG_DOMAIN, "Delete event occurred");
257 g_object_get (G_OBJECT (window->call), "status", &status, NULL);
258 if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
260 dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
261 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
262 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
263 "This call will be ended. Continue?");
265 result = gtk_dialog_run (GTK_DIALOG (dialog));
266 gtk_widget_destroy (dialog);
268 if (result != GTK_RESPONSE_YES)
276 call_window_destroy_cb (GtkWidget *widget,
277 EmpathyCallWindow *window)
279 call_window_finalize (window);
280 g_object_unref (window->output_video_socket);
281 g_object_unref (window->preview_video_socket);
282 g_object_unref (window->output_video_label);
283 g_slice_free (EmpathyCallWindow, window);
287 call_window_update (EmpathyCallWindow *window)
289 EmpathyContact *contact;
292 EmpathyTpCallStream *audio_stream;
293 EmpathyTpCallStream *video_stream;
294 gboolean is_incoming;
297 g_object_get (window->call,
299 "audio-stream", &audio_stream,
300 "video-stream", &video_stream,
302 "is-incoming", &is_incoming,
305 if (video_stream->state > audio_stream->state)
306 stream_state = video_stream->state;
308 stream_state = audio_stream->state;
310 empathy_debug (DEBUG_DOMAIN, "Status changed - status: %d, stream state: %d, "
311 "is-incoming: %d video-stream direction: %d",
312 status, stream_state, is_incoming, video_stream->direction);
314 /* Depending on the status we have to set:
317 * - sensibility of all buttons
319 if (status == EMPATHY_TP_CALL_STATUS_READYING)
321 gtk_window_set_title (GTK_WINDOW (window->window), _("Empathy Call"));
322 gtk_label_set_text (GTK_LABEL (window->status_label), _("Readying"));
323 gtk_widget_set_sensitive (window->start_call_button, is_incoming);
324 gtk_widget_set_sensitive (window->end_call_button, FALSE);
325 gtk_widget_set_sensitive (window->video_button, FALSE);
326 gtk_widget_set_sensitive (window->input_volume_scale, FALSE);
327 gtk_widget_set_sensitive (window->output_volume_scale, FALSE);
328 gtk_widget_set_sensitive (window->input_mute_button, FALSE);
329 gtk_widget_set_sensitive (window->output_mute_button, FALSE);
331 else if (status == EMPATHY_TP_CALL_STATUS_PENDING)
333 title = g_strdup_printf (_("%s - Empathy Call"),
334 empathy_contact_get_name (contact));
336 gtk_window_set_title (GTK_WINDOW (window->window), title);
337 gtk_label_set_text (GTK_LABEL (window->status_label), _("Ringing"));
338 gtk_widget_set_sensitive (window->start_call_button, is_incoming);
339 gtk_widget_set_sensitive (window->end_call_button, TRUE);
341 else if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
343 gboolean receiving_video;
344 gboolean sending_video;
346 if (stream_state == TP_MEDIA_STREAM_STATE_DISCONNECTED)
347 gtk_label_set_text (GTK_LABEL (window->status_label), "Disconnected");
348 if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTING)
349 gtk_label_set_text (GTK_LABEL (window->status_label), "Connecting");
350 else if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTED &&
351 window->timeout_event_id == 0)
353 /* The call started, launch the timer */
354 g_get_current_time (&(window->start_time));
355 window->timeout_event_id = g_timeout_add_seconds (1,
356 call_window_update_timer, window);
357 call_window_update_timer (window);
360 receiving_video = video_stream->direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE;
361 sending_video = video_stream->direction & TP_MEDIA_STREAM_DIRECTION_SEND;
362 call_window_set_output_video_is_drawing (window, receiving_video);
363 g_signal_handlers_block_by_func (window->video_button,
364 call_window_video_button_toggled_cb, window);
365 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->video_button),
367 g_signal_handlers_unblock_by_func (window->video_button,
368 call_window_video_button_toggled_cb, window);
370 gtk_widget_set_sensitive (window->video_button, TRUE);
371 gtk_widget_set_sensitive (window->input_volume_scale, TRUE);
372 gtk_widget_set_sensitive (window->output_volume_scale, TRUE);
373 gtk_widget_set_sensitive (window->input_mute_button, TRUE);
374 gtk_widget_set_sensitive (window->output_mute_button, TRUE);
376 else if (status == EMPATHY_TP_CALL_STATUS_CLOSED)
378 gtk_label_set_text (GTK_LABEL (window->status_label), "Closed");
379 gtk_widget_set_sensitive (window->start_call_button, FALSE);
380 gtk_widget_set_sensitive (window->end_call_button, FALSE);
381 gtk_widget_set_sensitive (window->video_button, FALSE);
382 gtk_widget_set_sensitive (window->input_volume_scale, FALSE);
383 gtk_widget_set_sensitive (window->output_volume_scale, FALSE);
384 gtk_widget_set_sensitive (window->input_mute_button, FALSE);
385 gtk_widget_set_sensitive (window->output_mute_button, FALSE);
387 call_window_finalize (window);
390 g_object_unref (contact);
394 empathy_call_window_new (EmpathyTpCall *call)
396 EmpathyCallWindow *window;
400 g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), NULL);
402 window = g_slice_new0 (EmpathyCallWindow);
403 window->call = g_object_ref (call);
405 filename = empathy_file_lookup ("empathy-call-window.glade", "src");
406 glade = empathy_glade_get_file (filename,
409 "window", &window->window,
410 "status_label", &window->status_label,
411 "start_call_button", &window->start_call_button,
412 "end_call_button", &window->end_call_button,
413 "input_volume_scale", &window->input_volume_scale,
414 "output_volume_scale", &window->output_volume_scale,
415 "input_mute_button", &window->input_mute_button,
416 "output_mute_button", &window->output_mute_button,
417 "preview_video_frame", &window->preview_video_frame,
418 "output_video_frame", &window->output_video_frame,
419 "video_button", &window->video_button,
423 empathy_glade_connect (glade,
425 "window", "destroy", call_window_destroy_cb,
426 "window", "delete_event", call_window_delete_event_cb,
427 "input_mute_button", "toggled", call_window_input_mute_button_toggled_cb,
428 "output_mute_button", "toggled", call_window_output_mute_button_toggled_cb,
429 "output_volume_scale", "value-changed", call_window_output_volume_changed_cb,
430 "start_call_button", "clicked", call_window_start_call_button_clicked_cb,
431 "end_call_button", "clicked", call_window_end_call_button_clicked_cb,
432 "video_button", "toggled", call_window_video_button_toggled_cb,
435 g_object_unref (glade);
437 /* Output video label */
438 window->output_video_label = g_object_ref (gtk_label_new ("No video output"));
439 gtk_container_add (GTK_CONTAINER (window->output_video_frame),
440 window->output_video_label);
441 gtk_widget_show (window->output_video_label);
443 /* Output video socket */
444 window->output_video_socket = g_object_ref (gtk_socket_new ());
445 g_signal_connect (GTK_OBJECT (window->output_video_socket), "realize",
446 G_CALLBACK (call_window_socket_realized_cb), window);
447 gtk_widget_show (window->output_video_socket);
449 /* Preview video socket */
450 window->preview_video_socket = g_object_ref (gtk_socket_new ());
451 g_signal_connect (GTK_OBJECT (window->preview_video_socket), "realize",
452 G_CALLBACK (call_window_socket_realized_cb), window);
453 gtk_container_add (GTK_CONTAINER (window->preview_video_frame),
454 window->preview_video_socket);
455 gtk_widget_show (window->preview_video_socket);
457 g_signal_connect_swapped (G_OBJECT (window->call), "notify",
458 G_CALLBACK (call_window_update),
461 call_window_update (window);
462 gtk_widget_show (window->window);
464 return window->window;