[gimp/wip/Jehan/issue-498-quick-brush-edit: 521/523] app: store keys as keyval/modifiers rather than string.




commit de66fd301bc910c0430d8386a51afb945fce5051
Author: Jehan <jehan girinstud io>
Date:   Thu Aug 11 13:34:42 2022 +0200

    app: store keys as keyval/modifiers rather than string.
    
    There is really no need to make back and forth between a string and
    int/enum representations, and it actually cause problems at times.
    
    It's also a problem for the button representation where a modifier will
    be represented as a key.

 app/widgets/gimpshortcutbutton.c | 190 ++++++++++++++++++++++++++++-----------
 app/widgets/gimpshortcutbutton.h |  12 ++-
 2 files changed, 149 insertions(+), 53 deletions(-)
---
diff --git a/app/widgets/gimpshortcutbutton.c b/app/widgets/gimpshortcutbutton.c
index c03cc77b54..2e5ce8c18d 100644
--- a/app/widgets/gimpshortcutbutton.c
+++ b/app/widgets/gimpshortcutbutton.c
@@ -33,6 +33,11 @@
 #include "gimp-intl.h"
 
 
+enum
+{
+  ACCELERATOR_CHANGED,
+  LAST_SIGNAL
+};
 enum
 {
   PROP_0,
@@ -41,7 +46,8 @@ enum
 
 struct _GimpShortcutButtonPrivate
 {
-  gchar           *accelerator;
+  guint            keyval;
+  GdkModifierType  modifiers;
 
   GtkWidget       *stack;
 
@@ -54,36 +60,39 @@ struct _GimpShortcutButtonPrivate
 };
 
 
-static void     gimp_shortcut_button_constructed     (GObject            *object);
-static void     gimp_shortcut_button_finalize        (GObject            *object);
-static void     gimp_shortcut_button_set_property    (GObject            *object,
-                                                      guint               property_id,
-                                                      const GValue       *value,
-                                                      GParamSpec         *pspec);
-static void     gimp_shortcut_button_get_property    (GObject            *object,
-                                                      guint               property_id,
-                                                      GValue             *value,
-                                                      GParamSpec         *pspec);
+static void     gimp_shortcut_button_constructed         (GObject            *object);
+static void     gimp_shortcut_button_finalize            (GObject            *object);
+static void     gimp_shortcut_button_set_property        (GObject            *object,
+                                                          guint               property_id,
+                                                          const GValue       *value,
+                                                          GParamSpec         *pspec);
+static void     gimp_shortcut_button_get_property        (GObject            *object,
+                                                          guint               property_id,
+                                                          GValue             *value,
+                                                          GParamSpec         *pspec);
 
-static gboolean gimp_shortcut_button_key_press_event (GtkWidget   *button,
-                                                      GdkEventKey *event,
-                                                      gpointer     user_data);
-static gboolean gimp_shortcut_button_focus_out_event (GimpShortcutButton* button,
-                                                      GdkEventFocus       event,
-                                                      gpointer            user_data);
-static void     gimp_shortcut_button_toggled         (GimpShortcutButton* button,
-                                                      gpointer            user_data);
+static gboolean gimp_shortcut_button_key_press_event     (GtkWidget          *button,
+                                                          GdkEventKey        *event,
+                                                          gpointer            user_data);
+static gboolean gimp_shortcut_button_focus_out_event     (GimpShortcutButton *button,
+                                                          GdkEventFocus       event,
+                                                          gpointer            user_data);
+static void     gimp_shortcut_button_toggled             (GimpShortcutButton *button,
+                                                          gpointer            user_data);
 
-static void     gimp_shortcut_button_update_label    (GimpShortcutButton *button);
+static void     gimp_shortcut_button_update_label        (GimpShortcutButton *button);
 
-static gboolean gimp_shortcut_button_timeout         (GimpShortcutButton *button);
+static gboolean gimp_shortcut_button_timeout             (GimpShortcutButton *button);
 
+static void     gimp_shortcut_button_keyval_to_modifiers (guint               keyval,
+                                                          GdkModifierType    *modifiers);
 
-G_DEFINE_TYPE_WITH_PRIVATE (GimpShortcutButton, gimp_shortcut_button,
-                            GTK_TYPE_TOGGLE_BUTTON)
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpShortcutButton, gimp_shortcut_button, GTK_TYPE_TOGGLE_BUTTON)
 
 #define parent_class gimp_shortcut_button_parent_class
 
+static guint signals[LAST_SIGNAL] = { 0 };
 
 static void
 gimp_shortcut_button_class_init (GimpShortcutButtonClass *klass)
@@ -100,6 +109,16 @@ gimp_shortcut_button_class_init (GimpShortcutButtonClass *klass)
                                                         NULL, NULL, NULL,
                                                         GIMP_PARAM_READWRITE |
                                                         G_PARAM_EXPLICIT_NOTIFY));
+
+  signals[ACCELERATOR_CHANGED] = g_signal_new ("accelerator-changed",
+                                               G_TYPE_FROM_CLASS (klass),
+                                               G_SIGNAL_RUN_FIRST,
+                                               G_STRUCT_OFFSET (GimpShortcutButtonClass, 
accelerator_changed),
+                                               NULL, NULL, NULL,
+                                               G_TYPE_NONE, 1,
+                                               G_TYPE_STRING);
+
+  klass->accelerator_changed = NULL;
 }
 
 static void
@@ -151,7 +170,6 @@ gimp_shortcut_button_finalize (GObject *object)
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 
-  g_free (button->priv->accelerator);
   if (button->priv->timer != 0)
     {
       g_source_remove (button->priv->timer);
@@ -170,7 +188,7 @@ gimp_shortcut_button_set_property (GObject      *object,
   switch (property_id)
     {
     case PROP_ACCELERATOR:
-      gimp_shortcut_button_set_accelerator (button, g_value_get_string (value));
+      gimp_shortcut_button_set_accelerator (button, g_value_get_string (value), 0, 0);
       break;
 
    default:
@@ -190,7 +208,12 @@ gimp_shortcut_button_get_property (GObject    *object,
   switch (property_id)
     {
     case PROP_ACCELERATOR:
-      g_value_set_string (value, button->priv->accelerator);
+        {
+          gchar *name = gtk_accelerator_name (button->priv->keyval, button->priv->modifiers);
+
+          g_value_set_string (value, gtk_accelerator_name (button->priv->keyval, button->priv->modifiers));
+          g_free (name);
+        }
       break;
 
    default:
@@ -213,33 +236,71 @@ gimp_shortcut_button_new (const gchar *accelerator)
   return GTK_WIDGET (button);
 }
 
-const gchar *
+gchar *
 gimp_shortcut_button_get_accelerator (GimpShortcutButton *button)
 {
   g_return_val_if_fail (GIMP_IS_SHORTCUT_BUTTON (button), NULL);
 
-  return button->priv->accelerator;
+  return gtk_accelerator_name (button->priv->keyval, button->priv->modifiers);
+}
+
+void
+gimp_shortcut_button_get_keys (GimpShortcutButton  *button,
+                               guint               *keyval,
+                               GdkModifierType     *modifiers)
+{
+  g_return_if_fail (GIMP_IS_SHORTCUT_BUTTON (button));
+
+  if (keyval)
+    *keyval = button->priv->keyval;
+  if (modifiers)
+    *modifiers = button->priv->modifiers;
 }
 
 void
 gimp_shortcut_button_set_accelerator (GimpShortcutButton *button,
-                                      const gchar        *accelerator)
+                                      const gchar        *accelerator,
+                                      guint               keyval,
+                                      GdkModifierType     modifiers)
 {
   g_return_if_fail (GIMP_IS_SHORTCUT_BUTTON (button));
 
-  if (g_strcmp0 (accelerator, button->priv->accelerator) != 0)
+  if (accelerator)
+    gtk_accelerator_parse (accelerator, &keyval, &modifiers);
+
+  if (button->priv->modifier_only_accepted && keyval != 0)
+    {
+      if (button->priv->single_modifier)
+        modifiers = 0;
+      gimp_shortcut_button_keyval_to_modifiers (keyval, &modifiers);
+      keyval = 0;
+    }
+
+  if (keyval != button->priv->keyval || modifiers != button->priv->modifiers)
     {
       GtkWidget *label;
+      gchar     *previous_accel;
+      gchar     *accel;
+
+      previous_accel = gtk_accelerator_name (button->priv->keyval, button->priv->modifiers);
+      button->priv->keyval = keyval;
+      button->priv->modifiers = modifiers;
 
       label = gtk_stack_get_child_by_name (GTK_STACK (button->priv->stack),
                                            "shortcut-label");
 
-      g_free (button->priv->accelerator);
-      button->priv->accelerator = accelerator ? g_strdup (accelerator) : NULL;
-
-      gtk_shortcut_label_set_accelerator (GTK_SHORTCUT_LABEL (label), accelerator);
+      accel = gtk_accelerator_name (keyval, modifiers);
+      gtk_shortcut_label_set_accelerator (GTK_SHORTCUT_LABEL (label), accel);
+      g_free (accel);
 
       g_object_notify (G_OBJECT (button), "accelerator");
+
+      g_signal_emit (button, signals[ACCELERATOR_CHANGED], 0,
+                     previous_accel);
+      g_free (previous_accel);
+
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), keyval != 0 || modifiers == 0);
+      gimp_shortcut_button_toggled (GIMP_SHORTCUT_BUTTON (button), NULL);
     }
 }
 
@@ -293,12 +354,8 @@ gimp_shortcut_button_key_press_event (GtkWidget   *widget,
             {
               if (event->is_modifier)
                 {
-                  gchar *accelerator;
-
-                  accelerator = gtk_accelerator_name (event->keyval, 0);
-                  gimp_shortcut_button_set_accelerator (button, accelerator);
+                  gimp_shortcut_button_set_accelerator (button, NULL, event->keyval, 0);
                   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
-                  g_free (accelerator);
                 }
             }
           else
@@ -315,12 +372,8 @@ gimp_shortcut_button_key_press_event (GtkWidget   *widget,
         }
       else if (! event->is_modifier)
         {
-          gchar *accelerator;
-
-          accelerator = gtk_accelerator_name (event->keyval, accel_mods);
-          gimp_shortcut_button_set_accelerator (button, accelerator);
+          gimp_shortcut_button_set_accelerator (button, NULL, event->keyval, event->state);
           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
-          g_free (accelerator);
         }
       return TRUE;
     }
@@ -355,7 +408,7 @@ gimp_shortcut_button_toggled (GimpShortcutButton* button,
   gimp_shortcut_button_update_label (button);
 
   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ||
-      button->priv->accelerator == NULL)
+      (button->priv->keyval == 0 && button->priv->modifiers == 0))
     gtk_stack_set_visible_child_name (GTK_STACK (button->priv->stack), "label");
   else
     gtk_stack_set_visible_child_name (GTK_STACK (button->priv->stack), "shortcut-label");
@@ -393,12 +446,9 @@ gimp_shortcut_button_update_label (GimpShortcutButton *button)
 static gboolean
 gimp_shortcut_button_timeout (GimpShortcutButton *button)
 {
-  gchar *accelerator;
-
-  accelerator = gtk_accelerator_name (button->priv->last_keyval,
-                                      button->priv->last_modifiers);
-  gimp_shortcut_button_set_accelerator (button, accelerator);
-  g_free (accelerator);
+  gimp_shortcut_button_set_accelerator (button, NULL,
+                                        button->priv->last_keyval,
+                                        button->priv->last_modifiers);
 
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
 
@@ -406,3 +456,41 @@ gimp_shortcut_button_timeout (GimpShortcutButton *button)
 
   return G_SOURCE_REMOVE;
 }
+
+static void
+gimp_shortcut_button_keyval_to_modifiers (guint            keyval,
+                                          GdkModifierType *modifiers)
+{
+  /* XXX I believe that more keysyms are considered modifiers, but let's
+   * start with this. This basic list is basically taken from GDK code
+   * in gdk/quartz/gdkevents-quartz.c file.
+   */
+  GdkModifierType mask = 0;
+
+  switch (keyval)
+    {
+    case GDK_KEY_Meta_R:
+    case GDK_KEY_Meta_L:
+      mask = GDK_MOD2_MASK;
+      break;
+    case GDK_KEY_Shift_R:
+    case GDK_KEY_Shift_L:
+      mask = GDK_SHIFT_MASK;
+      break;
+    case GDK_KEY_Caps_Lock:
+      mask = GDK_LOCK_MASK;
+      break;
+    case GDK_KEY_Alt_R:
+    case GDK_KEY_Alt_L:
+      mask = GDK_MOD1_MASK;
+      break;
+    case GDK_KEY_Control_R:
+    case GDK_KEY_Control_L:
+      mask = GDK_CONTROL_MASK;
+      break;
+    default:
+      mask = 0;
+    }
+
+  *modifiers |= mask;
+}
diff --git a/app/widgets/gimpshortcutbutton.h b/app/widgets/gimpshortcutbutton.h
index 448ac52765..bcc6bddd7d 100644
--- a/app/widgets/gimpshortcutbutton.h
+++ b/app/widgets/gimpshortcutbutton.h
@@ -43,6 +43,9 @@ struct _GimpShortcutButton
 struct _GimpShortcutButtonClass
 {
   GtkToggleButtonClass       parent_class;
+
+  void                    (* accelerator_changed)    (GimpShortcutButton *button,
+                                                      const gchar        *previous_accelerator);
 };
 
 
@@ -50,9 +53,14 @@ GType          gimp_shortcut_button_get_type         (void) G_GNUC_CONST;
 
 GtkWidget    * gimp_shortcut_button_new              (const gchar        *accelerator);
 
-const gchar  * gimp_shortcut_button_get_accelerator  (GimpShortcutButton  *button);
+gchar        * gimp_shortcut_button_get_accelerator  (GimpShortcutButton  *button);
+void           gimp_shortcut_button_get_keys         (GimpShortcutButton  *button,
+                                                      guint               *keyval,
+                                                      GdkModifierType     *modifiers);
 void           gimp_shortcut_button_set_accelerator  (GimpShortcutButton  *button,
-                                                      const gchar         *accelerator);
+                                                      const gchar         *accelerator,
+                                                      guint                keyval,
+                                                      GdkModifierType      modifiers);
 
 void           gimp_shortcut_button_accepts_modifier (GimpShortcutButton *button,
                                                       gboolean            only,


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