Index: shell/ev-media-player-keys.h
===================================================================
--- shell/ev-media-player-keys.h	(revision 0)
+++ shell/ev-media-player-keys.h	(revision 0)
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Copyright (C) 2007 Jan Arne Petersen <jap@gnome.org>
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "ev-window.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_MEDIA_PLAYER_KEYS		(ev_media_player_keys_get_type ())
+#define EV_MEDIA_PLAYER_KEYS(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_MEDIA_PLAYER_KEYS, EvMediaPlayerKeys))
+#define EV_MEDIA_PLAYER_KEYS_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_MEDIA_PLAYER_KEYS, EvMediaPlayerKeysClass))
+#define EV_IS_MEDIA_PLAYER_KEYS(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_MEDIA_PLAYER_KEYS))
+#define EV_IS_MEDIA_PLAYER_KEYS_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_MEDIA_PLAYER_KEYS))
+#define EV_MEDIA_PLAYER_KEYS_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), EV_TYPE_MEDIA_PLAYER_KEYS, EvMediaPlayerKeysClass))
+
+typedef struct _EvMediaPlayerKeys EvMediaPlayerKeys;
+typedef struct _EvMediaPlayerKeysClass EvMediaPlayerKeysClass;
+
+
+GType	ev_media_player_keys_get_type		(void) G_GNUC_CONST;
+
+EvMediaPlayerKeys * ev_media_player_keys_new	(void);
+
+void ev_media_player_keys_focused		(EvMediaPlayerKeys *keys,
+						 EvWindow *window);
+
Index: shell/ev-marshal.list
===================================================================
--- shell/ev-marshal.list	(revision 3058)
+++ shell/ev-marshal.list	(working copy)
@@ -1,3 +1,4 @@
 VOID:NONE
 VOID:OBJECT,OBJECT
 VOID:ENUM,BOOLEAN
+VOID:STRING,STRING
Index: shell/ev-application.c
===================================================================
--- shell/ev-application.c	(revision 3058)
+++ shell/ev-application.c	(working copy)
@@ -25,6 +25,9 @@
 #include "ev-utils.h"
 #include "ev-file-helpers.h"
 #include "ev-document-factory.h"
+#ifdef ENABLE_DBUS
+#include "ev-media-player-keys.h"
+#endif /* ENABLE_DBUS */
 #include "totem-scrsaver.h"
 
 #include <glib.h>
@@ -59,6 +62,10 @@
 
 	gchar *last_chooser_uri;
 
+#ifdef ENABLE_DBUS
+	EvMediaPlayerKeys *keys;
+#endif /* ENABLE_DBUS */
+
 	GtkPrintSettings *print_settings;
 #if GTK_CHECK_VERSION (2, 11, 0)
 	gchar            *print_settings_file;
@@ -715,6 +722,10 @@
 
 	egg_toolbars_model_set_flags (ev_application->toolbars_model, 0,
 				      EGG_TB_MODEL_NOT_REMOVABLE);
+
+#ifdef ENABLE_DBUS
+	ev_application->keys = ev_media_player_keys_new ();
+#endif /* ENABLE_DBUS */
 }
 
 /**
@@ -744,6 +755,26 @@
 	return windows;
 }
 
+/**
+ * ev_application_get_media_keys:
+ * @application: The instance of the application.
+ *
+ * It gives you access to the media player keys handler object.
+ *
+ * Returns: A #EvMediaPlayerKeys.
+ */
+GObject
+*ev_application_get_media_keys (EvApplication *application)
+{
+#ifdef ENABLE_DBUS
+	if (!application->keys)
+		return NULL;
+	return g_object_ref (G_OBJECT (application->keys));
+#else
+	return NULL;
+#endif /* ENABLE_DBUS */
+}
+
 EggToolbarsModel *
 ev_application_get_toolbars_model (EvApplication *application)
 {
Index: shell/ev-window.c
===================================================================
--- shell/ev-window.c	(revision 3058)
+++ shell/ev-window.c	(working copy)
@@ -68,6 +68,9 @@
 #include "ev-message-area.h"
 #include "ev-mount-operation.h"
 #include "ev-file-monitor.h"
+#ifdef ENABLE_DBUS
+#include "ev-media-player-keys.h"
+#endif /* ENABLE_DBUS */
 
 #include <gtk/gtkprintunixdialog.h>
 
@@ -3231,6 +3234,12 @@
 	ev_view_previous_page (EV_VIEW (ev_window->priv->view));
 }
 
+void
+ev_window_go_previous_page (EvWindow *ev_window)
+{
+	ev_window_cmd_go_previous_page (NULL, ev_window);
+}
+
 static void
 ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window)
 {
@@ -3239,6 +3248,12 @@
 	ev_view_next_page (EV_VIEW (ev_window->priv->view));
 }
 
+void
+ev_window_go_next_page (EvWindow *ev_window)
+{
+	ev_window_cmd_go_next_page (NULL, ev_window);
+}
+
 static void
 ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
 {
@@ -3247,6 +3262,12 @@
 	ev_page_cache_set_current_page (ev_window->priv->page_cache, 0);
 }
 
+void
+ev_window_go_first_page (EvWindow *ev_window)
+{
+	ev_window_cmd_go_first_page (NULL, ev_window);
+}
+
 static void
 ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
 {
@@ -3258,6 +3279,12 @@
 	ev_page_cache_set_current_page (ev_window->priv->page_cache, n_pages - 1);
 }
 
+void
+ev_window_go_last_page (EvWindow *ev_window)
+{
+	ev_window_cmd_go_last_page (NULL, ev_window);
+}
+
 static void
 ev_window_cmd_go_forward (GtkAction *action, EvWindow *ev_window)
 {
@@ -3358,6 +3385,12 @@
 	ev_window_run_presentation (window);
 }
 
+void
+ev_window_start_presentation (EvWindow *ev_window)
+{
+	ev_window_run_presentation (ev_window);
+}
+
 static gboolean
 ev_window_enumerate_printer_cb (GtkPrinter *printer,
 				EvWindow   *window)
@@ -4101,7 +4134,16 @@
 {
 	EvWindow *window = EV_WINDOW (object);
 	EvWindowPrivate *priv = window->priv;
+#ifdef ENABLE_DBUS
+	GObject *keys;
 
+	keys = ev_application_get_media_keys (EV_APP);
+	if (keys) {
+		ev_media_player_keys_focused (EV_MEDIA_PLAYER_KEYS (keys), NULL);
+		g_object_unref (keys);
+	}
+#endif /* ENABLE_DBUS */
+
 	if (priv->monitor) {
 		g_object_unref (priv->monitor);
 		priv->monitor = NULL;
@@ -4624,6 +4666,16 @@
 static gboolean
 view_actions_focus_in_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
 {
+#ifdef ENABLE_DBUS
+	GObject *keys;
+
+	keys = ev_application_get_media_keys (EV_APP);
+	if (keys) {
+		ev_media_player_keys_focused (EV_MEDIA_PLAYER_KEYS (keys), window);
+		g_object_unref (keys);
+	}
+#endif /* ENABLE_DBUS */
+
 	update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, FALSE);
 	ev_window_set_action_sensitive (window, "ViewToolbar", TRUE);
 
Index: shell/ev-application.h
===================================================================
--- shell/ev-application.h	(revision 3058)
+++ shell/ev-application.h	(working copy)
@@ -78,6 +78,7 @@
 						      GdkScreen       *screen,
     						      guint32          timestamp);
 GList		 *ev_application_get_windows	     (EvApplication   *application);
+GObject		 *ev_application_get_media_keys	     (EvApplication   *application);
 
 EggToolbarsModel *ev_application_get_toolbars_model  (EvApplication   *application);
 void              ev_application_save_toolbars_model (EvApplication   *application);
Index: shell/ev-window.h
===================================================================
--- shell/ev-window.h	(revision 3058)
+++ shell/ev-window.h	(working copy)
@@ -86,6 +86,13 @@
 					   int             first_page,
 					   int		   last_page);
 
+void		ev_window_go_last_page	  (EvWindow       *ev_window);
+void		ev_window_go_first_page	  (EvWindow       *ev_window);
+void		ev_window_go_next_page	  (EvWindow       *ev_window);
+void		ev_window_go_previous_page(EvWindow       *ev_window);
+void		ev_window_start_presentation
+					  (EvWindow       *ev_window);
+
 G_END_DECLS
 
 #endif /* !EV_WINDOW_H */
Index: shell/Makefile.am
===================================================================
--- shell/Makefile.am	(revision 3058)
+++ shell/Makefile.am	(working copy)
@@ -16,6 +16,13 @@
 
 bin_PROGRAMS=evince
 
+EV_MEDIA_PLAYER_KEYS_SOURCES = ev-media-player-keys.c ev-media-player-keys.h
+if ENABLE_DBUS
+DBUS_SOURCES = $(EV_MEDIA_PLAYER_KEYS_SOURCES)
+else
+DBUS_SOURCES = $(null)
+endif
+
 evince_SOURCES=				\
 	eggfindbar.c			\
 	eggfindbar.h			\
@@ -31,6 +38,7 @@
 	ev-history.h			\
 	ev-marshal.c			\
 	ev-marshal.h			\
+	$(DBUS_SOURCES)			\
 	ev-message-area.c		\
 	ev-message-area.h		\
 	ev-metadata-manager.c		\
@@ -105,7 +113,8 @@
 endif
 
 EXTRA_DIST = ev-marshal.list		\
-	ev-application-service.xml
+	ev-application-service.xml	\
+	$(EV_MEDIA_PLAYER_KEYS_SOURCES)
 
 
 ev-marshal.h: $(srcdir)/ev-marshal.list
Index: shell/ev-media-player-keys.c
===================================================================
--- shell/ev-media-player-keys.c	(revision 0)
+++ shell/ev-media-player-keys.c	(revision 0)
@@ -0,0 +1,193 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Copyright (C) 2007 Jan Arne Petersen <jap@gnome.org>
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <dbus/dbus-glib.h>
+#include <string.h>
+
+#include "ev-media-player-keys.h"
+
+#include "ev-marshal.h"
+
+struct _EvMediaPlayerKeys
+{
+	GObject        parent;
+	DBusGProxy    *media_player_keys_proxy;
+	EvWindow      *window;
+};
+
+struct _EvMediaPlayerKeysClass
+{
+	GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (EvMediaPlayerKeys, ev_media_player_keys, G_TYPE_OBJECT)
+
+GType	ev_media_player_keys_get_type		(void) G_GNUC_CONST;
+
+static void ev_media_player_keys_init		(EvMediaPlayerKeys *keys);
+static void ev_media_player_keys_finalize	(GObject *object);
+
+static void
+ev_media_player_keys_class_init (EvMediaPlayerKeysClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = ev_media_player_keys_finalize;
+}
+
+static void
+proxy_destroy (DBusGProxy *proxy,
+	       EvMediaPlayerKeys* keys)
+{
+	keys->media_player_keys_proxy = NULL;
+}
+
+static void
+on_media_player_key_pressed (DBusGProxy *proxy, const gchar *application, const gchar *key, EvMediaPlayerKeys *keys)
+{
+	if (strcmp ("Evince", application) == 0 && keys->window != NULL) {
+		/* Note how Previous/Next only go to the
+		 * next/previous page despite their icon telling you
+		 * they should go to the beginning/end.
+		 *
+		 * There's very few keyboards with FFW/RWD though,
+		 * so we stick the most useful keybinding on the most
+		 * often seen keys
+		 */
+		if (strcmp ("Play", key) == 0) {
+			ev_window_start_presentation (keys->window);
+		} else if (strcmp ("Previous", key) == 0) {
+			ev_window_go_previous_page (keys->window);
+		} else if (strcmp ("Next", key) == 0) {
+			ev_window_go_next_page (keys->window);
+		} else if (strcmp ("FastForward", key) == 0) {
+			ev_window_go_last_page (keys->window);
+		} else if (strcmp ("Rewind", key) == 0) {
+			ev_window_go_first_page (keys->window);
+		}
+	}
+}
+
+static void
+ev_media_player_keys_init (EvMediaPlayerKeys *keys)
+{
+	DBusGConnection *connection;
+	GError *err = NULL;
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err);
+	if (connection == NULL) {
+		g_warning ("Error connecting to D-Bus: %s", err->message);
+		return;
+	}
+
+	/* Try the gnome-settings-daemon version,
+	 * then the gnome-control-center version of things */
+	keys->media_player_keys_proxy = dbus_g_proxy_new_for_name_owner (connection,
+								       "org.gnome.SettingsDaemon",
+								       "/org/gnome/SettingsDaemon/MediaKeys",
+								       "org.gnome.SettingsDaemon.MediaKeys",
+								       NULL);
+	if (keys->media_player_keys_proxy == NULL) {
+		keys->media_player_keys_proxy = dbus_g_proxy_new_for_name_owner (connection,
+									       "org.gnome.SettingsDaemon",
+									       "/org/gnome/SettingsDaemon",
+									       "org.gnome.SettingsDaemon",
+									       &err);
+	}
+
+	dbus_g_connection_unref (connection);
+	if (err != NULL) {
+		g_warning ("Failed to create dbus proxy for org.gnome.SettingsDaemon: %s",
+			   err->message);
+		g_error_free (err);
+		return;
+	} else {
+		g_signal_connect_object (keys->media_player_keys_proxy,
+					 "destroy",
+					 G_CALLBACK (proxy_destroy),
+					 keys, 0);
+	}
+
+	dbus_g_proxy_call (keys->media_player_keys_proxy,
+			   "GrabMediaPlayerKeys", NULL,
+			   G_TYPE_STRING, "Evince", G_TYPE_UINT, 0, G_TYPE_INVALID,
+			   G_TYPE_INVALID);
+
+	dbus_g_object_register_marshaller (ev_marshal_VOID__STRING_STRING,
+					   G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (keys->media_player_keys_proxy, "MediaPlayerKeyPressed",
+				 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal (keys->media_player_keys_proxy, "MediaPlayerKeyPressed",
+				     G_CALLBACK (on_media_player_key_pressed), keys, NULL);
+}
+
+void
+ev_media_player_keys_focused (EvMediaPlayerKeys *keys, EvWindow *window)
+{
+	if (keys->media_player_keys_proxy != NULL) {
+		if (keys->window != NULL) {
+			g_object_unref (keys->window);
+			keys->window = NULL;
+		}
+		if (window != NULL) {
+			dbus_g_proxy_call (keys->media_player_keys_proxy,
+					   "GrabMediaPlayerKeys", NULL,
+					   G_TYPE_STRING, "Evince", G_TYPE_UINT, 0, G_TYPE_INVALID,
+					   G_TYPE_INVALID);
+			keys->window = g_object_ref (window);
+		}
+	}
+}
+
+static void
+ev_media_player_keys_finalize (GObject *object)
+{
+	EvMediaPlayerKeys *keys = EV_MEDIA_PLAYER_KEYS (object);
+
+	if (keys->media_player_keys_proxy != NULL) {
+		dbus_g_proxy_call (keys->media_player_keys_proxy,
+				   "ReleaseMediaPlayerKeys", NULL,
+				   G_TYPE_STRING, "Ev", G_TYPE_INVALID, G_TYPE_INVALID);
+		g_object_unref (keys->media_player_keys_proxy);
+		keys->media_player_keys_proxy = NULL;
+	}
+
+	if (keys->window != NULL) {
+		g_object_unref (keys->window);
+		keys->window = NULL;
+	}
+
+	G_OBJECT_CLASS (ev_media_player_keys_parent_class)->finalize (object);
+}
+
+EvMediaPlayerKeys *
+ev_media_player_keys_new (void)
+{
+	return g_object_new (EV_TYPE_MEDIA_PLAYER_KEYS, NULL);
+}
+
