]> Pileus Git - ~andy/gtk/blob - gtk/gtkaccelgroup.c
Add some docs
[~andy/gtk] / gtk / gtkaccelgroup.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1998, 2001 Tim Janik
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include <config.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include "gtkaccelgroup.h"
32 #include "gtkaccellabel.h" /* For _gtk_accel_label_class_get_accelerator_label */
33 #include "gtkaccelmap.h"
34 #include "gtkintl.h"
35 #include "gtkmain.h"            /* For _gtk_boolean_handled_accumulator */
36 #include "gdk/gdkkeysyms.h"
37 #include "gtkmarshalers.h"
38 #include "gtkalias.h"
39
40
41 /* --- prototypes --- */
42 static void gtk_accel_group_finalize    (GObject                *object);
43 static void accel_closure_invalidate    (gpointer  data,
44                                          GClosure *closure);
45
46
47 /* --- variables --- */
48 static guint             signal_accel_activate = 0;
49 static guint             signal_accel_changed = 0;
50 static guint             quark_acceleratable_groups = 0;
51 static guint             default_accel_mod_mask = (GDK_SHIFT_MASK |
52                                                    GDK_CONTROL_MASK |
53                                                    GDK_MOD1_MASK |
54                                                    GDK_SUPER_MASK |
55                                                    GDK_HYPER_MASK |
56                                                    GDK_META_MASK);
57
58
59 G_DEFINE_TYPE (GtkAccelGroup, gtk_accel_group, G_TYPE_OBJECT)
60
61 /* --- functions --- */
62 static void
63 gtk_accel_group_class_init (GtkAccelGroupClass *class)
64 {
65   GObjectClass *object_class = G_OBJECT_CLASS (class);
66
67   quark_acceleratable_groups = g_quark_from_static_string ("gtk-acceleratable-accel-groups");
68
69   object_class->finalize = gtk_accel_group_finalize;
70
71   class->accel_changed = NULL;
72
73   /**
74    * GtkAccelGroup::accel-activate:
75    * @accel_group: the #GtkAccelGroup which received the signal
76    * @acceleratable: the object on which the accelerator was activated
77    * @keyval: the accelerator keyval
78    * @modifier: the modifier combination of the accelerator
79    *
80    * The accel-activate signal is an implementation detail of
81    * #GtkAccelGroup and not meant to be used by applications.
82    * 
83    * Returns: %TRUE if the accelerator was activated
84    */
85   signal_accel_activate =
86     g_signal_new (I_("accel_activate"),
87                   G_OBJECT_CLASS_TYPE (class),
88                   G_SIGNAL_DETAILED,
89                   0,
90                   _gtk_boolean_handled_accumulator, NULL,
91                   _gtk_marshal_BOOLEAN__OBJECT_UINT_FLAGS,
92                   G_TYPE_BOOLEAN, 3,
93                   G_TYPE_OBJECT,
94                   G_TYPE_UINT,
95                   GDK_TYPE_MODIFIER_TYPE);
96   /**
97    * GtkAccelGroup::accel-changed:
98    * @accel_group: the #GtkAccelGroup which received the signal
99    * @keyval: the accelerator keyval
100    * @modifier: the modifier combination of the accelerator
101    * @accel_closure: the #GClosure of the accelerator
102    *
103    * The accel-changed signal is emitted when a #GtkAccelGroupEntry
104    * is added to or removed from the accel group. 
105    *
106    * Widgets like #GtkAccelLabel which display an associated 
107    * accelerator should connect to this signal, and rebuild 
108    * their visual representation if the @accel_closure is theirs.
109    */
110   signal_accel_changed =
111     g_signal_new (I_("accel_changed"),
112                   G_OBJECT_CLASS_TYPE (class),
113                   G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
114                   G_STRUCT_OFFSET (GtkAccelGroupClass, accel_changed),
115                   NULL, NULL,
116                   _gtk_marshal_VOID__UINT_FLAGS_BOXED,
117                   G_TYPE_NONE, 3,
118                   G_TYPE_UINT,
119                   GDK_TYPE_MODIFIER_TYPE,
120                   G_TYPE_CLOSURE);
121 }
122
123 static void
124 gtk_accel_group_finalize (GObject *object)
125 {
126   GtkAccelGroup *accel_group = GTK_ACCEL_GROUP (object);
127   guint i;
128   
129   for (i = 0; i < accel_group->n_accels; i++)
130     {
131       GtkAccelGroupEntry *entry = &accel_group->priv_accels[i];
132
133       if (entry->accel_path_quark)
134         {
135           const gchar *accel_path = g_quark_to_string (entry->accel_path_quark);
136
137           _gtk_accel_map_remove_group (accel_path, accel_group);
138         }
139       g_closure_remove_invalidate_notifier (entry->closure, accel_group, accel_closure_invalidate);
140     }
141
142   g_free (accel_group->priv_accels);
143
144   G_OBJECT_CLASS (gtk_accel_group_parent_class)->finalize (object);
145 }
146
147 static void
148 gtk_accel_group_init (GtkAccelGroup *accel_group)
149 {
150   accel_group->lock_count = 0;
151   accel_group->modifier_mask = gtk_accelerator_get_default_mod_mask ();
152   accel_group->acceleratables = NULL;
153   accel_group->n_accels = 0;
154   accel_group->priv_accels = NULL;
155 }
156
157 /**
158  * gtk_accel_group_new:
159  * @returns: a new #GtkAccelGroup object
160  * 
161  * Creates a new #GtkAccelGroup. 
162  */
163 GtkAccelGroup*
164 gtk_accel_group_new (void)
165 {
166   return g_object_new (GTK_TYPE_ACCEL_GROUP, NULL);
167 }
168
169 static void
170 accel_group_weak_ref_detach (GSList  *free_list,
171                              GObject *stale_object)
172 {
173   GSList *slist;
174   
175   for (slist = free_list; slist; slist = slist->next)
176     {
177       GtkAccelGroup *accel_group;
178       
179       accel_group = slist->data;
180       accel_group->acceleratables = g_slist_remove (accel_group->acceleratables, stale_object);
181       g_object_unref (accel_group);
182     }
183   g_slist_free (free_list);
184   g_object_set_qdata (stale_object, quark_acceleratable_groups, NULL);
185 }
186
187 void
188 _gtk_accel_group_attach (GtkAccelGroup *accel_group,
189                          GObject       *object)
190 {
191   GSList *slist;
192   
193   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
194   g_return_if_fail (G_IS_OBJECT (object));
195   g_return_if_fail (g_slist_find (accel_group->acceleratables, object) == NULL);
196   
197   g_object_ref (accel_group);
198   accel_group->acceleratables = g_slist_prepend (accel_group->acceleratables, object);
199   slist = g_object_get_qdata (object, quark_acceleratable_groups);
200   if (slist)
201     g_object_weak_unref (object,
202                          (GWeakNotify) accel_group_weak_ref_detach,
203                          slist);
204   slist = g_slist_prepend (slist, accel_group);
205   g_object_set_qdata (object, quark_acceleratable_groups, slist);
206   g_object_weak_ref (object,
207                      (GWeakNotify) accel_group_weak_ref_detach,
208                      slist);
209 }
210
211 void
212 _gtk_accel_group_detach (GtkAccelGroup *accel_group,
213                          GObject       *object)
214 {
215   GSList *slist;
216   
217   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
218   g_return_if_fail (G_IS_OBJECT (object));
219   g_return_if_fail (g_slist_find (accel_group->acceleratables, object) != NULL);
220   
221   accel_group->acceleratables = g_slist_remove (accel_group->acceleratables, object);
222   slist = g_object_get_qdata (object, quark_acceleratable_groups);
223   g_object_weak_unref (object,
224                        (GWeakNotify) accel_group_weak_ref_detach,
225                        slist);
226   slist = g_slist_remove (slist, accel_group);
227   g_object_set_qdata (object, quark_acceleratable_groups, slist);
228   if (slist)
229     g_object_weak_ref (object,
230                        (GWeakNotify) accel_group_weak_ref_detach,
231                        slist);
232   g_object_unref (accel_group);
233 }
234
235 /**
236  * gtk_accel_groups_from_object:
237  * @object:        a #GObject, usually a #GtkWindow 
238  * @returns: a list of all accel groups which are attached to @object
239  *
240  * Gets a list of all accel groups which are attached to @object.
241  */
242 GSList*
243 gtk_accel_groups_from_object (GObject *object)
244 {
245   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
246   
247   return g_object_get_qdata (object, quark_acceleratable_groups);
248 }
249
250 /**
251  * gtk_accel_group_find:
252  * @accel_group: a #GtkAccelGroup
253  * @find_func: a function to filter the entries of @accel_group with
254  * @data: data to pass to @find_func
255  * @returns: the key of the first entry passing @find_func. The key is 
256  * owned by GTK+ and must not be freed.
257  *
258  * Finds the first entry in an accelerator group for which 
259  * @find_func returns %TRUE and returns its #GtkAccelKey.
260  *
261  */
262 GtkAccelKey*
263 gtk_accel_group_find (GtkAccelGroup        *accel_group,
264                       GtkAccelGroupFindFunc find_func,
265                       gpointer              data)
266 {
267   GtkAccelKey *key = NULL;
268   guint i;
269
270   g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL);
271   g_return_val_if_fail (find_func != NULL, NULL);
272
273   g_object_ref (accel_group);
274   for (i = 0; i < accel_group->n_accels; i++)
275     if (find_func (&accel_group->priv_accels[i].key,
276                    accel_group->priv_accels[i].closure,
277                    data))
278       {
279         key = &accel_group->priv_accels[i].key;
280         break;
281       }
282   g_object_unref (accel_group);
283
284   return key;
285 }
286
287 /**
288  * gtk_accel_group_lock:
289  * @accel_group: a #GtkAccelGroup
290  * 
291  * Locks the given accelerator group.
292  *
293  * Locking an acelerator group prevents the accelerators contained
294  * within it to be changed during runtime. Refer to
295  * gtk_accel_map_change_entry() about runtime accelerator changes.
296  *
297  * If called more than once, @accel_group remains locked until
298  * gtk_accel_group_unlock() has been called an equivalent number
299  * of times.
300  */
301 void
302 gtk_accel_group_lock (GtkAccelGroup *accel_group)
303 {
304   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
305   
306   accel_group->lock_count += 1;
307 }
308
309 /**
310  * gtk_accel_group_unlock:
311  * @accel_group: a #GtkAccelGroup
312  * 
313  * Undoes the last call to gtk_accel_group_lock() on this @accel_group.
314  */
315 void
316 gtk_accel_group_unlock (GtkAccelGroup *accel_group)
317 {
318   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
319   g_return_if_fail (accel_group->lock_count > 0);
320
321   accel_group->lock_count -= 1;
322 }
323
324 static void
325 accel_closure_invalidate (gpointer  data,
326                           GClosure *closure)
327 {
328   GtkAccelGroup *accel_group = GTK_ACCEL_GROUP (data);
329
330   gtk_accel_group_disconnect (accel_group, closure);
331 }
332
333 static int
334 bsearch_compare_accels (const void *d1,
335                         const void *d2)
336 {
337   const GtkAccelGroupEntry *entry1 = d1;
338   const GtkAccelGroupEntry *entry2 = d2;
339
340   if (entry1->key.accel_key == entry2->key.accel_key)
341     return entry1->key.accel_mods < entry2->key.accel_mods ? -1 : entry1->key.accel_mods > entry2->key.accel_mods;
342   else
343     return entry1->key.accel_key < entry2->key.accel_key ? -1 : 1;
344 }
345
346 static void
347 quick_accel_add (GtkAccelGroup  *accel_group,
348                  guint           accel_key,
349                  GdkModifierType accel_mods,
350                  GtkAccelFlags   accel_flags,
351                  GClosure       *closure,
352                  GQuark          path_quark)
353 {
354   guint pos, i = accel_group->n_accels++;
355   GtkAccelGroupEntry key;
356
357   /* find position */
358   key.key.accel_key = accel_key;
359   key.key.accel_mods = accel_mods;
360   for (pos = 0; pos < i; pos++)
361     if (bsearch_compare_accels (&key, accel_group->priv_accels + pos) < 0)
362       break;
363
364   /* insert at position, ref closure */
365   accel_group->priv_accels = g_renew (GtkAccelGroupEntry, accel_group->priv_accels, accel_group->n_accels);
366   g_memmove (accel_group->priv_accels + pos + 1, accel_group->priv_accels + pos,
367              (i - pos) * sizeof (accel_group->priv_accels[0]));
368   accel_group->priv_accels[pos].key.accel_key = accel_key;
369   accel_group->priv_accels[pos].key.accel_mods = accel_mods;
370   accel_group->priv_accels[pos].key.accel_flags = accel_flags;
371   accel_group->priv_accels[pos].closure = g_closure_ref (closure);
372   accel_group->priv_accels[pos].accel_path_quark = path_quark;
373   g_closure_sink (closure);
374   
375   /* handle closure invalidation and reverse lookups */
376   g_closure_add_invalidate_notifier (closure, accel_group, accel_closure_invalidate);
377
378   /* get accel path notification */
379   if (path_quark)
380     _gtk_accel_map_add_group (g_quark_to_string (path_quark), accel_group);
381
382   /* connect and notify changed */
383   if (accel_key)
384     {
385       gchar *accel_name = gtk_accelerator_name (accel_key, accel_mods);
386       GQuark accel_quark = g_quark_from_string (accel_name);
387
388       g_free (accel_name);
389       
390       /* setup handler */
391       g_signal_connect_closure_by_id (accel_group, signal_accel_activate, accel_quark, closure, FALSE);
392       
393       /* and notify */
394       g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, closure);
395     }
396 }
397
398 static void
399 quick_accel_remove (GtkAccelGroup      *accel_group,
400                     guint               pos)
401 {
402   GQuark accel_quark = 0;
403   GtkAccelGroupEntry *entry = accel_group->priv_accels + pos;
404   guint accel_key = entry->key.accel_key;
405   GdkModifierType accel_mods = entry->key.accel_mods;
406   GClosure *closure = entry->closure;
407
408   /* quark for notification */
409   if (accel_key)
410     {
411       gchar *accel_name = gtk_accelerator_name (accel_key, accel_mods);
412
413       accel_quark = g_quark_from_string (accel_name);
414       g_free (accel_name);
415     }
416
417   /* clean up closure invalidate notification and disconnect */
418   g_closure_remove_invalidate_notifier (entry->closure, accel_group, accel_closure_invalidate);
419   if (accel_quark)
420     g_signal_handlers_disconnect_matched (accel_group,
421                                           G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_CLOSURE,
422                                           signal_accel_activate, accel_quark,
423                                           closure, NULL, NULL);
424   /* clean up accel path notification */
425   if (entry->accel_path_quark)
426     _gtk_accel_map_remove_group (g_quark_to_string (entry->accel_path_quark), accel_group);
427
428   /* physically remove */
429   accel_group->n_accels -= 1;
430   g_memmove (entry, entry + 1,
431              (accel_group->n_accels - pos) * sizeof (accel_group->priv_accels[0]));
432
433   /* and notify */
434   if (accel_quark)
435     g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, closure);
436
437   /* remove quick_accel_add() refcount */
438   g_closure_unref (closure);
439 }
440
441 static GtkAccelGroupEntry*
442 quick_accel_find (GtkAccelGroup  *accel_group,
443                   guint           accel_key,
444                   GdkModifierType accel_mods,
445                   guint          *count_p)
446 {
447   GtkAccelGroupEntry *entry;
448   GtkAccelGroupEntry key;
449
450   *count_p = 0;
451
452   if (!accel_group->n_accels)
453     return NULL;
454
455   key.key.accel_key = accel_key;
456   key.key.accel_mods = accel_mods;
457   entry = bsearch (&key, accel_group->priv_accels, accel_group->n_accels,
458                    sizeof (accel_group->priv_accels[0]), bsearch_compare_accels);
459   
460   if (!entry)
461     return NULL;
462
463   /* step back to the first member */
464   for (; entry > accel_group->priv_accels; entry--)
465     if (entry[-1].key.accel_key != accel_key ||
466         entry[-1].key.accel_mods != accel_mods)
467       break;
468   /* count equal members */
469   for (; entry + *count_p < accel_group->priv_accels + accel_group->n_accels; (*count_p)++)
470     if (entry[*count_p].key.accel_key != accel_key ||
471         entry[*count_p].key.accel_mods != accel_mods)
472       break;
473   return entry;
474 }
475
476 /**
477  * gtk_accel_group_connect:
478  * @accel_group:      the accelerator group to install an accelerator in
479  * @accel_key:        key value of the accelerator
480  * @accel_mods:       modifier combination of the accelerator
481  * @accel_flags:      a flag mask to configure this accelerator
482  * @closure:          closure to be executed upon accelerator activation
483  *
484  * Installs an accelerator in this group. When @accel_group is being activated
485  * in response to a call to gtk_accel_groups_activate(), @closure will be
486  * invoked if the @accel_key and @accel_mods from gtk_accel_groups_activate()
487  * match those of this connection.
488  *
489  * The signature used for the @closure is that of #GtkAccelGroupActivate.
490  * 
491  * Note that, due to implementation details, a single closure can only be
492  * connected to one accelerator group.
493  */
494 void
495 gtk_accel_group_connect (GtkAccelGroup  *accel_group,
496                          guint           accel_key,
497                          GdkModifierType accel_mods,
498                          GtkAccelFlags   accel_flags,
499                          GClosure       *closure)
500 {
501   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
502   g_return_if_fail (closure != NULL);
503   g_return_if_fail (accel_key > 0);
504   g_return_if_fail (gtk_accel_group_from_accel_closure (closure) == NULL);
505
506   g_object_ref (accel_group);
507   if (!closure->is_invalid)
508     quick_accel_add (accel_group,
509                      gdk_keyval_to_lower (accel_key),
510                      accel_mods, accel_flags, closure, 0);
511   g_object_unref (accel_group);
512 }
513
514 /**
515  * gtk_accel_group_connect_by_path:
516  * @accel_group:      the accelerator group to install an accelerator in
517  * @accel_path:       path used for determining key and modifiers.
518  * @closure:          closure to be executed upon accelerator activation
519  *
520  * Installs an accelerator in this group, using an accelerator path to look
521  * up the appropriate key and modifiers (see gtk_accel_map_add_entry()).
522  * When @accel_group is being activated in response to a call to
523  * gtk_accel_groups_activate(), @closure will be invoked if the @accel_key and
524  * @accel_mods from gtk_accel_groups_activate() match the key and modifiers
525  * for the path.
526  *
527  * The signature used for the @closure is that of #GtkAccelGroupActivate.
528  * 
529  * Note that @accel_path string will be stored in a #GQuark. Therefore, if you
530  * pass a static string, you can save some memory by interning it first with 
531  * g_intern_static_string().
532  */
533 void
534 gtk_accel_group_connect_by_path (GtkAccelGroup  *accel_group,
535                                  const gchar    *accel_path,
536                                  GClosure       *closure)
537 {
538   guint accel_key = 0;
539   GdkModifierType accel_mods = 0;
540   GtkAccelKey key;
541
542   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
543   g_return_if_fail (closure != NULL);
544   g_return_if_fail (_gtk_accel_path_is_valid (accel_path));
545
546   if (closure->is_invalid)
547     return;
548
549   g_object_ref (accel_group);
550
551   if (gtk_accel_map_lookup_entry (accel_path, &key))
552     {
553       accel_key = gdk_keyval_to_lower (key.accel_key);
554       accel_mods = key.accel_mods;
555     }
556
557   quick_accel_add (accel_group, accel_key, accel_mods, GTK_ACCEL_VISIBLE, closure,
558                    g_quark_from_string (accel_path));
559
560   g_object_unref (accel_group);
561 }
562
563 /**
564  * gtk_accel_group_disconnect:
565  * @accel_group: the accelerator group to remove an accelerator from
566  * @closure:     the closure to remove from this accelerator group
567  * @returns:     %TRUE if the closure was found and got disconnected
568  *
569  * Removes an accelerator previously installed through
570  * gtk_accel_group_connect().
571  */
572 gboolean
573 gtk_accel_group_disconnect (GtkAccelGroup *accel_group,
574                             GClosure      *closure)
575 {
576   guint i;
577
578   g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE);
579
580   for (i = 0; i < accel_group->n_accels; i++)
581     if (accel_group->priv_accels[i].closure == closure)
582       {
583         g_object_ref (accel_group);
584         quick_accel_remove (accel_group, i);
585         g_object_unref (accel_group);
586         return TRUE;
587       }
588   return FALSE;
589 }
590
591 /**
592  * gtk_accel_group_disconnect_key:
593  * @accel_group:      the accelerator group to install an accelerator in
594  * @accel_key:        key value of the accelerator
595  * @accel_mods:       modifier combination of the accelerator
596  * @returns:          %TRUE if there was an accelerator which could be 
597  *                    removed, %FALSE otherwise
598  *
599  * Removes an accelerator previously installed through
600  * gtk_accel_group_connect().
601  */
602 gboolean
603 gtk_accel_group_disconnect_key (GtkAccelGroup  *accel_group,
604                                 guint           accel_key,
605                                 GdkModifierType accel_mods)
606 {
607   GtkAccelGroupEntry *entries;
608   GSList *slist, *clist = NULL;
609   gboolean removed_one = FALSE;
610   guint n;
611
612   g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE);
613
614   g_object_ref (accel_group);
615   
616   accel_key = gdk_keyval_to_lower (accel_key);
617   entries = quick_accel_find (accel_group, accel_key, accel_mods, &n);
618   while (n--)
619     {
620       GClosure *closure = g_closure_ref (entries[n].closure);
621
622       clist = g_slist_prepend (clist, closure);
623     }
624
625   for (slist = clist; slist; slist = slist->next)
626     {
627       GClosure *closure = slist->data;
628
629       removed_one |= gtk_accel_group_disconnect (accel_group, closure);
630       g_closure_unref (closure);
631     }
632   g_slist_free (clist);
633
634   g_object_unref (accel_group);
635
636   return removed_one;
637 }
638
639 void
640 _gtk_accel_group_reconnect (GtkAccelGroup *accel_group,
641                             GQuark         accel_path_quark)
642 {
643   GSList *slist, *clist = NULL;
644   guint i;
645
646   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
647
648   g_object_ref (accel_group);
649
650   for (i = 0; i < accel_group->n_accels; i++)
651     if (accel_group->priv_accels[i].accel_path_quark == accel_path_quark)
652       {
653         GClosure *closure = g_closure_ref (accel_group->priv_accels[i].closure);
654
655         clist = g_slist_prepend (clist, closure);
656       }
657
658   for (slist = clist; slist; slist = slist->next)
659     {
660       GClosure *closure = slist->data;
661
662       gtk_accel_group_disconnect (accel_group, closure);
663       gtk_accel_group_connect_by_path (accel_group, g_quark_to_string (accel_path_quark), closure);
664       g_closure_unref (closure);
665     }
666   g_slist_free (clist);
667
668   g_object_unref (accel_group);
669 }
670
671 /**
672  * gtk_accel_group_query:
673  * @accel_group:      the accelerator group to query
674  * @accel_key:        key value of the accelerator
675  * @accel_mods:       modifier combination of the accelerator
676  * @n_entries:        location to return the number of entries found, or %NULL
677  * @returns:          an array of @n_entries #GtkAccelGroupEntry elements, or %NULL. The array is owned by GTK+ and must not be freed. 
678  *
679  * Queries an accelerator group for all entries matching @accel_key and 
680  * @accel_mods.
681  */
682 GtkAccelGroupEntry*
683 gtk_accel_group_query (GtkAccelGroup  *accel_group,
684                        guint           accel_key,
685                        GdkModifierType accel_mods,
686                        guint          *n_entries)
687 {
688   GtkAccelGroupEntry *entries;
689   guint n;
690
691   g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL);
692
693   entries = quick_accel_find (accel_group, gdk_keyval_to_lower (accel_key), accel_mods, &n);
694
695   if (n_entries)
696     *n_entries = entries ? n : 0;
697
698   return entries;
699 }
700
701 /**
702  * gtk_accel_group_from_accel_closure:
703  * @closure: a #GClosure
704  * @returns: the #GtkAccelGroup to which @closure is connected, or %NULL.
705  *
706  * Finds the #GtkAccelGroup to which @closure is connected; 
707  * see gtk_accel_group_connect().
708  */
709 GtkAccelGroup*
710 gtk_accel_group_from_accel_closure (GClosure *closure)
711 {
712   guint i;
713
714   g_return_val_if_fail (closure != NULL, NULL);
715
716   /* a few remarks on what we do here. in general, we need a way to reverse lookup
717    * accel_groups from closures that are being used in accel groups. this could
718    * be done e.g via a hashtable. it is however cheaper (memory wise) to just
719    * use the invalidation notifier on the closure itself (which we need to install
720    * anyway), that contains the accel group as data which, besides needing to peek
721    * a bit at closure internals, works just as good.
722    */
723   for (i = 0; i < G_CLOSURE_N_NOTIFIERS (closure); i++)
724     if (closure->notifiers[i].notify == accel_closure_invalidate)
725       return closure->notifiers[i].data;
726
727   return NULL;
728 }
729
730 /**
731  * gtk_accel_group_activate:
732  * @accel_group:   a #GtkAccelGroup
733  * @accel_quark:   the quark for the accelerator name
734  * @acceleratable: the #GObject, usually a #GtkWindow, on which
735  *                 to activate the accelerator.
736  * @accel_key:     accelerator keyval from a key event
737  * @accel_mods:    keyboard state mask from a key event
738  * @returns:       %TRUE if the accelerator was handled, %FALSE otherwise
739  * 
740  * Finds the first accelerator in @accel_group 
741  * that matches @accel_key and @accel_mods, and
742  * activates it.
743  *
744  * Returns: %TRUE if an accelerator was activated and handled this keypress
745  */
746 gboolean
747 gtk_accel_group_activate (GtkAccelGroup   *accel_group,
748                           GQuark           accel_quark,
749                           GObject         *acceleratable,
750                           guint            accel_key,
751                           GdkModifierType  accel_mods)
752 {
753   gboolean was_handled;
754
755   g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE);
756   g_return_val_if_fail (G_IS_OBJECT (acceleratable), FALSE);
757   
758   was_handled = FALSE;
759   g_signal_emit (accel_group, signal_accel_activate, accel_quark,
760                  acceleratable, accel_key, accel_mods, &was_handled);
761
762   return was_handled;
763 }
764
765 /**
766  * gtk_accel_groups_activate:
767  * @object:        the #GObject, usually a #GtkWindow, on which
768  *                 to activate the accelerator.
769  * @accel_key:     accelerator keyval from a key event
770  * @accel_mods:    keyboard state mask from a key event
771  * @returns:       %TRUE if the accelerator was handled, %FALSE otherwise
772  * 
773  * Finds the first accelerator in any #GtkAccelGroup attached
774  * to @object that matches @accel_key and @accel_mods, and
775  * activates that accelerator.
776  *
777  * Returns: %TRUE if an accelerator was activated and handled this keypress
778  */
779 gboolean
780 gtk_accel_groups_activate (GObject        *object,
781                            guint           accel_key,
782                            GdkModifierType accel_mods)
783 {
784   g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
785   
786   if (gtk_accelerator_valid (accel_key, accel_mods))
787     {
788       gchar *accel_name;
789       GQuark accel_quark;
790       GSList *slist;
791
792       accel_name = gtk_accelerator_name (accel_key, (accel_mods & gtk_accelerator_get_default_mod_mask ()));
793       accel_quark = g_quark_from_string (accel_name);
794       g_free (accel_name);
795       
796       for (slist = gtk_accel_groups_from_object (object); slist; slist = slist->next)
797         if (gtk_accel_group_activate (slist->data, accel_quark, object, accel_key, accel_mods))
798           return TRUE;
799     }
800   
801   return FALSE;
802 }
803
804 /**
805  * gtk_accelerator_valid:
806  * @keyval:    a GDK keyval
807  * @modifiers: modifier mask
808  * @returns:   %TRUE if the accelerator is valid
809  * 
810  * Determines whether a given keyval and modifier mask constitute
811  * a valid keyboard accelerator. For example, the #GDK_a keyval
812  * plus #GDK_CONTROL_MASK is valid - this is a "Ctrl+a" accelerator.
813  * But, you can't, for instance, use the #GDK_Control_L keyval
814  * as an accelerator.
815  */
816 gboolean
817 gtk_accelerator_valid (guint              keyval,
818                        GdkModifierType    modifiers)
819 {
820   static const guint invalid_accelerator_vals[] = {
821     GDK_Shift_L, GDK_Shift_R, GDK_Shift_Lock, GDK_Caps_Lock, GDK_ISO_Lock,
822     GDK_Control_L, GDK_Control_R, GDK_Meta_L, GDK_Meta_R,
823     GDK_Alt_L, GDK_Alt_R, GDK_Super_L, GDK_Super_R, GDK_Hyper_L, GDK_Hyper_R,
824     GDK_ISO_Level3_Shift, GDK_ISO_Next_Group, GDK_ISO_Prev_Group,
825     GDK_ISO_First_Group, GDK_ISO_Last_Group,
826     GDK_Mode_switch, GDK_Num_Lock, GDK_Multi_key,
827     GDK_Scroll_Lock, GDK_Sys_Req, 
828     GDK_Tab, GDK_ISO_Left_Tab, GDK_KP_Tab,
829     GDK_First_Virtual_Screen, GDK_Prev_Virtual_Screen,
830     GDK_Next_Virtual_Screen, GDK_Last_Virtual_Screen,
831     GDK_Terminate_Server, GDK_AudibleBell_Enable,
832     0
833   };
834   static const guint invalid_unmodified_vals[] = {
835     GDK_Up, GDK_Down, GDK_Left, GDK_Right,
836     GDK_KP_Up, GDK_KP_Down, GDK_KP_Left, GDK_KP_Right,
837     0
838   };
839   const guint *ac_val;
840
841   modifiers &= GDK_MODIFIER_MASK;
842     
843   if (keyval <= 0xFF)
844     return keyval >= 0x20;
845
846   ac_val = invalid_accelerator_vals;
847   while (*ac_val)
848     {
849       if (keyval == *ac_val++)
850         return FALSE;
851     }
852
853   if (!modifiers)
854     {
855       ac_val = invalid_unmodified_vals;
856       while (*ac_val)
857         {
858           if (keyval == *ac_val++)
859             return FALSE;
860         }
861     }
862   
863   return TRUE;
864 }
865
866 static inline gboolean
867 is_alt (const gchar *string)
868 {
869   return ((string[0] == '<') &&
870           (string[1] == 'a' || string[1] == 'A') &&
871           (string[2] == 'l' || string[2] == 'L') &&
872           (string[3] == 't' || string[3] == 'T') &&
873           (string[4] == '>'));
874 }
875
876 static inline gboolean
877 is_ctl (const gchar *string)
878 {
879   return ((string[0] == '<') &&
880           (string[1] == 'c' || string[1] == 'C') &&
881           (string[2] == 't' || string[2] == 'T') &&
882           (string[3] == 'l' || string[3] == 'L') &&
883           (string[4] == '>'));
884 }
885
886 static inline gboolean
887 is_modx (const gchar *string)
888 {
889   return ((string[0] == '<') &&
890           (string[1] == 'm' || string[1] == 'M') &&
891           (string[2] == 'o' || string[2] == 'O') &&
892           (string[3] == 'd' || string[3] == 'D') &&
893           (string[4] >= '1' && string[4] <= '5') &&
894           (string[5] == '>'));
895 }
896
897 static inline gboolean
898 is_ctrl (const gchar *string)
899 {
900   return ((string[0] == '<') &&
901           (string[1] == 'c' || string[1] == 'C') &&
902           (string[2] == 't' || string[2] == 'T') &&
903           (string[3] == 'r' || string[3] == 'R') &&
904           (string[4] == 'l' || string[4] == 'L') &&
905           (string[5] == '>'));
906 }
907
908 static inline gboolean
909 is_shft (const gchar *string)
910 {
911   return ((string[0] == '<') &&
912           (string[1] == 's' || string[1] == 'S') &&
913           (string[2] == 'h' || string[2] == 'H') &&
914           (string[3] == 'f' || string[3] == 'F') &&
915           (string[4] == 't' || string[4] == 'T') &&
916           (string[5] == '>'));
917 }
918
919 static inline gboolean
920 is_shift (const gchar *string)
921 {
922   return ((string[0] == '<') &&
923           (string[1] == 's' || string[1] == 'S') &&
924           (string[2] == 'h' || string[2] == 'H') &&
925           (string[3] == 'i' || string[3] == 'I') &&
926           (string[4] == 'f' || string[4] == 'F') &&
927           (string[5] == 't' || string[5] == 'T') &&
928           (string[6] == '>'));
929 }
930
931 static inline gboolean
932 is_control (const gchar *string)
933 {
934   return ((string[0] == '<') &&
935           (string[1] == 'c' || string[1] == 'C') &&
936           (string[2] == 'o' || string[2] == 'O') &&
937           (string[3] == 'n' || string[3] == 'N') &&
938           (string[4] == 't' || string[4] == 'T') &&
939           (string[5] == 'r' || string[5] == 'R') &&
940           (string[6] == 'o' || string[6] == 'O') &&
941           (string[7] == 'l' || string[7] == 'L') &&
942           (string[8] == '>'));
943 }
944
945 static inline gboolean
946 is_release (const gchar *string)
947 {
948   return ((string[0] == '<') &&
949           (string[1] == 'r' || string[1] == 'R') &&
950           (string[2] == 'e' || string[2] == 'E') &&
951           (string[3] == 'l' || string[3] == 'L') &&
952           (string[4] == 'e' || string[4] == 'E') &&
953           (string[5] == 'a' || string[5] == 'A') &&
954           (string[6] == 's' || string[6] == 'S') &&
955           (string[7] == 'e' || string[7] == 'E') &&
956           (string[8] == '>'));
957 }
958
959 static inline gboolean
960 is_meta (const gchar *string)
961 {
962   return ((string[0] == '<') &&
963           (string[1] == 'm' || string[1] == 'M') &&
964           (string[2] == 'e' || string[2] == 'E') &&
965           (string[3] == 't' || string[3] == 'T') &&
966           (string[4] == 'a' || string[4] == 'A') &&
967           (string[5] == '>'));
968 }
969
970 static inline gboolean
971 is_super (const gchar *string)
972 {
973   return ((string[0] == '<') &&
974           (string[1] == 's' || string[1] == 'S') &&
975           (string[2] == 'u' || string[2] == 'U') &&
976           (string[3] == 'p' || string[3] == 'P') &&
977           (string[4] == 'e' || string[4] == 'E') &&
978           (string[5] == 'r' || string[5] == 'R') &&
979           (string[6] == '>'));
980 }
981
982 static inline gboolean
983 is_hyper (const gchar *string)
984 {
985   return ((string[0] == '<') &&
986           (string[1] == 'h' || string[1] == 'H') &&
987           (string[2] == 'y' || string[2] == 'Y') &&
988           (string[3] == 'p' || string[3] == 'P') &&
989           (string[4] == 'e' || string[4] == 'E') &&
990           (string[5] == 'r' || string[5] == 'R') &&
991           (string[6] == '>'));
992 }
993
994 /**
995  * gtk_accelerator_parse:
996  * @accelerator:      string representing an accelerator
997  * @accelerator_key:  return location for accelerator keyval
998  * @accelerator_mods: return location for accelerator modifier mask
999  *
1000  * Parses a string representing an accelerator. The
1001  * format looks like "&lt;Control&gt;a" or "&lt;Shift&gt;&lt;Alt&gt;F1" or
1002  * "&lt;Release&gt;z" (the last one is for key release).
1003  * The parser is fairly liberal and allows lower or upper case,
1004  * and also abbreviations such as "&lt;Ctl&gt;" and "&lt;Ctrl&gt;".
1005  *
1006  * If the parse fails, @accelerator_key and @accelerator_mods will
1007  * be set to 0 (zero).
1008  */
1009 void
1010 gtk_accelerator_parse (const gchar     *accelerator,
1011                        guint           *accelerator_key,
1012                        GdkModifierType *accelerator_mods)
1013 {
1014   guint keyval;
1015   GdkModifierType mods;
1016   gint len;
1017   
1018   if (accelerator_key)
1019     *accelerator_key = 0;
1020   if (accelerator_mods)
1021     *accelerator_mods = 0;
1022   g_return_if_fail (accelerator != NULL);
1023   
1024   keyval = 0;
1025   mods = 0;
1026   len = strlen (accelerator);
1027   while (len)
1028     {
1029       if (*accelerator == '<')
1030         {
1031           if (len >= 9 && is_release (accelerator))
1032             {
1033               accelerator += 9;
1034               len -= 9;
1035               mods |= GDK_RELEASE_MASK;
1036             }
1037           else if (len >= 9 && is_control (accelerator))
1038             {
1039               accelerator += 9;
1040               len -= 9;
1041               mods |= GDK_CONTROL_MASK;
1042             }
1043           else if (len >= 7 && is_shift (accelerator))
1044             {
1045               accelerator += 7;
1046               len -= 7;
1047               mods |= GDK_SHIFT_MASK;
1048             }
1049           else if (len >= 6 && is_shft (accelerator))
1050             {
1051               accelerator += 6;
1052               len -= 6;
1053               mods |= GDK_SHIFT_MASK;
1054             }
1055           else if (len >= 6 && is_ctrl (accelerator))
1056             {
1057               accelerator += 6;
1058               len -= 6;
1059               mods |= GDK_CONTROL_MASK;
1060             }
1061           else if (len >= 6 && is_modx (accelerator))
1062             {
1063               static const guint mod_vals[] = {
1064                 GDK_MOD1_MASK, GDK_MOD2_MASK, GDK_MOD3_MASK,
1065                 GDK_MOD4_MASK, GDK_MOD5_MASK
1066               };
1067
1068               len -= 6;
1069               accelerator += 4;
1070               mods |= mod_vals[*accelerator - '1'];
1071               accelerator += 2;
1072             }
1073           else if (len >= 5 && is_ctl (accelerator))
1074             {
1075               accelerator += 5;
1076               len -= 5;
1077               mods |= GDK_CONTROL_MASK;
1078             }
1079           else if (len >= 5 && is_alt (accelerator))
1080             {
1081               accelerator += 5;
1082               len -= 5;
1083               mods |= GDK_MOD1_MASK;
1084             }
1085           else if (len >= 6 && is_meta (accelerator))
1086             {
1087               accelerator += 6;
1088               len -= 6;
1089               mods |= GDK_META_MASK;
1090             }
1091           else if (len >= 7 && is_hyper (accelerator))
1092             {
1093               accelerator += 7;
1094               len -= 7;
1095               mods |= GDK_HYPER_MASK;
1096             }
1097           else if (len >= 7 && is_super (accelerator))
1098             {
1099               accelerator += 7;
1100               len -= 7;
1101               mods |= GDK_SUPER_MASK;
1102             }
1103           else
1104             {
1105               gchar last_ch;
1106               
1107               last_ch = *accelerator;
1108               while (last_ch && last_ch != '>')
1109                 {
1110                   last_ch = *accelerator;
1111                   accelerator += 1;
1112                   len -= 1;
1113                 }
1114             }
1115         }
1116       else
1117         {
1118           keyval = gdk_keyval_from_name (accelerator);
1119           accelerator += len;
1120           len -= len;
1121         }
1122     }
1123   
1124   if (accelerator_key)
1125     *accelerator_key = gdk_keyval_to_lower (keyval);
1126   if (accelerator_mods)
1127     *accelerator_mods = mods;
1128 }
1129
1130 /**
1131  * gtk_accelerator_name:
1132  * @accelerator_key:  accelerator keyval
1133  * @accelerator_mods: accelerator modifier mask
1134  * 
1135  * Converts an accelerator keyval and modifier mask
1136  * into a string parseable by gtk_accelerator_parse().
1137  * For example, if you pass in #GDK_q and #GDK_CONTROL_MASK,
1138  * this function returns "&lt;Control&gt;q". 
1139  *
1140  * If you need to display accelerators in the user interface,
1141  * see gtk_accelerator_get_label().
1142  *
1143  * Returns: a newly-allocated accelerator name
1144  */
1145 gchar*
1146 gtk_accelerator_name (guint           accelerator_key,
1147                       GdkModifierType accelerator_mods)
1148 {
1149   static const gchar text_release[] = "<Release>";
1150   static const gchar text_shift[] = "<Shift>";
1151   static const gchar text_control[] = "<Control>";
1152   static const gchar text_mod1[] = "<Alt>";
1153   static const gchar text_mod2[] = "<Mod2>";
1154   static const gchar text_mod3[] = "<Mod3>";
1155   static const gchar text_mod4[] = "<Mod4>";
1156   static const gchar text_mod5[] = "<Mod5>";
1157   static const gchar text_meta[] = "<Meta>";
1158   static const gchar text_super[] = "<Super>";
1159   static const gchar text_hyper[] = "<Hyper>";
1160   guint l;
1161   gchar *keyval_name;
1162   gchar *accelerator;
1163
1164   accelerator_mods &= GDK_MODIFIER_MASK;
1165
1166   keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
1167   if (!keyval_name)
1168     keyval_name = "";
1169
1170   l = 0;
1171   if (accelerator_mods & GDK_RELEASE_MASK)
1172     l += sizeof (text_release) - 1;
1173   if (accelerator_mods & GDK_SHIFT_MASK)
1174     l += sizeof (text_shift) - 1;
1175   if (accelerator_mods & GDK_CONTROL_MASK)
1176     l += sizeof (text_control) - 1;
1177   if (accelerator_mods & GDK_MOD1_MASK)
1178     l += sizeof (text_mod1) - 1;
1179   if (accelerator_mods & GDK_MOD2_MASK)
1180     l += sizeof (text_mod2) - 1;
1181   if (accelerator_mods & GDK_MOD3_MASK)
1182     l += sizeof (text_mod3) - 1;
1183   if (accelerator_mods & GDK_MOD4_MASK)
1184     l += sizeof (text_mod4) - 1;
1185   if (accelerator_mods & GDK_MOD5_MASK)
1186     l += sizeof (text_mod5) - 1;
1187   l += strlen (keyval_name);
1188   if (accelerator_mods & GDK_META_MASK)
1189     l += sizeof (text_meta) - 1;
1190   if (accelerator_mods & GDK_HYPER_MASK)
1191     l += sizeof (text_hyper) - 1;
1192   if (accelerator_mods & GDK_SUPER_MASK)
1193     l += sizeof (text_super) - 1;
1194
1195   accelerator = g_new (gchar, l + 1);
1196
1197   l = 0;
1198   accelerator[l] = 0;
1199   if (accelerator_mods & GDK_RELEASE_MASK)
1200     {
1201       strcpy (accelerator + l, text_release);
1202       l += sizeof (text_release) - 1;
1203     }
1204   if (accelerator_mods & GDK_SHIFT_MASK)
1205     {
1206       strcpy (accelerator + l, text_shift);
1207       l += sizeof (text_shift) - 1;
1208     }
1209   if (accelerator_mods & GDK_CONTROL_MASK)
1210     {
1211       strcpy (accelerator + l, text_control);
1212       l += sizeof (text_control) - 1;
1213     }
1214   if (accelerator_mods & GDK_MOD1_MASK)
1215     {
1216       strcpy (accelerator + l, text_mod1);
1217       l += sizeof (text_mod1) - 1;
1218     }
1219   if (accelerator_mods & GDK_MOD2_MASK)
1220     {
1221       strcpy (accelerator + l, text_mod2);
1222       l += sizeof (text_mod2) - 1;
1223     }
1224   if (accelerator_mods & GDK_MOD3_MASK)
1225     {
1226       strcpy (accelerator + l, text_mod3);
1227       l += sizeof (text_mod3) - 1;
1228     }
1229   if (accelerator_mods & GDK_MOD4_MASK)
1230     {
1231       strcpy (accelerator + l, text_mod4);
1232       l += sizeof (text_mod4) - 1;
1233     }
1234   if (accelerator_mods & GDK_MOD5_MASK)
1235     {
1236       strcpy (accelerator + l, text_mod5);
1237       l += sizeof (text_mod5) - 1;
1238     }
1239   if (accelerator_mods & GDK_META_MASK)
1240     {
1241       strcpy (accelerator + l, text_meta);
1242       l += sizeof (text_meta) - 1;
1243     }
1244   if (accelerator_mods & GDK_HYPER_MASK)
1245     {
1246       strcpy (accelerator + l, text_hyper);
1247       l += sizeof (text_hyper) - 1;
1248     }
1249   if (accelerator_mods & GDK_SUPER_MASK)
1250     {
1251       strcpy (accelerator + l, text_super);
1252       l += sizeof (text_super) - 1;
1253     }
1254   strcpy (accelerator + l, keyval_name);
1255
1256   return accelerator;
1257 }
1258
1259 /**
1260  * gtk_accelerator_get_label:
1261  * @accelerator_key:  accelerator keyval
1262  * @accelerator_mods: accelerator modifier mask
1263  * 
1264  * Converts an accelerator keyval and modifier mask into a string 
1265  * which can be used to represent the accelerator to the user. 
1266  *
1267  * Returns: a newly-allocated string representing the accelerator.
1268  *
1269  * Since: 2.6
1270  */
1271 gchar*
1272 gtk_accelerator_get_label (guint           accelerator_key,
1273                            GdkModifierType accelerator_mods)
1274 {
1275   GtkAccelLabelClass *klass;
1276   gchar *label;
1277
1278   klass = g_type_class_ref (GTK_TYPE_ACCEL_LABEL);
1279   label = _gtk_accel_label_class_get_accelerator_label (klass, 
1280                                                         accelerator_key, 
1281                                                         accelerator_mods);
1282   g_type_class_unref (klass); /* klass is kept alive since gtk uses static types */
1283
1284   return label;
1285 }  
1286
1287 /**
1288  * gtk_accelerator_set_default_mod_mask:
1289  * @default_mod_mask: accelerator modifier mask
1290  *
1291  * Sets the modifiers that will be considered significant for keyboard
1292  * accelerators. The default mod mask is #GDK_CONTROL_MASK |
1293  * #GDK_SHIFT_MASK | #GDK_MOD1_MASK | #GDK_SUPER_MASK | 
1294  * #GDK_HYPER_MASK | #GDK_META_MASK, that is, Control, Shift, Alt, 
1295  * Super, Hyper and Meta. Other modifiers will by default be ignored 
1296  * by #GtkAccelGroup.
1297  * You must include at least the three modifiers Control, Shift
1298  * and Alt in any value you pass to this function.
1299  *
1300  * The default mod mask should be changed on application startup,
1301  * before using any accelerator groups.
1302  */
1303 void
1304 gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask)
1305 {
1306   default_accel_mod_mask = (default_mod_mask & GDK_MODIFIER_MASK) |
1307     (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK);
1308 }
1309
1310 /**
1311  * gtk_accelerator_get_default_mod_mask:
1312  * @returns: the default accelerator modifier mask
1313  *
1314  * Gets the value set by gtk_accelerator_set_default_mod_mask().
1315  */
1316 guint
1317 gtk_accelerator_get_default_mod_mask (void)
1318 {
1319   return default_accel_mod_mask;
1320 }
1321
1322 #define __GTK_ACCEL_GROUP_C__
1323 #include "gtkaliasdef.c"