diff options
-rw-r--r-- | src/common-defs.h | 1 | ||||
-rw-r--r-- | src/dbus-menu-manager.c | 5 | ||||
-rw-r--r-- | src/indicator-sound.c | 75 | ||||
-rw-r--r-- | src/pulse-manager.c | 15 | ||||
-rw-r--r-- | src/sound-service-dbus.c | 37 | ||||
-rw-r--r-- | src/sound-service-dbus.h | 1 | ||||
-rw-r--r-- | src/sound-service.xml | 10 |
7 files changed, 134 insertions, 10 deletions
diff --git a/src/common-defs.h b/src/common-defs.h index 942e269..9be1da5 100644 --- a/src/common-defs.h +++ b/src/common-defs.h @@ -22,6 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define SIGNAL_SINK_INPUT_WHILE_MUTED "SinkInputWhileMuted" #define SIGNAL_SINK_VOLUME_UPDATE "SinkVolumeUpdate" #define SIGNAL_SINK_MUTE_UPDATE "SinkMuteUpdate" +#define SIGNAL_SINK_AVAILABLE_UPDATE "SinkAvailableUpdate" // DBUS items #define DBUSMENU_SLIDER_MENUITEM_TYPE "x-canonical-ido-slider-item" diff --git a/src/dbus-menu-manager.c b/src/dbus-menu-manager.c index 243a3a7..38ed727 100644 --- a/src/dbus-menu-manager.c +++ b/src/dbus-menu-manager.c @@ -101,6 +101,8 @@ void dbus_menu_manager_update_pa_state(gboolean pa_state, gboolean sink_availabl refresh_menu(); } // 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); sound_service_dbus_update_sink_mute(dbus_interface, sink_muted); dbus_menu_manager_update_mute_ui(b_all_muted); @@ -199,7 +201,8 @@ static void rebuild_sound_menu(DbusmenuMenuitem *root, SoundServiceDbus *service dbusmenu_menuitem_child_append(root, DBUSMENU_MENUITEM(volume_slider_menuitem)); dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_MENUITEM_PROP_ENABLED, - b_sink_available); + b_sink_available && !b_all_muted); + g_debug("!!!!!!**in the rebuild sound menu - slider active = %i", b_sink_available && !b_all_muted); dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, b_sink_available); diff --git a/src/indicator-sound.c b/src/indicator-sound.c index 1fb8090..c10b549 100644 --- a/src/indicator-sound.c +++ b/src/indicator-sound.c @@ -93,8 +93,10 @@ static void connection_changed (IndicatorServiceManager * sm, gboolean connected 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(); /****Volume States 'members' ***/ @@ -110,11 +112,13 @@ static const gint STATE_SINKS_NONE = 6; static GHashTable *volume_states = NULL; static GtkImage *speaker_image = NULL; +static GtkImage *blocking_image = NULL; static GtkWidget* primary_image = NULL; static gint current_state = 0; static gint previous_state = 0; static gdouble initial_volume_percent = 0; static gboolean initial_mute = FALSE; +static gboolean device_available = TRUE; #define DESIGN_TEAM_SIZE design_team_size static GtkIconSize design_team_size; @@ -182,6 +186,8 @@ get_icon (IndicatorObject * io) gchar* current_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state)); //g_debug("At start-up attempting to set the image to %s", current_name); speaker_image = GTK_IMAGE(gtk_image_new_from_icon_name(current_name, DESIGN_TEAM_SIZE)); + gchar* blocking_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT)); + blocking_image = GTK_IMAGE(gtk_image_new_from_icon_name(blocking_name, DESIGN_TEAM_SIZE)); gtk_widget_show(GTK_WIDGET(speaker_image)); return speaker_image; } @@ -264,11 +270,14 @@ connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer u 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_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); // 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 { @@ -332,7 +341,8 @@ static void update_state(const gint state) void determine_state_from_volume(gdouble volume_percent) { /* g_debug("determine_state_from_volume - previous_state = %i", previous_state);*/ - + if (device_available == FALSE) + return; gint state = previous_state; if (volume_percent < 30.0 && volume_percent > 0){ state = STATE_LOW; @@ -350,6 +360,25 @@ void determine_state_from_volume(gdouble volume_percent) } +static void fetch_sink_availability_from_dbus() +{ + GError * error = NULL; + gboolean *available_input; + available_input = g_new0(gboolean, 1); + org_ayatana_indicator_sound_get_sink_availability(sound_dbus_proxy, available_input, &error); + if (error != NULL) { + g_warning("Unable to fetch AVAILABILITY at indicator start up: %s", error->message); + g_error_free(error); + g_free(available_input); + return; + } + device_available = *available_input; + if (device_available == FALSE) + update_state(STATE_SINKS_NONE); + 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() { @@ -391,6 +420,38 @@ static void fetch_mute_value_from_dbus() static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean block_value, gpointer userdata) { g_debug("signal caught - sink input while muted with value %i", block_value); + if (block_value == 1) { + GError* error= NULL; + // We can assume we are in the muted state ! + GtkIconTheme* theme = gtk_icon_theme_get_default(); + GdkPixbuf* mute_buf = gtk_icon_theme_load_icon(theme, + g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT)), + 22, + GTK_ICON_LOOKUP_GENERIC_FALLBACK, + &error); + if(error != NULL){ + g_error("indicator-sound : catch_signal_sink_input_while_muted - %s", error->message); + g_error_free(error); + return; + } + gchar* blocked_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT)); + GdkPixbuf* blocked_buf = gtk_icon_theme_load_icon(theme, blocked_name, + 22, + GTK_ICON_LOOKUP_GENERIC_FALLBACK, + &error); + if(error != NULL){ + g_error("indicator-sound : catch_signal_sink_input_while_muted - %s", error->message); + g_error_free(error); + return; + } + g_debug("gdk_pixbuf_get_width returns %i", gdk_pixbuf_get_width(blocked_buf)); + gdk_pixbuf_composite(mute_buf, blocked_buf, 0, 0, + gdk_pixbuf_get_width(blocked_buf), + gdk_pixbuf_get_height(blocked_buf), + 0, 0, 1, 1, GDK_INTERP_BILINEAR, 128); + //gtk_image_set_from_icon_name(speaker_image, blocked_name, DESIGN_TEAM_SIZE); + //gtk_image_set_from_pixbuf(speaker_image, blocked_buf); + } } static void catch_signal_sink_volume_update(DBusGProxy *proxy, gdouble volume_percent, gpointer userdata) @@ -409,13 +470,23 @@ static void catch_signal_sink_mute_update(DBusGProxy *proxy, gboolean mute_value { //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) + if(mute_value == TRUE && device_available != FALSE) { 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); } + +static void catch_signal_sink_availability_update(DBusGProxy *proxy, gboolean available_value, gpointer userdata) +{ + device_available = available_value; + if (device_available == FALSE){ + update_state(STATE_SINKS_NONE); + } + g_debug("signal caught - sink availability update with value: %i", available_value); +} + /** slider_prop_change_cb: Whenever we have a property change on a DbusmenuMenuitem this will be called. diff --git a/src/pulse-manager.c b/src/pulse-manager.c index 36e6351..40add4e 100644 --- a/src/pulse-manager.c +++ b/src/pulse-manager.c @@ -282,7 +282,7 @@ static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink, in else{ //Update the indicator to show PA either is not ready or has no available sink g_warning("Cannot find a suitable default sink ..."); - dbus_menu_manager_update_pa_state(FALSE, device_available, TRUE, 0); + dbus_menu_manager_update_pa_state(FALSE, device_available, default_sink_is_muted(), get_default_sink_volume()); } } else{ @@ -398,6 +398,7 @@ static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, v } else { + sink_info *value; value = g_new0(sink_info, 1); value->index = value->device_index = info->index; @@ -411,7 +412,8 @@ static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, v value->channel_map = info->channel_map; g_hash_table_insert(sink_hash, GINT_TO_POINTER(value->index), value); g_debug("pulse-manager:update_sink_info -> After adding a new sink to our hash"); - } + sound_service_dbus_update_sink_availability(dbus_service, TRUE); + } } @@ -460,8 +462,11 @@ static void subscribed_events_callback(pa_context *c, enum pa_subscription_event 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 + if(index == DEFAULT_SINK_INDEX) + g_debug("PA_SUBSCRIPTION_EVENT_SINK REMOVAL event triggered"); + sound_service_dbus_update_sink_availability(dbus_service, FALSE); + } + else { pa_operation_unref(pa_context_get_sink_info_by_index(c, index, update_sink_info, userdata)); } @@ -470,7 +475,7 @@ static void subscribed_events_callback(pa_context *c, enum pa_subscription_event 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 + //handle the remove event - not relevant for current design } else { diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 72337fd..1cc5f0d 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -32,6 +32,7 @@ // 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" @@ -43,6 +44,7 @@ struct _SoundServiceDbusPrivate DBusGConnection *connection; gdouble volume_percent; gboolean mute; + gboolean sink_availability; }; @@ -51,6 +53,7 @@ enum { SINK_INPUT_WHILE_MUTED, SINK_VOLUME_UPDATE, SINK_MUTE_UPDATE, + SINK_AVAILABLE_UPDATE, LAST_SIGNAL }; @@ -105,6 +108,15 @@ sound_service_dbus_class_init (SoundServiceDbusClass *klass) NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals[SINK_AVAILABLE_UPDATE] = g_signal_new("sink-available-update", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + } @@ -116,6 +128,8 @@ sound_service_dbus_init (SoundServiceDbus *self) priv->connection = NULL; priv->volume_percent = 0; + priv->mute = FALSE; + priv->sink_availability = FALSE; /* Fetch the session bus */ priv->connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); @@ -129,8 +143,6 @@ sound_service_dbus_init (SoundServiceDbus *self) dbus_g_connection_register_g_object(priv->connection, "/org/ayatana/indicator/sound/service", G_OBJECT(self)); - - return; } @@ -174,6 +186,14 @@ static gboolean sound_service_dbus_get_sink_mute (SoundServiceDbus *self, gboole return TRUE; } +static gboolean sound_service_dbus_get_sink_availability (SoundServiceDbus *self, gboolean *availability_input, GError** gerror) +{ + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); + g_debug("Get sink availability - sound service dbus!, about to send over availability_value of %i", priv->sink_availability); + *availability_input = priv->sink_availability; + return TRUE; +} + /** SIGNALS Utility methods to emit signals from the service into the ether. @@ -212,5 +232,18 @@ void sound_service_dbus_update_sink_mute(SoundServiceDbus* obj, gboolean sink_mu priv->mute); } +void sound_service_dbus_update_sink_availability(SoundServiceDbus* obj, gboolean sink_availability) +{ + g_debug("Emitting signal: SINK_AVAILABILITY_UPDATE, with value %i", sink_availability); + + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (obj); + priv->sink_availability = sink_availability; + + g_signal_emit(obj, + signals[SINK_AVAILABLE_UPDATE], + 0, + priv->sink_availability); +} + diff --git a/src/sound-service-dbus.h b/src/sound-service-dbus.h index 1a06117..ae4953e 100644 --- a/src/sound-service-dbus.h +++ b/src/sound-service-dbus.h @@ -56,6 +56,7 @@ GType sound_service_dbus_get_type (void) G_GNUC_CONST; 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); G_END_DECLS diff --git a/src/sound-service.xml b/src/sound-service.xml index 580f0e1..12ed03e 100644 --- a/src/sound-service.xml +++ b/src/sound-service.xml @@ -5,6 +5,7 @@ <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"/> @@ -15,6 +16,11 @@ <arg type='b' name='mute_input' direction="out"/> </method> + <method name = "GetSinkAvailability"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_get_sink_availability"/> + <arg type='b' name='availability_input' direction="out"/> + </method> + <!-- Will need to hook up another signal which monitors for volume change Our respective UI element should listen to this and therefore will be updated with accurate setting--> <!-- Triggered when a sink is muted but the input has been sent to that sink --> @@ -30,6 +36,10 @@ Our respective UI element should listen to this and therefore will be updated wi <arg name="mute_value" type="b" direction="out"/> </signal> + <signal name="SinkAvailableUpdate"> + <arg name="available_value" type="b" direction="out"/> + </signal> + </interface> </node> |