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.
This commit is contained in:
Jehan 2022-08-11 13:34:42 +02:00
parent 9d3ef444ea
commit 100bdeddd9
2 changed files with 149 additions and 53 deletions

View File

@ -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;
}

View File

@ -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,