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>
37 #define LINPHONE_ICON "linphone.png"
39 const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
41 static LinphoneCore *the_core=NULL;
42 static GtkWidget *the_ui=NULL;
44 static void linphone_gtk_show(LinphoneCore *lc);
45 static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from);
46 static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from);
47 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
48 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
49 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
50 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
51 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
52 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
53 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
54 static void linphone_gtk_display_question(LinphoneCore *lc, const char *question);
55 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
56 static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate);
57 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
58 static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window);
60 static LinphoneCoreVTable vtable={
61 .show=linphone_gtk_show,
62 .inv_recv=linphone_gtk_inv_recv,
63 .bye_recv=linphone_gtk_bye_recv,
64 .notify_presence_recv=linphone_gtk_notify_recv,
65 .new_unknown_subscriber=linphone_gtk_new_unknown_subscriber,
66 .auth_info_requested=linphone_gtk_auth_info_requested,
67 .display_status=linphone_gtk_display_status,
68 .display_message=linphone_gtk_display_message,
69 .display_warning=linphone_gtk_display_warning,
70 .display_url=linphone_gtk_display_url,
71 .display_question=linphone_gtk_display_question,
72 .call_log_updated=linphone_gtk_call_log_updated,
73 .text_received=linphone_gtk_text_received,
74 .general_state=linphone_gtk_general_state,
75 .refer_received=linphone_gtk_refer_received,
76 .buddy_info_updated=linphone_gtk_buddy_info_updated
79 static gboolean verbose=0;
80 static gboolean auto_answer = 0;
81 static gchar * addr_to_call = NULL;
82 static gboolean iconified=FALSE;
84 static gchar *workingdir=NULL;
86 static char *progpath=NULL;
88 static GOptionEntry linphone_options[]={
92 .arg=G_OPTION_ARG_NONE,
93 .arg_data= (gpointer)&verbose,
94 .description=N_("log to stdout some debug information while running.")
97 .long_name="iconified",
99 .arg=G_OPTION_ARG_NONE,
100 .arg_data= (gpointer)&iconified,
101 .description=N_("Start only in the system tray, do not show the main interface.")
106 .arg = G_OPTION_ARG_STRING,
107 .arg_data = &addr_to_call,
108 .description = N_("address to call right now")
111 .long_name = "auto-answer",
113 .arg = G_OPTION_ARG_NONE,
114 .arg_data = (gpointer) & auto_answer,
115 .description = N_("if set automatically answer incoming calls")
119 .long_name = "workdir",
121 .arg = G_OPTION_ARG_STRING,
122 .arg_data = (gpointer) & workingdir,
123 .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)")
129 #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone"
130 #define BUILD_TREE_XML_DIR "gtk-glade"
133 #define CONFIG_FILE ".linphonerc"
135 #define CONFIG_FILE "linphonerc"
140 static char _config_file[1024];
143 const char *linphone_gtk_get_config_file(){
144 /*try accessing a local file first if exists*/
145 if (access(CONFIG_FILE,F_OK)==0){
146 snprintf(_config_file,sizeof(_config_file),"%s",CONFIG_FILE);
149 const char *appdata=getenv("APPDATA");
151 snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR);
152 CreateDirectory(_config_file,NULL);
153 snprintf(_config_file,sizeof(_config_file),"%s\\%s",appdata,LINPHONE_CONFIG_DIR "\\" CONFIG_FILE);
156 const char *home=getenv("HOME");
157 if (home==NULL) home=".";
158 snprintf(_config_file,sizeof(_config_file),"%s/%s",home,CONFIG_FILE);
165 #define FACTORY_CONFIG_FILE "linphonerc.factory"
166 static char _factory_config_file[1024];
167 static const char *linphone_gtk_get_factory_config_file(){
168 /*try accessing a local file first if exists*/
169 if (access(FACTORY_CONFIG_FILE,F_OK)==0){
170 snprintf(_factory_config_file,sizeof(_factory_config_file),
171 "%s",FACTORY_CONFIG_FILE);
175 if (progpath != NULL) {
177 progdir = strdup(progpath);
179 basename = strrchr(progdir, '\\');
180 if (basename != NULL) {
183 snprintf(_factory_config_file, sizeof(_factory_config_file),
184 "%s\\..\\%s", progdir, FACTORY_CONFIG_FILE);
186 if (workingdir!=NULL) {
187 snprintf(_factory_config_file, sizeof(_factory_config_file),
188 "%s\\%s", workingdir, FACTORY_CONFIG_FILE);
195 basename = strrchr(progdir, '/');
196 if (basename != NULL) {
199 snprintf(_factory_config_file, sizeof(_factory_config_file),
200 "%s/../share/Linphone/%s", progdir, FACTORY_CONFIG_FILE);
209 return _factory_config_file;
212 static void linphone_gtk_init_liblinphone(const char *config_file,
213 const char *factory_config_file) {
214 linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
215 the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
216 linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
221 LinphoneCore *linphone_gtk_get_core(void){
225 GtkWidget *linphone_gtk_get_main_window(){
229 static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name){
230 static const char *icon_path=NULL;
231 static const char *hiddens=NULL;
232 static const char *shown=NULL;
233 static bool_t config_loaded=FALSE;
234 if (linphone_gtk_get_core()==NULL) return;
235 if (config_loaded==FALSE){
236 hiddens=linphone_gtk_get_ui_config("hidden_widgets",NULL);
237 shown=linphone_gtk_get_ui_config("shown_widgets",NULL);
238 icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
242 linphone_gtk_visibility_set(hiddens,window_name,w,FALSE);
244 linphone_gtk_visibility_set(shown,window_name,w,TRUE);
246 GdkPixbuf *pbuf=create_pixbuf(icon_path);
247 gtk_window_set_icon(GTK_WINDOW(w),pbuf);
248 g_object_unref(G_OBJECT(pbuf));
254 GtkWidget *linphone_gtk_create_window(const char *window_name){
258 snprintf(path,sizeof(path),"%s/%s.glade",BUILD_TREE_XML_DIR,window_name);
259 if (access(path,F_OK)!=0){
260 snprintf(path,sizeof(path),"%s/%s.glade",INSTALLED_XML_DIR,window_name);
261 if (access(path,F_OK)!=0){
262 g_error("Could not locate neither %s/%s.glade and %s/%s.glade .",BUILD_TREE_XML_DIR,window_name,
263 INSTALLED_XML_DIR,window_name);
267 gxml=glade_xml_new(path,NULL,NULL);
268 glade_xml_signal_autoconnect(gxml);
269 w=glade_xml_get_widget(gxml,window_name);
270 if (w==NULL) g_error("Could not retrieve '%s' window from xml file",window_name);
271 linphone_gtk_configure_window(w,window_name);
275 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
277 GladeXML *gxml=glade_get_widget_tree(window);
278 if (gxml==NULL) g_error("Could not retrieve XML tree of window %s",name);
279 w=glade_xml_get_widget(gxml,name);
280 if (w==NULL) g_error("Could not retrieve widget %s",name);
281 return GTK_WIDGET(w);
286 GtkWidget *linphone_gtk_create_window(const char *window_name){
290 GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){
291 GObject *w=gtk_builder_get_object(the_ui,name);
293 g_error("No widget named %s found in xml interface.",name);
295 return GTK_WIDGET(w);
300 void linphone_gtk_display_something(GtkMessageType type,const gchar *message){
302 GtkWidget *main_window=linphone_gtk_get_main_window();
304 gtk_widget_show(main_window);
305 if (type==GTK_MESSAGE_QUESTION)
307 /* draw a question box. link to dialog_click callback */
308 dialog = gtk_message_dialog_new (
309 GTK_WINDOW(main_window),
310 GTK_DIALOG_DESTROY_WITH_PARENT,
311 GTK_MESSAGE_QUESTION,
314 (const gchar*)message);
315 /* connect to some callback : REVISIT */
317 g_signal_connect_swapped (G_OBJECT (dialog), "response",
318 G_CALLBACK (dialog_click),
321 /* actually show the box */
322 gtk_widget_show(dialog);
326 dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
327 GTK_DIALOG_DESTROY_WITH_PARENT,
331 (const gchar*)message);
332 /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
333 g_signal_connect_swapped (G_OBJECT (dialog), "response",
334 G_CALLBACK (gtk_widget_destroy),
336 gtk_widget_show(dialog);
340 void linphone_gtk_about_response(GtkDialog *dialog, gint id){
341 if (id==GTK_RESPONSE_CANCEL){
342 gtk_widget_destroy(GTK_WIDGET(dialog));
346 static void about_url_clicked(GtkAboutDialog *dialog, const char *url, gpointer data){
347 g_message("About url clicked");
348 linphone_gtk_open_browser(url);
351 void linphone_gtk_show_about(){
352 struct stat filestat;
353 const char *license_file=PACKAGE_DATA_DIR "/linphone/COPYING";
355 GdkPixbuf *logo=create_pixbuf(
356 linphone_gtk_get_ui_config("logo","linphone-banner.png"));
358 about=linphone_gtk_create_window("about");
359 gtk_about_dialog_set_url_hook(about_url_clicked,NULL,NULL);
360 memset(&filestat,0,sizeof(filestat));
361 if (stat(license_file,&filestat)!=0){
362 license_file="COPYING";
363 stat(license_file,&filestat);
365 if (filestat.st_size>0){
366 char *license=g_malloc(filestat.st_size+1);
367 FILE *f=fopen(license_file,"r");
368 if (f && fread(license,filestat.st_size,1,f)==1){
369 license[filestat.st_size]='\0';
370 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about),license);
374 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),LINPHONE_VERSION);
375 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("title","Linphone"));
376 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),linphone_gtk_get_ui_config("home","http://www.linphone.org"));
377 if (logo) gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about),logo);
379 gtk_widget_show(about);
382 static void set_video_window_decorations(GdkWindow *w){
383 const char *title=linphone_gtk_get_ui_config("title","Linphone");
384 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
385 char video_title[256];
386 GdkPixbuf *pbuf=create_pixbuf(icon_path);
387 if (!linphone_core_in_call(linphone_gtk_get_core())){
388 snprintf(video_title,sizeof(video_title),"%s video",title);
389 /* When not in call, treat the video as a normal window */
390 gdk_window_set_keep_above(w, FALSE);
392 LinphoneAddress *uri =
393 linphone_address_clone(linphone_core_get_remote_uri(linphone_gtk_get_core()));
396 linphone_address_clean(uri);
397 if (linphone_address_get_display_name(uri)!=NULL){
398 display_name=ms_strdup(linphone_address_get_display_name(uri));
400 display_name=linphone_address_as_string(uri);
402 snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name);
403 linphone_address_destroy(uri);
404 ms_free(display_name);
406 /* During calls, bring up the video window, arrange so that
407 it is above all the other windows */
408 gdk_window_deiconify(w);
409 gdk_window_set_keep_above(w,TRUE);
410 /* Maybe we should have the following, but then we want to
411 have a timer that turns it off after a little while. */
412 /* gdk_window_set_urgency_hint(w,TRUE); */
414 gdk_window_set_title(w,video_title);
415 /* Refrain the video window to be closed at all times. */
416 gdk_window_set_functions(w,
417 GDK_FUNC_RESIZE|GDK_FUNC_MOVE|
418 GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE);
421 l=g_list_append(l,pbuf);
422 gdk_window_set_icon_list(w,l);
424 g_object_unref(G_OBJECT(pbuf));
428 static gboolean video_needs_update=FALSE;
430 static void update_video_title(){
431 video_needs_update=TRUE;
434 static gboolean linphone_gtk_iterate(LinphoneCore *lc){
435 static gboolean first_time=TRUE;
437 static unsigned long previd=0;
438 static gboolean in_iterate=FALSE;
441 if (in_iterate) return TRUE;
443 linphone_core_iterate(lc);
445 /*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
446 linphone_gtk_show_directory_search();
450 id=linphone_core_get_native_video_window_id(lc);
451 if (id!=previd || video_needs_update){
455 ms_message("Updating window decorations");
457 w=gdk_window_foreign_new(id);
459 w=gdk_window_foreign_new((HANDLE)id);
462 set_video_window_decorations(w);
463 g_object_unref(G_OBJECT(w));
465 else ms_error("gdk_window_foreign_new() failed");
466 if (video_needs_update) video_needs_update=FALSE;
469 if (addr_to_call!=NULL){
470 /*make sure we are not showing the login screen*/
471 GtkWidget *mw=linphone_gtk_get_main_window();
472 GtkWidget *login_frame=linphone_gtk_get_widget(mw,"login_frame");
473 if (!GTK_WIDGET_VISIBLE(login_frame)){
474 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
475 gtk_entry_set_text(GTK_ENTRY(uri_bar),addr_to_call);
477 linphone_gtk_start_call(uri_bar);
484 static void load_uri_history(){
485 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
488 GtkEntryCompletion *gep=gtk_entry_completion_new();
489 GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
492 snprintf(key,sizeof(key),"uri%i",i);
493 uri=linphone_gtk_get_ui_config(key,NULL);
496 gtk_list_store_append(model,&iter);
497 gtk_list_store_set(model,&iter,0,uri,-1);
498 if (i==0) gtk_entry_set_text(uribar,uri);
502 gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
503 gtk_entry_completion_set_text_column(gep,0);
504 gtk_entry_set_completion(uribar,gep);
507 static void save_uri_history(){
508 LinphoneCore *lc=linphone_gtk_get_core();
509 LpConfig *cfg=linphone_core_get_config(lc);
510 GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
515 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(uribar));
517 if (!gtk_tree_model_get_iter_first(model,&iter)) return;
519 gtk_tree_model_get(model,&iter,0,&uri,-1);
521 snprintf(key,sizeof(key),"uri%i",i);
522 lp_config_set_string(cfg,"GtkUi",key,uri);
527 }while(gtk_tree_model_iter_next(model,&iter));
531 static void completion_add_text(GtkEntry *entry, const char *text){
533 GtkTreeModel *model=gtk_entry_completion_get_model(gtk_entry_get_completion(entry));
535 if (gtk_tree_model_get_iter_first(model,&iter)){
538 gtk_tree_model_get(model,&iter,0,&uri,-1);
540 if (strcmp(uri,text)==0) {
542 gtk_list_store_remove(GTK_LIST_STORE(model),&iter);
548 }while (gtk_tree_model_iter_next(model,&iter));
550 /* and prepend it on top of the list */
551 gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
552 gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
556 void linphone_gtk_call_terminated(const char *error){
557 GtkWidget *mw=linphone_gtk_get_main_window();
559 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE);
560 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE);
561 linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"main_mute")),FALSE);
562 if (linphone_gtk_use_in_call_view())
563 linphone_gtk_in_call_view_terminate(error);
564 update_video_title();
565 icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
567 g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
568 gtk_widget_destroy(icw);
572 static gboolean in_call_timer(){
573 if (linphone_core_in_call(linphone_gtk_get_core())){
574 linphone_gtk_in_call_view_update_duration(
575 linphone_core_get_current_call_duration(linphone_gtk_get_core()));
581 static void linphone_gtk_call_started(GtkWidget *mw){
582 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE);
583 gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE);
584 update_video_title();
585 if (linphone_gtk_use_in_call_view())
586 g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
589 static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
590 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
591 if (linphone_core_invite(linphone_gtk_get_core(),entered)==0) {
592 completion_add_text(GTK_ENTRY(uri_bar),entered);
594 linphone_gtk_call_terminated(NULL);
599 static void _linphone_gtk_accept_call(){
600 LinphoneCore *lc=linphone_gtk_get_core();
601 GtkWidget *mw=linphone_gtk_get_main_window();
602 GtkWidget *icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call"));
604 g_object_set_data(G_OBJECT(mw),"incoming_call",NULL);
605 gtk_widget_destroy(icw);
608 linphone_core_accept_call(lc,NULL);
609 linphone_gtk_call_started(linphone_gtk_get_main_window());
610 if (linphone_gtk_use_in_call_view()){
611 linphone_gtk_in_call_view_set_in_call();
612 linphone_gtk_show_in_call_view();
614 linphone_gtk_enable_mute_button(
615 GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute"))
619 void linphone_gtk_start_call(GtkWidget *w){
620 LinphoneCore *lc=linphone_gtk_get_core();
621 if (linphone_core_inc_invite_pending(lc)){
623 _linphone_gtk_accept_call();
624 }else if (linphone_core_in_call(lc)) {
627 /*change into in-call mode, then do the work later as it might block a bit */
628 GtkWidget *mw=gtk_widget_get_toplevel(w);
629 GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
630 const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
631 linphone_gtk_call_started(mw);
632 if (linphone_gtk_use_in_call_view()){
633 linphone_gtk_in_call_view_set_calling(entered);
634 linphone_gtk_show_in_call_view();
636 g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar);
640 void linphone_gtk_uri_bar_activate(GtkWidget *w){
641 linphone_gtk_start_call(w);
645 void linphone_gtk_terminate_call(GtkWidget *button){
646 linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
649 void linphone_gtk_decline_call(GtkWidget *button){
650 linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
651 gtk_widget_destroy(gtk_widget_get_toplevel(button));
654 void linphone_gtk_accept_call(GtkWidget *button){
655 _linphone_gtk_accept_call();
658 static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window){
659 linphone_gtk_accept_call(linphone_gtk_get_widget(incall_window,"accept_call"));
663 void linphone_gtk_set_audio_video(){
664 linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE);
665 linphone_core_enable_video_preview(linphone_gtk_get_core(),
666 linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT));
669 void linphone_gtk_set_audio_only(){
670 linphone_core_enable_video(linphone_gtk_get_core(),FALSE,FALSE);
671 linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE);
674 void linphone_gtk_enable_self_view(GtkWidget *w){
675 gboolean val=gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
676 LinphoneCore *lc=linphone_gtk_get_core();
677 linphone_core_enable_video_preview(lc,val);
678 linphone_core_enable_self_view(lc,val);
679 linphone_gtk_set_ui_config_int("videoselfview",val);
682 void linphone_gtk_used_identity_changed(GtkWidget *w){
683 int active=gtk_combo_box_get_active(GTK_COMBO_BOX(w));
684 char *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
685 if (sel && strlen(sel)>0){ //avoid a dummy "changed" at gui startup
686 linphone_core_set_default_proxy_index(linphone_gtk_get_core(),(active==0) ? -1 : (active-1));
687 linphone_gtk_show_directory_search();
689 if (sel) g_free(sel);
692 static void linphone_gtk_show_main_window(){
693 GtkWidget *w=linphone_gtk_get_main_window();
694 LinphoneCore *lc=linphone_gtk_get_core();
695 if (linphone_core_video_enabled(lc)){
696 linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview",
697 VIDEOSELFVIEW_DEFAULT));
700 gtk_window_present(GTK_WINDOW(w));
703 static void linphone_gtk_show(LinphoneCore *lc){
704 linphone_gtk_show_main_window();
707 static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){
708 GtkWidget *w=linphone_gtk_create_window("incoming_call");
713 g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w);
716 gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window()));
717 gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT);
719 label=linphone_gtk_get_widget(w,"message");
720 msg=g_strdup_printf(_("Incoming call from %s"),from);
721 gtk_label_set_text(GTK_LABEL(label),msg);
722 gtk_window_set_title(GTK_WINDOW(w),msg);
724 gtk_window_present(GTK_WINDOW(w));
725 /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/
727 g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w);
728 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),
732 static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){
736 static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
737 linphone_gtk_show_friends();
740 static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
742 case GTK_RESPONSE_YES:
743 linphone_gtk_show_contact(lf);
746 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
748 gtk_widget_destroy(dialog);
751 static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
754 if (linphone_gtk_get_ui_config_int("subscribe_deny_all",0)){
755 linphone_core_reject_subscriber(linphone_gtk_get_core(),lf);
759 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);
760 dialog = gtk_message_dialog_new (
761 GTK_WINDOW(linphone_gtk_get_main_window()),
762 GTK_DIALOG_DESTROY_WITH_PARENT,
763 GTK_MESSAGE_QUESTION,
768 g_signal_connect(G_OBJECT (dialog), "response",
769 G_CALLBACK (linphone_gtk_new_subscriber_response),lf);
770 /* actually show the box */
771 gtk_widget_show(dialog);
774 typedef struct _AuthTimeout{
779 static void auth_timeout_clean(AuthTimeout *tout){
783 static gboolean auth_timeout_destroy(AuthTimeout *tout){
785 g_object_weak_unref(G_OBJECT(tout->w),(GWeakNotify)auth_timeout_clean,tout);
786 gtk_widget_destroy(tout->w);
792 static AuthTimeout * auth_timeout_new(GtkWidget *w){
793 AuthTimeout *tout=g_new(AuthTimeout,1);
795 /*so that the timeout no more references the widget when it is destroyed:*/
796 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)auth_timeout_clean,tout);
797 /*so that the widget is automatically destroyed after some time */
798 g_timeout_add(30000,(GtkFunction)auth_timeout_destroy,tout);
802 void linphone_gtk_password_cancel(GtkWidget *w){
803 LinphoneAuthInfo *info;
804 GtkWidget *window=gtk_widget_get_toplevel(w);
805 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
806 linphone_core_abort_authentication(linphone_gtk_get_core(),info);
807 gtk_widget_destroy(window);
810 void linphone_gtk_password_ok(GtkWidget *w){
812 GtkWidget *window=gtk_widget_get_toplevel(w);
813 LinphoneAuthInfo *info;
814 info=(LinphoneAuthInfo*)g_object_get_data(G_OBJECT(window),"auth_info");
815 g_object_weak_unref(G_OBJECT(window),(GWeakNotify)linphone_auth_info_destroy,info);
816 entry=linphone_gtk_get_widget(window,"password_entry");
817 linphone_auth_info_set_passwd(info,gtk_entry_get_text(GTK_ENTRY(entry)));
818 linphone_auth_info_set_userid(info,
819 gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(window,"userid_entry"))));
820 linphone_core_add_auth_info(linphone_gtk_get_core(),info);
821 gtk_widget_destroy(window);
824 static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){
825 GtkWidget *w=linphone_gtk_create_window("password");
826 GtkWidget *label=linphone_gtk_get_widget(w,"message");
827 LinphoneAuthInfo *info;
829 GtkWidget *mw=linphone_gtk_get_main_window();
831 if (mw && GTK_WIDGET_VISIBLE(linphone_gtk_get_widget(mw,"login_frame"))){
832 /*don't prompt for authentication when login frame is visible*/
833 linphone_core_abort_authentication(lc,NULL);
837 msg=g_strdup_printf(_("Please enter your password for username <i>%s</i>\n at domain <i>%s</i>:"),
839 gtk_label_set_markup(GTK_LABEL(label),msg);
841 gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username);
842 info=linphone_auth_info_new(username, NULL, NULL, NULL,realm);
843 g_object_set_data(G_OBJECT(w),"auth_info",info);
844 g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info);
849 static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
850 GtkWidget *w=linphone_gtk_get_main_window();
851 GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar");
852 gtk_statusbar_push(GTK_STATUSBAR(status_bar),
853 gtk_statusbar_get_context_id(GTK_STATUSBAR(status_bar),""),
857 static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
858 linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
861 static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning){
862 linphone_gtk_display_something(GTK_MESSAGE_WARNING,warning);
865 static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url){
867 snprintf(richtext,sizeof(richtext),"%s %s",msg,url);
868 linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
871 static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){
872 linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question);
875 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
876 GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
877 if (w) linphone_gtk_call_log_update(w);
880 static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){
881 switch(gstate->new_state){
882 case GSTATE_CALL_OUT_CONNECTED:
883 case GSTATE_CALL_IN_CONNECTED:
884 if (linphone_gtk_use_in_call_view())
885 linphone_gtk_in_call_view_set_in_call();
886 linphone_gtk_enable_mute_button(
887 GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
890 case GSTATE_CALL_ERROR:
891 linphone_gtk_call_terminated(gstate->message);
893 case GSTATE_CALL_END:
894 linphone_gtk_call_terminated(NULL);
901 static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
902 GtkWidget *menu=(GtkWidget*)g_object_get_data(G_OBJECT(status_icon),"menu");
903 gtk_menu_popup(GTK_MENU(menu),NULL,NULL,gtk_status_icon_position_menu,status_icon,button,activate_time);
906 void linphone_gtk_open_browser(const char *url){
907 /*in gtk 2.16, gtk_show_uri does not work...*/
909 #if GTK_CHECK_VERSION(2,18,3)
910 gtk_show_uri(NULL,url,GDK_CURRENT_TIME,NULL);
913 snprintf(cl,sizeof(cl),"/usr/bin/x-www-browser %s",url);
914 g_spawn_command_line_async(cl,NULL);
917 ShellExecute(0,"open",url,NULL,NULL,1);
921 void linphone_gtk_link_to_website(GtkWidget *item){
922 const gchar *home=(const gchar*)g_object_get_data(G_OBJECT(item),"home");
923 linphone_gtk_open_browser(home);
926 static GtkWidget *create_icon_menu(){
927 GtkWidget *menu=gtk_menu_new();
928 GtkWidget *menu_item;
931 const gchar *homesite;
933 homesite=linphone_gtk_get_ui_config("home","http://www.linphone.org");
934 menu_item=gtk_image_menu_item_new_with_label(_("Website link"));
935 tmp=g_strdup(homesite);
936 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
937 g_object_weak_ref(G_OBJECT(menu_item),(GWeakNotify)g_free,tmp);
939 image=gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
940 gtk_widget_show(image);
941 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),image);
942 //g_object_unref(G_OBJECT(image));
943 gtk_widget_show(menu_item);
944 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
945 g_signal_connect(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_link_to_website,NULL);
947 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT,NULL);
948 gtk_widget_show(menu_item);
949 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
950 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_show_about,NULL);
951 menu_item=gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);
952 gtk_widget_show(menu_item);
953 gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
954 g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)gtk_main_quit,NULL);
955 gtk_widget_show(menu);
959 static GtkStatusIcon *icon=NULL;
961 static void linphone_gtk_init_status_icon(){
962 const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON);
963 GdkPixbuf *pbuf=create_pixbuf(icon_path);
964 GtkWidget *menu=create_icon_menu();
966 icon=gtk_status_icon_new_from_pixbuf(pbuf);
967 g_object_unref(G_OBJECT(pbuf));
968 g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window());
969 g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL);
970 title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
971 gtk_status_icon_set_tooltip(icon,title);
972 gtk_status_icon_set_visible(icon,TRUE);
973 g_object_set_data(G_OBJECT(icon),"menu",menu);
974 g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu);
977 void linphone_gtk_load_identities(void){
979 GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
981 LinphoneProxyConfig *def=NULL;
985 store=GTK_LIST_STORE(gtk_combo_box_get_model(box));
986 gtk_list_store_clear(store);
988 linphone_core_get_default_proxy(linphone_gtk_get_core(),&def);
989 def_identity=g_strdup_printf(_("%s (Default)"),linphone_core_get_primary_contact(linphone_gtk_get_core()));
990 gtk_combo_box_append_text(box,def_identity);
991 g_free(def_identity);
992 for(i=1,elem=linphone_core_get_proxy_config_list(linphone_gtk_get_core());
994 elem=ms_list_next(elem),i++){
995 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
996 gtk_combo_box_append_text(box,linphone_proxy_config_get_identity(cfg));
1001 gtk_combo_box_set_active(box,def_index);
1004 static void linphone_gtk_dtmf_clicked(GtkButton *button){
1005 const char *label=gtk_button_get_label(button);
1006 if (linphone_core_in_call(linphone_gtk_get_core())){
1007 linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]);
1009 GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar");
1011 gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos);
1015 static void linphone_gtk_connect_digits(void){
1016 GtkContainer *cont=GTK_CONTAINER(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"dtmf_table"));
1017 GList *children=gtk_container_get_children(cont);
1019 for(elem=children;elem!=NULL;elem=elem->next){
1020 GtkButton *button=GTK_BUTTON(elem->data);
1021 g_signal_connect(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_dtmf_clicked,NULL);
1025 static void linphone_gtk_check_menu_items(void){
1026 bool_t audio_only=!linphone_core_video_enabled(linphone_gtk_get_core());
1027 bool_t selfview=linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT);
1028 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1029 linphone_gtk_get_main_window(),
1030 audio_only ? "audio_only_item" : "video_item")), TRUE);
1031 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(linphone_gtk_get_widget(
1032 linphone_gtk_get_main_window(),"selfview_item")),selfview);
1035 static gboolean linphone_gtk_can_manage_accounts(){
1036 LinphoneCore *lc=linphone_gtk_get_core();
1038 for(elem=linphone_core_get_sip_setups(lc);elem!=NULL;elem=elem->next){
1039 SipSetup *ss=(SipSetup*)elem->data;
1040 if (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER){
1047 static void linphone_gtk_configure_main_window(){
1048 static gboolean config_loaded=FALSE;
1049 static const char *title;
1050 static const char *home;
1051 static const char *start_call_icon;
1052 static const char *stop_call_icon;
1053 static const char *search_icon;
1054 static gboolean update_check_menu;
1055 static gboolean buttons_have_borders;
1056 GtkWidget *w=linphone_gtk_get_main_window();
1057 if (!config_loaded){
1058 title=linphone_gtk_get_ui_config("title","Linphone");
1059 home=linphone_gtk_get_ui_config("home","http://www.linphone.org");
1060 start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png");
1061 stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png");
1062 search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL);
1063 update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0);
1064 buttons_have_borders=linphone_gtk_get_ui_config_int("buttons_border",1);
1067 linphone_gtk_configure_window(w,"main_window");
1069 gtk_window_set_title(GTK_WINDOW(w),title);
1070 #if GTK_CHECK_VERSION(2,16,0)
1071 gtk_menu_item_set_label(GTK_MENU_ITEM(linphone_gtk_get_widget(w,"main_menu")),title);
1074 if (start_call_icon){
1075 GdkPixbuf *pbuf=create_pixbuf(start_call_icon);
1076 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"start_call_icon")),pbuf);
1077 if (buttons_have_borders)
1078 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NORMAL);
1079 g_object_unref(G_OBJECT(pbuf));
1081 if (stop_call_icon){
1082 GdkPixbuf *pbuf=create_pixbuf(stop_call_icon);
1083 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf);
1084 if (buttons_have_borders)
1085 gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NORMAL);
1086 g_object_unref(G_OBJECT(pbuf));
1089 GdkPixbuf *pbuf=create_pixbuf(search_icon);
1090 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
1091 g_object_unref(G_OBJECT(pbuf));
1095 GtkWidget *menu_item=linphone_gtk_get_widget(w,"home_item");
1097 g_object_set_data(G_OBJECT(menu_item),"home",tmp);
1100 GdkPixbuf *pbuf=create_pixbuf("contact-orange.png");
1102 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"contact_tab_icon")),pbuf);
1103 g_object_unref(G_OBJECT(pbuf));
1107 GdkPixbuf *pbuf=create_pixbuf("dialer-orange.png");
1109 gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"keypad_tab_icon")),pbuf);
1110 g_object_unref(G_OBJECT(pbuf));
1113 if (!linphone_gtk_can_manage_accounts())
1114 gtk_widget_hide(linphone_gtk_get_widget(w,"run_assistant"));
1115 if (update_check_menu){
1116 gtk_widget_show(linphone_gtk_get_widget(w,"versioncheck"));
1120 void linphone_gtk_manage_login(void){
1121 LinphoneCore *lc=linphone_gtk_get_core();
1122 LinphoneProxyConfig *cfg=NULL;
1123 linphone_core_get_default_proxy(lc,&cfg);
1125 SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
1126 if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
1127 linphone_gtk_show_login_frame(cfg);
1132 static void linphone_gtk_init_main_window(){
1133 GtkWidget *main_window;
1135 linphone_gtk_configure_main_window();
1136 linphone_gtk_manage_login();
1138 linphone_gtk_load_identities();
1139 linphone_gtk_set_my_presence(linphone_core_get_presence_info(linphone_gtk_get_core()));
1140 linphone_gtk_show_friends();
1141 linphone_gtk_connect_digits();
1142 linphone_gtk_check_menu_items();
1143 main_window=linphone_gtk_get_main_window();
1144 linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
1145 "main_mute")),FALSE);
1146 linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
1147 "incall_mute")),FALSE);
1148 if (!linphone_gtk_use_in_call_view()) {
1149 gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
1151 if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started(
1152 linphone_gtk_get_main_window());/*hide the call button, show terminate button*/
1155 void linphone_gtk_close(){
1156 /* couldn't find a way to prevent closing to destroy the main window*/
1157 LinphoneCore *lc=linphone_gtk_get_core();
1159 the_ui=linphone_gtk_create_window("main");
1160 linphone_gtk_init_main_window();
1161 /*shutdown call if any*/
1162 if (linphone_core_in_call(lc)){
1163 linphone_core_terminate_call(lc,NULL);
1164 linphone_gtk_call_terminated(NULL);
1166 linphone_core_enable_video_preview(lc,FALSE);
1169 void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
1171 const char *lname="undef";
1174 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/
1193 g_error("Bad level !");
1197 msg=g_strdup_vprintf(fmt,cap);
1200 msg=g_strdup_vprintf(fmt,args);
1202 fprintf(stdout,"linphone-%s : %s\n",lname,msg);
1205 linphone_gtk_log_push(lev,fmt,args);
1209 static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
1210 GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
1211 linphone_gtk_get_main_window(), "uribar"));
1212 linphone_gtk_show_main_window();
1213 gtk_entry_set_text(uri_bar, refer_to);
1214 linphone_gtk_start_call(linphone_gtk_get_main_window());
1217 static void linphone_gtk_check_soundcards(){
1218 const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core());
1219 if (devices==NULL || devices[0]==NULL){
1220 linphone_gtk_display_something(GTK_MESSAGE_WARNING,
1221 _("No sound cards have been detected on this computer.\n"
1222 "You won't be able to send or receive audio calls."));
1226 int main(int argc, char *argv[]){
1230 const char *config_file;
1231 const char *factory_config_file;
1233 GtkSettings *settings;
1235 g_thread_init(NULL);
1237 progpath = strdup(argv[0]);
1239 config_file=linphone_gtk_get_config_file();
1242 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
1243 if ((lang=getenv("LANG"))!=NULL){
1246 snprintf(tmp,sizeof(tmp),"LANG=",lang);
1252 if ((lang=linphone_gtk_get_lang(config_file))!=NULL && lang[0]!='\0'){
1255 snprintf(tmp,sizeof(tmp),"LANG=%s",lang);
1258 setenv("LANG",lang,1);
1263 p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
1264 if (p==NULL) perror("bindtextdomain failed");
1265 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1266 textdomain (GETTEXT_PACKAGE);
1268 g_message("NLS disabled.\n");
1271 gtk_rc_add_default_file("./gtkrc");
1273 gdk_threads_enter();
1275 if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"),
1276 linphone_options,NULL,NULL)){
1277 gdk_threads_leave();
1280 settings=gtk_settings_get_default();
1281 g_object_set(settings, "gtk-menu-images", TRUE, NULL);
1282 g_object_set(settings, "gtk-button-images", TRUE, NULL);
1284 if (workingdir!=NULL)
1287 /* Now, look for the factory configuration file, we do it this late
1288 since we want to have had time to change directory and to parse
1289 the options, in case we needed to access the working directory */
1290 factory_config_file = linphone_gtk_get_factory_config_file();
1292 if (linphone_core_wake_up_possible_already_running_instance(
1293 config_file, addr_to_call) == 0){
1294 g_message("addr_to_call=%s",addr_to_call);
1295 g_warning("Another running instance of linphone has been detected. It has been woken-up.");
1296 g_warning("This instance is going to exit now.");
1297 gdk_threads_leave();
1301 add_pixmap_directory("pixmaps");
1302 add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
1304 the_ui=linphone_gtk_create_window("main");
1306 linphone_gtk_create_log_window();
1307 linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
1309 linphone_gtk_init_liblinphone(config_file, factory_config_file);
1310 /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
1311 gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
1312 gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
1313 linphone_gtk_init_main_window();
1314 linphone_gtk_init_status_icon();
1316 linphone_gtk_show_main_window();
1317 linphone_gtk_check_soundcards();
1319 if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
1320 linphone_gtk_check_for_new_version();
1323 gdk_threads_leave();
1324 linphone_gtk_destroy_log_window();
1325 linphone_core_destroy(the_core);
1326 /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
1327 gtk_status_icon_set_visible(icon,FALSE);