summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek.chauhan@gmail.com>2009-02-10 12:26:11 +0530
committerNirbheek Chauhan <nirbheek.chauhan@gmail.com>2009-02-10 12:26:11 +0530
commit79433d416e392f084a0014f753f238c9f6df43f4 (patch)
tree4ec0dd75d7af00a89571e56d29f9f5c2ee15bbee /gnome-base/gnome-settings-daemon/files
parentgnome-extra/evolution-data-server: Add missing patch, bug #257698. (diff)
downloadgnome-79433d416e392f084a0014f753f238c9f6df43f4.tar.gz
gnome-79433d416e392f084a0014f753f238c9f6df43f4.tar.bz2
gnome-79433d416e392f084a0014f753f238c9f6df43f4.zip
Non-pulse support for gnome-base/gnome-settings-daemon
- gnome-settings-daemon completely removed support for gstreamer and alsa and only supported pulseaudio for volume control via media keys - The added patch #ifdefs in the older code if HAVE_PULSE is not defined - The changed libnotify patch is from trunk, and must be applied before the pulse patch.
Diffstat (limited to 'gnome-base/gnome-settings-daemon/files')
-rw-r--r--gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-libnotify-automagic.patch34
-rw-r--r--gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-readd-AcmeVolume-support.patch2053
2 files changed, 2077 insertions, 10 deletions
diff --git a/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-libnotify-automagic.patch b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-libnotify-automagic.patch
index eee4f65b..0c1f651c 100644
--- a/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-libnotify-automagic.patch
+++ b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-libnotify-automagic.patch
@@ -1,6 +1,8 @@
---- configure.ac 2008-10-09 00:03:09.000000000 +0200
-+++ configure.ac.new 2008-10-09 00:03:46.000000000 +0200
-@@ -87,9 +87,16 @@
+diff --git a/configure.ac b/configure.ac
+index 506c4e4..aa55fc1 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -89,9 +89,19 @@ dnl ---------------------------------------------------------------------------
dnl - Check for libnotify
dnl ---------------------------------------------------------------------------
@@ -8,15 +10,27 @@
- [AC_DEFINE(HAVE_LIBNOTIFY, 1, [Define if libnotify is available])
- have_libnotify=yes], [have_libnotify=no])
+have_libnotify=no
-+AC_ARG_ENABLE(libnotify,
-+ AS_HELP_STRING([--disable-libnotify], [Enable nice notifications]),
-+ , enable_libnotify=yes)
++AC_ARG_WITH(libnotify,
++ AC_HELP_STRING([--without-libnotify], [Disable notifications (default: auto)]),
++ with_libnotify=$withval, with_libnotify=auto)
+
-+if test "x$enable_libnotify" = "xyes"; then
-+ have_libnotify=yes
-+ PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED_VERSION)
-+ AC_DEFINE(HAVE_LIBNOTIFY, 1, [Define if libnotify is available])
++if test "x$with_libnotify" != "xno"; then
++ PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED_VERSION,
++ [AC_DEFINE(HAVE_LIBNOTIFY, 1, [Define if libnotify is available])
++ have_libnotify=yes], have_libnotify=no)
++ if test "x$have_libnotify" = xno -a "x$with_libnotify" = xyes; then
++ AC_MSG_ERROR([libnotify support requested but libraries not found])
++ fi
+fi
AC_SUBST(LIBNOTIFY_CFLAGS)
AC_SUBST(LIBNOTIFY_LIBS)
+@@ -386,7 +396,7 @@ echo "
+
+ dbus-1 system.d dir: ${DBUS_SYS_DIR}
+
++ Libnotify support: ${have_libnotify}
+ PulseAudio support: ${have_pulse}
+-
+ Profiling support: ${enable_profiling}
+ "
diff --git a/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-readd-AcmeVolume-support.patch b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-readd-AcmeVolume-support.patch
new file mode 100644
index 00000000..9e9d2872
--- /dev/null
+++ b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.25.90-readd-AcmeVolume-support.patch
@@ -0,0 +1,2053 @@
+From 26040f5f39c0a088d73c358927cf8fbae0d8ec66 Mon Sep 17 00:00:00 2001
+From: Nirbheek Chauhan <nirbheek.chauhan@gmail.com>
+Date: Tue, 10 Feb 2009 11:03:36 +0530
+Subject: [PATCH] Re-add AcmeVolume support
+
+---
+ configure.ac | 101 +++++
+ plugins/media-keys/Makefile.am | 30 +-
+ plugins/media-keys/actions/Makefile.am | 78 ++++
+ plugins/media-keys/actions/acme-volume-alsa.c | 326 +++++++++++++++
+ plugins/media-keys/actions/acme-volume-alsa.h | 47 +++
+ plugins/media-keys/actions/acme-volume-dummy.c | 82 ++++
+ plugins/media-keys/actions/acme-volume-dummy.h | 44 ++
+ plugins/media-keys/actions/acme-volume-gstreamer.c | 432 ++++++++++++++++++++
+ plugins/media-keys/actions/acme-volume-gstreamer.h | 48 +++
+ plugins/media-keys/actions/acme-volume-oss.c | 215 ++++++++++
+ plugins/media-keys/actions/acme-volume-oss.h | 47 +++
+ plugins/media-keys/actions/acme-volume.c | 125 ++++++
+ plugins/media-keys/actions/acme-volume.h | 63 +++
+ plugins/media-keys/gsd-media-keys-manager.c | 89 ++++-
+ 14 files changed, 1709 insertions(+), 18 deletions(-)
+ create mode 100644 plugins/media-keys/actions/Makefile.am
+ create mode 100644 plugins/media-keys/actions/acme-volume-alsa.c
+ create mode 100644 plugins/media-keys/actions/acme-volume-alsa.h
+ create mode 100644 plugins/media-keys/actions/acme-volume-dummy.c
+ create mode 100644 plugins/media-keys/actions/acme-volume-dummy.h
+ create mode 100644 plugins/media-keys/actions/acme-volume-gstreamer.c
+ create mode 100644 plugins/media-keys/actions/acme-volume-gstreamer.h
+ create mode 100644 plugins/media-keys/actions/acme-volume-oss.c
+ create mode 100644 plugins/media-keys/actions/acme-volume-oss.h
+ create mode 100644 plugins/media-keys/actions/acme-volume.c
+ create mode 100644 plugins/media-keys/actions/acme-volume.h
+
+diff --git a/configure.ac b/configure.ac
+index aa55fc1..f4748ff 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -253,11 +253,108 @@ if test x$WANT_PULSE = xyes ; then
+ AC_DEFINE(HAVE_PULSE, 1, [Define if PULSE sound server should be used])],
+ [have_pulse=false])
+ fi
++
+ AM_CONDITIONAL(HAVE_PULSE, test "x$have_pulse" = "xtrue")
+
+ AC_SUBST(PULSE_CFLAGS)
+ AC_SUBST(PULSE_LIBS)
+
++dnl ==============================================
++dnl GStreamer section
++dnl ==============================================
++GST_MAJORMINOR=auto
++
++AC_ARG_ENABLE(gstreamer,
++AC_HELP_STRING([--enable-gstreamer],[use gstreamer if available (and optionally specify a version)]),
++[case "${enableval}" in
++ yes) ENABLE_GSTREAMER=yes ;;
++ 0.10) ENABLE_GSTREAMER=yes && GST_MAJORMINOR=0.10 ;;
++ no) ENABLE_GSTREAMER=no ;;
++ *) AC_MSG_ERROR([
++ *** Bad value ${enableval} for --enable-gstreamer
++ *** Please use one of the following:
++ *** --enable-gstreamer=0.10
++ ]) ;;
++esac],
++[ENABLE_GSTREAMER=yes]) dnl Default value
++
++have_gstreamer=no
++if test "x$ENABLE_GSTREAMER" = "xyes"; then
++ GST_REQS=0.10.1.2
++ PKGS="gstreamer-0.10 >= $GST_REQS gstreamer-plugins-base-0.10 >= $GST_REQS"
++
++ PKG_CHECK_MODULES(GST, $PKGS, have_gstreamer=yes,
++ AC_MSG_RESULT([no]))
++
++ if test "x$have_gstreamer" = "xyes"; then
++ GST_LIBS="$GST_LIBS -lgstinterfaces-0.10 -lgstaudio-0.10"
++ fi
++else
++ AC_MSG_NOTICE([*** GStreamer support disabled ***])
++fi
++AM_CONDITIONAL(HAVE_GSTREAMER, test "x$have_gstreamer" = "xyes")
++AC_SUBST(GST_LIBS)
++AC_SUBST(GST_CFLAGS)
++
++dnl ==============================================
++dnl OSS section
++dnl ==============================================
++
++have_oss=no
++if test "x$have_gstreamer" != "xyes" -a "x$have_pulse" != "xtrue"; then
++ AC_TRY_COMPILE([
++ #ifdef __NetBSD__
++ #include <sys/param.h>
++ #include <sys/sysctl.h>
++ #include <soundcard.h>
++ #else
++ #include <sys/soundcard.h>
++ #endif
++ ],[
++ int arg = SNDCTL_DSP_SETFRAGMENT;
++ ],[
++ have_oss=yes
++ ])
++ AC_MSG_CHECKING(for OSS audio support)
++ AC_MSG_RESULT($have_oss)
++fi
++
++AM_CONDITIONAL(HAVE_OSS, test x"$have_oss" = "xyes")
++
++dnl ==============================================
++dnl ALSA section
++dnl ==============================================
++
++have_alsa=no
++if test "x$have_gstreamer" != "xyes"; then
++ AC_ARG_ENABLE(alsa,
++ AC_HELP_STRING([--disable-alsa],
++ [turn off ALSA audio support]),
++ [case "${enableval}" in
++ yes) WANT_ALSA=yes ;;
++ no) WANT_ALSA=no ;;
++ *) AC_MSG_ERROR(bad value ${enableval} for --disable-alsa) ;;
++ esac],
++ [WANT_ALSA=yes]) dnl Default value
++
++ if test x$WANT_ALSA = xyes ; then
++ PKG_CHECK_MODULES(ALSA, alsa >= 0.9.0,
++ have_alsa=yes,
++ AC_MSG_RESULT([disabled]))
++ fi
++
++ AC_SUBST(ALSA_LIBS)
++ AC_SUBST(ALSA_CFLAGS)
++fi
++
++AM_CONDITIONAL(HAVE_ALSA, test x"$have_alsa" = "xyes")
++
++if test x"$have_pulse" = "xtrue"; then
++ if test x"$have_gstreamer" = "xyes" -o x"$have_alsa" = "xyes" -o x"$have_oss" = "xyes"; then
++ AC_MSG_ERROR(Pulseaudio cannot be enabled with alsa or oss or gstreamer)
++ fi
++fi
++
+ # ---------------------------------------------------------------------------
+ # Enable Profiling
+ # ---------------------------------------------------------------------------
+@@ -355,6 +452,7 @@ plugins/housekeeping/Makefile
+ plugins/keybindings/Makefile
+ plugins/keyboard/Makefile
+ plugins/media-keys/Makefile
++plugins/media-keys/actions/Makefile
+ plugins/media-keys/cut-n-paste/Makefile
+ plugins/mouse/Makefile
+ plugins/screensaver/Makefile
+@@ -397,6 +495,9 @@ echo "
+ dbus-1 system.d dir: ${DBUS_SYS_DIR}
+
+ Libnotify support: ${have_libnotify}
++ OSS support: ${have_oss}
++ ALSA support: ${have_alsa}
++ GStreamer support: ${have_gstreamer}
+ PulseAudio support: ${have_pulse}
+ Profiling support: ${enable_profiling}
+ "
+diff --git a/plugins/media-keys/Makefile.am b/plugins/media-keys/Makefile.am
+index 78f3b2b..d31bc82 100644
+--- a/plugins/media-keys/Makefile.am
++++ b/plugins/media-keys/Makefile.am
+@@ -1,11 +1,12 @@
+ NULL =
+
+ SUBDIRS =
+-plugin_LTLIBRARIES =
++plugin_LTLIBRARIES = libmedia-keys.la
+
+ if HAVE_PULSE
+ SUBDIRS += cut-n-paste
+-plugin_LTLIBRARIES += libmedia-keys.la
++else
++SUBDIRS += actions
+ endif
+
+ BUILT_SOURCES = \
+@@ -39,7 +40,6 @@ libmedia_keys_la_SOURCES = \
+ libmedia_keys_la_CPPFLAGS = \
+ -I$(top_srcdir)/gnome-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+- -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGLADEDIR=\""$(pkgdatadir)"\" \
+ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+@@ -53,10 +53,10 @@ libmedia_keys_la_LDFLAGS = \
+ $(GSD_PLUGIN_LDFLAGS)
+
+ libmedia_keys_la_LIBADD = \
+- $(top_builddir)/plugins/common/libcommon.la \
+- $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \
+- $(SETTINGS_PLUGIN_LIBS) \
+- $(XF86MISC_LIBS)
++ $(top_builddir)/plugins/common/libcommon.la \
++ $(SETTINGS_PLUGIN_LIBS) \
++ $(XF86MISC_LIBS) \
++ $(GST_LIBS)
+
+ plugin_in_files = \
+ media-keys.gnome-settings-plugin.in
+@@ -76,7 +76,6 @@ test_media_window_SOURCES = \
+
+ test_media_window_CPPFLAGS = \
+ -I$(top_srcdir)/gnome-settings-daemon \
+- -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGLADEDIR=\""$(pkgdatadir)"\" \
+ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+@@ -104,7 +103,6 @@ test_media_keys_SOURCES = \
+ test_media_keys_CPPFLAGS = \
+ -I$(top_srcdir)/gnome-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+- -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGLADEDIR=\""$(pkgdatadir)"\" \
+ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+@@ -123,7 +121,17 @@ test_media_keys_LDADD = \
+ $(GST_LIBS)
+
+ if HAVE_PULSE
++libmedia_keys_la_CPPFLAGS += -I$(top_builddir)/plugins/media-keys/cut-n-paste
++libmedia_keys_la_LIBADD += $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la
++test_media_window_CPPFLAGS += -I$(top_builddir)/plugins/media-keys/cut-n-paste
++test_media_keys_CPPFLAGS += -I$(top_builddir)/plugins/media-keys/cut-n-paste
+ test_media_keys_LDADD += $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la
++else
++libmedia_keys_la_CPPFLAGS += -I$(top_builddir)/plugins/media-keys/actions
++libmedia_keys_la_LIBADD += $(top_builddir)/plugins/media-keys/actions/libacme.la
++test_media_window_CPPFLAGS += -I$(top_builddir)/plugins/media-keys/actions
++test_media_keys_CPPFLAGS += -I$(top_builddir)/plugins/media-keys/actions
++test_media_keys_LDADD += $(top_builddir)/plugins/media-keys/actions/libacme.la
+ endif
+
+ gladedir = $(pkgdatadir)
+@@ -136,7 +144,11 @@ pixmaps_DATA = \
+ acme-eject.png \
+ $(NULL)
+
++if HAVE_PULSE
+ DIST_SUBDIRS = cut-n-paste
++else
++DIST_SUBDIRS = actions
++endif
+
+ EXTRA_DIST = \
+ gsd-media-keys-manager.xml \
+diff --git a/plugins/media-keys/actions/Makefile.am b/plugins/media-keys/actions/Makefile.am
+new file mode 100644
+index 0000000..73c5c9e
+--- /dev/null
++++ b/plugins/media-keys/actions/Makefile.am
+@@ -0,0 +1,78 @@
++NULL =
++
++noinst_LTLIBRARIES = libacme.la
++
++libacme_la_SOURCES = \
++ ../acme.h \
++ acme-volume.c \
++ acme-volume.h \
++ acme-volume-dummy.c \
++ acme-volume-dummy.h \
++ $(NULL)
++
++libacme_la_CPPFLAGS = \
++ -I$(top_srcdir)/gnome-settings-daemon \
++ -I$(top_srcdir)/plugins/common \
++ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
++ $(AM_CPPFLAGS)
++
++libacme_la_CFLAGS = \
++ $(SETTINGS_PLUGIN_CFLAGS) \
++ $(GST_CFLAGS) \
++ $(AM_CFLAGS)
++
++libacme_la_LIBADD = \
++ $(NULL)
++
++if HAVE_GSTREAMER
++libacme_la_SOURCES += \
++ acme-volume-gstreamer.c \
++ acme-volume-gstreamer.h \
++ $(NULL)
++
++libacme_la_CPPFLAGS += -DHAVE_GSTREAMER
++
++libacme_la_LIBADD += $(GST_LIBS)
++
++else # HAVE_GSTREAMER
++
++if HAVE_ALSA
++libacme_la_SOURCES += \
++ acme-volume-alsa.c \
++ acme-volume-alsa.h \
++ $(NULL)
++
++libacme_la_CPPFLAGS += -DHAVE_ALSA
++
++libacme_la_LIBADD += $(ALSA_LIBS)
++
++else # HAVE_ALSA
++
++if HAVE_OSS
++libacme_la_SOURCES += \
++ acme-volume-oss.c \
++ acme-volume-oss.h \
++ $(NULL)
++
++libacme_la_CPPFLAGS += -DHAVE_OSS
++
++libacme_la_SOURCES += $(OSS_SOURCES)
++
++endif # HAVE_OSS
++endif # HAVE_ALSA
++endif # HAVE_GSTREAMER
++
++gladedir = $(pkgdatadir)
++glade_DATA = \
++ ../acme.glade \
++ $(NULL)
++
++pixmapsdir = $(pkgdatadir)
++pixmaps_DATA = \
++ ../acme-eject.png \
++ $(NULL)
++
++EXTRA_DIST = \
++ $(glade_DATA) \
++ $(pixmaps_DATA) \
++ $(NULL)
+diff --git a/plugins/media-keys/actions/acme-volume-alsa.c b/plugins/media-keys/actions/acme-volume-alsa.c
+new file mode 100644
+index 0000000..314820c
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-alsa.c
+@@ -0,0 +1,326 @@
++/* acme-volume-alsa.c
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#include "config.h"
++#include "acme-volume-alsa.h"
++
++#include <alsa/asoundlib.h>
++
++#ifndef DEFAULT_CARD
++#define DEFAULT_CARD "default"
++#endif
++
++#undef LOG
++#ifdef LOG
++#define D(x...) g_message (x)
++#else
++#define D(x...)
++#endif
++
++#define ROUND(x) ((x - (int)x > 0.5) ? x+1 : x)
++
++struct AcmeVolumeAlsaPrivate
++{
++ long pmin, pmax;
++ gboolean has_mute, has_master;
++ snd_mixer_t *handle;
++ snd_mixer_elem_t *elem;
++ int saved_volume;
++ guint timer_id;
++};
++
++static int acme_volume_alsa_get_volume (AcmeVolume *self);
++static void acme_volume_alsa_set_volume (AcmeVolume *self, int val);
++static gboolean acme_volume_alsa_open (AcmeVolumeAlsa *self);
++static void acme_volume_alsa_close (AcmeVolumeAlsa *self);
++static gboolean acme_volume_alsa_close_real (AcmeVolumeAlsa *self);
++
++G_DEFINE_TYPE (AcmeVolumeAlsa, acme_volume_alsa, ACME_TYPE_VOLUME)
++
++static void
++acme_volume_alsa_finalize (GObject *object)
++{
++ AcmeVolumeAlsa *self;
++
++ self = ACME_VOLUME_ALSA (object);
++
++ if (self->_priv)
++ {
++ if (self->_priv->timer_id != 0)
++ {
++ g_source_remove (self->_priv->timer_id);
++ self->_priv->timer_id = 0;
++ }
++
++ acme_volume_alsa_close_real (self);
++ g_free (self->_priv);
++ self->_priv = NULL;
++ }
++
++ G_OBJECT_CLASS (acme_volume_alsa_parent_class)->finalize (object);
++}
++
++static void
++acme_volume_alsa_set_mute (AcmeVolume *vol, gboolean val)
++{
++ AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol;
++
++ if (acme_volume_alsa_open (self) == FALSE)
++ return;
++
++ /* If we have a hardware mute */
++ if (self->_priv->has_mute)
++ {
++ snd_mixer_selem_set_playback_switch_all
++ (self->_priv->elem, !val);
++ acme_volume_alsa_close (self);
++ return;
++ }
++
++ acme_volume_alsa_close (self);
++
++ /* If we don't */
++ if (val == TRUE)
++ {
++ self->_priv->saved_volume = acme_volume_alsa_get_volume (vol);
++ acme_volume_alsa_set_volume (vol, 0);
++ } else {
++ if (self->_priv->saved_volume != -1)
++ acme_volume_alsa_set_volume (vol,
++ self->_priv->saved_volume);
++ }
++}
++
++static gboolean
++acme_volume_alsa_get_mute (AcmeVolume *vol)
++{
++ AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol;
++ int ival;
++
++ if (acme_volume_alsa_open (self) == FALSE)
++ return FALSE;
++
++ if (self->_priv->has_mute)
++ {
++ snd_mixer_selem_get_playback_switch(self->_priv->elem,
++ SND_MIXER_SCHN_FRONT_LEFT, &ival);
++
++ acme_volume_alsa_close (self);
++
++ return !ival;
++ } else {
++ acme_volume_alsa_close (self);
++
++ return (acme_volume_alsa_get_volume (vol) == 0);
++ }
++}
++
++static int
++acme_volume_alsa_get_volume (AcmeVolume *vol)
++{
++ AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol;
++ long lval, rval;
++ int tmp;
++ float alsa_vol;
++
++ if (acme_volume_alsa_open (self) == FALSE)
++ return 0;
++
++ snd_mixer_selem_get_playback_volume(self->_priv->elem,
++ SND_MIXER_SCHN_FRONT_LEFT, &lval);
++ snd_mixer_selem_get_playback_volume(self->_priv->elem,
++ SND_MIXER_SCHN_FRONT_RIGHT, &rval);
++
++ acme_volume_alsa_close (self);
++
++ alsa_vol = (lval + rval) / 2;
++ alsa_vol = alsa_vol * 100 / (self->_priv->pmax - self->_priv->pmin);
++ tmp = ROUND (alsa_vol);
++
++ return tmp;
++}
++
++static void
++acme_volume_alsa_set_volume (AcmeVolume *vol, int val)
++{
++ AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol;
++ float volume;
++ int tmp;
++
++ if (acme_volume_alsa_open (self) == FALSE)
++ return;
++
++ volume = (float) val / 100 * (self->_priv->pmax - self->_priv->pmin);
++ volume = CLAMP (volume, self->_priv->pmin, self->_priv->pmax);
++ tmp = ROUND (volume);
++
++ snd_mixer_selem_set_playback_volume_all (self->_priv->elem, tmp);
++
++ acme_volume_alsa_close (self);
++}
++
++static int
++acme_volume_alsa_get_threshold (AcmeVolume *vol)
++{
++ AcmeVolumeAlsa *self = (AcmeVolumeAlsa *) vol;
++ int steps;
++
++ if (acme_volume_alsa_open (self) == FALSE)
++ return 1;
++
++ acme_volume_alsa_close (self);
++
++ steps = self->_priv->pmax - self->_priv->pmin;
++ return (steps > 0) ? 100 / steps + 1 : 1;
++}
++
++static gboolean
++acme_volume_alsa_close_real (AcmeVolumeAlsa *self)
++{
++ if (self->_priv == NULL)
++ return FALSE;
++
++ if (self->_priv->handle != NULL)
++ {
++ snd_mixer_detach (self->_priv->handle, DEFAULT_CARD);
++ snd_mixer_free (self->_priv->handle);
++ self->_priv->handle = NULL;
++ self->_priv->elem = NULL;
++ }
++
++ self->_priv->timer_id = 0;
++
++ return FALSE;
++}
++
++static gboolean
++acme_volume_alsa_open (AcmeVolumeAlsa *self)
++{
++ snd_mixer_selem_id_t *sid;
++ snd_mixer_t *handle;
++ snd_mixer_elem_t *elem;
++
++ if (self->_priv->timer_id != 0)
++ {
++ g_source_remove (self->_priv->timer_id);
++ self->_priv->timer_id = 0;
++ return TRUE;
++ }
++
++ /* open the mixer */
++ if (snd_mixer_open (&handle, 0) < 0)
++ {
++ D("snd_mixer_open");
++ return FALSE;
++ }
++ /* attach the handle to the default card */
++ if (snd_mixer_attach (handle, DEFAULT_CARD) <0)
++ {
++ D("snd_mixer_attach");
++ goto bail;
++ }
++ /* ? */
++ if (snd_mixer_selem_register (handle, NULL, NULL) < 0)
++ {
++ D("snd_mixer_selem_register");
++ goto bail;
++ }
++ if (snd_mixer_load (handle) < 0)
++ {
++ D("snd_mixer_load");
++ goto bail;
++ }
++
++ snd_mixer_selem_id_alloca (&sid);
++ snd_mixer_selem_id_set_name (sid, "Master");
++ elem = snd_mixer_find_selem (handle, sid);
++ if (!elem)
++ {
++ snd_mixer_selem_id_alloca (&sid);
++ snd_mixer_selem_id_set_name (sid, "PCM");
++ elem = snd_mixer_find_selem (handle, sid);
++ if (!elem)
++ {
++ D("snd_mixer_find_selem");
++ goto bail;
++ }
++ }
++
++ if (!snd_mixer_selem_has_playback_volume (elem))
++ {
++ D("snd_mixer_selem_has_playback_volume");
++ goto bail;
++ }
++
++ snd_mixer_selem_get_playback_volume_range (elem,
++ &(self->_priv->pmin),
++ &(self->_priv->pmax));
++
++ self->_priv->has_mute = snd_mixer_selem_has_playback_switch (elem);
++ self->_priv->handle = handle;
++ self->_priv->elem = elem;
++
++ return TRUE;
++
++bail:
++ acme_volume_alsa_close_real (self);
++ return FALSE;
++}
++
++static void
++acme_volume_alsa_close (AcmeVolumeAlsa *self)
++{
++ self->_priv->timer_id = g_timeout_add (4000,
++ (GSourceFunc) acme_volume_alsa_close_real, self);
++}
++
++static void
++acme_volume_alsa_init (AcmeVolumeAlsa *self)
++{
++ self->_priv = g_new0 (AcmeVolumeAlsaPrivate, 1);
++
++ if (acme_volume_alsa_open (self) == FALSE)
++ {
++ g_free (self->_priv);
++ self->_priv = NULL;
++ return;
++ }
++
++ if (self->_priv->handle != NULL) {
++ acme_volume_alsa_close_real (self);
++ return;
++ }
++}
++
++static void
++acme_volume_alsa_class_init (AcmeVolumeAlsaClass *klass)
++{
++ AcmeVolumeClass *volume_class = ACME_VOLUME_CLASS (klass);
++ G_OBJECT_CLASS (klass)->finalize = acme_volume_alsa_finalize;
++
++ volume_class->set_volume = acme_volume_alsa_set_volume;
++ volume_class->get_volume = acme_volume_alsa_get_volume;
++ volume_class->set_mute = acme_volume_alsa_set_mute;
++ volume_class->get_mute = acme_volume_alsa_get_mute;
++ volume_class->get_threshold = acme_volume_alsa_get_threshold;
++}
++
+diff --git a/plugins/media-keys/actions/acme-volume-alsa.h b/plugins/media-keys/actions/acme-volume-alsa.h
+new file mode 100644
+index 0000000..83746ff
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-alsa.h
+@@ -0,0 +1,47 @@
++/* acme-volume-alsa.h
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#include <glib.h>
++#include <glib-object.h>
++#include "acme-volume.h"
++
++#define ACME_TYPE_VOLUME_ALSA (acme_volume_get_type ())
++#define ACME_VOLUME_ALSA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACME_TYPE_VOLUME_ALSA, AcmeVolumeAlsa))
++#define ACME_VOLUME_ALSA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ACME_TYPE_VOLUME_ALSA, AcmeVolumeAlsaClass))
++#define ACME_IS_VOLUME_ALSA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ACME_TYPE_VOLUME_ALSA))
++#define ACME_VOLUME_ALSA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ACME_TYPE_VOLUME_ALSA, AcmeVolumeAlsaClass))
++
++typedef struct AcmeVolumeAlsa AcmeVolumeAlsa;
++typedef struct AcmeVolumeAlsaClass AcmeVolumeAlsaClass;
++typedef struct AcmeVolumeAlsaPrivate AcmeVolumeAlsaPrivate;
++
++struct AcmeVolumeAlsa {
++ AcmeVolume parent;
++ AcmeVolumeAlsaPrivate *_priv;
++};
++
++struct AcmeVolumeAlsaClass {
++ AcmeVolumeClass parent;
++};
++
++GType acme_volume_alsa_get_type (void);
++
+diff --git a/plugins/media-keys/actions/acme-volume-dummy.c b/plugins/media-keys/actions/acme-volume-dummy.c
+new file mode 100644
+index 0000000..054b9e7
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-dummy.c
+@@ -0,0 +1,82 @@
++/* acme-volume-dummy.c
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#include "config.h"
++#include "acme-volume-dummy.h"
++
++G_DEFINE_TYPE (AcmeVolumeDummy, acme_volume_dummy, ACME_TYPE_VOLUME)
++
++static void
++acme_volume_dummy_finalize (GObject *object)
++{
++ g_return_if_fail (object != NULL);
++ g_return_if_fail (ACME_IS_VOLUME_DUMMY (object));
++
++ G_OBJECT_CLASS (acme_volume_dummy_parent_class)->finalize (object);
++}
++
++static void
++acme_volume_dummy_set_mute (AcmeVolume *vol, gboolean val)
++{
++}
++
++static gboolean
++acme_volume_dummy_get_mute (AcmeVolume *vol)
++{
++ return FALSE;
++}
++
++static int
++acme_volume_dummy_get_volume (AcmeVolume *vol)
++{
++ return 0;
++}
++
++static void
++acme_volume_dummy_set_volume (AcmeVolume *vol, int val)
++{
++}
++
++/* minimum step size (in percent) required to actually affect volume */
++static int
++acme_volume_dummy_get_threshold (AcmeVolume *vol)
++{
++ return 1;
++}
++
++static void
++acme_volume_dummy_init (AcmeVolumeDummy *vol)
++{
++}
++
++static void
++acme_volume_dummy_class_init (AcmeVolumeDummyClass *klass)
++{
++ AcmeVolumeClass *volume_class = ACME_VOLUME_CLASS (klass);
++ G_OBJECT_CLASS (klass)->finalize = acme_volume_dummy_finalize;
++
++ volume_class->set_volume = acme_volume_dummy_set_volume;
++ volume_class->get_volume = acme_volume_dummy_get_volume;
++ volume_class->set_mute = acme_volume_dummy_set_mute;
++ volume_class->get_mute = acme_volume_dummy_get_mute;
++ volume_class->get_threshold = acme_volume_dummy_get_threshold;
++}
+diff --git a/plugins/media-keys/actions/acme-volume-dummy.h b/plugins/media-keys/actions/acme-volume-dummy.h
+new file mode 100644
+index 0000000..b66ac14
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-dummy.h
+@@ -0,0 +1,44 @@
++/* acme-volume-dummy.h
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#include <glib.h>
++#include <glib-object.h>
++#include "acme-volume.h"
++
++#define ACME_TYPE_VOLUME_DUMMY (acme_volume_dummy_get_type ())
++#define ACME_VOLUME_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACME_TYPE_VOLUME_DUMMY, AcmeVolumeDummy))
++#define ACME_VOLUME_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ACME_TYPE_VOLUME_DUMMY, AcmeVolumeDummyClass))
++#define ACME_IS_VOLUME_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ACME_TYPE_VOLUME_DUMMY))
++#define ACME_VOLUME_DUMMY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ACME_TYPE_VOLUME_DUMMY, AcmeVolumeDummyClass))
++
++typedef struct AcmeVolumeDummy AcmeVolumeDummy;
++typedef struct AcmeVolumeDummyClass AcmeVolumeDummyClass;
++
++struct AcmeVolumeDummy {
++ AcmeVolume parent;
++};
++
++struct AcmeVolumeDummyClass {
++ AcmeVolumeClass parent;
++};
++
++GType acme_volume_dummy_get_type (void);
+diff --git a/plugins/media-keys/actions/acme-volume-gstreamer.c b/plugins/media-keys/actions/acme-volume-gstreamer.c
+new file mode 100644
+index 0000000..6990447
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-gstreamer.c
+@@ -0,0 +1,432 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* acme-volume-gstreamer.c
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++ Copyright (C) 2004 Novell, Inc.
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ Jon Trowbridge <trow@ximian.com>
++ */
++
++#include "config.h"
++#include "acme-volume-gstreamer.h"
++
++#include <gst/gst.h>
++#include <gst/audio/mixerutils.h>
++#include <gst/interfaces/mixer.h>
++#include <gst/interfaces/propertyprobe.h>
++
++#include <gconf/gconf-client.h>
++
++#include <string.h>
++
++#define TIMEOUT 4
++
++#define DEFAULT_MIXER_DEVICE_KEY "/desktop/gnome/sound/default_mixer_device"
++#define DEFAULT_MIXER_TRACKS_KEY "/desktop/gnome/sound/default_mixer_tracks"
++
++#define ACME_VOLUME_GSTREAMER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACME_TYPE_VOLUME_GSTREAMER, AcmeVolumeGStreamerPrivate))
++
++struct AcmeVolumeGStreamerPrivate
++{
++ GstMixer *mixer;
++ GList *mixer_tracks;
++ guint timer_id;
++ gdouble volume;
++ gboolean mute;
++ GConfClient *gconf_client;
++};
++
++G_DEFINE_TYPE (AcmeVolumeGStreamer, acme_volume_gstreamer, ACME_TYPE_VOLUME)
++
++static int acme_volume_gstreamer_get_volume (AcmeVolume *self);
++static void acme_volume_gstreamer_set_volume (AcmeVolume *self, int val);
++static gboolean acme_volume_gstreamer_open (AcmeVolumeGStreamer *self);
++static void acme_volume_gstreamer_close (AcmeVolumeGStreamer *self);
++static gboolean acme_volume_gstreamer_close_real (AcmeVolumeGStreamer *self);
++
++static void
++acme_volume_gstreamer_finalize (GObject *object)
++{
++ AcmeVolumeGStreamer *self;
++
++ g_return_if_fail (object != NULL);
++ g_return_if_fail (ACME_IS_VOLUME_GSTREAMER (object));
++
++ self = ACME_VOLUME_GSTREAMER (object);
++
++ if (self->_priv->timer_id != 0)
++ {
++ g_source_remove (self->_priv->timer_id);
++ self->_priv->timer_id = 0;
++ }
++ acme_volume_gstreamer_close_real (self);
++
++ if (self->_priv->gconf_client != NULL) {
++ g_object_unref (self->_priv->gconf_client);
++ self->_priv->gconf_client = NULL;
++ }
++
++ G_OBJECT_CLASS (acme_volume_gstreamer_parent_class)->finalize (object);
++}
++
++static void
++acme_volume_gstreamer_set_mute (AcmeVolume *vol, gboolean val)
++{
++ AcmeVolumeGStreamer *self = (AcmeVolumeGStreamer *) vol;
++ GList *t;
++
++ if (acme_volume_gstreamer_open (self) == FALSE)
++ return;
++
++ for (t = self->_priv->mixer_tracks; t != NULL; t = t->next)
++ {
++ GstMixerTrack *track = GST_MIXER_TRACK (t->data);
++ gst_mixer_set_mute (self->_priv->mixer, track, val);
++ }
++
++ if (val)
++ {
++ self->_priv->mute = TRUE;
++ } else {
++ self->_priv->mute = FALSE;
++
++ for (t = self->_priv->mixer_tracks; t != NULL; t = t->next)
++ {
++ GstMixerTrack *track = GST_MIXER_TRACK (t->data);
++ gint *volumes, n;
++ gdouble scale = (track->max_volume - track->min_volume) / 100.0;
++ gint vol = (gint) (self->_priv->volume * scale + track->min_volume + 0.5);
++
++ volumes = g_new (gint, track->num_channels);
++ for (n = 0; n < track->num_channels; n++)
++ volumes[n] = vol;
++ gst_mixer_set_volume (self->_priv->mixer, track, volumes);
++ g_free (volumes);
++ }
++ }
++
++ acme_volume_gstreamer_close (self);
++}
++
++static void
++update_state (AcmeVolumeGStreamer * self)
++{
++ gint *volumes, n;
++ gdouble vol = 0;
++ GstMixerTrack *track = GST_MIXER_TRACK (self->_priv->mixer_tracks->data);
++
++ /* update mixer by getting volume */
++ volumes = g_new0 (gint, track->num_channels);
++ gst_mixer_get_volume (self->_priv->mixer, track, volumes);
++ for (n = 0; n < track->num_channels; n++)
++ vol += volumes[n];
++ g_free (volumes);
++ vol /= track->num_channels;
++ vol = 100 * vol / (track->max_volume - track->min_volume);
++
++ /* update mute flag, and volume if not muted */
++ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE))
++ self->_priv->mute = TRUE;
++ else
++ self->_priv->volume = vol;
++}
++
++static gboolean
++acme_volume_gstreamer_get_mute (AcmeVolume *vol)
++{
++ AcmeVolumeGStreamer *self = (AcmeVolumeGStreamer *) vol;
++
++ if (acme_volume_gstreamer_open (self) == FALSE)
++ return FALSE;
++
++ update_state (self);
++ acme_volume_gstreamer_close (self);
++
++ return self->_priv->mute;
++}
++
++static int
++acme_volume_gstreamer_get_volume (AcmeVolume *vol)
++{
++ AcmeVolumeGStreamer *self = (AcmeVolumeGStreamer *) vol;
++
++ if (acme_volume_gstreamer_open (self) == FALSE)
++ return 0;
++
++ update_state (self);
++
++ acme_volume_gstreamer_close (self);
++
++ return (gint) (self->_priv->volume + 0.5);
++}
++
++static void
++acme_volume_gstreamer_set_volume (AcmeVolume *vol, int val)
++{
++ AcmeVolumeGStreamer *self = (AcmeVolumeGStreamer *) vol;
++ GList *t;
++
++ if (acme_volume_gstreamer_open (self) == FALSE)
++ return;
++
++ val = CLAMP (val, 0, 100);
++
++ for (t = self->_priv->mixer_tracks; t != NULL; t = t->next)
++ {
++ GstMixerTrack *track = GST_MIXER_TRACK (t->data);
++ gint *volumes, n;
++ gdouble scale = (track->max_volume - track->min_volume) / 100.0;
++ gint vol = (gint) (val * scale + track->min_volume + 0.5);
++
++ volumes = g_new (gint, track->num_channels);
++ for (n = 0; n < track->num_channels; n++)
++ volumes[n] = vol;
++ gst_mixer_set_volume (self->_priv->mixer, track, volumes);
++ g_free (volumes);
++ }
++
++ /* update state */
++ self->_priv->volume = val;
++
++ acme_volume_gstreamer_close (self);
++}
++
++static int
++acme_volume_gstreamer_get_threshold (AcmeVolume *vol)
++{
++ AcmeVolumeGStreamer *self = (AcmeVolumeGStreamer *) vol;
++ GList *t;
++ int steps = 101;
++
++ if (acme_volume_gstreamer_open (self) == FALSE)
++ return 1;
++
++ for (t = self->_priv->mixer_tracks; t != NULL; t = t->next)
++ {
++ GstMixerTrack *track = GST_MIXER_TRACK (t->data);
++ int track_steps = track->max_volume - track->min_volume;
++ if (track_steps > 0 && track_steps < steps)
++ steps = track_steps;
++ }
++
++ acme_volume_gstreamer_close (self);
++
++ return 100 / steps + 1;
++}
++
++static gboolean
++acme_volume_gstreamer_close_real (AcmeVolumeGStreamer *self)
++{
++ if (self->_priv->mixer != NULL)
++ {
++ gst_element_set_state (GST_ELEMENT (self->_priv->mixer), GST_STATE_NULL);
++ gst_object_unref (GST_OBJECT (self->_priv->mixer));
++ g_list_foreach (self->_priv->mixer_tracks, (GFunc) g_object_unref, NULL);
++ g_list_free (self->_priv->mixer_tracks);
++ self->_priv->mixer = NULL;
++ self->_priv->mixer_tracks = NULL;
++ }
++
++ self->_priv->timer_id = 0;
++ return FALSE;
++}
++
++/*
++ * _acme_set_mixer
++ * Arguments: mixer - pointer to mixer element
++ * data - pointer to user data (AcmeVolumeGStreamer to be modified)
++ * Returns: gboolean indicating success
++ */
++static gboolean
++_acme_set_mixer(GstMixer *mixer, gpointer user_data)
++{
++ const GList *tracks;
++
++ tracks = gst_mixer_list_tracks (mixer);
++
++ while (tracks != NULL) {
++ GstMixerTrack *track = GST_MIXER_TRACK (tracks->data);
++
++ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MASTER)) {
++ AcmeVolumeGStreamer *self;
++
++ self = ACME_VOLUME_GSTREAMER (user_data);
++
++ self->_priv->mixer = mixer;
++ self->_priv->mixer_tracks = g_list_append (self->_priv->mixer_tracks, g_object_ref (track));
++ return TRUE;
++ }
++
++ tracks = tracks->next;
++ }
++
++ return FALSE;
++}
++
++/* This is a modified version of code from gnome-media's gst-mixer */
++static gboolean
++acme_volume_gstreamer_open (AcmeVolumeGStreamer *vol)
++{
++ AcmeVolumeGStreamer *self = (AcmeVolumeGStreamer *) vol;
++ gchar *mixer_device, **factory_and_device = NULL;
++ GList *mixer_list;
++
++ if (self->_priv->timer_id != 0)
++ {
++ g_source_remove (self->_priv->timer_id);
++ self->_priv->timer_id = 0;
++ return TRUE;
++ }
++
++ mixer_device = gconf_client_get_string (self->_priv->gconf_client, DEFAULT_MIXER_DEVICE_KEY, NULL);
++ if (mixer_device != NULL)
++ {
++ factory_and_device = g_strsplit (mixer_device, ":", 2);
++ }
++
++ if (factory_and_device != NULL && factory_and_device[0] != NULL)
++ {
++ GstElement *element;
++
++ element = gst_element_factory_make (factory_and_device[0], NULL);
++
++ if (element != NULL) {
++ if (factory_and_device[1] != NULL &&
++ g_object_class_find_property (G_OBJECT_GET_CLASS (element), "device"))
++ {
++ g_object_set (G_OBJECT (element), "device", factory_and_device[1], NULL);
++ }
++
++ gst_element_set_state (element, GST_STATE_READY);
++
++ if (GST_IS_MIXER (element)) {
++ self->_priv->mixer = GST_MIXER (element);
++ } else {
++ gst_element_set_state (element, GST_STATE_NULL);
++ gst_object_unref (element);
++ }
++ }
++ }
++
++ g_free (mixer_device);
++ g_strfreev (factory_and_device);
++
++ if (self->_priv->mixer != NULL)
++ {
++ const GList *m;
++ GSList *tracks, *t;
++
++ /* Try to use tracks saved in GConf */
++ tracks = gconf_client_get_list (self->_priv->gconf_client, DEFAULT_MIXER_TRACKS_KEY, GCONF_VALUE_STRING, NULL);
++
++ for (m = gst_mixer_list_tracks (self->_priv->mixer); m != NULL; m = m->next)
++ {
++ GstMixerTrack *track = GST_MIXER_TRACK (m->data);
++
++ for (t = tracks; t != NULL; t = t->next)
++ {
++ if (!strcmp (t->data, track->label))
++ {
++ self->_priv->mixer_tracks = g_list_append (self->_priv->mixer_tracks, g_object_ref (track));
++ }
++ }
++
++ }
++
++ g_slist_foreach (tracks, (GFunc)g_free, NULL);
++ g_slist_free (tracks);
++
++ /* If no track stored in GConf is avaiable try to use master track */
++ if (self->_priv->mixer_tracks == NULL)
++ {
++ for (m = gst_mixer_list_tracks (self->_priv->mixer); m != NULL; m = m->next)
++ {
++ GstMixerTrack *track = GST_MIXER_TRACK (m->data);
++
++ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MASTER)) {
++ self->_priv->mixer_tracks = g_list_append (self->_priv->mixer_tracks, g_object_ref (track));
++ break;
++ }
++ }
++ }
++ }
++
++ if (self->_priv->mixer != NULL)
++ {
++ if (self->_priv->mixer_tracks != NULL)
++ {
++ return TRUE;
++ } else {
++ gst_element_set_state (GST_ELEMENT (self->_priv->mixer), GST_STATE_NULL);
++ gst_object_unref (self->_priv->mixer);
++ }
++ }
++
++ /* Go through all elements of a certain class and check whether
++ * they implement a mixer. If so, walk through the tracks and look
++ * for first one named "volume".
++ *
++ * We should probably do something intelligent if we don't find an
++ * appropriate mixer/track. But now we do something stupid...
++ * everything just becomes a no-op.
++ */
++ mixer_list = gst_audio_default_registry_mixer_filter (_acme_set_mixer,
++ TRUE,
++ self);
++
++ if (mixer_list == NULL)
++ return FALSE;
++
++ /* do not unref the mixer as we keep the ref for self->priv->mixer */
++ g_list_free (mixer_list);
++
++ return TRUE;
++}
++
++static void
++acme_volume_gstreamer_close (AcmeVolumeGStreamer *self)
++{
++ self->_priv->timer_id = g_timeout_add_seconds (TIMEOUT,
++ (GSourceFunc) acme_volume_gstreamer_close_real, self);
++}
++
++static void
++acme_volume_gstreamer_init (AcmeVolumeGStreamer *self)
++{
++ self->_priv = ACME_VOLUME_GSTREAMER_GET_PRIVATE (self);
++ self->_priv->gconf_client = gconf_client_get_default ();
++}
++
++static void
++acme_volume_gstreamer_class_init (AcmeVolumeGStreamerClass *klass)
++{
++ AcmeVolumeClass *volume_class = ACME_VOLUME_CLASS (klass);
++ G_OBJECT_CLASS (klass)->finalize = acme_volume_gstreamer_finalize;
++
++ gst_init (NULL, NULL);
++
++ volume_class->set_volume = acme_volume_gstreamer_set_volume;
++ volume_class->get_volume = acme_volume_gstreamer_get_volume;
++ volume_class->set_mute = acme_volume_gstreamer_set_mute;
++ volume_class->get_mute = acme_volume_gstreamer_get_mute;
++ volume_class->get_threshold = acme_volume_gstreamer_get_threshold;
++
++ g_type_class_add_private (klass, sizeof (AcmeVolumeGStreamerPrivate));
++}
+diff --git a/plugins/media-keys/actions/acme-volume-gstreamer.h b/plugins/media-keys/actions/acme-volume-gstreamer.h
+new file mode 100644
+index 0000000..f260688
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-gstreamer.h
+@@ -0,0 +1,48 @@
++/* acme-volume-gstreamer.h
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++ Copyright (C) 2004 Novell, Inc.
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ Jon Trowbridge <trow@ximian.com>
++ */
++
++#include <glib.h>
++#include <glib-object.h>
++#include "acme-volume.h"
++
++#define ACME_TYPE_VOLUME_GSTREAMER (acme_volume_gstreamer_get_type ())
++#define ACME_VOLUME_GSTREAMER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACME_TYPE_VOLUME_GSTREAMER, AcmeVolumeGStreamer))
++#define ACME_VOLUME_GSTREAMER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ACME_TYPE_VOLUME_GSTREAMER, AcmeVolumeGStreamerClass))
++#define ACME_IS_VOLUME_GSTREAMER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ACME_TYPE_VOLUME_GSTREAMER))
++#define ACME_VOLUME_GSTREAMER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ACME_TYPE_VOLUME_GSTREAMER, AcmeVolumeGStreamerClass))
++
++typedef struct AcmeVolumeGStreamer AcmeVolumeGStreamer;
++typedef struct AcmeVolumeGStreamerClass AcmeVolumeGStreamerClass;
++typedef struct AcmeVolumeGStreamerPrivate AcmeVolumeGStreamerPrivate;
++
++struct AcmeVolumeGStreamer {
++ AcmeVolume parent;
++ AcmeVolumeGStreamerPrivate *_priv;
++};
++
++struct AcmeVolumeGStreamerClass {
++ AcmeVolumeClass parent;
++};
++
++GType acme_volume_gstreamer_get_type (void);
+diff --git a/plugins/media-keys/actions/acme-volume-oss.c b/plugins/media-keys/actions/acme-volume-oss.c
+new file mode 100644
+index 0000000..26685ab
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-oss.c
+@@ -0,0 +1,215 @@
++/* acme-volume-oss.c
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#include "config.h"
++#include "acme-volume-oss.h"
++
++#include <fcntl.h>
++#include <unistd.h>
++#include <sys/ioctl.h>
++
++#ifdef __NetBSD__
++#include <sys/param.h>
++#include <sys/sysctl.h>
++#include <soundcard.h>
++#else
++#include <sys/soundcard.h>
++#endif /* __NetBSD__ */
++
++struct AcmeVolumeOssPrivate
++{
++ gboolean use_pcm;
++ gboolean mixerpb;
++ int volume;
++ int saved_volume;
++ gboolean pcm_avail;
++ gboolean mute;
++};
++
++static int acme_volume_oss_get_volume (AcmeVolume *self);
++static void acme_volume_oss_set_volume (AcmeVolume *self, int val);
++static gboolean acme_volume_oss_mixer_check (AcmeVolumeOss *self, int fd);
++
++G_DEFINE_TYPE (AcmeVolumeOss, acme_volume_oss, ACME_TYPE_VOLUME)
++
++static void
++acme_volume_oss_finalize (GObject *object)
++{
++ AcmeVolumeOss *self;
++
++ g_return_if_fail (object != NULL);
++ g_return_if_fail (ACME_IS_VOLUME_OSS (object));
++
++ self = ACME_VOLUME_OSS (object);
++
++ g_return_if_fail (self->_priv != NULL);
++ g_free (self->_priv);
++
++ G_OBJECT_CLASS (acme_volume_oss_parent_class)->finalize (object);
++}
++
++static int
++acme_volume_oss_vol_check (int volume)
++{
++ return CLAMP (volume, 0, 100);
++}
++
++static void
++acme_volume_oss_set_mute (AcmeVolume *vol, gboolean val)
++{
++ AcmeVolumeOss *self = (AcmeVolumeOss *) vol;
++
++ if (self->_priv->mute == FALSE)
++ {
++ self->_priv->saved_volume =
++ acme_volume_oss_get_volume (vol);
++ acme_volume_oss_set_volume (vol, 0);
++ self->_priv->mute = TRUE;
++ } else {
++ acme_volume_oss_set_volume (vol, self->_priv->saved_volume);
++ self->_priv->mute = FALSE;
++ }
++}
++
++static gboolean
++acme_volume_oss_get_mute (AcmeVolume *vol)
++{
++ AcmeVolumeOss *self = (AcmeVolumeOss *) vol;
++
++ /* somebody else might have changed the volume */
++ if ((self->_priv->mute == TRUE) && (self->_priv->volume != 0))
++ {
++ self->_priv->mute = FALSE;
++ }
++
++ return self->_priv->mute;
++}
++
++static int
++acme_volume_oss_get_volume (AcmeVolume *vol)
++{
++ gint volume, r, l, fd;
++ AcmeVolumeOss *self = (AcmeVolumeOss *) vol;
++
++ fd = open ("/dev/mixer", O_RDONLY);
++ if (acme_volume_oss_mixer_check(self, fd) == FALSE)
++ {
++ volume = 0;
++ } else {
++ if (self->_priv->use_pcm && self->_priv->pcm_avail)
++ ioctl (fd, MIXER_READ (SOUND_MIXER_PCM), &volume);
++ else
++ ioctl (fd, MIXER_READ (SOUND_MIXER_VOLUME), &volume);
++ close (fd);
++
++ r = (volume & 0xff);
++ l = (volume & 0xff00) >> 8;
++ volume = (r + l) / 2;
++ volume = acme_volume_oss_vol_check (volume);
++ }
++
++ return volume;
++}
++
++static void
++acme_volume_oss_set_volume (AcmeVolume *vol, int val)
++{
++ int fd, tvol, volume;
++ AcmeVolumeOss *self = (AcmeVolumeOss *) vol;
++
++ volume = acme_volume_oss_vol_check (val);
++
++ fd = open ("/dev/mixer", O_RDONLY);
++ if (acme_volume_oss_mixer_check (self, fd) == FALSE)
++ {
++ return;
++ } else {
++ tvol = (volume << 8) + volume;
++ if (self->_priv->use_pcm && self->_priv->pcm_avail)
++ ioctl (fd, MIXER_WRITE (SOUND_MIXER_PCM), &tvol);
++ else
++ ioctl (fd, MIXER_WRITE (SOUND_MIXER_VOLUME), &tvol);
++ close (fd);
++ self->_priv->volume = volume;
++ }
++}
++
++static int
++acme_volume_oss_get_threshold (AcmeVolume *vol)
++{
++ return 1;
++}
++
++static void
++acme_volume_oss_init (AcmeVolumeOss *self)
++{
++ int fd;
++
++ self->_priv = g_new0 (AcmeVolumeOssPrivate, 1);
++
++ fd = open ("/dev/mixer", O_RDONLY);
++ if (acme_volume_oss_mixer_check(self, fd) == FALSE)
++ {
++ self->_priv->pcm_avail = FALSE;
++ } else {
++ int mask = 0;
++
++ ioctl (fd, SOUND_MIXER_READ_DEVMASK, &mask);
++ if (mask & ( 1 << SOUND_MIXER_PCM))
++ self->_priv->pcm_avail = TRUE;
++ else
++ self->_priv->pcm_avail = FALSE;
++ if (!(mask & ( 1 << SOUND_MIXER_VOLUME)))
++ self->_priv->use_pcm = TRUE;
++
++ close (fd);
++ }
++}
++
++static void
++acme_volume_oss_class_init (AcmeVolumeOssClass *klass)
++{
++ AcmeVolumeClass *volume_class = ACME_VOLUME_CLASS (klass);
++ G_OBJECT_CLASS (klass)->finalize = acme_volume_oss_finalize;
++
++ volume_class->set_volume = acme_volume_oss_set_volume;
++ volume_class->get_volume = acme_volume_oss_get_volume;
++ volume_class->set_mute = acme_volume_oss_set_mute;
++ volume_class->get_mute = acme_volume_oss_get_mute;
++ volume_class->get_threshold = acme_volume_oss_get_threshold;
++}
++
++static gboolean
++acme_volume_oss_mixer_check (AcmeVolumeOss *self, int fd)
++{
++ gboolean retval;
++
++ if (fd <0) {
++ if (self->_priv->mixerpb == FALSE) {
++ self->_priv->mixerpb = TRUE;
++ //FIXME
++ //volume_oss_fd_problem(self);
++ }
++ }
++ retval = (!self->_priv->mixerpb);
++ return retval;
++}
+diff --git a/plugins/media-keys/actions/acme-volume-oss.h b/plugins/media-keys/actions/acme-volume-oss.h
+new file mode 100644
+index 0000000..b8805af
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume-oss.h
+@@ -0,0 +1,47 @@
++/* acme-volume-oss.h
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#include <glib.h>
++#include <glib-object.h>
++#include "acme-volume.h"
++
++#define ACME_TYPE_VOLUME_OSS (acme_volume_get_type ())
++#define ACME_VOLUME_OSS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACME_TYPE_VOLUME_OSS, AcmeVolumeOss))
++#define ACME_VOLUME_OSS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ACME_TYPE_VOLUME_OSS, AcmeVolumeOssClass))
++#define ACME_IS_VOLUME_OSS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ACME_TYPE_VOLUME_OSS))
++#define ACME_VOLUME_OSS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ACME_TYPE_VOLUME_OSS, AcmeVolumeOssClass))
++
++typedef struct AcmeVolumeOss AcmeVolumeOss;
++typedef struct AcmeVolumeOssClass AcmeVolumeOssClass;
++typedef struct AcmeVolumeOssPrivate AcmeVolumeOssPrivate;
++
++struct AcmeVolumeOss {
++ AcmeVolume parent;
++ AcmeVolumeOssPrivate *_priv;
++};
++
++struct AcmeVolumeOssClass {
++ AcmeVolumeClass parent;
++};
++
++GType acme_volume_oss_get_type (void);
++
+diff --git a/plugins/media-keys/actions/acme-volume.c b/plugins/media-keys/actions/acme-volume.c
+new file mode 100644
+index 0000000..b912749
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume.c
+@@ -0,0 +1,125 @@
++/* acme-volume.c
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#include "config.h"
++#include "acme-volume.h"
++#ifdef HAVE_OSS
++#include "acme-volume-oss.h"
++#endif
++#ifdef HAVE_ALSA
++#include "acme-volume-alsa.h"
++#endif
++#ifdef HAVE_GSTREAMER
++#include "acme-volume-gstreamer.h"
++#endif
++
++G_DEFINE_TYPE (AcmeVolume, acme_volume, G_TYPE_OBJECT)
++
++static void
++acme_volume_class_init (AcmeVolumeClass *klass)
++{
++}
++
++static void
++acme_volume_init (AcmeVolume *vol)
++{
++}
++
++int
++acme_volume_get_volume (AcmeVolume *self)
++{
++ g_return_val_if_fail (self != NULL, 0);
++ g_return_val_if_fail (ACME_IS_VOLUME (self), 0);
++
++ return ACME_VOLUME_GET_CLASS (self)->get_volume (self);
++}
++
++void
++acme_volume_set_volume (AcmeVolume *self, int val)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (ACME_IS_VOLUME (self));
++
++ ACME_VOLUME_GET_CLASS (self)->set_volume (self, val);
++}
++
++gboolean
++acme_volume_get_mute (AcmeVolume *self)
++{
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (ACME_IS_VOLUME (self), FALSE);
++
++ return ACME_VOLUME_GET_CLASS (self)->get_mute (self);
++}
++
++void
++acme_volume_set_mute (AcmeVolume *self, gboolean val)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (ACME_IS_VOLUME (self));
++
++ ACME_VOLUME_GET_CLASS (self)->set_mute (self, val);
++}
++
++void
++acme_volume_mute_toggle (AcmeVolume *self)
++{
++ gboolean muted;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (ACME_IS_VOLUME (self));
++
++ muted = ACME_VOLUME_GET_CLASS (self)->get_mute (self);
++ ACME_VOLUME_GET_CLASS (self)->set_mute (self, !muted);
++}
++
++int
++acme_volume_get_threshold (AcmeVolume *self)
++{
++ g_return_val_if_fail (self != NULL, 0);
++ g_return_val_if_fail (ACME_IS_VOLUME (self), 0);
++
++ return ACME_VOLUME_GET_CLASS (self)->get_threshold (self);
++}
++
++AcmeVolume *acme_volume_new (void)
++{
++ AcmeVolume *vol;
++
++#ifdef HAVE_GSTREAMER
++ vol = ACME_VOLUME (g_object_new (acme_volume_gstreamer_get_type (), NULL));
++ return vol;
++#endif
++#ifdef HAVE_ALSA
++ vol = ACME_VOLUME (g_object_new (acme_volume_alsa_get_type (), NULL));
++ if (vol != NULL && ACME_VOLUME_ALSA (vol)->_priv != NULL)
++ return vol;
++ if (ACME_VOLUME_ALSA (vol)->_priv == NULL)
++ g_object_unref (vol);
++#endif
++#ifdef HAVE_OSS
++ vol = ACME_VOLUME (g_object_new (acme_volume_oss_get_type (), NULL));
++ return vol;
++#endif
++ return NULL;
++}
++
+diff --git a/plugins/media-keys/actions/acme-volume.h b/plugins/media-keys/actions/acme-volume.h
+new file mode 100644
+index 0000000..ec5ee3d
+--- /dev/null
++++ b/plugins/media-keys/actions/acme-volume.h
+@@ -0,0 +1,63 @@
++/* acme-volume.h
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++
++ The Gnome Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The Gnome Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the Gnome Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA.
++
++ Author: Bastien Nocera <hadess@hadess.net>
++ */
++
++#ifndef _ACME_VOLUME_H
++#define _ACME_VOLUME_H
++
++#include <glib.h>
++#include <glib-object.h>
++
++G_BEGIN_DECLS
++
++#define ACME_TYPE_VOLUME (acme_volume_get_type ())
++#define ACME_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACME_TYPE_VOLUME, AcmeVolume))
++#define ACME_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ACME_TYPE_VOLUME, AcmeVolumeClass))
++#define ACME_IS_VOLUME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ACME_TYPE_VOLUME))
++#define ACME_VOLUME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ACME_TYPE_VOLUME, AcmeVolumeClass))
++
++typedef struct {
++ GObject parent;
++} AcmeVolume;
++
++typedef struct {
++ GObjectClass parent;
++
++ void (* set_volume) (AcmeVolume *self, int val);
++ int (* get_volume) (AcmeVolume *self);
++ void (* set_mute) (AcmeVolume *self, gboolean val);
++ int (* get_mute) (AcmeVolume *self);
++ int (* get_threshold) (AcmeVolume *self);
++} AcmeVolumeClass;
++
++GType acme_volume_get_type (void);
++int acme_volume_get_volume (AcmeVolume *self);
++void acme_volume_set_volume (AcmeVolume *self, int val);
++gboolean acme_volume_get_mute (AcmeVolume *self);
++void acme_volume_set_mute (AcmeVolume *self,
++ gboolean val);
++void acme_volume_mute_toggle (AcmeVolume *self);
++int acme_volume_get_threshold (AcmeVolume *self);
++AcmeVolume *acme_volume_new (void);
++
++G_END_DECLS
++
++#endif /* _ACME_VOLUME_H */
+diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
+index d35048c..205d25b 100644
+--- a/plugins/media-keys/gsd-media-keys-manager.c
++++ b/plugins/media-keys/gsd-media-keys-manager.c
+@@ -48,11 +48,12 @@
+
+ #include "eggaccelerators.h"
+ #include "acme.h"
+-#include "gsd-media-keys-window.h"
+-
+ #ifdef HAVE_PULSE
+ #include "gvc-mixer-control.h"
++#else
++#include "actions/acme-volume.h"
+ #endif /* HAVE_PULSE */
++#include "gsd-media-keys-window.h"
+
+ #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
+ #define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
+@@ -90,6 +91,8 @@ struct GsdMediaKeysManagerPrivate
+ /* Number of expected update signals, zero meaning we
+ * shouldn't be showing any update dialogues */
+ guint num_expected_update_signals;
++#else
++ AcmeVolume *volume;
+ #endif /* HAVE_PULSE */
+ GtkWidget *dialog;
+ GConfClient *conf_client;
+@@ -650,40 +653,75 @@ on_stream_event_notify (GObject *object,
+ {
+ update_dialog (manager);
+ }
+-
++#endif /* HAVE_PULSE */
+ static void
+ do_sound_action (GsdMediaKeysManager *manager,
+ int type)
+ {
+ gboolean muted;
++#ifdef HAVE_PULSE
+ guint vol, norm_vol_step;
+ int vol_step;
++#else
++ int vol;
++ int vol_step;
++ GError *error = NULL;
++#endif
+
++#ifdef HAVE_PULSE
+ if (manager->priv->stream == NULL)
++#else
++ if (manager->priv->volume == NULL)
++#endif
+ return;
+
+ vol_step = gconf_client_get_int (manager->priv->conf_client,
+ GCONF_MISC_DIR "/volume_step",
+- NULL);
++ &error);
+
+- if (vol_step <= 0 || vol_step > 100)
++#ifdef HAVE_PULSE
++ if (vol_step <= 0 || vol_step > 100) {
++#else
++ if (error) {
++#endif
+ vol_step = VOLUME_STEP;
++ g_error_free (error);
++ }
+
++#ifdef HAVE_PULSE
+ norm_vol_step = PA_VOLUME_NORM * vol_step / 100;
++#else
++ if (vol_step > 0) {
++ int threshold = acme_volume_get_threshold (manager->priv->volume);
++ if (vol_step < threshold)
++ vol_step = threshold;
++ g_debug ("Using volume step of %d", vol_step);
++ }
++#endif
+
+ /* FIXME: this is racy */
++#ifdef HAVE_PULSE
+ vol = gvc_mixer_stream_get_volume (manager->priv->stream);
+ muted = gvc_mixer_stream_get_is_muted (manager->priv->stream);
+ /* By default, we would be showing a dialogue
+ * based on the current values, eg. an unchanged dialogue */
+ manager->priv->num_expected_update_signals = 0;
++#else
++ vol = acme_volume_get_volume (manager->priv->volume);
++ muted = acme_volume_get_mute (manager->priv->volume);
++#endif
+
+ switch (type) {
+ case MUTE_KEY:
++#ifdef HAVE_PULSE
+ manager->priv->num_expected_update_signals = 1;
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, !muted);
++#else
++ acme_volume_mute_toggle (manager->priv->volume);
++#endif
+ break;
+ case VOLUME_DOWN_KEY:
++#ifdef HAVE_PULSE
+ if (!muted && (vol <= norm_vol_step)) {
+ manager->priv->num_expected_update_signals = 2;
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, !muted);
+@@ -692,18 +730,29 @@ do_sound_action (GsdMediaKeysManager *manager,
+ manager->priv->num_expected_update_signals = 1;
+ gvc_mixer_stream_change_volume (manager->priv->stream, vol - norm_vol_step);
+ }
++#else
++ if (!muted && (vol <= vol_step)) {
++ acme_volume_mute_toggle (manager->priv->volume);
++ }
++ acme_volume_set_volume (manager->priv->volume, vol - vol_step);
++#endif
+ break;
+ case VOLUME_UP_KEY:
+ if (muted) {
+ if (vol == 0) {
++#ifdef HAVE_PULSE
+ manager->priv->num_expected_update_signals = 2;
+ gvc_mixer_stream_change_volume (manager->priv->stream, vol + norm_vol_step);
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, !muted);
+ } else {
+ manager->priv->num_expected_update_signals = 1;
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, !muted);
++#else
++ acme_volume_set_volume (manager->priv->volume, vol + vol_step);
++#endif
+ }
+ } else {
++#ifdef HAVE_PULSE
+ if (vol < MAX_VOLUME) {
+ manager->priv->num_expected_update_signals = 1;
+ if (vol + norm_vol_step >= MAX_VOLUME) {
+@@ -712,17 +761,37 @@ do_sound_action (GsdMediaKeysManager *manager,
+ gvc_mixer_stream_change_volume (manager->priv->stream, vol + norm_vol_step);
+ }
+ }
++#else
++ acme_volume_set_volume (manager->priv->volume, vol + vol_step);
++#endif
+ }
+ break;
+ }
+
++#ifdef HAVE_PULSE
+ /* We didn't actually make any changes, so force showing the dialogue */
+ if (manager->priv->num_expected_update_signals == 0) {
+ manager->priv->num_expected_update_signals = 1;
+ update_dialog (manager);
+ }
++#else
++ muted = acme_volume_get_mute (manager->priv->volume);
++ vol = acme_volume_get_volume (manager->priv->volume);
++
++ /* FIXME: AcmeVolume should probably emit signals
++ instead of doing it like this */
++ dialog_init (manager);
++ gsd_media_keys_window_set_volume_muted (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
++ muted);
++ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
++ vol);
++ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
++ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
++ dialog_show (manager);
++#endif
+ }
+
++#ifdef HAVE_PULSE
+ static void
+ update_default_sink (GsdMediaKeysManager *manager)
+ {
+@@ -887,9 +956,7 @@ do_action (GsdMediaKeysManager *manager,
+ case MUTE_KEY:
+ case VOLUME_DOWN_KEY:
+ case VOLUME_UP_KEY:
+-#ifdef HAVE_PULSE
+ do_sound_action (manager, type);
+-#endif /* HAVE_PULSE */
+ break;
+ case POWER_KEY:
+ do_exit_action (manager);
+@@ -1069,13 +1136,13 @@ gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
+ {
+ gnome_settings_profile_start (NULL);
+
+-#ifdef HAVE_PULSE
+ /* initialise Volume handler
+ *
+ * We do this one here to force checking gstreamer cache, etc.
+ * The rest (grabbing and setting the keys) can happen in an
+ * idle.
+ */
++#ifdef HAVE_PULSE
+ gnome_settings_profile_start ("gvc_mixer_control_new");
+
+ manager->priv->volume = gvc_mixer_control_new ();
+@@ -1092,6 +1159,10 @@ gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
+ gvc_mixer_control_open (manager->priv->volume);
+
+ gnome_settings_profile_end ("gvc_mixer_control_new");
++#else
++ gnome_settings_profile_start ("acme_volume_new");
++ manager->priv->volume = acme_volume_new ();
++ gnome_settings_profile_end ("acme_volume_new");
+ #endif /* HAVE_PULSE */
+ g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager);
+
+@@ -1164,12 +1235,12 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
+ g_object_unref (priv->stream);
+ priv->stream = NULL;
+ }
++#endif /* HAVE_PULSE */
+
+ if (priv->volume) {
+ g_object_unref (priv->volume);
+ priv->volume = NULL;
+ }
+-#endif /* HAVE_PULSE */
+
+ if (priv->dialog != NULL) {
+ gtk_widget_destroy (priv->dialog);
+--
+1.6.1.2
+