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 gchar *linphone_gtk_get_call_record_path(LinphoneAddress *address){
754 const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
755 const char *id=linphone_address_get_username(address);
756 char filename[256]={0};
757 if (id==NULL) id=linphone_address_get_domain(address);
758 snprintf(filename,sizeof(filename)-1,"%s-%lu-%s-record.wav",
759 linphone_gtk_get_ui_config("title","Linphone"),
760 (unsigned long)time(NULL),id);
761 return g_build_filename(dir,filename,NULL);
764 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
765 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
766 LinphoneCore *lc=linphone_gtk_get_core();
767 LinphoneAddress *addr=linphone_core_interpret_url(lc,entered);
770 LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
771 gchar *record_file=linphone_gtk_get_call_record_path(addr);
772 linphone_call_params_set_record_file(params,record_file);
773 linphone_core_invite_address_with_params(lc,addr,params);
774 completion_add_text(GTK_ENTRY(uri_bar),entered);
775 linphone_address_destroy(addr);
776 linphone_call_params_destroy(params);
779 linphone_gtk_call_terminated(NULL,NULL);
784 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
785 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
786 linphone_core_accept_call (linphone_gtk_get_core(),call);
787 linphone_call_unref(call);
792 void linphone_gtk_start_call(GtkWidget *w){
793 LinphoneCore *lc=linphone_gtk_get_core();
795 /*change into in-call mode, then do the work later as it might block a bit */
796 GtkWidget *mw=gtk_widget_get_toplevel(w);
797 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
799 call=linphone_gtk_get_currently_displayed_call(NULL);
800 if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
801 linphone_core_accept_call(lc,call);
803 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
804 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
805 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
806 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
811 void linphone_gtk_uri_bar_activate(GtkWidget *w){
812 linphone_gtk_start_call(w);
815 void linphone_gtk_terminate_call(GtkWidget *button){
817 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
819 linphone_core_terminate_call(linphone_gtk_get_core(),call);
821 linphone_core_terminate_conference(linphone_gtk_get_core());
825 void linphone_gtk_decline_clicked(GtkWidget *button){
826 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
828 linphone_core_terminate_call(linphone_gtk_get_core(),call);
831 void linphone_gtk_answer_clicked(GtkWidget *button){
832 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
834 linphone_core_accept_call(linphone_gtk_get_core(),call);
835 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
839 void _linphone_gtk_enable_video(gboolean val){
840 LinphoneVideoPolicy policy={0};
841 policy.automatically_initiate=policy.automatically_accept=val;
842 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
843 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
846 linphone_core_enable_video_preview(linphone_gtk_get_core(),
847 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
849 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
853 void linphone_gtk_enable_video(GtkWidget *w){
854 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
855 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
856 _linphone_gtk_enable_video(val);
859 void linphone_gtk_enable_self_view(GtkWidget *w){
860 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
861 LinphoneCore *lc=linphone_gtk_get_core();
862 linphone_core_enable_video_preview(lc,val);
863 linphone_core_enable_self_view(lc,val);
864 linphone_gtk_set_ui_config_int("videoselfview",val);
867 void linphone_gtk_used_identity_changed(GtkWidget *w){
868 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
869 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
870 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
871 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
872 linphone_gtk_show_directory_search();
874 if (sel) g_free(sel);
877 void on_proxy_refresh_button_clicked(GtkWidget *w){
878 LinphoneCore *lc=linphone_gtk_get_core();
879 MSList const *item=linphone_core_get_proxy_config_list(lc);
880 while (item != NULL) {
881 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
882 linphone_proxy_config_edit(lpc);
883 linphone_proxy_config_done(lpc);
888 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
889 linphone_gtk_show_friends();
892 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
894 case GTK_RESPONSE_YES:
895 linphone_gtk_show_contact(lf);
898 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
900 gtk_widget_destroy(dialog);
903 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
906 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
907 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
911 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);
912 dialog = gtk_message_dialog_new (
913 GTK_WINDOW(linphone_gtk_get_main_window()),
914 GTK_DIALOG_DESTROY_WITH_PARENT,
915 GTK_MESSAGE_QUESTION,
920 g_signal_connect(G_OBJECT (dialog), "response",
921 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
922 /* actually show the box */
923 gtk_widget_show(dialog);
926 typedef struct _AuthTimeout{
930 static void auth_timeout_clean(AuthTimeout *tout){
934 static gboolean auth_timeout_destroy(AuthTimeout *tout){
936 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
937 gtk_widget_destroy(tout->w);
943 static AuthTimeout * auth_timeout_new(GtkWidget *w){
944 AuthTimeout *tout=g_new(AuthTimeout,1);
946 /*so that the timeout no more references the widget when it is destroyed:*/
947 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
948 /*so that the widget is automatically destroyed after some time */
949 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
953 void linphone_gtk_password_cancel(GtkWidget *w){
954 LinphoneAuthInfo *info;
955 GtkWidget *window=gtk_widget_get_toplevel(w);
956 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
957 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
958 gtk_widget_destroy(window);
961 void linphone_gtk_password_ok(GtkWidget *w){
963 GtkWidget *window=gtk_widget_get_toplevel(w);
964 LinphoneAuthInfo *info;
965 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
966 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
967 entry=linphone_gtk_get_widget(window,"password_entry");
968 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
969 linphone_auth_info_set_userid(info,
970 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
971 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
972 gtk_widget_destroy(window);
975 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
976 GtkWidget *w=linphone_gtk_create_window("password");
977 GtkWidget *label=linphone_gtk_get_widget(w,"message");
978 LinphoneAuthInfo *info;
980 GtkWidget *mw=linphone_gtk_get_main_window();
982 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
983 /*don't prompt for authentication when login frame is visible*/
984 linphone_core_abort_authentication(lc,NULL);
988 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
990 gtk_label_set_markup(GTK_LABEL(label),msg);
992 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
993 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
994 g_object_set_data(G_OBJECT(w),"auth_info",info);
995 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
1000 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
1001 GtkWidget *w=linphone_gtk_get_main_window();
1002 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
1004 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
1005 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
1009 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
1010 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
1013 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
1014 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
1017 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
1018 char richtext[4096];
1019 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
1020 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
1023 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1024 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1025 if (w) linphone_gtk_call_log_update(w);
1026 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1030 static bool_t notify_actions_supported() {
1031 bool_t accepts_actions = FALSE;
1032 GList *capabilities = notify_get_server_caps();
1034 if(capabilities != NULL) {
1035 for(c = capabilities; c != NULL; c = c->next) {
1036 if(strcmp((char*)c->data, "actions") == 0 ) {
1037 accepts_actions = TRUE;
1041 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1042 g_list_free(capabilities);
1044 return accepts_actions;
1047 static NotifyNotification* build_notification(const char *title, const char *body){
1048 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1055 static void show_notification(NotifyNotification* n){
1056 if (n && !notify_notification_show(n,NULL))
1057 ms_error("Failed to send notification.");
1060 static void make_notification(const char *title, const char *body){
1061 show_notification(build_notification(title,body));
1066 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1068 if (!notify_is_initted())
1069 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1074 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1080 ms_error("Failed to send notification.");
1082 linphone_gtk_show_main_window();
1084 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1087 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1088 NotifyNotification *n;
1089 switch(linphone_call_get_state(call)){
1090 case LinphoneCallError:
1091 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
1093 case LinphoneCallEnd:
1094 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1096 case LinphoneCallIncomingReceived:
1097 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1098 if (notify_actions_supported()) {
1099 notify_notification_add_action (n,"answer", _("Answer"),
1100 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1101 notify_notification_add_action (n,"decline",_("Decline"),
1102 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1104 show_notification(n);
1106 case LinphoneCallPausedByRemote:
1107 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<span size=\"large\">by %s</span>"),remote));
1112 if (body) g_free(body);
1113 if (remote) g_free(remote);
1118 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1119 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1120 LinphoneCore *lc=linphone_call_get_core(call);
1121 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1122 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1123 linphone_core_accept_call_update(lc,call,params);
1124 linphone_call_params_destroy(params);
1126 linphone_call_unref(call);
1127 g_source_remove_by_user_data(dialog);
1128 gtk_widget_destroy(dialog);
1131 static void on_call_updated_timeout(GtkWidget *dialog){
1132 gtk_widget_destroy(dialog);
1135 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1136 LinphoneCore *lc=linphone_call_get_core(call);
1137 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1138 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1139 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1140 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1141 gboolean video_used=linphone_call_params_video_enabled(current_params);
1142 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1143 video_used,video_requested,pol->automatically_accept);
1144 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1145 linphone_core_defer_call_update(lc,call);
1147 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1149 const char *dname=linphone_address_get_display_name(addr);
1150 if (dname==NULL) dname=linphone_address_get_username(addr);
1151 if (dname==NULL) dname=linphone_address_get_domain(addr);
1152 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1153 GTK_DIALOG_DESTROY_WITH_PARENT,
1154 GTK_MESSAGE_WARNING,
1156 _("%s proposed to start video. Do you accept ?"),dname);
1157 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1158 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1159 gtk_widget_show(dialog);
1164 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1166 case LinphoneCallOutgoingInit:
1167 linphone_gtk_create_in_call_view (call);
1169 case LinphoneCallOutgoingProgress:
1170 linphone_gtk_in_call_view_set_calling (call);
1172 case LinphoneCallStreamsRunning:
1173 linphone_gtk_in_call_view_set_in_call(call);
1175 case LinphoneCallUpdatedByRemote:
1176 linphone_gtk_call_updated_by_remote(call);
1178 case LinphoneCallError:
1179 linphone_gtk_in_call_view_terminate (call,msg);
1181 case LinphoneCallEnd:
1182 linphone_gtk_in_call_view_terminate(call,NULL);
1183 linphone_gtk_status_icon_set_blinking(FALSE);
1185 case LinphoneCallIncomingReceived:
1186 linphone_gtk_create_in_call_view(call);
1187 linphone_gtk_in_call_view_set_incoming(call);
1188 linphone_gtk_status_icon_set_blinking(TRUE);
1190 linphone_call_ref(call);
1191 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1194 case LinphoneCallResuming:
1195 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1196 linphone_gtk_in_call_view_set_in_call (call);
1198 case LinphoneCallPausing:
1199 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1200 update_tab_header(call,FALSE);
1201 case LinphoneCallPausedByRemote:
1202 linphone_gtk_in_call_view_set_paused(call);
1203 update_tab_header(call,TRUE);
1205 case LinphoneCallConnected:
1206 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1207 linphone_gtk_status_icon_set_blinking(FALSE);
1212 linphone_gtk_notify(call, msg);
1213 linphone_gtk_update_call_buttons (call);
1216 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1217 linphone_gtk_in_call_view_show_encryption(call);
1220 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1221 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1224 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1225 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1226 GtkTreeModel *model=gtk_combo_box_get_model(box);
1228 gboolean found=FALSE;
1229 const char *stock_id=NULL;
1231 if (gtk_tree_model_get_iter_first(model,&iter)){
1234 gtk_tree_model_get(model,&iter,2,&p,-1);
1239 }while(gtk_tree_model_iter_next(model,&iter));
1242 g_warning("Could not find proxy config in combo box of identities.");
1246 case LinphoneRegistrationOk:
1247 stock_id=GTK_STOCK_YES;
1249 case LinphoneRegistrationProgress:
1250 stock_id=GTK_STOCK_REFRESH;
1252 case LinphoneRegistrationCleared:
1255 case LinphoneRegistrationFailed:
1256 stock_id=GTK_STOCK_DIALOG_WARNING;
1261 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1264 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1265 LinphoneRegistrationState rs, const char *msg){
1267 case LinphoneRegistrationOk:
1269 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1270 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1271 linphone_gtk_exit_login_frame();
1278 update_registration_status(cfg,rs);
1281 void linphone_gtk_open_browser(const char *url){
1282 /*in gtk 2.16, gtk_show_uri does not work...*/
1284 #if GTK_CHECK_VERSION(2,18,3)
1285 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1288 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1289 g_spawn_command_line_async(cl,NULL);
1292 ShellExecute(0,"open",url,NULL,NULL,1);
1296 void linphone_gtk_link_to_website(GtkWidget *item){
1297 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1298 linphone_gtk_open_browser(home);
1301 #ifndef HAVE_GTK_OSX
1303 static GtkStatusIcon *icon=NULL;
1305 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1306 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1307 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1310 static GtkWidget *create_icon_menu(){
1311 GtkWidget *menu=gtk_menu_new();
1312 GtkWidget *menu_item;
1315 const gchar *homesite;
1317 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1318 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1319 tmp=g_strdup(homesite);
1320 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1321 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1323 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1324 gtk_widget_show(image);
1325 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1326 //g_object_unref(G_OBJECT(image));
1327 gtk_widget_show(menu_item);
1328 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1329 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1331 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1332 gtk_widget_show(menu_item);
1333 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1334 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1335 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1336 gtk_widget_show(menu_item);
1337 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1338 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1339 gtk_widget_show(menu);
1343 static void handle_icon_click() {
1344 GtkWidget *mw=linphone_gtk_get_main_window();
1345 if (!gtk_window_is_active((GtkWindow*)mw)) {
1346 linphone_gtk_show_main_window();
1348 gtk_widget_hide(mw);
1352 static void linphone_gtk_init_status_icon(){
1353 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1354 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1355 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1356 GtkWidget *menu=create_icon_menu();
1358 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1359 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1360 #if GTK_CHECK_VERSION(2,20,0)
1361 gtk_status_icon_set_name(icon,title);
1363 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1364 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1365 gtk_status_icon_set_tooltip(icon,title);
1366 gtk_status_icon_set_visible(icon,TRUE);
1367 g_object_set_data(G_OBJECT(icon),"menu",menu);
1368 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1369 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1370 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1371 pbuf=create_pixbuf(call_icon_path);
1372 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1375 static gboolean do_icon_blink(GtkStatusIcon *gi){
1376 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1377 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1378 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1379 if (cur_icon==call_icon){
1380 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1382 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1389 void linphone_gtk_status_icon_set_blinking(gboolean val){
1391 static gint attention_id;
1392 GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1394 attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
1395 else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
1399 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1400 if (val && tout==0){
1401 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1402 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1403 }else if (!val && tout!=0){
1404 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1405 g_source_remove(tout);
1406 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1407 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1413 void linphone_gtk_options_activate(GtkWidget *item){
1414 #ifndef HAVE_GTK_OSX
1415 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1420 static void init_identity_combo(GtkComboBox *box){
1421 GtkListStore *store;
1422 GtkCellRenderer *r1,*r2;
1423 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1424 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1425 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1426 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1427 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1428 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1429 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1430 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1433 void linphone_gtk_load_identities(void){
1435 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1437 LinphoneProxyConfig *def=NULL;
1439 GtkListStore *store;
1442 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1443 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1444 /* model is empty, this is the first time we go here */
1445 init_identity_combo(box);
1446 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1448 gtk_list_store_clear(store);
1449 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1450 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1451 gtk_list_store_append(store,&iter);
1452 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1453 g_free(def_identity);
1454 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1456 elem=ms_list_next(elem),i++){
1457 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1458 gtk_list_store_append(store,&iter);
1459 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1460 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1466 gtk_combo_box_set_active(box,def_index);
1469 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1470 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1471 GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
1473 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1474 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1475 if (linphone_core_in_call(linphone_gtk_get_core())){
1476 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1480 static void linphone_gtk_dtmf_released(GtkButton *button){
1481 linphone_core_stop_dtmf (linphone_gtk_get_core());
1485 static void linphone_gtk_connect_digits(GtkWidget *w){
1486 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
1487 GList *children=gtk_container_get_children(cont);
1489 for(elem=children;elem!=NULL;elem=elem->next){
1490 GtkButton *button=GTK_BUTTON(elem->data);
1491 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1492 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1496 static void linphone_gtk_check_menu_items(void){
1497 bool_t video_enabled=linphone_gtk_video_enabled();
1498 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1499 GtkWidget *selfview_item=linphone_gtk_get_widget(
1500 linphone_gtk_get_main_window(),"selfview_item");
1501 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1502 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1503 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1506 static gboolean linphone_gtk_can_manage_accounts(){
1507 LinphoneCore *lc=linphone_gtk_get_core();
1509 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1510 SipSetup *ss=(SipSetup*)elem->data;
1511 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1518 static void linphone_gtk_configure_main_window(){
1519 static gboolean config_loaded=FALSE;
1520 static const char *title;
1521 static const char *home;
1522 static const char *start_call_icon;
1523 static const char *add_call_icon;
1524 static const char *search_icon;
1525 static gboolean update_check_menu;
1526 static gboolean buttons_have_borders;
1527 static gboolean show_abcd;
1528 GtkWidget *w=linphone_gtk_get_main_window();
1529 GHashTable *contacts_history;
1531 contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1532 g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1534 if (!config_loaded){
1535 title=linphone_gtk_get_ui_config("title","Linphone");
1536 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1537 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1538 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1539 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1540 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1541 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1542 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1545 linphone_gtk_configure_window(w,"main_window");
1547 gtk_window_set_title(GTK_WINDOW(w),title);
1549 if (start_call_icon){
1550 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1551 create_pixmap (start_call_icon));
1552 if (!buttons_have_borders)
1553 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1556 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1557 create_pixmap (add_call_icon));
1558 if (!buttons_have_borders)
1559 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1562 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1564 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1565 g_object_unref(G_OBJECT(pbuf));
1570 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1572 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1576 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1578 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1579 g_object_unref(G_OBJECT(pbuf));
1584 GdkPixbuf *pbuf=create_pixbuf("dialer.png");
1586 GtkButton *button=GTK_BUTTON(linphone_gtk_get_widget(w,"keypad"));
1587 gtk_button_set_image(button,gtk_image_new_from_pixbuf (pbuf));
1590 if (linphone_gtk_can_manage_accounts()) {
1591 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1593 if (update_check_menu){
1594 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1596 g_object_set_data(G_OBJECT(w),"show_abcd",GINT_TO_POINTER(show_abcd));
1599 void linphone_gtk_manage_login(void){
1600 LinphoneCore *lc=linphone_gtk_get_core();
1601 LinphoneProxyConfig *cfg=NULL;
1602 linphone_core_get_default_proxy(lc,&cfg);
1604 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1605 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1606 linphone_gtk_show_login_frame(cfg);
1611 gboolean linphone_gtk_close(GtkWidget *mw){
1612 /*shutdown calls if any*/
1613 LinphoneCore *lc=linphone_gtk_get_core();
1614 if (linphone_core_in_call(lc)){
1615 linphone_core_terminate_all_calls(lc);
1617 linphone_core_enable_video_preview(lc,FALSE);
1618 #ifdef __APPLE__ /*until with have a better option*/
1619 gtk_window_iconify(GTK_WINDOW(mw));
1621 gtk_widget_hide(mw);
1627 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1628 bool_t video_enabled=linphone_gtk_video_enabled();
1629 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1630 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1632 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1633 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1639 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1640 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1641 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1643 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1644 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1645 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1646 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1647 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1648 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1649 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1650 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1651 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1652 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1653 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1654 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1655 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1656 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1657 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1658 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1661 void linphone_gtk_create_keypad(GtkWidget *button){
1662 GtkWidget *mw=linphone_gtk_get_main_window();
1663 GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad");
1665 gtk_widget_destroy(k);
1667 GtkWidget *keypad=linphone_gtk_create_window("keypad");
1668 linphone_gtk_connect_digits(keypad);
1669 linphone_gtk_init_dtmf_table(keypad);
1670 g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad);
1671 if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"show_abcd"))){
1672 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_A"));
1673 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_B"));
1674 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_C"));
1675 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_D"));
1676 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(keypad,"dtmf_table")),4,3);
1678 gtk_widget_show(keypad);
1681 static void linphone_gtk_init_main_window(){
1682 GtkWidget *main_window;
1683 linphone_gtk_configure_main_window();
1684 linphone_gtk_manage_login();
1686 linphone_gtk_load_identities();
1687 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1688 linphone_gtk_show_friends();
1689 main_window=linphone_gtk_get_main_window();
1690 linphone_gtk_call_log_update(main_window);
1692 linphone_gtk_update_call_buttons (NULL);
1693 g_object_set_data(G_OBJECT(main_window),"keypad",NULL);
1694 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1695 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1696 g_signal_connect (G_OBJECT (main_window), "delete-event",
1697 G_CALLBACK (linphone_gtk_close), main_window);
1700 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1701 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1702 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1703 gtk_widget_hide(menubar);
1704 gtk_osxapplication_ready(theMacApp);
1706 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1708 linphone_gtk_check_menu_items();
1712 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1714 const char *lname="undef";
1716 #if defined(__linux) || defined(__APPLE__)
1717 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1736 g_error("Bad level !");
1738 #if defined(__linux) || defined(__APPLE__)
1740 msg=g_strdup_vprintf(fmt,cap);
1743 msg=g_strdup_vprintf(fmt,args);
1745 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1748 linphone_gtk_log_push(lev,fmt,args);
1752 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1753 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1754 linphone_gtk_get_main_window(), "uribar"));
1756 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1758 gtk_entry_set_text(uri_bar, refer_to);
1759 linphone_gtk_start_call(linphone_gtk_get_main_window());
1762 static void linphone_gtk_check_soundcards(){
1763 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1764 if (devices==NULL || devices[0]==NULL){
1765 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1766 _("No sound cards have been detected on this computer.\n"
1767 "You won't be able to send or receive audio calls."));
1771 static void linphone_gtk_quit(void){
1772 static gboolean quit_done=FALSE;
1775 linphone_gtk_unmonitor_usb();
1776 g_source_remove_by_user_data(linphone_gtk_get_core());
1778 linphone_gtk_close_assistant();
1780 linphone_gtk_uninit_instance();
1781 linphone_gtk_destroy_log_window();
1782 linphone_core_destroy(the_core);
1783 linphone_gtk_log_uninit();
1787 gdk_threads_leave();
1793 This is not the correct way to implement block termination.
1794 The good way would be to call gtk_main_quit(), and return TRUE.
1795 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1796 As a result the program cannot exit at all.
1797 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1799 static gboolean on_block_termination(void){
1801 linphone_gtk_quit();
1806 int main(int argc, char *argv[]){
1811 const char *factory_config_file;
1813 GtkSettings *settings;
1815 const char *app_name="Linphone";
1818 #if !GLIB_CHECK_VERSION(2, 31, 0)
1819 g_thread_init(NULL);
1823 progpath = strdup(argv[0]);
1825 config_file=linphone_gtk_get_config_file(NULL);
1829 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1830 if ((lang=getenv("LANG"))!=NULL){
1833 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1839 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1842 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1845 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1847 if (strncmp(lang,"zh",2)==0){
1848 workaround_gtk_entry_chinese_bug=TRUE;
1851 setenv("LANG",lang,1);
1853 setenv("LANGUAGE",lang,1);
1858 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1859 if (p==NULL) perror("bindtextdomain failed");
1860 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1861 textdomain (GETTEXT_PACKAGE);
1863 g_message("NLS disabled.\n");
1866 gtk_rc_add_default_file("./gtkrc");
1868 gdk_threads_enter();
1870 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1871 linphone_options,NULL,NULL)){
1872 gdk_threads_leave();
1876 settings=gtk_settings_get_default();
1877 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1878 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1879 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1880 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1882 if (workingdir!=NULL){
1883 if (chdir(workingdir)==-1){
1884 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1888 /* Now, look for the factory configuration file, we do it this late
1889 since we want to have had time to change directory and to parse
1890 the options, in case we needed to access the working directory */
1891 factory_config_file = linphone_gtk_get_factory_config_file();
1892 if (factory_config_file){
1893 factory=lp_config_new(NULL);
1894 lp_config_read_file(factory,factory_config_file);
1895 app_name=lp_config_get_string(factory,"GtkUi","title","Linphone");
1898 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1899 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1900 g_warning("This instance is going to exit now.");
1901 gdk_threads_leave();
1905 add_pixmap_directory("pixmaps");
1906 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1909 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1910 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1911 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1912 /*never block termination:*/
1913 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1916 the_ui=linphone_gtk_create_window("main");
1918 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1920 linphone_gtk_create_log_window();
1921 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1923 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1925 g_set_application_name(app_name);
1926 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1927 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1929 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1930 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1931 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1932 linphone_gtk_init_main_window();
1935 // Veryfing if at least one sip account is configured. If not, show wizard
1936 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1937 linphone_gtk_show_assistant();
1941 #ifndef HAVE_GTK_OSX
1942 linphone_gtk_init_status_icon();
1945 linphone_gtk_show_main_window();
1946 linphone_gtk_check_soundcards();
1948 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1949 linphone_gtk_check_for_new_version();
1950 linphone_gtk_monitor_usb();
1953 linphone_gtk_quit();
1954 #ifndef HAVE_GTK_OSX
1955 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1956 gtk_status_icon_set_visible(icon,FALSE);