2 linphone, gtk-glade interface.
3 Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org)
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.
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.
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.
21 #define VIDEOSELFVIEW_DEFAULT 0
27 #include <sys/types.h>
32 #include <gtkosxapplication.h>
39 #if defined(HAVE_NOTIFY1) || defined(HAVE_NOTIFY4)
44 #include <libnotify/notify.h>
47 #define LINPHONE_ICON "linphone.png"
49 const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
51 static LinphoneCore *the_core=NULL;
52 static GtkWidget *the_ui=NULL;
54 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
55 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
56 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
57 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
58 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
59 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
60 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
61 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
62 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
63 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
64 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
65 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate);
66 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
67 void linphone_gtk_status_icon_set_blinking(gboolean val);
68 void _linphone_gtk_enable_video(gboolean val);
72 static gboolean verbose=0;
73 static gboolean auto_answer = 0;
74 static gchar * addr_to_call = NULL;
75 static gboolean no_video=FALSE;
76 static gboolean iconified=FALSE;
77 static gchar *workingdir=NULL;
78 static char *progpath=NULL;
79 gchar *linphone_logfile=NULL;
80 static gboolean workaround_gtk_entry_chinese_bug=FALSE;
82 static GOptionEntry linphone_options[]={
86 .arg=G_OPTION_ARG_NONE,
87 .arg_data= (gpointer)&verbose,
88 .description=N_("log to stdout some debug information while running.")
91 .long_name = "logfile",
93 .arg = G_OPTION_ARG_STRING,
94 .arg_data = &linphone_logfile,
95 .description = N_("path to a file to write logs into.")
98 .long_name = "no-video",
100 .arg = G_OPTION_ARG_NONE,
101 .arg_data = (gpointer)&no_video,
102 .description = N_("Start linphone with video disabled.")
105 .long_name="iconified",
107 .arg=G_OPTION_ARG_NONE,
108 .arg_data= (gpointer)&iconified,
109 .description=N_("Start only in the system tray, do not show the main interface.")
114 .arg = G_OPTION_ARG_STRING,
115 .arg_data = &addr_to_call,
116 .description = N_("address to call right now")
119 .long_name = "auto-answer",
121 .arg = G_OPTION_ARG_NONE,
122 .arg_data = (gpointer) & auto_answer,
123 .description = N_("if set automatically answer incoming calls")
126 .long_name = "workdir",
128 .arg = G_OPTION_ARG_STRING,
129 .arg_data = (gpointer) & workingdir,
130 .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
135 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
136 #define RELATIVE_XML_DIR
137 #define BUILD_TREE_XML_DIR "gtk"
140 #define CONFIG_FILE ".linphonerc"
141 #define SECRETS_FILE ".linphone-zidcache"
143 #define CONFIG_FILE "linphonerc"
144 #define SECRETS_FILE "linphone-zidcache"
147 char *linphone_gtk_get_config_file(const char *filename){
148 const int path_max=1024;
149 char *config_file=g_malloc0(path_max);
150 if (filename==NULL) filename=CONFIG_FILE;
151 /*try accessing a local file first if exists*/
152 if (access(CONFIG_FILE,F_OK)==0){
153 snprintf(config_file,path_max,"%s",filename);
156 const char *appdata=getenv("APPDATA");
158 snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
159 CreateDirectory(config_file,NULL);
160 snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename);
163 const char *home=getenv("HOME");
164 if (home==NULL) home=".";
165 snprintf(config_file,path_max,"%s/%s",home,filename);
171 #define FACTORY_CONFIG_FILE "linphonerc.factory"
172 static char _factory_config_file[1024];
173 static const char *linphone_gtk_get_factory_config_file(){
174 /*try accessing a local file first if exists*/
175 if (access(FACTORY_CONFIG_FILE,F_OK)==0){
176 snprintf(_factory_config_file,sizeof(_factory_config_file),
177 "%s",FACTORY_CONFIG_FILE);
181 if (progpath != NULL) {
183 progdir = strdup(progpath);
185 basename = strrchr(progdir, '\\');
186 if (basename != NULL) {
189 snprintf(_factory_config_file, sizeof(_factory_config_file),
190 "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
192 if (workingdir!=NULL) {
193 snprintf(_factory_config_file, sizeof(_factory_config_file),
194 "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
201 basename = strrchr(progdir, '/');
202 if (basename != NULL) {
205 snprintf(_factory_config_file, sizeof(_factory_config_file),
206 "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
215 return _factory_config_file;
218 static void linphone_gtk_init_liblinphone(const char *config_file,
219 const char *factory_config_file) {
220 LinphoneCoreVTable vtable={0};
221 gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
223 vtable.call_state_changed=linphone_gtk_call_state_changed;
224 vtable.registration_state_changed=linphone_gtk_registration_state_changed;
225 vtable.notify_presence_recv=linphone_gtk_notify_recv;
226 vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
227 vtable.auth_info_requested=linphone_gtk_auth_info_requested;
228 vtable.display_status=linphone_gtk_display_status;
229 vtable.display_message=linphone_gtk_display_message;
230 vtable.display_warning=linphone_gtk_display_warning;
231 vtable.display_url=linphone_gtk_display_url;
232 vtable.call_log_updated=linphone_gtk_call_log_updated;
233 //vtable.text_received=linphone_gtk_text_received;
234 vtable.message_received=linphone_gtk_text_received;
235 vtable.refer_received=linphone_gtk_refer_received;
236 vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
237 vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
238 vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
240 the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
241 //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
242 linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
243 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
244 linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
245 g_free(secrets_file);
246 linphone_core_enable_video(the_core,TRUE,TRUE);
248 _linphone_gtk_enable_video(FALSE);
249 linphone_gtk_set_ui_config_int("videoselfview",0);
253 LinphoneCore *linphone_gtk_get_core(void){
257 GtkWidget *linphone_gtk_get_main_window(){
261 void linphone_gtk_destroy_main_window() {
262 linphone_gtk_destroy_window(the_ui);
266 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
267 static const char *icon_path=NULL;
268 static const char *hiddens=NULL;
269 static const char *shown=NULL;
270 static bool_t config_loaded=FALSE;
271 if (linphone_gtk_get_core()==NULL) return;
272 if (config_loaded==FALSE){
273 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
274 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
275 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
279 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
281 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
283 GdkPixbuf *pbuf=create_pixbuf(icon_path);
285 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
286 g_object_unref(G_OBJECT(pbuf));
291 static int get_ui_file(const char *name, char *path, int pathsize){
292 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
293 if (access(path,F_OK)!=0){
294 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
295 if (access(path,F_OK)!=0){
296 g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,
297 INSTALLED_XML_DIR,name);
304 void linphone_gtk_destroy_window(GtkWidget *widget) {
305 GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder");
306 gtk_widget_destroy(widget);
307 g_object_unref (G_OBJECT (builder));
310 GtkWidget *linphone_gtk_create_window(const char *window_name){
311 GError* error = NULL;
312 GtkBuilder* builder = gtk_builder_new ();
316 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
318 if (!gtk_builder_add_from_file (builder, path, &error)){
319 g_error("Couldn't load builder file: %s", error->message);
320 g_error_free (error);
323 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
325 g_error("Could not retrieve '%s' window from xml file",window_name);
328 g_object_set_data(G_OBJECT(w), "builder",builder);
329 gtk_builder_connect_signals(builder,w);
330 linphone_gtk_configure_window(w,window_name);
334 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
337 GtkBuilder* builder = gtk_builder_new ();
339 gchar *object_ids[2];
340 object_ids[0]=g_strdup(widget_name);
343 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
344 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
345 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
346 g_error_free (error);
347 g_free(object_ids[0]);
350 g_free(object_ids[0]);
351 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
353 g_error("Could not retrieve '%s' window from xml file",widget_name);
356 g_object_set_data(G_OBJECT(w),"builder",builder);
357 g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
358 gtk_builder_connect_signals(builder,w);
362 static void entry_unmapped(GtkWidget *entry){
363 g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
364 gtk_widget_unrealize(entry);
367 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
370 if (window==NULL) return NULL;
371 builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
373 g_error("Fail to retrieve builder from window !");
376 w=gtk_builder_get_object(builder,name);
378 g_error("No widget named %s found in xml interface.",name);
380 if (workaround_gtk_entry_chinese_bug){
381 if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
382 if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
383 g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
384 g_message("%s is a GtkEntry",name);
385 g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
389 return GTK_WIDGET(w);
393 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
395 GtkWidget *main_window=linphone_gtk_get_main_window();
397 gtk_widget_show(main_window);
398 if (type==GTK_MESSAGE_QUESTION)
400 /* draw a question box. link to dialog_click callback */
401 dialog = gtk_message_dialog_new (
402 GTK_WINDOW(main_window),
403 GTK_DIALOG_DESTROY_WITH_PARENT,
404 GTK_MESSAGE_QUESTION,
407 (const gchar*)message);
408 /* connect to some callback : REVISIT */
410 g_signal_connect_swapped (G_OBJECT (dialog), "response",
411 G_CALLBACK (dialog_click),
414 /* actually show the box */
415 gtk_widget_show(dialog);
419 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
420 GTK_DIALOG_DESTROY_WITH_PARENT,
424 (const gchar*)message);
425 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
426 g_signal_connect_swapped (G_OBJECT (dialog), "response",
427 G_CALLBACK (gtk_widget_destroy),
429 gtk_widget_show(dialog);
433 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
434 if (id==GTK_RESPONSE_CANCEL){
435 gtk_widget_destroy(GTK_WIDGET(dialog));
439 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
440 g_message("About url clicked");
441 linphone_gtk_open_browser(url);
444 void linphone_gtk_show_about(){
445 struct stat filestat;
446 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
449 GdkPixbuf *logo=create_pixbuf(
450 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
451 static const char *defcfg="defcfg";
453 about=linphone_gtk_create_window("about");
454 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
455 memset(&filestat,0,sizeof(filestat));
456 if (stat(license_file,&filestat)!=0){
457 license_file="COPYING";
458 stat(license_file,&filestat);
460 if (filestat.st_size>0){
461 char *license=g_malloc(filestat.st_size+1);
462 FILE *f=fopen(license_file,"r");
463 if (f && fread(license,filestat.st_size,1,f)==1){
464 license[filestat.st_size]='\0';
465 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
469 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
470 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
471 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
472 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
473 tmp=linphone_gtk_get_ui_config("artists",defcfg);
478 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
480 tmp=linphone_gtk_get_ui_config("translators",defcfg);
482 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
483 tmp=linphone_gtk_get_ui_config("comments",defcfg);
485 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
486 gtk_widget_show(about);
489 static void set_video_window_decorations(GdkWindow *w){
490 const char *title=linphone_gtk_get_ui_config("title","Linphone");
491 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
492 char video_title[256];
493 GdkPixbuf *pbuf=create_pixbuf(icon_path);
495 if (!linphone_core_in_call(linphone_gtk_get_core())){
496 snprintf(video_title,sizeof(video_title),"%s video",title);
497 /* When not in call, treat the video as a normal window */
498 gdk_window_set_keep_above(w, FALSE);
500 LinphoneAddress *uri =
501 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
504 linphone_address_clean(uri);
505 if (linphone_address_get_display_name(uri)!=NULL){
506 display_name=ms_strdup(linphone_address_get_display_name(uri));
508 display_name=linphone_address_as_string(uri);
510 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
511 linphone_address_destroy(uri);
512 ms_free(display_name);
514 /* During calls, bring up the video window, arrange so that
515 it is above all the other windows */
516 gdk_window_deiconify(w);
517 gdk_window_set_keep_above(w,TRUE);
518 /* Maybe we should have the following, but then we want to
519 have a timer that turns it off after a little while. */
520 /* gdk_window_set_urgency_hint(w,TRUE); */
522 gdk_window_set_title(w,video_title);
523 /* Refrain the video window to be closed at all times. */
524 gdk_window_set_functions(w,
525 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
526 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
529 l=g_list_append(l,pbuf);
530 gdk_window_set_icon_list(w,l);
532 g_object_unref(G_OBJECT(pbuf));
536 static gboolean video_needs_update=FALSE;
538 static void update_video_title(){
539 video_needs_update=TRUE;
542 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
543 static gboolean first_time=TRUE;
545 static unsigned long previd=0;
546 static unsigned long preview_previd=0;
547 static gboolean in_iterate=FALSE;
550 if (in_iterate) return TRUE;
552 linphone_core_iterate(lc);
554 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
555 linphone_gtk_show_directory_search();
559 id=linphone_core_get_native_video_window_id(lc);
560 if (id!=previd || video_needs_update){
564 ms_message("Updating window decorations");
566 w=gdk_window_foreign_new(id);
568 w=gdk_window_foreign_new((HANDLE)id);
571 set_video_window_decorations(w);
572 g_object_unref(G_OBJECT(w));
574 else ms_error("gdk_window_foreign_new() failed");
575 if (video_needs_update) video_needs_update=FALSE;
578 id=linphone_core_get_native_preview_window_id (lc);
579 if (id!=preview_previd ){
583 ms_message("Updating window decorations for preview");
585 w=gdk_window_foreign_new(id);
587 w=gdk_window_foreign_new((HANDLE)id);
590 set_video_window_decorations(w);
591 g_object_unref(G_OBJECT(w));
593 else ms_error("gdk_window_foreign_new() failed");
594 if (video_needs_update) video_needs_update=FALSE;
597 if (addr_to_call!=NULL){
598 /*make sure we are not showing the login screen*/
599 GtkWidget *mw=linphone_gtk_get_main_window();
600 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
601 if (!GTK_WIDGET_VISIBLE(login_frame)){
602 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
603 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
605 linphone_gtk_start_call(uri_bar);
612 static void load_uri_history(){
613 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
616 GtkEntryCompletion *gep=gtk_entry_completion_new();
617 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
620 snprintf(key,sizeof(key),"uri%i",i);
621 uri=linphone_gtk_get_ui_config(key,NULL);
624 gtk_list_store_append(model,&iter);
625 gtk_list_store_set(model,&iter,0,uri,-1);
626 if (i==0) gtk_entry_set_text(uribar,uri);
630 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
631 gtk_entry_completion_set_text_column(gep,0);
632 gtk_entry_set_completion(uribar,gep);
635 static void save_uri_history(){
636 LinphoneCore *lc=linphone_gtk_get_core();
637 LpConfig *cfg=linphone_core_get_config(lc);
638 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
643 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
645 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
647 gtk_tree_model_get(model,&iter,0,&uri,-1);
649 snprintf(key,sizeof(key),"uri%i",i);
650 lp_config_set_string(cfg,"GtkUi",key,uri);
655 }while(gtk_tree_model_iter_next(model,&iter));
659 static void completion_add_text(GtkEntry *entry, const char *text){
661 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
663 if (gtk_tree_model_get_iter_first(model,&iter)){
666 gtk_tree_model_get(model,&iter,0,&uri,-1);
668 if (strcmp(uri,text)==0) {
670 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
676 }while (gtk_tree_model_iter_next(model,&iter));
678 /* and prepend it on top of the list */
679 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
680 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
684 bool_t linphone_gtk_video_enabled(void){
685 const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
686 return vpol->automatically_accept && vpol->automatically_initiate;
689 void linphone_gtk_show_main_window(){
690 GtkWidget *w=linphone_gtk_get_main_window();
691 LinphoneCore *lc=linphone_gtk_get_core();
692 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
693 VIDEOSELFVIEW_DEFAULT));
695 gtk_window_present(GTK_WINDOW(w));
698 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
699 GtkWidget *mw=linphone_gtk_get_main_window();
700 if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
701 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
703 if (linphone_gtk_use_in_call_view() && call)
704 linphone_gtk_in_call_view_terminate(call,error);
705 update_video_title();
708 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
709 LinphoneCore *lc=linphone_gtk_get_core();
710 GtkWidget *mw=linphone_gtk_get_main_window();
711 const MSList *calls=linphone_core_get_calls(lc);
713 bool_t start_active=TRUE;
714 //bool_t stop_active=FALSE;
715 bool_t add_call=FALSE;
716 int call_list_size=ms_list_size(calls);
726 button=linphone_gtk_get_widget(mw,"start_call");
727 gtk_widget_set_sensitive(button,start_active);
728 gtk_widget_set_visible(button,!add_call);
730 button=linphone_gtk_get_widget(mw,"add_call");
731 if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
732 gtk_widget_set_sensitive(button,FALSE);
734 gtk_widget_set_sensitive(button,start_active);
736 gtk_widget_set_visible(button,add_call);
738 //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
739 GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
740 if(conf_frame==NULL){
741 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
742 linphone_gtk_enable_conference_button(lc,call_list_size>1);
744 linphone_gtk_enable_transfer_button(lc,FALSE);
745 linphone_gtk_enable_conference_button(lc,FALSE);
747 update_video_title();
749 linphone_gtk_update_video_button(call);
753 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
754 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
755 if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
756 completion_add_text(GTK_ENTRY(uri_bar),entered);
758 linphone_gtk_call_terminated(NULL,NULL);
763 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
764 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
765 linphone_core_accept_call (linphone_gtk_get_core(),call);
766 linphone_call_unref(call);
771 void linphone_gtk_start_call(GtkWidget *w){
772 LinphoneCore *lc=linphone_gtk_get_core();
774 /*change into in-call mode, then do the work later as it might block a bit */
775 GtkWidget *mw=gtk_widget_get_toplevel(w);
776 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
778 call=linphone_gtk_get_currently_displayed_call(NULL);
779 if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
780 linphone_core_accept_call(lc,call);
782 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
783 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
784 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
785 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
790 void linphone_gtk_uri_bar_activate(GtkWidget *w){
791 linphone_gtk_start_call(w);
794 void linphone_gtk_terminate_call(GtkWidget *button){
796 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
798 linphone_core_terminate_call(linphone_gtk_get_core(),call);
800 linphone_core_terminate_conference(linphone_gtk_get_core());
804 void linphone_gtk_decline_clicked(GtkWidget *button){
805 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
807 linphone_core_terminate_call(linphone_gtk_get_core(),call);
810 void linphone_gtk_answer_clicked(GtkWidget *button){
811 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
813 linphone_core_accept_call(linphone_gtk_get_core(),call);
814 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
818 void _linphone_gtk_enable_video(gboolean val){
819 LinphoneVideoPolicy policy={0};
820 policy.automatically_initiate=policy.automatically_accept=val;
821 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
822 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
825 linphone_core_enable_video_preview(linphone_gtk_get_core(),
826 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
828 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
832 void linphone_gtk_enable_video(GtkWidget *w){
833 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
834 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
835 _linphone_gtk_enable_video(val);
838 void linphone_gtk_enable_self_view(GtkWidget *w){
839 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
840 LinphoneCore *lc=linphone_gtk_get_core();
841 linphone_core_enable_video_preview(lc,val);
842 linphone_core_enable_self_view(lc,val);
843 linphone_gtk_set_ui_config_int("videoselfview",val);
846 void linphone_gtk_used_identity_changed(GtkWidget *w){
847 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
848 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
849 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
850 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
851 linphone_gtk_show_directory_search();
853 if (sel) g_free(sel);
856 void on_proxy_refresh_button_clicked(GtkWidget *w){
857 LinphoneCore *lc=linphone_gtk_get_core();
858 MSList const *item=linphone_core_get_proxy_config_list(lc);
859 while (item != NULL) {
860 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
861 linphone_proxy_config_edit(lpc);
862 linphone_proxy_config_done(lpc);
867 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
868 linphone_gtk_show_friends();
871 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
873 case GTK_RESPONSE_YES:
874 linphone_gtk_show_contact(lf);
877 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
879 gtk_widget_destroy(dialog);
882 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
885 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
886 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
890 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);
891 dialog = gtk_message_dialog_new (
892 GTK_WINDOW(linphone_gtk_get_main_window()),
893 GTK_DIALOG_DESTROY_WITH_PARENT,
894 GTK_MESSAGE_QUESTION,
899 g_signal_connect(G_OBJECT (dialog), "response",
900 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
901 /* actually show the box */
902 gtk_widget_show(dialog);
905 typedef struct _AuthTimeout{
909 static void auth_timeout_clean(AuthTimeout *tout){
913 static gboolean auth_timeout_destroy(AuthTimeout *tout){
915 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
916 gtk_widget_destroy(tout->w);
922 static AuthTimeout * auth_timeout_new(GtkWidget *w){
923 AuthTimeout *tout=g_new(AuthTimeout,1);
925 /*so that the timeout no more references the widget when it is destroyed:*/
926 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
927 /*so that the widget is automatically destroyed after some time */
928 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
932 void linphone_gtk_password_cancel(GtkWidget *w){
933 LinphoneAuthInfo *info;
934 GtkWidget *window=gtk_widget_get_toplevel(w);
935 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
936 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
937 gtk_widget_destroy(window);
940 void linphone_gtk_password_ok(GtkWidget *w){
942 GtkWidget *window=gtk_widget_get_toplevel(w);
943 LinphoneAuthInfo *info;
944 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
945 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
946 entry=linphone_gtk_get_widget(window,"password_entry");
947 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
948 linphone_auth_info_set_userid(info,
949 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
950 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
951 gtk_widget_destroy(window);
954 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
955 GtkWidget *w=linphone_gtk_create_window("password");
956 GtkWidget *label=linphone_gtk_get_widget(w,"message");
957 LinphoneAuthInfo *info;
959 GtkWidget *mw=linphone_gtk_get_main_window();
961 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
962 /*don't prompt for authentication when login frame is visible*/
963 linphone_core_abort_authentication(lc,NULL);
967 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
969 gtk_label_set_markup(GTK_LABEL(label),msg);
971 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
972 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
973 g_object_set_data(G_OBJECT(w),"auth_info",info);
974 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
979 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
980 GtkWidget *w=linphone_gtk_get_main_window();
981 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
983 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
984 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
988 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
989 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
992 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
993 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
996 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
998 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
999 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
1002 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1003 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1004 if (w) linphone_gtk_call_log_update(w);
1005 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1009 static bool_t notify_actions_supported() {
1010 bool_t accepts_actions = FALSE;
1011 GList *capabilities = notify_get_server_caps();
1013 if(capabilities != NULL) {
1014 for(c = capabilities; c != NULL; c = c->next) {
1015 if(strcmp((char*)c->data, "actions") == 0 ) {
1016 accepts_actions = TRUE;
1020 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1021 g_list_free(capabilities);
1023 return accepts_actions;
1026 static NotifyNotification* build_notification(const char *title, const char *body){
1027 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1034 static void show_notification(NotifyNotification* n){
1035 if (n && !notify_notification_show(n,NULL))
1036 ms_error("Failed to send notification.");
1039 static void make_notification(const char *title, const char *body){
1040 show_notification(build_notification(title,body));
1045 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1047 if (!notify_is_initted())
1048 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1053 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1059 ms_error("Failed to send notification.");
1061 linphone_gtk_show_main_window();
1063 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1066 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1067 NotifyNotification *n;
1068 switch(linphone_call_get_state(call)){
1069 case LinphoneCallError:
1070 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
1072 case LinphoneCallEnd:
1073 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1075 case LinphoneCallIncomingReceived:
1076 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1077 if (notify_actions_supported()) {
1078 notify_notification_add_action (n,"answer", _("Answer"),
1079 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1080 notify_notification_add_action (n,"decline",_("Decline"),
1081 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1083 show_notification(n);
1085 case LinphoneCallPausedByRemote:
1086 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<span size=\"large\">by %s</span>"),remote));
1091 if (body) g_free(body);
1092 if (remote) g_free(remote);
1097 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1098 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1099 LinphoneCore *lc=linphone_call_get_core(call);
1100 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1101 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1102 linphone_core_accept_call_update(lc,call,params);
1103 linphone_call_params_destroy(params);
1105 linphone_call_unref(call);
1106 g_source_remove_by_user_data(dialog);
1107 gtk_widget_destroy(dialog);
1110 static void on_call_updated_timeout(GtkWidget *dialog){
1111 gtk_widget_destroy(dialog);
1114 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1115 LinphoneCore *lc=linphone_call_get_core(call);
1116 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1117 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1118 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1119 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1120 gboolean video_used=linphone_call_params_video_enabled(current_params);
1121 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1122 video_used,video_requested,pol->automatically_accept);
1123 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1124 linphone_core_defer_call_update(lc,call);
1126 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1128 const char *dname=linphone_address_get_display_name(addr);
1129 if (dname==NULL) dname=linphone_address_get_username(addr);
1130 if (dname==NULL) dname=linphone_address_get_domain(addr);
1131 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1132 GTK_DIALOG_DESTROY_WITH_PARENT,
1133 GTK_MESSAGE_WARNING,
1135 _("%s proposed to start video. Do you accept ?"),dname);
1136 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1137 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1138 gtk_widget_show(dialog);
1143 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1145 case LinphoneCallOutgoingInit:
1146 linphone_gtk_create_in_call_view (call);
1148 case LinphoneCallOutgoingProgress:
1149 linphone_gtk_in_call_view_set_calling (call);
1151 case LinphoneCallStreamsRunning:
1152 linphone_gtk_in_call_view_set_in_call(call);
1154 case LinphoneCallUpdatedByRemote:
1155 linphone_gtk_call_updated_by_remote(call);
1157 case LinphoneCallError:
1158 linphone_gtk_in_call_view_terminate (call,msg);
1160 case LinphoneCallEnd:
1161 linphone_gtk_in_call_view_terminate(call,NULL);
1162 linphone_gtk_status_icon_set_blinking(FALSE);
1164 case LinphoneCallIncomingReceived:
1165 linphone_gtk_create_in_call_view(call);
1166 linphone_gtk_in_call_view_set_incoming(call);
1167 linphone_gtk_status_icon_set_blinking(TRUE);
1169 linphone_call_ref(call);
1170 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1173 case LinphoneCallResuming:
1174 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1175 linphone_gtk_in_call_view_set_in_call (call);
1177 case LinphoneCallPausing:
1178 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1179 update_tab_header(call,FALSE);
1180 case LinphoneCallPausedByRemote:
1181 linphone_gtk_in_call_view_set_paused(call);
1182 update_tab_header(call,TRUE);
1184 case LinphoneCallConnected:
1185 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1186 linphone_gtk_status_icon_set_blinking(FALSE);
1191 linphone_gtk_notify(call, msg);
1192 linphone_gtk_update_call_buttons (call);
1195 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1196 linphone_gtk_in_call_view_show_encryption(call);
1199 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1200 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1203 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1204 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1205 GtkTreeModel *model=gtk_combo_box_get_model(box);
1207 gboolean found=FALSE;
1208 const char *stock_id=NULL;
1210 if (gtk_tree_model_get_iter_first(model,&iter)){
1213 gtk_tree_model_get(model,&iter,2,&p,-1);
1218 }while(gtk_tree_model_iter_next(model,&iter));
1221 g_warning("Could not find proxy config in combo box of identities.");
1225 case LinphoneRegistrationOk:
1226 stock_id=GTK_STOCK_YES;
1228 case LinphoneRegistrationProgress:
1229 stock_id=GTK_STOCK_REFRESH;
1231 case LinphoneRegistrationCleared:
1234 case LinphoneRegistrationFailed:
1235 stock_id=GTK_STOCK_DIALOG_WARNING;
1240 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1243 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1244 LinphoneRegistrationState rs, const char *msg){
1246 case LinphoneRegistrationOk:
1248 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1249 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1250 linphone_gtk_exit_login_frame();
1257 update_registration_status(cfg,rs);
1260 void linphone_gtk_open_browser(const char *url){
1261 /*in gtk 2.16, gtk_show_uri does not work...*/
1263 #if GTK_CHECK_VERSION(2,18,3)
1264 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1267 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1268 g_spawn_command_line_async(cl,NULL);
1271 ShellExecute(0,"open",url,NULL,NULL,1);
1275 void linphone_gtk_link_to_website(GtkWidget *item){
1276 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1277 linphone_gtk_open_browser(home);
1280 #ifndef HAVE_GTK_OSX
1282 static GtkStatusIcon *icon=NULL;
1284 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1285 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1286 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1289 static GtkWidget *create_icon_menu(){
1290 GtkWidget *menu=gtk_menu_new();
1291 GtkWidget *menu_item;
1294 const gchar *homesite;
1296 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1297 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1298 tmp=g_strdup(homesite);
1299 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1300 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1302 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1303 gtk_widget_show(image);
1304 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1305 //g_object_unref(G_OBJECT(image));
1306 gtk_widget_show(menu_item);
1307 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1308 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1310 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1311 gtk_widget_show(menu_item);
1312 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1313 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1314 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1315 gtk_widget_show(menu_item);
1316 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1317 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1318 gtk_widget_show(menu);
1322 static void handle_icon_click() {
1323 GtkWidget *mw=linphone_gtk_get_main_window();
1324 if (!gtk_window_is_active((GtkWindow*)mw)) {
1325 linphone_gtk_show_main_window();
1327 gtk_widget_hide(mw);
1331 static void linphone_gtk_init_status_icon(){
1332 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1333 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1334 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1335 GtkWidget *menu=create_icon_menu();
1337 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1338 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1339 #if GTK_CHECK_VERSION(2,20,0)
1340 gtk_status_icon_set_name(icon,title);
1342 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1343 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1344 gtk_status_icon_set_tooltip(icon,title);
1345 gtk_status_icon_set_visible(icon,TRUE);
1346 g_object_set_data(G_OBJECT(icon),"menu",menu);
1347 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1348 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1349 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1350 pbuf=create_pixbuf(call_icon_path);
1351 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1354 static gboolean do_icon_blink(GtkStatusIcon *gi){
1355 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1356 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1357 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1358 if (cur_icon==call_icon){
1359 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1361 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1368 void linphone_gtk_status_icon_set_blinking(gboolean val){
1370 static gint attention_id;
1371 GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1373 attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
1374 else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
1378 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1379 if (val && tout==0){
1380 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1381 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1382 }else if (!val && tout!=0){
1383 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1384 g_source_remove(tout);
1385 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1386 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1392 void linphone_gtk_options_activate(GtkWidget *item){
1393 #ifndef HAVE_GTK_OSX
1394 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1399 static void init_identity_combo(GtkComboBox *box){
1400 GtkListStore *store;
1401 GtkCellRenderer *r1,*r2;
1402 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1403 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1404 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1405 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1406 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1407 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1408 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1409 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1412 void linphone_gtk_load_identities(void){
1414 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1416 LinphoneProxyConfig *def=NULL;
1418 GtkListStore *store;
1421 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1422 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1423 /* model is empty, this is the first time we go here */
1424 init_identity_combo(box);
1425 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1427 gtk_list_store_clear(store);
1428 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1429 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1430 gtk_list_store_append(store,&iter);
1431 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1432 g_free(def_identity);
1433 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1435 elem=ms_list_next(elem),i++){
1436 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1437 gtk_list_store_append(store,&iter);
1438 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1439 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1445 gtk_combo_box_set_active(box,def_index);
1448 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1449 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1450 GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
1452 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1453 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1454 if (linphone_core_in_call(linphone_gtk_get_core())){
1455 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1459 static void linphone_gtk_dtmf_released(GtkButton *button){
1460 linphone_core_stop_dtmf (linphone_gtk_get_core());
1464 static void linphone_gtk_connect_digits(GtkWidget *w){
1465 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
1466 GList *children=gtk_container_get_children(cont);
1468 for(elem=children;elem!=NULL;elem=elem->next){
1469 GtkButton *button=GTK_BUTTON(elem->data);
1470 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1471 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1475 static void linphone_gtk_check_menu_items(void){
1476 bool_t video_enabled=linphone_gtk_video_enabled();
1477 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1478 GtkWidget *selfview_item=linphone_gtk_get_widget(
1479 linphone_gtk_get_main_window(),"selfview_item");
1480 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1481 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1482 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1485 static gboolean linphone_gtk_can_manage_accounts(){
1486 LinphoneCore *lc=linphone_gtk_get_core();
1488 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1489 SipSetup *ss=(SipSetup*)elem->data;
1490 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1497 static void linphone_gtk_configure_main_window(){
1498 static gboolean config_loaded=FALSE;
1499 static const char *title;
1500 static const char *home;
1501 static const char *start_call_icon;
1502 static const char *add_call_icon;
1503 static const char *search_icon;
1504 static gboolean update_check_menu;
1505 static gboolean buttons_have_borders;
1506 //static gboolean show_abcd;
1507 GtkWidget *w=linphone_gtk_get_main_window();
1508 GHashTable *contacts_history;
1510 contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1511 g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1513 if (!config_loaded){
1514 title=linphone_gtk_get_ui_config("title","Linphone");
1515 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1516 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1517 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1518 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1519 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1520 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1521 //show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1524 linphone_gtk_configure_window(w,"main_window");
1526 gtk_window_set_title(GTK_WINDOW(w),title);
1528 if (start_call_icon){
1529 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1530 create_pixmap (start_call_icon));
1531 if (!buttons_have_borders)
1532 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1535 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1536 create_pixmap (add_call_icon));
1537 if (!buttons_have_borders)
1538 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1541 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1543 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1544 g_object_unref(G_OBJECT(pbuf));
1549 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1551 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1555 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1557 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1558 g_object_unref(G_OBJECT(pbuf));
1563 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1565 GtkImage *img=GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon"));
1568 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU,&w,&h);
1569 scaled=gdk_pixbuf_scale_simple(pbuf,w,h,GDK_INTERP_BILINEAR);
1570 gtk_image_set_from_pixbuf(img,scaled);
1571 g_object_unref(G_OBJECT(scaled));
1572 g_object_unref(G_OBJECT(pbuf));
1575 if (linphone_gtk_can_manage_accounts()) {
1576 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1578 if (update_check_menu){
1579 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1582 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1583 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1584 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1585 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1586 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1590 void linphone_gtk_manage_login(void){
1591 LinphoneCore *lc=linphone_gtk_get_core();
1592 LinphoneProxyConfig *cfg=NULL;
1593 linphone_core_get_default_proxy(lc,&cfg);
1595 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1596 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1597 linphone_gtk_show_login_frame(cfg);
1603 gboolean linphone_gtk_close(GtkWidget *mw){
1604 /*shutdown calls if any*/
1605 LinphoneCore *lc=linphone_gtk_get_core();
1606 if (linphone_core_in_call(lc)){
1607 linphone_core_terminate_all_calls(lc);
1609 linphone_core_enable_video_preview(lc,FALSE);
1610 #ifdef __APPLE__ /*until with have a better option*/
1611 gtk_window_iconify(GTK_WINDOW(mw));
1613 gtk_widget_hide(mw);
1619 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1620 bool_t video_enabled=linphone_gtk_video_enabled();
1621 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1622 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1624 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1625 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1631 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1632 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1633 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1635 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1636 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1637 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1638 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1639 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1640 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1641 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1642 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1643 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1644 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1645 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1646 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1647 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1648 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1649 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1650 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1653 void linphone_gtk_create_keypad(GtkWidget *button){
1654 GtkWidget *mw=linphone_gtk_get_main_window();
1655 GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad");
1657 gtk_widget_destroy(k);
1659 GtkWidget *keypad=linphone_gtk_create_window("keypad");
1660 linphone_gtk_connect_digits(keypad);
1661 linphone_gtk_init_dtmf_table(keypad);
1662 g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad);
1663 gtk_widget_show(keypad);
1666 static void linphone_gtk_init_main_window(){
1667 GtkWidget *main_window;
1668 linphone_gtk_configure_main_window();
1669 linphone_gtk_manage_login();
1671 linphone_gtk_load_identities();
1672 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1673 linphone_gtk_show_friends();
1674 main_window=linphone_gtk_get_main_window();
1675 linphone_gtk_call_log_update(main_window);
1677 linphone_gtk_update_call_buttons (NULL);
1678 g_object_set_data(G_OBJECT(main_window),"keypad",NULL);
1679 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1680 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1681 g_signal_connect (G_OBJECT (main_window), "delete-event",
1682 G_CALLBACK (linphone_gtk_close), main_window);
1685 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1686 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1687 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1688 gtk_widget_hide(menubar);
1689 gtk_osxapplication_ready(theMacApp);
1691 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1693 linphone_gtk_check_menu_items();
1697 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1699 const char *lname="undef";
1701 #if defined(__linux) || defined(__APPLE__)
1702 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1721 g_error("Bad level !");
1723 #if defined(__linux) || defined(__APPLE__)
1725 msg=g_strdup_vprintf(fmt,cap);
1728 msg=g_strdup_vprintf(fmt,args);
1730 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1733 linphone_gtk_log_push(lev,fmt,args);
1737 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1738 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1739 linphone_gtk_get_main_window(), "uribar"));
1741 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1743 gtk_entry_set_text(uri_bar, refer_to);
1744 linphone_gtk_start_call(linphone_gtk_get_main_window());
1747 static void linphone_gtk_check_soundcards(){
1748 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1749 if (devices==NULL || devices[0]==NULL){
1750 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1751 _("No sound cards have been detected on this computer.\n"
1752 "You won't be able to send or receive audio calls."));
1756 static void linphone_gtk_quit(void){
1757 static gboolean quit_done=FALSE;
1760 linphone_gtk_unmonitor_usb();
1761 g_source_remove_by_user_data(linphone_gtk_get_core());
1763 linphone_gtk_close_assistant();
1765 linphone_gtk_uninit_instance();
1766 linphone_gtk_destroy_log_window();
1767 linphone_core_destroy(the_core);
1768 linphone_gtk_log_uninit();
1772 gdk_threads_leave();
1778 This is not the correct way to implement block termination.
1779 The good way would be to call gtk_main_quit(), and return TRUE.
1780 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1781 As a result the program cannot exit at all.
1782 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1784 static gboolean on_block_termination(void){
1786 linphone_gtk_quit();
1791 int main(int argc, char *argv[]){
1796 const char *factory_config_file;
1798 GtkSettings *settings;
1800 const char *app_name="Linphone";
1802 #if !GLIB_CHECK_VERSION(2, 31, 0)
1803 g_thread_init(NULL);
1807 progpath = strdup(argv[0]);
1809 config_file=linphone_gtk_get_config_file(NULL);
1813 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1814 if ((lang=getenv("LANG"))!=NULL){
1817 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1823 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1826 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1829 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1831 if (strncmp(lang,"zh",2)==0){
1832 workaround_gtk_entry_chinese_bug=TRUE;
1835 setenv("LANG",lang,1);
1837 setenv("LANGUAGE",lang,1);
1842 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1843 if (p==NULL) perror("bindtextdomain failed");
1844 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1845 textdomain (GETTEXT_PACKAGE);
1847 g_message("NLS disabled.\n");
1850 gtk_rc_add_default_file("./gtkrc");
1852 gdk_threads_enter();
1854 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1855 linphone_options,NULL,NULL)){
1856 gdk_threads_leave();
1860 settings=gtk_settings_get_default();
1861 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1862 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1863 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1864 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1866 if (workingdir!=NULL){
1867 if (chdir(workingdir)==-1){
1868 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1872 /* Now, look for the factory configuration file, we do it this late
1873 since we want to have had time to change directory and to parse
1874 the options, in case we needed to access the working directory */
1875 factory_config_file = linphone_gtk_get_factory_config_file();
1877 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1878 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1879 g_warning("This instance is going to exit now.");
1880 gdk_threads_leave();
1884 add_pixmap_directory("pixmaps");
1885 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1888 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1889 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1890 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1891 /*never block termination:*/
1892 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1895 the_ui=linphone_gtk_create_window("main");
1897 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1899 linphone_gtk_create_log_window();
1900 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1902 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1904 g_set_application_name(app_name);
1905 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1906 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1908 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1909 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1910 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1911 linphone_gtk_init_main_window();
1914 // Veryfing if at least one sip account is configured. If not, show wizard
1915 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1916 linphone_gtk_show_assistant();
1920 #ifndef HAVE_GTK_OSX
1921 linphone_gtk_init_status_icon();
1924 linphone_gtk_show_main_window();
1925 linphone_gtk_check_soundcards();
1927 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1928 linphone_gtk_check_for_new_version();
1929 linphone_gtk_monitor_usb();
1932 linphone_gtk_quit();
1933 #ifndef HAVE_GTK_OSX
1934 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1935 gtk_status_icon_set_visible(icon,FALSE);