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