]> Pileus Git - ~andy/gtk/blob - gtk/gtkaccelerator.c
It's all in the changelog. Well, almost all.
[~andy/gtk] / gtk / gtkaccelerator.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <ctype.h>
19 #include "gtkaccelerator.h"
20 #include "gtksignal.h"
21 #include "gtkwidget.h"
22
23
24 typedef struct _GtkAcceleratorEntry GtkAcceleratorEntry;
25
26 struct _GtkAcceleratorEntry
27 {
28   guint8 modifiers;
29   GtkObject *object;
30   gint signal_num;
31 };
32
33
34 static void gtk_accelerator_table_init  (GtkAcceleratorTable *table);
35 static void gtk_accelerator_table_clean (GtkAcceleratorTable *table);
36
37
38 static GtkAcceleratorTable *default_table = NULL;
39 static GSList *tables = NULL;
40 static guint8 gtk_accelerator_table_default_mod_mask = ~0;
41
42
43 GtkAcceleratorTable*
44 gtk_accelerator_table_new ()
45 {
46   GtkAcceleratorTable *table;
47
48   table = g_new (GtkAcceleratorTable, 1);
49   gtk_accelerator_table_init (table);
50
51   tables = g_slist_prepend (tables, table);
52
53   return table;
54 }
55
56 GtkAcceleratorTable*
57 gtk_accelerator_table_find (GtkObject   *object,
58                             const gchar *signal_name,
59                             guchar       accelerator_key,
60                             guint8       accelerator_mods)
61 {
62   GtkAcceleratorTable *table;
63   GtkAcceleratorEntry *entry;
64   GSList *tmp_list;
65   GList *entries;
66   gint signal_num;
67   guint hash;
68
69   g_return_val_if_fail (object != NULL, NULL);
70   g_return_val_if_fail (signal_name != NULL, NULL);
71
72   signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object));
73   hash = (guint) accelerator_key;
74
75   tmp_list = tables;
76   while (tmp_list)
77     {
78       table = tmp_list->data;
79       tmp_list = tmp_list->next;
80
81       entries = table->entries[hash];
82       while (entries)
83         {
84           entry = entries->data;
85           entries = entries->next;
86
87           if ((entry->object == object) &&
88               (entry->signal_num == signal_num) &&
89               ((entry->modifiers & table->modifier_mask) ==
90                (accelerator_mods & table->modifier_mask)))
91             return table;
92         }
93     }
94
95   return NULL;
96 }
97
98 GtkAcceleratorTable*
99 gtk_accelerator_table_ref (GtkAcceleratorTable *table)
100 {
101   g_return_val_if_fail (table != NULL, NULL);
102
103   table->ref_count += 1;
104   return table;
105 }
106
107 void
108 gtk_accelerator_table_unref (GtkAcceleratorTable *table)
109 {
110   g_return_if_fail (table != NULL);
111
112   table->ref_count -= 1;
113   if (table->ref_count <= 0)
114     {
115       tables = g_slist_remove (tables, table);
116       gtk_accelerator_table_clean (table);
117       g_free (table);
118     }
119 }
120
121 void
122 gtk_accelerator_table_install (GtkAcceleratorTable *table,
123                                GtkObject           *object,
124                                const gchar         *signal_name,
125                                guchar               accelerator_key,
126                                guint8               accelerator_mods)
127 {
128   GtkAcceleratorEntry *entry;
129   GList *entries;
130   gchar *signame;
131   gint signal_num;
132   guint hash;
133
134   g_return_if_fail (object != NULL);
135
136   if (!table)
137     {
138       if (!default_table)
139         default_table = gtk_accelerator_table_new ();
140       table = default_table;
141     }
142
143   signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object));
144   g_return_if_fail (signal_num != 0);
145
146   hash = (guint) accelerator_key;
147   entries = table->entries[hash];
148
149   while (entries)
150     {
151       entry = entries->data;
152
153       if ((entry->modifiers & table->modifier_mask) ==
154           (accelerator_mods & table->modifier_mask))
155         {
156           if (GTK_IS_WIDGET (entry->object))
157             {
158               signame = gtk_signal_name (entry->signal_num);
159               gtk_signal_emit_by_name (entry->object,
160                                        "remove_accelerator",
161                                        signame);
162             }
163
164           entry->modifiers = accelerator_mods;
165           entry->object = object;
166           entry->signal_num = signal_num;
167           return;
168         }
169
170       entries = entries->next;
171     }
172
173   entry = g_new (GtkAcceleratorEntry, 1);
174   entry->modifiers = accelerator_mods;
175   entry->object = object;
176   entry->signal_num = signal_num;
177
178   table->entries[hash] = g_list_prepend (table->entries[hash], entry);
179 }
180
181 void
182 gtk_accelerator_table_remove (GtkAcceleratorTable *table,
183                               GtkObject           *object,
184                               const gchar         *signal_name)
185 {
186   GtkAcceleratorEntry *entry;
187   GList *entries;
188   GList *temp_list;
189   gint signal_num;
190   gint i;
191
192   g_return_if_fail (object != NULL);
193
194   if (!table)
195     {
196       if (!default_table)
197         default_table = gtk_accelerator_table_new ();
198       table = default_table;
199     }
200
201   signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object));
202   g_return_if_fail (signal_num != 0);
203
204   for (i = 0; i < 256; i++)
205     {
206       entries = table->entries[i];
207
208       while (entries)
209         {
210           entry = entries->data;
211
212           if ((entry->object == object) && (entry->signal_num == signal_num))
213             {
214               g_free (entry);
215
216               temp_list = entries;
217               if (entries->next)
218                 entries->next->prev = entries->prev;
219               if (entries->prev)
220                 entries->prev->next = entries->next;
221               if (table->entries[i] == entries)
222                 table->entries[i] = entries->next;
223
224               temp_list->next = NULL;
225               temp_list->prev = NULL;
226               g_list_free (temp_list);
227
228               return;
229             }
230
231           entries = entries->next;
232         }
233     }
234 }
235
236 gint
237 gtk_accelerator_table_check (GtkAcceleratorTable *table,
238                              const guchar         accelerator_key,
239                              guint8               accelerator_mods)
240 {
241   GtkAcceleratorEntry *entry;
242   GList *entries;
243   guint hash;
244
245   if (!table)
246     {
247       if (!default_table)
248         default_table = gtk_accelerator_table_new ();
249       table = default_table;
250     }
251
252   hash = (guint) accelerator_key;
253   entries = table->entries[hash];
254
255   while (entries)
256     {
257       entry = entries->data;
258
259       if ((entry->modifiers & table->modifier_mask) ==
260           (accelerator_mods & table->modifier_mask))
261         {
262           gtk_signal_emit (entry->object, entry->signal_num);
263           return TRUE;
264         }
265
266       entries = entries->next;
267     }
268
269   if (!isupper (hash))
270     {
271       hash = toupper (hash);
272       entries = table->entries[hash];
273
274       while (entries)
275         {
276           entry = entries->data;
277
278           if (((entry->modifiers & table->modifier_mask) ==
279                (accelerator_mods & table->modifier_mask)) &&
280               (GTK_IS_WIDGET (entry->object) &&
281                GTK_WIDGET_SENSITIVE (entry->object)))
282             {
283               gtk_signal_emit (entry->object, entry->signal_num);
284               return TRUE;
285             }
286
287           entries = entries->next;
288         }
289     }
290
291   return FALSE;
292 }
293
294 void
295 gtk_accelerator_table_set_mod_mask (GtkAcceleratorTable *table,
296                                     guint8               modifier_mask)
297 {
298   if (table == NULL)
299     {
300       gtk_accelerator_table_default_mod_mask = modifier_mask;
301     }
302   else
303     {
304       table->modifier_mask = modifier_mask;
305     }
306 }
307
308 static void
309 gtk_accelerator_table_init (GtkAcceleratorTable *table)
310 {
311   gint i;
312
313   g_return_if_fail (table != NULL);
314
315   for (i = 0; i < 256; i++)
316     table->entries[i] = NULL;
317
318   table->ref_count = 1;
319   table->modifier_mask = gtk_accelerator_table_default_mod_mask;
320 }
321
322 static void
323 gtk_accelerator_table_clean (GtkAcceleratorTable *table)
324 {
325   GtkAcceleratorEntry *entry;
326   GList *entries;
327   gint i;
328
329   g_return_if_fail (table != NULL);
330
331   for (i = 0; i < 256; i++)
332     {
333       entries = table->entries[i];
334       while (entries)
335         {
336           entry = entries->data;
337           entries = entries->next;
338
339           g_free (entry);
340         }
341
342       g_list_free (table->entries[i]);
343       table->entries[i] = NULL;
344     }
345 }