1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1998, 2001 Tim Janik
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26 #include "gtkaccelgroup.h"
27 #include "gtkaccelmap.h"
28 #include "gdk/gdkkeysyms.h"
29 #include "gtksignal.h"
36 /* --- prototypes --- */
37 static void gtk_accel_group_class_init (GtkAccelGroupClass *class);
38 static void gtk_accel_group_init (GtkAccelGroup *accel_group);
39 static void gtk_accel_group_finalize (GObject *object);
42 /* --- variables --- */
43 static GObjectClass *parent_class = NULL;
44 static guint signal_accel_activate = 0;
45 static guint signal_accel_changed = 0;
46 static guint quark_acceleratable_groups = 0;
47 static guint default_accel_mod_mask = (GDK_SHIFT_MASK |
52 /* --- functions --- */
54 * gtk_accel_map_change_entry
55 * @returns: the type ID for accelerator groups
58 gtk_accel_group_get_type (void)
60 static GType object_type = 0;
64 static const GTypeInfo object_info = {
65 sizeof (GtkAccelGroupClass),
67 (GBaseFinalizeFunc) NULL,
68 (GClassInitFunc) gtk_accel_group_class_init,
69 NULL, /* clas_finalize */
70 NULL, /* class_data */
71 sizeof (GtkAccelGroup),
73 (GInstanceInitFunc) gtk_accel_group_init,
76 object_type = g_type_register_static (G_TYPE_OBJECT,
85 accel_activate_accumulator (GSignalInvocationHint *ihint,
87 const GValue *handler_return,
90 gboolean continue_emission;
93 /* handler returns whether the accelerator was handled */
94 handler_val = g_value_get_boolean (handler_return);
96 /* record that as result for this emission */
97 g_value_set_boolean (return_accu, handler_val);
99 /* don't continue if accelerator was handled */
100 continue_emission = !handler_val;
102 return continue_emission;
106 gtk_accel_group_class_init (GtkAccelGroupClass *class)
108 GObjectClass *object_class = G_OBJECT_CLASS (class);
110 parent_class = g_type_class_peek_parent (class);
112 quark_acceleratable_groups = g_quark_from_static_string ("gtk-acceleratable-accel-groups");
114 object_class->finalize = gtk_accel_group_finalize;
116 class->accel_changed = NULL;
117 signal_accel_activate = g_signal_new ("accel_activate",
118 G_OBJECT_CLASS_TYPE (class),
121 accel_activate_accumulator, NULL,
122 gtk_marshal_BOOLEAN__OBJECT_UINT_UINT,
123 G_TYPE_BOOLEAN, 3, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_UINT);
124 signal_accel_changed = g_signal_new ("accel_changed",
125 G_OBJECT_CLASS_TYPE (class),
126 G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
127 G_STRUCT_OFFSET (GtkAccelGroupClass, accel_changed),
129 gtk_marshal_VOID__UINT_UINT_BOXED,
130 G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_CLOSURE);
134 gtk_accel_group_finalize (GObject *object)
136 GtkAccelGroup *accel_group = GTK_ACCEL_GROUP (object);
138 g_free (accel_group->priv_accels);
140 G_OBJECT_CLASS (parent_class)->finalize (object);
144 gtk_accel_group_init (GtkAccelGroup *accel_group)
146 accel_group->lock_count = 0;
147 accel_group->modifier_mask = gtk_accelerator_get_default_mod_mask ();
148 accel_group->acceleratables = NULL;
149 accel_group->n_accels = 0;
150 accel_group->priv_accels = NULL;
154 * gtk_accel_group_new
155 * @returns: a new #GtkAccelGroup object
157 * Creates a new #GtkAccelGroup.
160 gtk_accel_group_new (void)
162 return g_object_new (GTK_TYPE_ACCEL_GROUP, NULL);
166 accel_group_weak_ref_detach (GSList *free_list,
167 GObject *stale_object)
171 for (slist = free_list; slist; slist = slist->next)
173 GtkAccelGroup *accel_group;
175 accel_group = slist->data;
176 accel_group->acceleratables = g_slist_remove (accel_group->acceleratables, stale_object);
177 g_object_unref (accel_group);
179 g_slist_free (free_list);
183 _gtk_accel_group_attach (GtkAccelGroup *accel_group,
188 g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
189 g_return_if_fail (G_IS_OBJECT (object));
190 g_return_if_fail (g_slist_find (accel_group->acceleratables, object) == NULL);
192 g_object_ref (accel_group);
193 accel_group->acceleratables = g_slist_prepend (accel_group->acceleratables, object);
194 slist = g_object_get_qdata (object, quark_acceleratable_groups);
196 g_object_weak_unref (object,
197 (GWeakNotify) accel_group_weak_ref_detach,
199 slist = g_slist_prepend (slist, accel_group);
200 g_object_set_qdata (object, quark_acceleratable_groups, slist);
201 g_object_weak_ref (object,
202 (GWeakNotify) accel_group_weak_ref_detach,
207 _gtk_accel_group_detach (GtkAccelGroup *accel_group,
212 g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
213 g_return_if_fail (G_IS_OBJECT (object));
214 g_return_if_fail (g_slist_find (accel_group->acceleratables, object) != NULL);
216 accel_group->acceleratables = g_slist_remove (accel_group->acceleratables, object);
217 slist = g_object_get_qdata (object, quark_acceleratable_groups);
218 g_object_weak_unref (object,
219 (GWeakNotify) accel_group_weak_ref_detach,
221 slist = g_slist_remove (slist, accel_group);
222 g_object_set_qdata (object, quark_acceleratable_groups, slist);
224 g_object_weak_ref (object,
225 (GWeakNotify) accel_group_weak_ref_detach,
227 g_object_unref (accel_group);
231 gtk_accel_groups_from_acceleratable (GObject *object)
233 g_return_val_if_fail (G_IS_OBJECT (object), NULL);
235 return g_object_get_qdata (object, quark_acceleratable_groups);
239 gtk_accel_group_find (GtkAccelGroup *accel_group,
240 gboolean (*find_func) (GtkAccelKey *key,
245 GtkAccelKey *key = NULL;
248 g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL);
249 g_return_val_if_fail (find_func != NULL, NULL);
251 g_object_ref (accel_group);
252 for (i = 0; i < accel_group->n_accels; i++)
253 if (find_func (&accel_group->priv_accels[i].key,
254 accel_group->priv_accels[i].closure,
257 key = &accel_group->priv_accels[i].key;
260 g_object_unref (accel_group);
266 * gtk_accel_group_lock
267 * @accel_group: a #GtkAccelGroup
269 * Locking an acelerator group prevents the accelerators contained
270 * within it to be changed during runtime. Refer to
271 * gtk_accel_map_change_entry() about runtime accelerator changes.
273 * If called more than once, @accel_group remains locked until
274 * gtk_accel_group_unlock() has been called an equivalent number
278 gtk_accel_group_lock (GtkAccelGroup *accel_group)
280 g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
282 accel_group->lock_count += 1;
286 * gtk_accel_group_unlock
287 * @accel_group: a #GtkAccelGroup
289 * This function undoes the last call to gtk_accel_group_lock()
290 * on this @accel_group.
293 gtk_accel_group_unlock (GtkAccelGroup *accel_group)
295 g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
296 g_return_if_fail (accel_group->lock_count > 0);
298 accel_group->lock_count -= 1;
302 accel_tag_func (gpointer data,
305 /* GtkAccelGroup *accel_group = data; */
309 bsearch_compare_accels (const void *d1,
312 const GtkAccelGroupEntry *entry1 = d1;
313 const GtkAccelGroupEntry *entry2 = d2;
315 if (entry1->key.accel_key == entry2->key.accel_key)
316 return entry1->key.accel_mods < entry2->key.accel_mods ? -1 : entry1->key.accel_mods > entry2->key.accel_mods;
318 return entry1->key.accel_key < entry2->key.accel_key ? -1 : 1;
322 quick_accel_add (GtkAccelGroup *accel_group,
324 GdkModifierType accel_mods,
325 GtkAccelFlags accel_flags,
329 guint pos, i = accel_group->n_accels++;
330 GtkAccelGroupEntry key;
332 key.key.accel_key = accel_key;
333 key.key.accel_mods = accel_mods;
334 for (pos = 0; pos < i; pos++)
335 if (bsearch_compare_accels (&key, accel_group->priv_accels + pos) < 0)
337 accel_group->priv_accels = g_renew (GtkAccelGroupEntry, accel_group->priv_accels, accel_group->n_accels);
338 g_memmove (accel_group->priv_accels + pos + 1, accel_group->priv_accels + pos,
339 (i - pos) * sizeof (accel_group->priv_accels[0]));
340 accel_group->priv_accels[pos].key.accel_key = accel_key;
341 accel_group->priv_accels[pos].key.accel_mods = accel_mods;
342 accel_group->priv_accels[pos].key.accel_flags = accel_flags;
343 accel_group->priv_accels[pos].closure = g_closure_ref (closure);
344 accel_group->priv_accels[pos].accel_path_quark = path_quark;
345 g_closure_sink (closure);
347 /* tag closure for backwards lookup */
348 g_closure_add_invalidate_notifier (closure, accel_group, accel_tag_func);
351 static GtkAccelGroupEntry*
352 quick_accel_find (GtkAccelGroup *accel_group,
354 GdkModifierType accel_mods,
357 GtkAccelGroupEntry *entry;
358 GtkAccelGroupEntry key;
360 if (!accel_group->n_accels)
363 key.key.accel_key = accel_key;
364 key.key.accel_mods = accel_mods;
365 entry = bsearch (&key, accel_group->priv_accels, accel_group->n_accels,
366 sizeof (accel_group->priv_accels[0]), bsearch_compare_accels);
371 /* step back to the first member */
372 for (; entry > accel_group->priv_accels; entry--)
373 if (entry[-1].key.accel_key != accel_key ||
374 entry[-1].key.accel_mods != accel_mods)
376 /* count equal members */
377 for (*count_p = 0; entry + *count_p < accel_group->priv_accels + accel_group->n_accels; (*count_p)++)
378 if (entry[*count_p].key.accel_key != accel_key ||
379 entry[*count_p].key.accel_mods != accel_mods)
385 quick_accel_remove (GtkAccelGroup *accel_group,
387 GdkModifierType accel_mods)
390 GtkAccelGroupEntry *entry = quick_accel_find (accel_group, accel_key, accel_mods, &n);
391 guint pos = entry - accel_group->priv_accels;
392 GSList *clist = NULL;
396 for (i = 0; i < n; i++)
398 g_closure_remove_invalidate_notifier (entry[i].closure, accel_group, accel_tag_func);
399 clist = g_slist_prepend (clist, entry[i].closure);
402 accel_group->n_accels -= n;
403 g_memmove (entry, entry + n,
404 (accel_group->n_accels - pos) * sizeof (accel_group->priv_accels[0]));
410 * gtk_accel_group_connect
411 * @accel_group: the ccelerator group to install an accelerator in
412 * @accel_key: key value of the accelerator
413 * @accel_mods: modifier combination of the accelerator
414 * @accel_flags: a flag mask to configure this accelerator
415 * @closure: closure to be executed upon accelerator activation
416 * @accel_path_quark: accelerator path quark from GtkAccelMapNotify
418 * Install an accelerator in this group. When @accel_group is being activated
419 * in response to a call to gtk_accel_groups_activate(), @closure will be
420 * invoked if the @accel_key and @accel_mods from gtk_accel_groups_activate()
421 * match those of this connection.
422 * The signature used for the @closure is that of #GtkAccelGroupActivate.
423 * If this connection is made in response to an accelerator path change (see
424 * gtk_accel_map_change_entry()) from a #GtkAccelMapNotify notifier,
425 * @accel_path_quark must be passed on from the notifier into this function,
426 * it should be 0 otherwise.
429 gtk_accel_group_connect (GtkAccelGroup *accel_group,
431 GdkModifierType accel_mods,
432 GtkAccelFlags accel_flags,
434 GQuark accel_path_quark)
439 g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
440 g_return_if_fail (closure != NULL);
441 g_return_if_fail (accel_key > 0);
443 accel_name = gtk_accelerator_name (accel_key, accel_mods);
444 accel_quark = g_quark_from_string (accel_name);
447 quick_accel_add (accel_group, accel_key, accel_mods, accel_flags, closure, accel_path_quark);
450 g_signal_connect_closure_by_id (accel_group, signal_accel_activate, accel_quark, closure, FALSE);
453 g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, closure);
457 accel_group_disconnect_closure (GtkAccelGroup *accel_group,
459 GdkModifierType accel_mods,
464 GSList *clist , *slist;
465 gboolean removed_some = FALSE;
467 accel_name = gtk_accelerator_name (accel_key, accel_mods);
468 accel_quark = g_quark_from_string (accel_name);
471 clist = quick_accel_remove (accel_group, accel_key, accel_mods);
475 g_object_ref (accel_group);
477 for (slist = clist; slist; slist = slist->next)
478 if (!closure || slist->data == (gpointer) closure)
480 g_signal_handlers_disconnect_matched (accel_group, G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_ID,
481 signal_accel_activate, 0,
482 slist->data, NULL, NULL);
484 g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, slist->data);
486 /* remove quick_accel_add() ref_count */
487 g_closure_unref (slist->data);
491 g_slist_free (clist);
493 g_object_unref (accel_group);
499 * gtk_accel_group_disconnect
500 * @accel_group: the ccelerator group to install an accelerator in
501 * @accel_key: key value of the accelerator
502 * @accel_mods: modifier combination of the accelerator
503 * @returns: %TRUE if there was an accelerator which could be removed, %FALSE otherwise
505 * Remove an accelerator previously installed through
506 * gtk_accel_group_connect().
509 gtk_accel_group_disconnect (GtkAccelGroup *accel_group,
511 GdkModifierType accel_mods)
513 g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE);
515 return accel_group_disconnect_closure (accel_group, accel_key, accel_mods, NULL);
519 gtk_accel_group_query (GtkAccelGroup *accel_group,
521 GdkModifierType accel_mods,
524 GtkAccelGroupEntry *entries;
527 g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL);
529 entries = quick_accel_find (accel_group, accel_key, accel_mods, &n);
532 *n_entries = entries ? n : 0;
538 find_accel_closure (GtkAccelKey *key,
542 return data == (gpointer) closure;
546 gtk_accel_groups_disconnect_closure (GClosure *closure)
548 GtkAccelGroup *group;
550 g_return_val_if_fail (closure != NULL, FALSE);
552 group = gtk_accel_group_from_accel_closure (closure);
555 GtkAccelKey *key = gtk_accel_group_find (group, find_accel_closure, closure);
557 /* sigh, not finding the key can unexpectedly happen if someone disposes
558 * accel groups. that's highly recommended to _not_ do though.
562 accel_group_disconnect_closure (group, key->accel_key, key->accel_mods, closure);
570 gtk_accel_group_from_accel_closure (GClosure *closure)
574 g_return_val_if_fail (closure != NULL, NULL);
576 /* a few remarks on wat we do here. in general, we need a way to back-lookup
577 * accel_groups from closures that are being used in accel groups. this could
578 * be done e.g via a hashtable. it is however cheaper (memory wise) to just
579 * store a NOP notifier on the closure itself that contains the accel group
580 * as data which, besides needing to peek a bit at closure internals, works
583 for (i = 0; i < G_CLOSURE_N_NOTIFIERS (closure); i++)
584 if (closure->notifiers[i].notify == accel_tag_func)
585 return closure->notifiers[i].data;
591 _gtk_accel_group_activate (GtkAccelGroup *accel_group,
593 GObject *acceleratable,
595 GdkModifierType accel_mods)
597 gboolean was_handled;
599 g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE);
602 g_signal_emit (accel_group, signal_accel_activate, accel_quark,
603 acceleratable, accel_key, accel_mods, &was_handled);
609 * gtk_accel_groups_activate:
610 * @acceleratable: usually a #GtkWindow
611 * @accel_key: accelerator keyval from a key event
612 * @accel_mods: keyboard state mask from a key event
613 * @returns: %TRUE if the accelerator was handled, %FALSE otherwise
615 * Finds the first accelerator in any #GtkAccelGroup attached
616 * to @acceleratable that matches @accel_key and @accel_mods, and
617 * activates that accelerator.
618 * If an accelerator was activated and handled this keypress, %TRUE
622 gtk_accel_groups_activate (GObject *acceleratable,
624 GdkModifierType accel_mods)
626 g_return_val_if_fail (G_IS_OBJECT (acceleratable), FALSE);
628 if (gtk_accelerator_valid (accel_key, accel_mods))
634 accel_name = gtk_accelerator_name (accel_key, accel_mods);
635 accel_quark = g_quark_from_string (accel_name);
638 for (slist = gtk_accel_groups_from_acceleratable (acceleratable); slist; slist = slist->next)
639 if (_gtk_accel_group_activate (slist->data, accel_quark, acceleratable, accel_key, accel_mods))
647 * gtk_accelerator_valid
648 * @keyval: a GDK keyval
649 * @modifiers: modifier mask
650 * @returns: %TRUE if the accelerator is valid
652 * Determines whether a given keyval and modifier mask constitute
653 * a valid keyboard accelerator. For example, the GDK_a keyval
654 * plus GDK_CONTROL_MASK is valid - this is a "Ctrl+a" accelerator.
655 * But by default (see gtk_accelerator_set_default_mod_mask()) you
656 * cannot use the NumLock key as an accelerator modifier.
659 gtk_accelerator_valid (guint keyval,
660 GdkModifierType modifiers)
662 static const guint invalid_accelerator_vals[] = {
663 GDK_BackSpace, GDK_Delete, GDK_KP_Delete,
664 GDK_Shift_L, GDK_Shift_R, GDK_Shift_Lock, GDK_Caps_Lock, GDK_ISO_Lock,
665 GDK_Control_L, GDK_Control_R, GDK_Meta_L, GDK_Meta_R,
666 GDK_Alt_L, GDK_Alt_R, GDK_Super_L, GDK_Super_R, GDK_Hyper_L, GDK_Hyper_R,
667 GDK_Mode_switch, GDK_Num_Lock, GDK_Multi_key,
668 GDK_Scroll_Lock, GDK_Sys_Req,
669 GDK_Up, GDK_Down, GDK_Left, GDK_Right, GDK_Tab, GDK_ISO_Left_Tab,
670 GDK_KP_Up, GDK_KP_Down, GDK_KP_Left, GDK_KP_Right, GDK_KP_Tab,
671 GDK_First_Virtual_Screen, GDK_Prev_Virtual_Screen,
672 GDK_Next_Virtual_Screen, GDK_Last_Virtual_Screen,
673 GDK_Terminate_Server, GDK_AudibleBell_Enable,
678 modifiers &= GDK_MODIFIER_MASK;
681 return keyval >= 0x20;
683 ac_val = invalid_accelerator_vals;
686 if (keyval == *ac_val++)
693 static inline gboolean
694 is_alt (const gchar *string)
696 return ((string[0] == '<') &&
697 (string[1] == 'a' || string[1] == 'A') &&
698 (string[2] == 'l' || string[2] == 'L') &&
699 (string[3] == 't' || string[3] == 'T') &&
703 static inline gboolean
704 is_ctl (const gchar *string)
706 return ((string[0] == '<') &&
707 (string[1] == 'c' || string[1] == 'C') &&
708 (string[2] == 't' || string[2] == 'T') &&
709 (string[3] == 'l' || string[3] == 'L') &&
713 static inline gboolean
714 is_modx (const gchar *string)
716 return ((string[0] == '<') &&
717 (string[1] == 'm' || string[1] == 'M') &&
718 (string[2] == 'o' || string[2] == 'O') &&
719 (string[3] == 'd' || string[3] == 'D') &&
720 (string[4] >= '1' && string[4] <= '5') &&
724 static inline gboolean
725 is_ctrl (const gchar *string)
727 return ((string[0] == '<') &&
728 (string[1] == 'c' || string[1] == 'C') &&
729 (string[2] == 't' || string[2] == 'T') &&
730 (string[3] == 'r' || string[3] == 'R') &&
731 (string[4] == 'l' || string[4] == 'L') &&
735 static inline gboolean
736 is_shft (const gchar *string)
738 return ((string[0] == '<') &&
739 (string[1] == 's' || string[1] == 'S') &&
740 (string[2] == 'h' || string[2] == 'H') &&
741 (string[3] == 'f' || string[3] == 'F') &&
742 (string[4] == 't' || string[4] == 'T') &&
746 static inline gboolean
747 is_shift (const gchar *string)
749 return ((string[0] == '<') &&
750 (string[1] == 's' || string[1] == 'S') &&
751 (string[2] == 'h' || string[2] == 'H') &&
752 (string[3] == 'i' || string[3] == 'I') &&
753 (string[4] == 'f' || string[4] == 'F') &&
754 (string[5] == 't' || string[5] == 'T') &&
758 static inline gboolean
759 is_control (const gchar *string)
761 return ((string[0] == '<') &&
762 (string[1] == 'c' || string[1] == 'C') &&
763 (string[2] == 'o' || string[2] == 'O') &&
764 (string[3] == 'n' || string[3] == 'N') &&
765 (string[4] == 't' || string[4] == 'T') &&
766 (string[5] == 'r' || string[5] == 'R') &&
767 (string[6] == 'o' || string[6] == 'O') &&
768 (string[7] == 'l' || string[7] == 'L') &&
772 static inline gboolean
773 is_release (const gchar *string)
775 return ((string[0] == '<') &&
776 (string[1] == 'r' || string[1] == 'R') &&
777 (string[2] == 'e' || string[2] == 'E') &&
778 (string[3] == 'l' || string[3] == 'L') &&
779 (string[4] == 'e' || string[4] == 'E') &&
780 (string[5] == 'a' || string[5] == 'A') &&
781 (string[6] == 's' || string[6] == 'S') &&
782 (string[7] == 'e' || string[7] == 'E') &&
787 * gtk_accelerator_parse
788 * @accelerator: string representing an accelerator
789 * @accelerator_key: return location for accelerator keyval
790 * @accelerator_mods: return location for accelerator modifier mask
792 * Parses a string representing an accelerator. The
793 * format looks like "<Control>a" or "<Shift><Alt>F1" or
794 * "<Release>z" (the last one is for key release).
795 * The parser is fairly liberal and allows lower or upper case,
796 * and also abbreviations such as "<Ctl>" and "<Ctrl>".
798 * If the parse fails, @accelerator_key and @accelerator_mods will
799 * be set to 0 (zero).
802 gtk_accelerator_parse (const gchar *accelerator,
803 guint *accelerator_key,
804 GdkModifierType *accelerator_mods)
807 GdkModifierType mods;
811 *accelerator_key = 0;
812 if (accelerator_mods)
813 *accelerator_mods = 0;
814 g_return_if_fail (accelerator != NULL);
818 len = strlen (accelerator);
821 if (*accelerator == '<')
823 if (len >= 9 && is_release (accelerator))
827 mods |= GDK_RELEASE_MASK;
829 else if (len >= 9 && is_control (accelerator))
833 mods |= GDK_CONTROL_MASK;
835 else if (len >= 7 && is_shift (accelerator))
839 mods |= GDK_SHIFT_MASK;
841 else if (len >= 6 && is_shft (accelerator))
845 mods |= GDK_SHIFT_MASK;
847 else if (len >= 6 && is_ctrl (accelerator))
851 mods |= GDK_CONTROL_MASK;
853 else if (len >= 6 && is_modx (accelerator))
855 static const guint mod_vals[] = {
856 GDK_MOD1_MASK, GDK_MOD2_MASK, GDK_MOD3_MASK,
857 GDK_MOD4_MASK, GDK_MOD5_MASK
862 mods |= mod_vals[*accelerator - '1'];
865 else if (len >= 5 && is_ctl (accelerator))
869 mods |= GDK_CONTROL_MASK;
871 else if (len >= 5 && is_alt (accelerator))
875 mods |= GDK_MOD1_MASK;
881 last_ch = *accelerator;
882 while (last_ch && last_ch != '>')
884 last_ch = *accelerator;
892 keyval = gdk_keyval_from_name (accelerator);
899 *accelerator_key = gdk_keyval_to_lower (keyval);
900 if (accelerator_mods)
901 *accelerator_mods = mods;
905 * gtk_accelerator_name
906 * @accelerator_key: accelerator keyval
907 * @accelerator_mods: accelerator modifier mask
908 * @returns: a newly allocated accelerator name
910 * Converts an accelerator keyval and modifier mask
911 * into a string parseable by gtk_accelerator_parse().
912 * For example, if you pass in GDK_q and GDK_CONTROL_MASK,
913 * this function returns "<Control>q".
915 * The caller of this function must free the returned string.
918 gtk_accelerator_name (guint accelerator_key,
919 GdkModifierType accelerator_mods)
921 static const gchar text_release[] = "<Release>";
922 static const gchar text_shift[] = "<Shift>";
923 static const gchar text_control[] = "<Control>";
924 static const gchar text_mod1[] = "<Alt>";
925 static const gchar text_mod2[] = "<Mod2>";
926 static const gchar text_mod3[] = "<Mod3>";
927 static const gchar text_mod4[] = "<Mod4>";
928 static const gchar text_mod5[] = "<Mod5>";
933 accelerator_mods &= GDK_MODIFIER_MASK;
935 keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
940 if (accelerator_mods & GDK_RELEASE_MASK)
941 l += sizeof (text_release) - 1;
942 if (accelerator_mods & GDK_SHIFT_MASK)
943 l += sizeof (text_shift) - 1;
944 if (accelerator_mods & GDK_CONTROL_MASK)
945 l += sizeof (text_control) - 1;
946 if (accelerator_mods & GDK_MOD1_MASK)
947 l += sizeof (text_mod1) - 1;
948 if (accelerator_mods & GDK_MOD2_MASK)
949 l += sizeof (text_mod2) - 1;
950 if (accelerator_mods & GDK_MOD3_MASK)
951 l += sizeof (text_mod3) - 1;
952 if (accelerator_mods & GDK_MOD4_MASK)
953 l += sizeof (text_mod4) - 1;
954 if (accelerator_mods & GDK_MOD5_MASK)
955 l += sizeof (text_mod5) - 1;
956 l += strlen (keyval_name);
958 accelerator = g_new (gchar, l + 1);
962 if (accelerator_mods & GDK_RELEASE_MASK)
964 strcpy (accelerator + l, text_release);
965 l += sizeof (text_release) - 1;
967 if (accelerator_mods & GDK_SHIFT_MASK)
969 strcpy (accelerator + l, text_shift);
970 l += sizeof (text_shift) - 1;
972 if (accelerator_mods & GDK_CONTROL_MASK)
974 strcpy (accelerator + l, text_control);
975 l += sizeof (text_control) - 1;
977 if (accelerator_mods & GDK_MOD1_MASK)
979 strcpy (accelerator + l, text_mod1);
980 l += sizeof (text_mod1) - 1;
982 if (accelerator_mods & GDK_MOD2_MASK)
984 strcpy (accelerator + l, text_mod2);
985 l += sizeof (text_mod2) - 1;
987 if (accelerator_mods & GDK_MOD3_MASK)
989 strcpy (accelerator + l, text_mod3);
990 l += sizeof (text_mod3) - 1;
992 if (accelerator_mods & GDK_MOD4_MASK)
994 strcpy (accelerator + l, text_mod4);
995 l += sizeof (text_mod4) - 1;
997 if (accelerator_mods & GDK_MOD5_MASK)
999 strcpy (accelerator + l, text_mod5);
1000 l += sizeof (text_mod5) - 1;
1002 strcpy (accelerator + l, keyval_name);
1008 * gtk_accelerator_set_default_mod_mask
1009 * @default_mod_mask: accelerator modifier mask
1011 * Sets the modifiers that will be considered significant for keyboard
1012 * accelerators. The default mod mask is #GDK_CONTROL_MASK |
1013 * #GDK_SHIFT_MASK | #GDK_MOD1_MASK, that is, Control, Shift, and Alt.
1014 * Other modifiers will by default be ignored by #GtkAccelGroup.
1016 * The default mod mask should be changed on application startup,
1017 * before using any accelerator groups.
1020 gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask)
1022 default_accel_mod_mask = default_mod_mask & GDK_MODIFIER_MASK;
1026 * gtk_accelerator_get_default_mod_mask
1027 * @returns: the default accelerator modifier mask
1029 * Gets the value set by gtk_accelerator_set_default_mod_mask().
1032 gtk_accelerator_get_default_mod_mask (void)
1034 return default_accel_mod_mask;