diff options
author | Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk> | 2011-03-15 00:23:03 +0800 |
---|---|---|
committer | Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk> | 2011-03-15 00:23:03 +0800 |
commit | c6b85f107a481541d8cd8622d54edee506a637f2 (patch) | |
tree | 06251c14a637c325b866a19a732d7d4271b112e9 | |
parent | 572751ddc752f35b95bdf9bd587569cac19cd80d (diff) | |
parent | acb39f9316c77ace16b473d258f4024d7a5e43ce (diff) | |
download | gsoc2013-empathy-c6b85f107a481541d8cd8622d54edee506a637f2.tar gsoc2013-empathy-c6b85f107a481541d8cd8622d54edee506a637f2.tar.gz gsoc2013-empathy-c6b85f107a481541d8cd8622d54edee506a637f2.tar.bz2 gsoc2013-empathy-c6b85f107a481541d8cd8622d54edee506a637f2.tar.lz gsoc2013-empathy-c6b85f107a481541d8cd8622d54edee506a637f2.tar.xz gsoc2013-empathy-c6b85f107a481541d8cd8622d54edee506a637f2.tar.zst gsoc2013-empathy-c6b85f107a481541d8cd8622d54edee506a637f2.zip |
Merge branch 'empathy-skype' into debian
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | libempathy-gtk/Makefile.am | 7 | ||||
-rw-r--r-- | libempathy-gtk/empathy-account-widget.c | 4 | ||||
-rw-r--r-- | libempathy-gtk/empathy-individual-view.c | 15 | ||||
-rw-r--r-- | libempathy-gtk/mx-gtk-light-switch.c | 536 | ||||
-rw-r--r-- | libempathy-gtk/mx-gtk-light-switch.h | 71 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/empathy-accounts-dialog.c | 63 | ||||
-rw-r--r-- | src/empathy-audio-sink.c | 302 | ||||
-rw-r--r-- | src/empathy-audio-sink.h | 2 | ||||
-rw-r--r-- | src/empathy-call-handler.c | 17 | ||||
-rw-r--r-- | src/empathy-call-window.c | 119 | ||||
-rw-r--r-- | src/empathy-event-manager.c | 29 | ||||
-rw-r--r-- | src/empathy-streamed-media-window.c | 119 |
14 files changed, 1030 insertions, 258 deletions
diff --git a/configure.ac b/configure.ac index 0b3b06456..06f5188d4 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,7 @@ FOLKS_REQUIRED=0.3.5 GCONF_REQUIRED=1.2.0 GLIB_REQUIRED=2.27.2 GNUTLS_REQUIRED=2.8.5 +GSTREAMER_REQUIRED=0.10.32 GTK_REQUIRED=2.22.0 KEYRING_REQUIRED=2.26.0 LIBCANBERRA_GTK_REQUIRED=0.4 @@ -154,7 +155,7 @@ PKG_CHECK_MODULES(EMPATHY, gnutls >= $GNUTLS_REQUIRED gmodule-export-2.0 gobject-2.0 - gstreamer-0.10 + gstreamer-0.10 >= $GSTREAMER_REQUIRED gstreamer-interfaces-0.10 libxml-2.0 telepathy-glib >= $TELEPATHY_GLIB_REQUIRED diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index a7f23ece1..28bfbe07c 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -91,7 +91,8 @@ libempathy_gtk_handwritten_source = \ empathy-theme-irc.c \ empathy-theme-manager.c \ empathy-tls-dialog.c \ - empathy-ui-utils.c + empathy-ui-utils.c \ + $(NULL) libempathy_gtk_headers = \ empathy-account-chooser.h \ @@ -154,12 +155,14 @@ libempathy_gtk_headers = \ empathy-theme-irc.h \ empathy-theme-manager.h \ empathy-tls-dialog.h \ - empathy-ui-utils.h + empathy-ui-utils.h \ + $(NULL) libempathy_gtk_la_SOURCES = \ $(libempathy_gtk_handwritten_source) \ $(libempathy_gtk_headers) \ gcr-simple-certificate.c gcr-simple-certificate.h \ + mx-gtk-light-switch.c mx-gtk-light-switch.h \ totem-subtitle-encoding.c totem-subtitle-encoding.h # do not distribute generated files diff --git a/libempathy-gtk/empathy-account-widget.c b/libempathy-gtk/empathy-account-widget.c index b8f28d71e..3d3e3d0f8 100644 --- a/libempathy-gtk/empathy-account-widget.c +++ b/libempathy-gtk/empathy-account-widget.c @@ -1448,6 +1448,7 @@ empathy_account_widget_enabled_cb (TpAccount *account, } } +#if 0 static void #ifdef HAVE_MEEGO account_widget_switch_flipped_cb (MxGtkLightSwitch *sw, @@ -1474,6 +1475,7 @@ account_widget_enabled_toggled_cb (GtkToggleButton *toggle_button, tp_account_set_enabled_async (account, state, account_widget_account_enabled_cb, user_data); } +#endif void empathy_account_widget_set_other_accounts_exist (EmpathyAccountWidget *self, @@ -1636,6 +1638,7 @@ static void add_enable_checkbox (EmpathyAccountWidget *self, TpAccount *account) { +#if 0 EmpathyAccountWidgetPriv *priv = GET_PRIV (self); #ifdef HAVE_MEEGO GtkWidget *w; @@ -1698,6 +1701,7 @@ add_enable_checkbox (EmpathyAccountWidget *self, g_signal_connect (G_OBJECT (priv->enabled_checkbox), "toggled", G_CALLBACK (account_widget_enabled_toggled_cb), self); #endif /* HAVE_MEEGO */ +#endif } #ifndef HAVE_MEEGO diff --git a/libempathy-gtk/empathy-individual-view.c b/libempathy-gtk/empathy-individual-view.c index 34bb7f32d..f455cd74e 100644 --- a/libempathy-gtk/empathy-individual-view.c +++ b/libempathy-gtk/empathy-individual-view.c @@ -2236,8 +2236,19 @@ individual_view_remove_dialog_show (GtkWindow *parent, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", message); if (block_button) - gtk_dialog_add_button (GTK_DIALOG (dialog), - _("Remove and Block"), GTK_RESPONSE_REJECT); + { + GtkWidget *button; + + /* gtk_dialog_add_button() doesn't allow us to pass a string with a + * mnemonic so we have to create the button manually. */ + button = gtk_button_new_with_mnemonic ( + _("Delete and _Block")); + + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, + GTK_RESPONSE_REJECT); + + gtk_widget_show (button); + } gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_NO, diff --git a/libempathy-gtk/mx-gtk-light-switch.c b/libempathy-gtk/mx-gtk-light-switch.c new file mode 100644 index 000000000..6337b41b6 --- /dev/null +++ b/libempathy-gtk/mx-gtk-light-switch.c @@ -0,0 +1,536 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright 2009 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * Boston, MA 02111-1307, USA. + * + */ + +/** + * SECTION:mx-gtk-light-switch + * @short_description: a toggle switch between two states + * + * A visual representation of a toggle switch that can move between two states. + */ + +#include <config.h> +#include "mx-gtk-light-switch.h" + +#include <glib/gi18n-lib.h> + +#if 0 +/* We use the special gcc constructor attribute so we can avoid + * requiring an init function to get translations to work! This + * function is also in mx-utils but we also need it here + * because that is a separate library */ +static void __attribute__ ((constructor)) +_start (void) +{ + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +} +#endif + +G_DEFINE_TYPE (MxGtkLightSwitch, mx_gtk_light_switch, GTK_TYPE_DRAWING_AREA) + +#define MX_GTK_LIGHT_SWITCH_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), MX_GTK_TYPE_LIGHT_SWITCH, MxGtkLightSwitchPrivate)) + +static gboolean mx_gtk_light_switch_configure (GtkWidget *lightswitch, + GdkEventConfigure *event); +static gboolean mx_gtk_light_switch_expose (GtkWidget *lightswitch, + GdkEventExpose *event); +static gboolean mx_gtk_light_switch_button_release (GtkWidget *lightswitch, + GdkEventButton *event); +static gboolean mx_gtk_light_switch_button_press (GtkWidget *lightswitch, + GdkEventButton *event); +static gboolean mx_gtk_light_switch_motion_notify (GtkWidget *lightswitch, + GdkEventMotion *event); +static void mx_gtk_light_switch_size_request (GtkWidget *lightswitch, + GtkRequisition *req); + +static void mx_gtk_light_switch_style_set (GtkWidget *lightswitch, + GtkStyle *previous_style); + +enum { + SWITCH_FLIPPED, + LAST_SIGNAL +}; + +static guint mx_gtk_light_switch_signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + PROP_ACTIVE, +}; + +typedef struct _MxGtkLightSwitchPrivate MxGtkLightSwitchPrivate; + +struct _MxGtkLightSwitchPrivate { + gboolean active; /* boolean state of switch */ + gboolean dragging; /* true if dragging switch */ + gint x; /* the x position of the switch */ + gint drag_start; /* position dragging started at */ + gint drag_threshold; + gint switch_width; + gint switch_height; + gint trough_width; + gint offset; /* offset of the mouse to slider when dragging */ +}; + +#define ON_STRING _("On") +#define OFF_STRING _("Off") + +#define UNAVAILABLE_STRING _("Unavailable") + +static void +mx_gtk_light_switch_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MxGtkLightSwitch *ls; + + ls = MX_GTK_LIGHT_SWITCH (object); + + switch (prop_id) + { + case PROP_ACTIVE: + mx_gtk_light_switch_set_active (ls, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +mx_gtk_light_switch_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MxGtkLightSwitchPrivate *priv; + + priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (object); + + switch (prop_id) + { + case PROP_ACTIVE: + g_value_set_boolean (value, priv->active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +mx_gtk_light_switch_class_init (MxGtkLightSwitchClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + GParamSpec *spec; + + object_class = G_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + object_class->set_property = mx_gtk_light_switch_set_property; + object_class->get_property = mx_gtk_light_switch_get_property; + + widget_class->configure_event = mx_gtk_light_switch_configure; + widget_class->expose_event = mx_gtk_light_switch_expose; + widget_class->button_release_event = mx_gtk_light_switch_button_release; + widget_class->button_press_event = mx_gtk_light_switch_button_press; + widget_class->motion_notify_event = mx_gtk_light_switch_motion_notify; + widget_class->size_request = mx_gtk_light_switch_size_request; + widget_class->style_set = mx_gtk_light_switch_style_set; + + spec = g_param_spec_boolean ("active", + "Active", + "Is the light switch on or not", + FALSE, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_ACTIVE, spec); + + /* MxGtkLightSwitch signals */ + mx_gtk_light_switch_signals[SWITCH_FLIPPED] = + g_signal_new ("switch-flipped", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MxGtkLightSwitchClass, switch_flipped), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, + G_TYPE_BOOLEAN); + + g_type_class_add_private (klass, + sizeof (MxGtkLightSwitchPrivate)); +} + +static void +mx_gtk_light_switch_init (MxGtkLightSwitch *self) +{ + MxGtkLightSwitchPrivate *priv; + + priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (self); + priv->active = FALSE; + priv->x = 0; + + /* add events, do initial draw/update, etc */ + gtk_widget_add_events (GTK_WIDGET (self), + GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK); +} + +static void +draw (GtkWidget *lightswitch, + cairo_t *cr) +{ + MxGtkLightSwitchPrivate *priv; + + gint on_label_x; + gint off_label_x; + gint label_width; + gint label_height; + GtkStyle *style; + PangoLayout *layout; + PangoContext *context; + GtkStateType state_type; + + priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + style = lightswitch->style; +#if GTK_CHECK_VERSION (2,19,5) + state_type = gtk_widget_get_state (lightswitch); +#else + state_type = GTK_WIDGET_STATE (lightswitch); +#endif + + on_label_x = (priv->trough_width / 5) * 0.75; + off_label_x = (priv->trough_width / 8) * 5; + + /* draw the trough */ + gtk_paint_box (style, + lightswitch->window, + (state_type != GTK_STATE_INSENSITIVE && priv->active) + ? GTK_STATE_SELECTED : state_type, + GTK_SHADOW_IN, + NULL, + NULL, + "light-switch-trough", + 0, + 0, + (priv->trough_width), + priv->switch_height); + +#if 0 + if (state_type == GTK_STATE_INSENSITIVE) + return; +#else + if (state_type == GTK_STATE_INSENSITIVE) + { + context = gdk_pango_context_get (); + layout = pango_layout_new (context); + g_object_unref (context); + + pango_layout_set_font_description (layout, style->font_desc); + pango_layout_set_text (layout, UNAVAILABLE_STRING, -1); + pango_layout_get_size (layout, &label_width, &label_height); + gtk_paint_layout (style, lightswitch->window, state_type, FALSE, + NULL, lightswitch, "lighswitch-label", + (priv->trough_width - (label_width / PANGO_SCALE)) / 2, + (priv->switch_height - (label_height / PANGO_SCALE)) / 2, + layout); + g_object_unref (layout); + return; + } + + /* Draw the first label; "On" */ + context = gdk_pango_context_get (); + layout = pango_layout_new (context); + g_object_unref (context); + pango_layout_set_font_description (layout, + style->font_desc); + pango_layout_set_text (layout, ON_STRING, -1); + pango_layout_get_size (layout, + &label_width, + &label_height); + gtk_paint_layout (style, + lightswitch->window, + (priv->active) ? GTK_STATE_SELECTED : GTK_STATE_NORMAL, + FALSE, + NULL, + (GtkWidget*) lightswitch, + "lightswitch-label", + on_label_x, + (priv->switch_height + - (label_height / PANGO_SCALE)) / 2, + layout); + + pango_layout_set_text (layout, OFF_STRING, -1); + pango_layout_get_size (layout, + &label_width, + &label_height); + gtk_paint_layout (style, + lightswitch->window, + (priv->active) ? GTK_STATE_SELECTED : GTK_STATE_NORMAL, + FALSE, + NULL, + (GtkWidget*) lightswitch, + "lightswitch-label", + off_label_x, + (priv->switch_height + - (label_height / PANGO_SCALE)) / 2, + layout); + g_object_unref (layout); +#endif + /* draw the switch itself */ + gtk_paint_box (style, + lightswitch->window, +#if GTK_CHECK_VERSION (2,19,5) + gtk_widget_get_state (lightswitch), +#else + GTK_WIDGET_STATE (lightswitch), +#endif + GTK_SHADOW_OUT, + NULL, + NULL, + "light-switch-handle", + priv->x + style->xthickness, + style->ythickness, + priv->switch_width - style->xthickness * 2, + priv->switch_height - style->ythickness * 2); + +} + +static void +mx_gtk_light_switch_size_request (GtkWidget *lightswitch, + GtkRequisition *req) +{ + MxGtkLightSwitchPrivate *priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + + req->height = priv->switch_height; + req->width = priv->trough_width; +} + +static void +mx_gtk_light_switch_style_set (GtkWidget *lightswitch, + GtkStyle *previous_style) +{ + MxGtkLightSwitchPrivate *priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + PangoLayout *layout; + gint label_width, label_height; + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (lightswitch), NULL); + pango_layout_set_text (layout, UNAVAILABLE_STRING, -1); + pango_layout_get_pixel_size (layout, &label_width, &label_height); + g_object_unref (layout); + + /* MxToggle is 105x39, so make sure light-switch is at least this size */ + priv->trough_width = MAX (103, label_width); + priv->switch_width = (priv->trough_width / 2) * 1.1; + //priv->switch_height = MAX (39, label_height); + priv->switch_height = 24; + priv->switch_width = 50; + priv->trough_width = 98; +} + +static gboolean +mx_gtk_light_switch_configure (GtkWidget *lightswitch, + GdkEventConfigure *event) +{ + MxGtkLightSwitchPrivate *priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + + if (priv->active) + priv->x = priv->trough_width - priv->switch_width; + else + priv->x = 0; + + return FALSE; +} + +static gboolean +mx_gtk_light_switch_expose (GtkWidget *lightswitch, + GdkEventExpose *event) +{ + cairo_t *cr; + cr = gdk_cairo_create (lightswitch->window); + + cairo_rectangle (cr, + event->area.x, + event->area.y, + event->area.width, + event->area.height); + + cairo_clip (cr); + + draw (lightswitch, cr); + + cairo_destroy (cr); + + return FALSE; +} + +static gboolean +mx_gtk_light_switch_motion_notify (GtkWidget *lightswitch, + GdkEventMotion *event) +{ + MxGtkLightSwitchPrivate *priv; + + priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + + if (ABS (event->x - priv->drag_start) < priv->drag_threshold) + return TRUE; + + if (event->state & GDK_BUTTON1_MASK) + { + gint position = event->x - priv->offset; + + if (position > (priv->trough_width - priv->switch_width)) + priv->x = (priv->trough_width - priv->switch_width); + else if (position < 0) + priv->x = 0; + else + priv->x = position; + + priv->dragging = TRUE; + gtk_widget_queue_draw ((GtkWidget *) lightswitch); + } + + return TRUE; +} + +/** + * mx_gtk_light_switch_get_active: + * @lightswitch: A #MxGtkLightSwitch + * + * Get the value of the "active" property + * + * Returns: #TRUE if the switch is "on" + */ +gboolean +mx_gtk_light_switch_get_active (MxGtkLightSwitch *lightswitch) +{ + MxGtkLightSwitchPrivate *priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + + return priv->active; +} + +/** + * mx_gtk_light_switch_set_active: + * @lightswitch: A #MxGtkLightSwitch + * @active: #TRUE to set the switch to its ON state + * + * Set the value of the "active" property + * + */ +void +mx_gtk_light_switch_set_active (MxGtkLightSwitch *lightswitch, + gboolean active) +{ + MxGtkLightSwitchPrivate *priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + + if (priv->active == active) + { + return; + } + else + { + priv->active = active; + if (active == TRUE) + { + priv->x = priv->trough_width - priv->switch_width; + } + else + { + priv->x = 0; + } + + gtk_widget_queue_draw ((GtkWidget *) lightswitch); + + g_object_notify (G_OBJECT (lightswitch), "active"); + g_signal_emit (lightswitch, + mx_gtk_light_switch_signals[SWITCH_FLIPPED], + 0, + priv->active); + } +} + +static gboolean +mx_gtk_light_switch_button_press (GtkWidget *lightswitch, + GdkEventButton *event) +{ + MxGtkLightSwitchPrivate *priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + + if (priv->active) + priv->offset = event->x - (priv->trough_width - priv->switch_width); + else + priv->offset = event->x; + + priv->drag_start = event->x; + + g_object_get (gtk_widget_get_settings (lightswitch), + "gtk-dnd-drag-threshold", &priv->drag_threshold, + NULL); + + return FALSE; +} + +static gboolean +mx_gtk_light_switch_button_release (GtkWidget *lightswitch, + GdkEventButton *event) +{ + MxGtkLightSwitchPrivate *priv; + + priv = MX_GTK_LIGHT_SWITCH_GET_PRIVATE (lightswitch); + + /* detect whereabouts we are and "drop" into a state */ + if (priv->dragging) + { + priv->dragging = FALSE; + if (priv->x + (priv->switch_width / 2) > priv->trough_width / 2) + { + mx_gtk_light_switch_set_active ((MxGtkLightSwitch *) lightswitch, TRUE); + priv->x = priv->trough_width - priv->switch_width; + } + else + { + mx_gtk_light_switch_set_active ((MxGtkLightSwitch *) lightswitch, FALSE); + priv->x = 0; + } + /* we always need to queue a redraw after dragging to put the slider back + * in the correct place */ + gtk_widget_queue_draw ((GtkWidget *) lightswitch); + } + else + { + mx_gtk_light_switch_set_active ((MxGtkLightSwitch *) lightswitch, !priv->active); + } + + return FALSE; +} + +/** + * mx_gtk_light_switch_new: + * + * Create a #MxGtkLightSwitch + * + * Returns: a newly allocated #MxGtkLightSwitch + */ +GtkWidget* +mx_gtk_light_switch_new (void) +{ + return g_object_new (MX_GTK_TYPE_LIGHT_SWITCH, NULL); +} + diff --git a/libempathy-gtk/mx-gtk-light-switch.h b/libempathy-gtk/mx-gtk-light-switch.h new file mode 100644 index 000000000..88fdf69e6 --- /dev/null +++ b/libempathy-gtk/mx-gtk-light-switch.h @@ -0,0 +1,71 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright 2009 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * Boston, MA 02111-1307, USA. + * + */ +#ifndef _MX_GTK_LIGHT_SWITCH +#define _MX_GTK_LIGHT_SWITCH + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define MX_GTK_TYPE_LIGHT_SWITCH mx_gtk_light_switch_get_type () + +#define MX_GTK_LIGHT_SWITCH(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MX_GTK_TYPE_LIGHT_SWITCH, MxGtkLightSwitch)) + +#define MX_GTK_LIGHT_SWITCH_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MX_GTK_TYPE_LIGHT_SWITCH, MxGtkLightSwitchClass)) + +#define MX_GTK_IS_LIGHT_SWITCH(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MX_GTK_TYPE_LIGHT_SWITCH)) + +#define MX_GTK_IS_LIGHT_SWITCH_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MX_GTK_TYPE_LIGHT_SWITCH)) + +#define MX_GTK_LIGHT_SWITCH_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MX_GTK_TYPE_LIGHT_SWITCH, MxGtkLightSwitchClass)) + +/** + * MxGtkLightSwitch: + * + * The contents of this structure are private and should only be accessed + * through the public API. + */ +typedef struct { + /*< private >*/ + GtkDrawingArea parent; +} MxGtkLightSwitch; + +typedef struct { + GtkDrawingAreaClass parent_class; + + void (*switch_flipped) (MxGtkLightSwitch *lightswitch, gboolean state); +} MxGtkLightSwitchClass; + +GType mx_gtk_light_switch_get_type (void); + +void mx_gtk_light_switch_set_active (MxGtkLightSwitch *lightswitch, + gboolean active); +gboolean mx_gtk_light_switch_get_active (MxGtkLightSwitch *lightswitch); + +GtkWidget* mx_gtk_light_switch_new (void); + +G_END_DECLS + +#endif /* _MX_GTK_LIGHT_SWITCH */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 205ab7539..a137605e5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -74,6 +74,7 @@ libempathy-gtk/empathy-theme-manager.c libempathy-gtk/empathy-tls-dialog.c libempathy-gtk/empathy-ui-utils.c libempathy-gtk/totem-subtitle-encoding.c +libempathy-gtk/mx-gtk-light-switch.c nautilus-sendto-plugin/empathy-nautilus-sendto.c diff --git a/src/empathy-accounts-dialog.c b/src/empathy-accounts-dialog.c index 1e267df92..206e7bca1 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -49,6 +49,7 @@ #include <libempathy-gtk/empathy-account-widget-skype.h> #include <libempathy-gtk/empathy-cell-renderer-activatable.h> #include <libempathy-gtk/empathy-images.h> +#include <libempathy-gtk/mx-gtk-light-switch.h> #include "empathy-accounts-dialog.h" #include "empathy-import-dialog.h" @@ -87,6 +88,7 @@ typedef struct { GtkWidget *label_status; GtkWidget *image_status; GtkWidget *throbber; + GtkWidget *enabled_switch; GtkWidget *frame_no_protocol; GtkWidget *treeview; @@ -218,6 +220,49 @@ accounts_dialog_status_infobar_set_message (EmpathyAccountsDialog *dialog, } static void +accounts_dialog_enable_account_cb (GObject *account, + GAsyncResult *result, + gpointer user_data) +{ + GError *error = NULL; + + tp_account_set_enabled_finish (TP_ACCOUNT (account), result, &error); + + if (error != NULL) + { + DEBUG ("Could not enable the account: %s", error->message); + g_error_free (error); + } + else + { + TpAccountManager *am = tp_account_manager_dup (); + + empathy_connect_new_account (TP_ACCOUNT (account), am); + g_object_unref (am); + } +} + +static void +accounts_dialog_enable_switch_flipped (MxGtkLightSwitch *sw, + gboolean state, + EmpathyAccountsDialog *dialog) +{ + EmpathyAccountSettings *settings; + TpAccount *account; + + settings = accounts_dialog_model_get_selected_settings (dialog); + if (settings == NULL) + return; + + account = empathy_account_settings_get_account (settings); + if (account == NULL) + return; + + tp_account_set_enabled_async (account, state, + accounts_dialog_enable_account_cb, NULL); +} + +static void accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog, TpAccount *account) { @@ -279,6 +324,14 @@ accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog, gtk_image_set_from_icon_name (GTK_IMAGE (priv->image_status), empathy_icon_name_for_presence (presence), GTK_ICON_SIZE_SMALL_TOOLBAR); + /* update the enabled switch */ + g_signal_handlers_block_by_func (priv->enabled_switch, + accounts_dialog_enable_switch_flipped, dialog); + mx_gtk_light_switch_set_active (MX_GTK_LIGHT_SWITCH (priv->enabled_switch), + account_enabled); + g_signal_handlers_unblock_by_func (priv->enabled_switch, + accounts_dialog_enable_switch_flipped, dialog); + if (account_enabled) { switch (status) @@ -2214,6 +2267,16 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog) gtk_box_pack_start (GTK_BOX (hbox), priv->image_status, FALSE, FALSE, 3); gtk_box_pack_start (GTK_BOX (hbox), priv->label_status, TRUE, TRUE, 0); + /* enabled switch */ + align = gtk_alignment_new (0.5, 0.5, 1., 0.); + gtk_box_pack_start (GTK_BOX (content_area), align, FALSE, TRUE, 0); + + priv->enabled_switch = mx_gtk_light_switch_new (); + gtk_container_add (GTK_CONTAINER (align), priv->enabled_switch); + g_signal_connect (priv->enabled_switch, "switch-flipped", + G_CALLBACK (accounts_dialog_enable_switch_flipped), dialog); + gtk_widget_show_all (align); + /* Tweak the dialog */ gtk_window_set_title (GTK_WINDOW (dialog), _("Messaging and VoIP Accounts")); gtk_window_set_role (GTK_WINDOW (dialog), "accounts"); diff --git a/src/empathy-audio-sink.c b/src/empathy-audio-sink.c index 1d2169593..c410d7a30 100644 --- a/src/empathy-audio-sink.c +++ b/src/empathy-audio-sink.c @@ -22,6 +22,7 @@ #include <stdio.h> #include <stdlib.h> +#include <gst/audio/audio.h> #include <gst/farsight/fs-element-added-notifier.h> #include "empathy-audio-sink.h" @@ -38,20 +39,61 @@ enum static guint signals[LAST_SIGNAL] = {0}; #endif +typedef struct { + GstPad *pad; + GstElement *bin; + GstElement *volume; + GstElement *sink; +} AudioBin; + +static AudioBin * +audio_bin_new (GstPad *pad, + GstElement *bin, + GstElement *volume, + GstElement *sink) +{ + AudioBin *result = g_slice_new0 (AudioBin); + + result->pad = pad; + result->bin = bin; + result->volume = gst_object_ref (volume); + result->sink = sink; + + return result; +} + +static void +audio_bin_free (AudioBin *bin) +{ + gst_object_unref (bin->volume); + g_slice_free (AudioBin, bin); +} + + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE( + "sink%d", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS ( GST_AUDIO_INT_PAD_TEMPLATE_CAPS " ; " + GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS) +); enum { PROP_VOLUME = 1, }; -/* private structure */ -typedef struct _EmpathyGstAudioSinkPrivate EmpathyGstAudioSinkPrivate; - struct _EmpathyGstAudioSinkPrivate { gboolean dispose_has_run; - GstElement *sink; - GstElement *volume; FsElementAddedNotifier *notifier; + + gdouble volume; + + /* Pad -> *owned* subbin hash */ + GHashTable *audio_bins; + + /* Mutex to hold while change the hash table */ + GMutex *audio_bins_lock; }; #define EMPATHY_GST_AUDIO_SINK_GET_PRIVATE(o) \ @@ -66,54 +108,72 @@ empathy_audio_sink_element_added_cb (FsElementAddedNotifier *notifier, if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), "volume")) { - gdouble volume; - - volume = empathy_audio_sink_get_volume (self); - empathy_audio_sink_set_volume (self, 1.0); - - if (priv->volume != NULL) - g_object_unref (priv->volume); - priv->volume = g_object_ref (element); - - if (volume != 1.0) - empathy_audio_sink_set_volume (self, volume); + /* An element was added with a volume property, lets find its subbin and + * update the volume in it */ + GHashTableIter iter; + AudioBin *audio_bin = NULL; + gpointer value; + + g_mutex_lock (self->priv->audio_bins_lock); + g_hash_table_iter_init (&iter, priv->audio_bins); + + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + AudioBin *b = value; + + if (gst_object_has_ancestor (GST_OBJECT (element), + GST_OBJECT (b->bin))) + { + audio_bin = b; + break; + } + } + + if (audio_bin == NULL) + { + g_warning ("Element added that doesn't belong to us ?"); + return; + } + + /* Set the old volume to 1 and the new volume to the volume */ + g_object_set (audio_bin->volume, "volume", 1.0, NULL); + gst_object_unref (audio_bin->volume); + + audio_bin->volume = gst_object_ref (element); + g_object_set (audio_bin->volume, "volume", self->priv->volume, NULL); + g_mutex_unlock (self->priv->audio_bins_lock); } } static void -empathy_audio_sink_init (EmpathyGstAudioSink *obj) +empathy_audio_sink_init (EmpathyGstAudioSink *self) { - EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (obj); - GstElement *resample; - GstPad *ghost, *sink; - - priv->notifier = fs_element_added_notifier_new (); - g_signal_connect (priv->notifier, "element-added", - G_CALLBACK (empathy_audio_sink_element_added_cb), obj); - - resample = gst_element_factory_make ("audioresample", NULL); + EmpathyGstAudioSinkPrivate *priv; - priv->volume = gst_element_factory_make ("volume", NULL); - g_object_ref (priv->volume); + priv = self->priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (self); - priv->sink = gst_element_factory_make ("gconfaudiosink", NULL); + priv->volume = 1.0; - fs_element_added_notifier_add (priv->notifier, GST_BIN (priv->sink)); + priv->audio_bins = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) audio_bin_free); - gst_bin_add_many (GST_BIN (obj), resample, priv->volume, priv->sink, NULL); - gst_element_link_many (resample, priv->volume, priv->sink, NULL); + priv->audio_bins_lock = g_mutex_new (); - sink = gst_element_get_static_pad (resample, "sink"); - - ghost = gst_ghost_pad_new ("sink", sink); - gst_element_add_pad (GST_ELEMENT (obj), ghost); - - gst_object_unref (G_OBJECT (sink)); + priv->notifier = fs_element_added_notifier_new (); + g_signal_connect (priv->notifier, "element-added", + G_CALLBACK (empathy_audio_sink_element_added_cb), self); } static void empathy_audio_sink_dispose (GObject *object); static void empathy_audio_sink_finalize (GObject *object); +static GstPad * empathy_audio_sink_request_new_pad (GstElement *self, + GstPadTemplate *templ, + const gchar* name); + +static void empathy_audio_sink_release_pad (GstElement *self, + GstPad *pad); + static void empathy_audio_sink_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) @@ -149,8 +209,13 @@ empathy_audio_sink_class_init (EmpathyGstAudioSinkClass *empathy_audio_sink_class) { GObjectClass *object_class = G_OBJECT_CLASS (empathy_audio_sink_class); + GstElementClass *element_class = + GST_ELEMENT_CLASS (empathy_audio_sink_class); GParamSpec *param_spec; + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + g_type_class_add_private (empathy_audio_sink_class, sizeof (EmpathyGstAudioSinkPrivate)); @@ -160,6 +225,9 @@ empathy_audio_sink_class_init (EmpathyGstAudioSinkClass object_class->set_property = empathy_audio_sink_set_property; object_class->get_property = empathy_audio_sink_get_property; + element_class->request_new_pad = empathy_audio_sink_request_new_pad; + element_class->release_pad = empathy_audio_sink_release_pad; + param_spec = g_param_spec_double ("volume", "Volume", "volume control", 0.0, 5.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); @@ -181,9 +249,13 @@ empathy_audio_sink_dispose (GObject *object) g_object_unref (priv->notifier); priv->notifier = NULL; - if (priv->volume != NULL) - g_object_unref (priv->volume); - priv->volume = NULL; + if (priv->audio_bins != NULL) + g_hash_table_unref (priv->audio_bins); + priv->audio_bins = NULL; + + if (priv->audio_bins_lock != NULL) + g_mutex_free (priv->audio_bins_lock); + priv->audio_bins_lock = NULL; if (G_OBJECT_CLASS (empathy_audio_sink_parent_class)->dispose) G_OBJECT_CLASS (empathy_audio_sink_parent_class)->dispose (object); @@ -219,17 +291,157 @@ void empathy_audio_sink_set_volume (EmpathyGstAudioSink *sink, gdouble volume) { EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (sink); + GHashTableIter iter; + gpointer value; + + priv->volume = volume; + + g_mutex_lock (priv->audio_bins_lock); - g_object_set (G_OBJECT (priv->volume), "volume", volume, NULL); + g_hash_table_iter_init (&iter, priv->audio_bins); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + AudioBin *b = value; + g_object_set (b->volume, "volume", volume, NULL); + } + + g_mutex_unlock (priv->audio_bins_lock); } gdouble empathy_audio_sink_get_volume (EmpathyGstAudioSink *sink) { EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (sink); - gdouble volume; + return priv->volume; +} + +static GstPad * +empathy_audio_sink_request_new_pad (GstElement *element, + GstPadTemplate *templ, + const gchar* name) +{ + EmpathyGstAudioSink *self = EMPATHY_GST_AUDIO_SINK (element); + GstElement *bin, *sink, *volume, *resample, *audioconvert0, *audioconvert1; + GstPad *pad = NULL; + GstPad *subpad, *filterpad; + AudioBin *audiobin; + + bin = gst_bin_new (NULL); + + audioconvert0 = gst_element_factory_make ("audioconvert", NULL); + if (audioconvert0 == NULL) + goto error; + + gst_bin_add (GST_BIN (bin), audioconvert0); + + resample = gst_element_factory_make ("audioresample", NULL); + if (resample == NULL) + goto error; + + gst_bin_add (GST_BIN (bin), resample); + + audioconvert1 = gst_element_factory_make ("audioconvert", NULL); + if (audioconvert1 == NULL) + goto error; + + gst_bin_add (GST_BIN (bin), audioconvert1); + + volume = gst_element_factory_make ("volume", NULL); + if (volume == NULL) + goto error; + + gst_bin_add (GST_BIN (bin), volume); + + sink = gst_element_factory_make ("gconfaudiosink", NULL); + if (sink == NULL) + goto error; + + gst_bin_add (GST_BIN (bin), sink); + fs_element_added_notifier_add (self->priv->notifier, GST_BIN (sink)); + + if (!gst_element_link_many (audioconvert0, resample, audioconvert1, + volume, sink, NULL)) + goto error; + + filterpad = gst_element_get_static_pad (audioconvert0, "sink"); + + if (filterpad == NULL) + goto error; + + subpad = gst_ghost_pad_new ("sink", filterpad); + if (!gst_element_add_pad (GST_ELEMENT (bin), subpad)) + goto error; + + + /* Ensure that state changes only happen _after_ the element has been added + * to the hash table. But add it to the bin first so we can create our + * ghostpad (if we create the ghostpad before adding it to the bin it will + * get unlinked) */ + gst_element_set_locked_state (GST_ELEMENT (bin), TRUE); + gst_bin_add (GST_BIN (self), bin); + + pad = gst_ghost_pad_new (name, subpad); + g_assert (pad != NULL); + + audiobin = audio_bin_new (pad, bin, volume, sink); + + g_mutex_lock (self->priv->audio_bins_lock); + g_hash_table_insert (self->priv->audio_bins, pad, audiobin); + g_mutex_unlock (self->priv->audio_bins_lock); + + gst_element_set_locked_state (GST_ELEMENT (bin), FALSE); + + if (!gst_element_sync_state_with_parent (bin)) + goto error; + + if (!gst_pad_set_active (pad, TRUE)) + goto error; + + if (!gst_element_add_pad (GST_ELEMENT (self), pad)) + goto error; + + + return pad; + +error: + if (pad != NULL) + { + g_mutex_lock (self->priv->audio_bins_lock); + g_hash_table_remove (self->priv->audio_bins, pad); + g_mutex_unlock (self->priv->audio_bins_lock); + + gst_object_unref (pad); + } + + gst_object_unref (bin); + g_warning ("Failed to create output subpipeline"); + return NULL; +} + +static void +empathy_audio_sink_release_pad (GstElement *element, + GstPad *pad) +{ + EmpathyGstAudioSink *self = EMPATHY_GST_AUDIO_SINK (element); + AudioBin *abin; + + g_mutex_lock (self->priv->audio_bins_lock); + abin = g_hash_table_lookup (self->priv->audio_bins, pad); + g_hash_table_steal (self->priv->audio_bins, pad); + g_mutex_unlock (self->priv->audio_bins_lock); + + if (abin == NULL) + { + g_warning ("Releasing a pad that doesn't belong to us ?"); + return; + } + + gst_pad_set_active (pad, FALSE); + gst_element_remove_pad (element, pad); - g_object_get (G_OBJECT (priv->volume), "volume", &volume, NULL); + gst_element_set_locked_state (abin->bin, TRUE); + gst_element_set_state (abin->bin, GST_STATE_NULL); + gst_bin_remove (GST_BIN (self), abin->bin); - return volume; + audio_bin_free (abin); } diff --git a/src/empathy-audio-sink.h b/src/empathy-audio-sink.h index 21ebf2b5a..cc21fc467 100644 --- a/src/empathy-audio-sink.h +++ b/src/empathy-audio-sink.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS typedef struct _EmpathyGstAudioSink EmpathyGstAudioSink; typedef struct _EmpathyGstAudioSinkClass EmpathyGstAudioSinkClass; +typedef struct _EmpathyGstAudioSinkPrivate EmpathyGstAudioSinkPrivate; struct _EmpathyGstAudioSinkClass { GstBinClass parent_class; @@ -35,6 +36,7 @@ struct _EmpathyGstAudioSinkClass { struct _EmpathyGstAudioSink { GstBin parent; + EmpathyGstAudioSinkPrivate *priv; }; GType empathy_audio_sink_get_type (void); diff --git a/src/empathy-call-handler.c b/src/empathy-call-handler.c index eeb13ba82..752405727 100644 --- a/src/empathy-call-handler.c +++ b/src/empathy-call-handler.c @@ -167,6 +167,18 @@ on_get_contacts_cb (TpConnection *connection, } static void +on_call_state_changed_cb (TpyCallChannel *call, + TpyCallState state, + TpyCallFlags flags, + const GValueArray *call_state_reason, + GHashTable *call_state_details, + EmpathyCallHandler *handler) +{ + if (state == TPY_CALL_STATE_ENDED) + tp_channel_close_async (TP_CHANNEL (call), NULL, NULL); +} + +static void on_members_changed_cb (TpyCallChannel *call, GHashTable *members, EmpathyCallHandler *self) @@ -233,7 +245,12 @@ empathy_call_handler_set_property (GObject *object, priv->members = g_value_get_boxed (value); break; case PROP_CALL_CHANNEL: + g_return_if_fail (priv->call == NULL); + priv->call = g_value_dup_object (value); + + tp_g_signal_connect_object (priv->call, "state-changed", + G_CALLBACK (on_call_state_changed_cb), object, 0); break; case PROP_INITIAL_AUDIO: priv->initial_audio = g_value_get_boolean (value); diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index ef6222344..6db01d2ef 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -178,7 +178,6 @@ struct _EmpathyCallWindowPriv GstElement *video_tee; GstElement *funnel; - GstElement *liveadder; GList *notifiers; @@ -623,17 +622,6 @@ create_video_output_widget (EmpathyCallWindow *self) } static void -create_audio_output (EmpathyCallWindow *self) -{ - EmpathyCallWindowPriv *priv = GET_PRIV (self); - - g_assert (priv->audio_output == NULL); - priv->audio_output = empathy_audio_sink_new (); - gst_object_ref (priv->audio_output); - gst_object_sink (priv->audio_output); -} - -static void create_video_input (EmpathyCallWindow *self) { EmpathyCallWindowPriv *priv = GET_PRIV (self); @@ -1115,7 +1103,6 @@ empathy_call_window_init (EmpathyCallWindow *self) create_pipeline (self); create_video_output_widget (self); create_audio_input (self); - create_audio_output (self); create_video_input (self); /* The call will be started as soon the pipeline is playing */ @@ -1657,17 +1644,12 @@ empathy_call_window_dispose (GObject *object) tp_clear_object (&priv->pipeline); tp_clear_object (&priv->video_input); tp_clear_object (&priv->audio_input); - tp_clear_object (&priv->audio_output); tp_clear_object (&priv->video_tee); tp_clear_object (&priv->ui_manager); tp_clear_object (&priv->fullscreen); g_list_free_full (priv->notifiers, g_object_unref); - if (priv->liveadder != NULL) - gst_object_unref (priv->liveadder); - priv->liveadder = NULL; - if (priv->timer_id != 0) g_source_remove (priv->timer_id); priv->timer_id = 0; @@ -1792,7 +1774,6 @@ empathy_call_window_reset_pipeline (EmpathyCallWindow *self) gtk_widget_destroy (priv->video_preview); priv->video_preview = NULL; - priv->liveadder = NULL; priv->funnel = NULL; create_pipeline (self); @@ -1891,7 +1872,8 @@ empathy_call_window_disconnected (EmpathyCallWindow *self, /* destroy the video output; it will be recreated when we'll redial */ disconnect_video_output_motion_handler (self); - gtk_widget_destroy (priv->video_output); + if (priv->video_output != NULL) + gtk_widget_destroy (priv->video_output); priv->video_output = NULL; gtk_widget_show (priv->remote_user_avatar_widget); @@ -1957,14 +1939,12 @@ empathy_call_window_sink_removed_cb (EmpathyCallHandler *handler, } else if (media_type == FS_MEDIA_TYPE_AUDIO) { - if (priv->liveadder != NULL) + if (priv->audio_output != NULL) { gst_element_set_state (priv->audio_output, GST_STATE_NULL); - gst_element_set_state (priv->liveadder, GST_STATE_NULL); gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_output); - gst_bin_remove (GST_BIN (priv->pipeline), priv->liveadder); - priv->liveadder = NULL; + priv->audio_output = NULL; return TRUE; } } @@ -2059,112 +2039,47 @@ empathy_call_window_get_audio_sink_pad (EmpathyCallWindow *self) { EmpathyCallWindowPriv *priv = GET_PRIV (self); GstPad *pad; - GstElement *filter; - GError *gerror = NULL; + GstPadTemplate *template; - if (priv->liveadder == NULL) + if (priv->audio_output == NULL) { - priv->liveadder = gst_element_factory_make ("liveadder", NULL); + priv->audio_output = empathy_audio_sink_new (); - if (!gst_bin_add (GST_BIN (priv->pipeline), priv->liveadder)) - { - g_warning ("Could not add liveadder to the pipeline"); - goto error_add_liveadder; - } if (!gst_bin_add (GST_BIN (priv->pipeline), priv->audio_output)) { g_warning ("Could not add audio sink to pipeline"); + g_object_unref (priv->audio_output); goto error_add_output; } - if (gst_element_set_state (priv->liveadder, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start liveadder"); - goto error; - } - if (gst_element_set_state (priv->audio_output, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { g_warning ("Could not start audio sink"); goto error; } - - if (GST_PAD_LINK_FAILED ( - gst_element_link (priv->liveadder, priv->audio_output))) - { - g_warning ("Could not link liveadder to audio output"); - goto error; - } } - filter = gst_parse_bin_from_description ( - "audioconvert ! audioresample ! audioconvert", TRUE, &gerror); - if (filter == NULL) - { - g_warning ("Could not make audio conversion filter: %s", gerror->message); - g_clear_error (&gerror); - goto error; - } + template = gst_element_class_get_pad_template ( + GST_ELEMENT_GET_CLASS (priv->audio_output), "sink%d"); - if (!gst_bin_add (GST_BIN (priv->pipeline), filter)) - { - g_warning ("Could not add audio conversion filter to pipeline"); - gst_object_unref (filter); - goto error; - } - - if (gst_element_set_state (filter, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start audio conversion filter"); - goto error_filter; - } - - if (!gst_element_link (filter, priv->liveadder)) - { - g_warning ("Could not link audio conversion filter to liveadder"); - goto error_filter; - } - - pad = gst_element_get_static_pad (filter, "sink"); + pad = gst_element_request_pad (priv->audio_output, + template, NULL, NULL); if (pad == NULL) { - g_warning ("Could not get sink pad from filter"); - goto error_filter; + g_warning ("Could not get sink pad from sink"); + return NULL; } return pad; - error_filter: - - gst_element_set_locked_state (filter, TRUE); - gst_element_set_state (filter, GST_STATE_NULL); - gst_bin_remove (GST_BIN (priv->pipeline), filter); - - error: - - gst_element_set_locked_state (priv->liveadder, TRUE); +error: gst_element_set_locked_state (priv->audio_output, TRUE); - - gst_element_set_state (priv->liveadder, GST_STATE_NULL); gst_element_set_state (priv->audio_output, GST_STATE_NULL); - gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_output); + priv->audio_output = NULL; - error_add_output: - - gst_bin_remove (GST_BIN (priv->pipeline), priv->liveadder); - - gst_element_set_locked_state (priv->liveadder, FALSE); - gst_element_set_locked_state (priv->audio_output, FALSE); - - error_add_liveadder: - - if (priv->liveadder != NULL) - { - gst_object_unref (priv->liveadder); - priv->liveadder = NULL; - } +error_add_output: return NULL; } diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c index 5b4434522..61ebcf56a 100644 --- a/src/empathy-event-manager.c +++ b/src/empathy-event-manager.c @@ -662,6 +662,21 @@ cdo_invalidated_cb (TpProxy *cdo, } static void +event_manager_call_state_changed_cb (TpyCallChannel *call, + TpyCallState state, + TpyCallFlags flags, + const GValueArray *call_state_reason, + GHashTable *call_state_details, + EventManagerApproval *approval) +{ + if (state == TPY_CALL_STATE_ENDED) + { + DEBUG ("Call ended, seems we missed it :/"); + reject_approval (approval); + } +} + +static void event_manager_call_channel_got_contact_cb (TpConnection *connection, EmpathyContact *contact, const GError *error, @@ -675,6 +690,8 @@ event_manager_call_channel_got_contact_cb (TpConnection *connection, gchar *header; gboolean video; + call = TPY_CALL_CHANNEL (approval->handler_instance); + if (error != NULL) { DEBUG ("Can't get the contact for the call.. Rejecting?"); @@ -682,11 +699,19 @@ event_manager_call_channel_got_contact_cb (TpConnection *connection, return; } + if (tpy_call_channel_get_state (call, NULL, NULL) == TPY_CALL_STATE_ENDED) + { + DEBUG ("Call already ended, seems we missed it :/"); + reject_approval (approval); + return; + } + + approval->handler = g_signal_connect (call, "state-changed", + G_CALLBACK (event_manager_call_state_changed_cb), approval); + window = empathy_main_window_dup (); approval->contact = g_object_ref (contact); - call = TPY_CALL_CHANNEL (approval->handler_instance); - g_object_get (G_OBJECT (call), "initial-video", &video, NULL); header = g_strdup_printf ( diff --git a/src/empathy-streamed-media-window.c b/src/empathy-streamed-media-window.c index e203bdc5f..1566da40a 100644 --- a/src/empathy-streamed-media-window.c +++ b/src/empathy-streamed-media-window.c @@ -189,7 +189,6 @@ struct _EmpathyStreamedMediaWindowPriv GstElement *video_tee; GstElement *funnel; - GstElement *liveadder; FsElementAddedNotifier *fsnotifier; @@ -639,17 +638,6 @@ create_video_output_widget (EmpathyStreamedMediaWindow *self) } static void -create_audio_output (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - g_assert (priv->audio_output == NULL); - priv->audio_output = empathy_audio_sink_new (); - gst_object_ref (priv->audio_output); - gst_object_sink (priv->audio_output); -} - -static void create_video_input (EmpathyStreamedMediaWindow *self) { EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); @@ -1131,7 +1119,6 @@ empathy_streamed_media_window_init (EmpathyStreamedMediaWindow *self) create_pipeline (self); create_video_output_widget (self); create_audio_input (self); - create_audio_output (self); create_video_input (self); priv->fsnotifier = fs_element_added_notifier_new (); @@ -1725,18 +1712,10 @@ empathy_streamed_media_window_dispose (GObject *object) g_object_unref (priv->audio_input); priv->audio_input = NULL; - if (priv->audio_output != NULL) - g_object_unref (priv->audio_output); - priv->audio_output = NULL; - if (priv->video_tee != NULL) g_object_unref (priv->video_tee); priv->video_tee = NULL; - if (priv->liveadder != NULL) - gst_object_unref (priv->liveadder); - priv->liveadder = NULL; - if (priv->fsnotifier != NULL) g_object_unref (priv->fsnotifier); priv->fsnotifier = NULL; @@ -1867,7 +1846,6 @@ empathy_streamed_media_window_reset_pipeline (EmpathyStreamedMediaWindow *self) gtk_widget_destroy (priv->video_preview); priv->video_preview = NULL; - priv->liveadder = NULL; priv->funnel = NULL; create_pipeline (self); @@ -2031,14 +2009,12 @@ empathy_streamed_media_window_channel_stream_closed_cb (EmpathyStreamedMediaHand } else if (media_type == TP_MEDIA_STREAM_TYPE_AUDIO) { - if (priv->liveadder != NULL) + if (priv->audio_output != NULL) { gst_element_set_state (priv->audio_output, GST_STATE_NULL); - gst_element_set_state (priv->liveadder, GST_STATE_NULL); gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_output); - gst_bin_remove (GST_BIN (priv->pipeline), priv->liveadder); - priv->liveadder = NULL; + priv->audio_output = NULL; } } } @@ -2130,112 +2106,47 @@ empathy_streamed_media_window_get_audio_sink_pad (EmpathyStreamedMediaWindow *se { EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); GstPad *pad; - GstElement *filter; - GError *gerror = NULL; + GstPadTemplate *template; - if (priv->liveadder == NULL) + if (priv->audio_output == NULL) { - priv->liveadder = gst_element_factory_make ("liveadder", NULL); + priv->audio_output = empathy_audio_sink_new (); - if (!gst_bin_add (GST_BIN (priv->pipeline), priv->liveadder)) - { - g_warning ("Could not add liveadder to the pipeline"); - goto error_add_liveadder; - } if (!gst_bin_add (GST_BIN (priv->pipeline), priv->audio_output)) { g_warning ("Could not add audio sink to pipeline"); + g_object_unref (priv->audio_output); goto error_add_output; } - if (gst_element_set_state (priv->liveadder, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start liveadder"); - goto error; - } - if (gst_element_set_state (priv->audio_output, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { g_warning ("Could not start audio sink"); goto error; } - - if (GST_PAD_LINK_FAILED ( - gst_element_link (priv->liveadder, priv->audio_output))) - { - g_warning ("Could not link liveadder to audio output"); - goto error; - } - } - - filter = gst_parse_bin_from_description ( - "audioconvert ! audioresample ! audioconvert", TRUE, &gerror); - if (filter == NULL) - { - g_warning ("Could not make audio conversion filter: %s", gerror->message); - g_clear_error (&gerror); - goto error; } - if (!gst_bin_add (GST_BIN (priv->pipeline), filter)) - { - g_warning ("Could not add audio conversion filter to pipeline"); - gst_object_unref (filter); - goto error; - } + template = gst_element_class_get_pad_template ( + GST_ELEMENT_GET_CLASS (priv->audio_output), "sink%d"); - if (gst_element_set_state (filter, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start audio conversion filter"); - goto error_filter; - } - - if (!gst_element_link (filter, priv->liveadder)) - { - g_warning ("Could not link audio conversion filter to liveadder"); - goto error_filter; - } - - pad = gst_element_get_static_pad (filter, "sink"); + pad = gst_element_request_pad (priv->audio_output, + template, NULL, NULL); if (pad == NULL) { - g_warning ("Could not get sink pad from filter"); - goto error_filter; + g_warning ("Could not get sink pad from sink"); + return NULL; } return pad; - error_filter: - - gst_element_set_locked_state (filter, TRUE); - gst_element_set_state (filter, GST_STATE_NULL); - gst_bin_remove (GST_BIN (priv->pipeline), filter); - - error: - - gst_element_set_locked_state (priv->liveadder, TRUE); +error: gst_element_set_locked_state (priv->audio_output, TRUE); - - gst_element_set_state (priv->liveadder, GST_STATE_NULL); gst_element_set_state (priv->audio_output, GST_STATE_NULL); - gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_output); + priv->audio_output = NULL; - error_add_output: - - gst_bin_remove (GST_BIN (priv->pipeline), priv->liveadder); - - gst_element_set_locked_state (priv->liveadder, FALSE); - gst_element_set_locked_state (priv->audio_output, FALSE); - - error_add_liveadder: - - if (priv->liveadder != NULL) - { - gst_object_unref (priv->liveadder); - priv->liveadder = NULL; - } +error_add_output: return NULL; } |