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