aboutsummaryrefslogtreecommitdiff
path: root/src/sound-service-dbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sound-service-dbus.c')
-rw-r--r--src/sound-service-dbus.c336
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);
+}
+
+