]> sjero.net Git - linphone/blob - gtk/main.c
implement better system for "single instance application" requirement.
[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 bool_t all_other_calls_paused(LinphoneCall *refcall, const MSList *calls){
659         for(;calls!=NULL;calls=calls->next){
660                 LinphoneCall *call=(LinphoneCall*)calls->data;
661                 LinphoneCallState cs=linphone_call_get_state(call);
662                 if (refcall!=call){
663                         if (cs!=LinphoneCallPaused  && cs!=LinphoneCallPausing)
664                                 return FALSE;
665                 }
666         }
667         return TRUE;
668 }
669
670 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
671         LinphoneCore *lc=linphone_gtk_get_core();
672         GtkWidget *mw=linphone_gtk_get_main_window();
673         const MSList *calls=linphone_core_get_calls(lc);
674         GtkWidget *button;
675         bool_t start_active=TRUE;
676         bool_t stop_active=FALSE;
677         bool_t add_call=FALSE;
678         int call_list_size=ms_list_size(calls);
679         
680         if (calls==NULL){
681                 start_active=TRUE;
682                 stop_active=FALSE;
683         }else{
684                 stop_active=TRUE;
685                 if (all_other_calls_paused(NULL,calls)){
686                         start_active=TRUE;
687                         add_call=TRUE;
688                 }else if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived && all_other_calls_paused(call,calls)){
689                         if (call_list_size>1){
690                                 start_active=TRUE;
691                                 add_call=TRUE;
692                         }else{
693                                 start_active=TRUE;
694                                 add_call=FALSE;
695                         }
696                 }else{
697                         start_active=FALSE;
698                 }
699         }
700         button=linphone_gtk_get_widget(mw,"start_call");
701         gtk_widget_set_sensitive(button,start_active);
702         gtk_widget_set_visible(button,!add_call);
703         
704         button=linphone_gtk_get_widget(mw,"add_call");
705         gtk_widget_set_sensitive(button,start_active);
706         gtk_widget_set_visible(button,add_call);
707         
708         gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
709
710         linphone_gtk_enable_transfer_button(lc,call_list_size>1);
711         update_video_title();
712 }
713
714 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
715         const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
716         if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
717                 completion_add_text(GTK_ENTRY(uri_bar),entered);
718         }else{
719                 linphone_gtk_call_terminated(NULL,NULL);
720         }
721         return FALSE;
722 }
723
724 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
725         if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
726                 linphone_core_accept_call (linphone_gtk_get_core(),call);
727                 linphone_call_unref(call);
728         }
729         return FALSE;
730 }
731
732
733 void linphone_gtk_start_call(GtkWidget *w){
734         LinphoneCore *lc=linphone_gtk_get_core();
735         LinphoneCall *call;
736         /*change into in-call mode, then do the work later as it might block a bit */
737         GtkWidget *mw=gtk_widget_get_toplevel(w);
738         GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
739
740         call=linphone_gtk_get_currently_displayed_call ();
741         if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
742                 linphone_core_accept_call(lc,call);
743         }else{
744                 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
745                 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
746                 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
747                 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
748         }
749         
750 }
751
752 void linphone_gtk_uri_bar_activate(GtkWidget *w){
753         linphone_gtk_start_call(w);
754 }
755
756
757 void linphone_gtk_terminate_call(GtkWidget *button){
758         LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
759         if (call)
760                 linphone_core_terminate_call(linphone_gtk_get_core(),call);
761 }
762
763 void linphone_gtk_decline_clicked(GtkWidget *button){
764         LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
765         if (call)
766                 linphone_core_terminate_call(linphone_gtk_get_core(),call);
767 }
768
769 void linphone_gtk_answer_clicked(GtkWidget *button){
770         LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
771         if (call){
772                 linphone_core_pause_all_calls(linphone_gtk_get_core());
773                 linphone_core_accept_call(linphone_gtk_get_core(),call);
774                 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
775         }
776 }
777
778 void linphone_gtk_enable_video(GtkWidget *w){
779         gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
780         GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
781         linphone_core_enable_video(linphone_gtk_get_core(),val,val);
782         gtk_widget_set_sensitive(selfview_item,val);
783         if (val){
784                 linphone_core_enable_video_preview(linphone_gtk_get_core(),
785                 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
786         }else{
787                 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
788         }
789 }
790
791 void linphone_gtk_enable_self_view(GtkWidget *w){
792         gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
793         LinphoneCore *lc=linphone_gtk_get_core();
794         linphone_core_enable_video_preview(lc,val);
795         linphone_core_enable_self_view(lc,val);
796         linphone_gtk_set_ui_config_int("videoselfview",val);
797 }
798
799 void linphone_gtk_used_identity_changed(GtkWidget *w){
800         int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
801         char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
802         if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
803                 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
804                 linphone_gtk_show_directory_search();
805         }
806         if (sel) g_free(sel);
807 }
808
809 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
810         linphone_gtk_show_friends();
811 }
812
813 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
814         switch(response_id){
815                 case GTK_RESPONSE_YES:
816                         linphone_gtk_show_contact(lf);
817                 break;
818                 default:
819                         linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
820         }
821         gtk_widget_destroy(dialog);
822 }
823
824 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
825         GtkWidget *dialog;
826
827         if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
828                 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
829                 return;
830         }
831
832         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);
833         dialog = gtk_message_dialog_new (
834                                 GTK_WINDOW(linphone_gtk_get_main_window()),
835                                 GTK_DIALOG_DESTROY_WITH_PARENT,
836                                 GTK_MESSAGE_QUESTION,
837                                 GTK_BUTTONS_YES_NO,
838                                 "%s",
839                                 message);
840         g_free(message);
841         g_signal_connect(G_OBJECT (dialog), "response",
842                 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
843         /* actually show the box */
844         gtk_widget_show(dialog);
845 }
846
847 typedef struct _AuthTimeout{
848         GtkWidget *w;
849 } AuthTimeout;
850
851
852 static void auth_timeout_clean(AuthTimeout *tout){
853         tout->w=NULL;
854 }
855
856 static gboolean auth_timeout_destroy(AuthTimeout *tout){
857         if (tout->w)  {
858                 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
859                 gtk_widget_destroy(tout->w);
860         }
861         g_free(tout);
862         return FALSE;
863 }
864
865 static AuthTimeout * auth_timeout_new(GtkWidget *w){
866         AuthTimeout *tout=g_new(AuthTimeout,1);
867         tout->w=w;
868         /*so that the timeout no more references the widget when it is destroyed:*/
869         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
870         /*so that the widget is automatically destroyed after some time */
871         g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
872         return tout;
873 }
874
875 void linphone_gtk_password_cancel(GtkWidget *w){
876         LinphoneAuthInfo *info;
877         GtkWidget *window=gtk_widget_get_toplevel(w);
878         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
879         linphone_core_abort_authentication(linphone_gtk_get_core(),info);
880         gtk_widget_destroy(window);
881 }
882
883 void linphone_gtk_password_ok(GtkWidget *w){
884         GtkWidget *entry;
885         GtkWidget *window=gtk_widget_get_toplevel(w);
886         LinphoneAuthInfo *info;
887         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
888         g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
889         entry=linphone_gtk_get_widget(window,"password_entry");
890         linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
891         linphone_auth_info_set_userid(info,
892                 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
893         linphone_core_add_auth_info(linphone_gtk_get_core(),info);
894         gtk_widget_destroy(window);
895 }
896
897 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
898         GtkWidget *w=linphone_gtk_create_window("password");
899         GtkWidget *label=linphone_gtk_get_widget(w,"message");
900         LinphoneAuthInfo *info;
901         gchar *msg;
902         GtkWidget *mw=linphone_gtk_get_main_window();
903         
904         if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
905                 /*don't prompt for authentication when login frame is visible*/
906                 linphone_core_abort_authentication(lc,NULL);
907                 return;
908         }
909
910         msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
911                 username,realm);
912         gtk_label_set_markup(GTK_LABEL(label),msg);
913         g_free(msg);
914         gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
915         info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
916         g_object_set_data(G_OBJECT(w),"auth_info",info);
917         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
918         gtk_widget_show(w);
919         auth_timeout_new(w);
920 }
921
922 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
923         GtkWidget *w=linphone_gtk_get_main_window();
924         GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
925         gtk_statusbar_push(GTK_STATUSBAR(status_bar),
926                         gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
927                         status);
928 }
929
930 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
931         linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
932 }
933
934 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
935         linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
936 }
937
938 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
939         char richtext[4096];
940         snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
941         linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
942 }
943
944 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
945         GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
946         if (w) linphone_gtk_call_log_update(w);
947         linphone_gtk_call_log_update(linphone_gtk_get_main_window());
948 }
949
950 #ifdef HAVE_NOTIFY
951 static void make_notification(const char *title, const char *body){
952         NotifyNotification *n;
953         n = notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
954         if (n && !notify_notification_show(n,NULL))
955                         ms_error("Failed to send notification.");
956 }
957
958 #endif
959
960 static void linphone_gtk_notify(LinphoneCall *call, const char *msg){
961 #ifdef HAVE_NOTIFY
962         if (!notify_is_initted())
963                 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
964 #endif
965         if (!call) {
966 #ifdef HAVE_NOTIFY
967                 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL),NULL))
968                                 ms_error("Failed to send notification.");
969 #else
970                 linphone_gtk_show_main_window();
971 #endif
972         } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
973 #ifdef HAVE_NOTIFY
974                 char *body=NULL;
975                 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
976                 switch(linphone_call_get_state(call)){
977                         case LinphoneCallError:
978                                 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
979                         break;
980                         case LinphoneCallEnd:
981                                 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
982                         break;
983                         case LinphoneCallIncomingReceived:
984                                 make_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
985                         break;
986                         case LinphoneCallPausedByRemote:
987                                 make_notification(_("Call paused"),body=g_markup_printf_escaped("<span size=\"large\">by %s</span>",remote));
988                         break;
989                         default:
990                         break;
991                 }
992                 if (body) g_free(body);
993                 if (remote) g_free(remote);
994 #endif
995         }
996 }
997
998 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
999         switch(cs){
1000                 case LinphoneCallOutgoingInit:
1001                         linphone_gtk_create_in_call_view (call);
1002                 break;
1003                 case LinphoneCallOutgoingProgress:
1004                         linphone_gtk_in_call_view_set_calling (call);
1005                 break;
1006                 case LinphoneCallStreamsRunning:
1007                         linphone_gtk_in_call_view_set_in_call(call);
1008                 break;
1009                 case LinphoneCallError:
1010                         linphone_gtk_in_call_view_terminate (call,msg);
1011                 break;
1012                 case LinphoneCallEnd:
1013                         linphone_gtk_in_call_view_terminate(call,NULL);
1014                         linphone_gtk_status_icon_set_blinking(FALSE);
1015                 break;
1016                 case LinphoneCallIncomingReceived:
1017                         linphone_gtk_create_in_call_view (call);
1018                         linphone_gtk_in_call_view_set_incoming(call,!all_other_calls_paused (call,linphone_core_get_calls(lc)));
1019                         linphone_gtk_status_icon_set_blinking(TRUE);
1020                         if (auto_answer)  {
1021                                 linphone_call_ref(call);
1022                                 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1023                         }               
1024                 break;
1025                 case LinphoneCallResuming:
1026                         linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1027                         linphone_gtk_in_call_view_set_in_call (call);
1028                 break;
1029                 case LinphoneCallPausing:
1030                         linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1031                 case LinphoneCallPausedByRemote:
1032                         linphone_gtk_in_call_view_set_paused(call);
1033                 break;
1034                 case LinphoneCallConnected:
1035                         linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1036                         linphone_gtk_status_icon_set_blinking(FALSE);
1037                 break;
1038                 default:
1039                 break;
1040         }
1041         linphone_gtk_notify(call, msg);
1042         linphone_gtk_update_call_buttons (call);
1043 }
1044
1045 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1046         GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1047         GtkTreeModel *model=gtk_combo_box_get_model(box);
1048         GtkTreeIter iter;
1049         gboolean found=FALSE;
1050         const char *stock_id=NULL;
1051         
1052         if (gtk_tree_model_get_iter_first(model,&iter)){
1053                 gpointer p;
1054                 do{
1055                         gtk_tree_model_get(model,&iter,2,&p,-1);
1056                         if (p==cfg) {
1057                                 found=TRUE;
1058                                 break;
1059                         }
1060                 }while(gtk_tree_model_iter_next(model,&iter));
1061         }
1062         if (!found) {
1063                 g_warning("Could not find proxy config in combo box of identities.");
1064                 return;
1065         }
1066         switch (rs){
1067                 case LinphoneRegistrationOk:
1068                         stock_id=GTK_STOCK_YES;
1069                 break;
1070                 case LinphoneRegistrationProgress:
1071                         stock_id=GTK_STOCK_REFRESH;
1072                 break;
1073                 case LinphoneRegistrationCleared:
1074                         stock_id=NULL;
1075                 break;
1076                 case LinphoneRegistrationFailed:
1077                         stock_id=GTK_STOCK_DIALOG_WARNING;
1078                 break;
1079                 default:
1080                 break;
1081         }
1082         gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1083 }
1084
1085 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, 
1086                                                     LinphoneRegistrationState rs, const char *msg){
1087         switch (rs){
1088                 case LinphoneRegistrationOk:
1089                         if (cfg){
1090                                 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1091                                 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1092                                         linphone_gtk_exit_login_frame();
1093                                 }
1094                         }
1095                 break;
1096                 default:
1097                 break;
1098         }
1099         update_registration_status(cfg,rs);
1100 }
1101
1102
1103 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1104         GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1105         gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1106 }
1107
1108 void linphone_gtk_open_browser(const char *url){
1109         /*in gtk 2.16, gtk_show_uri does not work...*/
1110 #ifndef WIN32
1111 #if GTK_CHECK_VERSION(2,18,3)
1112         gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1113 #else
1114         char cl[255];
1115         snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1116         g_spawn_command_line_async(cl,NULL);
1117 #endif
1118 #else /*WIN32*/
1119         ShellExecute(0,"open",url,NULL,NULL,1);
1120 #endif
1121 }
1122
1123 void linphone_gtk_link_to_website(GtkWidget *item){
1124         const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1125         linphone_gtk_open_browser(home);
1126 }
1127
1128 static GtkWidget *create_icon_menu(){
1129         GtkWidget *menu=gtk_menu_new();
1130         GtkWidget *menu_item;
1131         GtkWidget *image;
1132         gchar *tmp;
1133         const gchar *homesite;
1134         
1135         homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1136         menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1137         tmp=g_strdup(homesite);
1138         g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1139         g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1140         
1141         image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1142         gtk_widget_show(image);
1143         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1144         //g_object_unref(G_OBJECT(image));
1145         gtk_widget_show(menu_item);
1146         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1147         g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1148         
1149         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1150         gtk_widget_show(menu_item);
1151         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1152         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1153         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1154         gtk_widget_show(menu_item);
1155         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1156         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1157         gtk_widget_show(menu);
1158         return menu;
1159 }
1160
1161 static GtkStatusIcon *icon=NULL;
1162
1163 static void linphone_gtk_init_status_icon(){
1164         const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1165         const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1166         GdkPixbuf *pbuf=create_pixbuf(icon_path);
1167         GtkWidget *menu=create_icon_menu();
1168         const char *title;
1169         title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1170         icon=gtk_status_icon_new_from_pixbuf(pbuf);
1171         gtk_status_icon_set_name(icon,title);
1172         g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
1173         g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1174         gtk_status_icon_set_tooltip(icon,title);
1175         gtk_status_icon_set_visible(icon,TRUE);
1176         g_object_set_data(G_OBJECT(icon),"menu",menu);
1177         g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1178         g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1179         g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1180         pbuf=create_pixbuf(call_icon_path);
1181         g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1182 }
1183
1184 static gboolean do_icon_blink(GtkStatusIcon *gi){
1185         GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1186         GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1187         GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1188         if (cur_icon==call_icon){
1189                 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1190         }else{
1191                 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1192         }
1193         return TRUE;
1194 }
1195
1196 static void linphone_gtk_status_icon_set_blinking(gboolean val){
1197         guint tout;
1198         tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1199         if (val && tout==0){
1200                 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1201                 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1202         }else if (!val && tout!=0){
1203                 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1204                 g_source_remove(tout);
1205                 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1206                 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1207         }
1208 }
1209
1210 static void init_identity_combo(GtkComboBox *box){
1211         GtkListStore *store;
1212         GtkCellRenderer *r1,*r2;
1213         store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1214         gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1215         gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1216         gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1217         gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1218         gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1219         g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1220         gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1221 }
1222
1223 void linphone_gtk_load_identities(void){
1224         const MSList *elem;
1225         GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1226         char *def_identity;
1227         LinphoneProxyConfig *def=NULL;
1228         int def_index=0,i;
1229         GtkListStore *store;
1230         GtkTreeIter iter;
1231
1232         store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1233         if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1234                 /* model is empty, this is the first time we go here */
1235                 init_identity_combo(box);
1236                 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1237         }
1238         gtk_list_store_clear(store);
1239         linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1240         def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1241         gtk_list_store_append(store,&iter);
1242         gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1243         g_free(def_identity);
1244         for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1245                         elem!=NULL;
1246                         elem=ms_list_next(elem),i++){
1247                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1248                 gtk_list_store_append(store,&iter);
1249                 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1250                                    linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1251                                    2,cfg,-1);
1252                 if (cfg==def) {
1253                         def_index=i;
1254                 }
1255         }
1256         gtk_combo_box_set_active(box,def_index);
1257 }
1258
1259 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1260         const char *label=gtk_button_get_label(button);
1261         GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1262         int pos=-1;
1263         gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1264         linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1265         if (linphone_core_in_call(linphone_gtk_get_core())){
1266                 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1267         }
1268 }
1269
1270 static void linphone_gtk_dtmf_released(GtkButton *button){
1271         linphone_core_stop_dtmf (linphone_gtk_get_core());
1272 }
1273
1274 static void linphone_gtk_connect_digits(void){
1275         GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1276         GList *children=gtk_container_get_children(cont);
1277         GList *elem;
1278         for(elem=children;elem!=NULL;elem=elem->next){
1279                 GtkButton *button=GTK_BUTTON(elem->data);
1280                 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1281                 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1282         }
1283 }
1284
1285 static void linphone_gtk_check_menu_items(void){
1286         bool_t video_enabled=linphone_core_video_enabled(linphone_gtk_get_core());
1287         bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1288         GtkWidget *selfview_item=linphone_gtk_get_widget(
1289                                         linphone_gtk_get_main_window(),"selfview_item");
1290         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1291                                         linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1292         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1293         gtk_widget_set_sensitive(selfview_item,video_enabled);
1294 }
1295
1296 static gboolean linphone_gtk_can_manage_accounts(){
1297         LinphoneCore *lc=linphone_gtk_get_core();
1298         const MSList *elem;
1299         for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1300                 SipSetup *ss=(SipSetup*)elem->data;
1301                 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1302                         return TRUE;
1303                 }
1304         }
1305         return FALSE;
1306 }
1307
1308 static void linphone_gtk_configure_main_window(){
1309         static gboolean config_loaded=FALSE;
1310         static const char *title;
1311         static const char *home;
1312         static const char *start_call_icon;
1313         static const char *add_call_icon;
1314         static const char *stop_call_icon;
1315         static const char *search_icon;
1316         static gboolean update_check_menu;
1317         static gboolean buttons_have_borders;
1318         static gboolean show_abcd;
1319         GtkWidget *w=linphone_gtk_get_main_window();
1320         if (!config_loaded){
1321                 title=linphone_gtk_get_ui_config("title","Linphone");
1322                 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1323                 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1324                 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1325                 stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
1326                 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1327                 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1328                 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1329                 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1330                 config_loaded=TRUE;
1331         }
1332         linphone_gtk_configure_window(w,"main_window");
1333         if (title) {
1334                 gtk_window_set_title(GTK_WINDOW(w),title);
1335         }
1336         if (start_call_icon){
1337                 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1338                                     create_pixmap (start_call_icon));
1339                 if (!buttons_have_borders)
1340                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1341         }
1342         if (add_call_icon){
1343                 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1344                                     create_pixmap (add_call_icon));
1345                 if (!buttons_have_borders)
1346                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1347         }
1348         if (stop_call_icon){
1349                 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),
1350                                     create_pixmap (stop_call_icon));
1351                 if (!buttons_have_borders)
1352                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NONE);
1353         }
1354         if (search_icon){
1355                 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1356                 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1357                 g_object_unref(G_OBJECT(pbuf));
1358         }
1359         if (home){
1360                 gchar *tmp;
1361                 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1362                 tmp=g_strdup(home);
1363                 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1364         }
1365         {
1366                 /*
1367                 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1368                 if (pbuf) {
1369                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1370                         g_object_unref(G_OBJECT(pbuf));
1371                 }
1372                 */
1373         }
1374         {
1375                 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1376                 if (pbuf) {
1377                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")),pbuf);
1378                         g_object_unref(G_OBJECT(pbuf));
1379                 }
1380         }
1381         if (linphone_gtk_can_manage_accounts())
1382                 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1383         if (update_check_menu){
1384                 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1385         }
1386         if (!show_abcd){
1387                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1388                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1389                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1390                 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1391                 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1392         }
1393 }
1394
1395 void linphone_gtk_manage_login(void){
1396         LinphoneCore *lc=linphone_gtk_get_core();
1397         LinphoneProxyConfig *cfg=NULL;
1398         linphone_core_get_default_proxy(lc,&cfg);
1399         if (cfg){
1400                 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1401                 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1402                         linphone_gtk_show_login_frame(cfg);
1403                 }
1404         }
1405 }
1406
1407
1408 gboolean linphone_gtk_close(GtkWidget *mw){
1409         /*shutdown calls if any*/
1410         LinphoneCore *lc=linphone_gtk_get_core();
1411         if (linphone_core_in_call(lc)){
1412                 linphone_core_terminate_all_calls(lc);
1413         }
1414         linphone_core_enable_video_preview(lc,FALSE);
1415 #ifdef __APPLE__ /*until with have a better option*/
1416         gtk_window_iconify(GTK_WINDOW(mw));
1417 #else
1418         gtk_widget_hide(mw);
1419 #endif
1420         return TRUE;
1421 }
1422
1423 #ifdef HAVE_GTK_OSX
1424 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1425         if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1426                 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1427         }else{
1428                 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1429                 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && linphone_core_video_enabled(linphone_gtk_get_core()));
1430         }
1431         return FALSE;
1432 }
1433 #endif
1434
1435
1436 static void linphone_gtk_init_main_window(){
1437         GtkWidget *main_window;
1438
1439         linphone_gtk_configure_main_window();
1440         linphone_gtk_manage_login();
1441         load_uri_history();
1442         linphone_gtk_load_identities();
1443         linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1444         linphone_gtk_show_friends();
1445         linphone_gtk_connect_digits();
1446         main_window=linphone_gtk_get_main_window();
1447         linphone_gtk_call_log_update(main_window);
1448         
1449         linphone_gtk_update_call_buttons (NULL);
1450         /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1451         g_signal_connect (G_OBJECT (main_window), "delete-event",
1452                 G_CALLBACK (linphone_gtk_close), main_window);
1453 #ifdef HAVE_GTK_OSX
1454         {
1455                 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1456                 gtk_widget_destroy(linphone_gtk_get_widget(main_window,"imagemenuitem5"));
1457                 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1458                 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1459                 gtk_widget_hide(menubar);
1460                 gtk_osxapplication_ready(theMacApp);
1461         }
1462         g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1463 #endif
1464         linphone_gtk_check_menu_items();
1465 }
1466
1467
1468 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1469         if (verbose){
1470                 const char *lname="undef";
1471                 char *msg;
1472 #if defined(__linux) || defined(__APPLE__)
1473                 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1474 #endif
1475                 switch(lev){
1476                         case ORTP_DEBUG:
1477                                 lname="debug";
1478                                 break;
1479                         case ORTP_MESSAGE:
1480                                 lname="message";
1481                                 break;
1482                         case ORTP_WARNING:
1483                                 lname="warning";
1484                                 break;
1485                         case ORTP_ERROR:
1486                                 lname="error";
1487                                 break;
1488                         case ORTP_FATAL:
1489                                 lname="fatal";
1490                                 break;
1491                         default:
1492                                 g_error("Bad level !");
1493                 }
1494 #if defined(__linux) || defined(__APPLE__)
1495                 va_copy(cap,args);
1496                 msg=g_strdup_vprintf(fmt,cap);
1497                 va_end(cap);
1498 #else
1499                 msg=g_strdup_vprintf(fmt,args);
1500 #endif
1501                 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1502                 ortp_free(msg);
1503         }
1504         linphone_gtk_log_push(lev,fmt,args);
1505 }
1506
1507
1508 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1509         GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1510                 linphone_gtk_get_main_window(), "uribar"));
1511         char *text;
1512         linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1513         g_free(text);
1514         gtk_entry_set_text(uri_bar, refer_to);
1515         linphone_gtk_start_call(linphone_gtk_get_main_window());
1516 }
1517
1518 static void linphone_gtk_check_soundcards(){
1519         const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1520         if (devices==NULL || devices[0]==NULL){
1521                 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1522                         _("No sound cards have been detected on this computer.\n"
1523                                 "You won't be able to send or receive audio calls."));
1524         }
1525 }
1526
1527 static void linphone_gtk_quit(void){
1528         linphone_gtk_uninit_instance();
1529         gdk_threads_leave();
1530         linphone_gtk_destroy_log_window();
1531         linphone_core_destroy(the_core);
1532         linphone_gtk_log_uninit();
1533 #ifdef HAVE_NOTIFY
1534         notify_uninit();
1535 #endif
1536 }
1537
1538 #ifdef HAVE_GTK_OSX
1539 /*
1540 This is not the correct way to implement block termination.
1541 The good way would be to call gtk_main_quit(), and return TRUE.
1542 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1543 As a result the program cannot exit at all.
1544 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1545 */
1546 static gboolean on_block_termination(void){
1547         gtk_main_quit();
1548         linphone_gtk_quit();
1549         return FALSE;
1550 }
1551 #endif
1552
1553 int main(int argc, char *argv[]){
1554 #ifdef ENABLE_NLS
1555         void *p;
1556 #endif
1557         const char *config_file;
1558         const char *factory_config_file;
1559         const char *lang;
1560         GtkSettings *settings;
1561         GdkPixbuf *pbuf;
1562         const char *app_name="Linphone";
1563
1564         g_thread_init(NULL);
1565         gdk_threads_init();
1566         
1567         progpath = strdup(argv[0]);
1568         
1569         config_file=linphone_gtk_get_config_file();
1570         
1571
1572 #ifdef WIN32
1573         /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1574         if ((lang=getenv("LANG"))!=NULL){
1575                 if (atoi(lang)!=0){
1576                         char tmp[128];
1577                         snprintf(tmp,sizeof(tmp),"LANG=",lang);
1578                         _putenv(tmp);
1579                 }
1580         }
1581 #else
1582         /*for pulseaudio:*/
1583         g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1584 #endif
1585
1586         if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1587 #ifdef WIN32
1588                 char tmp[128];
1589                 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1590                 _putenv(tmp);
1591 #else
1592                 setenv("LANG",lang,1);
1593 #endif
1594         }
1595
1596 #ifdef ENABLE_NLS
1597         p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1598         if (p==NULL) perror("bindtextdomain failed");
1599         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1600         textdomain (GETTEXT_PACKAGE);
1601 #else
1602         g_message("NLS disabled.\n");
1603 #endif
1604 #ifdef WIN32
1605         gtk_rc_add_default_file("./gtkrc");
1606 #endif
1607         gdk_threads_enter();
1608         
1609         if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1610                                 linphone_options,NULL,NULL)){
1611                 gdk_threads_leave();
1612                 return -1;
1613         }
1614         
1615         settings=gtk_settings_get_default();
1616         g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1617         g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1618         g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1619         g_object_set(settings, "gtk-button-images", TRUE, NULL);
1620
1621         if (workingdir!=NULL){
1622                 if (chdir(workingdir)==-1){
1623                         g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1624                 }
1625         }
1626
1627         /* Now, look for the factory configuration file, we do it this late
1628                  since we want to have had time to change directory and to parse
1629                  the options, in case we needed to access the working directory */
1630         factory_config_file = linphone_gtk_get_factory_config_file();
1631
1632         if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1633                 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1634                 g_warning("This instance is going to exit now.");
1635                 gdk_threads_leave();
1636                 return 0;
1637         }
1638
1639         add_pixmap_directory("pixmaps");
1640         add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1641
1642 #ifdef HAVE_GTK_OSX
1643         GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1644         g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1645         g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1646         /*never block termination:*/
1647         g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1648 #endif
1649         
1650         the_ui=linphone_gtk_create_window("main");
1651         
1652         linphone_gtk_create_log_window();
1653         linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1654
1655         linphone_gtk_init_liblinphone(config_file, factory_config_file);
1656         
1657         g_set_application_name(app_name);
1658         pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1659         if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1660         
1661         /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1662         gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1663         gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1664         linphone_gtk_init_main_window();
1665 #ifndef HAVE_GTK_OSX
1666         linphone_gtk_init_status_icon();
1667 #endif
1668         if (!iconified){
1669                 linphone_gtk_show_main_window();
1670                 linphone_gtk_check_soundcards();
1671         }
1672         if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1673                 linphone_gtk_check_for_new_version();
1674
1675         gtk_main();
1676         linphone_gtk_quit();
1677 #ifndef HAVE_GTK_OSX
1678         /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1679         gtk_status_icon_set_visible(icon,FALSE);
1680 #endif
1681         free(progpath);
1682         return 0;
1683 }
1684