source: trunk/third/gtk/gtk/gtkaccelgroup.c @ 14482

Revision 14482, 28.0 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * GtkAccelGroup: Accelerator manager for GtkObjects.
5 * Copyright (C) 1998 Tim Janik
6 *
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.
11 *
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.
16 *
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.
21 */
22
23/*
24 * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
25 * file for a list of people on the GTK+ Team.  See the ChangeLog
26 * files for a list of changes.  These files are distributed with
27 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 */
29
30#include <ctype.h>
31#include <string.h>
32#include "gtkaccelgroup.h"
33#include "gdk/gdkkeysyms.h"
34#include "gtksignal.h"
35#include "gtkwidget.h"
36
37
38/* --- signals --- */
39typedef void (*GtkSignalAddAccelerator)    (GtkObject       *object,
40                                            guint            accel_signal_id,
41                                            GtkAccelGroup   *accel_group,
42                                            guint            accel_key,
43                                            GdkModifierType  accel_mods,
44                                            GtkAccelFlags    accel_flags,
45                                            gpointer         func_data);
46typedef void (*GtkSignalRemoveAccelerator) (GtkObject       *object,
47                                            GtkAccelGroup   *accel_group,
48                                            guint            accel_key,
49                                            GdkModifierType  accel_mods,
50                                            gpointer         func_data);
51
52/* --- variables --- */
53static GtkAccelGroup    *default_accel_group = NULL;
54static guint             default_accel_mod_mask = (GDK_SHIFT_MASK |
55                                                   GDK_CONTROL_MASK |
56                                                   GDK_MOD1_MASK);
57static const gchar      *accel_groups_key = "gtk-accel-groups";
58static guint             accel_groups_key_id = 0;
59static const gchar      *accel_entries_key = "gtk-accel-entries";
60static guint             accel_entries_key_id = 0;
61static GHashTable       *accel_entry_hash_table = NULL;
62static GMemChunk        *accel_tables_mem_chunk = NULL;
63static GMemChunk        *accel_entries_mem_chunk = NULL;
64
65
66/* --- functions --- */
67static gint
68gtk_accel_entries_equal (gconstpointer a,
69                         gconstpointer b)
70{
71  const GtkAccelEntry *e1;
72  const GtkAccelEntry *e2;
73 
74  e1 = a;
75  e2 = b;
76 
77  return ((e1->accel_group == e2->accel_group) &&
78          (e1->accelerator_key == e2->accelerator_key) &&
79          (e1->accelerator_mods == e2->accelerator_mods));
80}
81
82static guint
83gtk_accel_entries_hash (gconstpointer a)
84{
85  const GtkAccelEntry *e;
86  guint h;
87 
88  e = a;
89 
90  h = (gulong) e->accel_group;
91  h ^= e->accelerator_key << 16;
92  h ^= e->accelerator_key >> 16;
93  h ^= e->accelerator_mods;
94 
95  return h;
96}
97
98GtkAccelGroup*
99gtk_accel_group_new (void)
100{
101  GtkAccelGroup *accel_group;
102 
103  if (!accel_groups_key_id)
104    {
105      accel_groups_key_id = g_quark_from_static_string (accel_groups_key);
106      accel_entries_key_id = g_quark_from_static_string (accel_entries_key);
107     
108      accel_entry_hash_table = g_hash_table_new (gtk_accel_entries_hash,
109                                                 gtk_accel_entries_equal);
110     
111      accel_tables_mem_chunk = g_mem_chunk_create (GtkAccelGroup, 8, G_ALLOC_AND_FREE);
112      accel_entries_mem_chunk = g_mem_chunk_create (GtkAccelEntry, 64, G_ALLOC_AND_FREE);
113    }
114 
115  accel_group = g_chunk_new (GtkAccelGroup, accel_tables_mem_chunk);
116 
117  accel_group->ref_count = 1;
118  accel_group->lock_count = 0;
119  accel_group->modifier_mask = gtk_accelerator_get_default_mod_mask ();
120  accel_group->attach_objects = NULL;
121 
122  return accel_group;
123}
124
125GtkAccelGroup*
126gtk_accel_group_get_default (void)
127{
128  if (!default_accel_group)
129    default_accel_group = gtk_accel_group_new ();
130 
131  return default_accel_group;
132}
133
134GtkAccelGroup*
135gtk_accel_group_ref (GtkAccelGroup      *accel_group)
136{
137  g_return_val_if_fail (accel_group != NULL, NULL);
138 
139  accel_group->ref_count += 1;
140 
141  return accel_group;
142}
143
144void
145gtk_accel_group_unref (GtkAccelGroup  *accel_group)
146{
147  g_return_if_fail (accel_group != NULL);
148  g_return_if_fail (accel_group->ref_count > 0);
149 
150  accel_group->ref_count -= 1;
151  if (accel_group->ref_count == 0)
152    {
153      g_return_if_fail (accel_group != default_accel_group);
154      g_return_if_fail (accel_group->attach_objects == NULL);
155     
156      g_chunk_free (accel_group, accel_tables_mem_chunk);
157    }
158}
159
160static void
161gtk_accel_group_object_destroy (GtkObject *object)
162{
163  GSList *free_list, *slist;
164 
165  free_list = gtk_object_get_data_by_id (object, accel_groups_key_id);
166  gtk_object_set_data_by_id (object, accel_groups_key_id, NULL);
167 
168  for (slist = free_list; slist; slist = slist->next)
169    {
170      GtkAccelGroup *accel_group;
171     
172      accel_group = slist->data;
173      accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, object);
174      gtk_accel_group_unref (accel_group);
175    }
176  g_slist_free (free_list);
177}
178
179void
180gtk_accel_group_attach (GtkAccelGroup   *accel_group,
181                        GtkObject       *object)
182{
183  GSList *slist;
184 
185  g_return_if_fail (accel_group != NULL);
186  g_return_if_fail (object != NULL);
187  g_return_if_fail (GTK_IS_OBJECT (object));
188  g_return_if_fail (g_slist_find (accel_group->attach_objects, object) == NULL);
189 
190  accel_group->attach_objects = g_slist_prepend (accel_group->attach_objects, object);
191  gtk_accel_group_ref (accel_group);
192  slist = gtk_object_get_data_by_id (object, accel_groups_key_id);
193  if (!slist)
194    gtk_signal_connect (object,
195                        "destroy",
196                        GTK_SIGNAL_FUNC (gtk_accel_group_object_destroy),
197                        NULL);
198  slist = g_slist_prepend (slist, accel_group);
199  gtk_object_set_data_by_id (object, accel_groups_key_id, slist);
200}
201
202void
203gtk_accel_group_detach (GtkAccelGroup   *accel_group,
204                        GtkObject       *object)
205{
206  GSList *slist;
207 
208  g_return_if_fail (accel_group != NULL);
209  g_return_if_fail (object != NULL);
210  g_return_if_fail (GTK_IS_OBJECT (object));
211  g_return_if_fail (g_slist_find (accel_group->attach_objects, object) != NULL);
212 
213  accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, object);
214  gtk_accel_group_unref (accel_group);
215  slist = gtk_object_get_data_by_id (object, accel_groups_key_id);
216  slist = g_slist_remove (slist, accel_group);
217  if (!slist)
218    gtk_signal_disconnect_by_func (object,
219                                   GTK_SIGNAL_FUNC (gtk_accel_group_object_destroy),
220                                   NULL);
221  gtk_object_set_data_by_id (object, accel_groups_key_id, slist);
222}
223
224void
225gtk_accel_group_lock (GtkAccelGroup      *accel_group)
226{
227  g_return_if_fail (accel_group != NULL);
228 
229  accel_group->lock_count += 1;
230}
231
232void
233gtk_accel_group_unlock (GtkAccelGroup  *accel_group)
234{
235  g_return_if_fail (accel_group != NULL);
236 
237  if (accel_group->lock_count)
238    accel_group->lock_count -= 1;
239}
240
241static GtkAccelEntry*
242gtk_accel_group_lookup (GtkAccelGroup   *accel_group,
243                        guint            accel_key,
244                        GdkModifierType  accel_mods)
245{
246  GtkAccelEntry key_entry = { 0 };
247 
248  key_entry.accel_group = accel_group;
249  key_entry.accelerator_key = gdk_keyval_to_lower (accel_key);
250  key_entry.accelerator_mods = accel_mods & accel_group->modifier_mask;
251 
252  return g_hash_table_lookup (accel_entry_hash_table, &key_entry);
253}
254
255gboolean
256gtk_accel_group_activate (GtkAccelGroup  *accel_group,
257                          guint           accel_key,
258                          GdkModifierType accel_mods)
259{
260  GtkAccelEntry *entry;
261 
262  g_return_val_if_fail (accel_group != NULL, FALSE);
263 
264  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
265  if (entry && entry->signal_id &&
266      (!GTK_IS_WIDGET (entry->object) || GTK_WIDGET_IS_SENSITIVE (entry->object)))
267    {
268      gtk_signal_emit (entry->object, entry->signal_id);
269      return TRUE;
270    }
271  return FALSE;
272}
273
274gboolean
275gtk_accel_groups_activate (GtkObject        *object,
276                           guint             accel_key,
277                           GdkModifierType   accel_mods)
278{
279  g_return_val_if_fail (object != NULL, FALSE);
280  g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE);
281 
282  if (gtk_accelerator_valid (accel_key, accel_mods))
283    {
284      GSList *slist;
285     
286      for (slist = gtk_accel_groups_from_object (object); slist; slist = slist->next)
287        if (gtk_accel_group_activate (slist->data, accel_key, accel_mods))
288          return TRUE;
289      return gtk_accel_group_activate (gtk_accel_group_get_default (), accel_key, accel_mods);
290    }
291 
292  return FALSE;
293}
294
295void
296gtk_accel_group_lock_entry (GtkAccelGroup        *accel_group,
297                            guint                 accel_key,
298                            GdkModifierType       accel_mods)
299{
300  GtkAccelEntry *entry;
301 
302  g_return_if_fail (accel_group != NULL);
303 
304  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
305  if (entry)
306    entry->accel_flags |= GTK_ACCEL_LOCKED;
307}
308
309void
310gtk_accel_group_unlock_entry (GtkAccelGroup     *accel_group,
311                              guint              accel_key,
312                              GdkModifierType    accel_mods)
313{
314  GtkAccelEntry *entry;
315 
316  g_return_if_fail (accel_group != NULL);
317 
318  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
319  if (entry)
320    entry->accel_flags &= ~GTK_ACCEL_LOCKED;
321}
322
323GtkAccelEntry*
324gtk_accel_group_get_entry (GtkAccelGroup    *accel_group,
325                           guint             accel_key,
326                           GdkModifierType   accel_mods)
327{
328  g_return_val_if_fail (accel_group != NULL, 0);
329 
330  return gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
331}
332
333void
334gtk_accel_group_add (GtkAccelGroup      *accel_group,
335                     guint               accel_key,
336                     GdkModifierType     accel_mods,
337                     GtkAccelFlags       accel_flags,
338                     GtkObject          *object,
339                     const gchar        *accel_signal)
340{
341  guint accel_signal_id = 0;
342  guint add_accelerator_signal_id = 0;
343  guint remove_accelerator_signal_id = 0;
344  gchar *signal;
345  GtkSignalQuery *query;
346  GSList *slist;
347  GSList *groups;
348  GSList *attach_objects;
349  GtkAccelEntry *entry;
350 
351  g_return_if_fail (accel_group != NULL);
352  g_return_if_fail (object != NULL);
353  g_return_if_fail (GTK_IS_OBJECT (object));
354  g_return_if_fail (accel_signal != NULL);
355 
356  /* check for required signals in the objects branch
357   */
358  signal = (gchar*) accel_signal;
359  accel_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object));
360  if (accel_signal_id)
361    {
362      signal = "add-accelerator";
363      add_accelerator_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object));
364    }
365  if (add_accelerator_signal_id)
366    {
367      signal = "remove-accelerator";
368      remove_accelerator_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object));
369    }
370  if (!accel_signal_id ||
371      !add_accelerator_signal_id ||
372      !remove_accelerator_signal_id)
373    {
374      g_warning ("gtk_accel_group_add(): could not find signal \"%s\""
375                 "in the `%s' class ancestry",
376                 signal,
377                 gtk_type_name (GTK_OBJECT_TYPE (object)));
378      return;
379    }
380  query = gtk_signal_query (accel_signal_id);
381  if (!query ||
382      query->nparams > 0)
383    {
384      g_warning ("gtk_accel_group_add(): signal \"%s\" in the `%s' class ancestry"
385                 "cannot be used as accelerator signal",
386                 accel_signal,
387                 gtk_type_name (GTK_OBJECT_TYPE (object)));
388      if (query)
389        g_free (query);
390
391      return;
392    }
393  g_free (query);
394
395  /* prematurely abort if the group/entry is already locked
396   */
397  if (accel_group->lock_count > 0)
398    return;
399  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
400  if (entry && entry->accel_flags & GTK_ACCEL_LOCKED)
401    return;
402 
403  /* make sure our structures stay alive
404   */
405  gtk_accel_group_ref (accel_group);
406  gtk_object_ref (object);
407 
408  /* remove an existing entry
409   */
410  if (entry)
411    gtk_signal_emit (entry->object, remove_accelerator_signal_id,
412                     accel_group,
413                     gdk_keyval_to_lower (accel_key),
414                     accel_mods & accel_group->modifier_mask);
415 
416  /* abort if the entry still exists
417   */
418  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
419  if (entry)
420    {
421      gtk_accel_group_unref (accel_group);
422      gtk_object_unref (object);
423     
424      return;
425    }
426 
427  /* collect accel groups and remove existing entries
428   */
429  attach_objects = accel_group->attach_objects;
430  groups = NULL;
431  for (attach_objects = accel_group->attach_objects; attach_objects; attach_objects = attach_objects->next)
432    {
433      GSList *tmp_groups;
434     
435      tmp_groups = gtk_object_get_data_by_id (attach_objects->data, accel_groups_key_id);
436      while (tmp_groups)
437        {
438          groups = g_slist_prepend (groups, tmp_groups->data);
439          gtk_accel_group_ref (tmp_groups->data);
440          tmp_groups = tmp_groups->next;
441        }
442    }
443  for (slist = groups; slist; slist = slist->next)
444    {
445      GtkAccelGroup *tmp_group;
446     
447      tmp_group = slist->data;
448     
449      /* we only remove the accelerator if neccessary
450       */
451      if (tmp_group->lock_count == 0)
452        {
453          entry = gtk_accel_group_lookup (tmp_group, accel_key, accel_mods);
454          if (entry && !(entry->accel_flags & GTK_ACCEL_LOCKED))
455            gtk_signal_emit (entry->object, remove_accelerator_signal_id,
456                             tmp_group,
457                             gdk_keyval_to_lower (accel_key),
458                             accel_mods & tmp_group->modifier_mask);
459        }
460      gtk_accel_group_unref (tmp_group);
461    }
462  g_slist_free (groups);
463 
464  /* now install the new accelerator
465   */
466  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
467  if (!entry)
468    gtk_signal_emit (object, add_accelerator_signal_id,
469                     accel_signal_id,
470                     accel_group,
471                     gdk_keyval_to_lower (accel_key),
472                     accel_mods & accel_group->modifier_mask,
473                     accel_flags & GTK_ACCEL_MASK);
474 
475  /* and release the structures again
476   */
477  gtk_accel_group_unref (accel_group);
478  gtk_object_unref (object);
479}
480
481static void
482gtk_accel_group_delete_entries (GtkObject *object)
483{
484  GSList *free_slist, *slist;
485 
486  gtk_signal_disconnect_by_func (object,
487                                 GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries),
488                                 NULL);
489
490  /* we remove all entries of this object the hard
491   * way (i.e. without signal emission).
492   */
493  free_slist = gtk_object_get_data_by_id (object, accel_entries_key_id);
494  gtk_object_set_data_by_id (object, accel_entries_key_id, NULL);
495  for (slist = free_slist; slist; slist = slist->next)
496    {
497      GtkAccelEntry *entry;
498     
499      entry = slist->data;
500     
501      g_hash_table_remove (accel_entry_hash_table, entry);
502      gtk_accel_group_unref (entry->accel_group);
503      g_chunk_free (entry, accel_entries_mem_chunk);
504    }
505  g_slist_free (free_slist);
506}
507
508void
509gtk_accel_group_handle_add (GtkObject         *object,
510                            guint              accel_signal_id,
511                            GtkAccelGroup     *accel_group,
512                            guint              accel_key,
513                            GdkModifierType    accel_mods,
514                            GtkAccelFlags      accel_flags)
515{
516  GtkAccelEntry *entry;
517 
518  g_return_if_fail (object != NULL);
519  g_return_if_fail (GTK_IS_OBJECT (object));
520  g_return_if_fail (accel_group != NULL);
521  g_return_if_fail (accel_signal_id > 0);
522
523  if (!gtk_accelerator_valid (accel_key, accel_mods))
524    return;
525 
526  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
527  if (!entry)
528    {
529      GSList *slist;
530     
531      gtk_accel_group_ref (accel_group);
532     
533      entry = g_chunk_new (GtkAccelEntry, accel_entries_mem_chunk);
534      entry->accel_group = accel_group;
535      entry->accelerator_key = gdk_keyval_to_lower (accel_key);
536      entry->accelerator_mods = accel_mods & accel_group->modifier_mask;
537      entry->accel_flags = accel_flags & GTK_ACCEL_MASK;
538      entry->object = object;
539      entry->signal_id = accel_signal_id;
540     
541      g_hash_table_insert (accel_entry_hash_table, entry, entry);
542     
543      slist = gtk_object_get_data_by_id (object, accel_entries_key_id);
544      if (!slist)
545        gtk_signal_connect (object,
546                            "destroy",
547                            GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries),
548                            NULL);
549      slist = g_slist_prepend (slist, entry);
550      gtk_object_set_data_by_id (object, accel_entries_key_id, slist);
551    }
552}
553
554void
555gtk_accel_group_remove (GtkAccelGroup     *accel_group,
556                        guint              accel_key,
557                        GdkModifierType    accel_mods,
558                        GtkObject         *object)
559{
560  GtkAccelEntry *entry;
561  guint remove_accelerator_signal_id = 0;
562 
563  g_return_if_fail (accel_group != NULL);
564  g_return_if_fail (object != NULL);
565  g_return_if_fail (GTK_IS_OBJECT (object));
566 
567  /* check for required signals in the objects branch
568   */
569  remove_accelerator_signal_id = gtk_signal_lookup ("remove-accelerator", GTK_OBJECT_TYPE (object));
570  if (!remove_accelerator_signal_id)
571    {
572      g_warning ("gtk_accel_group_remove(): could not find signal \"%s\""
573                 "in the `%s' class ancestry",
574                 "remove-accelerator",
575                 gtk_type_name (GTK_OBJECT_TYPE (object)));
576      return;
577    }
578 
579  /* prematurely abort if the entry is locked
580   */
581  if (accel_group->lock_count > 0)
582    return;
583  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
584  if (!entry ||
585      entry->accel_flags & GTK_ACCEL_LOCKED)
586    return;
587  if (entry->object != object)
588    {
589      g_warning ("gtk_accel_group_remove(): invalid object reference for accel-group entry");
590      return;
591    }
592 
593  /* make sure our structures stay alive
594   */
595  gtk_accel_group_ref (accel_group);
596  gtk_object_ref (object);
597 
598  /* remove the entry
599   */
600  gtk_signal_emit (entry->object, remove_accelerator_signal_id,
601                   accel_group,
602                   gdk_keyval_to_lower (accel_key),
603                   accel_mods & accel_group->modifier_mask);
604 
605  /* and release the structures again
606   */
607  gtk_accel_group_unref (accel_group);
608  gtk_object_unref (object);
609}
610
611void
612gtk_accel_group_handle_remove (GtkObject         *object,
613                               GtkAccelGroup     *accel_group,
614                               guint              accel_key,
615                               GdkModifierType    accel_mods)
616{
617  GtkAccelEntry *entry;
618 
619  g_return_if_fail (object != NULL);
620  g_return_if_fail (GTK_IS_OBJECT (object));
621  g_return_if_fail (accel_group != NULL);
622 
623  entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods);
624  if (entry)
625    {
626      if (entry->object == object)
627        {
628          GSList *slist;
629         
630          g_hash_table_remove (accel_entry_hash_table, entry);
631         
632          slist = gtk_object_get_data_by_id (object, accel_entries_key_id);
633          if (slist)
634            {
635              slist = g_slist_remove (slist, entry);
636              if (!slist)
637                gtk_signal_disconnect_by_func (object,
638                                               GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries),
639                                               NULL);
640              gtk_object_set_data_by_id (object, accel_entries_key_id, slist);
641             
642              gtk_accel_group_unref (accel_group);
643             
644              g_chunk_free (entry, accel_entries_mem_chunk);
645            }
646        }
647      else
648        g_warning ("gtk_accel_group_handle_remove(): invalid object reference for accel-group entry");
649    }
650  else
651    g_warning ("gtk_accel_group_handle_remove(): attempt to remove unexisting accel-group entry");
652}
653
654guint
655gtk_accel_group_create_add (GtkType          class_type,
656                            GtkSignalRunType signal_flags,
657                            guint            handler_offset)
658{
659  g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_OBJECT), 0);
660
661  return gtk_signal_new ("add-accelerator",
662                         signal_flags,
663                         class_type,
664                         handler_offset,
665                         gtk_marshal_NONE__UINT_POINTER_UINT_UINT_ENUM,
666                         GTK_TYPE_NONE, 5,
667                         GTK_TYPE_UINT,
668                         GTK_TYPE_ACCEL_GROUP,
669                         GTK_TYPE_UINT,
670                         GTK_TYPE_GDK_MODIFIER_TYPE,
671                         GTK_TYPE_ACCEL_FLAGS);
672}
673
674guint
675gtk_accel_group_create_remove (GtkType          class_type,
676                               GtkSignalRunType signal_flags,
677                               guint            handler_offset)
678{
679  g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_OBJECT), 0);
680
681  return gtk_signal_new ("remove-accelerator",
682                         signal_flags,
683                         class_type,
684                         handler_offset,
685                         gtk_marshal_NONE__POINTER_UINT_UINT,
686                         GTK_TYPE_NONE, 3,
687                         GTK_TYPE_ACCEL_GROUP,
688                         GTK_TYPE_UINT,
689                         GTK_TYPE_GDK_MODIFIER_TYPE);
690}
691
692GSList*
693gtk_accel_groups_from_object (GtkObject      *object)
694{
695  g_return_val_if_fail (object != NULL, NULL);
696  g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
697 
698  return gtk_object_get_data_by_id (object, accel_groups_key_id);
699}
700
701GSList*
702gtk_accel_group_entries_from_object (GtkObject       *object)
703{
704  g_return_val_if_fail (object != NULL, NULL);
705  g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
706 
707  return gtk_object_get_data_by_id (object, accel_entries_key_id);
708}
709
710gboolean
711gtk_accelerator_valid (guint              keyval,
712                       GdkModifierType    modifiers)
713{
714  static const guint invalid_accelerator_vals[] = {
715    GDK_BackSpace, GDK_Delete, GDK_KP_Delete,
716    GDK_Shift_L, GDK_Shift_R, GDK_Shift_Lock, GDK_Caps_Lock, GDK_ISO_Lock,
717    GDK_Control_L, GDK_Control_R, GDK_Meta_L, GDK_Meta_R,
718    GDK_Alt_L, GDK_Alt_R, GDK_Super_L, GDK_Super_R, GDK_Hyper_L, GDK_Hyper_R,
719    GDK_Mode_switch, GDK_Num_Lock, GDK_Multi_key,
720    GDK_Scroll_Lock, GDK_Sys_Req,
721    GDK_Up, GDK_Down, GDK_Left, GDK_Right, GDK_Tab, GDK_ISO_Left_Tab,
722    GDK_KP_Up, GDK_KP_Down, GDK_KP_Left, GDK_KP_Right, GDK_KP_Tab,
723    GDK_First_Virtual_Screen, GDK_Prev_Virtual_Screen,
724    GDK_Next_Virtual_Screen, GDK_Last_Virtual_Screen,
725    GDK_Terminate_Server, GDK_AudibleBell_Enable,
726    0
727  };
728  const guint *ac_val;
729
730  modifiers &= GDK_MODIFIER_MASK;
731   
732  if (keyval <= 0xFF)
733    return keyval >= 0x20;
734
735  ac_val = invalid_accelerator_vals;
736  while (*ac_val)
737    {
738      if (keyval == *ac_val++)
739        return FALSE;
740    }
741
742  return TRUE;
743}
744
745static inline gboolean
746is_alt (const gchar *string)
747{
748  return ((string[0] == '<') &&
749          (string[1] == 'a' || string[1] == 'A') &&
750          (string[2] == 'l' || string[2] == 'L') &&
751          (string[3] == 't' || string[3] == 'T') &&
752          (string[4] == '>'));
753}
754
755static inline gboolean
756is_ctl (const gchar *string)
757{
758  return ((string[0] == '<') &&
759          (string[1] == 'c' || string[1] == 'C') &&
760          (string[2] == 't' || string[2] == 'T') &&
761          (string[3] == 'l' || string[3] == 'L') &&
762          (string[4] == '>'));
763}
764
765static inline gboolean
766is_modx (const gchar *string)
767{
768  return ((string[0] == '<') &&
769          (string[1] == 'm' || string[1] == 'M') &&
770          (string[2] == 'o' || string[2] == 'O') &&
771          (string[3] == 'd' || string[3] == 'D') &&
772          (string[4] >= '1' && string[4] <= '5') &&
773          (string[5] == '>'));
774}
775
776static inline gboolean
777is_ctrl (const gchar *string)
778{
779  return ((string[0] == '<') &&
780          (string[1] == 'c' || string[1] == 'C') &&
781          (string[2] == 't' || string[2] == 'T') &&
782          (string[3] == 'r' || string[3] == 'R') &&
783          (string[4] == 'l' || string[4] == 'L') &&
784          (string[5] == '>'));
785}
786
787static inline gboolean
788is_shft (const gchar *string)
789{
790  return ((string[0] == '<') &&
791          (string[1] == 's' || string[1] == 'S') &&
792          (string[2] == 'h' || string[2] == 'H') &&
793          (string[3] == 'f' || string[3] == 'F') &&
794          (string[4] == 't' || string[4] == 'T') &&
795          (string[5] == '>'));
796}
797
798static inline gboolean
799is_shift (const gchar *string)
800{
801  return ((string[0] == '<') &&
802          (string[1] == 's' || string[1] == 'S') &&
803          (string[2] == 'h' || string[2] == 'H') &&
804          (string[3] == 'i' || string[3] == 'I') &&
805          (string[4] == 'f' || string[4] == 'F') &&
806          (string[5] == 't' || string[5] == 'T') &&
807          (string[6] == '>'));
808}
809
810static inline gboolean
811is_control (const gchar *string)
812{
813  return ((string[0] == '<') &&
814          (string[1] == 'c' || string[1] == 'C') &&
815          (string[2] == 'o' || string[2] == 'O') &&
816          (string[3] == 'n' || string[3] == 'N') &&
817          (string[4] == 't' || string[4] == 'T') &&
818          (string[5] == 'r' || string[5] == 'R') &&
819          (string[6] == 'o' || string[6] == 'O') &&
820          (string[7] == 'l' || string[7] == 'L') &&
821          (string[8] == '>'));
822}
823
824static inline gboolean
825is_release (const gchar *string)
826{
827  return ((string[0] == '<') &&
828          (string[1] == 'r' || string[1] == 'R') &&
829          (string[2] == 'e' || string[2] == 'E') &&
830          (string[3] == 'l' || string[3] == 'L') &&
831          (string[4] == 'e' || string[4] == 'E') &&
832          (string[5] == 'a' || string[5] == 'A') &&
833          (string[6] == 's' || string[6] == 'S') &&
834          (string[7] == 'e' || string[7] == 'E') &&
835          (string[8] == '>'));
836}
837
838void
839gtk_accelerator_parse (const gchar    *accelerator,
840                       guint          *accelerator_key,
841                       GdkModifierType*accelerator_mods)
842{
843  guint keyval;
844  GdkModifierType mods;
845  gint len;
846 
847  if (accelerator_key)
848    *accelerator_key = 0;
849  if (accelerator_mods)
850    *accelerator_mods = 0;
851  g_return_if_fail (accelerator != NULL);
852 
853  keyval = 0;
854  mods = 0;
855  len = strlen (accelerator);
856  while (len)
857    {
858      if (*accelerator == '<')
859        {
860          if (len >= 9 && is_release (accelerator))
861            {
862              accelerator += 9;
863              len -= 9;
864              mods |= GDK_RELEASE_MASK;
865            }
866          else if (len >= 9 && is_control (accelerator))
867            {
868              accelerator += 9;
869              len -= 9;
870              mods |= GDK_CONTROL_MASK;
871            }
872          else if (len >= 7 && is_shift (accelerator))
873            {
874              accelerator += 7;
875              len -= 7;
876              mods |= GDK_SHIFT_MASK;
877            }
878          else if (len >= 6 && is_shft (accelerator))
879            {
880              accelerator += 6;
881              len -= 6;
882              mods |= GDK_SHIFT_MASK;
883            }
884          else if (len >= 6 && is_ctrl (accelerator))
885            {
886              accelerator += 6;
887              len -= 6;
888              mods |= GDK_CONTROL_MASK;
889            }
890          else if (len >= 6 && is_modx (accelerator))
891            {
892              static const guint mod_vals[] = {
893                GDK_MOD1_MASK, GDK_MOD2_MASK, GDK_MOD3_MASK,
894                GDK_MOD4_MASK, GDK_MOD5_MASK
895              };
896
897              len -= 6;
898              accelerator += 4;
899              mods |= mod_vals[*accelerator - '1'];
900              accelerator += 2;
901            }
902          else if (len >= 5 && is_ctl (accelerator))
903            {
904              accelerator += 5;
905              len -= 5;
906              mods |= GDK_CONTROL_MASK;
907            }
908          else if (len >= 5 && is_alt (accelerator))
909            {
910              accelerator += 5;
911              len -= 5;
912              mods |= GDK_MOD1_MASK;
913            }
914          else
915            {
916              gchar last_ch;
917             
918              last_ch = *accelerator;
919              while (last_ch && last_ch != '>')
920                {
921                  last_ch = *accelerator;
922                  accelerator += 1;
923                  len -= 1;
924                }
925            }
926        }
927      else
928        {
929          keyval = gdk_keyval_from_name (accelerator);
930          accelerator += len;
931          len -= len;
932        }
933    }
934 
935  if (accelerator_key)
936    *accelerator_key = gdk_keyval_to_lower (keyval);
937  if (accelerator_mods)
938    *accelerator_mods = mods;
939}
940
941gchar*
942gtk_accelerator_name (guint           accelerator_key,
943                      GdkModifierType accelerator_mods)
944{
945  static const gchar text_release[] = "<Release>";
946  static const gchar text_shift[] = "<Shift>";
947  static const gchar text_control[] = "<Control>";
948  static const gchar text_mod1[] = "<Alt>";
949  static const gchar text_mod2[] = "<Mod2>";
950  static const gchar text_mod3[] = "<Mod3>";
951  static const gchar text_mod4[] = "<Mod4>";
952  static const gchar text_mod5[] = "<Mod5>";
953  guint l;
954  gchar *keyval_name;
955  gchar *accelerator;
956
957  accelerator_mods &= GDK_MODIFIER_MASK;
958
959  keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
960  if (!keyval_name)
961    keyval_name = "";
962
963  l = 0;
964  if (accelerator_mods & GDK_RELEASE_MASK)
965    l += sizeof (text_release) - 1;
966  if (accelerator_mods & GDK_SHIFT_MASK)
967    l += sizeof (text_shift) - 1;
968  if (accelerator_mods & GDK_CONTROL_MASK)
969    l += sizeof (text_control) - 1;
970  if (accelerator_mods & GDK_MOD1_MASK)
971    l += sizeof (text_mod1) - 1;
972  if (accelerator_mods & GDK_MOD2_MASK)
973    l += sizeof (text_mod2) - 1;
974  if (accelerator_mods & GDK_MOD3_MASK)
975    l += sizeof (text_mod3) - 1;
976  if (accelerator_mods & GDK_MOD4_MASK)
977    l += sizeof (text_mod4) - 1;
978  if (accelerator_mods & GDK_MOD5_MASK)
979    l += sizeof (text_mod5) - 1;
980  l += strlen (keyval_name);
981
982  accelerator = g_new (gchar, l + 1);
983
984  l = 0;
985  accelerator[l] = 0;
986  if (accelerator_mods & GDK_RELEASE_MASK)
987    {
988      strcpy (accelerator + l, text_release);
989      l += sizeof (text_release) - 1;
990    }
991  if (accelerator_mods & GDK_SHIFT_MASK)
992    {
993      strcpy (accelerator + l, text_shift);
994      l += sizeof (text_shift) - 1;
995    }
996  if (accelerator_mods & GDK_CONTROL_MASK)
997    {
998      strcpy (accelerator + l, text_control);
999      l += sizeof (text_control) - 1;
1000    }
1001  if (accelerator_mods & GDK_MOD1_MASK)
1002    {
1003      strcpy (accelerator + l, text_mod1);
1004      l += sizeof (text_mod1) - 1;
1005    }
1006  if (accelerator_mods & GDK_MOD2_MASK)
1007    {
1008      strcpy (accelerator + l, text_mod2);
1009      l += sizeof (text_mod2) - 1;
1010    }
1011  if (accelerator_mods & GDK_MOD3_MASK)
1012    {
1013      strcpy (accelerator + l, text_mod3);
1014      l += sizeof (text_mod3) - 1;
1015    }
1016  if (accelerator_mods & GDK_MOD4_MASK)
1017    {
1018      strcpy (accelerator + l, text_mod4);
1019      l += sizeof (text_mod4) - 1;
1020    }
1021  if (accelerator_mods & GDK_MOD5_MASK)
1022    {
1023      strcpy (accelerator + l, text_mod5);
1024      l += sizeof (text_mod5) - 1;
1025    }
1026  strcpy (accelerator + l, keyval_name);
1027
1028  return accelerator;
1029}
1030
1031void
1032gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask)
1033{
1034  default_accel_mod_mask = default_mod_mask & GDK_MODIFIER_MASK;
1035}
1036
1037guint
1038gtk_accelerator_get_default_mod_mask (void)
1039{
1040  return default_accel_mod_mask;
1041}
Note: See TracBrowser for help on using the repository browser.