From 3a02574fc523bb08bae37f47a2054feaf4864bc2 Mon Sep 17 00:00:00 2001 From: Simon Morlat <simon.morlat@linphone.org> Date: Thu, 9 Sep 2010 15:23:23 +0200 Subject: [PATCH] multicall support in gtk interface --- coreapi/callbacks.c | 3 + coreapi/linphonecall.c | 18 +- coreapi/linphonecore.c | 9 +- coreapi/linphonecore.h | 1 + gtk/Makefile.am | 1 - gtk/incall_view.c | 216 +++++++++++--------- gtk/linphone.h | 15 +- gtk/logging.c | 10 +- gtk/main.c | 314 ++++++++++++++++------------- gtk/main.ui | 408 ++++++++++++++++++-------------------- pixmaps/addcall-green.png | Bin 0 -> 2629 bytes 11 files changed, 525 insertions(+), 470 deletions(-) create mode 100644 pixmaps/addcall-green.png diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index aad80a60d1..8cbccc7c37 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -221,6 +221,9 @@ static void call_accepted(SalOp *op){ } linphone_call_set_state(call,LinphoneCallPaused,"Call paused"); }else{ + if (lc->vtable.display_status){ + lc->vtable.display_status(lc,_("Call answered - connected.")); + } linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); } linphone_connect_incoming (lc,call); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b5c3e8e940..3244aac7ed 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -229,17 +229,23 @@ static void linphone_call_set_terminated(LinphoneCall *call){ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){ LinphoneCore *lc=call->core; + bool_t finalize_call=FALSE; if (call->state!=cstate){ if (cstate!=LinphoneCallRefered){ /*LinphoneCallRefered is rather an event, not a state. Indeed it does not change the state of the call (still paused or running)*/ call->state=cstate; } + if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){ + finalize_call=TRUE; + linphone_call_ref(call); + linphone_call_set_terminated (call); + } if (lc->vtable.call_state_changed) lc->vtable.call_state_changed(lc,call,cstate,message); + if (finalize_call) + linphone_call_unref(call); } - if (call->state==LinphoneCallEnd || call->state==LinphoneCallError) - linphone_call_set_terminated (call); } static void linphone_call_destroy(LinphoneCall *obj) @@ -369,6 +375,14 @@ bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){ return call->refer_pending; } +/** + * Returns call's duration in seconds. +**/ +int linphone_call_get_duration(const LinphoneCall *call){ + if (call->media_start_time==0) return 0; + return time(NULL)-call->media_start_time; +} + /** * @} **/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 145f670121..5f07f27494 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -300,15 +300,10 @@ bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){ return FALSE; } -int linphone_core_get_call_duration(LinphoneCall *call){ - if (call==NULL) return 0; - if (call->media_start_time==0) return 0; - return time(NULL)-call->media_start_time; -} - int linphone_core_get_current_call_duration(const LinphoneCore *lc){ LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc); - return linphone_core_get_call_duration(call); + if (call) return linphone_call_get_duration(call); + return -1; } const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 47a6ae47f9..e8bbd41ba8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -174,6 +174,7 @@ void linphone_call_unref(LinphoneCall *call); LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); const char *linphone_call_get_refer_to(const LinphoneCall *call); bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); +int linphone_call_get_duration(const LinphoneCall *call); void *linphone_call_get_user_pointer(LinphoneCall *call); void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 7bcba956fd..546e9f4943 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -2,7 +2,6 @@ UI_FILES= about.ui \ main.ui \ password.ui \ contact.ui \ - incoming_call.ui \ parameters.ui \ sip_account.ui \ chatroom.ui \ diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 4d60d6309c..fca97adda3 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -36,115 +36,155 @@ gboolean linphone_gtk_use_in_call_view(){ return val; } -void linphone_gtk_show_in_call_view(void){ - GtkWidget *main_window=linphone_gtk_get_main_window(); +LinphoneCall *linphone_gtk_get_currently_displayed_call(){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *main_window=linphone_gtk_get_main_window (); GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); - GtkWidget *in_call_frame=linphone_gtk_get_widget(main_window,"in_call_frame"); - gint idx; - - /* Make the in call frame visible and arrange for the notebook to - show that page */ - gtk_widget_show(in_call_frame); - idx = gtk_notebook_page_num(notebook, in_call_frame); - if (idx >= 0) { - gtk_notebook_set_current_page(notebook, idx); + const MSList *calls=linphone_core_get_calls(lc); + if (!linphone_gtk_use_in_call_view() || ms_list_size(calls)==1){ + if (calls) return (LinphoneCall*)calls->data; + }else{ + int idx=gtk_notebook_get_current_page (notebook); + GtkWidget *page=gtk_notebook_get_nth_page(notebook,idx); + if (page!=NULL){ + LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(page),"call"); + return call; + } } + return NULL; } -void linphone_gtk_show_idle_view(void){ - GtkWidget *main_window=linphone_gtk_get_main_window(); +static GtkWidget *make_tab_header(int number){ + GtkWidget *w=gtk_hbox_new (FALSE,0); + GtkWidget *i=create_pixmap ("status-green.png"); + GtkWidget *l; + gchar *text=g_strdup_printf("Call %i",number); + l=gtk_label_new (text); + gtk_box_pack_start (GTK_BOX(w),i,FALSE,FALSE,0); + gtk_box_pack_end(GTK_BOX(w),l,TRUE,TRUE,0); + gtk_widget_show_all(w); + return w; +} + +void linphone_gtk_create_in_call_view(LinphoneCall *call){ + GtkWidget *call_view=linphone_gtk_create_widget("main","in_call_frame"); + GtkWidget *main_window=linphone_gtk_get_main_window (); GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); - GtkWidget *idle_frame=linphone_gtk_get_widget(main_window,"idle_frame"); - GtkWidget *in_call_frame=linphone_gtk_get_widget(main_window,"in_call_frame"); - gint idx; + static int call_index=1; + int idx; + + g_object_set_data(G_OBJECT(call_view),"call",call); + linphone_call_set_user_pointer (call,call_view); + linphone_call_ref(call); + gtk_notebook_append_page (notebook,call_view,make_tab_header(call_index)); + gtk_widget_show(call_view); + idx = gtk_notebook_page_num(notebook, call_view); + gtk_notebook_set_current_page(notebook, idx); + call_index++; +} - /* Switch back to the idle frame page, maybe we should have - remembered where we were in gtk_show_in_call_view() to switch - back to that page of the notebook, but this should do in most - cases. */ - gtk_widget_show(idle_frame); /* Make sure it is visible... */ - idx = gtk_notebook_page_num(notebook, idle_frame); - if (idx >= 0) { - gtk_notebook_set_current_page(notebook, idx); - gtk_widget_hide(in_call_frame); - } +void linphone_gtk_remove_in_call_view(LinphoneCall *call){ + GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer (call); + GtkWidget *main_window=linphone_gtk_get_main_window (); + GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch"); + int idx; + g_return_if_fail(w!=NULL); + idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w); + gtk_notebook_remove_page (GTK_NOTEBOOK(nb),idx); + gtk_widget_destroy(w); + linphone_call_set_user_pointer (call,NULL); + linphone_call_unref(call); + gtk_notebook_set_current_page(GTK_NOTEBOOK(nb), 0); } -void display_peer_name_in_label(GtkWidget *label, const char *uri){ - LinphoneAddress *from; +static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *from){ const char *displayname=NULL; - char *id=NULL; + const char *id; char *uri_label; - - if (uri==NULL) { - ms_error("Strange: in call with nobody ?"); - return; - } - - from=linphone_address_new(uri); - if (from!=NULL){ - displayname=linphone_address_get_display_name(from); - id=linphone_address_as_string_uri_only(from); - }else id=ms_strdup(uri); - + displayname=linphone_address_get_display_name(from); + id=linphone_address_as_string_uri_only(from); + if (displayname!=NULL){ uri_label=g_markup_printf_escaped("<span size=\"large\">%s</span>\n<i>%s</i>", displayname,id); }else uri_label=g_markup_printf_escaped("<span size=\"large\"><i>%s</i></span>\n",id); gtk_label_set_markup(GTK_LABEL(label),uri_label); - ms_free(id); g_free(uri_label); - if (from!=NULL) linphone_address_destroy(from); } -void linphone_gtk_in_call_view_set_calling(const char *uri){ - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *status=linphone_gtk_get_widget(main_window,"in_call_status"); - GtkWidget *callee=linphone_gtk_get_widget(main_window,"in_call_uri"); - GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration"); - GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation"); +void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); + GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); + GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); + GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation"); GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif"); - + gtk_label_set_markup(GTK_LABEL(status),_("<b>Calling...</b>")); - display_peer_name_in_label(callee,uri); + display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); gtk_label_set_text(GTK_LABEL(duration),_("00::00::00")); if (pbuf!=NULL){ gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf); g_object_unref(G_OBJECT(pbuf)); - }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_INFO,GTK_ICON_SIZE_DIALOG); + }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_FIND,GTK_ICON_SIZE_DIALOG); } -void linphone_gtk_in_call_view_set_in_call(){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *status=linphone_gtk_get_widget(main_window,"in_call_status"); - GtkWidget *callee=linphone_gtk_get_widget(main_window,"in_call_uri"); - GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration"); - GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation"); +void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); + GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); + GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); + GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation"); + GdkPixbufAnimation *pbuf=create_pixbuf_animation("calling_anim.gif"); + + gtk_label_set_markup(GTK_LABEL(status),_("<b>Incoming call</b>")); + gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel")); + display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); + + gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(callview,"accept_call")), + create_pixmap (linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"))); + gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(callview,"decline_call")), + create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"))); + + gtk_label_set_text(GTK_LABEL(duration),_("00::00::00")); + if (pbuf!=NULL){ + gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf); + g_object_unref(G_OBJECT(pbuf)); + }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG); +} + +void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); + GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); + GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); + GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation"); GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif"); - const LinphoneAddress *uri=linphone_core_get_current_call_remote_address(lc); - char *tmp=linphone_address_as_string(uri); - display_peer_name_in_label(callee,tmp); - ms_free(tmp); + GtkWidget *holdbutton; + + display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); + gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),_("<b>In call with</b>")); gtk_label_set_text(GTK_LABEL(duration),_("00::00::00")); if (pbuf!=NULL){ gtk_image_set_from_animation(GTK_IMAGE(animation),pbuf); g_object_unref(G_OBJECT(pbuf)); - }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_INFO,GTK_ICON_SIZE_DIALOG); + }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG); linphone_gtk_enable_mute_button( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),TRUE); - linphone_gtk_enable_hold_button( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"hold_call")),TRUE); + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE); + holdbutton=linphone_gtk_get_widget(callview,"hold_call"); + linphone_gtk_enable_hold_button(GTK_TOGGLE_BUTTON(holdbutton),TRUE); + g_object_set_data(G_OBJECT(holdbutton),"call",call); } -void linphone_gtk_in_call_view_update_duration(int duration){ - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *duration_label=linphone_gtk_get_widget(main_window,"in_call_duration"); +void linphone_gtk_in_call_view_update_duration(LinphoneCall *call){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *duration_label=linphone_gtk_get_widget(callview,"in_call_duration"); + int duration=linphone_call_get_duration(call); char tmp[256]={0}; int seconds=duration%60; int minutes=(duration/60)%60; @@ -153,15 +193,15 @@ void linphone_gtk_in_call_view_update_duration(int duration){ gtk_label_set_text(GTK_LABEL(duration_label),tmp); } -static gboolean in_call_view_terminated(){ - linphone_gtk_show_idle_view(); +static gboolean in_call_view_terminated(LinphoneCall *call){ + linphone_gtk_remove_in_call_view(call); return FALSE; } -void linphone_gtk_in_call_view_terminate(const char *error_msg){ - GtkWidget *main_window=linphone_gtk_get_main_window(); - GtkWidget *status=linphone_gtk_get_widget(main_window,"in_call_status"); - GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation"); +void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); + GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation"); GdkPixbuf *pbuf=create_pixbuf(linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png")); if (error_msg==NULL) @@ -175,11 +215,12 @@ void linphone_gtk_in_call_view_terminate(const char *error_msg){ gtk_image_set_from_pixbuf(GTK_IMAGE(animation),pbuf); g_object_unref(G_OBJECT(pbuf)); } + gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); linphone_gtk_enable_mute_button( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),FALSE); + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE); linphone_gtk_enable_hold_button( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"hold_call")),FALSE); - g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,NULL); + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(callview,"hold_call")),FALSE); + g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call); } void linphone_gtk_draw_mute_button(GtkToggleButton *button, gboolean active){ @@ -215,14 +256,14 @@ void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive void linphone_gtk_draw_hold_button(GtkToggleButton *button, gboolean active){ if (active){ GtkWidget *image=create_pixmap("hold_off.png"); - gtk_button_set_label(GTK_BUTTON(button),_("HoldOff")); + gtk_button_set_label(GTK_BUTTON(button),_("Resume")); if (image!=NULL) { gtk_button_set_image(GTK_BUTTON(button),image); gtk_widget_show(image); } }else{ GtkWidget *image=create_pixmap("hold_on.png"); - gtk_button_set_label(GTK_BUTTON(button),_("HoldOn")); + gtk_button_set_label(GTK_BUTTON(button),_("Pause")); if (image!=NULL) { gtk_button_set_image(GTK_BUTTON(button),image); gtk_widget_show(image); @@ -232,23 +273,14 @@ void linphone_gtk_draw_hold_button(GtkToggleButton *button, gboolean active){ void linphone_gtk_hold_toggled(GtkToggleButton *button){ gboolean active=gtk_toggle_button_get_active(button); - + LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(button),"call"); if(active) { - LinphoneCall *call=linphone_core_get_current_call (linphone_gtk_get_core()); - if (call==NULL) return; linphone_core_pause_call(linphone_gtk_get_core(),call); } else { - const MSList *calls=linphone_core_get_calls(linphone_gtk_get_core()); - if (calls==NULL) return; - if (ms_list_size(calls)>1){ - g_warning("Simultaneously calls not yet implemented in gtk ui."); - return; - } - /*we are supposed to have only one */ - linphone_core_resume_call(linphone_gtk_get_core(),(LinphoneCall*)calls->data); + linphone_core_resume_call(linphone_gtk_get_core(),call); } linphone_gtk_draw_hold_button(button,active); } diff --git a/gtk/linphone.h b/gtk/linphone.h index 8502771557..c50dde5910 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -48,6 +48,8 @@ GdkPixbuf *_gdk_pixbuf_new_from_memory_at_scale(const void *data, gint len, gint GtkWidget *linphone_gtk_create_window(const char *window_name); GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name); +GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name); + LinphoneCore *linphone_gtk_get_core(void); GtkWidget *linphone_gtk_get_main_window(); void linphone_gtk_display_something(GtkMessageType type,const gchar *message); @@ -85,12 +87,13 @@ void linphone_gtk_show_directory_search(void); /*functions controlling the different views*/ gboolean linphone_gtk_use_in_call_view(); -void linphone_gtk_show_in_call_view(void); -void linphone_gtk_show_idle_view(void); -void linphone_gtk_in_call_view_set_calling(const char *uri); -void linphone_gtk_in_call_view_set_in_call(void); -void linphone_gtk_in_call_view_update_duration(int duration); -void linphone_gtk_in_call_view_terminate(const char *error_msg); +LinphoneCall *linphone_gtk_get_currently_displayed_call(); +void linphone_gtk_create_in_call_view(LinphoneCall *call); +void linphone_gtk_in_call_view_set_calling(LinphoneCall *call); +void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call); +void linphone_gtk_in_call_view_update_duration(LinphoneCall *call); +void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg); +void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call); void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive); void linphone_gtk_enable_hold_button(GtkToggleButton *button, gboolean sensitive); diff --git a/gtk/logging.c b/gtk/logging.c index 9bdf1dc0ea..4b3af66383 100644 --- a/gtk/logging.c +++ b/gtk/logging.c @@ -213,14 +213,6 @@ static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg) } } - - -static gboolean delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - gtk_widget_hide (widget); - return TRUE; -} - void linphone_gtk_log_hide(){ if (log_window) gtk_widget_hide(log_window); @@ -234,7 +226,7 @@ void linphone_gtk_create_log_window(void){ gtk_text_buffer_create_tag(b,"orange","foreground","orange",NULL); /*prevent the log window from being destroyed*/ g_signal_connect (G_OBJECT (log_window), "delete-event", - G_CALLBACK (delete_event_cb), NULL); + G_CALLBACK (gtk_widget_hide_on_delete), log_window); } diff --git a/gtk/main.c b/gtk/main.c index ea176e666c..f435ff31a0 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -42,7 +42,6 @@ static LinphoneCore *the_core=NULL; static GtkWidget *the_ui=NULL; static void linphone_gtk_show(LinphoneCore *lc); -static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call); static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); @@ -53,7 +52,7 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to); static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); -static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window); +static gboolean linphone_gtk_auto_answer(LinphoneCall *call); static gboolean verbose=0; @@ -107,7 +106,7 @@ static GOptionEntry linphone_options[]={ }; #define INSTALLED_XML_DIR PACKAGE_DATA_DIR "/linphone" -#define BUILD_TREE_XML_DIR "gtk-glade" +#define BUILD_TREE_XML_DIR "gtk" #ifndef WIN32 #define CONFIG_FILE ".linphonerc" @@ -279,23 +278,31 @@ GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ #else -GtkWidget *linphone_gtk_create_window(const char *window_name){ - GError* error = NULL; - GtkBuilder* builder = gtk_builder_new (); - char path[2048]; - GtkWidget *w; - snprintf(path,sizeof(path),"%s/%s.ui",BUILD_TREE_XML_DIR,window_name); +static int get_ui_file(const char *name, char *path, int pathsize){ + snprintf(path,pathsize,"%s/%s.ui",BUILD_TREE_XML_DIR,name); if (access(path,F_OK)!=0){ - snprintf(path,sizeof(path),"%s/%s.ui",INSTALLED_XML_DIR,window_name); + snprintf(path,pathsize,"%s/%s.ui",INSTALLED_XML_DIR,name); if (access(path,F_OK)!=0){ - g_error("Could not locate neither %s/%s.ui and %s/%s.ui .",BUILD_TREE_XML_DIR,window_name, - INSTALLED_XML_DIR,window_name); - return NULL; + g_error("Could not locate neither %s/%s.ui and %s/%s.ui .",BUILD_TREE_XML_DIR,name, + INSTALLED_XML_DIR,name); + return -1; } } + return 0; +} + +GtkWidget *linphone_gtk_create_window(const char *window_name){ + GError* error = NULL; + GtkBuilder* builder = gtk_builder_new (); + char path[512]; + GtkWidget *w; + + if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL; + if (!gtk_builder_add_from_file (builder, path, &error)){ g_error("Couldn't load builder file: %s", error->message); g_error_free (error); + return NULL; } w=GTK_WIDGET(gtk_builder_get_object (builder,window_name)); if (w==NULL){ @@ -308,6 +315,33 @@ GtkWidget *linphone_gtk_create_window(const char *window_name){ return w; } +GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_name){ + char path[2048]; + GtkWidget *w; + GtkBuilder* builder = gtk_builder_new (); + GError *error=NULL; + gchar *object_ids[2]; + object_ids[0]=g_strdup(widget_name); + object_ids[1]=NULL; + + if (get_ui_file(filename,path,sizeof(path))==-1) return NULL; + if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){ + g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message); + g_error_free (error); + g_free(object_ids[0]); + return NULL; + } + g_free(object_ids[0]); + w=GTK_WIDGET(gtk_builder_get_object (builder,widget_name)); + if (w==NULL){ + g_error("Could not retrieve '%s' window from xml file",widget_name); + return NULL; + } + g_object_set_data(G_OBJECT(w),"builder",builder); + gtk_builder_connect_signals(builder,w); + return w; +} + GtkWidget *linphone_gtk_get_widget(GtkWidget *window, const char *name){ GtkBuilder *builder=(GtkBuilder*)g_object_get_data(G_OBJECT(window),"builder"); GObject *w; @@ -580,37 +614,74 @@ static void completion_add_text(GtkEntry *entry, const char *text){ save_uri_history(); } -void linphone_gtk_call_terminated(const char *error){ +void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){ GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *icw; gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE); gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),TRUE); - linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"main_mute")),FALSE); - if (linphone_gtk_use_in_call_view()) - linphone_gtk_in_call_view_terminate(error); + + if (linphone_gtk_use_in_call_view() && call) + linphone_gtk_in_call_view_terminate(call,error); update_video_title(); - icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call")); - if (icw!=NULL){ - g_object_set_data(G_OBJECT(mw),"incoming_call",NULL); - gtk_widget_destroy(icw); - } } static gboolean in_call_timer(){ - if (linphone_core_in_call(linphone_gtk_get_core())){ - linphone_gtk_in_call_view_update_duration( - linphone_core_get_current_call_duration(linphone_gtk_get_core())); + LinphoneCall *call=linphone_core_get_current_call(linphone_gtk_get_core()); + if (call){ + linphone_gtk_in_call_view_update_duration(call); return TRUE; } return FALSE; } -static void linphone_gtk_call_started(GtkWidget *mw){ - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE); - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE); +static bool_t all_calls_paused(const MSList *calls){ + for(;calls!=NULL;calls=calls->next){ + LinphoneCall *call=(LinphoneCall*)calls->data; + if (linphone_call_get_state(call)!=LinphoneCallPaused) + return FALSE; + } + return TRUE; +} + +static void linphone_gtk_update_call_buttons(LinphoneCall *call){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *mw=linphone_gtk_get_main_window(); + const MSList *calls=linphone_core_get_calls(lc); + GtkWidget *button; + bool_t start_active=TRUE; + bool_t stop_active=FALSE; + bool_t add_call=FALSE; + + if (calls==NULL){ + start_active=TRUE; + stop_active=FALSE; + }else if (linphone_core_get_current_call(lc)!=NULL){ + start_active=FALSE; + stop_active=TRUE; + }else if (all_calls_paused(calls)){ + start_active=TRUE; + stop_active=TRUE; + add_call=TRUE; + }else if (call!=NULL){ + if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){ + start_active=TRUE; + stop_active=TRUE; + } + } + button=linphone_gtk_get_widget(mw,"start_call"); + gtk_widget_set_sensitive(button,start_active); + gtk_widget_set_visible(button,!add_call); + + button=linphone_gtk_get_widget(mw,"add_call"); + gtk_widget_set_sensitive(button,start_active); + gtk_widget_set_visible(button,add_call); + + gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),stop_active); + if (linphone_core_get_calls(lc)==NULL){ + linphone_gtk_enable_mute_button( + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")), + FALSE); + } update_video_title(); - if (linphone_gtk_use_in_call_view()) - g_timeout_add(250,(GSourceFunc)in_call_timer,NULL); } static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){ @@ -618,50 +689,37 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){ if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) { completion_add_text(GTK_ENTRY(uri_bar),entered); }else{ - linphone_gtk_call_terminated(NULL); + linphone_gtk_call_terminated(NULL,NULL); } return FALSE; } -static void _linphone_gtk_accept_call(){ - LinphoneCore *lc=linphone_gtk_get_core(); - GtkWidget *mw=linphone_gtk_get_main_window(); - GtkWidget *icw=GTK_WIDGET(g_object_get_data(G_OBJECT(mw),"incoming_call")); - if (icw!=NULL){ - g_object_set_data(G_OBJECT(mw),"incoming_call",NULL); - gtk_widget_destroy(icw); +static gboolean linphone_gtk_auto_answer(LinphoneCall *call){ + if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){ + linphone_core_accept_call (linphone_gtk_get_core(),call); + linphone_call_unref(call); } - - linphone_core_accept_call(lc,NULL); - linphone_gtk_call_started(linphone_gtk_get_main_window()); - if (linphone_gtk_use_in_call_view()){ - linphone_gtk_in_call_view_set_in_call(); - linphone_gtk_show_in_call_view(); - } - linphone_gtk_enable_mute_button( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")) - ,TRUE); + return FALSE; } + void linphone_gtk_start_call(GtkWidget *w){ LinphoneCore *lc=linphone_gtk_get_core(); - if (linphone_core_inc_invite_pending(lc)){ - /*accept the call*/ - _linphone_gtk_accept_call(); - }else if (linphone_core_in_call(lc)) { - /*already in call */ + LinphoneCall *call; + /*change into in-call mode, then do the work later as it might block a bit */ + GtkWidget *mw=gtk_widget_get_toplevel(w); + GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar"); + + call=linphone_gtk_get_currently_displayed_call (); + if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){ + linphone_core_accept_call(lc,call); }else{ - /*change into in-call mode, then do the work later as it might block a bit */ - GtkWidget *mw=gtk_widget_get_toplevel(w); - GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar"); - const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); - linphone_gtk_call_started(mw); - if (linphone_gtk_use_in_call_view()){ - linphone_gtk_in_call_view_set_calling(entered); - linphone_gtk_show_in_call_view(); - } + /*immediately disable the button and delay a bit the execution the linphone_core_invite() + so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/ + gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"start_call"),FALSE); g_timeout_add(100,(GSourceFunc)linphone_gtk_start_call_do,uri_bar); } + } void linphone_gtk_uri_bar_activate(GtkWidget *w){ @@ -670,23 +728,21 @@ void linphone_gtk_uri_bar_activate(GtkWidget *w){ void linphone_gtk_terminate_call(GtkWidget *button){ - const MSList *elem=linphone_core_get_calls(linphone_gtk_get_core()); - if (elem==NULL) return; - linphone_core_terminate_call(linphone_gtk_get_core(),(LinphoneCall*)elem->data); + LinphoneCall *call=linphone_gtk_get_currently_displayed_call (); + if (call) + linphone_core_terminate_call(linphone_gtk_get_core(),call); } -void linphone_gtk_decline_call(GtkWidget *button){ - linphone_core_terminate_call(linphone_gtk_get_core(),NULL); - gtk_widget_destroy(gtk_widget_get_toplevel(button)); +void linphone_gtk_decline_clicked(GtkWidget *button){ + LinphoneCall *call=linphone_gtk_get_currently_displayed_call (); + if (call) + linphone_core_terminate_call(linphone_gtk_get_core(),call); } -void linphone_gtk_accept_call(GtkWidget *button){ - _linphone_gtk_accept_call(); -} - -static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window){ - linphone_gtk_accept_call(linphone_gtk_get_widget(incall_window,"accept_call")); - return FALSE; +void linphone_gtk_answer_clicked(GtkWidget *button){ + LinphoneCall *call=linphone_gtk_get_currently_displayed_call (); + if (call) + linphone_core_accept_call(linphone_gtk_get_core(),call); } void linphone_gtk_set_audio_video(){ @@ -733,33 +789,6 @@ static void linphone_gtk_show(LinphoneCore *lc){ linphone_gtk_show_main_window(); } -static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call){ - GtkWidget *w=linphone_gtk_create_window("incoming_call"); - GtkWidget *label; - gchar *msg; - char *from=linphone_call_get_remote_address_as_string(call); - - if (auto_answer){ - g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w); - } - - gtk_window_set_transient_for(GTK_WINDOW(w),GTK_WINDOW(linphone_gtk_get_main_window())); - gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER_ON_PARENT); - - label=linphone_gtk_get_widget(w,"message"); - msg=g_strdup_printf(_("Incoming call from %s"),from); - gtk_label_set_text(GTK_LABEL(label),msg); - gtk_window_set_title(GTK_WINDOW(w),msg); - gtk_widget_show(w); - gtk_window_present(GTK_WINDOW(w)); - /*gtk_window_set_urgency_hint(GTK_WINDOW(w),TRUE);*/ - g_free(msg); - g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")), - from); - ms_free(from); -} - static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){ linphone_gtk_show_friends(); } @@ -902,25 +931,38 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){ switch(cs){ + case LinphoneCallOutgoingInit: + linphone_gtk_create_in_call_view (call); + break; + case LinphoneCallOutgoingProgress: + linphone_gtk_in_call_view_set_calling (call); + break; case LinphoneCallConnected: - if (linphone_gtk_use_in_call_view()) - linphone_gtk_in_call_view_set_in_call(); + linphone_gtk_in_call_view_set_in_call(call); linphone_gtk_enable_mute_button( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")), TRUE); + g_timeout_add(250,(GSourceFunc)in_call_timer,NULL); break; case LinphoneCallError: - linphone_gtk_call_terminated(msg); + linphone_gtk_in_call_view_terminate (call,msg); break; case LinphoneCallEnd: - linphone_gtk_call_terminated(NULL); + linphone_gtk_in_call_view_terminate(call,NULL); break; case LinphoneCallIncomingReceived: - linphone_gtk_inv_recv (lc,call); + linphone_gtk_create_in_call_view (call); + linphone_gtk_in_call_view_set_incoming(call); + if (auto_answer) { + linphone_call_ref(call); + g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call); + } + break; default: break; } + linphone_gtk_update_call_buttons (call); } static void icon_popup_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){ @@ -1074,6 +1116,7 @@ static void linphone_gtk_configure_main_window(){ static const char *title; static const char *home; static const char *start_call_icon; + static const char *add_call_icon; static const char *stop_call_icon; static const char *search_icon; static gboolean update_check_menu; @@ -1083,6 +1126,7 @@ static void linphone_gtk_configure_main_window(){ title=linphone_gtk_get_ui_config("title","Linphone"); home=linphone_gtk_get_ui_config("home","http://www.linphone.org"); start_call_icon=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"); + add_call_icon=linphone_gtk_get_ui_config("add_call_icon","addcall-green.png"); stop_call_icon=linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"); search_icon=linphone_gtk_get_ui_config("directory_search_icon",NULL); update_check_menu=linphone_gtk_get_ui_config_int("update_check_menu",0); @@ -1097,18 +1141,22 @@ static void linphone_gtk_configure_main_window(){ #endif } if (start_call_icon){ - GdkPixbuf *pbuf=create_pixbuf(start_call_icon); - gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"start_call_icon")),pbuf); - if (buttons_have_borders) - gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NORMAL); - g_object_unref(G_OBJECT(pbuf)); + gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")), + create_pixmap (start_call_icon)); + if (!buttons_have_borders) + gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"start_call")),GTK_RELIEF_NONE); + } + if (add_call_icon){ + gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")), + create_pixmap (add_call_icon)); + if (!buttons_have_borders) + gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"add_call")),GTK_RELIEF_NONE); } if (stop_call_icon){ - GdkPixbuf *pbuf=create_pixbuf(stop_call_icon); - gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"terminate_call_icon")),pbuf); - if (buttons_have_borders) - gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NORMAL); - g_object_unref(G_OBJECT(pbuf)); + gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")), + create_pixmap (stop_call_icon)); + if (!buttons_have_borders) + gtk_button_set_relief(GTK_BUTTON(linphone_gtk_get_widget(w,"terminate_call")),GTK_RELIEF_NONE); } if (search_icon){ GdkPixbuf *pbuf=create_pixbuf(search_icon); @@ -1154,6 +1202,17 @@ void linphone_gtk_manage_login(void){ } } + +void linphone_gtk_close(GtkWidget *mw){ + /*shutdown calls if any*/ + LinphoneCore *lc=linphone_gtk_get_core(); + if (linphone_core_in_call(lc)){ + linphone_core_terminate_all_calls(lc); + } + linphone_core_enable_video_preview(lc,FALSE); + gtk_widget_hide(mw); +} + static void linphone_gtk_init_main_window(){ GtkWidget *main_window; @@ -1175,23 +1234,12 @@ static void linphone_gtk_init_main_window(){ if (!linphone_gtk_use_in_call_view()) { gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute")); } - if (linphone_core_in_call(linphone_gtk_get_core())) linphone_gtk_call_started( - linphone_gtk_get_main_window());/*hide the call button, show terminate button*/ + linphone_gtk_update_call_buttons (NULL); + /*prevent the main window from being destroyed by a user click on WM controls, instead we hide it*/ + g_signal_connect (G_OBJECT (main_window), "delete-event", + G_CALLBACK (linphone_gtk_close), main_window); } -void linphone_gtk_close(){ - /* couldn't find a way to prevent closing to destroy the main window*/ - LinphoneCore *lc=linphone_gtk_get_core(); - the_ui=NULL; - the_ui=linphone_gtk_create_window("main"); - linphone_gtk_init_main_window(); - /*shutdown call if any*/ - if (linphone_core_in_call(lc)){ - linphone_core_terminate_call(lc,NULL); - linphone_gtk_call_terminated(NULL); - } - linphone_core_enable_video_preview(lc,FALSE); -} void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ if (verbose){ diff --git a/gtk/main.ui b/gtk/main.ui index 616c8e9f1a..2f9433a3fb 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -58,7 +58,6 @@ <object class="GtkUIManager" id="uimanager1"/> <object class="GtkWindow" id="main"> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="destroy" handler="linphone_gtk_close"/> <child> <object class="GtkVBox" id="vbox2"> <property name="visible">True</property> @@ -244,41 +243,27 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="has_tooltip">True</property> - <property name="tooltip_text" translatable="yes">Start call</property> - <property name="relief">none</property> <signal name="clicked" handler="linphone_gtk_start_call"/> - <child> - <object class="GtkHBox" id="hbox4"> - <property name="visible">True</property> - <child> - <object class="GtkImage" id="start_call_icon"> - <property name="visible">True</property> - <property name="stock">gtk-apply</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="start_call_label"> - <property name="label" translatable="yes">Start call</property> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - </child> </object> <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="padding">10</property> <property name="position">0</property> </packing> </child> + <child> + <object class="GtkButton" id="add_call"> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Initiate a new call</property> + <signal name="clicked" handler="linphone_gtk_start_call"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> <child> <object class="GtkFrame" id="frame4"> <property name="visible">True</property> @@ -321,51 +306,20 @@ </child> </object> <packing> - <property name="position">1</property> + <property name="position">2</property> </packing> </child> <child> <object class="GtkButton" id="terminate_call"> <property name="visible">True</property> - <property name="sensitive">False</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="has_tooltip">True</property> - <property name="tooltip_text" translatable="yes">Terminate call</property> - <property name="relief">none</property> <signal name="clicked" handler="linphone_gtk_terminate_call"/> - <child> - <object class="GtkHBox" id="hbox21"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <child> - <object class="GtkImage" id="terminate_call_icon"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="stock">gtk-close</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="terminate_call_label"> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Terminate call</property> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - </child> </object> <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="padding">10</property> - <property name="position">2</property> + <property name="position">3</property> </packing> </child> </object> @@ -1116,167 +1070,10 @@ </packing> </child> <child> - <object class="GtkFrame" id="in_call_frame"> - <property name="label_xalign">0.5</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkAlignment" id="alignment1"> - <property name="visible">True</property> - <property name="left_padding">12</property> - <property name="right_padding">12</property> - <child> - <object class="GtkVBox" id="vbox3"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkImage" id="in_call_animation"> - <property name="visible">True</property> - <property name="stock">gtk-info</property> - <property name="icon-size">5</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkFrame" id="frame2"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <child> - <object class="GtkLabel" id="in_call_uri"> - <property name="visible">True</property> - <property name="label" translatable="yes">label</property> - <property name="justify">center</property> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="use_markup">True</property> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkFrame" id="frame1"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <child> - <object class="GtkVBox" id="vbox4"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkLabel" id="in_call_duration"> - <property name="visible">True</property> - <property name="label" translatable="yes">Duration</property> - <property name="justify">center</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="call_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Duration:</property> - <property name="use_markup">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkHButtonBox" id="hbuttonbox4"> - <property name="visible">True</property> - <property name="layout_style">spread</property> - <child> - <object class="GtkToggleButton" id="incall_mute"> - <property name="label" translatable="yes">Mute</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="toggled" handler="linphone_gtk_mute_toggled"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkToggleButton" id="hold_call"> - <property name="label" translatable="yes">HoldOn</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="toggled" handler="linphone_gtk_hold_toggled"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="in_call_status"> - <property name="visible">True</property> - <property name="label" translatable="yes">In call</property> - <property name="use_markup">True</property> - <property name="justify">center</property> - </object> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> + <placeholder/> </child> <child type="tab"> - <object class="GtkHBox" id="hbox10"> - <property name="visible">True</property> - <child> - <object class="GtkImage" id="incall_icon"> - <property name="visible">True</property> - <property name="stock">gtk-missing-image</property> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label18"> - <property name="visible">True</property> - <property name="label" translatable="yes">Call Details</property> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">2</property> - <property name="tab_fill">False</property> - </packing> + <placeholder/> </child> </object> <packing> @@ -1497,4 +1294,175 @@ <property name="visible">True</property> <property name="stock">gtk-execute</property> </object> + <object class="GtkWindow" id="dummy_in_call_window"> + <child> + <object class="GtkFrame" id="in_call_frame"> + <property name="label_xalign">0.5</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <property name="right_padding">12</property> + <child> + <object class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkImage" id="in_call_animation"> + <property name="visible">True</property> + <property name="stock">gtk-info</property> + <property name="icon-size">5</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame2"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <object class="GtkLabel" id="in_call_uri"> + <property name="visible">True</property> + <property name="label" translatable="yes">label</property> + <property name="justify">center</property> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="answer_decline_panel"> + <property name="layout_style">spread</property> + <child> + <object class="GtkButton" id="accept_call"> + <property name="label" translatable="yes">Answer</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="linphone_gtk_answer_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="decline_call"> + <property name="label" translatable="yes">Decline</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="linphone_gtk_decline_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <child> + <object class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel" id="in_call_duration"> + <property name="visible">True</property> + <property name="label" translatable="yes">Duration</property> + <property name="justify">center</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="call_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Duration:</property> + <property name="use_markup">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox4"> + <property name="visible">True</property> + <property name="layout_style">spread</property> + <child> + <object class="GtkToggleButton" id="incall_mute"> + <property name="label" translatable="yes">Mute</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="toggled" handler="linphone_gtk_mute_toggled"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToggleButton" id="hold_call"> + <property name="label" translatable="yes">HoldOn</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="toggled" handler="linphone_gtk_hold_toggled"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">4</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="in_call_status"> + <property name="visible">True</property> + <property name="label" translatable="yes">In call</property> + <property name="use_markup">True</property> + <property name="justify">center</property> + </object> + </child> + </object> + </child> + </object> </interface> diff --git a/pixmaps/addcall-green.png b/pixmaps/addcall-green.png new file mode 100644 index 0000000000000000000000000000000000000000..3e6ae3b7a8b30334482123a99c963bdbc787f559 GIT binary patch literal 2629 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 literal 0 HcmV?d00001 -- GitLab