1 /* gtkmnemonichash.c: Sets of mnemonics with cycling
2 *
3 * GTK - The GIMP Toolkit
4 * Copyright (C) 2002, Red Hat Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "gtkmnemonichash.h"
21
22 struct _GtkMnemnonicHash
23 {
24 GHashTable *hash;
25 };
26
27
28 GtkMnemonicHash *
_gtk_mnemonic_hash_new(void)29 _gtk_mnemonic_hash_new (void)
30 {
31 GtkMnemonicHash *mnemonic_hash = g_new (GtkMnemonicHash, 1);
32
33 mnemonic_hash->hash = g_hash_table_new (g_direct_hash, NULL);
34
35 return mnemonic_hash;
36 }
37
38 static void
mnemonic_hash_free_foreach(gpointer key,gpointer value,gpointer user)39 mnemonic_hash_free_foreach (gpointer key,
40 gpointer value,
41 gpointer user)
42 {
43 guint keyval = GPOINTER_TO_UINT (key);
44 GSList *targets = value;
45
46 gchar *name = gtk_accelerator_name (keyval, 0);
47
48 g_warning ("mnemonic \"%s\" wasn't removed for widget (%p)",
49 name, targets->data);
50 g_free (name);
51
52 g_slist_free (targets);
53 }
54
55 void
_gtk_mnemonic_hash_free(GtkMnemonicHash * mnemonic_hash)56 _gtk_mnemonic_hash_free (GtkMnemonicHash *mnemonic_hash)
57 {
58 g_hash_table_foreach (mnemonic_hash->hash,
59 mnemonic_hash_free_foreach,
60 NULL);
61
62 g_hash_table_destroy (mnemonic_hash->hash);
63 g_free (mnemonic_hash);
64 }
65
66 void
_gtk_mnemonic_hash_add(GtkMnemonicHash * mnemonic_hash,guint keyval,GtkWidget * target)67 _gtk_mnemonic_hash_add (GtkMnemonicHash *mnemonic_hash,
68 guint keyval,
69 GtkWidget *target)
70 {
71 gpointer key = GUINT_TO_POINTER (keyval);
72 GSList *targets, *new_targets;
73
74 g_return_if_fail (GTK_IS_WIDGET (target));
75
76 targets = g_hash_table_lookup (mnemonic_hash->hash, key);
77 g_return_if_fail (g_slist_find (targets, target) == NULL);
78
79 new_targets = g_slist_append (targets, target);
80 if (new_targets != targets)
81 g_hash_table_insert (mnemonic_hash->hash, key, new_targets);
82 }
83
84 void
_gtk_mnemonic_hash_remove(GtkMnemonicHash * mnemonic_hash,guint keyval,GtkWidget * target)85 _gtk_mnemonic_hash_remove (GtkMnemonicHash *mnemonic_hash,
86 guint keyval,
87 GtkWidget *target)
88 {
89 gpointer key = GUINT_TO_POINTER (keyval);
90 GSList *targets, *new_targets;
91
92 g_return_if_fail (GTK_IS_WIDGET (target));
93
94 targets = g_hash_table_lookup (mnemonic_hash->hash, key);
95
96 g_return_if_fail (targets && g_slist_find (targets, target) != NULL);
97
98 new_targets = g_slist_remove (targets, target);
99 if (new_targets != targets)
100 {
101 if (new_targets == NULL)
102 g_hash_table_remove (mnemonic_hash->hash, key);
103 else
104 g_hash_table_insert (mnemonic_hash->hash, key, new_targets);
105 }
106 }
107
108 gboolean
_gtk_mnemonic_hash_activate(GtkMnemonicHash * mnemonic_hash,guint keyval)109 _gtk_mnemonic_hash_activate (GtkMnemonicHash *mnemonic_hash,
110 guint keyval)
111 {
112 GSList *list, *targets;
113 GtkWidget *widget, *chosen_widget;
114 GdkWindow *window;
115 gboolean overloaded;
116
117 targets = g_hash_table_lookup (mnemonic_hash->hash,
118 GUINT_TO_POINTER (keyval));
119 if (!targets)
120 return FALSE;
121
122 overloaded = FALSE;
123 chosen_widget = NULL;
124 for (list = targets; list; list = list->next)
125 {
126 widget = GTK_WIDGET (list->data);
127 window = gtk_widget_get_window (widget);
128
129 if (gtk_widget_is_sensitive (widget) &&
130 gtk_widget_get_mapped (widget) &&
131 window && gdk_window_is_viewable (window))
132 {
133 if (chosen_widget)
134 {
135 overloaded = TRUE;
136 break;
137 }
138 else
139 chosen_widget = widget;
140 }
141 }
142
143 if (chosen_widget)
144 {
145 /* For round robin we put the activated entry on
146 * the end of the list after activation
147 */
148 targets = g_slist_remove (targets, chosen_widget);
149 targets = g_slist_append (targets, chosen_widget);
150 g_hash_table_insert (mnemonic_hash->hash,
151 GUINT_TO_POINTER (keyval),
152 targets);
153
154 return gtk_widget_mnemonic_activate (chosen_widget, overloaded);
155 }
156 return FALSE;
157 }
158
159 GSList *
_gtk_mnemonic_hash_lookup(GtkMnemonicHash * mnemonic_hash,guint keyval)160 _gtk_mnemonic_hash_lookup (GtkMnemonicHash *mnemonic_hash,
161 guint keyval)
162 {
163 return g_hash_table_lookup (mnemonic_hash->hash, GUINT_TO_POINTER (keyval));
164 }
165
166 static void
mnemonic_hash_foreach_func(gpointer key,gpointer value,gpointer data)167 mnemonic_hash_foreach_func (gpointer key,
168 gpointer value,
169 gpointer data)
170 {
171 struct {
172 GtkMnemonicHashForeach func;
173 gpointer func_data;
174 } *info = data;
175
176 guint keyval = GPOINTER_TO_UINT (key);
177 GSList *targets = value;
178
179 (*info->func) (keyval, targets, info->func_data);
180 }
181
182 void
_gtk_mnemonic_hash_foreach(GtkMnemonicHash * mnemonic_hash,GtkMnemonicHashForeach func,gpointer func_data)183 _gtk_mnemonic_hash_foreach (GtkMnemonicHash *mnemonic_hash,
184 GtkMnemonicHashForeach func,
185 gpointer func_data)
186 {
187 struct {
188 GtkMnemonicHashForeach func;
189 gpointer func_data;
190 } info;
191
192 info.func = func;
193 info.func_data = func_data;
194
195 g_hash_table_foreach (mnemonic_hash->hash,
196 mnemonic_hash_foreach_func,
197 &info);
198 }
199