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