diff options
-rw-r--r-- | src/indicator-sound.c | 103 | ||||
-rw-r--r-- | src/pulse-manager.c | 130 | ||||
-rw-r--r-- | src/sound-service.c | 41 |
3 files changed, 156 insertions, 118 deletions
diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 26b73a6..9c73df4 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -82,7 +82,8 @@ 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); @@ -99,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; @@ -148,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. */ @@ -264,14 +255,7 @@ static void catch_signal_sink_volume_update(DBusGProxy *proxy, gdouble volume_pe // 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); - - // Don't like this solution - too fuzzy - // Need the ability to detect if the slider is grabbed - if(floor(current_value) != floor(volume_percent)) - { - g_debug("Going to update slider value"); - gtk_range_set_value(range, volume_percent); - } + gtk_range_set_value(range, volume_percent); determine_state_from_volume(volume_percent); } @@ -281,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); } @@ -337,15 +322,6 @@ static void update_state(const gint 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) { @@ -377,12 +353,16 @@ 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 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); 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); @@ -398,8 +378,9 @@ static gboolean new_slider_item(DbusmenuMenuitem * newitem, DbusmenuMenuitem * p // 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); @@ -412,8 +393,10 @@ static gboolean new_slider_item(DbusmenuMenuitem * newitem, DbusmenuMenuitem * p 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 "); @@ -425,22 +408,21 @@ 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)*/ -/* {*/ + 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); -/* }*/ + 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; } @@ -450,9 +432,6 @@ key_press_cb: static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data) { - if(event->length > 0) - g_debug("The key event's string is '%s'\n", event->string); - GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider); GtkRange* range = (GtkRange*)slider; gdouble current_value = gtk_range_get_value(range); @@ -464,45 +443,37 @@ static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer dat case GDK_Right: if(event->state & GDK_CONTROL_MASK) { -/* g_debug("right key was pressed with ctrl- volume set to 100"); */ new_value = 100; } else { -/* g_debug("right key was pressed - normal 5 percent increase"); */ new_value = current_value + five_percent; } break; case GDK_Left: if(event->state & GDK_CONTROL_MASK) { -/* g_debug("left key was pressed with ctrl- volume set to 0"); */ new_value = 0; } else { -/* g_debug("left key was pressed - normal 5 percent decrease"); */ new_value = current_value - five_percent; } break; case GDK_plus: -/* g_debug("Plus key was pressed");*/ new_value = current_value + five_percent; break; case GDK_minus: -/* g_debug("minus key was pressed");*/ new_value = current_value - five_percent; break; default: break; } -/* g_debug("new range value without being clamped = %f", new_value); */ - new_value = CLAMP(new_value, 0, 100); if(new_value != current_value) { - g_debug("Attempting to set the range to %f", new_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; @@ -510,18 +481,20 @@ static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer dat /** This callback should only be called when the user actually drags the slider. -Turned off for now in favour of the non descriminating call back. +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; -} +/*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; */ +/*} */ diff --git a/src/pulse-manager.c b/src/pulse-manager.c index 269ac58..52f9cba 100644 --- a/src/pulse-manager.c +++ b/src/pulse-manager.c @@ -43,10 +43,16 @@ static void context_success_callback(pa_context *c, int success, void *userdata) static void pulse_sink_input_info_callback(pa_context *c, const pa_sink_input_info *info, int eol, void *userdata); static void pulse_server_info_callback(pa_context *c, const pa_server_info *info, void *userdata); static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, void *userdata); +static void pulse_source_info_callback(pa_context *c, const pa_source_info *i, int eol, void *userdata); static void destroy_sink_info(void *value); static gboolean determine_sink_availability(); +/** +Refactoring notes +Push all UI updates out through update PA state in the service. +**/ + /* Entry point */ @@ -86,16 +92,6 @@ static void destroy_sink_info(void *value) g_free(sink); } -/*static void test_hash(){*/ -/* guint size = 0;*/ -/* size = g_hash_table_size(sink_hash);*/ -/* g_debug("Size of hash = %i", size);*/ -/* sink_info *s = g_hash_table_lookup(sink_hash, GINT_TO_POINTER(DEFAULT_SINK_INDEX)); */ -/* g_debug("The name of our sink is %s", s->name); */ -/* g_debug("and the max volume is %f", (gdouble)s->base_volume); */ - -/*}*/ - /* Controllers & Utilities */ @@ -167,6 +163,13 @@ static void mute_each_sink(gpointer key, gpointer value, gpointer user_data) { sink_info *info = (sink_info*)value; pa_operation_unref(pa_context_set_sink_mute_by_index(pulse_context, info->index, GPOINTER_TO_INT(user_data), context_success_callback, NULL)); + 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()); + } + g_debug("in the pulse manager: mute each sink %i", GPOINTER_TO_INT(user_data)); } @@ -197,8 +200,9 @@ void set_sink_volume(gdouble percent) g_debug("new volume calculated :%f", (gdouble)new_volume); pa_cvolume dev_vol; pa_cvolume_set(&dev_vol, s->volume.channels, new_volume); - // TODO why don't you update the sink_info here with the appropriate pa_cvolume (&dev_vol) + s->volume = dev_vol; pa_operation_unref(pa_context_set_sink_volume_by_index(pulse_context, DEFAULT_SINK_INDEX, &dev_vol, NULL, NULL)); + } @@ -242,9 +246,6 @@ static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink, in if(device_available == TRUE) { update_pa_state(TRUE, device_available, default_sink_is_muted(), get_default_sink_volume()); - sound_service_dbus_update_sink_volume(dbus_service, get_default_sink_volume()); - sound_service_dbus_update_sink_mute(dbus_service, default_sink_is_muted()); - g_debug("default sink index : %d", DEFAULT_SINK_INDEX); } else{ //Update the indicator to show PA either is not ready or has no available sink @@ -281,7 +282,17 @@ static void pulse_default_sink_info_callback(pa_context *c, const pa_sink_info * else{ DEFAULT_SINK_INDEX = info->index; g_debug("Just set the default sink index to %i", DEFAULT_SINK_INDEX); - pa_operation_unref(pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL)); + GList *keys = g_hash_table_get_keys(sink_hash); + gint position = g_list_index(keys, GINT_TO_POINTER(info->index)); + // Only update sink-list if the index is not in our already fetched list. + if(position < 0) + { + pa_operation_unref(pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL)); + } + else + { + update_pa_state(TRUE, determine_sink_availability(), default_sink_is_muted(), get_default_sink_volume()); + } } } @@ -322,22 +333,35 @@ static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, v s->description = g_strdup(info->description); s->icon_name = g_strdup(pa_proplist_gets(info->proplist, PA_PROP_DEVICE_ICON_NAME)); s->active_port = (info->active_port != NULL); - // NASTY!! gboolean mute_changed = s->mute != !!info->mute; s->mute = !!info->mute; + gboolean volume_changed = (pa_cvolume_equal(&info->volume, &s->volume) == 0); s->volume = info->volume; s->base_volume = info->base_volume; s->channel_map = info->channel_map; if(DEFAULT_SINK_INDEX == s->index) { //update the UI - pa_volume_t vol = pa_cvolume_avg(&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); - if (mute_changed == TRUE) + if (volume_changed == TRUE) + { + pa_volume_t vol = pa_cvolume_avg(&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); + } + + if (mute_changed == TRUE) + { + g_debug("Updating Mute from PA manager with mute = %i", s->mute); sound_service_dbus_update_sink_mute(dbus_service, s->mute); - update_mute_ui(s->mute); + update_mute_ui(s->mute); + if(s->mute == FALSE){ + pa_volume_t vol = pa_cvolume_avg(&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); + } + } } } else @@ -382,24 +406,64 @@ static void pulse_server_info_callback(pa_context *c, const pa_server_info *info pa_operation_unref(operation); } -static void subscribed_events_callback(pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata){ - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { +static void pulse_source_info_callback(pa_context *c, const pa_source_info *i, int eol, void *userdata) +{ + g_debug("pulse source info callback"); +} + + +static void subscribed_events_callback(pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) +{ + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + { case PA_SUBSCRIPTION_EVENT_SINK: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { - //TODO handle the remove event => if its our default sink - grey out the ui with update_pa_state - } else { + g_debug("PA_SUBSCRIPTION_EVENT_SINK event triggered"); + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) + { + //TODO handle the remove event => if its our default sink - update date pa state + } else + { pa_operation_unref(pa_context_get_sink_info_by_index(c, index, update_sink_info, userdata)); } break; case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - // This will be triggered when the sink receives input from a new stream - // If a playback client is paused and then resumed this will NOT trigger this event. - pa_operation_unref(pa_context_get_sink_input_info(c, index, pulse_sink_input_info_callback, userdata)); - break; + g_debug("PA_SUBSCRIPTION_EVENT_SINK_INPUT event triggered!!"); + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) + { + //TODO handle the remove event + } + else + { + pa_operation_unref(pa_context_get_sink_input_info(c, index, pulse_sink_input_info_callback, userdata)); + } + break; + case PA_SUBSCRIPTION_EVENT_SOURCE: + g_debug("PA_SUBSCRIPTION_EVENT_SOURCE of some description ???"); + + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) + { + //TODO handle the remove event + } + else + { + pa_operation *o; + if (!(o = pa_context_get_source_info_by_index(c, index, pulse_source_info_callback, userdata))) { + g_warning("pa_context_get_source_info_by_index() failed"); + return; + } + pa_operation_unref(o); + } + break; case PA_SUBSCRIPTION_EVENT_SERVER: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_SINK ) { - g_debug("server change of some sink type ???"); + g_debug("PA_SUBSCRIPTION_EVENT_SERVER change of some description ???"); + pa_operation *o; + if(!(o = pa_context_get_server_info(c, pulse_server_info_callback, userdata))) + { + g_warning("pa_context_get_server_info() failed"); + return; } + pa_operation_unref(o); + break; } } diff --git a/src/sound-service.c b/src/sound-service.c index d5c4eae..62f6bc6 100644 --- a/src/sound-service.c +++ b/src/sound-service.c @@ -74,7 +74,6 @@ static void rebuild_sound_menu(DbusmenuMenuitem *root, SoundServiceDbus *service mute_all_menuitem = dbusmenu_menuitem_new(); dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(b_all_muted == FALSE ? "Mute All" : "Unmute")); g_signal_connect(G_OBJECT(mute_all_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(set_global_mute_from_ui), NULL); - //TODO: If no valid sinks are found grey out the item(s) dbusmenu_menuitem_property_set_bool(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_ENABLED, b_sink_available); // Slider @@ -92,25 +91,29 @@ static void rebuild_sound_menu(DbusmenuMenuitem *root, SoundServiceDbus *service g_signal_connect(G_OBJECT(settings_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(show_sound_settings_dialog), NULL); } -/* 'public' method allowing the server to update the mute UI*/ + +/** +update_mute_ui: +'public' method allowing the server to update the mute UI +**/ void update_mute_ui(gboolean incoming_mute_value) { b_all_muted = incoming_mute_value; - dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(b_all_muted == FALSE ? "Mute All" : "Unmute")); + dbusmenu_menuitem_property_set(mute_all_menuitem, + DBUSMENU_MENUITEM_PROP_LABEL, + _(b_all_muted == FALSE ? "Mute All" : "Unmute")); } - +/** +set_global_mute_from_ui: +Callback for the dbusmenuitem button +**/ static void set_global_mute_from_ui() { b_all_muted = !b_all_muted; toggle_global_mute(b_all_muted); - dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(b_all_muted == FALSE ? "Mute All" : "Unmute")); - -/* GValue value = {0};*/ -/* g_value_init(&value, G_TYPE_DOUBLE);*/ -/* g_value_set_double(&value, 99.0);*/ -/* // Testing*/ -/* g_debug("BUGGY volume update");*/ -/* dbusmenu_menuitem_property_set_value(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_SLIDER_MENUITEM_PROP_VOLUME, &value);*/ + dbusmenu_menuitem_property_set(mute_all_menuitem, + DBUSMENU_MENUITEM_PROP_LABEL, + _(b_all_muted == FALSE ? "Mute All" : "Unmute")); } @@ -137,7 +140,12 @@ void update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_m b_pulse_ready = pa_state; volume_percent = percent; g_debug("update pa state with state %i, availability of %i, mute value of %i and a volume percent is %f", pa_state, sink_available, sink_muted, volume_percent); - rebuild_sound_menu(root_menuitem, dbus_interface); + sound_service_dbus_update_sink_volume(dbus_interface, percent); + sound_service_dbus_update_sink_mute(dbus_interface, sink_muted); + + // Only rebuild the menu on start up... + if(volume_slider_menuitem == NULL) + rebuild_sound_menu(root_menuitem, dbus_interface); } @@ -169,13 +177,6 @@ main (int argc, char ** argv) dbusmenu_server_set_root(server, root_menuitem); establish_pulse_activities(dbus_interface); -/* // THIS DOES NOT WORK FROM HERE*/ -/* GValue value = {0};*/ -/* g_value_init(&value, G_TYPE_DOUBLE);*/ -/* g_value_set_double(&value, volume_percent * 100);*/ -/* g_debug("About to send over the volume slider initial value %f", (volume_percent * 100));*/ -/* dbusmenu_menuitem_property_set_value(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_SLIDER_MENUITEM_PROP_VOLUME, &value);*/ - // Run the loop mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); |