Index: gnome-settings-multimedia-keys.c
===================================================================
--- gnome-settings-multimedia-keys.c	(revision 7040)
+++ gnome-settings-multimedia-keys.c	(working copy)
@@ -34,11 +34,14 @@
 
 #include <gconf/gconf-client.h>
 
+#include <dbus/dbus-glib-bindings.h>
+
 #include "eggaccelerators.h"
 
 #include "actions/acme.h"
 #include "actions/acme-volume.h"
 #include "gsd-media-keys-window.h"
+#include "gnome-settings-marshal.h"
 
 #define VOLUME_STEP 6           /* percents for one volume button press */
 
@@ -51,7 +54,19 @@
  * for these set */
 #define USED_MODS (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)
 
-typedef struct {
+#define GNOME_SETTINGS_TYPE_ACME              (acme_get_type ())
+#define GNOME_SETTINGS_ACME(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GNOME_SETTINGS_TYPE_ACME, Acme))
+#define GNOME_SETTINGS_ACME_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_SETTINGS_TYPE_ACME, AcmeClass))
+#define GNOME_SETTINGS_IS_ACME(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GNOME_SETTINGS_TYPE_ACME))
+#define GNOME_SETTINGS_IS_ACME_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_SETTINGS_TYPE_ACME))
+#define GNOME_SETTINGS_ACME_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_SETTINGS_TYPE_ACME, AcmeClass))
+
+typedef struct Acme Acme;
+typedef struct AcmeClass AcmeClass;
+
+struct Acme {
+	GObject parent;
+
 	AcmeVolume *volobj;
 	GtkWidget *dialog;
 	GConfClient *conf_client;
@@ -59,9 +74,144 @@
 	/* Multihead stuff */
 	GdkScreen *current_screen;
 	GSList *screens;
-} Acme;
 
+	/* multimedia player keys */
+	GList *media_players;
+};
+
+struct AcmeClass {
+	GObjectClass parent;
+
+	DBusGConnection *connection;
+
+	void (*media_player_key_pressed) (Acme *acme, const gchar *application, const gchar *key);
+};
+
+G_DEFINE_TYPE (Acme, acme, G_TYPE_OBJECT);
+
+enum {
+	MEDIA_PLAYER_KEY_PRESSED,
+	LAST_SIGNAL
+};
+
+static guint acme_signals[LAST_SIGNAL] = { 0 };
+
+typedef struct {
+	gchar *application;
+	guint32 time;
+} MediaPlayer;
+
+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
+acme_grab_media_player_keys (Acme *acme, const gchar *application, guint32 time, GError **error)
+{
+	GList *iter;
+	MediaPlayer *media_player;
+
+	iter = g_list_find_custom (acme->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);
+			acme->media_players = g_list_delete_link (acme->media_players, iter);
+		} else {
+			return;
+		}
+	}
+
+	media_player = g_new0 (MediaPlayer, 1);
+	media_player->application = g_strdup (application);
+	media_player->time = time;
+
+	acme->media_players = g_list_insert_sorted (acme->media_players, media_player, find_by_time);
+
+	return TRUE;
+}
+
+gboolean
+acme_release_media_player_keys (Acme *acme, const gchar *application, GError **error)
+{
+	GList *iter;
+
+	iter = g_list_find_custom (acme->media_players, application, find_by_application);
+
+	if (iter != NULL) {
+		g_free (((MediaPlayer *)iter->data)->application);
+		g_free (iter->data);
+		acme->media_players = g_list_delete_link (acme->media_players, iter);
+	}
+
+	return TRUE;
+}
+
+#include "gnome-settings-multimedia-keys-server.h"
+
 static void
+acme_class_init (AcmeClass *klass)
+{
+	GError *error = NULL;
+
+	acme_signals[MEDIA_PLAYER_KEY_PRESSED] = g_signal_new ("media-player-key-pressed",
+			G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AcmeClass, 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) {
+		g_warning ("Unable to connect to dbus: %s",
+			   error->message);
+		g_error_free (error);
+		return;
+	}
+
+	/* &dbus_glib_acme_object_info is provided in the gnome-settings-multimedia-keys-server.h file */
+	dbus_g_object_type_install_info (GNOME_SETTINGS_TYPE_ACME,
+					 &dbus_glib_acme_object_info);
+}
+
+static void
+acme_init (Acme *acme)
+{
+	GError *error = NULL;
+	DBusGProxy *driver_proxy;
+	AcmeClass *klass = GNOME_SETTINGS_ACME_GET_CLASS (acme);
+	unsigned request_ret;
+
+	/* Register DBUS path */
+	dbus_g_connection_register_g_object (klass->connection,
+					     "/org/gnome/MultimediaKeys",
+					     G_OBJECT (acme));
+
+	/* Register the service name, the constant here are defined in dbus-glib-bindings.h */
+	driver_proxy = dbus_g_proxy_new_for_name (klass->connection,
+						  DBUS_SERVICE_DBUS,
+						  DBUS_PATH_DBUS,
+						  DBUS_INTERFACE_DBUS);
+
+	if (!org_freedesktop_DBus_request_name
+	    (driver_proxy, "org.gnome.MultimediaKeys", 0, &request_ret,
+	     &error)) {
+		g_warning ("Unable to register service: %s",
+			   error->message);
+		g_error_free (error);
+	}
+
+	g_object_unref (driver_proxy);
+}
+
+static void
 acme_error (char * msg)
 {
 	GtkWidget *error_dialog;
@@ -191,36 +341,7 @@
 	}
 }
 
-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)
 {
 	if (string == NULL || string[0] == '\0')
@@ -241,7 +362,7 @@
 	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 +406,6 @@
 
 	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 +439,7 @@
 {
 	int i;
 
-	for (i = 0; i < PLAY_KEY; i++)
+	for (i = 0; i < HANDLED_KEYS; i++)
 	{
 		char *tmp;
 		Key *key;
@@ -412,52 +478,6 @@
 
 		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 +703,18 @@
 }
 
 static void
+do_multimedia_player_action (Acme *acme, const gchar *key)
+{
+	const gchar *application = NULL;
+
+	if (acme->media_players != NULL) {
+		application = ((MediaPlayer *)acme->media_players->data)->application;
+	}
+
+	g_signal_emit (acme, acme_signals[MEDIA_PLAYER_KEY_PRESSED], 0, application, key);
+}
+
+static void
 do_action (Acme *acme, int type)
 {
 	gchar *cmd;
@@ -725,6 +757,21 @@
 	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 +811,7 @@
 	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;
@@ -806,7 +853,7 @@
 	GSList *l;
 	Acme   *acme;
 
-	acme = g_new0 (Acme, 1);
+	acme = g_object_new (GNOME_SETTINGS_TYPE_ACME, NULL);
 
 	acme->conf_client = client;
 	gconf_client_add_dir (acme->conf_client,
Index: org.gnome.MultimediaKeys.service.in
===================================================================
--- org.gnome.MultimediaKeys.service.in	(revision 0)
+++ org.gnome.MultimediaKeys.service.in	(revision 0)
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.MultimediaKeys
+Exec=@libexecdir@/gnome-settings-daemon
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 7040)
+++ Makefile.am	(working copy)
@@ -85,14 +85,27 @@
 #	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-multimedia-keys-server.h	\
+	gnome-settings-multimedia-keys-client.h
 
+gnome_settings_daemon_SOURCES+=$(BUILT_SOURCES)
+
 Gladedir   = $(GNOMECC_GLADE_DIR)
 Glade_DATA = modmap-dialog.glade
 
 Dbusapidir   = $(includedir)/gnome-settings-daemon-2.0/gnome-settings-daemon
-Dbusapi_DATA = gnome-settings-client.h
+Dbusapi_DATA = gnome-settings-client.h	gnome-settings-multimedia-keys-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 $< > $@
@@ -100,16 +113,26 @@
 gnome-settings-client.h:  gsd-infos.xml
 	dbus-binding-tool --prefix=settings_daemon --mode=glib-client $< > $@
 
+gnome-settings-multimedia-keys-server.h:  gsd-multimedia-keys.xml
+	dbus-binding-tool --prefix=acme --mode=glib-server $< > $@
+
+gnome-settings-multimedia-keys-client.h:  gsd-multimedia-keys.xml
+	dbus-binding-tool --prefix=acme --mode=glib-client $< > $@
+
 # DBUS stuff
 servicedir = $(DBUS_SERVICES_DIR)
-service_in_files = org.gnome.SettingsDaemon.service.in
+service_in_files = org.gnome.SettingsDaemon.service.in org.gnome.MultimediaKeys.service.in
 service_DATA = $(service_in_files:.service.in=.service)
 
 org.gnome.SettingsDaemon.service: org.gnome.SettingsDaemon.service.in Makefile
 	@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
 
+org.gnome.MultimediaKeys.service: org.gnome.MultimediaKeys.service.in Makefile
+	@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 gsd-multimedia-keys.xml	\
+	org.gnome.SettingsDaemon.service.in gnome-settings-marshal.list
 CLEANFILES = $(BUILT_SOURCES) $(service_DATA)
 
 pkgconfigdir = $(libdir)/pkgconfig
Index: gsd-multimedia-keys.xml
===================================================================
--- gsd-multimedia-keys.xml	(revision 0)
+++ gsd-multimedia-keys.xml	(revision 0)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<node name="/org/gnome/MultimediaKeys">
+	<interface name="org.gnome.MultimediaKeys">
+		<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="acme"/>
+		<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>
