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);
819 linphone_call_unref(call);
824 void linphone_gtk_start_call(GtkWidget *w){
825 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
826 /*change into in-call mode, then do the work later as it might block a bit */
827 GtkWidget *mw=gtk_widget_get_toplevel(w);
828 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
829 LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle;
831 if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){
832 accept_incoming_call(call);
834 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
835 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
836 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
837 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
842 void linphone_gtk_uri_bar_activate(GtkWidget *w){
843 linphone_gtk_start_call(w);
846 void linphone_gtk_terminate_call(GtkWidget *button){
848 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
850 linphone_core_terminate_call(linphone_gtk_get_core(),call);
852 linphone_core_terminate_conference(linphone_gtk_get_core());
856 void linphone_gtk_decline_clicked(GtkWidget *button){
857 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
859 linphone_core_terminate_call(linphone_gtk_get_core(),call);
862 void linphone_gtk_answer_clicked(GtkWidget *button){
863 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
865 accept_incoming_call(call);
866 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
870 void _linphone_gtk_enable_video(gboolean val){
871 LinphoneVideoPolicy policy={0};
872 policy.automatically_initiate=policy.automatically_accept=val;
873 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
874 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
877 linphone_core_enable_video_preview(linphone_gtk_get_core(),
878 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
880 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
884 void linphone_gtk_enable_video(GtkWidget *w){
885 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
886 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
887 _linphone_gtk_enable_video(val);
890 void linphone_gtk_enable_self_view(GtkWidget *w){
891 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
892 LinphoneCore *lc=linphone_gtk_get_core();
893 linphone_core_enable_video_preview(lc,val);
894 linphone_core_enable_self_view(lc,val);
895 linphone_gtk_set_ui_config_int("videoselfview",val);
898 void linphone_gtk_used_identity_changed(GtkWidget *w){
899 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
900 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
901 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
902 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
903 linphone_gtk_show_directory_search();
905 if (sel) g_free(sel);
908 void on_proxy_refresh_button_clicked(GtkWidget *w){
909 LinphoneCore *lc=linphone_gtk_get_core();
910 MSList const *item=linphone_core_get_proxy_config_list(lc);
911 while (item != NULL) {
912 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
913 linphone_proxy_config_edit(lpc);
914 linphone_proxy_config_done(lpc);
919 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
920 linphone_gtk_show_friends();
923 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
925 case GTK_RESPONSE_YES:
926 linphone_gtk_show_contact(lf);
929 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
931 gtk_widget_destroy(dialog);
934 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
937 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
938 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
942 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);
943 dialog = gtk_message_dialog_new (
944 GTK_WINDOW(linphone_gtk_get_main_window()),
945 GTK_DIALOG_DESTROY_WITH_PARENT,
946 GTK_MESSAGE_QUESTION,
951 g_signal_connect(G_OBJECT (dialog), "response",
952 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
953 /* actually show the box */
954 gtk_widget_show(dialog);
957 typedef struct _AuthTimeout{
961 static void auth_timeout_clean(AuthTimeout *tout){
965 static gboolean auth_timeout_destroy(AuthTimeout *tout){
967 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
968 gtk_widget_destroy(tout->w);
974 static AuthTimeout * auth_timeout_new(GtkWidget *w){
975 AuthTimeout *tout=g_new(AuthTimeout,1);
977 /*so that the timeout no more references the widget when it is destroyed:*/
978 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
979 /*so that the widget is automatically destroyed after some time */
980 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
984 void linphone_gtk_password_cancel(GtkWidget *w){
985 LinphoneAuthInfo *info;
986 GtkWidget *window=gtk_widget_get_toplevel(w);
987 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
988 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
989 gtk_widget_destroy(window);
992 void linphone_gtk_password_ok(GtkWidget *w){
994 GtkWidget *window=gtk_widget_get_toplevel(w);
995 LinphoneAuthInfo *info;
996 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
997 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
998 entry=linphone_gtk_get_widget(window,"password_entry");
999 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
1000 linphone_auth_info_set_userid(info,
1001 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
1002 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
1003 gtk_widget_destroy(window);
1006 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
1007 GtkWidget *w=linphone_gtk_create_window("password");
1008 GtkWidget *label=linphone_gtk_get_widget(w,"message");
1009 LinphoneAuthInfo *info;
1011 GtkWidget *mw=linphone_gtk_get_main_window();
1013 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
1014 /*don't prompt for authentication when login frame is visible*/
1015 linphone_core_abort_authentication(lc,NULL);
1019 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
1021 gtk_label_set_markup(GTK_LABEL(label),msg);
1023 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
1024 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
1025 g_object_set_data(G_OBJECT(w),"auth_info",info);
1026 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
1028 auth_timeout_new(w);
1031 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
1032 GtkWidget *w=linphone_gtk_get_main_window();
1033 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
1035 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
1036 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
1040 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
1041 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
1044 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
1045 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
1048 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
1049 char richtext[4096];
1050 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
1051 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
1054 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1055 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1056 if (w) linphone_gtk_call_log_update(w);
1057 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1061 static bool_t notify_actions_supported() {
1062 bool_t accepts_actions = FALSE;
1063 GList *capabilities = notify_get_server_caps();
1065 if(capabilities != NULL) {
1066 for(c = capabilities; c != NULL; c = c->next) {
1067 if(strcmp((char*)c->data, "actions") == 0 ) {
1068 accepts_actions = TRUE;
1072 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1073 g_list_free(capabilities);
1075 return accepts_actions;
1078 static NotifyNotification* build_notification(const char *title, const char *body){
1079 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1086 static void show_notification(NotifyNotification* n){
1087 if (n && !notify_notification_show(n,NULL))
1088 ms_error("Failed to send notification.");
1091 static void make_notification(const char *title, const char *body){
1092 show_notification(build_notification(title,body));
1097 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1099 if (!notify_is_initted())
1100 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1105 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1111 ms_error("Failed to send notification.");
1113 linphone_gtk_show_main_window();
1115 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1118 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1119 NotifyNotification *n;
1120 switch(linphone_call_get_state(call)){
1121 case LinphoneCallError:
1122 make_notification(_("Call error"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>\n%s",msg,remote));
1124 case LinphoneCallEnd:
1125 make_notification(_("Call ended"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1127 case LinphoneCallIncomingReceived:
1128 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<span size=\"large\">%s</span>",remote));
1129 if (notify_actions_supported()) {
1130 notify_notification_add_action (n,"answer", _("Answer"),
1131 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1132 notify_notification_add_action (n,"decline",_("Decline"),
1133 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1135 show_notification(n);
1137 case LinphoneCallPausedByRemote:
1138 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<span size=\"large\">by %s</span>"),remote));
1143 if (body) g_free(body);
1144 if (remote) g_free(remote);
1149 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1150 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1151 LinphoneCore *lc=linphone_call_get_core(call);
1152 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1153 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1154 linphone_core_accept_call_update(lc,call,params);
1155 linphone_call_params_destroy(params);
1157 linphone_call_unref(call);
1158 g_source_remove_by_user_data(dialog);
1159 gtk_widget_destroy(dialog);
1162 static void on_call_updated_timeout(GtkWidget *dialog){
1163 gtk_widget_destroy(dialog);
1166 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1167 LinphoneCore *lc=linphone_call_get_core(call);
1168 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1169 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1170 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1171 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1172 gboolean video_used=linphone_call_params_video_enabled(current_params);
1173 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1174 video_used,video_requested,pol->automatically_accept);
1175 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1176 linphone_core_defer_call_update(lc,call);
1178 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1180 const char *dname=linphone_address_get_display_name(addr);
1181 if (dname==NULL) dname=linphone_address_get_username(addr);
1182 if (dname==NULL) dname=linphone_address_get_domain(addr);
1183 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1184 GTK_DIALOG_DESTROY_WITH_PARENT,
1185 GTK_MESSAGE_WARNING,
1187 _("%s proposed to start video. Do you accept ?"),dname);
1188 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1189 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1190 gtk_widget_show(dialog);
1195 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1197 case LinphoneCallOutgoingInit:
1198 linphone_gtk_create_in_call_view (call);
1200 case LinphoneCallOutgoingProgress:
1201 linphone_gtk_in_call_view_set_calling (call);
1203 case LinphoneCallStreamsRunning:
1204 linphone_gtk_in_call_view_set_in_call(call);
1206 case LinphoneCallUpdatedByRemote:
1207 linphone_gtk_call_updated_by_remote(call);
1209 case LinphoneCallError:
1210 linphone_gtk_in_call_view_terminate (call,msg);
1212 case LinphoneCallEnd:
1213 linphone_gtk_in_call_view_terminate(call,NULL);
1214 linphone_gtk_status_icon_set_blinking(FALSE);
1216 case LinphoneCallIncomingReceived:
1217 linphone_gtk_create_in_call_view(call);
1218 linphone_gtk_in_call_view_set_incoming(call);
1219 linphone_gtk_status_icon_set_blinking(TRUE);
1221 linphone_call_ref(call);
1222 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1225 case LinphoneCallResuming:
1226 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1227 linphone_gtk_in_call_view_set_in_call (call);
1229 case LinphoneCallPausing:
1230 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1231 update_tab_header(call,FALSE);
1232 case LinphoneCallPausedByRemote:
1233 linphone_gtk_in_call_view_set_paused(call);
1234 update_tab_header(call,TRUE);
1236 case LinphoneCallConnected:
1237 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1238 linphone_gtk_status_icon_set_blinking(FALSE);
1243 linphone_gtk_notify(call, msg);
1244 linphone_gtk_update_call_buttons (call);
1247 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1248 linphone_gtk_in_call_view_show_encryption(call);
1251 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1252 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1255 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1256 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1257 GtkTreeModel *model=gtk_combo_box_get_model(box);
1259 gboolean found=FALSE;
1260 const char *stock_id=NULL;
1262 if (gtk_tree_model_get_iter_first(model,&iter)){
1265 gtk_tree_model_get(model,&iter,2,&p,-1);
1270 }while(gtk_tree_model_iter_next(model,&iter));
1273 g_warning("Could not find proxy config in combo box of identities.");
1277 case LinphoneRegistrationOk:
1278 stock_id=GTK_STOCK_YES;
1280 case LinphoneRegistrationProgress:
1281 stock_id=GTK_STOCK_REFRESH;
1283 case LinphoneRegistrationCleared:
1286 case LinphoneRegistrationFailed:
1287 stock_id=GTK_STOCK_DIALOG_WARNING;
1292 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1295 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1296 LinphoneRegistrationState rs, const char *msg){
1298 case LinphoneRegistrationOk:
1300 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1301 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1302 linphone_gtk_exit_login_frame();
1309 update_registration_status(cfg,rs);
1312 void linphone_gtk_open_browser(const char *url){
1313 /*in gtk 2.16, gtk_show_uri does not work...*/
1315 #if GTK_CHECK_VERSION(2,18,3)
1316 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1319 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1320 g_spawn_command_line_async(cl,NULL);
1323 ShellExecute(0,"open",url,NULL,NULL,1);
1327 void linphone_gtk_link_to_website(GtkWidget *item){
1328 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1329 linphone_gtk_open_browser(home);
1332 #ifndef HAVE_GTK_OSX
1334 static GtkStatusIcon *icon=NULL;
1336 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1337 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1338 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1341 static GtkWidget *create_icon_menu(){
1342 GtkWidget *menu=gtk_menu_new();
1343 GtkWidget *menu_item;
1346 const gchar *homesite;
1348 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1349 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1350 tmp=g_strdup(homesite);
1351 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1352 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1354 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1355 gtk_widget_show(image);
1356 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1357 //g_object_unref(G_OBJECT(image));
1358 gtk_widget_show(menu_item);
1359 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1360 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1362 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1363 gtk_widget_show(menu_item);
1364 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1365 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1366 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1367 gtk_widget_show(menu_item);
1368 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1369 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1370 gtk_widget_show(menu);
1374 static void handle_icon_click() {
1375 GtkWidget *mw=linphone_gtk_get_main_window();
1376 if (!gtk_window_is_active((GtkWindow*)mw)) {
1377 linphone_gtk_show_main_window();
1379 gtk_widget_hide(mw);
1383 static void linphone_gtk_init_status_icon(){
1384 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1385 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1386 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1387 GtkWidget *menu=create_icon_menu();
1389 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1390 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1391 #if GTK_CHECK_VERSION(2,20,0)
1392 gtk_status_icon_set_name(icon,title);
1394 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1395 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1396 gtk_status_icon_set_tooltip(icon,title);
1397 gtk_status_icon_set_visible(icon,TRUE);
1398 g_object_set_data(G_OBJECT(icon),"menu",menu);
1399 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1400 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1401 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1402 pbuf=create_pixbuf(call_icon_path);
1403 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1406 static gboolean do_icon_blink(GtkStatusIcon *gi){
1407 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1408 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1409 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1410 if (cur_icon==call_icon){
1411 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1413 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1420 void linphone_gtk_status_icon_set_blinking(gboolean val){
1422 static gint attention_id;
1423 GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1425 attention_id=gtk_osxapplication_attention_request(theMacApp,CRITICAL_REQUEST);
1426 else gtk_osxapplication_cancel_attention_request(theMacApp,attention_id);
1430 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1431 if (val && tout==0){
1432 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1433 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1434 }else if (!val && tout!=0){
1435 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1436 g_source_remove(tout);
1437 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1438 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1444 void linphone_gtk_options_activate(GtkWidget *item){
1445 #ifndef HAVE_GTK_OSX
1446 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1451 static void init_identity_combo(GtkComboBox *box){
1452 GtkListStore *store;
1453 GtkCellRenderer *r1,*r2;
1454 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1455 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1456 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1457 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1458 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1459 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1460 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1461 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1464 void linphone_gtk_load_identities(void){
1466 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1468 LinphoneProxyConfig *def=NULL;
1470 GtkListStore *store;
1473 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1474 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1475 /* model is empty, this is the first time we go here */
1476 init_identity_combo(box);
1477 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1479 gtk_list_store_clear(store);
1480 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1481 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1482 gtk_list_store_append(store,&iter);
1483 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1484 g_free(def_identity);
1485 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1487 elem=ms_list_next(elem),i++){
1488 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1489 gtk_list_store_append(store,&iter);
1490 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1491 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1497 gtk_combo_box_set_active(box,def_index);
1500 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1501 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1502 GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
1504 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1505 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1506 if (linphone_core_in_call(linphone_gtk_get_core())){
1507 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1511 static void linphone_gtk_dtmf_released(GtkButton *button){
1512 linphone_core_stop_dtmf (linphone_gtk_get_core());
1516 static void linphone_gtk_connect_digits(GtkWidget *w){
1517 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
1518 GList *children=gtk_container_get_children(cont);
1520 for(elem=children;elem!=NULL;elem=elem->next){
1521 GtkButton *button=GTK_BUTTON(elem->data);
1522 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1523 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1527 static void linphone_gtk_check_menu_items(void){
1528 bool_t video_enabled=linphone_gtk_video_enabled();
1529 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1530 GtkWidget *selfview_item=linphone_gtk_get_widget(
1531 linphone_gtk_get_main_window(),"selfview_item");
1532 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1533 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1534 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1537 static gboolean linphone_gtk_can_manage_accounts(){
1538 LinphoneCore *lc=linphone_gtk_get_core();
1540 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1541 SipSetup *ss=(SipSetup*)elem->data;
1542 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1549 static void linphone_gtk_configure_main_window(){
1550 static gboolean config_loaded=FALSE;
1551 static const char *title;
1552 static const char *home;
1553 static const char *start_call_icon;
1554 static const char *add_call_icon;
1555 static const char *search_icon;
1556 static gboolean update_check_menu;
1557 static gboolean buttons_have_borders;
1558 static gboolean show_abcd;
1559 GtkWidget *w=linphone_gtk_get_main_window();
1560 GHashTable *contacts_history;
1562 contacts_history=g_hash_table_new_full(g_str_hash, g_str_equal,g_free, NULL);
1563 g_object_set_data(G_OBJECT(w),"history",(gpointer)contacts_history);
1565 if (!config_loaded){
1566 title=linphone_gtk_get_ui_config("title","Linphone");
1567 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1568 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1569 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1570 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1571 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1572 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1573 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1576 linphone_gtk_configure_window(w,"main_window");
1578 gtk_window_set_title(GTK_WINDOW(w),title);
1580 if (start_call_icon){
1581 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1582 create_pixmap (start_call_icon));
1583 if (!buttons_have_borders)
1584 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1587 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1588 create_pixmap (add_call_icon));
1589 if (!buttons_have_borders)
1590 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1593 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1595 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1596 g_object_unref(G_OBJECT(pbuf));
1601 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1603 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1607 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1609 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1610 g_object_unref(G_OBJECT(pbuf));
1615 GdkPixbuf *pbuf=create_pixbuf("dialer.png");
1617 GtkButton *button=GTK_BUTTON(linphone_gtk_get_widget(w,"keypad"));
1618 gtk_button_set_image(button,gtk_image_new_from_pixbuf (pbuf));
1621 if (linphone_gtk_can_manage_accounts()) {
1622 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1624 if (update_check_menu){
1625 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1627 g_object_set_data(G_OBJECT(w),"show_abcd",GINT_TO_POINTER(show_abcd));
1630 void linphone_gtk_manage_login(void){
1631 LinphoneCore *lc=linphone_gtk_get_core();
1632 LinphoneProxyConfig *cfg=NULL;
1633 linphone_core_get_default_proxy(lc,&cfg);
1635 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1636 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1637 linphone_gtk_show_login_frame(cfg);
1642 gboolean linphone_gtk_close(GtkWidget *mw){
1643 /*shutdown calls if any*/
1644 LinphoneCore *lc=linphone_gtk_get_core();
1645 if (linphone_core_in_call(lc)){
1646 linphone_core_terminate_all_calls(lc);
1648 linphone_core_enable_video_preview(lc,FALSE);
1649 #ifdef __APPLE__ /*until with have a better option*/
1650 gtk_window_iconify(GTK_WINDOW(mw));
1652 gtk_widget_hide(mw);
1658 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1659 bool_t video_enabled=linphone_gtk_video_enabled();
1660 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1661 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1663 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1664 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1670 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1671 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1672 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1674 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1675 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1676 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1677 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1678 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1679 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1680 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1681 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1682 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1683 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1684 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1685 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1686 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1687 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1688 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1689 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1692 void linphone_gtk_create_keypad(GtkWidget *button){
1693 GtkWidget *mw=linphone_gtk_get_main_window();
1694 GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad");
1696 gtk_widget_destroy(k);
1698 GtkWidget *keypad=linphone_gtk_create_window("keypad");
1699 linphone_gtk_connect_digits(keypad);
1700 linphone_gtk_init_dtmf_table(keypad);
1701 g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad);
1702 if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"show_abcd"))){
1703 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_A"));
1704 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_B"));
1705 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_C"));
1706 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_D"));
1707 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(keypad,"dtmf_table")),4,3);
1709 gtk_widget_show(keypad);
1712 static void linphone_gtk_init_main_window(){
1713 GtkWidget *main_window;
1714 linphone_gtk_configure_main_window();
1715 linphone_gtk_manage_login();
1717 linphone_gtk_load_identities();
1718 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1719 linphone_gtk_show_friends();
1720 main_window=linphone_gtk_get_main_window();
1721 linphone_gtk_call_log_update(main_window);
1723 linphone_gtk_update_call_buttons (NULL);
1724 g_object_set_data(G_OBJECT(main_window),"keypad",NULL);
1725 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1726 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1727 g_signal_connect (G_OBJECT (main_window), "delete-event",
1728 G_CALLBACK (linphone_gtk_close), main_window);
1731 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1732 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1733 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1734 gtk_widget_hide(menubar);
1735 gtk_osxapplication_ready(theMacApp);
1737 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1739 linphone_gtk_check_menu_items();
1743 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1745 const char *lname="undef";
1747 #if defined(__linux) || defined(__APPLE__)
1748 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1767 g_error("Bad level !");
1769 #if defined(__linux) || defined(__APPLE__)
1771 msg=g_strdup_vprintf(fmt,cap);
1774 msg=g_strdup_vprintf(fmt,args);
1776 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1779 linphone_gtk_log_push(lev,fmt,args);
1783 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1784 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1785 linphone_gtk_get_main_window(), "uribar"));
1787 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1789 gtk_entry_set_text(uri_bar, refer_to);
1790 linphone_gtk_start_call(linphone_gtk_get_main_window());
1793 static void linphone_gtk_check_soundcards(){
1794 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1795 if (devices==NULL || devices[0]==NULL){
1796 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1797 _("No sound cards have been detected on this computer.\n"
1798 "You won't be able to send or receive audio calls."));
1802 static void linphone_gtk_quit(void){
1803 static gboolean quit_done=FALSE;
1806 linphone_gtk_unmonitor_usb();
1807 g_source_remove_by_user_data(linphone_gtk_get_core());
1809 linphone_gtk_close_assistant();
1811 linphone_gtk_uninit_instance();
1812 linphone_gtk_destroy_log_window();
1813 linphone_core_destroy(the_core);
1814 linphone_gtk_log_uninit();
1818 gdk_threads_leave();
1824 This is not the correct way to implement block termination.
1825 The good way would be to call gtk_main_quit(), and return TRUE.
1826 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1827 As a result the program cannot exit at all.
1828 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1830 static gboolean on_block_termination(void){
1832 linphone_gtk_quit();
1837 int main(int argc, char *argv[]){
1842 const char *factory_config_file;
1844 GtkSettings *settings;
1846 const char *app_name="Linphone";
1849 #if !GLIB_CHECK_VERSION(2, 31, 0)
1850 g_thread_init(NULL);
1854 progpath = strdup(argv[0]);
1856 config_file=linphone_gtk_get_config_file(NULL);
1860 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1861 if ((lang=getenv("LANG"))!=NULL){
1864 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1870 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1873 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1876 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1878 if (strncmp(lang,"zh",2)==0){
1879 workaround_gtk_entry_chinese_bug=TRUE;
1882 setenv("LANG",lang,1);
1884 setenv("LANGUAGE",lang,1);
1889 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1890 if (p==NULL) perror("bindtextdomain failed");
1891 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1892 textdomain (GETTEXT_PACKAGE);
1894 g_message("NLS disabled.\n");
1897 gtk_rc_add_default_file("./gtkrc");
1899 gdk_threads_enter();
1901 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1902 linphone_options,NULL,NULL)){
1903 gdk_threads_leave();
1907 settings=gtk_settings_get_default();
1908 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1909 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1910 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1911 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1913 if (workingdir!=NULL){
1914 if (chdir(workingdir)==-1){
1915 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1919 /* Now, look for the factory configuration file, we do it this late
1920 since we want to have had time to change directory and to parse
1921 the options, in case we needed to access the working directory */
1922 factory_config_file = linphone_gtk_get_factory_config_file();
1923 if (factory_config_file){
1924 factory=lp_config_new(NULL);
1925 lp_config_read_file(factory,factory_config_file);
1926 app_name=lp_config_get_string(factory,"GtkUi","title","Linphone");
1929 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1930 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1931 g_warning("This instance is going to exit now.");
1932 gdk_threads_leave();
1936 add_pixmap_directory("pixmaps");
1937 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1940 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1941 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1942 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1943 /*never block termination:*/
1944 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1947 the_ui=linphone_gtk_create_window("main");
1949 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1951 linphone_gtk_create_log_window();
1952 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1954 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1956 g_set_application_name(app_name);
1957 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1958 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1960 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1961 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1962 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1963 linphone_gtk_init_main_window();
1966 // Veryfing if at least one sip account is configured. If not, show wizard
1967 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1968 linphone_gtk_show_assistant();
1972 #ifndef HAVE_GTK_OSX
1973 linphone_gtk_init_status_icon();
1976 linphone_gtk_show_main_window();
1977 linphone_gtk_check_soundcards();
1979 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1980 linphone_gtk_check_for_new_version();
1981 linphone_gtk_monitor_usb();
1984 linphone_gtk_quit();
1985 #ifndef HAVE_GTK_OSX
1986 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1987 gtk_status_icon_set_visible(icon,FALSE);