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.
20 //#define USE_LIBGLADE 1
22 #define VIDEOSELFVIEW_DEFAULT 1
30 #include <glade/glade.h>
33 #include <sys/types.h>
41 #define LINPHONE_ICON "linphone.png"
43 const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
45 static LinphoneCore *the_core=NULL;
46 static GtkWidget *the_ui=NULL;
48 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
49 static void linphone_gtk_show(LinphoneCore *lc);
50 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
51 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
52 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
53 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
54 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
55 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
56 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
57 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
58 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
59 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
60 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
63 static gboolean verbose=0;
64 static gboolean auto_answer = 0;
65 static gchar * addr_to_call = NULL;
66 static gboolean iconified=FALSE;
67 static gchar *workingdir=NULL;
68 static char *progpath=NULL;
70 static GOptionEntry linphone_options[]={
74 .arg=G_OPTION_ARG_NONE,
75 .arg_data= (gpointer)&verbose,
76 .description=N_("log to stdout some debug information while running.")
79 .long_name="iconified",
81 .arg=G_OPTION_ARG_NONE,
82 .arg_data= (gpointer)&iconified,
83 .description=N_("Start only in the system tray, do not show the main interface.")
88 .arg = G_OPTION_ARG_STRING,
89 .arg_data = &addr_to_call,
90 .description = N_("address to call right now")
93 .long_name = "auto-answer",
95 .arg = G_OPTION_ARG_NONE,
96 .arg_data = (gpointer) & auto_answer,
97 .description = N_("if set automatically answer incoming calls")
100 .long_name = "workdir",
102 .arg = G_OPTION_ARG_STRING,
103 .arg_data = (gpointer) & workingdir,
104 .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
109 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
110 #define BUILD_TREE_XML_DIR "gtk"
113 #define CONFIG_FILE ".linphonerc"
115 #define CONFIG_FILE "linphonerc"
120 static char _config_file[1024];
123 const char *linphone_gtk_get_config_file(){
124 /*try accessing a local file first if exists*/
125 if (access(CONFIG_FILE,F_OK)==0){
126 snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
129 const char *appdata=getenv("APPDATA");
131 snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
132 CreateDirectory(_config_file,NULL);
133 snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR "\\" CONFIG_FILE);
136 const char *home=getenv("HOME");
137 if (home==NULL) home=".";
138 snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
145 #define FACTORY_CONFIG_FILE "linphonerc.factory"
146 static char _factory_config_file[1024];
147 static const char *linphone_gtk_get_factory_config_file(){
148 /*try accessing a local file first if exists*/
149 if (access(FACTORY_CONFIG_FILE,F_OK)==0){
150 snprintf(_factory_config_file,sizeof(_factory_config_file),
151 "%s",FACTORY_CONFIG_FILE);
155 if (progpath != NULL) {
157 progdir = strdup(progpath);
159 basename = strrchr(progdir, '\\');
160 if (basename != NULL) {
163 snprintf(_factory_config_file, sizeof(_factory_config_file),
164 "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
166 if (workingdir!=NULL) {
167 snprintf(_factory_config_file, sizeof(_factory_config_file),
168 "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
175 basename = strrchr(progdir, '/');
176 if (basename != NULL) {
179 snprintf(_factory_config_file, sizeof(_factory_config_file),
180 "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
189 return _factory_config_file;
192 static void linphone_gtk_init_liblinphone(const char *config_file,
193 const char *factory_config_file) {
194 LinphoneCoreVTable vtable={0};
196 vtable.call_state_changed=linphone_gtk_call_state_changed;
197 vtable.registration_state_changed=linphone_gtk_registration_state_changed;
198 vtable.show=linphone_gtk_show;
199 vtable.notify_presence_recv=linphone_gtk_notify_recv;
200 vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber;
201 vtable.auth_info_requested=linphone_gtk_auth_info_requested;
202 vtable.display_status=linphone_gtk_display_status;
203 vtable.display_message=linphone_gtk_display_message;
204 vtable.display_warning=linphone_gtk_display_warning;
205 vtable.display_url=linphone_gtk_display_url;
206 vtable.call_log_updated=linphone_gtk_call_log_updated;
207 vtable.text_received=linphone_gtk_text_received;
208 vtable.refer_received=linphone_gtk_refer_received;
209 vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
211 linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
212 the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
213 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
218 LinphoneCore *linphone_gtk_get_core(void){
222 GtkWidget *linphone_gtk_get_main_window(){
226 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
227 static const char *icon_path=NULL;
228 static const char *hiddens=NULL;
229 static const char *shown=NULL;
230 static bool_t config_loaded=FALSE;
231 if (linphone_gtk_get_core()==NULL) return;
232 if (config_loaded==FALSE){
233 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
234 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
235 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
239 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
241 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
243 GdkPixbuf *pbuf=create_pixbuf(icon_path);
244 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
245 g_object_unref(G_OBJECT(pbuf));
251 GtkWidget *linphone_gtk_create_window(const char *window_name){
255 snprintf(path,sizeof(path),"%s/%s.glade",BUILD_TREE_XML_DIR,window_name);
256 if (access(path,F_OK)!=0){
257 snprintf(path,sizeof(path),"%s/%s.glade",INSTALLED_XML_DIR,window_name);
258 if (access(path,F_OK)!=0){
259 g_error("Could not locate neither %s/%s.glade and %s/%s.glade .",BUILD_TREE_XML_DIR,window_name,
260 INSTALLED_XML_DIR,window_name);
264 gxml=glade_xml_new(path,NULL,NULL);
265 glade_xml_signal_autoconnect(gxml);
266 w=glade_xml_get_widget(gxml,window_name);
267 if (w==NULL) g_error("Could not retrieve '%s' window from xml file",window_name);
268 linphone_gtk_configure_window(w,window_name);
272 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
274 GladeXML *gxml=glade_get_widget_tree(window);
275 if (gxml==NULL) g_error("Could not retrieve XML tree of window %s",name);
276 w=glade_xml_get_widget(gxml,name);
277 if (w==NULL) g_error("Could not retrieve widget %s",name);
278 return GTK_WIDGET(w);
283 static int get_ui_file(const char *name, char *path, int pathsize){
284 snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name);
285 if (access(path,F_OK)!=0){
286 snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name);
287 if (access(path,F_OK)!=0){
288 g_error("Could not locate neither %s/%s.ui and %s/%s.ui .",BUILD_TREE_XML_DIR,name,
289 INSTALLED_XML_DIR,name);
296 GtkWidget *linphone_gtk_create_window(const char *window_name){
297 GError* error = NULL;
298 GtkBuilder* builder = gtk_builder_new ();
302 if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
304 if (!gtk_builder_add_from_file (builder, path, &error)){
305 g_error("Couldn't load builder file: %s", error->message);
306 g_error_free (error);
309 w=GTK_WIDGET(gtk_builder_get_object (builder,window_name));
311 g_error("Could not retrieve '%s' window from xml file",window_name);
314 g_object_set_data(G_OBJECT(w),"builder",builder);
315 gtk_builder_connect_signals(builder,w);
316 linphone_gtk_configure_window(w,window_name);
320 GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){
323 GtkBuilder* builder = gtk_builder_new ();
325 gchar *object_ids[2];
326 object_ids[0]=g_strdup(widget_name);
329 if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
330 if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
331 g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
332 g_error_free (error);
333 g_free(object_ids[0]);
336 g_free(object_ids[0]);
337 w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name));
339 g_error("Could not retrieve '%s' window from xml file",widget_name);
342 g_object_set_data(G_OBJECT(w),"builder",builder);
343 gtk_builder_connect_signals(builder,w);
347 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
348 GtkBuilder *builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder");
351 g_error("Fail to retrieve builder from window !");
354 w=gtk_builder_get_object(builder,name);
356 g_error("No widget named %s found in xml interface.",name);
358 return GTK_WIDGET(w);
363 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
365 GtkWidget *main_window=linphone_gtk_get_main_window();
367 gtk_widget_show(main_window);
368 if (type==GTK_MESSAGE_QUESTION)
370 /* draw a question box. link to dialog_click callback */
371 dialog = gtk_message_dialog_new (
372 GTK_WINDOW(main_window),
373 GTK_DIALOG_DESTROY_WITH_PARENT,
374 GTK_MESSAGE_QUESTION,
377 (const gchar*)message);
378 /* connect to some callback : REVISIT */
380 g_signal_connect_swapped (G_OBJECT (dialog), "response",
381 G_CALLBACK (dialog_click),
384 /* actually show the box */
385 gtk_widget_show(dialog);
389 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
390 GTK_DIALOG_DESTROY_WITH_PARENT,
394 (const gchar*)message);
395 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
396 g_signal_connect_swapped (G_OBJECT (dialog), "response",
397 G_CALLBACK (gtk_widget_destroy),
399 gtk_widget_show(dialog);
403 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
404 if (id==GTK_RESPONSE_CANCEL){
405 gtk_widget_destroy(GTK_WIDGET(dialog));
409 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
410 g_message("About url clicked");
411 linphone_gtk_open_browser(url);
414 void linphone_gtk_show_about(){
415 struct stat filestat;
416 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
419 GdkPixbuf *logo=create_pixbuf(
420 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
421 static const char *defcfg="defcfg";
423 about=linphone_gtk_create_window("about");
424 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
425 memset(&filestat,0,sizeof(filestat));
426 if (stat(license_file,&filestat)!=0){
427 license_file="COPYING";
428 stat(license_file,&filestat);
430 if (filestat.st_size>0){
431 char *license=g_malloc(filestat.st_size+1);
432 FILE *f=fopen(license_file,"r");
433 if (f && fread(license,filestat.st_size,1,f)==1){
434 license[filestat.st_size]='\0';
435 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
439 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
440 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
441 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
442 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
443 tmp=linphone_gtk_get_ui_config("artists",defcfg);
448 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about),tmp2);
450 tmp=linphone_gtk_get_ui_config("translators",defcfg);
452 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(about),tmp);
453 tmp=linphone_gtk_get_ui_config("comments",defcfg);
455 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about),tmp);
456 gtk_widget_show(about);
459 static void set_video_window_decorations(GdkWindow *w){
460 const char *title=linphone_gtk_get_ui_config("title","Linphone");
461 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
462 char video_title[256];
463 GdkPixbuf *pbuf=create_pixbuf(icon_path);
464 if (!linphone_core_in_call(linphone_gtk_get_core())){
465 snprintf(video_title,sizeof(video_title),"%s video",title);
466 /* When not in call, treat the video as a normal window */
467 gdk_window_set_keep_above(w, FALSE);
469 LinphoneAddress *uri =
470 linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
473 linphone_address_clean(uri);
474 if (linphone_address_get_display_name(uri)!=NULL){
475 display_name=ms_strdup(linphone_address_get_display_name(uri));
477 display_name=linphone_address_as_string(uri);
479 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
480 linphone_address_destroy(uri);
481 ms_free(display_name);
483 /* During calls, bring up the video window, arrange so that
484 it is above all the other windows */
485 gdk_window_deiconify(w);
486 gdk_window_set_keep_above(w,TRUE);
487 /* Maybe we should have the following, but then we want to
488 have a timer that turns it off after a little while. */
489 /* gdk_window_set_urgency_hint(w,TRUE); */
491 gdk_window_set_title(w,video_title);
492 /* Refrain the video window to be closed at all times. */
493 gdk_window_set_functions(w,
494 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
495 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
498 l=g_list_append(l,pbuf);
499 gdk_window_set_icon_list(w,l);
501 g_object_unref(G_OBJECT(pbuf));
505 static gboolean video_needs_update=FALSE;
507 static void update_video_title(){
508 video_needs_update=TRUE;
511 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
512 static gboolean first_time=TRUE;
514 static unsigned long previd=0;
515 static unsigned long preview_previd=0;
516 static gboolean in_iterate=FALSE;
519 if (in_iterate) return TRUE;
521 linphone_core_iterate(lc);
523 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
524 linphone_gtk_show_directory_search();
528 id=linphone_core_get_native_video_window_id(lc);
529 if (id!=previd || video_needs_update){
533 ms_message("Updating window decorations");
535 w=gdk_window_foreign_new(id);
537 w=gdk_window_foreign_new((HANDLE)id);
540 set_video_window_decorations(w);
541 g_object_unref(G_OBJECT(w));
543 else ms_error("gdk_window_foreign_new() failed");
544 if (video_needs_update) video_needs_update=FALSE;
547 id=linphone_core_get_native_preview_window_id (lc);
548 if (id!=preview_previd ){
552 ms_message("Updating window decorations for preview");
554 w=gdk_window_foreign_new(id);
556 w=gdk_window_foreign_new((HANDLE)id);
559 set_video_window_decorations(w);
560 g_object_unref(G_OBJECT(w));
562 else ms_error("gdk_window_foreign_new() failed");
563 if (video_needs_update) video_needs_update=FALSE;
566 if (addr_to_call!=NULL){
567 /*make sure we are not showing the login screen*/
568 GtkWidget *mw=linphone_gtk_get_main_window();
569 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
570 if (!GTK_WIDGET_VISIBLE(login_frame)){
571 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
572 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
574 linphone_gtk_start_call(uri_bar);
581 static void load_uri_history(){
582 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
585 GtkEntryCompletion *gep=gtk_entry_completion_new();
586 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
589 snprintf(key,sizeof(key),"uri%i",i);
590 uri=linphone_gtk_get_ui_config(key,NULL);
593 gtk_list_store_append(model,&iter);
594 gtk_list_store_set(model,&iter,0,uri,-1);
595 if (i==0) gtk_entry_set_text(uribar,uri);
599 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
600 gtk_entry_completion_set_text_column(gep,0);
601 gtk_entry_set_completion(uribar,gep);
604 static void save_uri_history(){
605 LinphoneCore *lc=linphone_gtk_get_core();
606 LpConfig *cfg=linphone_core_get_config(lc);
607 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
612 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
614 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
616 gtk_tree_model_get(model,&iter,0,&uri,-1);
618 snprintf(key,sizeof(key),"uri%i",i);
619 lp_config_set_string(cfg,"GtkUi",key,uri);
624 }while(gtk_tree_model_iter_next(model,&iter));
628 static void completion_add_text(GtkEntry *entry, const char *text){
630 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
632 if (gtk_tree_model_get_iter_first(model,&iter)){
635 gtk_tree_model_get(model,&iter,0,&uri,-1);
637 if (strcmp(uri,text)==0) {
639 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
645 }while (gtk_tree_model_iter_next(model,&iter));
647 /* and prepend it on top of the list */
648 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
649 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
653 void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
654 GtkWidget *mw=linphone_gtk_get_main_window();
655 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
656 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
658 if (linphone_gtk_use_in_call_view() && call)
659 linphone_gtk_in_call_view_terminate(call,error);
660 update_video_title();
663 static gboolean in_call_timer(){
664 LinphoneCall *call=linphone_core_get_current_call(linphone_gtk_get_core());
666 linphone_gtk_in_call_view_update_duration(call);
672 static bool_t all_other_calls_paused(LinphoneCall *refcall, const MSList *calls){
673 for(;calls!=NULL;calls=calls->next){
674 LinphoneCall *call=(LinphoneCall*)calls->data;
675 LinphoneCallState cs=linphone_call_get_state(call);
677 if (cs!=LinphoneCallPaused && cs!=LinphoneCallPausing)
684 static void linphone_gtk_update_call_buttons(LinphoneCall *call){
685 LinphoneCore *lc=linphone_gtk_get_core();
686 GtkWidget *mw=linphone_gtk_get_main_window();
687 const MSList *calls=linphone_core_get_calls(lc);
689 bool_t start_active=TRUE;
690 bool_t stop_active=FALSE;
691 bool_t add_call=FALSE;
692 int call_list_size=ms_list_size(calls);
699 if (all_other_calls_paused(NULL,calls)){
702 }else if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived && all_other_calls_paused(call,calls)){
703 if (call_list_size>1){
714 button=linphone_gtk_get_widget(mw,"start_call");
715 gtk_widget_set_sensitive(button,start_active);
716 gtk_widget_set_visible(button,!add_call);
718 button=linphone_gtk_get_widget(mw,"add_call");
719 gtk_widget_set_sensitive(button,start_active);
720 gtk_widget_set_visible(button,add_call);
722 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active);
723 if (linphone_core_get_calls(lc)==NULL){
724 linphone_gtk_enable_mute_button(
725 GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
728 linphone_gtk_enable_transfer_button(lc,call_list_size>1);
729 update_video_title();
732 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
733 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
734 if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
735 completion_add_text(GTK_ENTRY(uri_bar),entered);
737 linphone_gtk_call_terminated(NULL,NULL);
742 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
743 if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
744 linphone_core_accept_call (linphone_gtk_get_core(),call);
745 linphone_call_unref(call);
751 void linphone_gtk_start_call(GtkWidget *w){
752 LinphoneCore *lc=linphone_gtk_get_core();
754 /*change into in-call mode, then do the work later as it might block a bit */
755 GtkWidget *mw=gtk_widget_get_toplevel(w);
756 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
758 call=linphone_gtk_get_currently_displayed_call ();
759 if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
760 linphone_core_accept_call(lc,call);
762 /*immediately disable the button and delay a bit the execution the linphone_core_invite()
763 so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
764 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
765 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
770 void linphone_gtk_uri_bar_activate(GtkWidget *w){
771 linphone_gtk_start_call(w);
775 void linphone_gtk_terminate_call(GtkWidget *button){
776 LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
778 linphone_core_terminate_call(linphone_gtk_get_core(),call);
781 void linphone_gtk_decline_clicked(GtkWidget *button){
782 LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
784 linphone_core_terminate_call(linphone_gtk_get_core(),call);
787 void linphone_gtk_answer_clicked(GtkWidget *button){
788 LinphoneCall *call=linphone_gtk_get_currently_displayed_call ();
790 linphone_core_pause_all_calls(linphone_gtk_get_core());
791 linphone_core_accept_call(linphone_gtk_get_core(),call);
795 void linphone_gtk_set_audio_video(){
796 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
797 linphone_core_enable_video_preview(linphone_gtk_get_core(),
798 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
801 void linphone_gtk_set_audio_only(){
802 linphone_core_enable_video(linphone_gtk_get_core(),FALSE,FALSE);
803 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
806 void linphone_gtk_enable_self_view(GtkWidget *w){
807 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
808 LinphoneCore *lc=linphone_gtk_get_core();
809 linphone_core_enable_video_preview(lc,val);
810 linphone_core_enable_self_view(lc,val);
811 linphone_gtk_set_ui_config_int("videoselfview",val);
814 void linphone_gtk_used_identity_changed(GtkWidget *w){
815 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
816 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
817 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
818 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
819 linphone_gtk_show_directory_search();
821 if (sel) g_free(sel);
824 static void linphone_gtk_show_main_window(){
825 GtkWidget *w=linphone_gtk_get_main_window();
826 LinphoneCore *lc=linphone_gtk_get_core();
827 if (linphone_core_video_enabled(lc)){
828 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
829 VIDEOSELFVIEW_DEFAULT));
832 gtk_window_present(GTK_WINDOW(w));
835 static void linphone_gtk_show(LinphoneCore *lc){
836 linphone_gtk_show_main_window();
839 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
840 linphone_gtk_show_friends();
843 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
845 case GTK_RESPONSE_YES:
846 linphone_gtk_show_contact(lf);
849 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
851 gtk_widget_destroy(dialog);
854 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
857 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
858 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
862 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);
863 dialog = gtk_message_dialog_new (
864 GTK_WINDOW(linphone_gtk_get_main_window()),
865 GTK_DIALOG_DESTROY_WITH_PARENT,
866 GTK_MESSAGE_QUESTION,
871 g_signal_connect(G_OBJECT (dialog), "response",
872 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
873 /* actually show the box */
874 gtk_widget_show(dialog);
877 typedef struct _AuthTimeout{
882 static void auth_timeout_clean(AuthTimeout *tout){
886 static gboolean auth_timeout_destroy(AuthTimeout *tout){
888 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
889 gtk_widget_destroy(tout->w);
895 static AuthTimeout * auth_timeout_new(GtkWidget *w){
896 AuthTimeout *tout=g_new(AuthTimeout,1);
898 /*so that the timeout no more references the widget when it is destroyed:*/
899 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
900 /*so that the widget is automatically destroyed after some time */
901 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
905 void linphone_gtk_password_cancel(GtkWidget *w){
906 LinphoneAuthInfo *info;
907 GtkWidget *window=gtk_widget_get_toplevel(w);
908 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
909 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
910 gtk_widget_destroy(window);
913 void linphone_gtk_password_ok(GtkWidget *w){
915 GtkWidget *window=gtk_widget_get_toplevel(w);
916 LinphoneAuthInfo *info;
917 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
918 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
919 entry=linphone_gtk_get_widget(window,"password_entry");
920 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
921 linphone_auth_info_set_userid(info,
922 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
923 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
924 gtk_widget_destroy(window);
927 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
928 GtkWidget *w=linphone_gtk_create_window("password");
929 GtkWidget *label=linphone_gtk_get_widget(w,"message");
930 LinphoneAuthInfo *info;
932 GtkWidget *mw=linphone_gtk_get_main_window();
934 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
935 /*don't prompt for authentication when login frame is visible*/
936 linphone_core_abort_authentication(lc,NULL);
940 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
942 gtk_label_set_markup(GTK_LABEL(label),msg);
944 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
945 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
946 g_object_set_data(G_OBJECT(w),"auth_info",info);
947 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
952 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
953 GtkWidget *w=linphone_gtk_get_main_window();
954 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
955 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
956 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
960 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
961 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
964 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
965 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
968 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
970 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
971 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
974 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
975 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
976 if (w) linphone_gtk_call_log_update(w);
979 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
981 case LinphoneCallOutgoingInit:
982 linphone_gtk_create_in_call_view (call);
984 case LinphoneCallOutgoingProgress:
985 linphone_gtk_in_call_view_set_calling (call);
987 case LinphoneCallStreamsRunning:
988 linphone_gtk_in_call_view_set_in_call(call);
989 linphone_gtk_enable_mute_button(
990 GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
992 g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
994 case LinphoneCallError:
995 linphone_gtk_in_call_view_terminate (call,msg);
997 case LinphoneCallEnd:
998 linphone_gtk_in_call_view_terminate(call,NULL);
1000 case LinphoneCallIncomingReceived:
1001 linphone_gtk_create_in_call_view (call);
1002 linphone_gtk_in_call_view_set_incoming(call,!all_other_calls_paused (call,linphone_core_get_calls(lc)));
1004 linphone_call_ref(call);
1005 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call);
1008 case LinphoneCallResuming:
1009 linphone_gtk_enable_hold_button(call,TRUE,TRUE);
1010 linphone_gtk_in_call_view_set_in_call (call);
1012 case LinphoneCallPausing:
1013 linphone_gtk_enable_hold_button(call,TRUE,FALSE);
1014 case LinphoneCallPausedByRemote:
1015 linphone_gtk_in_call_view_set_paused(call);
1017 case LinphoneCallConnected:
1018 linphone_gtk_enable_hold_button (call,TRUE,TRUE);
1023 linphone_gtk_update_call_buttons (call);
1026 static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg,
1027 LinphoneRegistrationState rs, const char *msg){
1029 case LinphoneRegistrationOk:
1031 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1032 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1033 linphone_gtk_exit_login_frame();
1043 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
1044 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
1045 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
1048 void linphone_gtk_open_browser(const char *url){
1049 /*in gtk 2.16, gtk_show_uri does not work...*/
1051 #if GTK_CHECK_VERSION(2,18,3)
1052 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
1055 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
1056 g_spawn_command_line_async(cl,NULL);
1059 ShellExecute(0,"open",url,NULL,NULL,1);
1063 void linphone_gtk_link_to_website(GtkWidget *item){
1064 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
1065 linphone_gtk_open_browser(home);
1068 static GtkWidget *create_icon_menu(){
1069 GtkWidget *menu=gtk_menu_new();
1070 GtkWidget *menu_item;
1073 const gchar *homesite;
1075 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1076 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
1077 tmp=g_strdup(homesite);
1078 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1079 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
1081 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
1082 gtk_widget_show(image);
1083 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
1084 //g_object_unref(G_OBJECT(image));
1085 gtk_widget_show(menu_item);
1086 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1087 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
1089 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
1090 gtk_widget_show(menu_item);
1091 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1092 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
1093 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
1094 gtk_widget_show(menu_item);
1095 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
1096 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
1097 gtk_widget_show(menu);
1101 static GtkStatusIcon *icon=NULL;
1103 static void linphone_gtk_init_status_icon(){
1104 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
1105 GdkPixbuf *pbuf=create_pixbuf(icon_path);
1106 GtkWidget *menu=create_icon_menu();
1108 icon=gtk_status_icon_new_from_pixbuf(pbuf);
1109 g_object_unref(G_OBJECT(pbuf));
1110 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
1111 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
1112 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
1113 gtk_status_icon_set_tooltip(icon,title);
1114 gtk_status_icon_set_visible(icon,TRUE);
1115 g_object_set_data(G_OBJECT(icon),"menu",menu);
1116 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
1119 void linphone_gtk_load_identities(void){
1121 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
1123 LinphoneProxyConfig *def=NULL;
1125 GtkListStore *store;
1127 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
1128 gtk_list_store_clear(store);
1130 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
1131 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
1132 gtk_combo_box_append_text(box,def_identity);
1133 g_free(def_identity);
1134 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
1136 elem=ms_list_next(elem),i++){
1137 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1138 gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg));
1143 gtk_combo_box_set_active(box,def_index);
1146 static void linphone_gtk_dtmf_pressed(GtkButton *button){
1147 const char *label=gtk_button_get_label(button);
1148 GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1150 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1151 linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],-1);
1152 if (linphone_core_in_call(linphone_gtk_get_core())){
1153 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1157 static void linphone_gtk_dtmf_released(GtkButton *button){
1158 linphone_core_stop_dtmf (linphone_gtk_get_core());
1161 static void linphone_gtk_connect_digits(void){
1162 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1163 GList *children=gtk_container_get_children(cont);
1165 for(elem=children;elem!=NULL;elem=elem->next){
1166 GtkButton *button=GTK_BUTTON(elem->data);
1167 g_signal_connect(G_OBJECT(button),"pressed",(GCallback)linphone_gtk_dtmf_pressed,NULL);
1168 g_signal_connect(G_OBJECT(button),"released",(GCallback)linphone_gtk_dtmf_released,NULL);
1172 static void linphone_gtk_check_menu_items(void){
1173 bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core());
1174 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1175 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1176 linphone_gtk_get_main_window(),
1177 audio_only ? "audio_only_item" : "video_item")), TRUE);
1178 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1179 linphone_gtk_get_main_window(),"selfview_item")),selfview);
1182 static gboolean linphone_gtk_can_manage_accounts(){
1183 LinphoneCore *lc=linphone_gtk_get_core();
1185 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1186 SipSetup *ss=(SipSetup*)elem->data;
1187 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1194 static void linphone_gtk_configure_main_window(){
1195 static gboolean config_loaded=FALSE;
1196 static const char *title;
1197 static const char *home;
1198 static const char *start_call_icon;
1199 static const char *add_call_icon;
1200 static const char *stop_call_icon;
1201 static const char *search_icon;
1202 static gboolean update_check_menu;
1203 static gboolean buttons_have_borders;
1204 static gboolean show_abcd;
1205 GtkWidget *w=linphone_gtk_get_main_window();
1206 if (!config_loaded){
1207 title=linphone_gtk_get_ui_config("title","Linphone");
1208 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1209 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1210 add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png");
1211 stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
1212 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1213 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1214 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1215 show_abcd=linphone_gtk_get_ui_config_int("show_abcd",1);
1218 linphone_gtk_configure_window(w,"main_window");
1220 gtk_window_set_title(GTK_WINDOW(w),title);
1221 #if GTK_CHECK_VERSION(2,16,0)
1222 gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),title);
1225 if (start_call_icon){
1226 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),
1227 create_pixmap (start_call_icon));
1228 if (!buttons_have_borders)
1229 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE);
1232 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),
1233 create_pixmap (add_call_icon));
1234 if (!buttons_have_borders)
1235 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE);
1237 if (stop_call_icon){
1238 gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),
1239 create_pixmap (stop_call_icon));
1240 if (!buttons_have_borders)
1241 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NONE);
1244 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1245 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1246 g_object_unref(G_OBJECT(pbuf));
1250 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1252 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1255 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1257 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1258 g_object_unref(G_OBJECT(pbuf));
1262 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1264 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")),pbuf);
1265 g_object_unref(G_OBJECT(pbuf));
1268 if (linphone_gtk_can_manage_accounts())
1269 gtk_widget_show(linphone_gtk_get_widget(w,"assistant_item"));
1270 if (update_check_menu){
1271 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck_item"));
1274 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_A"));
1275 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_B"));
1276 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_C"));
1277 gtk_widget_hide(linphone_gtk_get_widget(w,"dtmf_D"));
1278 gtk_table_resize(GTK_TABLE(linphone_gtk_get_widget(w,"dtmf_table")),4,3);
1282 void linphone_gtk_manage_login(void){
1283 LinphoneCore *lc=linphone_gtk_get_core();
1284 LinphoneProxyConfig *cfg=NULL;
1285 linphone_core_get_default_proxy(lc,&cfg);
1287 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1288 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1289 linphone_gtk_show_login_frame(cfg);
1295 gboolean linphone_gtk_close(GtkWidget *mw){
1296 /*shutdown calls if any*/
1297 LinphoneCore *lc=linphone_gtk_get_core();
1298 if (linphone_core_in_call(lc)){
1299 linphone_core_terminate_all_calls(lc);
1301 linphone_core_enable_video_preview(lc,FALSE);
1302 gtk_widget_hide(mw);
1306 static void linphone_gtk_init_main_window(){
1307 GtkWidget *main_window;
1309 linphone_gtk_configure_main_window();
1310 linphone_gtk_manage_login();
1312 linphone_gtk_load_identities();
1313 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1314 linphone_gtk_show_friends();
1315 linphone_gtk_connect_digits();
1316 linphone_gtk_check_menu_items();
1317 main_window=linphone_gtk_get_main_window();
1318 linphone_gtk_enable_mute_button(GTK_BUTTON(linphone_gtk_get_widget(main_window,
1319 "main_mute")),FALSE);
1320 if (!linphone_gtk_use_in_call_view()) {
1321 gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
1323 linphone_gtk_update_call_buttons (NULL);
1324 /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/
1325 g_signal_connect (G_OBJECT (main_window), "delete-event",
1326 G_CALLBACK (linphone_gtk_close), main_window);
1330 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1332 const char *lname="undef";
1334 #if defined(__linux) || defined(__APPLE__)
1335 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1354 g_error("Bad level !");
1356 #if defined(__linux) || defined(__APPLE__)
1358 msg=g_strdup_vprintf(fmt,cap);
1361 msg=g_strdup_vprintf(fmt,args);
1363 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1366 linphone_gtk_log_push(lev,fmt,args);
1370 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1371 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1372 linphone_gtk_get_main_window(), "uribar"));
1373 linphone_gtk_show_main_window();
1374 gtk_entry_set_text(uri_bar, refer_to);
1375 linphone_gtk_start_call(linphone_gtk_get_main_window());
1378 static void linphone_gtk_check_soundcards(){
1379 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1380 if (devices==NULL || devices[0]==NULL){
1381 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1382 _("No sound cards have been detected on this computer.\n"
1383 "You won't be able to send or receive audio calls."));
1387 int main(int argc, char *argv[]){
1391 const char *config_file;
1392 const char *factory_config_file;
1394 GtkSettings *settings;
1397 g_thread_init(NULL);
1400 progpath = strdup(argv[0]);
1402 config_file=linphone_gtk_get_config_file();
1405 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1406 if ((lang=getenv("LANG"))!=NULL){
1409 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1415 g_setenv("PULSE_PROP_media.role", "phone", TRUE);
1418 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1421 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1424 setenv("LANG",lang,1);
1429 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1430 if (p==NULL) perror("bindtextdomain failed");
1431 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1432 textdomain (GETTEXT_PACKAGE);
1434 g_message("NLS disabled.\n");
1437 gtk_rc_add_default_file("./gtkrc");
1439 gdk_threads_enter();
1441 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1442 linphone_options,NULL,NULL)){
1443 gdk_threads_leave();
1447 settings=gtk_settings_get_default();
1448 g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
1449 g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
1450 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1451 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1453 if (workingdir!=NULL)
1456 /* Now, look for the factory configuration file, we do it this late
1457 since we want to have had time to change directory and to parse
1458 the options, in case we needed to access the working directory */
1459 factory_config_file = linphone_gtk_get_factory_config_file();
1461 if (linphone_core_wake_up_possible_already_running_instance(
1462 config_file, addr_to_call) == 0){
1463 g_message("addr_to_call=%s",addr_to_call);
1464 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1465 g_warning("This instance is going to exit now.");
1466 gdk_threads_leave();
1470 add_pixmap_directory("pixmaps");
1471 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1476 the_ui=linphone_gtk_create_window("main");
1478 linphone_gtk_create_log_window();
1479 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1481 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1483 g_set_application_name(linphone_gtk_get_ui_config("title","Linphone"));
1484 pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
1485 if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
1487 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1488 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1489 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1490 linphone_gtk_init_main_window();
1491 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 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1504 gtk_status_icon_set_visible(icon,FALSE);