diff options
author | Tim Janik <timj@gtk.org> | 1998-06-07 06:48:56 +0000 |
---|---|---|
committer | Tim Janik <timj@src.gnome.org> | 1998-06-07 06:48:56 +0000 |
commit | a391196ba51da34253593712e8bf4552c04f19e5 (patch) | |
tree | 50c2edfc5d066467f3c33c1f82c89dd9923c44c4 /gtk/gtkaccelgroup.c | |
parent | f522f36dd1c484b133ba6b04027667aa9144ad04 (diff) | |
download | gdk-pixbuf-a391196ba51da34253593712e8bf4552c04f19e5.tar.gz |
fixed an assertment.
Sat Jun 6 06:01:24 1998 Tim Janik <timj@gtk.org>
* gtk/gtksignal.c (gtk_signal_emitv): fixed an assertment.
* gtk/makeenums.awk: a script to generate the GtkEnumValue arrays from,
this should eventually be done by gentypeinfo.el somewhen.
* gtk/gtkenumvalues.c: new generated file to hold GtkEnumValue arrays.
* gtk/gtktypeutils.h: new function gtk_enum_values() to retrive all the
enum values of an enum type.
* gtk/gtk.defs:
* gtk/gtkcurve.h:
* gtk/gtkobject.h:
* gtk/gtkprivate.h:
* gtk/gtkwidget.h:
* gtk/gtkenums.h:
brought enum/flags definitions in sync, added a few more enum
definitions for bindings and pattern matching.
* some more macro and GtkType fixups in various places.
* gdk/gdktypes.h (enum): added a new value GDK_AFTER_MASK, which is used
as a key-release modifier for the binding system.
Fri Jun 5 06:06:06 1998 Tim Janik <timj@gtk.org>
* gtk/gtkmenu.h (struct _GtkMenu): removed GList*children, since it
was a stale list pointer that is already present in GtkMenuShell.
* gtk/gtkmenushell.h (struct _GtkMenuShellClass): added a signal
GtkMenuShell::selection_done which is emitted after the menu shell
poped down again and all possible menu items have been activated.
Thu Jun 4 02:20:42 1998 Tim Janik <timj@gtk.org>
* gtk/gtkmenushell.c (gtk_menu_shell_button_release): flush the x-queue
before activation of the menuitem, so the menu is actually taken off the
screen prior to any menu item activation.
* gtk/gtkctree.c (gtk_ctree_get_row_data): allow function invokation
for NULL nodes.
* gtk/gtkwidget.h:
* gtk/gtkwidget.c: new function gtk_widget_stop_accelerator to stop
the emission of the "add-accelerator" signal on a widget. this is
usefull to prevent accelerator installation on certain widgets.
* gtk/gtknotebook.c (gtk_notebook_menu_item_create): keep the menu
labels left justified, by setting their alignment. stop accelerator
installation for the menu items, since we use dynamic menus.
Wed Jun 3 06:41:22 1998 Tim Janik <timj@gtk.org>
* gtk/gtkmenufactory.c: adaptions to use the new accel groups. people
should *really* use GtkItemFactory. this is only for preserving source
compatibility where possible, use of GtkMenuFactory is deprecated as of
now.
* gtk/gtkobject.h (gtk_object_class_add_user_signal): new function
to create user signals of type GTK_RUN_NO_RECURSE. don't know why i
missed this possibility when i added gtk_object_class_add_user_signal
in late january.
* gtk/gtkmain.c (gtk_init): ignore subsequent function calls.
Sun May 31 07:31:09 1998 Tim Janik <timj@gtk.org>
* gtk/gtkaccelgroup.h:
* gtk/gtkaccelgroup.c: new implementation of the accelerator concept.
* gtk/gtkaccellabel.h:
* gtk/gtkaccellabel.c: new widget derived from GtkLabel whitch features
display of the accelerators associated with a certain widget.
* gtk/gtkitemfactory.h:
* gtk/gtkitemfactory.c: new widget, item factory with automatic rc
parsing and accelerator handling.
* gtk/gtkmenu.c (gtk_menu_reposition): new function to care for
positioning a menu.
(gtk_menu_map): removed the allocation code.
(gtk_menu_size_allocate): care for redrawing of children and resize
our widget->window correctly.
(gtk_menu_key_press): feature the new accelerator groups.
* gtk/gtkmenuitem.c (gtk_menu_item_size_allocate): reposition the
submenu if neccessary.
* gtk/gtkmenuitem.c:
* gtk/gtkcheckmenuitem.c:
* gtk/gtkradiomenuitem.c: use GtkAccelLabel in the *_new_with_label()
function variants.
* gdk/gdk.c:
(gdk_keyval_from_name):
(gdk_keyval_name): new functions for keyval<->key-name associations.
(gdk_keyval_to_upper):
(gdk_keyval_to_lower):
(gdk_keyval_is_upper):
(gdk_keyval_is_lower): new functions to check/translate keyvalues with
regards to their cases.
Wed May 27 00:48:10 1998 Tim Janik <timj@gtk.org>
* gtk/gtkwidget.c (gtk_widget_class_path): new function to calculate a
widget's class path.
(gtk_widget_path): new function to calculate a widget's name path.
* gtk/gtkrc.c: newly introduced GtkPatternSpec structures to speed up
pattern matching, features reversed pattern matches.
Diffstat (limited to 'gtk/gtkaccelgroup.c')
-rw-r--r-- | gtk/gtkaccelgroup.c | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c new file mode 100644 index 000000000..bfba69c6e --- /dev/null +++ b/gtk/gtkaccelgroup.c @@ -0,0 +1,1062 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkAccelGroup: Accelerator manager for GtkObjects. + * Copyright (C) 1998 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include <ctype.h> +#include <strings.h> +#include "gtkaccelgroup.h" +#include "gdk/gdkkeysyms.h" +#include "gtksignal.h" +#include "gtkwidget.h" + + +/* --- signals --- */ +typedef void (*GtkSignalAddAccelerator) (GtkObject *object, + guint accel_signal_id, + GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods, + GtkAccelFlags accel_flags, + gpointer func_data); +typedef void (*GtkSignalRemoveAccelerator) (GtkObject *object, + GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods, + gpointer func_data); + +/* --- variables --- */ +static GtkAccelGroup *default_accel_group = NULL; +static guint default_accel_mod_mask = (GDK_SHIFT_MASK | + GDK_CONTROL_MASK | + GDK_MOD1_MASK); +static const gchar *accel_groups_key = "gtk-accel-groups"; +static guint accel_groups_key_id = 0; +static const gchar *accel_entries_key = "gtk-accel-entries"; +static guint accel_entries_key_id = 0; +static GHashTable *accel_entry_hash_table = NULL; +static GMemChunk *accel_tables_mem_chunk = NULL; +static GMemChunk *accel_entries_mem_chunk = NULL; + + +/* --- functions --- */ +static gint +gtk_accel_entries_equal (gpointer a, + gpointer b) +{ + GtkAccelEntry *e1; + GtkAccelEntry *e2; + + e1 = a; + e2 = b; + + return ((e1->accel_group == e2->accel_group) && + (e1->accelerator_key == e2->accelerator_key) && + (e1->accelerator_mods == e2->accelerator_mods)); +} + +static guint +gtk_accel_entries_hash (gpointer a) +{ + GtkAccelEntry *e; + guint h; + + e = a; + + h = (gulong) e->accel_group; + h ^= e->accelerator_key << 16; + h ^= e->accelerator_key >> 16; + h ^= e->accelerator_mods; + + return h; +} + +GtkAccelGroup* +gtk_accel_group_new (void) +{ + GtkAccelGroup *accel_group; + + if (!accel_groups_key_id) + { + accel_groups_key_id = gtk_object_data_force_id (accel_groups_key); + accel_entries_key_id = gtk_object_data_force_id (accel_entries_key); + + accel_entry_hash_table = g_hash_table_new (gtk_accel_entries_hash, + gtk_accel_entries_equal); + + accel_tables_mem_chunk = g_mem_chunk_create (GtkAccelGroup, 8, G_ALLOC_AND_FREE); + accel_entries_mem_chunk = g_mem_chunk_create (GtkAccelEntry, 64, G_ALLOC_AND_FREE); + } + + accel_group = g_chunk_new (GtkAccelGroup, accel_tables_mem_chunk); + + accel_group->ref_count = 1; + accel_group->lock_count = 0; + accel_group->modifier_mask = gtk_accelerator_get_default_mod_mask (); + accel_group->attach_objects = NULL; + + return accel_group; +} + +GtkAccelGroup* +gtk_accel_group_get_default (void) +{ + if (!default_accel_group) + default_accel_group = gtk_accel_group_new (); + + return default_accel_group; +} + +GtkAccelGroup* +gtk_accel_group_ref (GtkAccelGroup *accel_group) +{ + g_return_val_if_fail (accel_group != NULL, NULL); + + accel_group->ref_count += 1; + + return accel_group; +} + +void +gtk_accel_group_unref (GtkAccelGroup *accel_group) +{ + g_return_if_fail (accel_group != NULL); + g_return_if_fail (accel_group->ref_count > 0); + + accel_group->ref_count -= 1; + if (accel_group->ref_count == 0) + { + g_return_if_fail (accel_group != default_accel_group); + g_return_if_fail (accel_group->attach_objects == NULL); + + g_chunk_free (accel_group, accel_tables_mem_chunk); + } +} + +static void +gtk_accel_group_object_destroy (GtkObject *object) +{ + GSList *free_list, *slist; + + free_list = gtk_object_get_data_by_id (object, accel_groups_key_id); + gtk_object_set_data_by_id (object, accel_groups_key_id, NULL); + + for (slist = free_list; slist; slist = slist->next) + { + GtkAccelGroup *accel_group; + + accel_group = slist->data; + accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, object); + gtk_accel_group_unref (accel_group); + } + g_slist_free (free_list); +} + +void +gtk_accel_group_attach (GtkAccelGroup *accel_group, + GtkObject *object) +{ + GSList *slist; + + g_return_if_fail (accel_group != NULL); + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (g_slist_find (accel_group->attach_objects, object) == NULL); + + accel_group->attach_objects = g_slist_prepend (accel_group->attach_objects, object); + gtk_accel_group_ref (accel_group); + slist = gtk_object_get_data_by_id (object, accel_groups_key_id); + if (!slist) + gtk_signal_connect (object, + "destroy", + GTK_SIGNAL_FUNC (gtk_accel_group_object_destroy), + NULL); + slist = g_slist_prepend (slist, accel_group); + gtk_object_set_data_by_id (object, accel_groups_key_id, slist); +} + +void +gtk_accel_group_detach (GtkAccelGroup *accel_group, + GtkObject *object) +{ + GSList *slist; + + g_return_if_fail (accel_group != NULL); + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (g_slist_find (accel_group->attach_objects, object) != NULL); + + accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, object); + gtk_accel_group_unref (accel_group); + slist = gtk_object_get_data_by_id (object, accel_groups_key_id); + slist = g_slist_remove (slist, accel_group); + if (!slist) + gtk_signal_disconnect_by_func (object, + GTK_SIGNAL_FUNC (gtk_accel_group_object_destroy), + NULL); + gtk_object_set_data_by_id (object, accel_groups_key_id, slist); +} + +void +gtk_accel_group_lock (GtkAccelGroup *accel_group) +{ + g_return_if_fail (accel_group != NULL); + + accel_group->lock_count += 1; +} + +void +gtk_accel_group_unlock (GtkAccelGroup *accel_group) +{ + g_return_if_fail (accel_group != NULL); + + if (accel_group->lock_count) + accel_group->lock_count -= 1; +} + +static GtkAccelEntry* +gtk_accel_group_lookup (GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods) +{ + GtkAccelEntry key_entry = { 0 }; + + key_entry.accel_group = accel_group; + key_entry.accelerator_key = gdk_keyval_to_lower (accel_key); + key_entry.accelerator_mods = accel_mods & accel_group->modifier_mask; + + return g_hash_table_lookup (accel_entry_hash_table, &key_entry); +} + +gboolean +gtk_accel_group_activate (GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods) +{ + GtkAccelEntry *entry; + + g_return_val_if_fail (accel_group != NULL, FALSE); + + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (entry && entry->signal_id) + { + gtk_signal_emit (entry->object, entry->signal_id); + return TRUE; + } + return FALSE; +} + +gboolean +gtk_accel_groups_activate (GtkObject *object, + guint accel_key, + guint accel_mods) +{ + g_return_val_if_fail (object != NULL, FALSE); + g_return_val_if_fail (GTK_IS_OBJECT (object), FALSE); + + if (gtk_accelerator_valid (accel_key, accel_mods)) + { + GSList *slist; + + for (slist = gtk_accel_groups_from_object (object); slist; slist = slist->next) + if (gtk_accel_group_activate (slist->data, accel_key, accel_mods)) + return TRUE; + return gtk_accel_group_activate (gtk_accel_group_get_default (), accel_key, accel_mods); + } + + return FALSE; +} + +void +gtk_accel_group_lock_entry (GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods) +{ + GtkAccelEntry *entry; + + g_return_if_fail (accel_group != NULL); + + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (entry) + entry->accel_flags |= GTK_ACCEL_LOCKED; +} + +void +gtk_accel_group_unlock_entry (GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods) +{ + GtkAccelEntry *entry; + + g_return_if_fail (accel_group != NULL); + + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (entry) + entry->accel_flags &= ~GTK_ACCEL_LOCKED; +} + +GtkAccelEntry* +gtk_accel_group_get_entry (GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods) +{ + g_return_val_if_fail (accel_group != NULL, 0); + + return gtk_accel_group_lookup (accel_group, accel_key, accel_mods); +} + +void +gtk_accel_group_add (GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods, + GtkAccelFlags accel_flags, + GtkObject *object, + const gchar *accel_signal) +{ + guint accel_signal_id = 0; + guint add_accelerator_signal_id = 0; + guint remove_accelerator_signal_id = 0; + gchar *signal; + GtkSignalQuery *query; + GSList *slist; + GSList *groups; + GSList *attach_objects; + GtkAccelEntry *entry; + + g_return_if_fail (accel_group != NULL); + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (accel_signal != NULL); + + /* check for required signals in the objects branch + */ + signal = (gchar*) accel_signal; + accel_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object)); + if (accel_signal_id) + { + signal = "add-accelerator"; + add_accelerator_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object)); + } + if (add_accelerator_signal_id) + { + signal = "remove-accelerator"; + remove_accelerator_signal_id = gtk_signal_lookup (signal, GTK_OBJECT_TYPE (object)); + } + if (!accel_signal_id || + !add_accelerator_signal_id || + !remove_accelerator_signal_id) + { + g_warning ("gtk_accel_group_add(): could not find signal \"%s\"" + "in the `%s' class ancestry", + signal, + gtk_type_name (GTK_OBJECT_TYPE (object))); + return; + } + query = gtk_signal_query (accel_signal_id); + if (!query || + query->nparams > 0) + { + g_warning ("gtk_accel_group_add(): signal \"%s\" in the `%s' class ancestry" + "cannot be used as accelerator signal", + accel_signal, + gtk_type_name (GTK_OBJECT_TYPE (object))); + return; + } + + /* prematurely abort if the group/entry is already locked + */ + if (accel_group->lock_count > 0) + return; + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (entry && entry->accel_flags & GTK_ACCEL_LOCKED) + return; + + /* make sure our structures stay alive + */ + gtk_accel_group_ref (accel_group); + gtk_object_ref (object); + + /* remove an existing entry + */ + if (entry) + gtk_signal_emit (entry->object, remove_accelerator_signal_id, + accel_group, + gdk_keyval_to_lower (accel_key), + accel_mods & accel_group->modifier_mask); + + /* abort if the entry still exists + */ + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (entry) + { + gtk_accel_group_unref (accel_group); + gtk_object_unref (object); + + return; + } + + /* collect accel groups and remove existing entries + */ + attach_objects = accel_group->attach_objects; + groups = NULL; + for (attach_objects = accel_group->attach_objects; attach_objects; attach_objects = attach_objects->next) + { + GSList *tmp_groups; + + tmp_groups = gtk_object_get_data_by_id (attach_objects->data, accel_groups_key_id); + while (tmp_groups) + { + groups = g_slist_prepend (groups, tmp_groups->data); + gtk_accel_group_ref (tmp_groups->data); + tmp_groups = tmp_groups->next; + } + } + for (slist = groups; slist; slist = slist->next) + { + GtkAccelGroup *tmp_group; + + tmp_group = slist->data; + + /* we only remove the accelerator if neccessary + */ + if (tmp_group->lock_count == 0) + { + entry = gtk_accel_group_lookup (tmp_group, accel_key, accel_mods); + if (entry && !(entry->accel_flags & GTK_ACCEL_LOCKED)) + gtk_signal_emit (entry->object, remove_accelerator_signal_id, + tmp_group, + gdk_keyval_to_lower (accel_key), + accel_mods & tmp_group->modifier_mask); + } + gtk_accel_group_unref (tmp_group); + } + g_slist_free (groups); + + /* now install the new accelerator + */ + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (!entry) + gtk_signal_emit (object, add_accelerator_signal_id, + accel_signal_id, + accel_group, + gdk_keyval_to_lower (accel_key), + accel_mods & accel_group->modifier_mask, + accel_flags & GTK_ACCEL_MASK); + + /* and release the structures again + */ + gtk_accel_group_unref (accel_group); + gtk_object_unref (object); +} + +static void +gtk_accel_group_delete_entries (GtkObject *object) +{ + GSList *free_slist, *slist; + + gtk_signal_disconnect_by_func (object, + GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries), + NULL); + + /* we remove all entries of this object the hard + * way (i.e. without signal emission). + */ + free_slist = gtk_object_get_data_by_id (object, accel_entries_key_id); + gtk_object_set_data_by_id (object, accel_entries_key_id, NULL); + for (slist = free_slist; slist; slist = slist->next) + { + GtkAccelEntry *entry; + + entry = slist->data; + + g_hash_table_remove (accel_entry_hash_table, entry); + gtk_accel_group_unref (entry->accel_group); + g_chunk_free (entry, accel_entries_mem_chunk); + } + g_slist_free (free_slist); +} + +void +gtk_accel_group_handle_add (GtkObject *object, + guint accel_signal_id, + GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods, + GtkAccelFlags accel_flags) +{ + GtkAccelEntry *entry; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (accel_group != NULL); + g_return_if_fail (accel_signal_id > 0); + + if (!gtk_accelerator_valid (accel_key, accel_mods)) + return; + + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (!entry) + { + GSList *slist; + + gtk_accel_group_ref (accel_group); + + entry = g_chunk_new (GtkAccelEntry, accel_entries_mem_chunk); + entry->accel_group = accel_group; + entry->accelerator_key = gdk_keyval_to_lower (accel_key); + entry->accelerator_mods = accel_mods & accel_group->modifier_mask; + entry->accel_flags = accel_flags & GTK_ACCEL_MASK; + entry->object = object; + entry->signal_id = accel_signal_id; + + g_hash_table_insert (accel_entry_hash_table, entry, entry); + + slist = gtk_object_get_data_by_id (object, accel_entries_key_id); + if (!slist) + gtk_signal_connect (object, + "destroy", + GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries), + NULL); + slist = g_slist_prepend (slist, entry); + gtk_object_set_data_by_id (object, accel_entries_key_id, slist); + } +} + +void +gtk_accel_group_remove (GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods, + GtkObject *object) +{ + GtkAccelEntry *entry; + guint remove_accelerator_signal_id = 0; + + g_return_if_fail (accel_group != NULL); + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + /* check for required signals in the objects branch + */ + remove_accelerator_signal_id = gtk_signal_lookup ("remove-accelerator", GTK_OBJECT_TYPE (object)); + if (!remove_accelerator_signal_id) + { + g_warning ("gtk_accel_group_remove(): could not find signal \"%s\"" + "in the `%s' class ancestry", + "remove-accelerator", + gtk_type_name (GTK_OBJECT_TYPE (object))); + return; + } + + /* prematurely abort if the entry is locked + */ + if (accel_group->lock_count > 0) + return; + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (!entry || + entry->accel_flags & GTK_ACCEL_LOCKED) + return; + if (entry->object != object) + { + g_warning ("gtk_accel_group_remove(): invalid object reference for accel-group entry"); + return; + } + + /* make sure our structures stay alive + */ + gtk_accel_group_ref (accel_group); + gtk_object_ref (object); + + /* remove the entry + */ + gtk_signal_emit (entry->object, remove_accelerator_signal_id, + accel_group, + gdk_keyval_to_lower (accel_key), + accel_mods & accel_group->modifier_mask); + + /* and release the structures again + */ + gtk_accel_group_unref (accel_group); + gtk_object_unref (object); +} + +void +gtk_accel_group_handle_remove (GtkObject *object, + GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods) +{ + GtkAccelEntry *entry; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (accel_group != NULL); + + entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + if (entry) + { + if (entry->object == object) + { + GSList *slist; + + g_hash_table_remove (accel_entry_hash_table, entry); + + slist = gtk_object_get_data_by_id (object, accel_entries_key_id); + if (slist) + { + slist = g_slist_remove (slist, entry); + if (!slist) + gtk_signal_disconnect_by_func (object, + GTK_SIGNAL_FUNC (gtk_accel_group_delete_entries), + NULL); + gtk_object_set_data_by_id (object, accel_entries_key_id, slist); + + gtk_accel_group_unref (accel_group); + + g_chunk_free (entry, accel_entries_mem_chunk); + } + } + else + g_warning ("gtk_accel_group_handle_remove(): invalid object reference for accel-group entry"); + } + else + g_warning ("gtk_accel_group_handle_remove(): attempt to remove unexisting accel-group entry"); +} + +guint +gtk_accel_group_create_add (GtkType class_type, + GtkSignalRunType run_type, + guint handler_offset) +{ + g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_OBJECT), 0); + + return gtk_signal_new ("add-accelerator", + run_type, + class_type, + handler_offset, + gtk_accel_group_marshal_add, + GTK_TYPE_NONE, 5, + GTK_TYPE_UINT, + GTK_TYPE_BOXED, + GTK_TYPE_UINT, + GTK_TYPE_UINT, + GTK_TYPE_ENUM); +} + +guint +gtk_accel_group_create_remove (GtkType class_type, + GtkSignalRunType run_type, + guint handler_offset) +{ + g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_OBJECT), 0); + + return gtk_signal_new ("remove-accelerator", + run_type, + class_type, + handler_offset, + gtk_accel_group_marshal_remove, + GTK_TYPE_NONE, 3, + GTK_TYPE_BOXED, + GTK_TYPE_UINT, + GTK_TYPE_UINT); +} + +void +gtk_accel_group_marshal_add (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkSignalAddAccelerator signal_func; + + signal_func = (GtkSignalAddAccelerator) func; + + signal_func (object, + GTK_VALUE_UINT (args[0]), + GTK_VALUE_BOXED (args[1]), + GTK_VALUE_UINT (args[2]), + GTK_VALUE_UINT (args[3]), + GTK_VALUE_ENUM (args[4]), + func_data); +} + +void +gtk_accel_group_marshal_remove (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkSignalRemoveAccelerator signal_func; + + signal_func = (GtkSignalRemoveAccelerator) func; + + signal_func (object, + GTK_VALUE_BOXED (args[0]), + GTK_VALUE_UINT (args[1]), + GTK_VALUE_UINT (args[2]), + func_data); +} + +GSList* +gtk_accel_groups_from_object (GtkObject *object) +{ + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (GTK_IS_OBJECT (object), NULL); + + return gtk_object_get_data_by_id (object, accel_groups_key_id); +} + +GSList* +gtk_accel_group_entries_from_object (GtkObject *object) +{ + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (GTK_IS_OBJECT (object), NULL); + + return gtk_object_get_data_by_id (object, accel_entries_key_id); +} + +gboolean +gtk_accelerator_valid (guint keyval, + guint modifiers) +{ + guint invalid_accelerator_vals[] = { + GDK_BackSpace, GDK_Delete, GDK_KP_Delete, + GDK_Shift_L, GDK_Shift_R, GDK_Shift_Lock, GDK_Caps_Lock, GDK_ISO_Lock, + GDK_Control_L, GDK_Control_R, GDK_Meta_L, GDK_Meta_R, + GDK_Super_L, GDK_Super_R, GDK_Hyper_L, GDK_Hyper_R, + GDK_Mode_switch, GDK_Num_Lock, GDK_Multi_key, + GDK_Scroll_Lock, GDK_Sys_Req, + GDK_Up, GDK_Down, GDK_Left, GDK_Right, GDK_Tab, GDK_ISO_Left_Tab, + GDK_KP_Up, GDK_KP_Down, GDK_KP_Left, GDK_KP_Right, GDK_KP_Tab, + GDK_First_Virtual_Screen, GDK_Prev_Virtual_Screen, + GDK_Next_Virtual_Screen, GDK_Last_Virtual_Screen, + GDK_Terminate_Server, GDK_AudibleBell_Enable, + 0 + }; + guint *ac_val; + + modifiers &= GDK_MODIFIER_MASK; + + if (keyval <= 0xFF) + return keyval >= 0x20; + + ac_val = invalid_accelerator_vals; + while (*ac_val) + { + if (keyval == *ac_val++) + return FALSE; + } + + return TRUE; +} + +static inline gboolean +is_alt (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'a' || string[1] == 'A') && + (string[2] == 'l' || string[2] == 'L') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == '>')); +} + +static inline gboolean +is_ctl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'l' || string[3] == 'L') && + (string[4] == '>')); +} + +static inline gboolean +is_modx (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'm' || string[1] == 'M') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'd' || string[3] == 'D') && + (string[4] >= '1' && string[4] <= '5') && + (string[5] == '>')); +} + +static inline gboolean +is_ctrl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'r' || string[3] == 'R') && + (string[4] == 'l' || string[4] == 'L') && + (string[5] == '>')); +} + +static inline gboolean +is_shft (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'f' || string[3] == 'F') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == '>')); +} + +static inline gboolean +is_shift (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'f' || string[4] == 'F') && + (string[5] == 't' || string[5] == 'T') && + (string[6] == '>')); +} + +static inline gboolean +is_after (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'a' || string[1] == 'A') && + (string[2] == 'f' || string[2] == 'F') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == '>')); +} + +static inline gboolean +is_control (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'n' || string[3] == 'N') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == 'o' || string[6] == 'O') && + (string[7] == 'l' || string[7] == 'L') && + (string[8] == '>')); +} + +void +gtk_accelerator_parse (const gchar *accelerator, + guint *accelerator_key, + guint *accelerator_mods) +{ + guint keyval; + guint mods; + gint len; + + if (accelerator_key) + *accelerator_key = 0; + if (accelerator_mods) + *accelerator_mods = 0; + g_return_if_fail (accelerator != NULL); + + keyval = 0; + mods = 0; + len = strlen (accelerator); + while (len) + { + if (*accelerator == '<') + { + if (len >= 9 && is_control (accelerator)) + { + accelerator += 9; + len -= 9; + mods |= GDK_CONTROL_MASK; + } + else if (len >= 7 && is_shift (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= GDK_SHIFT_MASK; + } + else if (len >= 7 && is_after (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= GDK_AFTER_MASK; + } + else if (len >= 6 && is_shft (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= GDK_SHIFT_MASK; + } + else if (len >= 6 && is_ctrl (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= GDK_CONTROL_MASK; + } + else if (len >= 6 && is_modx (accelerator)) + { + guint mod_vals[] = { + GDK_MOD1_MASK, GDK_MOD2_MASK, GDK_MOD3_MASK, + GDK_MOD4_MASK, GDK_MOD5_MASK + }; + + len -= 6; + accelerator += 4; + mods |= mod_vals[*accelerator - '1']; + accelerator += 2; + } + else if (len >= 5 && is_ctl (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= GDK_CONTROL_MASK; + } + else if (len >= 5 && is_alt (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= GDK_MOD1_MASK; + } + else + { + gchar last_ch; + + last_ch = *accelerator; + while (last_ch && last_ch != '>') + { + last_ch = *accelerator; + accelerator += 1; + len -= 1; + } + } + } + else + { + keyval = gdk_keyval_from_name (accelerator); + accelerator += len; + len -= len; + } + } + + if (accelerator_key) + *accelerator_key = gdk_keyval_to_lower (keyval); + if (accelerator_mods) + *accelerator_mods = mods; +} + +gchar* +gtk_accelerator_name (guint accelerator_key, + guint accelerator_mods) +{ + static const gchar text_shift[] = "<Shift>"; + static const gchar text_control[] = "<Control>"; + static const gchar text_mod1[] = "<Alt>"; + static const gchar text_mod2[] = "<Mod2>"; + static const gchar text_mod3[] = "<Mod3>"; + static const gchar text_mod4[] = "<Mod4>"; + static const gchar text_mod5[] = "<Mod5>"; + static const gchar text_after[] = "<After>"; + guint l; + gchar *keyval_name; + gchar *accelerator; + + accelerator_mods &= GDK_MODIFIER_MASK; + + keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key)); + if (!keyval_name) + keyval_name = ""; + + l = 0; + if (accelerator_mods & GDK_SHIFT_MASK) + l += sizeof (text_shift) - 1; + if (accelerator_mods & GDK_CONTROL_MASK) + l += sizeof (text_control) - 1; + if (accelerator_mods & GDK_MOD1_MASK) + l += sizeof (text_mod1) - 1; + if (accelerator_mods & GDK_MOD2_MASK) + l += sizeof (text_mod2) - 1; + if (accelerator_mods & GDK_MOD3_MASK) + l += sizeof (text_mod3) - 1; + if (accelerator_mods & GDK_MOD4_MASK) + l += sizeof (text_mod4) - 1; + if (accelerator_mods & GDK_MOD5_MASK) + l += sizeof (text_mod5) - 1; + if (accelerator_mods & GDK_AFTER_MASK) + l += sizeof (text_after) - 1; + l += strlen (keyval_name); + + accelerator = g_new (gchar, l + 1); + + l = 0; + accelerator[l] = 0; + if (accelerator_mods & GDK_SHIFT_MASK) + { + strcpy (accelerator + l, text_shift); + l += sizeof (text_shift) - 1; + } + if (accelerator_mods & GDK_CONTROL_MASK) + { + strcpy (accelerator + l, text_control); + l += sizeof (text_control) - 1; + } + if (accelerator_mods & GDK_MOD1_MASK) + { + strcpy (accelerator + l, text_mod1); + l += sizeof (text_mod1) - 1; + } + if (accelerator_mods & GDK_MOD2_MASK) + { + strcpy (accelerator + l, text_mod2); + l += sizeof (text_mod2) - 1; + } + if (accelerator_mods & GDK_MOD3_MASK) + { + strcpy (accelerator + l, text_mod3); + l += sizeof (text_mod3) - 1; + } + if (accelerator_mods & GDK_MOD4_MASK) + { + strcpy (accelerator + l, text_mod4); + l += sizeof (text_mod4) - 1; + } + if (accelerator_mods & GDK_MOD5_MASK) + { + strcpy (accelerator + l, text_mod5); + l += sizeof (text_mod5) - 1; + } + if (accelerator_mods & GDK_AFTER_MASK) + { + strcpy (accelerator + l, text_after); + l += sizeof (text_after) - 1; + } + strcpy (accelerator + l, keyval_name); + + return accelerator; +} + +void +gtk_accelerator_set_default_mod_mask (guint default_mod_mask) +{ + default_accel_mod_mask = default_mod_mask & GDK_MODIFIER_MASK; +} + +guint +gtk_accelerator_get_default_mod_mask (void) +{ + return default_accel_mod_mask; +} |