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;
76 static gboolean verbose=0;
77 static gboolean auto_answer = 0;
78 static gchar * addr_to_call = NULL;
79 static gboolean no_video=FALSE;
80 static gboolean iconified=FALSE;
81 static gchar *workingdir=NULL;
82 static char *progpath=NULL;
83 gchar *linphone_logfile=NULL;
84 static gboolean workaround_gtk_entry_chinese_bug=FALSE;
86 static GOptionEntry linphone_options[]={
90 .arg=G_OPTION_ARG_NONE,
91 .arg_data= (gpointer)&verbose,
92 .description=N_("log to stdout some debug information while running.")
95 .long_name = "logfile",
97 .arg = G_OPTION_ARG_STRING,
98 .arg_data = &linphone_logfile,
99 .description = N_("path to a file to write logs into.")
102 .long_name = "no-video",
104 .arg = G_OPTION_ARG_NONE,
105 .arg_data = (gpointer)&no_video,
106 .description = N_("Start linphone with video disabled.")
109 .long_name="iconified",
111 .arg=G_OPTION_ARG_NONE,
112 .arg_data= (gpointer)&iconified,
113 .description=N_("Start only in the system tray, do not show the main interface.")
118 .arg = G_OPTION_ARG_STRING,
119 .arg_data = &addr_to_call,
120 .description = N_("address to call right now")
123 .long_name = "auto-answer",
125 .arg = G_OPTION_ARG_NONE,
126 .arg_data = (gpointer) & auto_answer,
127 .description = N_("if set automatically answer incoming calls")
130 .long_name = "workdir",
132 .arg = G_OPTION_ARG_STRING,
133 .arg_data = (gpointer) & workingdir,
134 .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
139 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
140 #define RELATIVE_XML_DIR
141 #define BUILD_TREE_XML_DIR "gtk"
144 #define CONFIG_FILE ".linphonerc"
145 #define SECRETS_FILE ".linphone-zidcache"
147 #define CONFIG_FILE "linphonerc"
148 #define SECRETS_FILE "linphone-zidcache"
151 char *linphone_gtk_get_config_file(const char *filename){
152 const int path_max=1024;
153 char *config_file=g_malloc0(path_max);
154 if (filename==NULL) filename=CONFIG_FILE;
155 /*try accessing a local file first if exists*/
156 if (access(CONFIG_FILE,F_OK)==0){
157 snprintf(config_file,path_max,"%s",filename);
160 const char *appdata=getenv("APPDATA");
162 snprintf(config_file,path_max,"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
163 CreateDirectory(config_file,NULL);
164 snprintf(config_file,path_max,"%s\\%s\\%s",appdata,LINPHONE_CONFIG_DIR,filename);
167 const char *home=getenv("HOME");
168 if (home==NULL) home=".";
169 snprintf(config_file,path_max,"%s/%s",home,filename);
175 #define FACTORY_CONFIG_FILE "linphonerc.factory"
176 static char _factory_config_file[1024];
177 static const char *linphone_gtk_get_factory_config_file(){
178 /*try accessing a local file first if exists*/
179 if (access(FACTORY_CONFIG_FILE,F_OK)==0){
180 snprintf(_factory_config_file,sizeof(_factory_config_file),
181 "%s",FACTORY_CONFIG_FILE);
185 if (progpath != NULL) {
187 progdir = strdup(progpath);
189 basename = strrchr(progdir, '\\');
190 if (basename != NULL) {
193 snprintf(_factory_config_file, sizeof(_factory_config_file),
194 "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
196 if (workingdir!=NULL) {
197 snprintf(_factory_config_file, sizeof(_factory_config_file),
198 "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
205 basename = strrchr(progdir, '/');
206 if (basename != NULL) {
209 snprintf(_factory_config_file, sizeof(_factory_config_file),
210 "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
219 return _factory_config_file;
222 static void linphone_gtk_init_liblinphone(const char *config_file,
223 const char *factory_config_file, const char *db_file) {
224 LinphoneCoreVTable vtable={0};
225 gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
227 vtable.call_state_changed=linphone_gtk_call_state_changed;
228 vtable.registration_state_changed=linphone_gtk_registration_state_changed;
229 vtable.notify_presence_recv=linphone_gtk_notify_recv;
230 vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
231 vtable.auth_info_requested=linphone_gtk_auth_info_requested;
232 vtable.display_status=linphone_gtk_display_status;
233 vtable.display_message=linphone_gtk_display_message;
234 vtable.display_warning=linphone_gtk_display_warning;
235 vtable.display_url=linphone_gtk_display_url;
236 vtable.call_log_updated=linphone_gtk_call_log_updated;
237 //vtable.text_received=linphone_gtk_text_received;
238 vtable.message_received=linphone_gtk_text_received;
239 vtable.refer_received=linphone_gtk_refer_received;
240 vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
241 vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
242 vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
244 the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
245 //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
246 linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
247 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
248 linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
249 g_free(secrets_file);
250 linphone_core_enable_video(the_core,TRUE,TRUE);
252 _linphone_gtk_enable_video(FALSE);
253 linphone_gtk_set_ui_config_int("videoselfview",0);
255 if (db_file) linphone_core_set_chat_database_path(the_core,db_file);
258 LinphoneCore *linphone_gtk_get_core(void){
262 GtkWidget *linphone_gtk_get_main_window(){
266 void linphone_gtk_destroy_main_window() {
267 linphone_gtk_destroy_window(the_ui);
271 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
272 static const char *icon_path=NULL;
273 static const char *hiddens=NULL;
274 static const char *shown=NULL;
275 static bool_t config_loaded=FALSE;
276 if (linphone_gtk_get_core()==NULL) return;
277 if (config_loaded==FALSE){
278 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
279 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
280 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
284 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
286 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
288 GdkPixbuf *pbuf=create_pixbuf(icon_path);
290 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
291 g_object_unref(G_OBJECT(pbuf));
296 static int get_ui_file(const char *name, char *path, int pathsize){
297 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
298 if (access(path,F_OK)!=0){
299 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
300 if (access(path,F_OK)!=0){
301 g_error("Could not locate neither %s/%s.ui nor %s/%s.ui",BUILD_TREE_XML_DIR,name,
302 INSTALLED_XML_DIR,name);
309 void linphone_gtk_destroy_window(GtkWidget *widget) {
310 GtkBuilder* builder = g_object_get_data(G_OBJECT(widget), "builder");
311 gtk_widget_destroy(widget);
312 g_object_unref (G_OBJECT (builder));
315 GtkWidget *linphone_gtk_create_window(const char *window_name){
316 GError* error = NULL;
317 GtkBuilder* builder = gtk_builder_new ();
321 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
323 if (!gtk_builder_add_from_file (builder, path, &error)){
324 g_error("Couldn't load builder file: %s", error->message);
325 g_error_free (error);
328 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
330 g_error("Could not retrieve '%s' window from xml file",window_name);
333 g_object_set_data(G_OBJECT(w), "builder",builder);
334 gtk_builder_connect_signals(builder,w);
335 linphone_gtk_configure_window(w,window_name);
339 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
342 GtkBuilder* builder = gtk_builder_new ();
344 gchar *object_ids[2];
345 object_ids[0]=g_strdup(widget_name);
348 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
349 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
350 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
351 g_error_free (error);
352 g_free(object_ids[0]);
355 g_free(object_ids[0]);
356 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
358 g_error("Could not retrieve '%s' window from xml file",widget_name);
361 g_object_set_data(G_OBJECT(w),"builder",builder);
362 g_signal_connect_swapped(G_OBJECT(w),"destroy",(GCallback)g_object_unref,builder);
363 gtk_builder_connect_signals(builder,w);
367 static void entry_unmapped(GtkWidget *entry){
368 g_message("Entry is unmapped, calling unrealize to workaround chinese bug.");
369 gtk_widget_unrealize(entry);
372 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
375 if (window==NULL) return NULL;
376 builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
378 g_error("Fail to retrieve builder from window !");
381 w=gtk_builder_get_object(builder,name);
383 g_error("No widget named %s found in xml interface.",name);
385 if (workaround_gtk_entry_chinese_bug){
386 if (strcmp(G_OBJECT_TYPE_NAME(w),"GtkEntry")==0){
387 if (g_object_get_data(G_OBJECT(w),"entry_bug_workaround")==NULL){
388 g_object_set_data(G_OBJECT(w),"entry_bug_workaround",GINT_TO_POINTER(1));
389 g_message("%s is a GtkEntry",name);
390 g_signal_connect(G_OBJECT(w),"unmap",(GCallback)entry_unmapped,NULL);
394 return GTK_WIDGET(w);
398 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
400 GtkWidget *main_window=linphone_gtk_get_main_window();
402 gtk_widget_show(main_window);
403 if (type==GTK_MESSAGE_QUESTION)
405 /* draw a question box. link to dialog_click callback */
406 dialog = gtk_message_dialog_new (
407 GTK_WINDOW(main_window),
408 GTK_DIALOG_DESTROY_WITH_PARENT,
409 GTK_MESSAGE_QUESTION,
412 (const gchar*)message);
413 /* connect to some callback : REVISIT */
415 g_signal_connect_swapped (G_OBJECT (dialog), "response",
416 G_CALLBACK (dialog_click),
419 /* actually show the box */
420 gtk_widget_show(dialog);
424 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
425 GTK_DIALOG_DESTROY_WITH_PARENT,
429 (const gchar*)message);
430 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
431 g_signal_connect_swapped (G_OBJECT (dialog), "response",
432 G_CALLBACK (gtk_widget_destroy),
434 gtk_widget_show(dialog);
438 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
439 if (id==GTK_RESPONSE_CANCEL){
440 gtk_widget_destroy(GTK_WIDGET(dialog));
444 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
445 g_message("About url clicked");
446 linphone_gtk_open_browser(url);
449 void linphone_gtk_show_about(){
450 struct stat filestat;
451 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
454 GdkPixbuf *logo=create_pixbuf(
455 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
456 static const char *defcfg="defcfg";
458 about=linphone_gtk_create_window("about");
459 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
460 memset(&filestat,0,sizeof(filestat));
461 if (stat(license_file,&filestat)!=0){
462 license_file="COPYING";
463 stat(license_file,&filestat);
465 if (filestat.st_size>0){
466 char *license=g_malloc(filestat.st_size+1);
467 FILE *f=fopen(license_file,"r");
468 if (f && fread(license,filestat.st_size,1,f)==1){
469 license[filestat.st_size]='\0';
470 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
474 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
475 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
476 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
477 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
478 tmp=linphone_gtk_get_ui_config("artists",defcfg);
483 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
485 tmp=linphone_gtk_get_ui_config("translators",defcfg);
487 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
488 tmp=linphone_gtk_get_ui_config("comments",defcfg);
490 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
491 gtk_widget_show(about);
494 static void set_video_window_decorations(GdkWindow *w){
495 const char *title=linphone_gtk_get_ui_config("title","Linphone");
496 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
497 char video_title[256];
498 GdkPixbuf *pbuf=create_pixbuf(icon_path);
500 if (!linphone_core_in_call(linphone_gtk_get_core())){
501 snprintf(video_title,sizeof(video_title),"%s video",title);
502 /* When not in call, treat the video as a normal window */
503 gdk_window_set_keep_above(w, FALSE);
505 LinphoneAddress *uri =
506 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
509 linphone_address_clean(uri);
510 if (linphone_address_get_display_name(uri)!=NULL){
511 display_name=ms_strdup(linphone_address_get_display_name(uri));
513 display_name=linphone_address_as_string(uri);
515 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
516 linphone_address_destroy(uri);
517 ms_free(display_name);
519 /* During calls, bring up the video window, arrange so that
520 it is above all the other windows */
521 gdk_window_deiconify(w);
522 gdk_window_set_keep_above(w,TRUE);
523 /* Maybe we should have the following, but then we want to
524 have a timer that turns it off after a little while. */
525 /* gdk_window_set_urgency_hint(w,TRUE); */
527 gdk_window_set_title(w,video_title);
528 /* Refrain the video window to be closed at all times. */
529 gdk_window_set_functions(w,
530 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
531 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
534 l=g_list_append(l,pbuf);
535 gdk_window_set_icon_list(w,l);
537 g_object_unref(G_OBJECT(pbuf));
541 static gboolean video_needs_update=FALSE;
543 static void update_video_title(){
544 video_needs_update=TRUE;
547 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
548 static gboolean first_time=TRUE;
550 static unsigned long previd=0;
551 static unsigned long preview_previd=0;
552 static gboolean in_iterate=FALSE;
555 if (in_iterate) return TRUE;
557 linphone_core_iterate(lc);
559 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
560 linphone_gtk_show_directory_search();
564 id=linphone_core_get_native_video_window_id(lc);
565 if (id!=previd || video_needs_update){
569 ms_message("Updating window decorations");
571 w=gdk_window_foreign_new((GdkNativeWindow)id);
573 w=gdk_window_foreign_new((HANDLE)id);
576 set_video_window_decorations(w);
577 g_object_unref(G_OBJECT(w));
579 else ms_error("gdk_window_foreign_new() failed");
580 if (video_needs_update) video_needs_update=FALSE;
583 id=linphone_core_get_native_preview_window_id (lc);
584 if (id!=preview_previd ){
588 ms_message("Updating window decorations for preview");
590 w=gdk_window_foreign_new((GdkNativeWindow)id);
592 w=gdk_window_foreign_new((HANDLE)id);
595 set_video_window_decorations(w);
596 g_object_unref(G_OBJECT(w));
598 else ms_error("gdk_window_foreign_new() failed");
599 if (video_needs_update) video_needs_update=FALSE;
602 if (addr_to_call!=NULL){
603 /*make sure we are not showing the login screen*/
604 GtkWidget *mw=linphone_gtk_get_main_window();
605 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
606 if (!GTK_WIDGET_VISIBLE(login_frame)){
607 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
608 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
610 linphone_gtk_start_call(uri_bar);
617 static void load_uri_history(){
618 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
621 GtkEntryCompletion *gep=gtk_entry_completion_new();
622 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
625 snprintf(key,sizeof(key),"uri%i",i);
626 uri=linphone_gtk_get_ui_config(key,NULL);
629 gtk_list_store_append(model,&iter);
630 gtk_list_store_set(model,&iter,0,uri,-1);
631 if (i==0) gtk_entry_set_text(uribar,uri);
635 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
636 gtk_entry_completion_set_text_column(gep,0);
637 gtk_entry_set_completion(uribar,gep);
640 static void save_uri_history(){
641 LinphoneCore *lc=linphone_gtk_get_core();
642 LpConfig *cfg=linphone_core_get_config(lc);
643 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
648 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
650 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
652 gtk_tree_model_get(model,&iter,0,&uri,-1);
654 snprintf(key,sizeof(key),"uri%i",i);
655 lp_config_set_string(cfg,"GtkUi",key,uri);
660 }while(gtk_tree_model_iter_next(model,&iter));
664 static void completion_add_text(GtkEntry *entry, const char *text){
666 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
668 if (gtk_tree_model_get_iter_first(model,&iter)){
671 gtk_tree_model_get(model,&iter,0,&uri,-1);
673 if (strcmp(uri,text)==0) {
675 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
681 }while (gtk_tree_model_iter_next(model,&iter));
683 /* and prepend it on top of the list */
684 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
685 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
689 bool_t linphone_gtk_video_enabled(void){
690 const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
691 return vpol->automatically_accept && vpol->automatically_initiate;
694 void linphone_gtk_show_main_window(){
695 GtkWidget *w=linphone_gtk_get_main_window();
696 LinphoneCore *lc=linphone_gtk_get_core();
697 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
698 VIDEOSELFVIEW_DEFAULT));
700 gtk_window_present(GTK_WINDOW(w));
703 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
704 GtkWidget *mw=linphone_gtk_get_main_window();
705 if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
706 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
708 if (linphone_gtk_use_in_call_view() && call)
709 linphone_gtk_in_call_view_terminate(call,error);
710 update_video_title();
713 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
714 LinphoneCore *lc=linphone_gtk_get_core();
715 GtkWidget *mw=linphone_gtk_get_main_window();
716 const MSList *calls=linphone_core_get_calls(lc);
718 bool_t start_active=TRUE;
719 //bool_t stop_active=FALSE;
720 bool_t add_call=FALSE;
721 int call_list_size=ms_list_size(calls);
731 button=linphone_gtk_get_widget(mw,"start_call");
732 gtk_widget_set_sensitive(button,start_active);
733 gtk_widget_set_visible(button,!add_call);
735 button=linphone_gtk_get_widget(mw,"add_call");
736 if (linphone_core_sound_resources_locked(lc) || (call && linphone_call_get_state(call)==LinphoneCallIncomingReceived)) {
737 gtk_widget_set_sensitive(button,FALSE);
739 gtk_widget_set_sensitive(button,start_active);
741 gtk_widget_set_visible(button,add_call);
743 //gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
744 GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
745 if(conf_frame==NULL){
746 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
747 linphone_gtk_enable_conference_button(lc,call_list_size>1);
749 linphone_gtk_enable_transfer_button(lc,FALSE);
750 linphone_gtk_enable_conference_button(lc,FALSE);
752 update_video_title();
754 linphone_gtk_update_video_button(call);
758 gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference){
759 const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
760 const char *id="unknown";
761 char filename[256]={0};
763 time_t curtime=time(NULL);
767 loctime=*localtime(&curtime);
769 localtime_r(&curtime,&loctime);
771 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);
774 id=linphone_address_get_username(address);
775 if (id==NULL) id=linphone_address_get_domain(address);
778 snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav",
779 linphone_gtk_get_ui_config("title","Linphone"),
782 snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav",
783 linphone_gtk_get_ui_config("title","Linphone"),
787 return g_build_filename(dir,filename,NULL);
790 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
791 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
792 LinphoneCore *lc=linphone_gtk_get_core();
793 LinphoneAddress *addr=linphone_core_interpret_url(lc,entered);
796 LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
797 gchar *record_file=linphone_gtk_get_record_path(addr,FALSE);
798 linphone_call_params_set_record_file(params,record_file);
799 linphone_core_invite_address_with_params(lc,addr,params);
800 completion_add_text(GTK_ENTRY(uri_bar),entered);
801 linphone_address_destroy(addr);
802 linphone_call_params_destroy(params);
805 linphone_gtk_call_terminated(NULL,NULL);
811 static void accept_incoming_call(LinphoneCall *call){
812 LinphoneCore *lc=linphone_gtk_get_core();
813 LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
814 gchar *record_file=linphone_gtk_get_record_path(linphone_call_get_remote_address(call),FALSE);
815 linphone_call_params_set_record_file(params,record_file);
816 linphone_core_accept_call_with_params(lc,call,params);
817 linphone_call_params_destroy(params);
820 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
821 LinphoneCallState state=linphone_call_get_state(call);
822 if (state==LinphoneCallIncomingReceived || state==LinphoneCallIncomingEarlyMedia){
823 accept_incoming_call(call);
828 void linphone_gtk_start_call(GtkWidget *w){
829 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
830 /*change into in-call mode, then do the work later as it might block a bit */
831 GtkWidget *mw=gtk_widget_get_toplevel(w);
832 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
833 LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle;
835 if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){
836 accept_incoming_call(call);
838 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
839 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
840 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
841 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
846 void linphone_gtk_uri_bar_activate(GtkWidget *w){
847 linphone_gtk_start_call(w);
850 void linphone_gtk_terminate_call(GtkWidget *button){
852 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
854 linphone_core_terminate_call(linphone_gtk_get_core(),call);
856 linphone_core_terminate_conference(linphone_gtk_get_core());
860 void linphone_gtk_decline_clicked(GtkWidget *button){
861 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
863 linphone_core_terminate_call(linphone_gtk_get_core(),call);
866 void linphone_gtk_answer_clicked(GtkWidget *button){
867 LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
869 accept_incoming_call(call);
870 linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
874 void _linphone_gtk_enable_video(gboolean val){
875 LinphoneVideoPolicy policy={0};
876 policy.automatically_initiate=policy.automatically_accept=val;
877 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
878 linphone_core_set_video_policy(linphone_gtk_get_core(),&policy);
881 linphone_core_enable_video_preview(linphone_gtk_get_core(),
882 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
884 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
888 void linphone_gtk_enable_video(GtkWidget *w){
889 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
890 //GtkWidget *selfview_item=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"selfview_item");
891 _linphone_gtk_enable_video(val);
894 void linphone_gtk_enable_self_view(GtkWidget *w){
895 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
896 LinphoneCore *lc=linphone_gtk_get_core();
897 linphone_core_enable_video_preview(lc,val);
898 linphone_core_enable_self_view(lc,val);
899 linphone_gtk_set_ui_config_int("videoselfview",val);
902 void linphone_gtk_used_identity_changed(GtkWidget *w){
903 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
904 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
905 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
906 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
907 linphone_gtk_show_directory_search();
909 if (sel) g_free(sel);
912 void on_proxy_refresh_button_clicked(GtkWidget *w){
913 LinphoneCore *lc=linphone_gtk_get_core();
914 MSList const *item=linphone_core_get_proxy_config_list(lc);
915 while (item != NULL) {
916 LinphoneProxyConfig *lpc=(LinphoneProxyConfig*)item->data;
917 linphone_proxy_config_edit(lpc);
918 linphone_proxy_config_done(lpc);
923 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
924 linphone_gtk_show_friends();
927 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
929 case GTK_RESPONSE_YES:
930 linphone_gtk_show_contact(lf);
933 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
935 gtk_widget_destroy(dialog);
938 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
941 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
942 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
946 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);
947 dialog = gtk_message_dialog_new (
948 GTK_WINDOW(linphone_gtk_get_main_window()),
949 GTK_DIALOG_DESTROY_WITH_PARENT,
950 GTK_MESSAGE_QUESTION,
955 g_signal_connect(G_OBJECT (dialog), "response",
956 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
957 /* actually show the box */
958 gtk_widget_show(dialog);
961 typedef struct _AuthTimeout{
965 static void auth_timeout_clean(AuthTimeout *tout){
969 static gboolean auth_timeout_destroy(AuthTimeout *tout){
971 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
972 gtk_widget_destroy(tout->w);
978 static AuthTimeout * auth_timeout_new(GtkWidget *w){
979 AuthTimeout *tout=g_new(AuthTimeout,1);
981 /*so that the timeout no more references the widget when it is destroyed:*/
982 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
983 /*so that the widget is automatically destroyed after some time */
984 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
988 void linphone_gtk_password_cancel(GtkWidget *w){
989 LinphoneAuthInfo *info;
990 GtkWidget *window=gtk_widget_get_toplevel(w);
991 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
992 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
993 gtk_widget_destroy(window);
996 void linphone_gtk_password_ok(GtkWidget *w){
998 GtkWidget *window=gtk_widget_get_toplevel(w);
999 LinphoneAuthInfo *info;
1000 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
1001 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
1002 entry=linphone_gtk_get_widget(window,"password_entry");
1003 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
1004 linphone_auth_info_set_userid(info,
1005 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
1006 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
1007 gtk_widget_destroy(window);
1010 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
1011 GtkWidget *w=linphone_gtk_create_window("password");
1012 GtkWidget *label=linphone_gtk_get_widget(w,"message");
1013 LinphoneAuthInfo *info;
1015 GtkWidget *mw=linphone_gtk_get_main_window();
1017 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
1018 /*don't prompt for authentication when login frame is visible*/
1019 linphone_core_abort_authentication(lc,NULL);
1023 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
1025 gtk_label_set_markup(GTK_LABEL(label),msg);
1027 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
1028 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
1029 g_object_set_data(G_OBJECT(w),"auth_info",info);
1030 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
1032 auth_timeout_new(w);
1035 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
1036 GtkWidget *w=linphone_gtk_get_main_window();
1037 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
1039 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
1040 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
1044 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
1045 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
1048 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
1049 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
1052 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
1053 char richtext[4096];
1054 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
1055 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
1058 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
1059 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
1060 if (w) linphone_gtk_call_log_update(w);
1061 linphone_gtk_call_log_update(linphone_gtk_get_main_window());
1065 static bool_t notify_actions_supported() {
1066 bool_t accepts_actions = FALSE;
1067 GList *capabilities = notify_get_server_caps();
1069 if(capabilities != NULL) {
1070 for(c = capabilities; c != NULL; c = c->next) {
1071 if(strcmp((char*)c->data, "actions") == 0 ) {
1072 accepts_actions = TRUE;
1076 g_list_foreach(capabilities, (GFunc)g_free, NULL);
1077 g_list_free(capabilities);
1079 return accepts_actions;
1082 static NotifyNotification* build_notification(const char *title, const char *body){
1083 return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)
1090 static void show_notification(NotifyNotification* n){
1091 if (n && !notify_notification_show(n,NULL))
1092 ms_error("Failed to send notification.");
1095 static void make_notification(const char *title, const char *body){
1096 show_notification(build_notification(title,body));
1101 void linphone_gtk_notify(LinphoneCall *call, const char *msg){
1103 if (!notify_is_initted())
1104 if (!notify_init ("Linphone")) ms_error("Libnotify failed to init.");
1109 if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL
1115 ms_error("Failed to send notification.");
1117 linphone_gtk_show_main_window();
1119 } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) {
1122 char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL;
1123 NotifyNotification *n;
1124 switch(linphone_call_get_state(call)){
1125 case LinphoneCallError:
1126 make_notification(_("Call error"),body=g_markup_printf_escaped("<b>%s</b>\n%s",msg,remote));
1128 case LinphoneCallEnd:
1129 make_notification(_("Call ended"),body=g_markup_printf_escaped("<b>%s</b>",remote));
1131 case LinphoneCallIncomingReceived:
1132 n=build_notification(_("Incoming call"),body=g_markup_printf_escaped("<b>%s</b>",remote));
1133 if (notify_actions_supported()) {
1134 notify_notification_add_action (n,"answer", _("Answer"),
1135 NOTIFY_ACTION_CALLBACK(linphone_gtk_answer_clicked),NULL,NULL);
1136 notify_notification_add_action (n,"decline",_("Decline"),
1137 NOTIFY_ACTION_CALLBACK(linphone_gtk_decline_clicked),NULL,NULL);
1139 show_notification(n);
1141 case LinphoneCallPausedByRemote:
1142 make_notification(_("Call paused"),body=g_markup_printf_escaped(_("<b>by %s</b>"),remote));
1147 if (body) g_free(body);
1148 if (remote) g_free(remote);
1153 static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
1154 if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
1155 LinphoneCore *lc=linphone_call_get_core(call);
1156 LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
1157 linphone_call_params_enable_video(params,responseid==GTK_RESPONSE_YES);
1158 linphone_core_accept_call_update(lc,call,params);
1159 linphone_call_params_destroy(params);
1161 linphone_call_unref(call);
1162 g_source_remove_by_user_data(dialog);
1163 gtk_widget_destroy(dialog);
1166 static void on_call_updated_timeout(GtkWidget *dialog){
1167 gtk_widget_destroy(dialog);
1170 static void linphone_gtk_call_updated_by_remote(LinphoneCall *call){
1171 LinphoneCore *lc=linphone_call_get_core(call);
1172 const LinphoneVideoPolicy *pol=linphone_core_get_video_policy(lc);
1173 const LinphoneCallParams *rparams=linphone_call_get_remote_params(call);
1174 const LinphoneCallParams *current_params=linphone_call_get_current_params(call);
1175 gboolean video_requested=linphone_call_params_video_enabled(rparams);
1176 gboolean video_used=linphone_call_params_video_enabled(current_params);
1177 g_message("Video used=%i, video requested=%i, automatically_accept=%i",
1178 video_used,video_requested,pol->automatically_accept);
1179 if (video_used==FALSE && video_requested && !pol->automatically_accept){
1180 linphone_core_defer_call_update(lc,call);
1182 const LinphoneAddress *addr=linphone_call_get_remote_address(call);
1184 const char *dname=linphone_address_get_display_name(addr);
1185 if (dname==NULL) dname=linphone_address_get_username(addr);
1186 if (dname==NULL) dname=linphone_address_get_domain(addr);
1187 dialog=gtk_message_dialog_new(GTK_WINDOW(linphone_gtk_get_main_window()),
1188 GTK_DIALOG_DESTROY_WITH_PARENT,
1189 GTK_MESSAGE_WARNING,
1191 _("%s proposed to start video. Do you accept ?"),dname);
1192 g_signal_connect(G_OBJECT(dialog),"response",(GCallback)on_call_updated_response,linphone_call_ref(call));
1193 g_timeout_add(20000,(GSourceFunc)on_call_updated_timeout,dialog);
1194 gtk_widget_show(dialog);
1199 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
1201 case LinphoneCallOutgoingInit:
1202 linphone_gtk_create_in_call_view (call);
1204 case LinphoneCallOutgoingProgress:
1205 linphone_gtk_in_call_view_set_calling (call);
1207 case LinphoneCallStreamsRunning:
1208 linphone_gtk_in_call_view_set_in_call(call);
1210 case LinphoneCallUpdatedByRemote:
1211 linphone_gtk_call_updated_by_remote(call);
1213 case LinphoneCallError:
1214 linphone_gtk_in_call_view_terminate (call,msg);
1216 case LinphoneCallEnd:
1217 linphone_gtk_in_call_view_terminate(call,NULL);
1218 linphone_gtk_status_icon_set_blinking(FALSE);
1220 case LinphoneCallIncomingReceived:
1221 linphone_gtk_create_in_call_view(call);
1222 linphone_gtk_in_call_view_set_incoming(call);
1223 linphone_gtk_status_icon_set_blinking(TRUE);
1225 linphone_call_ref(call);
1226 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1229 case LinphoneCallResuming:
1230 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1231 linphone_gtk_in_call_view_set_in_call (call);
1233 case LinphoneCallPausing:
1234 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1235 linphone_gtk_call_update_tab_header(call,FALSE);
1236 case LinphoneCallPausedByRemote:
1237 linphone_gtk_in_call_view_set_paused(call);
1238 linphone_gtk_call_update_tab_header(call,TRUE);
1240 case LinphoneCallConnected:
1241 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1242 linphone_gtk_status_icon_set_blinking(FALSE);
1247 linphone_gtk_notify(call, msg);
1248 linphone_gtk_update_call_buttons (call);
1251 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token){
1252 linphone_gtk_in_call_view_show_encryption(call);
1255 static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
1256 linphone_gtk_in_call_view_set_transfer_status(call,cstate);
1259 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
1260 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1261 GtkTreeModel *model=gtk_combo_box_get_model(box);
1263 gboolean found=FALSE;
1264 const char *stock_id=NULL;
1266 if (gtk_tree_model_get_iter_first(model,&iter)){
1269 gtk_tree_model_get(model,&iter,2,&p,-1);
1274 }while(gtk_tree_model_iter_next(model,&iter));
1277 g_warning("Could not find proxy config in combo box of identities.");
1281 case LinphoneRegistrationOk:
1282 stock_id=GTK_STOCK_YES;
1284 case LinphoneRegistrationProgress:
1285 stock_id=GTK_STOCK_REFRESH;
1287 case LinphoneRegistrationCleared:
1290 case LinphoneRegistrationFailed:
1291 stock_id=GTK_STOCK_DIALOG_WARNING;
1296 gtk_list_store_set(GTK_LIST_STORE(model),&iter,1,stock_id,-1);
1299 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1300 LinphoneRegistrationState rs, const char *msg){
1302 case LinphoneRegistrationOk:
1304 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1305 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1306 linphone_gtk_exit_login_frame();
1313 update_registration_status(cfg,rs);
1316 void linphone_gtk_open_browser(const char *url){
1317 /*in gtk 2.16, gtk_show_uri does not work...*/
1319 #if GTK_CHECK_VERSION(2,18,3)
1320 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1323 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1324 g_spawn_command_line_async(cl,NULL);
1327 ShellExecute(0,"open",url,NULL,NULL,1);
1331 void linphone_gtk_link_to_website(GtkWidget *item){
1332 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1333 linphone_gtk_open_browser(home);
1336 #ifndef HAVE_GTK_OSX
1338 static GtkStatusIcon *icon=NULL;
1340 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1341 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1342 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1345 static GtkWidget *create_icon_menu(){
1346 GtkWidget *menu=gtk_menu_new();
1347 GtkWidget *menu_item;
1350 const gchar *homesite;
1352 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1353 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1354 tmp=g_strdup(homesite);
1355 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1356 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1358 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1359 gtk_widget_show(image);
1360 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1361 //g_object_unref(G_OBJECT(image));
1362 gtk_widget_show(menu_item);
1363 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1364 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1366 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,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)linphone_gtk_show_about,NULL);
1370 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1371 gtk_widget_show(menu_item);
1372 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1373 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1374 gtk_widget_show(menu);
1378 void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data){
1379 gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y);
1382 static void handle_icon_click() {
1383 GtkWidget *mw=linphone_gtk_get_main_window();
1384 if (!gtk_window_is_active((GtkWindow*)mw)) {
1385 if(!gtk_widget_is_drawable(mw)){
1386 //we only move if window was hidden. If it was simply behind the window stack, ie, drawable, we keep it as it was
1387 gtk_window_move (GTK_WINDOW(mw), main_window_x, main_window_y);
1389 linphone_gtk_show_main_window();
1391 linphone_gtk_save_main_window_position((GtkWindow*)mw, NULL, NULL);
1392 gtk_widget_hide(mw);
1396 static void linphone_gtk_init_status_icon(){
1397 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1398 const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1399 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1400 GtkWidget *menu=create_icon_menu();
1402 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1403 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1404 #if GTK_CHECK_VERSION(2,20,0)
1405 gtk_status_icon_set_name(icon,title);
1407 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
1408 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1409 gtk_status_icon_set_tooltip(icon,title);
1410 gtk_status_icon_set_visible(icon,TRUE);
1411 g_object_set_data(G_OBJECT(icon),"menu",menu);
1412 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1413 g_object_set_data(G_OBJECT(icon),"icon",pbuf);
1414 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf);
1415 pbuf=create_pixbuf(call_icon_path);
1416 g_object_set_data(G_OBJECT(icon),"call_icon",pbuf);
1419 static gboolean do_icon_blink(GtkStatusIcon *gi){
1420 GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon");
1421 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon");
1422 GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi);
1423 if (cur_icon==call_icon){
1424 gtk_status_icon_set_from_pixbuf(gi,normal_icon);
1426 gtk_status_icon_set_from_pixbuf(gi,call_icon);
1433 void linphone_gtk_status_icon_set_blinking(gboolean val){
1435 static gint attention_id;
1436 GtkosxApplication *theMacApp=gtkosx_application_get();
1438 attention_id=gtkosx_application_attention_request(theMacApp,CRITICAL_REQUEST);
1439 else gtkosx_application_cancel_attention_request(theMacApp,attention_id);
1443 tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout"));
1444 if (val && tout==0){
1445 tout=g_timeout_add(500,(GSourceFunc)do_icon_blink,icon);
1446 g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout));
1447 }else if (!val && tout!=0){
1448 GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon");
1449 g_source_remove(tout);
1450 g_object_set_data(G_OBJECT(icon),"timeout",NULL);
1451 gtk_status_icon_set_from_pixbuf(icon,normal_icon);
1457 void linphone_gtk_options_activate(GtkWidget *item){
1458 #ifndef HAVE_GTK_OSX
1459 gtk_widget_set_visible(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"quit_item"),
1464 static void init_identity_combo(GtkComboBox *box){
1465 GtkListStore *store;
1466 GtkCellRenderer *r1,*r2;
1467 store=gtk_list_store_new(3,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_POINTER);
1468 gtk_cell_layout_clear(GTK_CELL_LAYOUT(box));
1469 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(box),(r1=gtk_cell_renderer_text_new()),TRUE);
1470 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(box),(r2=gtk_cell_renderer_pixbuf_new()),FALSE);
1471 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r1,"text",0);
1472 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(box),r2,"stock-id",1);
1473 g_object_set(G_OBJECT(r1),"ellipsize",PANGO_ELLIPSIZE_END,NULL);
1474 gtk_combo_box_set_model(box,GTK_TREE_MODEL(store));
1477 void linphone_gtk_load_identities(void){
1479 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1481 LinphoneProxyConfig *def=NULL;
1483 GtkListStore *store;
1486 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1487 if (gtk_tree_model_get_n_columns(GTK_TREE_MODEL(store))==1){
1488 /* model is empty, this is the first time we go here */
1489 init_identity_combo(box);
1490 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1492 gtk_list_store_clear(store);
1493 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1494 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1495 gtk_list_store_append(store,&iter);
1496 gtk_list_store_set(store,&iter,0,def_identity,1,NULL,2,NULL,-1);
1497 g_free(def_identity);
1498 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1500 elem=ms_list_next(elem),i++){
1501 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1502 gtk_list_store_append(store,&iter);
1503 gtk_list_store_set(store,&iter,0,linphone_proxy_config_get_identity(cfg),1,
1504 linphone_proxy_config_is_registered(cfg) ? GTK_STOCK_YES : NULL,
1510 gtk_combo_box_set_active(box,def_index);
1513 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1514 const char *label=(char *)g_object_get_data(G_OBJECT(button),"label");
1515 GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar");
1517 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1518 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1519 if (linphone_core_in_call(linphone_gtk_get_core())){
1520 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1524 static void linphone_gtk_dtmf_released(GtkButton *button){
1525 linphone_core_stop_dtmf (linphone_gtk_get_core());
1529 static void linphone_gtk_connect_digits(GtkWidget *w){
1530 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(w,"dtmf_table"));
1531 GList *children=gtk_container_get_children(cont);
1533 for(elem=children;elem!=NULL;elem=elem->next){
1534 GtkButton *button=GTK_BUTTON(elem->data);
1535 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1536 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1540 static void linphone_gtk_check_menu_items(void){
1541 bool_t video_enabled=linphone_gtk_video_enabled();
1542 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1543 GtkWidget *selfview_item=linphone_gtk_get_widget(
1544 linphone_gtk_get_main_window(),"selfview_item");
1545 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1546 linphone_gtk_get_main_window(),"enable_video_item")), video_enabled);
1547 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(selfview_item),selfview);
1550 static gboolean linphone_gtk_can_manage_accounts(){
1551 LinphoneCore *lc=linphone_gtk_get_core();
1553 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1554 SipSetup *ss=(SipSetup*)elem->data;
1555 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1562 static void linphone_gtk_configure_main_window(){
1563 static gboolean config_loaded=FALSE;
1564 static const char *title;
1565 static const char *home;
1566 static const char *start_call_icon;
1567 static const char *add_call_icon;
1568 static const char *search_icon;
1569 static gboolean update_check_menu;
1570 static gboolean buttons_have_borders;
1571 static gboolean show_abcd;
1572 GtkWidget *w=linphone_gtk_get_main_window();
1574 if (!config_loaded){
1575 title=linphone_gtk_get_ui_config("title","Linphone");
1576 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1577 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1578 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1579 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1580 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1581 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1582 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1585 linphone_gtk_configure_window(w,"main_window");
1587 gtk_window_set_title(GTK_WINDOW(w),title);
1589 if (start_call_icon){
1590 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1591 create_pixmap (start_call_icon));
1592 if (!buttons_have_borders)
1593 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1596 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1597 create_pixmap (add_call_icon));
1598 if (!buttons_have_borders)
1599 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1602 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1604 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1605 g_object_unref(G_OBJECT(pbuf));
1610 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1612 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1616 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1618 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1619 g_object_unref(G_OBJECT(pbuf));
1624 GdkPixbuf *pbuf=create_pixbuf("dialer.png");
1626 GtkButton *button=GTK_BUTTON(linphone_gtk_get_widget(w,"keypad"));
1627 gtk_button_set_image(button,gtk_image_new_from_pixbuf (pbuf));
1630 if (linphone_gtk_can_manage_accounts()) {
1631 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1633 if (update_check_menu){
1634 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1636 g_object_set_data(G_OBJECT(w),"show_abcd",GINT_TO_POINTER(show_abcd));
1639 void linphone_gtk_manage_login(void){
1640 LinphoneCore *lc=linphone_gtk_get_core();
1641 LinphoneProxyConfig *cfg=NULL;
1642 linphone_core_get_default_proxy(lc,&cfg);
1644 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1645 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1646 linphone_gtk_show_login_frame(cfg);
1651 gboolean linphone_gtk_close(GtkWidget *mw){
1652 /*shutdown calls if any*/
1653 LinphoneCore *lc=linphone_gtk_get_core();
1654 if (linphone_core_in_call(lc)){
1655 linphone_core_terminate_all_calls(lc);
1657 linphone_core_enable_video_preview(lc,FALSE);
1658 #ifdef __APPLE__ /*until with have a better option*/
1659 gtk_window_iconify(GTK_WINDOW(mw));
1661 gtk_widget_hide(mw);
1667 static gboolean on_window_state_event(GtkWidget *w, GdkEventWindowState *event){
1668 bool_t video_enabled=linphone_gtk_video_enabled();
1669 if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) ||(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) ){
1670 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
1672 linphone_core_enable_video_preview(linphone_gtk_get_core(),
1673 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT) && video_enabled);
1679 void linphone_gtk_init_dtmf_table(GtkWidget *mw){
1680 GtkWidget *dtmf_table=linphone_gtk_get_widget(mw,"dtmf_table");
1681 gtk_widget_set_direction(dtmf_table, GTK_TEXT_DIR_LTR);
1683 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_A")),"label","A");
1684 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_B")),"label","B");
1685 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_C")),"label","C");
1686 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_D")),"label","D");
1687 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_1")),"label","1");
1688 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_2")),"label","2");
1689 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_3")),"label","3");
1690 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_4")),"label","4");
1691 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_5")),"label","5");
1692 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_6")),"label","6");
1693 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_7")),"label","7");
1694 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_8")),"label","8");
1695 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_9")),"label","9");
1696 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_0")),"label","0");
1697 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_#")),"label","#");
1698 g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*");
1701 void linphone_gtk_create_keypad(GtkWidget *button){
1702 GtkWidget *mw=linphone_gtk_get_main_window();
1703 GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad");
1705 gtk_widget_destroy(k);
1707 GtkWidget *keypad=linphone_gtk_create_window("keypad");
1708 linphone_gtk_connect_digits(keypad);
1709 linphone_gtk_init_dtmf_table(keypad);
1710 g_object_set_data(G_OBJECT(mw),"keypad",(gpointer)keypad);
1711 if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(mw),"show_abcd"))){
1712 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_A"));
1713 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_B"));
1714 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_C"));
1715 gtk_widget_hide(linphone_gtk_get_widget(keypad,"dtmf_D"));
1716 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(keypad,"dtmf_table")),4,3);
1718 gtk_widget_show(keypad);
1721 static void linphone_gtk_init_main_window(){
1722 GtkWidget *main_window;
1723 linphone_gtk_configure_main_window();
1724 linphone_gtk_manage_login();
1726 linphone_gtk_load_identities();
1727 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1728 linphone_gtk_show_friends();
1729 linphone_core_reset_missed_calls_count(linphone_gtk_get_core());
1730 main_window=linphone_gtk_get_main_window();
1731 linphone_gtk_call_log_update(main_window);
1733 linphone_gtk_update_call_buttons (NULL);
1734 g_object_set_data(G_OBJECT(main_window),"keypad",NULL);
1735 g_object_set_data(G_OBJECT(main_window),"is_conf",GINT_TO_POINTER(FALSE));
1736 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1737 g_signal_connect (G_OBJECT (main_window), "delete-event",
1738 G_CALLBACK (linphone_gtk_close), main_window);
1741 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1742 GtkosxApplication *theMacApp = gtkosx_application_get();
1743 gtkosx_application_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1744 gtk_widget_hide(menubar);
1745 gtkosx_application_ready(theMacApp);
1747 g_signal_connect(G_OBJECT(main_window), "window-state-event",G_CALLBACK(on_window_state_event), NULL);
1749 linphone_gtk_check_menu_items();
1752 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1754 const char *lname="undef";
1756 #if defined(__linux) || defined(__APPLE__)
1757 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1776 g_error("Bad level !");
1778 #if defined(__linux) || defined(__APPLE__)
1780 msg=g_strdup_vprintf(fmt,cap);
1783 msg=g_strdup_vprintf(fmt,args);
1785 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1788 linphone_gtk_log_push(lev,fmt,args);
1792 void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1793 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1794 linphone_gtk_get_main_window(), "uribar"));
1796 linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
1798 gtk_entry_set_text(uri_bar, refer_to);
1799 linphone_gtk_start_call(linphone_gtk_get_main_window());
1802 static void linphone_gtk_check_soundcards(){
1803 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1804 if (devices==NULL || devices[0]==NULL){
1805 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1806 _("No sound cards have been detected on this computer.\n"
1807 "You won't be able to send or receive audio calls."));
1811 static void linphone_gtk_quit(void){
1812 static gboolean quit_done=FALSE;
1815 linphone_gtk_unmonitor_usb();
1816 g_source_remove_by_user_data(linphone_gtk_get_core());
1818 linphone_gtk_close_assistant();
1820 linphone_gtk_uninit_instance();
1821 linphone_gtk_destroy_log_window();
1822 linphone_core_destroy(the_core);
1823 linphone_gtk_log_uninit();
1827 gdk_threads_leave();
1833 This is not the correct way to implement block termination.
1834 The good way would be to call gtk_main_quit(), and return TRUE.
1835 Unfortunately this does not work, because if we return TRUE the NSApplication sometimes calls the CFRunLoop recursively, which prevents gtk_main() to exit.
1836 As a result the program cannot exit at all.
1837 As a workaround we do all the cleanup (unregistration and config save) within the handler.
1839 static gboolean on_block_termination(void){
1841 linphone_gtk_quit();
1846 int main(int argc, char *argv[]){
1851 const char *factory_config_file;
1853 GtkSettings *settings;
1855 const char *app_name="Linphone";
1857 const char *db_file;
1859 #if !GLIB_CHECK_VERSION(2, 31, 0)
1860 g_thread_init(NULL);
1864 progpath = strdup(argv[0]);
1866 config_file=linphone_gtk_get_config_file(NULL);
1870 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1871 if ((lang=getenv("LANG"))!=NULL){
1874 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1880 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1883 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1886 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1888 if (strncmp(lang,"zh",2)==0){
1889 workaround_gtk_entry_chinese_bug=TRUE;
1892 setenv("LANG",lang,1);
1894 setenv("LANGUAGE",lang,1);
1899 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1900 if (p==NULL) perror("bindtextdomain failed");
1901 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1902 textdomain (GETTEXT_PACKAGE);
1904 g_message("NLS disabled.\n");
1907 gtk_rc_add_default_file("./gtkrc");
1909 gdk_threads_enter();
1911 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1912 linphone_options,NULL,NULL)){
1913 gdk_threads_leave();
1917 settings=gtk_settings_get_default();
1918 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1919 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1920 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1921 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1923 if (workingdir!=NULL){
1924 if (chdir(workingdir)==-1){
1925 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1929 /* Now, look for the factory configuration file, we do it this late
1930 since we want to have had time to change directory and to parse
1931 the options, in case we needed to access the working directory */
1932 factory_config_file = linphone_gtk_get_factory_config_file();
1933 if (factory_config_file){
1934 factory=lp_config_new(NULL);
1935 lp_config_read_file(factory,factory_config_file);
1936 app_name=lp_config_get_string(factory,"GtkUi","title","Linphone");
1939 if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
1940 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1941 g_warning("This instance is going to exit now.");
1942 gdk_threads_leave();
1946 add_pixmap_directory("pixmaps");
1947 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1950 GtkosxApplication *theMacApp = gtkosx_application_get();
1951 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1952 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1953 /*never block termination:*/
1954 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
1957 the_ui=linphone_gtk_create_window("main");
1959 g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
1961 linphone_gtk_create_log_window();
1962 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1964 db_file=linphone_gtk_message_storage_get_db_file(NULL);
1965 linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file);
1967 g_set_application_name(app_name);
1968 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1969 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1971 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1972 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1973 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1974 linphone_gtk_init_main_window();
1977 // Veryfing if at least one sip account is configured. If not, show wizard
1978 if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
1979 linphone_gtk_show_assistant();
1983 #ifndef HAVE_GTK_OSX
1984 linphone_gtk_init_status_icon();
1987 linphone_gtk_show_main_window();
1988 linphone_gtk_check_soundcards();
1990 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1991 linphone_gtk_check_for_new_version();
1992 linphone_gtk_monitor_usb();
1995 linphone_gtk_quit();
1996 #ifndef HAVE_GTK_OSX
1997 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1998 gtk_status_icon_set_visible(icon,FALSE);