aboutsummaryrefslogtreecommitdiff
path: root/src/indicator-sound.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/indicator-sound.c')
-rw-r--r--src/indicator-sound.c381
1 files changed, 248 insertions, 133 deletions
diff --git a/src/indicator-sound.c b/src/indicator-sound.c
index 34f5ed9..3867f27 100644
--- a/src/indicator-sound.c
+++ b/src/indicator-sound.c
@@ -7,7 +7,6 @@ Copyright 2010 Canonical Ltd.
Authors:
Conor Curran <conor.curran@canonical.com>
Ted Gould <ted@canonical.com>
- Cody Russell <cody.russell@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
@@ -29,8 +28,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libdbusmenu-gtk/menu.h>
#include <libido/idoscalemenuitem.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
+#include <gio/gio.h>
#include "indicator-sound.h"
#include "transport-widget.h"
@@ -39,7 +37,8 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "volume-widget.h"
#include "dbus-shared-names.h"
-#include "sound-service-client.h"
+
+#include "gen-sound-service.xml.h"
#include "common-defs.h"
typedef struct _IndicatorSoundPrivate IndicatorSoundPrivate;
@@ -48,6 +47,7 @@ struct _IndicatorSoundPrivate
{
GtkWidget* volume_widget;
GList* transport_widgets_list;
+ GDBusProxy *dbus_proxy;
};
#define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate))
@@ -81,13 +81,36 @@ static gboolean new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem
static gboolean new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
// DBUS communication
-static DBusGProxy *sound_dbus_proxy = NULL;
-static void connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer userdata);
-static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean value, 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_mute_value_from_dbus();
-static void fetch_sink_availability_from_dbus(IndicatorSound* self);
+
+static GDBusNodeInfo *node_info = NULL;
+static GDBusInterfaceInfo *interface_info = NULL;
+static void create_connection_to_service (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data);
+static void connection_changed (IndicatorServiceManager * sm,
+ gboolean connected,
+ gpointer userdata);
+static void g_signal_cb ( GDBusProxy* proxy,
+ gchar* sender_name,
+ gchar* signal_name,
+ GVariant* parameters,
+ gpointer user_data);
+
+static void react_to_signal_sink_input_while_muted (gboolean value,
+ IndicatorSound* self);
+static void react_to_signal_sink_mute_update (gboolean value,
+ IndicatorSound* self);
+static void react_to_signal_sink_availability_update (gboolean value,
+ IndicatorSound* self);
+static void fetch_state ( IndicatorSound* self );
+
+static void get_sink_mute_cb ( GObject *object,
+ GAsyncResult *res,
+ gpointer user_data );
+
+static void get_sink_availability_cb ( GObject *object,
+ GAsyncResult *res,
+ gpointer user_data );
/****Volume States 'members' ***/
static void update_state(const gint state);
@@ -138,15 +161,15 @@ indicator_sound_class_init (IndicatorSoundClass *klass)
io_class->get_menu = get_menu;
io_class->scroll = indicator_sound_scroll;
design_team_size = gtk_icon_size_register("design-team-size", 22, 22);
-
- return;
}
static void
indicator_sound_init (IndicatorSound *self)
{
self->service = NULL;
- self->service = indicator_service_manager_new_version(INDICATOR_SOUND_DBUS_NAME, INDICATOR_SOUND_DBUS_VERSION);
+ self->service = indicator_service_manager_new_version(INDICATOR_SOUND_DBUS_NAME,
+ INDICATOR_SOUND_DBUS_VERSION);
+
prepare_state_machine();
prepare_blocked_animation();
animation_id = 0;
@@ -156,13 +179,13 @@ indicator_sound_init (IndicatorSound *self)
IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
priv->volume_widget = NULL;
+ priv->dbus_proxy = NULL;
GList* t_list = NULL;
priv->transport_widgets_list = t_list;
-
+
g_signal_connect(G_OBJECT(self->service),
INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE,
G_CALLBACK(connection_changed), self);
- return;
}
static void
@@ -219,7 +242,8 @@ get_icon (IndicatorObject * io)
static GtkMenu *
get_menu (IndicatorObject * io)
{
- DbusmenuGtkMenu* menu = dbusmenu_gtkmenu_new(INDICATOR_SOUND_DBUS_NAME, INDICATOR_SOUND_DBUS_OBJECT);
+ DbusmenuGtkMenu* menu = dbusmenu_gtkmenu_new(INDICATOR_SOUND_DBUS_NAME,
+ INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH);
DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu);
g_object_set_data (G_OBJECT (client), "indicator", io);
@@ -247,7 +271,7 @@ free_the_animation_list()
static gboolean
new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
- //g_debug("indicator-sound: new_transport_bar() called ");
+ g_debug("indicator-sound: new_transport_bar() called ");
GtkWidget* bar = NULL;
IndicatorObject *io = NULL;
@@ -271,7 +295,7 @@ new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbus
static gboolean
new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
- //g_debug("indicator-sound: new_metadata_widget");
+ g_debug("indicator-sound: new_metadata_widget");
GtkWidget* metadata = NULL;
@@ -290,11 +314,10 @@ new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm
static gboolean
new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
- //g_debug("indicator-sound: new_title_widget");
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
- //g_debug ("%s (\"%s\")", __func__, dbusmenu_menuitem_property_get(newitem, DBUSMENU_TITLE_MENUITEM_NAME));
+ g_debug ("%s (\"%s\")", __func__, dbusmenu_menuitem_property_get(newitem, DBUSMENU_TITLE_MENUITEM_NAME));
GtkWidget* title = NULL;
@@ -312,7 +335,7 @@ new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
static gboolean
new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
- //g_debug("indicator-sound: new_volume_slider_widget");
+ g_debug("indicator-sound: new_volume_slider_widget");
GtkWidget* volume_widget = NULL;
IndicatorObject *io = NULL;
@@ -337,70 +360,187 @@ new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent,
dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client),
newitem,
menu_volume_item,
- parent);
- fetch_mute_value_from_dbus();
- fetch_sink_availability_from_dbus(INDICATOR_SOUND (io));
+ parent);
+ fetch_state(INDICATOR_SOUND (io));
return TRUE;
}
static void
-connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer user_data)
-{
- if (connected) {
- gboolean service_restart = FALSE;
- if (sound_dbus_proxy != NULL) {
- g_object_unref (sound_dbus_proxy);
- sound_dbus_proxy = NULL;
- service_restart = TRUE;
- }
- GError * error = NULL;
-
- DBusGConnection * sbus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
-
- sound_dbus_proxy = dbus_g_proxy_new_for_name_owner(sbus,
- INDICATOR_SOUND_DBUS_NAME,
- INDICATOR_SOUND_SERVICE_DBUS_OBJECT,
- INDICATOR_SOUND_SERVICE_DBUS_INTERFACE,
- &error);
+connection_changed (IndicatorServiceManager * sm,
+ gboolean connected,
+ gpointer user_data)
+{
+ IndicatorSound* indicator = INDICATOR_SOUND(user_data);
+ g_return_if_fail ( IS_INDICATOR_SOUND (indicator) );
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE (indicator);
+ GError *error = NULL;
+ if (connected == FALSE){
+ update_state (STATE_SINKS_NONE);
+ return;
+ //TODO: Gracefully handle disconnection
+ // do a timeout to wait for reconnection
+ // for 5 seconds and then if no connection message
+ // is received put the state at 'sink not available'
+ }
+ // If the proxy is not null and connected is true => its a reconnect,
+ // we don't need to anything, gdbus takes care of the rest - bless.
+ // just fetch the state.
+ if (priv->dbus_proxy != NULL){
+ fetch_state (indicator);
+ return;
+ }
+
+ if ( node_info == NULL ){
+ node_info = g_dbus_node_info_new_for_xml ( _sound_service,
+ &error );
if (error != NULL) {
- g_warning("Unable to get status proxy: %s", error->message);
+ g_warning( "Failed to get create interface info from xml: %s",
+ error->message );
g_error_free(error);
+ return;
}
- //g_debug("about to connect to the signals");
- dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_INPUT_WHILE_MUTED, G_TYPE_BOOLEAN, G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_INPUT_WHILE_MUTED, G_CALLBACK(catch_signal_sink_input_while_muted), 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), user_data, 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);
-
- if( service_restart == TRUE){
- fetch_mute_value_from_dbus();
- // Ensure UI is in sync with service again.
- IndicatorSound* indicator = INDICATOR_SOUND(user_data);
- fetch_sink_availability_from_dbus(indicator);
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator);
- if(priv->volume_widget != NULL){
- determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget));
- }
+ }
+
+ if (interface_info == NULL) {
+ interface_info = g_dbus_node_info_lookup_interface (node_info,
+ INDICATOR_SOUND_DBUS_INTERFACE);
+ if (interface_info == NULL) {
+ g_error("Unable to find interface '" INDICATOR_SOUND_DBUS_INTERFACE "'");
}
- }
- else{
- g_warning("Indicator has been disconnected from the service -> SHOCK HORROR");
- IndicatorSound* indicator = INDICATOR_SOUND(user_data);
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator);
-
- if(priv->volume_widget != NULL){
- g_warning("indicator still has a slider, service must have crashed");
- volume_widget_tidy_up(priv->volume_widget);
- g_object_unref(G_OBJECT(priv->volume_widget));
- priv->volume_widget = NULL;
- }
- device_available = FALSE;
+ }
+
+ g_dbus_proxy_new_for_bus( G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ interface_info,
+ INDICATOR_SOUND_DBUS_NAME,
+ INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH,
+ INDICATOR_SOUND_DBUS_INTERFACE,
+ NULL,
+ create_connection_to_service,
+ indicator );
+}
+
+static void create_connection_to_service (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ IndicatorSound *self = INDICATOR_SOUND(user_data);
+ GError *error = NULL;
+
+ g_return_if_fail( IS_INDICATOR_SOUND(self) );
+
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+
+ priv->dbus_proxy = g_dbus_proxy_new_finish(res, &error);
+
+ if (error != NULL) {
+ g_warning("Failed to get dbus proxy: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ g_signal_connect(priv->dbus_proxy, "g-signal",
+ G_CALLBACK(g_signal_cb), self);
+
+ fetch_state (self);
+}
+
+static void fetch_state (IndicatorSound* self)
+{
+
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+ if(priv->volume_widget != NULL){
+ determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget));
+ }
+
+ g_dbus_proxy_call ( priv->dbus_proxy,
+ "GetSinkMute",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)get_sink_mute_cb,
+ self);
+
+ g_dbus_proxy_call ( priv->dbus_proxy,
+ "GetSinkAvailability",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)get_sink_availability_cb,
+ self);
+
+}
+
+static void get_sink_availability_cb ( GObject *object,
+ GAsyncResult *res,
+ gpointer user_data )
+{
+ IndicatorSound* self = INDICATOR_SOUND(user_data);
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+
+ GVariant *result, *value;
+ GError *error = NULL;
+
+ result = g_dbus_proxy_call_finish ( priv->dbus_proxy,
+ res,
+ &error );
+
+ if (error != NULL) {
+ g_debug("get_sink_availability call failed: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ value = g_variant_get_child_value(result, 0);
+ device_available = g_variant_get_boolean(value);
+
+ if (device_available == FALSE) {
update_state(STATE_SINKS_NONE);
}
+
+ if(priv->volume_widget != NULL){
+ GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
+ gtk_widget_set_sensitive(slider_widget, device_available);
+ }
+
+ g_variant_unref(value);
+ g_variant_unref(result);
+}
+
+
+static void get_sink_mute_cb ( GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ IndicatorSound* self = INDICATOR_SOUND(user_data);
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+
+ GVariant *result, *value;
+ GError *error = NULL;
+ gboolean is_muted;
+ result = g_dbus_proxy_call_finish ( priv->dbus_proxy,
+ res,
+ &error );
+
+ if (error != NULL) {
+ g_debug("get_sink_mute call failed: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ value = g_variant_get_child_value(result, 0);
+ is_muted = g_variant_get_boolean(value);
+
+ if ( is_muted == TRUE ){
+ update_state(STATE_MUTED);
+ }
+
+ g_variant_unref(value);
+ g_variant_unref(result);
}
/*
@@ -550,69 +690,39 @@ reset_mute_blocking_animation()
}
+
/*******************************************************************/
-//DBus method handlers
+// DBUS Signal reactions
/*******************************************************************/
-static void
-fetch_sink_availability_from_dbus(IndicatorSound* self)
+static void g_signal_cb ( GDBusProxy* proxy,
+ gchar* sender_name,
+ gchar* signal_name,
+ GVariant* parameters,
+ gpointer user_data)
{
- g_return_if_fail(IS_INDICATOR_SOUND(self));
-
- GError * error = NULL;
- gboolean * available_input;
- available_input = g_new0(gboolean, 1);
- com_canonical_indicators_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_debug("NO DEVICE AVAILABLE");
- }
+ IndicatorSound *self = INDICATOR_SOUND(user_data);
+ g_return_if_fail ( IS_INDICATOR_SOUND(self) );
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+ g_variant_ref (parameters);
+ GVariant *value = g_variant_get_child_value (parameters, 0);
+ gboolean input = g_variant_get_boolean (value);
+ g_variant_unref (parameters);
- if(priv->volume_widget != NULL){
- GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
- gtk_widget_set_sensitive(slider_widget, device_available);
+ g_debug ( "!!! signal_cb with value %i", input);
+
+ if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_SINK_AVAILABLE_UPDATE) == 0){
+ react_to_signal_sink_availability_update ( input, self );
}
-
- g_free(available_input);
- //g_debug("IndicatorSound::fetch_sink_availability_from_dbus ->%i", device_available);
-}
-
-
-static void
-fetch_mute_value_from_dbus()
-{
- GError * error = NULL;
- gboolean *mute_input;
- mute_input = g_new0(gboolean, 1);
- com_canonical_indicators_sound_get_sink_mute(sound_dbus_proxy, mute_input, &error);
- if (error != NULL) {
- g_warning("Unable to fetch MUTE at indicator start up: %s", error->message);
- g_error_free(error);
- g_free(mute_input);
- return;
+ else if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_SINK_MUTE_UPDATE) == 0){
+ react_to_signal_sink_mute_update ( input, self );
}
- initial_mute = *mute_input;
- if (initial_mute == TRUE){
- update_state(STATE_MUTED);
+ else if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_SINK_INPUT_WHILE_MUTED) == 0){
+ react_to_signal_sink_input_while_muted ( input, self );
}
- g_free(mute_input);
- //g_debug("at the indicator start up and the MUTE returned from dbus method is %i", initial_mute);
}
-/*******************************************************************/
-//DBus signal catchers
-/*******************************************************************/
static void
-catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean block_value, gpointer userdata)
+react_to_signal_sink_input_while_muted(gboolean block_value, IndicatorSound* self)
{
//g_debug("signal caught - sink input while muted with value %i", block_value);
if (block_value == 1 && blocked_id == 0 && animation_id == 0 && blocked_animation_list != NULL) {
@@ -627,7 +737,7 @@ catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean block_value, gp
UNMUTE's force a volume update therefore icon is updated appropriately => no need for unmute handling here.
*/
static void
-catch_signal_sink_mute_update(DBusGProxy *proxy, gboolean mute_value, gpointer userdata)
+react_to_signal_sink_mute_update(gboolean mute_value, IndicatorSound* self)
{
if (mute_value == TRUE && device_available == TRUE) {
update_state(STATE_MUTED);
@@ -635,25 +745,30 @@ catch_signal_sink_mute_update(DBusGProxy *proxy, gboolean mute_value, gpointer u
reset_mute_blocking_animation();
}
//g_debug("signal caught - sink mute update with mute value: %i", mute_value);
- g_return_if_fail(IS_INDICATOR_SOUND(userdata));
- IndicatorSound* indicator = INDICATOR_SOUND(userdata);
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(indicator);
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
if(priv->volume_widget == NULL){
return;
}
GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
gtk_widget_set_sensitive(slider_widget, !mute_value);
+ if(mute_value == FALSE){
+ determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget));
+ }
}
static void
-catch_signal_sink_availability_update(DBusGProxy *proxy, gboolean available_value, gpointer userdata)
+react_to_signal_sink_availability_update(gboolean available_value, IndicatorSound* self)
{
device_available = available_value;
if (device_available == FALSE) {
update_state(STATE_SINKS_NONE);
+ return;
}
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+
+ determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget));
//g_debug("signal caught - sink availability update with value: %i", available_value);
}
@@ -724,7 +839,7 @@ key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
}
}
else if (IS_TRANSPORT_WIDGET(menuitem) == TRUE) {
- TransportWidget* transport_widget;
+ TransportWidget* transport_widget = NULL;
GList* elem;
for ( elem = priv->transport_widgets_list; elem; elem = elem->next ) {
@@ -779,7 +894,7 @@ key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
menuitem = GTK_MENU_SHELL (widget)->active_menu_item;
if (IS_TRANSPORT_WIDGET(menuitem) == TRUE) {
- TransportWidget* transport_widget;
+ TransportWidget* transport_widget = NULL;
GList* elem;
for(elem = priv->transport_widgets_list; elem; elem = elem->next) {