From 7042909ab901b54e952410572b3d724e49094158 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 24 Jun 2008 18:15:12 +0000 Subject: [PATCH] When building with D-Bus support, listen for multimedia key events from 2008-06-24 Bastien Nocera * shell/Makefile.am: * shell/ev-application.c (ev_application_init), (ev_application_get_media_keys): * shell/ev-application.h: * shell/ev-marshal.list: * shell/ev-media-player-keys.c (ev_media_player_keys_class_init), (proxy_destroy), (on_media_player_key_pressed), (ev_media_player_keys_init), (ev_media_player_keys_focused), (ev_media_player_keys_finalize), (ev_media_player_keys_new): * shell/ev-media-player-keys.h: * shell/ev-window.c (ev_window_go_previous_page), (ev_window_go_next_page), (ev_window_go_first_page), (ev_window_go_last_page), (ev_window_start_presentation), (ev_window_dispose), (view_actions_focus_in_cb): * shell/ev-window.h: When building with D-Bus support, listen for multimedia key events from gnome-settings-daemon. This allows to go to the next/previous/first/last pages using, respectively, Next/Previous/Rewing/Fast Forward. The Play button is used to start a presentation. Fixes bug #539971. svn path=/trunk/; revision=3059 --- ChangeLog | 22 ++++ shell/Makefile.am | 11 +- shell/ev-application.c | 31 ++++++ shell/ev-application.h | 1 + shell/ev-marshal.list | 1 + shell/ev-media-player-keys.c | 191 +++++++++++++++++++++++++++++++++++ shell/ev-media-player-keys.h | 49 +++++++++ shell/ev-window.c | 52 ++++++++++ shell/ev-window.h | 7 ++ 9 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 shell/ev-media-player-keys.c create mode 100644 shell/ev-media-player-keys.h diff --git a/ChangeLog b/ChangeLog index 8892d4d7..96e81d8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2008-06-24 Bastien Nocera + + * shell/Makefile.am: + * shell/ev-application.c (ev_application_init), + (ev_application_get_media_keys): + * shell/ev-application.h: + * shell/ev-marshal.list: + * shell/ev-media-player-keys.c (ev_media_player_keys_class_init), + (proxy_destroy), (on_media_player_key_pressed), + (ev_media_player_keys_init), (ev_media_player_keys_focused), + (ev_media_player_keys_finalize), (ev_media_player_keys_new): + * shell/ev-media-player-keys.h: + * shell/ev-window.c (ev_window_go_previous_page), + (ev_window_go_next_page), (ev_window_go_first_page), + (ev_window_go_last_page), (ev_window_start_presentation), + (ev_window_dispose), (view_actions_focus_in_cb): + * shell/ev-window.h: When building with D-Bus support, listen + for multimedia key events from gnome-settings-daemon. This allows + to go to the next/previous/first/last pages using, respectively, + Next/Previous/Rewing/Fast Forward. The Play button is used to start + a presentation. Fixes bug #539971. + 2008-06-19 Nickolay V. Shmyrev * configure.ac: diff --git a/shell/Makefile.am b/shell/Makefile.am index 824cf3f7..3d857716 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -16,6 +16,13 @@ INCLUDES= \ 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 @@ evince_SOURCES= \ 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 @@ BUILT_SOURCES += ev-application-service.h 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 diff --git a/shell/ev-application.c b/shell/ev-application.c index 6e7a6e67..7ad13820 100644 --- a/shell/ev-application.c +++ b/shell/ev-application.c @@ -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 @@ -59,6 +62,10 @@ struct _EvApplication { 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 @@ ev_application_init (EvApplication *ev_application) 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 @@ ev_application_get_windows (EvApplication *application) 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) { diff --git a/shell/ev-application.h b/shell/ev-application.h index 4525590e..efaf0b63 100644 --- a/shell/ev-application.h +++ b/shell/ev-application.h @@ -78,6 +78,7 @@ void ev_application_open_uri_list (EvApplication *application, 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); diff --git a/shell/ev-marshal.list b/shell/ev-marshal.list index c2a026bf..d3b99fd9 100644 --- a/shell/ev-marshal.list +++ b/shell/ev-marshal.list @@ -1,3 +1,4 @@ VOID:NONE VOID:OBJECT,OBJECT VOID:ENUM,BOOLEAN +VOID:STRING,STRING diff --git a/shell/ev-media-player-keys.c b/shell/ev-media-player-keys.c new file mode 100644 index 00000000..c244b2e9 --- /dev/null +++ b/shell/ev-media-player-keys.c @@ -0,0 +1,191 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Jan Arne Petersen + * Copyright (C) 2008 Bastien Nocera + * + * 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 +#include +#include +#include +#include +#include + +#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) + +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); +} + diff --git a/shell/ev-media-player-keys.h b/shell/ev-media-player-keys.h new file mode 100644 index 00000000..135aa818 --- /dev/null +++ b/shell/ev-media-player-keys.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Jan Arne Petersen + * Copyright (C) 2008 Bastien Nocera + * + * 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. + * + */ + +#ifndef EV_MEDIA_PLAYER_KEYS_H +#define EV_MEDIA_PLAYER_KEYS_H + +#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); + +G_END_DECLS + +#endif /* !EV_MEDIA_PLAYER_KEYS_H */ diff --git a/shell/ev-window.c b/shell/ev-window.c index 81efe3d7..6849b240 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -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 @@ -3231,6 +3234,12 @@ ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window) 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_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window) 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_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window) 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_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window) 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_cmd_start_presentation (GtkAction *action, EvWindow *window) 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,6 +4134,15 @@ ev_window_dispose (GObject *object) { 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); @@ -4624,6 +4666,16 @@ sidebar_widget_model_set (EvSidebarLinks *ev_sidebar_links, 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); diff --git a/shell/ev-window.h b/shell/ev-window.h index 3680bbff..ebaff35a 100644 --- a/shell/ev-window.h +++ b/shell/ev-window.h @@ -86,6 +86,13 @@ void ev_window_print_range (EvWindow *ev_window, 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 */ -- 2.43.5