📄 gtkbindings.c
字号:
/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * GtkBindingSet: Keybinding 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 <stdarg.h>#include "gtkbindings.h"#include "gtksignal.h"#include "gtkwidget.h"#include "gtkrc.h"/* --- defines --- */#define BINDING_MOD_MASK() (gtk_accelerator_get_default_mod_mask () | GDK_RELEASE_MASK)/* --- variables --- */static GHashTable *binding_entry_hash_table = NULL;static GSList *binding_set_list = NULL;static const gchar *key_class_binding_set = "gtk-class-binding-set";static GQuark key_id_class_binding_set = 0;/* --- functions --- */static GtkBindingSignal*binding_signal_new (const gchar *signal_name, guint n_args){ GtkBindingSignal *signal; signal = g_new (GtkBindingSignal, 1); signal->next = NULL; signal->signal_name = g_strdup (signal_name); signal->n_args = n_args; signal->args = g_new0 (GtkBindingArg, n_args); return signal;}static voidbinding_signal_free (GtkBindingSignal *sig){ guint i; for (i = 0; i < sig->n_args; i++) { if (GTK_FUNDAMENTAL_TYPE (sig->args[i].arg_type) == GTK_TYPE_STRING) g_free (sig->args[i].d.string_data); } g_free (sig->args); g_free (sig->signal_name); g_free (sig);}static guintbinding_entry_hash (gconstpointer key){ register const GtkBindingEntry *e = key; register guint h; h = e->keyval; h ^= e->modifiers; return h;}static gintbinding_entries_compare (gconstpointer a, gconstpointer b){ register const GtkBindingEntry *ea = a; register const GtkBindingEntry *eb = b; return (ea->keyval == eb->keyval && ea->modifiers == eb->modifiers);}static GtkBindingEntry*binding_entry_new (GtkBindingSet *binding_set, guint keyval, guint modifiers){ GtkBindingEntry *entry; if (!binding_entry_hash_table) binding_entry_hash_table = g_hash_table_new (binding_entry_hash, binding_entries_compare); entry = g_new (GtkBindingEntry, 1); entry->keyval = keyval; entry->modifiers = modifiers; entry->binding_set = binding_set, entry->destroyed = FALSE; entry->in_emission = FALSE; entry->signals = NULL; entry->set_next = binding_set->entries; binding_set->entries = entry; entry->hash_next = g_hash_table_lookup (binding_entry_hash_table, entry); g_hash_table_freeze (binding_entry_hash_table); if (entry->hash_next) g_hash_table_remove (binding_entry_hash_table, entry->hash_next); g_hash_table_insert (binding_entry_hash_table, entry, entry); g_hash_table_thaw (binding_entry_hash_table); return entry;}static voidbinding_entry_free (GtkBindingEntry *entry){ GtkBindingSignal *sig; g_assert (entry->set_next == NULL && entry->hash_next == NULL && entry->in_emission == FALSE && entry->destroyed == TRUE); entry->destroyed = FALSE; sig = entry->signals; while (sig) { GtkBindingSignal *prev; prev = sig; sig = prev->next; binding_signal_free (prev); } g_free (entry);}static voidbinding_entry_destroy (GtkBindingEntry *entry){ GtkBindingEntry *o_entry; register GtkBindingEntry *tmp; GtkBindingEntry *begin; register GtkBindingEntry *last; /* unlink from binding set */ last = NULL; tmp = entry->binding_set->entries; while (tmp) { if (tmp == entry) { if (last) last->set_next = entry->set_next; else entry->binding_set->entries = entry->set_next; break; } last = tmp; tmp = last->set_next; } entry->set_next = NULL; o_entry = g_hash_table_lookup (binding_entry_hash_table, entry); begin = o_entry; last = NULL; tmp = begin; while (tmp) { if (tmp == entry) { if (last) last->hash_next = entry->hash_next; else begin = entry->hash_next; break; } last = tmp; tmp = last->hash_next; } entry->hash_next = NULL; if (!begin) g_hash_table_remove (binding_entry_hash_table, entry); else if (begin != o_entry) { g_hash_table_freeze (binding_entry_hash_table); g_hash_table_remove (binding_entry_hash_table, entry); g_hash_table_insert (binding_entry_hash_table, begin, begin); g_hash_table_thaw (binding_entry_hash_table); } entry->destroyed = TRUE; if (!entry->in_emission) binding_entry_free (entry);}static GtkBindingEntry*binding_ht_lookup_list (guint keyval, guint modifiers){ GtkBindingEntry lookup_entry = { 0 }; if (!binding_entry_hash_table) return NULL; lookup_entry.keyval = keyval; lookup_entry.modifiers = modifiers; return g_hash_table_lookup (binding_entry_hash_table, &lookup_entry);}static GtkBindingEntry*binding_ht_lookup_entry (GtkBindingSet *set, guint keyval, guint modifiers){ GtkBindingEntry lookup_entry = { 0 }; GtkBindingEntry *entry; if (!binding_entry_hash_table) return NULL; lookup_entry.keyval = keyval; lookup_entry.modifiers = modifiers; entry = g_hash_table_lookup (binding_entry_hash_table, &lookup_entry); for (; entry; entry = entry->hash_next) if (entry->binding_set == set) return entry; return NULL;}static gbooleanbinding_compose_params (GtkBindingArg *args, GtkSignalQuery *query, GtkArg **params_p){ GtkArg *params; const GtkType *types; guint i; gboolean valid; params = g_new0 (GtkArg, query->nparams); *params_p = params; types = query->params; valid = TRUE; for (i = 0; i < query->nparams && valid; i++) { GtkType param_ftype; params->type = *types; params->name = NULL; param_ftype = GTK_FUNDAMENTAL_TYPE (params->type); switch (GTK_FUNDAMENTAL_TYPE (args->arg_type)) { case GTK_TYPE_DOUBLE: if (param_ftype == GTK_TYPE_FLOAT) GTK_VALUE_FLOAT (*params) = args->d.double_data; else if (param_ftype == GTK_TYPE_DOUBLE) GTK_VALUE_DOUBLE (*params) = args->d.double_data; else valid = FALSE; break; case GTK_TYPE_LONG: if (param_ftype == GTK_TYPE_BOOL && (args->d.long_data == 0 || args->d.long_data == 1)) GTK_VALUE_BOOL (*params) = args->d.long_data; else if (param_ftype == GTK_TYPE_INT || param_ftype == GTK_TYPE_ENUM) GTK_VALUE_INT (*params) = args->d.long_data; else if ((param_ftype == GTK_TYPE_UINT || param_ftype == GTK_TYPE_FLAGS) && args->d.long_data >= 0) GTK_VALUE_UINT (*params) = args->d.long_data; else if (param_ftype == GTK_TYPE_LONG) GTK_VALUE_LONG (*params) = args->d.long_data; else if (param_ftype == GTK_TYPE_ULONG && args->d.long_data >= 0) GTK_VALUE_ULONG (*params) = args->d.long_data; else if (param_ftype == GTK_TYPE_FLOAT) GTK_VALUE_FLOAT (*params) = args->d.long_data; else if (param_ftype == GTK_TYPE_DOUBLE) GTK_VALUE_DOUBLE (*params) = args->d.long_data; else valid = FALSE; break; case GTK_TYPE_STRING: if (args->arg_type == GTK_TYPE_STRING && param_ftype == GTK_TYPE_STRING) GTK_VALUE_STRING (*params) = args->d.string_data; else if (args->arg_type == GTK_TYPE_IDENTIFIER && (param_ftype == GTK_TYPE_ENUM || param_ftype == GTK_TYPE_FLAGS)) { GtkEnumValue *value; value = gtk_type_enum_find_value (params->type, args->d.string_data); if (value) GTK_VALUE_ENUM (*params) = value->value; else valid = FALSE; } else valid = FALSE; break; default: valid = FALSE; break; } types++; params++; args++; } if (!valid) { g_free (*params_p); *params_p = NULL; } return valid;}static voidgtk_binding_entry_activate (GtkBindingEntry *entry, GtkObject *object){ GtkBindingSignal *sig; gboolean old_emission; old_emission = entry->in_emission; entry->in_emission = TRUE; gtk_object_ref (object); for (sig = entry->signals; sig; sig = sig->next) { GtkSignalQuery *query; guint signal_id; GtkArg *params = NULL; gchar *accelerator = NULL; signal_id = gtk_signal_lookup (sig->signal_name, GTK_OBJECT_TYPE (object)); if (!signal_id) { accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers); g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": " "could not find signal \"%s\" in the `%s' class ancestry", entry->binding_set->set_name, accelerator, sig->signal_name, gtk_type_name (GTK_OBJECT_TYPE (object))); g_free (accelerator); continue; } query = gtk_signal_query (signal_id); if (query->nparams != sig->n_args || query->return_val != GTK_TYPE_NONE || !binding_compose_params (sig->args, query, ¶ms)) { accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers); g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": " "signature mismatch for signal \"%s\" in the `%s' class ancestry", entry->binding_set->set_name, accelerator, sig->signal_name, gtk_type_name (GTK_OBJECT_TYPE (object))); } else if (!(query->signal_flags & GTK_RUN_ACTION)) { accelerator = gtk_accelerator_name (entry->keyval, entry->modifiers); g_warning ("gtk_binding_entry_activate(): binding \"%s::%s\": " "signal \"%s\" in the `%s' class ancestry cannot be used for action emissions", entry->binding_set->set_name, accelerator, sig->signal_name, gtk_type_name (GTK_OBJECT_TYPE (object))); } g_free (accelerator); g_free (query); if (accelerator) continue; gtk_signal_emitv (object, signal_id, params); g_free (params); if (GTK_OBJECT_DESTROYED (object) || entry->destroyed) break; } gtk_object_unref (object); entry->in_emission = old_emission; if (entry->destroyed && !entry->in_emission) binding_entry_free (entry);}GtkBindingSet*gtk_binding_set_new (const gchar *set_name){ GtkBindingSet *binding_set; g_return_val_if_fail (set_name != NULL, NULL); binding_set = g_new (GtkBindingSet, 1); binding_set->set_name = g_strdup (set_name); binding_set->widget_path_pspecs = NULL; binding_set->widget_class_pspecs = NULL; binding_set->class_branch_pspecs = NULL; binding_set->entries = NULL; binding_set->current = NULL; binding_set_list = g_slist_prepend (binding_set_list, binding_set); return binding_set;}GtkBindingSet*gtk_binding_set_by_class (gpointer object_class){ GtkObjectClass *class = object_class; GtkBindingSet* binding_set; g_return_val_if_fail (GTK_IS_OBJECT_CLASS (class), NULL); if (!key_id_class_binding_set) key_id_class_binding_set = g_quark_from_static_string (key_class_binding_set); binding_set = g_dataset_id_get_data (class, key_id_class_binding_set); if (binding_set) return binding_set; binding_set = gtk_binding_set_new (gtk_type_name (class->type)); gtk_binding_set_add_path (binding_set, GTK_PATH_CLASS, gtk_type_name (class->type), GTK_PATH_PRIO_GTK); g_dataset_id_set_data (class, key_id_class_binding_set, binding_set); return binding_set;}GtkBindingSet*gtk_binding_set_find (const gchar *set_name){ GSList *slist; g_return_val_if_fail (set_name != NULL, NULL); for (slist = binding_set_list; slist; slist = slist->next) { GtkBindingSet *binding_set; binding_set = slist->data; if (g_str_equal (binding_set->set_name, (gpointer) set_name)) return binding_set; } return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -