diff options
author | Benjamin Otte <otte@redhat.com> | 2018-08-24 08:46:54 +0200 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2020-03-25 23:14:44 -0400 |
commit | bb4fbe3d8f04ba2df1197c7647842fd3f37d8a74 (patch) | |
tree | fb9ca1cee391811180588acdb5e674c89b7e0180 /gtk/gtkaccelgroup.c | |
parent | 7c4d8d49b643ef0d2c449c1a0fb5ff311162005b (diff) | |
download | gtk+-bb4fbe3d8f04ba2df1197c7647842fd3f37d8a74.tar.gz |
accels: Remove GtkAccelGroup
Diffstat (limited to 'gtk/gtkaccelgroup.c')
-rw-r--r-- | gtk/gtkaccelgroup.c | 668 |
1 files changed, 4 insertions, 664 deletions
diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c index 76817a0d12..97cdc22791 100644 --- a/gtk/gtkaccelgroup.c +++ b/gtk/gtkaccelgroup.c @@ -35,678 +35,18 @@ /** * SECTION:gtkaccelgroup - * @Short_description: Groups of global keyboard accelerators for an - * entire GtkWindow - * @Title: Accelerator Groups - * @See_also: gtk_window_add_accel_group(), gtk_accel_map_change_entry(), - * gtk_label_new_with_mnemonic() + * @Short_description: Utilities for accelerators + * @Title: Keyboard Accelerators * - * A #GtkAccelGroup represents a group of keyboard accelerators, - * typically attached to a toplevel #GtkWindow (with - * gtk_window_add_accel_group()). - * - * Note that “accelerators” are different from - * “mnemonics”. Accelerators are shortcuts for - * activating a menu item; they appear alongside the menu item they’re a - * shortcut for. For example “Ctrl+Q” might appear alongside the “Quit” - * menu item. Mnemonics are shortcuts for GUI elements such as text - * entries or buttons; they appear as underlined characters. See - * gtk_label_new_with_mnemonic(). Menu items can have both accelerators - * and mnemonics, of course. + * We have various utility functions to parse and generate + * textual representations of keyboard accelerators. */ -/* --- prototypes --- */ -static void gtk_accel_group_finalize (GObject *object); -static void accel_closure_invalidate (gpointer data, - GClosure *closure); - - /* --- variables --- */ -static guint signal_accel_activate = 0; -static guint signal_accel_changed = 0; -static guint quark_acceleratable_groups = 0; static guint default_accel_mod_mask = 0; -G_DEFINE_TYPE_WITH_PRIVATE (GtkAccelGroup, gtk_accel_group, G_TYPE_OBJECT) - /* --- functions --- */ -static void -gtk_accel_group_class_init (GtkAccelGroupClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - - quark_acceleratable_groups = g_quark_from_static_string ("gtk-acceleratable-accel-groups"); - - object_class->finalize = gtk_accel_group_finalize; - - class->accel_changed = NULL; - - /** - * GtkAccelGroup::accel-activate: - * @accel_group: the #GtkAccelGroup which received the signal - * @acceleratable: the object on which the accelerator was activated - * @keyval: the accelerator keyval - * @modifier: the modifier combination of the accelerator - * - * The accel-activate signal is an implementation detail of - * #GtkAccelGroup and not meant to be used by applications. - * - * Returns: %TRUE if the accelerator was activated - */ - signal_accel_activate = - g_signal_new (I_("accel-activate"), - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_DETAILED, - 0, - _gtk_boolean_handled_accumulator, NULL, - _gtk_marshal_BOOLEAN__OBJECT_UINT_FLAGS, - G_TYPE_BOOLEAN, 3, - G_TYPE_OBJECT, - G_TYPE_UINT, - GDK_TYPE_MODIFIER_TYPE); - /** - * GtkAccelGroup::accel-changed: - * @accel_group: the #GtkAccelGroup which received the signal - * @keyval: the accelerator keyval - * @modifier: the modifier combination of the accelerator - * @accel_closure: the #GClosure of the accelerator - * - * The accel-changed signal is emitted when an entry - * is added to or removed from the accel group. - * - * Widgets like #GtkAccelLabel which display an associated - * accelerator should connect to this signal, and rebuild - * their visual representation if the @accel_closure is theirs. - */ - signal_accel_changed = - g_signal_new (I_("accel-changed"), - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, - G_STRUCT_OFFSET (GtkAccelGroupClass, accel_changed), - NULL, NULL, - _gtk_marshal_VOID__UINT_FLAGS_BOXED, - G_TYPE_NONE, 3, - G_TYPE_UINT, - GDK_TYPE_MODIFIER_TYPE, - G_TYPE_CLOSURE); -} - -static void -gtk_accel_group_finalize (GObject *object) -{ - GtkAccelGroup *accel_group = GTK_ACCEL_GROUP (object); - guint i; - - for (i = 0; i < accel_group->priv->n_accels; i++) - { - GtkAccelGroupEntry *entry = &accel_group->priv->priv_accels[i]; - - g_closure_remove_invalidate_notifier (entry->closure, accel_group, accel_closure_invalidate); - - /* remove quick_accel_add() refcount */ - g_closure_unref (entry->closure); - } - - g_free (accel_group->priv->priv_accels); - - G_OBJECT_CLASS (gtk_accel_group_parent_class)->finalize (object); -} - -static void -gtk_accel_group_init (GtkAccelGroup *accel_group) -{ - GtkAccelGroupPrivate *priv; - - accel_group->priv = gtk_accel_group_get_instance_private (accel_group); - priv = accel_group->priv; - - priv->acceleratables = NULL; - priv->n_accels = 0; - priv->priv_accels = NULL; -} - -/** - * gtk_accel_group_new: - * - * Creates a new #GtkAccelGroup. - * - * Returns: a new #GtkAccelGroup object - */ -GtkAccelGroup* -gtk_accel_group_new (void) -{ - return g_object_new (GTK_TYPE_ACCEL_GROUP, NULL); -} - -static void -accel_group_weak_ref_detach (GSList *free_list, - GObject *stale_object) -{ - GSList *slist; - - for (slist = free_list; slist; slist = slist->next) - { - GtkAccelGroup *accel_group; - - accel_group = slist->data; - accel_group->priv->acceleratables = g_slist_remove (accel_group->priv->acceleratables, stale_object); - g_object_unref (accel_group); - } - g_slist_free (free_list); - g_object_set_qdata (stale_object, quark_acceleratable_groups, NULL); -} - -void -_gtk_accel_group_attach (GtkAccelGroup *accel_group, - GObject *object) -{ - GSList *slist; - - g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (g_slist_find (accel_group->priv->acceleratables, object) == NULL); - - g_object_ref (accel_group); - accel_group->priv->acceleratables = g_slist_prepend (accel_group->priv->acceleratables, object); - slist = g_object_get_qdata (object, quark_acceleratable_groups); - if (slist) - g_object_weak_unref (object, - (GWeakNotify) accel_group_weak_ref_detach, - slist); - slist = g_slist_prepend (slist, accel_group); - g_object_set_qdata (object, quark_acceleratable_groups, slist); - g_object_weak_ref (object, - (GWeakNotify) accel_group_weak_ref_detach, - slist); -} - -void -_gtk_accel_group_detach (GtkAccelGroup *accel_group, - GObject *object) -{ - GSList *slist; - - g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (g_slist_find (accel_group->priv->acceleratables, object) != NULL); - - accel_group->priv->acceleratables = g_slist_remove (accel_group->priv->acceleratables, object); - slist = g_object_get_qdata (object, quark_acceleratable_groups); - g_object_weak_unref (object, - (GWeakNotify) accel_group_weak_ref_detach, - slist); - slist = g_slist_remove (slist, accel_group); - g_object_set_qdata (object, quark_acceleratable_groups, slist); - if (slist) - g_object_weak_ref (object, - (GWeakNotify) accel_group_weak_ref_detach, - slist); - g_object_unref (accel_group); -} - -/** - * gtk_accel_groups_from_object: - * @object: a #GObject, usually a #GtkWindow - * - * Gets a list of all accel groups which are attached to @object. - * - * Returns: (element-type GtkAccelGroup) (transfer none): a list of - * all accel groups which are attached to @object - */ -GSList* -gtk_accel_groups_from_object (GObject *object) -{ - g_return_val_if_fail (G_IS_OBJECT (object), NULL); - - return g_object_get_qdata (object, quark_acceleratable_groups); -} - -/** - * gtk_accel_group_find: - * @accel_group: a #GtkAccelGroup - * @find_func: (scope call): a function to filter the entries - * of @accel_group with - * @data: data to pass to @find_func - * - * Finds the first entry in an accelerator group for which - * @find_func returns %TRUE and returns its #GtkAccelKey. - * - * Returns: (transfer none): the key of the first entry passing - * @find_func. The key is owned by GTK+ and must not be freed. - */ -GtkAccelKey* -gtk_accel_group_find (GtkAccelGroup *accel_group, - GtkAccelGroupFindFunc find_func, - gpointer data) -{ - GtkAccelKey *key = NULL; - guint i; - - g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL); - g_return_val_if_fail (find_func != NULL, NULL); - - g_object_ref (accel_group); - for (i = 0; i < accel_group->priv->n_accels; i++) - if (find_func (&accel_group->priv->priv_accels[i].key, - accel_group->priv->priv_accels[i].closure, - data)) - { - key = &accel_group->priv->priv_accels[i].key; - break; - } - g_object_unref (accel_group); - - return key; -} - -static void -accel_closure_invalidate (gpointer data, - GClosure *closure) -{ - GtkAccelGroup *accel_group = GTK_ACCEL_GROUP (data); - - gtk_accel_group_disconnect (accel_group, closure); -} - -static int -bsearch_compare_accels (const void *d1, - const void *d2) -{ - const GtkAccelGroupEntry *entry1 = d1; - const GtkAccelGroupEntry *entry2 = d2; - - if (entry1->key.accel_key == entry2->key.accel_key) - return entry1->key.accel_mods < entry2->key.accel_mods ? -1 : entry1->key.accel_mods > entry2->key.accel_mods; - else - return entry1->key.accel_key < entry2->key.accel_key ? -1 : 1; -} - -static void -quick_accel_add (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GtkAccelFlags accel_flags, - GClosure *closure) -{ - guint pos, i = accel_group->priv->n_accels++; - GtkAccelGroupEntry key; - - /* find position */ - key.key.accel_key = accel_key; - key.key.accel_mods = accel_mods; - for (pos = 0; pos < i; pos++) - if (bsearch_compare_accels (&key, accel_group->priv->priv_accels + pos) < 0) - break; - - /* insert at position, ref closure */ - accel_group->priv->priv_accels = g_renew (GtkAccelGroupEntry, accel_group->priv->priv_accels, accel_group->priv->n_accels); - memmove (accel_group->priv->priv_accels + pos + 1, accel_group->priv->priv_accels + pos, - (i - pos) * sizeof (accel_group->priv->priv_accels[0])); - accel_group->priv->priv_accels[pos].key.accel_key = accel_key; - accel_group->priv->priv_accels[pos].key.accel_mods = accel_mods; - accel_group->priv->priv_accels[pos].key.accel_flags = accel_flags; - accel_group->priv->priv_accels[pos].closure = g_closure_ref (closure); - g_closure_sink (closure); - - /* handle closure invalidation and reverse lookups */ - g_closure_add_invalidate_notifier (closure, accel_group, accel_closure_invalidate); - - /* connect and notify changed */ - if (accel_key) - { - gchar *accel_name = gtk_accelerator_name (accel_key, accel_mods); - GQuark accel_quark = g_quark_from_string (accel_name); - - g_free (accel_name); - - /* setup handler */ - g_signal_connect_closure_by_id (accel_group, signal_accel_activate, accel_quark, closure, FALSE); - - /* and notify */ - g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, closure); - } -} - -static void -quick_accel_remove (GtkAccelGroup *accel_group, - guint pos) -{ - GQuark accel_quark = 0; - GtkAccelGroupEntry *entry = accel_group->priv->priv_accels + pos; - guint accel_key = entry->key.accel_key; - GdkModifierType accel_mods = entry->key.accel_mods; - GClosure *closure = entry->closure; - - /* quark for notification */ - if (accel_key) - { - gchar *accel_name = gtk_accelerator_name (accel_key, accel_mods); - - accel_quark = g_quark_from_string (accel_name); - g_free (accel_name); - } - - /* clean up closure invalidate notification and disconnect */ - g_closure_remove_invalidate_notifier (entry->closure, accel_group, accel_closure_invalidate); - if (accel_quark) - g_signal_handlers_disconnect_matched (accel_group, - G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_CLOSURE, - signal_accel_activate, accel_quark, - closure, NULL, NULL); - - /* physically remove */ - accel_group->priv->n_accels -= 1; - memmove (entry, entry + 1, - (accel_group->priv->n_accels - pos) * sizeof (accel_group->priv->priv_accels[0])); - - /* and notify */ - if (accel_quark) - g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, closure); - - /* remove quick_accel_add() refcount */ - g_closure_unref (closure); -} - -static GtkAccelGroupEntry* -quick_accel_find (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - guint *count_p) -{ - GtkAccelGroupEntry *entry; - GtkAccelGroupEntry key; - - *count_p = 0; - - if (!accel_group->priv->n_accels) - return NULL; - - key.key.accel_key = accel_key; - key.key.accel_mods = accel_mods; - entry = bsearch (&key, accel_group->priv->priv_accels, accel_group->priv->n_accels, - sizeof (accel_group->priv->priv_accels[0]), bsearch_compare_accels); - - if (!entry) - return NULL; - - /* step back to the first member */ - for (; entry > accel_group->priv->priv_accels; entry--) - if (entry[-1].key.accel_key != accel_key || - entry[-1].key.accel_mods != accel_mods) - break; - /* count equal members */ - for (; entry + *count_p < accel_group->priv->priv_accels + accel_group->priv->n_accels; (*count_p)++) - if (entry[*count_p].key.accel_key != accel_key || - entry[*count_p].key.accel_mods != accel_mods) - break; - return entry; -} - -/** - * gtk_accel_group_connect: - * @accel_group: the accelerator group to install an accelerator in - * @accel_key: key value of the accelerator - * @accel_mods: modifier combination of the accelerator - * @accel_flags: a flag mask to configure this accelerator - * @closure: closure to be executed upon accelerator activation - * - * Installs an accelerator in this group. When @accel_group is being - * activated in response to a call to gtk_accel_groups_activate(), - * @closure will be invoked if the @accel_key and @accel_mods from - * gtk_accel_groups_activate() match those of this connection. - * - * The signature used for the @closure is that of #GtkAccelGroupActivate. - * - * Note that, due to implementation details, a single closure can - * only be connected to one accelerator group. - */ -void -gtk_accel_group_connect (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GtkAccelFlags accel_flags, - GClosure *closure) -{ - g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); - g_return_if_fail (closure != NULL); - g_return_if_fail (accel_key > 0); - g_return_if_fail (gtk_accel_group_from_accel_closure (closure) == NULL); - - g_object_ref (accel_group); - if (!closure->is_invalid) - quick_accel_add (accel_group, - gdk_keyval_to_lower (accel_key), - accel_mods, accel_flags, closure); - g_object_unref (accel_group); -} - -/** - * gtk_accel_group_disconnect: - * @accel_group: the accelerator group to remove an accelerator from - * @closure: (allow-none): the closure to remove from this accelerator - * group, or %NULL to remove all closures - * - * Removes an accelerator previously installed through - * gtk_accel_group_connect(). - * - * Returns: %TRUE if the closure was found and got disconnected - */ -gboolean -gtk_accel_group_disconnect (GtkAccelGroup *accel_group, - GClosure *closure) -{ - guint i; - - g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE); - - for (i = 0; i < accel_group->priv->n_accels; i++) - if (accel_group->priv->priv_accels[i].closure == closure) - { - g_object_ref (accel_group); - quick_accel_remove (accel_group, i); - g_object_unref (accel_group); - return TRUE; - } - return FALSE; -} - -/** - * gtk_accel_group_disconnect_key: - * @accel_group: the accelerator group to install an accelerator in - * @accel_key: key value of the accelerator - * @accel_mods: modifier combination of the accelerator - * - * Removes an accelerator previously installed through - * gtk_accel_group_connect(). - * - * Returns: %TRUE if there was an accelerator which could be - * removed, %FALSE otherwise - */ -gboolean -gtk_accel_group_disconnect_key (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods) -{ - GtkAccelGroupEntry *entries; - GSList *slist, *clist = NULL; - gboolean removed_one = FALSE; - guint n; - - g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE); - - g_object_ref (accel_group); - - accel_key = gdk_keyval_to_lower (accel_key); - entries = quick_accel_find (accel_group, accel_key, accel_mods, &n); - while (n--) - { - GClosure *closure = g_closure_ref (entries[n].closure); - - clist = g_slist_prepend (clist, closure); - } - - for (slist = clist; slist; slist = slist->next) - { - GClosure *closure = slist->data; - - removed_one |= gtk_accel_group_disconnect (accel_group, closure); - g_closure_unref (closure); - } - g_slist_free (clist); - - g_object_unref (accel_group); - - return removed_one; -} - -GSList* -_gtk_accel_group_get_accelerables (GtkAccelGroup *accel_group) -{ - g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL); - - return accel_group->priv->acceleratables; -} - -/** - * gtk_accel_group_query: - * @accel_group: the accelerator group to query - * @accel_key: key value of the accelerator - * @accel_mods: modifier combination of the accelerator - * @n_entries: (out) (optional): location to return the number - * of entries found, or %NULL - * - * Queries an accelerator group for all entries matching @accel_key - * and @accel_mods. - * - * Returns: (nullable) (transfer none) (array length=n_entries): an array of - * @n_entries #GtkAccelGroupEntry elements, or %NULL. The array - * is owned by GTK+ and must not be freed. - */ -GtkAccelGroupEntry* -gtk_accel_group_query (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - guint *n_entries) -{ - GtkAccelGroupEntry *entries; - guint n; - - g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL); - - entries = quick_accel_find (accel_group, gdk_keyval_to_lower (accel_key), accel_mods, &n); - - if (n_entries) - *n_entries = entries ? n : 0; - - return entries; -} - -/** - * gtk_accel_group_from_accel_closure: - * @closure: a #GClosure - * - * Finds the #GtkAccelGroup to which @closure is connected; - * see gtk_accel_group_connect(). - * - * Returns: (nullable) (transfer none): the #GtkAccelGroup to which @closure - * is connected, or %NULL - */ -GtkAccelGroup* -gtk_accel_group_from_accel_closure (GClosure *closure) -{ - guint i; - - g_return_val_if_fail (closure != NULL, NULL); - - /* A few remarks on what we do here. in general, we need a way to - * reverse lookup accel_groups from closures that are being used in - * accel groups. this could be done e.g via a hashtable. it is however - * cheaper (memory wise) to just use the invalidation notifier on the - * closure itself (which we need to install anyway), that contains the - * accel group as data which, besides needing to peek a bit at closure - * internals, works just as good. - */ - for (i = 0; i < G_CLOSURE_N_NOTIFIERS (closure); i++) - if (closure->notifiers[i].notify == accel_closure_invalidate) - return closure->notifiers[i].data; - - return NULL; -} - -/** - * gtk_accel_group_activate: - * @accel_group: a #GtkAccelGroup - * @accel_quark: the quark for the accelerator name - * @acceleratable: the #GObject, usually a #GtkWindow, on which - * to activate the accelerator - * @accel_key: accelerator keyval from a key event - * @accel_mods: keyboard state mask from a key event - * - * Finds the first accelerator in @accel_group that matches - * @accel_key and @accel_mods, and activates it. - * - * Returns: %TRUE if an accelerator was activated and handled - * this keypress - */ -gboolean -gtk_accel_group_activate (GtkAccelGroup *accel_group, - GQuark accel_quark, - GObject *acceleratable, - guint accel_key, - GdkModifierType accel_mods) -{ - gboolean was_handled; - - g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE); - g_return_val_if_fail (G_IS_OBJECT (acceleratable), FALSE); - - was_handled = FALSE; - g_signal_emit (accel_group, signal_accel_activate, accel_quark, - acceleratable, accel_key, accel_mods, &was_handled); - - return was_handled; -} - -/** - * gtk_accel_groups_activate: - * @object: the #GObject, usually a #GtkWindow, on which - * to activate the accelerator - * @accel_key: accelerator keyval from a key event - * @accel_mods: keyboard state mask from a key event - * - * Finds the first accelerator in any #GtkAccelGroup attached - * to @object that matches @accel_key and @accel_mods, and - * activates that accelerator. - * - * Returns: %TRUE if an accelerator was activated and handled - * this keypress - */ -gboolean -gtk_accel_groups_activate (GObject *object, - guint accel_key, - GdkModifierType accel_mods) -{ - g_return_val_if_fail (G_IS_OBJECT (object), FALSE); - - if (gtk_accelerator_valid (accel_key, accel_mods)) - { - gchar *accel_name; - GQuark accel_quark; - GSList *slist; - - accel_name = gtk_accelerator_name (accel_key, (accel_mods & gtk_accelerator_get_default_mod_mask ())); - accel_quark = g_quark_from_string (accel_name); - g_free (accel_name); - - for (slist = gtk_accel_groups_from_object (object); slist; slist = slist->next) - if (gtk_accel_group_activate (slist->data, accel_quark, object, accel_key, accel_mods)) - return TRUE; - } - - return FALSE; -} - /** * gtk_accelerator_valid: * @keyval: a GDK keyval |