1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* Copyright (C) 2007 Elliot Fairweather
4
* Copyright (C) 2007 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>
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>
27
#include <glib/gi18n.h>
23
#include <libtelepathy/tp-chan.h>
24
#include <libtelepathy/tp-helpers.h>
26
#include <libmissioncontrol/mc-account.h>
27
#include <libmissioncontrol/mc-account-monitor.h>
28
#include <libmissioncontrol/mission-control.h>
30
#include <libempathy/empathy-contact.h>
31
#include <libempathy/empathy-tp-call.h>
32
#include <libempathy/empathy-chandler.h>
29
33
#include <libempathy/empathy-debug.h>
34
#include <libempathy/empathy-utils.h>
31
#include "empathy-call-window.h"
32
#include "empathy-ui-utils.h"
36
#include <libempathy-gtk/empathy-call-window.h>
37
#include <libempathy-gtk/empathy-ui-utils.h>
34
39
#define DEBUG_DOMAIN "CallWindow"
38
GtkWidget *input_volume_scale;
39
GtkWidget *output_volume_scale;
40
GtkWidget *input_mute_togglebutton;
41
GtkWidget *output_mute_togglebutton;
42
GtkWidget *preview_video_frame;
43
GtkWidget *output_video_frame;
44
GtkWidget *preview_video_socket;
45
GtkWidget *output_video_socket;
46
GtkWidget *send_video_checkbutton;
44
GtkWidget *status_label;
45
GtkWidget *start_call_button;
46
GtkWidget *end_call_button;
47
GtkWidget *input_volume_scale;
48
GtkWidget *output_volume_scale;
49
GtkWidget *input_mute_button;
50
GtkWidget *output_mute_button;
51
GtkWidget *preview_video_frame;
52
GtkWidget *output_video_frame;
53
GtkWidget *preview_video_socket;
54
GtkWidget *output_video_socket;
55
GtkWidget *video_button;
56
GtkWidget *output_video_label;
61
guint timeout_event_id;
49
64
} EmpathyCallWindow;
52
call_window_output_volume_changed_cb (GtkWidget *scale,
53
EmpathyCallWindow *window)
57
volume = (guint) gtk_range_get_value (GTK_RANGE (scale));
58
empathy_tp_call_set_output_volume (window->call, volume);
63
call_window_output_mute_toggled_cb (GtkWidget *button,
64
EmpathyCallWindow *window)
68
is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
69
empathy_tp_call_mute_output (window->call, is_muted);
74
call_window_input_mute_toggled_cb (GtkWidget *button,
75
EmpathyCallWindow *window)
79
is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
80
empathy_tp_call_mute_input (window->call, is_muted);
85
call_window_send_video_toggled_cb (GtkWidget *button,
86
EmpathyCallWindow *window)
90
is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
91
empathy_tp_call_send_video (window->call, is_sending);
95
call_window_capabilities_notify_cb (EmpathyContact *contact,
97
EmpathyCallWindow *window)
99
EmpathyCapabilities capabilities;
101
capabilities = empathy_contact_get_capabilities (contact);
102
empathy_tp_call_request_streams (window->call,
103
capabilities & EMPATHY_CAPABILITIES_AUDIO,
104
capabilities & EMPATHY_CAPABILITIES_VIDEO);
108
call_window_name_notify_cb (EmpathyContact *contact,
110
EmpathyCallWindow *window)
115
name = empathy_contact_get_name (contact);
116
title = g_strdup_printf (_("Call from %s"), name);
117
gtk_window_set_title (GTK_WINDOW (window->window), title);
122
call_window_status_notify_cb (EmpathyTpCall *call,
124
EmpathyCallWindow *window)
128
status = empathy_tp_call_get_status (call);
129
empathy_debug (DEBUG_DOMAIN, "Status changed to %d",
132
if (status == EMPATHY_TP_CALL_STATUS_RINGING) {
133
if (empathy_tp_call_is_incoming (window->call)) {
134
empathy_tp_call_accept (window->call);
136
EmpathyContact *contact;
138
contact = empathy_tp_call_get_contact (call);
139
g_signal_connect (contact, "notify::capabilities",
140
G_CALLBACK (call_window_capabilities_notify_cb),
142
g_signal_connect (contact, "notify::name",
143
G_CALLBACK (call_window_name_notify_cb),
145
call_window_capabilities_notify_cb (contact, NULL, window);
146
call_window_name_notify_cb (contact, NULL, window);
150
if (status == EMPATHY_TP_CALL_STATUS_RUNNING) {
151
empathy_tp_call_set_output_window (window->call,
152
gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
157
call_window_destroy_cb (GtkWidget *widget,
158
EmpathyCallWindow *window)
160
g_object_unref (window->call);
161
g_slice_free (EmpathyCallWindow, window);
67
call_window_update_timer (gpointer data)
69
EmpathyCallWindow *window = data;
73
glong time, seconds, minutes, hours;
75
g_get_current_time (¤t);
78
then = (window->start_time).tv_sec;
90
str = g_strdup_printf ("Connected - %02ld : %02ld : %02ld", hours,
95
str = g_strdup_printf ("Connected - %02ld : %02ld", minutes, seconds);
98
gtk_label_set_text (GTK_LABEL (window->status_label), str);
106
call_window_stop_timeout (EmpathyCallWindow *window)
108
GMainContext *context;
111
context = g_main_context_default ();
113
empathy_debug (DEBUG_DOMAIN, "Timer stopped");
115
if (window->timeout_event_id)
117
source = g_main_context_find_source_by_id (context,
118
window->timeout_event_id);
119
g_source_destroy (source);
120
window->timeout_event_id = 0;
125
call_window_set_output_video_is_drawing (EmpathyCallWindow *window,
130
child = gtk_bin_get_child (GTK_BIN (window->output_video_frame));
132
empathy_debug (DEBUG_DOMAIN,
133
"Setting output video is drawing - %d", is_drawing);
137
if (!window->is_drawing)
141
gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
144
gtk_container_add (GTK_CONTAINER (window->output_video_frame),
145
window->output_video_socket);
146
gtk_widget_show (window->output_video_socket);
147
empathy_tp_call_add_output_video (window->call,
148
gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
149
window->is_drawing = is_drawing;
154
if (window->is_drawing)
156
empathy_tp_call_add_output_video (window->call, 0);
159
gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
162
gtk_container_add (GTK_CONTAINER (window->output_video_frame),
163
window->output_video_label);
164
gtk_widget_show (window->output_video_label);
165
window->is_drawing = is_drawing;
171
call_window_delete_event_cb (GtkWidget *widget,
173
EmpathyCallWindow *window)
179
empathy_debug (DEBUG_DOMAIN, "Delete event occurred");
181
g_object_get (G_OBJECT (window->call), "status", &status, NULL);
183
if (status != EMPATHY_TP_CALL_STATUS_CLOSED)
185
dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
186
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
187
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
188
"This call will be ended. Continue?");
190
result = gtk_dialog_run (GTK_DIALOG (dialog));
191
gtk_widget_destroy (dialog);
195
case GTK_RESPONSE_YES:
196
call_window_stop_timeout (window);
197
call_window_set_output_video_is_drawing (window, FALSE);
198
empathy_tp_call_close_channel (window->call);
199
empathy_tp_call_remove_preview_video (window->call,
200
gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
208
empathy_tp_call_remove_preview_video (window->call,
209
gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
215
call_window_video_button_toggled_cb (GtkWidget *button,
216
EmpathyCallWindow *window)
220
is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
222
empathy_debug (DEBUG_DOMAIN, "Send video toggled - %d", is_sending);
224
empathy_tp_call_request_video_stream_direction (window->call, is_sending);
228
call_window_status_changed_cb (EmpathyTpCall *call,
229
EmpathyCallWindow *window)
231
EmpathyContact *contact;
234
EmpathyTpCallStream *audio_stream;
235
EmpathyTpCallStream *video_stream;
236
gboolean is_incoming;
239
g_object_get (G_OBJECT (window->call), "status", &status, NULL);
240
g_object_get (G_OBJECT (window->call), "audio-stream", &audio_stream, NULL);
241
g_object_get (G_OBJECT (window->call), "video-stream", &video_stream, NULL);
243
if (video_stream->state > audio_stream->state)
245
stream_state = video_stream->state;
249
stream_state = audio_stream->state;
252
empathy_debug (DEBUG_DOMAIN, "Status changed - status: %d, stream state: %d",
253
status, stream_state);
255
if (window->timeout_event_id)
257
call_window_stop_timeout (window);
260
if (status == EMPATHY_TP_CALL_STATUS_CLOSED)
262
gtk_label_set_text (GTK_LABEL (window->status_label), "Closed");
263
gtk_widget_set_sensitive (window->end_call_button, FALSE);
264
gtk_widget_set_sensitive (window->start_call_button, FALSE);
266
call_window_set_output_video_is_drawing (window, FALSE);
268
else if (stream_state == TP_MEDIA_STREAM_STATE_DISCONNECTED)
270
gtk_label_set_text (GTK_LABEL (window->status_label), "Disconnected");
272
else if (status == EMPATHY_TP_CALL_STATUS_PENDING)
274
g_object_get (G_OBJECT (window->call), "contact", &contact, NULL);
276
title = g_strdup_printf ("%s - Empathy Call",
277
empathy_contact_get_name (contact));
278
gtk_window_set_title (GTK_WINDOW (window->window), title);
280
gtk_label_set_text (GTK_LABEL (window->status_label), "Ringing");
281
gtk_widget_set_sensitive (window->end_call_button, TRUE);
282
gtk_widget_set_sensitive (window->video_button, TRUE);
284
g_object_get (G_OBJECT (window->call), "is-incoming", &is_incoming, NULL);
287
gtk_widget_set_sensitive (window->start_call_button, TRUE);
291
g_signal_connect (GTK_OBJECT (window->video_button), "toggled",
292
G_CALLBACK (call_window_video_button_toggled_cb),
296
else if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
298
if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTING)
300
gtk_label_set_text (GTK_LABEL (window->status_label), "Connecting");
302
else if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTED)
304
if ((window->start_time).tv_sec == 0)
306
g_get_current_time (&(window->start_time));
308
window->timeout_event_id = g_timeout_add (1000,
309
call_window_update_timer, window);
310
empathy_debug (DEBUG_DOMAIN, "Timer started");
316
call_window_receiving_video_cb (EmpathyTpCall *call,
317
gboolean receiving_video,
318
EmpathyCallWindow *window)
320
empathy_debug (DEBUG_DOMAIN, "Receiving video signal received");
322
call_window_set_output_video_is_drawing (window, receiving_video);
326
call_window_sending_video_cb (EmpathyTpCall *call,
327
gboolean sending_video,
328
EmpathyCallWindow *window)
330
empathy_debug (DEBUG_DOMAIN, "Sending video signal received");
332
g_signal_handlers_block_by_func (window->video_button,
333
call_window_video_button_toggled_cb, window);
334
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->video_button),
336
g_signal_handlers_unblock_by_func (window->video_button,
337
call_window_video_button_toggled_cb, window);
341
call_window_socket_realized_cb (GtkWidget *widget,
342
EmpathyCallWindow *window)
344
if (widget == window->preview_video_socket)
346
empathy_debug (DEBUG_DOMAIN, "Preview socket realized");
347
empathy_tp_call_add_preview_video (window->call,
348
gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
352
empathy_debug (DEBUG_DOMAIN, "Output socket realized");
357
call_window_start_call_button_clicked_cb (GtkWidget *widget,
358
EmpathyCallWindow *window)
361
gboolean is_incoming;
363
empathy_debug (DEBUG_DOMAIN, "Start call clicked");
365
gtk_widget_set_sensitive (window->start_call_button, FALSE);
366
g_object_get (G_OBJECT (window->call), "is-incoming", &is_incoming, NULL);
369
empathy_tp_call_accept_incoming_call (window->call);
370
send_video = gtk_toggle_button_get_active
371
(GTK_TOGGLE_BUTTON (window->video_button));
372
empathy_tp_call_request_video_stream_direction (window->call, send_video);
373
g_signal_connect (GTK_OBJECT (window->video_button), "toggled",
374
G_CALLBACK (call_window_video_button_toggled_cb), window);
379
call_window_end_call_button_clicked_cb (GtkWidget *widget,
380
EmpathyCallWindow *window)
382
empathy_debug (DEBUG_DOMAIN, "End call clicked");
384
call_window_set_output_video_is_drawing (window, FALSE);
385
empathy_tp_call_close_channel (window->call);
386
gtk_widget_set_sensitive (window->end_call_button, FALSE);
387
gtk_widget_set_sensitive (window->start_call_button, FALSE);
391
call_window_output_volume_changed_cb (GtkWidget *scale,
392
EmpathyCallWindow *window)
396
volume = (guint) gtk_range_get_value (GTK_RANGE (scale));
398
empathy_debug (DEBUG_DOMAIN, "Output volume changed - %u", volume);
400
empathy_tp_call_set_output_volume (window->call, volume);
404
call_window_output_mute_button_toggled_cb (GtkWidget *button,
405
EmpathyCallWindow *window)
409
is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
411
empathy_debug (DEBUG_DOMAIN, "Mute output toggled - %d", is_muted);
413
empathy_tp_call_mute_output (window->call, is_muted);
417
call_window_input_mute_button_toggled_cb (GtkWidget *button,
418
EmpathyCallWindow *window)
422
is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
424
empathy_debug (DEBUG_DOMAIN, "Mute input toggled - %d", is_muted);
426
empathy_tp_call_mute_input (window->call, is_muted);
430
call_window_destroy_cb (GtkWidget *widget,
431
EmpathyCallWindow *window)
433
g_signal_handlers_disconnect_by_func (window->call,
434
call_window_status_changed_cb, window);
435
g_signal_handlers_disconnect_by_func (window->call,
436
call_window_receiving_video_cb, window);
437
g_signal_handlers_disconnect_by_func (window->call,
438
call_window_sending_video_cb, window);
440
g_object_unref (window->call);
441
g_object_unref (window->output_video_socket);
442
g_object_unref (window->preview_video_socket);
443
g_object_unref (window->output_video_label);
445
g_slice_free (EmpathyCallWindow, window);
165
empathy_call_window_show (EmpathyTpCall *call)
449
empathy_call_window_new (EmpathyTpCall *call)
167
EmpathyCallWindow *window;
170
window = g_slice_new0 (EmpathyCallWindow);
172
glade = empathy_glade_get_file ("empathy-call-window.glade",
175
"window", &window->window,
176
"input_volume_scale", &window->input_volume_scale,
177
"output_volume_scale", &window->output_volume_scale,
178
"input_mute_togglebutton", &window->input_mute_togglebutton,
179
"output_mute_togglebutton", &window->output_mute_togglebutton,
180
"preview_video_frame", &window->preview_video_frame,
181
"output_video_frame", &window->output_video_frame,
182
"send_video_checkbutton", &window->send_video_checkbutton,
185
empathy_glade_connect (glade,
187
"window", "destroy", call_window_destroy_cb,
188
"input_mute_togglebutton", "toggled", call_window_input_mute_toggled_cb,
189
"output_mute_togglebutton", "toggled", call_window_output_mute_toggled_cb,
190
"output_volume_scale", "value-changed", call_window_output_volume_changed_cb,
191
"send_video_checkbutton", "toggled", call_window_send_video_toggled_cb,
193
g_object_unref (glade);
195
/* Set output window socket */
196
window->output_video_socket = gtk_socket_new ();
197
gtk_widget_show (window->output_video_socket);
198
gtk_container_add (GTK_CONTAINER (window->output_video_frame),
199
window->output_video_socket);
201
/* Set preview window socket */
202
window->preview_video_socket = gtk_socket_new ();
203
gtk_widget_show (window->preview_video_socket);
204
gtk_container_add (GTK_CONTAINER (window->preview_video_frame),
205
window->preview_video_socket);
208
window->call = g_object_ref (call);
209
empathy_tp_call_add_preview_window (window->call,
210
gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
211
g_signal_connect (window->call, "notify::status",
212
G_CALLBACK (call_window_status_notify_cb),
215
gtk_widget_show (window->window);
217
return window->window;
451
EmpathyCallWindow *window;
455
g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), NULL);
457
window = g_slice_new0 (EmpathyCallWindow);
458
window->call = g_object_ref (call);
460
glade = empathy_glade_get_file ("empathy-call-window.glade",
463
"window", &window->window,
464
"status_label", &window->status_label,
465
"start_call_button", &window->start_call_button,
466
"end_call_button", &window->end_call_button,
467
"input_volume_scale", &window->input_volume_scale,
468
"output_volume_scale", &window->output_volume_scale,
469
"input_mute_button", &window->input_mute_button,
470
"output_mute_button", &window->output_mute_button,
471
"preview_video_frame", &window->preview_video_frame,
472
"output_video_frame", &window->output_video_frame,
473
"video_button", &window->video_button,
476
empathy_glade_connect (glade,
478
"window", "destroy", call_window_destroy_cb,
479
"window", "delete_event", call_window_delete_event_cb,
480
"input_mute_button", "toggled", call_window_input_mute_button_toggled_cb,
481
"output_mute_button", "toggled", call_window_output_mute_button_toggled_cb,
482
"output_volume_scale", "value-changed", call_window_output_volume_changed_cb,
483
"start_call_button", "clicked", call_window_start_call_button_clicked_cb,
484
"end_call_button", "clicked", call_window_end_call_button_clicked_cb,
487
g_object_unref (glade);
489
/* Output video label */
490
window->output_video_label = g_object_ref (gtk_label_new ("No video output"));
491
gtk_container_add (GTK_CONTAINER (window->output_video_frame),
492
window->output_video_label);
493
gtk_widget_show (window->output_video_label);
495
/* Output video socket */
496
window->output_video_socket = g_object_ref (gtk_socket_new ());
497
g_signal_connect (GTK_OBJECT (window->output_video_socket), "realize",
498
G_CALLBACK (call_window_socket_realized_cb), window);
499
gtk_widget_show (window->output_video_socket);
501
/* Preview video socket */
502
window->preview_video_socket = g_object_ref (gtk_socket_new ());
503
g_signal_connect (GTK_OBJECT (window->preview_video_socket), "realize",
504
G_CALLBACK (call_window_socket_realized_cb), window);
505
gtk_container_add (GTK_CONTAINER (window->preview_video_frame),
506
window->preview_video_socket);
507
gtk_widget_show (window->preview_video_socket);
509
g_signal_connect (G_OBJECT (window->call), "status-changed",
510
G_CALLBACK (call_window_status_changed_cb),
512
g_signal_connect (G_OBJECT (window->call), "receiving-video",
513
G_CALLBACK (call_window_receiving_video_cb),
515
g_signal_connect (G_OBJECT (window->call), "sending-video",
516
G_CALLBACK (call_window_sending_video_cb),
519
window->is_drawing = FALSE;
521
g_object_get (G_OBJECT (window->call), "status", &status, NULL);
523
if (status == EMPATHY_TP_CALL_STATUS_READYING)
525
gtk_window_set_title (GTK_WINDOW (window->window), "Empathy Call");
526
gtk_label_set_text (GTK_LABEL (window->status_label), "Readying");
529
gtk_widget_show (window->window);
531
return window->window;