1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkAccelGroup: Accelerator manager for GtkObjects.
5 * Copyright (C) 1998 Tim Janik
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 #include "gtkaccelgroup.h"
25 #include "gdk/gdkkeysyms.h"
26 #include "gtksignal.h"
27 #include "gtkwidget.h"
31 typedef void (*GtkSignalAddAccelerator) (GtkObject *object,
32 guint accel_signal_id,
33 GtkAccelGroup *accel_group,
35 GdkModifierType accel_mods,
36 GtkAccelFlags accel_flags,
38 typedef void (*GtkSignalRemoveAccelerator) (GtkObject *object,
39 GtkAccelGroup *accel_group,
41 GdkModifierType accel_mods,
44 /* --- variables --- */
45 static GtkAccelGroup *default_accel_group = NULL;
46 static guint default_accel_mod_mask = (GDK_SHIFT_MASK |
49 static const gchar *accel_groups_key = "gtk-accel-groups";
50 static guint accel_groups_key_id = 0;
51 static const gchar *accel_entries_key = "gtk-accel-entries";
52 static guint accel_entries_key_id = 0;
53 static GHashTable *accel_entry_hash_table = NULL;
54 static GMemChunk *accel_tables_mem_chunk = NULL;
55 static GMemChunk *accel_entries_mem_chunk = NULL;
58 /* --- functions --- */
60 gtk_accel_entries_equal (gconstpointer a,
63 const GtkAccelEntry *e1;
64 const GtkAccelEntry *e2;
69 return ((e1->accel_group == e2->accel_group) &&
70 (e1->accelerator_key == e2->accelerator_key) &&
71 (e1->accelerator_mods == e2->accelerator_mods));
75 gtk_accel_entries_hash (gconstpointer a)
77 const GtkAccelEntry *e;
82 h = (gulong) e->accel_group;
83 h ^= e->accelerator_key << 16;
84 h ^= e->accelerator_key >> 16;
85 h ^= e->accelerator_mods;
91 gtk_accel_group_new (void)
93 GtkAccelGroup *accel_group;
95 if (!accel_groups_key_id)
97 accel_groups_key_id = g_quark_from_static_string (accel_groups_key);
98 accel_entries_key_id = g_quark_from_static_string (accel_entries_key);
100 accel_entry_hash_table = g_hash_table_new (gtk_accel_entries_hash,
101 gtk_accel_entries_equal);
103 accel_tables_mem_chunk = g_mem_chunk_create (GtkAccelGroup, 8, G_ALLOC_AND_FREE);
104 accel_entries_mem_chunk = g_mem_chunk_create (GtkAccelEntry, 64, G_ALLOC_AND_FREE);
107 accel_group = g_chunk_new (GtkAccelGroup, accel_tables_mem_chunk);
109 accel_group->ref_count = 1;
110 accel_group->lock_count = 0;
111 accel_group->modifier_mask = gtk_accelerator_get_default_mod_mask ();
112 accel_group->attach_objects = NULL;
118 gtk_accel_group_get_default (void)
120 if (!default_accel_group)
121 default_accel_group = gtk_accel_group_new ();
123 return default_accel_group;
127 gtk_accel_group_ref (GtkAccelGroup *accel_group)
129 g_return_val_if_fail (accel_group != NULL, NULL);
131 accel_group->ref_count += 1;
137 gtk_accel_group_unref (GtkAccelGroup *accel_group)
139 g_return_if_fail (accel_group != NULL);
140 g_return_if_fail (accel_group->ref_count > 0);
142 accel_group->ref_count -= 1;
143 if (accel_group->ref_count == 0)
145 g_return_if_fail (accel_group != default_accel_group);
146 g_return_if_fail (accel_group->attach_objects == NULL);
148 g_chunk_free (accel_group, accel_tables_mem_chunk);
153 gtk_accel_group_object_destroy (GtkObject *object)
155 GSList *free_list, *slist;
157 free_list = gtk_object_get_data_by_id (object, accel_groups_key_id);
158 gtk_object_set_data_by_id (object, accel_groups_key_id, NULL);
160 for (slist = free_list; slist; slist = slist->next)
162 GtkAccelGroup *accel_group;
164 accel_group = slist->data;
165 accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, object);
166 gtk_accel_group_unref (accel_group);
168 g_slist_free (free_list);
172 gtk_accel_group_attach (GtkAccelGroup *accel_group,
177 g_return_if_fail (accel_group != NULL);
178 g_return_if_fail (object != NULL);
179 g_return_if_fail (GTK_IS_OBJECT (object));
180 g_return_if_fail (g_slist_find (accel_group->attach_objects, object) == NULL);
182 accel_group->attach_objects = g_slist_prepend (accel_group->attach_objects, object);
183 gtk_accel_group_ref (accel_group);
184 slist = gtk_object_get_data_by_id (object, accel_groups_key_id);
186 gtk_signal_connect (object,
188 GTK_SIGNAL_FUNC (gtk_accel_group_object_destroy),
190 slist = g_slist_prepend (slist, accel_group);
191 gtk_object_set_data_by_id (object, accel_groups_key_id, slist);
195 gtk_accel_group_detach (GtkAccelGroup *accel_group,
200 g_return_if_fail (accel_group != NULL);
201 g_return_if_fail (object != NULL);
202 g_return_if_fail (GTK_IS_OBJECT (object));
203 g_return_if_fail (g_slist_find (accel_group->attach_objects, object) != NULL);
205 accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, object);
206 gtk_accel_group_unref (accel_group);
207 slist = gtk_object_get_data_by_id (object, accel_groups_key_id);
208 slist = g_slist_remove (slist, accel_group);
210 gtk_signal_disconnect_by_func (object,
211 GTK_SIGNAL_FUNC (gtk_accel_group_object_destroy),
213 gtk_object_set_data_by_id (object, accel_groups_key_id, slist);
217 gtk_accel_group_lock (GtkAccelGroup *accel_group)
219 g_return_if_fail (accel_group != NULL);
221 accel_group->lock_count += 1;
225 gtk_accel_group_unlock (GtkAccelGroup *accel_group)
227 g_return_if_fail (accel_group != NULL);
229 if (accel_group->lock_count)
230 accel_group->lock_count -= 1;
233 static GtkAccelEntry*
234 gtk_accel_group_lookup (GtkAccelGroup *accel_group,
236 GdkModifierType accel_mods)
238 GtkAccelEntry key_entry = { 0 };
240 key_entry.accel_group = accel_group;
241 key_entry.accelerator_key = gdk_keyval_to_lower (accel_key);
242 key_entry.accelerator_mods = accel_mods & accel_group->modifier_mask;
244 return g_hash_table_lookup (accel_entry_hash_table, &key_entry);
248 gtk_accel_group_activate (GtkAccelGroup *accel_group,
250 GdkModifierType accel_mods)
252 GtkAccelEntry *entry;
254 g_return_val_if_fail (accel_group != NULL, FALSE);
256 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
257 if (entry && entry->signal_id)
259 gtk_signal_emit (entry->object, entry->signal_id);
266 gtk_accel_groups_activate (GtkObject *object,
268 GdkModifierType accel_mods)
270 g_return_val_if_fail (object != NULL, FALSE);
271 g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
273 if (gtk_accelerator_valid (accel_key, accel_mods))
277 for (slist = gtk_accel_groups_from_object (object); slist; slist = slist->next)
278 if (gtk_accel_group_activate (slist->data, accel_key, accel_mods))
280 return gtk_accel_group_activate (gtk_accel_group_get_default (), accel_key, accel_mods);
287 gtk_accel_group_lock_entry (GtkAccelGroup *accel_group,
289 GdkModifierType accel_mods)
291 GtkAccelEntry *entry;
293 g_return_if_fail (accel_group != NULL);
295 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
297 entry->accel_flags |= GTK_ACCEL_LOCKED;
301 gtk_accel_group_unlock_entry (GtkAccelGroup *accel_group,
303 GdkModifierType accel_mods)
305 GtkAccelEntry *entry;
307 g_return_if_fail (accel_group != NULL);
309 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
311 entry->accel_flags &= ~GTK_ACCEL_LOCKED;
315 gtk_accel_group_get_entry (GtkAccelGroup *accel_group,
317 GdkModifierType accel_mods)
319 g_return_val_if_fail (accel_group != NULL, 0);
321 return gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
325 gtk_accel_group_add (GtkAccelGroup *accel_group,
327 GdkModifierType accel_mods,
328 GtkAccelFlags accel_flags,
330 const gchar *accel_signal)
332 guint accel_signal_id = 0;
333 guint add_accelerator_signal_id = 0;
334 guint remove_accelerator_signal_id = 0;
336 GtkSignalQuery *query;
339 GSList *attach_objects;
340 GtkAccelEntry *entry;
342 g_return_if_fail (accel_group != NULL);
343 g_return_if_fail (object != NULL);
344 g_return_if_fail (GTK_IS_OBJECT (object));
345 g_return_if_fail (accel_signal != NULL);
347 /* check for required signals in the objects branch
349 signal = (gchar*) accel_signal;
350 accel_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object));
353 signal = "add-accelerator";
354 add_accelerator_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object));
356 if (add_accelerator_signal_id)
358 signal = "remove-accelerator";
359 remove_accelerator_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object));
361 if (!accel_signal_id ||
362 !add_accelerator_signal_id ||
363 !remove_accelerator_signal_id)
365 g_warning ("gtk_accel_group_add(): could not find signal \"%s\""
366 "in the `%s' class ancestry",
368 gtk_type_name (GTK_OBJECT_TYPE (object)));
371 query = gtk_signal_query (accel_signal_id);
375 g_warning ("gtk_accel_group_add(): signal \"%s\" in the `%s' class ancestry"
376 "cannot be used as accelerator signal",
378 gtk_type_name (GTK_OBJECT_TYPE (object)));
382 /* prematurely abort if the group/entry is already locked
384 if (accel_group->lock_count > 0)
386 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
387 if (entry && entry->accel_flags & GTK_ACCEL_LOCKED)
390 /* make sure our structures stay alive
392 gtk_accel_group_ref (accel_group);
393 gtk_object_ref (object);
395 /* remove an existing entry
398 gtk_signal_emit (entry->object, remove_accelerator_signal_id,
400 gdk_keyval_to_lower (accel_key),
401 accel_mods & accel_group->modifier_mask);
403 /* abort if the entry still exists
405 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
408 gtk_accel_group_unref (accel_group);
409 gtk_object_unref (object);
414 /* collect accel groups and remove existing entries
416 attach_objects = accel_group->attach_objects;
418 for (attach_objects = accel_group->attach_objects; attach_objects; attach_objects = attach_objects->next)
422 tmp_groups = gtk_object_get_data_by_id (attach_objects->data, accel_groups_key_id);
425 groups = g_slist_prepend (groups, tmp_groups->data);
426 gtk_accel_group_ref (tmp_groups->data);
427 tmp_groups = tmp_groups->next;
430 for (slist = groups; slist; slist = slist->next)
432 GtkAccelGroup *tmp_group;
434 tmp_group = slist->data;
436 /* we only remove the accelerator if neccessary
438 if (tmp_group->lock_count == 0)
440 entry = gtk_accel_group_lookup (tmp_group, accel_key, accel_mods);
441 if (entry && !(entry->accel_flags & GTK_ACCEL_LOCKED))
442 gtk_signal_emit (entry->object, remove_accelerator_signal_id,
444 gdk_keyval_to_lower (accel_key),
445 accel_mods & tmp_group->modifier_mask);
447 gtk_accel_group_unref (tmp_group);
449 g_slist_free (groups);
451 /* now install the new accelerator
453 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
455 gtk_signal_emit (object, add_accelerator_signal_id,
458 gdk_keyval_to_lower (accel_key),
459 accel_mods & accel_group->modifier_mask,
460 accel_flags & GTK_ACCEL_MASK);
462 /* and release the structures again
464 gtk_accel_group_unref (accel_group);
465 gtk_object_unref (object);
469 gtk_accel_group_delete_entries (GtkObject *object)
471 GSList *free_slist, *slist;
473 gtk_signal_disconnect_by_func (object,
474 GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries),
477 /* we remove all entries of this object the hard
478 * way (i.e. without signal emission).
480 free_slist = gtk_object_get_data_by_id (object, accel_entries_key_id);
481 gtk_object_set_data_by_id (object, accel_entries_key_id, NULL);
482 for (slist = free_slist; slist; slist = slist->next)
484 GtkAccelEntry *entry;
488 g_hash_table_remove (accel_entry_hash_table, entry);
489 gtk_accel_group_unref (entry->accel_group);
490 g_chunk_free (entry, accel_entries_mem_chunk);
492 g_slist_free (free_slist);
496 gtk_accel_group_handle_add (GtkObject *object,
497 guint accel_signal_id,
498 GtkAccelGroup *accel_group,
500 GdkModifierType accel_mods,
501 GtkAccelFlags accel_flags)
503 GtkAccelEntry *entry;
505 g_return_if_fail (object != NULL);
506 g_return_if_fail (GTK_IS_OBJECT (object));
507 g_return_if_fail (accel_group != NULL);
508 g_return_if_fail (accel_signal_id > 0);
510 if (!gtk_accelerator_valid (accel_key, accel_mods))
513 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
518 gtk_accel_group_ref (accel_group);
520 entry = g_chunk_new (GtkAccelEntry, accel_entries_mem_chunk);
521 entry->accel_group = accel_group;
522 entry->accelerator_key = gdk_keyval_to_lower (accel_key);
523 entry->accelerator_mods = accel_mods & accel_group->modifier_mask;
524 entry->accel_flags = accel_flags & GTK_ACCEL_MASK;
525 entry->object = object;
526 entry->signal_id = accel_signal_id;
528 g_hash_table_insert (accel_entry_hash_table, entry, entry);
530 slist = gtk_object_get_data_by_id (object, accel_entries_key_id);
532 gtk_signal_connect (object,
534 GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries),
536 slist = g_slist_prepend (slist, entry);
537 gtk_object_set_data_by_id (object, accel_entries_key_id, slist);
542 gtk_accel_group_remove (GtkAccelGroup *accel_group,
544 GdkModifierType accel_mods,
547 GtkAccelEntry *entry;
548 guint remove_accelerator_signal_id = 0;
550 g_return_if_fail (accel_group != NULL);
551 g_return_if_fail (object != NULL);
552 g_return_if_fail (GTK_IS_OBJECT (object));
554 /* check for required signals in the objects branch
556 remove_accelerator_signal_id = gtk_signal_lookup ("remove-accelerator", GTK_OBJECT_TYPE (object));
557 if (!remove_accelerator_signal_id)
559 g_warning ("gtk_accel_group_remove(): could not find signal \"%s\""
560 "in the `%s' class ancestry",
561 "remove-accelerator",
562 gtk_type_name (GTK_OBJECT_TYPE (object)));
566 /* prematurely abort if the entry is locked
568 if (accel_group->lock_count > 0)
570 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
572 entry->accel_flags & GTK_ACCEL_LOCKED)
574 if (entry->object != object)
576 g_warning ("gtk_accel_group_remove(): invalid object reference for accel-group entry");
580 /* make sure our structures stay alive
582 gtk_accel_group_ref (accel_group);
583 gtk_object_ref (object);
587 gtk_signal_emit (entry->object, remove_accelerator_signal_id,
589 gdk_keyval_to_lower (accel_key),
590 accel_mods & accel_group->modifier_mask);
592 /* and release the structures again
594 gtk_accel_group_unref (accel_group);
595 gtk_object_unref (object);
599 gtk_accel_group_handle_remove (GtkObject *object,
600 GtkAccelGroup *accel_group,
602 GdkModifierType accel_mods)
604 GtkAccelEntry *entry;
606 g_return_if_fail (object != NULL);
607 g_return_if_fail (GTK_IS_OBJECT (object));
608 g_return_if_fail (accel_group != NULL);
610 entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
613 if (entry->object == object)
617 g_hash_table_remove (accel_entry_hash_table, entry);
619 slist = gtk_object_get_data_by_id (object, accel_entries_key_id);
622 slist = g_slist_remove (slist, entry);
624 gtk_signal_disconnect_by_func (object,
625 GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries),
627 gtk_object_set_data_by_id (object, accel_entries_key_id, slist);
629 gtk_accel_group_unref (accel_group);
631 g_chunk_free (entry, accel_entries_mem_chunk);
635 g_warning ("gtk_accel_group_handle_remove(): invalid object reference for accel-group entry");
638 g_warning ("gtk_accel_group_handle_remove(): attempt to remove unexisting accel-group entry");
642 gtk_accel_group_create_add (GtkType class_type,
643 GtkSignalRunType signal_flags,
644 guint handler_offset)
646 g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_OBJECT), 0);
648 return gtk_signal_new ("add-accelerator",
652 gtk_accel_group_marshal_add,
655 GTK_TYPE_ACCEL_GROUP,
657 GTK_TYPE_GDK_MODIFIER_TYPE,
658 GTK_TYPE_ACCEL_FLAGS);
662 gtk_accel_group_create_remove (GtkType class_type,
663 GtkSignalRunType signal_flags,
664 guint handler_offset)
666 g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_OBJECT), 0);
668 return gtk_signal_new ("remove-accelerator",
672 gtk_accel_group_marshal_remove,
674 GTK_TYPE_ACCEL_GROUP,
676 GTK_TYPE_GDK_MODIFIER_TYPE);
680 gtk_accel_group_marshal_add (GtkObject *object,
685 GtkSignalAddAccelerator signal_func;
687 signal_func = (GtkSignalAddAccelerator) func;
690 GTK_VALUE_UINT (args[0]),
691 GTK_VALUE_BOXED (args[1]),
692 GTK_VALUE_UINT (args[2]),
693 GTK_VALUE_UINT (args[3]),
694 GTK_VALUE_ENUM (args[4]),
699 gtk_accel_group_marshal_remove (GtkObject *object,
704 GtkSignalRemoveAccelerator signal_func;
706 signal_func = (GtkSignalRemoveAccelerator) func;
709 GTK_VALUE_BOXED (args[0]),
710 GTK_VALUE_UINT (args[1]),
711 GTK_VALUE_UINT (args[2]),
716 gtk_accel_groups_from_object (GtkObject *object)
718 g_return_val_if_fail (object != NULL, NULL);
719 g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
721 return gtk_object_get_data_by_id (object, accel_groups_key_id);
725 gtk_accel_group_entries_from_object (GtkObject *object)
727 g_return_val_if_fail (object != NULL, NULL);
728 g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
730 return gtk_object_get_data_by_id (object, accel_entries_key_id);
734 gtk_accelerator_valid (guint keyval,
737 guint invalid_accelerator_vals[] = {
738 GDK_BackSpace, GDK_Delete, GDK_KP_Delete,
739 GDK_Shift_L, GDK_Shift_R, GDK_Shift_Lock, GDK_Caps_Lock, GDK_ISO_Lock,
740 GDK_Control_L, GDK_Control_R, GDK_Meta_L, GDK_Meta_R,
741 GDK_Super_L, GDK_Super_R, GDK_Hyper_L, GDK_Hyper_R,
742 GDK_Mode_switch, GDK_Num_Lock, GDK_Multi_key,
743 GDK_Scroll_Lock, GDK_Sys_Req,
744 GDK_Up, GDK_Down, GDK_Left, GDK_Right, GDK_Tab, GDK_ISO_Left_Tab,
745 GDK_KP_Up, GDK_KP_Down, GDK_KP_Left, GDK_KP_Right, GDK_KP_Tab,
746 GDK_First_Virtual_Screen, GDK_Prev_Virtual_Screen,
747 GDK_Next_Virtual_Screen, GDK_Last_Virtual_Screen,
748 GDK_Terminate_Server, GDK_AudibleBell_Enable,
753 modifiers &= GDK_MODIFIER_MASK;
756 return keyval >= 0x20;
758 ac_val = invalid_accelerator_vals;
761 if (keyval == *ac_val++)
768 static inline gboolean
769 is_alt (const gchar *string)
771 return ((string[0] == '<') &&
772 (string[1] == 'a' || string[1] == 'A') &&
773 (string[2] == 'l' || string[2] == 'L') &&
774 (string[3] == 't' || string[3] == 'T') &&
778 static inline gboolean
779 is_ctl (const gchar *string)
781 return ((string[0] == '<') &&
782 (string[1] == 'c' || string[1] == 'C') &&
783 (string[2] == 't' || string[2] == 'T') &&
784 (string[3] == 'l' || string[3] == 'L') &&
788 static inline gboolean
789 is_modx (const gchar *string)
791 return ((string[0] == '<') &&
792 (string[1] == 'm' || string[1] == 'M') &&
793 (string[2] == 'o' || string[2] == 'O') &&
794 (string[3] == 'd' || string[3] == 'D') &&
795 (string[4] >= '1' && string[4] <= '5') &&
799 static inline gboolean
800 is_ctrl (const gchar *string)
802 return ((string[0] == '<') &&
803 (string[1] == 'c' || string[1] == 'C') &&
804 (string[2] == 't' || string[2] == 'T') &&
805 (string[3] == 'r' || string[3] == 'R') &&
806 (string[4] == 'l' || string[4] == 'L') &&
810 static inline gboolean
811 is_shft (const gchar *string)
813 return ((string[0] == '<') &&
814 (string[1] == 's' || string[1] == 'S') &&
815 (string[2] == 'h' || string[2] == 'H') &&
816 (string[3] == 'f' || string[3] == 'F') &&
817 (string[4] == 't' || string[4] == 'T') &&
821 static inline gboolean
822 is_shift (const gchar *string)
824 return ((string[0] == '<') &&
825 (string[1] == 's' || string[1] == 'S') &&
826 (string[2] == 'h' || string[2] == 'H') &&
827 (string[3] == 'i' || string[3] == 'I') &&
828 (string[4] == 'f' || string[4] == 'F') &&
829 (string[5] == 't' || string[5] == 'T') &&
833 static inline gboolean
834 is_control (const gchar *string)
836 return ((string[0] == '<') &&
837 (string[1] == 'c' || string[1] == 'C') &&
838 (string[2] == 'o' || string[2] == 'O') &&
839 (string[3] == 'n' || string[3] == 'N') &&
840 (string[4] == 't' || string[4] == 'T') &&
841 (string[5] == 'r' || string[5] == 'R') &&
842 (string[6] == 'o' || string[6] == 'O') &&
843 (string[7] == 'l' || string[7] == 'L') &&
847 static inline gboolean
848 is_release (const gchar *string)
850 return ((string[0] == '<') &&
851 (string[1] == 'r' || string[1] == 'R') &&
852 (string[2] == 'e' || string[2] == 'E') &&
853 (string[3] == 'l' || string[3] == 'L') &&
854 (string[4] == 'e' || string[4] == 'E') &&
855 (string[5] == 'a' || string[5] == 'A') &&
856 (string[6] == 's' || string[6] == 'S') &&
857 (string[7] == 'e' || string[7] == 'E') &&
862 gtk_accelerator_parse (const gchar *accelerator,
863 guint *accelerator_key,
864 GdkModifierType*accelerator_mods)
867 GdkModifierType mods;
871 *accelerator_key = 0;
872 if (accelerator_mods)
873 *accelerator_mods = 0;
874 g_return_if_fail (accelerator != NULL);
878 len = strlen (accelerator);
881 if (*accelerator == '<')
883 if (len >= 9 && is_release (accelerator))
887 mods |= GDK_RELEASE_MASK;
889 else if (len >= 9 && is_control (accelerator))
893 mods |= GDK_CONTROL_MASK;
895 else if (len >= 7 && is_shift (accelerator))
899 mods |= GDK_SHIFT_MASK;
901 else if (len >= 6 && is_shft (accelerator))
905 mods |= GDK_SHIFT_MASK;
907 else if (len >= 6 && is_ctrl (accelerator))
911 mods |= GDK_CONTROL_MASK;
913 else if (len >= 6 && is_modx (accelerator))
916 GDK_MOD1_MASK, GDK_MOD2_MASK, GDK_MOD3_MASK,
917 GDK_MOD4_MASK, GDK_MOD5_MASK
922 mods |= mod_vals[*accelerator - '1'];
925 else if (len >= 5 && is_ctl (accelerator))
929 mods |= GDK_CONTROL_MASK;
931 else if (len >= 5 && is_alt (accelerator))
935 mods |= GDK_MOD1_MASK;
941 last_ch = *accelerator;
942 while (last_ch && last_ch != '>')
944 last_ch = *accelerator;
952 keyval = gdk_keyval_from_name (accelerator);
959 *accelerator_key = gdk_keyval_to_lower (keyval);
960 if (accelerator_mods)
961 *accelerator_mods = mods;
965 gtk_accelerator_name (guint accelerator_key,
966 GdkModifierType accelerator_mods)
968 static const gchar text_release[] = "<Release>";
969 static const gchar text_shift[] = "<Shift>";
970 static const gchar text_control[] = "<Control>";
971 static const gchar text_mod1[] = "<Alt>";
972 static const gchar text_mod2[] = "<Mod2>";
973 static const gchar text_mod3[] = "<Mod3>";
974 static const gchar text_mod4[] = "<Mod4>";
975 static const gchar text_mod5[] = "<Mod5>";
980 accelerator_mods &= GDK_MODIFIER_MASK;
982 keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
987 if (accelerator_mods & GDK_RELEASE_MASK)
988 l += sizeof (text_release) - 1;
989 if (accelerator_mods & GDK_SHIFT_MASK)
990 l += sizeof (text_shift) - 1;
991 if (accelerator_mods & GDK_CONTROL_MASK)
992 l += sizeof (text_control) - 1;
993 if (accelerator_mods & GDK_MOD1_MASK)
994 l += sizeof (text_mod1) - 1;
995 if (accelerator_mods & GDK_MOD2_MASK)
996 l += sizeof (text_mod2) - 1;
997 if (accelerator_mods & GDK_MOD3_MASK)
998 l += sizeof (text_mod3) - 1;
999 if (accelerator_mods & GDK_MOD4_MASK)
1000 l += sizeof (text_mod4) - 1;
1001 if (accelerator_mods & GDK_MOD5_MASK)
1002 l += sizeof (text_mod5) - 1;
1003 l += strlen (keyval_name);
1005 accelerator = g_new (gchar, l + 1);
1009 if (accelerator_mods & GDK_RELEASE_MASK)
1011 strcpy (accelerator + l, text_release);
1012 l += sizeof (text_release) - 1;
1014 if (accelerator_mods & GDK_SHIFT_MASK)
1016 strcpy (accelerator + l, text_shift);
1017 l += sizeof (text_shift) - 1;
1019 if (accelerator_mods & GDK_CONTROL_MASK)
1021 strcpy (accelerator + l, text_control);
1022 l += sizeof (text_control) - 1;
1024 if (accelerator_mods & GDK_MOD1_MASK)
1026 strcpy (accelerator + l, text_mod1);
1027 l += sizeof (text_mod1) - 1;
1029 if (accelerator_mods & GDK_MOD2_MASK)
1031 strcpy (accelerator + l, text_mod2);
1032 l += sizeof (text_mod2) - 1;
1034 if (accelerator_mods & GDK_MOD3_MASK)
1036 strcpy (accelerator + l, text_mod3);
1037 l += sizeof (text_mod3) - 1;
1039 if (accelerator_mods & GDK_MOD4_MASK)
1041 strcpy (accelerator + l, text_mod4);
1042 l += sizeof (text_mod4) - 1;
1044 if (accelerator_mods & GDK_MOD5_MASK)
1046 strcpy (accelerator + l, text_mod5);
1047 l += sizeof (text_mod5) - 1;
1049 strcpy (accelerator + l, keyval_name);
1055 gtk_accelerator_set_default_mod_mask (guint default_mod_mask)
1057 default_accel_mod_mask = default_mod_mask & GDK_MODIFIER_MASK;
1061 gtk_accelerator_get_default_mod_mask (void)
1063 return default_accel_mod_mask;