Index: gnome-settings-multimedia-keys.c
===================================================================
--- gnome-settings-multimedia-keys.c	(revision 7036)
+++ 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,121 @@
 	/* Multihead stuff */
 	GdkScreen *current_screen;
 	GSList *screens;
-} Acme;
 
+	/* multimedia player keys */
+	GHashTable *multimedia_players;
+	gchar *current_multimedia_player;
+};
+
+struct AcmeClass {
+	GObjectClass parent;
+
+	DBusGConnection *connection;
+
+	void (*multimedia_player_key_action) (Acme *acme, const gchar *application, const gchar *key);
+};
+
+G_DEFINE_TYPE (Acme, acme, G_TYPE_OBJECT);
+
+enum {
+	MULTIMEDIA_PLAYER_KEY_ACTION,
+	LAST_SIGNAL
+};
+
+static guint acme_signals[LAST_SIGNAL] = { 0 };
+
+void
+acme_activate_multimedia_player (Acme *acme, const gchar *application, guint32 time, GError **error)
+{
+	acme->current_multimedia_player = g_strdup (application);
+
+	g_hash_table_insert (acme->multimedia_players, acme->current_multimedia_player, GUINT_TO_POINTER (time));
+}
+
+typedef struct {
+	gchar *application;
+	guint32 time;
+} LatestActivatedPlayer;
+
 static void
+acme_find_latest_activated_player (gpointer key, gpointer value, LatestActivatedPlayer *data)
+{
+	if (GPOINTER_TO_UINT (value) > data->time) {
+		data->time = GPOINTER_TO_UINT (value);
+		data->application = (gchar *) key;
+	}
+}
+
+void
+acme_remove_multimedia_player (Acme *acme, const gchar *application, GError **error)
+{
+	LatestActivatedPlayer data = { 0 };
+
+	g_hash_table_remove (acme->multimedia_players, application);
+
+	g_hash_table_foreach (acme->multimedia_players, (GHFunc)acme_find_latest_activated_player, &data);
+
+	acme->current_multimedia_player = data.application;
+}
+
+#include "gnome-settings-multimedia-keys-server.h"
+
+static void
+acme_class_init (AcmeClass *klass)
+{
+	GError *error = NULL;
+
+	acme_signals[MULTIMEDIA_PLAYER_KEY_ACTION] = g_signal_new ("multimedia-player-key-action",
+			G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AcmeClass, multimedia_player_key_action),
+			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;
+
+	acme->multimedia_players = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+	/* 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 +318,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 +339,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 +383,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 +416,7 @@
 {
 	int i;
 
-	for (i = 0; i < PLAY_KEY; i++)
+	for (i = 0; i < HANDLED_KEYS; i++)
 	{
 		char *tmp;
 		Key *key;
@@ -412,52 +455,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 +680,12 @@
 }
 
 static void
+do_multimedia_player_action (Acme *acme, const gchar *key)
+{
+	g_signal_emit (acme, acme_signals[MULTIMEDIA_PLAYER_KEY_ACTION], 0, acme->current_multimedia_player, key);
+}
+
+static void
 do_action (Acme *acme, int type)
 {
 	gchar *cmd;
@@ -725,6 +728,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 +782,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 +824,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: Makefile.am
===================================================================
--- Makefile.am	(revision 7036)
+++ 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
--- /dev/null	2006-12-21 10:28:09.000000000 +0100
+++ gsd-multimedia-keys.xml	2007-01-02 00:55:07.000000000 +0100
@@ -0,0 +1,16 @@
+<?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="activateMultimediaPlayer">
+			<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="acme_activate_multimedia_player"/>
+			<arg type="s" name="application" direction="in"/>
+			<arg type="u" name="time" direction="in"/>
+		</method>
+		<method name="removeMultimediaPlayer">
+			<arg type="s" name="application" direction="in"/>
+		</method>
+		<signal name="MultimediaPlayerKeyAction"/>
+	</interface>
+</node>
--- /dev/null	2006-12-21 10:28:09.000000000 +0100
+++ gnome-settings-marshal.list	2007-01-01 23:46:27.000000000 +0100
@@ -0,0 +1 @@
+VOID:STRING,STRING
--- /dev/null	2006-12-21 10:28:09.000000000 +0100
+++ org.gnome.MultimediaKeys.service.in	2007-01-02 00:10:02.000000000 +0100
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.MultimediaKeys
+Exec=@libexecdir@/gnome-settings-daemon
