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