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.refer_received=linphone_gtk_refer_received;
235 vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
236 vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
237 vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
239 the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
240 linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
241 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
242 linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
243 g_free(secrets_file);
244 linphone_core_enable_video(the_core,TRUE,TRUE);
246 _linphone_gtk_enable_video(FALSE);
247 linphone_gtk_set_ui_config_int("videoselfview",0);
251 LinphoneCore *linphone_gtk_get_core(void){
255 GtkWidget *linphone_gtk_get_main_window(){
259 void linphone_gtk_destroy_main_window() {
260 linphone_gtk_destroy_window(the_ui);
264 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
265 static const char *icon_path=NULL;
266 static const char *hiddens=NULL;
267 static const char *shown=NULL;
268 static bool_t config_loaded=FALSE;
269 if (linphone_gtk_get_core()==NULL) return;
270 if (config_loaded==FALSE){
271 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
272 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
273 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
277 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
279 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
281 GdkPixbuf *pbuf=create_pixbuf(icon_path);
283 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
284 g_object_unref(G_OBJECT(pbuf));
289 static int get_ui_file(const char *name, char *path, int pathsize){
290 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
291 if (access(path,F_OK)!=0){
292 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
293 if (access(path,F_OK)!=0){
294 g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,
295 INSTALLED_XML_DIR,name);
302 void linphone_gtk_destroy_window(GtkWidget *widget) {
303 GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder");
304 gtk_widget_destroy(widget);
305 g_object_unref (G_OBJECT (builder));
308 GtkWidget *linphone_gtk_create_window(const char *window_name){
309 GError* error = NULL;
310 GtkBuilder* builder = gtk_builder_new ();
314 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
316 if (!gtk_builder_add_from_file (builder, path, &error)){
317 g_error("Couldn't load builder file: %s", error->message);
318 g_error_free (error);
321 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
323 g_error("Could not retrieve '%s' window from xml file",window_name);
326 g_object_set_data(G_OBJECT(w), "builder",builder);
327 gtk_builder_connect_signals(builder,w);
328 linphone_gtk_configure_window(w,window_name);
332 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
335 GtkBuilder* builder = gtk_builder_new ();
337 gchar *object_ids[2];
338 object_ids[0]=g_strdup(widget_name);
341 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
342 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
343 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
344 g_error_free (error);
345 g_free(object_ids[0]);
348 g_free(object_ids[0]);
349 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
351 g_error("Could not retrieve '%s' window from xml file",widget_name);
354 g_object_set_data(G_OBJECT(w),"builder",builder);
355 g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
356 gtk_builder_connect_signals(builder,w);
360 static void entry_unmapped(GtkWidget *entry){
361 g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
362 gtk_widget_unrealize(entry);
365 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
368 if (window==NULL) return NULL;
369 builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
371 g_error("Fail to retrieve builder from window !");
374 w=gtk_builder_get_object(builder,name);
376 g_error("No widget named %s found in xml interface.",name);
378 if (workaround_gtk_entry_chinese_bug){
379 if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
380 if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
381 g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
382 g_message("%s is a GtkEntry",name);
383 g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
387 return GTK_WIDGET(w);
391 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
393 GtkWidget *main_window=linphone_gtk_get_main_window();
395 gtk_widget_show(main_window);
396 if (type==GTK_MESSAGE_QUESTION)
398 /* draw a question box. link to dialog_click callback */
399 dialog = gtk_message_dialog_new (
400 GTK_WINDOW(main_window),
401 GTK_DIALOG_DESTROY_WITH_PARENT,
402 GTK_MESSAGE_QUESTION,
405 (const gchar*)message);
406 /* connect to some callback : REVISIT */
408 g_signal_connect_swapped (G_OBJECT (dialog), "response",
409 G_CALLBACK (dialog_click),
412 /* actually show the box */
413 gtk_widget_show(dialog);
417 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
418 GTK_DIALOG_DESTROY_WITH_PARENT,
422 (const gchar*)message);
423 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
424 g_signal_connect_swapped (G_OBJECT (dialog), "response",
425 G_CALLBACK (gtk_widget_destroy),
427 gtk_widget_show(dialog);
431 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
432 if (id==GTK_RESPONSE_CANCEL){
433 gtk_widget_destroy(GTK_WIDGET(dialog));
437 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
438 g_message("About url clicked");
439 linphone_gtk_open_browser(url);
442 void linphone_gtk_show_about(){
443 struct stat filestat;
444 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
447 GdkPixbuf *logo=create_pixbuf(
448 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
449 static const char *defcfg="defcfg";
451 about=linphone_gtk_create_window("about");
452 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
453 memset(&filestat,0,sizeof(filestat));
454 if (stat(license_file,&filestat)!=0){
455 license_file="COPYING";
456 stat(license_file,&filestat);
458 if (filestat.st_size>0){
459 char *license=g_malloc(filestat.st_size+1);
460 FILE *f=fopen(license_file,"r");
461 if (f && fread(license,filestat.st_size,1,f)==1){
462 license[filestat.st_size]='\0';
463 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
467 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
468 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
469 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
470 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
471 tmp=linphone_gtk_get_ui_config("artists",defcfg);
476 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
478 tmp=linphone_gtk_get_ui_config("translators",defcfg);
480 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
481 tmp=linphone_gtk_get_ui_config("comments",defcfg);
483 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
484 gtk_widget_show(about);
487 static void set_video_window_decorations(GdkWindow *w){
488 const char *title=linphone_gtk_get_ui_config("title","Linphone");
489 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
490 char video_title[256];
491 GdkPixbuf *pbuf=create_pixbuf(icon_path);
493 if (!linphone_core_in_call(linphone_gtk_get_core())){
494 snprintf(video_title,sizeof(video_title),"%s video",title);
495 /* When not in call, treat the video as a normal window */
496 gdk_window_set_keep_above(w, FALSE);
498 LinphoneAddress *uri =
499 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
502 linphone_address_clean(uri);
503 if (linphone_address_get_display_name(uri)!=NULL){
504 display_name=ms_strdup(linphone_address_get_display_name(uri));
506 display_name=linphone_address_as_string(uri);
508 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
509 linphone_address_destroy(uri);
510 ms_free(display_name);
512 /* During calls, bring up the video window, arrange so that
513 it is above all the other windows */
514 gdk_window_deiconify(w);
515 gdk_window_set_keep_above(w,TRUE);
516 /* Maybe we should have the following, but then we want to
517 have a timer that turns it off after a little while. */
518 /* gdk_window_set_urgency_hint(w,TRUE); */
520 gdk_window_set_title(w,video_title);
521 /* Refrain the video window to be closed at all times. */
522 gdk_window_set_functions(w,
523 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
524 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
527 l=g_list_append(l,pbuf);
528 gdk_window_set_icon_list(w,l);
530 g_object_unref(G_OBJECT(pbuf));
534 static gboolean video_needs_update=FALSE;
536 static void update_video_title(){
537 video_needs_update=TRUE;
540 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
541 static gboolean first_time=TRUE;
543 static unsigned long previd=0;
544 static unsigned long preview_previd=0;
545 static gboolean in_iterate=FALSE;
548 if (in_iterate) return TRUE;
550 linphone_core_iterate(lc);
552 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
553 linphone_gtk_show_directory_search();
557 id=linphone_core_get_native_video_window_id(lc);
558 if (id!=previd || video_needs_update){
562 ms_message("Updating window decorations");
564 w=gdk_window_foreign_new(id);
566 w=gdk_window_foreign_new((HANDLE)id);
569 set_video_window_decorations(w);
570 g_object_unref(G_OBJECT(w));
572 else ms_error("gdk_window_foreign_new() failed");
573 if (video_needs_update) video_needs_update=FALSE;
576 id=linphone_core_get_native_preview_window_id (lc);
577 if (id!=preview_previd ){
581 ms_message("Updating window decorations for preview");
583 w=gdk_window_foreign_new(id);
585 w=gdk_window_foreign_new((HANDLE)id);
588 set_video_window_decorations(w);
589 g_object_unref(G_OBJECT(w));
591 else ms_error("gdk_window_foreign_new() failed");
592 if (video_needs_update) video_needs_update=FALSE;
595 if (addr_to_call!=NULL){
596 /*make sure we are not showing the login screen*/
597 GtkWidget *mw=linphone_gtk_get_main_window();
598 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
599 if (!GTK_WIDGET_VISIBLE(login_frame)){
600 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
601 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
603 linphone_gtk_start_call(uri_bar);
610 static void load_uri_history(){
611 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
614 GtkEntryCompletion *gep=gtk_entry_completion_new();
615 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
618 snprintf(key,sizeof(key),"uri%i",i);
619 uri=linphone_gtk_get_ui_config(key,NULL);
622 gtk_list_store_append(model,&iter);
623 gtk_list_store_set(model,&iter,0,uri,-1);
624 if (i==0) gtk_entry_set_text(uribar,uri);
628 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
629 gtk_entry_completion_set_text_column(gep,0);
630 gtk_entry_set_completion(uribar,gep);
633 static void save_uri_history(){
634 LinphoneCore *lc=linphone_gtk_get_core();
635 LpConfig *cfg=linphone_core_get_config(lc);
636 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
641 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
643 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
645 gtk_tree_model_get(model,&iter,0,&uri,-1);
647 snprintf(key,sizeof(key),"uri%i",i);
648 lp_config_set_string(cfg,"GtkUi",key,uri);
653 }while(gtk_tree_model_iter_next(model,&iter));
657 static void completion_add_text(GtkEntry *entry, const char *text){
659 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
661 if (gtk_tree_model_get_iter_first(model,&iter)){
664 gtk_tree_model_get(model,&iter,0,&uri,-1);
666 if (strcmp(uri,text)==0) {
668 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
674 }while (gtk_tree_model_iter_next(model,&iter));
676 /* and prepend it on top of the list */
677 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
678 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
682 bool_t linphone_gtk_video_enabled(void){
683 const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
684 return vpol->automatically_accept && vpol->automatically_initiate;
687 void linphone_gtk_show_main_window(){
688 GtkWidget *w=linphone_gtk_get_main_window();
689 LinphoneCore *lc=linphone_gtk_get_core();
690 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
691 VIDEOSELFVIEW_DEFAULT));
693 gtk_window_present(GTK_WINDOW(w));
696 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
697 GtkWidget *mw=linphone_gtk_get_main_window();
698 if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
699 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
701 if (linphone_gtk_use_in_call_view() && call)
702 linphone_gtk_in_call_view_terminate(call,error);
703 update_video_title();
706 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
707 LinphoneCore *lc=linphone_gtk_get_core();
708 GtkWidget *mw=linphone_gtk_get_main_window();
709 const MSList *calls=linphone_core_get_calls(lc);
711 bool_t start_active=TRUE;
712 //bool_t stop_active=FALSE;
713 bool_t add_call=FALSE;
714 int call_list_size=ms_list_size(calls);
724 button=linphone_gtk_get_widget(mw,"start_call");
725 gtk_widget_set_sensitive(button,start_active);
726 gtk_widget_set_visible(button,!add_call);
728 button=linphone_gtk_get_widget(mw,"add_call");
729 if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
730 gtk_widget_set_sensitive(button,FALSE);
732 gtk_widget_set_sensitive(button,start_active);
734 gtk_widget_set_visible(button,add_call);
736 //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
737 GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
738 if(conf_frame==NULL){
739 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
740 linphone_gtk_enable_conference_button(lc,call_list_size>1);
742 linphone_gtk_enable_transfer_button(lc,FALSE);
743 linphone_gtk_enable_conference_button(lc,FALSE);
745 update_video_title();
746 if (call) linphone_gtk_update_video_button(call);
749 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
750 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
751 if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
752 completion_add_text(GTK_ENTRY(uri_bar),entered);
754 linphone_gtk_call_terminated(NULL,NULL);
759 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
760 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
761 linphone_core_accept_call (linphone_gtk_get_core(),call);
762 linphone_call_unref(call);
767 void linphone_gtk_start_call(GtkWidget *w){
768 LinphoneCore *lc=linphone_gtk_get_core();
770 /*change into in-call mode, then do the work later as it might block a bit */
771 GtkWidget *mw=gtk_widget_get_toplevel(w);
772 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
774 call=linphone_gtk_get_currently_displayed_call(NULL);
775 if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
776 linphone_core_accept_call(lc,call);
778 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
779 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
780 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
781 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
786 void linphone_gtk_uri_bar_activate(GtkWidget *w){
787 linphone_gtk_start_call(w);
790 void linphone_gtk_terminate_call(GtkWidget *button){
792 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
794 linphone_core_terminate_call(linphone_gtk_get_core(),call);
796 linphone_core_terminate_conference(linphone_gtk_get_core());
800 void linphone_gtk_decline_clicked(GtkWidget *button){
801 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
803 linphone_core_terminate_call(linphone_gtk_get_core(),call);
806 void linphone_gtk_answer_clicked(GtkWidget *button){
807 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
809 linphone_core_accept_call(linphone_gtk_get_core(),call);
810 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
814 void _linphone_gtk_enable_video(gboolean val){
815 LinphoneVideoPolicy policy={0};
816 policy.automatically_initiate=policy.automatically_accept=val;
817 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
818 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
821 linphone_core_enable_video_preview(linphone_gtk_get_core(),
822 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
824 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
828 void linphone_gtk_enable_video(GtkWidget *w){
829 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
830 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
831 _linphone_gtk_enable_video(val);
834 void linphone_gtk_enable_self_view(GtkWidget *w){
835 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
836 LinphoneCore *lc=linphone_gtk_get_core();
837 linphone_core_enable_video_preview(lc,val);
838 linphone_core_enable_self_view(lc,val);
839 linphone_gtk_set_ui_config_int("videoselfview",val);
842 void linphone_gtk_used_identity_changed(GtkWidget *w){
843 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
844 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
845 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
846 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
847 linphone_gtk_show_directory_search();
849 if (sel) g_free(sel);
852 void on_proxy_refresh_button_clicked(GtkWidget *w){
853 LinphoneCore *lc=linphone_gtk_get_core();
854 MSList const *item=linphone_core_get_proxy_config_list(lc);
855 while (item != NULL) {
856 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
857 linphone_proxy_config_edit(lpc);
858 linphone_proxy_config_done(lpc);
863 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
864 linphone_gtk_show_friends();
867 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
869 case GTK_RESPONSE_YES:
870 linphone_gtk_show_contact(lf);
873 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
875 gtk_widget_destroy(dialog);
878 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
881 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
882 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
886 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);
887 dialog = gtk_message_dialog_new (
888 GTK_WINDOW(linphone_gtk_get_main_window()),
889 GTK_DIALOG_DESTROY_WITH_PARENT,
890 GTK_MESSAGE_QUESTION,
895 g_signal_connect(G_OBJECT (dialog), "response",
896 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
897 /* actually show the box */
898 gtk_widget_show(dialog);
901 typedef struct _AuthTimeout{
905 static void auth_timeout_clean(AuthTimeout *tout){
909 static gboolean auth_timeout_destroy(AuthTimeout *tout){
911 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
912 gtk_widget_destroy(tout->w);
918 static AuthTimeout * auth_timeout_new(GtkWidget *w){
919 AuthTimeout *tout=g_new(AuthTimeout,1);
921 /*so that the timeout no more references the widget when it is destroyed:*/
922 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
923 /*so that the widget is automatically destroyed after some time */
924 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
928 void linphone_gtk_password_cancel(GtkWidget *w){
929 LinphoneAuthInfo *info;
930 GtkWidget *window=gtk_widget_get_toplevel(w);
931 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
932 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
933 gtk_widget_destroy(window);
936 void linphone_gtk_password_ok(GtkWidget *w){
938 GtkWidget *window=gtk_widget_get_toplevel(w);
939 LinphoneAuthInfo *info;
940 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
941 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
942 entry=linphone_gtk_get_widget(window,"password_entry");
943 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
944 linphone_auth_info_set_userid(info,
945 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
946 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
947 gtk_widget_destroy(window);
950 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
951 GtkWidget *w=linphone_gtk_create_window("password");
952 GtkWidget *label=linphone_gtk_get_widget(w,"message");
953 LinphoneAuthInfo *info;
955 GtkWidget *mw=linphone_gtk_get_main_window();
957 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
958 /*don't prompt for authentication when login frame is visible*/
959 linphone_core_abort_authentication(lc,NULL);
963 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
965 gtk_label_set_markup(GTK_LABEL(label),msg);
967 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
968 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
969 g_object_set_data(G_OBJECT(w),"auth_info",info);
970 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
975 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
976 GtkWidget *w=linphone_gtk_get_main_window();
977 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
979 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
980 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
984 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
985 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
988 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
989 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
992 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
994 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
995 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
998 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
999 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1000 if (w) linphone_gtk_call_log_update(w);
1001 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1005 static bool_t notify_actions_supported() {
1006 bool_t accepts_actions = FALSE;
1007 GList *capabilities = notify_get_server_caps();
1009 if(capabilities != NULL) {
1010 for(c = capabilities; c != NULL; c = c->next) {
1011 if(strcmp((char*)c->data, "actions") == 0 ) {
1012 accepts_actions = TRUE;
1016 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1017 g_list_free(capabilities);
1019 return accepts_actions;
1022 static NotifyNotification* build_notification(const char *title, const char *body){
1023 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1030 static void show_notification(NotifyNotification* n){
1031 if (n && !notify_notification_show(n,NULL))
1032 ms_error("Failed to send notification.");
1035 static void make_notification(const char *title, const char *body){
1036 show_notification(build_notification(title,body));
1041 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1043 if (!notify_is_initted())
1044 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1049 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1055 ms_error("Failed to send notification.");
1057 linphone_gtk_show_main_window();
1059 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1062 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1063 NotifyNotification *n;
1064 switch(linphone_call_get_state(call)){
1065 case LinphoneCallError:
1066 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
1068 case LinphoneCallEnd:
1069 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1071 case LinphoneCallIncomingReceived:
1072 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1073 if (notify_actions_supported()) {
1074 notify_notification_add_action (n,"answer", _("Answer"),
1075 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1076 notify_notification_add_action (n,"decline",_("Decline"),
1077 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1079 show_notification(n);
1081 case LinphoneCallPausedByRemote:
1082 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<span size=\"large\">by %s</span>"),remote));
1087 if (body) g_free(body);
1088 if (remote) g_free(remote);
1093 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1094 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1095 LinphoneCore *lc=linphone_call_get_core(call);
1096 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1097 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1098 linphone_core_accept_call_update(lc,call,params);
1099 linphone_call_params_destroy(params);
1101 linphone_call_unref(call);
1102 g_source_remove_by_user_data(dialog);
1103 gtk_widget_destroy(dialog);
1106 static void on_call_updated_timeout(GtkWidget *dialog){
1107 gtk_widget_destroy(dialog);
1110 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1111 LinphoneCore *lc=linphone_call_get_core(call);
1112 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1113 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1114 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1115 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1116 gboolean video_used=linphone_call_params_video_enabled(current_params);
1117 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1118 video_used,video_requested,pol->automatically_accept);
1119 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1120 linphone_core_defer_call_update(lc,call);
1122 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1124 const char *dname=linphone_address_get_display_name(addr);
1125 if (dname==NULL) dname=linphone_address_get_username(addr);
1126 if (dname==NULL) dname=linphone_address_get_domain(addr);
1127 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1128 GTK_DIALOG_DESTROY_WITH_PARENT,
1129 GTK_MESSAGE_WARNING,
1131 _("%s proposed to start video. Do you accept ?"),dname);
1132 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1133 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1134 gtk_widget_show(dialog);
1139 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1141 case LinphoneCallOutgoingInit:
1142 linphone_gtk_create_in_call_view (call);
1144 case LinphoneCallOutgoingProgress:
1145 linphone_gtk_in_call_view_set_calling (call);
1147 case LinphoneCallStreamsRunning:
1148 linphone_gtk_in_call_view_set_in_call(call);
1150 case LinphoneCallUpdatedByRemote:
1151 linphone_gtk_call_updated_by_remote(call);
1153 case LinphoneCallError:
1154 linphone_gtk_in_call_view_terminate (call,msg);
1156 case LinphoneCallEnd:
1157 linphone_gtk_in_call_view_terminate(call,NULL);
1158 linphone_gtk_status_icon_set_blinking(FALSE);
1160 case LinphoneCallIncomingReceived:
1161 linphone_gtk_create_in_call_view(call);
1162 linphone_gtk_in_call_view_set_incoming(call);
1163 linphone_gtk_status_icon_set_blinking(TRUE);
1165 linphone_call_ref(call);
1166 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1169 case LinphoneCallResuming:
1170 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1171 linphone_gtk_in_call_view_set_in_call (call);
1173 case LinphoneCallPausing:
1174 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1175 update_tab_header(call,FALSE);
1176 case LinphoneCallPausedByRemote:
1177 linphone_gtk_in_call_view_set_paused(call);
1178 update_tab_header(call,TRUE);
1180 case LinphoneCallConnected:
1181 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1182 linphone_gtk_status_icon_set_blinking(FALSE);
1187 linphone_gtk_notify(call, msg);
1188 linphone_gtk_update_call_buttons (call);
1191 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1192 linphone_gtk_in_call_view_show_encryption(call);
1195 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1196 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1199 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1200 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1201 GtkTreeModel *model=gtk_combo_box_get_model(box);
1203 gboolean found=FALSE;
1204 const char *stock_id=NULL;
1206 if (gtk_tree_model_get_iter_first(model,&iter)){
1209 gtk_tree_model_get(model,&iter,2,&p,-1);
1214 }while(gtk_tree_model_iter_next(model,&iter));
1217 g_warning("Could not find proxy config in combo box of identities.");
1221 case LinphoneRegistrationOk:
1222 stock_id=GTK_STOCK_YES;
1224 case LinphoneRegistrationProgress:
1225 stock_id=GTK_STOCK_REFRESH;
1227 case LinphoneRegistrationCleared:
1230 case LinphoneRegistrationFailed:
1231 stock_id=GTK_STOCK_DIALOG_WARNING;
1236 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1239 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1240 LinphoneRegistrationState rs, const char *msg){
1242 case LinphoneRegistrationOk:
1244 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1245 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1246 linphone_gtk_exit_login_frame();
1253 update_registration_status(cfg,rs);
1256 void linphone_gtk_open_browser(const char *url){
1257 /*in gtk 2.16, gtk_show_uri does not work...*/
1259 #if GTK_CHECK_VERSION(2,18,3)
1260 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1263 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1264 g_spawn_command_line_async(cl,NULL);
1267 ShellExecute(0,"open",url,NULL,NULL,1);
1271 void linphone_gtk_link_to_website(GtkWidget *item){
1272 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1273 linphone_gtk_open_browser(home);
1276 #ifndef HAVE_GTK_OSX
1278 static GtkStatusIcon *icon=NULL;
1280 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1281 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1282 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1285 static GtkWidget *create_icon_menu(){
1286 GtkWidget *menu=gtk_menu_new();
1287 GtkWidget *menu_item;
1290 const gchar *homesite;
1292 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1293 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1294 tmp=g_strdup(homesite);
1295 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1296 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1298 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1299 gtk_widget_show(image);
1300 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1301 //g_object_unref(G_OBJECT(image));
1302 gtk_widget_show(menu_item);
1303 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1304 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1306 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1307 gtk_widget_show(menu_item);
1308 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1309 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1310 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,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)gtk_main_quit,NULL);
1314 gtk_widget_show(menu);
1318 static void handle_icon_click() {
1319 GtkWidget *mw=linphone_gtk_get_main_window();
1320 if (!gtk_window_is_active((GtkWindow*)mw)) {
1321 linphone_gtk_show_main_window();
1323 gtk_widget_hide(mw);
1327 static void linphone_gtk_init_status_icon(){
1328 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1329 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1330 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1331 GtkWidget *menu=create_icon_menu();
1333 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1334 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1335 #if GTK_CHECK_VERSION(2,20,0)
1336 gtk_status_icon_set_name(icon,title);
1338 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1339 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1340 gtk_status_icon_set_tooltip(icon,title);
1341 gtk_status_icon_set_visible(icon,TRUE);
1342 g_object_set_data(G_OBJECT(icon),"menu",menu);
1343 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1344 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1345 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1346 pbuf=create_pixbuf(call_icon_path);
1347 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1350 static gboolean do_icon_blink(GtkStatusIcon *gi){
1351 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1352 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1353 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1354 if (cur_icon==call_icon){
1355 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1357 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1364 void linphone_gtk_status_icon_set_blinking(gboolean val){
1366 static gint attention_id;
1367 GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1369 attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
1370 else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
1374 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1375 if (val && tout==0){
1376 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1377 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1378 }else if (!val && tout!=0){
1379 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1380 g_source_remove(tout);
1381 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1382 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1388 void linphone_gtk_options_activate(GtkWidget *item){
1389 #ifndef HAVE_GTK_OSX
1390 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1395 static void init_identity_combo(GtkComboBox *box){
1396 GtkListStore *store;
1397 GtkCellRenderer *r1,*r2;
1398 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1399 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1400 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1401 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1402 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1403 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1404 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1405 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1408 void linphone_gtk_load_identities(void){
1410 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1412 LinphoneProxyConfig *def=NULL;
1414 GtkListStore *store;
1417 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1418 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1419 /* model is empty, this is the first time we go here */
1420 init_identity_combo(box);
1421 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1423 gtk_list_store_clear(store);
1424 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1425 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1426 gtk_list_store_append(store,&iter);
1427 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1428 g_free(def_identity);
1429 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1431 elem=ms_list_next(elem),i++){
1432 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1433 gtk_list_store_append(store,&iter);
1434 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1435 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1441 gtk_combo_box_set_active(box,def_index);
1444 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1445 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1446 GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1448 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1449 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1450 if (linphone_core_in_call(linphone_gtk_get_core())){
1451 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1455 static void linphone_gtk_dtmf_released(GtkButton *button){
1456 linphone_core_stop_dtmf (linphone_gtk_get_core());
1460 static void linphone_gtk_connect_digits(void){
1461 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1462 GList *children=gtk_container_get_children(cont);
1464 for(elem=children;elem!=NULL;elem=elem->next){
1465 GtkButton *button=GTK_BUTTON(elem->data);
1466 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1467 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1471 static void linphone_gtk_check_menu_items(void){
1472 bool_t video_enabled=linphone_gtk_video_enabled();
1473 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1474 GtkWidget *selfview_item=linphone_gtk_get_widget(
1475 linphone_gtk_get_main_window(),"selfview_item");
1476 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1477 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1478 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1481 static gboolean linphone_gtk_can_manage_accounts(){
1482 LinphoneCore *lc=linphone_gtk_get_core();
1484 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1485 SipSetup *ss=(SipSetup*)elem->data;
1486 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1493 static void linphone_gtk_configure_main_window(){
1494 static gboolean config_loaded=FALSE;
1495 static const char *title;
1496 static const char *home;
1497 static const char *start_call_icon;
1498 static const char *add_call_icon;
1499 //static const char *stop_call_icon;
1500 static const char *search_icon;
1501 static gboolean update_check_menu;
1502 static gboolean buttons_have_borders;
1503 static gboolean show_abcd;
1504 GtkWidget *w=linphone_gtk_get_main_window();
1505 GHashTable *contacts_history;
1507 contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1508 g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1510 if (!config_loaded){
1511 title=linphone_gtk_get_ui_config("title","Linphone");
1512 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1513 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1514 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1515 //stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png");
1516 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1517 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1518 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1519 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1522 linphone_gtk_configure_window(w,"main_window");
1524 gtk_window_set_title(GTK_WINDOW(w),title);
1526 if (start_call_icon){
1527 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1528 create_pixmap (start_call_icon));
1529 if (!buttons_have_borders)
1530 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1533 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1534 create_pixmap (add_call_icon));
1535 if (!buttons_have_borders)
1536 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1539 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1541 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1542 g_object_unref(G_OBJECT(pbuf));
1547 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1549 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1553 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1555 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1556 g_object_unref(G_OBJECT(pbuf));
1561 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1563 GtkImage *img=GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon"));
1566 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU,&w,&h);
1567 scaled=gdk_pixbuf_scale_simple(pbuf,w,h,GDK_INTERP_BILINEAR);
1568 gtk_image_set_from_pixbuf(img,scaled);
1569 g_object_unref(G_OBJECT(scaled));
1570 g_object_unref(G_OBJECT(pbuf));
1573 if (linphone_gtk_can_manage_accounts()) {
1574 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1576 if (update_check_menu){
1577 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1580 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1581 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1582 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1583 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1584 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1588 void linphone_gtk_manage_login(void){
1589 LinphoneCore *lc=linphone_gtk_get_core();
1590 LinphoneProxyConfig *cfg=NULL;
1591 linphone_core_get_default_proxy(lc,&cfg);
1593 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1594 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1595 linphone_gtk_show_login_frame(cfg);
1601 gboolean linphone_gtk_close(GtkWidget *mw){
1602 /*shutdown calls if any*/
1603 LinphoneCore *lc=linphone_gtk_get_core();
1604 if (linphone_core_in_call(lc)){
1605 linphone_core_terminate_all_calls(lc);
1607 linphone_core_enable_video_preview(lc,FALSE);
1608 #ifdef __APPLE__ /*until with have a better option*/
1609 gtk_window_iconify(GTK_WINDOW(mw));
1611 gtk_widget_hide(mw);
1617 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1618 bool_t video_enabled=linphone_gtk_video_enabled();
1619 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1620 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1622 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1623 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1629 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1630 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1631 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1633 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1634 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1635 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1636 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1637 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1638 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1639 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1640 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1641 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1642 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1643 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1644 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1645 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1646 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1647 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1648 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1652 static void linphone_gtk_init_main_window(){
1653 GtkWidget *main_window;
1655 linphone_gtk_configure_main_window();
1656 linphone_gtk_manage_login();
1658 linphone_gtk_load_identities();
1659 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1660 linphone_gtk_show_friends();
1661 linphone_gtk_connect_digits();
1662 main_window=linphone_gtk_get_main_window();
1663 linphone_gtk_call_log_update(main_window);
1665 linphone_gtk_init_dtmf_table(main_window);
1666 linphone_gtk_update_call_buttons (NULL);
1667 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1668 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1669 g_signal_connect (G_OBJECT (main_window), "delete-event",
1670 G_CALLBACK (linphone_gtk_close), main_window);
1673 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1674 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1675 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1676 gtk_widget_hide(menubar);
1677 gtk_osxapplication_ready(theMacApp);
1679 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1681 linphone_gtk_check_menu_items();
1685 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1687 const char *lname="undef";
1689 #if defined(__linux) || defined(__APPLE__)
1690 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1709 g_error("Bad level !");
1711 #if defined(__linux) || defined(__APPLE__)
1713 msg=g_strdup_vprintf(fmt,cap);
1716 msg=g_strdup_vprintf(fmt,args);
1718 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1721 linphone_gtk_log_push(lev,fmt,args);
1725 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1726 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1727 linphone_gtk_get_main_window(), "uribar"));
1729 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1731 gtk_entry_set_text(uri_bar, refer_to);
1732 linphone_gtk_start_call(linphone_gtk_get_main_window());
1735 static void linphone_gtk_check_soundcards(){
1736 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1737 if (devices==NULL || devices[0]==NULL){
1738 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1739 _("No sound cards have been detected on this computer.\n"
1740 "You won't be able to send or receive audio calls."));
1744 static void linphone_gtk_quit(void){
1745 static gboolean quit_done=FALSE;
1748 linphone_gtk_unmonitor_usb();
1749 g_source_remove_by_user_data(linphone_gtk_get_core());
1751 linphone_gtk_close_assistant();
1753 linphone_gtk_destroy_main_window();
1754 linphone_gtk_uninit_instance();
1755 linphone_gtk_destroy_log_window();
1756 linphone_core_destroy(the_core);
1757 linphone_gtk_log_uninit();
1761 gdk_threads_leave();
1767 This is not the correct way to implement block termination.
1768 The good way would be to call gtk_main_quit(), and return TRUE.
1769 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1770 As a result the program cannot exit at all.
1771 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1773 static gboolean on_block_termination(void){
1775 linphone_gtk_quit();
1780 int main(int argc, char *argv[]){
1785 const char *factory_config_file;
1787 GtkSettings *settings;
1789 const char *app_name="Linphone";
1791 #if !GLIB_CHECK_VERSION(2, 31, 0)
1792 g_thread_init(NULL);
1796 progpath = strdup(argv[0]);
1798 config_file=linphone_gtk_get_config_file(NULL);
1802 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1803 if ((lang=getenv("LANG"))!=NULL){
1806 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1812 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1815 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1818 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1820 if (strncmp(lang,"zh",2)==0){
1821 workaround_gtk_entry_chinese_bug=TRUE;
1824 setenv("LANG",lang,1);
1826 setenv("LANGUAGE",lang,1);
1831 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1832 if (p==NULL) perror("bindtextdomain failed");
1833 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1834 textdomain (GETTEXT_PACKAGE);
1836 g_message("NLS disabled.\n");
1839 gtk_rc_add_default_file("./gtkrc");
1841 gdk_threads_enter();
1843 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1844 linphone_options,NULL,NULL)){
1845 gdk_threads_leave();
1849 settings=gtk_settings_get_default();
1850 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1851 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1852 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1853 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1855 if (workingdir!=NULL){
1856 if (chdir(workingdir)==-1){
1857 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1861 /* Now, look for the factory configuration file, we do it this late
1862 since we want to have had time to change directory and to parse
1863 the options, in case we needed to access the working directory */
1864 factory_config_file = linphone_gtk_get_factory_config_file();
1866 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1867 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1868 g_warning("This instance is going to exit now.");
1869 gdk_threads_leave();
1873 add_pixmap_directory("pixmaps");
1874 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1877 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1878 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1879 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1880 /*never block termination:*/
1881 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1884 the_ui=linphone_gtk_create_window("main");
1886 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1888 linphone_gtk_create_log_window();
1889 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1891 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1893 g_set_application_name(app_name);
1894 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1895 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1897 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1898 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1899 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1900 linphone_gtk_init_main_window();
1903 // Veryfing if at least one sip account is configured. If not, show wizard
1904 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1905 linphone_gtk_show_assistant();
1909 #ifndef HAVE_GTK_OSX
1910 linphone_gtk_init_status_icon();
1913 linphone_gtk_show_main_window();
1914 linphone_gtk_check_soundcards();
1916 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1917 linphone_gtk_check_for_new_version();
1918 linphone_gtk_monitor_usb();
1921 linphone_gtk_quit();
1922 #ifndef HAVE_GTK_OSX
1923 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1924 gtk_status_icon_set_visible(icon,FALSE);