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_record_path(const LinphoneAddress *address, gboolean is_conference){
754 const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
755 const char *id="unknown";
756 char filename[256]={0};
758 time_t curtime=time(NULL);
762 loctime=*localtime(&curtime);
764 localtime_r(&curtime,&loctime);
766 snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min);
769 id=linphone_address_get_username(address);
770 if (id==NULL) id=linphone_address_get_domain(address);
773 snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav",
774 linphone_gtk_get_ui_config("title","Linphone"),
777 snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav",
778 linphone_gtk_get_ui_config("title","Linphone"),
782 return g_build_filename(dir,filename,NULL);
785 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
786 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
787 LinphoneCore *lc=linphone_gtk_get_core();
788 LinphoneAddress *addr=linphone_core_interpret_url(lc,entered);
791 LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
792 gchar *record_file=linphone_gtk_get_record_path(addr,FALSE);
793 linphone_call_params_set_record_file(params,record_file);
794 linphone_core_invite_address_with_params(lc,addr,params);
795 completion_add_text(GTK_ENTRY(uri_bar),entered);
796 linphone_address_destroy(addr);
797 linphone_call_params_destroy(params);
800 linphone_gtk_call_terminated(NULL,NULL);
806 static void accept_incoming_call(LinphoneCall *call){
807 LinphoneCore *lc=linphone_gtk_get_core();
808 LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
809 gchar *record_file=linphone_gtk_get_record_path(linphone_call_get_remote_address(call),FALSE);
810 linphone_call_params_set_record_file(params,record_file);
811 linphone_core_accept_call_with_params(lc,call,params);
812 linphone_call_params_destroy(params);
815 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
816 LinphoneCallState state=linphone_call_get_state(call);
817 if (state==LinphoneCallIncomingReceived || state==LinphoneCallIncomingEarlyMedia){
818 accept_incoming_call(call);
823 void linphone_gtk_start_call(GtkWidget *w){
824 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
825 /*change into in-call mode, then do the work later as it might block a bit */
826 GtkWidget *mw=gtk_widget_get_toplevel(w);
827 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
828 LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle;
830 if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){
831 accept_incoming_call(call);
833 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
834 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
835 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
836 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
841 void linphone_gtk_uri_bar_activate(GtkWidget *w){
842 linphone_gtk_start_call(w);
845 void linphone_gtk_terminate_call(GtkWidget *button){
847 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
849 linphone_core_terminate_call(linphone_gtk_get_core(),call);
851 linphone_core_terminate_conference(linphone_gtk_get_core());
855 void linphone_gtk_decline_clicked(GtkWidget *button){
856 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
858 linphone_core_terminate_call(linphone_gtk_get_core(),call);
861 void linphone_gtk_answer_clicked(GtkWidget *button){
862 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
864 accept_incoming_call(call);
865 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
869 void _linphone_gtk_enable_video(gboolean val){
870 LinphoneVideoPolicy policy={0};
871 policy.automatically_initiate=policy.automatically_accept=val;
872 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
873 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
876 linphone_core_enable_video_preview(linphone_gtk_get_core(),
877 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
879 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
883 void linphone_gtk_enable_video(GtkWidget *w){
884 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
885 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
886 _linphone_gtk_enable_video(val);
889 void linphone_gtk_enable_self_view(GtkWidget *w){
890 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
891 LinphoneCore *lc=linphone_gtk_get_core();
892 linphone_core_enable_video_preview(lc,val);
893 linphone_core_enable_self_view(lc,val);
894 linphone_gtk_set_ui_config_int("videoselfview",val);
897 void linphone_gtk_used_identity_changed(GtkWidget *w){
898 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
899 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
900 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
901 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
902 linphone_gtk_show_directory_search();
904 if (sel) g_free(sel);
907 void on_proxy_refresh_button_clicked(GtkWidget *w){
908 LinphoneCore *lc=linphone_gtk_get_core();
909 MSList const *item=linphone_core_get_proxy_config_list(lc);
910 while (item != NULL) {
911 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
912 linphone_proxy_config_edit(lpc);
913 linphone_proxy_config_done(lpc);
918 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
919 linphone_gtk_show_friends();
922 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
924 case GTK_RESPONSE_YES:
925 linphone_gtk_show_contact(lf);
928 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
930 gtk_widget_destroy(dialog);
933 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
936 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
937 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
941 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);
942 dialog = gtk_message_dialog_new (
943 GTK_WINDOW(linphone_gtk_get_main_window()),
944 GTK_DIALOG_DESTROY_WITH_PARENT,
945 GTK_MESSAGE_QUESTION,
950 g_signal_connect(G_OBJECT (dialog), "response",
951 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
952 /* actually show the box */
953 gtk_widget_show(dialog);
956 typedef struct _AuthTimeout{
960 static void auth_timeout_clean(AuthTimeout *tout){
964 static gboolean auth_timeout_destroy(AuthTimeout *tout){
966 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
967 gtk_widget_destroy(tout->w);
973 static AuthTimeout * auth_timeout_new(GtkWidget *w){
974 AuthTimeout *tout=g_new(AuthTimeout,1);
976 /*so that the timeout no more references the widget when it is destroyed:*/
977 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
978 /*so that the widget is automatically destroyed after some time */
979 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
983 void linphone_gtk_password_cancel(GtkWidget *w){
984 LinphoneAuthInfo *info;
985 GtkWidget *window=gtk_widget_get_toplevel(w);
986 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
987 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
988 gtk_widget_destroy(window);
991 void linphone_gtk_password_ok(GtkWidget *w){
993 GtkWidget *window=gtk_widget_get_toplevel(w);
994 LinphoneAuthInfo *info;
995 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
996 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
997 entry=linphone_gtk_get_widget(window,"password_entry");
998 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
999 linphone_auth_info_set_userid(info,
1000 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
1001 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
1002 gtk_widget_destroy(window);
1005 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
1006 GtkWidget *w=linphone_gtk_create_window("password");
1007 GtkWidget *label=linphone_gtk_get_widget(w,"message");
1008 LinphoneAuthInfo *info;
1010 GtkWidget *mw=linphone_gtk_get_main_window();
1012 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
1013 /*don't prompt for authentication when login frame is visible*/
1014 linphone_core_abort_authentication(lc,NULL);
1018 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
1020 gtk_label_set_markup(GTK_LABEL(label),msg);
1022 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
1023 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
1024 g_object_set_data(G_OBJECT(w),"auth_info",info);
1025 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
1027 auth_timeout_new(w);
1030 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
1031 GtkWidget *w=linphone_gtk_get_main_window();
1032 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
1034 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
1035 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
1039 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
1040 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
1043 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
1044 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
1047 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
1048 char richtext[4096];
1049 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
1050 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
1053 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1054 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1055 if (w) linphone_gtk_call_log_update(w);
1056 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1060 static bool_t notify_actions_supported() {
1061 bool_t accepts_actions = FALSE;
1062 GList *capabilities = notify_get_server_caps();
1064 if(capabilities != NULL) {
1065 for(c = capabilities; c != NULL; c = c->next) {
1066 if(strcmp((char*)c->data, "actions") == 0 ) {
1067 accepts_actions = TRUE;
1071 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1072 g_list_free(capabilities);
1074 return accepts_actions;
1077 static NotifyNotification* build_notification(const char *title, const char *body){
1078 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1085 static void show_notification(NotifyNotification* n){
1086 if (n && !notify_notification_show(n,NULL))
1087 ms_error("Failed to send notification.");
1090 static void make_notification(const char *title, const char *body){
1091 show_notification(build_notification(title,body));
1096 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1098 if (!notify_is_initted())
1099 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1104 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1110 ms_error("Failed to send notification.");
1112 linphone_gtk_show_main_window();
1114 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1117 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1118 NotifyNotification *n;
1119 switch(linphone_call_get_state(call)){
1120 case LinphoneCallError:
1121 make_notification(_("Call error"),body=g_markup_printf_escaped("<b>%s</b>\n%s",msg,remote));
1123 case LinphoneCallEnd:
1124 make_notification(_("Call ended"),body=g_markup_printf_escaped("<b>%s</b>",remote));
1126 case LinphoneCallIncomingReceived:
1127 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<b>%s</b>",remote));
1128 if (notify_actions_supported()) {
1129 notify_notification_add_action (n,"answer", _("Answer"),
1130 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1131 notify_notification_add_action (n,"decline",_("Decline"),
1132 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1134 show_notification(n);
1136 case LinphoneCallPausedByRemote:
1137 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<b>by %s</b>"),remote));
1142 if (body) g_free(body);
1143 if (remote) g_free(remote);
1148 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1149 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1150 LinphoneCore *lc=linphone_call_get_core(call);
1151 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1152 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1153 linphone_core_accept_call_update(lc,call,params);
1154 linphone_call_params_destroy(params);
1156 linphone_call_unref(call);
1157 g_source_remove_by_user_data(dialog);
1158 gtk_widget_destroy(dialog);
1161 static void on_call_updated_timeout(GtkWidget *dialog){
1162 gtk_widget_destroy(dialog);
1165 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1166 LinphoneCore *lc=linphone_call_get_core(call);
1167 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1168 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1169 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1170 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1171 gboolean video_used=linphone_call_params_video_enabled(current_params);
1172 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1173 video_used,video_requested,pol->automatically_accept);
1174 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1175 linphone_core_defer_call_update(lc,call);
1177 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1179 const char *dname=linphone_address_get_display_name(addr);
1180 if (dname==NULL) dname=linphone_address_get_username(addr);
1181 if (dname==NULL) dname=linphone_address_get_domain(addr);
1182 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1183 GTK_DIALOG_DESTROY_WITH_PARENT,
1184 GTK_MESSAGE_WARNING,
1186 _("%s proposed to start video. Do you accept ?"),dname);
1187 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1188 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1189 gtk_widget_show(dialog);
1194 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1196 case LinphoneCallOutgoingInit:
1197 linphone_gtk_create_in_call_view (call);
1199 case LinphoneCallOutgoingProgress:
1200 linphone_gtk_in_call_view_set_calling (call);
1202 case LinphoneCallStreamsRunning:
1203 linphone_gtk_in_call_view_set_in_call(call);
1205 case LinphoneCallUpdatedByRemote:
1206 linphone_gtk_call_updated_by_remote(call);
1208 case LinphoneCallError:
1209 linphone_gtk_in_call_view_terminate (call,msg);
1211 case LinphoneCallEnd:
1212 linphone_gtk_in_call_view_terminate(call,NULL);
1213 linphone_gtk_status_icon_set_blinking(FALSE);
1215 case LinphoneCallIncomingReceived:
1216 linphone_gtk_create_in_call_view(call);
1217 linphone_gtk_in_call_view_set_incoming(call);
1218 linphone_gtk_status_icon_set_blinking(TRUE);
1220 linphone_call_ref(call);
1221 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1224 case LinphoneCallResuming:
1225 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1226 linphone_gtk_in_call_view_set_in_call (call);
1228 case LinphoneCallPausing:
1229 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1230 update_tab_header(call,FALSE);
1231 case LinphoneCallPausedByRemote:
1232 linphone_gtk_in_call_view_set_paused(call);
1233 update_tab_header(call,TRUE);
1235 case LinphoneCallConnected:
1236 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1237 linphone_gtk_status_icon_set_blinking(FALSE);
1242 linphone_gtk_notify(call, msg);
1243 linphone_gtk_update_call_buttons (call);
1246 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1247 linphone_gtk_in_call_view_show_encryption(call);
1250 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1251 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1254 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1255 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1256 GtkTreeModel *model=gtk_combo_box_get_model(box);
1258 gboolean found=FALSE;
1259 const char *stock_id=NULL;
1261 if (gtk_tree_model_get_iter_first(model,&iter)){
1264 gtk_tree_model_get(model,&iter,2,&p,-1);
1269 }while(gtk_tree_model_iter_next(model,&iter));
1272 g_warning("Could not find proxy config in combo box of identities.");
1276 case LinphoneRegistrationOk:
1277 stock_id=GTK_STOCK_YES;
1279 case LinphoneRegistrationProgress:
1280 stock_id=GTK_STOCK_REFRESH;
1282 case LinphoneRegistrationCleared:
1285 case LinphoneRegistrationFailed:
1286 stock_id=GTK_STOCK_DIALOG_WARNING;
1291 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1294 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1295 LinphoneRegistrationState rs, const char *msg){
1297 case LinphoneRegistrationOk:
1299 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1300 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1301 linphone_gtk_exit_login_frame();
1308 update_registration_status(cfg,rs);
1311 void linphone_gtk_open_browser(const char *url){
1312 /*in gtk 2.16, gtk_show_uri does not work...*/
1314 #if GTK_CHECK_VERSION(2,18,3)
1315 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1318 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1319 g_spawn_command_line_async(cl,NULL);
1322 ShellExecute(0,"open",url,NULL,NULL,1);
1326 void linphone_gtk_link_to_website(GtkWidget *item){
1327 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1328 linphone_gtk_open_browser(home);
1331 #ifndef HAVE_GTK_OSX
1333 static GtkStatusIcon *icon=NULL;
1335 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1336 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1337 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1340 static GtkWidget *create_icon_menu(){
1341 GtkWidget *menu=gtk_menu_new();
1342 GtkWidget *menu_item;
1345 const gchar *homesite;
1347 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1348 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1349 tmp=g_strdup(homesite);
1350 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1351 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1353 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1354 gtk_widget_show(image);
1355 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1356 //g_object_unref(G_OBJECT(image));
1357 gtk_widget_show(menu_item);
1358 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1359 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1361 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1362 gtk_widget_show(menu_item);
1363 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1364 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1365 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1366 gtk_widget_show(menu_item);
1367 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1368 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1369 gtk_widget_show(menu);
1373 static void handle_icon_click() {
1374 GtkWidget *mw=linphone_gtk_get_main_window();
1375 if (!gtk_window_is_active((GtkWindow*)mw)) {
1376 linphone_gtk_show_main_window();
1378 gtk_widget_hide(mw);
1382 static void linphone_gtk_init_status_icon(){
1383 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1384 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1385 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1386 GtkWidget *menu=create_icon_menu();
1388 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1389 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1390 #if GTK_CHECK_VERSION(2,20,0)
1391 gtk_status_icon_set_name(icon,title);
1393 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1394 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1395 gtk_status_icon_set_tooltip(icon,title);
1396 gtk_status_icon_set_visible(icon,TRUE);
1397 g_object_set_data(G_OBJECT(icon),"menu",menu);
1398 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1399 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1400 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1401 pbuf=create_pixbuf(call_icon_path);
1402 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1405 static gboolean do_icon_blink(GtkStatusIcon *gi){
1406 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1407 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1408 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1409 if (cur_icon==call_icon){
1410 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1412 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1419 void linphone_gtk_status_icon_set_blinking(gboolean val){
1421 static gint attention_id;
1422 GtkosxApplication *theMacApp=gtkosx_application_get();
1424 attention_id=gtkosx_application_attention_request(theMacApp,CRITICAL_REQUEST);
1425 else gtkosx_application_cancel_attention_request(theMacApp,attention_id);
1429 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1430 if (val && tout==0){
1431 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1432 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1433 }else if (!val && tout!=0){
1434 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1435 g_source_remove(tout);
1436 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1437 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1443 void linphone_gtk_options_activate(GtkWidget *item){
1444 #ifndef HAVE_GTK_OSX
1445 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1450 static void init_identity_combo(GtkComboBox *box){
1451 GtkListStore *store;
1452 GtkCellRenderer *r1,*r2;
1453 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1454 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1455 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1456 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1457 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1458 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1459 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1460 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1463 void linphone_gtk_load_identities(void){
1465 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1467 LinphoneProxyConfig *def=NULL;
1469 GtkListStore *store;
1472 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1473 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1474 /* model is empty, this is the first time we go here */
1475 init_identity_combo(box);
1476 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1478 gtk_list_store_clear(store);
1479 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1480 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1481 gtk_list_store_append(store,&iter);
1482 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1483 g_free(def_identity);
1484 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1486 elem=ms_list_next(elem),i++){
1487 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1488 gtk_list_store_append(store,&iter);
1489 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1490 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1496 gtk_combo_box_set_active(box,def_index);
1499 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1500 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1501 GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
1503 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1504 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1505 if (linphone_core_in_call(linphone_gtk_get_core())){
1506 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1510 static void linphone_gtk_dtmf_released(GtkButton *button){
1511 linphone_core_stop_dtmf (linphone_gtk_get_core());
1515 static void linphone_gtk_connect_digits(GtkWidget *w){
1516 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
1517 GList *children=gtk_container_get_children(cont);
1519 for(elem=children;elem!=NULL;elem=elem->next){
1520 GtkButton *button=GTK_BUTTON(elem->data);
1521 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1522 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1526 static void linphone_gtk_check_menu_items(void){
1527 bool_t video_enabled=linphone_gtk_video_enabled();
1528 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1529 GtkWidget *selfview_item=linphone_gtk_get_widget(
1530 linphone_gtk_get_main_window(),"selfview_item");
1531 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1532 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1533 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1536 static gboolean linphone_gtk_can_manage_accounts(){
1537 LinphoneCore *lc=linphone_gtk_get_core();
1539 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1540 SipSetup *ss=(SipSetup*)elem->data;
1541 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1548 static void linphone_gtk_configure_main_window(){
1549 static gboolean config_loaded=FALSE;
1550 static const char *title;
1551 static const char *home;
1552 static const char *start_call_icon;
1553 static const char *add_call_icon;
1554 static const char *search_icon;
1555 static gboolean update_check_menu;
1556 static gboolean buttons_have_borders;
1557 static gboolean show_abcd;
1558 GtkWidget *w=linphone_gtk_get_main_window();
1559 GHashTable *contacts_history;
1561 contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1562 g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1564 if (!config_loaded){
1565 title=linphone_gtk_get_ui_config("title","Linphone");
1566 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1567 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1568 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1569 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1570 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1571 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1572 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1575 linphone_gtk_configure_window(w,"main_window");
1577 gtk_window_set_title(GTK_WINDOW(w),title);
1579 if (start_call_icon){
1580 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1581 create_pixmap (start_call_icon));
1582 if (!buttons_have_borders)
1583 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1586 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1587 create_pixmap (add_call_icon));
1588 if (!buttons_have_borders)
1589 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1592 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1594 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1595 g_object_unref(G_OBJECT(pbuf));
1600 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1602 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1606 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1608 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1609 g_object_unref(G_OBJECT(pbuf));
1614 GdkPixbuf *pbuf=create_pixbuf("dialer.png");
1616 GtkButton *button=GTK_BUTTON(linphone_gtk_get_widget(w,"keypad"));
1617 gtk_button_set_image(button,gtk_image_new_from_pixbuf (pbuf));
1620 if (linphone_gtk_can_manage_accounts()) {
1621 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1623 if (update_check_menu){
1624 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1626 g_object_set_data(G_OBJECT(w),"show_abcd",GINT_TO_POINTER(show_abcd));
1629 void linphone_gtk_manage_login(void){
1630 LinphoneCore *lc=linphone_gtk_get_core();
1631 LinphoneProxyConfig *cfg=NULL;
1632 linphone_core_get_default_proxy(lc,&cfg);
1634 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1635 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1636 linphone_gtk_show_login_frame(cfg);
1641 gboolean linphone_gtk_close(GtkWidget *mw){
1642 /*shutdown calls if any*/
1643 LinphoneCore *lc=linphone_gtk_get_core();
1644 if (linphone_core_in_call(lc)){
1645 linphone_core_terminate_all_calls(lc);
1647 linphone_core_enable_video_preview(lc,FALSE);
1648 #ifdef __APPLE__ /*until with have a better option*/
1649 gtk_window_iconify(GTK_WINDOW(mw));
1651 gtk_widget_hide(mw);
1657 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1658 bool_t video_enabled=linphone_gtk_video_enabled();
1659 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1660 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1662 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1663 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1669 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1670 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1671 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1673 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1674 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1675 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1676 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1677 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1678 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1679 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1680 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1681 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1682 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1683 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1684 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1685 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1686 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1687 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1688 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1691 void linphone_gtk_create_keypad(GtkWidget *button){
1692 GtkWidget *mw=linphone_gtk_get_main_window();
1693 GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad");
1695 gtk_widget_destroy(k);
1697 GtkWidget *keypad=linphone_gtk_create_window("keypad");
1698 linphone_gtk_connect_digits(keypad);
1699 linphone_gtk_init_dtmf_table(keypad);
1700 g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad);
1701 if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"show_abcd"))){
1702 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_A"));
1703 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_B"));
1704 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_C"));
1705 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_D"));
1706 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(keypad,"dtmf_table")),4,3);
1708 gtk_widget_show(keypad);
1711 static void linphone_gtk_init_main_window(){
1712 GtkWidget *main_window;
1713 linphone_gtk_configure_main_window();
1714 linphone_gtk_manage_login();
1716 linphone_gtk_load_identities();
1717 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1718 linphone_gtk_show_friends();
1719 main_window=linphone_gtk_get_main_window();
1720 linphone_gtk_call_log_update(main_window);
1722 linphone_gtk_update_call_buttons (NULL);
1723 g_object_set_data(G_OBJECT(main_window),"keypad",NULL);
1724 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1725 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1726 g_signal_connect (G_OBJECT (main_window), "delete-event",
1727 G_CALLBACK (linphone_gtk_close), main_window);
1730 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1731 GtkosxApplication *theMacApp = gtkosx_application_get();
1732 gtkosx_application_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1733 gtk_widget_hide(menubar);
1734 gtkosx_application_ready(theMacApp);
1736 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1738 linphone_gtk_check_menu_items();
1742 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1744 const char *lname="undef";
1746 #if defined(__linux) || defined(__APPLE__)
1747 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1766 g_error("Bad level !");
1768 #if defined(__linux) || defined(__APPLE__)
1770 msg=g_strdup_vprintf(fmt,cap);
1773 msg=g_strdup_vprintf(fmt,args);
1775 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1778 linphone_gtk_log_push(lev,fmt,args);
1782 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1783 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1784 linphone_gtk_get_main_window(), "uribar"));
1786 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1788 gtk_entry_set_text(uri_bar, refer_to);
1789 linphone_gtk_start_call(linphone_gtk_get_main_window());
1792 static void linphone_gtk_check_soundcards(){
1793 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1794 if (devices==NULL || devices[0]==NULL){
1795 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1796 _("No sound cards have been detected on this computer.\n"
1797 "You won't be able to send or receive audio calls."));
1801 static void linphone_gtk_quit(void){
1802 static gboolean quit_done=FALSE;
1805 linphone_gtk_unmonitor_usb();
1806 g_source_remove_by_user_data(linphone_gtk_get_core());
1808 linphone_gtk_close_assistant();
1810 linphone_gtk_uninit_instance();
1811 linphone_gtk_destroy_log_window();
1812 linphone_core_destroy(the_core);
1813 linphone_gtk_log_uninit();
1817 gdk_threads_leave();
1823 This is not the correct way to implement block termination.
1824 The good way would be to call gtk_main_quit(), and return TRUE.
1825 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1826 As a result the program cannot exit at all.
1827 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1829 static gboolean on_block_termination(void){
1831 linphone_gtk_quit();
1836 int main(int argc, char *argv[]){
1841 const char *factory_config_file;
1843 GtkSettings *settings;
1845 const char *app_name="Linphone";
1848 #if !GLIB_CHECK_VERSION(2, 31, 0)
1849 g_thread_init(NULL);
1853 progpath = strdup(argv[0]);
1855 config_file=linphone_gtk_get_config_file(NULL);
1859 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1860 if ((lang=getenv("LANG"))!=NULL){
1863 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1869 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1872 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1875 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1877 if (strncmp(lang,"zh",2)==0){
1878 workaround_gtk_entry_chinese_bug=TRUE;
1881 setenv("LANG",lang,1);
1883 setenv("LANGUAGE",lang,1);
1888 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1889 if (p==NULL) perror("bindtextdomain failed");
1890 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1891 textdomain (GETTEXT_PACKAGE);
1893 g_message("NLS disabled.\n");
1896 gtk_rc_add_default_file("./gtkrc");
1898 gdk_threads_enter();
1900 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1901 linphone_options,NULL,NULL)){
1902 gdk_threads_leave();
1906 settings=gtk_settings_get_default();
1907 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1908 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1909 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1910 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1912 if (workingdir!=NULL){
1913 if (chdir(workingdir)==-1){
1914 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1918 /* Now, look for the factory configuration file, we do it this late
1919 since we want to have had time to change directory and to parse
1920 the options, in case we needed to access the working directory */
1921 factory_config_file = linphone_gtk_get_factory_config_file();
1922 if (factory_config_file){
1923 factory=lp_config_new(NULL);
1924 lp_config_read_file(factory,factory_config_file);
1925 app_name=lp_config_get_string(factory,"GtkUi","title","Linphone");
1928 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1929 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1930 g_warning("This instance is going to exit now.");
1931 gdk_threads_leave();
1935 add_pixmap_directory("pixmaps");
1936 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1939 GtkosxApplication *theMacApp = gtkosx_application_get();
1940 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1941 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1942 /*never block termination:*/
1943 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1946 the_ui=linphone_gtk_create_window("main");
1948 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1950 linphone_gtk_create_log_window();
1951 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1953 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1955 g_set_application_name(app_name);
1956 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1957 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1959 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1960 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1961 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1962 linphone_gtk_init_main_window();
1965 // Veryfing if at least one sip account is configured. If not, show wizard
1966 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1967 linphone_gtk_show_assistant();
1971 #ifndef HAVE_GTK_OSX
1972 linphone_gtk_init_status_icon();
1975 linphone_gtk_show_main_window();
1976 linphone_gtk_check_soundcards();
1978 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1979 linphone_gtk_check_for_new_version();
1980 linphone_gtk_monitor_usb();
1983 linphone_gtk_quit();
1984 #ifndef HAVE_GTK_OSX
1985 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1986 gtk_status_icon_set_visible(icon,FALSE);