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