]> sjero.net Git - linphone/blob - gtk-glade/main.c
Merge branch 'master' into dev_multicall
[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, LinphoneCall *call);
46 static void linphone_gtk_bye_recv(LinphoneCore *lc, LinphoneCall *call);
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, LinphoneCall *call, 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_current_call_remote_address(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=linphone_address_get_display_name_unquoted (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)!=NULL) {
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, LinphoneCall *call){
708         GtkWidget *w=linphone_gtk_create_window("incoming_call");
709         GtkWidget *label;
710         gchar *msg;
711         char *from=linphone_call_get_remote_address_as_string(call);
712
713         if (auto_answer){
714                 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w);
715         }
716
717         gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window()));
718         gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT);
719
720         label=linphone_gtk_get_widget(w,"message");
721         msg=g_strdup_printf(_("Incoming call from %s"),from);
722         gtk_label_set_text(GTK_LABEL(label),msg);
723         gtk_window_set_title(GTK_WINDOW(w),msg);
724         gtk_widget_show(w);
725         gtk_window_present(GTK_WINDOW(w));
726         /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/
727         g_free(msg);
728         g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w);
729         gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),
730                         from);
731         ms_free(from);
732 }
733
734 static void linphone_gtk_bye_recv(LinphoneCore *lc, LinphoneCall *call){
735         
736 }
737
738 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
739         linphone_gtk_show_friends();
740 }
741
742 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
743         switch(response_id){
744                 case GTK_RESPONSE_YES:
745                         linphone_gtk_show_contact(lf);
746                 break;
747                 default:
748                         linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
749         }
750         gtk_widget_destroy(dialog);
751 }
752
753 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
754         GtkWidget *dialog;
755
756         if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
757                 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
758                 return;
759         }
760
761         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);
762         dialog = gtk_message_dialog_new (
763                                 GTK_WINDOW(linphone_gtk_get_main_window()),
764                                 GTK_DIALOG_DESTROY_WITH_PARENT,
765                                 GTK_MESSAGE_QUESTION,
766                                 GTK_BUTTONS_YES_NO,
767                                 "%s",
768                                 message);
769         g_free(message);
770         g_signal_connect(G_OBJECT (dialog), "response",
771                 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
772         /* actually show the box */
773         gtk_widget_show(dialog);
774 }
775
776 typedef struct _AuthTimeout{
777         GtkWidget *w;
778 } AuthTimeout;
779
780
781 static void auth_timeout_clean(AuthTimeout *tout){
782         tout->w=NULL;
783 }
784
785 static gboolean auth_timeout_destroy(AuthTimeout *tout){
786         if (tout->w)  {
787                 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
788                 gtk_widget_destroy(tout->w);
789         }
790         g_free(tout);
791         return FALSE;
792 }
793
794 static AuthTimeout * auth_timeout_new(GtkWidget *w){
795         AuthTimeout *tout=g_new(AuthTimeout,1);
796         tout->w=w;
797         /*so that the timeout no more references the widget when it is destroyed:*/
798         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
799         /*so that the widget is automatically destroyed after some time */
800         g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
801         return tout;
802 }
803
804 void linphone_gtk_password_cancel(GtkWidget *w){
805         LinphoneAuthInfo *info;
806         GtkWidget *window=gtk_widget_get_toplevel(w);
807         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
808         linphone_core_abort_authentication(linphone_gtk_get_core(),info);
809         gtk_widget_destroy(window);
810 }
811
812 void linphone_gtk_password_ok(GtkWidget *w){
813         GtkWidget *entry;
814         GtkWidget *window=gtk_widget_get_toplevel(w);
815         LinphoneAuthInfo *info;
816         info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
817         g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
818         entry=linphone_gtk_get_widget(window,"password_entry");
819         linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
820         linphone_auth_info_set_userid(info,
821                 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
822         linphone_core_add_auth_info(linphone_gtk_get_core(),info);
823         gtk_widget_destroy(window);
824 }
825
826 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
827         GtkWidget *w=linphone_gtk_create_window("password");
828         GtkWidget *label=linphone_gtk_get_widget(w,"message");
829         LinphoneAuthInfo *info;
830         gchar *msg;
831         GtkWidget *mw=linphone_gtk_get_main_window();
832         
833         if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
834                 /*don't prompt for authentication when login frame is visible*/
835                 linphone_core_abort_authentication(lc,NULL);
836                 return;
837         }
838
839         msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
840                 username,realm);
841         gtk_label_set_markup(GTK_LABEL(label),msg);
842         g_free(msg);
843         gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
844         info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
845         g_object_set_data(G_OBJECT(w),"auth_info",info);
846         g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
847         gtk_widget_show(w);
848         auth_timeout_new(w);
849 }
850
851 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
852         GtkWidget *w=linphone_gtk_get_main_window();
853         GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
854         gtk_statusbar_push(GTK_STATUSBAR(status_bar),
855                         gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
856                         status);
857 }
858
859 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
860         linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
861 }
862
863 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
864         linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
865 }
866
867 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
868         char richtext[4096];
869         snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
870         linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
871 }
872
873 static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){
874         linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question);
875 }
876
877 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
878         GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
879         if (w) linphone_gtk_call_log_update(w);
880 }
881
882 static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){
883         switch(gstate->new_state){
884                 case GSTATE_CALL_OUT_CONNECTED:
885                 case GSTATE_CALL_IN_CONNECTED:
886                         if (linphone_gtk_use_in_call_view())
887                                 linphone_gtk_in_call_view_set_in_call();
888                         linphone_gtk_enable_mute_button(
889                                 GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
890                         TRUE);
891                 break;
892                 case GSTATE_CALL_ERROR:
893                         linphone_gtk_call_terminated(gstate->message);
894                 break;
895                 case GSTATE_CALL_END:
896                         linphone_gtk_call_terminated(NULL);
897                 break;
898                 default:
899                 break;
900         }
901 }
902
903 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
904         GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
905         gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
906 }
907
908 void linphone_gtk_open_browser(const char *url){
909         /*in gtk 2.16, gtk_show_uri does not work...*/
910 #ifndef WIN32
911 #if GTK_CHECK_VERSION(2,18,3)
912         gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
913 #else
914         char cl[255];
915         snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
916         g_spawn_command_line_async(cl,NULL);
917 #endif
918 #else /*WIN32*/
919         ShellExecute(0,"open",url,NULL,NULL,1);
920 #endif
921 }
922
923 void linphone_gtk_link_to_website(GtkWidget *item){
924         const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
925         linphone_gtk_open_browser(home);
926 }
927
928 static GtkWidget *create_icon_menu(){
929         GtkWidget *menu=gtk_menu_new();
930         GtkWidget *menu_item;
931         GtkWidget *image;
932         gchar *tmp;
933         const gchar *homesite;
934         
935         homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
936         menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
937         tmp=g_strdup(homesite);
938         g_object_set_data(G_OBJECT(menu_item),"home",tmp);
939         g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
940         
941         image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
942         gtk_widget_show(image);
943         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
944         //g_object_unref(G_OBJECT(image));
945         gtk_widget_show(menu_item);
946         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
947         g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
948         
949         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
950         gtk_widget_show(menu_item);
951         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
952         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
953         menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
954         gtk_widget_show(menu_item);
955         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
956         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
957         gtk_widget_show(menu);
958         return menu;
959 }
960
961 static GtkStatusIcon *icon=NULL;
962
963 static void linphone_gtk_init_status_icon(){
964         const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
965         GdkPixbuf *pbuf=create_pixbuf(icon_path);
966         GtkWidget *menu=create_icon_menu();
967         const char *title;
968         icon=gtk_status_icon_new_from_pixbuf(pbuf);
969         g_object_unref(G_OBJECT(pbuf));
970         g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
971         g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
972         title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
973         gtk_status_icon_set_tooltip(icon,title);
974         gtk_status_icon_set_visible(icon,TRUE);
975         g_object_set_data(G_OBJECT(icon),"menu",menu);
976         g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
977 }
978
979 void linphone_gtk_load_identities(void){
980         const MSList *elem;
981         GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
982         char *def_identity;
983         LinphoneProxyConfig *def=NULL;
984         int def_index=0,i;
985         GtkListStore *store;
986
987         store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
988         gtk_list_store_clear(store);
989
990         linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
991         def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
992         gtk_combo_box_append_text(box,def_identity);
993         g_free(def_identity);
994         for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
995                         elem!=NULL;
996                         elem=ms_list_next(elem),i++){
997                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
998                 gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg));
999                 if (cfg==def) {
1000                         def_index=i;
1001                 }
1002         }
1003         gtk_combo_box_set_active(box,def_index);
1004 }
1005
1006 static void linphone_gtk_dtmf_clicked(GtkButton *button){
1007         const char *label=gtk_button_get_label(button);
1008         if (linphone_core_in_call(linphone_gtk_get_core())){
1009                 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1010         }else{
1011                 GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1012                 int pos=-1;
1013                 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1014         }
1015 }
1016
1017 static void linphone_gtk_connect_digits(void){
1018         GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1019         GList *children=gtk_container_get_children(cont);
1020         GList *elem;
1021         for(elem=children;elem!=NULL;elem=elem->next){
1022                 GtkButton *button=GTK_BUTTON(elem->data);
1023                 g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_dtmf_clicked,NULL);
1024         }
1025 }
1026
1027 static void linphone_gtk_check_menu_items(void){
1028         bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core());
1029         bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1030         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1031                                         linphone_gtk_get_main_window(),
1032                                         audio_only ? "audio_only_item" : "video_item")), TRUE);
1033         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1034                                         linphone_gtk_get_main_window(),"selfview_item")),selfview);
1035 }
1036
1037 static gboolean linphone_gtk_can_manage_accounts(){
1038         LinphoneCore *lc=linphone_gtk_get_core();
1039         const MSList *elem;
1040         for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1041                 SipSetup *ss=(SipSetup*)elem->data;
1042                 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1043                         return TRUE;
1044                 }
1045         }
1046         return FALSE;
1047 }
1048
1049 static void linphone_gtk_configure_main_window(){
1050         static gboolean config_loaded=FALSE;
1051         static const char *title;
1052         static const char *home;
1053         static const char *start_call_icon;
1054         static const char *stop_call_icon;
1055         static const char *search_icon;
1056         static gboolean update_check_menu;
1057         static gboolean buttons_have_borders;
1058         GtkWidget *w=linphone_gtk_get_main_window();
1059         if (!config_loaded){
1060                 title=linphone_gtk_get_ui_config("title","Linphone");
1061                 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1062                 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1063                 stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
1064                 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1065                 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1066                 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1067                 config_loaded=TRUE;
1068         }
1069         linphone_gtk_configure_window(w,"main_window");
1070         if (title) {
1071                 gtk_window_set_title(GTK_WINDOW(w),title);
1072 #if GTK_CHECK_VERSION(2,16,0)
1073                 gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),title);
1074 #endif
1075         }
1076         if (start_call_icon){
1077                 GdkPixbuf *pbuf=create_pixbuf(start_call_icon);
1078                 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"start_call_icon")),pbuf);
1079                 if (buttons_have_borders)
1080                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NORMAL);
1081                 g_object_unref(G_OBJECT(pbuf));
1082         }
1083         if (stop_call_icon){
1084                 GdkPixbuf *pbuf=create_pixbuf(stop_call_icon);
1085                 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf);
1086                 if (buttons_have_borders)
1087                         gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NORMAL);
1088                 g_object_unref(G_OBJECT(pbuf));
1089         }
1090         if (search_icon){
1091                 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1092                 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1093                 g_object_unref(G_OBJECT(pbuf));
1094         }
1095         if (home){
1096                 gchar *tmp;
1097                 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1098                 tmp=g_strdup(home);
1099                 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1100         }
1101         {
1102                 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1103                 if (pbuf) {
1104                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1105                         g_object_unref(G_OBJECT(pbuf));
1106                 }
1107         }
1108         {
1109                 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1110                 if (pbuf) {
1111                         gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")),pbuf);
1112                         g_object_unref(G_OBJECT(pbuf));
1113                 }
1114         }
1115         if (!linphone_gtk_can_manage_accounts())
1116                 gtk_widget_hide(linphone_gtk_get_widget(w,"run_assistant"));
1117         if (update_check_menu){
1118                 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck"));
1119         }
1120 }
1121
1122 void linphone_gtk_manage_login(void){
1123         LinphoneCore *lc=linphone_gtk_get_core();
1124         LinphoneProxyConfig *cfg=NULL;
1125         linphone_core_get_default_proxy(lc,&cfg);
1126         if (cfg){
1127                 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1128                 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1129                         linphone_gtk_show_login_frame(cfg);
1130                 }
1131         }
1132 }
1133
1134 static void linphone_gtk_init_main_window(){
1135         GtkWidget *main_window;
1136
1137         linphone_gtk_configure_main_window();
1138         linphone_gtk_manage_login();
1139         load_uri_history();
1140         linphone_gtk_load_identities();
1141         linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1142         linphone_gtk_show_friends();
1143         linphone_gtk_connect_digits();
1144         linphone_gtk_check_menu_items();
1145         main_window=linphone_gtk_get_main_window();
1146         linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
1147                                         "main_mute")),FALSE);
1148         linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
1149                                         "incall_mute")),FALSE);
1150         linphone_gtk_enable_hold_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
1151                                         "hold_call")),FALSE);
1152         if (!linphone_gtk_use_in_call_view()) {
1153                 gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
1154         }
1155         if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started(
1156                 linphone_gtk_get_main_window());/*hide the call button, show terminate button*/
1157 }
1158
1159 void linphone_gtk_close(){
1160         /* couldn't find a way to prevent closing to destroy the main window*/
1161         LinphoneCore *lc=linphone_gtk_get_core();
1162         the_ui=NULL;
1163         the_ui=linphone_gtk_create_window("main");
1164         linphone_gtk_init_main_window();
1165         /*shutdown call if any*/
1166         if (linphone_core_in_call(lc)){
1167                 linphone_core_terminate_call(lc,NULL);
1168                 linphone_gtk_call_terminated(NULL);
1169         }
1170         linphone_core_enable_video_preview(lc,FALSE);
1171 }
1172
1173 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1174         if (verbose){
1175                 const char *lname="undef";
1176                 char *msg;
1177                 #ifdef __linux
1178                 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1179                 #endif
1180                 switch(lev){
1181                         case ORTP_DEBUG:
1182                                 lname="debug";
1183                                 break;
1184                         case ORTP_MESSAGE:
1185                                 lname="message";
1186                                 break;
1187                         case ORTP_WARNING:
1188                                 lname="warning";
1189                                 break;
1190                         case ORTP_ERROR:
1191                                 lname="error";
1192                                 break;
1193                         case ORTP_FATAL:
1194                                 lname="fatal";
1195                                 break;
1196                         default:
1197                                 g_error("Bad level !");
1198                 }
1199 #ifdef __linux
1200                 va_copy(cap,args);
1201                 msg=g_strdup_vprintf(fmt,cap);
1202                 va_end(cap);
1203 #else
1204                 msg=g_strdup_vprintf(fmt,args);
1205 #endif
1206                 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1207                 ortp_free(msg);
1208         }
1209         linphone_gtk_log_push(lev,fmt,args);
1210 }
1211
1212
1213 static void linphone_gtk_refer_received(LinphoneCore *lc, LinphoneCall *call, const char *refer_to){
1214     GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1215                 linphone_gtk_get_main_window(), "uribar"));
1216         linphone_gtk_show_main_window();
1217         gtk_entry_set_text(uri_bar, refer_to);
1218         linphone_gtk_start_call(linphone_gtk_get_main_window());
1219 }
1220
1221 static void linphone_gtk_check_soundcards(){
1222         const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1223         if (devices==NULL || devices[0]==NULL){
1224                 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1225                     _("No sound cards have been detected on this computer.\n"
1226                             "You won't be able to send or receive audio calls."));
1227         }
1228 }
1229
1230 int main(int argc, char *argv[]){
1231 #ifdef ENABLE_NLS
1232         void *p;
1233 #endif
1234         const char *config_file;
1235         const char *factory_config_file;
1236         const char *lang;
1237         GtkSettings *settings;
1238         GdkPixbuf *pbuf;
1239
1240         g_thread_init(NULL);
1241         gdk_threads_init();
1242         
1243         progpath = strdup(argv[0]);
1244         
1245         config_file=linphone_gtk_get_config_file();
1246
1247 #ifdef WIN32
1248         /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1249         if ((lang=getenv("LANG"))!=NULL){
1250                 if (atoi(lang)!=0){
1251                         char tmp[128];
1252                         snprintf(tmp,sizeof(tmp),"LANG=",lang);
1253                         _putenv(tmp);
1254                 }
1255         }
1256 #else
1257         /*for pulseaudio:*/
1258         g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1259 #endif
1260
1261         if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1262 #ifdef WIN32
1263                 char tmp[128];
1264                 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1265                 _putenv(tmp);
1266 #else
1267                 setenv("LANG",lang,1);
1268 #endif
1269         }
1270
1271 #ifdef ENABLE_NLS
1272         p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1273         if (p==NULL) perror("bindtextdomain failed");
1274         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1275         textdomain (GETTEXT_PACKAGE);
1276 #else
1277         g_message("NLS disabled.\n");
1278 #endif
1279 #ifdef WIN32
1280         gtk_rc_add_default_file("./gtkrc");
1281 #endif
1282         gdk_threads_enter();
1283         
1284         if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1285                                 linphone_options,NULL,NULL)){
1286                 gdk_threads_leave();
1287                 return -1;
1288         }
1289         
1290         settings=gtk_settings_get_default();
1291         g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1292         g_object_set(settings, "gtk-button-images", TRUE, NULL);
1293 #ifdef WIN32
1294         if (workingdir!=NULL)
1295                 _chdir(workingdir);
1296 #endif
1297         /* Now, look for the factory configuration file, we do it this late
1298                  since we want to have had time to change directory and to parse
1299                  the options, in case we needed to access the working directory */
1300         factory_config_file = linphone_gtk_get_factory_config_file();
1301
1302         if (linphone_core_wake_up_possible_already_running_instance(
1303                 config_file, addr_to_call) == 0){
1304                 g_message("addr_to_call=%s",addr_to_call);
1305                 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1306                 g_warning("This instance is going to exit now.");
1307                 gdk_threads_leave();
1308                 return 0;
1309         }
1310
1311         add_pixmap_directory("pixmaps");
1312         add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1313
1314         
1315         g_set_application_name("Linphone");
1316         pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1317         if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1318         
1319         the_ui=linphone_gtk_create_window("main");
1320         
1321         linphone_gtk_create_log_window();
1322         linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1323
1324         linphone_gtk_init_liblinphone(config_file, factory_config_file);
1325         /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1326         gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1327         gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1328         linphone_gtk_init_main_window();
1329         linphone_gtk_init_status_icon();
1330         if (!iconified){
1331                 linphone_gtk_show_main_window();
1332                 linphone_gtk_check_soundcards();
1333         }
1334         if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1335                 linphone_gtk_check_for_new_version();
1336
1337         gtk_main();
1338         gdk_threads_leave();
1339         linphone_gtk_destroy_log_window();
1340         linphone_core_destroy(the_core);
1341         /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1342         gtk_status_icon_set_visible(icon,FALSE);
1343         free(progpath);
1344         return 0;
1345 }