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