aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>2011-03-15 00:23:03 +0800
committerEmilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>2011-03-15 00:23:03 +0800
commitc6b85f107a481541d8cd8622d54edee506a637f2 (patch)
tree06251c14a637c325b866a19a732d7d4271b112e9
parent572751ddc752f35b95bdf9bd587569cac19cd80d (diff)
parentacb39f9316c77ace16b473d258f4024d7a5e43ce (diff)
downloadgsoc2013-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.ac3
-rw-r--r--libempathy-gtk/Makefile.am7
-rw-r--r--libempathy-gtk/empathy-account-widget.c4
-rw-r--r--libempathy-gtk/empathy-individual-view.c15
-rw-r--r--libempathy-gtk/mx-gtk-light-switch.c536
-rw-r--r--libempathy-gtk/mx-gtk-light-switch.h71
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/empathy-accounts-dialog.c63
-rw-r--r--src/empathy-audio-sink.c302
-rw-r--r--src/empathy-audio-sink.h2
-rw-r--r--src/empathy-call-handler.c17
-rw-r--r--src/empathy-call-window.c119
-rw-r--r--src/empathy-event-manager.c29
-rw-r--r--src/empathy-streamed-media-window.c119
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;
}