]> sjero.net Git - linphone/blob - gtk/main.c
Option to store auth_info in linphonerc
[linphone] / gtk / main.c
1 /*
2 linphone, gtk-glade interface.
3 Copyright (C) 2008  Simon MORLAT (simon.morlat@linphone.org)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20
21 #define VIDEOSELFVIEW_DEFAULT 0
22
23 #include "linphone.h"
24 #include "lpconfig.h"
25
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30
31 #ifdef HAVE_GTK_OSX
32 #include <gtkosxapplication.h>
33 #endif
34
35 #ifdef WIN32
36 #define chdir _chdir
37 #endif
38
39 #if defined(HAVE_NOTIFY1) || defined(HAVE_NOTIFY4)
40 #define HAVE_NOTIFY
41 #endif
42
43 #ifdef HAVE_NOTIFY
44 #include <libnotify/notify.h>
45 #endif
46
47 #define LINPHONE_ICON "linphone.png"
48
49 const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
50
51 static LinphoneCore *the_core=NULL;
52 static GtkWidget *the_ui=NULL;
53
54 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
55 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
56 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
57 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
58 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
59 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
60 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
61 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
62 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
63 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
64 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
65 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate);
66 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
67 void linphone_gtk_status_icon_set_blinking(gboolean val);
68 void _linphone_gtk_enable_video(gboolean val);
69
70
71
72 static gboolean verbose=0;
73 static gboolean auto_answer = 0;
74 static gchar * addr_to_call = NULL;
75 static gboolean no_video=FALSE;
76 static gboolean iconified=FALSE;
77 static gchar *workingdir=NULL;
78 static char *progpath=NULL;
79 gchar *linphone_logfile=NULL;
80 static gboolean workaround_gtk_entry_chinese_bug=FALSE;
81
82 static GOptionEntry linphone_options[]={
83         {
84                 .long_name="verbose",
85                 .short_name= '\0',
86                 .arg=G_OPTION_ARG_NONE,
87                 .arg_data= (gpointer)&verbose,
88                 .description=N_("log to stdout some debug information while running.")
89         },
90         {
91             .long_name = "logfile",
92             .short_name = 'l',
93             .arg = G_OPTION_ARG_STRING,
94             .arg_data = &linphone_logfile,
95             .description = N_("path to a file to write logs into.")
96         },
97         {
98             .long_name = "no-video",
99             .short_name = '\0',
100             .arg = G_OPTION_ARG_NONE,
101             .arg_data = (gpointer)&no_video,
102             .description = N_("Start linphone with video disabled.")
103         },
104         {
105                 .long_name="iconified",
106                 .short_name= '\0',
107                 .arg=G_OPTION_ARG_NONE,
108                 .arg_data= (gpointer)&iconified,
109                 .description=N_("Start only in the system tray, do not show the main interface.")
110         },
111         {
112             .long_name = "call",
113             .short_name = 'c',
114             .arg = G_OPTION_ARG_STRING,
115             .arg_data = &addr_to_call,
116             .description = N_("address to call right now")
117         },
118         {
119             .long_name = "auto-answer",
120             .short_name = 'a',
121             .arg = G_OPTION_ARG_NONE,
122             .arg_data = (gpointer) & auto_answer,
123             .description = N_("if set automatically answer incoming calls")
124         },
125         {
126             .long_name = "workdir",
127             .short_name = '\0',
128             .arg = G_OPTION_ARG_STRING,
129             .arg_data = (gpointer) & workingdir,
130             .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
131         },
132         {0}
133 };
134
135 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
136 #define RELATIVE_XML_DIR
137 #define BUILD_TREE_XML_DIR "gtk"
138
139 #ifndef WIN32
140 #define CONFIG_FILE ".linphonerc"
141 #define SECRETS_FILE ".linphone-zidcache"
142 #else
143 #define CONFIG_FILE "linphonerc"
144 #define SECRETS_FILE "linphone-zidcache"
145 #endif
146
147 char *linphone_gtk_get_config_file(const char *filename){
148         const int path_max=1024;
149         char *config_file=g_malloc0(path_max);
150         if (filename==NULL) filename=CONFIG_FILE;
151         /*try accessing a local file first if exists*/
152         if (access(CONFIG_FILE,F_OK)==0){
153                 snprintf(config_file,path_max,"%s",filename);
154         }else{
155 #ifdef WIN32
156                 const char *appdata=getenv("APPDATA");
157                 if (appdata){
158                         snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
159                         CreateDirectory(config_file,NULL);
160                         snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename);
161                 }
162 #else
163                 const char *home=getenv("HOME");
164                 if (home==NULL) home=".";
165                 snprintf(config_file,path_max,"%s/%s",home,filename);
166 #endif
167         }
168         return config_file;
169 }
170
171 #define FACTORY_CONFIG_FILE "linphonerc.factory"
172 static char _factory_config_file[1024];
173 static const char *linphone_gtk_get_factory_config_file(){
174         /*try accessing a local file first if exists*/
175         if (access(FACTORY_CONFIG_FILE,F_OK)==0){
176                 snprintf(_factory_config_file,sizeof(_factory_config_file),
177                                                  "%s",FACTORY_CONFIG_FILE);
178         } else {
179                 char *progdir;
180
181                 if (progpath != NULL) {
182                         char *basename;
183                         progdir = strdup(progpath);
184 #ifdef WIN32
185                         basename = strrchr(progdir, '\\');
186                         if (basename != NULL) {
187                                 basename ++;
188                                 *basename = '\0';
189                                 snprintf(_factory_config_file, sizeof(_factory_config_file),
190                                                                  "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
191                         } else {
192                                 if (workingdir!=NULL) {
193                                         snprintf(_factory_config_file, sizeof(_factory_config_file),
194                                                                          "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
195                                 } else {
196                                         free(progdir);
197                                         return NULL;
198                                 }
199                         }
200 #else
201                         basename = strrchr(progdir, '/');
202                         if (basename != NULL) {
203                                 basename ++;
204                                 *basename = '\0';
205                                 snprintf(_factory_config_file, sizeof(_factory_config_file),
206                                                                  "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
207                         } else {
208                                 free(progdir);
209                                 return NULL;
210                         }
211 #endif
212                         free(progdir);
213                 }
214         }
215         return _factory_config_file;
216 }
217
218 static void linphone_gtk_init_liblinphone(const char *config_file,
219                 const char *factory_config_file) {
220         LinphoneCoreVTable vtable={0};
221         gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
222
223         vtable.call_state_changed=linphone_gtk_call_state_changed;
224         vtable.registration_state_changed=linphone_gtk_registration_state_changed;
225         vtable.notify_presence_recv=linphone_gtk_notify_recv;
226         vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
227         vtable.auth_info_requested=linphone_gtk_auth_info_requested;
228         vtable.display_status=linphone_gtk_display_status;
229         vtable.display_message=linphone_gtk_display_message;
230         vtable.display_warning=linphone_gtk_display_warning;
231         vtable.display_url=linphone_gtk_display_url;
232         vtable.call_log_updated=linphone_gtk_call_log_updated;
233         vtable.text_received=linphone_gtk_text_received;
234         vtable.refer_received=linphone_gtk_refer_received;
235         vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
236         vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
237         vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
238
239         the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
240         //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
241         linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
242         linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
243         linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
244         g_free(secrets_file);
245         linphone_core_enable_video(the_core,TRUE,TRUE);
246         if (no_video) {
247                 _linphone_gtk_enable_video(FALSE);
248                 linphone_gtk_set_ui_config_int("videoselfview",0);
249         }
250 }
251
252 LinphoneCore *linphone_gtk_get_core(void){
253         return the_core;
254 }
255
256 GtkWidget *linphone_gtk_get_main_window(){
257         return the_ui;
258 }
259
260 void linphone_gtk_destroy_main_window() {
261         linphone_gtk_destroy_window(the_ui);    
262         the_ui = NULL;
263 }
264
265 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
266         static const char *icon_path=NULL;
267         static const char *hiddens=NULL;
268         static const char *shown=NULL;
269         static bool_t config_loaded=FALSE;
270         if (linphone_gtk_get_core()==NULL) return;
271         if (config_loaded==FALSE){
272                 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
273                 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
274                 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
275                 config_loaded=TRUE;
276         }
277         if (hiddens)
278                 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
279         if (shown)
280                 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
281         if (icon_path) {
282                 GdkPixbuf *pbuf=create_pixbuf(icon_path);
283                 if(pbuf != NULL) {
284                         gtk_window_set_icon(GTK_WINDOW(w),pbuf);
285                         g_object_unref(G_OBJECT(pbuf));
286                 }
287         }
288 }
289
290 static int get_ui_file(const char *name, char *path, int pathsize){
291         snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
292         if (access(path,F_OK)!=0){
293                 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
294                 if (access(path,F_OK)!=0){
295                         g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,
296                                 INSTALLED_XML_DIR,name);
297                         return -1;
298                 }
299         }
300         return 0;
301 }
302
303 void linphone_gtk_destroy_window(GtkWidget *widget) {
304         GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder");
305         gtk_widget_destroy(widget);
306         g_object_unref (G_OBJECT (builder));
307 }
308
309 GtkWidget *linphone_gtk_create_window(const char *window_name){
310         GError* error = NULL;
311         GtkBuilder* builder = gtk_builder_new ();
312         char path[512];
313         GtkWidget *w;
314
315         if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
316
317         if (!gtk_builder_add_from_file (builder, path, &error)){
318                 g_error("Couldn't load builder file: %s", error->message);
319                 g_error_free (error);
320                 return NULL;
321         }
322         w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
323         if (w==NULL){
324                 g_error("Could not retrieve '%s' window from xml file",window_name);
325                 return NULL;
326         }
327         g_object_set_data(G_OBJECT(w), "builder",builder);
328         gtk_builder_connect_signals(builder,w);
329         linphone_gtk_configure_window(w,window_name);
330         return w;
331 }
332
333 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
334         char path[2048];
335         GtkWidget *w;
336         GtkBuilder* builder = gtk_builder_new ();
337         GError *error=NULL;
338         gchar *object_ids[2];
339         object_ids[0]=g_strdup(widget_name);
340         object_ids[1]=NULL;
341
342         if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
343         if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
344                 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
345                 g_error_free (error);
346                 g_free(object_ids[0]);
347                 return NULL;
348         }
349         g_free(object_ids[0]);
350         w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
351         if (w==NULL){
352                 g_error("Could not retrieve '%s' window from xml file",widget_name);
353                 return NULL;
354         }
355         g_object_set_data(G_OBJECT(w),"builder",builder);
356         g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
357         gtk_builder_connect_signals(builder,w);
358         return w;
359 }
360
361 static void entry_unmapped(GtkWidget *entry){
362         g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
363         gtk_widget_unrealize(entry);
364 }
365
366 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
367         GtkBuilder *builder;
368         GObject *w;
369         if (window==NULL) return NULL;
370         builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
371         if (builder==NULL){
372                 g_error("Fail to retrieve builder from window !");
373                 return NULL;
374         }
375         w=gtk_builder_get_object(builder,name);
376         if (w==NULL){
377                 g_error("No widget named %s found in xml interface.",name);
378         }
379         if (workaround_gtk_entry_chinese_bug){
380                 if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
381                         if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
382                                 g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
383                                 g_message("%s is a GtkEntry",name);
384                                 g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
385                         }
386                 }
387         }
388         return GTK_WIDGET(w);
389 }
390
391
392 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
393         GtkWidget *dialog;
394         GtkWidget *main_window=linphone_gtk_get_main_window();
395
396         gtk_widget_show(main_window);
397         if (type==GTK_MESSAGE_QUESTION)
398         {
399                 /* draw a question box. link to dialog_click callback */
400                 dialog = gtk_message_dialog_new (
401                                 GTK_WINDOW(main_window),
402                                 GTK_DIALOG_DESTROY_WITH_PARENT,
403                                 GTK_MESSAGE_QUESTION,
404                                 GTK_BUTTONS_YES_NO,
405                                 "%s",
406                                 (const gchar*)message);
407                 /* connect to some callback : REVISIT */
408                 /*
409                 g_signal_connect_swapped (G_OBJECT (dialog), "response",
410                            G_CALLBACK (dialog_click),
411                            G_OBJECT (dialog));
412                 */
413                 /* actually show the box */
414                 gtk_widget_show(dialog);
415         }
416         else
417         {
418                 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
419                                   GTK_DIALOG_DESTROY_WITH_PARENT,
420                                   type,
421                                   GTK_BUTTONS_CLOSE,
422                                   "%s",
423                                   (const gchar*)message);
424                 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
425                 g_signal_connect_swapped (G_OBJECT (dialog), "response",
426                            G_CALLBACK (gtk_widget_destroy),
427                            G_OBJECT (dialog));
428                 gtk_widget_show(dialog);
429         }
430 }
431
432 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
433         if (id==GTK_RESPONSE_CANCEL){
434                 gtk_widget_destroy(GTK_WIDGET(dialog));
435         }
436 }
437
438 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
439         g_message("About url clicked");
440         linphone_gtk_open_browser(url);
441 }
442
443 void linphone_gtk_show_about(){
444         struct stat filestat;
445         const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
446         GtkWidget *about;
447         const char *tmp;
448         GdkPixbuf *logo=create_pixbuf(
449             linphone_gtk_get_ui_config("logo","linphone-banner.png"));
450         static const char *defcfg="defcfg";
451
452         about=linphone_gtk_create_window("about");
453         gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
454         memset(&filestat,0,sizeof(filestat));
455         if (stat(license_file,&filestat)!=0){
456                 license_file="COPYING";
457                 stat(license_file,&filestat);
458         }
459         if (filestat.st_size>0){
460                 char *license=g_malloc(filestat.st_size+1);
461                 FILE *f=fopen(license_file,"r");
462                 if (f && fread(license,filestat.st_size,1,f)==1){
463                         license[filestat.st_size]='\0';
464                         gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
465                 }
466                 g_free(license);
467         }
468         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
469         gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
470         gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
471         if (logo)       gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
472         tmp=linphone_gtk_get_ui_config("artists",defcfg);
473         if (tmp!=defcfg){
474                 const char *tmp2[2];
475                 tmp2[0]=tmp;
476                 tmp2[1]=NULL;
477                 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
478         }
479         tmp=linphone_gtk_get_ui_config("translators",defcfg);
480         if (tmp!=defcfg)
481                 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
482         tmp=linphone_gtk_get_ui_config("comments",defcfg);
483         if (tmp!=defcfg)
484                 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
485         gtk_widget_show(about);
486 }
487
488 static void set_video_window_decorations(GdkWindow *w){
489         const char *title=linphone_gtk_get_ui_config("title","Linphone");
490         const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
491         char video_title[256];
492         GdkPixbuf *pbuf=create_pixbuf(icon_path);
493
494         if (!linphone_core_in_call(linphone_gtk_get_core())){
495                 snprintf(video_title,sizeof(video_title),"%s video",title);
496                 /* When not in call, treat the video as a normal window */
497                 gdk_window_set_keep_above(w, FALSE);
498         }else{
499                 LinphoneAddress *uri =
500                         linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
501                 char *display_name;
502
503                 linphone_address_clean(uri);
504                 if (linphone_address_get_display_name(uri)!=NULL){
505                         display_name=ms_strdup(linphone_address_get_display_name(uri));
506                 }else{
507                         display_name=linphone_address_as_string(uri);
508                 }
509                 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
510                 linphone_address_destroy(uri);
511                 ms_free(display_name);
512
513                 /* During calls, bring up the video window, arrange so that
514                 it is above all the other windows */
515                 gdk_window_deiconify(w);
516                 gdk_window_set_keep_above(w,TRUE);
517                 /* Maybe we should have the following, but then we want to
518                 have a timer that turns it off after a little while. */
519                 /* gdk_window_set_urgency_hint(w,TRUE); */
520         }
521         gdk_window_set_title(w,video_title);
522         /* Refrain the video window to be closed at all times. */
523         gdk_window_set_functions(w,
524                                  GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
525                                  GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
526         if (pbuf){
527                 GList *l=NULL;
528                 l=g_list_append(l,pbuf);
529                 gdk_window_set_icon_list(w,l);
530                 g_list_free(l);
531                 g_object_unref(G_OBJECT(pbuf));
532         }
533 }
534
535 static gboolean video_needs_update=FALSE;
536
537 static void update_video_title(){
538         video_needs_update=TRUE;
539 }
540
541 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
542         static gboolean first_time=TRUE;
543         unsigned long id;
544         static unsigned long previd=0;
545         static unsigned long preview_previd=0;
546         static gboolean in_iterate=FALSE;
547
548         /*avoid reentrancy*/
549         if (in_iterate) return TRUE;
550         in_iterate=TRUE;
551         linphone_core_iterate(lc);
552         if (first_time){
553                 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
554                 linphone_gtk_show_directory_search();
555                 first_time=FALSE;
556         }
557
558         id=linphone_core_get_native_video_window_id(lc);
559         if (id!=previd || video_needs_update){
560                 GdkWindow *w;
561                 previd=id;
562                 if (id!=0){
563                         ms_message("Updating window decorations");
564 #ifndef WIN32
565                         w=gdk_window_foreign_new(id);
566 #else
567                         w=gdk_window_foreign_new((HANDLE)id);
568 #endif
569                         if (w) {
570                                 set_video_window_decorations(w);
571                                 g_object_unref(G_OBJECT(w));
572                         }
573                         else ms_error("gdk_window_foreign_new() failed");
574                         if (video_needs_update) video_needs_update=FALSE;
575                 }
576         }
577         id=linphone_core_get_native_preview_window_id (lc);
578         if (id!=preview_previd ){
579                 GdkWindow *w;
580                 preview_previd=id;
581                 if (id!=0){
582                         ms_message("Updating window decorations for preview");
583 #ifndef WIN32
584                         w=gdk_window_foreign_new(id);
585 #else
586                         w=gdk_window_foreign_new((HANDLE)id);
587 #endif
588                         if (w) {
589                                 set_video_window_decorations(w);
590                                 g_object_unref(G_OBJECT(w));
591                         }
592                         else ms_error("gdk_window_foreign_new() failed");
593                         if (video_needs_update) video_needs_update=FALSE;
594                 }
595         }
596         if (addr_to_call!=NULL){
597                 /*make sure we are not showing the login screen*/
598                 GtkWidget *mw=linphone_gtk_get_main_window();
599                 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
600                 if (!GTK_WIDGET_VISIBLE(login_frame)){
601                         GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
602                         gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
603                         addr_to_call=NULL;
604                         linphone_gtk_start_call(uri_bar);
605                 }
606         }
607         in_iterate=FALSE;
608         return TRUE;
609 }
610
611 static void load_uri_history(){
612         GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
613         char key[20];
614         int i;
615         GtkEntryCompletion *gep=gtk_entry_completion_new();
616         GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
617         for (i=0;;i++){
618                 const char *uri;
619                 snprintf(key,sizeof(key),"uri%i",i);
620                 uri=linphone_gtk_get_ui_config(key,NULL);
621                 if (uri!=NULL) {
622                         GtkTreeIter iter;
623                         gtk_list_store_append(model,&iter);
624                         gtk_list_store_set(model,&iter,0,uri,-1);
625                         if (i==0) gtk_entry_set_text(uribar,uri);
626                 }
627                 else break;
628         }
629         gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
630         gtk_entry_completion_set_text_column(gep,0);
631         gtk_entry_set_completion(uribar,gep);
632 }
633
634 static void save_uri_history(){
635         LinphoneCore *lc=linphone_gtk_get_core();
636         LpConfig *cfg=linphone_core_get_config(lc);
637         GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
638         char key[20];
639         int i=0;
640         char *uri=NULL;
641         GtkTreeIter iter;
642         GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
643
644         if (!gtk_tree_model_get_iter_first(model,&iter)) return;
645         do {
646                 gtk_tree_model_get(model,&iter,0,&uri,-1);
647                 if (uri) {
648                         snprintf(key,sizeof(key),"uri%i",i);
649                         lp_config_set_string(cfg,"GtkUi",key,uri);
650                         g_free(uri);
651                 }else break;
652                 i++;
653                 if (i>5) break;
654         }while(gtk_tree_model_iter_next(model,&iter));
655         lp_config_sync(cfg);
656 }
657
658 static void completion_add_text(GtkEntry *entry, const char *text){
659         GtkTreeIter iter;
660         GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
661
662         if (gtk_tree_model_get_iter_first(model,&iter)){
663                 do {
664                         gchar *uri=NULL;
665                         gtk_tree_model_get(model,&iter,0,&uri,-1);
666                         if (uri!=NULL){
667                                 if (strcmp(uri,text)==0) {
668                                         /*remove text */
669                                         gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
670                                         g_free(uri);
671                                         break;
672                                 }
673                                 g_free(uri);
674                         }
675                 }while (gtk_tree_model_iter_next(model,&iter));
676         }
677         /* and prepend it on top of the list */
678         gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
679         gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
680         save_uri_history();
681 }
682
683 bool_t linphone_gtk_video_enabled(void){
684         const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
685         return vpol->automatically_accept && vpol->automatically_initiate;
686 }
687
688 void linphone_gtk_show_main_window(){
689         GtkWidget *w=linphone_gtk_get_main_window();
690         LinphoneCore *lc=linphone_gtk_get_core();
691         linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
692                 VIDEOSELFVIEW_DEFAULT));
693         gtk_widget_show(w);
694         gtk_window_present(GTK_WINDOW(w));
695 }
696
697 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
698         GtkWidget *mw=linphone_gtk_get_main_window();
699         if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
700             gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
701         }
702         if (linphone_gtk_use_in_call_view() && call)
703                 linphone_gtk_in_call_view_terminate(call,error);
704         update_video_title();
705 }
706
707 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
708         LinphoneCore *lc=linphone_gtk_get_core();
709         GtkWidget *mw=linphone_gtk_get_main_window();
710         const MSList *calls=linphone_core_get_calls(lc);
711         GtkWidget *button;
712         bool_t start_active=TRUE;
713         //bool_t stop_active=FALSE;
714         bool_t add_call=FALSE;
715         int call_list_size=ms_list_size(calls);
716
717         if (calls==NULL){
718                 start_active=TRUE;
719                 //stop_active=FALSE;
720         }else{
721                 //stop_active=TRUE;
722                 start_active=TRUE;
723                 add_call=TRUE;
724         }
725         button=linphone_gtk_get_widget(mw,"start_call");
726         gtk_widget_set_sensitive(button,start_active);
727         gtk_widget_set_visible(button,!add_call);
728
729         button=linphone_gtk_get_widget(mw,"add_call");
730         if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
731                 gtk_widget_set_sensitive(button,FALSE);
732         } else {
733                 gtk_widget_set_sensitive(button,start_active);
734         }
735         gtk_widget_set_visible(button,add_call);
736
737         //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
738         GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
739         if(conf_frame==NULL){
740                 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
741                 linphone_gtk_enable_conference_button(lc,call_list_size>1);
742         } else {
743                 linphone_gtk_enable_transfer_button(lc,FALSE);
744                 linphone_gtk_enable_conference_button(lc,FALSE);
745         }
746         update_video_title();
747         if (call) linphone_gtk_update_video_button(call);
748 }
749
750 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
751         const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
752         if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
753                 completion_add_text(GTK_ENTRY(uri_bar),entered);
754         }else{
755                 linphone_gtk_call_terminated(NULL,NULL);
756         }
757         return FALSE;
758 }
759
760 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
761         if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
762                 linphone_core_accept_call (linphone_gtk_get_core(),call);
763                 linphone_call_unref(call);
764         }
765         return FALSE;
766 }
767
768 void linphone_gtk_start_call(GtkWidget *w){
769         LinphoneCore *lc=linphone_gtk_get_core();
770         LinphoneCall *call;
771         /*change into in-call mode, then do the work later as it might block a bit */
772         GtkWidget *mw=gtk_widget_get_toplevel(w);
773         GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
774
775         call=linphone_gtk_get_currently_displayed_call(NULL);
776         if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
777                 linphone_core_accept_call(lc,call);
778         }else{
779                 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
780                 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
781                 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
782                 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
783         }
784
785 }
786
787 void linphone_gtk_uri_bar_activate(GtkWidget *w){
788         linphone_gtk_start_call(w);
789 }
790
791 void linphone_gtk_terminate_call(GtkWidget *button){
792         gboolean is_conf;
793         LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
794         if (call){
795                 linphone_core_terminate_call(linphone_gtk_get_core(),call);
796         }else if (is_conf){
797                 linphone_core_terminate_conference(linphone_gtk_get_core());
798         }
799 }
800
801 void linphone_gtk_decline_clicked(GtkWidget *button){
802         LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
803         if (call)
804                 linphone_core_terminate_call(linphone_gtk_get_core(),call);
805 }
806
807 void linphone_gtk_answer_clicked(GtkWidget *button){
808         LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
809         if (call){
810                 linphone_core_accept_call(linphone_gtk_get_core(),call);
811                 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
812         }
813 }
814
815 void _linphone_gtk_enable_video(gboolean val){
816         LinphoneVideoPolicy policy={0};
817         policy.automatically_initiate=policy.automatically_accept=val;
818         linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
819         linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
820
821         if (val){
822                 linphone_core_enable_video_preview(linphone_gtk_get_core(),
823                 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
824         }else{
825                 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
826         }
827 }
828
829 void linphone_gtk_enable_video(GtkWidget *w){
830         gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
831         //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
832         _linphone_gtk_enable_video(val);
833 }
834
835 void linphone_gtk_enable_self_view(GtkWidget *w){
836         gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
837         LinphoneCore *lc=linphone_gtk_get_core();
838         linphone_core_enable_video_preview(lc,val);
839         linphone_core_enable_self_view(lc,val);
840         linphone_gtk_set_ui_config_int("videoselfview",val);
841 }
842
843 void linphone_gtk_used_identity_changed(GtkWidget *w){
844         int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
845         char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
846         if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
847                 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
848                 linphone_gtk_show_directory_search();
849         }
850         if (sel) g_free(sel);
851 }
852
853 void on_proxy_refresh_button_clicked(GtkWidget *w){
854         LinphoneCore *lc=linphone_gtk_get_core();
855         MSList const *item=linphone_core_get_proxy_config_list(lc);
856         while (item != NULL) {
857                 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
858                 linphone_proxy_config_edit(lpc);
859                 linphone_proxy_config_done(lpc);
860                 item = item->next;
861         }
862 }
863
864 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
865         linphone_gtk_show_friends();
866 }
867
868 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
869         switch(response_id){
870                 case GTK_RESPONSE_YES:
871                         linphone_gtk_show_contact(lf);
872                 break;
873                 default:
874                         linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
875         }
876         gtk_widget_destroy(dialog);
877 }
878
879 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
880         GtkWidget *dialog;
881
882         if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
883                 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
884                 return;
885         }
886
887         gchar *message=g_strdup_printf(_("%s would like to add you to his contact list.\nWould you allow him to see your presence status or add him to your contact list ?\nIf you answer no, this person will be temporarily blacklisted."),url);
888         dialog = gtk_message_dialog_new (
889                                 GTK_WINDOW(linphone_gtk_get_main_window()),
890                                 GTK_DIALOG_DESTROY_WITH_PARENT,
891                                 GTK_MESSAGE_QUESTION,
892                                 GTK_BUTTONS_YES_NO,
893                                 "%s",
894                                 message);
895         g_free(message);
896         g_signal_connect(G_OBJECT (dialog), "response",
897                 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
898         /* actually show the box */
899         gtk_widget_show(dialog);
900 }
901
902 typedef struct _AuthTimeout{
903         GtkWidget *w;
904 } AuthTimeout;
905
906 static void auth_timeout_clean(AuthTimeout *tout){
907         tout->w=NULL;
908 }
909
910 static gboolean auth_timeout_destroy(AuthTimeout *tout){
911         if (tout->w)  {
912                 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
913                 gtk_widget_destroy(tout->w);
914         }
915         g_free(tout);
916         return FALSE;
917 }
918
919 static AuthTimeout * auth_timeout_new(GtkWidget *w){
920         AuthTimeout *tout=g_new(AuthTimeout,1);
921         tout->w=w;
922         /*so that the timeout no more references the widget when it is destroyed:*/
923         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
924         /*so that the widget is automatically destroyed after some time */
925         g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
926         return tout;
927 }
928
929 void linphone_gtk_password_cancel(GtkWidget *w){
930         LinphoneAuthInfo *info;
931         GtkWidget *window=gtk_widget_get_toplevel(w);
932         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
933         linphone_core_abort_authentication(linphone_gtk_get_core(),info);
934         gtk_widget_destroy(window);
935 }
936
937 void linphone_gtk_password_ok(GtkWidget *w){
938         GtkWidget *entry;
939         GtkWidget *window=gtk_widget_get_toplevel(w);
940         LinphoneAuthInfo *info;
941         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
942         g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
943         entry=linphone_gtk_get_widget(window,"password_entry");
944         linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
945         linphone_auth_info_set_userid(info,
946                 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
947         linphone_core_add_auth_info(linphone_gtk_get_core(),info);
948         gtk_widget_destroy(window);
949 }
950
951 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
952         GtkWidget *w=linphone_gtk_create_window("password");
953         GtkWidget *label=linphone_gtk_get_widget(w,"message");
954         LinphoneAuthInfo *info;
955         gchar *msg;
956         GtkWidget *mw=linphone_gtk_get_main_window();
957
958         if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
959                 /*don't prompt for authentication when login frame is visible*/
960                 linphone_core_abort_authentication(lc,NULL);
961                 return;
962         }
963
964         msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
965                 username,realm);
966         gtk_label_set_markup(GTK_LABEL(label),msg);
967         g_free(msg);
968         gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
969         info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
970         g_object_set_data(G_OBJECT(w),"auth_info",info);
971         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
972         gtk_widget_show(w);
973         auth_timeout_new(w);
974 }
975
976 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
977         GtkWidget *w=linphone_gtk_get_main_window();
978         GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
979
980         gtk_statusbar_push(GTK_STATUSBAR(status_bar),
981                         gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
982                         status);
983 }
984
985 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
986         linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
987 }
988
989 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
990         linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
991 }
992
993 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
994         char richtext[4096];
995         snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
996         linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
997 }
998
999 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1000         GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1001         if (w) linphone_gtk_call_log_update(w);
1002         linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1003 }
1004
1005 #ifdef HAVE_NOTIFY
1006 static bool_t notify_actions_supported() {
1007         bool_t accepts_actions = FALSE;
1008         GList *capabilities = notify_get_server_caps();
1009         GList *c;
1010         if(capabilities != NULL) {
1011                 for(c = capabilities; c != NULL; c = c->next) {
1012                         if(strcmp((char*)c->data, "actions") == 0 ) {
1013                                 accepts_actions = TRUE;
1014                                 break;
1015                         }
1016                 }
1017                 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1018                 g_list_free(capabilities);
1019         }
1020         return accepts_actions;
1021 }
1022
1023 static NotifyNotification* build_notification(const char *title, const char *body){
1024          return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1025 #ifdef HAVE_NOTIFY1
1026         ,NULL
1027 #endif
1028         );
1029 }
1030
1031 static void show_notification(NotifyNotification* n){
1032         if (n && !notify_notification_show(n,NULL))
1033                 ms_error("Failed to send notification.");
1034 }
1035
1036 static void make_notification(const char *title, const char *body){
1037         show_notification(build_notification(title,body));
1038 }
1039
1040 #endif
1041
1042 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1043 #ifdef HAVE_NOTIFY
1044         if (!notify_is_initted())
1045                 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1046 #endif
1047         if (!call) {
1048
1049 #ifdef HAVE_NOTIFY
1050                 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1051 #ifdef HAVE_NOTIFY1
1052         ,NULL
1053 #endif
1054 ),NULL))
1055
1056                                 ms_error("Failed to send notification.");
1057 #else
1058                 linphone_gtk_show_main_window();
1059 #endif
1060         } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1061 #ifdef HAVE_NOTIFY
1062                 char *body=NULL;
1063                 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1064                 NotifyNotification *n;
1065                 switch(linphone_call_get_state(call)){
1066                         case LinphoneCallError:
1067                                 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
1068                         break;
1069                         case LinphoneCallEnd:
1070                                 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1071                         break;
1072                         case LinphoneCallIncomingReceived:
1073                                 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1074                                 if (notify_actions_supported()) {
1075                                         notify_notification_add_action (n,"answer", _("Answer"),
1076                                                 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1077                                         notify_notification_add_action (n,"decline",_("Decline"),
1078                                                 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1079                                 }
1080                                 show_notification(n);
1081                         break;
1082                         case LinphoneCallPausedByRemote:
1083                                 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<span size=\"large\">by %s</span>"),remote));
1084                         break;
1085                         default:
1086                         break;
1087                 }
1088                 if (body) g_free(body);
1089                 if (remote) g_free(remote);
1090 #endif
1091         }
1092 }
1093
1094 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1095         if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1096                 LinphoneCore *lc=linphone_call_get_core(call);
1097                 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1098                 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1099                 linphone_core_accept_call_update(lc,call,params);
1100                 linphone_call_params_destroy(params);
1101         }
1102         linphone_call_unref(call);
1103         g_source_remove_by_user_data(dialog);
1104         gtk_widget_destroy(dialog);
1105 }
1106
1107 static void on_call_updated_timeout(GtkWidget *dialog){
1108         gtk_widget_destroy(dialog);
1109 }
1110
1111 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1112         LinphoneCore *lc=linphone_call_get_core(call);
1113         const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1114         const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1115         const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1116         gboolean video_requested=linphone_call_params_video_enabled(rparams);
1117         gboolean video_used=linphone_call_params_video_enabled(current_params);
1118         g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1119                   video_used,video_requested,pol->automatically_accept);
1120         if (video_used==FALSE && video_requested && !pol->automatically_accept){
1121                 linphone_core_defer_call_update(lc,call);
1122                 {
1123                         const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1124                         GtkWidget *dialog;
1125                         const char *dname=linphone_address_get_display_name(addr);
1126                         if (dname==NULL) dname=linphone_address_get_username(addr);
1127                         if (dname==NULL) dname=linphone_address_get_domain(addr);
1128                         dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1129                                                                  GTK_DIALOG_DESTROY_WITH_PARENT,
1130                                                                  GTK_MESSAGE_WARNING,
1131                                                                  GTK_BUTTONS_YES_NO,
1132                                                                  _("%s proposed to start video. Do you accept ?"),dname);
1133                         g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1134                         g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1135                         gtk_widget_show(dialog);
1136                 }
1137         }
1138 }
1139
1140 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1141         switch(cs){
1142                 case LinphoneCallOutgoingInit:
1143                         linphone_gtk_create_in_call_view (call);
1144                 break;
1145                 case LinphoneCallOutgoingProgress:
1146                         linphone_gtk_in_call_view_set_calling (call);
1147                 break;
1148                 case LinphoneCallStreamsRunning:
1149                         linphone_gtk_in_call_view_set_in_call(call);
1150                 break;
1151                 case LinphoneCallUpdatedByRemote:
1152                         linphone_gtk_call_updated_by_remote(call);
1153                 break;
1154                 case LinphoneCallError:
1155                         linphone_gtk_in_call_view_terminate (call,msg);
1156                 break;
1157                 case LinphoneCallEnd:
1158                         linphone_gtk_in_call_view_terminate(call,NULL);
1159                         linphone_gtk_status_icon_set_blinking(FALSE);
1160                 break;
1161                 case LinphoneCallIncomingReceived:
1162                         linphone_gtk_create_in_call_view(call);
1163                         linphone_gtk_in_call_view_set_incoming(call);
1164                         linphone_gtk_status_icon_set_blinking(TRUE);
1165                         if (auto_answer)  {
1166                                 linphone_call_ref(call);
1167                                 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1168                         }
1169                 break;
1170                 case LinphoneCallResuming:
1171                         linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1172                         linphone_gtk_in_call_view_set_in_call (call);
1173                 break;
1174                 case LinphoneCallPausing:
1175                         linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1176                         update_tab_header(call,FALSE);
1177                 case LinphoneCallPausedByRemote:
1178                         linphone_gtk_in_call_view_set_paused(call);
1179                         update_tab_header(call,TRUE);
1180                 break;
1181                 case LinphoneCallConnected:
1182                         linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1183                         linphone_gtk_status_icon_set_blinking(FALSE);
1184                 break;
1185                 default:
1186                 break;
1187         }
1188         linphone_gtk_notify(call, msg);
1189         linphone_gtk_update_call_buttons (call);
1190 }
1191
1192 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1193         linphone_gtk_in_call_view_show_encryption(call);
1194 }
1195
1196 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1197         linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1198 }
1199
1200 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1201         GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1202         GtkTreeModel *model=gtk_combo_box_get_model(box);
1203         GtkTreeIter iter;
1204         gboolean found=FALSE;
1205         const char *stock_id=NULL;
1206
1207         if (gtk_tree_model_get_iter_first(model,&iter)){
1208                 gpointer p;
1209                 do{
1210                         gtk_tree_model_get(model,&iter,2,&p,-1);
1211                         if (p==cfg) {
1212                                 found=TRUE;
1213                                 break;
1214                         }
1215                 }while(gtk_tree_model_iter_next(model,&iter));
1216         }
1217         if (!found) {
1218                 g_warning("Could not find proxy config in combo box of identities.");
1219                 return;
1220         }
1221         switch (rs){
1222                 case LinphoneRegistrationOk:
1223                         stock_id=GTK_STOCK_YES;
1224                 break;
1225                 case LinphoneRegistrationProgress:
1226                         stock_id=GTK_STOCK_REFRESH;
1227                 break;
1228                 case LinphoneRegistrationCleared:
1229                         stock_id=NULL;
1230                 break;
1231                 case LinphoneRegistrationFailed:
1232                         stock_id=GTK_STOCK_DIALOG_WARNING;
1233                 break;
1234                 default:
1235                 break;
1236         }
1237         gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1238 }
1239
1240 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1241                                                     LinphoneRegistrationState rs, const char *msg){
1242         switch (rs){
1243                 case LinphoneRegistrationOk:
1244                         if (cfg){
1245                                 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1246                                 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1247                                         linphone_gtk_exit_login_frame();
1248                                 }
1249                         }
1250                 break;
1251                 default:
1252                 break;
1253         }
1254         update_registration_status(cfg,rs);
1255 }
1256
1257 void linphone_gtk_open_browser(const char *url){
1258         /*in gtk 2.16, gtk_show_uri does not work...*/
1259 #ifndef WIN32
1260 #if GTK_CHECK_VERSION(2,18,3)
1261         gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1262 #else
1263         char cl[255];
1264         snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1265         g_spawn_command_line_async(cl,NULL);
1266 #endif
1267 #else /*WIN32*/
1268         ShellExecute(0,"open",url,NULL,NULL,1);
1269 #endif
1270 }
1271
1272 void linphone_gtk_link_to_website(GtkWidget *item){
1273         const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1274         linphone_gtk_open_browser(home);
1275 }
1276
1277 #ifndef HAVE_GTK_OSX
1278
1279 static GtkStatusIcon *icon=NULL;
1280
1281 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1282         GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1283         gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1284 }
1285
1286 static GtkWidget *create_icon_menu(){
1287         GtkWidget *menu=gtk_menu_new();
1288         GtkWidget *menu_item;
1289         GtkWidget *image;
1290         gchar *tmp;
1291         const gchar *homesite;
1292
1293         homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1294         menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1295         tmp=g_strdup(homesite);
1296         g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1297         g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1298
1299         image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1300         gtk_widget_show(image);
1301         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1302         //g_object_unref(G_OBJECT(image));
1303         gtk_widget_show(menu_item);
1304         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1305         g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1306
1307         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1308         gtk_widget_show(menu_item);
1309         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1310         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1311         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1312         gtk_widget_show(menu_item);
1313         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1314         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1315         gtk_widget_show(menu);
1316         return menu;
1317 }
1318
1319 static void handle_icon_click() {
1320         GtkWidget *mw=linphone_gtk_get_main_window();
1321         if (!gtk_window_is_active((GtkWindow*)mw)) {
1322                 linphone_gtk_show_main_window();
1323         } else {
1324                 gtk_widget_hide(mw);
1325         }
1326 }
1327
1328 static void linphone_gtk_init_status_icon(){
1329         const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1330         const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1331         GdkPixbuf *pbuf=create_pixbuf(icon_path);
1332         GtkWidget *menu=create_icon_menu();
1333         const char *title;
1334         title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1335         icon=gtk_status_icon_new_from_pixbuf(pbuf);
1336 #if GTK_CHECK_VERSION(2,20,0)
1337         gtk_status_icon_set_name(icon,title);
1338 #endif
1339         g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1340         g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1341         gtk_status_icon_set_tooltip(icon,title);
1342         gtk_status_icon_set_visible(icon,TRUE);
1343         g_object_set_data(G_OBJECT(icon),"menu",menu);
1344         g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1345         g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1346         g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1347         pbuf=create_pixbuf(call_icon_path);
1348         g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1349 }
1350
1351 static gboolean do_icon_blink(GtkStatusIcon *gi){
1352         GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1353         GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1354         GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1355         if (cur_icon==call_icon){
1356                 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1357         }else{
1358                 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1359         }
1360         return TRUE;
1361 }
1362
1363 #endif
1364
1365 void linphone_gtk_status_icon_set_blinking(gboolean val){
1366 #ifdef HAVE_GTK_OSX
1367         static gint attention_id;
1368         GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1369         if (val)
1370                 attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
1371         else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
1372 #else
1373         if (icon!=NULL){
1374                 guint tout;
1375                 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1376                 if (val && tout==0){
1377                         tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1378                         g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1379                 }else if (!val && tout!=0){
1380                         GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1381                         g_source_remove(tout);
1382                         g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1383                         gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1384                 }
1385         }
1386 #endif
1387 }
1388
1389 void linphone_gtk_options_activate(GtkWidget *item){
1390 #ifndef HAVE_GTK_OSX
1391         gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1392                 TRUE);
1393 #endif
1394 }
1395
1396 static void init_identity_combo(GtkComboBox *box){
1397         GtkListStore *store;
1398         GtkCellRenderer *r1,*r2;
1399         store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1400         gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1401         gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1402         gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1403         gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1404         gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1405         g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1406         gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1407 }
1408
1409 void linphone_gtk_load_identities(void){
1410         const MSList *elem;
1411         GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1412         char *def_identity;
1413         LinphoneProxyConfig *def=NULL;
1414         int def_index=0,i;
1415         GtkListStore *store;
1416         GtkTreeIter iter;
1417
1418         store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1419         if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1420                 /* model is empty, this is the first time we go here */
1421                 init_identity_combo(box);
1422                 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1423         }
1424         gtk_list_store_clear(store);
1425         linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1426         def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1427         gtk_list_store_append(store,&iter);
1428         gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1429         g_free(def_identity);
1430         for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1431                         elem!=NULL;
1432                         elem=ms_list_next(elem),i++){
1433                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1434                 gtk_list_store_append(store,&iter);
1435                 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1436                                    linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1437                                    2,cfg,-1);
1438                 if (cfg==def) {
1439                         def_index=i;
1440                 }
1441         }
1442         gtk_combo_box_set_active(box,def_index);
1443 }
1444
1445 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1446         const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1447         GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1448         int pos=-1;
1449         gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1450         linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1451         if (linphone_core_in_call(linphone_gtk_get_core())){
1452                 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1453         }
1454 }
1455
1456 static void linphone_gtk_dtmf_released(GtkButton *button){
1457         linphone_core_stop_dtmf (linphone_gtk_get_core());
1458 }
1459
1460
1461 static void linphone_gtk_connect_digits(void){
1462         GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1463         GList *children=gtk_container_get_children(cont);
1464         GList *elem;
1465         for(elem=children;elem!=NULL;elem=elem->next){
1466                 GtkButton *button=GTK_BUTTON(elem->data);
1467                 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1468                 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1469         }
1470 }
1471
1472 static void linphone_gtk_check_menu_items(void){
1473         bool_t video_enabled=linphone_gtk_video_enabled();
1474         bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1475         GtkWidget *selfview_item=linphone_gtk_get_widget(
1476                                         linphone_gtk_get_main_window(),"selfview_item");
1477         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1478                                         linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1479         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1480 }
1481
1482 static gboolean linphone_gtk_can_manage_accounts(){
1483         LinphoneCore *lc=linphone_gtk_get_core();
1484         const MSList *elem;
1485         for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1486                 SipSetup *ss=(SipSetup*)elem->data;
1487                 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1488                         return TRUE;
1489                 }
1490         }
1491         return FALSE;
1492 }
1493
1494 static void linphone_gtk_configure_main_window(){
1495         static gboolean config_loaded=FALSE;
1496         static const char *title;
1497         static const char *home;
1498         static const char *start_call_icon;
1499         static const char *add_call_icon;
1500         //static const char *stop_call_icon;
1501         static const char *search_icon;
1502         static gboolean update_check_menu;
1503         static gboolean buttons_have_borders;
1504         static gboolean show_abcd;
1505         GtkWidget *w=linphone_gtk_get_main_window();
1506         GHashTable *contacts_history;
1507
1508         contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1509         g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1510
1511         if (!config_loaded){
1512                 title=linphone_gtk_get_ui_config("title","Linphone");
1513                 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1514                 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1515                 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1516                 //stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png");
1517                 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1518                 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1519                 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1520                 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1521                 config_loaded=TRUE;
1522         }
1523         linphone_gtk_configure_window(w,"main_window");
1524         if (title) {
1525                 gtk_window_set_title(GTK_WINDOW(w),title);
1526         }
1527         if (start_call_icon){
1528                 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1529                                     create_pixmap (start_call_icon));
1530                 if (!buttons_have_borders)
1531                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1532         }
1533         if (add_call_icon){
1534                 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1535                                     create_pixmap (add_call_icon));
1536                 if (!buttons_have_borders)
1537                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1538         }
1539         if (search_icon){
1540                 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1541                 if(pbuf != NULL) {
1542                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1543                         g_object_unref(G_OBJECT(pbuf));
1544                 }
1545         }
1546         if (home){
1547                 gchar *tmp;
1548                 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1549                 tmp=g_strdup(home);
1550                 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1551         }
1552         {
1553                 /*
1554                 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1555                 if (pbuf) {
1556                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1557                         g_object_unref(G_OBJECT(pbuf));
1558                 }
1559                 */
1560         }
1561         {
1562                 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1563                 if (pbuf) {
1564                         GtkImage *img=GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon"));
1565                         int w,h;
1566                         GdkPixbuf *scaled;
1567                         gtk_icon_size_lookup(GTK_ICON_SIZE_MENU,&w,&h);
1568                         scaled=gdk_pixbuf_scale_simple(pbuf,w,h,GDK_INTERP_BILINEAR);
1569                         gtk_image_set_from_pixbuf(img,scaled);
1570                         g_object_unref(G_OBJECT(scaled));
1571                         g_object_unref(G_OBJECT(pbuf));
1572                 }
1573         }
1574         if (linphone_gtk_can_manage_accounts()) {
1575                 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1576         }
1577         if (update_check_menu){
1578                 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1579         }
1580         if (!show_abcd){
1581                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1582                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1583                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1584                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1585                 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1586         }
1587 }
1588
1589 void linphone_gtk_manage_login(void){
1590         LinphoneCore *lc=linphone_gtk_get_core();
1591         LinphoneProxyConfig *cfg=NULL;
1592         linphone_core_get_default_proxy(lc,&cfg);
1593         if (cfg){
1594                 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1595                 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1596                         linphone_gtk_show_login_frame(cfg);
1597                 }
1598         }
1599 }
1600
1601
1602 gboolean linphone_gtk_close(GtkWidget *mw){
1603         /*shutdown calls if any*/
1604         LinphoneCore *lc=linphone_gtk_get_core();
1605         if (linphone_core_in_call(lc)){
1606                 linphone_core_terminate_all_calls(lc);
1607         }
1608         linphone_core_enable_video_preview(lc,FALSE);
1609 #ifdef __APPLE__ /*until with have a better option*/
1610         gtk_window_iconify(GTK_WINDOW(mw));
1611 #else
1612         gtk_widget_hide(mw);
1613 #endif
1614         return TRUE;
1615 }
1616
1617 #ifdef HAVE_GTK_OSX
1618 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1619         bool_t video_enabled=linphone_gtk_video_enabled();
1620         if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1621                 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1622         }else{
1623                 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1624                 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1625         }
1626         return FALSE;
1627 }
1628 #endif
1629
1630 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1631         GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1632         gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1633
1634         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1635         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1636         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1637         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1638         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1639         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1640         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1641         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1642         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1643         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1644         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1645         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1646         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1647         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1648         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1649         g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1650         
1651 }
1652
1653 static void linphone_gtk_init_main_window(){
1654         GtkWidget *main_window;
1655
1656         linphone_gtk_configure_main_window();
1657         linphone_gtk_manage_login();
1658         load_uri_history();
1659         linphone_gtk_load_identities();
1660         linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1661         linphone_gtk_show_friends();
1662         linphone_gtk_connect_digits();
1663         main_window=linphone_gtk_get_main_window();
1664         linphone_gtk_call_log_update(main_window);
1665
1666         linphone_gtk_init_dtmf_table(main_window);
1667         linphone_gtk_update_call_buttons (NULL);
1668         g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1669         /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1670         g_signal_connect (G_OBJECT (main_window), "delete-event",
1671                 G_CALLBACK (linphone_gtk_close), main_window);
1672 #ifdef HAVE_GTK_OSX
1673         {
1674                 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1675                 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1676                 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1677                 gtk_widget_hide(menubar);
1678                 gtk_osxapplication_ready(theMacApp);
1679         }
1680         g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1681 #endif
1682         linphone_gtk_check_menu_items();
1683 }
1684
1685
1686 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1687         if (verbose){
1688                 const char *lname="undef";
1689                 char *msg;
1690 #if defined(__linux) || defined(__APPLE__)
1691                 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1692 #endif
1693                 switch(lev){
1694                         case ORTP_DEBUG:
1695                                 lname="debug";
1696                                 break;
1697                         case ORTP_MESSAGE:
1698                                 lname="message";
1699                                 break;
1700                         case ORTP_WARNING:
1701                                 lname="warning";
1702                                 break;
1703                         case ORTP_ERROR:
1704                                 lname="error";
1705                                 break;
1706                         case ORTP_FATAL:
1707                                 lname="fatal";
1708                                 break;
1709                         default:
1710                                 g_error("Bad level !");
1711                 }
1712 #if defined(__linux) || defined(__APPLE__)
1713                 va_copy(cap,args);
1714                 msg=g_strdup_vprintf(fmt,cap);
1715                 va_end(cap);
1716 #else
1717                 msg=g_strdup_vprintf(fmt,args);
1718 #endif
1719                 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1720                 ortp_free(msg);
1721         }
1722         linphone_gtk_log_push(lev,fmt,args);
1723 }
1724
1725
1726 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1727         GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1728                 linphone_gtk_get_main_window(), "uribar"));
1729         char *text;
1730         linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1731         g_free(text);
1732         gtk_entry_set_text(uri_bar, refer_to);
1733         linphone_gtk_start_call(linphone_gtk_get_main_window());
1734 }
1735
1736 static void linphone_gtk_check_soundcards(){
1737         const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1738         if (devices==NULL || devices[0]==NULL){
1739                 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1740                         _("No sound cards have been detected on this computer.\n"
1741                                 "You won't be able to send or receive audio calls."));
1742         }
1743 }
1744
1745 static void linphone_gtk_quit(void){
1746         static gboolean quit_done=FALSE;
1747         if (!quit_done){
1748                 quit_done=TRUE;
1749                 linphone_gtk_unmonitor_usb();
1750                 g_source_remove_by_user_data(linphone_gtk_get_core());
1751 #ifdef BUILD_WIZARD
1752                 linphone_gtk_close_assistant();
1753 #endif
1754                 linphone_gtk_uninit_instance();
1755                 linphone_gtk_destroy_log_window();
1756                 linphone_core_destroy(the_core);
1757                 linphone_gtk_log_uninit();
1758 #ifdef HAVE_NOTIFY
1759                 notify_uninit();
1760 #endif
1761                 gdk_threads_leave();
1762         }
1763 }
1764
1765 #ifdef HAVE_GTK_OSX
1766 /*
1767 This is not the correct way to implement block termination.
1768 The good way would be to call gtk_main_quit(), and return TRUE.
1769 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1770 As a result the program cannot exit at all.
1771 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1772 */
1773 static gboolean on_block_termination(void){
1774         gtk_main_quit();
1775         linphone_gtk_quit();
1776         return FALSE;
1777 }
1778 #endif
1779
1780 int main(int argc, char *argv[]){
1781 #ifdef ENABLE_NLS
1782         void *p;
1783 #endif
1784         char *config_file;
1785         const char *factory_config_file;
1786         const char *lang;
1787         GtkSettings *settings;
1788         GdkPixbuf *pbuf;
1789         const char *app_name="Linphone";
1790
1791 #if !GLIB_CHECK_VERSION(2, 31, 0)
1792         g_thread_init(NULL);
1793 #endif
1794         gdk_threads_init();
1795
1796         progpath = strdup(argv[0]);
1797
1798         config_file=linphone_gtk_get_config_file(NULL);
1799
1800
1801 #ifdef WIN32
1802         /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1803         if ((lang=getenv("LANG"))!=NULL){
1804                 if (atoi(lang)!=0){
1805                         char tmp[128];
1806                         snprintf(tmp,sizeof(tmp),"LANG=",lang);
1807                         _putenv(tmp);
1808                 }
1809         }
1810 #else
1811         /*for pulseaudio:*/
1812         g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1813 #endif
1814
1815         if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1816 #ifdef WIN32
1817                 char tmp[128];
1818                 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1819                 _putenv(tmp);
1820                 if (strncmp(lang,"zh",2)==0){
1821                         workaround_gtk_entry_chinese_bug=TRUE;
1822                 }
1823 #elif __APPLE__
1824                 setenv("LANG",lang,1);
1825 #else
1826                 setenv("LANGUAGE",lang,1);
1827 #endif
1828         }
1829
1830 #ifdef ENABLE_NLS
1831         p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1832         if (p==NULL) perror("bindtextdomain failed");
1833         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1834         textdomain (GETTEXT_PACKAGE);
1835 #else
1836         g_message("NLS disabled.\n");
1837 #endif
1838 #ifdef WIN32
1839         gtk_rc_add_default_file("./gtkrc");
1840 #endif
1841         gdk_threads_enter();
1842
1843         if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1844                                 linphone_options,NULL,NULL)){
1845                 gdk_threads_leave();
1846                 return -1;
1847         }
1848
1849         settings=gtk_settings_get_default();
1850         g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1851         g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1852         g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1853         g_object_set(settings, "gtk-button-images", TRUE, NULL);
1854
1855         if (workingdir!=NULL){
1856                 if (chdir(workingdir)==-1){
1857                         g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1858                 }
1859         }
1860
1861         /* Now, look for the factory configuration file, we do it this late
1862                  since we want to have had time to change directory and to parse
1863                  the options, in case we needed to access the working directory */
1864         factory_config_file = linphone_gtk_get_factory_config_file();
1865
1866         if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1867                 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1868                 g_warning("This instance is going to exit now.");
1869                 gdk_threads_leave();
1870                 return 0;
1871         }
1872
1873         add_pixmap_directory("pixmaps");
1874         add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1875
1876 #ifdef HAVE_GTK_OSX
1877         GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1878         g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1879         g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1880         /*never block termination:*/
1881         g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1882 #endif
1883
1884         the_ui=linphone_gtk_create_window("main");
1885
1886         g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1887
1888         linphone_gtk_create_log_window();
1889         linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1890
1891         linphone_gtk_init_liblinphone(config_file, factory_config_file);
1892
1893         g_set_application_name(app_name);
1894         pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1895         if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1896
1897         /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1898         gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1899         gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1900         linphone_gtk_init_main_window();
1901
1902 #ifdef BUILD_WIZARD
1903         // Veryfing if at least one sip account is configured. If not, show wizard
1904         if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1905                 linphone_gtk_show_assistant();
1906         }
1907 #endif
1908
1909 #ifndef HAVE_GTK_OSX
1910         linphone_gtk_init_status_icon();
1911 #endif
1912         if (!iconified){
1913                 linphone_gtk_show_main_window();
1914                 linphone_gtk_check_soundcards();
1915         }
1916         if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1917                 linphone_gtk_check_for_new_version();
1918         linphone_gtk_monitor_usb();
1919
1920         gtk_main();
1921         linphone_gtk_quit();
1922 #ifndef HAVE_GTK_OSX
1923         /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1924         gtk_status_icon_set_visible(icon,FALSE);
1925 #endif
1926         free(progpath);
1927         return 0;
1928 }
1929