Index: gnome-settings-multimedia-keys.c
===================================================================
--- gnome-settings-multimedia-keys.c	(revision 7051)
+++ gnome-settings-multimedia-keys.c	(working copy)
@@ -39,6 +39,7 @@
 #include "actions/acme.h"
 #include "actions/acme-volume.h"
 #include "gsd-media-keys-window.h"
+#include "gnome-settings-dbus.h"
 
 #define VOLUME_STEP 6           /* percents for one volume button press */
 
@@ -51,7 +52,9 @@
  * for these set */
 #define USED_MODS (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)
 
-typedef struct {
+typedef struct Acme Acme;
+
+struct Acme {
 	AcmeVolume *volobj;
 	GtkWidget *dialog;
 	GConfClient *conf_client;
@@ -59,7 +62,10 @@ typedef struct {
 	/* Multihead stuff */
 	GdkScreen *current_screen;
 	GSList *screens;
-} Acme;
+
+	/* GnomeSettingsServer */
+	GObject *server;
+};
 
 static void
 acme_error (char * msg)
@@ -191,35 +197,6 @@ grab_key (Acme *acme, Key *key, gboolean
 	}
 }
 
-static void
-unhookup_keysym (int keycode)
-{
-	char *command;
-
-	if (keycode <= 0)
-		return;
-
-	command = g_strdup_printf ("xmodmap -e \"keycode %d = \"", keycode);
-	g_spawn_command_line_sync (command, NULL, NULL, NULL, NULL);
-	g_free (command);
-}
-
-static gboolean
-hookup_keysym (int keycode, const char *keysym)
-{
-	char *command;
-
-	if (keycode <= 0)
-		return TRUE;
-
-	command = g_strdup_printf ("xmodmap -e \"keycode %d = %s\"",
-				   keycode, keysym);
-	g_spawn_command_line_sync (command, NULL, NULL, NULL, NULL);
-	g_free (command);
-
-	return FALSE;
-}
-
 static gboolean
 is_valid_shortcut (const char *string)
 {
@@ -241,7 +218,7 @@ update_kbd_cb (GConfClient *client, guin
 	g_return_if_fail (entry->key != NULL);
 
 	/* Find the key that was modified */
-	for (i = 0; i < PLAY_KEY; i++)
+	for (i = 0; i < HANDLED_KEYS; i++)
 	{
 		if (strcmp (entry->key, keys[i].gconf_key) == 0)
 		{
@@ -285,61 +262,6 @@ update_kbd_cb (GConfClient *client, guin
 
 	if (found != FALSE)
 		return;
-
-	for (i = PLAY_KEY; i < HANDLED_KEYS; i++)
-	{
-		if (strcmp (entry->key, keys[i].gconf_key) == 0)
-		{
-			char *tmp;
-			Key *key;
-
-			if (keys[i].key != NULL)
-				unhookup_keysym (keys[i].key->keycode);
-
-			g_free (keys[i].key);
-			keys[i].key = NULL;
-
-			tmp = gconf_client_get_string (acme->conf_client,
-						       keys[i].gconf_key, NULL);
-
-			if (is_valid_shortcut (tmp) == FALSE)
-			{
-				g_free (tmp);
-				break;
-			}
-
-			key = g_new0 (Key, 1);
-			if (egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycode, &key->state) == FALSE
-			    || key->keycode == 0)
-			{
-				g_free (tmp);
-				g_free (key);
-				break;
-			}
-
-			switch (keys[i].key_type) {
-			case PLAY_KEY:
-				hookup_keysym (key->keycode, "XF86AudioPlay");
-				break;
-			case PAUSE_KEY:
-				hookup_keysym (key->keycode, "XF86AudioPause");
-				break;
-			case STOP_KEY:
-				hookup_keysym (key->keycode, "XF86AudioStop");
-				break;
-			case PREVIOUS_KEY:
-				hookup_keysym (key->keycode, "XF86AudioPrev");
-				break;
-			case NEXT_KEY:
-				hookup_keysym (key->keycode, "XF86AudioNext");
-				break;
-			}
-
-			keys[i].key = key;
-
-			g_free (tmp);
-		}
-	}
 }
 
 static void
@@ -373,7 +295,7 @@ init_kbd (Acme *acme)
 {
 	int i;
 
-	for (i = 0; i < PLAY_KEY; i++)
+	for (i = 0; i < HANDLED_KEYS; i++)
 	{
 		char *tmp;
 		Key *key;
@@ -412,52 +334,6 @@ init_kbd (Acme *acme)
 
 		grab_key (acme, key, TRUE);
 	}
-
-	for (i = PLAY_KEY; i < HANDLED_KEYS; i++)
-	{
-		char *tmp;
-		Key *key;
-
-		gconf_client_notify_add (acme->conf_client,
-					 keys[i].gconf_key, update_kbd_cb,
-					 acme, NULL, NULL);
-
-		tmp = gconf_client_get_string (acme->conf_client,
-					       keys[i].gconf_key, NULL);
-		if (!is_valid_shortcut (tmp)) {
-			g_free (tmp);
-			continue;
-		}
-
-		key = g_new0 (Key, 1);
-		if (egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycode, &key->state) == FALSE
-		    || key->keycode == 0)
-		{
-			g_free (tmp);
-			g_free (key);
-			continue;
-		}
-		g_free (tmp);
-
-		keys[i].key = key;
-		switch (keys[i].key_type) {
-		case PLAY_KEY:
-			hookup_keysym (keys[i].key->keycode, "XF86AudioPlay");
-			break;
-		case PAUSE_KEY:
-			hookup_keysym (keys[i].key->keycode, "XF86AudioPause");
-			break;
-		case STOP_KEY:
-			hookup_keysym (keys[i].key->keycode, "XF86AudioStop");
-			break;
-		case PREVIOUS_KEY:
-			hookup_keysym (keys[i].key->keycode, "XF86AudioPrev");
-			break;
-		case NEXT_KEY:
-			hookup_keysym (keys[i].key->keycode, "XF86AudioNext");
-			break;
-		}
-	}
 }
 
 static void
@@ -683,6 +559,12 @@ do_sound_action (Acme *acme, int type)
 }
 
 static void
+do_multimedia_player_action (Acme *acme, const gchar *key)
+{
+	gnome_settings_server_media_player_key_pressed (acme->server, key);
+}
+
+static void
 do_action (Acme *acme, int type)
 {
 	gchar *cmd;
@@ -725,6 +607,21 @@ do_action (Acme *acme, int type)
 	case WWW_KEY:
 		do_www_action (acme, NULL);
 		break;
+	case PLAY_KEY:
+		do_multimedia_player_action (acme, "Play");
+		break;
+	case PAUSE_KEY:
+		do_multimedia_player_action (acme, "Pause");
+		break;
+	case STOP_KEY:
+		do_multimedia_player_action (acme, "Stop");
+		break;
+	case PREVIOUS_KEY:
+		do_multimedia_player_action (acme, "Previous");
+		break;
+	case NEXT_KEY:
+		do_multimedia_player_action (acme, "Next");
+		break;
 	default:
 		g_assert_not_reached ();
 	}
@@ -764,7 +661,7 @@ acme_filter_events (GdkXEvent *xevent, G
 	keycode = xev->xkey.keycode;
 	state = xev->xkey.state;
 
-	for (i = 0; i < PLAY_KEY; i++)
+	for (i = 0; i < HANDLED_KEYS; i++)
 	{
 		if (keys[i].key == NULL)
 			continue;
@@ -817,6 +714,8 @@ gnome_settings_multimedia_keys_load (GCo
 	init_screens (acme);
 	init_kbd (acme);
 
+	acme->server = gnome_settings_server_get ();
+
 	/* initialise Volume handler */
 	acme->volobj = acme_volume_new();
 
Index: gnome-settings-dbus.c
===================================================================
--- gnome-settings-dbus.c	(revision 7051)
+++ gnome-settings-dbus.c	(working copy)
@@ -1,5 +1,30 @@
+/*
+ * gnome-settings-dbus.c
+ *
+ * Copyright (C) 2007 Jan Arne Petersen <jap@gnome.org>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
+ * USA.
+ */
+
+
+#include <string.h>
 #include <dbus/dbus-glib-bindings.h>
 #include <gnome-settings-daemon.h>
+#include "gnome-settings-marshal.h"
+#include "gnome-settings-dbus.h"
 
 static GObjectClass *parent_class = NULL;
 
@@ -8,13 +33,30 @@ typedef struct GnomeSettingsServerClass 
 
 struct GnomeSettingsServer {
 	GObject parent;
+
+	/* multimedia player keys */
+	GList *media_players;
 };
 
 struct GnomeSettingsServerClass {
 	GObjectClass parent;
 	DBusGConnection *connection;
+
+	void (*media_player_key_pressed) (GObject *server, const gchar *application, const gchar *key);
 };
 
+enum {
+	MEDIA_PLAYER_KEY_PRESSED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct {
+	gchar *application;
+	guint32 time;
+} MediaPlayer;
+
 #define GNOME_SETTINGS_TYPE_SERVER              (gnome_settings_server_get_type ())
 #define GNOME_SETTINGS_SERVER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GNOME_SETTINGS_TYPE_SERVER, GnomeSettingsServer))
 #define GNOME_SETTINGS_SERVER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_SETTINGS_TYPE_SERVER, GnomeSettingsServerClass))
@@ -22,6 +64,61 @@ struct GnomeSettingsServerClass {
 #define GNOME_SETTINGS_IS_SERVER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_SETTINGS_TYPE_SERVER))
 #define GNOME_SETTINGS_SERVER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_SETTINGS_TYPE_SERVER, GnomeSettingsServerClass))
 
+static gint
+find_by_application (gconstpointer a, gconstpointer b)
+{
+	return strcmp (((MediaPlayer *)a)->application, b);
+}
+
+static gint
+find_by_time (gconstpointer a, gconstpointer b)
+{
+	return ((MediaPlayer *)a)->time != 0 && ((MediaPlayer *)a)->time < ((MediaPlayer *)b)->time;
+}
+
+gboolean
+settings_daemon_grab_media_player_keys (GnomeSettingsServer *server, const gchar *application, guint32 time, GError **error)
+{
+	GList *iter;
+	MediaPlayer *media_player;
+
+	iter = g_list_find_custom (server->media_players, application, find_by_application);
+
+	if (iter != NULL) {
+		if (time == 0 || ((MediaPlayer *)iter->data)->time < time) {
+			g_free (((MediaPlayer *)iter->data)->application);
+			g_free (iter->data);
+			server->media_players = g_list_delete_link (server->media_players, iter);
+		} else {
+			return TRUE;
+		}
+	}
+
+	media_player = g_new0 (MediaPlayer, 1);
+	media_player->application = g_strdup (application);
+	media_player->time = time;
+
+	server->media_players = g_list_insert_sorted (server->media_players, media_player, find_by_time);
+
+	return TRUE;
+}
+
+gboolean
+settings_daemon_release_media_player_keys (GnomeSettingsServer *server, const gchar *application, GError **error)
+{
+	GList *iter;
+
+	iter = g_list_find_custom (server->media_players, application, find_by_application);
+
+	if (iter != NULL) {
+		g_free (((MediaPlayer *)iter->data)->application);
+		g_free (iter->data);
+		server->media_players = g_list_delete_link (server->media_players, iter);
+	}
+
+	return TRUE;
+}
+
 gboolean
 settings_daemon_awake (GObject * object, GError ** error)
 {
@@ -31,12 +128,59 @@ settings_daemon_awake (GObject * object,
 G_DEFINE_TYPE (GnomeSettingsServer, gnome_settings_server, G_TYPE_OBJECT)
 #include "gnome-settings-server.h"
 
+GObject *
+gnome_settings_server_get (void)
+{
+	return g_object_new (GNOME_SETTINGS_TYPE_SERVER, NULL);
+}
+
+void
+gnome_settings_server_media_player_key_pressed (GObject *server, const gchar *key)
+{
+	const gchar *application = NULL;
+
+	if (GNOME_SETTINGS_SERVER (server)->media_players != NULL) {
+		application = ((MediaPlayer *)GNOME_SETTINGS_SERVER (server)->media_players->data)->application;
+	}
+
+	g_signal_emit (server, signals[MEDIA_PLAYER_KEY_PRESSED], 0, application, key);
+}
+
+static GObject*
+gnome_settins_server_constructor (GType                  type,
+				  guint                  n_construct_params,
+				  GObjectConstructParam *construct_params)
+{
+	static GObject *singleton = NULL;
+	GObject *object;
+
+	if (!singleton) {
+		singleton = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_params, construct_params);
+		object = singleton;
+	} else {
+		object = g_object_ref (singleton);
+	}
+
+	return object;
+}
+
+
 static void
 gnome_settings_server_class_init (GnomeSettingsServerClass * klass)
 {
 	GError *error = NULL;
 	GObjectClass *object_class;
 
+	object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->constructor = gnome_settins_server_constructor;
+
+	signals[MEDIA_PLAYER_KEY_PRESSED] = g_signal_new ("media-player-key-pressed",
+			G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GnomeSettingsServerClass, media_player_key_pressed),
+			NULL, NULL, gnome_settings_marshal_VOID__STRING_STRING, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+
 	/* Init the DBus connection, per-klass */
 	klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
 	if (klass->connection == NULL) {
@@ -49,10 +193,6 @@ gnome_settings_server_class_init (GnomeS
 	/* &dbus_glib__object_info is provided in the server-bindings.h file */
 	dbus_g_object_type_install_info (GNOME_SETTINGS_TYPE_SERVER,
 					 &dbus_glib_settings_daemon_object_info);
-
-	object_class = G_OBJECT_CLASS (klass);
-
-	parent_class = g_type_class_peek_parent (klass);
 }
 
 static void
Index: gnome-settings-dbus.h
===================================================================
--- gnome-settings-dbus.h	(revision 0)
+++ gnome-settings-dbus.h	(revision 0)
@@ -0,0 +1,34 @@
+/*
+ * gnome-settings-dbus.h
+ *
+ * Copyright (C) 2007 Jan Arne Petersen <jap@gnome.org>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
+ * USA.
+ */
+
+#ifndef __GNOME_SETTINGS_DBUS_H__
+#define __GNOME_SETTINGS_DBUS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GObject *gnome_settings_server_get                      (void);
+void     gnome_settings_server_media_player_key_pressed (GObject *server, const gchar *key);
+
+G_END_DECLS
+
+#endif
Index: gsd-infos.xml
===================================================================
--- gsd-infos.xml	(revision 7051)
+++ gsd-infos.xml	(working copy)
@@ -4,5 +4,13 @@
 	<interface name="org.gnome.SettingsDaemon">
 		<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="settings_daemon"/>
 		<method name="Awake"/>
+		<method name="GrabMediaPlayerKeys">
+			<arg type="s" name="application" direction="in"/>
+			<arg type="u" name="time" direction="in"/>
+		</method>
+		<method name="ReleaseMediaPlayerKeys">
+			<arg type="s" name="application" direction="in"/>
+		</method>
+		<signal name="MediaPlayerKeyPressed"/>
 	</interface>
 </node>
Index: gnome-settings-marshal.list
===================================================================
--- gnome-settings-marshal.list	(revision 0)
+++ gnome-settings-marshal.list	(revision 0)
@@ -0,0 +1 @@
+VOID:STRING,STRING
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 7051)
+++ Makefile.am	(working copy)
@@ -42,6 +42,7 @@ gnome_settings_daemon_SOURCES =	\
 	gnome-settings-gtk1theme.h	\
 	gnome-settings-server.h		\
 	gnome-settings-dbus.c		\
+	gnome-settings-dbus.h		\
 	gnome-settings-xrdb.c		\
 	gnome-settings-xrdb.h		\
 	gsd-media-keys-window.c		\
@@ -85,7 +86,11 @@ gnome_settings_daemon_LDADD = \
 #	AccessXlibint.h
 
 BUILT_SOURCES=gnome-settings-server.h		\
-	gnome-settings-client.h
+	gnome-settings-client.h			\
+	gnome-settings-marshal.h		\
+	gnome-settings-marshal.c
+
+gnome_settings_daemon_SOURCES+=$(BUILT_SOURCES)
 
 Gladedir   = $(GNOMECC_GLADE_DIR)
 Glade_DATA = modmap-dialog.glade
@@ -93,6 +98,13 @@ Glade_DATA = modmap-dialog.glade
 Dbusapidir   = $(includedir)/gnome-settings-daemon-2.0/gnome-settings-daemon
 Dbusapi_DATA = gnome-settings-client.h
 
+#Rule to generate the marshal files
+gnome-settings-marshal.c: gnome-settings-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=gnome_settings_marshal $< --header --body > $@
+
+gnome-settings-marshal.h: gnome-settings-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=gnome_settings_marshal $< --header > $@
+
 #Rule to generate the binding headers
 gnome-settings-server.h:  gsd-infos.xml
 	dbus-binding-tool --prefix=settings_daemon --mode=glib-server $< > $@
@@ -109,7 +121,8 @@ org.gnome.SettingsDaemon.service: org.gn
 	@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
 
 EXTRA_DIST = $(Glade_DATA) $(Dbusapi_DATA) \
-             gnome-settings-daemon.pc.in gsd-infos.xml org.gnome.SettingsDaemon.service.in
+	gnome-settings-daemon.pc.in gsd-infos.xml \
+	org.gnome.SettingsDaemon.service.in gnome-settings-marshal.list
 CLEANFILES = $(BUILT_SOURCES) $(service_DATA)
 
 pkgconfigdir = $(libdir)/pkgconfig
