]> git.0d.be Git - empathy.git/blob - src/empathy-call-window.c
Fix translators complains about ambigous strings. Fixes bug #546154.
[empathy.git] / src / empathy-call-window.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007 Elliot Fairweather
4  * Copyright (C) 2007-2008 Collabora Ltd.
5  *
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.
10  *
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.
15  *
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
19  *
20  * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
21  *          Xavier Claessens <xclaesse@gmail.com>
22  */
23
24 #include <string.h>
25
26 #include <glade/glade.h>
27 #include <glib/gi18n.h>
28
29 #include <telepathy-glib/enums.h>
30
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>
35
36 #include "empathy-call-window.h"
37
38 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
39 #include <libempathy/empathy-debug.h>
40
41 typedef struct
42 {
43   EmpathyTpCall *call;
44   GTimeVal start_time;
45   guint timeout_event_id;
46   gboolean is_drawing;
47   guint status; 
48
49   GtkWidget *window;
50   GtkWidget *main_hbox;
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;
61   GtkWidget *keypad_expander;
62 } EmpathyCallWindow;
63
64 static GSList *windows = NULL;
65
66 static gboolean
67 call_window_update_timer (gpointer data)
68 {
69   EmpathyCallWindow *window = data;
70   GTimeVal current;
71   gchar *str;
72   glong now, then;
73   glong time, seconds, minutes, hours;
74
75   g_get_current_time (&current);
76
77   now = current.tv_sec;
78   then = (window->start_time).tv_sec;
79
80   time = now - then;
81
82   seconds = time % 60;
83   time /= 60;
84   minutes = time % 60;
85   time /= 60;
86   hours = time % 60;
87
88   if (hours > 0)
89       str = g_strdup_printf ("Connected  -  %02ld : %02ld : %02ld", hours,
90           minutes, seconds);
91   else
92       str = g_strdup_printf ("Connected  -  %02ld : %02ld", minutes, seconds);
93
94   gtk_label_set_text (GTK_LABEL (window->status_label), str);
95
96   g_free (str);
97
98   return TRUE;
99 }
100
101 static void
102 call_window_stop_timeout (EmpathyCallWindow *window)
103 {
104   DEBUG ("Timer stopped");
105
106   if (window->timeout_event_id)
107     {
108       g_source_remove (window->timeout_event_id);
109       window->timeout_event_id = 0;
110     }
111 }
112
113 static void
114 call_window_set_output_video_is_drawing (EmpathyCallWindow *window,
115                                          gboolean is_drawing)
116 {
117   DEBUG ("Setting output video is drawing - %d", is_drawing);
118
119   if (is_drawing && !window->is_drawing)
120     {
121       gtk_window_set_resizable (GTK_WINDOW (window->window), TRUE);
122       gtk_box_pack_end (GTK_BOX (window->main_hbox),
123           window->output_video_socket, TRUE, TRUE, 0);
124       empathy_tp_call_add_output_video (window->call,
125           gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
126     }
127   if (!is_drawing && window->is_drawing)
128     {
129       gtk_window_set_resizable (GTK_WINDOW (window->window), FALSE);
130       empathy_tp_call_add_output_video (window->call, 0);
131       gtk_container_remove (GTK_CONTAINER (window->main_hbox),
132           window->output_video_socket);
133     }
134
135   window->is_drawing = is_drawing;
136 }
137
138 static void
139 call_window_finalize (EmpathyCallWindow *window)
140 {
141   gtk_label_set_text (GTK_LABEL (window->status_label), _("Closed"));
142   gtk_widget_set_sensitive (window->hang_up_button, FALSE);
143   gtk_widget_set_sensitive (window->video_button, FALSE);
144   gtk_widget_set_sensitive (window->output_volume_button, FALSE);
145   gtk_widget_set_sensitive (window->input_volume_button, FALSE);
146   gtk_widget_set_sensitive (window->keypad_expander, FALSE);
147
148   if (window->call)
149     { 
150       call_window_stop_timeout (window);
151       call_window_set_output_video_is_drawing (window, FALSE);
152       empathy_tp_call_remove_preview_video (window->call,
153           gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
154       g_object_unref (window->call);
155       window->call = NULL;
156     }
157
158   if (window->confirmation_dialog)
159       gtk_widget_destroy (window->confirmation_dialog);
160 }
161
162 static void
163 call_window_socket_realized_cb (GtkWidget *widget,
164                                 EmpathyCallWindow *window)
165 {
166   if (widget == window->preview_video_socket)
167     {
168       DEBUG ("Preview socket realized");
169       empathy_tp_call_add_preview_video (window->call,
170           gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
171     }
172   else
173       DEBUG ("Output socket realized");
174 }
175
176 static void
177 call_window_video_button_toggled_cb (GtkWidget *button,
178                                      EmpathyCallWindow *window)
179 {
180   gboolean is_sending;
181   guint status;
182
183   is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
184
185   DEBUG ("Send video toggled - %d", is_sending);
186
187   g_object_get (window->call, "status", &status, NULL);
188   if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
189       empathy_tp_call_request_video_stream_direction (window->call, is_sending);
190 }
191
192 static void
193 call_window_hang_up_button_clicked_cb (GtkWidget *widget,
194                                        EmpathyCallWindow *window)
195 {
196   DEBUG ("Call clicked, end call");
197   call_window_finalize (window);
198 }
199
200 static void
201 call_window_output_volume_changed_cb (GtkScaleButton *button,
202                                       gdouble value,
203                                       EmpathyCallWindow *window)
204 {
205   if (!window->call)
206       return;
207
208   if (value <= 0)
209       empathy_tp_call_mute_output (window->call, TRUE);
210   else
211     {
212       empathy_tp_call_mute_output (window->call, FALSE);
213       empathy_tp_call_set_output_volume (window->call, value * 100);
214     }
215 }
216
217 static void
218 call_window_input_volume_changed_cb (GtkScaleButton    *button,
219                                      gdouble            value,
220                                      EmpathyCallWindow *window)
221 {
222   if (!window->call)
223       return;
224
225   if (value <= 0)
226       empathy_tp_call_mute_input (window->call, TRUE);
227   else
228     {
229       empathy_tp_call_mute_input (window->call, FALSE);
230       /* FIXME: Not implemented?
231       empathy_tp_call_set_input_volume (window->call, value * 100);*/
232     }
233 }
234
235 static gboolean
236 call_window_delete_event_cb (GtkWidget *widget,
237                              GdkEvent *event,
238                              EmpathyCallWindow *window)
239 {
240   GtkWidget *dialog;
241   gint result;
242   guint status = EMPATHY_TP_CALL_STATUS_CLOSED;
243
244   DEBUG ("Delete event occurred");
245
246   if (window->call)
247       g_object_get (window->call, "status", &status, NULL);
248
249   if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
250     {
251       dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
252           GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
253           GTK_MESSAGE_WARNING, GTK_BUTTONS_CANCEL, _("End this call?"));
254       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
255           _("Closing this window will end the call in progress."));
256       gtk_dialog_add_button (GTK_DIALOG (dialog), _("_End Call"), GTK_RESPONSE_OK);
257       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
258
259       result = gtk_dialog_run (GTK_DIALOG (dialog));
260       gtk_widget_destroy (dialog);
261
262       if (result != GTK_RESPONSE_OK)
263           return TRUE;
264     }
265
266   return FALSE;
267 }
268
269 static void
270 call_window_destroy_cb (GtkWidget *widget,
271                         EmpathyCallWindow *window)
272 {
273   call_window_finalize (window);
274
275   g_object_unref (window->output_video_socket);
276   g_object_unref (window->preview_video_socket);
277
278   windows = g_slist_remove (windows, window);
279   g_slice_free (EmpathyCallWindow, window);
280 }
281
282 static void
283 call_window_confirmation_dialog_response_cb (GtkDialog *dialog,
284                                              gint response,
285                                              EmpathyCallWindow *window)
286 {
287   if (response == GTK_RESPONSE_OK && window->call)
288       empathy_tp_call_accept_incoming_call (window->call);
289   else
290       call_window_finalize (window);
291
292   gtk_widget_destroy (window->confirmation_dialog);
293   window->confirmation_dialog = NULL;
294 }
295
296 static void
297 call_window_show_confirmation_dialog (EmpathyCallWindow *window)
298 {
299   EmpathyContact *contact;
300   GtkWidget *button;
301   GtkWidget *image;
302
303   if (window->confirmation_dialog)
304       return;
305
306   g_object_get (window->call, "contact", &contact, NULL);
307
308   window->confirmation_dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
309       GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
310       GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Incoming call"));
311   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (window->confirmation_dialog),
312       _("%s is calling you, do you want to answer?"),
313       empathy_contact_get_name (contact));
314   gtk_dialog_set_default_response (GTK_DIALOG (window->confirmation_dialog),
315       GTK_RESPONSE_OK);
316
317   button = gtk_dialog_add_button (GTK_DIALOG (window->confirmation_dialog),
318       _("_Reject"), GTK_RESPONSE_CANCEL);
319   image = gtk_image_new_from_icon_name (GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
320   gtk_button_set_image (GTK_BUTTON (button), image);
321
322   button = gtk_dialog_add_button (GTK_DIALOG (window->confirmation_dialog),
323       _("_Answer"), GTK_RESPONSE_OK);
324   image = gtk_image_new_from_icon_name (GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON);
325   gtk_button_set_image (GTK_BUTTON (button), image);
326
327   g_signal_connect (window->confirmation_dialog, "response",
328       G_CALLBACK (call_window_confirmation_dialog_response_cb),
329       window);
330
331   gtk_widget_show (window->confirmation_dialog);
332   g_object_unref (contact);
333 }
334
335 static void
336 call_window_update (EmpathyCallWindow *window)
337 {
338   EmpathyContact *contact;
339   guint stream_state;
340   EmpathyTpCallStream *audio_stream;
341   EmpathyTpCallStream *video_stream;
342   gboolean is_incoming;
343   gchar *title;
344
345   g_object_get (window->call,
346       "status", &window->status,
347       "audio-stream", &audio_stream,
348       "video-stream", &video_stream,
349       "contact", &contact,
350       "is-incoming", &is_incoming,
351       NULL);
352
353   if (video_stream->state > audio_stream->state)
354       stream_state = video_stream->state;
355   else
356       stream_state = audio_stream->state;
357
358   DEBUG ("Status changed - status: %d, stream state: %d, "
359       "is-incoming: %d video-stream direction: %d",
360       window->status, stream_state, is_incoming, video_stream->direction);
361
362   if (empathy_tp_call_has_dtmf (window->call))
363     {
364       gtk_widget_show (window->keypad_expander);
365     }
366   else
367     {
368       gtk_widget_hide (window->keypad_expander);
369     }
370
371   /* Depending on the status we have to set:
372    * - window's title
373    * - status's label
374    * - sensibility of all buttons
375    * */
376   if (window->status == EMPATHY_TP_CALL_STATUS_READYING)
377     {
378       gtk_window_set_title (GTK_WINDOW (window->window), _("Empathy Call"));
379       /* To translators: Readying is the first state of the call, it is
380        * preparing the connection and it does not yet ring. */
381       gtk_label_set_text (GTK_LABEL (window->status_label), _("Readying"));
382       gtk_widget_set_sensitive (window->video_button, FALSE);
383       gtk_widget_set_sensitive (window->output_volume_button, FALSE);
384       gtk_widget_set_sensitive (window->input_volume_button, FALSE);
385       gtk_widget_set_sensitive (window->hang_up_button, FALSE);
386       gtk_widget_set_sensitive (window->keypad_expander, FALSE);
387     }
388   else if (window->status == EMPATHY_TP_CALL_STATUS_PENDING)
389     {
390       title = g_strdup_printf (_("%s - Empathy Call"),
391           empathy_contact_get_name (contact));
392
393       gtk_window_set_title (GTK_WINDOW (window->window), title);
394       gtk_label_set_text (GTK_LABEL (window->status_label), _("Ringing"));
395       gtk_widget_set_sensitive (window->hang_up_button, TRUE);
396       if (is_incoming)
397           call_window_show_confirmation_dialog (window);
398     }
399   else if (window->status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
400     {
401       gboolean receiving_video;
402       gboolean sending_video;
403
404       if (stream_state == TP_MEDIA_STREAM_STATE_DISCONNECTED)
405           gtk_label_set_text (GTK_LABEL (window->status_label), _("Disconnected"));
406       if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTING)
407           gtk_label_set_text (GTK_LABEL (window->status_label), _("Connecting"));
408       else if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTED &&
409                window->timeout_event_id == 0)
410         {
411           /* The call started, launch the timer */
412           g_get_current_time (&(window->start_time));
413           window->timeout_event_id = g_timeout_add_seconds (1,
414               call_window_update_timer, window);
415           call_window_update_timer (window);
416         }
417
418       receiving_video = video_stream->direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE;
419       sending_video = video_stream->direction & TP_MEDIA_STREAM_DIRECTION_SEND;
420       call_window_set_output_video_is_drawing (window, receiving_video);
421       g_signal_handlers_block_by_func (window->video_button,
422           call_window_video_button_toggled_cb, window);
423       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->video_button),
424           sending_video);
425       g_signal_handlers_unblock_by_func (window->video_button,
426           call_window_video_button_toggled_cb, window);
427
428       gtk_widget_set_sensitive (window->video_button, TRUE);
429       gtk_widget_set_sensitive (window->output_volume_button, TRUE);
430       gtk_widget_set_sensitive (window->input_volume_button, TRUE);
431       gtk_widget_set_sensitive (window->hang_up_button, TRUE);
432       gtk_widget_set_sensitive (window->keypad_expander, TRUE);
433     }
434   else if (window->status == EMPATHY_TP_CALL_STATUS_CLOSED)
435       call_window_finalize (window);
436
437   if (contact)
438       g_object_unref (contact);
439 }
440
441 static gboolean
442 call_window_dtmf_button_release_event_cb (GtkWidget *widget,
443                                           GdkEventButton *event,
444                                           EmpathyCallWindow *window)
445 {
446   empathy_tp_call_stop_tone (window->call);
447   return FALSE;
448 }
449
450 static gboolean
451 call_window_dtmf_button_press_event_cb (GtkWidget *widget,
452                                         GdkEventButton *event,
453                                         EmpathyCallWindow *window)
454 {
455   TpDTMFEvent dtmf_event;
456
457   dtmf_event = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "code"));
458   empathy_tp_call_start_tone (window->call, dtmf_event);
459   return FALSE;
460 }
461
462 static void
463 call_window_dtmf_connect (GladeXML *glade,
464                           EmpathyCallWindow *window,
465                           const gchar *name,
466                           TpDTMFEvent event)
467 {
468   GtkWidget *widget;
469
470   widget = glade_xml_get_widget (glade, name);
471   g_object_set_data (G_OBJECT (widget), "code", GUINT_TO_POINTER (event));
472   g_signal_connect (widget, "button-press-event",
473       G_CALLBACK (call_window_dtmf_button_press_event_cb), window);
474   g_signal_connect (widget, "button-release-event",
475       G_CALLBACK (call_window_dtmf_button_release_event_cb), window);
476   /* FIXME: Connect "key-[press/release]-event" to*/
477 }
478
479 GtkWidget *
480 empathy_call_window_new (TpChannel *channel)
481 {
482   EmpathyCallWindow *window;
483   GladeXML *glade;
484   gchar *filename;
485   const gchar *icons[] = {"audio-input-microphone", NULL};
486
487   g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL);
488
489   if (windows)
490     {
491       window = (EmpathyCallWindow*) windows->data;
492       if (!window->call)
493         {
494           window->call = empathy_tp_call_new (channel);
495           g_signal_connect_swapped (G_OBJECT (window->call), "notify",
496               G_CALLBACK (call_window_update), window);
497           call_window_update (window);
498
499           if (GTK_WIDGET_REALIZED (GTK_WIDGET (window->preview_video_socket)))
500             {
501               call_window_socket_realized_cb (window->preview_video_socket,
502                   window);
503             }
504         }
505       else
506         {
507           GtkWidget *dialog;
508           EmpathyContact *contact;
509
510           g_object_get (window->call, "contact", &contact, NULL);
511
512           /* We don't want to have multiple calls running.
513            * FIXME: We should use the hold interface... */
514           tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
515
516           dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_INFO,
517               GTK_BUTTONS_CLOSE,
518               _("Incoming call from %s rejected because there is already a"
519                 " running call."), empathy_contact_get_name (contact));
520
521           g_object_unref (contact);
522
523           g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy),
524               NULL);
525           gtk_widget_show (dialog);
526         }
527
528       gtk_window_present (GTK_WINDOW (window->window));
529       return window->window;
530     }
531
532   window = g_slice_new0 (EmpathyCallWindow);
533   windows = g_slist_prepend (windows, window);
534   window->call = empathy_tp_call_new (channel);
535
536   filename = empathy_file_lookup ("empathy-call-window.glade", "src");
537   glade = empathy_glade_get_file (filename,
538       "window",
539       NULL,
540       "window", &window->window,
541       "main_hbox", &window->main_hbox,
542       "controls_vbox", &window->controls_vbox,
543       "volume_hbox", &window->volume_hbox,
544       "status_label", &window->status_label,
545       "video_button", &window->video_button,
546       "hang_up_button", &window->hang_up_button,
547       "keypad_expander", &window->keypad_expander,
548       NULL);
549   g_free (filename);
550
551   empathy_glade_connect (glade,
552       window,
553       "window", "destroy", call_window_destroy_cb,
554       "window", "delete_event", call_window_delete_event_cb,
555       "hang_up_button", "clicked", call_window_hang_up_button_clicked_cb,
556       "video_button", "toggled", call_window_video_button_toggled_cb,
557       NULL);
558
559   /* Setup DTMF buttons */
560   call_window_dtmf_connect (glade, window, "button_0", TP_DTMF_EVENT_DIGIT_0);
561   call_window_dtmf_connect (glade, window, "button_1", TP_DTMF_EVENT_DIGIT_1);
562   call_window_dtmf_connect (glade, window, "button_2", TP_DTMF_EVENT_DIGIT_2);
563   call_window_dtmf_connect (glade, window, "button_3", TP_DTMF_EVENT_DIGIT_3);
564   call_window_dtmf_connect (glade, window, "button_4", TP_DTMF_EVENT_DIGIT_4);
565   call_window_dtmf_connect (glade, window, "button_5", TP_DTMF_EVENT_DIGIT_5);
566   call_window_dtmf_connect (glade, window, "button_6", TP_DTMF_EVENT_DIGIT_6);
567   call_window_dtmf_connect (glade, window, "button_7", TP_DTMF_EVENT_DIGIT_7);
568   call_window_dtmf_connect (glade, window, "button_8", TP_DTMF_EVENT_DIGIT_8);
569   call_window_dtmf_connect (glade, window, "button_9", TP_DTMF_EVENT_DIGIT_9);
570   call_window_dtmf_connect (glade, window, "button_asterisk", TP_DTMF_EVENT_ASTERISK);
571   call_window_dtmf_connect (glade, window, "button_hash", TP_DTMF_EVENT_HASH);
572
573   g_object_unref (glade);
574
575   /* Output volume button */
576   window->output_volume_button = gtk_volume_button_new ();
577   gtk_scale_button_set_value (GTK_SCALE_BUTTON (window->output_volume_button), 1);
578   gtk_box_pack_start (GTK_BOX (window->volume_hbox),
579       window->output_volume_button, FALSE, FALSE, 0);
580   gtk_widget_show (window->output_volume_button);
581   g_signal_connect (window->output_volume_button, "value-changed",
582       G_CALLBACK (call_window_output_volume_changed_cb), window);
583
584   /* Input volume button */
585   window->input_volume_button = gtk_volume_button_new ();
586   gtk_scale_button_set_icons (GTK_SCALE_BUTTON (window->input_volume_button),
587       icons);
588   gtk_scale_button_set_value (GTK_SCALE_BUTTON (window->input_volume_button), 1);
589   gtk_box_pack_start (GTK_BOX (window->volume_hbox),
590       window->input_volume_button, FALSE, FALSE, 0);
591   gtk_widget_show (window->input_volume_button);
592   g_signal_connect (window->input_volume_button, "value-changed",
593       G_CALLBACK (call_window_input_volume_changed_cb), window);
594
595   /* Output video socket */
596   window->output_video_socket = g_object_ref (gtk_socket_new ());
597   gtk_widget_set_size_request (window->output_video_socket, 400, 300);
598   g_signal_connect (GTK_OBJECT (window->output_video_socket), "realize",
599       G_CALLBACK (call_window_socket_realized_cb), window);
600   gtk_widget_show (window->output_video_socket);
601
602   /* Preview video socket */
603   window->preview_video_socket = g_object_ref (gtk_socket_new ());
604   gtk_widget_set_size_request (window->preview_video_socket, 176, 144);
605   g_signal_connect (GTK_OBJECT (window->preview_video_socket), "realize",
606       G_CALLBACK (call_window_socket_realized_cb), window);
607   gtk_widget_show (window->preview_video_socket);
608
609   /* FIXME: We shouldn't do this if there is no video input */
610   gtk_box_pack_start (GTK_BOX (window->controls_vbox),
611       window->preview_video_socket, FALSE, FALSE, 0);
612   gtk_box_reorder_child (GTK_BOX (window->controls_vbox),
613       window->preview_video_socket, 0);
614
615   g_signal_connect_swapped (G_OBJECT (window->call), "notify",
616       G_CALLBACK (call_window_update),
617       window);
618
619   call_window_update (window);
620   gtk_widget_show (window->window);
621
622   return window->window;
623 }
624