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 1
27 #include <sys/types.h>
32 #include <gtkosxapplication.h>
39 #define LINPHONE_ICON "linphone.png"
41 const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
43 static LinphoneCore *the_core=NULL;
44 static GtkWidget *the_ui=NULL;
46 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
47 static void linphone_gtk_show(LinphoneCore *lc);
48 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
49 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
50 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
51 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
52 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
53 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
54 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
55 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
56 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
57 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
58 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
61 static gboolean verbose=0;
62 static gboolean auto_answer = 0;
63 static gchar * addr_to_call = NULL;
64 static gboolean iconified=FALSE;
65 static gchar *workingdir=NULL;
66 static char *progpath=NULL;
67 gchar *linphone_logfile=NULL;
69 static GOptionEntry linphone_options[]={
73 .arg=G_OPTION_ARG_NONE,
74 .arg_data= (gpointer)&verbose,
75 .description=N_("log to stdout some debug information while running.")
78 .long_name = "logfile",
80 .arg = G_OPTION_ARG_STRING,
81 .arg_data = &linphone_logfile,
82 .description = N_("path to a file to write logs into.")
85 .long_name="iconified",
87 .arg=G_OPTION_ARG_NONE,
88 .arg_data= (gpointer)&iconified,
89 .description=N_("Start only in the system tray, do not show the main interface.")
94 .arg = G_OPTION_ARG_STRING,
95 .arg_data = &addr_to_call,
96 .description = N_("address to call right now")
99 .long_name = "auto-answer",
101 .arg = G_OPTION_ARG_NONE,
102 .arg_data = (gpointer) & auto_answer,
103 .description = N_("if set automatically answer incoming calls")
106 .long_name = "workdir",
108 .arg = G_OPTION_ARG_STRING,
109 .arg_data = (gpointer) & workingdir,
110 .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
115 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
116 #define BUILD_TREE_XML_DIR "gtk"
119 #define CONFIG_FILE ".linphonerc"
121 #define CONFIG_FILE "linphonerc"
126 static char _config_file[1024];
129 const char *linphone_gtk_get_config_file(){
130 /*try accessing a local file first if exists*/
131 if (access(CONFIG_FILE,F_OK)==0){
132 snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
135 const char *appdata=getenv("APPDATA");
137 snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
138 CreateDirectory(_config_file,NULL);
139 snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR "\\" CONFIG_FILE);
142 const char *home=getenv("HOME");
143 if (home==NULL) home=".";
144 snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
151 #define FACTORY_CONFIG_FILE "linphonerc.factory"
152 static char _factory_config_file[1024];
153 static const char *linphone_gtk_get_factory_config_file(){
154 /*try accessing a local file first if exists*/
155 if (access(FACTORY_CONFIG_FILE,F_OK)==0){
156 snprintf(_factory_config_file,sizeof(_factory_config_file),
157 "%s",FACTORY_CONFIG_FILE);
161 if (progpath != NULL) {
163 progdir = strdup(progpath);
165 basename = strrchr(progdir, '\\');
166 if (basename != NULL) {
169 snprintf(_factory_config_file, sizeof(_factory_config_file),
170 "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
172 if (workingdir!=NULL) {
173 snprintf(_factory_config_file, sizeof(_factory_config_file),
174 "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
181 basename = strrchr(progdir, '/');
182 if (basename != NULL) {
185 snprintf(_factory_config_file, sizeof(_factory_config_file),
186 "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
195 return _factory_config_file;
198 static void linphone_gtk_init_liblinphone(const char *config_file,
199 const char *factory_config_file) {
200 LinphoneCoreVTable vtable={0};
202 vtable.call_state_changed=linphone_gtk_call_state_changed;
203 vtable.registration_state_changed=linphone_gtk_registration_state_changed;
204 vtable.show=linphone_gtk_show;
205 vtable.notify_presence_recv=linphone_gtk_notify_recv;
206 vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
207 vtable.auth_info_requested=linphone_gtk_auth_info_requested;
208 vtable.display_status=linphone_gtk_display_status;
209 vtable.display_message=linphone_gtk_display_message;
210 vtable.display_warning=linphone_gtk_display_warning;
211 vtable.display_url=linphone_gtk_display_url;
212 vtable.call_log_updated=linphone_gtk_call_log_updated;
213 vtable.text_received=linphone_gtk_text_received;
214 vtable.refer_received=linphone_gtk_refer_received;
215 vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
217 linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
218 the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
219 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
224 LinphoneCore *linphone_gtk_get_core(void){
228 GtkWidget *linphone_gtk_get_main_window(){
232 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
233 static const char *icon_path=NULL;
234 static const char *hiddens=NULL;
235 static const char *shown=NULL;
236 static bool_t config_loaded=FALSE;
237 if (linphone_gtk_get_core()==NULL) return;
238 if (config_loaded==FALSE){
239 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
240 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
241 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
245 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
247 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
249 GdkPixbuf *pbuf=create_pixbuf(icon_path);
250 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
251 g_object_unref(G_OBJECT(pbuf));
255 static int get_ui_file(const char *name, char *path, int pathsize){
256 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
257 if (access(path,F_OK)!=0){
258 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
259 if (access(path,F_OK)!=0){
260 g_error("Could not locate neither %s/%s.ui and %s/%s.ui .",BUILD_TREE_XML_DIR,name,
261 INSTALLED_XML_DIR,name);
268 GtkWidget *linphone_gtk_create_window(const char *window_name){
269 GError* error = NULL;
270 GtkBuilder* builder = gtk_builder_new ();
274 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
276 if (!gtk_builder_add_from_file (builder, path, &error)){
277 g_error("Couldn't load builder file: %s", error->message);
278 g_error_free (error);
281 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
283 g_error("Could not retrieve '%s' window from xml file",window_name);
286 g_object_set_data(G_OBJECT(w),"builder",builder);
287 gtk_builder_connect_signals(builder,w);
288 linphone_gtk_configure_window(w,window_name);
292 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
295 GtkBuilder* builder = gtk_builder_new ();
297 gchar *object_ids[2];
298 object_ids[0]=g_strdup(widget_name);
301 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
302 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
303 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
304 g_error_free (error);
305 g_free(object_ids[0]);
308 g_free(object_ids[0]);
309 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
311 g_error("Could not retrieve '%s' window from xml file",widget_name);
314 g_object_set_data(G_OBJECT(w),"builder",builder);
315 gtk_builder_connect_signals(builder,w);
319 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
320 GtkBuilder *builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
323 g_error("Fail to retrieve builder from window !");
326 w=gtk_builder_get_object(builder,name);
328 g_error("No widget named %s found in xml interface.",name);
330 return GTK_WIDGET(w);
334 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
336 GtkWidget *main_window=linphone_gtk_get_main_window();
338 gtk_widget_show(main_window);
339 if (type==GTK_MESSAGE_QUESTION)
341 /* draw a question box. link to dialog_click callback */
342 dialog = gtk_message_dialog_new (
343 GTK_WINDOW(main_window),
344 GTK_DIALOG_DESTROY_WITH_PARENT,
345 GTK_MESSAGE_QUESTION,
348 (const gchar*)message);
349 /* connect to some callback : REVISIT */
351 g_signal_connect_swapped (G_OBJECT (dialog), "response",
352 G_CALLBACK (dialog_click),
355 /* actually show the box */
356 gtk_widget_show(dialog);
360 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
361 GTK_DIALOG_DESTROY_WITH_PARENT,
365 (const gchar*)message);
366 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
367 g_signal_connect_swapped (G_OBJECT (dialog), "response",
368 G_CALLBACK (gtk_widget_destroy),
370 gtk_widget_show(dialog);
374 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
375 if (id==GTK_RESPONSE_CANCEL){
376 gtk_widget_destroy(GTK_WIDGET(dialog));
380 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
381 g_message("About url clicked");
382 linphone_gtk_open_browser(url);
385 void linphone_gtk_show_about(){
386 struct stat filestat;
387 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
390 GdkPixbuf *logo=create_pixbuf(
391 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
392 static const char *defcfg="defcfg";
394 about=linphone_gtk_create_window("about");
395 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
396 memset(&filestat,0,sizeof(filestat));
397 if (stat(license_file,&filestat)!=0){
398 license_file="COPYING";
399 stat(license_file,&filestat);
401 if (filestat.st_size>0){
402 char *license=g_malloc(filestat.st_size+1);
403 FILE *f=fopen(license_file,"r");
404 if (f && fread(license,filestat.st_size,1,f)==1){
405 license[filestat.st_size]='\0';
406 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
410 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
411 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
412 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
413 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
414 tmp=linphone_gtk_get_ui_config("artists",defcfg);
419 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
421 tmp=linphone_gtk_get_ui_config("translators",defcfg);
423 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
424 tmp=linphone_gtk_get_ui_config("comments",defcfg);
426 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
427 gtk_widget_show(about);
430 static void set_video_window_decorations(GdkWindow *w){
431 const char *title=linphone_gtk_get_ui_config("title","Linphone");
432 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
433 char video_title[256];
434 GdkPixbuf *pbuf=create_pixbuf(icon_path);
435 if (!linphone_core_in_call(linphone_gtk_get_core())){
436 snprintf(video_title,sizeof(video_title),"%s video",title);
437 /* When not in call, treat the video as a normal window */
438 gdk_window_set_keep_above(w, FALSE);
440 LinphoneAddress *uri =
441 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
444 linphone_address_clean(uri);
445 if (linphone_address_get_display_name(uri)!=NULL){
446 display_name=ms_strdup(linphone_address_get_display_name(uri));
448 display_name=linphone_address_as_string(uri);
450 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
451 linphone_address_destroy(uri);
452 ms_free(display_name);
454 /* During calls, bring up the video window, arrange so that
455 it is above all the other windows */
456 gdk_window_deiconify(w);
457 gdk_window_set_keep_above(w,TRUE);
458 /* Maybe we should have the following, but then we want to
459 have a timer that turns it off after a little while. */
460 /* gdk_window_set_urgency_hint(w,TRUE); */
462 gdk_window_set_title(w,video_title);
463 /* Refrain the video window to be closed at all times. */
464 gdk_window_set_functions(w,
465 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
466 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
469 l=g_list_append(l,pbuf);
470 gdk_window_set_icon_list(w,l);
472 g_object_unref(G_OBJECT(pbuf));
476 static gboolean video_needs_update=FALSE;
478 static void update_video_title(){
479 video_needs_update=TRUE;
482 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
483 static gboolean first_time=TRUE;
485 static unsigned long previd=0;
486 static unsigned long preview_previd=0;
487 static gboolean in_iterate=FALSE;
490 if (in_iterate) return TRUE;
492 linphone_core_iterate(lc);
494 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
495 linphone_gtk_show_directory_search();
499 id=linphone_core_get_native_video_window_id(lc);
500 if (id!=previd || video_needs_update){
504 ms_message("Updating window decorations");
506 w=gdk_window_foreign_new(id);
508 w=gdk_window_foreign_new((HANDLE)id);
511 set_video_window_decorations(w);
512 g_object_unref(G_OBJECT(w));
514 else ms_error("gdk_window_foreign_new() failed");
515 if (video_needs_update) video_needs_update=FALSE;
518 id=linphone_core_get_native_preview_window_id (lc);
519 if (id!=preview_previd ){
523 ms_message("Updating window decorations for preview");
525 w=gdk_window_foreign_new(id);
527 w=gdk_window_foreign_new((HANDLE)id);
530 set_video_window_decorations(w);
531 g_object_unref(G_OBJECT(w));
533 else ms_error("gdk_window_foreign_new() failed");
534 if (video_needs_update) video_needs_update=FALSE;
537 if (addr_to_call!=NULL){
538 /*make sure we are not showing the login screen*/
539 GtkWidget *mw=linphone_gtk_get_main_window();
540 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
541 if (!GTK_WIDGET_VISIBLE(login_frame)){
542 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
543 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
545 linphone_gtk_start_call(uri_bar);
552 static void load_uri_history(){
553 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
556 GtkEntryCompletion *gep=gtk_entry_completion_new();
557 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
560 snprintf(key,sizeof(key),"uri%i",i);
561 uri=linphone_gtk_get_ui_config(key,NULL);
564 gtk_list_store_append(model,&iter);
565 gtk_list_store_set(model,&iter,0,uri,-1);
566 if (i==0) gtk_entry_set_text(uribar,uri);
570 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
571 gtk_entry_completion_set_text_column(gep,0);
572 gtk_entry_set_completion(uribar,gep);
575 static void save_uri_history(){
576 LinphoneCore *lc=linphone_gtk_get_core();
577 LpConfig *cfg=linphone_core_get_config(lc);
578 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
583 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
585 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
587 gtk_tree_model_get(model,&iter,0,&uri,-1);
589 snprintf(key,sizeof(key),"uri%i",i);
590 lp_config_set_string(cfg,"GtkUi",key,uri);
595 }while(gtk_tree_model_iter_next(model,&iter));
599 static void completion_add_text(GtkEntry *entry, const char *text){
601 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
603 if (gtk_tree_model_get_iter_first(model,&iter)){
606 gtk_tree_model_get(model,&iter,0,&uri,-1);
608 if (strcmp(uri,text)==0) {
610 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
616 }while (gtk_tree_model_iter_next(model,&iter));
618 /* and prepend it on top of the list */
619 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
620 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
624 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
625 GtkWidget *mw=linphone_gtk_get_main_window();
626 if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){
627 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
628 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
630 if (linphone_gtk_use_in_call_view() && call)
631 linphone_gtk_in_call_view_terminate(call,error);
632 update_video_title();
635 static gboolean in_call_timer(){
636 LinphoneCall *call=linphone_core_get_current_call(linphone_gtk_get_core());
638 linphone_gtk_in_call_view_update_duration(call);
644 static bool_t all_other_calls_paused(LinphoneCall *refcall, const MSList *calls){
645 for(;calls!=NULL;calls=calls->next){
646 LinphoneCall *call=(LinphoneCall*)calls->data;
647 LinphoneCallState cs=linphone_call_get_state(call);
649 if (cs!=LinphoneCallPaused && cs!=LinphoneCallPausing)
656 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
657 LinphoneCore *lc=linphone_gtk_get_core();
658 GtkWidget *mw=linphone_gtk_get_main_window();
659 const MSList *calls=linphone_core_get_calls(lc);
661 bool_t start_active=TRUE;
662 bool_t stop_active=FALSE;
663 bool_t add_call=FALSE;
664 int call_list_size=ms_list_size(calls);
671 if (all_other_calls_paused(NULL,calls)){
674 }else if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived && all_other_calls_paused(call,calls)){
675 if (call_list_size>1){
686 button=linphone_gtk_get_widget(mw,"start_call");
687 gtk_widget_set_sensitive(button,start_active);
688 gtk_widget_set_visible(button,!add_call);
690 button=linphone_gtk_get_widget(mw,"add_call");
691 gtk_widget_set_sensitive(button,start_active);
692 gtk_widget_set_visible(button,add_call);
694 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
695 if (linphone_core_get_calls(lc)==NULL){
696 linphone_gtk_enable_mute_button(
697 GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
700 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
701 update_video_title();
704 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
705 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
706 if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
707 completion_add_text(GTK_ENTRY(uri_bar),entered);
709 linphone_gtk_call_terminated(NULL,NULL);
714 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
715 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
716 linphone_core_accept_call (linphone_gtk_get_core(),call);
717 linphone_call_unref(call);
723 void linphone_gtk_start_call(GtkWidget *w){
724 LinphoneCore *lc=linphone_gtk_get_core();
726 /*change into in-call mode, then do the work later as it might block a bit */
727 GtkWidget *mw=gtk_widget_get_toplevel(w);
728 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
730 call=linphone_gtk_get_currently_displayed_call ();
731 if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
732 linphone_core_accept_call(lc,call);
734 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
735 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
736 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
737 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
742 void linphone_gtk_uri_bar_activate(GtkWidget *w){
743 linphone_gtk_start_call(w);
747 void linphone_gtk_terminate_call(GtkWidget *button){
748 LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
750 linphone_core_terminate_call(linphone_gtk_get_core(),call);
753 void linphone_gtk_decline_clicked(GtkWidget *button){
754 LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
756 linphone_core_terminate_call(linphone_gtk_get_core(),call);
759 void linphone_gtk_answer_clicked(GtkWidget *button){
760 LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
762 linphone_core_pause_all_calls(linphone_gtk_get_core());
763 linphone_core_accept_call(linphone_gtk_get_core(),call);
767 void linphone_gtk_set_audio_video(){
768 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
769 linphone_core_enable_video_preview(linphone_gtk_get_core(),
770 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
773 void linphone_gtk_set_audio_only(){
774 linphone_core_enable_video(linphone_gtk_get_core(),FALSE,FALSE);
775 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
778 void linphone_gtk_enable_self_view(GtkWidget *w){
779 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
780 LinphoneCore *lc=linphone_gtk_get_core();
781 linphone_core_enable_video_preview(lc,val);
782 linphone_core_enable_self_view(lc,val);
783 linphone_gtk_set_ui_config_int("videoselfview",val);
786 void linphone_gtk_used_identity_changed(GtkWidget *w){
787 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
788 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
789 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
790 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
791 linphone_gtk_show_directory_search();
793 if (sel) g_free(sel);
796 static void linphone_gtk_show_main_window(){
797 GtkWidget *w=linphone_gtk_get_main_window();
798 LinphoneCore *lc=linphone_gtk_get_core();
799 if (linphone_core_video_enabled(lc)){
800 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
801 VIDEOSELFVIEW_DEFAULT));
804 gtk_window_present(GTK_WINDOW(w));
807 static void linphone_gtk_show(LinphoneCore *lc){
808 linphone_gtk_show_main_window();
811 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
812 linphone_gtk_show_friends();
815 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
817 case GTK_RESPONSE_YES:
818 linphone_gtk_show_contact(lf);
821 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
823 gtk_widget_destroy(dialog);
826 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
829 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
830 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
834 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);
835 dialog = gtk_message_dialog_new (
836 GTK_WINDOW(linphone_gtk_get_main_window()),
837 GTK_DIALOG_DESTROY_WITH_PARENT,
838 GTK_MESSAGE_QUESTION,
843 g_signal_connect(G_OBJECT (dialog), "response",
844 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
845 /* actually show the box */
846 gtk_widget_show(dialog);
849 typedef struct _AuthTimeout{
854 static void auth_timeout_clean(AuthTimeout *tout){
858 static gboolean auth_timeout_destroy(AuthTimeout *tout){
860 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
861 gtk_widget_destroy(tout->w);
867 static AuthTimeout * auth_timeout_new(GtkWidget *w){
868 AuthTimeout *tout=g_new(AuthTimeout,1);
870 /*so that the timeout no more references the widget when it is destroyed:*/
871 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
872 /*so that the widget is automatically destroyed after some time */
873 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
877 void linphone_gtk_password_cancel(GtkWidget *w){
878 LinphoneAuthInfo *info;
879 GtkWidget *window=gtk_widget_get_toplevel(w);
880 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
881 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
882 gtk_widget_destroy(window);
885 void linphone_gtk_password_ok(GtkWidget *w){
887 GtkWidget *window=gtk_widget_get_toplevel(w);
888 LinphoneAuthInfo *info;
889 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
890 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
891 entry=linphone_gtk_get_widget(window,"password_entry");
892 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
893 linphone_auth_info_set_userid(info,
894 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
895 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
896 gtk_widget_destroy(window);
899 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
900 GtkWidget *w=linphone_gtk_create_window("password");
901 GtkWidget *label=linphone_gtk_get_widget(w,"message");
902 LinphoneAuthInfo *info;
904 GtkWidget *mw=linphone_gtk_get_main_window();
906 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
907 /*don't prompt for authentication when login frame is visible*/
908 linphone_core_abort_authentication(lc,NULL);
912 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
914 gtk_label_set_markup(GTK_LABEL(label),msg);
916 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
917 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
918 g_object_set_data(G_OBJECT(w),"auth_info",info);
919 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
924 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
925 GtkWidget *w=linphone_gtk_get_main_window();
926 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
927 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
928 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
932 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
933 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
936 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
937 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
940 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
942 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
943 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
946 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
947 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
948 if (w) linphone_gtk_call_log_update(w);
951 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
953 case LinphoneCallOutgoingInit:
954 linphone_gtk_create_in_call_view (call);
956 case LinphoneCallOutgoingProgress:
957 linphone_gtk_in_call_view_set_calling (call);
959 case LinphoneCallStreamsRunning:
960 linphone_gtk_in_call_view_set_in_call(call);
961 linphone_gtk_enable_mute_button(
962 GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
964 g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
966 case LinphoneCallError:
967 linphone_gtk_in_call_view_terminate (call,msg);
969 case LinphoneCallEnd:
970 linphone_gtk_in_call_view_terminate(call,NULL);
972 case LinphoneCallIncomingReceived:
973 linphone_gtk_create_in_call_view (call);
974 linphone_gtk_in_call_view_set_incoming(call,!all_other_calls_paused (call,linphone_core_get_calls(lc)));
976 linphone_call_ref(call);
977 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
980 case LinphoneCallResuming:
981 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
982 linphone_gtk_in_call_view_set_in_call (call);
984 case LinphoneCallPausing:
985 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
986 case LinphoneCallPausedByRemote:
987 linphone_gtk_in_call_view_set_paused(call);
989 case LinphoneCallConnected:
990 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
995 linphone_gtk_update_call_buttons (call);
998 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
999 LinphoneRegistrationState rs, const char *msg){
1001 case LinphoneRegistrationOk:
1003 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1004 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1005 linphone_gtk_exit_login_frame();
1015 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1016 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1017 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1020 void linphone_gtk_open_browser(const char *url){
1021 /*in gtk 2.16, gtk_show_uri does not work...*/
1023 #if GTK_CHECK_VERSION(2,18,3)
1024 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1027 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1028 g_spawn_command_line_async(cl,NULL);
1031 ShellExecute(0,"open",url,NULL,NULL,1);
1035 void linphone_gtk_link_to_website(GtkWidget *item){
1036 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1037 linphone_gtk_open_browser(home);
1040 static GtkWidget *create_icon_menu(){
1041 GtkWidget *menu=gtk_menu_new();
1042 GtkWidget *menu_item;
1045 const gchar *homesite;
1047 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1048 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1049 tmp=g_strdup(homesite);
1050 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1051 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1053 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1054 gtk_widget_show(image);
1055 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1056 //g_object_unref(G_OBJECT(image));
1057 gtk_widget_show(menu_item);
1058 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1059 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1061 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1062 gtk_widget_show(menu_item);
1063 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1064 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1065 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1066 gtk_widget_show(menu_item);
1067 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1068 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1069 gtk_widget_show(menu);
1073 static GtkStatusIcon *icon=NULL;
1075 static void linphone_gtk_init_status_icon(){
1076 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1077 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1078 GtkWidget *menu=create_icon_menu();
1080 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1081 g_object_unref(G_OBJECT(pbuf));
1082 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
1083 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1084 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1085 gtk_status_icon_set_tooltip(icon,title);
1086 gtk_status_icon_set_visible(icon,TRUE);
1087 g_object_set_data(G_OBJECT(icon),"menu",menu);
1088 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1091 void linphone_gtk_load_identities(void){
1093 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1095 LinphoneProxyConfig *def=NULL;
1097 GtkListStore *store;
1099 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1100 gtk_list_store_clear(store);
1102 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1103 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1104 gtk_combo_box_append_text(box,def_identity);
1105 g_free(def_identity);
1106 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1108 elem=ms_list_next(elem),i++){
1109 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1110 gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg));
1115 gtk_combo_box_set_active(box,def_index);
1118 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1119 const char *label=gtk_button_get_label(button);
1120 GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1122 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1123 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1124 if (linphone_core_in_call(linphone_gtk_get_core())){
1125 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1129 static void linphone_gtk_dtmf_released(GtkButton *button){
1130 linphone_core_stop_dtmf (linphone_gtk_get_core());
1133 static void linphone_gtk_connect_digits(void){
1134 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1135 GList *children=gtk_container_get_children(cont);
1137 for(elem=children;elem!=NULL;elem=elem->next){
1138 GtkButton *button=GTK_BUTTON(elem->data);
1139 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1140 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1144 static void linphone_gtk_check_menu_items(void){
1145 bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core());
1146 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1147 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1148 linphone_gtk_get_main_window(),
1149 audio_only ? "audio_only_item" : "video_item")), TRUE);
1150 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1151 linphone_gtk_get_main_window(),"selfview_item")),selfview);
1154 static gboolean linphone_gtk_can_manage_accounts(){
1155 LinphoneCore *lc=linphone_gtk_get_core();
1157 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1158 SipSetup *ss=(SipSetup*)elem->data;
1159 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1166 static void linphone_gtk_configure_main_window(){
1167 static gboolean config_loaded=FALSE;
1168 static const char *title;
1169 static const char *home;
1170 static const char *start_call_icon;
1171 static const char *add_call_icon;
1172 static const char *stop_call_icon;
1173 static const char *search_icon;
1174 static gboolean update_check_menu;
1175 static gboolean buttons_have_borders;
1176 static gboolean show_abcd;
1177 GtkWidget *w=linphone_gtk_get_main_window();
1178 if (!config_loaded){
1179 title=linphone_gtk_get_ui_config("title","Linphone");
1180 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1181 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1182 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1183 stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
1184 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1185 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1186 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1187 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1190 linphone_gtk_configure_window(w,"main_window");
1192 gtk_window_set_title(GTK_WINDOW(w),title);
1193 #if GTK_CHECK_VERSION(2,16,0)
1195 gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),_("Windows"));
1197 gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),title);
1201 if (start_call_icon){
1202 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1203 create_pixmap (start_call_icon));
1204 if (!buttons_have_borders)
1205 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1208 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1209 create_pixmap (add_call_icon));
1210 if (!buttons_have_borders)
1211 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1213 if (stop_call_icon){
1214 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),
1215 create_pixmap (stop_call_icon));
1216 if (!buttons_have_borders)
1217 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NONE);
1220 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1221 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1222 g_object_unref(G_OBJECT(pbuf));
1226 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1228 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1231 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1233 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1234 g_object_unref(G_OBJECT(pbuf));
1238 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1240 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")),pbuf);
1241 g_object_unref(G_OBJECT(pbuf));
1244 if (linphone_gtk_can_manage_accounts())
1245 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1246 if (update_check_menu){
1247 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1250 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1251 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1252 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1253 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1254 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1258 void linphone_gtk_manage_login(void){
1259 LinphoneCore *lc=linphone_gtk_get_core();
1260 LinphoneProxyConfig *cfg=NULL;
1261 linphone_core_get_default_proxy(lc,&cfg);
1263 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1264 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1265 linphone_gtk_show_login_frame(cfg);
1271 gboolean linphone_gtk_close(GtkWidget *mw){
1272 /*shutdown calls if any*/
1273 LinphoneCore *lc=linphone_gtk_get_core();
1274 if (linphone_core_in_call(lc)){
1275 linphone_core_terminate_all_calls(lc);
1277 linphone_core_enable_video_preview(lc,FALSE);
1278 #ifdef __APPLE__ /*until with have a better option*/
1279 gtk_window_iconify(GTK_WINDOW(mw));
1281 gtk_widget_hide(mw);
1286 static void linphone_gtk_init_main_window(){
1287 GtkWidget *main_window;
1289 linphone_gtk_configure_main_window();
1290 linphone_gtk_manage_login();
1292 linphone_gtk_load_identities();
1293 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1294 linphone_gtk_show_friends();
1295 linphone_gtk_connect_digits();
1296 main_window=linphone_gtk_get_main_window();
1297 linphone_gtk_enable_mute_button(GTK_BUTTON(linphone_gtk_get_widget(main_window,
1298 "main_mute")),FALSE);
1299 if (!linphone_gtk_use_in_call_view()) {
1300 gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
1302 linphone_gtk_update_call_buttons (NULL);
1303 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1304 g_signal_connect (G_OBJECT (main_window), "delete-event",
1305 G_CALLBACK (linphone_gtk_close), main_window);
1308 GtkWidget *menubar=linphone_gtk_get_widget(main_window,"menubar1");
1309 gtk_widget_destroy(linphone_gtk_get_widget(main_window,"imagemenuitem5"));
1310 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1311 gtk_osxapplication_set_menu_bar(theMacApp,GTK_MENU_SHELL(menubar));
1312 gtk_widget_hide(menubar);
1313 gtk_osxapplication_ready(theMacApp);
1316 linphone_gtk_check_menu_items();
1320 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1322 const char *lname="undef";
1324 #if defined(__linux) || defined(__APPLE__)
1325 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1344 g_error("Bad level !");
1346 #if defined(__linux) || defined(__APPLE__)
1348 msg=g_strdup_vprintf(fmt,cap);
1351 msg=g_strdup_vprintf(fmt,args);
1353 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1356 linphone_gtk_log_push(lev,fmt,args);
1360 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1361 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1362 linphone_gtk_get_main_window(), "uribar"));
1363 linphone_gtk_show_main_window();
1364 gtk_entry_set_text(uri_bar, refer_to);
1365 linphone_gtk_start_call(linphone_gtk_get_main_window());
1368 static void linphone_gtk_check_soundcards(){
1369 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1370 if (devices==NULL || devices[0]==NULL){
1371 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1372 _("No sound cards have been detected on this computer.\n"
1373 "You won't be able to send or receive audio calls."));
1377 int main(int argc, char *argv[]){
1381 const char *config_file;
1382 const char *factory_config_file;
1384 GtkSettings *settings;
1387 g_thread_init(NULL);
1390 progpath = strdup(argv[0]);
1392 config_file=linphone_gtk_get_config_file();
1395 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1396 if ((lang=getenv("LANG"))!=NULL){
1399 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1405 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1408 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1411 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1414 setenv("LANG",lang,1);
1419 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1420 if (p==NULL) perror("bindtextdomain failed");
1421 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1422 textdomain (GETTEXT_PACKAGE);
1424 g_message("NLS disabled.\n");
1427 gtk_rc_add_default_file("./gtkrc");
1429 gdk_threads_enter();
1431 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1432 linphone_options,NULL,NULL)){
1433 gdk_threads_leave();
1437 settings=gtk_settings_get_default();
1438 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1439 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1440 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1441 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1443 if (workingdir!=NULL){
1444 if (chdir(workingdir)==-1){
1445 g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
1449 /* Now, look for the factory configuration file, we do it this late
1450 since we want to have had time to change directory and to parse
1451 the options, in case we needed to access the working directory */
1452 factory_config_file = linphone_gtk_get_factory_config_file();
1454 if (linphone_core_wake_up_possible_already_running_instance(
1455 config_file, addr_to_call) == 0){
1456 g_message("addr_to_call=%s",addr_to_call);
1457 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1458 g_warning("This instance is going to exit now.");
1459 gdk_threads_leave();
1463 add_pixmap_directory("pixmaps");
1464 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1467 GtkOSXApplication *theMacApp = (GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL);
1468 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL);
1469 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationWillTerminate",(GCallback)gtk_main_quit,NULL);
1470 /*never block termination:*/
1471 g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)gtk_false,NULL);
1474 the_ui=linphone_gtk_create_window("main");
1476 linphone_gtk_create_log_window();
1477 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1479 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1481 g_set_application_name(linphone_gtk_get_ui_config("title","Linphone"));
1482 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1483 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1485 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1486 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1487 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1488 linphone_gtk_init_main_window();
1489 #ifndef HAVE_GTK_OSX
1490 linphone_gtk_init_status_icon();
1493 linphone_gtk_show_main_window();
1494 linphone_gtk_check_soundcards();
1496 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1497 linphone_gtk_check_for_new_version();
1500 gdk_threads_leave();
1501 linphone_gtk_destroy_log_window();
1502 linphone_core_destroy(the_core);
1503 linphone_gtk_log_uninit();
1504 #ifndef HAVE_GTK_OSX
1505 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1506 gtk_status_icon_set_visible(icon,FALSE);