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