1 /*
2 * keys.c: Key dialog widget
3 *
4 * Written by: Ullrich Hafner
5 *
6 * Copyright (C) 1998 Ullrich Hafner <hafner@bigfoot.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
21 */
22
23 /*
24 * $Date: 2000/01/09 17:31:29 $
25 * $Author: hafner $
26 * $Revision: 1.26 $
27 * $State: Exp $
28 */
29
30 #include "config.h"
31
32 #if HAVE_STRING_H
33 # include <string.h>
34 #else /* not HAVE_STRING_H */
35 # include <strings.h>
36 #endif /* not HAVE_STRING_H */
37
38 #include <ctype.h>
39 #include <gtk/gtk.h>
40 #include <gdk/gdkx.h>
41 #include <X11/keysym.h>
42 #include "proplist_t.h"
43
44 #include "keys.h"
45 #include "misc.h"
46 #include "icons.h"
47 #include "error.h"
48
49 /*******************************************************************************
50
51 global variables
52
53 *******************************************************************************/
54
55 extern GtkWidget *main_window; /* from window.c */
56 extern proplist_t windowmaker; /* from window.c */
57
58 /*******************************************************************************
59
60 local variables
61
62 *******************************************************************************/
63
64 static GList *keylist = NULL;
65
66 /*******************************************************************************
67
68 prototypes
69
70 *******************************************************************************/
71
72 static GList *
73 keysym_list (void);
74 static int
75 compare (const void *string1, const void *string2);
76 static void
77 set_key (GtkWidget *widget, gpointer ptr);
78 static gint
79 grab_key (GtkWidget *widget, GdkEventKey *event, gpointer ptr);
80 static gint
81 leave_focus (GtkWidget *widget, GdkEventAny *event, gpointer ptr);
82 static void
83 toggle_pressed (GtkWidget *widget, gpointer ptr);
84 static bool_t
85 modifier_available (const char *modifier, const char **modifier_list);
86
87 /*******************************************************************************
88
89 public code
90
91 *******************************************************************************/
92
93 GtkWidget *
key_dialog(const char * keytext,GtkTooltips * tooltips,const char * infotext,void (* update)(const key_widget_t * data),void * data)94 key_dialog (const char *keytext, GtkTooltips *tooltips, const char *infotext,
95 void (*update) (const key_widget_t *data), void *data)
96 /*
97 * Generate shortcurt widget.
98 *
99 * Side effects: user data of widget object is set to key_widget_t struct.
100 */
101 {
102 GtkWidget *box;
103 GtkWidget *lbox;
104 key_widget_t *kw = Calloc (1, sizeof (key_widget_t));
105 const char **modlist = modifier_list ();
106 unsigned n;
107 unsigned nmod;
108
109 for (nmod = n = 0; modlist [n]; n++)
110 if (strncaseeq (modlist [n], "mod", 3))
111 nmod++;
112
113 if (!keylist)
114 keylist = keysym_list ();
115
116 kw->data = data;
117 kw->update = update;
118
119 box = gtk_hbox_new (FALSE, 0);
120 lbox = gtk_vbox_new (FALSE, 0);
121 gtk_box_pack_start (GTK_BOX (box), lbox, TRUE, TRUE, 0);
122
123 /*
124 * Check buttons for control, shift and mod1-5
125 */
126 {
127 GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
128 GtkWidget *button;
129
130 gtk_box_pack_start (GTK_BOX (lbox), hbox, TRUE, TRUE, 0);
131
132 if (nmod <= 1)
133 {
134 kw->control = kw->lcontrol = button
135 = gtk_check_button_new_with_label (_("Control"));
136 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
137 if (infotext)
138 gtk_tooltips_set_tip (tooltips, button, infotext, NULL);
139
140 kw->shift = kw->lshift = button
141 = gtk_check_button_new_with_label (_("Shift"));
142 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
143 if (infotext)
144 gtk_tooltips_set_tip (tooltips, button, infotext, NULL);
145
146 for (n = 0; n < 5; n++)
147 {
148 char *modname = g_strdup_printf ("Mod%d", n + 1);
149
150 if (modifier_available (modname, modlist))
151 {
152 kw->mod [n] = kw->lmod [n] = button
153 = gtk_check_button_new_with_label (modname);
154 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
155 if (infotext)
156 gtk_tooltips_set_tip (tooltips, button, infotext, NULL);
157 }
158 else
159 kw->mod [n] = NULL;
160 Free (modname);
161 }
162 }
163 else
164 {
165 GtkWidget *vbox;
166 GtkWidget *gbox;
167
168 vbox = gtk_vbox_new (FALSE, 0);
169 gbox = gtk_hbox_new (TRUE, 0);
170 kw->lcontrol = gtk_label_new (_("Control"));
171 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 5);
172 gtk_box_pack_start (GTK_BOX (vbox), kw->lcontrol, TRUE, TRUE, 0);
173 kw->control = button = gtk_check_button_new ();
174 gtk_box_pack_start (GTK_BOX (gbox), button, FALSE, FALSE, 0);
175 gtk_box_pack_start (GTK_BOX (vbox), gbox, TRUE, TRUE, 0);
176 if (infotext)
177 gtk_tooltips_set_tip (tooltips, button, infotext, NULL);
178
179 gbox = gtk_hbox_new (TRUE, 0);
180 vbox = gtk_vbox_new (FALSE, 0);
181 kw->lshift = gtk_label_new (_("Shift"));
182 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 5);
183 gtk_box_pack_start (GTK_BOX (vbox), kw->lshift, TRUE, TRUE, 0);
184 kw->shift = button = gtk_check_button_new ();
185 gtk_box_pack_start (GTK_BOX (gbox), button, FALSE, FALSE, 0);
186 gtk_box_pack_start (GTK_BOX (vbox), gbox, TRUE, TRUE, 0);
187 if (infotext)
188 gtk_tooltips_set_tip (tooltips, button, infotext, NULL);
189
190 for (n = 0; n < 5; n++)
191 {
192 char *modname = g_strdup_printf ("Mod%d", n + 1);
193
194 if (modifier_available (modname, modlist))
195 {
196 if (n == 0 && nmod == 5)
197 {
198 hbox = gtk_hbox_new (FALSE, 0);
199 gtk_box_pack_start (GTK_BOX (lbox), hbox, TRUE, TRUE, 0);
200 }
201
202 kw->lmod [n] = gtk_label_new (modname);
203 gbox = gtk_hbox_new (TRUE, 0);
204 vbox = gtk_vbox_new (FALSE, 0);
205 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 5);
206 gtk_box_pack_start (GTK_BOX (vbox), kw->lmod [n], TRUE, TRUE, 0);
207 kw->mod [n] = button = gtk_check_button_new ();
208 gtk_box_pack_start (GTK_BOX (gbox), button, FALSE, FALSE, 0);
209 gtk_box_pack_start (GTK_BOX (vbox), gbox, TRUE, TRUE, 0);
210 if (infotext)
211 gtk_tooltips_set_tip (tooltips, button, infotext, NULL);
212 }
213 else
214 kw->mod [n] = NULL;
215 Free (modname);
216 }
217 }
218 }
219 /*
220 * Combo box for all available keysyms
221 */
222 {
223 GtkWidget *cb;
224
225 kw->combo = cb = gtk_combo_new ();
226 gtk_combo_set_popdown_strings (GTK_COMBO (cb), keylist);
227 gtk_widget_set_usize (GTK_COMBO (cb)->entry, 120, 0);
228 gtk_widget_set_usize (cb, 120, 0);
229 gtk_box_pack_start (GTK_BOX (lbox), cb, FALSE, TRUE, 5);
230 if (infotext)
231 gtk_tooltips_set_tip (tooltips, GTK_COMBO (cb)->entry, infotext,
232 NULL);
233 kw->keyname = GTK_COMBO (cb)->entry;
234 }
235 /*
236 * Eventbox for key grabber
237 */
238 {
239 GtkWidget *bbox = gtk_hbutton_box_new ();
240 GtkWidget *pixmap;
241
242 pixmap = gtk_pixmap_new (p_array [P_KEYBOARD].pixmap,
243 p_array [P_KEYBOARD].mask);
244
245 kw->toggle = gtk_toggle_button_new ();
246
247 gtk_box_pack_start (GTK_BOX (bbox), kw->toggle, FALSE, TRUE, 0);
248 gtk_box_pack_start (GTK_BOX (lbox), bbox, FALSE, TRUE, 0);
249 gtk_widget_show (kw->toggle);
250
251 gtk_container_add (GTK_CONTAINER (kw->toggle), pixmap);
252 gtk_container_set_border_width (GTK_CONTAINER (kw->toggle), 8);
253
254 gtk_tooltips_set_tip (tooltips, kw->toggle,
255 _("Press this button to activate capture mode "
256 "- then press the desired key sequence."), NULL);
257 gtk_signal_connect (GTK_OBJECT(kw->toggle), "clicked",
258 GTK_SIGNAL_FUNC (toggle_pressed), kw);
259 gtk_signal_connect (GTK_OBJECT(kw->toggle), "focus_out_event",
260 GTK_SIGNAL_FUNC (leave_focus), kw);
261 gtk_signal_connect (GTK_OBJECT(kw->toggle), "key_press_event",
262 GTK_SIGNAL_FUNC (grab_key), kw);
263
264 gtk_widget_show_all (kw->toggle);
265 }
266
267 gtk_widget_show_all (box);
268 gtk_object_set_user_data (GTK_OBJECT (box), kw);
269
270 update_keywidget (kw, keytext);
271
272 gtk_signal_connect (GTK_OBJECT (kw->control), "toggled",
273 GTK_SIGNAL_FUNC (set_key), (gpointer) kw);
274 for (n = 0; n < 5; n++)
275 if (kw->mod [n])
276 gtk_signal_connect (GTK_OBJECT (kw->mod [n]), "toggled",
277 GTK_SIGNAL_FUNC (set_key), (gpointer) kw);
278 gtk_signal_connect (GTK_OBJECT (kw->shift), "toggled",
279 GTK_SIGNAL_FUNC (set_key), (gpointer) kw);
280 gtk_signal_connect (GTK_OBJECT (GTK_COMBO (kw->combo)->entry), "changed",
281 GTK_SIGNAL_FUNC (set_key), (gpointer) kw);
282
283 return box;
284 }
285
286 void
update_keywidget(key_widget_t * kw,const char * keytext)287 update_keywidget (key_widget_t *kw, const char *keytext)
288 /*
289 * Update keywidget with given keyname (Window Maker string format)
290 */
291 {
292 bool_t control, meta, shift, mod [5];
293 unsigned number, n;
294
295 /*
296 * Extract modifiers and keysym from attribute 'key'
297 */
298 {
299 char *s = g_strdup (keytext);
300
301 control = meta = shift = mod [0] = mod [1] = mod [2]
302 = mod [3] = mod [4] = FALSE;
303 number = 0;
304
305 if (!strcaseeq (s, "None"))
306 {
307 char *next;
308 char *cur = s;
309
310 while ((next = strchr (cur, '+')))
311 {
312 *next = 0;
313 if (strcaseeq (cur, "Control"))
314 control = TRUE;
315 else if (strcaseeq (cur, "Meta") || strcaseeq (cur, "Alt"))
316 meta = TRUE;
317 else if (strcaseeq (cur, "Mod1"))
318 mod [0] = TRUE;
319 else if (strcaseeq (cur, "Mod2"))
320 mod [1] = TRUE;
321 else if (strcaseeq (cur, "Mod3"))
322 mod [2] = TRUE;
323 else if (strcaseeq (cur, "Mod4"))
324 mod [3] = TRUE;
325 else if (strcaseeq (cur, "Mod5"))
326 mod [4] = TRUE;
327 else if (strcaseeq (cur, "Shift"))
328 shift = TRUE;
329 cur = next + 1;
330 }
331 {
332 GList *l = g_list_first (keylist);
333
334 while (l)
335 {
336 if (strcaseeq ((char *) l->data, cur))
337 break;
338 number++;
339 l = l->next;
340 }
341 if (number > g_list_length (keylist))
342 {
343 number = 0;
344 control = meta = shift = mod [0] = mod [1] = mod [2]
345 = mod [3] = mod [4] = FALSE;
346 }
347 }
348
349 }
350 kw->keytext = s;
351 }
352
353 gtk_list_select_item (GTK_LIST (GTK_COMBO (kw->combo)->list), number);
354
355 gtk_widget_set_sensitive (kw->lcontrol, number);
356 gtk_widget_set_sensitive (kw->lshift, number);
357 for (n = 0; n < 5; n++)
358 if (kw->mod [n])
359 gtk_widget_set_sensitive (kw->lmod [n], number);
360 gtk_widget_set_sensitive (kw->control, number);
361 gtk_widget_set_sensitive (kw->shift, number);
362 for (n = 0; n < 5; n++)
363 if (kw->mod [n])
364 gtk_widget_set_sensitive (kw->mod [n], number);
365
366 {
367 proplist_t plmod = WMCreatePLString ("ModifierKey");
368 char *modkey = WMGetFromPLString (WMGetFromPLDictionary (windowmaker,
369 plmod));
370
371 for (n = 0; n < 5; n++)
372 {
373 if (kw->mod [n])
374 {
375 char *modname = g_strdup_printf ("Mod%d", n + 1);
376
377 if (strcaseeq (modname, modkey))
378 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [n]),
379 mod [n] || meta);
380 else
381 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [n]),
382 mod [n]);
383 Free (modname);
384 }
385 }
386
387 WMReleasePropList (plmod);
388 }
389
390 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->shift), shift);
391 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->control), control);
392 }
393
394 const char **
modifier_list(void)395 modifier_list (void)
396 /*
397 * Get list of defined modifiers
398 */
399 {
400 static const char **modifiers = NULL;
401
402 if (!modifiers)
403 {
404 XModifierKeymap *modmap = XGetModifierMapping (GDK_DISPLAY());
405 const char *modlist[9] = {"Shift", "Lock", "Control", "Mod1",
406 "Mod2", "Mod3", "Mod4", "Mod5", NULL};
407 unsigned n = 0;
408
409 if (modmap)
410 {
411 unsigned mkey = modmap->max_keypermod;
412 unsigned modifier, k;
413
414 modifiers = Calloc (sizeof (modlist) / sizeof (modlist [0]),
415 sizeof (const char *));
416 for (modifier = 0; modifier < 8; modifier++)
417 for (k = 0; k < mkey; k++)
418 {
419 KeyCode c = modmap->modifiermap [modifier * mkey + k];
420 if (c != 0)
421 {
422 modifiers [n++] = g_strdup (modlist [modifier]);
423 break;
424 }
425 }
426 XFree (modmap);
427 modifiers [n++] = NULL;
428 }
429 }
430
431 return modifiers;
432 }
433
434 /*******************************************************************************
435
436 private code
437
438 *******************************************************************************/
439
440 static gint
leave_focus(GtkWidget * widget,GdkEventAny * event,gpointer ptr)441 leave_focus (GtkWidget *widget, GdkEventAny *event, gpointer ptr)
442 {
443 GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR);
444
445 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
446 gdk_window_set_cursor (main_window->window, cursor);
447 gdk_cursor_destroy (cursor);
448
449 return TRUE;
450 }
451
452 static void
toggle_pressed(GtkWidget * widget,gpointer ptr)453 toggle_pressed (GtkWidget *widget, gpointer ptr)
454 {
455 GdkCursor *cursor = gdk_cursor_new (GTK_TOGGLE_BUTTON (widget)->active
456 ? GDK_HAND2 : GDK_LEFT_PTR);
457 gdk_window_set_cursor (main_window->window, cursor);
458 gdk_cursor_destroy (cursor);
459 }
460
461 static gint
grab_key(GtkWidget * widget,GdkEventKey * event,gpointer ptr)462 grab_key (GtkWidget *widget, GdkEventKey *event, gpointer ptr)
463 {
464 key_widget_t *kw = (key_widget_t *) ptr;
465
466 if (GTK_TOGGLE_BUTTON (widget)->active && !IsModifierKey (event->keyval))
467 {
468 GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR);
469
470 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
471 gdk_window_set_cursor (main_window->window, cursor);
472 gdk_cursor_destroy (cursor);
473
474 gtk_entry_set_text (GTK_ENTRY (kw->keyname),
475 XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), XKeysymToKeycode (GDK_DISPLAY(), event->keyval), 0)));
476
477 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->control),
478 event->state & GDK_CONTROL_MASK);
479 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->shift),
480 event->state & GDK_SHIFT_MASK);
481 if (kw->mod [0])
482 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [0]),
483 event->state & GDK_MOD1_MASK);
484 if (kw->mod [1])
485 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [1]),
486 event->state & GDK_MOD2_MASK);
487 if (kw->mod [2])
488 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [2]),
489 event->state & GDK_MOD3_MASK);
490 if (kw->mod [3])
491 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [3]),
492 event->state & GDK_MOD4_MASK);
493 if (kw->mod [4])
494 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [4]),
495 event->state & GDK_MOD5_MASK);
496 return TRUE;
497 }
498
499 return FALSE;
500 }
501
502 static GList *
keysym_list(void)503 keysym_list (void)
504 /*
505 * Get list of available key symbols
506 */
507 {
508 int m, M; /* minimum and maximum keycode */
509 int kpk; /* keys per keycode */
510 int i, k; /* counter */
511 KeySym *keysyms; /* all available keysyms */
512 char **keyname; /* array of keynames */
513 static GList *list = NULL; /* list of keynames */
514
515 if (list)
516 return list; /* already computed */
517
518 XDisplayKeycodes (GDK_DISPLAY(), &m, &M);
519 keysyms = XGetKeyboardMapping (GDK_DISPLAY(), m, M - m + 1, &kpk);
520
521 keyname = Calloc ((M - m + 1 + 1), sizeof (char *));
522
523 for (i = k = 0; i < (M - m + 1); i++)
524 if (!IsModifierKey (keysyms [i * kpk]))
525 {
526 char *name = XKeysymToString (keysyms [i * kpk]);
527
528 if (name)
529 {
530 keyname [k] = g_strdup (name);
531 #if 0
532 if (isalpha (*keyname [k]))
533 *keyname [k] = toupper (*keyname [k]);
534 #endif
535 k++;
536 }
537 }
538 XFree (keysyms);
539
540 qsort (keyname, k, sizeof (char *), compare);
541
542 list = g_list_append (NULL, "None");
543 for (i = 0; i < k; i++)
544 list = g_list_append (list, keyname [i]);
545
546 Free (keyname);
547
548 return list;
549 }
550
551 static int
compare(const void * string1,const void * string2)552 compare (const void *string1, const void *string2)
553 /*
554 * Compare two keynames. Sort by 1) string length and 2) alphabet.
555 *
556 * Return value:
557 * < 0 : string1 < string2
558 * == 0 : string1 = string2
559 * > 0 : string1 > string2
560 */
561 {
562 const char *s1 = *(char **) string1;
563 const char *s2 = *(char **) string2;
564 unsigned l1 = strlen (s1);
565 unsigned l2 = strlen (s2);
566
567 /*
568 * KP_ entries should be grouped together
569 */
570 {
571 char *t1 = g_strdup (s1);
572 char *t2 = g_strdup (s2);
573
574 if (l1 > 3)
575 t1 [3] = 0;
576 if (l2 > 3)
577 t2 [3] = 0;
578
579 if (strcaseeq (t1, "KP_") && !strcaseeq (t2, "KP_"))
580 {
581 Free (t1);
582 Free (t2);
583 return +1;
584 }
585 if (strcaseeq (t2, "KP_") && !strcaseeq (t1, "KP_"))
586 {
587 Free (t1);
588 Free (t2);
589 return -1;
590 }
591 Free (t1);
592 Free (t2);
593 }
594 /*
595 * Fnum entries should be grouped together
596 */
597 if (s1 [0] != 'F' && l1 > 1)
598 l1 +=2;
599 if (s2 [0] != 'F' && l2 > 1)
600 l2 +=2;
601
602 if (l1 > 3 && l2 > 3)
603 return strcmp (s1, s2);
604
605 if (l1 != l2)
606 return l1 - l2;
607
608 if (l1 == 1) /* letter or digit */
609 return *s1 - *s2;
610
611 return 0;
612 }
613
614 static void
set_key(GtkWidget * widget,gpointer ptr)615 set_key (GtkWidget *widget, gpointer ptr)
616 /*
617 * Change key attribute
618 */
619 {
620 key_widget_t *kw = (key_widget_t *) ptr;
621 const char *text = gtk_entry_get_text (GTK_ENTRY (kw->keyname));
622 unsigned n;
623
624 if (strcaseeq (text, "None"))
625 {
626 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->control), FALSE);
627 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->shift), FALSE);
628 for (n = 0; n < 5; n++)
629 if (kw->mod [n])
630 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (kw->mod [n]),
631 FALSE);
632
633 gtk_widget_set_sensitive (kw->control, FALSE);
634 gtk_widget_set_sensitive (kw->shift, FALSE);
635 for (n = 0; n < 5; n++)
636 if (kw->mod [n])
637 gtk_widget_set_sensitive (kw->mod [n], FALSE);
638 gtk_widget_set_sensitive (kw->lcontrol, FALSE);
639 gtk_widget_set_sensitive (kw->lshift, FALSE);
640 for (n = 0; n < 5; n++)
641 if (kw->mod [n])
642 gtk_widget_set_sensitive (kw->lmod [n], FALSE);
643
644 Free (kw->keytext);
645 kw->keytext = g_strdup (text);
646 }
647 else
648 {
649 char tmp [MAXSTRLEN];
650
651 gtk_widget_set_sensitive (kw->control, TRUE);
652 gtk_widget_set_sensitive (kw->shift, TRUE);
653 for (n = 0; n < 5; n++)
654 if (kw->mod [n])
655 gtk_widget_set_sensitive (kw->mod [n], TRUE);
656
657 gtk_widget_set_sensitive (kw->lcontrol, TRUE);
658 gtk_widget_set_sensitive (kw->lshift, TRUE);
659 for (n = 0; n < 5; n++)
660 if (kw->mod [n])
661 gtk_widget_set_sensitive (kw->lmod [n], TRUE);
662
663 tmp [0] = 0;
664 if (GTK_TOGGLE_BUTTON (kw->control)->active)
665 strcat (tmp, "Control+");
666 if (GTK_TOGGLE_BUTTON (kw->shift)->active)
667 strcat (tmp, "Shift+");
668 for (n = 0; n < 5; n++)
669 if (kw->mod [n])
670 if (GTK_TOGGLE_BUTTON (kw->mod [n])->active)
671 {
672 char *mod = g_strdup_printf ("Mod%d+", n + 1);
673 strcat (tmp, mod);
674 Free (mod);
675 }
676
677
678 strcat (tmp, text);
679
680 Free (kw->keytext);
681 kw->keytext = g_strdup (tmp);
682 }
683
684 kw->update ((const key_widget_t *) kw);
685 }
686
687 static bool_t
modifier_available(const char * modifier,const char ** modifier_list)688 modifier_available (const char *modifier, const char **modifier_list)
689 {
690 unsigned n;
691
692 for (n = 0; *modifier_list; modifier_list++)
693 if (strcaseeq (*modifier_list, modifier))
694 return TRUE;
695
696 return FALSE;
697 }
698