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 //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
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 void linphone_gtk_destroy_main_window() {
261 linphone_gtk_destroy_window(the_ui);
265 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
266 static const char *icon_path=NULL;
267 static const char *hiddens=NULL;
268 static const char *shown=NULL;
269 static bool_t config_loaded=FALSE;
270 if (linphone_gtk_get_core()==NULL) return;
271 if (config_loaded==FALSE){
272 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
273 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
274 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
278 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
280 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
282 GdkPixbuf *pbuf=create_pixbuf(icon_path);
284 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
285 g_object_unref(G_OBJECT(pbuf));
290 static int get_ui_file(const char *name, char *path, int pathsize){
291 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
292 if (access(path,F_OK)!=0){
293 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
294 if (access(path,F_OK)!=0){
295 g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,
296 INSTALLED_XML_DIR,name);
303 void linphone_gtk_destroy_window(GtkWidget *widget) {
304 GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder");
305 gtk_widget_destroy(widget);
306 g_object_unref (G_OBJECT (builder));
309 GtkWidget *linphone_gtk_create_window(const char *window_name){
310 GError* error = NULL;
311 GtkBuilder* builder = gtk_builder_new ();
315 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
317 if (!gtk_builder_add_from_file (builder, path, &error)){
318 g_error("Couldn't load builder file: %s", error->message);
319 g_error_free (error);
322 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
324 g_error("Could not retrieve '%s' window from xml file",window_name);
327 g_object_set_data(G_OBJECT(w), "builder",builder);
328 gtk_builder_connect_signals(builder,w);
329 linphone_gtk_configure_window(w,window_name);
333 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
336 GtkBuilder* builder = gtk_builder_new ();
338 gchar *object_ids[2];
339 object_ids[0]=g_strdup(widget_name);
342 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
343 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
344 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
345 g_error_free (error);
346 g_free(object_ids[0]);
349 g_free(object_ids[0]);
350 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
352 g_error("Could not retrieve '%s' window from xml file",widget_name);
355 g_object_set_data(G_OBJECT(w),"builder",builder);
356 g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
357 gtk_builder_connect_signals(builder,w);
361 static void entry_unmapped(GtkWidget *entry){
362 g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
363 gtk_widget_unrealize(entry);
366 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
369 if (window==NULL) return NULL;
370 builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
372 g_error("Fail to retrieve builder from window !");
375 w=gtk_builder_get_object(builder,name);
377 g_error("No widget named %s found in xml interface.",name);
379 if (workaround_gtk_entry_chinese_bug){
380 if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
381 if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
382 g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
383 g_message("%s is a GtkEntry",name);
384 g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
388 return GTK_WIDGET(w);
392 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
394 GtkWidget *main_window=linphone_gtk_get_main_window();
396 gtk_widget_show(main_window);
397 if (type==GTK_MESSAGE_QUESTION)
399 /* draw a question box. link to dialog_click callback */
400 dialog = gtk_message_dialog_new (
401 GTK_WINDOW(main_window),
402 GTK_DIALOG_DESTROY_WITH_PARENT,
403 GTK_MESSAGE_QUESTION,
406 (const gchar*)message);
407 /* connect to some callback : REVISIT */
409 g_signal_connect_swapped (G_OBJECT (dialog), "response",
410 G_CALLBACK (dialog_click),
413 /* actually show the box */
414 gtk_widget_show(dialog);
418 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
419 GTK_DIALOG_DESTROY_WITH_PARENT,
423 (const gchar*)message);
424 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
425 g_signal_connect_swapped (G_OBJECT (dialog), "response",
426 G_CALLBACK (gtk_widget_destroy),
428 gtk_widget_show(dialog);
432 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
433 if (id==GTK_RESPONSE_CANCEL){
434 gtk_widget_destroy(GTK_WIDGET(dialog));
438 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
439 g_message("About url clicked");
440 linphone_gtk_open_browser(url);
443 void linphone_gtk_show_about(){
444 struct stat filestat;
445 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
448 GdkPixbuf *logo=create_pixbuf(
449 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
450 static const char *defcfg="defcfg";
452 about=linphone_gtk_create_window("about");
453 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
454 memset(&filestat,0,sizeof(filestat));
455 if (stat(license_file,&filestat)!=0){
456 license_file="COPYING";
457 stat(license_file,&filestat);
459 if (filestat.st_size>0){
460 char *license=g_malloc(filestat.st_size+1);
461 FILE *f=fopen(license_file,"r");
462 if (f && fread(license,filestat.st_size,1,f)==1){
463 license[filestat.st_size]='\0';
464 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
468 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
469 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
470 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
471 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
472 tmp=linphone_gtk_get_ui_config("artists",defcfg);
477 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
479 tmp=linphone_gtk_get_ui_config("translators",defcfg);
481 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
482 tmp=linphone_gtk_get_ui_config("comments",defcfg);
484 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
485 gtk_widget_show(about);
488 static void set_video_window_decorations(GdkWindow *w){
489 const char *title=linphone_gtk_get_ui_config("title","Linphone");
490 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
491 char video_title[256];
492 GdkPixbuf *pbuf=create_pixbuf(icon_path);
494 if (!linphone_core_in_call(linphone_gtk_get_core())){
495 snprintf(video_title,sizeof(video_title),"%s video",title);
496 /* When not in call, treat the video as a normal window */
497 gdk_window_set_keep_above(w, FALSE);
499 LinphoneAddress *uri =
500 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
503 linphone_address_clean(uri);
504 if (linphone_address_get_display_name(uri)!=NULL){
505 display_name=ms_strdup(linphone_address_get_display_name(uri));
507 display_name=linphone_address_as_string(uri);
509 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
510 linphone_address_destroy(uri);
511 ms_free(display_name);
513 /* During calls, bring up the video window, arrange so that
514 it is above all the other windows */
515 gdk_window_deiconify(w);
516 gdk_window_set_keep_above(w,TRUE);
517 /* Maybe we should have the following, but then we want to
518 have a timer that turns it off after a little while. */
519 /* gdk_window_set_urgency_hint(w,TRUE); */
521 gdk_window_set_title(w,video_title);
522 /* Refrain the video window to be closed at all times. */
523 gdk_window_set_functions(w,
524 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
525 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
528 l=g_list_append(l,pbuf);
529 gdk_window_set_icon_list(w,l);
531 g_object_unref(G_OBJECT(pbuf));
535 static gboolean video_needs_update=FALSE;
537 static void update_video_title(){
538 video_needs_update=TRUE;
541 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
542 static gboolean first_time=TRUE;
544 static unsigned long previd=0;
545 static unsigned long preview_previd=0;
546 static gboolean in_iterate=FALSE;
549 if (in_iterate) return TRUE;
551 linphone_core_iterate(lc);
553 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
554 linphone_gtk_show_directory_search();
558 id=linphone_core_get_native_video_window_id(lc);
559 if (id!=previd || video_needs_update){
563 ms_message("Updating window decorations");
565 w=gdk_window_foreign_new(id);
567 w=gdk_window_foreign_new((HANDLE)id);
570 set_video_window_decorations(w);
571 g_object_unref(G_OBJECT(w));
573 else ms_error("gdk_window_foreign_new() failed");
574 if (video_needs_update) video_needs_update=FALSE;
577 id=linphone_core_get_native_preview_window_id (lc);
578 if (id!=preview_previd ){
582 ms_message("Updating window decorations for preview");
584 w=gdk_window_foreign_new(id);
586 w=gdk_window_foreign_new((HANDLE)id);
589 set_video_window_decorations(w);
590 g_object_unref(G_OBJECT(w));
592 else ms_error("gdk_window_foreign_new() failed");
593 if (video_needs_update) video_needs_update=FALSE;
596 if (addr_to_call!=NULL){
597 /*make sure we are not showing the login screen*/
598 GtkWidget *mw=linphone_gtk_get_main_window();
599 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
600 if (!GTK_WIDGET_VISIBLE(login_frame)){
601 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
602 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
604 linphone_gtk_start_call(uri_bar);
611 static void load_uri_history(){
612 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
615 GtkEntryCompletion *gep=gtk_entry_completion_new();
616 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
619 snprintf(key,sizeof(key),"uri%i",i);
620 uri=linphone_gtk_get_ui_config(key,NULL);
623 gtk_list_store_append(model,&iter);
624 gtk_list_store_set(model,&iter,0,uri,-1);
625 if (i==0) gtk_entry_set_text(uribar,uri);
629 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
630 gtk_entry_completion_set_text_column(gep,0);
631 gtk_entry_set_completion(uribar,gep);
634 static void save_uri_history(){
635 LinphoneCore *lc=linphone_gtk_get_core();
636 LpConfig *cfg=linphone_core_get_config(lc);
637 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
642 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
644 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
646 gtk_tree_model_get(model,&iter,0,&uri,-1);
648 snprintf(key,sizeof(key),"uri%i",i);
649 lp_config_set_string(cfg,"GtkUi",key,uri);
654 }while(gtk_tree_model_iter_next(model,&iter));
658 static void completion_add_text(GtkEntry *entry, const char *text){
660 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
662 if (gtk_tree_model_get_iter_first(model,&iter)){
665 gtk_tree_model_get(model,&iter,0,&uri,-1);
667 if (strcmp(uri,text)==0) {
669 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
675 }while (gtk_tree_model_iter_next(model,&iter));
677 /* and prepend it on top of the list */
678 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
679 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
683 bool_t linphone_gtk_video_enabled(void){
684 const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
685 return vpol->automatically_accept && vpol->automatically_initiate;
688 void linphone_gtk_show_main_window(){
689 GtkWidget *w=linphone_gtk_get_main_window();
690 LinphoneCore *lc=linphone_gtk_get_core();
691 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
692 VIDEOSELFVIEW_DEFAULT));
694 gtk_window_present(GTK_WINDOW(w));
697 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
698 GtkWidget *mw=linphone_gtk_get_main_window();
699 if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
700 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
702 if (linphone_gtk_use_in_call_view() && call)
703 linphone_gtk_in_call_view_terminate(call,error);
704 update_video_title();
707 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
708 LinphoneCore *lc=linphone_gtk_get_core();
709 GtkWidget *mw=linphone_gtk_get_main_window();
710 const MSList *calls=linphone_core_get_calls(lc);
712 bool_t start_active=TRUE;
713 //bool_t stop_active=FALSE;
714 bool_t add_call=FALSE;
715 int call_list_size=ms_list_size(calls);
725 button=linphone_gtk_get_widget(mw,"start_call");
726 gtk_widget_set_sensitive(button,start_active);
727 gtk_widget_set_visible(button,!add_call);
729 button=linphone_gtk_get_widget(mw,"add_call");
730 if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
731 gtk_widget_set_sensitive(button,FALSE);
733 gtk_widget_set_sensitive(button,start_active);
735 gtk_widget_set_visible(button,add_call);
737 //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
738 GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
739 if(conf_frame==NULL){
740 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
741 linphone_gtk_enable_conference_button(lc,call_list_size>1);
743 linphone_gtk_enable_transfer_button(lc,FALSE);
744 linphone_gtk_enable_conference_button(lc,FALSE);
746 update_video_title();
748 linphone_gtk_update_video_button(call);
752 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
753 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
754 if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
755 completion_add_text(GTK_ENTRY(uri_bar),entered);
757 linphone_gtk_call_terminated(NULL,NULL);
762 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
763 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
764 linphone_core_accept_call (linphone_gtk_get_core(),call);
765 linphone_call_unref(call);
770 void linphone_gtk_start_call(GtkWidget *w){
771 LinphoneCore *lc=linphone_gtk_get_core();
773 /*change into in-call mode, then do the work later as it might block a bit */
774 GtkWidget *mw=gtk_widget_get_toplevel(w);
775 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
777 call=linphone_gtk_get_currently_displayed_call(NULL);
778 if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
779 linphone_core_accept_call(lc,call);
781 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
782 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
783 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
784 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
789 void linphone_gtk_uri_bar_activate(GtkWidget *w){
790 linphone_gtk_start_call(w);
793 void linphone_gtk_terminate_call(GtkWidget *button){
795 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
797 linphone_core_terminate_call(linphone_gtk_get_core(),call);
799 linphone_core_terminate_conference(linphone_gtk_get_core());
803 void linphone_gtk_decline_clicked(GtkWidget *button){
804 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
806 linphone_core_terminate_call(linphone_gtk_get_core(),call);
809 void linphone_gtk_answer_clicked(GtkWidget *button){
810 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
812 linphone_core_accept_call(linphone_gtk_get_core(),call);
813 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
817 void _linphone_gtk_enable_video(gboolean val){
818 LinphoneVideoPolicy policy={0};
819 policy.automatically_initiate=policy.automatically_accept=val;
820 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
821 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
824 linphone_core_enable_video_preview(linphone_gtk_get_core(),
825 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
827 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
831 void linphone_gtk_enable_video(GtkWidget *w){
832 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
833 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
834 _linphone_gtk_enable_video(val);
837 void linphone_gtk_enable_self_view(GtkWidget *w){
838 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
839 LinphoneCore *lc=linphone_gtk_get_core();
840 linphone_core_enable_video_preview(lc,val);
841 linphone_core_enable_self_view(lc,val);
842 linphone_gtk_set_ui_config_int("videoselfview",val);
845 void linphone_gtk_used_identity_changed(GtkWidget *w){
846 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
847 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
848 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
849 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
850 linphone_gtk_show_directory_search();
852 if (sel) g_free(sel);
855 void on_proxy_refresh_button_clicked(GtkWidget *w){
856 LinphoneCore *lc=linphone_gtk_get_core();
857 MSList const *item=linphone_core_get_proxy_config_list(lc);
858 while (item != NULL) {
859 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
860 linphone_proxy_config_edit(lpc);
861 linphone_proxy_config_done(lpc);
866 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
867 linphone_gtk_show_friends();
870 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
872 case GTK_RESPONSE_YES:
873 linphone_gtk_show_contact(lf);
876 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
878 gtk_widget_destroy(dialog);
881 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
884 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
885 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
889 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);
890 dialog = gtk_message_dialog_new (
891 GTK_WINDOW(linphone_gtk_get_main_window()),
892 GTK_DIALOG_DESTROY_WITH_PARENT,
893 GTK_MESSAGE_QUESTION,
898 g_signal_connect(G_OBJECT (dialog), "response",
899 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
900 /* actually show the box */
901 gtk_widget_show(dialog);
904 typedef struct _AuthTimeout{
908 static void auth_timeout_clean(AuthTimeout *tout){
912 static gboolean auth_timeout_destroy(AuthTimeout *tout){
914 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
915 gtk_widget_destroy(tout->w);
921 static AuthTimeout * auth_timeout_new(GtkWidget *w){
922 AuthTimeout *tout=g_new(AuthTimeout,1);
924 /*so that the timeout no more references the widget when it is destroyed:*/
925 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
926 /*so that the widget is automatically destroyed after some time */
927 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
931 void linphone_gtk_password_cancel(GtkWidget *w){
932 LinphoneAuthInfo *info;
933 GtkWidget *window=gtk_widget_get_toplevel(w);
934 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
935 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
936 gtk_widget_destroy(window);
939 void linphone_gtk_password_ok(GtkWidget *w){
941 GtkWidget *window=gtk_widget_get_toplevel(w);
942 LinphoneAuthInfo *info;
943 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
944 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
945 entry=linphone_gtk_get_widget(window,"password_entry");
946 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
947 linphone_auth_info_set_userid(info,
948 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
949 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
950 gtk_widget_destroy(window);
953 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
954 GtkWidget *w=linphone_gtk_create_window("password");
955 GtkWidget *label=linphone_gtk_get_widget(w,"message");
956 LinphoneAuthInfo *info;
958 GtkWidget *mw=linphone_gtk_get_main_window();
960 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
961 /*don't prompt for authentication when login frame is visible*/
962 linphone_core_abort_authentication(lc,NULL);
966 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
968 gtk_label_set_markup(GTK_LABEL(label),msg);
970 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
971 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
972 g_object_set_data(G_OBJECT(w),"auth_info",info);
973 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
978 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
979 GtkWidget *w=linphone_gtk_get_main_window();
980 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
982 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
983 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
987 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
988 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
991 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
992 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
995 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
997 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
998 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
1001 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1002 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1003 if (w) linphone_gtk_call_log_update(w);
1004 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1008 static bool_t notify_actions_supported() {
1009 bool_t accepts_actions = FALSE;
1010 GList *capabilities = notify_get_server_caps();
1012 if(capabilities != NULL) {
1013 for(c = capabilities; c != NULL; c = c->next) {
1014 if(strcmp((char*)c->data, "actions") == 0 ) {
1015 accepts_actions = TRUE;
1019 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1020 g_list_free(capabilities);
1022 return accepts_actions;
1025 static NotifyNotification* build_notification(const char *title, const char *body){
1026 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1033 static void show_notification(NotifyNotification* n){
1034 if (n && !notify_notification_show(n,NULL))
1035 ms_error("Failed to send notification.");
1038 static void make_notification(const char *title, const char *body){
1039 show_notification(build_notification(title,body));
1044 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1046 if (!notify_is_initted())
1047 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1052 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1058 ms_error("Failed to send notification.");
1060 linphone_gtk_show_main_window();
1062 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1065 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1066 NotifyNotification *n;
1067 switch(linphone_call_get_state(call)){
1068 case LinphoneCallError:
1069 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
1071 case LinphoneCallEnd:
1072 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1074 case LinphoneCallIncomingReceived:
1075 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1076 if (notify_actions_supported()) {
1077 notify_notification_add_action (n,"answer", _("Answer"),
1078 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1079 notify_notification_add_action (n,"decline",_("Decline"),
1080 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1082 show_notification(n);
1084 case LinphoneCallPausedByRemote:
1085 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<span size=\"large\">by %s</span>"),remote));
1090 if (body) g_free(body);
1091 if (remote) g_free(remote);
1096 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1097 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1098 LinphoneCore *lc=linphone_call_get_core(call);
1099 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1100 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1101 linphone_core_accept_call_update(lc,call,params);
1102 linphone_call_params_destroy(params);
1104 linphone_call_unref(call);
1105 g_source_remove_by_user_data(dialog);
1106 gtk_widget_destroy(dialog);
1109 static void on_call_updated_timeout(GtkWidget *dialog){
1110 gtk_widget_destroy(dialog);
1113 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1114 LinphoneCore *lc=linphone_call_get_core(call);
1115 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1116 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1117 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1118 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1119 gboolean video_used=linphone_call_params_video_enabled(current_params);
1120 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1121 video_used,video_requested,pol->automatically_accept);
1122 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1123 linphone_core_defer_call_update(lc,call);
1125 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1127 const char *dname=linphone_address_get_display_name(addr);
1128 if (dname==NULL) dname=linphone_address_get_username(addr);
1129 if (dname==NULL) dname=linphone_address_get_domain(addr);
1130 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1131 GTK_DIALOG_DESTROY_WITH_PARENT,
1132 GTK_MESSAGE_WARNING,
1134 _("%s proposed to start video. Do you accept ?"),dname);
1135 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1136 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1137 gtk_widget_show(dialog);
1142 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1144 case LinphoneCallOutgoingInit:
1145 linphone_gtk_create_in_call_view (call);
1147 case LinphoneCallOutgoingProgress:
1148 linphone_gtk_in_call_view_set_calling (call);
1150 case LinphoneCallStreamsRunning:
1151 linphone_gtk_in_call_view_set_in_call(call);
1153 case LinphoneCallUpdatedByRemote:
1154 linphone_gtk_call_updated_by_remote(call);
1156 case LinphoneCallError:
1157 linphone_gtk_in_call_view_terminate (call,msg);
1159 case LinphoneCallEnd:
1160 linphone_gtk_in_call_view_terminate(call,NULL);
1161 linphone_gtk_status_icon_set_blinking(FALSE);
1163 case LinphoneCallIncomingReceived:
1164 linphone_gtk_create_in_call_view(call);
1165 linphone_gtk_in_call_view_set_incoming(call);
1166 linphone_gtk_status_icon_set_blinking(TRUE);
1168 linphone_call_ref(call);
1169 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1172 case LinphoneCallResuming:
1173 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1174 linphone_gtk_in_call_view_set_in_call (call);
1176 case LinphoneCallPausing:
1177 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1178 update_tab_header(call,FALSE);
1179 case LinphoneCallPausedByRemote:
1180 linphone_gtk_in_call_view_set_paused(call);
1181 update_tab_header(call,TRUE);
1183 case LinphoneCallConnected:
1184 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1185 linphone_gtk_status_icon_set_blinking(FALSE);
1190 linphone_gtk_notify(call, msg);
1191 linphone_gtk_update_call_buttons (call);
1194 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1195 linphone_gtk_in_call_view_show_encryption(call);
1198 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1199 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1202 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1203 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1204 GtkTreeModel *model=gtk_combo_box_get_model(box);
1206 gboolean found=FALSE;
1207 const char *stock_id=NULL;
1209 if (gtk_tree_model_get_iter_first(model,&iter)){
1212 gtk_tree_model_get(model,&iter,2,&p,-1);
1217 }while(gtk_tree_model_iter_next(model,&iter));
1220 g_warning("Could not find proxy config in combo box of identities.");
1224 case LinphoneRegistrationOk:
1225 stock_id=GTK_STOCK_YES;
1227 case LinphoneRegistrationProgress:
1228 stock_id=GTK_STOCK_REFRESH;
1230 case LinphoneRegistrationCleared:
1233 case LinphoneRegistrationFailed:
1234 stock_id=GTK_STOCK_DIALOG_WARNING;
1239 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1242 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1243 LinphoneRegistrationState rs, const char *msg){
1245 case LinphoneRegistrationOk:
1247 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1248 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1249 linphone_gtk_exit_login_frame();
1256 update_registration_status(cfg,rs);
1259 void linphone_gtk_open_browser(const char *url){
1260 /*in gtk 2.16, gtk_show_uri does not work...*/
1262 #if GTK_CHECK_VERSION(2,18,3)
1263 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1266 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1267 g_spawn_command_line_async(cl,NULL);
1270 ShellExecute(0,"open",url,NULL,NULL,1);
1274 void linphone_gtk_link_to_website(GtkWidget *item){
1275 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1276 linphone_gtk_open_browser(home);
1279 #ifndef HAVE_GTK_OSX
1281 static GtkStatusIcon *icon=NULL;
1283 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1284 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1285 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1288 static GtkWidget *create_icon_menu(){
1289 GtkWidget *menu=gtk_menu_new();
1290 GtkWidget *menu_item;
1293 const gchar *homesite;
1295 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1296 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1297 tmp=g_strdup(homesite);
1298 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1299 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1301 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1302 gtk_widget_show(image);
1303 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1304 //g_object_unref(G_OBJECT(image));
1305 gtk_widget_show(menu_item);
1306 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1307 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1309 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1310 gtk_widget_show(menu_item);
1311 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1312 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1313 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1314 gtk_widget_show(menu_item);
1315 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1316 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1317 gtk_widget_show(menu);
1321 static void handle_icon_click() {
1322 GtkWidget *mw=linphone_gtk_get_main_window();
1323 if (!gtk_window_is_active((GtkWindow*)mw)) {
1324 linphone_gtk_show_main_window();
1326 gtk_widget_hide(mw);
1330 static void linphone_gtk_init_status_icon(){
1331 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1332 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1333 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1334 GtkWidget *menu=create_icon_menu();
1336 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1337 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1338 #if GTK_CHECK_VERSION(2,20,0)
1339 gtk_status_icon_set_name(icon,title);
1341 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1342 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1343 gtk_status_icon_set_tooltip(icon,title);
1344 gtk_status_icon_set_visible(icon,TRUE);
1345 g_object_set_data(G_OBJECT(icon),"menu",menu);
1346 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1347 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1348 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1349 pbuf=create_pixbuf(call_icon_path);
1350 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1353 static gboolean do_icon_blink(GtkStatusIcon *gi){
1354 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1355 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1356 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1357 if (cur_icon==call_icon){
1358 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1360 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1367 void linphone_gtk_status_icon_set_blinking(gboolean val){
1369 static gint attention_id;
1370 GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1372 attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
1373 else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
1377 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1378 if (val && tout==0){
1379 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1380 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1381 }else if (!val && tout!=0){
1382 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1383 g_source_remove(tout);
1384 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1385 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1391 void linphone_gtk_options_activate(GtkWidget *item){
1392 #ifndef HAVE_GTK_OSX
1393 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1398 static void init_identity_combo(GtkComboBox *box){
1399 GtkListStore *store;
1400 GtkCellRenderer *r1,*r2;
1401 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1402 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1403 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1404 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1405 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1406 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1407 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1408 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1411 void linphone_gtk_load_identities(void){
1413 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1415 LinphoneProxyConfig *def=NULL;
1417 GtkListStore *store;
1420 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1421 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1422 /* model is empty, this is the first time we go here */
1423 init_identity_combo(box);
1424 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1426 gtk_list_store_clear(store);
1427 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1428 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1429 gtk_list_store_append(store,&iter);
1430 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1431 g_free(def_identity);
1432 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1434 elem=ms_list_next(elem),i++){
1435 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1436 gtk_list_store_append(store,&iter);
1437 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1438 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1444 gtk_combo_box_set_active(box,def_index);
1447 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1448 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1449 GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
1451 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1452 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1453 if (linphone_core_in_call(linphone_gtk_get_core())){
1454 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1458 static void linphone_gtk_dtmf_released(GtkButton *button){
1459 linphone_core_stop_dtmf (linphone_gtk_get_core());
1463 static void linphone_gtk_connect_digits(GtkWidget *w){
1464 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
1465 GList *children=gtk_container_get_children(cont);
1467 for(elem=children;elem!=NULL;elem=elem->next){
1468 GtkButton *button=GTK_BUTTON(elem->data);
1469 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1470 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1474 static void linphone_gtk_check_menu_items(void){
1475 bool_t video_enabled=linphone_gtk_video_enabled();
1476 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1477 GtkWidget *selfview_item=linphone_gtk_get_widget(
1478 linphone_gtk_get_main_window(),"selfview_item");
1479 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1480 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1481 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1484 static gboolean linphone_gtk_can_manage_accounts(){
1485 LinphoneCore *lc=linphone_gtk_get_core();
1487 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1488 SipSetup *ss=(SipSetup*)elem->data;
1489 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1496 static void linphone_gtk_configure_main_window(){
1497 static gboolean config_loaded=FALSE;
1498 static const char *title;
1499 static const char *home;
1500 static const char *start_call_icon;
1501 static const char *add_call_icon;
1502 static const char *search_icon;
1503 static gboolean update_check_menu;
1504 static gboolean buttons_have_borders;
1505 //static gboolean show_abcd;
1506 GtkWidget *w=linphone_gtk_get_main_window();
1507 GHashTable *contacts_history;
1509 contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1510 g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1512 if (!config_loaded){
1513 title=linphone_gtk_get_ui_config("title","Linphone");
1514 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1515 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1516 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1517 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1518 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1519 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1520 //show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1523 linphone_gtk_configure_window(w,"main_window");
1525 gtk_window_set_title(GTK_WINDOW(w),title);
1527 if (start_call_icon){
1528 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1529 create_pixmap (start_call_icon));
1530 if (!buttons_have_borders)
1531 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1534 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1535 create_pixmap (add_call_icon));
1536 if (!buttons_have_borders)
1537 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1540 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1542 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1543 g_object_unref(G_OBJECT(pbuf));
1548 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1550 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1554 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1556 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1557 g_object_unref(G_OBJECT(pbuf));
1562 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1564 GtkImage *img=GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon"));
1567 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU,&w,&h);
1568 scaled=gdk_pixbuf_scale_simple(pbuf,w,h,GDK_INTERP_BILINEAR);
1569 gtk_image_set_from_pixbuf(img,scaled);
1570 g_object_unref(G_OBJECT(scaled));
1571 g_object_unref(G_OBJECT(pbuf));
1574 if (linphone_gtk_can_manage_accounts()) {
1575 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1577 if (update_check_menu){
1578 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1581 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1582 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1583 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1584 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1585 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1589 void linphone_gtk_manage_login(void){
1590 LinphoneCore *lc=linphone_gtk_get_core();
1591 LinphoneProxyConfig *cfg=NULL;
1592 linphone_core_get_default_proxy(lc,&cfg);
1594 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1595 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1596 linphone_gtk_show_login_frame(cfg);
1602 gboolean linphone_gtk_close(GtkWidget *mw){
1603 /*shutdown calls if any*/
1604 LinphoneCore *lc=linphone_gtk_get_core();
1605 if (linphone_core_in_call(lc)){
1606 linphone_core_terminate_all_calls(lc);
1608 linphone_core_enable_video_preview(lc,FALSE);
1609 #ifdef __APPLE__ /*until with have a better option*/
1610 gtk_window_iconify(GTK_WINDOW(mw));
1612 gtk_widget_hide(mw);
1618 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1619 bool_t video_enabled=linphone_gtk_video_enabled();
1620 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1621 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1623 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1624 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1630 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1631 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1632 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1634 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1635 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1636 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1637 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1638 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1639 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1640 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1641 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1642 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1643 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1644 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1645 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1646 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1647 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1648 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1649 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1653 void linphone_gtk_create_keypad(LinphoneCall *call){
1654 GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
1655 GtkWidget *keypad=linphone_gtk_create_window("keypad");
1656 linphone_gtk_connect_digits(keypad);
1657 linphone_gtk_init_dtmf_table(keypad);
1658 g_object_set_data(G_OBJECT(w),"keypad",(gpointer)keypad);
1659 gtk_widget_show(keypad);
1662 static void linphone_gtk_init_main_window(){
1663 GtkWidget *main_window;
1665 linphone_gtk_configure_main_window();
1666 linphone_gtk_manage_login();
1668 linphone_gtk_load_identities();
1669 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1670 linphone_gtk_show_friends();
1671 main_window=linphone_gtk_get_main_window();
1672 linphone_gtk_call_log_update(main_window);
1674 //linphone_gtk_init_dtmf_table(main_window);
1675 linphone_gtk_update_call_buttons (NULL);
1676 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1677 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1678 g_signal_connect (G_OBJECT (main_window), "delete-event",
1679 G_CALLBACK (linphone_gtk_close), main_window);
1682 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1683 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1684 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1685 gtk_widget_hide(menubar);
1686 gtk_osxapplication_ready(theMacApp);
1688 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1690 linphone_gtk_check_menu_items();
1694 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1696 const char *lname="undef";
1698 #if defined(__linux) || defined(__APPLE__)
1699 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1718 g_error("Bad level !");
1720 #if defined(__linux) || defined(__APPLE__)
1722 msg=g_strdup_vprintf(fmt,cap);
1725 msg=g_strdup_vprintf(fmt,args);
1727 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1730 linphone_gtk_log_push(lev,fmt,args);
1734 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1735 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1736 linphone_gtk_get_main_window(), "uribar"));
1738 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1740 gtk_entry_set_text(uri_bar, refer_to);
1741 linphone_gtk_start_call(linphone_gtk_get_main_window());
1744 static void linphone_gtk_check_soundcards(){
1745 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1746 if (devices==NULL || devices[0]==NULL){
1747 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1748 _("No sound cards have been detected on this computer.\n"
1749 "You won't be able to send or receive audio calls."));
1753 static void linphone_gtk_quit(void){
1754 static gboolean quit_done=FALSE;
1757 linphone_gtk_unmonitor_usb();
1758 g_source_remove_by_user_data(linphone_gtk_get_core());
1760 linphone_gtk_close_assistant();
1762 linphone_gtk_uninit_instance();
1763 linphone_gtk_destroy_log_window();
1764 linphone_core_destroy(the_core);
1765 linphone_gtk_log_uninit();
1769 gdk_threads_leave();
1775 This is not the correct way to implement block termination.
1776 The good way would be to call gtk_main_quit(), and return TRUE.
1777 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1778 As a result the program cannot exit at all.
1779 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1781 static gboolean on_block_termination(void){
1783 linphone_gtk_quit();
1788 int main(int argc, char *argv[]){
1793 const char *factory_config_file;
1795 GtkSettings *settings;
1797 const char *app_name="Linphone";
1799 #if !GLIB_CHECK_VERSION(2, 31, 0)
1800 g_thread_init(NULL);
1804 progpath = strdup(argv[0]);
1806 config_file=linphone_gtk_get_config_file(NULL);
1810 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1811 if ((lang=getenv("LANG"))!=NULL){
1814 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1820 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1823 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1826 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1828 if (strncmp(lang,"zh",2)==0){
1829 workaround_gtk_entry_chinese_bug=TRUE;
1832 setenv("LANG",lang,1);
1834 setenv("LANGUAGE",lang,1);
1839 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1840 if (p==NULL) perror("bindtextdomain failed");
1841 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1842 textdomain (GETTEXT_PACKAGE);
1844 g_message("NLS disabled.\n");
1847 gtk_rc_add_default_file("./gtkrc");
1849 gdk_threads_enter();
1851 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1852 linphone_options,NULL,NULL)){
1853 gdk_threads_leave();
1857 settings=gtk_settings_get_default();
1858 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1859 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1860 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1861 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1863 if (workingdir!=NULL){
1864 if (chdir(workingdir)==-1){
1865 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1869 /* Now, look for the factory configuration file, we do it this late
1870 since we want to have had time to change directory and to parse
1871 the options, in case we needed to access the working directory */
1872 factory_config_file = linphone_gtk_get_factory_config_file();
1874 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1875 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1876 g_warning("This instance is going to exit now.");
1877 gdk_threads_leave();
1881 add_pixmap_directory("pixmaps");
1882 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1885 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1886 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1887 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1888 /*never block termination:*/
1889 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1892 the_ui=linphone_gtk_create_window("main");
1894 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1896 linphone_gtk_create_log_window();
1897 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1899 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1901 g_set_application_name(app_name);
1902 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1903 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1905 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1906 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1907 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1908 linphone_gtk_init_main_window();
1911 // Veryfing if at least one sip account is configured. If not, show wizard
1912 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1913 linphone_gtk_show_assistant();
1917 #ifndef HAVE_GTK_OSX
1918 linphone_gtk_init_status_icon();
1921 linphone_gtk_show_main_window();
1922 linphone_gtk_check_soundcards();
1924 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1925 linphone_gtk_check_for_new_version();
1926 linphone_gtk_monitor_usb();
1929 linphone_gtk_quit();
1930 #ifndef HAVE_GTK_OSX
1931 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1932 gtk_status_icon_set_visible(icon,FALSE);