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