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