X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkaccelgroup.c;h=b76e2268d1d6becbb37be18bae57d473906eec0c;hb=9d0febc9a64a5bfb0fcfc3a88de4757f6c1ff090;hp=7631ece85a0f9c55cc2d8f344962a3e959d5a55a;hpb=5ff8fe69715a7f0da56816246be7ffaa05bd5ce9;p=~andy%2Fgtk diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c index 7631ece85..b76e2268d 100644 --- a/gtk/gtkaccelgroup.c +++ b/gtk/gtkaccelgroup.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -31,11 +29,10 @@ #include "gtkaccelgroup.h" #include "gtkaccelgroupprivate.h" #include "gtkaccellabel.h" -#include "gtkaccelmap.h" +#include "gtkaccelmapprivate.h" #include "gtkintl.h" -#include "gtkmainprivate.h" #include "gtkmarshalers.h" - +#include "gtkprivate.h" /** * SECTION:gtkaccelgroup @@ -1152,42 +1149,72 @@ is_hyper (const gchar *string) (string[6] == '>')); } +static inline gboolean +is_primary (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'p' || string[1] == 'P') && + (string[2] == 'r' || string[2] == 'R') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'm' || string[4] == 'M') && + (string[5] == 'a' || string[5] == 'A') && + (string[6] == 'r' || string[6] == 'R') && + (string[7] == 'y' || string[7] == 'Y') && + (string[8] == '>')); +} + +static inline gboolean +is_keycode (const gchar *string) +{ + return (string[0] == '0' && + string[1] == 'x' && + g_ascii_isxdigit (string[2]) && + g_ascii_isxdigit (string[3])); +} + /** - * gtk_accelerator_parse: + * gtk_accelerator_parse_with_keycode: * @accelerator: string representing an accelerator * @accelerator_key: (out) (allow-none): return location for accelerator * keyval, or %NULL + * @accelerator_codes: (out) (allow-none): return location for accelerator + * keycodes, or %NULL * @accelerator_mods: (out) (allow-none): return location for accelerator * modifier mask, %NULL * - * Parses a string representing an accelerator. The - * format looks like "<Control>a" or "<Shift><Alt>F1" - * or "<Release>z" (the last one is for key release). + * Parses a string representing an accelerator, similarly to + * gtk_accelerator_parse() but handles keycodes as well. This is only + * useful for system-level components, applications should use + * gtk_accelerator_parse() instead. * - * The parser is fairly liberal and allows lower or upper case, - * and also abbreviations such as "<Ctl>" and "<Ctrl>". - * Key names are parsed using gdk_keyval_from_name(). For character - * keys the name is not the symbol, but the lowercase name, e.g. one - * would use "<Ctrl>minus" instead of "<Ctrl>-". + * If a keycode is present in the accelerator and no @accelerator_codes + * is given, the parse will fail. * - * If the parse fails, @accelerator_key and @accelerator_mods will - * be set to 0 (zero). + * If the parse fails, @accelerator_key, @accelerator_mods and + * @accelerator_codes will be set to 0 (zero). + * + * Since: 3.4 */ void -gtk_accelerator_parse (const gchar *accelerator, - guint *accelerator_key, - GdkModifierType *accelerator_mods) +gtk_accelerator_parse_with_keycode (const gchar *accelerator, + guint *accelerator_key, + guint **accelerator_codes, + GdkModifierType *accelerator_mods) { guint keyval; GdkModifierType mods; gint len; + gboolean error; if (accelerator_key) *accelerator_key = 0; if (accelerator_mods) *accelerator_mods = 0; + if (accelerator_codes) + *accelerator_codes = NULL; g_return_if_fail (accelerator != NULL); + error = FALSE; keyval = 0; mods = 0; len = strlen (accelerator); @@ -1201,6 +1228,12 @@ gtk_accelerator_parse (const gchar *accelerator, len -= 9; mods |= GDK_RELEASE_MASK; } + else if (len >= 9 && is_primary (accelerator)) + { + accelerator += 9; + len -= 9; + mods |= _gtk_get_primary_accel_mod (); + } else if (len >= 9 && is_control (accelerator)) { accelerator += 9; @@ -1282,18 +1315,180 @@ gtk_accelerator_parse (const gchar *accelerator, } else { - keyval = gdk_keyval_from_name (accelerator); + if (len >= 4 && is_keycode (accelerator)) + { + char keystring[5]; + gchar *endptr; + gint tmp_keycode; + + memcpy (keystring, accelerator, 4); + keystring [4] = '\000'; + + tmp_keycode = strtol (keystring, &endptr, 16); + + if (endptr == NULL || *endptr != '\000') + { + error = TRUE; + goto out; + } + else if (accelerator_codes != NULL) + { + /* 0x00 is an invalid keycode too. */ + if (tmp_keycode == 0) + { + error = TRUE; + goto out; + } + else + { + *accelerator_codes = g_new0 (guint, 2); + (*accelerator_codes)[0] = tmp_keycode; + } + } + else + { + /* There was a keycode in the string, but + * we cannot store it, so we have an error */ + error = TRUE; + goto out; + } + } + else + { + keyval = gdk_keyval_from_name (accelerator); + if (keyval == GDK_KEY_VoidSymbol) + { + error = TRUE; + goto out; + } + } + + if (keyval && accelerator_codes != NULL) + { + GdkKeymapKey *keys; + gint n_keys, i, j; + + if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), keyval, &keys, &n_keys)) + { + /* Not in keymap */ + error = TRUE; + goto out; + } + else + { + *accelerator_codes = g_new0 (guint, n_keys + 1); + + /* Prefer level-0 keys to modified keys */ + for (i = 0, j = 0; i < n_keys; ++i) + { + if (keys[i].level == 0) + (*accelerator_codes)[j++] = keys[i].keycode; + } + + /* No level-0 keys? Find in the whole keymap */ + if (j == 0) + { + for (i = 0, j = 0; i < n_keys; ++i) + (*accelerator_codes)[j++] = keys[i].keycode; + } + + if (j == 0) + { + g_free (*accelerator_codes); + *accelerator_codes = NULL; + /* Not in keymap */ + error = TRUE; + goto out; + } + g_free (keys); + } + } + accelerator += len; len -= len; } } +out: + if (error) + keyval = mods = 0; + if (accelerator_key) *accelerator_key = gdk_keyval_to_lower (keyval); if (accelerator_mods) *accelerator_mods = mods; } +/** + * gtk_accelerator_parse: + * @accelerator: string representing an accelerator + * @accelerator_key: (out) (allow-none): return location for accelerator + * keyval, or %NULL + * @accelerator_mods: (out) (allow-none): return location for accelerator + * modifier mask, %NULL + * + * Parses a string representing an accelerator. The + * format looks like "<Control>a" or "<Shift><Alt>F1" + * or "<Release>z" (the last one is for key release). + * + * The parser is fairly liberal and allows lower or upper case, + * and also abbreviations such as "<Ctl>" and "<Ctrl>". + * Key names are parsed using gdk_keyval_from_name(). For character + * keys the name is not the symbol, but the lowercase name, e.g. one + * would use "<Ctrl>minus" instead of "<Ctrl>-". + * + * If the parse fails, @accelerator_key and @accelerator_mods will + * be set to 0 (zero). + */ +void +gtk_accelerator_parse (const gchar *accelerator, + guint *accelerator_key, + GdkModifierType *accelerator_mods) +{ + gtk_accelerator_parse_with_keycode (accelerator, accelerator_key, NULL, accelerator_mods); +} + +/** + * gtk_accelerator_name_with_keycode: + * @display: (allow-none): a #GdkDisplay or %NULL to use the default display + * @accelerator_key: accelerator keyval + * @accelerator_mods: accelerator modifier mask + * + * Converts an accelerator keyval and modifier mask + * into a string parseable by gtk_accelerator_parse_full(), + * similarly to gtk_accelerator_name() but handling keycodes. + * This is only useful for system-level components, applications + * should use gtk_accelerator_parse() instead. + * + * Returns: a newly allocated accelerator name. + * + * Since: 3.4 + */ +gchar * +gtk_accelerator_name_with_keycode (GdkDisplay *display, + guint accelerator_key, + guint keycode, + GdkModifierType accelerator_mods) +{ + gchar *gtk_name; + + if (display == NULL) + display = gdk_display_manager_get_default_display (gdk_display_manager_get ()); + + gdk_keymap_add_virtual_modifiers (gdk_keymap_get_for_display (display), &accelerator_mods); + gtk_name = gtk_accelerator_name (accelerator_key, accelerator_mods); + + if (!accelerator_key) + { + gchar *name; + name = g_strdup_printf ("%s0x%02x", gtk_name, keycode); + g_free (gtk_name); + return name; + } + + return gtk_name; +} + /** * gtk_accelerator_name: * @accelerator_key: accelerator keyval @@ -1314,6 +1509,7 @@ gtk_accelerator_name (guint accelerator_key, GdkModifierType accelerator_mods) { static const gchar text_release[] = ""; + static const gchar text_primary[] = ""; static const gchar text_shift[] = ""; static const gchar text_control[] = ""; static const gchar text_mod1[] = ""; @@ -1324,6 +1520,7 @@ gtk_accelerator_name (guint accelerator_key, static const gchar text_meta[] = ""; static const gchar text_super[] = ""; static const gchar text_hyper[] = ""; + GdkModifierType saved_mods; guint l; gchar *keyval_name; gchar *accelerator; @@ -1334,9 +1531,15 @@ gtk_accelerator_name (guint accelerator_key, if (!keyval_name) keyval_name = ""; + saved_mods = accelerator_mods; l = 0; if (accelerator_mods & GDK_RELEASE_MASK) l += sizeof (text_release) - 1; + if (accelerator_mods & _gtk_get_primary_accel_mod ()) + { + l += sizeof (text_primary) - 1; + accelerator_mods &= ~_gtk_get_primary_accel_mod (); /* consume the default accel */ + } if (accelerator_mods & GDK_SHIFT_MASK) l += sizeof (text_shift) - 1; if (accelerator_mods & GDK_CONTROL_MASK) @@ -1361,6 +1564,7 @@ gtk_accelerator_name (guint accelerator_key, accelerator = g_new (gchar, l + 1); + accelerator_mods = saved_mods; l = 0; accelerator[l] = 0; if (accelerator_mods & GDK_RELEASE_MASK) @@ -1368,6 +1572,12 @@ gtk_accelerator_name (guint accelerator_key, strcpy (accelerator + l, text_release); l += sizeof (text_release) - 1; } + if (accelerator_mods & _gtk_get_primary_accel_mod ()) + { + strcpy (accelerator + l, text_primary); + l += sizeof (text_primary) - 1; + accelerator_mods &= ~_gtk_get_primary_accel_mod (); /* consume the default accel */ + } if (accelerator_mods & GDK_SHIFT_MASK) { strcpy (accelerator + l, text_shift); @@ -1423,6 +1633,49 @@ gtk_accelerator_name (guint accelerator_key, return accelerator; } +/** + * gtk_accelerator_get_label_with_keycode: + * @display: (allow-none): a #GdkDisplay or %NULL to use the default display + * @accelerator_key: accelerator keyval + * @accelerator_mods: accelerator modifier mask + * + * Converts an accelerator keyval and modifier mask + * into a (possibly translated) string that can be displayed to + * a user, similarly to gtk_accelerator_get_label(), but handling + * keycodes. + * + * This is only useful for system-level components, applications + * should use gtk_accelerator_parse() instead. + * + * Returns: a newly-allocated string representing the accelerator. + * + * Since: 3.4 + */ +gchar * +gtk_accelerator_get_label_with_keycode (GdkDisplay *display, + guint accelerator_key, + guint keycode, + GdkModifierType accelerator_mods) +{ + gchar *gtk_label; + + if (display == NULL) + display = gdk_display_manager_get_default_display (gdk_display_manager_get ()); + + gdk_keymap_add_virtual_modifiers (gdk_keymap_get_for_display (display), &accelerator_mods); + gtk_label = gtk_accelerator_get_label (accelerator_key, accelerator_mods); + + if (!accelerator_key) + { + gchar *label; + label = g_strdup_printf ("%s0x%02x", gtk_label, keycode); + g_free (gtk_label); + return label; + } + + return gtk_label; +} + /** * gtk_accelerator_get_label: * @accelerator_key: accelerator keyval