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;
53 GtkWidget *the_wizard=NULL;
55 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
56 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
57 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
58 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
59 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
60 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
61 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
62 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
63 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
64 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
65 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
66 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate);
67 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
68 void linphone_gtk_status_icon_set_blinking(gboolean val);
69 void _linphone_gtk_enable_video(gboolean val);
73 static gboolean verbose=0;
74 static gboolean auto_answer = 0;
75 static gchar * addr_to_call = NULL;
76 static gboolean no_video=FALSE;
77 static gboolean iconified=FALSE;
78 static gchar *workingdir=NULL;
79 static char *progpath=NULL;
80 gchar *linphone_logfile=NULL;
81 static gboolean workaround_gtk_entry_chinese_bug=FALSE;
83 static GOptionEntry linphone_options[]={
87 .arg=G_OPTION_ARG_NONE,
88 .arg_data= (gpointer)&verbose,
89 .description=N_("log to stdout some debug information while running.")
92 .long_name = "logfile",
94 .arg = G_OPTION_ARG_STRING,
95 .arg_data = &linphone_logfile,
96 .description = N_("path to a file to write logs into.")
99 .long_name = "no-video",
101 .arg = G_OPTION_ARG_NONE,
102 .arg_data = (gpointer)&no_video,
103 .description = N_("Start linphone with video disabled.")
106 .long_name="iconified",
108 .arg=G_OPTION_ARG_NONE,
109 .arg_data= (gpointer)&iconified,
110 .description=N_("Start only in the system tray, do not show the main interface.")
115 .arg = G_OPTION_ARG_STRING,
116 .arg_data = &addr_to_call,
117 .description = N_("address to call right now")
120 .long_name = "auto-answer",
122 .arg = G_OPTION_ARG_NONE,
123 .arg_data = (gpointer) & auto_answer,
124 .description = N_("if set automatically answer incoming calls")
127 .long_name = "workdir",
129 .arg = G_OPTION_ARG_STRING,
130 .arg_data = (gpointer) & workingdir,
131 .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
136 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
137 #define RELATIVE_XML_DIR
138 #define BUILD_TREE_XML_DIR "gtk"
141 #define CONFIG_FILE ".linphonerc"
142 #define SECRETS_FILE ".linphone-zidcache"
144 #define CONFIG_FILE "linphonerc"
145 #define SECRETS_FILE "linphone-zidcache"
148 char *linphone_gtk_get_config_file(const char *filename){
149 const int path_max=1024;
150 char *config_file=g_malloc0(path_max);
151 if (filename==NULL) filename=CONFIG_FILE;
152 /*try accessing a local file first if exists*/
153 if (access(CONFIG_FILE,F_OK)==0){
154 snprintf(config_file,path_max,"%s",filename);
157 const char *appdata=getenv("APPDATA");
159 snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
160 CreateDirectory(config_file,NULL);
161 snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename);
164 const char *home=getenv("HOME");
165 if (home==NULL) home=".";
166 snprintf(config_file,path_max,"%s/%s",home,filename);
172 #define FACTORY_CONFIG_FILE "linphonerc.factory"
173 static char _factory_config_file[1024];
174 static const char *linphone_gtk_get_factory_config_file(){
175 /*try accessing a local file first if exists*/
176 if (access(FACTORY_CONFIG_FILE,F_OK)==0){
177 snprintf(_factory_config_file,sizeof(_factory_config_file),
178 "%s",FACTORY_CONFIG_FILE);
182 if (progpath != NULL) {
184 progdir = strdup(progpath);
186 basename = strrchr(progdir, '\\');
187 if (basename != NULL) {
190 snprintf(_factory_config_file, sizeof(_factory_config_file),
191 "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
193 if (workingdir!=NULL) {
194 snprintf(_factory_config_file, sizeof(_factory_config_file),
195 "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
202 basename = strrchr(progdir, '/');
203 if (basename != NULL) {
206 snprintf(_factory_config_file, sizeof(_factory_config_file),
207 "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
216 return _factory_config_file;
219 static void linphone_gtk_init_liblinphone(const char *config_file,
220 const char *factory_config_file) {
221 LinphoneCoreVTable vtable={0};
222 gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
224 vtable.call_state_changed=linphone_gtk_call_state_changed;
225 vtable.registration_state_changed=linphone_gtk_registration_state_changed;
226 vtable.notify_presence_recv=linphone_gtk_notify_recv;
227 vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
228 vtable.auth_info_requested=linphone_gtk_auth_info_requested;
229 vtable.display_status=linphone_gtk_display_status;
230 vtable.display_message=linphone_gtk_display_message;
231 vtable.display_warning=linphone_gtk_display_warning;
232 vtable.display_url=linphone_gtk_display_url;
233 vtable.call_log_updated=linphone_gtk_call_log_updated;
234 vtable.text_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 linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
242 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
243 linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
244 g_free(secrets_file);
245 linphone_core_enable_video(the_core,TRUE,TRUE);
247 _linphone_gtk_enable_video(FALSE);
248 linphone_gtk_set_ui_config_int("videoselfview",0);
252 LinphoneCore *linphone_gtk_get_core(void){
256 GtkWidget *linphone_gtk_get_main_window(){
260 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
261 static const char *icon_path=NULL;
262 static const char *hiddens=NULL;
263 static const char *shown=NULL;
264 static bool_t config_loaded=FALSE;
265 if (linphone_gtk_get_core()==NULL) return;
266 if (config_loaded==FALSE){
267 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
268 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
269 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
273 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
275 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
277 GdkPixbuf *pbuf=create_pixbuf(icon_path);
279 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
280 g_object_unref(G_OBJECT(pbuf));
285 static int get_ui_file(const char *name, char *path, int pathsize){
286 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
287 if (access(path,F_OK)!=0){
288 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
289 if (access(path,F_OK)!=0){
290 g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,
291 INSTALLED_XML_DIR,name);
298 GtkWidget *linphone_gtk_create_window(const char *window_name){
299 GError* error = NULL;
300 GtkBuilder* builder = gtk_builder_new ();
304 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
306 if (!gtk_builder_add_from_file (builder, path, &error)){
307 g_error("Couldn't load builder file: %s", error->message);
308 g_error_free (error);
311 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
313 g_error("Could not retrieve '%s' window from xml file",window_name);
316 g_object_set_data(G_OBJECT(w),"builder",builder);
317 gtk_builder_connect_signals(builder,w);
318 linphone_gtk_configure_window(w,window_name);
322 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
325 GtkBuilder* builder = gtk_builder_new ();
327 gchar *object_ids[2];
328 object_ids[0]=g_strdup(widget_name);
331 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
332 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
333 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
334 g_error_free (error);
335 g_free(object_ids[0]);
338 g_free(object_ids[0]);
339 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
341 g_error("Could not retrieve '%s' window from xml file",widget_name);
344 g_object_set_data(G_OBJECT(w),"builder",builder);
345 g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
346 gtk_builder_connect_signals(builder,w);
350 static void entry_unmapped(GtkWidget *entry){
351 g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
352 gtk_widget_unrealize(entry);
355 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
358 if (window==NULL) return NULL;
359 builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
361 g_error("Fail to retrieve builder from window !");
364 w=gtk_builder_get_object(builder,name);
366 g_error("No widget named %s found in xml interface.",name);
368 if (workaround_gtk_entry_chinese_bug){
369 if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
370 if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
371 g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
372 g_message("%s is a GtkEntry",name);
373 g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
377 return GTK_WIDGET(w);
381 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
383 GtkWidget *main_window=linphone_gtk_get_main_window();
385 gtk_widget_show(main_window);
386 if (type==GTK_MESSAGE_QUESTION)
388 /* draw a question box. link to dialog_click callback */
389 dialog = gtk_message_dialog_new (
390 GTK_WINDOW(main_window),
391 GTK_DIALOG_DESTROY_WITH_PARENT,
392 GTK_MESSAGE_QUESTION,
395 (const gchar*)message);
396 /* connect to some callback : REVISIT */
398 g_signal_connect_swapped (G_OBJECT (dialog), "response",
399 G_CALLBACK (dialog_click),
402 /* actually show the box */
403 gtk_widget_show(dialog);
407 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
408 GTK_DIALOG_DESTROY_WITH_PARENT,
412 (const gchar*)message);
413 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
414 g_signal_connect_swapped (G_OBJECT (dialog), "response",
415 G_CALLBACK (gtk_widget_destroy),
417 gtk_widget_show(dialog);
421 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
422 if (id==GTK_RESPONSE_CANCEL){
423 gtk_widget_destroy(GTK_WIDGET(dialog));
427 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
428 g_message("About url clicked");
429 linphone_gtk_open_browser(url);
432 void linphone_gtk_show_about(){
433 struct stat filestat;
434 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
437 GdkPixbuf *logo=create_pixbuf(
438 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
439 static const char *defcfg="defcfg";
441 about=linphone_gtk_create_window("about");
442 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
443 memset(&filestat,0,sizeof(filestat));
444 if (stat(license_file,&filestat)!=0){
445 license_file="COPYING";
446 stat(license_file,&filestat);
448 if (filestat.st_size>0){
449 char *license=g_malloc(filestat.st_size+1);
450 FILE *f=fopen(license_file,"r");
451 if (f && fread(license,filestat.st_size,1,f)==1){
452 license[filestat.st_size]='\0';
453 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
457 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
458 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
459 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
460 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
461 tmp=linphone_gtk_get_ui_config("artists",defcfg);
466 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
468 tmp=linphone_gtk_get_ui_config("translators",defcfg);
470 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
471 tmp=linphone_gtk_get_ui_config("comments",defcfg);
473 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
474 gtk_widget_show(about);
477 static void set_video_window_decorations(GdkWindow *w){
478 const char *title=linphone_gtk_get_ui_config("title","Linphone");
479 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
480 char video_title[256];
481 GdkPixbuf *pbuf=create_pixbuf(icon_path);
483 if (!linphone_core_in_call(linphone_gtk_get_core())){
484 snprintf(video_title,sizeof(video_title),"%s video",title);
485 /* When not in call, treat the video as a normal window */
486 gdk_window_set_keep_above(w, FALSE);
488 LinphoneAddress *uri =
489 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
492 linphone_address_clean(uri);
493 if (linphone_address_get_display_name(uri)!=NULL){
494 display_name=ms_strdup(linphone_address_get_display_name(uri));
496 display_name=linphone_address_as_string(uri);
498 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
499 linphone_address_destroy(uri);
500 ms_free(display_name);
502 /* During calls, bring up the video window, arrange so that
503 it is above all the other windows */
504 gdk_window_deiconify(w);
505 gdk_window_set_keep_above(w,TRUE);
506 /* Maybe we should have the following, but then we want to
507 have a timer that turns it off after a little while. */
508 /* gdk_window_set_urgency_hint(w,TRUE); */
510 gdk_window_set_title(w,video_title);
511 /* Refrain the video window to be closed at all times. */
512 gdk_window_set_functions(w,
513 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
514 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
517 l=g_list_append(l,pbuf);
518 gdk_window_set_icon_list(w,l);
520 g_object_unref(G_OBJECT(pbuf));
524 static gboolean video_needs_update=FALSE;
526 static void update_video_title(){
527 video_needs_update=TRUE;
530 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
531 static gboolean first_time=TRUE;
533 static unsigned long previd=0;
534 static unsigned long preview_previd=0;
535 static gboolean in_iterate=FALSE;
538 if (in_iterate) return TRUE;
540 linphone_core_iterate(lc);
542 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
543 linphone_gtk_show_directory_search();
547 id=linphone_core_get_native_video_window_id(lc);
548 if (id!=previd || video_needs_update){
552 ms_message("Updating window decorations");
554 w=gdk_window_foreign_new(id);
556 w=gdk_window_foreign_new((HANDLE)id);
559 set_video_window_decorations(w);
560 g_object_unref(G_OBJECT(w));
562 else ms_error("gdk_window_foreign_new() failed");
563 if (video_needs_update) video_needs_update=FALSE;
566 id=linphone_core_get_native_preview_window_id (lc);
567 if (id!=preview_previd ){
571 ms_message("Updating window decorations for preview");
573 w=gdk_window_foreign_new(id);
575 w=gdk_window_foreign_new((HANDLE)id);
578 set_video_window_decorations(w);
579 g_object_unref(G_OBJECT(w));
581 else ms_error("gdk_window_foreign_new() failed");
582 if (video_needs_update) video_needs_update=FALSE;
585 if (addr_to_call!=NULL){
586 /*make sure we are not showing the login screen*/
587 GtkWidget *mw=linphone_gtk_get_main_window();
588 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
589 if (!GTK_WIDGET_VISIBLE(login_frame)){
590 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
591 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
593 linphone_gtk_start_call(uri_bar);
600 static void load_uri_history(){
601 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
604 GtkEntryCompletion *gep=gtk_entry_completion_new();
605 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
608 snprintf(key,sizeof(key),"uri%i",i);
609 uri=linphone_gtk_get_ui_config(key,NULL);
612 gtk_list_store_append(model,&iter);
613 gtk_list_store_set(model,&iter,0,uri,-1);
614 if (i==0) gtk_entry_set_text(uribar,uri);
618 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
619 gtk_entry_completion_set_text_column(gep,0);
620 gtk_entry_set_completion(uribar,gep);
623 static void save_uri_history(){
624 LinphoneCore *lc=linphone_gtk_get_core();
625 LpConfig *cfg=linphone_core_get_config(lc);
626 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
631 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
633 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
635 gtk_tree_model_get(model,&iter,0,&uri,-1);
637 snprintf(key,sizeof(key),"uri%i",i);
638 lp_config_set_string(cfg,"GtkUi",key,uri);
643 }while(gtk_tree_model_iter_next(model,&iter));
647 static void completion_add_text(GtkEntry *entry, const char *text){
649 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
651 if (gtk_tree_model_get_iter_first(model,&iter)){
654 gtk_tree_model_get(model,&iter,0,&uri,-1);
656 if (strcmp(uri,text)==0) {
658 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
664 }while (gtk_tree_model_iter_next(model,&iter));
666 /* and prepend it on top of the list */
667 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
668 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
672 bool_t linphone_gtk_video_enabled(void){
673 const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
674 return vpol->automatically_accept && vpol->automatically_initiate;
677 void linphone_gtk_show_main_window(){
678 GtkWidget *w=linphone_gtk_get_main_window();
679 LinphoneCore *lc=linphone_gtk_get_core();
680 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
681 VIDEOSELFVIEW_DEFAULT));
683 gtk_window_present(GTK_WINDOW(w));
686 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
687 GtkWidget *mw=linphone_gtk_get_main_window();
688 if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
689 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
691 if (linphone_gtk_use_in_call_view() && call)
692 linphone_gtk_in_call_view_terminate(call,error);
693 update_video_title();
696 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
697 LinphoneCore *lc=linphone_gtk_get_core();
698 GtkWidget *mw=linphone_gtk_get_main_window();
699 const MSList *calls=linphone_core_get_calls(lc);
701 bool_t start_active=TRUE;
702 //bool_t stop_active=FALSE;
703 bool_t add_call=FALSE;
704 int call_list_size=ms_list_size(calls);
714 button=linphone_gtk_get_widget(mw,"start_call");
715 gtk_widget_set_sensitive(button,start_active);
716 gtk_widget_set_visible(button,!add_call);
718 button=linphone_gtk_get_widget(mw,"add_call");
719 if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
720 gtk_widget_set_sensitive(button,FALSE);
722 gtk_widget_set_sensitive(button,start_active);
724 gtk_widget_set_visible(button,add_call);
726 //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
727 GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
728 if(conf_frame==NULL){
729 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
730 linphone_gtk_enable_conference_button(lc,call_list_size>1);
732 linphone_gtk_enable_transfer_button(lc,FALSE);
733 linphone_gtk_enable_conference_button(lc,FALSE);
735 update_video_title();
736 if (call) linphone_gtk_update_video_button(call);
739 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
740 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
741 if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
742 completion_add_text(GTK_ENTRY(uri_bar),entered);
744 linphone_gtk_call_terminated(NULL,NULL);
749 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
750 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
751 linphone_core_accept_call (linphone_gtk_get_core(),call);
752 linphone_call_unref(call);
757 void linphone_gtk_start_call(GtkWidget *w){
758 LinphoneCore *lc=linphone_gtk_get_core();
760 /*change into in-call mode, then do the work later as it might block a bit */
761 GtkWidget *mw=gtk_widget_get_toplevel(w);
762 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
764 call=linphone_gtk_get_currently_displayed_call(NULL);
765 if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
766 linphone_core_accept_call(lc,call);
768 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
769 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
770 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
771 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
776 void linphone_gtk_uri_bar_activate(GtkWidget *w){
777 linphone_gtk_start_call(w);
780 void linphone_gtk_terminate_call(GtkWidget *button){
782 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
784 linphone_core_terminate_call(linphone_gtk_get_core(),call);
786 linphone_core_terminate_conference(linphone_gtk_get_core());
790 void linphone_gtk_decline_clicked(GtkWidget *button){
791 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
793 linphone_core_terminate_call(linphone_gtk_get_core(),call);
796 void linphone_gtk_answer_clicked(GtkWidget *button){
797 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
799 linphone_core_accept_call(linphone_gtk_get_core(),call);
800 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
804 void _linphone_gtk_enable_video(gboolean val){
805 LinphoneVideoPolicy policy={0};
806 policy.automatically_initiate=policy.automatically_accept=val;
807 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
808 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
811 linphone_core_enable_video_preview(linphone_gtk_get_core(),
812 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
814 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
818 void linphone_gtk_enable_video(GtkWidget *w){
819 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
820 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
821 _linphone_gtk_enable_video(val);
824 void linphone_gtk_enable_self_view(GtkWidget *w){
825 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
826 LinphoneCore *lc=linphone_gtk_get_core();
827 linphone_core_enable_video_preview(lc,val);
828 linphone_core_enable_self_view(lc,val);
829 linphone_gtk_set_ui_config_int("videoselfview",val);
832 void linphone_gtk_used_identity_changed(GtkWidget *w){
833 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
834 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
835 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
836 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
837 linphone_gtk_show_directory_search();
839 if (sel) g_free(sel);
842 void on_proxy_refresh_button_clicked(GtkWidget *w){
843 LinphoneCore *lc=linphone_gtk_get_core();
844 MSList const *item=linphone_core_get_proxy_config_list(lc);
845 while (item != NULL) {
846 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
847 linphone_proxy_config_edit(lpc);
848 linphone_proxy_config_done(lpc);
853 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
854 linphone_gtk_show_friends();
857 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
859 case GTK_RESPONSE_YES:
860 linphone_gtk_show_contact(lf);
863 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
865 gtk_widget_destroy(dialog);
868 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
871 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
872 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
876 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);
877 dialog = gtk_message_dialog_new (
878 GTK_WINDOW(linphone_gtk_get_main_window()),
879 GTK_DIALOG_DESTROY_WITH_PARENT,
880 GTK_MESSAGE_QUESTION,
885 g_signal_connect(G_OBJECT (dialog), "response",
886 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
887 /* actually show the box */
888 gtk_widget_show(dialog);
891 typedef struct _AuthTimeout{
895 static void auth_timeout_clean(AuthTimeout *tout){
899 static gboolean auth_timeout_destroy(AuthTimeout *tout){
901 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
902 gtk_widget_destroy(tout->w);
908 static AuthTimeout * auth_timeout_new(GtkWidget *w){
909 AuthTimeout *tout=g_new(AuthTimeout,1);
911 /*so that the timeout no more references the widget when it is destroyed:*/
912 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
913 /*so that the widget is automatically destroyed after some time */
914 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
918 void linphone_gtk_password_cancel(GtkWidget *w){
919 LinphoneAuthInfo *info;
920 GtkWidget *window=gtk_widget_get_toplevel(w);
921 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
922 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
923 gtk_widget_destroy(window);
926 void linphone_gtk_password_ok(GtkWidget *w){
928 GtkWidget *window=gtk_widget_get_toplevel(w);
929 LinphoneAuthInfo *info;
930 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
931 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
932 entry=linphone_gtk_get_widget(window,"password_entry");
933 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
934 linphone_auth_info_set_userid(info,
935 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
936 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
937 gtk_widget_destroy(window);
940 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
941 GtkWidget *w=linphone_gtk_create_window("password");
942 GtkWidget *label=linphone_gtk_get_widget(w,"message");
943 LinphoneAuthInfo *info;
945 GtkWidget *mw=linphone_gtk_get_main_window();
947 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
948 /*don't prompt for authentication when login frame is visible*/
949 linphone_core_abort_authentication(lc,NULL);
953 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
955 gtk_label_set_markup(GTK_LABEL(label),msg);
957 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
958 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
959 g_object_set_data(G_OBJECT(w),"auth_info",info);
960 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
965 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
966 GtkWidget *w=linphone_gtk_get_main_window();
967 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
969 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
970 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
974 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
975 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
978 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
979 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
982 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
984 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
985 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
988 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
989 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
990 if (w) linphone_gtk_call_log_update(w);
991 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
995 static bool_t notify_actions_supported() {
996 bool_t accepts_actions = FALSE;
997 GList *capabilities = notify_get_server_caps();
999 if(capabilities != NULL) {
1000 for(c = capabilities; c != NULL; c = c->next) {
1001 if(strcmp((char*)c->data, "actions") == 0 ) {
1002 accepts_actions = TRUE;
1006 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1007 g_list_free(capabilities);
1009 return accepts_actions;
1012 static NotifyNotification* build_notification(const char *title, const char *body){
1013 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1020 static void show_notification(NotifyNotification* n){
1021 if (n && !notify_notification_show(n,NULL))
1022 ms_error("Failed to send notification.");
1025 static void make_notification(const char *title, const char *body){
1026 show_notification(build_notification(title,body));
1031 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1033 if (!notify_is_initted())
1034 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1039 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1045 ms_error("Failed to send notification.");
1047 linphone_gtk_show_main_window();
1049 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1052 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1053 NotifyNotification *n;
1054 switch(linphone_call_get_state(call)){
1055 case LinphoneCallError:
1056 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
1058 case LinphoneCallEnd:
1059 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1061 case LinphoneCallIncomingReceived:
1062 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1063 if (notify_actions_supported()) {
1064 notify_notification_add_action (n,"answer", _("Answer"),
1065 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1066 notify_notification_add_action (n,"decline",_("Decline"),
1067 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1069 show_notification(n);
1071 case LinphoneCallPausedByRemote:
1072 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<span size=\"large\">by %s</span>"),remote));
1077 if (body) g_free(body);
1078 if (remote) g_free(remote);
1083 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1084 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1085 LinphoneCore *lc=linphone_call_get_core(call);
1086 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1087 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1088 linphone_core_accept_call_update(lc,call,params);
1089 linphone_call_params_destroy(params);
1091 linphone_call_unref(call);
1092 g_source_remove_by_user_data(dialog);
1093 gtk_widget_destroy(dialog);
1096 static void on_call_updated_timeout(GtkWidget *dialog){
1097 gtk_widget_destroy(dialog);
1100 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1101 LinphoneCore *lc=linphone_call_get_core(call);
1102 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1103 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1104 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1105 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1106 gboolean video_used=linphone_call_params_video_enabled(current_params);
1107 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1108 video_used,video_requested,pol->automatically_accept);
1109 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1110 linphone_core_defer_call_update(lc,call);
1112 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1114 const char *dname=linphone_address_get_display_name(addr);
1115 if (dname==NULL) dname=linphone_address_get_username(addr);
1116 if (dname==NULL) dname=linphone_address_get_domain(addr);
1117 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1118 GTK_DIALOG_DESTROY_WITH_PARENT,
1119 GTK_MESSAGE_WARNING,
1121 _("%s proposed to start video. Do you accept ?"),dname);
1122 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1123 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1124 gtk_widget_show(dialog);
1129 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1131 case LinphoneCallOutgoingInit:
1132 linphone_gtk_create_in_call_view (call);
1134 case LinphoneCallOutgoingProgress:
1135 linphone_gtk_in_call_view_set_calling (call);
1137 case LinphoneCallStreamsRunning:
1138 linphone_gtk_in_call_view_set_in_call(call);
1140 case LinphoneCallUpdatedByRemote:
1141 linphone_gtk_call_updated_by_remote(call);
1143 case LinphoneCallError:
1144 linphone_gtk_in_call_view_terminate (call,msg);
1146 case LinphoneCallEnd:
1147 linphone_gtk_in_call_view_terminate(call,NULL);
1148 linphone_gtk_status_icon_set_blinking(FALSE);
1150 case LinphoneCallIncomingReceived:
1151 linphone_gtk_create_in_call_view(call);
1152 linphone_gtk_in_call_view_set_incoming(call);
1153 linphone_gtk_status_icon_set_blinking(TRUE);
1155 linphone_call_ref(call);
1156 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1159 case LinphoneCallResuming:
1160 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1161 linphone_gtk_in_call_view_set_in_call (call);
1163 case LinphoneCallPausing:
1164 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1165 update_tab_header(call,FALSE);
1166 case LinphoneCallPausedByRemote:
1167 linphone_gtk_in_call_view_set_paused(call);
1168 update_tab_header(call,TRUE);
1170 case LinphoneCallConnected:
1171 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1172 linphone_gtk_status_icon_set_blinking(FALSE);
1177 linphone_gtk_notify(call, msg);
1178 linphone_gtk_update_call_buttons (call);
1181 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1182 linphone_gtk_in_call_view_show_encryption(call);
1185 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1186 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1189 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1190 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1191 GtkTreeModel *model=gtk_combo_box_get_model(box);
1193 gboolean found=FALSE;
1194 const char *stock_id=NULL;
1196 if (gtk_tree_model_get_iter_first(model,&iter)){
1199 gtk_tree_model_get(model,&iter,2,&p,-1);
1204 }while(gtk_tree_model_iter_next(model,&iter));
1207 g_warning("Could not find proxy config in combo box of identities.");
1211 case LinphoneRegistrationOk:
1212 stock_id=GTK_STOCK_YES;
1214 case LinphoneRegistrationProgress:
1215 stock_id=GTK_STOCK_REFRESH;
1217 case LinphoneRegistrationCleared:
1220 case LinphoneRegistrationFailed:
1221 stock_id=GTK_STOCK_DIALOG_WARNING;
1226 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1229 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1230 LinphoneRegistrationState rs, const char *msg){
1232 case LinphoneRegistrationOk:
1234 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1235 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1236 linphone_gtk_exit_login_frame();
1243 update_registration_status(cfg,rs);
1246 void linphone_gtk_open_browser(const char *url){
1247 /*in gtk 2.16, gtk_show_uri does not work...*/
1249 #if GTK_CHECK_VERSION(2,18,3)
1250 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1253 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1254 g_spawn_command_line_async(cl,NULL);
1257 ShellExecute(0,"open",url,NULL,NULL,1);
1261 void linphone_gtk_link_to_website(GtkWidget *item){
1262 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1263 linphone_gtk_open_browser(home);
1266 #ifndef HAVE_GTK_OSX
1268 static GtkStatusIcon *icon=NULL;
1270 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1271 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1272 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1275 static GtkWidget *create_icon_menu(){
1276 GtkWidget *menu=gtk_menu_new();
1277 GtkWidget *menu_item;
1280 const gchar *homesite;
1282 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1283 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1284 tmp=g_strdup(homesite);
1285 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1286 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1288 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1289 gtk_widget_show(image);
1290 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1291 //g_object_unref(G_OBJECT(image));
1292 gtk_widget_show(menu_item);
1293 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1294 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1296 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1297 gtk_widget_show(menu_item);
1298 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1299 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1300 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1301 gtk_widget_show(menu_item);
1302 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1303 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1304 gtk_widget_show(menu);
1308 static void handle_icon_click() {
1309 GtkWidget *mw=linphone_gtk_get_main_window();
1310 if (!gtk_window_is_active((GtkWindow*)mw)) {
1311 linphone_gtk_show_main_window();
1313 gtk_widget_hide(mw);
1317 static void linphone_gtk_init_status_icon(){
1318 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1319 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1320 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1321 GtkWidget *menu=create_icon_menu();
1323 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1324 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1325 #if GTK_CHECK_VERSION(2,20,0)
1326 gtk_status_icon_set_name(icon,title);
1328 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1329 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1330 gtk_status_icon_set_tooltip(icon,title);
1331 gtk_status_icon_set_visible(icon,TRUE);
1332 g_object_set_data(G_OBJECT(icon),"menu",menu);
1333 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1334 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1335 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1336 pbuf=create_pixbuf(call_icon_path);
1337 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1340 static gboolean do_icon_blink(GtkStatusIcon *gi){
1341 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1342 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1343 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1344 if (cur_icon==call_icon){
1345 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1347 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1354 void linphone_gtk_status_icon_set_blinking(gboolean val){
1356 static gint attention_id;
1357 GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1359 attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
1360 else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
1364 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1365 if (val && tout==0){
1366 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1367 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1368 }else if (!val && tout!=0){
1369 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1370 g_source_remove(tout);
1371 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1372 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1378 void linphone_gtk_options_activate(GtkWidget *item){
1379 #ifndef HAVE_GTK_OSX
1380 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1385 static void init_identity_combo(GtkComboBox *box){
1386 GtkListStore *store;
1387 GtkCellRenderer *r1,*r2;
1388 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1389 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1390 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1391 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1392 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1393 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1394 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1395 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1398 void linphone_gtk_load_identities(void){
1400 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1402 LinphoneProxyConfig *def=NULL;
1404 GtkListStore *store;
1407 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1408 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1409 /* model is empty, this is the first time we go here */
1410 init_identity_combo(box);
1411 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1413 gtk_list_store_clear(store);
1414 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1415 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1416 gtk_list_store_append(store,&iter);
1417 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1418 g_free(def_identity);
1419 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1421 elem=ms_list_next(elem),i++){
1422 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1423 gtk_list_store_append(store,&iter);
1424 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1425 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1431 gtk_combo_box_set_active(box,def_index);
1434 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1435 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1436 GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1438 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1439 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1440 if (linphone_core_in_call(linphone_gtk_get_core())){
1441 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1445 static void linphone_gtk_dtmf_released(GtkButton *button){
1446 linphone_core_stop_dtmf (linphone_gtk_get_core());
1450 static void linphone_gtk_connect_digits(void){
1451 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1452 GList *children=gtk_container_get_children(cont);
1454 for(elem=children;elem!=NULL;elem=elem->next){
1455 GtkButton *button=GTK_BUTTON(elem->data);
1456 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1457 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1461 static void linphone_gtk_check_menu_items(void){
1462 bool_t video_enabled=linphone_gtk_video_enabled();
1463 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1464 GtkWidget *selfview_item=linphone_gtk_get_widget(
1465 linphone_gtk_get_main_window(),"selfview_item");
1466 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1467 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1468 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1471 static gboolean linphone_gtk_can_manage_accounts(){
1472 LinphoneCore *lc=linphone_gtk_get_core();
1474 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1475 SipSetup *ss=(SipSetup*)elem->data;
1476 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1483 static void linphone_gtk_configure_main_window(){
1484 static gboolean config_loaded=FALSE;
1485 static const char *title;
1486 static const char *home;
1487 static const char *start_call_icon;
1488 static const char *add_call_icon;
1489 //static const char *stop_call_icon;
1490 static const char *search_icon;
1491 static gboolean update_check_menu;
1492 static gboolean buttons_have_borders;
1493 static gboolean show_abcd;
1494 GtkWidget *w=linphone_gtk_get_main_window();
1495 GHashTable *contacts_history;
1497 contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1498 g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1500 if (!config_loaded){
1501 title=linphone_gtk_get_ui_config("title","Linphone");
1502 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1503 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1504 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1505 //stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png");
1506 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1507 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1508 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1509 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1512 linphone_gtk_configure_window(w,"main_window");
1514 gtk_window_set_title(GTK_WINDOW(w),title);
1516 if (start_call_icon){
1517 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1518 create_pixmap (start_call_icon));
1519 if (!buttons_have_borders)
1520 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1523 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1524 create_pixmap (add_call_icon));
1525 if (!buttons_have_borders)
1526 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1529 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1531 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1532 g_object_unref(G_OBJECT(pbuf));
1537 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1539 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1543 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1545 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1546 g_object_unref(G_OBJECT(pbuf));
1551 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1553 GtkImage *img=GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon"));
1556 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU,&w,&h);
1557 scaled=gdk_pixbuf_scale_simple(pbuf,w,h,GDK_INTERP_BILINEAR);
1558 gtk_image_set_from_pixbuf(img,scaled);
1559 g_object_unref(G_OBJECT(scaled));
1560 g_object_unref(G_OBJECT(pbuf));
1563 if (linphone_gtk_can_manage_accounts()) {
1564 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1566 if (update_check_menu){
1567 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1570 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1571 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1572 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1573 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1574 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1578 void linphone_gtk_manage_login(void){
1579 LinphoneCore *lc=linphone_gtk_get_core();
1580 LinphoneProxyConfig *cfg=NULL;
1581 linphone_core_get_default_proxy(lc,&cfg);
1583 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1584 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1585 linphone_gtk_show_login_frame(cfg);
1591 gboolean linphone_gtk_close(GtkWidget *mw){
1592 /*shutdown calls if any*/
1593 LinphoneCore *lc=linphone_gtk_get_core();
1594 if (linphone_core_in_call(lc)){
1595 linphone_core_terminate_all_calls(lc);
1597 linphone_core_enable_video_preview(lc,FALSE);
1598 #ifdef __APPLE__ /*until with have a better option*/
1599 gtk_window_iconify(GTK_WINDOW(mw));
1601 gtk_widget_hide(mw);
1607 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1608 bool_t video_enabled=linphone_gtk_video_enabled();
1609 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1610 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1612 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1613 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1619 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1620 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1621 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1623 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1624 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1625 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1626 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1627 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1628 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1629 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1630 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1631 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1632 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1633 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1634 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1635 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1636 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1637 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1638 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1642 static void linphone_gtk_init_main_window(){
1643 GtkWidget *main_window;
1645 linphone_gtk_configure_main_window();
1646 linphone_gtk_manage_login();
1648 linphone_gtk_load_identities();
1649 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1650 linphone_gtk_show_friends();
1651 linphone_gtk_connect_digits();
1652 main_window=linphone_gtk_get_main_window();
1653 linphone_gtk_call_log_update(main_window);
1655 linphone_gtk_init_dtmf_table(main_window);
1656 linphone_gtk_update_call_buttons (NULL);
1657 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1658 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1659 g_signal_connect (G_OBJECT (main_window), "delete-event",
1660 G_CALLBACK (linphone_gtk_close), main_window);
1663 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1664 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1665 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1666 gtk_widget_hide(menubar);
1667 gtk_osxapplication_ready(theMacApp);
1669 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1671 linphone_gtk_check_menu_items();
1675 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1677 const char *lname="undef";
1679 #if defined(__linux) || defined(__APPLE__)
1680 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1699 g_error("Bad level !");
1701 #if defined(__linux) || defined(__APPLE__)
1703 msg=g_strdup_vprintf(fmt,cap);
1706 msg=g_strdup_vprintf(fmt,args);
1708 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1711 linphone_gtk_log_push(lev,fmt,args);
1715 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1716 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1717 linphone_gtk_get_main_window(), "uribar"));
1719 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1721 gtk_entry_set_text(uri_bar, refer_to);
1722 linphone_gtk_start_call(linphone_gtk_get_main_window());
1725 static void linphone_gtk_check_soundcards(){
1726 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1727 if (devices==NULL || devices[0]==NULL){
1728 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1729 _("No sound cards have been detected on this computer.\n"
1730 "You won't be able to send or receive audio calls."));
1735 // Display the account wizard
1736 void linphone_gtk_display_wizard() {
1737 if (the_wizard == NULL || !gtk_widget_get_visible(the_wizard)) { // Only one instance of the wizard at the same time
1738 the_wizard = linphone_gtk_create_assistant();
1743 static void linphone_gtk_quit(void){
1744 static gboolean quit_done=FALSE;
1747 linphone_gtk_unmonitor_usb();
1748 g_source_remove_by_user_data(linphone_gtk_get_core());
1749 linphone_gtk_uninit_instance();
1750 linphone_gtk_destroy_log_window();
1751 linphone_core_destroy(the_core);
1752 linphone_gtk_log_uninit();
1756 gdk_threads_leave();
1762 This is not the correct way to implement block termination.
1763 The good way would be to call gtk_main_quit(), and return TRUE.
1764 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1765 As a result the program cannot exit at all.
1766 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1768 static gboolean on_block_termination(void){
1770 linphone_gtk_quit();
1775 int main(int argc, char *argv[]){
1780 const char *factory_config_file;
1782 GtkSettings *settings;
1784 const char *app_name="Linphone";
1786 #if !GLIB_CHECK_VERSION(2, 31, 0)
1787 g_thread_init(NULL);
1791 progpath = strdup(argv[0]);
1793 config_file=linphone_gtk_get_config_file(NULL);
1797 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1798 if ((lang=getenv("LANG"))!=NULL){
1801 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1807 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1810 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1813 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1815 if (strncmp(lang,"zh",2)==0){
1816 workaround_gtk_entry_chinese_bug=TRUE;
1819 setenv("LANG",lang,1);
1821 setenv("LANGUAGE",lang,1);
1826 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1827 if (p==NULL) perror("bindtextdomain failed");
1828 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1829 textdomain (GETTEXT_PACKAGE);
1831 g_message("NLS disabled.\n");
1834 gtk_rc_add_default_file("./gtkrc");
1836 gdk_threads_enter();
1838 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1839 linphone_options,NULL,NULL)){
1840 gdk_threads_leave();
1844 settings=gtk_settings_get_default();
1845 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1846 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1847 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1848 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1850 if (workingdir!=NULL){
1851 if (chdir(workingdir)==-1){
1852 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1856 /* Now, look for the factory configuration file, we do it this late
1857 since we want to have had time to change directory and to parse
1858 the options, in case we needed to access the working directory */
1859 factory_config_file = linphone_gtk_get_factory_config_file();
1861 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1862 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1863 g_warning("This instance is going to exit now.");
1864 gdk_threads_leave();
1868 add_pixmap_directory("pixmaps");
1869 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1872 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1873 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1874 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1875 /*never block termination:*/
1876 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1879 the_ui=linphone_gtk_create_window("main");
1881 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1883 linphone_gtk_create_log_window();
1884 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1886 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1888 g_set_application_name(app_name);
1889 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1890 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1892 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1893 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1894 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1895 linphone_gtk_init_main_window();
1898 // Veryfing if at least one sip account is configured. If not, show wizard
1899 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1900 linphone_gtk_display_wizard();
1904 #ifndef HAVE_GTK_OSX
1905 linphone_gtk_init_status_icon();
1908 linphone_gtk_show_main_window();
1909 linphone_gtk_check_soundcards();
1911 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1912 linphone_gtk_check_for_new_version();
1913 linphone_gtk_monitor_usb();
1916 linphone_gtk_quit();
1917 #ifndef HAVE_GTK_OSX
1918 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1919 gtk_status_icon_set_visible(icon,FALSE);