📄 gtkaccelgroup.c
字号:
/* 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. *//* * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */#include <ctype.h>#include <string.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, GdkModifierType accel_mods, GtkAccelFlags accel_flags, gpointer func_data);typedef void (*GtkSignalRemoveAccelerator) (GtkObject *object, GtkAccelGroup *accel_group, guint accel_key, GdkModifierType 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 gintgtk_accel_entries_equal (gconstpointer a, gconstpointer b){ const GtkAccelEntry *e1; const 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 guintgtk_accel_entries_hash (gconstpointer a){ const 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 = g_quark_from_static_string (accel_groups_key); accel_entries_key_id = g_quark_from_static_string (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;}voidgtk_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 voidgtk_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);}voidgtk_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);}voidgtk_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);}voidgtk_accel_group_lock (GtkAccelGroup *accel_group){ g_return_if_fail (accel_group != NULL); accel_group->lock_count += 1;}voidgtk_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, GdkModifierType 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);}gbooleangtk_accel_group_activate (GtkAccelGroup *accel_group, guint accel_key, GdkModifierType 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_IS_WIDGET (entry->object) || GTK_WIDGET_IS_SENSITIVE (entry->object))) { gtk_signal_emit (entry->object, entry->signal_id); return TRUE; } return FALSE;}gbooleangtk_accel_groups_activate (GtkObject *object, guint accel_key, GdkModifierType 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;}voidgtk_accel_group_lock_entry (GtkAccelGroup *accel_group, guint accel_key, GdkModifierType 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;}voidgtk_accel_group_unlock_entry (GtkAccelGroup *accel_group, guint accel_key, GdkModifierType 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, GdkModifierType accel_mods){ g_return_val_if_fail (accel_group != NULL, 0); return gtk_accel_group_lookup (accel_group, accel_key, accel_mods);}voidgtk_accel_group_add (GtkAccelGroup *accel_group, guint accel_key, GdkModifierType 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))); if (query) g_free (query); return; } g_free (query); /* 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 voidgtk_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);}voidgtk_accel_group_handle_add (GtkObject *object, guint accel_signal_id, GtkAccelGroup *accel_group, guint accel_key, GdkModifierType 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -