diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/common-defs.h | 3 | ||||
-rw-r--r-- | src/dbus-menu-manager.c | 16 | ||||
-rw-r--r-- | src/dbus-menu-manager.h | 1 | ||||
-rw-r--r-- | src/indicator-sound.c | 363 | ||||
-rw-r--r-- | src/indicator-sound.h | 27 | ||||
-rw-r--r-- | src/metadata-widget.h | 2 | ||||
-rw-r--r-- | src/pulse-manager.c | 10 | ||||
-rw-r--r-- | src/scrub-widget.h | 2 | ||||
-rw-r--r-- | src/slider-menu-item.c | 7 | ||||
-rw-r--r-- | src/sound-service-dbus.c | 46 | ||||
-rw-r--r-- | src/sound-service-dbus.h | 1 | ||||
-rw-r--r-- | src/sound-service.xml | 14 | ||||
-rw-r--r-- | src/title-widget.h | 2 | ||||
-rw-r--r-- | src/transport-widget.h | 2 | ||||
-rw-r--r-- | src/volume-widget.c | 247 | ||||
-rw-r--r-- | src/volume-widget.h | 54 |
17 files changed, 474 insertions, 325 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/common-defs.h b/src/common-defs.h index 46ff520..e3b4552 100644 --- a/src/common-defs.h +++ b/src/common-defs.h @@ -27,7 +27,8 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #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" diff --git a/src/dbus-menu-manager.c b/src/dbus-menu-manager.c index 4cd4a6b..5b97a0d 100644 --- a/src/dbus-menu-manager.c +++ b/src/dbus-menu-manager.c @@ -31,6 +31,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #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 @@ DbusmenuMenuitem* dbus_menu_manager_setup() 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 @@ void dbus_menu_manager_update_pa_state(gboolean pa_state, gboolean sink_availabl // 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 @@ void dbus_menu_manager_update_mute_ui(gboolean incoming_mute_value) /*-------------------------------------------------------------------------*/ // Private Methods /*-------------------------------------------------------------------------*/ - static void refresh_menu() { g_debug("in the refresh menu method"); diff --git a/src/dbus-menu-manager.h b/src/dbus-menu-manager.h index 926e292..ec2b2e2 100644 --- a/src/dbus-menu-manager.h +++ b/src/dbus-menu-manager.h @@ -25,6 +25,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. 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); diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 1c6041b..557ce85 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -42,34 +42,22 @@ 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" -// 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; -}; +typedef struct _IndicatorSoundPrivate IndicatorSoundPrivate; -//GObject instance struct -struct _IndicatorSound { - IndicatorObject parent; - GtkWidget *slider; - IndicatorServiceManager *service; +struct _IndicatorSoundPrivate +{ + GtkWidget* volume_widget; }; + +#define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate)) + // GObject Boiler plate -GType indicator_sound_get_type (void); INDICATOR_SET_VERSION INDICATOR_SET_TYPE(INDICATOR_SOUND_TYPE) @@ -84,15 +72,10 @@ G_DEFINE_TYPE (IndicatorSound, indicator_sound, INDICATOR_OBJECT_TYPE); 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 gboolean new_scrub_bar_widget(DbusmenuMenuitem * newitem, DbusmenuMenuite 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_MEDIUM = 3; 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 @@ indicator_sound_class_init (IndicatorSoundClass *klass) 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 @@ indicator_sound_init (IndicatorSound *self) 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 @@ indicator_sound_dispose (GObject *object) 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 @@ get_menu (IndicatorObject * io) 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 @@ 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); + 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 @@ connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer u } 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 @@ prepare_blocked_animation() g_object_unref(blocked_buf); } - gint get_state() { @@ -564,7 +515,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; } @@ -584,12 +535,30 @@ fade_back_to_mute_image() } } +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) { + g_return_if_fail(IS_INDICATOR_SOUND(self)); + GError * error = NULL; gboolean * available_input; available_input = g_new0(gboolean, 1); @@ -600,38 +569,21 @@ fetch_sink_availability_from_dbus() g_free(available_input); return; } + device_available = *available_input; if (device_available == FALSE) { update_state(STATE_SINKS_NONE); g_debug("NO DEVICE AVAILABLE"); } - 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); - + g_debug("IndicatorSound::fetch_sink_availability_from_dbus ->%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() @@ -667,52 +619,31 @@ catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean block_value, gp } } - -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); - } -} - +/* + We can be sure the service won't send a mute signal unless it has changed ! + UNMUTE's force a volume update therefore icon is updated appropriately => no need for unmute handling here. +*/ 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 ! - //UNMUTE's force a volume update therefore icon is updated appropriately => no need for unmute handling here. if (mute_value == TRUE && device_available == TRUE) { update_state(STATE_MUTED); } else { 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); -} + g_return_if_fail(IS_INDICATOR_SOUND(userdata)); + IndicatorSound* indicator = INDICATOR_SOUND(userdata); + IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator); -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; - } + 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 +654,9 @@ catch_signal_sink_availability_update(DBusGProxy *proxy, gboolean available_valu 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 +666,17 @@ 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), 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 +713,10 @@ key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) 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 +732,3 @@ style_changed_cb(GtkWidget *widget, gpointer user_data) 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); -} diff --git a/src/indicator-sound.h b/src/indicator-sound.h index 386ad2a..251295c 100644 --- a/src/indicator-sound.h +++ b/src/indicator-sound.h @@ -24,9 +24,32 @@ You should have received a copy of the GNU General Public License along 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); diff --git a/src/metadata-widget.h b/src/metadata-widget.h index 6f1d4d3..814d5e8 100644 --- a/src/metadata-widget.h +++ b/src/metadata-widget.h @@ -20,7 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define __METADATA_WIDGET_H__ #include <gtk/gtkmenuitem.h> -#include <libdbusmenu-gtk/menu.h> +#include <libdbusmenu-gtk/menuitem.h> G_BEGIN_DECLS diff --git a/src/pulse-manager.c b/src/pulse-manager.c index a9a47e4..4ff9e1d 100644 --- a/src/pulse-manager.c +++ b/src/pulse-manager.c @@ -211,7 +211,8 @@ static void mute_each_sink(gpointer key, gpointer value, gpointer user_data) 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 @@ static void context_success_callback(pa_context *c, int success, void *userdata) /** 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 @@ static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, v 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 @@ static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, v 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); } } } diff --git a/src/scrub-widget.h b/src/scrub-widget.h index cebe890..e518a80 100644 --- a/src/scrub-widget.h +++ b/src/scrub-widget.h @@ -21,7 +21,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> #include <glib-object.h> -#include <libdbusmenu-gtk/menu.h> +#include <libdbusmenu-gtk/menuitem.h> G_BEGIN_DECLS diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c index d56422a..77c8635 100644 --- a/src/slider-menu-item.c +++ b/src/slider-menu-item.c @@ -79,7 +79,6 @@ slider_menu_item_finalize (GObject *object) static void handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, guint timestamp) { - g_debug("in the handle event method of slider_menu_item"); gdouble volume_input = 0; volume_input = g_value_get_double(value); if (value != NULL) @@ -90,9 +89,11 @@ handle_event (DbusmenuMenuitem * mi, const gchar * name, const GValue * value, g 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; } diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 85945d0..d553285 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -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 @@ typedef struct _SoundServiceDbusPrivate SoundServiceDbusPrivate; struct _SoundServiceDbusPrivate { DBusGConnection *connection; - gdouble volume_percent; gboolean mute; gboolean sink_availability; }; @@ -49,7 +46,6 @@ struct _SoundServiceDbusPrivate { /* 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_init (SoundServiceDbus *self); 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 @@ sound_service_dbus_class_init (SoundServiceDbusClass *klass) 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 @@ sound_service_dbus_class_init (SoundServiceDbusClass *klass) NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - - - } static void @@ -125,7 +109,6 @@ sound_service_dbus_init (SoundServiceDbus *self) 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 @@ sound_service_dbus_finalize (GObject *object) } -/** -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 @@ 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) -{ - 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);*/ diff --git a/src/sound-service-dbus.h b/src/sound-service-dbus.h index 72556ad..b6e8193 100644 --- a/src/sound-service-dbus.h +++ b/src/sound-service-dbus.h @@ -52,7 +52,6 @@ GType sound_service_dbus_get_type (void) G_GNUC_CONST; // 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); diff --git a/src/sound-service.xml b/src/sound-service.xml index 12ed03e..ee19ceb 100644 --- a/src/sound-service.xml +++ b/src/sound-service.xml @@ -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 @@ Our respective UI element should listen to this and therefore will be updated wi <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> diff --git a/src/title-widget.h b/src/title-widget.h index efc0c78..fc8f169 100644 --- a/src/title-widget.h +++ b/src/title-widget.h @@ -20,7 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define __TITLE_WIDGET_H__ #include <gtk/gtkmenuitem.h> -#include <libdbusmenu-gtk/menu.h> +#include <libdbusmenu-gtk/menuitem.h> G_BEGIN_DECLS diff --git a/src/transport-widget.h b/src/transport-widget.h index 1d1aa6e..c69836a 100644 --- a/src/transport-widget.h +++ b/src/transport-widget.h @@ -20,7 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define __TRANSPORT_WIDGET_H__ #include <gtk/gtkmenuitem.h> -#include <libdbusmenu-gtk/menu.h> +#include <libdbusmenu-gtk/menuitem.h> G_BEGIN_DECLS diff --git a/src/volume-widget.c b/src/volume-widget.c new file mode 100644 index 0000000..bf1ddb9 --- /dev/null +++ b/src/volume-widget.c @@ -0,0 +1,247 @@ +/* +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 <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); + g_object_ref (priv->ido_volume_slider); + 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_object_ref(priv->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); + 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; +} + +/* + We only want this callback to catch mouse icon press events + which set the slider to 0 or 100. Ignore all other events. +*/ +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); + + 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; +} + + diff --git a/src/volume-widget.h b/src/volume-widget.h new file mode 100644 index 0000000..d4929ec --- /dev/null +++ b/src/volume-widget.h @@ -0,0 +1,54 @@ +/* +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/menuitem.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 + |