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