[rhythmbox] replace default window event handling



commit 6073129ef5baee45fbd60d2747bb013d586d6584
Author: Jonathan Matthew <jonathan d14n org>
Date:   Thu Mar 17 20:58:41 2016 +1000

    replace default window event handling
    
    This allows us to add default actions for keys without overriding
    normal widget behaviour.  Some of the playback controls were
    overriding tree view shortcuts, which is apparently an outrage.

 shell/rb-application.c  |   79 +++++++++++++++++++++++++++++++++++++++++++++++
 shell/rb-application.h  |    3 ++
 shell/rb-shell-player.c |   11 ++++--
 shell/rb-shell.c        |   32 ++++++++++++++-----
 4 files changed, 113 insertions(+), 12 deletions(-)
---
diff --git a/shell/rb-application.c b/shell/rb-application.c
index 2b922b3..8e91f1d 100644
--- a/shell/rb-application.c
+++ b/shell/rb-application.c
@@ -53,6 +53,14 @@
 static void rb_application_class_init (RBApplicationClass *klass);
 static void rb_application_init (RBApplication *app);
 
+typedef struct {
+       guint keyval;
+       GdkModifierType mods;
+       char *prefix;
+       char *action;
+       GVariant *parameter;
+} RBApplicationAccel;
+
 struct _RBApplicationPrivate
 {
        RBShell *shell;
@@ -69,6 +77,8 @@ struct _RBApplicationPrivate
        gboolean disable_plugins;
        char *rhythmdb_file;
        char *playlists_file;
+
+       GList *accelerators;
 };
 
 G_DEFINE_TYPE (RBApplication, rb_application, GTK_TYPE_APPLICATION);
@@ -899,3 +909,72 @@ rb_application_set_menu_accelerators (RBApplication *app, GMenuModel *menu, gboo
                g_object_unref (iter);
        }
 }
+
+/**
+ * rb_application_add_accelerator:
+ * @app: the #RBApplication
+ * @accel: accelerator string
+ * @action: the name of the action to activate
+ * @parameter: parameter to pass when activating the action, or NULL if
+ *   the action does not accept an activation parameter.
+ *
+ * Like #gtk_application_add_accelerator, except the accelerator only applies
+ * if the key was not handled by the focused widget.
+ */
+void
+rb_application_add_accelerator (RBApplication *app, const char *accel, const char *action, GVariant 
*parameter)
+{
+       RBApplicationAccel *a = g_new0 (RBApplicationAccel, 1);
+       char **bits;
+
+       gtk_accelerator_parse (accel, &a->keyval, &a->mods);
+       if (parameter != NULL)
+               a->parameter = g_variant_ref (parameter);
+
+       bits = g_strsplit (action, ".", 2);
+       a->prefix = bits[0];
+       a->action = bits[1];
+       g_free (bits);
+
+       app->priv->accelerators = g_list_append (app->priv->accelerators, a);
+}
+
+/**
+ * rb_application_activate_key:
+ * @app: the #RBApplication
+ * @event: a #GdkEventKey
+ *
+ * Attempts to activate an accelerator registered using #rb_application_add_accelerator.
+ *
+ * Return value: %TRUE if an accelerator was activated
+ */
+gboolean
+rb_application_activate_key (RBApplication *app, GdkEventKey *event)
+{
+       GList *l;
+       GtkWidget *window;
+       gboolean ret = FALSE;
+
+       g_object_get (app->priv->shell, "window", &window, NULL);
+
+       for (l = app->priv->accelerators; l != NULL; l = l->next) {
+               RBApplicationAccel *accel = l->data;
+               if (accel->keyval == event->keyval &&
+                   accel->mods == event->state) {
+                       GActionGroup *group;
+
+                       group = gtk_widget_get_action_group (window, accel->prefix);
+                       if (group == NULL)
+                               group = G_ACTION_GROUP (app);
+
+                       g_action_group_activate_action (group,
+                                                       accel->action,
+                                                       accel->parameter);
+                       ret = TRUE;
+                       break;
+               }
+       }
+
+       g_object_unref (window);
+       return ret;
+}
diff --git a/shell/rb-application.h b/shell/rb-application.h
index 747652a..d02e568 100644
--- a/shell/rb-application.h
+++ b/shell/rb-application.h
@@ -69,6 +69,9 @@ GMenuModel *  rb_application_get_plugin_menu (RBApplication *app, const char *men
 void           rb_application_add_plugin_menu_item (RBApplication *app, const char *menu, const char *id, 
GMenuItem *item);
 void           rb_application_remove_plugin_menu_item (RBApplication *app, const char *menu, const char *id);
 
+void           rb_application_add_accelerator (RBApplication *app, const char *accel, const char *action, 
GVariant *parameter);
+gboolean       rb_application_activate_key (RBApplication *app, GdkEventKey *event);
+
 G_END_DECLS
 
 #endif /* RB_APPLICATION_H */
diff --git a/shell/rb-shell-player.c b/shell/rb-shell-player.c
index 8d5933b..5aa03b1 100644
--- a/shell/rb-shell-player.c
+++ b/shell/rb-shell-player.c
@@ -2972,11 +2972,14 @@ rb_shell_player_constructed (GObject *object)
                                         G_N_ELEMENTS (actions),
                                         player);
 
+       /* these only take effect if the focused widget doesn't handle the event */
+       rb_application_add_accelerator (app, "<Ctrl>Left", "app.play-previous", NULL);
+       rb_application_add_accelerator (app, "<Ctrl>Right", "app.play-next", NULL);
+       rb_application_add_accelerator (app, "<Ctrl>Up", "app.volume-up", NULL);
+       rb_application_add_accelerator (app, "<Ctrl>Down", "app.volume-down", NULL);
+
+       /* these take effect regardless of widget key handling */
        gtk_application_add_accelerator (GTK_APPLICATION (app), "<Ctrl>p", "app.play", NULL);
-       gtk_application_add_accelerator (GTK_APPLICATION (app), "<Ctrl>Left", "app.play-previous", NULL);
-       gtk_application_add_accelerator (GTK_APPLICATION (app), "<Ctrl>Right", "app.play-next", NULL);
-       gtk_application_add_accelerator (GTK_APPLICATION (app), "<Ctrl>Up", "app.volume-up", NULL);
-       gtk_application_add_accelerator (GTK_APPLICATION (app), "<Ctrl>Down", "app.volume-down", NULL);
        gtk_application_add_accelerator (GTK_APPLICATION (app), "<Ctrl>r", "app.play-repeat", 
g_variant_new_boolean (TRUE));
        gtk_application_add_accelerator (GTK_APPLICATION (app), "<Ctrl>u", "app.play-shuffle", 
g_variant_new_boolean (TRUE));
 
diff --git a/shell/rb-shell.c b/shell/rb-shell.c
index 39e0082..0130337 100644
--- a/shell/rb-shell.c
+++ b/shell/rb-shell.c
@@ -1978,25 +1978,41 @@ rb_shell_key_press_event_cb (GtkWidget *win,
                             GdkEventKey *event,
                             RBShell *shell)
 {
-#ifndef HAVE_MMKEYS
-       return FALSE;
-#else
-
-       gboolean retval = TRUE;
+       GtkWindow *window = GTK_WINDOW (win);
+       gboolean handled = FALSE;
 
+#ifdef HAVE_MMKEYS
        switch (event->keyval) {
        case XF86XK_Back:
                rb_shell_player_do_previous (shell->priv->player_shell, NULL);
+               handled = TRUE;
                break;
        case XF86XK_Forward:
                rb_shell_player_do_next (shell->priv->player_shell, NULL);
+               handled = TRUE;
                break;
        default:
-               retval = FALSE;
+               break;
+       }
+#endif
+
+       if (!handled)
+               handled = gtk_window_activate_key (window, event);
+
+       if (!handled)
+               handled = gtk_window_propagate_key_event (window, event);
+
+       if (!handled)
+               handled = rb_application_activate_key (shell->priv->application, event);
+
+       if (!handled) {
+               GObjectClass *object_class;
+               object_class = G_OBJECT_GET_CLASS (win);
+               handled = GTK_WIDGET_CLASS (g_type_class_peek_parent (object_class))->key_press_event (win, 
event);
        }
 
-       return retval;
-#endif /* !HAVE_MMKEYS */
+       /* we're completely replacing the default window handling, so always return TRUE */
+       return TRUE;
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]