aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/indicator-sound.c47
-rw-r--r--src/volume-widget.c271
-rw-r--r--src/volume-widget.h53
4 files changed, 370 insertions, 3 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ed3e394..ce7a580 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,8 @@ libsoundmenu_la_SOURCES = \
title-widget.h \
scrub-widget.c \
scrub-widget.h \
+ volume-widget.c \
+ volume-widget.h \
dbus-shared-names.h \
sound-service-client.h
diff --git a/src/indicator-sound.c b/src/indicator-sound.c
index 1c6041b..fee87c8 100644
--- a/src/indicator-sound.c
+++ b/src/indicator-sound.c
@@ -42,6 +42,8 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "metadata-widget.h"
#include "title-widget.h"
#include "scrub-widget.h"
+#include "volume-widget.h"
+
#include "dbus-shared-names.h"
#include "sound-service-client.h"
#include "common-defs.h"
@@ -89,6 +91,7 @@ static void scroll (IndicatorObject*io, gint delta, IndicatorScrollDirec
//Slider related
static GtkWidget *volume_slider = NULL;
static gboolean new_slider_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+static gboolean new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
static gboolean value_changed_event_cb(GtkRange *range, gpointer user_data);
static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data);
static void slider_grabbed(GtkWidget *widget, gpointer user_data);
@@ -251,7 +254,7 @@ get_menu (IndicatorObject * io)
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SCRUB_MENUITEM_TYPE, new_scrub_bar_widget);
// register Key-press listening on the menu widget as the slider does not allow this.
- g_signal_connect(menu, "key-press-event", G_CALLBACK(key_press_cb), NULL);
+ g_signal_connect(menu, "key-press-event", G_CALLBACK(key_press_cb), io);
return GTK_MENU(menu);
}
@@ -398,6 +401,40 @@ new_scrub_bar_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbus
return TRUE;
}
+static gboolean
+new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
+{
+ g_debug("indicator-sound: new_volume_slider_widget");
+
+ GtkWidget* volume_widget = NULL;
+ IndicatorObject *io = NULL;
+
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+
+ volume_widget = volume_widget_new (newitem);
+ GtkWidget* ido_slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(volume_widget));
+
+
+ io = g_object_get_data (G_OBJECT (client), "indicator");
+ // we still need to hold to a reference to the actual slider to
+ // react to menu wide key events
+ // not ideal: to be revisited post beta
+ INDICATOR_SOUND (io)->slider = ido_slider_widget;
+
+ gtk_widget_show_all(ido_slider_widget);
+ gtk_widget_set_sensitive(ido_slider_widget,
+ !initial_mute);
+
+ GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget);
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client),
+ newitem,
+ menu_volume_item,
+ parent);
+
+ return TRUE;
+}
+
static void
connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer userdata)
@@ -564,7 +601,7 @@ start_animation()
{
blocked_iter = blocked_animation_list;
blocked_id = 0;
- g_debug("exit from blocked hold start the animation\n");
+ //g_debug("exit from blocked hold start the animation\n");
animation_id = g_timeout_add(50, fade_back_to_mute_image, NULL);
return FALSE;
}
@@ -777,7 +814,11 @@ key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
{
gboolean digested = FALSE;
- GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);
+ g_return_val_if_fail(IS_INDICATOR_SOUND(data));
+
+ IndicatorSound *sound = INDICATOR_SOUND (data);
+
+ GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)sound->slider);
GtkRange* range = (GtkRange*)slider;
gdouble current_value = gtk_range_get_value(range);
gdouble new_value = current_value;
diff --git a/src/volume-widget.c b/src/volume-widget.c
new file mode 100644
index 0000000..8b54a32
--- /dev/null
+++ b/src/volume-widget.c
@@ -0,0 +1,271 @@
+/*
+Copyright 2010 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+#include "volume-widget.h"
+#include "common-defs.h"
+#include <libido/idoscalemenuitem.h>
+
+typedef struct _VolumeWidgetPrivate VolumeWidgetPrivate;
+
+struct _VolumeWidgetPrivate
+{
+ DbusmenuMenuitem* twin_item;
+ GtkWidget* ido_volume_slider;
+ gboolean grabbed;
+};
+
+#define VOLUME_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VOLUME_WIDGET_TYPE, VolumeWidgetPrivate))
+
+/* Prototypes */
+static void volume_widget_class_init (VolumeWidgetClass *klass);
+static void volume_widget_init (VolumeWidget *self);
+static void volume_widget_dispose (GObject *object);
+static void volume_widget_finalize (GObject *object);
+static void volume_widget_set_twin_item( VolumeWidget* self,
+ DbusmenuMenuitem* twin_item);
+static void volume_widget_set_ido_position(VolumeWidget* self,
+ gint position,
+ gint duration);
+//callbacks
+static void volume_widget_property_update( DbusmenuMenuitem* item, gchar* property,
+ GValue* value, gpointer userdata);
+static gboolean volume_widget_change_value_cb (GtkRange *range,
+ GtkScrollType scroll,
+ gdouble value,
+ gpointer user_data);
+static void volume_widget_slider_grabbed(GtkWidget *widget, gpointer user_data);
+static void volume_widget_slider_released(GtkWidget *widget, gpointer user_data);
+static void volume_widget_parent_changed (GtkWidget *widget, gpointer user_data);
+
+G_DEFINE_TYPE (VolumeWidget, volume_widget, G_TYPE_OBJECT);
+
+static void
+volume_widget_class_init (VolumeWidgetClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (VolumeWidgetPrivate));
+
+ gobject_class->dispose = volume_widget_dispose;
+ gobject_class->finalize = volume_widget_finalize;
+}
+
+static void
+volume_widget_init (VolumeWidget *self)
+{
+ g_debug("VolumeWidget::volume_widget_init");
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self);
+
+ priv->ido_volume_slider = ido_scale_menu_item_new_with_range ("VOLUME", IDO_RANGE_STYLE_DEFAULT, 0, 0, 100, 1);
+
+ ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (priv->ido_volume_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE);
+ g_object_set(priv->ido_volume_slider, "reverse-scroll-events", TRUE, NULL);
+
+ g_signal_connect (volume_slider,
+ "notify::parent", G_CALLBACK (slider_parent_changed),
+ NULL);
+
+ GtkWidget* volume_widget = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
+
+ // register slider changes listening on the range
+ g_signal_connect(volume_widget, "change-value", G_CALLBACK(volume_widget_change_value_cb), self);
+ g_signal_connect(volume_widget, "value-changed", G_CALLBACK(volume_widget_value_changed_cb), self);
+ g_signal_connect(priv->ido_volume_slider, "slider-grabbed", G_CALLBACK(volume_widget_slider_grabbed), self);
+ g_signal_connect(priv->ido_volume_slider, "slider-released", G_CALLBACK(volume_widget_slider_released), self);
+
+ // Set images on the ido
+ GtkWidget* primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)priv->ido_volume_slider);
+ GIcon * primary_gicon = g_themed_icon_new_with_default_fallbacks("audio-volume-low-zero-panel");
+ gtk_image_set_from_gicon(GTK_IMAGE(primary_image), primary_gicon, GTK_ICON_SIZE_MENU);
+ g_object_unref(primary_gicon);
+
+ GtkWidget* secondary_image = ido_scale_menu_item_get_secondary_image((IdoScaleMenuItem*)priv->ido_volume_slider);
+ GIcon * secondary_gicon = g_themed_icon_new_with_default_fallbacks("audio-volume-high-panel");
+ gtk_image_set_from_gicon(GTK_IMAGE(secondary_image), secondary_gicon, GTK_ICON_SIZE_MENU);
+ g_object_unref(secondary_gicon);
+
+ GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (volume_widget));
+ gtk_adjustment_set_step_increment(adj, 3);
+
+ gtk_widget_show_all(volume_widget);
+}
+
+static void
+volume_widget_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (volume_widget_parent_class)->dispose (object);
+}
+
+static void
+volume_widget_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (volume_widget_parent_class)->finalize (object);
+}
+
+static void
+volume_widget_property_update(DbusmenuMenuitem* item, gchar* property,
+ GValue* value, gpointer userdata)
+{
+ g_debug("scrub-widget::property_update");
+
+ g_return_if_fail (IS_VOLUME_WIDGET (userdata));
+ VolumeWidget* mitem = VOLUME_WIDGET(userdata);
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem);
+
+}
+
+static void
+volume_widget_set_twin_item(VolumeWidget* self,
+ DbusmenuMenuitem* twin_item)
+{
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self);
+ priv->twin_item = twin_item;
+
+ g_signal_connect(G_OBJECT(twin_item), "property-changed",
+ G_CALLBACK(volume_widget_property_update), self);
+
+ /*volume_widget_set_ido_position(self,
+ dbusmenu_menuitem_property_get_int(priv->twin_item, DBUSMENU_SCRUB_MENUITEM_POSITION)/1000,
+ dbusmenu_menuitem_property_get_int(priv->twin_item, DBUSMENU_SCRUB_MENUITEM_DURATION));
+ */
+}
+
+static gboolean
+volume_widget_change_value_cb (GtkRange *range,
+ GtkScrollType scroll,
+ gdouble new_value,
+ gpointer user_data)
+{
+ g_return_val_if_fail (IS_VOLUME_WIDGET (user_data), FALSE);
+ VolumeWidget* mitem = VOLUME_WIDGET(user_data);
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem);
+
+ // Don't bother when the slider is grabbed
+ if(priv->grabbed == TRUE)
+ return FALSE;
+
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_DOUBLE);
+ gdouble clamped = CLAMP(new_value, 0, 100);
+ g_value_set_double(&value, clamped);
+ dbusmenu_menuitem_handle_event (priv->twin_item, "grabbed", &value, 0);
+ return TRUE;
+}
+
+static gboolean
+volume_widget_value_changed(GtkRange *range, gpointer user_data)
+{
+ g_return_val_if_fail (IS_VOLUME_WIDGET (user_data), FALSE);
+ VolumeWidget* mitem = VOLUME_WIDGET(user_data);
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem);
+
+ gdouble current_value = CLAMP(gtk_range_get_value(GTK_RANGE(priv->ido_volume_slider), 0, 100);
+
+ // Replace with dbus properties inspection
+ /*if (current_value == exterior_vol_update) {
+ g_debug("ignore the value changed event - its come from the outside");
+ return FALSE;
+ }*/
+
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_DOUBLE);
+ g_value_set_double(&value, current_value);
+ g_debug("volume_widget_value changed callback - = %f", current_value);
+ dbusmenu_menuitem_handle_event (priv->twin_item, "slider_change", &value, 0);
+ // This is not ideal in that the icon ui will update on ui actions and not on actual service feedback.
+ // but necessary for now as the server does not send volume update information if the source of change was this ui.
+ determine_state_from_volume(current_value);
+ return FALSE;
+}
+
+
+GtkWidget*
+volume_widget_get_ido_bar(VolumeWidget* self)
+{
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self);
+ return priv->ido_volume_slider;
+}
+
+static void
+volume_widget_parent_changed (GtkWidget *widget,
+ gpointer user_data)
+{
+ gtk_widget_set_size_request (widget, 200, -1);
+ g_debug("volume_widget_parent_changed");
+}
+
+
+static void
+volume_widget_set_ido_position(VolumeWidget* self,
+ gint position,
+ gint duration)
+{
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self);
+ gdouble ido_position = position/(gdouble)duration * 100.0;
+ g_debug("volume_widget_set_ido_position - pos: %i, duration: %i, ido_pos: %f", position, duration, ido_position);
+ GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
+ GtkRange *range = (GtkRange*)slider;
+ if(duration == 0)
+ ido_position = 0.0;
+ gtk_range_set_value(range, ido_position);
+}
+
+static void
+volume_widget_slider_grabbed(GtkWidget *widget, gpointer user_data)
+{
+ VolumeWidget* mitem = VOLUME_WIDGET(user_data);
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem);
+ priv->grabbed = TRUE;
+}
+
+static void
+volume_widget_slider_released(GtkWidget *widget, gpointer user_data)
+{
+ VolumeWidget* mitem = VOLUME_WIDGET(user_data);
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem);
+ priv->grabbed = FALSE;
+ GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
+ gdouble new_value = gtk_range_get_value(GTK_RANGE(slider));
+ g_debug("okay set the scrub position with %f", new_value);
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_DOUBLE);
+ gdouble clamped = CLAMP(new_value, 0, 100);
+ g_value_set_double(&value, clamped);
+ dbusmenu_menuitem_handle_event (priv->twin_item, "volume-change", &value, 0);
+}
+
+
+/**
+ * volume_widget_new:
+ * @returns: a new #VolumeWidget.
+ **/
+GtkWidget*
+volume_widget_new(DbusmenuMenuitem *item)
+{
+ GtkWidget* widget = g_object_new(VOLUME_WIDGET_TYPE, NULL);
+ volume_widget_set_twin_item((VolumeWidget*)widget, item);
+ return widget;
+}
+
+
diff --git a/src/volume-widget.h b/src/volume-widget.h
new file mode 100644
index 0000000..8e3e895
--- /dev/null
+++ b/src/volume-widget.h
@@ -0,0 +1,53 @@
+/*
+Copyright 2010 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef __VOLUME_WIDGET_H__
+#define __VOLUME_WIDGET_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libdbusmenu-gtk/menu.h>
+
+G_BEGIN_DECLS
+
+#define VOLUME_WIDGET_TYPE (volume_widget_get_type ())
+#define VOLUME_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VOLUME_WIDGET_TYPE, VolumeWidget))
+#define VOLUME_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VOLUME_WIDGET_TYPE, VolumeWidgetClass))
+#define IS_VOLUME_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VOLUME_WIDGET_TYPE))
+#define IS_VOLUME_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VOLUME_WIDGET_TYPE))
+#define VOLUME_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VOLUME_WIDGET_TYPE, VolumeWidgetClass))
+
+typedef struct _VolumeWidget VolumeWidget;
+typedef struct _VolumeWidgetClass VolumeWidgetClass;
+
+struct _VolumeWidgetClass {
+ GObjectClass parent_class;
+};
+
+struct _VolumeWidget {
+ GObject parent;
+};
+
+GType volume_widget_get_type (void) G_GNUC_CONST;
+GtkWidget* volume_widget_new(DbusmenuMenuitem* twin_item);
+GtkWidget* volume_widget_get_ido_bar(VolumeWidget* self);
+
+G_END_DECLS
+
+#endif
+