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 void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data);
67 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
68 void linphone_gtk_status_icon_set_blinking(gboolean val);
69 void _linphone_gtk_enable_video(gboolean val);
73 static gint main_window_x=0;
74 static gint main_window_y=0;
75 static gboolean verbose=0;
76 static gboolean auto_answer = 0;
77 static gchar * addr_to_call = NULL;
78 static gboolean no_video=FALSE;
79 static gboolean iconified=FALSE;
80 static gchar *workingdir=NULL;
81 static char *progpath=NULL;
82 gchar *linphone_logfile=NULL;
83 static gboolean workaround_gtk_entry_chinese_bug=FALSE;
85 static GOptionEntry linphone_options[]={
89 .arg=G_OPTION_ARG_NONE,
90 .arg_data= (gpointer)&verbose,
91 .description=N_("log to stdout some debug information while running.")
94 .long_name = "logfile",
96 .arg = G_OPTION_ARG_STRING,
97 .arg_data = &linphone_logfile,
98 .description = N_("path to a file to write logs into.")
101 .long_name = "no-video",
103 .arg = G_OPTION_ARG_NONE,
104 .arg_data = (gpointer)&no_video,
105 .description = N_("Start linphone with video disabled.")
108 .long_name="iconified",
110 .arg=G_OPTION_ARG_NONE,
111 .arg_data= (gpointer)&iconified,
112 .description=N_("Start only in the system tray, do not show the main interface.")
117 .arg = G_OPTION_ARG_STRING,
118 .arg_data = &addr_to_call,
119 .description = N_("address to call right now")
122 .long_name = "auto-answer",
124 .arg = G_OPTION_ARG_NONE,
125 .arg_data = (gpointer) & auto_answer,
126 .description = N_("if set automatically answer incoming calls")
129 .long_name = "workdir",
131 .arg = G_OPTION_ARG_STRING,
132 .arg_data = (gpointer) & workingdir,
133 .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
138 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
139 #define RELATIVE_XML_DIR
140 #define BUILD_TREE_XML_DIR "gtk"
143 #define CONFIG_FILE ".linphonerc"
144 #define SECRETS_FILE ".linphone-zidcache"
146 #define CONFIG_FILE "linphonerc"
147 #define SECRETS_FILE "linphone-zidcache"
150 char *linphone_gtk_get_config_file(const char *filename){
151 const int path_max=1024;
152 char *config_file=g_malloc0(path_max);
153 if (filename==NULL) filename=CONFIG_FILE;
154 /*try accessing a local file first if exists*/
155 if (access(CONFIG_FILE,F_OK)==0){
156 snprintf(config_file,path_max,"%s",filename);
159 const char *appdata=getenv("APPDATA");
161 snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
162 CreateDirectory(config_file,NULL);
163 snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename);
166 const char *home=getenv("HOME");
167 if (home==NULL) home=".";
168 snprintf(config_file,path_max,"%s/%s",home,filename);
174 #define FACTORY_CONFIG_FILE "linphonerc.factory"
175 static char _factory_config_file[1024];
176 static const char *linphone_gtk_get_factory_config_file(){
177 /*try accessing a local file first if exists*/
178 if (access(FACTORY_CONFIG_FILE,F_OK)==0){
179 snprintf(_factory_config_file,sizeof(_factory_config_file),
180 "%s",FACTORY_CONFIG_FILE);
184 if (progpath != NULL) {
186 progdir = strdup(progpath);
188 basename = strrchr(progdir, '\\');
189 if (basename != NULL) {
192 snprintf(_factory_config_file, sizeof(_factory_config_file),
193 "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
195 if (workingdir!=NULL) {
196 snprintf(_factory_config_file, sizeof(_factory_config_file),
197 "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
204 basename = strrchr(progdir, '/');
205 if (basename != NULL) {
208 snprintf(_factory_config_file, sizeof(_factory_config_file),
209 "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
218 return _factory_config_file;
221 static void linphone_gtk_init_liblinphone(const char *config_file,
222 const char *factory_config_file, const char *db_file) {
223 LinphoneCoreVTable vtable={0};
224 gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
226 vtable.call_state_changed=linphone_gtk_call_state_changed;
227 vtable.registration_state_changed=linphone_gtk_registration_state_changed;
228 vtable.notify_presence_recv=linphone_gtk_notify_recv;
229 vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
230 vtable.auth_info_requested=linphone_gtk_auth_info_requested;
231 vtable.display_status=linphone_gtk_display_status;
232 vtable.display_message=linphone_gtk_display_message;
233 vtable.display_warning=linphone_gtk_display_warning;
234 vtable.display_url=linphone_gtk_display_url;
235 vtable.call_log_updated=linphone_gtk_call_log_updated;
236 //vtable.text_received=linphone_gtk_text_received;
237 vtable.message_received=linphone_gtk_text_received;
238 vtable.refer_received=linphone_gtk_refer_received;
239 vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
240 vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
241 vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
243 the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
244 //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
245 linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
246 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
247 linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
248 g_free(secrets_file);
249 linphone_core_enable_video(the_core,TRUE,TRUE);
251 _linphone_gtk_enable_video(FALSE);
252 linphone_gtk_set_ui_config_int("videoselfview",0);
254 if (db_file) linphone_core_set_chat_database_path(the_core,db_file);
257 LinphoneCore *linphone_gtk_get_core(void){
261 GtkWidget *linphone_gtk_get_main_window(){
265 void linphone_gtk_destroy_main_window() {
266 linphone_gtk_destroy_window(the_ui);
270 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
271 static const char *icon_path=NULL;
272 static const char *hiddens=NULL;
273 static const char *shown=NULL;
274 static bool_t config_loaded=FALSE;
275 if (linphone_gtk_get_core()==NULL) return;
276 if (config_loaded==FALSE){
277 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
278 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
279 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
283 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
285 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
287 GdkPixbuf *pbuf=create_pixbuf(icon_path);
289 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
290 g_object_unref(G_OBJECT(pbuf));
295 static int get_ui_file(const char *name, char *path, int pathsize){
296 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
297 if (access(path,F_OK)!=0){
298 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
299 if (access(path,F_OK)!=0){
300 g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,
301 INSTALLED_XML_DIR,name);
308 void linphone_gtk_destroy_window(GtkWidget *widget) {
309 GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder");
310 gtk_widget_destroy(widget);
311 g_object_unref (G_OBJECT (builder));
314 GtkWidget *linphone_gtk_create_window(const char *window_name){
315 GError* error = NULL;
316 GtkBuilder* builder = gtk_builder_new ();
320 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
322 if (!gtk_builder_add_from_file (builder, path, &error)){
323 g_error("Couldn't load builder file: %s", error->message);
324 g_error_free (error);
327 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
329 g_error("Could not retrieve '%s' window from xml file",window_name);
332 g_object_set_data(G_OBJECT(w), "builder",builder);
333 gtk_builder_connect_signals(builder,w);
334 linphone_gtk_configure_window(w,window_name);
338 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
341 GtkBuilder* builder = gtk_builder_new ();
343 gchar *object_ids[2];
344 object_ids[0]=g_strdup(widget_name);
347 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
348 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
349 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
350 g_error_free (error);
351 g_free(object_ids[0]);
354 g_free(object_ids[0]);
355 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
357 g_error("Could not retrieve '%s' window from xml file",widget_name);
360 g_object_set_data(G_OBJECT(w),"builder",builder);
361 g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
362 gtk_builder_connect_signals(builder,w);
366 static void entry_unmapped(GtkWidget *entry){
367 g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
368 gtk_widget_unrealize(entry);
371 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
374 if (window==NULL) return NULL;
375 builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
377 g_error("Fail to retrieve builder from window !");
380 w=gtk_builder_get_object(builder,name);
382 g_error("No widget named %s found in xml interface.",name);
384 if (workaround_gtk_entry_chinese_bug){
385 if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
386 if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
387 g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
388 g_message("%s is a GtkEntry",name);
389 g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
393 return GTK_WIDGET(w);
397 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
399 GtkWidget *main_window=linphone_gtk_get_main_window();
401 gtk_widget_show(main_window);
402 if (type==GTK_MESSAGE_QUESTION)
404 /* draw a question box. link to dialog_click callback */
405 dialog = gtk_message_dialog_new (
406 GTK_WINDOW(main_window),
407 GTK_DIALOG_DESTROY_WITH_PARENT,
408 GTK_MESSAGE_QUESTION,
411 (const gchar*)message);
412 /* connect to some callback : REVISIT */
414 g_signal_connect_swapped (G_OBJECT (dialog), "response",
415 G_CALLBACK (dialog_click),
418 /* actually show the box */
419 gtk_widget_show(dialog);
423 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
424 GTK_DIALOG_DESTROY_WITH_PARENT,
428 (const gchar*)message);
429 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
430 g_signal_connect_swapped (G_OBJECT (dialog), "response",
431 G_CALLBACK (gtk_widget_destroy),
433 gtk_widget_show(dialog);
437 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
438 if (id==GTK_RESPONSE_CANCEL){
439 gtk_widget_destroy(GTK_WIDGET(dialog));
443 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
444 g_message("About url clicked");
445 linphone_gtk_open_browser(url);
448 void linphone_gtk_show_about(){
449 struct stat filestat;
450 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
453 GdkPixbuf *logo=create_pixbuf(
454 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
455 static const char *defcfg="defcfg";
457 about=linphone_gtk_create_window("about");
458 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
459 memset(&filestat,0,sizeof(filestat));
460 if (stat(license_file,&filestat)!=0){
461 license_file="COPYING";
462 stat(license_file,&filestat);
464 if (filestat.st_size>0){
465 char *license=g_malloc(filestat.st_size+1);
466 FILE *f=fopen(license_file,"r");
467 if (f && fread(license,filestat.st_size,1,f)==1){
468 license[filestat.st_size]='\0';
469 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
473 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
474 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
475 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
476 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
477 tmp=linphone_gtk_get_ui_config("artists",defcfg);
482 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
484 tmp=linphone_gtk_get_ui_config("translators",defcfg);
486 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
487 tmp=linphone_gtk_get_ui_config("comments",defcfg);
489 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
490 gtk_widget_show(about);
493 static void set_video_window_decorations(GdkWindow *w){
494 const char *title=linphone_gtk_get_ui_config("title","Linphone");
495 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
496 char video_title[256];
497 GdkPixbuf *pbuf=create_pixbuf(icon_path);
499 if (!linphone_core_in_call(linphone_gtk_get_core())){
500 snprintf(video_title,sizeof(video_title),"%s video",title);
501 /* When not in call, treat the video as a normal window */
502 gdk_window_set_keep_above(w, FALSE);
504 LinphoneAddress *uri =
505 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
508 linphone_address_clean(uri);
509 if (linphone_address_get_display_name(uri)!=NULL){
510 display_name=ms_strdup(linphone_address_get_display_name(uri));
512 display_name=linphone_address_as_string(uri);
514 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
515 linphone_address_destroy(uri);
516 ms_free(display_name);
518 /* During calls, bring up the video window, arrange so that
519 it is above all the other windows */
520 gdk_window_deiconify(w);
521 gdk_window_set_keep_above(w,TRUE);
522 /* Maybe we should have the following, but then we want to
523 have a timer that turns it off after a little while. */
524 /* gdk_window_set_urgency_hint(w,TRUE); */
526 gdk_window_set_title(w,video_title);
527 /* Refrain the video window to be closed at all times. */
528 gdk_window_set_functions(w,
529 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
530 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
533 l=g_list_append(l,pbuf);
534 gdk_window_set_icon_list(w,l);
536 g_object_unref(G_OBJECT(pbuf));
540 static gboolean video_needs_update=FALSE;
542 static void update_video_title(){
543 video_needs_update=TRUE;
546 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
547 static gboolean first_time=TRUE;
549 static unsigned long previd=0;
550 static unsigned long preview_previd=0;
551 static gboolean in_iterate=FALSE;
554 if (in_iterate) return TRUE;
556 linphone_core_iterate(lc);
558 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
559 linphone_gtk_show_directory_search();
563 id=linphone_core_get_native_video_window_id(lc);
564 if (id!=previd || video_needs_update){
568 ms_message("Updating window decorations");
570 w=gdk_window_foreign_new(id);
572 w=gdk_window_foreign_new((HANDLE)id);
575 set_video_window_decorations(w);
576 g_object_unref(G_OBJECT(w));
578 else ms_error("gdk_window_foreign_new() failed");
579 if (video_needs_update) video_needs_update=FALSE;
582 id=linphone_core_get_native_preview_window_id (lc);
583 if (id!=preview_previd ){
587 ms_message("Updating window decorations for preview");
589 w=gdk_window_foreign_new(id);
591 w=gdk_window_foreign_new((HANDLE)id);
594 set_video_window_decorations(w);
595 g_object_unref(G_OBJECT(w));
597 else ms_error("gdk_window_foreign_new() failed");
598 if (video_needs_update) video_needs_update=FALSE;
601 if (addr_to_call!=NULL){
602 /*make sure we are not showing the login screen*/
603 GtkWidget *mw=linphone_gtk_get_main_window();
604 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
605 if (!GTK_WIDGET_VISIBLE(login_frame)){
606 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
607 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
609 linphone_gtk_start_call(uri_bar);
616 static void load_uri_history(){
617 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
620 GtkEntryCompletion *gep=gtk_entry_completion_new();
621 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
624 snprintf(key,sizeof(key),"uri%i",i);
625 uri=linphone_gtk_get_ui_config(key,NULL);
628 gtk_list_store_append(model,&iter);
629 gtk_list_store_set(model,&iter,0,uri,-1);
630 if (i==0) gtk_entry_set_text(uribar,uri);
634 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
635 gtk_entry_completion_set_text_column(gep,0);
636 gtk_entry_set_completion(uribar,gep);
639 static void save_uri_history(){
640 LinphoneCore *lc=linphone_gtk_get_core();
641 LpConfig *cfg=linphone_core_get_config(lc);
642 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
647 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
649 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
651 gtk_tree_model_get(model,&iter,0,&uri,-1);
653 snprintf(key,sizeof(key),"uri%i",i);
654 lp_config_set_string(cfg,"GtkUi",key,uri);
659 }while(gtk_tree_model_iter_next(model,&iter));
663 static void completion_add_text(GtkEntry *entry, const char *text){
665 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
667 if (gtk_tree_model_get_iter_first(model,&iter)){
670 gtk_tree_model_get(model,&iter,0,&uri,-1);
672 if (strcmp(uri,text)==0) {
674 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
680 }while (gtk_tree_model_iter_next(model,&iter));
682 /* and prepend it on top of the list */
683 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
684 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
688 bool_t linphone_gtk_video_enabled(void){
689 const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
690 return vpol->automatically_accept && vpol->automatically_initiate;
693 void linphone_gtk_show_main_window(){
694 GtkWidget *w=linphone_gtk_get_main_window();
695 LinphoneCore *lc=linphone_gtk_get_core();
696 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
697 VIDEOSELFVIEW_DEFAULT));
699 gtk_window_present(GTK_WINDOW(w));
702 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
703 GtkWidget *mw=linphone_gtk_get_main_window();
704 if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
705 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
707 if (linphone_gtk_use_in_call_view() && call)
708 linphone_gtk_in_call_view_terminate(call,error);
709 update_video_title();
712 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
713 LinphoneCore *lc=linphone_gtk_get_core();
714 GtkWidget *mw=linphone_gtk_get_main_window();
715 const MSList *calls=linphone_core_get_calls(lc);
717 bool_t start_active=TRUE;
718 //bool_t stop_active=FALSE;
719 bool_t add_call=FALSE;
720 int call_list_size=ms_list_size(calls);
730 button=linphone_gtk_get_widget(mw,"start_call");
731 gtk_widget_set_sensitive(button,start_active);
732 gtk_widget_set_visible(button,!add_call);
734 button=linphone_gtk_get_widget(mw,"add_call");
735 if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
736 gtk_widget_set_sensitive(button,FALSE);
738 gtk_widget_set_sensitive(button,start_active);
740 gtk_widget_set_visible(button,add_call);
742 //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
743 GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
744 if(conf_frame==NULL){
745 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
746 linphone_gtk_enable_conference_button(lc,call_list_size>1);
748 linphone_gtk_enable_transfer_button(lc,FALSE);
749 linphone_gtk_enable_conference_button(lc,FALSE);
751 update_video_title();
753 linphone_gtk_update_video_button(call);
757 gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference){
758 const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
759 const char *id="unknown";
760 char filename[256]={0};
762 time_t curtime=time(NULL);
766 loctime=*localtime(&curtime);
768 localtime_r(&curtime,&loctime);
770 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);
773 id=linphone_address_get_username(address);
774 if (id==NULL) id=linphone_address_get_domain(address);
777 snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav",
778 linphone_gtk_get_ui_config("title","Linphone"),
781 snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav",
782 linphone_gtk_get_ui_config("title","Linphone"),
786 return g_build_filename(dir,filename,NULL);
789 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
790 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
791 LinphoneCore *lc=linphone_gtk_get_core();
792 LinphoneAddress *addr=linphone_core_interpret_url(lc,entered);
795 LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
796 gchar *record_file=linphone_gtk_get_record_path(addr,FALSE);
797 linphone_call_params_set_record_file(params,record_file);
798 linphone_core_invite_address_with_params(lc,addr,params);
799 completion_add_text(GTK_ENTRY(uri_bar),entered);
800 linphone_address_destroy(addr);
801 linphone_call_params_destroy(params);
804 linphone_gtk_call_terminated(NULL,NULL);
810 static void accept_incoming_call(LinphoneCall *call){
811 LinphoneCore *lc=linphone_gtk_get_core();
812 LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
813 gchar *record_file=linphone_gtk_get_record_path(linphone_call_get_remote_address(call),FALSE);
814 linphone_call_params_set_record_file(params,record_file);
815 linphone_core_accept_call_with_params(lc,call,params);
816 linphone_call_params_destroy(params);
819 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
820 LinphoneCallState state=linphone_call_get_state(call);
821 if (state==LinphoneCallIncomingReceived || state==LinphoneCallIncomingEarlyMedia){
822 accept_incoming_call(call);
827 void linphone_gtk_start_call(GtkWidget *w){
828 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
829 /*change into in-call mode, then do the work later as it might block a bit */
830 GtkWidget *mw=gtk_widget_get_toplevel(w);
831 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
832 LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle;
834 if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){
835 accept_incoming_call(call);
837 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
838 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
839 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
840 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
845 void linphone_gtk_uri_bar_activate(GtkWidget *w){
846 linphone_gtk_start_call(w);
849 void linphone_gtk_terminate_call(GtkWidget *button){
851 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
853 linphone_core_terminate_call(linphone_gtk_get_core(),call);
855 linphone_core_terminate_conference(linphone_gtk_get_core());
859 void linphone_gtk_decline_clicked(GtkWidget *button){
860 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
862 linphone_core_terminate_call(linphone_gtk_get_core(),call);
865 void linphone_gtk_answer_clicked(GtkWidget *button){
866 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
868 accept_incoming_call(call);
869 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
873 void _linphone_gtk_enable_video(gboolean val){
874 LinphoneVideoPolicy policy={0};
875 policy.automatically_initiate=policy.automatically_accept=val;
876 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
877 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
880 linphone_core_enable_video_preview(linphone_gtk_get_core(),
881 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
883 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
887 void linphone_gtk_enable_video(GtkWidget *w){
888 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
889 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
890 _linphone_gtk_enable_video(val);
893 void linphone_gtk_enable_self_view(GtkWidget *w){
894 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
895 LinphoneCore *lc=linphone_gtk_get_core();
896 linphone_core_enable_video_preview(lc,val);
897 linphone_core_enable_self_view(lc,val);
898 linphone_gtk_set_ui_config_int("videoselfview",val);
901 void linphone_gtk_used_identity_changed(GtkWidget *w){
902 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
903 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
904 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
905 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
906 linphone_gtk_show_directory_search();
908 if (sel) g_free(sel);
911 void on_proxy_refresh_button_clicked(GtkWidget *w){
912 LinphoneCore *lc=linphone_gtk_get_core();
913 MSList const *item=linphone_core_get_proxy_config_list(lc);
914 while (item != NULL) {
915 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
916 linphone_proxy_config_edit(lpc);
917 linphone_proxy_config_done(lpc);
922 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
923 linphone_gtk_show_friends();
926 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
928 case GTK_RESPONSE_YES:
929 linphone_gtk_show_contact(lf);
932 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
934 gtk_widget_destroy(dialog);
937 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
940 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
941 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
945 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);
946 dialog = gtk_message_dialog_new (
947 GTK_WINDOW(linphone_gtk_get_main_window()),
948 GTK_DIALOG_DESTROY_WITH_PARENT,
949 GTK_MESSAGE_QUESTION,
954 g_signal_connect(G_OBJECT (dialog), "response",
955 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
956 /* actually show the box */
957 gtk_widget_show(dialog);
960 typedef struct _AuthTimeout{
964 static void auth_timeout_clean(AuthTimeout *tout){
968 static gboolean auth_timeout_destroy(AuthTimeout *tout){
970 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
971 gtk_widget_destroy(tout->w);
977 static AuthTimeout * auth_timeout_new(GtkWidget *w){
978 AuthTimeout *tout=g_new(AuthTimeout,1);
980 /*so that the timeout no more references the widget when it is destroyed:*/
981 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
982 /*so that the widget is automatically destroyed after some time */
983 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
987 void linphone_gtk_password_cancel(GtkWidget *w){
988 LinphoneAuthInfo *info;
989 GtkWidget *window=gtk_widget_get_toplevel(w);
990 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
991 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
992 gtk_widget_destroy(window);
995 void linphone_gtk_password_ok(GtkWidget *w){
997 GtkWidget *window=gtk_widget_get_toplevel(w);
998 LinphoneAuthInfo *info;
999 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
1000 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
1001 entry=linphone_gtk_get_widget(window,"password_entry");
1002 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
1003 linphone_auth_info_set_userid(info,
1004 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
1005 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
1006 gtk_widget_destroy(window);
1009 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
1010 GtkWidget *w=linphone_gtk_create_window("password");
1011 GtkWidget *label=linphone_gtk_get_widget(w,"message");
1012 LinphoneAuthInfo *info;
1014 GtkWidget *mw=linphone_gtk_get_main_window();
1016 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
1017 /*don't prompt for authentication when login frame is visible*/
1018 linphone_core_abort_authentication(lc,NULL);
1022 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
1024 gtk_label_set_markup(GTK_LABEL(label),msg);
1026 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
1027 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
1028 g_object_set_data(G_OBJECT(w),"auth_info",info);
1029 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
1031 auth_timeout_new(w);
1034 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
1035 GtkWidget *w=linphone_gtk_get_main_window();
1036 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
1038 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
1039 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
1043 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
1044 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
1047 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
1048 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
1051 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
1052 char richtext[4096];
1053 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
1054 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
1057 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1058 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1059 if (w) linphone_gtk_call_log_update(w);
1060 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1064 static bool_t notify_actions_supported() {
1065 bool_t accepts_actions = FALSE;
1066 GList *capabilities = notify_get_server_caps();
1068 if(capabilities != NULL) {
1069 for(c = capabilities; c != NULL; c = c->next) {
1070 if(strcmp((char*)c->data, "actions") == 0 ) {
1071 accepts_actions = TRUE;
1075 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1076 g_list_free(capabilities);
1078 return accepts_actions;
1081 static NotifyNotification* build_notification(const char *title, const char *body){
1082 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1089 static void show_notification(NotifyNotification* n){
1090 if (n && !notify_notification_show(n,NULL))
1091 ms_error("Failed to send notification.");
1094 static void make_notification(const char *title, const char *body){
1095 show_notification(build_notification(title,body));
1100 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1102 if (!notify_is_initted())
1103 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1108 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1114 ms_error("Failed to send notification.");
1116 linphone_gtk_show_main_window();
1118 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1121 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1122 NotifyNotification *n;
1123 switch(linphone_call_get_state(call)){
1124 case LinphoneCallError:
1125 make_notification(_("Call error"),body=g_markup_printf_escaped("<b>%s</b>\n%s",msg,remote));
1127 case LinphoneCallEnd:
1128 make_notification(_("Call ended"),body=g_markup_printf_escaped("<b>%s</b>",remote));
1130 case LinphoneCallIncomingReceived:
1131 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<b>%s</b>",remote));
1132 if (notify_actions_supported()) {
1133 notify_notification_add_action (n,"answer", _("Answer"),
1134 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1135 notify_notification_add_action (n,"decline",_("Decline"),
1136 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1138 show_notification(n);
1140 case LinphoneCallPausedByRemote:
1141 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<b>by %s</b>"),remote));
1146 if (body) g_free(body);
1147 if (remote) g_free(remote);
1152 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1153 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1154 LinphoneCore *lc=linphone_call_get_core(call);
1155 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1156 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1157 linphone_core_accept_call_update(lc,call,params);
1158 linphone_call_params_destroy(params);
1160 linphone_call_unref(call);
1161 g_source_remove_by_user_data(dialog);
1162 gtk_widget_destroy(dialog);
1165 static void on_call_updated_timeout(GtkWidget *dialog){
1166 gtk_widget_destroy(dialog);
1169 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1170 LinphoneCore *lc=linphone_call_get_core(call);
1171 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1172 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1173 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1174 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1175 gboolean video_used=linphone_call_params_video_enabled(current_params);
1176 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1177 video_used,video_requested,pol->automatically_accept);
1178 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1179 linphone_core_defer_call_update(lc,call);
1181 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1183 const char *dname=linphone_address_get_display_name(addr);
1184 if (dname==NULL) dname=linphone_address_get_username(addr);
1185 if (dname==NULL) dname=linphone_address_get_domain(addr);
1186 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1187 GTK_DIALOG_DESTROY_WITH_PARENT,
1188 GTK_MESSAGE_WARNING,
1190 _("%s proposed to start video. Do you accept ?"),dname);
1191 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1192 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1193 gtk_widget_show(dialog);
1198 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1200 case LinphoneCallOutgoingInit:
1201 linphone_gtk_create_in_call_view (call);
1203 case LinphoneCallOutgoingProgress:
1204 linphone_gtk_in_call_view_set_calling (call);
1206 case LinphoneCallStreamsRunning:
1207 linphone_gtk_in_call_view_set_in_call(call);
1209 case LinphoneCallUpdatedByRemote:
1210 linphone_gtk_call_updated_by_remote(call);
1212 case LinphoneCallError:
1213 linphone_gtk_in_call_view_terminate (call,msg);
1215 case LinphoneCallEnd:
1216 linphone_gtk_in_call_view_terminate(call,NULL);
1217 linphone_gtk_status_icon_set_blinking(FALSE);
1219 case LinphoneCallIncomingReceived:
1220 linphone_gtk_create_in_call_view(call);
1221 linphone_gtk_in_call_view_set_incoming(call);
1222 linphone_gtk_status_icon_set_blinking(TRUE);
1224 linphone_call_ref(call);
1225 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1228 case LinphoneCallResuming:
1229 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1230 linphone_gtk_in_call_view_set_in_call (call);
1232 case LinphoneCallPausing:
1233 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1234 update_tab_header(call,FALSE);
1235 case LinphoneCallPausedByRemote:
1236 linphone_gtk_in_call_view_set_paused(call);
1237 update_tab_header(call,TRUE);
1239 case LinphoneCallConnected:
1240 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1241 linphone_gtk_status_icon_set_blinking(FALSE);
1246 linphone_gtk_notify(call, msg);
1247 linphone_gtk_update_call_buttons (call);
1250 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1251 linphone_gtk_in_call_view_show_encryption(call);
1254 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1255 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1258 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1259 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1260 GtkTreeModel *model=gtk_combo_box_get_model(box);
1262 gboolean found=FALSE;
1263 const char *stock_id=NULL;
1265 if (gtk_tree_model_get_iter_first(model,&iter)){
1268 gtk_tree_model_get(model,&iter,2,&p,-1);
1273 }while(gtk_tree_model_iter_next(model,&iter));
1276 g_warning("Could not find proxy config in combo box of identities.");
1280 case LinphoneRegistrationOk:
1281 stock_id=GTK_STOCK_YES;
1283 case LinphoneRegistrationProgress:
1284 stock_id=GTK_STOCK_REFRESH;
1286 case LinphoneRegistrationCleared:
1289 case LinphoneRegistrationFailed:
1290 stock_id=GTK_STOCK_DIALOG_WARNING;
1295 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1298 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1299 LinphoneRegistrationState rs, const char *msg){
1301 case LinphoneRegistrationOk:
1303 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1304 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1305 linphone_gtk_exit_login_frame();
1312 update_registration_status(cfg,rs);
1315 void linphone_gtk_open_browser(const char *url){
1316 /*in gtk 2.16, gtk_show_uri does not work...*/
1318 #if GTK_CHECK_VERSION(2,18,3)
1319 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1322 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1323 g_spawn_command_line_async(cl,NULL);
1326 ShellExecute(0,"open",url,NULL,NULL,1);
1330 void linphone_gtk_link_to_website(GtkWidget *item){
1331 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1332 linphone_gtk_open_browser(home);
1335 #ifndef HAVE_GTK_OSX
1337 static GtkStatusIcon *icon=NULL;
1339 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1340 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1341 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1344 static GtkWidget *create_icon_menu(){
1345 GtkWidget *menu=gtk_menu_new();
1346 GtkWidget *menu_item;
1349 const gchar *homesite;
1351 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1352 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1353 tmp=g_strdup(homesite);
1354 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1355 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1357 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1358 gtk_widget_show(image);
1359 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1360 //g_object_unref(G_OBJECT(image));
1361 gtk_widget_show(menu_item);
1362 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1363 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1365 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,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)linphone_gtk_show_about,NULL);
1369 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1370 gtk_widget_show(menu_item);
1371 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1372 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1373 gtk_widget_show(menu);
1377 void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data){
1378 gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y);
1381 static void handle_icon_click() {
1382 GtkWidget *mw=linphone_gtk_get_main_window();
1383 if (!gtk_window_is_active((GtkWindow*)mw)) {
1384 if(!gtk_widget_is_drawable(mw)){
1385 //we only move if window was hidden. If it was simply behind the window stack, ie, drawable, we keep it as it was
1386 gtk_window_move (GTK_WINDOW(mw), main_window_x, main_window_y);
1388 linphone_gtk_show_main_window();
1390 linphone_gtk_save_main_window_position((GtkWindow*)mw, NULL, NULL);
1391 gtk_widget_hide(mw);
1395 static void linphone_gtk_init_status_icon(){
1396 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1397 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1398 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1399 GtkWidget *menu=create_icon_menu();
1401 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1402 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1403 #if GTK_CHECK_VERSION(2,20,0)
1404 gtk_status_icon_set_name(icon,title);
1406 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1407 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1408 gtk_status_icon_set_tooltip(icon,title);
1409 gtk_status_icon_set_visible(icon,TRUE);
1410 g_object_set_data(G_OBJECT(icon),"menu",menu);
1411 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1412 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1413 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1414 pbuf=create_pixbuf(call_icon_path);
1415 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1418 static gboolean do_icon_blink(GtkStatusIcon *gi){
1419 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1420 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1421 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1422 if (cur_icon==call_icon){
1423 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1425 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1432 void linphone_gtk_status_icon_set_blinking(gboolean val){
1434 static gint attention_id;
1435 GtkosxApplication *theMacApp=gtkosx_application_get();
1437 attention_id=gtkosx_application_attention_request(theMacApp,CRITICAL_REQUEST);
1438 else gtkosx_application_cancel_attention_request(theMacApp,attention_id);
1442 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1443 if (val && tout==0){
1444 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1445 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1446 }else if (!val && tout!=0){
1447 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1448 g_source_remove(tout);
1449 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1450 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1456 void linphone_gtk_options_activate(GtkWidget *item){
1457 #ifndef HAVE_GTK_OSX
1458 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1463 static void init_identity_combo(GtkComboBox *box){
1464 GtkListStore *store;
1465 GtkCellRenderer *r1,*r2;
1466 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1467 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1468 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1469 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1470 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1471 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1472 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1473 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1476 void linphone_gtk_load_identities(void){
1478 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1480 LinphoneProxyConfig *def=NULL;
1482 GtkListStore *store;
1485 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1486 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1487 /* model is empty, this is the first time we go here */
1488 init_identity_combo(box);
1489 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1491 gtk_list_store_clear(store);
1492 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1493 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1494 gtk_list_store_append(store,&iter);
1495 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1496 g_free(def_identity);
1497 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1499 elem=ms_list_next(elem),i++){
1500 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1501 gtk_list_store_append(store,&iter);
1502 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1503 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1509 gtk_combo_box_set_active(box,def_index);
1512 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1513 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1514 GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
1516 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1517 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1518 if (linphone_core_in_call(linphone_gtk_get_core())){
1519 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1523 static void linphone_gtk_dtmf_released(GtkButton *button){
1524 linphone_core_stop_dtmf (linphone_gtk_get_core());
1528 static void linphone_gtk_connect_digits(GtkWidget *w){
1529 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
1530 GList *children=gtk_container_get_children(cont);
1532 for(elem=children;elem!=NULL;elem=elem->next){
1533 GtkButton *button=GTK_BUTTON(elem->data);
1534 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1535 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1539 static void linphone_gtk_check_menu_items(void){
1540 bool_t video_enabled=linphone_gtk_video_enabled();
1541 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1542 GtkWidget *selfview_item=linphone_gtk_get_widget(
1543 linphone_gtk_get_main_window(),"selfview_item");
1544 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1545 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1546 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1549 static gboolean linphone_gtk_can_manage_accounts(){
1550 LinphoneCore *lc=linphone_gtk_get_core();
1552 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1553 SipSetup *ss=(SipSetup*)elem->data;
1554 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1561 static void linphone_gtk_configure_main_window(){
1562 static gboolean config_loaded=FALSE;
1563 static const char *title;
1564 static const char *home;
1565 static const char *start_call_icon;
1566 static const char *add_call_icon;
1567 static const char *search_icon;
1568 static gboolean update_check_menu;
1569 static gboolean buttons_have_borders;
1570 static gboolean show_abcd;
1571 GtkWidget *w=linphone_gtk_get_main_window();
1573 if (!config_loaded){
1574 title=linphone_gtk_get_ui_config("title","Linphone");
1575 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1576 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1577 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1578 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1579 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1580 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1581 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1584 linphone_gtk_configure_window(w,"main_window");
1586 gtk_window_set_title(GTK_WINDOW(w),title);
1588 if (start_call_icon){
1589 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1590 create_pixmap (start_call_icon));
1591 if (!buttons_have_borders)
1592 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1595 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1596 create_pixmap (add_call_icon));
1597 if (!buttons_have_borders)
1598 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1601 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1603 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1604 g_object_unref(G_OBJECT(pbuf));
1609 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1611 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1615 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1617 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1618 g_object_unref(G_OBJECT(pbuf));
1623 GdkPixbuf *pbuf=create_pixbuf("dialer.png");
1625 GtkButton *button=GTK_BUTTON(linphone_gtk_get_widget(w,"keypad"));
1626 gtk_button_set_image(button,gtk_image_new_from_pixbuf (pbuf));
1629 if (linphone_gtk_can_manage_accounts()) {
1630 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1632 if (update_check_menu){
1633 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1635 g_object_set_data(G_OBJECT(w),"show_abcd",GINT_TO_POINTER(show_abcd));
1638 void linphone_gtk_manage_login(void){
1639 LinphoneCore *lc=linphone_gtk_get_core();
1640 LinphoneProxyConfig *cfg=NULL;
1641 linphone_core_get_default_proxy(lc,&cfg);
1643 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1644 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1645 linphone_gtk_show_login_frame(cfg);
1650 gboolean linphone_gtk_close(GtkWidget *mw){
1651 /*shutdown calls if any*/
1652 LinphoneCore *lc=linphone_gtk_get_core();
1653 if (linphone_core_in_call(lc)){
1654 linphone_core_terminate_all_calls(lc);
1656 linphone_core_enable_video_preview(lc,FALSE);
1657 #ifdef __APPLE__ /*until with have a better option*/
1658 gtk_window_iconify(GTK_WINDOW(mw));
1660 gtk_widget_hide(mw);
1666 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1667 bool_t video_enabled=linphone_gtk_video_enabled();
1668 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1669 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1671 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1672 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1678 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1679 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1680 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1682 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1683 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1684 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1685 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1686 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1687 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1688 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1689 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1690 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1691 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1692 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1693 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1694 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1695 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1696 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1697 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1700 void linphone_gtk_create_keypad(GtkWidget *button){
1701 GtkWidget *mw=linphone_gtk_get_main_window();
1702 GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad");
1704 gtk_widget_destroy(k);
1706 GtkWidget *keypad=linphone_gtk_create_window("keypad");
1707 linphone_gtk_connect_digits(keypad);
1708 linphone_gtk_init_dtmf_table(keypad);
1709 g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad);
1710 if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"show_abcd"))){
1711 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_A"));
1712 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_B"));
1713 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_C"));
1714 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_D"));
1715 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(keypad,"dtmf_table")),4,3);
1717 gtk_widget_show(keypad);
1720 static void linphone_gtk_init_main_window(){
1721 GtkWidget *main_window;
1722 linphone_gtk_configure_main_window();
1723 linphone_gtk_manage_login();
1725 linphone_gtk_load_identities();
1726 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1727 linphone_gtk_show_friends();
1728 main_window=linphone_gtk_get_main_window();
1729 linphone_gtk_call_log_update(main_window);
1731 linphone_gtk_update_call_buttons (NULL);
1732 g_object_set_data(G_OBJECT(main_window),"keypad",NULL);
1733 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1734 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1735 g_signal_connect (G_OBJECT (main_window), "delete-event",
1736 G_CALLBACK (linphone_gtk_close), main_window);
1739 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1740 GtkosxApplication *theMacApp = gtkosx_application_get();
1741 gtkosx_application_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1742 gtk_widget_hide(menubar);
1743 gtkosx_application_ready(theMacApp);
1745 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1747 linphone_gtk_check_menu_items();
1751 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1753 const char *lname="undef";
1755 #if defined(__linux) || defined(__APPLE__)
1756 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1775 g_error("Bad level !");
1777 #if defined(__linux) || defined(__APPLE__)
1779 msg=g_strdup_vprintf(fmt,cap);
1782 msg=g_strdup_vprintf(fmt,args);
1784 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1787 linphone_gtk_log_push(lev,fmt,args);
1791 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1792 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1793 linphone_gtk_get_main_window(), "uribar"));
1795 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1797 gtk_entry_set_text(uri_bar, refer_to);
1798 linphone_gtk_start_call(linphone_gtk_get_main_window());
1801 static void linphone_gtk_check_soundcards(){
1802 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1803 if (devices==NULL || devices[0]==NULL){
1804 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1805 _("No sound cards have been detected on this computer.\n"
1806 "You won't be able to send or receive audio calls."));
1810 static void linphone_gtk_quit(void){
1811 static gboolean quit_done=FALSE;
1814 linphone_gtk_unmonitor_usb();
1815 g_source_remove_by_user_data(linphone_gtk_get_core());
1817 linphone_gtk_close_assistant();
1819 linphone_gtk_uninit_instance();
1820 linphone_gtk_destroy_log_window();
1821 linphone_core_destroy(the_core);
1822 linphone_gtk_log_uninit();
1826 gdk_threads_leave();
1832 This is not the correct way to implement block termination.
1833 The good way would be to call gtk_main_quit(), and return TRUE.
1834 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1835 As a result the program cannot exit at all.
1836 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1838 static gboolean on_block_termination(void){
1840 linphone_gtk_quit();
1845 int main(int argc, char *argv[]){
1850 const char *factory_config_file;
1852 GtkSettings *settings;
1854 const char *app_name="Linphone";
1856 const char *db_file;
1858 #if !GLIB_CHECK_VERSION(2, 31, 0)
1859 g_thread_init(NULL);
1863 progpath = strdup(argv[0]);
1865 config_file=linphone_gtk_get_config_file(NULL);
1869 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1870 if ((lang=getenv("LANG"))!=NULL){
1873 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1879 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1882 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1885 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1887 if (strncmp(lang,"zh",2)==0){
1888 workaround_gtk_entry_chinese_bug=TRUE;
1891 setenv("LANG",lang,1);
1893 setenv("LANGUAGE",lang,1);
1898 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1899 if (p==NULL) perror("bindtextdomain failed");
1900 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1901 textdomain (GETTEXT_PACKAGE);
1903 g_message("NLS disabled.\n");
1906 gtk_rc_add_default_file("./gtkrc");
1908 gdk_threads_enter();
1910 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1911 linphone_options,NULL,NULL)){
1912 gdk_threads_leave();
1916 settings=gtk_settings_get_default();
1917 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1918 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1919 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1920 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1922 if (workingdir!=NULL){
1923 if (chdir(workingdir)==-1){
1924 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1928 /* Now, look for the factory configuration file, we do it this late
1929 since we want to have had time to change directory and to parse
1930 the options, in case we needed to access the working directory */
1931 factory_config_file = linphone_gtk_get_factory_config_file();
1932 if (factory_config_file){
1933 factory=lp_config_new(NULL);
1934 lp_config_read_file(factory,factory_config_file);
1935 app_name=lp_config_get_string(factory,"GtkUi","title","Linphone");
1938 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1939 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1940 g_warning("This instance is going to exit now.");
1941 gdk_threads_leave();
1945 add_pixmap_directory("pixmaps");
1946 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1949 GtkosxApplication *theMacApp = gtkosx_application_get();
1950 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1951 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1952 /*never block termination:*/
1953 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1956 the_ui=linphone_gtk_create_window("main");
1958 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1960 linphone_gtk_create_log_window();
1961 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1963 db_file=linphone_gtk_message_storage_get_db_file(NULL);
1964 linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file);
1966 g_set_application_name(app_name);
1967 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1968 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1970 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1971 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1972 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1973 linphone_gtk_init_main_window();
1976 // Veryfing if at least one sip account is configured. If not, show wizard
1977 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1978 linphone_gtk_show_assistant();
1982 #ifndef HAVE_GTK_OSX
1983 linphone_gtk_init_status_icon();
1986 linphone_gtk_show_main_window();
1987 linphone_gtk_check_soundcards();
1989 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1990 linphone_gtk_check_for_new_version();
1991 linphone_gtk_monitor_usb();
1994 linphone_gtk_quit();
1995 #ifndef HAVE_GTK_OSX
1996 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1997 gtk_status_icon_set_visible(icon,FALSE);