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