summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRomain Perier <mrpouet@gentoo.org>2010-04-06 20:21:08 +0200
committerRomain Perier <mrpouet@gentoo.org>2010-04-06 20:21:08 +0200
commit765796a48a69f35ccf1f8fd7983cdd2cf70e68a5 (patch)
tree2a81e51b12111f7f0ba915fa99e1cb873cf45e0f
parentgnome-extra/indicator-application: (diff)
downloadmrpouet-master.tar.gz
mrpouet-master.tar.bz2
mrpouet-master.zip
gnome-base/gnome-settings-daemon:HEADmaster
* Port settings-daemon to notify OSD gnome-extra/xchat-indicator: * New ebuild
-rw-r--r--gnome-base/gnome-settings-daemon/Manifest4
-rw-r--r--gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-gst-vol-control-support.patch856
-rw-r--r--gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-osd-notifications.patch670
-rw-r--r--gnome-base/gnome-settings-daemon/gnome-settings-daemon-2.30.0-r1.ebuild85
-rw-r--r--gnome-extra/xchat-indicator/Manifest2
-rw-r--r--gnome-extra/xchat-indicator/xchat-indicator-0.3.2.ebuild35
6 files changed, 1652 insertions, 0 deletions
diff --git a/gnome-base/gnome-settings-daemon/Manifest b/gnome-base/gnome-settings-daemon/Manifest
new file mode 100644
index 0000000..bb17bb1
--- /dev/null
+++ b/gnome-base/gnome-settings-daemon/Manifest
@@ -0,0 +1,4 @@
+AUX gnome-settings-daemon-2.30.0-gst-vol-control-support.patch 27189 RMD160 77e44583894977b6255fba168d565c5948481401 SHA1 8db1dde75b1866619d6589e989ed27fc45050c50 SHA256 0858e7fdb97086f7f0a284d535d642c23f06fb7d9fc71d9f7477dc856439a158
+AUX gnome-settings-daemon-2.30.0-osd-notifications.patch 27262 RMD160 7821d5b11c058f1a40fe71e4fefd33e8c2633d62 SHA1 2a9f33f69dbfa1d22e29a6e71d6528eb1c889d77 SHA256 2a99de82289ca80281a4c71c5b38b19edf30a9f78a4dd9b355b43e1bf1d8fff2
+DIST gnome-settings-daemon-2.30.0.tar.bz2 1230687 RMD160 b88c58ab6344c78990aa84c999a0c33f00f3a273 SHA1 af65282fd28249a7958115568cc4e410858c4f26 SHA256 cb759f2aa403ad10f7b0a196c523fa0b3842cf4432b26a4b308ed1e5bf67e6aa
+EBUILD gnome-settings-daemon-2.30.0-r1.ebuild 2113 RMD160 f7b9155c01318b77f7211d55cc9d4d753c8b92ad SHA1 4611e42ec9bd671dbd04bda0a5ef39d55c089a8b SHA256 6ef84aa58d3e3a90b86e1c33b078bf95d32bc73aea74342417bac5236fd9cda3
diff --git a/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-gst-vol-control-support.patch b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-gst-vol-control-support.patch
new file mode 100644
index 0000000..57bb633
--- /dev/null
+++ b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-gst-vol-control-support.patch
@@ -0,0 +1,856 @@
+From 32a79f1b04c352dc9b9c28c4bdd3d772eeff974d Mon Sep 17 00:00:00 2001
+From: Priit Laes <plaes@plaes.org>
+Date: Wed, 31 Mar 2010 20:53:05 +0300
+Subject: [PATCH] GStreamer support in the volume applet; powered by the Gentoo GNOME team.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=571145
+---
+ configure.ac | 43 ++
+ plugins/media-keys/Makefile.am | 15 +-
+ plugins/media-keys/cut-n-paste/Makefile.am | 34 ++-
+ .../cut-n-paste/gvc-gstreamer-acme-vol.c | 402 ++++++++++++++++++++
+ .../cut-n-paste/gvc-gstreamer-acme-vol.h | 56 +++
+ plugins/media-keys/gsd-media-keys-manager.c | 64 +++-
+ 6 files changed, 589 insertions(+), 25 deletions(-)
+ create mode 100644 plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.c
+ create mode 100644 plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.h
+
+diff --git a/configure.ac b/configure.ac
+index 92f20c8..723a0cf 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -251,6 +251,48 @@ 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_pulse" = "xtrue"; then
++ AC_MSG_ERROR([*** GStreamer & Pulseaudio both are selected ***])
++ fi
++
++ if test "x$have_gstreamer" = "xyes"; then
++ GST_LIBS="$GST_LIBS -lgstinterfaces-0.10 -lgstaudio-0.10"
++ AC_DEFINE(HAVE_GSTREAMER,1,[enable gstreamer])
++ 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)
++
+ # ---------------------------------------------------------------------------
+ # Enable Profiling
+ # ---------------------------------------------------------------------------
+@@ -389,6 +431,7 @@ echo "
+ dbus-1 system.d dir: ${DBUS_SYS_DIR}
+
+ Libnotify support: ${have_libnotify}
++ 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 f9a71cd..92b19f4 100644
+--- a/plugins/media-keys/Makefile.am
++++ b/plugins/media-keys/Makefile.am
+@@ -3,13 +3,8 @@ context = actions
+
+ NULL =
+
+-SUBDIRS =
+-plugin_LTLIBRARIES =
+-
+-if HAVE_PULSE
+-SUBDIRS += cut-n-paste
+-plugin_LTLIBRARIES += libmedia-keys.la
+-endif
++SUBDIRS = cut-n-paste
++plugin_LTLIBRARIES = libmedia-keys.la
+
+ BUILT_SOURCES = \
+ gsd-media-keys-manager-glue.h \
+@@ -100,7 +95,7 @@ libmedia_keys_la_LDFLAGS = \
+
+ libmedia_keys_la_LIBADD = \
+ $(top_builddir)/plugins/common/libcommon.la \
+- $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \
++ $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(XF86MISC_LIBS) \
+ -lm
+@@ -108,9 +103,7 @@ libmedia_keys_la_LIBADD = \
+ plugin_in_files = \
+ media-keys.gnome-settings-plugin.in
+
+-if HAVE_PULSE
+ plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin)
+-endif
+
+ noinst_PROGRAMS = \
+ test-media-keys \
+@@ -176,9 +169,7 @@ test_media_keys_LDADD = \
+ $(GST_LIBS) \
+ -lm
+
+-if HAVE_PULSE
+ test_media_keys_LDADD += $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la
+-endif
+
+ gtkbuilderdir = $(pkgdatadir)
+ gtkbuilder_DATA = \
+diff --git a/plugins/media-keys/cut-n-paste/Makefile.am b/plugins/media-keys/cut-n-paste/Makefile.am
+index bc59a10..6486ac0 100644
+--- a/plugins/media-keys/cut-n-paste/Makefile.am
++++ b/plugins/media-keys/cut-n-paste/Makefile.am
+@@ -4,16 +4,24 @@ noinst_LTLIBRARIES = libgvc.la
+
+ INCLUDES = \
+ $(WARN_CFLAGS) \
+- $(VOLUME_CONTROL_CFLAGS) \
+- $(PULSE_CFLAGS) \
+ $(NULL)
+
+ libgvc_la_LIBADD = \
+- $(VOLUME_CONTROL_LIBS) \
+- $(PULSE_LIBS) \
+ $(NULL)
+
+ libgvc_la_SOURCES = \
++ $(NULL)
++
++if HAVE_PULSE
++INCLUDES += \
++ $(VOLUME_CONTROL_CFLAGS) \
++ $(PULSE_CFLAGS)
++
++libgvc_la_LIBADD += \
++ $(VOLUME_CONTROL_LIBS) \
++ $(PULSE_LIBS)
++
++libgvc_la_SOURCES += \
+ gvc-mixer-stream.h \
+ gvc-mixer-stream.c \
+ gvc-channel-map.h \
+@@ -31,8 +39,22 @@ libgvc_la_SOURCES = \
+ gvc-mixer-event-role.h \
+ gvc-mixer-event-role.c \
+ gvc-mixer-control.h \
+- gvc-mixer-control.c \
+- $(NULL)
++ gvc-mixer-control.c
++endif
++
++if HAVE_GSTREAMER
++INCLUDES += \
++ $(SETTINGS_PLUGIN_CFLAGS) \
++ $(AM_CFLAGS) \
++ $(GST_CFLAGS)
++
++libgvc_la_LIBADD += \
++ $(GST_LIBS)
++
++libgvc_la_SOURCES += \
++ gvc-gstreamer-acme-vol.c \
++ gvc-gstreamer-acme-vol.h
++endif
+
+ MAINTAINERCLEANFILES = \
+ *~ \
+diff --git a/plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.c b/plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.c
+new file mode 100644
+index 0000000..8948480
+--- /dev/null
++++ b/plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.c
+@@ -0,0 +1,402 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
++
++/* acme-volume.c
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++ Copyright (C) 2004 Novell, Inc.
++ Copyright (C) 2009 PERIER Romain <mrpouet@tuxfamily.org>
++
++ 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 "gvc-gstreamer-acme-vol.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_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ACME_TYPE_VOLUME, AcmeVolumePrivate))
++
++struct AcmeVolumePrivate {
++ GstMixer *mixer;
++ GList *mixer_tracks;
++ guint timer_id;
++ gdouble volume;
++ gboolean mute;
++ GConfClient *gconf_client;
++};
++
++G_DEFINE_TYPE (AcmeVolume, acme_volume, G_TYPE_OBJECT)
++
++static gboolean acme_volume_open (AcmeVolume *acme);
++static void acme_volume_close (AcmeVolume *acme);
++static gboolean acme_volume_close_real (AcmeVolume *self);
++
++static gpointer acme_volume_object = NULL;
++
++static void
++acme_volume_finalize (GObject *object)
++{
++ AcmeVolume *self;
++
++ g_return_if_fail (object != NULL);
++ g_return_if_fail (ACME_IS_VOLUME (object));
++
++ self = ACME_VOLUME (object);
++
++ if (self->_priv->timer_id != 0)
++ g_source_remove (self->_priv->timer_id);
++ acme_volume_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_parent_class)->finalize (object);
++}
++
++void
++acme_volume_set_mute (AcmeVolume *self, gboolean val)
++{
++ GList *t;
++
++ g_return_if_fail(ACME_IS_VOLUME(self));
++ g_return_if_fail(acme_volume_open(self));
++
++ 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);
++ }
++ self->_priv->mute = val;
++ acme_volume_close (self);
++}
++
++static void
++update_state (AcmeVolume * 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;
++ self->_priv->volume = vol;
++}
++
++gboolean
++acme_volume_get_mute (AcmeVolume *self)
++{
++ g_return_val_if_fail(acme_volume_open(self), FALSE);
++
++ update_state (self);
++ acme_volume_close (self);
++
++ return self->_priv->mute;
++}
++
++gint
++acme_volume_get_volume (AcmeVolume *self)
++{
++
++ g_return_val_if_fail(acme_volume_open(self), 0);
++
++ update_state (self);
++
++ acme_volume_close (self);
++
++ return (gint) (self->_priv->volume + 0.5);
++}
++
++void
++acme_volume_set_volume (AcmeVolume *self, gint val)
++{
++ GList *t;
++
++ g_return_if_fail(acme_volume_open(self));
++
++ 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_close (self);
++}
++
++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_mute(self);
++ acme_volume_set_mute(self, !muted);
++}
++
++gint
++acme_volume_get_threshold (AcmeVolume *self)
++{
++ GList *t;
++ gint steps = 101;
++
++ g_return_val_if_fail(acme_volume_open(self), 1);
++
++ for (t = self->_priv->mixer_tracks; t != NULL; t = t->next) {
++ GstMixerTrack *track = GST_MIXER_TRACK (t->data);
++ gint track_steps = track->max_volume - track->min_volume;
++ if (track_steps > 0 && track_steps < steps)
++ steps = track_steps;
++ }
++
++ acme_volume_close (self);
++
++ return 100 / steps + 1;
++}
++
++static gboolean
++acme_volume_close_real (AcmeVolume *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
++ * @mixer A pointer to mixer element
++ * @data A pointer to user data (AcmeVolume instance to be modified)
++ * @return A gboolean indicating success if Master track was found, failed otherwises.
++ */
++static gboolean
++_acme_set_mixer(GstMixer *mixer, gpointer user_data)
++{
++ const GList *tracks;
++
++ for (tracks = gst_mixer_list_tracks (mixer); tracks != NULL; tracks = tracks->next) {
++ GstMixerTrack *track = GST_MIXER_TRACK (tracks->data);
++
++ if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MASTER)) {
++ AcmeVolume *self;
++
++ self = ACME_VOLUME (user_data);
++
++ self->_priv->mixer = mixer;
++ self->_priv->mixer_tracks = g_list_append (self->_priv->mixer_tracks, g_object_ref (track));
++ return TRUE;
++ }
++
++ continue;
++ }
++
++ return FALSE;
++}
++
++/* This is a modified version of code from gnome-media's gst-mixer */
++static gboolean
++acme_volume_open (AcmeVolume *self)
++{
++ 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;
++ GError *error = NULL;
++
++ /* Try to use tracks saved in GConf
++ Note: errors need to be treated , for example if the user set a non type list for this key
++ or if the elements type_list are not "matched" */
++ tracks = gconf_client_get_list (self->_priv->gconf_client, DEFAULT_MIXER_TRACKS_KEY,
++ GCONF_VALUE_STRING, &error);
++
++ if (error) {
++ g_warning("ERROR: %s\n", error->message);
++ g_error_free(error);
++ }
++
++ /* We use these tracks ONLY if they are supported on the system with the following mixer */
++ 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_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_close (AcmeVolume *self)
++{
++ self->_priv->timer_id = g_timeout_add_seconds (TIMEOUT,
++ (GSourceFunc) acme_volume_close_real, self);
++}
++
++static void
++acme_volume_init (AcmeVolume *self)
++{
++ self->_priv = ACME_VOLUME_GET_PRIVATE (self);
++ self->_priv->gconf_client = gconf_client_get_default ();
++}
++
++static void
++acme_volume_class_init (AcmeVolumeClass *klass)
++{
++ G_OBJECT_CLASS (klass)->finalize = acme_volume_finalize;
++
++ gst_init (NULL, NULL);
++
++ g_type_class_add_private (klass, sizeof (AcmeVolumePrivate));
++}
++
++/* acme_volume_new
++ * @return A singleton instance of type AcmeVolume
++ */
++AcmeVolume *
++acme_volume_new (void)
++{
++ if (acme_volume_object == NULL) {
++ acme_volume_object = g_object_new (ACME_TYPE_VOLUME, NULL);
++ return ACME_VOLUME(acme_volume_object);
++ }
++ g_object_ref(acme_volume_object);
++ return ACME_VOLUME(acme_volume_object);
++}
++
+diff --git a/plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.h b/plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.h
+new file mode 100644
+index 0000000..c14ebc8
+--- /dev/null
++++ b/plugins/media-keys/cut-n-paste/gvc-gstreamer-acme-vol.h
+@@ -0,0 +1,56 @@
++/* acme-volume.h
++
++ Copyright (C) 2002, 2003 Bastien Nocera
++ Copyright (C) 2004 Novell, Inc.
++ Copyright (C) 2009 PERIER Romain <mrpouet@tuxfamily.org>
++
++ 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-object.h>
++
++#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 AcmeVolume AcmeVolume;
++typedef struct AcmeVolumeClass AcmeVolumeClass;
++typedef struct AcmeVolumePrivate AcmeVolumePrivate;
++
++struct AcmeVolume {
++ GObject parent;
++ AcmeVolumePrivate *_priv;
++};
++
++struct AcmeVolumeClass {
++ GObjectClass parent;
++};
++
++GType acme_volume_get_type (void);
++AcmeVolume *acme_volume_new (void);
++void acme_volume_set_mute (AcmeVolume *self, gboolean val);
++void acme_volume_mute_toggle (AcmeVolume *self);
++gboolean acme_volume_get_mute (AcmeVolume *self);
++void acme_volume_set_volume (AcmeVolume *self, gint val);
++gint acme_volume_get_volume (AcmeVolume *self);
++gint acme_volume_get_threshold (AcmeVolume *self);
++
++
+diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
+index b563f73..64893b5 100644
+--- a/plugins/media-keys/gsd-media-keys-manager.c
++++ b/plugins/media-keys/gsd-media-keys-manager.c
+@@ -53,6 +53,8 @@
+ #ifdef HAVE_PULSE
+ #include <canberra-gtk.h>
+ #include "gvc-mixer-control.h"
++#elif defined(HAVE_GSTREAMER)
++#include "gvc-gstreamer-acme-vol.h"
+ #endif /* HAVE_PULSE */
+
+ #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
+@@ -78,6 +80,8 @@ struct GsdMediaKeysManagerPrivate
+ /* Volume bits */
+ GvcMixerControl *volume;
+ GvcMixerStream *stream;
++#elif defined(HAVE_GSTREAMER)
++ AcmeVolume *volume;
+ #endif /* HAVE_PULSE */
+ GtkWidget *dialog;
+ GConfClient *conf_client;
+@@ -650,14 +654,16 @@ do_touchpad_action (GsdMediaKeysManager *manager)
+ gconf_client_set_bool (client, TOUCHPAD_ENABLED_KEY, !state, NULL);
+ }
+
+-#ifdef HAVE_PULSE
++#if defined(HAVE_PULSE) || defined(HAVE_GSTREAMER)
+ static void
+ update_dialog (GsdMediaKeysManager *manager,
+ guint vol,
+ gboolean muted,
+ gboolean sound_changed)
+ {
++#ifdef HAVE_PULSE
+ vol = (int) (100 * (double) vol / PA_VOLUME_NORM);
++#endif
+ vol = CLAMP (vol, 0, 100);
+
+ dialog_init (manager);
+@@ -668,12 +674,14 @@ update_dialog (GsdMediaKeysManager *manager,
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+ dialog_show (manager);
+
++#ifdef HAVE_PULSE
+ if (sound_changed != FALSE && muted == FALSE)
+ ca_gtk_play_for_widget (manager->priv->dialog, 0,
+ CA_PROP_EVENT_ID, "audio-volume-change",
+ CA_PROP_EVENT_DESCRIPTION, "volume changed through key press",
+ CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
+ NULL);
++#endif
+ }
+
+ static void
+@@ -685,7 +693,11 @@ do_sound_action (GsdMediaKeysManager *manager,
+ int vol_step;
+ gboolean sound_changed;
+
++#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,
+@@ -695,20 +707,35 @@ do_sound_action (GsdMediaKeysManager *manager,
+ if (vol_step <= 0 || vol_step > 100)
+ vol_step = VOLUME_STEP;
+
++ sound_changed = FALSE;
++#ifdef HAVE_PULSE
+ norm_vol_step = PA_VOLUME_NORM * vol_step / 100;
+
+ /* FIXME: this is racy */
+ vol = gvc_mixer_stream_get_volume (manager->priv->stream);
+ muted = gvc_mixer_stream_get_is_muted (manager->priv->stream);
+- sound_changed = FALSE;
+-
++#else
++ if (vol_step > 0) {
++ gint threshold = acme_volume_get_threshold (manager->priv->volume);
++ if (vol_step < threshold)
++ vol_step = threshold;
++ g_debug ("Using volume step of %d", vol_step);
++ }
++ vol = acme_volume_get_volume (manager->priv->volume);
++ muted = acme_volume_get_mute (manager->priv->volume);
++#endif
+ switch (type) {
+ case MUTE_KEY:
+ muted = !muted;
+- gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+ sound_changed = TRUE;
++#ifdef HAVE_PULSE
++ 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)) {
+ muted = !muted;
+ vol = 0;
+@@ -724,11 +751,17 @@ do_sound_action (GsdMediaKeysManager *manager,
+ sound_changed = TRUE;
+ }
+ }
++#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) {
+ muted = !muted;
+ if (vol == 0) {
++#ifdef HAVE_PULSE
+ vol = vol + norm_vol_step;
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+@@ -739,7 +772,15 @@ do_sound_action (GsdMediaKeysManager *manager,
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+ sound_changed = TRUE;
+ }
++#else
++ /* We need to unmute otherwise vol is blocked (and muted) */
++ acme_volume_set_mute (manager->priv->volume, FALSE);
++ }
++ acme_volume_set_volume (manager->priv->volume, vol + vol_step);
++
++#endif
+ } else {
++#ifdef HAVE_PULSE
+ if (vol < MAX_VOLUME) {
+ if (vol + norm_vol_step >= MAX_VOLUME) {
+ vol = MAX_VOLUME;
+@@ -751,13 +792,18 @@ do_sound_action (GsdMediaKeysManager *manager,
+ sound_changed = TRUE;
+ }
+ }
++#else
++ acme_volume_set_volume (manager->priv->volume, vol + vol_step);
++#endif /* HAVE_PULSE */
+ }
+ break;
+ }
+
+ update_dialog (manager, vol, muted, sound_changed);
+ }
++#endif /* defined(HAVE_PULSE) || defined(HAVE_GSTREAMER) */
+
++#ifdef HAVE_PULSE
+ static void
+ update_default_sink (GsdMediaKeysManager *manager)
+ {
+@@ -793,7 +839,6 @@ on_control_default_sink_changed (GvcMixerControl *control,
+ {
+ update_default_sink (manager);
+ }
+-
+ #endif /* HAVE_PULSE */
+
+ static gint
+@@ -919,9 +964,9 @@ do_action (GsdMediaKeysManager *manager,
+ case MUTE_KEY:
+ case VOLUME_DOWN_KEY:
+ case VOLUME_UP_KEY:
+-#ifdef HAVE_PULSE
++#if defined(HAVE_PULSE) || defined(HAVE_GSTREAMER)
+ do_sound_action (manager, type);
+-#endif /* HAVE_PULSE */
++#endif /* HAVE_PULSE || HAVE_GSTREAMER */
+ break;
+ case POWER_KEY:
+ do_exit_action (manager);
+@@ -1122,6 +1167,10 @@ gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
+ gvc_mixer_control_open (manager->priv->volume);
+
+ gnome_settings_profile_end ("gvc_mixer_control_new");
++#elif defined(HAVE_GSTREAMER)
++ 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);
+
+@@ -1199,6 +1248,7 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
+ g_object_unref (priv->stream);
+ priv->stream = NULL;
+ }
++#elif defined(HAVE_GSTREAMER)
+
+ if (priv->volume) {
+ g_object_unref (priv->volume);
+--
+1.7.0.3
+
diff --git a/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-osd-notifications.patch b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-osd-notifications.patch
new file mode 100644
index 0000000..9b2f131
--- /dev/null
+++ b/gnome-base/gnome-settings-daemon/files/gnome-settings-daemon-2.30.0-osd-notifications.patch
@@ -0,0 +1,670 @@
+ plugins/common/Makefile.am | 9 +-
+ plugins/common/gsd-osd-notification.c | 296 +++++++++++++++++++++++++++
+ plugins/common/gsd-osd-notification.h | 75 +++++++
+ plugins/media-keys/gsd-media-keys-manager.c | 106 +++++++---
+ 4 files changed, 456 insertions(+), 30 deletions(-)
+
+diff --git a/plugins/common/Makefile.am b/plugins/common/Makefile.am
+index 447d02d..94ad74f 100644
+--- a/plugins/common/Makefile.am
++++ b/plugins/common/Makefile.am
+@@ -7,17 +7,22 @@ libcommon_la_SOURCES = \
+ gsd-keygrab.c \
+ gsd-keygrab.h \
+ gsd-osd-window.c \
+- gsd-osd-window.h
++ gsd-osd-window.h \
++ gsd-osd-notification.c \
++ gsd-osd-notification.h
+
+ libcommon_la_CPPFLAGS = \
+ $(AM_CPPFLAGS)
+
+ libcommon_la_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
++ $(LIBNOTIFY_CFLAGS) \
+ $(AM_CFLAGS)
+
+ libcommon_la_LDFLAGS = \
+ $(GSD_PLUGIN_LDFLAGS) $(X11_LIBS)
+
+ libcommon_la_LIBADD = \
+- $(SETTINGS_PLUGIN_LIBS)
++ $(SETTINGS_PLUGIN_LIBS) \
++ $(LIBNOTIFY_LIBS)
++
+diff --git a/plugins/common/gsd-osd-notification.c b/plugins/common/gsd-osd-notification.c
+new file mode 100644
+index 0000000..8ebc5a5
+--- /dev/null
++++ b/plugins/common/gsd-osd-notification.c
+@@ -0,0 +1,296 @@
++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*- */
++/*
++ * gsd-osd-notification.c
++ * Copyright (C) 2010 Chris Coulson <chrisccoulson@ubuntu.com>
++ * Copyright (C) 2009 Canonical Ltd
++ *
++ * gsd-osd-notification.c is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * gsd-osd-notification.c 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 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 <libnotify/notify.h>
++#include "gsd-osd-notification.h"
++
++struct _GsdOsdNotificationPrivate
++{
++ NotifyNotification *notification;
++ char **icon_names;
++ char *hint;
++ guint icon_array_size;
++};
++
++#define GSD_OSD_NOTIFICATION_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_OSD_NOTIFICATION, GsdOsdNotificationPrivate))
++
++enum
++{
++ PROP_0,
++ PROP_ICON_NAMES,
++ PROP_HINT
++};
++
++static NotifyNotification *icon_only_notification = NULL;
++static gulong handler_id;
++
++#define NOTIFY_CAP_PRIVATE_SYNCHRONOUS "x-canonical-private-synchronous"
++#define NOTIFY_CAP_PRIVATE_ICON_ONLY "x-canonical-private-icon-only"
++#define NOTIFY_HINT_TRUE "true"
++
++G_DEFINE_TYPE (GsdOsdNotification, gsd_osd_notification, G_TYPE_OBJECT);
++
++static const char*
++_calculate_icon (GsdOsdNotification *notifier, guint value, gboolean muted)
++{
++ guint s;
++
++ s = (notifier->priv->icon_array_size -1) * value / 100 + 1;
++ s = MAX (s, 1);
++ s = MIN (s, notifier->priv->icon_array_size -1);
++ if (value <= 0)
++ s = 0;
++
++ return muted ? notifier->priv->icon_names[0] : notifier->priv->icon_names[s];
++}
++
++void
++gsd_osd_notification_set_icon_array (GsdOsdNotification *notifier, const char **icon_names)
++{
++ g_return_if_fail (GSD_IS_OSD_NOTIFICATION (notifier));
++
++ g_strfreev (notifier->priv->icon_names);
++ notifier->priv->icon_names = g_strdupv ((gchar **) icon_names);
++
++ notifier->priv->icon_array_size = g_strv_length ((gchar **) icon_names);
++}
++
++void
++gsd_osd_notification_set_hint (GsdOsdNotification *notifier, const char *hint)
++{
++ g_return_if_fail (GSD_IS_OSD_NOTIFICATION (notifier));
++
++ g_free (notifier->priv->hint);
++ notifier->priv->hint = g_strdup (hint);
++}
++
++gboolean
++gsd_osd_notification_is_supported (void)
++{
++ GList *caps;
++ gboolean has_cap;
++
++ caps = notify_get_server_caps ();
++ has_cap = (g_list_find_custom (caps, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, (GCompareFunc) g_strcmp0) != NULL);
++ g_list_foreach (caps, (GFunc) g_free, NULL);
++ g_list_free (caps);
++
++ return has_cap;
++}
++
++static void
++notification_closed_cb (NotifyNotification *notification,
++ gpointer data)
++{
++ g_signal_handler_disconnect (icon_only_notification, handler_id);
++ g_object_unref (icon_only_notification);
++ icon_only_notification = NULL;
++}
++
++gboolean
++gsd_osd_notification_show_icon_only (const char *icon, const char *hint)
++{
++ g_return_val_if_fail (icon != NULL, FALSE);
++ g_return_val_if_fail (hint != NULL, FALSE);
++
++ if (!gsd_osd_notification_is_supported ())
++ return FALSE;
++
++ if (icon_only_notification == NULL) {
++ icon_only_notification = notify_notification_new (" ", "", icon, NULL);
++ notify_notification_set_hint_string (icon_only_notification, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, hint);
++ notify_notification_set_hint_string (icon_only_notification, NOTIFY_CAP_PRIVATE_ICON_ONLY, NOTIFY_HINT_TRUE);
++ handler_id = g_signal_connect (icon_only_notification, "closed", G_CALLBACK (notification_closed_cb), NULL);
++ } else {
++ notify_notification_set_hint_string (icon_only_notification, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, hint);
++ notify_notification_update (icon_only_notification, " ", "", icon);
++ }
++
++ if (!notify_notification_show (icon_only_notification, NULL)) {
++ g_signal_handler_disconnect (icon_only_notification, handler_id);
++ g_object_unref (icon_only_notification);
++ icon_only_notification = NULL;
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++gboolean
++gsd_osd_notification_show_value (GsdOsdNotification *notifier, gint value, gboolean muted)
++{
++ const char *icon;
++
++ g_return_val_if_fail (GSD_IS_OSD_NOTIFICATION (notifier), FALSE);
++ g_return_val_if_fail (notifier->priv->icon_names != NULL, FALSE);
++ g_return_val_if_fail (notifier->priv->hint != NULL, FALSE);
++
++ if (!gsd_osd_notification_is_supported ())
++ return FALSE;
++
++ if (notifier->priv->notification == NULL) {
++ notifier->priv->notification = notify_notification_new (" ", "", NULL, NULL);
++ notify_notification_set_hint_string (notifier->priv->notification, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, notifier->priv->hint);
++}
++ if (notifier->priv->notification != NULL) {
++ value = MIN (value, 101);
++ value = MAX (value, -1);
++ icon = _calculate_icon (notifier, value, muted);
++ notify_notification_set_hint_int32(notifier->priv->notification, "value", (muted && value > 0) ? 0 : value);
++ notify_notification_update (notifier->priv->notification, " ", "", icon);
++ } else {
++ return FALSE;
++ }
++
++ if (!notify_notification_show (notifier->priv->notification, NULL))
++ return FALSE;
++
++ return TRUE;
++}
++
++gboolean
++gsd_osd_notification_show_overshoot (GsdOsdNotification *notifier, GsdOsdNotifierOvershootType type)
++{
++ gint value;
++ gboolean muted;
++
++ g_return_val_if_fail (type == GSD_OSD_NOTIFICATION_UNDERSHOOT || type == GSD_OSD_NOTIFICATION_OVERSHOOT, FALSE);
++
++ switch (type)
++ {
++ case GSD_OSD_NOTIFICATION_UNDERSHOOT:
++ value = -1;
++ muted = TRUE;
++ break;
++ case GSD_OSD_NOTIFICATION_OVERSHOOT:
++ value = 101;
++ muted = FALSE;
++ break;
++ default:
++ g_assert_not_reached ();
++ break;
++ }
++
++ return gsd_osd_notification_show_value (notifier, value, muted);
++}
++
++GsdOsdNotification*
++gsd_osd_notification_new (const char **icon_names, const char *hint)
++{
++ return (GsdOsdNotification *) g_object_new (GSD_TYPE_OSD_NOTIFICATION,
++ "icon-names", icon_names,
++ "hint", hint,
++ NULL);
++}
++
++static void
++gsd_osd_notification_init (GsdOsdNotification *object)
++{
++ object->priv = GSD_OSD_NOTIFICATION_PRIVATE (object);
++
++ if (!notify_is_initted ())
++ notify_init (g_get_application_name ());
++
++ object->priv->hint = NULL;
++ object->priv->icon_names = NULL;
++ object->priv->notification = NULL;
++}
++
++static void
++gsd_osd_notification_finalize (GObject *object)
++{
++ GsdOsdNotification *notifier = GSD_OSD_NOTIFICATION (object);
++
++ g_strfreev (notifier->priv->icon_names);
++ g_free (notifier->priv->hint);
++
++ if (notifier->priv->notification)
++ g_object_unref (notifier->priv->notification);
++
++ G_OBJECT_CLASS (gsd_osd_notification_parent_class)->finalize (object);
++}
++
++static void
++gsd_osd_notification_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
++{
++ g_return_if_fail (GSD_IS_OSD_NOTIFICATION (object));
++ GsdOsdNotification *notifier = GSD_OSD_NOTIFICATION (object);
++
++ switch (prop_id)
++ {
++ case PROP_ICON_NAMES:
++ gsd_osd_notification_set_icon_array (notifier, (const char**) g_value_get_boxed (value));
++ break;
++ case PROP_HINT:
++ gsd_osd_notification_set_hint (notifier, g_value_get_string (value));
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++ break;
++ }
++}
++
++static void
++gsd_osd_notification_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
++{
++ g_return_if_fail (GSD_IS_OSD_NOTIFICATION (object));
++ GsdOsdNotification *notifier = GSD_OSD_NOTIFICATION (object);
++
++ switch (prop_id)
++ {
++ case PROP_ICON_NAMES:
++ g_value_set_boxed (value, notifier->priv->icon_names);
++ break;
++ case PROP_HINT:
++ g_value_set_string (value, notifier->priv->hint);
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++ break;
++ }
++}
++
++static void
++gsd_osd_notification_class_init (GsdOsdNotificationClass *klass)
++{
++ GObjectClass* object_class = G_OBJECT_CLASS (klass);
++
++ object_class->finalize = gsd_osd_notification_finalize;
++ object_class->set_property = gsd_osd_notification_set_property;
++ object_class->get_property = gsd_osd_notification_get_property;
++
++ g_object_class_install_property (object_class,
++ PROP_ICON_NAMES,
++ g_param_spec_boxed ("icon-names",
++ "Icon name array",
++ "An array of icon names for the notification",
++ G_TYPE_STRV,
++ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
++
++ g_object_class_install_property (object_class,
++ PROP_HINT,
++ g_param_spec_string ("hint",
++ "Notification hint",
++ "Hint for the notification",
++ NULL,
++ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
++
++ g_type_class_add_private (klass, sizeof (GsdOsdNotificationPrivate));
++}
+diff --git a/plugins/common/gsd-osd-notification.h b/plugins/common/gsd-osd-notification.h
+new file mode 100644
+index 0000000..8205639
+--- /dev/null
++++ b/plugins/common/gsd-osd-notification.h
+@@ -0,0 +1,75 @@
++/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*- */
++/*
++ * gsd-osd-notification.c
++ * Copyright (C) 2010 Chris Coulson <chrisccoulson@ubuntu.com>
++ * Copyright (C) 2009 Canonical Ltd
++ *
++ * gsd-osd-notification.c is free software: you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * gsd-osd-notification.c 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 General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _GSD_OSD_NOTIFICATION_H_
++#define _GSD_OSD_NOTIFICATION_H_
++
++#include <glib-object.h>
++
++G_BEGIN_DECLS
++
++#define GSD_TYPE_OSD_NOTIFICATION (gsd_osd_notification_get_type ())
++#define GSD_OSD_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_OSD_NOTIFICATION, GsdOsdNotification))
++#define GSD_OSD_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSD_TYPE_OSD_NOTIFICATION, GsdOsdNotificationClass))
++#define GSD_IS_OSD_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSD_TYPE_OSD_NOTIFICATION))
++#define GSD_IS_OSD_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSD_TYPE_OSD_NOTIFICATION))
++#define GSD_OSD_NOTIFICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSD_TYPE_OSD_NOTIFICATION, GsdOsdNotificationClass))
++
++typedef struct _GsdOsdNotificationClass GsdOsdNotificationClass;
++typedef struct _GsdOsdNotification GsdOsdNotification;
++typedef struct _GsdOsdNotificationPrivate GsdOsdNotificationPrivate;
++
++struct _GsdOsdNotificationClass
++{
++ GObjectClass parent_class;
++};
++
++struct _GsdOsdNotification
++{
++ GObject parent_instance;
++
++ GsdOsdNotificationPrivate *priv;
++};
++
++typedef enum {
++ GSD_OSD_NOTIFICATION_NO_OVERSHOOT = 0,
++ GSD_OSD_NOTIFICATION_UNDERSHOOT,
++ GSD_OSD_NOTIFICATION_OVERSHOOT,
++} GsdOsdNotifierOvershootType;
++
++GType gsd_osd_notification_get_type (void) G_GNUC_CONST;
++GsdOsdNotification* gsd_osd_notification_new (const char **icon_names,
++ const char *hint);
++void gsd_osd_notification_set_icon_array (GsdOsdNotification *notifier,
++ const char **icon_names);
++void gsd_osd_notification_set_hint (GsdOsdNotification *notifier,
++ const char *hint);
++gboolean gsd_osd_notification_is_supported (void);
++gboolean gsd_osd_notification_show_value (GsdOsdNotification *notifier,
++ gint value,
++ gboolean muted);
++gboolean gsd_osd_notification_show_overshoot (GsdOsdNotification *notifier,
++ GsdOsdNotifierOvershootType type);
++gboolean gsd_osd_notification_show_icon_only (const char *icon,
++ const char *hint);
++
++G_END_DECLS
++
++#endif /* _GSD_OSD_NOTIFICATION_H_ */
+diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
+index 64893b5..ef977f0 100644
+--- a/plugins/media-keys/gsd-media-keys-manager.c
++++ b/plugins/media-keys/gsd-media-keys-manager.c
+@@ -49,6 +49,7 @@
+ #include "eggaccelerators.h"
+ #include "acme.h"
+ #include "gsd-media-keys-window.h"
++#include "gsd-osd-notification.h"
+
+ #ifdef HAVE_PULSE
+ #include <canberra-gtk.h>
+@@ -86,6 +87,7 @@ struct GsdMediaKeysManagerPrivate
+ GtkWidget *dialog;
+ GConfClient *conf_client;
+ GVolumeMonitor *volume_monitor;
++ GsdOsdNotification *notifier;
+
+ /* Multihead stuff */
+ GdkScreen *current_screen;
+@@ -112,6 +114,13 @@ G_DEFINE_TYPE (GsdMediaKeysManager, gsd_media_keys_manager, G_TYPE_OBJECT)
+
+ static gpointer manager_object = NULL;
+
++static const char *volume_icons[] = {
++ "notification-audio-volume-muted",
++ "notification-audio-volume-low",
++ "notification-audio-volume-medium",
++ "notification-audio-volume-high",
++ NULL
++};
+
+ static void
+ init_screens (GsdMediaKeysManager *manager)
+@@ -616,12 +625,14 @@ do_eject_action (GsdMediaKeysManager *manager)
+ }
+
+ /* Show the dialogue */
+- dialog_init (manager);
+- gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
+- "media-eject",
+- FALSE);
+- dialog_show (manager);
+-
++ if (!gsd_osd_notification_show_icon_only ("notification-device-eject", "Eject")) {
++ dialog_init (manager);
++ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
++ "media-eject",
++ FALSE);
++ dialog_show (manager);
++ }
++
+ /* Clean up the drive selection and exit if no suitable
+ * drives are found */
+ if (fav_drive != NULL)
+@@ -645,12 +656,14 @@ do_touchpad_action (GsdMediaKeysManager *manager)
+ GConfClient *client = manager->priv->conf_client;
+ gboolean state = gconf_client_get_bool (client, TOUCHPAD_ENABLED_KEY, NULL);
+
+- dialog_init (manager);
+- gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
+- (!state) ? "touchpad-enabled" : "touchpad-disabled",
+- FALSE);
+- dialog_show (manager);
+-
++ if (!gsd_osd_notification_show_icon_only ((!state) ? "touchpad-enabled" : "touchpad-disabled", "Touchpad")) {
++ dialog_init (manager);
++ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
++ (!state) ? "touchpad-enabled" : "touchpad-disabled",
++ FALSE);
++ dialog_show (manager);
++ }
++
+ gconf_client_set_bool (client, TOUCHPAD_ENABLED_KEY, !state, NULL);
+ }
+
+@@ -659,11 +672,20 @@ static void
+ update_dialog (GsdMediaKeysManager *manager,
+ guint vol,
+ gboolean muted,
+- gboolean sound_changed)
++ gboolean sound_changed,
++ GsdOsdNotifierOvershootType overshoot)
+ {
++ GtkWidget *window;
+ #ifdef HAVE_PULSE
+ vol = (int) (100 * (double) vol / PA_VOLUME_NORM);
+ #endif
++ if (overshoot != GSD_OSD_NOTIFICATION_NO_OVERSHOOT) {
++ if (gsd_osd_notification_show_overshoot (manager->priv->notifier, overshoot))
++ goto done;
++ } else {
++ if (gsd_osd_notification_show_value (manager->priv->notifier, vol, muted))
++ goto done;
++ }
+ vol = CLAMP (vol, 0, 100);
+
+ dialog_init (manager);
+@@ -673,14 +695,25 @@ update_dialog (GsdMediaKeysManager *manager,
+ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+ dialog_show (manager);
+-
++done:
+ #ifdef HAVE_PULSE
+- if (sound_changed != FALSE && muted == FALSE)
+- ca_gtk_play_for_widget (manager->priv->dialog, 0,
+- CA_PROP_EVENT_ID, "audio-volume-change",
+- CA_PROP_EVENT_DESCRIPTION, "volume changed through key press",
+- CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
+- NULL);
++ if (sound_changed != FALSE && muted == FALSE) {
++ if (manager->priv->dialog == NULL) {
++ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++ gtk_window_set_screen (GTK_WINDOW (window), manager->priv->current_screen);
++ gtk_widget_realize (window);
++ play_volume_event_sound (window);
++ gtk_widget_destroy (window);
++ } else {
++ ca_gtk_play_for_widget (manager->priv->dialog, 0,
++ CA_PROP_EVENT_ID, "audio-volume-change",
++ CA_PROP_EVENT_DESCRIPTION, "volume changed through key press",
++ CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
++ NULL);
++ }
++ }
++#else
++ return;
+ #endif
+ }
+
+@@ -691,6 +724,7 @@ do_sound_action (GsdMediaKeysManager *manager,
+ gboolean muted;
+ guint vol, norm_vol_step;
+ int vol_step;
++ GsdOsdNotifierOvershootType overshoot = GSD_OSD_NOTIFICATION_NO_OVERSHOOT;
+ gboolean sound_changed;
+
+ #ifdef HAVE_PULSE
+@@ -743,17 +777,23 @@ do_sound_action (GsdMediaKeysManager *manager,
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+ gvc_mixer_stream_push_volume (manager->priv->stream);
+ sound_changed = TRUE;
++ } else {
++ overshoot = GSD_OSD_NOTIFICATION_UNDERSHOOT;
+ }
+ } else if (!muted) {
+ vol = vol - norm_vol_step;
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+ gvc_mixer_stream_push_volume (manager->priv->stream);
+ sound_changed = TRUE;
++ } else {
++ overshoot = GSD_OSD_NOTIFICATION_UNDERSHOOT;
+ }
+ }
+ #else
+- if (!muted && (vol <= vol_step))
++ if (!muted && (vol <= vol_step)) {
+ acme_volume_mute_toggle (manager->priv->volume);
++ overshoot = GSD_OSD_NOTIFICATION_UNDERSHOOT;
++ }
+ acme_volume_set_volume (manager->priv->volume, vol - vol_step);
+ #endif
+ break;
+@@ -767,6 +807,8 @@ do_sound_action (GsdMediaKeysManager *manager,
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+ gvc_mixer_stream_push_volume (manager->priv->stream);
+ sound_changed = TRUE;
++ } else {
++ overshoot = GSD_OSD_NOTIFICATION_OVERSHOOT;
+ }
+ } else {
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+@@ -777,7 +819,6 @@ do_sound_action (GsdMediaKeysManager *manager,
+ acme_volume_set_mute (manager->priv->volume, FALSE);
+ }
+ acme_volume_set_volume (manager->priv->volume, vol + vol_step);
+-
+ #endif
+ } else {
+ #ifdef HAVE_PULSE
+@@ -794,12 +835,14 @@ do_sound_action (GsdMediaKeysManager *manager,
+ }
+ #else
+ acme_volume_set_volume (manager->priv->volume, vol + vol_step);
++ if (acme_volume_get_volume (manager->priv->volume) == 100)
++ overshoot = GSD_OSD_NOTIFICATION_OVERSHOOT;
+ #endif /* HAVE_PULSE */
+ }
+ break;
+ }
+
+- update_dialog (manager, vol, muted, sound_changed);
++ update_dialog (manager, vol, muted, sound_changed, overshoot);
+ }
+ #endif /* defined(HAVE_PULSE) || defined(HAVE_GSTREAMER) */
+
+@@ -945,8 +988,11 @@ gsd_media_player_key_pressed (GsdMediaKeysManager *manager,
+
+ static gboolean
+ do_multimedia_player_action (GsdMediaKeysManager *manager,
++ const char *icon,
+ const char *key)
+ {
++ if (icon != NULL)
++ gsd_osd_notification_show_icon_only (icon, key);
+ return gsd_media_player_key_pressed (manager, key);
+ }
+
+@@ -1017,19 +1063,19 @@ do_action (GsdMediaKeysManager *manager,
+ execute (manager, "gcalctool", FALSE, FALSE);
+ break;
+ case PLAY_KEY:
+- return do_multimedia_player_action (manager, "Play");
++ return do_multimedia_player_action (manager, NULL, "Play");
+ break;
+ case PAUSE_KEY:
+- return do_multimedia_player_action (manager, "Pause");
++ return do_multimedia_player_action (manager, NULL, "Pause");
+ break;
+ case STOP_KEY:
+- return do_multimedia_player_action (manager, "Stop");
++ return do_multimedia_player_action (manager, NULL, "Stop");
+ break;
+ case PREVIOUS_KEY:
+- return do_multimedia_player_action (manager, "Previous");
++ return do_multimedia_player_action (manager, NULL, "Previous");
+ break;
+ case NEXT_KEY:
+- return do_multimedia_player_action (manager, "Next");
++ return do_multimedia_player_action (manager, NULL, "Next");
+ break;
+ default:
+ g_assert_not_reached ();
+@@ -1172,6 +1218,7 @@ gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
+ manager->priv->volume = acme_volume_new ();
+ gnome_settings_profile_end ("acme_volume_new");
+ #endif /* HAVE_PULSE */
++ manager->priv->notifier = gsd_osd_notification_new (volume_icons, "volume");
+ g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager);
+
+ gnome_settings_profile_end (NULL);
+@@ -1268,6 +1315,9 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
+ }
+ g_list_free (priv->media_players);
+ priv->media_players = NULL;
++
++ if (manager->priv->notifier != NULL)
++ g_object_unref (manager->priv->notifier);
+ }
+
+ static void
diff --git a/gnome-base/gnome-settings-daemon/gnome-settings-daemon-2.30.0-r1.ebuild b/gnome-base/gnome-settings-daemon/gnome-settings-daemon-2.30.0-r1.ebuild
new file mode 100644
index 0000000..cdd9471
--- /dev/null
+++ b/gnome-base/gnome-settings-daemon/gnome-settings-daemon-2.30.0-r1.ebuild
@@ -0,0 +1,85 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI="2"
+
+inherit autotools eutils gnome2
+
+DESCRIPTION="Gnome Settings Daemon"
+HOMEPAGE="http://www.gnome.org"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~ppc ~ppc64 ~sh ~sparc ~x86 ~x86-fbsd ~x86-freebsd ~amd64-linux ~x86-linux ~x86-solaris"
+IUSE="debug libnotify pulseaudio"
+
+RDEPEND=">=dev-libs/dbus-glib-0.74
+ >=dev-libs/glib-2.18.0
+ >=x11-libs/gtk+-2.16
+ >=gnome-base/gconf-2.6.1
+ >=gnome-base/libgnomekbd-2.29.5
+ >=gnome-base/gnome-desktop-2.29.92
+
+ x11-libs/libX11
+ x11-libs/libXi
+ x11-libs/libXrandr
+ x11-libs/libXext
+ x11-libs/libXxf86misc
+ >=x11-libs/libxklavier-5.0
+ media-libs/fontconfig
+
+ libnotify? ( >=x11-libs/libnotify-0.4.3 )
+ pulseaudio? (
+ >=media-sound/pulseaudio-0.9.15
+ media-libs/libcanberra[gtk] )
+ !pulseaudio? (
+ >=media-libs/gstreamer-0.10.1.2
+ >=media-libs/gst-plugins-base-0.10.1.2 )"
+DEPEND="${RDEPEND}
+ !<gnome-base/gnome-control-center-2.22
+ sys-devel/gettext
+ >=dev-util/intltool-0.40
+ >=dev-util/pkgconfig-0.19
+ x11-proto/inputproto
+ x11-proto/xproto"
+
+# README is empty
+DOCS="AUTHORS NEWS ChangeLog MAINTAINERS"
+
+pkg_setup() {
+ G2CONF="${G2CONF}
+ --disable-static
+ $(use_enable debug)
+ $(use_with libnotify)
+ $(use_enable pulseaudio pulse)
+ $(use_enable !pulseaudio gstreamer)"
+
+ if use pulseaudio; then
+ elog "Building volume media keys using Pulseaudio"
+ else
+ elog "Building volume media keys using GStreamer"
+ fi
+}
+
+src_prepare() {
+ gnome2_src_prepare
+
+ # Restore gstreamer volume control support, upstream bug #571145
+ epatch "${FILESDIR}/${PN}-2.30.0-gst-vol-control-support.patch"
+
+ # Use OSD notifications (import from ubuntu)
+ epatch "${FILESDIR}/${PN}-2.30.0-osd-notifications.patch"
+
+ intltoolize --force --copy --automake || die "intltoolize failed"
+ eautoreconf
+}
+
+pkg_postinst() {
+ gnome2_pkg_postinst
+
+ if ! use pulseaudio; then
+ elog "GStreamer volume control support is a feature powered by Gentoo GNOME Team"
+ elog "PLEASE DO NOT report bugs upstream, report on https://bugs.gentoo.org instead"
+ fi
+}
diff --git a/gnome-extra/xchat-indicator/Manifest b/gnome-extra/xchat-indicator/Manifest
new file mode 100644
index 0000000..2670f0a
--- /dev/null
+++ b/gnome-extra/xchat-indicator/Manifest
@@ -0,0 +1,2 @@
+DIST xchat-indicator-0.3.2.tar.gz 287084 RMD160 c5861a86f856c2947ac86f0072d239a39dbc2945 SHA1 5da1f32a179cf0f41081149b6555b9c20056d6c1 SHA256 3ae672df9e9d3f67eae3bde2d344927a926d89e427f6e92829809bf5e201521a
+EBUILD xchat-indicator-0.3.2.ebuild 869 RMD160 ce83a65839bd0acd9fcdc6ad6b8c5682517673e9 SHA1 bb557dc9edcbd7df8b38dccab4774c780642376e SHA256 c64f3ba517f34e89040f94dab214f2f989052827526deba0c871085a7effe6df
diff --git a/gnome-extra/xchat-indicator/xchat-indicator-0.3.2.ebuild b/gnome-extra/xchat-indicator/xchat-indicator-0.3.2.ebuild
new file mode 100644
index 0000000..7fc31f9
--- /dev/null
+++ b/gnome-extra/xchat-indicator/xchat-indicator-0.3.2.ebuild
@@ -0,0 +1,35 @@
+# Copyright 1999-2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI="2"
+
+inherit gnome2
+
+DESCRIPTION="Plugin to make XChat use the messaging indicator"
+HOMEPAGE="https://launchpad.net/xchat-indicator"
+SRC_URI="http://launchpad.net/${PN}/trunk/${PV}/+download/${P}.tar.gz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~amd64"
+IUSE=""
+
+RDEPEND=">=x11-libs/gtk+-2.14.0
+ >=dev-libs/libindicate-0.3.0
+ net-irc/xchat-gnome"
+DEPEND="${COMMON_DEPEND}
+ dev-util/pkgconfig"
+
+pkg_setup() {
+ G2CONF="--disable-dependency-tracking --disable-static"
+ DOCS="AUTHORS NEWS"
+}
+
+src_prepare() {
+ gnome2_src_prepare
+
+ # Don't use embedded header, use system header instead.
+ # xchat-gnome installs its own xchat-gnome/xchat-plugin.h so we've to use it
+ sed "s:\"\(xchat-plugin.h\)\":<xchat-gnome/\1>:g" -i indicator.c || die "sed failed"
+}