diff options
Diffstat (limited to 'src/indicator-sound.c')
-rw-r--r-- | src/indicator-sound.c | 186 |
1 files changed, 123 insertions, 63 deletions
diff --git a/src/indicator-sound.c b/src/indicator-sound.c index a8bbeea..8e79db6 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -20,10 +20,11 @@ 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/>. */ - +#include <math.h> #include <glib.h> #include <glib-object.h> #include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> #include <libdbusmenu-gtk/menu.h> #include <libido/idoscalemenuitem.h> @@ -81,8 +82,10 @@ static GtkMenu * get_menu (IndicatorObject * io); static GtkWidget *volume_slider = NULL; static gboolean new_slider_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); static void slider_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkWidget *widget); -static gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data); +// Alternative callback mechanism, may use this again once ido is updated. +/*static gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data);*/ static gboolean value_changed_event_cb(GtkRange *range, gpointer user_data); +static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data); // DBUS communication static DBusGProxy *sound_dbus_proxy = NULL; @@ -97,7 +100,6 @@ static void fetch_mute_value_from_dbus(); static void prepare_state_machine(); static void determine_state_from_volume(gdouble volume_percent); static void update_state(const gint state); -/*static void revert_state();*/ static const gint STATE_MUTED = 0; static const gint STATE_ZERO = 1; static const gint STATE_LOW = 2; @@ -146,15 +148,6 @@ static void indicator_sound_init (IndicatorSound *self) } -/*static void test_images_hash()*/ -/*{*/ -/* g_debug("about to test the images hash"); */ -/* gchar* current_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state));*/ -/* g_debug("start up current image name = %s", current_name); */ -/* gchar* previous_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(previous_state));*/ -/* g_debug("start up previous image name = %s", previous_name); */ -/*}*/ - /* Prepare states Array. */ @@ -162,14 +155,13 @@ static void prepare_state_machine() { // TODO we need three more images volume_states = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); - g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MUTED), g_strdup("audio-volume-muted")); - g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_ZERO), g_strdup(/*"audio-volume-zero"*/"audio-volume-muted")); - g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_LOW), g_strdup("audio-volume-low")); - g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MEDIUM), g_strdup("audio-volume-medium")); - g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_HIGH), g_strdup("audio-volume-high")); - g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT), g_strdup(/*"audio-volume-muted-blocking"*/"audio-volume-muted")); - g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_SINKS_NONE), g_strdup(/*"audio-output-none"*/"audio-volume-muted")); - //test_images_hash(); + g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MUTED), g_strdup("audio-volume-muted-panel")); + g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_ZERO), g_strdup("audio-volume-zero-panel")); + g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_LOW), g_strdup("audio-volume-low-panel")); + g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MEDIUM), g_strdup("audio-volume-medium-panel")); + g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_HIGH), g_strdup("audio-volume-high-panel")); + g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT), g_strdup("audio-volume-muted-blocking-panel")); + g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_SINKS_NONE), g_strdup("audio-output-none-panel")); } static void @@ -257,9 +249,12 @@ static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean blo static void catch_signal_sink_volume_update(DBusGProxy *proxy, gdouble volume_percent, gpointer userdata) { - g_debug("signal caught - update sink volume with value : %f", volume_percent); 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); gtk_range_set_value(range, volume_percent); determine_state_from_volume(volume_percent); } @@ -270,9 +265,10 @@ static void catch_signal_sink_mute_update(DBusGProxy *proxy, gboolean mute_value //UNMUTE's force a volume update therefore icon is updated appropriately => no need for unmute handling here. if(mute_value == TRUE) { - g_debug("signal caught - sink mute update - MUTE"); update_state(STATE_MUTED); } + g_debug("signal caught - sink mute update with mute value: %i", mute_value); + gtk_widget_set_sensitive(volume_slider, !mute_value); } @@ -315,30 +311,22 @@ get_icon (IndicatorObject * io) static void update_state(const gint state) { - g_debug("update state beginning - previous_state = %i", previous_state); +/* g_debug("update state beginning - previous_state = %i", previous_state);*/ previous_state = current_state; - g_debug("update state 3rd line - previous_state = %i", previous_state); +/* g_debug("update state 3rd line - previous_state = %i", previous_state);*/ current_state = state; gchar* image_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state)); gtk_image_set_from_icon_name(speaker_image, image_name, GTK_ICON_SIZE_MENU); } -/*static void revert_state()*/ -/*{*/ - -/* g_debug("revert state beginning - previous_state = %i", previous_state);*/ -/* current_state = previous_state;*/ -/* gchar* image_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state));*/ -/* gtk_image_set_from_icon_name(speaker_image, image_name, GTK_ICON_SIZE_MENU);*/ -/* g_debug("after reverting back to previous state of %i", current_state);*/ -/*}*/ static void determine_state_from_volume(gdouble volume_percent) { - g_debug("determine_state_from_volume - previous_state = %i", previous_state); +/* g_debug("determine_state_from_volume - previous_state = %i", previous_state);*/ + gint state = previous_state; if (volume_percent < 30.0 && volume_percent > 0){ state = STATE_LOW; @@ -366,38 +354,50 @@ get_menu (IndicatorObject * io) DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu); dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SLIDER_MENUITEM_TYPE, new_slider_item); + // 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); + return GTK_MENU(menu); } +/** +new_slider_item: +Create a new dBusMenu Slider item, register the +**/ static gboolean new_slider_item(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client) { g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); volume_slider = ido_scale_menu_item_new_with_range ("Volume", initial_volume_percent, 0, 100, 0.5); + g_object_set(volume_slider, "reverse-scroll-events", TRUE, NULL); GtkMenuItem *menu_volume_slider = GTK_MENU_ITEM(volume_slider); + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_volume_slider, parent); g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(slider_prop_change_cb), volume_slider); + // register slider changes listening on the range GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider); - g_signal_connect(slider, "change-value", G_CALLBACK(user_change_value_event_cb), newitem); g_signal_connect(slider, "value-changed", G_CALLBACK(value_changed_event_cb), newitem); + // alternative callback mechanism which i could use again at some point. +/* g_signal_connect(slider, "change-value", G_CALLBACK(user_change_value_event_cb), newitem); */ + // Set images on the ido primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)volume_slider); gtk_image_set_from_icon_name(GTK_IMAGE(primary_image), g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_ZERO)), GTK_ICON_SIZE_MENU); GtkWidget* secondary_image = ido_scale_menu_item_get_secondary_image((IdoScaleMenuItem*)volume_slider); gtk_image_set_from_icon_name(GTK_IMAGE(secondary_image), g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_HIGH)), GTK_ICON_SIZE_MENU); -/* GtkRange* range = (GtkRange*)slider; */ -/* gtk_range_set_value(range, initial_volume_percent); */ - gtk_widget_show_all(volume_slider); + return TRUE; } -/* Whenever we have a property change on a DbusmenuMenuitem - we need to be responsive to that. */ +/** +slider_prop_change_cb: +Whenever we have a property change on a DbusmenuMenuitem this will be called. +**/ static void slider_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkWidget *widget) { g_debug("slider_prop_change_cb - dodgy updater "); @@ -409,35 +409,95 @@ static void slider_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * } /** -This callback will get triggered irregardless of whether its a user change or a programmatic change -Our usecase for this particular callback is only interested if the slider is changed by the user hitting either icon -which will result in a programmatic value change of 0 or 100 (work around). +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 = gtk_range_get_value(range); - if(current_value == 0 || current_value == 100) - { - 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 listener - = %f", current_value); - dbusmenu_menuitem_handle_event (item, "slider_change", &value, 0); - } + gdouble current_value = CLAMP(gtk_range_get_value(range), 0, 100); + 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 gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data) +/** +key_press_cb: +**/ +static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) { - DbusmenuMenuitem *item = (DbusmenuMenuitem*)user_data; - gdouble clamped_input = CLAMP(input_value, 0, 100); - GValue value = {0}; - g_debug("User input on SLIDER - = %f", clamped_input); - g_value_init(&value, G_TYPE_DOUBLE); - g_value_set_double(&value, clamped_input); - dbusmenu_menuitem_handle_event (item, "slider_change", &value, 0); - return FALSE; -} + if (current_state == STATE_MUTED) + return FALSE; + + GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider); + GtkRange* range = (GtkRange*)slider; + gdouble current_value = gtk_range_get_value(range); + gdouble new_value = current_value; + const gdouble five_percent = 5; + + switch(event->keyval) + { + case GDK_Right: + if(event->state & GDK_CONTROL_MASK) + { + new_value = 100; + } + else + { + new_value = current_value + five_percent; + } + break; + case GDK_Left: + if(event->state & GDK_CONTROL_MASK) + { + new_value = 0; + } + else + { + new_value = current_value - five_percent; + } + break; + case GDK_plus: + new_value = current_value + five_percent; + break; + case GDK_minus: + new_value = current_value - five_percent; + break; + default: + break; + } + + new_value = CLAMP(new_value, 0, 100); + if(new_value != current_value) + { + g_debug("Attempting to set the range from the key listener to %f", new_value); + gtk_range_set_value(range, new_value); + } + return FALSE; +} + +/** +This callback should only be called when the user actually drags the slider. +Turned off for now in favour of the non descriminating value-changed call back. +Once the grabbing listener is implemented on the slider may revert to using this. +Its another tool for filtering unwanted volume change updates. +**/ +/*static gboolean user_change_value_event_cb(GtkRange *range, GtkScrollType scroll_type, gdouble input_value, gpointer user_data)*/ +/*{*/ +/* DbusmenuMenuitem *item = (DbusmenuMenuitem*)user_data;*/ +/* gdouble clamped_input = CLAMP(input_value, 0, 100);*/ +/* GValue value = {0};*/ +/* g_debug("User input on SLIDER - = %f", clamped_input);*/ +/* g_value_init(&value, G_TYPE_DOUBLE);*/ +/* g_value_set_double(&value, clamped_input);*/ +/* dbusmenu_menuitem_handle_event (item, "slider_change", &value, 0);*/ +/* return FALSE; */ +/*} */ |