← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~cjcurran/indicator-sound/tests_branch into lp:indicator-sound

 

Conor Curran has proposed merging lp:~cjcurran/indicator-sound/tests_branch into lp:indicator-sound.

Requested reviews:
  Indicator Applet Developers (indicator-applet-developers)


This branch contains a big refactor necessary for proper testing. It introduces the need for a dbus_menu_manager c and header living the sound-service.c just containing the main and exit functions
It also contains the start of the testing framework with tests in place for the indicator-sound and sound-service-dbus using dbus-test-runner.


-- 
https://code.launchpad.net/~cjcurran/indicator-sound/tests_branch/+merge/20642
Your team ayatana-commits is subscribed to branch lp:indicator-sound.
=== modified file 'Makefile.am'
--- Makefile.am	2010-02-11 20:47:53 +0000
+++ Makefile.am	2010-03-04 12:22:15 +0000
@@ -2,6 +2,7 @@
 SUBDIRS = \
 	src \
     data \
+    tests \
 	po
 
 EXTRA_DIST = autogen.sh

=== modified file 'configure.ac'
--- configure.ac	2010-03-04 10:56:49 +0000
+++ configure.ac	2010-03-04 12:22:15 +0000
@@ -1,5 +1,5 @@
 
-AC_INIT(src/indicator-sound.c)
+AC_INIT(indicator-sound, 0.1.2, conor.curran@xxxxxxxxxxxxx)
 
 AC_PREREQ(2.53)
 
@@ -127,6 +127,7 @@
 Makefile
 src/Makefile
 data/Makefile
+tests/Makefile
 po/Makefile.in
 ])
 

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2010-02-04 06:02:41 +0000
+++ src/Makefile.am	2010-03-04 12:22:15 +0000
@@ -8,6 +8,7 @@
 soundmenulib_LTLIBRARIES = libsoundmenu.la
 libsoundmenu_la_SOURCES = \
     common-defs.h \
+	indicator-sound.h \
 	indicator-sound.c \
 	dbus-shared-names.h \
     sound-service-client.h \
@@ -47,6 +48,8 @@
     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 \

=== added file 'src/dbus-menu-manager.c'
--- src/dbus-menu-manager.c	1970-01-01 00:00:00 +0000
+++ src/dbus-menu-manager.c	2010-03-04 12:22:15 +0000
@@ -0,0 +1,229 @@
+/*
+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@xxxxxxxxxxxxx>
+
+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 <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#include <libdbusmenu-glib/server.h>
+#include <libdbusmenu-glib/menuitem.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 "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:
+**/
+void 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_DBUS_OBJECT);
+    dbusmenu_server_set_root(server, root_menuitem);
+    establish_pulse_activities(dbus_interface);
+}
+
+/**
+teardown:
+**/
+void dbus_menu_manager_teardown()
+{
+    //TODO tidy up dbus_interface and items!
+}
+
+/**
+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
+    sound_service_dbus_update_sink_volume(dbus_interface, percent); 
+    sound_service_dbus_update_sink_mute(dbus_interface, sink_muted); 
+    dbus_menu_manager_update_mute_ui(b_all_muted);
+}
+
+/**
+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 All" : "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);        
+    }
+}
+
+
+
+/**
+
+**/
+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", &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 All" : "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);       
+    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..."));
+    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 All" : "Unmute"));
+}
+
+

=== added file 'src/dbus-menu-manager.h'
--- src/dbus-menu-manager.h	1970-01-01 00:00:00 +0000
+++ src/dbus-menu-manager.h	2010-03-04 12:22:15 +0000
@@ -0,0 +1,31 @@
+#ifndef __INCLUDE_DBUS_MENU_MANAGER_H__
+#define __INCLUDE_DBUS_MENU_MANAGER_H__
+
+/*
+This handles the management of the dbusmeneu items.
+Copyright 2010 Canonical Ltd.
+
+Authors:
+    Conor Curran <conor.curran@xxxxxxxxxxxxx>
+
+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/>.
+*/
+
+void dbus_menu_manager_setup();
+void dbus_menu_manager_teardown();
+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
+

=== modified file 'src/indicator-sound.c'
--- src/indicator-sound.c	2010-03-03 17:33:28 +0000
+++ src/indicator-sound.c	2010-03-04 12:22:15 +0000
@@ -35,7 +35,7 @@
 #include <libindicator/indicator-object.h>
 #include <libindicator/indicator-service-manager.h>
 
-
+#include "indicator-sound.h"
 #include "dbus-shared-names.h"
 #include "sound-service-client.h"
 #include "common-defs.h"
@@ -90,23 +90,23 @@
 // DBUS communication
 static DBusGProxy *sound_dbus_proxy = NULL;
 static void connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer userdata);
-static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean value, gpointer userdata);
+/*static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean value, gpointer userdata);*/
 static void catch_signal_sink_volume_update(DBusGProxy * proxy, gdouble volume_percent, gpointer userdata); 
 static void catch_signal_sink_mute_update(DBusGProxy *proxy, gboolean mute_value, gpointer userdata);
 static void fetch_volume_percent_from_dbus();
 static void fetch_mute_value_from_dbus();
 
 /****Volume States 'members' ***/
-static void prepare_state_machine();
-static void determine_state_from_volume(gdouble volume_percent);
 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 = 5;
+static const gint STATE_SINKS_NONE = 6;
+
 static GHashTable *volume_states = NULL;
 static GtkImage *speaker_image = NULL;
 static GtkWidget* primary_image = NULL;
@@ -115,6 +115,7 @@
 static gdouble initial_volume_percent = 0;
 static gboolean initial_mute = FALSE;
 
+// Construction
 static void
 indicator_sound_class_init (IndicatorSoundClass *klass)
 {
@@ -128,11 +129,11 @@
 	io_class->get_image = get_icon;
 	io_class->get_menu = get_menu;
 
-    dbus_g_object_register_marshaller (_sound_service_marshal_VOID__INT_BOOLEAN,
-                                     G_TYPE_NONE,
-                                     G_TYPE_INT,
-                                     G_TYPE_BOOLEAN,
-                                     G_TYPE_INVALID);
+/*    dbus_g_object_register_marshaller (_sound_service_marshal_VOID__INT_BOOLEAN,*/
+/*                                     G_TYPE_NONE,*/
+/*                                     G_TYPE_INT,*/
+/*                                     G_TYPE_BOOLEAN,*/
+/*                                     G_TYPE_INVALID);*/
 	return;
 }
 
@@ -147,26 +148,97 @@
     return;
 }
 
-
-/*
-Prepare states Array.
-*/
-static void prepare_state_machine()
-{
-    // TODO we need three more images
-    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-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"));
+static void
+indicator_sound_dispose (GObject *object)
+{
+	IndicatorSound * self = INDICATOR_SOUND(object);
+
+	if (self->service != NULL) {
+		g_object_unref(G_OBJECT(self->service));
+		self->service = NULL;
+	}
+    g_hash_table_destroy(volume_states);
+	G_OBJECT_CLASS (indicator_sound_parent_class)->dispose (object);
+	return;
+}
+
+static void
+indicator_sound_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (indicator_sound_parent_class)->finalize (object);
+	return;
+}
+
+static GtkLabel *
+get_label (IndicatorObject * io)
+{
+	return NULL;
+}
+
+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 = GTK_IMAGE(gtk_image_new_from_icon_name(current_name, GTK_ICON_SIZE_MENU));
+	gtk_widget_show(GTK_WIDGET(speaker_image));
+	return speaker_image;
+}
+
+/* Indicator based function to get the menu for the whole
+   applet.  This starts up asking for the parts of the menu
+   from the various services. */
+static GtkMenu *
+get_menu (IndicatorObject * io)
+{
+    DbusmenuGtkMenu *menu = dbusmenu_gtkmenu_new(INDICATOR_SOUND_DBUS_NAME, INDICATOR_SOUND_DBUS_OBJECT);    
+	DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu);	
+    dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SLIDER_MENUITEM_TYPE, new_slider_item);
+
+    // 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), NULL);         
+
+    return GTK_MENU(menu);
+}
+
+/**
+new_slider_item:
+Create a new dBusMenu Slider item.
+**/
+static gboolean new_slider_item(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);
+    
+    volume_slider = ido_scale_menu_item_new_with_range ("Volume", initial_volume_percent, 0, 100, 0.5);
+	g_object_set(volume_slider, "reverse-scroll-events", TRUE, NULL);
+
+    GtkMenuItem *menu_volume_slider = GTK_MENU_ITEM(volume_slider);
+
+	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_volume_slider, parent);
+	g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(slider_prop_change_cb), volume_slider);
+    
+    // register slider changes listening on the range
+    GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);  
+    g_signal_connect(slider, "value-changed", G_CALLBACK(value_changed_event_cb), newitem);     
+    // alternative callback mechanism which i could use again at some point.
+/*    g_signal_connect(slider, "change-value", G_CALLBACK(user_change_value_event_cb), newitem);     */
+    
+    // Set images on the ido
+    primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)volume_slider);    
+    gtk_image_set_from_icon_name(GTK_IMAGE(primary_image), g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_ZERO)), GTK_ICON_SIZE_MENU);
+    GtkWidget* secondary_image = ido_scale_menu_item_get_secondary_image((IdoScaleMenuItem*)volume_slider);                 
+    gtk_image_set_from_icon_name(GTK_IMAGE(secondary_image), g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_HIGH)), GTK_ICON_SIZE_MENU);
+
+    gtk_widget_show_all(volume_slider);
+
+	return TRUE;
 }
 
 static void
 connection_changed (IndicatorServiceManager * sm, gboolean connected, gpointer userdata)
 {
+    // TODO: This could be safer.
 	if (connected) {
 		if (sound_dbus_proxy == NULL) {
 			GError * error = NULL;
@@ -186,7 +258,7 @@
             g_debug("about to connect to the signals");
 			dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_INPUT_WHILE_MUTED, G_TYPE_BOOLEAN, G_TYPE_INVALID);
 
-			dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_INPUT_WHILE_MUTED, G_CALLBACK(catch_signal_sink_input_while_muted), NULL, NULL);
+/*			dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_INPUT_WHILE_MUTED, G_CALLBACK(catch_signal_sink_input_while_muted), NULL, NULL);*/
 			dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_VOLUME_UPDATE, G_TYPE_DOUBLE, G_TYPE_INVALID);
 			dbus_g_proxy_connect_signal(sound_dbus_proxy, SIGNAL_SINK_VOLUME_UPDATE, G_CALLBACK(catch_signal_sink_volume_update), NULL, NULL);
 			dbus_g_proxy_add_signal(sound_dbus_proxy, SIGNAL_SINK_MUTE_UPDATE, G_TYPE_BOOLEAN, G_TYPE_INVALID);
@@ -205,6 +277,82 @@
 	return;
 }
 
+
+
+
+/*
+Prepare states Array.
+*/
+void prepare_state_machine()
+{
+    // TODO we need three more images
+    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"));
+}
+
+gint get_state()
+{
+    return current_state;
+}
+
+gchar* get_state_image_name(gint state)
+{
+    return g_hash_table_lookup(volume_states, GINT_TO_POINTER(state));
+}
+
+void prepare_for_tests(IndicatorObject *io)
+{
+    prepare_state_machine();
+    get_icon(io);
+}
+
+void tidy_up_hash()
+{
+    g_hash_table_destroy(volume_states);
+}
+
+static void update_state(const gint state)
+{
+/*    g_debug("update state beginning - previous_state = %i", previous_state);*/
+
+    previous_state = current_state;
+
+/*    g_debug("update state 3rd line - previous_state = %i", previous_state);*/
+
+    current_state = state;
+    gchar* image_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state));
+    gtk_image_set_from_icon_name(speaker_image, image_name, GTK_ICON_SIZE_MENU);
+}
+
+
+void determine_state_from_volume(gdouble volume_percent)
+{
+/*    g_debug("determine_state_from_volume - previous_state = %i", previous_state);*/
+
+    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);   
+}
+ 
+
+
 static void fetch_volume_percent_from_dbus()
 {
     GError * error = NULL;
@@ -242,10 +390,10 @@
     g_debug("at the indicator start up and the MUTE returned from dbus method is %i", initial_mute);
 }
 
-static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean block_value, gpointer userdata)
-{
-    g_debug("signal caught - sink input while muted with value %i", block_value);
-}
+/*static void catch_signal_sink_input_while_muted(DBusGProxy * proxy, gboolean block_value, gpointer userdata)*/
+/*{*/
+/*    g_debug("signal caught - sink input while muted with value %i", block_value);*/
+/*}*/
 
 static void catch_signal_sink_volume_update(DBusGProxy *proxy, gdouble volume_percent, gpointer userdata)
 {
@@ -270,130 +418,6 @@
     g_debug("signal caught - sink mute update with mute value: %i", mute_value);
     gtk_widget_set_sensitive(volume_slider, !mute_value);
 }
-
-
-static void
-indicator_sound_dispose (GObject *object)
-{
-	IndicatorSound * self = INDICATOR_SOUND(object);
-
-	if (self->service != NULL) {
-		g_object_unref(G_OBJECT(self->service));
-		self->service = NULL;
-	}
-    g_hash_table_destroy(volume_states);
-	G_OBJECT_CLASS (indicator_sound_parent_class)->dispose (object);
-	return;
-}
-
-static void
-indicator_sound_finalize (GObject *object)
-{
-	G_OBJECT_CLASS (indicator_sound_parent_class)->finalize (object);
-	return;
-}
-
-static GtkLabel *
-get_label (IndicatorObject * io)
-{
-	return NULL;
-}
-
-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 = GTK_IMAGE(gtk_image_new_from_icon_name(current_name, GTK_ICON_SIZE_MENU));
-	gtk_widget_show(GTK_WIDGET(speaker_image));
-	return speaker_image;
-}
-
-static void update_state(const gint state)
-{
-/*    g_debug("update state beginning - previous_state = %i", previous_state);*/
-
-    previous_state = current_state;
-
-/*    g_debug("update state 3rd line - previous_state = %i", previous_state);*/
-
-    current_state = state;
-    gchar* image_name = g_hash_table_lookup(volume_states, GINT_TO_POINTER(current_state));
-    gtk_image_set_from_icon_name(speaker_image, image_name, GTK_ICON_SIZE_MENU);
-}
-
-
-static void determine_state_from_volume(gdouble volume_percent)
-{
-/*    g_debug("determine_state_from_volume - previous_state = %i", previous_state);*/
-
-    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);   
-}
- 
-
-/* Indicator based function to get the menu for the whole
-   applet.  This starts up asking for the parts of the menu
-   from the various services. */
-static GtkMenu *
-get_menu (IndicatorObject * io)
-{
-    DbusmenuGtkMenu *menu = dbusmenu_gtkmenu_new(INDICATOR_SOUND_DBUS_NAME, INDICATOR_SOUND_DBUS_OBJECT);    
-	DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(menu);	
-    dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_SLIDER_MENUITEM_TYPE, new_slider_item);
-
-    // 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), NULL);         
-
-    return GTK_MENU(menu);
-}
-
-/**
-new_slider_item:
-Create a new dBusMenu Slider item, register the 
-**/
-static gboolean new_slider_item(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);
-    
-    volume_slider = ido_scale_menu_item_new_with_range ("Volume", initial_volume_percent, 0, 100, 0.5);
-	g_object_set(volume_slider, "reverse-scroll-events", TRUE, NULL);
-
-    GtkMenuItem *menu_volume_slider = GTK_MENU_ITEM(volume_slider);
-
-	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, menu_volume_slider, parent);
-	g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(slider_prop_change_cb), volume_slider);
-    
-    // register slider changes listening on the range
-    GtkWidget* slider = ido_scale_menu_item_get_scale((IdoScaleMenuItem*)volume_slider);  
-    g_signal_connect(slider, "value-changed", G_CALLBACK(value_changed_event_cb), newitem);     
-    // alternative callback mechanism which i could use again at some point.
-/*    g_signal_connect(slider, "change-value", G_CALLBACK(user_change_value_event_cb), newitem);     */
-    
-    // Set images on the ido
-    primary_image = ido_scale_menu_item_get_primary_image((IdoScaleMenuItem*)volume_slider);    
-    gtk_image_set_from_icon_name(GTK_IMAGE(primary_image), g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_ZERO)), GTK_ICON_SIZE_MENU);
-    GtkWidget* secondary_image = ido_scale_menu_item_get_secondary_image((IdoScaleMenuItem*)volume_slider);                 
-    gtk_image_set_from_icon_name(GTK_IMAGE(secondary_image), g_hash_table_lookup(volume_states, GINT_TO_POINTER(STATE_HIGH)), GTK_ICON_SIZE_MENU);
-
-    gtk_widget_show_all(volume_slider);
-
-	return TRUE;
-}
-
 /**
 slider_prop_change_cb:
 Whenever we have a property change on a DbusmenuMenuitem this will be called. 

=== added file 'src/indicator-sound.h'
--- src/indicator-sound.h	1970-01-01 00:00:00 +0000
+++ src/indicator-sound.h	2010-03-04 12:22:15 +0000
@@ -0,0 +1,35 @@
+#ifndef __INCLUDE_INDICATOR_SOUND_H__
+#define __INCLUDE_INDICATOR_SOUND_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:
+    Conor Curran <conor.curra@xxxxxxxxxxxxx>
+    Ted Gould <ted@xxxxxxxxxxxxx>
+
+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/>.
+*/
+
+// Essentially these are all exported to faciltiate testing
+void prepare_state_machine();
+void determine_state_from_volume(gdouble volume_percent);
+gint get_state();
+gchar* get_state_image_name(gint state);
+void prepare_for_tests(IndicatorObject * io);
+void tidy_up_hash();
+
+#endif

=== modified file 'src/pulse-manager.c'
--- src/pulse-manager.c	2010-02-26 14:40:28 +0000
+++ src/pulse-manager.c	2010-03-04 12:22:15 +0000
@@ -26,8 +26,7 @@
 #include <pulse/gccmacro.h>
 
 #include "pulse-manager.h"
-#include "sound-service.h"
-
+#include "dbus-menu-manager.h"
 
 static GHashTable *sink_hash = NULL;
 static SoundServiceDbus *dbus_service = NULL;
@@ -68,10 +67,17 @@
 
     // Establish event callback registration
 	pa_context_set_state_callback(pulse_context, context_state_callback, NULL);
+<<<<<<< TREE
     // BUILD MENU ANYWHO - it will be updated
     update_pa_state(FALSE, FALSE, FALSE, 0);
 
 	pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);    
+=======
+    // BUILD MENU ANYWHO - it will be updated
+    dbus_menu_manager_update_pa_state(FALSE, FALSE, FALSE, 0);
+
+	pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);    
+>>>>>>> MERGE-SOURCE
 }
 
 void close_pulse_activites()
@@ -87,6 +93,7 @@
     g_debug("I just closed communication with Pulse");
 }
 
+<<<<<<< TREE
 /** 
 reconnect_to_pulse()
 In the event of Pulseaudio flapping in the wind handle gracefully without
@@ -111,6 +118,32 @@
     update_pa_state(FALSE, FALSE, FALSE, 0);
 	pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);        
 }
+=======
+/** 
+reconnect_to_pulse()
+In the event of Pulseaudio flapping in the wind handle gracefully without
+memory leaks !
+*/
+static void reconnect_to_pulse()
+{
+    // reset
+    if (pulse_context != NULL){
+        g_debug("freeing the pulse context");
+ 	    pa_context_unref(pulse_context);
+        pulse_context = NULL;
+   	}
+    g_hash_table_destroy(sink_hash);
+
+    // reconnect
+	pulse_context = pa_context_new(pa_glib_mainloop_get_api(pa_main_loop), "ayatana.indicator.sound");
+	g_assert(pulse_context);   
+    sink_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_sink_info);
+    // 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);
+	pa_context_connect(pulse_context, NULL, PA_CONTEXT_NOFAIL, NULL);        
+}
+>>>>>>> MERGE-SOURCE
 
 static void destroy_sink_info(void *value)
 {
@@ -276,12 +309,15 @@
         gboolean device_available = determine_sink_availability();
         if(device_available == TRUE)
         {
-            update_pa_state(TRUE, device_available, default_sink_is_muted(), get_default_sink_volume()); 
+            dbus_menu_manager_update_pa_state(TRUE, 
+                                              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 ...");
-            update_pa_state(FALSE, device_available, TRUE, 0); 
+            dbus_menu_manager_update_pa_state(FALSE, device_available, TRUE, 0); 
         }
     }
     else{
@@ -322,7 +358,7 @@
         }
         else
         {
-            update_pa_state(TRUE, determine_sink_availability(), default_sink_is_muted(), get_default_sink_volume());             
+            dbus_menu_manager_update_pa_state(TRUE, determine_sink_availability(), default_sink_is_muted(), get_default_sink_volume());             
         }    
     }
 }
@@ -385,7 +421,7 @@
             {     
                 g_debug("Updating Mute from PA manager with mute = %i", s->mute);
                 sound_service_dbus_update_sink_mute(dbus_service, s->mute);
-                update_mute_ui(s->mute);
+                dbus_menu_manager_update_mute_ui(s->mute);
                 if(s->mute == FALSE){
                     pa_volume_t vol = pa_cvolume_avg(&s->volume);
                     gdouble volume_percent = ((gdouble) vol * 100) / PA_VOLUME_NORM;
@@ -421,7 +457,7 @@
     if (info == NULL)
     {
         g_warning("No server - get the hell out of here");
-        update_pa_state(FALSE, FALSE, TRUE, 0); 
+        dbus_menu_manager_update_pa_state(FALSE, FALSE, TRUE, 0); 
         pa_server_available = FALSE;
         return;    
     }

=== modified file 'src/pulse-manager.h'
--- src/pulse-manager.h	2010-02-11 15:19:22 +0000
+++ src/pulse-manager.h	2010-03-04 12:22:15 +0000
@@ -1,3 +1,5 @@
+#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.
@@ -21,7 +23,6 @@
 */
 
 
-
 #include <pulse/pulseaudio.h>
 #include <glib.h>
 #include "sound-service-dbus.h"
@@ -47,4 +48,5 @@
 void toggle_global_mute(gboolean mute_value); 
 void close_pulse_activites();
 
+#endif
 

=== modified file 'src/sound-service-dbus.c'
--- src/sound-service-dbus.c	2010-02-16 16:37:27 +0000
+++ src/sound-service-dbus.c	2010-03-04 12:22:15 +0000
@@ -29,8 +29,7 @@
 #include "sound-service-marshal.h"
 #include "pulse-manager.h"
 
-// DBUS methods - 
-// TODO - other should be static and moved from the header to here
+// DBUS methods 
 static gboolean sound_service_dbus_get_sink_volume(SoundServiceDbus* service, gdouble* volume_percent_input, GError** gerror);
 static gboolean sound_service_dbus_get_sink_mute(SoundServiceDbus* service, gboolean* mute_input, GError** gerror);
 static void sound_service_dbus_set_sink_volume(SoundServiceDbus* service, const guint volume_percent, GError** gerror);
@@ -41,7 +40,6 @@
 
 struct _SoundServiceDbusPrivate
 {
-    DBusGConnection *system_bus;
     DBusGConnection *connection;
     gdouble         volume_percent;
     gboolean        mute;
@@ -50,7 +48,7 @@
 
 /* Signals */
 enum {
-  SINK_INPUT_WHILE_MUTED,  
+  SINK_INPUT_WHILE_MUTED,
   SINK_VOLUME_UPDATE,
   SINK_MUTE_UPDATE,
   LAST_SIGNAL
@@ -116,20 +114,18 @@
     GError *error = NULL;
     SoundServiceDbusPrivate * priv = SOUND_SERVICE_DBUS_GET_PRIVATE(self);
 
-	priv->system_bus = NULL;
 	priv->connection = NULL;
     priv->volume_percent = 0;
 
-    /* Get the system bus */
-    priv->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
-	/* Put the object on DBus */
+	/* Fetch the session bus */
 	priv->connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
 
 	if (error != NULL) {
-		g_error("Unable to connect to the session bus when creating application indicator: %s", error->message);
+		g_error("sound-service-dbus:Unable to connect to the session bus when creating indicator sound service : %s", error->message);
 		g_error_free(error);
 		return;
 	}
+    /* register the service on it */
 	dbus_g_connection_register_g_object(priv->connection,
 	                                    "/org/ayatana/indicator/sound/service",
 	                                    G_OBJECT(self));

=== modified file 'src/sound-service.c'
--- src/sound-service.c	2010-03-03 17:40:55 +0000
+++ src/sound-service.c	2010-03-04 12:22:15 +0000
@@ -19,15 +19,13 @@
 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 "sound-service.h"
-#include "sound-service-dbus.h" 
+#include "dbus-menu-manager.h"
 #include "pulse-manager.h"
-#include "slider-menu-item.h"
-#include "common-defs.h"
-
-
-// GTK + DBUS
+
 static GMainLoop *mainloop = NULL;
+<<<<<<< TREE
 static DbusmenuMenuitem *root_menuitem = NULL;
 static DbusmenuMenuitem *mute_all_menuitem = NULL;
 static SliderMenuItem *volume_slider_menuitem = NULL;
@@ -130,6 +128,18 @@
 /* When the service interface starts to shutdown, we
    should follow it. - 
 */
+=======
+
+/**********************************************************************************************************************/
+//    Init and exit functions
+/**********************************************************************************************************************/
+
+/**
+service_shutdown:
+When the service interface starts to shutdown, we
+should follow it. 
+**/
+>>>>>>> MERGE-SOURCE
 void
 service_shutdown (IndicatorService *service, gpointer user_data)
 {
@@ -137,12 +147,13 @@
 	if (mainloop != NULL) {
 		g_debug("Service shutdown !");
         // TODO: uncomment for release !!
-        close_pulse_activites();
-        g_main_loop_quit(mainloop);
+/*        close_pulse_activites();*/
+/*        g_main_loop_quit(mainloop);*/
 	}
 	return;
 }
 
+<<<<<<< TREE
 void update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_muted, gdouble percent)
 {
     b_sink_available = sink_available;
@@ -198,6 +209,11 @@
 
 /* Main, is well, main.  It brings everything up and throws
    us into the mainloop of no return. Some refactoring needed.*/
+=======
+/**
+main: 
+**/
+>>>>>>> MERGE-SOURCE
 int
 main (int argc, char ** argv)
 {
@@ -213,16 +229,7 @@
 	                 INDICATOR_SERVICE_SIGNAL_SHUTDOWN,
 	                 G_CALLBACK(service_shutdown), NULL);    
 
-    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_DBUS_OBJECT);
-    dbusmenu_server_set_root(server, root_menuitem);
-    establish_pulse_activities(dbus_interface);
+    dbus_menu_manager_setup();
 
     // Run the loop
     mainloop = g_main_loop_new(NULL, FALSE);

=== modified file 'src/sound-service.h'
--- src/sound-service.h	2010-02-08 19:19:07 +0000
+++ src/sound-service.h	2010-03-04 12:22:15 +0000
@@ -27,13 +27,6 @@
 #include <unistd.h>
 #include <glib/gi18n.h>
 
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
-
-#include <libdbusmenu-glib/server.h>
-#include <libdbusmenu-glib/menuitem.h>
-#include <libdbusmenu-glib/client.h>
-
 #include <libindicator/indicator-service.h>
 
 #include "dbus-shared-names.h"
@@ -41,7 +34,5 @@
 // ENTRY AND EXIT POINTS
 void service_shutdown(IndicatorService * service, gpointer user_data);
 int main (int argc, char ** argv);
-void update_pa_state(gboolean pa_state, gboolean sink_available, gboolean sink_muted, gdouble current_vol);
-void update_mute_ui(gboolean incoming_mute_value);
+
 #endif
-

=== added directory 'tests'
=== added file 'tests/Makefile.am'
--- tests/Makefile.am	1970-01-01 00:00:00 +0000
+++ tests/Makefile.am	2010-03-04 12:22:15 +0000
@@ -0,0 +1,95 @@
+
+check_PROGRAMS = \
+	test-indicator-sound \
+	test-indicator-sound-dbus-client \
+	test-indicator-sound-dbus-server 
+
+TESTS =
+DISTCLEANFILES = $(TESTS)
+
+#########################################
+##  test-indicator-sound
+#########################################
+test_indicator_sound_SOURCES = \
+	test-indicator-sound.c \
+    $(top_builddir)/src/indicator-sound.c
+    
+test_indicator_sound_CFLAGS = \
+	$(APPLET_CFLAGS) \
+	-Wall -Werror \
+	-I$(srcdir) \
+	-DTOP_BUILD_DIR="\"${abs_top_builddir}\""
+
+test_indicator_sound_LDADD = \
+	$(APPLET_LIBS) 
+
+
+#########################################
+##  test-indicator-sound-dbus-client
+#########################################
+test_indicator_sound_dbus_client_SOURCES = \
+	test-defines.h \
+	test-indicator-sound-dbus-client.c 
+
+test_indicator_sound_dbus_client_CFLAGS = \
+	$(SOUNDSERVICE_CFLAGS) \
+	-Wall -Werror \
+	-I$(srcdir) 
+
+test_indicator_sound_dbus_client_LDADD = \
+	$(SOUNDSERVICE_LIBS)
+
+########################################
+#  test-indicator-sound-dbus-server
+########################################
+test_indicator_sound_dbus_server_SOURCES = \
+	test-defines.h \
+    test-indicator-sound-dbus-server.c \
+    $(top_builddir)/src/sound-service-dbus.c \
+    $(top_builddir)/src/pulse-manager.c \
+    $(top_builddir)/src/slider-menu-item.c \
+    $(top_builddir)/src/dbus-menu-manager.c
+
+test_indicator_sound_dbus_server_CFLAGS = \
+    $(SOUNDSERVICE_CFLAGS) \
+	-Wall -Werror \
+	-I$(srcdir) 
+
+test_indicator_sound_dbus_server_LDADD = \
+	$(SOUNDSERVICE_LIBS) 
+
+
+#########################################
+##  Actual tests
+#########################################
+
+XML_REPORT   = indicator-sound-check-results.xml
+HTML_REPORT  = indicator-sound-check-results.html
+
+indicator-sound-tests: indicator-sound-tests-gtester Makefile.am
+	@echo "#!/bin/sh" > $@
+	@echo $(DBUS_RUNNER) --task ./indicator-sound-tests-gtester >> $@
+	@chmod +x $@
+
+indicator-sound-tests-gtester: test-indicator-sound Makefile.am
+	@echo "#!/bin/sh" > $@
+	@echo gtester -k --verbose -o=$(XML_REPORT) ./test-indicator-sound >> $@
+	@chmod +x $@
+
+TESTS += indicator-sound-tests
+
+DISTCLEANFILES += $(XML_REPORT) $(HTML_REPORT) indicator-sound-tests-gtester
+
+DBUS_RUNNER=dbus-test-runner --dbus-config /usr/share/dbus-test-runner/session.conf
+
+test-indicator-sound-dbus: test-indicator-sound-dbus-client test-indicator-sound-dbus-server Makefile.am
+	@echo "#!/bin/sh" > test-indicator-sound-dbus
+	@echo $(DBUS_RUNNER) --task ./test-indicator-sound-dbus-client --task-name Client --task ./test-indicator-sound-dbus-server --task-name Server --ignore-return >> test-indicator-sound-dbus
+	@chmod +x test-indicator-sound-dbus
+
+TESTS += test-indicator-sound-dbus
+
+
+
+
+

=== added file 'tests/run-xvfb.sh'
--- tests/run-xvfb.sh	1970-01-01 00:00:00 +0000
+++ tests/run-xvfb.sh	2010-03-04 12:22:15 +0000
@@ -0,0 +1,8 @@
+if [ "$DISPLAY" == "" ]; then
+Xvfb -ac -noreset -screen 0 800x600x16 -help 2>/dev/null 1>&2
+XID=`for id in 101 102 103 104 105 106 107 197 199 211 223 227 293 307 308 309 310 311 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 4703 4721 4723 4729 4733 4751 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 ; do test -e /tmp/.X$id-lock || { echo $id; exit 0; }; done; exit 1`
+{ Xvfb -ac -noreset -screen 0 800x600x16 :$XID -screen 0 800x600x16 -nolisten tcp -auth /dev/null >/dev/null 2>&1 & trap "kill -15 $! " 0 HUP INT QUIT TRAP USR1 PIPE TERM ; } || { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; }
+DISPLAY=:$XID
+export DISPLAY
+echo Setting display: $DISPLAY
+fi

=== added file 'tests/test-defines.h'
--- tests/test-defines.h	1970-01-01 00:00:00 +0000
+++ tests/test-defines.h	2010-03-04 12:22:15 +0000
@@ -0,0 +1,24 @@
+/*
+Testing defines to be shared between various tests.
+
+Copyright 2010 Canonical Ltd.
+
+Authors:
+    Conor Curran <conor.curran@xxxxxxxxxxxxx>
+    Ted Gould <ted@xxxxxxxxxxxxx>
+
+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/>.
+*/
+
+#define  TEST_MUTE                  FALSE
+

=== added file 'tests/test-indicator-sound-dbus-client.c'
--- tests/test-indicator-sound-dbus-client.c	1970-01-01 00:00:00 +0000
+++ tests/test-indicator-sound-dbus-client.c	2010-03-04 12:22:15 +0000
@@ -0,0 +1,112 @@
+/*
+Tests for the libappindicator library that are over DBus.  This is
+the client side of those tests.
+
+Copyright 2010 Canonical Ltd.
+
+Authors:
+    Conor Curran <conor.curran@xxxxxxxxxxxxx>
+    Ted Gould <ted@xxxxxxxxxxxxx>
+
+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 <glib.h>
+#include <dbus/dbus-glib.h>
+#include "../src/dbus-shared-names.h"
+#include "test-defines.h"
+
+static GMainLoop * mainloop = NULL;
+static gboolean passed = TRUE;
+
+static void
+fetch_mute_cb (DBusGProxy * proxy, DBusGProxyCall * call, void * data)
+{
+	GError * error = NULL;
+	GValue value = {0};
+
+	if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
+		g_warning("Getting mute failed: %s", error->message);
+		g_error_free(error);
+		passed = FALSE;
+		return;
+	}
+
+	if (TEST_MUTE != g_value_get_boolean(&value)) {
+		g_debug("Mute vale Returned: FAILED");
+		passed = FALSE;
+	} else {
+		g_debug("Property ID Returned: PASSED");
+	}
+	return;
+}
+
+
+gboolean
+kill_func (gpointer userdata)
+{
+	g_main_loop_quit(mainloop);
+	g_warning("Forced to Kill");
+	passed = FALSE;
+	return FALSE;
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+	g_type_init();
+
+	g_usleep(500000);
+
+	GError * error = NULL;
+	DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+	if (error != NULL) {
+		g_error("Unable to get session bus: %s", error->message);
+		return 1;
+	}
+
+	DBusGProxy * props = dbus_g_proxy_new_for_name_owner(session_bus,
+                                                         INDICATOR_SOUND_DBUS_NAME,
+														 INDICATOR_SOUND_SERVICE_DBUS_OBJECT,
+														 INDICATOR_SOUND_SERVICE_DBUS_INTERFACE,
+                                                         &error);
+/*	                                                     ":1.0",*/
+/*	                                                     "/need/a/path",*/
+/*	                                                     DBUS_INTERFACE_PROPERTIES,*/
+/*	                                                     &error);*/
+	if (error != NULL) {
+		g_error("Unable to get property proxy: %s", error->message);
+		return 1;
+	}
+
+	dbus_g_proxy_begin_call (props,
+	                         "GetSinkMute",
+	                         fetch_mute_cb,
+	                         NULL, NULL,
+	                         G_TYPE_INVALID);
+
+	g_timeout_add_seconds(2, kill_func, NULL);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+	g_main_loop_run(mainloop);
+
+	if (passed) {
+		g_debug("Quiting");
+		return 0;
+	} else {
+		g_debug("Quiting as we're a failure");
+		return 1;
+	}
+	return 0;
+}

=== added file 'tests/test-indicator-sound-dbus-server.c'
--- tests/test-indicator-sound-dbus-server.c	1970-01-01 00:00:00 +0000
+++ tests/test-indicator-sound-dbus-server.c	2010-03-04 12:22:15 +0000
@@ -0,0 +1,63 @@
+/*
+Tests for the libappindicator library that are over DBus.  This is
+the server side of those tests.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+    Conor Curran <conor.curran@xxxxxxxxxxxxx>
+    Ted Gould <ted@xxxxxxxxxxxxx>
+
+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 <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib.h>
+#include "../src/sound-service-dbus.h"
+#include "test-defines.h"
+
+static GMainLoop * mainloop = NULL;
+static SoundServiceDbus *dbus_interface = NULL;
+
+gboolean
+kill_func (gpointer userdata)
+{
+	g_main_loop_quit(mainloop);
+    // TODO free the dbus interface !!
+	return FALSE;
+}
+
+gint
+main (gint argc, gchar * argv[])
+{
+    g_type_init();
+	g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
+
+    dbus_interface = g_object_new(SOUND_SERVICE_DBUS_TYPE, NULL);
+
+    // Set the mute value
+    sound_service_dbus_update_sink_mute(dbus_interface, TEST_MUTE);
+    g_timeout_add_seconds(2, kill_func, NULL);
+
+    // Run the loop
+    mainloop = g_main_loop_new(NULL, FALSE);
+    g_main_loop_run(mainloop);
+
+	g_debug("Quiting");
+
+    return 0;
+}
+
+

=== added file 'tests/test-indicator-sound.c'
--- tests/test-indicator-sound.c	1970-01-01 00:00:00 +0000
+++ tests/test-indicator-sound.c	2010-03-04 12:22:15 +0000
@@ -0,0 +1,101 @@
+/*
+Copyright 2010 Canonical Ltd.
+
+Authors:
+    Conor Curran <conor.curran@xxxxxxxxxxxxx>
+
+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 <string.h>
+#include <gtk/gtk.h>
+#include <libindicator/indicator-object.h>
+#include "../src/indicator-sound.h"
+
+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;
+
+void test_libindicator_sound_init()
+{
+	IndicatorObject * sound_menu = indicator_object_new_from_file(TOP_BUILD_DIR "/src/.libs/libsoundmenu.so");
+	g_assert(sound_menu != NULL);
+	g_object_unref(G_OBJECT(sound_menu));
+}
+
+void test_libindicator_determine_state()
+{
+	IndicatorObject * sound_menu = indicator_object_new_from_file(TOP_BUILD_DIR "/src/.libs/libsoundmenu.so");
+    prepare_for_tests(sound_menu);
+
+    determine_state_from_volume(40);
+	g_assert(get_state() == STATE_MEDIUM);
+
+    determine_state_from_volume(0);
+	g_assert(get_state() == STATE_ZERO);
+
+    determine_state_from_volume(15);
+	g_assert(get_state() == STATE_LOW);
+
+    determine_state_from_volume(70);
+	g_assert(get_state() == STATE_HIGH);
+
+	g_object_unref(G_OBJECT(sound_menu));
+}
+
+void test_libindicator_image_names()
+{
+    prepare_state_machine();
+
+    gchar* muted_name = get_state_image_name(STATE_MUTED);        
+    g_assert(g_ascii_strncasecmp("audio-volume-muted-panel", muted_name, strlen("audio-volume-muted-panel")) == 0);
+
+    gchar* zero_name = get_state_image_name(STATE_ZERO);        
+    g_assert(g_ascii_strncasecmp("audio-volume-low-zero-panel", zero_name, strlen("audio-volume-low-zero-panel")) == 0);
+
+    gchar* low_name = get_state_image_name(STATE_LOW);        
+    g_assert(g_ascii_strncasecmp("audio-volume-low-panel", low_name, strlen("audio-volume-low-panel")) == 0);
+
+    gchar* medium_name = get_state_image_name(STATE_MEDIUM);        
+    g_assert(g_ascii_strncasecmp("audio-volume-medium-panel", medium_name, strlen("audio-volume-medium-panel")) == 0);
+
+    gchar* high_name = get_state_image_name(STATE_HIGH);        
+    g_assert(g_ascii_strncasecmp("audio-volume-high-panel", high_name, strlen("audio-volume-high-panel")) == 0);
+
+    gchar* blocked_name = get_state_image_name(STATE_MUTED_WHILE_INPUT);        
+    g_assert(g_ascii_strncasecmp("audio-volume-muted-blocking-panel", blocked_name, strlen("audio-volume-muted-blocking-panel")) == 0);
+
+    gchar* none_name = get_state_image_name(STATE_SINKS_NONE);        
+    g_assert(g_ascii_strncasecmp("audio-output-none-panel", none_name, strlen("audio-output-none-panel")) == 0);
+    
+    tidy_up_hash();
+}
+
+
+
+gint main (gint argc, gchar * argv[])
+{
+	g_type_init();
+	g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/indicator-sound/indicator-sound/init", test_libindicator_sound_init);
+    g_test_add_func("/indicator-sound/indicator-sound/state_machine", test_libindicator_determine_state);
+    g_test_add_func("/indicator-sound/indicator-sound/image_names", test_libindicator_image_names);
+
+	return g_test_run ();
+}
+


Follow ups