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