aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am10
-rw-r--r--src/common-defs.h25
-rw-r--r--src/dbus-menu-manager.c234
-rw-r--r--src/dbus-menu-manager.h34
-rw-r--r--src/dbus-shared-names.h7
-rw-r--r--src/indicator-sound.c641
-rw-r--r--src/indicator-sound.h1
-rw-r--r--src/metadata-widget.c1
-rw-r--r--src/mute-menu-item.c130
-rw-r--r--src/mute-menu-item.h59
-rw-r--r--src/pulse-manager.c54
-rw-r--r--src/pulse-manager.h3
-rw-r--r--src/slider-menu-item.c42
-rw-r--r--src/slider-menu-item.h8
-rw-r--r--src/sound-service-dbus.c324
-rw-r--r--src/sound-service-dbus.h16
-rw-r--r--src/sound-service.c12
-rw-r--r--src/sound-service.h3
-rw-r--r--src/sound-service.list2
-rw-r--r--src/sound-service.xml30
-rw-r--r--src/sound-state-manager.c388
-rw-r--r--src/sound-state-manager.h66
-rw-r--r--src/volume-widget.c3
23 files changed, 1116 insertions, 977 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 32b6928..ed64aeb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,11 +9,13 @@ soundmenulib_LTLIBRARIES = libsoundmenu.la
libsoundmenu_la_SOURCES = \
common-defs.h \
indicator-sound.h \
+ indicator-sound.c \
+ sound-state-manager.c \
+ sound-state-manager.h \
transport-widget.c \
transport-widget.h \
metadata-widget.c \
metadata-widget.h \
- indicator-sound.c \
title-widget.c \
title-widget.h \
volume-widget.c \
@@ -87,15 +89,15 @@ indicator_sound_service_SOURCES = \
common-defs.h \
sound-service.h \
sound-service.c \
- dbus-menu-manager.c \
- dbus-menu-manager.h \
pulse-manager.h \
pulse-manager.c \
sound-service-dbus.h \
sound-service-dbus.c \
slider-menu-item.h \
slider-menu-item.c \
- gen-sound-service.xml.h \
+ mute-menu-item.h \
+ mute-menu-item.c \
+ gen-sound-service.xml.h \
gen-sound-service.xml.c \
$(music_bridge_VALASOURCES:.vala=.c)
diff --git a/src/common-defs.h b/src/common-defs.h
index 8ec69e8..5458dc5 100644
--- a/src/common-defs.h
+++ b/src/common-defs.h
@@ -16,13 +16,21 @@ PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifndef __COMMON_DEFS_H__
+#define __COMMON_DEFS_H__
-/* constants used for signals on the dbus. This file is shared between client and server implementation */
-#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"
+typedef enum {
+ MUTED,
+ ZERO_LEVEL,
+ LOW_LEVEL,
+ MEDIUM_LEVEL,
+ HIGH_LEVEL,
+ BLOCKED,
+ UNAVAILABLE,
+ AVAILABLE
+}SoundState;
+
#define DBUSMENU_PROPERTY_EMPTY -1
@@ -30,6 +38,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define DBUSMENU_VOLUME_MENUITEM_TYPE "x-canonical-ido-volume-type"
#define DBUSMENU_VOLUME_MENUITEM_LEVEL "x-canonical-ido-volume-level"
+#define DBUSMENU_MUTE_MENUITEM_TYPE "x-canonical-sound-menu-mute-type"
+#define DBUSMENU_MUTE_MENUITEM_VALUE "x-canonical-sound-menu-mute-value"
+
#define DBUSMENU_TRANSPORT_MENUITEM_TYPE "x-canonical-sound-menu-player-transport-type"
#define DBUSMENU_TRANSPORT_MENUITEM_PLAY_STATE "x-canonical-sound-menu-player-transport-state"
@@ -51,4 +62,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define DBUSMENU_PLAYLISTS_MENUITEM_TYPE "x-canonical-sound-menu-player-playlists-type"
#define DBUSMENU_PLAYLISTS_MENUITEM_TITLE "x-canonical-sound-menu-player-playlists-title"
-#define DBUSMENU_PLAYLISTS_MENUITEM_PLAYLISTS "x-canonical-sound-menu-player-playlists-playlists" \ No newline at end of file
+#define DBUSMENU_PLAYLISTS_MENUITEM_PLAYLISTS "x-canonical-sound-menu-player-playlists-playlists"
+
+#endif
diff --git a/src/dbus-menu-manager.c b/src/dbus-menu-manager.c
deleted file mode 100644
index 92bfba5..0000000
--- a/src/dbus-menu-manager.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
-This service primarily controls PulseAudio and is driven by the sound indicator menu on the panel.
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Conor Curran <conor.curran@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
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <unistd.h>
-#include <glib/gi18n.h>
-
-#include <libdbusmenu-glib/server.h>
-#include <libdbusmenu-glib/client.h>
-
-#include "dbus-menu-manager.h"
-#include "sound-service-dbus.h"
-#include "pulse-manager.h"
-#include "slider-menu-item.h"
-#include "common-defs.h"
-
-#include "dbus-shared-names.h"
-
-// DBUS items
-static DbusmenuMenuitem *root_menuitem = NULL;
-static DbusmenuMenuitem *mute_all_menuitem = NULL;
-static SliderMenuItem *volume_slider_menuitem = NULL;
-static SoundServiceDbus *dbus_interface = NULL;
-
-// PULSEAUDIO
-static gboolean b_sink_available = FALSE;
-static gboolean b_all_muted = FALSE;
-static gboolean b_pulse_ready = FALSE;
-static gboolean b_startup = TRUE;
-static gdouble volume_percent = 0.0;
-
-static void set_global_mute_from_ui();
-static gboolean idle_routine (gpointer data);
-static void rebuild_sound_menu(DbusmenuMenuitem *root,
- SoundServiceDbus *service);
-static void refresh_menu();
-
-
-/*-------------------------------------------------------------------------*/
-// Public Methods
-/*-------------------------------------------------------------------------*/
-
-/**
-setup:
-**/
-DbusmenuMenuitem* dbus_menu_manager_setup()
-{
- root_menuitem = dbusmenu_menuitem_new();
- g_debug("Root ID: %d", dbusmenu_menuitem_get_id(root_menuitem));
-
- g_idle_add(idle_routine, root_menuitem);
-
- dbus_interface = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL);
-
- DbusmenuServer *server = dbusmenu_server_new(INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH);
- dbusmenu_server_set_root(server, root_menuitem);
- establish_pulse_activities(dbus_interface);
- return root_menuitem;
-}
-
-void dbus_menu_manager_update_volume(gdouble volume)
-{
- GVariant* new_volume = g_variant_new_double(volume);
- dbusmenu_menuitem_property_set_variant(DBUSMENU_MENUITEM(volume_slider_menuitem),
- DBUSMENU_VOLUME_MENUITEM_LEVEL,
- new_volume);
-}
-
-
-/**
-update_pa_state:
-**/
-void dbus_menu_manager_update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_muted, gdouble percent)
-{
- b_sink_available = sink_available;
- b_all_muted = sink_muted;
- 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);
- // Only rebuild the menu on start up...
- if (b_startup == TRUE) {
- rebuild_sound_menu(root_menuitem, dbus_interface);
- b_startup = FALSE;
- } else {
- refresh_menu();
- }
- // Emit the signals after the menus are setup/torn down
- // preserve ordering !
- sound_service_dbus_update_sink_availability(dbus_interface, sink_available);
- dbus_menu_manager_update_volume(percent);
- sound_service_dbus_update_sink_mute(dbus_interface, sink_muted);
- dbus_menu_manager_update_mute_ui(b_all_muted);
-}
-
-/**
-update_mute_ui:
-'public' method allowing the pa manager to update the mute menu item.
-**/
-void dbus_menu_manager_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") : _("Unmute"));
-}
-
-
-/*-------------------------------------------------------------------------*/
-// Private Methods
-/*-------------------------------------------------------------------------*/
-static void refresh_menu()
-{
- g_debug("in the refresh menu method");
- if (b_sink_available == FALSE || b_pulse_ready == FALSE) {
-
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem),
- DBUSMENU_MENUITEM_PROP_ENABLED,
- FALSE);
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem),
- DBUSMENU_MENUITEM_PROP_VISIBLE,
- FALSE);
- dbusmenu_menuitem_property_set_bool(mute_all_menuitem,
- DBUSMENU_MENUITEM_PROP_ENABLED,
- FALSE);
-
- } else if (b_sink_available == TRUE && b_pulse_ready == TRUE) {
-
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem),
- DBUSMENU_MENUITEM_PROP_ENABLED,
- TRUE);
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(volume_slider_menuitem),
- DBUSMENU_MENUITEM_PROP_VISIBLE,
- TRUE);
- dbusmenu_menuitem_property_set_bool(mute_all_menuitem,
- DBUSMENU_MENUITEM_PROP_ENABLED,
- TRUE);
- }
-}
-
-
-/**
-idle_routine:
-Something for glip mainloop to do when idle
-**/
-static gboolean idle_routine (gpointer data)
-{
- return FALSE;
-}
-
-
-
-/**
-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);
- }
-}
-
-/**
-rebuild_sound_menu:
-Build the DBus menu items, mute/unmute, slider, separator and sound preferences 'link'
-**/
-static void rebuild_sound_menu(DbusmenuMenuitem *root, SoundServiceDbus *service)
-{
- // Mute button
- mute_all_menuitem = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, b_all_muted == FALSE ? _("Mute") : _("Unmute"));
- g_signal_connect(G_OBJECT(mute_all_menuitem), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(set_global_mute_from_ui), NULL);
- dbusmenu_menuitem_property_set_bool(mute_all_menuitem, DBUSMENU_MENUITEM_PROP_ENABLED, b_sink_available);
-
- // Slider
- volume_slider_menuitem = slider_menu_item_new(b_sink_available, volume_percent);
- dbusmenu_menuitem_child_append(root, mute_all_menuitem);
- 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_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);
- // Separator
- DbusmenuMenuitem *separator = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
- dbusmenu_menuitem_child_append(root, separator);
-
- // Sound preferences dialog
- DbusmenuMenuitem *settings_mi = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(settings_mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Sound Preferences..."));
-
- //_("Sound Preferences..."));
- dbusmenu_menuitem_child_append(root, settings_mi);
- g_signal_connect(G_OBJECT(settings_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
- G_CALLBACK(show_sound_settings_dialog), NULL);
-}
-
-/**
-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") : _("Unmute"));
-}
-
-
diff --git a/src/dbus-menu-manager.h b/src/dbus-menu-manager.h
deleted file mode 100644
index ec2b2e2..0000000
--- a/src/dbus-menu-manager.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __INCLUDE_DBUS_MENU_MANAGER_H__
-#define __INCLUDE_DBUS_MENU_MANAGER_H__
-
-#include <libdbusmenu-glib/menuitem.h>
-
-/*
-This handles the management of the dbusmeneu items.
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Conor Curran <conor.curran@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
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-DbusmenuMenuitem* dbus_menu_manager_setup();
-void dbus_menu_manager_teardown();
-void dbus_menu_manager_update_volume(gdouble volume);
-void dbus_menu_manager_update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_muted, gdouble current_vol);
-// TODO update pa_state should incorporate the method below !
-void dbus_menu_manager_update_mute_ui(gboolean incoming_mute_value);
-
-#endif
-
diff --git a/src/dbus-shared-names.h b/src/dbus-shared-names.h
index bdc40cb..346a031 100644
--- a/src/dbus-shared-names.h
+++ b/src/dbus-shared-names.h
@@ -23,16 +23,15 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef __DBUS_SHARED_NAMES_H__
-#define __DBUS_SHARED_NAMES_H__ 1
+#define __DBUS_SHARED_NAMES_H__
#define INDICATOR_SOUND_DBUS_NAME "com.canonical.indicators.sound"
#define INDICATOR_SOUND_MENU_DBUS_OBJECT_PATH "/com/canonical/indicators/sound/menu"
#define INDICATOR_SOUND_SERVICE_DBUS_OBJECT_PATH "/com/canonical/indicators/sound/service"
#define INDICATOR_SOUND_DBUS_INTERFACE "com.canonical.indicators.sound"
#define INDICATOR_SOUND_DBUS_VERSION 0
-#define INDICATOR_SOUND_SIGNAL_SINK_INPUT_WHILE_MUTED "SinkInputWhileMuted"
-#define INDICATOR_SOUND_SIGNAL_SINK_MUTE_UPDATE "SinkMuteUpdate"
-#define INDICATOR_SOUND_SIGNAL_SINK_AVAILABLE_UPDATE "SinkAvailableUpdate"
+
+#define INDICATOR_SOUND_SIGNAL_STATE_UPDATE "SoundStateUpdate"
#endif /* __DBUS_SHARED_NAMES_H__ */
diff --git a/src/indicator-sound.c b/src/indicator-sound.c
index 3867f27..3c65a90 100644
--- a/src/indicator-sound.c
+++ b/src/indicator-sound.c
@@ -1,12 +1,8 @@
/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
Copyright 2010 Canonical Ltd.
Authors:
Conor Curran <conor.curran@canonical.com>
- Ted Gould <ted@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
@@ -20,6 +16,7 @@ PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
#include <math.h>
#include <glib.h>
#include <glib-object.h>
@@ -40,6 +37,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "gen-sound-service.xml.h"
#include "common-defs.h"
+#include "sound-state-manager.h"
typedef struct _IndicatorSoundPrivate IndicatorSoundPrivate;
@@ -47,7 +45,8 @@ struct _IndicatorSoundPrivate
{
GtkWidget* volume_widget;
GList* transport_widgets_list;
- GDBusProxy *dbus_proxy;
+ GDBusProxy *dbus_proxy;
+ SoundStateManager* state_manager;
};
#define INDICATOR_SOUND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SOUND_TYPE, IndicatorSoundPrivate))
@@ -67,18 +66,27 @@ G_DEFINE_TYPE (IndicatorSound, indicator_sound, INDICATOR_OBJECT_TYPE);
static GtkLabel * get_label (IndicatorObject * io);
static GtkImage * get_icon (IndicatorObject * io);
static GtkMenu * get_menu (IndicatorObject * io);
-static void indicator_sound_scroll (IndicatorObject* io, gint delta, IndicatorScrollDirection direction);
+static void indicator_sound_scroll (IndicatorObject* io,
+ gint delta,
+ IndicatorScrollDirection direction);
-//Slider related
-static gboolean new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+//key/moust event handlers
static gboolean key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data);
static gboolean key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data);
-static void style_changed_cb(GtkWidget *widget, gpointer user_data);
-//player widget realisation methods
-static gboolean new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
-static gboolean new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
-static gboolean new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+//custom widget realisation methods
+static gboolean new_volume_slider_widget (DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client);
+static gboolean new_transport_widget (DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client);
+static gboolean new_metadata_widget (DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client);
+static gboolean new_title_widget (DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client);
// DBUS communication
@@ -90,59 +98,6 @@ static void create_connection_to_service (GObject *source_object,
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);
-
-static const gint STATE_MUTED = 0;
-static const gint STATE_ZERO = 1;
-static const gint STATE_LOW = 2;
-static const gint STATE_MEDIUM = 3;
-static const gint STATE_HIGH = 4;
-static const gint STATE_MUTED_WHILE_INPUT = 5;
-static const gint STATE_SINKS_NONE = 6;
-
-static GHashTable *volume_states = NULL;
-static GtkImage *speaker_image = NULL;
-static gint current_state = 0;
-static gint previous_state = 0;
-
-static gboolean initial_mute ;
-static gboolean device_available;
-
-static GtkIconSize design_team_size;
-static gint blocked_id;
-static gint animation_id;
-
-static GList * blocked_animation_list = NULL;
-static GList * blocked_iter = NULL;
-static void prepare_blocked_animation();
-static gboolean fade_back_to_mute_image();
-static gboolean start_animation();
-static void reset_mute_blocking_animation();
-static void free_the_animation_list();
-
static void
indicator_sound_class_init (IndicatorSoundClass *klass)
@@ -160,7 +115,6 @@ indicator_sound_class_init (IndicatorSoundClass *klass)
io_class->get_image = get_icon;
io_class->get_menu = get_menu;
io_class->scroll = indicator_sound_scroll;
- design_team_size = gtk_icon_size_register("design-team-size", 22, 22);
}
static void
@@ -169,39 +123,29 @@ indicator_sound_init (IndicatorSound *self)
self->service = NULL;
self->service = indicator_service_manager_new_version(INDICATOR_SOUND_DBUS_NAME,
INDICATOR_SOUND_DBUS_VERSION);
-
- prepare_state_machine();
- prepare_blocked_animation();
- animation_id = 0;
- blocked_id = 0;
- initial_mute = FALSE;
- device_available = TRUE;
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;
+ priv->state_manager = g_object_new (SOUND_TYPE_STATE_MANAGER, NULL);
- g_signal_connect(G_OBJECT(self->service),
- INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE,
- G_CALLBACK(connection_changed), self);
+ g_signal_connect ( G_OBJECT(self->service),
+ INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE,
+ G_CALLBACK(connection_changed), self );
}
static void
indicator_sound_dispose (GObject *object)
{
IndicatorSound * self = INDICATOR_SOUND(object);
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
if (self->service != NULL) {
g_object_unref(G_OBJECT(self->service));
self->service = NULL;
}
- g_hash_table_destroy(volume_states);
-
- free_the_animation_list();
-
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (self));
g_list_free ( priv->transport_widgets_list );
@@ -209,7 +153,6 @@ indicator_sound_dispose (GObject *object)
return;
}
-
static void
indicator_sound_finalize (GObject *object)
{
@@ -226,14 +169,9 @@ get_label (IndicatorObject * io)
static GtkImage *
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 = indicator_image_helper(current_name);
- gtk_widget_show(GTK_WIDGET(speaker_image));
-
- return speaker_image;
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
+ gtk_widget_show( GTK_WIDGET(sound_state_manager_get_current_icon (priv->state_manager)) );
+ return sound_state_manager_get_current_icon (priv->state_manager);
}
/* Indicator based function to get the menu for the whole
@@ -251,122 +189,15 @@ get_menu (IndicatorObject * io)
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_TRANSPORT_MENUITEM_TYPE, new_transport_widget);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_METADATA_MENUITEM_TYPE, new_metadata_widget);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_TITLE_MENUITEM_TYPE, new_title_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), io);
- g_signal_connect(menu, "key-release-event", G_CALLBACK(key_release_cb), io);
+ // Note: Not ideal but all key handling needs to be managed here and then
+ // delegated to the appropriate widget.
+ g_signal_connect (menu, "key-press-event", G_CALLBACK(key_press_cb), io);
+ g_signal_connect (menu, "key-release-event", G_CALLBACK(key_release_cb), io);
return GTK_MENU(menu);
}
static void
-free_the_animation_list()
-{
- if (blocked_animation_list != NULL) {
- g_list_foreach (blocked_animation_list, (GFunc)g_object_unref, NULL);
- g_list_free(blocked_animation_list);
- blocked_animation_list = NULL;
- }
-}
-
-static gboolean
-new_transport_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
-{
- g_debug("indicator-sound: new_transport_bar() called ");
-
- GtkWidget* bar = NULL;
- IndicatorObject *io = NULL;
-
- g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
- g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
-
- bar = transport_widget_new(newitem);
- io = g_object_get_data (G_OBJECT (client), "indicator");
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
- priv->transport_widgets_list = g_list_append ( priv->transport_widgets_list, bar );
-
- GtkMenuItem *menu_transport_bar = GTK_MENU_ITEM(bar);
-
- gtk_widget_show_all(bar);
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_transport_bar, parent);
-
- return TRUE;
-}
-
-static gboolean
-new_metadata_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
-{
- g_debug("indicator-sound: new_metadata_widget");
-
- GtkWidget* metadata = NULL;
-
- g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
- g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
-
- metadata = metadata_widget_new (newitem);
- GtkMenuItem *menu_metadata_widget = GTK_MENU_ITEM(metadata);
-
- gtk_widget_show_all(metadata);
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_metadata_widget, parent);
-
- return TRUE;
-}
-
-static gboolean
-new_title_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
-{
- 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));
-
- GtkWidget* title = NULL;
-
- title = title_widget_new (newitem);
- GtkMenuItem *menu_title_widget = GTK_MENU_ITEM(title);
-
- gtk_widget_show_all(title);
-
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client),
- newitem,
- menu_title_widget, parent);
- return TRUE;
-}
-
-static gboolean
-new_volume_slider_widget(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
-{
- g_debug("indicator-sound: new_volume_slider_widget");
-
- GtkWidget* volume_widget = NULL;
- IndicatorObject *io = NULL;
-
- g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
- g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
-
- volume_widget = volume_widget_new (newitem);
- io = g_object_get_data (G_OBJECT (client), "indicator");
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
- priv->volume_widget = volume_widget;
-
- GtkWidget* ido_slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
-
- g_signal_connect(ido_slider_widget, "style-set", G_CALLBACK(style_changed_cb), NULL);
- gtk_widget_set_sensitive(ido_slider_widget,
- !initial_mute);
- gtk_widget_show_all(ido_slider_widget);
-
-
- GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget);
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client),
- newitem,
- menu_volume_item,
- parent);
- fetch_state(INDICATOR_SOUND (io));
- return TRUE;
-}
-
-
-static void
connection_changed (IndicatorServiceManager * sm,
gboolean connected,
gpointer user_data)
@@ -377,7 +208,7 @@ connection_changed (IndicatorServiceManager * sm,
GError *error = NULL;
if (connected == FALSE){
- update_state (STATE_SINKS_NONE);
+ sound_state_manager_deal_with_disconnect (priv->state_manager);
return;
//TODO: Gracefully handle disconnection
// do a timeout to wait for reconnection
@@ -388,7 +219,14 @@ connection_changed (IndicatorServiceManager * sm,
// 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);
+ g_dbus_proxy_call ( priv->dbus_proxy,
+ "GetSoundState",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)sound_state_manager_get_state_cb,
+ priv->state_manager);
return;
}
@@ -440,336 +278,117 @@ static void create_connection_to_service (GObject *source_object,
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_debug ("Connection to dbus seemed to work fine from the indicator side");
+ sound_state_manager_connect_to_dbus (priv->state_manager,
+ priv->dbus_proxy);
- 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 )
+static gboolean
+new_transport_widget (DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client)
{
- 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);
-}
+ g_debug("indicator-sound: new_transport_bar() called ");
+ GtkWidget* bar = NULL;
+ IndicatorObject *io = NULL;
-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 );
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
- if (error != NULL) {
- g_debug("get_sink_mute call failed: %s", error->message);
- g_error_free(error);
- return;
- }
+ bar = transport_widget_new(newitem);
+ io = g_object_get_data (G_OBJECT (client), "indicator");
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
+ priv->transport_widgets_list = g_list_append ( priv->transport_widgets_list, bar );
- 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);
-}
+ GtkMenuItem *menu_transport_bar = GTK_MENU_ITEM(bar);
-/*
-Prepare states Array.
-*/
-void
-prepare_state_machine()
-{
- volume_states = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
- g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MUTED), g_strdup("audio-volume-muted-panel"));
- g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_ZERO), g_strdup("audio-volume-low-zero-panel"));
- g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_LOW), g_strdup("audio-volume-low-panel"));
- g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MEDIUM), g_strdup("audio-volume-medium-panel"));
- g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_HIGH), g_strdup("audio-volume-high-panel"));
- g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT), g_strdup("audio-volume-muted-blocking-panel"));
- g_hash_table_insert(volume_states, GINT_TO_POINTER(STATE_SINKS_NONE), g_strdup("audio-output-none-panel"));
+ gtk_widget_show_all(bar);
+ dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client),
+ newitem,
+ menu_transport_bar,
+ parent);
+ return TRUE;
}
-/*
-prepare_blocked_animation:
-Prepares the array of images to be used in the blocked animation.
-Only called at startup.
-*/
-static void
-prepare_blocked_animation()
+static gboolean
+new_metadata_widget (DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client)
{
- gchar* blocked_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT));
- gchar* muted_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_MUTED));
-
- GtkImage* temp_image = indicator_image_helper(muted_name);
- GdkPixbuf* mute_buf = gtk_image_get_pixbuf(temp_image);
-
- temp_image = indicator_image_helper(blocked_name);
- GdkPixbuf* blocked_buf = gtk_image_get_pixbuf(temp_image);
-
- if (mute_buf == NULL || blocked_buf == NULL) {
- //g_debug("Don bother with the animation, the theme aint got the goods !");
- return;
- }
-
- int i;
-
- // sample 51 snapshots - range : 0-256
- for (i = 0; i < 51; i++) {
- gdk_pixbuf_composite(mute_buf, blocked_buf, 0, 0,
- gdk_pixbuf_get_width(mute_buf),
- gdk_pixbuf_get_height(mute_buf),
- 0, 0, 1, 1, GDK_INTERP_BILINEAR, MIN(255, i * 5));
- blocked_animation_list = g_list_append(blocked_animation_list, gdk_pixbuf_copy(blocked_buf));
- }
- g_object_ref_sink(mute_buf);
- g_object_unref(mute_buf);
- g_object_ref_sink(blocked_buf);
- g_object_unref(blocked_buf);
-}
+ g_debug("indicator-sound: new_metadata_widget");
-gint
-get_state()
-{
- return current_state;
-}
+ GtkWidget* metadata = NULL;
-gchar*
-get_state_image_name(gint state)
-{
- return g_hash_table_lookup(volume_states, GINT_TO_POINTER(state));
-}
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
-void
-prepare_for_tests(IndicatorObject *io)
-{
- prepare_state_machine();
- get_icon(io);
-}
+ metadata = metadata_widget_new (newitem);
+ GtkMenuItem *menu_metadata_widget = GTK_MENU_ITEM(metadata);
-void
-tidy_up_hash()
-{
- g_hash_table_destroy(volume_states);
+ gtk_widget_show_all(metadata);
+ dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client),
+ newitem, menu_metadata_widget, parent);
+ return TRUE;
}
-static void
-update_state(const gint state)
+static gboolean
+new_title_widget(DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client)
{
- previous_state = current_state;
- current_state = state;
- gchar* image_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state));
- indicator_image_helper_update(speaker_image, image_name);
-}
+ 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));
-void
-determine_state_from_volume(gdouble volume_percent)
-{
- if (device_available == FALSE)
- return;
- gint state = previous_state;
- if (volume_percent < 30.0 && volume_percent > 0) {
- state = STATE_LOW;
- } else if (volume_percent < 70.0 && volume_percent >= 30.0) {
- state = STATE_MEDIUM;
- } else if (volume_percent >= 70.0) {
- state = STATE_HIGH;
- } else if (volume_percent == 0.0) {
- state = STATE_ZERO;
- }
- update_state(state);
-}
+ GtkWidget* title = NULL;
+ title = title_widget_new (newitem);
+ GtkMenuItem *menu_title_widget = GTK_MENU_ITEM(title);
+
+ gtk_widget_show_all(title);
-static gboolean
-start_animation()
-{
- blocked_iter = blocked_animation_list;
- blocked_id = 0;
- animation_id = g_timeout_add(50, fade_back_to_mute_image, NULL);
- return FALSE;
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client),
+ newitem,
+ menu_title_widget, parent);
+ return TRUE;
}
static gboolean
-fade_back_to_mute_image()
+new_volume_slider_widget(DbusmenuMenuitem * newitem,
+ DbusmenuMenuitem * parent,
+ DbusmenuClient * client)
{
- if (blocked_iter != NULL) {
- gtk_image_set_from_pixbuf(speaker_image, blocked_iter->data);
- blocked_iter = blocked_iter->next;
- return TRUE;
- } else {
- animation_id = 0;
- //g_debug("exit from animation now\n");
- return FALSE;
- }
-}
-
-static void
-reset_mute_blocking_animation()
-{
- if (animation_id != 0) {
- //g_debug("about to remove the animation_id callback from the mainloop!!**");
- g_source_remove(animation_id);
- animation_id = 0;
- }
- if (blocked_id != 0) {
- //g_debug("about to remove the blocked_id callback from the mainloop!!**");
- g_source_remove(blocked_id);
- blocked_id = 0;
- }
-}
-
-
-
-/*******************************************************************/
-// DBUS Signal reactions
-/*******************************************************************/
-static void g_signal_cb ( GDBusProxy* proxy,
- gchar* sender_name,
- gchar* signal_name,
- GVariant* parameters,
- gpointer user_data)
-{
- IndicatorSound *self = INDICATOR_SOUND(user_data);
- g_return_if_fail ( IS_INDICATOR_SOUND(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);
-
- 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 );
- }
- else if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_SINK_MUTE_UPDATE) == 0){
- react_to_signal_sink_mute_update ( input, self );
- }
- else if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_SINK_INPUT_WHILE_MUTED) == 0){
- react_to_signal_sink_input_while_muted ( input, self );
- }
-}
+ g_debug("indicator-sound: new_volume_slider_widget");
-static void
-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) {
- gchar* image_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_MUTED_WHILE_INPUT));
- indicator_image_helper_update(speaker_image, image_name);
- blocked_id = g_timeout_add_seconds(5, start_animation, NULL);
- }
-}
+ GtkWidget* volume_widget = NULL;
+ IndicatorObject *io = NULL;
-/*
- 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.
-*/
-static void
-react_to_signal_sink_mute_update(gboolean mute_value, IndicatorSound* self)
-{
- if (mute_value == TRUE && device_available == TRUE) {
- update_state(STATE_MUTED);
- } else {
- reset_mute_blocking_animation();
- }
- //g_debug("signal caught - sink mute update with mute value: %i", mute_value);
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(self);
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
- 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));
- }
-}
+ volume_widget = volume_widget_new (newitem);
+ io = g_object_get_data (G_OBJECT (client), "indicator");
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
+ priv->volume_widget = volume_widget;
+ GtkWidget* ido_slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
-static void
-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);
+ gtk_widget_show_all(ido_slider_widget);
+ // register the style callback on this widget with state manager's style change
+ // handler (needs to remake the blocking animation for each style).
+ g_signal_connect (ido_slider_widget, "style-set",
+ G_CALLBACK(sound_state_manager_style_changed_cb),
+ priv->state_manager);
- determine_state_from_volume (volume_widget_get_current_volume(priv->volume_widget));
- //g_debug("signal caught - sink availability update with value: %i", available_value);
+ GtkMenuItem *menu_volume_item = GTK_MENU_ITEM(ido_slider_widget);
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client),
+ newitem,
+ menu_volume_item,
+ parent);
+ return TRUE;
}
/*******************************************************************/
@@ -833,7 +452,7 @@ key_press_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
break;
}
new_value = CLAMP(new_value, 0, 100);
- if (new_value != current_value && current_state != STATE_MUTED) {
+ if (new_value != current_value && sound_state_manager_get_current_state (priv->state_manager) != MUTED) {
//g_debug("Attempting to set the range from the key listener to %f", new_value);
volume_widget_update(VOLUME_WIDGET(priv->volume_widget), new_value);
}
@@ -930,25 +549,17 @@ key_release_cb(GtkWidget* widget, GdkEventKey* event, gpointer data)
return digested;
}
-static void
-style_changed_cb(GtkWidget *widget, gpointer user_data)
-{
- //g_debug("Just caught a style change event");
- update_state(current_state);
- reset_mute_blocking_animation();
- update_state(current_state);
- free_the_animation_list();
- prepare_blocked_animation();
-}
static void
-indicator_sound_scroll (IndicatorObject *io, gint delta, IndicatorScrollDirection direction)
+indicator_sound_scroll (IndicatorObject *io, gint delta,
+ IndicatorScrollDirection direction)
{
//g_debug("indicator-sound-scroll - current slider value");
+ IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
+ SoundState current_state = sound_state_manager_get_current_state (priv->state_manager);
- if (device_available == FALSE || current_state == STATE_MUTED)
+ if (current_state == UNAVAILABLE || current_state == MUTED)
return;
- IndicatorSoundPrivate* priv = INDICATOR_SOUND_GET_PRIVATE(INDICATOR_SOUND (io));
GtkWidget* slider_widget = volume_widget_get_ido_slider(VOLUME_WIDGET(priv->volume_widget));
GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)slider_widget);
diff --git a/src/indicator-sound.h b/src/indicator-sound.h
index 9f829bb..ecc38fb 100644
--- a/src/indicator-sound.h
+++ b/src/indicator-sound.h
@@ -26,7 +26,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libindicator/indicator.h>
#include <libindicator/indicator-object.h>
#include <libindicator/indicator-service-manager.h>
-#include <libindicator/indicator-image-helper.h>
#define INDICATOR_SOUND_TYPE (indicator_sound_get_type ())
#define INDICATOR_SOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SOUND_TYPE, IndicatorSound))
diff --git a/src/metadata-widget.c b/src/metadata-widget.c
index afc8a2d..a37053b 100644
--- a/src/metadata-widget.c
+++ b/src/metadata-widget.c
@@ -393,7 +393,6 @@ metadata_widget_button_press_event (GtkWidget *menuitem,
return FALSE;
}
-// TODO: Manage empty/mangled music details <unknown artist> etc.
static void
metadata_widget_property_update(DbusmenuMenuitem* item, gchar* property,
GVariant* value, gpointer userdata)
diff --git a/src/mute-menu-item.c b/src/mute-menu-item.c
new file mode 100644
index 0000000..2f40177
--- /dev/null
+++ b/src/mute-menu-item.c
@@ -0,0 +1,130 @@
+/*
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@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
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+
+#include "common-defs.h"
+#include "mute-menu-item.h"
+#include "pulse-manager.h"
+
+typedef struct _MuteMenuItemPrivate MuteMenuItemPrivate;
+
+struct _MuteMenuItemPrivate {
+ DbusmenuMenuitem* button;
+};
+
+#define MUTE_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MUTE_MENU_ITEM_TYPE, MuteMenuItemPrivate))
+
+/* Prototypes */
+static void mute_menu_item_class_init (MuteMenuItemClass *klass);
+static void mute_menu_item_init (MuteMenuItem *self);
+static void mute_menu_item_dispose (GObject *object);
+static void mute_menu_item_finalize (GObject *object);
+static void mute_menu_item_set_global_mute_from_ui (gpointer user_data);
+
+G_DEFINE_TYPE (MuteMenuItem, mute_menu_item, G_TYPE_OBJECT);
+
+static void mute_menu_item_class_init (MuteMenuItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (MuteMenuItemPrivate));
+
+ object_class->dispose = mute_menu_item_dispose;
+ object_class->finalize = mute_menu_item_finalize;
+
+ return;
+}
+
+static void mute_menu_item_init (MuteMenuItem *self)
+{
+ g_debug("Building new Mute Menu Item");
+ MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE(self);
+ priv->button = dbusmenu_menuitem_new();
+
+ g_signal_connect (G_OBJECT (priv->button),
+ DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ G_CALLBACK (mute_menu_item_set_global_mute_from_ui),
+ self);
+ return;
+}
+
+static void mute_menu_item_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (mute_menu_item_parent_class)->dispose (object);
+ return;
+}
+
+static void
+mute_menu_item_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (mute_menu_item_parent_class)->finalize (object);
+}
+
+static void
+mute_menu_item_set_global_mute_from_ui (gpointer user_data)
+{
+ g_return_if_fail (DBUSMENU_IS_MENUITEM (user_data));
+ DbusmenuMenuitem* button = DBUSMENU_MENUITEM (user_data);
+ gboolean current_value = dbusmenu_menuitem_property_get_bool (button,
+ DBUSMENU_MUTE_MENUITEM_VALUE);
+
+ gboolean new_value = !current_value;
+ // pa manager api - to be refactored
+ toggle_global_mute (new_value);
+}
+
+
+void mute_menu_item_update(MuteMenuItem* item, gboolean value_update)
+{
+ MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item);
+
+ dbusmenu_menuitem_property_set_bool (priv->button,
+ DBUSMENU_MUTE_MENUITEM_VALUE,
+ value_update);
+ dbusmenu_menuitem_property_set (priv->button,
+ DBUSMENU_MENUITEM_PROP_LABEL,
+ value_update == FALSE ? _("Mute") : _("Unmute"));
+}
+
+void mute_menu_item_enable(MuteMenuItem* item, gboolean active)
+{
+ MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item);
+
+ dbusmenu_menuitem_property_set_bool (priv->button,
+ DBUSMENU_MENUITEM_PROP_ENABLED,
+ active);
+}
+
+DbusmenuMenuitem* mute_menu_item_get_button (MuteMenuItem* item)
+{
+ MuteMenuItemPrivate* priv = MUTE_MENU_ITEM_GET_PRIVATE (item);
+ return priv->button;
+}
+
+MuteMenuItem* mute_menu_item_new (gboolean initial_update, gboolean enabled)
+{
+ MuteMenuItem *self = g_object_new (MUTE_MENU_ITEM_TYPE, NULL);
+ mute_menu_item_update (self, initial_update);
+ mute_menu_item_enable (self, enabled);
+ return self;
+}
diff --git a/src/mute-menu-item.h b/src/mute-menu-item.h
new file mode 100644
index 0000000..8240441
--- /dev/null
+++ b/src/mute-menu-item.h
@@ -0,0 +1,59 @@
+/*
+Copyright 2010 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@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
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __MUTE_MENU_ITEM_H__
+#define __MUTE_MENU_ITEM_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libdbusmenu-glib/menuitem.h>
+
+G_BEGIN_DECLS
+
+#define MUTE_MENU_ITEM_TYPE (mute_menu_item_get_type ())
+#define MUTE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTE_MENU_ITEM_TYPE, MuteMenuItem))
+#define MUTE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTE_MENU_ITEM_TYPE, MuteMenuItemClass))
+#define IS_MUTE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTE_MENU_ITEM_TYPE))
+#define IS_MUTE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTE_MENU_ITEM_TYPE))
+#define MUTE_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTE_MENU_ITEM_TYPE, MuteMenuItemClass))
+
+typedef struct _MuteMenuItem MuteMenuItem;
+typedef struct _MuteMenuItemClass MuteMenuItemClass;
+
+struct _MuteMenuItemClass {
+ GObjectClass parent_class;
+};
+
+struct _MuteMenuItem {
+ GObject parent;
+};
+
+GType mute_menu_item_get_type (void);
+
+MuteMenuItem* mute_menu_item_new ();
+
+void mute_menu_item_update (MuteMenuItem* item, gboolean update);
+void mute_menu_item_enable (MuteMenuItem* item, gboolean active);
+
+DbusmenuMenuitem* mute_menu_item_get_button (MuteMenuItem* item);
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/pulse-manager.c b/src/pulse-manager.c
index 4443044..ca008a7 100644
--- a/src/pulse-manager.c
+++ b/src/pulse-manager.c
@@ -25,7 +25,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <pulse/gccmacro.h>
#include "pulse-manager.h"
-#include "dbus-menu-manager.h"
#define RECONNECT_DELAY 5
@@ -75,7 +74,7 @@ void establish_pulse_activities(SoundServiceDbus *service)
// Establish event callback registration
pa_context_set_state_callback (pulse_context, context_state_callback, NULL);
- dbus_menu_manager_update_pa_state (FALSE, FALSE, FALSE, 0);
+ sound_service_dbus_update_pa_state (dbus_service, FALSE, FALSE, 0);
pa_context_connect (pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);
}
@@ -199,10 +198,12 @@ static void check_sink_input_while_muted_event(gint sink_index)
/* g_debug("SINKINPUTWHILEMUTED SIGNAL EVENT TO BE SENT FROM PA MANAGER - check trace for value");*/
if (default_sink_is_muted(sink_index) == TRUE) {
- sound_service_dbus_sink_input_while_muted (dbus_service, TRUE);
- } else {
- sound_service_dbus_sink_input_while_muted(dbus_service, FALSE);
+ sound_service_dbus_update_sound_state(dbus_service, BLOCKED);
}
+// Why do you need to send a false for a blocked event, it times out after 5 secs anyway
+//} else {
+ // sound_service_dbus_sink_input_while_muted(dbus_service, FALSE);
+ //}
}
static gdouble get_default_sink_volume()
@@ -223,10 +224,8 @@ static void mute_each_sink(gpointer key, gpointer value, gpointer user_data)
if (GPOINTER_TO_INT(user_data) == 1) {
sound_service_dbus_update_sink_mute(dbus_service, TRUE);
} else {
- dbus_menu_manager_update_volume(get_default_sink_volume());
+ sound_service_dbus_update_volume(dbus_service, get_default_sink_volume());
}
-
- /* g_debug("in the pulse manager: mute each sink %i", GPOINTER_TO_INT(user_data));*/
}
void toggle_global_mute(gboolean mute_value)
@@ -309,14 +308,17 @@ static void pulse_sink_info_callback(pa_context *c, const pa_sink_info *sink, in
gboolean device_available = determine_sink_availability();
if (device_available == TRUE) {
- dbus_menu_manager_update_pa_state(TRUE,
- device_available,
- default_sink_is_muted(),
- get_default_sink_volume());
+ sound_service_dbus_update_pa_state( dbus_service,
+ device_available,
+ default_sink_is_muted(),
+ get_default_sink_volume() );
} 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, default_sink_is_muted(), get_default_sink_volume());
+ sound_service_dbus_update_pa_state( dbus_service,
+ device_available,
+ default_sink_is_muted(),
+ get_default_sink_volume() );
}
} else {
/* g_debug("About to add an item to our hash");*/
@@ -346,7 +348,10 @@ static void pulse_default_sink_info_callback(pa_context *c, const pa_sink_info *
if (position < 0) {
pa_operation_unref(pa_context_get_sink_info_list(c, pulse_sink_info_callback, NULL));
} else {
- dbus_menu_manager_update_pa_state(TRUE, determine_sink_availability(), default_sink_is_muted(), get_default_sink_volume());
+ sound_service_dbus_update_pa_state(dbus_service,
+ determine_sink_availability(),
+ default_sink_is_muted(),
+ get_default_sink_volume());
}
}
}
@@ -408,18 +413,17 @@ static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, v
pa_volume_t vol = pa_cvolume_max(&s->volume);
gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM;
/* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/
- dbus_menu_manager_update_volume(volume_percent);
+ sound_service_dbus_update_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);
- dbus_menu_manager_update_mute_ui(s->mute);
if (s->mute == FALSE) {
pa_volume_t vol = pa_cvolume_max(&s->volume);
gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM;
- /* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/
- dbus_menu_manager_update_volume(volume_percent);
+ /* g_debug("Updating volume from PA manager with volume = %f", volume_percent);*/
+ sound_service_dbus_update_volume(dbus_service, volume_percent);
}
}
}
@@ -434,7 +438,7 @@ static void update_sink_info(pa_context *c, const pa_sink_info *info, int eol, v
value->base_volume = info->base_volume;
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);
+ sound_service_dbus_update_sound_state(dbus_service, AVAILABLE);
}
}
@@ -463,7 +467,7 @@ static void pulse_server_info_callback(pa_context *c,
pa_operation *operation;
if (info == NULL) {
g_warning("No server - get the hell out of here");
- dbus_menu_manager_update_pa_state(FALSE, FALSE, TRUE, 0);
+ sound_service_dbus_update_pa_state(dbus_service, FALSE, TRUE, 0);
pa_server_available = FALSE;
return;
}
@@ -493,7 +497,7 @@ static void subscribed_events_callback(pa_context *c, enum pa_subscription_event
case PA_SUBSCRIPTION_EVENT_SINK:
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
if (index == DEFAULT_SINK_INDEX)
- sound_service_dbus_update_sink_availability(dbus_service, FALSE);
+ sound_service_dbus_update_sound_state(dbus_service, UNAVAILABLE);
/* g_debug("Subscribed_events_callback - removing sink of index %i from our sink hash - keep the cache tidy !", index);*/
g_hash_table_remove(sink_hash, GINT_TO_POINTER(index));
@@ -548,10 +552,10 @@ static void context_state_callback(pa_context *c, void *userdata)
case PA_CONTEXT_FAILED:
g_warning("PA_CONTEXT_FAILED - Is PulseAudio Daemon running ?");
pa_server_available = FALSE;
- dbus_menu_manager_update_pa_state(TRUE,
- pa_server_available,
- default_sink_is_muted(),
- get_default_sink_volume());
+ sound_service_dbus_update_pa_state( dbus_service,
+ pa_server_available,
+ default_sink_is_muted(),
+ get_default_sink_volume() );
if (reconnect_idle_id == 0){
reconnect_idle_id = g_timeout_add_seconds (RECONNECT_DELAY,
diff --git a/src/pulse-manager.h b/src/pulse-manager.h
index fc01f1c..dfe1256 100644
--- a/src/pulse-manager.h
+++ b/src/pulse-manager.h
@@ -1,9 +1,6 @@
#ifndef __INCLUDE_PULSE_MANAGER_H__
#define __INCLUDE_PULSE_MANAGER_H__
/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
Copyright 2010 Canonical Ltd.
Authors:
diff --git a/src/slider-menu-item.c b/src/slider-menu-item.c
index 0f2f07b..64db277 100644
--- a/src/slider-menu-item.c
+++ b/src/slider-menu-item.c
@@ -29,7 +29,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
typedef struct _SliderMenuItemPrivate SliderMenuItemPrivate;
struct _SliderMenuItemPrivate {
- gdouble slider_value;
};
#define SLIDER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SLIDER_MENU_ITEM_TYPE, SliderMenuItemPrivate))
@@ -76,45 +75,56 @@ slider_menu_item_finalize (GObject *object)
G_OBJECT_CLASS (slider_menu_item_parent_class)->finalize (object);
}
-
static void
handle_event (DbusmenuMenuitem * mi,
const gchar * name,
GVariant * value,
guint timestamp)
{
- gdouble volume_input = 0;
/*g_debug ( "handle-event in the slider at the backend, input is of type %s",
g_variant_get_type_string(value));*/
GVariant* input = NULL;
input = value;
- g_variant_ref (input);
-
// Please note: Subject to change in future DBusmenu revisions
if (g_variant_is_of_type(value, G_VARIANT_TYPE_VARIANT) == TRUE) {
input = g_variant_get_variant(value);
}
- volume_input = g_variant_get_double(input);
+ gboolean volume_input = g_variant_get_double(input);
if (value != NULL){
set_sink_volume(volume_input);
}
- g_variant_unref (input);
}
+void slider_menu_item_update (SliderMenuItem* item,
+ gdouble update)
+{
+ // TODO
+ // Check if that variant below will leak !!!
+ GVariant* new_volume = g_variant_new_double(update);
+ dbusmenu_menuitem_property_set_variant(DBUSMENU_MENUITEM(item),
+ DBUSMENU_VOLUME_MENUITEM_LEVEL,
+ new_volume);
+}
+void slider_menu_item_enable (SliderMenuItem* item,
+ gboolean active)
+{
+ dbusmenu_menuitem_property_set_bool( DBUSMENU_MENUITEM(item),
+ DBUSMENU_MENUITEM_PROP_ENABLED,
+ active );
+}
-SliderMenuItem* slider_menu_item_new(gboolean sinks_available, gdouble start_volume)
+SliderMenuItem* slider_menu_item_new (gboolean sinks_available,
+ gdouble start_volume)
{
SliderMenuItem *self = g_object_new(SLIDER_MENU_ITEM_TYPE, NULL);
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_VOLUME_MENUITEM_TYPE);
+ dbusmenu_menuitem_property_set( DBUSMENU_MENUITEM(self),
+ DBUSMENU_MENUITEM_PROP_TYPE,
+ DBUSMENU_VOLUME_MENUITEM_TYPE );
+ slider_menu_item_update (self, start_volume);
+ slider_menu_item_enable (self, sinks_available);
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ENABLED, sinks_available);
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, sinks_available);
return self;
-}
-
-
-
-
+} \ No newline at end of file
diff --git a/src/slider-menu-item.h b/src/slider-menu-item.h
index 763944f..51336ae 100644
--- a/src/slider-menu-item.h
+++ b/src/slider-menu-item.h
@@ -45,8 +45,12 @@ struct _SliderMenuItem {
};
GType slider_menu_item_get_type (void);
-// TODO for now the volume percent param is not being used - remove once init mystery is solved
-SliderMenuItem* slider_menu_item_new(gboolean sinks_available, gdouble current_vol);
+
+void slider_menu_item_update(SliderMenuItem* item, gdouble update);
+void slider_menu_item_enable(SliderMenuItem* item, gboolean active);
+
+SliderMenuItem* slider_menu_item_new (gboolean sinks_available,
+ gdouble current_vol);
G_END_DECLS
diff --git a/src/sound-service-dbus.c b/src/sound-service-dbus.c
index 6057a29..b444a91 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,12 +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"
// DBUS methods
static void bus_method_call (GDBusConnection * connection,
@@ -50,14 +56,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 +73,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 +127,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 +153,104 @@ 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 +265,135 @@ 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);
+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)
+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 &&
+ dbusmenu_menuitem_property_get_bool ( DBUSMENU_MENUITEM(priv->mute_menuitem),
+ DBUSMENU_MUTE_MENUITEM_VALUE) == 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);
+}
+
+
diff --git a/src/sound-service-dbus.h b/src/sound-service-dbus.h
index 0d1573b..fab3549 100644
--- a/src/sound-service-dbus.h
+++ b/src/sound-service-dbus.h
@@ -3,7 +3,6 @@
*
* Authors:
* Conor Curran <conor.curran@canonical.com>
- * Cody Russell <crussell@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,6 +22,9 @@
#include <glib.h>
#include <glib-object.h>
+#include <libdbusmenu-glib/menuitem.h>
+#include "common-defs.h"
+
G_BEGIN_DECLS
@@ -51,10 +53,14 @@ struct _SoundServiceDbusClass {
GType sound_service_dbus_get_type (void) G_GNUC_CONST;
-// Utility methods to get the SIGNAL messages across into the sound-service-dbus
-void sound_service_dbus_sink_input_while_muted (SoundServiceDbus* obj, gboolean block_value);
-void sound_service_dbus_update_sink_mute(SoundServiceDbus* obj, gboolean sink_mute);
-void sound_service_dbus_update_sink_availability(SoundServiceDbus* obj, gboolean sink_availibity);
+DbusmenuMenuitem* sound_service_dbus_create_root_item (SoundServiceDbus* self);
+void sound_service_dbus_update_sound_state (SoundServiceDbus* self, SoundState new_state);
+void sound_service_dbus_update_sink_mute(SoundServiceDbus* self, gboolean sink_mute);
+void sound_service_dbus_update_volume(SoundServiceDbus* self, gdouble volume);
+void sound_service_dbus_update_pa_state ( SoundServiceDbus* root,
+ gboolean availability,
+ gboolean mute_update,
+ gdouble volume );
G_END_DECLS
diff --git a/src/sound-service.c b/src/sound-service.c
index defcb94..2cb33d3 100644
--- a/src/sound-service.c
+++ b/src/sound-service.c
@@ -1,5 +1,4 @@
/*
-This service primarily controls PulseAudio and is driven by the sound indicator menu on the panel.
Copyright 2010 Canonical Ltd.
Authors:
@@ -19,8 +18,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sound-service.h"
-#include "dbus-menu-manager.h"
+
#include "pulse-manager.h"
+#include "sound-service-dbus.h"
#include "music-player-bridge.h"
static GMainLoop *mainloop = NULL;
@@ -40,8 +40,8 @@ service_shutdown (IndicatorService *service, gpointer user_data)
{
if (mainloop != NULL) {
g_debug("Service shutdown !");
- //close_pulse_activites();
- //g_main_loop_quit(mainloop);
+ close_pulse_activites();
+ g_main_loop_quit(mainloop);
}
return;
}
@@ -64,7 +64,9 @@ main (int argc, char ** argv)
INDICATOR_SERVICE_SIGNAL_SHUTDOWN,
G_CALLBACK(service_shutdown), NULL);
- DbusmenuMenuitem* root_menuitem = dbus_menu_manager_setup();
+ SoundServiceDbus* sound_service = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL);
+
+ DbusmenuMenuitem* root_menuitem = sound_service_dbus_create_root_item(sound_service);
MusicPlayerBridge* server = music_player_bridge_new();
music_player_bridge_set_root_menu_item(server, root_menuitem);
diff --git a/src/sound-service.h b/src/sound-service.h
index e95d4c7..7c5d0c3 100644
--- a/src/sound-service.h
+++ b/src/sound-service.h
@@ -2,13 +2,10 @@
#define __INCLUDE_SOUND_SERVICE_H__
/*
-This service primarily controls PulseAudio and is driven by the sound indicator menu on the panel.
Copyright 2010 Canonical Ltd.
Authors:
Conor Curran <conor.curran@canonical.com>
- Ted Gould <ted@canonical.com>
- Cody Russell <crussell@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
diff --git a/src/sound-service.list b/src/sound-service.list
deleted file mode 100644
index ee376e9..0000000
--- a/src/sound-service.list
+++ /dev/null
@@ -1,2 +0,0 @@
-VOID:INT,BOOLEAN
-
diff --git a/src/sound-service.xml b/src/sound-service.xml
index a552d52..07c9c3d 100644
--- a/src/sound-service.xml
+++ b/src/sound-service.xml
@@ -1,31 +1,17 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/canonical/indicators/sound">
<interface name="com.canonical.indicators.sound">
- <method name = "GetSinkMute">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_get_sink_mute"/>
- <arg type='b' name='mute_input' direction="out"/>
+ <method name = "BlacklistMediaPlayer">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_blacklist_media_player"/>
+ <arg type='s' name='player_desktop_name' direction="in"/>
</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 name = "GetSoundState">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="sound_service_dbus_get_sink_state"/>
+ <arg type='i' name='current_state' 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 -->
- <signal name="SinkInputWhileMuted">
- <arg name="block_value" type="b" direction="out"/>
- </signal>
-
- <signal name="SinkMuteUpdate">
- <arg name="mute_value" type="b" direction="out"/>
+ <signal name="SoundStateUpdate">
+ <arg name="new_state" type="i" direction="out"/>
</signal>
-
- <signal name="SinkAvailableUpdate">
- <arg name="available_value" type="b" direction="out"/>
- </signal>
-
</interface>
</node>
diff --git a/src/sound-state-manager.c b/src/sound-state-manager.c
new file mode 100644
index 0000000..2ea9b1a
--- /dev/null
+++ b/src/sound-state-manager.c
@@ -0,0 +1,388 @@
+/*
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@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
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <libindicator/indicator-image-helper.h>
+#include "sound-state-manager.h"
+#include "dbus-shared-names.h"
+
+typedef struct _SoundStateManagerPrivate SoundStateManagerPrivate;
+
+struct _SoundStateManagerPrivate
+{
+ GDBusProxy* dbus_proxy;
+ GHashTable* volume_states;
+ GList* blocked_animation_list;
+ SoundState current_state;
+ GtkImage* speaker_image;
+};
+
+#define SOUND_STATE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUND_TYPE_STATE_MANAGER, SoundStateManagerPrivate))
+G_DEFINE_TYPE (SoundStateManager, sound_state_manager, G_TYPE_OBJECT);
+
+static GtkIconSize design_team_size;
+static gint blocked_id;
+static gint animation_id;
+static GList* blocked_iter = NULL;
+static gboolean can_animate = FALSE;
+
+static void sound_state_manager_prepare_blocked_animation(SoundStateManager* self);
+static gboolean sound_state_manager_start_animation (gpointer user_data);
+static gboolean sound_state_manager_fade_back_to_mute_image (gpointer user_data);
+static void sound_state_manager_reset_mute_blocking_animation (SoundStateManager* self);
+static void sound_state_manager_free_the_animation_list (SoundStateManager* self);
+static void sound_state_manager_prepare_state_image_names (SoundStateManager* self);
+static void sound_state_signal_cb ( GDBusProxy* proxy,
+ gchar* sender_name,
+ gchar* signal_name,
+ GVariant* parameters,
+ gpointer user_data );
+static gboolean sound_state_manager_can_proceed_with_blocking_animation (SoundStateManager* self);
+
+static void
+sound_state_manager_init (SoundStateManager* self)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+
+ priv->dbus_proxy = NULL;
+ priv->volume_states = NULL;
+ priv->speaker_image = NULL;
+ priv->blocked_animation_list = NULL;
+
+ sound_state_manager_prepare_state_image_names (self);
+ sound_state_manager_prepare_blocked_animation (self);
+
+ priv->current_state = UNAVAILABLE;
+ priv->speaker_image = indicator_image_helper (g_hash_table_lookup (priv->volume_states,
+ GINT_TO_POINTER(priv->current_state)));
+}
+
+static void
+sound_state_manager_finalize (GObject *object)
+{
+ /* TODO: Add deinitalization code here */
+
+ G_OBJECT_CLASS (sound_state_manager_parent_class)->finalize (object);
+}
+
+static void
+sound_state_manager_dispose (GObject *object)
+{
+ SoundStateManager* self = SOUND_STATE_MANAGER (object);
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+
+ g_hash_table_destroy (priv->volume_states);
+
+ sound_state_manager_free_the_animation_list (self);
+ G_OBJECT_CLASS (sound_state_manager_parent_class)->dispose (object);
+}
+
+
+static void
+sound_state_manager_class_init (SoundStateManagerClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = sound_state_manager_finalize;
+ object_class->dispose = sound_state_manager_dispose;
+
+ g_type_class_add_private (klass, sizeof (SoundStateManagerPrivate));
+
+ design_team_size = gtk_icon_size_register("design-team-size", 22, 22);
+}
+
+/*
+Prepare states versus images names hash.
+*/
+static void
+sound_state_manager_prepare_state_image_names (SoundStateManager* self)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+ priv->volume_states = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(MUTED), g_strdup("audio-volume-muted-panel"));
+ g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(ZERO_LEVEL), g_strdup("audio-volume-low-zero-panel"));
+ g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(LOW_LEVEL), g_strdup("audio-volume-low-panel"));
+ g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(MEDIUM_LEVEL), g_strdup("audio-volume-medium-panel"));
+ g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(HIGH_LEVEL), g_strdup("audio-volume-high-panel"));
+ g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(BLOCKED), g_strdup("audio-volume-muted-blocking-panel"));
+ g_hash_table_insert (priv->volume_states, GINT_TO_POINTER(UNAVAILABLE), g_strdup("audio-output-none-panel"));
+}
+
+/*
+prepare_blocked_animation:
+Prepares the array of images to be used in the blocked animation.
+Only called at startup.
+*/
+static void
+sound_state_manager_prepare_blocked_animation (SoundStateManager* self)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+
+ gchar* blocked_name = g_hash_table_lookup(priv->volume_states,
+ GINT_TO_POINTER(BLOCKED));
+ gchar* muted_name = g_hash_table_lookup(priv->volume_states,
+ GINT_TO_POINTER(MUTED));
+
+ GtkImage* temp_image = indicator_image_helper(muted_name);
+ GdkPixbuf* mute_buf = gtk_image_get_pixbuf(temp_image);
+
+ temp_image = indicator_image_helper(blocked_name);
+ GdkPixbuf* blocked_buf = gtk_image_get_pixbuf(temp_image);
+
+ if (mute_buf == NULL || blocked_buf == NULL) {
+ //g_debug("Don bother with the animation, the theme aint got the goods !");
+ return;
+ }
+
+ int i;
+
+ // sample 51 snapshots - range : 0-256
+ for (i = 0; i < 51; i++) {
+ gdk_pixbuf_composite(mute_buf, blocked_buf, 0, 0,
+ gdk_pixbuf_get_width(mute_buf),
+ gdk_pixbuf_get_height(mute_buf),
+ 0, 0, 1, 1, GDK_INTERP_BILINEAR, MIN(255, i * 5));
+ priv->blocked_animation_list = g_list_append(priv->blocked_animation_list,
+ gdk_pixbuf_copy(blocked_buf));
+ }
+ can_animate = TRUE;
+ g_object_ref_sink(mute_buf);
+ g_object_unref(mute_buf);
+ g_object_ref_sink(blocked_buf);
+ g_object_unref(blocked_buf);
+}
+
+
+GtkImage*
+sound_state_manager_get_current_icon (SoundStateManager* self)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+ return priv->speaker_image;
+}
+
+SoundState
+sound_state_manager_get_current_state (SoundStateManager* self)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+ return priv->current_state;
+}
+
+/**
+ * sound_state_manager_connect_to_dbus:
+ * @returns: void
+ * When ready the indicator-sound calls this method to enable state communication
+ * between the indicator and the service.
+ **/
+void
+sound_state_manager_connect_to_dbus (SoundStateManager* self, GDBusProxy* proxy)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+ priv->dbus_proxy = proxy;
+ g_debug (" here about to register for signal callback on %s", g_dbus_proxy_get_name (priv->dbus_proxy));
+ g_signal_connect (priv->dbus_proxy, "g-signal",
+ G_CALLBACK (sound_state_signal_cb), self);
+
+ g_dbus_proxy_call ( priv->dbus_proxy,
+ "GetSoundState",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)sound_state_manager_get_state_cb,
+ self);
+}
+
+void
+sound_state_manager_get_state_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data));
+ SoundStateManager* self = SOUND_STATE_MANAGER (user_data);
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_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_sound_state call failed: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ value = g_variant_get_child_value(result, 0);
+ priv->current_state = (SoundState)g_variant_get_int32(value);
+
+ gchar* image_name = g_hash_table_lookup (priv->volume_states,
+ GINT_TO_POINTER(priv->current_state) );
+ indicator_image_helper_update (priv->speaker_image, image_name);
+
+ g_variant_unref(value);
+ g_variant_unref(result);
+}
+
+void
+sound_state_manager_deal_with_disconnect (SoundStateManager* self)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+ priv->current_state = UNAVAILABLE;
+
+ gchar* image_name = g_hash_table_lookup (priv->volume_states,
+ GINT_TO_POINTER(priv->current_state) );
+ indicator_image_helper_update (priv->speaker_image, image_name);
+}
+
+static void
+sound_state_signal_cb ( GDBusProxy* proxy,
+ gchar* sender_name,
+ gchar* signal_name,
+ GVariant* parameters,
+ gpointer user_data)
+{
+ //g_debug ( "!!! sound state manager signal_cb" );
+
+ g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data));
+ SoundStateManager* self = SOUND_STATE_MANAGER (user_data);
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+
+ g_variant_ref (parameters);
+ GVariant *value = g_variant_get_child_value (parameters, 0);
+ gint update = g_variant_get_int32 (value);
+
+ //g_debug ( "!!! signal_cb with value %i", update);
+
+ priv->current_state = (SoundState)update;
+
+ g_variant_unref (parameters);
+
+ if (g_strcmp0(signal_name, INDICATOR_SOUND_SIGNAL_STATE_UPDATE) == 0){
+
+ gchar* image_name = g_hash_table_lookup (priv->volume_states,
+ GINT_TO_POINTER(priv->current_state) );
+ if (priv->current_state == BLOCKED &&
+ sound_state_manager_can_proceed_with_blocking_animation (self) == TRUE) {
+ blocked_id = g_timeout_add_seconds (4,
+ sound_state_manager_start_animation,
+ self);
+ indicator_image_helper_update (priv->speaker_image, image_name);
+
+ }
+ else{
+ indicator_image_helper_update (priv->speaker_image, image_name);
+ }
+ }
+ else {
+ g_warning ("sorry don't know what signal this is - %s", signal_name);
+ }
+
+}
+
+void
+sound_state_manager_style_changed_cb (GtkWidget *widget,
+ GtkStyle *previous_style,
+ gpointer user_data)
+{
+ g_debug("Just caught a style change event");
+ g_return_if_fail (SOUND_IS_STATE_MANAGER (user_data));
+ SoundStateManager* self = SOUND_STATE_MANAGER (user_data);
+ sound_state_manager_reset_mute_blocking_animation (self);
+ sound_state_manager_free_the_animation_list (self);
+ sound_state_manager_prepare_blocked_animation (self);
+}
+
+static void
+sound_state_manager_reset_mute_blocking_animation (SoundStateManager* self)
+{
+ if (animation_id != 0) {
+ //g_debug("about to remove the animation_id callback from the mainloop!!**");
+ g_source_remove(animation_id);
+ animation_id = 0;
+ }
+ if (blocked_id != 0) {
+ //g_debug("about to remove the blocked_id callback from the mainloop!!**");
+ g_source_remove(blocked_id);
+ blocked_id = 0;
+ }
+}
+
+static void
+sound_state_manager_free_the_animation_list (SoundStateManager* self)
+{
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+
+ if (priv->blocked_animation_list != NULL) {
+ g_list_foreach (priv->blocked_animation_list, (GFunc)g_object_unref, NULL);
+ g_list_free (priv->blocked_animation_list);
+ priv->blocked_animation_list = NULL;
+ }
+}
+
+
+static gboolean
+sound_state_manager_start_animation (gpointer userdata)
+{
+ g_return_val_if_fail (SOUND_IS_STATE_MANAGER (userdata), FALSE);
+ SoundStateManager* self = SOUND_STATE_MANAGER (userdata);
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE(self);
+
+ blocked_iter = priv->blocked_animation_list;
+ blocked_id = 0;
+ animation_id = g_timeout_add (50,
+ sound_state_manager_fade_back_to_mute_image,
+ self);
+ return FALSE;
+}
+
+static gboolean
+sound_state_manager_fade_back_to_mute_image (gpointer user_data)
+{
+ g_return_val_if_fail (SOUND_IS_STATE_MANAGER (user_data), FALSE);
+ SoundStateManager* self = SOUND_STATE_MANAGER (user_data);
+ SoundStateManagerPrivate* priv = SOUND_STATE_MANAGER_GET_PRIVATE (self);
+
+ if (blocked_iter != NULL) {
+ gtk_image_set_from_pixbuf (priv->speaker_image, blocked_iter->data);
+ blocked_iter = blocked_iter->next;
+ return TRUE;
+ } else {
+ animation_id = 0;
+ //g_debug("exit from animation now\n");
+ g_dbus_proxy_call ( priv->dbus_proxy,
+ "GetSoundState",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)sound_state_manager_get_state_cb,
+ self);
+
+ return FALSE;
+ }
+}
+
+
+// Simple static helper to determine if the coast is clear to animate
+static
+gboolean sound_state_manager_can_proceed_with_blocking_animation (SoundStateManager* self)
+{
+ return (can_animate && blocked_id == 0 && animation_id == 0 );
+}
+
diff --git a/src/sound-state-manager.h b/src/sound-state-manager.h
new file mode 100644
index 0000000..d73d5d9
--- /dev/null
+++ b/src/sound-state-manager.h
@@ -0,0 +1,66 @@
+/*
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Conor Curran <conor.curran@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
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SOUND_STATE_MANAGER_H_
+#define _SOUND_STATE_MANAGER_H_
+
+#include <glib.h>
+#include "common-defs.h"
+
+G_BEGIN_DECLS
+
+#define SOUND_TYPE_STATE_MANAGER (sound_state_manager_get_type ())
+#define SOUND_STATE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUND_TYPE_STATE_MANAGER, SoundStateManager))
+#define SOUND_STATE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUND_TYPE_STATE_MANAGER, SoundStateManagerClass))
+#define SOUND_IS_STATE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUND_TYPE_STATE_MANAGER))
+#define SOUND_IS_STATE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUND_TYPE_STATE_MANAGER))
+#define SOUND_STATE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUND_TYPE_STATE_MANAGER, SoundStateManagerClass))
+
+typedef struct _SoundStateManagerClass SoundStateManagerClass;
+typedef struct _SoundStateManager SoundStateManager;
+
+struct _SoundStateManagerClass
+{
+ GObjectClass parent_class;
+};
+
+struct _SoundStateManager
+{
+ GObject parent_instance;
+};
+
+GType sound_state_manager_get_type (void) G_GNUC_CONST;
+
+void sound_state_manager_style_changed_cb (GtkWidget *widget,
+ GtkStyle *previous_style,
+ gpointer user_data);
+GtkImage* sound_state_manager_get_current_icon (SoundStateManager* self);
+SoundState sound_state_manager_get_current_state (SoundStateManager* self);
+void sound_state_manager_connect_to_dbus (SoundStateManager* self,
+ GDBusProxy* proxy);
+void sound_state_manager_deal_with_disconnect (SoundStateManager* self);
+void sound_state_manager_get_state_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data);
+
+
+
+G_END_DECLS
+
+#endif /* _SOUND_STATE_MANAGER_H_ */
diff --git a/src/volume-widget.c b/src/volume-widget.c
index 38dc9bb..ceebec5 100644
--- a/src/volume-widget.c
+++ b/src/volume-widget.c
@@ -137,7 +137,6 @@ volume_widget_property_update( DbusmenuMenuitem* item, gchar* property,
gdouble update = g_variant_get_double (value);
//g_debug("volume-widget - update level with value %f", update);
gtk_range_set_value(range, update);
- determine_state_from_volume(update);
}
}
}
@@ -157,7 +156,6 @@ volume_widget_set_twin_item(VolumeWidget* self,
GtkWidget *slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)priv->ido_volume_slider);
GtkRange *range = (GtkRange*)slider;
gtk_range_set_value(range, initial_level);
- determine_state_from_volume(initial_level);
}
static gboolean
@@ -169,7 +167,6 @@ volume_widget_change_value_cb (GtkRange *range,
g_return_val_if_fail (IS_VOLUME_WIDGET (user_data), FALSE);
VolumeWidget* mitem = VOLUME_WIDGET(user_data);
volume_widget_update(mitem, new_value);
- determine_state_from_volume(new_value);
return FALSE;
}