shortcuttrigger: Add support for mnemonics
authorBenjamin Otte <otte@redhat.com>
Thu, 16 Aug 2018 01:59:24 +0000 (03:59 +0200)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 26 Mar 2020 03:14:27 +0000 (23:14 -0400)
Mnemonics need to be triggered with help from the controllers (who
determine the modifiers). Support for that has been added, too.

Mnemonics do not use this yet though.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkshortcut.c
gtk/gtkshortcut.h
gtk/gtkshortcutcontroller.c
gtk/gtkshortcutcontroller.h
gtk/gtkshortcuttrigger.c
gtk/gtkshortcuttrigger.h

index cfc8e03fde2a408603ccafa4dfc547ef2fd69364..534653d9228580c46fc1980a461a90164686504e 100644 (file)
@@ -6061,6 +6061,10 @@ gtk_keyval_trigger_new
 gtk_keyval_trigger_get_modifiers
 gtk_keyval_trigger_get_keyval
 
+<SUBSECTION>
+gtk_mnemonic_trigger_new
+gtk_mnemonic_trigger_get_keyval
+
 <SUBSECTION Private>
 gtk_shortcut_trigger_get_type
 </SECTION>
@@ -6099,6 +6103,8 @@ gtk_shortcut_get_type
 GtkShortcutController
 gtk_shortcut_controller_new
 GtkShortcutScope
+gtk_shortcut_controller_set_mnemonics_modifiers
+gtk_shortcut_controller_get_mnemonics_modifiers
 gtk_shortcut_controller_set_scope
 gtk_shortcut_controller_get_scope
 gtk_shortcut_controller_add_shortcut
index 6f8012c20ff557a1a3e1808ae5d8e2da3c8b7703..6d017e37219540b80767d1b38ae289c81f40475c 100644 (file)
@@ -259,13 +259,6 @@ gtk_shortcut_new (void)
   return g_object_new (GTK_TYPE_SHORTCUT, NULL);
 }
 
-gboolean
-gtk_shortcut_trigger (GtkShortcut *self,
-                      GdkEvent    *event)
-{
-  return gtk_shortcut_trigger_trigger (self->trigger, event);
-}
-
 static gboolean
 binding_compose_params (GObject         *object,
                         GVariantIter    *args,
index 9ed37ea90d9ba57ef11d0a00e4a2d3842f759b06..a3a02a75140b62bf6a80225d009e15755f5a0187 100644 (file)
@@ -44,9 +44,6 @@ GtkShortcutTrigger *
                 gtk_shortcut_get_trigger                        (GtkShortcut            *self);
 
 GDK_AVAILABLE_IN_ALL
-gboolean        gtk_shortcut_trigger                            (GtkShortcut            *self,
-                                                                 GdkEvent               *event);
-GDK_AVAILABLE_IN_ALL
 gboolean        gtk_shortcut_activate                           (GtkShortcut            *self,
                                                                  GtkWidget              *widget);
 
index ed56a98dc67d030bef4991424c1badc130f2afff..c47d657f393bf388d9acf3bd92bbf84706b8947c 100644 (file)
@@ -34,6 +34,7 @@
 #include "gtkeventcontrollerprivate.h"
 #include "gtkintl.h"
 #include "gtkshortcut.h"
+#include "gtkshortcuttrigger.h"
 #include "gtktypebuiltins.h"
 #include "gtkwidgetprivate.h"
 
@@ -45,6 +46,7 @@ struct _GtkShortcutController
 
   GSList *shortcuts;
   GtkShortcutScope scope;
+  GdkModifierType mnemonics_modifiers;
 
   guint run_class : 1;
   guint run_managed : 1;
@@ -57,6 +59,7 @@ struct _GtkShortcutControllerClass
 
 enum {
   PROP_0,
+  PROP_MNEMONICS_MODIFIERS,
   PROP_SCOPE,
 
   N_PROPS
@@ -88,6 +91,10 @@ gtk_shortcut_controller_set_property (GObject      *object,
 
   switch (prop_id)
     {
+    case PROP_MNEMONICS_MODIFIERS:
+      gtk_shortcut_controller_set_mnemonics_modifiers (self, g_value_get_flags (value));
+      break;
+
     case PROP_SCOPE:
       gtk_shortcut_controller_set_scope (self, g_value_get_enum (value));
       break;
@@ -107,6 +114,10 @@ gtk_shortcut_controller_get_property (GObject    *object,
 
   switch (prop_id)
     {
+    case PROP_MNEMONICS_MODIFIERS:
+      g_value_set_flags (value, self->mnemonics_modifiers);
+      break;
+
     case PROP_SCOPE:
       g_value_set_enum (value, self->scope);
       break;
@@ -130,9 +141,10 @@ gtk_shortcut_controller_dispose (GObject *object)
 static gboolean
 gtk_shortcut_controller_trigger_shortcut (GtkShortcutController *self,
                                           GtkShortcut           *shortcut,
-                                          GdkEvent              *event)
+                                          GdkEvent              *event,
+                                          gboolean               enable_mnemonics)
 {
-  if (!gtk_shortcut_trigger (shortcut, event))
+  if (!gtk_shortcut_trigger_trigger (gtk_shortcut_get_trigger (shortcut), event, enable_mnemonics))
     return FALSE;
 
   return gtk_shortcut_activate (shortcut, gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)));
@@ -142,7 +154,8 @@ static gboolean
 gtk_shortcut_controller_run_controllers (GtkEventController *controller,
                                          GdkEvent           *event,
                                          double              x,
-                                         double              y)
+                                         double              y,
+                                         gboolean            enable_mnemonics)
 {
   GtkShortcutController *self = GTK_SHORTCUT_CONTROLLER (controller);
   GtkWidget *widget;
@@ -150,7 +163,7 @@ gtk_shortcut_controller_run_controllers (GtkEventController *controller,
 
   for (l = self->shortcuts; l; l = l->next)
     {
-      if (gtk_shortcut_controller_trigger_shortcut (self, l->data, event))
+      if (gtk_shortcut_controller_trigger_shortcut (self, l->data, event, enable_mnemonics))
         return TRUE;
     }
 
@@ -160,7 +173,7 @@ gtk_shortcut_controller_run_controllers (GtkEventController *controller,
 
       for (l = gtk_widget_class_get_shortcuts (GTK_WIDGET_GET_CLASS (widget)); l; l = l->next)
         {
-          if (gtk_shortcut_controller_trigger_shortcut (self, l->data, event))
+          if (gtk_shortcut_controller_trigger_shortcut (self, l->data, event, enable_mnemonics))
             return TRUE;
         }
     }
@@ -175,7 +188,7 @@ gtk_shortcut_controller_run_controllers (GtkEventController *controller,
           if (gtk_event_controller_get_propagation_phase (l->data) != current_phase)
             continue;
 
-          if (gtk_shortcut_controller_run_controllers (l->data, event, x, y))
+          if (gtk_shortcut_controller_run_controllers (l->data, event, x, y, enable_mnemonics))
             return TRUE;
         }
     }
@@ -190,11 +203,23 @@ gtk_shortcut_controller_handle_event (GtkEventController *controller,
                                       double              y)
 {
   GtkShortcutController *self = GTK_SHORTCUT_CONTROLLER (controller);
+  gboolean enable_mnemonics;
 
   if (self->scope != GTK_SHORTCUT_SCOPE_LOCAL)
     return FALSE;
 
-  return gtk_shortcut_controller_run_controllers (controller, event, x, y);
+  if (gdk_event_get_event_type (event) == GDK_KEY_PRESS)
+    {
+      GdkModifierType modifiers;
+      modifiers = gdk_event_get_modifier_state (event);
+      enable_mnemonics = (modifiers & gtk_accelerator_get_default_mod_mask ()) == self->mnemonics_modifiers;
+    }
+  else
+    {
+      enable_mnemonics = FALSE;
+    }
+
+  return gtk_shortcut_controller_run_controllers (controller, event, x, y, enable_mnemonics);
 }
 
 static void
@@ -235,6 +260,19 @@ gtk_shortcut_controller_class_init (GtkShortcutControllerClass *klass)
   controller_class->set_widget = gtk_shortcut_controller_set_widget;
   controller_class->unset_widget = gtk_shortcut_controller_unset_widget;
 
+  /**
+   * GtkShortcutController:mnemonic-modifiers:
+   *
+   * The modifiers that need to be pressed to allow mnemonics activation.
+   */
+  properties[PROP_MNEMONICS_MODIFIERS] =
+      g_param_spec_flags ("mnemonic-modifiers",
+                          P_("Mnemonic modifers"),
+                          P_("The modifiers to be pressed to allow mnemonics activation"),
+                          GDK_TYPE_MODIFIER_TYPE,
+                          GDK_MOD1_MASK,
+                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
   /**
    * GtkShortcutController:scope:
    *
@@ -249,12 +287,12 @@ gtk_shortcut_controller_class_init (GtkShortcutControllerClass *klass)
                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
-
 }
 
 static void
-gtk_shortcut_controller_init (GtkShortcutController *controller)
+gtk_shortcut_controller_init (GtkShortcutController *self)
 {
+  self->mnemonics_modifiers = GDK_MOD1_MASK;
 }
 
 static void
@@ -441,3 +479,48 @@ gtk_shortcut_controller_get_scope (GtkShortcutController *self)
   return self->scope;
 }
 
+/**
+ * gtk_shortcut_controller_set_mnemonics_modifiers:
+ * @self: a #GtkShortcutController
+ * @modifiers: the new mnemonics_modifiers to use
+ *
+ * Sets the controller to have the given @mnemonics_modifiers.
+ *
+ * The mnemonics modifiers determines which modifiers need to be pressed to allow
+ * activation of shortcuts with mnemonics triggers.
+ *
+ * This value is only relevant for local shortcut controllers. Global and managed
+ * shortcut controllers will have their shortcuts activated from other places which
+ * have their own modifiers for activating mnemonics.
+ **/
+void
+gtk_shortcut_controller_set_mnemonics_modifiers (GtkShortcutController *self,
+                                                 GdkModifierType        modifiers)
+{
+  g_return_if_fail (GTK_IS_SHORTCUT_CONTROLLER (self));
+
+  if (self->mnemonics_modifiers == modifiers)
+    return;
+
+  self->mnemonics_modifiers = modifiers;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MNEMONICS_MODIFIERS]);
+}
+
+/**
+ * gtk_shortcut_controller_get_mnemonics_modifiers:
+ * @self: a #GtkShortcutController
+ *
+ * Gets the mnemonics modifiers for when this controller activates its shortcuts. See
+ * gtk_shortcut_controller_set_mnemonics_modifiers() for details.
+ *
+ * Returns: the controller's mnemonics modifiers
+ **/
+GdkModifierType
+gtk_shortcut_controller_get_mnemonics_modifiers (GtkShortcutController *self)
+{
+  g_return_val_if_fail (GTK_IS_SHORTCUT_CONTROLLER (self), GTK_SHORTCUT_SCOPE_LOCAL);
+
+  return self->mnemonics_modifiers;
+}
+
index fea66f34555b9549dc09d1a30b6a8184865a7f89..fb31ffe8cb586384d51e3e76b262a7ef476fc8ac 100644 (file)
@@ -45,6 +45,11 @@ GType                   gtk_shortcut_controller_get_type                (void) G
 GDK_AVAILABLE_IN_ALL
 GtkEventController *    gtk_shortcut_controller_new                     (void);
 
+GDK_AVAILABLE_IN_ALL
+void                    gtk_shortcut_controller_set_mnemonics_modifiers (GtkShortcutController  *self,
+                                                                         GdkModifierType         modifiers);
+GDK_AVAILABLE_IN_ALL
+GdkModifierType         gtk_shortcut_controller_get_mnemonics_modifiers (GtkShortcutController  *self);
 GDK_AVAILABLE_IN_ALL
 void                    gtk_shortcut_controller_set_scope               (GtkShortcutController  *self,
                                                                          GtkShortcutScope        scope);
index cdefa820597bce054c1854505b741268b2f319a6..b56cf6d0eed75681afd3a40a9e0330cc1316ba1a 100644 (file)
@@ -60,7 +60,8 @@ struct _GtkShortcutTriggerClass
 
   void            (* finalize)    (GtkShortcutTrigger  *trigger);
   gboolean        (* trigger)     (GtkShortcutTrigger  *trigger,
-                                   GdkEvent            *event);
+                                   GdkEvent            *event,
+                                   gboolean             enable_mnemonics);
   void            (* print)       (GtkShortcutTrigger  *trigger,
                                    GString             *string);
   gboolean        (* print_label) (GtkShortcutTrigger  *trigger,
@@ -158,6 +159,9 @@ gtk_shortcut_trigger_get_trigger_type (GtkShortcutTrigger *self)
  * gtk_shortcut_trigger_trigger:
  * @self: a #GtkShortcutTrigger
  * @event: the event to check
+ * @enable_mnemonics: %TRUE if mnemonics should trigger. Usually the
+ *     value of this property is determined by checking that the passed
+ *     in @event is a Key event and has the right modifiers set.
  *
  * Checks if the given @event triggers @self. If so,
  * returns %TRUE.
@@ -166,11 +170,12 @@ gtk_shortcut_trigger_get_trigger_type (GtkShortcutTrigger *self)
  **/
 gboolean
 gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
-                              GdkEvent           *event)
+                              GdkEvent           *event,
+                              gboolean            enable_mnemonics)
 {
   g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), FALSE);
 
-  return self->trigger_class->trigger (self, event);
+  return self->trigger_class->trigger (self, event, enable_mnemonics);
 }
 
 /**
@@ -302,7 +307,8 @@ gtk_never_trigger_finalize (GtkShortcutTrigger *trigger)
 
 static gboolean
 gtk_never_trigger_trigger (GtkShortcutTrigger *trigger,
-                           GdkEvent           *event)
+                           GdkEvent           *event,
+                           gboolean            enable_mnemonics)
 {
   return FALSE;
 }
@@ -368,7 +374,8 @@ gtk_keyval_trigger_finalize (GtkShortcutTrigger *trigger)
 
 static gboolean
 gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
-                            GdkEvent           *event)
+                            GdkEvent           *event,
+                            gboolean            enable_mnemonics)
 {
   GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
   GdkModifierType modifiers;
@@ -489,6 +496,134 @@ gtk_keyval_trigger_get_keyval (GtkShortcutTrigger *self)
   return trigger->keyval;
 }
 
+/*** GTK_MNEMONIC_TRIGGER ***/
+
+typedef struct _GtkMnemonicTrigger GtkMnemonicTrigger;
+
+struct _GtkMnemonicTrigger
+{
+  GtkShortcutTrigger trigger;
+
+  guint keyval;
+};
+
+static void
+gtk_mnemonic_trigger_finalize (GtkShortcutTrigger *trigger)
+{
+}
+
+static gboolean
+gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger,
+                              GdkEvent           *event,
+                              gboolean            enable_mnemonics)
+{
+  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+  guint keyval;
+
+  if (!enable_mnemonics)
+    return FALSE;
+
+  if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
+    return FALSE;
+
+  /* XXX: This needs to deal with groups */
+  keyval = gdk_key_event_get_keyval (event);
+
+  if (keyval == GDK_KEY_ISO_Left_Tab)
+    keyval = GDK_KEY_Tab;
+  else
+    keyval = gdk_keyval_to_lower (keyval);
+
+  return keyval == self->keyval;
+}
+
+static void
+gtk_mnemonic_trigger_print (GtkShortcutTrigger *trigger,
+                            GString            *string)
+{
+  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+  const char *keyval_str;
+
+  keyval_str = gdk_keyval_name (self->keyval);
+  if (keyval_str == NULL)
+    keyval_str = "???";
+
+  g_string_append (string, keyval_str);
+}
+
+static gboolean
+gtk_mnemonic_trigger_print_label (GtkShortcutTrigger *trigger,
+                                  GdkDisplay         *display,
+                                  GString            *string)
+{
+  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+  const char *keyval_str;
+
+  keyval_str = gdk_keyval_name (self->keyval);
+  if (keyval_str == NULL)
+    return FALSE;
+
+  g_string_append (string, keyval_str);
+
+  return TRUE;
+}
+
+static const GtkShortcutTriggerClass GTK_MNEMONIC_TRIGGER_CLASS = {
+  GTK_SHORTCUT_TRIGGER_MNEMONIC,
+  sizeof (GtkMnemonicTrigger),
+  "GtkMnemonicTrigger",
+  gtk_mnemonic_trigger_finalize,
+  gtk_mnemonic_trigger_trigger,
+  gtk_mnemonic_trigger_print,
+  gtk_mnemonic_trigger_print_label
+};
+
+/**
+ * gtk_mnemonic_trigger_new:
+ * @keyval: The keyval to trigger for
+ *
+ * Creates a #GtkShortcutTrigger that will trigger whenever the key with
+ * the given @keyval is pressed and mnemonics have been activated.
+ *
+ * Mnemonics are activated by calling code when a key event with the right
+ * modifiers is detected.
+ *
+ * Returns: A new #GtkShortcutTrigger
+ */
+GtkShortcutTrigger *
+gtk_mnemonic_trigger_new (guint keyval)
+{
+  GtkMnemonicTrigger *self;
+
+  self = (GtkMnemonicTrigger *) gtk_shortcut_trigger_new (&GTK_MNEMONIC_TRIGGER_CLASS);
+
+  /* We store keyvals as lower key */
+  if (keyval == GDK_KEY_ISO_Left_Tab)
+    self->keyval = GDK_KEY_Tab;
+  else
+    self->keyval = gdk_keyval_to_lower (keyval);
+
+  return &self->trigger;
+}
+
+/**
+ * gtk_mnemonic_trigger_get_keyval:
+ * @trigger: a mnemonic #GtkShortcutTrigger
+ *
+ * Gets the keyval that must be pressed to succeed triggering @self.
+ *
+ * Returns: the keyval
+ **/
+guint
+gtk_mnemonic_trigger_get_keyval (GtkShortcutTrigger *trigger)
+{
+  GtkMnemonicTrigger *self = (GtkMnemonicTrigger *) trigger;
+
+  g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER_TYPE (trigger, GTK_SHORTCUT_TRIGGER_MNEMONIC), 0);
+
+  return self->keyval;
+}
+
 /*** GTK_ALTERNATIVE_TRIGGER ***/
 
 typedef struct _GtkAlternativeTrigger GtkAlternativeTrigger;
@@ -512,14 +647,15 @@ gtk_alternative_trigger_finalize (GtkShortcutTrigger *trigger)
 
 static gboolean
 gtk_alternative_trigger_trigger (GtkShortcutTrigger *trigger,
-                                 GdkEvent           *event)
+                                 GdkEvent           *event,
+                                 gboolean            enable_mnemonics)
 {
   GtkAlternativeTrigger *self = (GtkAlternativeTrigger *) trigger;
 
-  if (gtk_shortcut_trigger_trigger (self->first, event))
+  if (gtk_shortcut_trigger_trigger (self->first, event, enable_mnemonics))
     return TRUE;
 
-  if (gtk_shortcut_trigger_trigger (self->second, event))
+  if (gtk_shortcut_trigger_trigger (self->second, event, enable_mnemonics))
     return TRUE;
 
   return FALSE;
index 2323bb0d13d35f277b4a74192622f936a66924b6..c9b499e74d63c63e7ab85a34e0e248f44cf62da0 100644 (file)
@@ -37,6 +37,8 @@ G_BEGIN_DECLS
  * @GTK_SHORTCUT_TRIGGER_NEVER: Never ever trigger
  * @GTK_SHORTCUT_TRIGGER_KEYVAL: Trigger if a key event with matching
  *     modifiers and keyval is received.
+ * @GTK_SHORTCUT_TRIGGER_MNEMONIC: Trigger if a key event with matching
+ *     keyval is received and mnemonics are enabled for this event.
  * @GTK_SHORTCUT_TRIGGER_ALTERNAITVE: Trigger if either if two
  *     alternatives triggers
  *
@@ -45,6 +47,7 @@ G_BEGIN_DECLS
 typedef enum {
   GTK_SHORTCUT_TRIGGER_NEVER,
   GTK_SHORTCUT_TRIGGER_KEYVAL,
+  GTK_SHORTCUT_TRIGGER_MNEMONIC,
   GTK_SHORTCUT_TRIGGER_ALTERNATIVE
 } GtkShortcutTriggerType;
 
@@ -74,7 +77,8 @@ gboolean                gtk_shortcut_trigger_print_label        (GtkShortcutTrig
 
 GDK_AVAILABLE_IN_ALL
 gboolean                gtk_shortcut_trigger_trigger            (GtkShortcutTrigger *self,
-                                                                 GdkEvent           *event);
+                                                                 GdkEvent           *event,
+                                                                 gboolean            enable_mnemonics);
 
 GDK_AVAILABLE_IN_ALL
 GtkShortcutTrigger *    gtk_never_trigger_get                   (void);
@@ -87,6 +91,11 @@ GdkModifierType         gtk_keyval_trigger_get_modifiers        (GtkShortcutTrig
 GDK_AVAILABLE_IN_ALL
 guint                   gtk_keyval_trigger_get_keyval           (GtkShortcutTrigger *self);
 
+GDK_AVAILABLE_IN_ALL
+GtkShortcutTrigger *    gtk_mnemonic_trigger_new                (guint               keyval);
+GDK_AVAILABLE_IN_ALL
+guint                   gtk_mnemonic_trigger_get_keyval         (GtkShortcutTrigger *self);
+
 GDK_AVAILABLE_IN_ALL
 GtkShortcutTrigger *    gtk_alternative_trigger_new             (GtkShortcutTrigger *one,
                                                                  GtkShortcutTrigger *two);