]> sjero.net Git - linphone/blob - gtk-glade/main.c
implements global b=AS in sending and receiving side
[linphone] / gtk-glade / 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 #define USE_LIBGLADE 1
21
22 #define VIDEOSELFVIEW_DEFAULT 1
23
24 #include "linphone.h"
25 #include "lpconfig.h"
26
27
28
29 #ifdef USE_LIBGLADE
30 #include <glade/glade.h>
31 #endif
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36
37 #define LINPHONE_ICON "linphone.png"
38
39 const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
40
41 static LinphoneCore *the_core=NULL;
42 static GtkWidget *the_ui=NULL;
43
44 static void linphone_gtk_show(LinphoneCore *lc);
45 static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from);
46 static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from);
47 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
48 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
49 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
50 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
51 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
52 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
53 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
54 static void linphone_gtk_display_question(LinphoneCore *lc, const char *question);
55 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
56 static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate);
57 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
58 static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window);
59
60 static LinphoneCoreVTable vtable={
61         .show=linphone_gtk_show,
62         .inv_recv=linphone_gtk_inv_recv,
63         .bye_recv=linphone_gtk_bye_recv,
64         .notify_presence_recv=linphone_gtk_notify_recv,
65         .new_unknown_subscriber=linphone_gtk_new_unknown_subscriber,
66         .auth_info_requested=linphone_gtk_auth_info_requested,
67         .display_status=linphone_gtk_display_status,
68         .display_message=linphone_gtk_display_message,
69         .display_warning=linphone_gtk_display_warning,
70         .display_url=linphone_gtk_display_url,
71         .display_question=linphone_gtk_display_question,
72         .call_log_updated=linphone_gtk_call_log_updated,
73         .text_received=linphone_gtk_text_received,
74         .general_state=linphone_gtk_general_state,
75         .refer_received=linphone_gtk_refer_received,
76         .buddy_info_updated=linphone_gtk_buddy_info_updated
77 };
78
79 static gboolean verbose=0;
80 static gboolean auto_answer = 0;
81 static gchar * addr_to_call = NULL;
82 static gboolean iconified=FALSE;
83 #ifdef WIN32
84 static gchar *workingdir=NULL;
85 #endif
86 static char *progpath=NULL;
87
88 static GOptionEntry linphone_options[]={
89         {
90                 .long_name="verbose",
91                 .short_name= '\0',
92                 .arg=G_OPTION_ARG_NONE,
93                 .arg_data= (gpointer)&verbose,
94                 .description=N_("log to stdout some debug information while running.")
95         },
96         {
97                 .long_name="iconified",
98                 .short_name= '\0',
99                 .arg=G_OPTION_ARG_NONE,
100                 .arg_data= (gpointer)&iconified,
101                 .description=N_("Start only in the system tray, do not show the main interface.")
102         },
103         {
104             .long_name = "call",
105             .short_name = 'c',
106             .arg = G_OPTION_ARG_STRING,
107             .arg_data = &addr_to_call,
108             .description = N_("address to call right now")
109         },
110         {
111             .long_name = "auto-answer",
112             .short_name = 'a',
113             .arg = G_OPTION_ARG_NONE,
114             .arg_data = (gpointer) & auto_answer,
115             .description = N_("if set automatically answer incoming calls")
116         },
117 #ifdef WIN32
118         {                               /* zsd addition */
119             .long_name = "workdir",
120             .short_name = '\0',
121             .arg = G_OPTION_ARG_STRING,
122             .arg_data = (gpointer) & workingdir,
123             .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
124         },
125 #endif
126         {0}
127 };
128
129 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
130 #define BUILD_TREE_XML_DIR "gtk-glade"
131
132 #ifndef WIN32
133 #define CONFIG_FILE ".linphonerc"
134 #else
135 #define CONFIG_FILE "linphonerc"
136 #endif
137
138
139
140 static char _config_file[1024];
141
142
143 const char *linphone_gtk_get_config_file(){
144         /*try accessing a local file first if exists*/
145         if (access(CONFIG_FILE,F_OK)==0){
146                 snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
147         }else{
148 #ifdef WIN32
149                 const char *appdata=getenv("APPDATA");
150                 if (appdata){
151                         snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
152                         CreateDirectory(_config_file,NULL);
153                         snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR "\\" CONFIG_FILE);
154                 }
155 #else
156                 const char *home=getenv("HOME");
157                 if (home==NULL) home=".";
158                 snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
159 #endif
160         }
161         return _config_file;
162 }
163
164
165 #define FACTORY_CONFIG_FILE "linphonerc.factory"
166 static char _factory_config_file[1024];
167 static const char *linphone_gtk_get_factory_config_file(){
168         /*try accessing a local file first if exists*/
169         if (access(FACTORY_CONFIG_FILE,F_OK)==0){
170                 snprintf(_factory_config_file,sizeof(_factory_config_file),
171                                                  "%s",FACTORY_CONFIG_FILE);
172         } else {
173                 char *progdir;
174                 
175                 if (progpath != NULL) {
176                         char *basename;
177                         progdir = strdup(progpath);
178 #ifdef WIN32
179                         basename = strrchr(progdir, '\\');
180                         if (basename != NULL) {
181                                 basename ++;
182                                 *basename = '\0';
183                                 snprintf(_factory_config_file, sizeof(_factory_config_file),
184                                                                  "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
185                         } else {
186                                 if (workingdir!=NULL) {
187                                         snprintf(_factory_config_file, sizeof(_factory_config_file),
188                                                                          "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
189                                 } else {
190                                         free(progdir);
191                                         return NULL;
192                                 }
193                         }
194 #else
195                         basename = strrchr(progdir, '/');
196                         if (basename != NULL) {
197                                 basename ++;
198                                 *basename = '\0';
199                                 snprintf(_factory_config_file, sizeof(_factory_config_file),
200                                                                  "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
201                         } else {
202                                 free(progdir);
203                                 return NULL;
204                         }
205 #endif
206                         free(progdir);
207                 }
208         }
209         return _factory_config_file;
210 }
211
212 static void linphone_gtk_init_liblinphone(const char *config_file,
213                 const char *factory_config_file) {
214         linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
215         the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
216         linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
217 }
218
219
220
221 LinphoneCore *linphone_gtk_get_core(void){
222         return the_core;
223 }
224
225 GtkWidget *linphone_gtk_get_main_window(){
226         return the_ui;
227 }
228
229 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
230         static const char *icon_path=NULL;
231         static const char *hiddens=NULL;
232         static const char *shown=NULL;
233         static bool_t config_loaded=FALSE;
234         if (linphone_gtk_get_core()==NULL) return;
235         if (config_loaded==FALSE){
236                 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
237                 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
238                 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
239                 config_loaded=TRUE;
240         }
241         if (hiddens)
242                 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
243         if (shown)
244                 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
245         if (icon_path) {
246                 GdkPixbuf *pbuf=create_pixbuf(icon_path);
247                 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
248                 g_object_unref(G_OBJECT(pbuf));
249         }
250 }
251
252 #ifdef USE_LIBGLADE
253
254 GtkWidget *linphone_gtk_create_window(const char *window_name){
255         GtkWidget *w;
256         GladeXML *gxml;
257         char path[2048];
258         snprintf(path,sizeof(path),"%s/%s.glade",BUILD_TREE_XML_DIR,window_name);
259         if (access(path,F_OK)!=0){
260                 snprintf(path,sizeof(path),"%s/%s.glade",INSTALLED_XML_DIR,window_name);
261                 if (access(path,F_OK)!=0){
262                         g_error("Could not locate neither %s/%s.glade and %s/%s.glade .",BUILD_TREE_XML_DIR,window_name,
263                                 INSTALLED_XML_DIR,window_name);
264                         return NULL;
265                 }
266         }
267         gxml=glade_xml_new(path,NULL,NULL);
268         glade_xml_signal_autoconnect(gxml);
269         w=glade_xml_get_widget(gxml,window_name);
270         if (w==NULL) g_error("Could not retrieve '%s' window from xml file",window_name);
271         linphone_gtk_configure_window(w,window_name);
272         return w;
273 }
274
275 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
276         GtkWidget *w;
277         GladeXML *gxml=glade_get_widget_tree(window);
278         if (gxml==NULL) g_error("Could not retrieve XML tree of window %s",name);
279         w=glade_xml_get_widget(gxml,name);
280         if (w==NULL) g_error("Could not retrieve widget %s",name);
281         return GTK_WIDGET(w);
282 }
283
284 #else
285
286 GtkWidget *linphone_gtk_create_window(const char *window_name){
287         
288 }
289
290 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
291         GObject *w=gtk_builder_get_object(the_ui,name);
292         if (w==NULL){
293                 g_error("No widget named %s found in xml interface.",name);
294         }
295         return GTK_WIDGET(w);
296 }
297
298 #endif
299
300 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
301         GtkWidget *dialog;
302         GtkWidget *main_window=linphone_gtk_get_main_window();
303         
304         gtk_widget_show(main_window);
305         if (type==GTK_MESSAGE_QUESTION)
306         {
307                 /* draw a question box. link to dialog_click callback */
308                 dialog = gtk_message_dialog_new (
309                                 GTK_WINDOW(main_window),
310                                 GTK_DIALOG_DESTROY_WITH_PARENT,
311                                 GTK_MESSAGE_QUESTION,
312                                 GTK_BUTTONS_YES_NO,
313                                 "%s",
314                                 (const gchar*)message);
315                 /* connect to some callback : REVISIT */
316                 /*
317                 g_signal_connect_swapped (G_OBJECT (dialog), "response",
318                            G_CALLBACK (dialog_click),
319                            G_OBJECT (dialog));
320                 */
321                 /* actually show the box */
322                 gtk_widget_show(dialog);
323         }
324         else
325         {
326                 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
327                                   GTK_DIALOG_DESTROY_WITH_PARENT,
328                                   type,
329                                   GTK_BUTTONS_CLOSE,
330                                   "%s",
331                                   (const gchar*)message);
332                 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
333                 g_signal_connect_swapped (G_OBJECT (dialog), "response",
334                            G_CALLBACK (gtk_widget_destroy),
335                            G_OBJECT (dialog));
336                 gtk_widget_show(dialog);
337         }
338 }
339
340 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
341         if (id==GTK_RESPONSE_CANCEL){
342                 gtk_widget_destroy(GTK_WIDGET(dialog));
343         }
344 }
345
346 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
347         g_message("About url clicked");
348         linphone_gtk_open_browser(url);
349 }
350
351 void linphone_gtk_show_about(){
352         struct stat filestat;
353         const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
354         GtkWidget *about;
355         GdkPixbuf *logo=create_pixbuf(
356             linphone_gtk_get_ui_config("logo","linphone-banner.png"));
357         
358         about=linphone_gtk_create_window("about");
359         gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
360         memset(&filestat,0,sizeof(filestat));
361         if (stat(license_file,&filestat)!=0){
362                 license_file="COPYING";
363                 stat(license_file,&filestat);
364         }
365         if (filestat.st_size>0){
366                 char *license=g_malloc(filestat.st_size+1);
367                 FILE *f=fopen(license_file,"r");
368                 if (f && fread(license,filestat.st_size,1,f)==1){
369                         license[filestat.st_size]='\0';
370                         gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
371                 }
372                 g_free(license);
373         }
374         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
375         gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
376         gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
377         if (logo)       gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
378             
379         gtk_widget_show(about);
380 }
381
382 static void set_video_window_decorations(GdkWindow *w){
383         const char *title=linphone_gtk_get_ui_config("title","Linphone");
384         const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
385         char video_title[256];
386         GdkPixbuf *pbuf=create_pixbuf(icon_path);
387         if (!linphone_core_in_call(linphone_gtk_get_core())){
388                 snprintf(video_title,sizeof(video_title),"%s video",title);
389                 /* When not in call, treat the video as a normal window */
390                 gdk_window_set_keep_above(w, FALSE);
391         }else{
392                 LinphoneAddress *uri =
393                         linphone_address_clone(linphone_core_get_remote_uri(linphone_gtk_get_core()));
394                 char *display_name;
395
396                 linphone_address_clean(uri);
397                 if (linphone_address_get_display_name(uri)!=NULL){
398                         display_name=ms_strdup(linphone_address_get_display_name(uri));
399                 }else{
400                         display_name=linphone_address_as_string(uri);
401                 }
402                 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
403                 linphone_address_destroy(uri);
404                 ms_free(display_name);
405
406                 /* During calls, bring up the video window, arrange so that
407                 it is above all the other windows */
408                 gdk_window_deiconify(w);
409                 gdk_window_set_keep_above(w,TRUE);
410                 /* Maybe we should have the following, but then we want to
411                 have a timer that turns it off after a little while. */
412                 /* gdk_window_set_urgency_hint(w,TRUE); */
413         }
414         gdk_window_set_title(w,video_title);
415         /* Refrain the video window to be closed at all times. */
416         gdk_window_set_functions(w,
417                                  GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
418                                  GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
419         if (pbuf){
420                 GList *l=NULL;
421                 l=g_list_append(l,pbuf);
422                 gdk_window_set_icon_list(w,l);
423                 g_list_free(l);
424                 g_object_unref(G_OBJECT(pbuf));
425         }
426 }
427
428 static gboolean video_needs_update=FALSE;
429
430 static void update_video_title(){
431         video_needs_update=TRUE;
432 }
433
434 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
435         static gboolean first_time=TRUE;
436         unsigned long id;
437         static unsigned long previd=0;
438         static gboolean in_iterate=FALSE;
439         
440         /*avoid reentrancy*/
441         if (in_iterate) return TRUE;
442         in_iterate=TRUE;
443         linphone_core_iterate(lc);
444         if (first_time){
445                 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
446                 linphone_gtk_show_directory_search();
447                 first_time=FALSE;
448         }
449
450         id=linphone_core_get_native_video_window_id(lc);
451         if (id!=previd || video_needs_update){
452                 GdkWindow *w;
453                 previd=id;
454                 if (id!=0){
455                         ms_message("Updating window decorations");
456 #ifndef WIN32
457                         w=gdk_window_foreign_new(id);
458 #else
459                         w=gdk_window_foreign_new((HANDLE)id);
460 #endif
461                         if (w) {
462                                 set_video_window_decorations(w);
463                                 g_object_unref(G_OBJECT(w));
464                         }
465                         else ms_error("gdk_window_foreign_new() failed");
466                         if (video_needs_update) video_needs_update=FALSE;
467                 }
468         }
469         if (addr_to_call!=NULL){
470                 /*make sure we are not showing the login screen*/
471                 GtkWidget *mw=linphone_gtk_get_main_window();
472                 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
473                 if (!GTK_WIDGET_VISIBLE(login_frame)){
474                         GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
475                         gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
476                         addr_to_call=NULL;
477                         linphone_gtk_start_call(uri_bar);
478                 }
479         }
480         in_iterate=FALSE;
481         return TRUE;
482 }
483
484 static void load_uri_history(){
485         GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
486         char key[20];
487         int i;
488         GtkEntryCompletion *gep=gtk_entry_completion_new();
489         GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
490         for (i=0;;i++){
491                 const char *uri;
492                 snprintf(key,sizeof(key),"uri%i",i);
493                 uri=linphone_gtk_get_ui_config(key,NULL);
494                 if (uri!=NULL) {
495                         GtkTreeIter iter;
496                         gtk_list_store_append(model,&iter);
497                         gtk_list_store_set(model,&iter,0,uri,-1);
498                         if (i==0) gtk_entry_set_text(uribar,uri);
499                 }
500                 else break;
501         }
502         gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
503         gtk_entry_completion_set_text_column(gep,0);
504         gtk_entry_set_completion(uribar,gep);
505 }
506
507 static void save_uri_history(){
508         LinphoneCore *lc=linphone_gtk_get_core();
509         LpConfig *cfg=linphone_core_get_config(lc);
510         GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
511         char key[20];
512         int i=0;
513         char *uri=NULL;
514         GtkTreeIter iter;
515         GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
516
517         if (!gtk_tree_model_get_iter_first(model,&iter)) return;
518         do {
519                 gtk_tree_model_get(model,&iter,0,&uri,-1);
520                 if (uri) {
521                         snprintf(key,sizeof(key),"uri%i",i);
522                         lp_config_set_string(cfg,"GtkUi",key,uri);
523                         g_free(uri);
524                 }else break;
525                 i++;
526                 if (i>5) break;
527         }while(gtk_tree_model_iter_next(model,&iter));
528         lp_config_sync(cfg);
529 }
530
531 static void completion_add_text(GtkEntry *entry, const char *text){
532         GtkTreeIter iter;
533         GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
534         
535         if (gtk_tree_model_get_iter_first(model,&iter)){ 
536                 do {
537                         gchar *uri=NULL;
538                         gtk_tree_model_get(model,&iter,0,&uri,-1);
539                         if (uri!=NULL){
540                                 if (strcmp(uri,text)==0) {
541                                         /*remove text */
542                                         gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
543                                         g_free(uri);
544                                         break;
545                                 }
546                                 g_free(uri);
547                         }
548                 }while (gtk_tree_model_iter_next(model,&iter));
549         }
550         /* and prepend it on top of the list */
551         gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
552         gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
553         save_uri_history();
554 }
555
556 void linphone_gtk_call_terminated(const char *error){
557         GtkWidget *mw=linphone_gtk_get_main_window();
558         GtkWidget *icw;
559         gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
560         gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
561         linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"main_mute")),FALSE);
562         if (linphone_gtk_use_in_call_view())
563                 linphone_gtk_in_call_view_terminate(error);
564         update_video_title();
565         icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
566         if (icw!=NULL){
567                 g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
568                 gtk_widget_destroy(icw);
569         }
570 }
571
572 static gboolean in_call_timer(){
573         if (linphone_core_in_call(linphone_gtk_get_core())){
574                 linphone_gtk_in_call_view_update_duration(
575                         linphone_core_get_current_call_duration(linphone_gtk_get_core()));
576                 return TRUE;
577         }
578         return FALSE;
579 }
580
581 static void linphone_gtk_call_started(GtkWidget *mw){
582         gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
583         gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE);
584         update_video_title();
585         if (linphone_gtk_use_in_call_view())
586                 g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
587 }
588
589 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
590         const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
591         if (linphone_core_invite(linphone_gtk_get_core(),entered)==0) {
592                 completion_add_text(GTK_ENTRY(uri_bar),entered);
593         }else{
594                 linphone_gtk_call_terminated(NULL);
595         }
596         return FALSE;
597 }
598
599 static void _linphone_gtk_accept_call(){
600         LinphoneCore *lc=linphone_gtk_get_core();
601         GtkWidget *mw=linphone_gtk_get_main_window();
602         GtkWidget *icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
603         if (icw!=NULL){
604                 g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
605                 gtk_widget_destroy(icw);
606         }
607
608         linphone_core_accept_call(lc,NULL);
609         linphone_gtk_call_started(linphone_gtk_get_main_window());
610         if (linphone_gtk_use_in_call_view()){
611                 linphone_gtk_in_call_view_set_in_call();
612                 linphone_gtk_show_in_call_view();
613         }
614         linphone_gtk_enable_mute_button(
615                 GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute"))
616                 ,TRUE);
617 }
618
619 void linphone_gtk_start_call(GtkWidget *w){
620         LinphoneCore *lc=linphone_gtk_get_core();
621         if (linphone_core_inc_invite_pending(lc)){
622                 /*accept the call*/
623                 _linphone_gtk_accept_call();
624         }else if (linphone_core_in_call(lc)) {
625                 /*already in call */
626         }else{
627                 /*change into in-call mode, then do the work later as it might block a bit */
628                 GtkWidget *mw=gtk_widget_get_toplevel(w);
629                 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
630                 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
631                 linphone_gtk_call_started(mw);
632                 if (linphone_gtk_use_in_call_view()){
633                         linphone_gtk_in_call_view_set_calling(entered);
634                         linphone_gtk_show_in_call_view();
635                 }
636                 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
637         }
638 }
639
640 void linphone_gtk_uri_bar_activate(GtkWidget *w){
641         linphone_gtk_start_call(w);
642 }
643
644
645 void linphone_gtk_terminate_call(GtkWidget *button){
646         linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
647 }
648
649 void linphone_gtk_decline_call(GtkWidget *button){
650         linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
651         gtk_widget_destroy(gtk_widget_get_toplevel(button));
652 }
653
654 void linphone_gtk_accept_call(GtkWidget *button){
655         _linphone_gtk_accept_call();
656 }
657
658 static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window){
659         linphone_gtk_accept_call(linphone_gtk_get_widget(incall_window,"accept_call"));
660         return FALSE;
661 }
662
663 void linphone_gtk_set_audio_video(){
664         linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
665         linphone_core_enable_video_preview(linphone_gtk_get_core(),
666             linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
667 }
668
669 void linphone_gtk_set_audio_only(){
670         linphone_core_enable_video(linphone_gtk_get_core(),FALSE,FALSE);
671         linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
672 }
673
674 void linphone_gtk_enable_self_view(GtkWidget *w){
675         gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
676         LinphoneCore *lc=linphone_gtk_get_core();
677         linphone_core_enable_video_preview(lc,val);
678         linphone_core_enable_self_view(lc,val);
679         linphone_gtk_set_ui_config_int("videoselfview",val);
680 }
681
682 void linphone_gtk_used_identity_changed(GtkWidget *w){
683         int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
684         char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
685         if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
686                 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
687                 linphone_gtk_show_directory_search();
688         }
689         if (sel) g_free(sel);
690 }
691
692 static void linphone_gtk_show_main_window(){
693         GtkWidget *w=linphone_gtk_get_main_window();
694         LinphoneCore *lc=linphone_gtk_get_core();
695         if (linphone_core_video_enabled(lc)){
696                 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
697                 VIDEOSELFVIEW_DEFAULT));
698         }
699         gtk_widget_show(w);
700         gtk_window_present(GTK_WINDOW(w));
701 }
702
703 static void linphone_gtk_show(LinphoneCore *lc){
704         linphone_gtk_show_main_window();
705 }
706
707 static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){
708         GtkWidget *w=linphone_gtk_create_window("incoming_call");
709         GtkWidget *label;
710         gchar *msg;
711
712         if (auto_answer){
713                 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w);
714         }
715
716         gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window()));
717         gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT);
718
719         label=linphone_gtk_get_widget(w,"message");
720         msg=g_strdup_printf(_("Incoming call from %s"),from);
721         gtk_label_set_text(GTK_LABEL(label),msg);
722         gtk_window_set_title(GTK_WINDOW(w),msg);
723         gtk_widget_show(w);
724         gtk_window_present(GTK_WINDOW(w));
725         /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/
726         g_free(msg);
727         g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w);
728         gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),
729                         from);
730 }
731
732 static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){
733         
734 }
735
736 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
737         linphone_gtk_show_friends();
738 }
739
740 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
741         switch(response_id){
742                 case GTK_RESPONSE_YES:
743                         linphone_gtk_show_contact(lf);
744                 break;
745                 default:
746                         linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
747         }
748         gtk_widget_destroy(dialog);
749 }
750
751 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
752         GtkWidget *dialog;
753
754         if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
755                 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
756                 return;
757         }
758
759         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);
760         dialog = gtk_message_dialog_new (
761                                 GTK_WINDOW(linphone_gtk_get_main_window()),
762                                 GTK_DIALOG_DESTROY_WITH_PARENT,
763                                 GTK_MESSAGE_QUESTION,
764                                 GTK_BUTTONS_YES_NO,
765                                 "%s",
766                                 message);
767         g_free(message);
768         g_signal_connect(G_OBJECT (dialog), "response",
769                 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
770         /* actually show the box */
771         gtk_widget_show(dialog);
772 }
773
774 typedef struct _AuthTimeout{
775         GtkWidget *w;
776 } AuthTimeout;
777
778
779 static void auth_timeout_clean(AuthTimeout *tout){
780         tout->w=NULL;
781 }
782
783 static gboolean auth_timeout_destroy(AuthTimeout *tout){
784         if (tout->w)  {
785                 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
786                 gtk_widget_destroy(tout->w);
787         }
788         g_free(tout);
789         return FALSE;
790 }
791
792 static AuthTimeout * auth_timeout_new(GtkWidget *w){
793         AuthTimeout *tout=g_new(AuthTimeout,1);
794         tout->w=w;
795         /*so that the timeout no more references the widget when it is destroyed:*/
796         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
797         /*so that the widget is automatically destroyed after some time */
798         g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
799         return tout;
800 }
801
802 void linphone_gtk_password_cancel(GtkWidget *w){
803         LinphoneAuthInfo *info;
804         GtkWidget *window=gtk_widget_get_toplevel(w);
805         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
806         linphone_core_abort_authentication(linphone_gtk_get_core(),info);
807         gtk_widget_destroy(window);
808 }
809
810 void linphone_gtk_password_ok(GtkWidget *w){
811         GtkWidget *entry;
812         GtkWidget *window=gtk_widget_get_toplevel(w);
813         LinphoneAuthInfo *info;
814         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
815         g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
816         entry=linphone_gtk_get_widget(window,"password_entry");
817         linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
818         linphone_auth_info_set_userid(info,
819                 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
820         linphone_core_add_auth_info(linphone_gtk_get_core(),info);
821         gtk_widget_destroy(window);
822 }
823
824 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
825         GtkWidget *w=linphone_gtk_create_window("password");
826         GtkWidget *label=linphone_gtk_get_widget(w,"message");
827         LinphoneAuthInfo *info;
828         gchar *msg;
829         GtkWidget *mw=linphone_gtk_get_main_window();
830         
831         if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
832                 /*don't prompt for authentication when login frame is visible*/
833                 linphone_core_abort_authentication(lc,NULL);
834                 return;
835         }
836
837         msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
838                 username,realm);
839         gtk_label_set_markup(GTK_LABEL(label),msg);
840         g_free(msg);
841         gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
842         info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
843         g_object_set_data(G_OBJECT(w),"auth_info",info);
844         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
845         gtk_widget_show(w);
846         auth_timeout_new(w);
847 }
848
849 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
850         GtkWidget *w=linphone_gtk_get_main_window();
851         GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
852         gtk_statusbar_push(GTK_STATUSBAR(status_bar),
853                         gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
854                         status);
855 }
856
857 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
858         linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
859 }
860
861 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
862         linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
863 }
864
865 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
866         char richtext[4096];
867         snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
868         linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
869 }
870
871 static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){
872         linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question);
873 }
874
875 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
876         GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
877         if (w) linphone_gtk_call_log_update(w);
878 }
879
880 static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){
881         switch(gstate->new_state){
882                 case GSTATE_CALL_OUT_CONNECTED:
883                 case GSTATE_CALL_IN_CONNECTED:
884                         if (linphone_gtk_use_in_call_view())
885                                 linphone_gtk_in_call_view_set_in_call();
886                         linphone_gtk_enable_mute_button(
887                                 GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
888                         TRUE);
889                 break;
890                 case GSTATE_CALL_ERROR:
891                         linphone_gtk_call_terminated(gstate->message);
892                 break;
893                 case GSTATE_CALL_END:
894                         linphone_gtk_call_terminated(NULL);
895                 break;
896                 default:
897                 break;
898         }
899 }
900
901 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
902         GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
903         gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
904 }
905
906 void linphone_gtk_open_browser(const char *url){
907         /*in gtk 2.16, gtk_show_uri does not work...*/
908 #ifndef WIN32
909 #if GTK_CHECK_VERSION(2,18,3)
910         gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
911 #else
912         char cl[255];
913         snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
914         g_spawn_command_line_async(cl,NULL);
915 #endif
916 #else /*WIN32*/
917         ShellExecute(0,"open",url,NULL,NULL,1);
918 #endif
919 }
920
921 void linphone_gtk_link_to_website(GtkWidget *item){
922         const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
923         linphone_gtk_open_browser(home);
924 }
925
926 static GtkWidget *create_icon_menu(){
927         GtkWidget *menu=gtk_menu_new();
928         GtkWidget *menu_item;
929         GtkWidget *image;
930         gchar *tmp;
931         const gchar *homesite;
932         
933         homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
934         menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
935         tmp=g_strdup(homesite);
936         g_object_set_data(G_OBJECT(menu_item),"home",tmp);
937         g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
938         
939         image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
940         gtk_widget_show(image);
941         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
942         //g_object_unref(G_OBJECT(image));
943         gtk_widget_show(menu_item);
944         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
945         g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
946         
947         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
948         gtk_widget_show(menu_item);
949         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
950         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
951         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
952         gtk_widget_show(menu_item);
953         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
954         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
955         gtk_widget_show(menu);
956         return menu;
957 }
958
959 static GtkStatusIcon *icon=NULL;
960
961 static void linphone_gtk_init_status_icon(){
962         const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
963         GdkPixbuf *pbuf=create_pixbuf(icon_path);
964         GtkWidget *menu=create_icon_menu();
965         const char *title;
966         icon=gtk_status_icon_new_from_pixbuf(pbuf);
967         g_object_unref(G_OBJECT(pbuf));
968         g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
969         g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
970         title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
971         gtk_status_icon_set_tooltip(icon,title);
972         gtk_status_icon_set_visible(icon,TRUE);
973         g_object_set_data(G_OBJECT(icon),"menu",menu);
974         g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
975 }
976
977 void linphone_gtk_load_identities(void){
978         const MSList *elem;
979         GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
980         char *def_identity;
981         LinphoneProxyConfig *def=NULL;
982         int def_index=0,i;
983         GtkListStore *store;
984
985         store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
986         gtk_list_store_clear(store);
987
988         linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
989         def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
990         gtk_combo_box_append_text(box,def_identity);
991         g_free(def_identity);
992         for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
993                         elem!=NULL;
994                         elem=ms_list_next(elem),i++){
995                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
996                 gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg));
997                 if (cfg==def) {
998                         def_index=i;
999                 }
1000         }
1001         gtk_combo_box_set_active(box,def_index);
1002 }
1003
1004 static void linphone_gtk_dtmf_clicked(GtkButton *button){
1005         const char *label=gtk_button_get_label(button);
1006         if (linphone_core_in_call(linphone_gtk_get_core())){
1007                 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1008         }else{
1009                 GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1010                 int pos=-1;
1011                 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1012         }
1013 }
1014
1015 static void linphone_gtk_connect_digits(void){
1016         GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1017         GList *children=gtk_container_get_children(cont);
1018         GList *elem;
1019         for(elem=children;elem!=NULL;elem=elem->next){
1020                 GtkButton *button=GTK_BUTTON(elem->data);
1021                 g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_dtmf_clicked,NULL);
1022         }
1023 }
1024
1025 static void linphone_gtk_check_menu_items(void){
1026         bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core());
1027         bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1028         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1029                                         linphone_gtk_get_main_window(),
1030                                         audio_only ? "audio_only_item" : "video_item")), TRUE);
1031         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1032                                         linphone_gtk_get_main_window(),"selfview_item")),selfview);
1033 }
1034
1035 static gboolean linphone_gtk_can_manage_accounts(){
1036         LinphoneCore *lc=linphone_gtk_get_core();
1037         const MSList *elem;
1038         for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1039                 SipSetup *ss=(SipSetup*)elem->data;
1040                 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1041                         return TRUE;
1042                 }
1043         }
1044         return FALSE;
1045 }
1046
1047 static void linphone_gtk_configure_main_window(){
1048         static gboolean config_loaded=FALSE;
1049         static const char *title;
1050         static const char *home;
1051         static const char *start_call_icon;
1052         static const char *stop_call_icon;
1053         static const char *search_icon;
1054         static gboolean update_check_menu;
1055         static gboolean buttons_have_borders;
1056         GtkWidget *w=linphone_gtk_get_main_window();
1057         if (!config_loaded){
1058                 title=linphone_gtk_get_ui_config("title","Linphone");
1059                 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1060                 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1061                 stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
1062                 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1063                 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1064                 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1065                 config_loaded=TRUE;
1066         }
1067         linphone_gtk_configure_window(w,"main_window");
1068         if (title) {
1069                 gtk_window_set_title(GTK_WINDOW(w),title);
1070 #if GTK_CHECK_VERSION(2,16,0)
1071                 gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),title);
1072 #endif
1073         }
1074         if (start_call_icon){
1075                 GdkPixbuf *pbuf=create_pixbuf(start_call_icon);
1076                 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"start_call_icon")),pbuf);
1077                 if (buttons_have_borders)
1078                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NORMAL);
1079                 g_object_unref(G_OBJECT(pbuf));
1080         }
1081         if (stop_call_icon){
1082                 GdkPixbuf *pbuf=create_pixbuf(stop_call_icon);
1083                 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf);
1084                 if (buttons_have_borders)
1085                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NORMAL);
1086                 g_object_unref(G_OBJECT(pbuf));
1087         }
1088         if (search_icon){
1089                 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1090                 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1091                 g_object_unref(G_OBJECT(pbuf));
1092         }
1093         if (home){
1094                 gchar *tmp;
1095                 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1096                 tmp=g_strdup(home);
1097                 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1098         }
1099         {
1100                 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1101                 if (pbuf) {
1102                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1103                         g_object_unref(G_OBJECT(pbuf));
1104                 }
1105         }
1106         {
1107                 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1108                 if (pbuf) {
1109                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")),pbuf);
1110                         g_object_unref(G_OBJECT(pbuf));
1111                 }
1112         }
1113         if (!linphone_gtk_can_manage_accounts())
1114                 gtk_widget_hide(linphone_gtk_get_widget(w,"run_assistant"));
1115         if (update_check_menu){
1116                 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck"));
1117         }
1118 }
1119
1120 void linphone_gtk_manage_login(void){
1121         LinphoneCore *lc=linphone_gtk_get_core();
1122         LinphoneProxyConfig *cfg=NULL;
1123         linphone_core_get_default_proxy(lc,&cfg);
1124         if (cfg){
1125                 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1126                 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1127                         linphone_gtk_show_login_frame(cfg);
1128                 }
1129         }
1130 }
1131
1132 static void linphone_gtk_init_main_window(){
1133         GtkWidget *main_window;
1134
1135         linphone_gtk_configure_main_window();
1136         linphone_gtk_manage_login();
1137         load_uri_history();
1138         linphone_gtk_load_identities();
1139         linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1140         linphone_gtk_show_friends();
1141         linphone_gtk_connect_digits();
1142         linphone_gtk_check_menu_items();
1143         main_window=linphone_gtk_get_main_window();
1144         linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
1145                                         "main_mute")),FALSE);
1146         linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
1147                                         "incall_mute")),FALSE);
1148         if (!linphone_gtk_use_in_call_view()) {
1149                 gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
1150         }
1151         if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started(
1152                 linphone_gtk_get_main_window());/*hide the call button, show terminate button*/
1153 }
1154
1155 void linphone_gtk_close(){
1156         /* couldn't find a way to prevent closing to destroy the main window*/
1157         LinphoneCore *lc=linphone_gtk_get_core();
1158         the_ui=NULL;
1159         the_ui=linphone_gtk_create_window("main");
1160         linphone_gtk_init_main_window();
1161         /*shutdown call if any*/
1162         if (linphone_core_in_call(lc)){
1163                 linphone_core_terminate_call(lc,NULL);
1164                 linphone_gtk_call_terminated(NULL);
1165         }
1166         linphone_core_enable_video_preview(lc,FALSE);
1167 }
1168
1169 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1170         if (verbose){
1171                 const char *lname="undef";
1172                 char *msg;
1173                 #ifdef __linux
1174                 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1175                 #endif
1176                 switch(lev){
1177                         case ORTP_DEBUG:
1178                                 lname="debug";
1179                                 break;
1180                         case ORTP_MESSAGE:
1181                                 lname="message";
1182                                 break;
1183                         case ORTP_WARNING:
1184                                 lname="warning";
1185                                 break;
1186                         case ORTP_ERROR:
1187                                 lname="error";
1188                                 break;
1189                         case ORTP_FATAL:
1190                                 lname="fatal";
1191                                 break;
1192                         default:
1193                                 g_error("Bad level !");
1194                 }
1195 #ifdef __linux
1196                 va_copy(cap,args);
1197                 msg=g_strdup_vprintf(fmt,cap);
1198                 va_end(cap);
1199 #else
1200                 msg=g_strdup_vprintf(fmt,args);
1201 #endif
1202                 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1203                 ortp_free(msg);
1204         }
1205         linphone_gtk_log_push(lev,fmt,args);
1206 }
1207
1208
1209 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1210     GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1211                 linphone_gtk_get_main_window(), "uribar"));
1212         linphone_gtk_show_main_window();
1213         gtk_entry_set_text(uri_bar, refer_to);
1214         linphone_gtk_start_call(linphone_gtk_get_main_window());
1215 }
1216
1217 static void linphone_gtk_check_soundcards(){
1218         const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1219         if (devices==NULL || devices[0]==NULL){
1220                 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1221                     _("No sound cards have been detected on this computer.\n"
1222                             "You won't be able to send or receive audio calls."));
1223         }
1224 }
1225
1226 int main(int argc, char *argv[]){
1227 #ifdef ENABLE_NLS
1228         void *p;
1229 #endif
1230         const char *config_file;
1231         const char *factory_config_file;
1232         const char *lang;
1233         GtkSettings *settings;
1234
1235         g_thread_init(NULL);
1236         gdk_threads_init();
1237         progpath = strdup(argv[0]);
1238         
1239         config_file=linphone_gtk_get_config_file();
1240
1241 #ifdef WIN32
1242         /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1243         if ((lang=getenv("LANG"))!=NULL){
1244                 if (atoi(lang)!=0){
1245                         char tmp[128];
1246                         snprintf(tmp,sizeof(tmp),"LANG=",lang);
1247                         _putenv(tmp);
1248                 }
1249         }
1250 #endif
1251
1252         if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1253 #ifdef WIN32
1254                 char tmp[128];
1255                 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1256                 _putenv(tmp);
1257 #else
1258                 setenv("LANG",lang,1);
1259 #endif
1260         }
1261
1262 #ifdef ENABLE_NLS
1263         p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1264         if (p==NULL) perror("bindtextdomain failed");
1265         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1266         textdomain (GETTEXT_PACKAGE);
1267 #else
1268         g_message("NLS disabled.\n");
1269 #endif
1270 #ifdef WIN32
1271         gtk_rc_add_default_file("./gtkrc");
1272 #endif
1273         gdk_threads_enter();
1274         
1275         if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1276                                 linphone_options,NULL,NULL)){
1277                 gdk_threads_leave();
1278                 return -1;
1279         }
1280         settings=gtk_settings_get_default();
1281         g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1282         g_object_set(settings, "gtk-button-images", TRUE, NULL);
1283 #ifdef WIN32
1284         if (workingdir!=NULL)
1285                 _chdir(workingdir);
1286 #endif
1287         /* Now, look for the factory configuration file, we do it this late
1288                  since we want to have had time to change directory and to parse
1289                  the options, in case we needed to access the working directory */
1290         factory_config_file = linphone_gtk_get_factory_config_file();
1291
1292         if (linphone_core_wake_up_possible_already_running_instance(
1293                 config_file, addr_to_call) == 0){
1294                 g_message("addr_to_call=%s",addr_to_call);
1295                 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1296                 g_warning("This instance is going to exit now.");
1297                 gdk_threads_leave();
1298                 return 0;
1299         }
1300
1301         add_pixmap_directory("pixmaps");
1302         add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1303
1304         the_ui=linphone_gtk_create_window("main");
1305         
1306         linphone_gtk_create_log_window();
1307         linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1308
1309         linphone_gtk_init_liblinphone(config_file, factory_config_file);
1310         /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1311         gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1312         gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1313         linphone_gtk_init_main_window();
1314         linphone_gtk_init_status_icon();
1315         if (!iconified){
1316                 linphone_gtk_show_main_window();
1317                 linphone_gtk_check_soundcards();
1318         }
1319         if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1320                 linphone_gtk_check_for_new_version();
1321
1322         gtk_main();
1323         gdk_threads_leave();
1324         linphone_gtk_destroy_log_window();
1325         linphone_core_destroy(the_core);
1326         /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1327         gtk_status_icon_set_visible(icon,FALSE);
1328         free(progpath);
1329         return 0;
1330 }