diff options
Diffstat (limited to 'src/sound-service-dbus.c')
-rw-r--r-- | src/sound-service-dbus.c | 336 |
1 files changed, 244 insertions, 92 deletions
diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c index 6057a29..a532c0e 100644 --- a/src/sound-service-dbus.c +++ b/src/sound-service-dbus.c @@ -3,7 +3,6 @@ * * Authors: * Conor Curran <conor.curran@canonical.com> - * Ted Gould <ted.gould@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 @@ -23,11 +22,19 @@ #endif #include <gio/gio.h> +#include <unistd.h> +#include <glib/gi18n.h> #include <libindicator/indicator-service.h> +#include <libdbusmenu-glib/server.h> +#include <libdbusmenu-glib/client.h> + +#include "sound-service-dbus.h" + #include "gen-sound-service.xml.h" #include "dbus-shared-names.h" -#include "sound-service-dbus.h" -#include "common-defs.h" +#include "pulse-manager.h" +#include "slider-menu-item.h" +#include "mute-menu-item.h" #include "pulse-manager.h" // DBUS methods @@ -50,14 +57,16 @@ static GDBusInterfaceVTable interface_table = { typedef struct _SoundServiceDbusPrivate SoundServiceDbusPrivate; struct _SoundServiceDbusPrivate { - GDBusConnection *connection; - gboolean mute; - gboolean sink_availability; + GDBusConnection* connection; + DbusmenuMenuitem* root_menuitem; + SliderMenuItem* volume_slider_menuitem; + MuteMenuItem* mute_menuitem; + SoundState current_sound_state; }; static GDBusNodeInfo * node_info = NULL; static GDBusInterfaceInfo * interface_info = NULL; - +static gboolean b_startup = TRUE; #define SOUND_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_SERVICE_DBUS_TYPE, SoundServiceDbusPrivate)) static void sound_service_dbus_class_init (SoundServiceDbusClass *klass); @@ -65,7 +74,18 @@ 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 */ +static void sound_service_dbus_build_sound_menu ( SoundServiceDbus* root, + gboolean mute_update, + gboolean availability, + gdouble volume ); +static void show_sound_settings_dialog (DbusmenuMenuitem *mi, + gpointer user_data); +static SoundState sound_service_dbus_get_state_from_volume (SoundServiceDbus* self); +static void sound_service_dbus_determine_state (SoundServiceDbus* self, + gboolean availability, + gboolean mute, + gdouble volume); + G_DEFINE_TYPE (SoundServiceDbus, sound_service_dbus, G_TYPE_OBJECT); static void @@ -108,8 +128,8 @@ sound_service_dbus_init (SoundServiceDbus *self) SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); priv->connection = NULL; - priv->mute = FALSE; - priv->sink_availability = FALSE; + + priv->current_sound_state = UNAVAILABLE; /* Fetch the session bus */ priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); @@ -134,6 +154,108 @@ sound_service_dbus_init (SoundServiceDbus *self) } } +DbusmenuMenuitem* +sound_service_dbus_create_root_item (SoundServiceDbus* self) +{ + SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); + priv->root_menuitem = dbusmenu_menuitem_new(); + g_debug("Root ID: %d", dbusmenu_menuitem_get_id(priv->root_menuitem)); + DbusmenuServer *server = dbusmenu_server_new(INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH); + dbusmenu_server_set_root (server, priv->root_menuitem); + g_object_unref (priv->root_menuitem); + establish_pulse_activities (self); + return priv->root_menuitem; +} + +static void +sound_service_dbus_build_sound_menu ( SoundServiceDbus* self, + gboolean mute_update, + gboolean availability, + gdouble volume ) +{ + SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); + + // Mute button + priv->mute_menuitem = mute_menu_item_new ( mute_update, availability); + dbusmenu_menuitem_child_append (priv->root_menuitem, + mute_menu_item_get_button (priv->mute_menuitem)); + + // Slider + priv->volume_slider_menuitem = slider_menu_item_new ( availability, volume ); + dbusmenu_menuitem_child_append (priv->root_menuitem, DBUSMENU_MENUITEM ( priv->volume_slider_menuitem )); + + // Separator + + DbusmenuMenuitem* separator = dbusmenu_menuitem_new(); + + dbusmenu_menuitem_property_set( separator, + DBUSMENU_MENUITEM_PROP_TYPE, + DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_child_append(priv->root_menuitem, separator); + g_object_unref (separator); + + // Sound preferences dialog + DbusmenuMenuitem* settings_mi = dbusmenu_menuitem_new(); + + dbusmenu_menuitem_property_set( settings_mi, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Sound Preferences...")); + dbusmenu_menuitem_child_append(priv->root_menuitem, settings_mi); + g_object_unref (settings_mi); + g_signal_connect(G_OBJECT(settings_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK(show_sound_settings_dialog), NULL); + + sound_service_dbus_determine_state (self, availability, mute_update, volume); +} + +/** +show_sound_settings_dialog: +Bring up the gnome volume preferences dialog +**/ +static void +show_sound_settings_dialog (DbusmenuMenuitem *mi, + gpointer user_data) +{ + GError * error = NULL; + if (!g_spawn_command_line_async("gnome-volume-control --page=applications", &error) && + !g_spawn_command_line_async("xfce4-mixer", &error)) + { + g_warning("Unable to show dialog: %s", error->message); + g_error_free(error); + } +} + +void +sound_service_dbus_update_pa_state ( SoundServiceDbus* self, + gboolean availability, + gboolean mute_update, + gdouble volume ) +{ + g_debug("update pa state with availability of %i, mute value of %i and a volume percent is %f", availability, mute_update, volume); + SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self); + + if (b_startup == TRUE) { + sound_service_dbus_build_sound_menu ( self, + mute_update, + availability, + volume ); + b_startup = FALSE; + return; + } + + mute_menu_item_update ( priv->mute_menuitem, + mute_update ); + slider_menu_item_update ( priv->volume_slider_menuitem, + volume ); + + mute_menu_item_enable ( priv->mute_menuitem, availability); + slider_menu_item_enable ( priv->volume_slider_menuitem, + availability ); + sound_service_dbus_determine_state (self, availability, mute_update, volume); + +} + + static void sound_service_dbus_dispose (GObject *object) { @@ -148,112 +270,142 @@ sound_service_dbus_finalize (GObject *object) return; } -/* A method has been called from our dbus inteface. Figure out what it - is and dispatch it. */ -static void -bus_method_call (GDBusConnection * connection, - const gchar * sender, - const gchar * path, - const gchar * interface, - const gchar * method, - GVariant * params, - GDBusMethodInvocation * invocation, - gpointer user_data) -{ - SoundServiceDbus* service = SOUND_SERVICE_DBUS(user_data); - g_return_if_fail ( IS_SOUND_SERVICE_DBUS(service) ); - GVariant * retval = NULL; - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (service); - - if (g_strcmp0(method, "GetSinkMute") == 0) { - g_debug("Get sink mute - sound service dbus!,about to send over mute_value of %i", priv->mute); - retval = g_variant_new ( "(b)", priv->mute); - } - else if (g_strcmp0(method, "GetSinkAvailability") == 0) { - g_debug("Get sink availability - sound service dbus!, about to send over availability_value of %i", priv->sink_availability); - retval = g_variant_new ( "(b)", priv->sink_availability); - } - else { - g_warning("Calling method '%s' on the sound service but it's unknown", method); - } - g_dbus_method_invocation_return_value(invocation, retval); +// UNTIL PA-MANAGER IS REFACTORED AND THE ACTIVESINK CLASS IS CREATED LEAVE +// THE UI ELEMENTS SEPARATELY HANDLED LIKE THIS. +void +sound_service_dbus_update_volume (SoundServiceDbus* self, + gdouble volume) +{ + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); + slider_menu_item_update (priv->volume_slider_menuitem, volume); + sound_service_dbus_update_sound_state (self, + sound_service_dbus_get_state_from_volume (self)); } +void +sound_service_dbus_update_sink_mute (SoundServiceDbus* self, + gboolean mute_update) +{ + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); + mute_menu_item_update (priv->mute_menuitem, mute_update); + SoundState state = sound_service_dbus_get_state_from_volume (self); + if (mute_update == TRUE){ + state = MUTED; + } + sound_service_dbus_update_sound_state (self, state); +} -/** -SIGNALS -Utility methods to emit signals from the service into the ether. -**/ -void sound_service_dbus_sink_input_while_muted(SoundServiceDbus* obj, - gboolean block_value) +/*------- State calculators ------------------*/ +static SoundState +sound_service_dbus_get_state_from_volume (SoundServiceDbus* self) { - g_debug("Emitting signal: SINK_INPUT_WHILE_MUTED, with block_value: %i", - block_value); - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (obj); - GVariant* v_output = g_variant_new("(b)", block_value); + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); + GVariant* v = dbusmenu_menuitem_property_get_variant (DBUSMENU_MENUITEM(priv->volume_slider_menuitem), + DBUSMENU_VOLUME_MENUITEM_LEVEL); + gdouble volume_percent = g_variant_get_double (v); - GError * error = NULL; + SoundState state = LOW_LEVEL; - g_dbus_connection_emit_signal( priv->connection, - NULL, - INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH, - INDICATOR_SOUND_DBUS_INTERFACE, - INDICATOR_SOUND_SIGNAL_SINK_INPUT_WHILE_MUTED, - v_output, - &error ); - if (error != NULL) { - g_error("Unable to emit signal 'sinkinputwhilemuted' because : %s", error->message); - g_error_free(error); - return; + if (volume_percent < 30.0 && volume_percent > 0) { + state = LOW_LEVEL; + } + else if (volume_percent < 70.0 && volume_percent >= 30.0) { + state = MEDIUM_LEVEL; + } + else if (volume_percent >= 70.0) { + state = HIGH_LEVEL; + } + else if (volume_percent == 0.0) { + state = ZERO_LEVEL; } + return state; } -void sound_service_dbus_update_sink_mute(SoundServiceDbus* obj, - gboolean sink_mute) +static void +sound_service_dbus_determine_state (SoundServiceDbus* self, + gboolean availability, + gboolean mute, + gdouble volume) { - g_debug("Emitting signal: SINK_MUTE_UPDATE, with sink mute %i", sink_mute); - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (obj); - priv->mute = sink_mute; - - GVariant* v_output = g_variant_new("(b)", sink_mute); - GError * error = NULL; - g_dbus_connection_emit_signal( priv->connection, - NULL, - INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, - INDICATOR_SOUND_DBUS_INTERFACE, - INDICATOR_SOUND_SIGNAL_SINK_MUTE_UPDATE, - v_output, - &error ); - if (error != NULL) { - g_error("Unable to emit signal 'sinkmuteupdate' because : %s", error->message); - g_error_free(error); - return; + SoundState update; + if (availability == FALSE) { + update = UNAVAILABLE; } + else if (mute == TRUE) { + update = MUTED; + } + else{ + update = sound_service_dbus_get_state_from_volume (self); + } + sound_service_dbus_update_sound_state (self, update); } -void sound_service_dbus_update_sink_availability(SoundServiceDbus* obj, - gboolean sink_availability) + +// EMIT STATE SIGNAL + +// TODO: this will be a bit messy until the pa_manager is sorted. +// And we figure out all of the edge cases. +void +sound_service_dbus_update_sound_state (SoundServiceDbus* self, + SoundState new_state) { - g_debug("Emitting signal: SinkAvailableUpdate, with %i", sink_availability); - SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (obj); - priv->sink_availability = sink_availability; - - GVariant* v_output = g_variant_new("(b)", priv->sink_availability); + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (self); + SoundState update = new_state; + // Ensure that after it has become available update the state with the current volume level + if (new_state == AVAILABLE && + mute_menu_item_is_muted (priv->mute_menuitem) == FALSE){ + update = sound_service_dbus_get_state_from_volume (self); + } + if (update != BLOCKED){ + priv->current_sound_state = update; + } + + GVariant* v_output = g_variant_new("(i)", (int)update); + GError * error = NULL; - + + g_debug ("emitting signal with value %i", (int)update); g_dbus_connection_emit_signal( priv->connection, NULL, INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH, INDICATOR_SOUND_DBUS_INTERFACE, - INDICATOR_SOUND_SIGNAL_SINK_AVAILABLE_UPDATE, - v_output, - &error ); + INDICATOR_SOUND_SIGNAL_STATE_UPDATE, + v_output, + &error ); if (error != NULL) { - g_error("Unable to emit signal 'SinkAvailableUpdate' because : %s", error->message); + g_error("Unable to emit signal 'sinkinputwhilemuted' because : %s", error->message); g_error_free(error); return; } } +//HANDLE DBUS METHOD CALLS +// TODO we will need to implement the black_list method. +static void +bus_method_call (GDBusConnection * connection, + const gchar * sender, + const gchar * path, + const gchar * interface, + const gchar * method, + GVariant * params, + GDBusMethodInvocation * invocation, + gpointer user_data) +{ + SoundServiceDbus* service = SOUND_SERVICE_DBUS(user_data); + g_return_if_fail ( IS_SOUND_SERVICE_DBUS(service) ); + GVariant * retval = NULL; + SoundServiceDbusPrivate *priv = SOUND_SERVICE_DBUS_GET_PRIVATE (service); + + if (g_strcmp0(method, "GetSoundState") == 0) { + g_debug("Get state - %i", priv->current_sound_state ); + retval = g_variant_new ( "(i)", priv->current_sound_state); + } + else { + g_warning("Calling method '%s' on the sound service but it's unknown", method); + } + g_dbus_method_invocation_return_value (invocation, retval); +} + + |