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