ayatana-commits team mailing list archive
-
ayatana-commits team
-
Mailing list archive
-
Message #02012
[Merge] lp:~cjcurran/indicator-sound/volume-slider-refactor into lp:indicator-sound
Conor Curran has proposed merging lp:~cjcurran/indicator-sound/volume-slider-refactor into lp:indicator-sound.
Requested reviews:
Ted Gould (ted)
Refactors the volume slider out of the indicator-sound.c and into its own file volume-widget.c/h.
Forces the volume widget to use dbusmenuitem properties which as a result brings inline the direction of communication between the indicator and the service. The slider updates the service and the service updates the slider only through property updates. The dbus volume method and signal are no longer needed and therefore have been removed.
Other little cleanups have been carried out. This large refactor was necessary inorder to standardise how communication between the indicator and service is operated. Also makes the indicator-sound.c and far more maintainable c file going forward.
--
https://code.launchpad.net/~cjcurran/indicator-sound/volume-slider-refactor/+merge/31739
Your team ayatana-commits is subscribed to branch lp:indicator-sound.
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2010-07-13 12:52:04 +0000
+++ src/Makefile.am 2010-08-04 11:38:45 +0000
@@ -20,6 +20,8 @@
title-widget.h \
scrub-widget.c \
scrub-widget.h \
+ volume-widget.c \
+ volume-widget.h \
dbus-shared-names.h \
sound-service-client.h
=== modified file 'src/common-defs.h'
--- src/common-defs.h 2010-07-27 11:39:51 +0000
+++ src/common-defs.h 2010-08-04 11:38:45 +0000
@@ -27,7 +27,8 @@
#define DBUSMENU_PROPERTY_EMPTY -1
/* DBUS Custom Items */
-#define DBUSMENU_SLIDER_MENUITEM_TYPE "x-canonical-ido-slider-type"
+#define DBUSMENU_VOLUME_MENUITEM_TYPE "x-canonical-ido-volume-type"
+#define DBUSMENU_VOLUME_MENUITEM_LEVEL "x-canonical-ido-volume-level"
#define DBUSMENU_TRANSPORT_MENUITEM_TYPE "x-canonical-sound-menu-player-transport-type"
#define DBUSMENU_TRANSPORT_MENUITEM_PLAY_STATE "x-canonical-sound-menu-player-transport-state"
=== modified file 'src/dbus-menu-manager.c'
--- src/dbus-menu-manager.c 2010-07-07 10:51:47 +0000
+++ src/dbus-menu-manager.c 2010-08-04 11:38:45 +0000
@@ -31,6 +31,7 @@
#include "sound-service-dbus.h"
#include "pulse-manager.h"
#include "slider-menu-item.h"
+#include "common-defs.h"
#include "dbus-shared-names.h"
@@ -74,13 +75,15 @@
return root_menuitem;
}
-/**
-teardown:
-**/
-void dbus_menu_manager_teardown()
+
+void dbus_menu_manager_update_volume(gdouble volume)
{
- //TODO tidy up dbus_interface and items!
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_DOUBLE);
+ g_value_set_double(&value, volume);
+ dbusmenu_menuitem_property_set_value(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_VOLUME_MENUITEM_LEVEL, &value);
}
+
/**
update_pa_state:
@@ -102,7 +105,7 @@
// Emit the signals after the menus are setup/torn down
// preserve ordering !
sound_service_dbus_update_sink_availability(dbus_interface, sink_available);
- sound_service_dbus_update_sink_volume(dbus_interface, percent);
+ dbus_menu_manager_update_volume(percent);
sound_service_dbus_update_sink_mute(dbus_interface, sink_muted);
dbus_menu_manager_update_mute_ui(b_all_muted);
}
@@ -123,7 +126,6 @@
/*-------------------------------------------------------------------------*/
// Private Methods
/*-------------------------------------------------------------------------*/
-
static void refresh_menu()
{
g_debug("in the refresh menu method");
=== modified file 'src/dbus-menu-manager.h'
--- src/dbus-menu-manager.h 2010-06-18 09:02:20 +0000
+++ src/dbus-menu-manager.h 2010-08-04 11:38:45 +0000
@@ -25,6 +25,7 @@
DbusmenuMenuitem* dbus_menu_manager_setup();
void dbus_menu_manager_teardown();
+void dbus_menu_manager_update_volume(gdouble volume);
void dbus_menu_manager_update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_muted, gdouble current_vol);
// TODO update pa_state should incorporate the method below !
void dbus_menu_manager_update_mute_ui(gboolean incoming_mute_value);
=== modified file 'src/indicator-sound.c'
--- src/indicator-sound.c 2010-07-15 16:08:36 +0000
+++ src/indicator-sound.c 2010-08-04 11:38:45 +0000
@@ -42,34 +42,22 @@
#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"
-// GObject Boiler plate
-#define INDICATOR_SOUND_TYPE (indicator_sound_get_type ())
-#define INDICATOR_SOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SOUND_TYPE, IndicatorSound))
-#define INDICATOR_SOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SOUND_TYPE, IndicatorSoundClass))
-#define IS_INDICATOR_SOUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SOUND_TYPE))
-#define IS_INDICATOR_SOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SOUND_TYPE))
-#define INDICATOR_SOUND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SOUND_TYPE, IndicatorSoundClass))
-
-typedef struct _IndicatorSound IndicatorSound;
-typedef struct _IndicatorSoundClass IndicatorSoundClass;
-
-//GObject class struct
-struct _IndicatorSoundClass {
- IndicatorObjectClass parent_class;
-};
-
-//GObject instance struct
-struct _IndicatorSound {
- IndicatorObject parent;
- GtkWidget *slider;
- IndicatorServiceManager *service;
-};
-// GObject Boiler plate
-GType indicator_sound_get_type (void);
+typedef struct _IndicatorSoundPrivate IndicatorSoundPrivate;
+
+struct _IndicatorSoundPrivate
+{
+ GtkWidget* volume_widget;
+};
+
+#define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate))
+
+// GObject Boiler plate
INDICATOR_SET_VERSION
INDICATOR_SET_TYPE(INDICATOR_SOUND_TYPE)
@@ -84,15 +72,10 @@
static GtkLabel * get_label (IndicatorObject * io);
static GtkImage * get_icon (IndicatorObject * io);
static GtkMenu * get_menu (IndicatorObject * io);
-static void scroll (IndicatorObject*io, gint delta, IndicatorScrollDirection direction);
//Slider related
-static GtkWidget *volume_slider = NULL;
-static gboolean new_slider_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
-static gboolean value_changed_event_cb(GtkRange *range, gpointer user_data);
+static gboolean new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data);
-static void slider_grabbed(GtkWidget *widget, gpointer user_data);
-static void slider_released(GtkWidget *widget, gpointer user_data);
static void style_changed_cb(GtkWidget *widget, gpointer user_data);
//player widget realisation methods
@@ -105,12 +88,10 @@
static DBusGProxy *sound_dbus_proxy = NULL;
static void connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer userdata);
static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean value, gpointer userdata);
-static void catch_signal_sink_volume_update(DBusGProxy * proxy, gdouble volume_percent, gpointer userdata);
static void catch_signal_sink_mute_update(DBusGProxy *proxy, gboolean mute_value, gpointer userdata);
static void catch_signal_sink_availability_update(DBusGProxy *proxy, gboolean available_value, gpointer userdata);
-static void fetch_volume_percent_from_dbus();
static void fetch_mute_value_from_dbus();
-static void fetch_sink_availability_from_dbus();
+static void fetch_sink_availability_from_dbus(IndicatorSound* self);
/****Volume States 'members' ***/
static void update_state(const gint state);
@@ -122,18 +103,14 @@
static const gint STATE_HIGH = 4;
static const gint STATE_MUTED_WHILE_INPUT = 5;
static const gint STATE_SINKS_NONE = 6;
-static const gint OUT_OF_RANGE = -10;
static GHashTable *volume_states = NULL;
static GtkImage *speaker_image = NULL;
static gint current_state = 0;
static gint previous_state = 0;
-static gdouble initial_volume_percent;
static gboolean initial_mute ;
static gboolean device_available;
-static gboolean slider_in_direct_use;
-static gdouble exterior_vol_update;
static GtkIconSize design_team_size;
static gint blocked_id;
@@ -157,10 +134,12 @@
object_class->finalize = indicator_sound_finalize;
IndicatorObjectClass *io_class = INDICATOR_OBJECT_CLASS(klass);
+
+ g_type_class_add_private (klass, sizeof (IndicatorSoundPrivate));
+
io_class->get_label = get_label;
io_class->get_image = get_icon;
io_class->get_menu = get_menu;
- io_class->scroll = scroll;
design_team_size = gtk_icon_size_register("design-team-size", 22, 22);
@@ -178,10 +157,11 @@
blocked_id = 0;
initial_mute = FALSE;
device_available = TRUE;
- slider_in_direct_use = FALSE;
- exterior_vol_update = OUT_OF_RANGE;
+
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+ priv->volume_widget = NULL;
- g_signal_connect(G_OBJECT(self->service), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connection_changed), self);
+ g_signal_connect(G_OBJECT(self->service), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connection_changed), self);
return;
}
@@ -202,15 +182,6 @@
return;
}
-static void
-free_the_animation_list()
-{
- if (blocked_animation_list != NULL) {
- g_list_foreach (blocked_animation_list, (GFunc)g_object_unref, NULL);
- g_list_free(blocked_animation_list);
- blocked_animation_list = NULL;
- }
-}
static void
indicator_sound_finalize (GObject *object)
@@ -244,81 +215,35 @@
DbusmenuGtkMenu *menu = dbusmenu_gtkmenu_new(INDICATOR_SOUND_DBUS_NAME, INDICATOR_SOUND_DBUS_OBJECT);
DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu);
g_object_set_data (G_OBJECT (client), "indicator", io);
- dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SLIDER_MENUITEM_TYPE, new_slider_item);
+ dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_VOLUME_MENUITEM_TYPE, new_volume_slider_widget);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_TRANSPORT_MENUITEM_TYPE, new_transport_widget);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_METADATA_MENUITEM_TYPE, new_metadata_widget);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_TITLE_MENUITEM_TYPE, new_title_widget);
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);
}
static void
+free_the_animation_list()
+{
+ if (blocked_animation_list != NULL) {
+ g_list_foreach (blocked_animation_list, (GFunc)g_object_unref, NULL);
+ g_list_free(blocked_animation_list);
+ blocked_animation_list = NULL;
+ }
+}
+
+/*static void
slider_parent_changed (GtkWidget *widget,
gpointer user_data)
{
gtk_widget_set_size_request (widget, 200, -1);
g_debug("slider parent changed");
-}
-
-/**
-new_slider_item:
-Create a new dBusMenu Slider item.
-**/
-static gboolean
-new_slider_item(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
-{
- IndicatorObject *io = NULL;
-
- g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
- g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
-
- io = g_object_get_data (G_OBJECT (client), "indicator");
-
- volume_slider = ido_scale_menu_item_new_with_range ("Volume", IDO_RANGE_STYLE_DEFAULT, initial_volume_percent, 0, 100, 1);
- ido_scale_menu_item_set_style (IDO_SCALE_MENU_ITEM (volume_slider), IDO_SCALE_MENU_ITEM_STYLE_IMAGE);
- g_object_set(volume_slider, "reverse-scroll-events", TRUE, NULL);
-
- g_signal_connect (volume_slider,
- "notify::parent", G_CALLBACK (slider_parent_changed),
- NULL);
-
- GtkMenuItem *menu_volume_slider = GTK_MENU_ITEM(volume_slider);
-
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_volume_slider, parent);
-
- // register slider changes listening on the range
- GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);
-
- INDICATOR_SOUND (io)->slider = slider;
-
- g_signal_connect(slider, "value-changed", G_CALLBACK(value_changed_event_cb), newitem);
- g_signal_connect(volume_slider, "slider-grabbed", G_CALLBACK(slider_grabbed), NULL);
- g_signal_connect(volume_slider, "slider-released", G_CALLBACK(slider_released), NULL);
- g_signal_connect(slider, "style-set", G_CALLBACK(style_changed_cb), NULL);
-
- // Set images on the ido
- GtkWidget* primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)volume_slider);
- GIcon * primary_gicon = g_themed_icon_new_with_default_fallbacks(g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_ZERO)));
- 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*)volume_slider);
- GIcon * secondary_gicon = g_themed_icon_new_with_default_fallbacks(g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_HIGH)));
- gtk_image_set_from_gicon(GTK_IMAGE(secondary_image), secondary_gicon, GTK_ICON_SIZE_MENU);
- g_object_unref(secondary_gicon);
-
- gtk_widget_set_sensitive(volume_slider, !initial_mute);
-
- GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (slider));
- gtk_adjustment_set_step_increment(adj, 3);
-
- gtk_widget_show_all(volume_slider);
-
- return TRUE;
-}
+}*/
+
static gboolean
new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
@@ -398,6 +323,42 @@
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);
+ io = g_object_get_data (G_OBJECT (client), "indicator");
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
+ priv->volume_widget = volume_widget;
+
+ GtkWidget* ido_slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
+
+ g_signal_connect(ido_slider_widget, "style-set", G_CALLBACK(style_changed_cb), NULL);
+ gtk_widget_set_sensitive(ido_slider_widget,
+ !initial_mute);
+ gtk_widget_show_all(ido_slider_widget);
+
+
+ GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget);
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client),
+ newitem,
+ menu_volume_item,
+ parent);
+
+ fetch_mute_value_from_dbus();
+ fetch_sink_availability_from_dbus(INDICATOR_SOUND (io));
+
+ return TRUE;
+}
+
static void
connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer userdata)
@@ -420,27 +381,18 @@
}
g_debug("about to connect to the signals");
dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_INPUT_WHILE_MUTED, G_TYPE_BOOLEAN, G_TYPE_INVALID);
-
dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_INPUT_WHILE_MUTED, G_CALLBACK(catch_signal_sink_input_while_muted), NULL, NULL);
- dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_VOLUME_UPDATE, G_TYPE_DOUBLE, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_VOLUME_UPDATE, G_CALLBACK(catch_signal_sink_volume_update), NULL, NULL);
dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_MUTE_UPDATE, G_TYPE_BOOLEAN, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_MUTE_UPDATE, G_CALLBACK(catch_signal_sink_mute_update), NULL, NULL);
+ dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_MUTE_UPDATE, G_CALLBACK(catch_signal_sink_mute_update), userdata, NULL);
dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_AVAILABLE_UPDATE, G_TYPE_BOOLEAN, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_AVAILABLE_UPDATE, G_CALLBACK(catch_signal_sink_availability_update), NULL, NULL);
+ g_return_if_fail(IS_INDICATOR_SOUND(userdata));
+
// Ensure we are in a coherent state with the service at start up.
// Preserve ordering!
- fetch_volume_percent_from_dbus();
- fetch_mute_value_from_dbus();
- fetch_sink_availability_from_dbus();
}
-
- } else {
- //TODO : will need to handle this scenario
- // Not much can we do here really, if there is no dbus connection tis goosed.
}
-
return;
}
@@ -498,7 +450,6 @@
g_object_unref(blocked_buf);
}
-
gint
get_state()
{
@@ -564,7 +515,7 @@
{
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;
}
@@ -584,11 +535,27 @@
}
}
+static void
+reset_mute_blocking_animation()
+{
+ if (animation_id != 0) {
+ g_debug("about to remove the animation_id callback from the mainloop!!**");
+ g_source_remove(animation_id);
+ animation_id = 0;
+ }
+ if (blocked_id != 0) {
+ g_debug("about to remove the blocked_id callback from the mainloop!!**");
+ g_source_remove(blocked_id);
+ blocked_id = 0;
+ }
+}
+
+
/*******************************************************************/
//DBus method handlers
/*******************************************************************/
static void
-fetch_sink_availability_from_dbus()
+fetch_sink_availability_from_dbus(IndicatorSound* self)
{
GError * error = NULL;
gboolean * available_input;
@@ -600,38 +567,25 @@
g_free(available_input);
return;
}
+
device_available = *available_input;
if (device_available == FALSE) {
update_state(STATE_SINKS_NONE);
g_debug("NO DEVICE AVAILABLE");
}
+ if(IS_INDICATOR_SOUND(self) == FALSE){
+ g_warning("okay pointer is arseways");
+ }
- if (GTK_IS_WIDGET (volume_slider))
- gtk_widget_set_sensitive(volume_slider, device_available);
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+ GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
+ gtk_widget_set_sensitive(slider_widget, device_available);
g_free(available_input);
g_debug("IndicatorSound::fetch_sink_availability_from_dbus -> AVAILABILTY returned from dbus method is %i", device_available);
}
-static void
-fetch_volume_percent_from_dbus()
-{
- GError * error = NULL;
- gdouble *volume_percent_input;
- volume_percent_input = g_new0(gdouble, 1);
- org_ayatana_indicator_sound_get_sink_volume(sound_dbus_proxy, volume_percent_input, &error);
- if (error != NULL) {
- g_warning("Unable to fetch VOLUME at indicator start up: %s", error->message);
- g_error_free(error);
- g_free(volume_percent_input);
- return;
- }
- initial_volume_percent = *volume_percent_input;
- determine_state_from_volume(initial_volume_percent);
- g_free(volume_percent_input);
- g_debug("at the indicator start up and the volume percent returned from dbus method is %f", initial_volume_percent);
-}
static void
fetch_mute_value_from_dbus()
@@ -669,22 +623,6 @@
static void
-catch_signal_sink_volume_update(DBusGProxy *proxy, gdouble volume_percent, gpointer userdata)
-{
- if (slider_in_direct_use == FALSE) {
- GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);
- GtkRange *range = (GtkRange*)slider;
-
- // DEBUG
- gdouble current_value = gtk_range_get_value(range);
- g_debug("SIGNAL- update sink volume - current_value : %f and new value : %f", current_value, volume_percent);
- exterior_vol_update = volume_percent;
- gtk_range_set_value(range, volume_percent);
- determine_state_from_volume(volume_percent);
- }
-}
-
-static void
catch_signal_sink_mute_update(DBusGProxy *proxy, gboolean mute_value, gpointer userdata)
{
//We can be sure the service won't send a mute signal unless it has changed !
@@ -695,23 +633,17 @@
reset_mute_blocking_animation();
}
g_debug("signal caught - sink mute update with mute value: %i", mute_value);
- gtk_widget_set_sensitive(volume_slider, !mute_value);
-}
-
-static void
-reset_mute_blocking_animation()
-{
- if (animation_id != 0) {
- g_debug("about to remove the animation_id callback from the mainloop!!**");
- g_source_remove(animation_id);
- animation_id = 0;
- }
- if (blocked_id != 0) {
- g_debug("about to remove the blocked_id callback from the mainloop!!**");
- g_source_remove(blocked_id);
- blocked_id = 0;
- }
-}
+ g_return_if_fail(IS_INDICATOR_SOUND(userdata));
+ IndicatorSound* indicator = INDICATOR_SOUND(userdata);
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator);
+
+ if(priv->volume_widget == NULL){
+ return;
+ }
+ GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
+ gtk_widget_set_sensitive(slider_widget, !mute_value);
+}
+
static void
catch_signal_sink_availability_update(DBusGProxy *proxy, gboolean available_value, gpointer userdata)
@@ -723,51 +655,9 @@
g_debug("signal caught - sink availability update with value: %i", available_value);
}
-
-
-
/*******************************************************************/
//UI callbacks
/******************************************************************/
-/**
-value_changed_event_cb:
-This callback will get triggered irregardless of whether its a user change or a programmatic change.
-**/
-static gboolean
-value_changed_event_cb(GtkRange *range, gpointer user_data)
-{
- gdouble current_value = CLAMP(gtk_range_get_value(range), 0, 100);
- if (current_value == exterior_vol_update) {
- g_debug("ignore the value changed event - its come from the outside");
- return FALSE;
- }
- DbusmenuMenuitem *item = (DbusmenuMenuitem*)user_data;
- GValue value = {0};
- g_value_init(&value, G_TYPE_DOUBLE);
- g_value_set_double(&value, current_value);
- g_debug("Value changed callback - = %f", current_value);
- dbusmenu_menuitem_handle_event (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;
-}
-
-
-static void
-slider_grabbed (GtkWidget *widget, gpointer user_data)
-{
- slider_in_direct_use = TRUE;
- g_debug ("!!!!!! grabbed\n");
-}
-
-static void
-slider_released (GtkWidget *widget, gpointer user_data)
-{
- slider_in_direct_use = FALSE;
- g_debug ("!!!!!! released\n");
-}
-
/**
key_press_cb:
@@ -777,7 +667,17 @@
{
gboolean digested = FALSE;
- GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);
+ g_return_val_if_fail(IS_INDICATOR_SOUND(data), FALSE);
+
+ IndicatorSound *indicator = INDICATOR_SOUND (data);
+
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator);
+ if(priv->volume_widget == NULL){
+ return FALSE;
+ }
+
+ GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
+ GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget);
GtkRange* range = (GtkRange*)slider;
gdouble current_value = gtk_range_get_value(range);
gdouble new_value = current_value;
@@ -814,14 +714,10 @@
default:
break;
}
-
new_value = CLAMP(new_value, 0, 100);
if (new_value != current_value && current_state != STATE_MUTED) {
g_debug("Attempting to set the range from the key listener to %f", new_value);
- // In order to ensure that the exterior filtering does not catch this, reset the exterior_vol_update
- // to ensure these updates.
- exterior_vol_update = OUT_OF_RANGE;
- gtk_range_set_value(range, new_value);
+ volume_widget_update(VOLUME_WIDGET(priv->volume_widget), new_value);
}
}
return digested;
@@ -837,21 +733,3 @@
free_the_animation_list();
prepare_blocked_animation();
}
-
-static void
-scroll (IndicatorObject *io, gint delta, IndicatorScrollDirection direction)
-{
- if (device_available == FALSE || current_state == STATE_MUTED)
- return;
-
- IndicatorSound *sound = INDICATOR_SOUND (io);
- GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (sound->slider));
- gdouble value = gtk_range_get_value (GTK_RANGE (sound->slider));
-
- if (direction == INDICATOR_OBJECT_SCROLL_UP) {
- value += adj->step_increment;
- } else {
- value -= adj->step_increment;
- }
- gtk_range_set_value (GTK_RANGE (sound->slider), value);
-}
=== modified file 'src/indicator-sound.h'
--- src/indicator-sound.h 2010-06-18 09:02:20 +0000
+++ src/indicator-sound.h 2010-08-04 11:38:45 +0000
@@ -24,9 +24,32 @@
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-// Essentially these are all exported to faciltiate testing
+#define INDICATOR_SOUND_TYPE (indicator_sound_get_type ())
+#define INDICATOR_SOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SOUND_TYPE, IndicatorSound))
+#define INDICATOR_SOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SOUND_TYPE, IndicatorSoundClass))
+#define IS_INDICATOR_SOUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SOUND_TYPE))
+#define IS_INDICATOR_SOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SOUND_TYPE))
+#define INDICATOR_SOUND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SOUND_TYPE, IndicatorSoundClass))
+
+typedef struct _IndicatorSound IndicatorSound;
+typedef struct _IndicatorSoundClass IndicatorSoundClass;
+
+//GObject class struct
+struct _IndicatorSoundClass {
+ IndicatorObjectClass parent_class;
+};
+
+//GObject instance struct
+struct _IndicatorSound {
+ IndicatorObject parent;
+ IndicatorServiceManager *service;
+};
+
+// GObject Boiler plate
+GType indicator_sound_get_type (void);
+
void prepare_state_machine();
-void determine_state_from_volume(gdouble volume_percent);
+extern void determine_state_from_volume(gdouble volume_percent);
gint get_state();
gchar* get_state_image_name(gint state);
void prepare_for_tests(IndicatorObject * io);
=== modified file 'src/pulse-manager.c'
--- src/pulse-manager.c 2010-06-18 09:02:20 +0000
+++ src/pulse-manager.c 2010-08-04 11:38:45 +0000
@@ -211,7 +211,8 @@
if (GPOINTER_TO_INT(user_data) == 1) {
sound_service_dbus_update_sink_mute(dbus_service, TRUE);
} else {
- sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume());
+ //sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume());
+ dbus_menu_manager_update_volume(get_default_sink_volume());
}
/* g_debug("in the pulse manager: mute each sink %i", GPOINTER_TO_INT(user_data));*/
@@ -288,7 +289,7 @@
/**
On Service startup this callback will be called multiple times resulting our sinks_hash container to be filled with the
available sinks.
-For now this callback it assumes it only used at startup. It may be necessary to use if sinks become available after startup.
+For now this callback assumes it only used at startup. It may be necessary to use if sinks become available after startup.
Major candidate for refactoring.
**/
static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink, int eol, void *userdata)
@@ -399,7 +400,7 @@
pa_volume_t vol = pa_cvolume_max(&s->volume);
gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM;
/* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/
- sound_service_dbus_update_sink_volume(dbus_service, volume_percent);
+ dbus_menu_manager_update_volume(volume_percent);
}
if (mute_changed == TRUE) {
@@ -410,7 +411,8 @@
pa_volume_t vol = pa_cvolume_max(&s->volume);
gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM;
/* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/
- sound_service_dbus_update_sink_volume(dbus_service, volume_percent);
+ //sound_service_dbus_update_sink_volume(dbus_service, volume_percent);
+ dbus_menu_manager_update_volume(volume_percent);
}
}
}
=== modified file 'src/slider-menu-item.c'
--- src/slider-menu-item.c 2010-06-18 09:02:20 +0000
+++ src/slider-menu-item.c 2010-08-04 11:38:45 +0000
@@ -90,9 +90,11 @@
SliderMenuItem* slider_menu_item_new(gboolean sinks_available, gdouble start_volume)
{
+
SliderMenuItem *self = g_object_new(SLIDER_MENU_ITEM_TYPE, NULL);
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_SLIDER_MENUITEM_TYPE);
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ENABLED, sinks_available);
+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_VOLUME_MENUITEM_TYPE);
+
+ dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ENABLED, sinks_available);
dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, sinks_available);
return self;
}
=== modified file 'src/sound-service-dbus.c'
--- src/sound-service-dbus.c 2010-06-18 09:02:20 +0000
+++ src/sound-service-dbus.c 2010-08-04 11:38:45 +0000
@@ -29,10 +29,8 @@
#include "pulse-manager.h"
// DBUS methods
-static gboolean sound_service_dbus_get_sink_volume(SoundServiceDbus* service, gdouble* volume_percent_input, GError** gerror);
static gboolean sound_service_dbus_get_sink_mute(SoundServiceDbus* service, gboolean* mute_input, GError** gerror);
static gboolean sound_service_dbus_get_sink_availability(SoundServiceDbus* service, gboolean* availability_input, GError** gerror);
-static void sound_service_dbus_set_sink_volume(SoundServiceDbus* service, const guint volume_percent, GError** gerror);
#include "sound-service-server.h"
@@ -40,7 +38,6 @@
struct _SoundServiceDbusPrivate {
DBusGConnection *connection;
- gdouble volume_percent;
gboolean mute;
gboolean sink_availability;
};
@@ -49,7 +46,6 @@
/* Signals */
enum {
SINK_INPUT_WHILE_MUTED,
- SINK_VOLUME_UPDATE,
SINK_MUTE_UPDATE,
SINK_AVAILABLE_UPDATE,
LAST_SIGNAL
@@ -65,7 +61,6 @@
static void sound_service_dbus_dispose (GObject *object);
static void sound_service_dbus_finalize (GObject *object);
-
/* GObject Boilerplate */
G_DEFINE_TYPE (SoundServiceDbus, sound_service_dbus, G_TYPE_OBJECT);
@@ -91,14 +86,6 @@
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
- signals[SINK_VOLUME_UPDATE] = g_signal_new("sink-volume-update",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__DOUBLE,
- G_TYPE_NONE, 1, G_TYPE_DOUBLE);
-
signals[SINK_MUTE_UPDATE] = g_signal_new("sink-mute-update",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
@@ -113,9 +100,6 @@
NULL, NULL,
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
-
-
}
static void
@@ -125,7 +109,6 @@
SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self);
priv->connection = NULL;
- priv->volume_percent = 0;
priv->mute = FALSE;
priv->sink_availability = FALSE;
@@ -159,23 +142,6 @@
}
-/**
-DBUS Method Callbacks
-**/
-static void sound_service_dbus_set_sink_volume(SoundServiceDbus* service, const guint volume_percent, GError** gerror)
-{
- g_debug("in the set sink volume method in the sound service dbus!, with volume_percent of %i", volume_percent);
- set_sink_volume(volume_percent);
-}
-
-static gboolean sound_service_dbus_get_sink_volume (SoundServiceDbus *self, gdouble *volume_percent_input, GError** gerror)
-{
- SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self);
- g_debug("Get sink volume method in the sound service dbus!, about to send over volume percent of %f", priv->volume_percent);
- *volume_percent_input = priv->volume_percent;
- return TRUE;
-}
-
static gboolean sound_service_dbus_get_sink_mute (SoundServiceDbus *self, gboolean *mute_input, GError** gerror)
{
SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self);
@@ -205,18 +171,6 @@
block_value);
}
-void sound_service_dbus_update_sink_volume(SoundServiceDbus* obj, gdouble sink_volume)
-{
- SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (obj);
- priv->volume_percent = sink_volume;
-
- /* g_debug("Emitting signal: SINK_VOLUME_UPDATE, with sink_volme %f", priv->volume_percent);*/
- g_signal_emit(obj,
- signals[SINK_VOLUME_UPDATE],
- 0,
- priv->volume_percent);
-}
-
void sound_service_dbus_update_sink_mute(SoundServiceDbus* obj, gboolean sink_mute)
{
/* g_debug("Emitting signal: SINK_MUTE_UPDATE, with sink mute %i", sink_mute);*/
=== modified file 'src/sound-service-dbus.h'
--- src/sound-service-dbus.h 2010-07-13 12:52:04 +0000
+++ src/sound-service-dbus.h 2010-08-04 11:38:45 +0000
@@ -52,7 +52,6 @@
// Utility methods to get the SIGNAL messages across into the sound-service-dbus
void sound_service_dbus_sink_input_while_muted (SoundServiceDbus* obj, gboolean block_value);
-void sound_service_dbus_update_sink_volume(SoundServiceDbus* obj, gdouble sink_volume);
void sound_service_dbus_update_sink_mute(SoundServiceDbus* obj, gboolean sink_mute);
void sound_service_dbus_update_sink_availability(SoundServiceDbus* obj, gboolean sink_availibity);
=== modified file 'src/sound-service.xml'
--- src/sound-service.xml 2010-03-08 19:12:18 +0000
+++ src/sound-service.xml 2010-08-04 11:38:45 +0000
@@ -1,16 +1,6 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/ayatana/indicator/sound">
<interface name="org.ayatana.indicator.sound">
- <method name = "SetSinkVolume">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_set_sink_volume"/>
- <arg type='u' name='volume_percent' direction="in"/>
- </method>
-
- <method name = "GetSinkVolume">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_get_sink_volume"/>
- <arg type='d' name='volume_percent_input' direction="out"/>
- </method>
-
<method name = "GetSinkMute">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_get_sink_mute"/>
<arg type='b' name='mute_input' direction="out"/>
@@ -28,10 +18,6 @@
<arg name="block_value" type="b" direction="out"/>
</signal>
- <signal name="SinkVolumeUpdate">
- <arg name="volume_percent" type="u" direction="out"/>
- </signal>
-
<signal name="SinkMuteUpdate">
<arg name="mute_value" type="b" direction="out"/>
</signal>
=== added file 'src/volume-widget.c'
--- src/volume-widget.c 1970-01-01 00:00:00 +0000
+++ src/volume-widget.c 2010-08-04 11:38:45 +0000
@@ -0,0 +1,246 @@
+/*
+Copyright 2010 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@xxxxxxxxxxxxx>
+
+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 <math.h>
+#include <glib.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_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 gboolean volume_widget_value_changed_cb(GtkRange *range, 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 (priv->ido_volume_slider,
+ "notify::parent", G_CALLBACK (volume_widget_parent_changed),
+ NULL);
+
+ GtkWidget* volume_widget = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
+
+ 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);
+
+ 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);
+}
+
+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_return_if_fail (IS_VOLUME_WIDGET (userdata));
+ VolumeWidget* mitem = VOLUME_WIDGET(userdata);
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(mitem);
+ g_debug("scrub-widget::property_update for prop %s", property);
+ if(g_ascii_strcasecmp(DBUSMENU_VOLUME_MENUITEM_LEVEL, property) == 0){
+ if(priv->grabbed == FALSE){
+ GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
+ GtkRange *range = (GtkRange*)slider;
+ gdouble update = g_value_get_double (value);
+ g_debug("volume-widget - update level with value %f", update);
+ gtk_range_set_value(range, update);
+ determine_state_from_volume(update);
+ }
+ }
+}
+
+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);
+ gdouble initial_level = g_value_get_double (dbusmenu_menuitem_property_get_value(twin_item,
+ DBUSMENU_VOLUME_MENUITEM_LEVEL));
+ g_debug("volume_widget_set_twin_item initial level = %f", initial_level);
+ //volume_widget_update(self, initial_level);
+ GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
+ GtkRange *range = (GtkRange*)slider;
+ gtk_range_set_value(range, initial_level);
+ determine_state_from_volume(initial_level);
+}
+
+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);
+ volume_widget_update(mitem, new_value);
+ determine_state_from_volume(new_value);
+ return FALSE;
+}
+
+static gboolean
+volume_widget_value_changed_cb(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);
+ GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
+ gdouble current_value = CLAMP(gtk_range_get_value(GTK_RANGE(slider)), 0, 100);
+
+ // We just want this callback to catch mouse icon press events
+ // which set the slider to 0 or 100
+ if(current_value == 0 || current_value == 100){
+ volume_widget_update(mitem, current_value);
+ }
+ return FALSE;
+}
+
+void
+volume_widget_update(VolumeWidget* self, gdouble update)
+{
+ VolumeWidgetPrivate * priv = VOLUME_WIDGET_GET_PRIVATE(self);
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_DOUBLE);
+ gdouble clamped = CLAMP(update, 0, 100);
+ g_value_set_double(&value, clamped);
+ dbusmenu_menuitem_handle_event (priv->twin_item, "update", &value, 0);
+}
+
+
+
+GtkWidget*
+volume_widget_get_ido_slider(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_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;
+}
+
+/**
+ * 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;
+}
+
+
=== added file 'src/volume-widget.h'
--- src/volume-widget.h 1970-01-01 00:00:00 +0000
+++ src/volume-widget.h 2010-08-04 11:38:45 +0000
@@ -0,0 +1,54 @@
+/*
+Copyright 2010 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@xxxxxxxxxxxxx>
+
+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_slider(VolumeWidget* self);
+void volume_widget_update(VolumeWidget* self, gdouble update);
+
+G_END_DECLS
+
+#endif
+
Follow ups