From 4a7a67339a3c8a7c523b32b36a7fc2ea5abfb8f8 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Tue, 27 Sep 2011 09:50:34 +0200 Subject: [PATCH] Bug 659602 - Provide an abstraction for the platform's use of modifier keys Add enum GdkModifierIntent which identifies use cases for modifier masks and GdkKeyMap::get_modifier_mask(). Add a default implementation which returns what is currently hardcoded all over GTK+, and an implementation in the quartz backend. Also add gtk_widget_get_modifier_mask() which simplifies things by doing widget->display->keymap->get_modifier_mask(). --- gdk/gdkkeys.c | 62 +++++++++++++++++++++++++++++++++++++ gdk/gdkkeys.h | 3 ++ gdk/gdkkeysprivate.h | 2 ++ gdk/gdktypes.h | 35 +++++++++++++++++++++ gdk/quartz/gdkkeys-quartz.c | 27 ++++++++++++++++ gtk/gtkwidget.c | 28 +++++++++++++++++ gtk/gtkwidget.h | 3 ++ 7 files changed, 160 insertions(+) diff --git a/gdk/gdkkeys.c b/gdk/gdkkeys.c index f52de39e04..d2b7b61f6e 100644 --- a/gdk/gdkkeys.c +++ b/gdk/gdkkeys.c @@ -108,6 +108,11 @@ enum { LAST_SIGNAL }; + +static GdkModifierType gdk_keymap_real_get_modifier_mask (GdkKeymap *keymap, + GdkModifierIntent intent); + + static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (GdkKeymap, gdk_keymap, G_TYPE_OBJECT) @@ -117,6 +122,8 @@ gdk_keymap_class_init (GdkKeymapClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + klass->get_modifier_mask = gdk_keymap_real_get_modifier_mask; + /** * GdkKeymap::direction-changed: * @keymap: the object on which the signal is emitted @@ -605,6 +612,61 @@ gdk_keymap_map_virtual_modifiers (GdkKeymap *keymap, return GDK_KEYMAP_GET_CLASS(keymap)->map_virtual_modifiers (keymap, state); } +static GdkModifierType +gdk_keymap_real_get_modifier_mask (GdkKeymap *keymap, + GdkModifierIntent intent) +{ + switch (intent) + { + case GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR: + return GDK_CONTROL_MASK; + + case GDK_MODIFIER_INTENT_CONTEXT_MENU: + return 0; + + case GDK_MODIFIER_INTENT_EXTEND_SELECTION: + return GDK_SHIFT_MASK; + + case GDK_MODIFIER_INTENT_MODIFY_SELECTION: + return GDK_CONTROL_MASK; + + case GDK_MODIFIER_INTENT_NO_TEXT_INPUT: + return GDK_MOD1_MASK | GDK_CONTROL_MASK; + + default: + g_return_val_if_reached (0); + } +} + +/** + * gdk_keymap_get_modifier_mask: + * @keymap: a #GdkKeymap + * @intent: the use case for the modifier mask + * + * Returns the modifier mask the @keymap's windowing system backend + * uses for a particular purpose. + * + * Note that this function always returns real hardware modifiers, not + * virtual ones (e.g. it will return #GDK_MOD1_MASK rather than + * #GDK_META_MASK if the backend maps MOD1 to META), so there are use + * cases where the return value of this function has to be transformed + * by gdk_keymap_add_virtual_modifiers() in order to contain the + * expected result. + * + * Returns: the modifier mask used for @intent. + * + * Since: 3.4 + **/ +GdkModifierType +gdk_keymap_get_modifier_mask (GdkKeymap *keymap, + GdkModifierIntent intent) +{ + g_return_val_if_fail (GDK_IS_KEYMAP (keymap), 0); + + return GDK_KEYMAP_GET_CLASS (keymap)->get_modifier_mask (keymap, intent); +} + + /** * gdk_keyval_name: * @keyval: a key value diff --git a/gdk/gdkkeys.h b/gdk/gdkkeys.h index 96e360f1ea..b085d246ca 100644 --- a/gdk/gdkkeys.h +++ b/gdk/gdkkeys.h @@ -114,6 +114,9 @@ void gdk_keymap_add_virtual_modifiers (GdkKeymap *keymap, GdkModifierType *state); gboolean gdk_keymap_map_virtual_modifiers (GdkKeymap *keymap, GdkModifierType *state); +GdkModifierType gdk_keymap_get_modifier_mask (GdkKeymap *keymap, + GdkModifierIntent intent); + /* Key values */ diff --git a/gdk/gdkkeysprivate.h b/gdk/gdkkeysprivate.h index c0f1f0eaa9..be1be41d03 100644 --- a/gdk/gdkkeysprivate.h +++ b/gdk/gdkkeysprivate.h @@ -61,6 +61,8 @@ struct _GdkKeymapClass GdkModifierType *state); gboolean (* map_virtual_modifiers) (GdkKeymap *keymap, GdkModifierType *state); + GdkModifierType (*get_modifier_mask) (GdkKeymap *keymap, + GdkModifierIntent intent); /* Signals */ diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h index 87ac3b2491..a0ea89368d 100644 --- a/gdk/gdktypes.h +++ b/gdk/gdktypes.h @@ -242,6 +242,41 @@ typedef enum GDK_MODIFIER_MASK = 0x5c001fff } GdkModifierType; +/** + * GdkModifierIntent: + * @GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR: the primary modifier used to invoke + * menu accelerators. + * @GDK_MODIFIER_INTENT_CONTEXT_MENU: the modifier used to invoke context menus. + * Note that mouse button 3 always triggers context menus. When this modifier + * is not 0, it additionally triggers context menus when used + * with mouse button 1. + * @GDK_MODIFIER_INTENT_EXTEND_SELECTION: the modifier used to extend selections + * using <modifier>-click or <modifier>-cursor-key + * @GDK_MODIFIER_INTENT_MODIFY_SELECTION: the modifier used to modify selections, + * which in most cases means toggling the clicked item into or out of the selection. + * @GDK_MODIFIER_INTENT_NO_TEXT_INPUT: when any of these modifiers is pressed, the + * key event cannot produce a symbol directly. This is meant to be used for + * input methods, and for use cases like typeahead search. + * + * This enum is used with gdk_keymap_get_modifier_mask() and + * gdk_get_modifier_mask() in order to determine what modifiers the + * currently used windowing system backend uses for particular + * purposes. For example, on X11/Windows, the Control key is used for + * invoking menu shortcuts (accelerators), whereas on Apple computers + * it's the Command key (which correspond to %GDK_CONTROL_MASK and + * %GDK_MOD2_MASK, respectively). + * + * Since: 3.4 + **/ +typedef enum +{ + GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR, + GDK_MODIFIER_INTENT_CONTEXT_MENU, + GDK_MODIFIER_INTENT_EXTEND_SELECTION, + GDK_MODIFIER_INTENT_MODIFY_SELECTION, + GDK_MODIFIER_INTENT_NO_TEXT_INPUT +} GdkModifierIntent; + typedef enum { GDK_OK = 0, diff --git a/gdk/quartz/gdkkeys-quartz.c b/gdk/quartz/gdkkeys-quartz.c index 9c925ae14c..2b9307f868 100644 --- a/gdk/quartz/gdkkeys-quartz.c +++ b/gdk/quartz/gdkkeys-quartz.c @@ -746,6 +746,32 @@ gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap *keymap, return TRUE; } +static GdkModifierType +gdk_quartz_keymap_get_modifier_mask (GdkKeymap *keymap, + GdkModifierIntent intent) +{ + switch (intent) + { + case GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR: + return GDK_MOD2_MASK; + + case GDK_MODIFIER_INTENT_CONTEXT_MENU: + return GDK_CONTROL_MASK; + + case GDK_MODIFIER_INTENT_EXTEND_SELECTION: + return GDK_SHIFT_MASK; + + case GDK_MODIFIER_INTENT_MODIFY_SELECTION: + return GDK_MOD2_MASK; + + case GDK_MODIFIER_INTENT_NO_TEXT_INPUT: + return GDK_MOD2_MASK | GDK_CONTROL_MASK; + + default: + g_return_val_if_reached (0); + } +} + /* What sort of key event is this? Returns one of * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored) */ @@ -835,4 +861,5 @@ gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass) keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state; keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers; keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers; + keymap_class->get_modifier_mask = gdk_quartz_keymap_get_modifier_mask; } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index f90e3b3099..3e9e1d5e76 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -14542,3 +14542,31 @@ gtk_widget_get_style_context (GtkWidget *widget) return widget->priv->context; } + +/** + * gtk_widget_get_modifier_mask: + * @widget: a #GtkWidget + * @intent: the use case for the modifier mask + * + * Returns the modifier mask the @widget's windowing system backend + * uses for a particular purpose. + * + * See gdk_keymap_get_modifier_mask(). + * + * Returns: the modifier mask used for @intent. + * + * Since: 3.4 + **/ +GdkModifierType +gtk_widget_get_modifier_mask (GtkWidget *widget, + GdkModifierIntent intent) +{ + GdkDisplay *display; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); + + display = gtk_widget_get_display (widget); + + return gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display), + intent); +} diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index ead01ed4d1..2da9ae3623 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -949,6 +949,9 @@ GtkStyleContext * gtk_widget_get_style_context (GtkWidget *widget); GtkWidgetPath * gtk_widget_get_path (GtkWidget *widget); +GdkModifierType gtk_widget_get_modifier_mask (GtkWidget *widget, + GdkModifierIntent intent); + G_END_DECLS