1 /* xkeycaps, Copyright (c) 1991, 1992, 1993, 1994, 1997, 1998
2  * by Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or
10  * implied warranty.
11  */
12 
13 #if defined(__STDC__) && defined(__unix)
14 #include <unistd.h>
15 #endif
16 
17 #include <stdio.h>
18 #include <string.h>
19 #include <time.h>
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 
24 #ifndef NO_UNAME
25 # include <sys/utsname.h>
26 #endif
27 
28 #include <X11/X.h>
29 #include <X11/Xos.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/Xproto.h>
33 
34 #include <X11/StringDefs.h>
35 #include <X11/Intrinsic.h>
36 #include <X11/Shell.h>
37 
38 #include <X11/Xmu/WinUtil.h>
39 #include <X11/Xmu/Error.h>
40 
41 #include <X11/Xaw/Simple.h>
42 #include <X11/Xaw/Box.h>
43 #include <X11/Xaw/Form.h>
44 #include <X11/Xaw/Label.h>
45 #include <X11/Xaw/Paned.h>
46 #include <X11/Xaw/List.h>
47 #include <X11/Xaw/Viewport.h>
48 #include <X11/Xaw/Dialog.h>
49 #include <X11/Xaw/Command.h>
50 #include <X11/Xaw/Toggle.h>
51 #include <X11/Xaw/SimpleMenu.h>
52 #include <X11/Xaw/SmeBSB.h>
53 #include <X11/Xaw/MenuButton.h>
54 #include <X11/Xaw/Scrollbar.h>
55 
56 #ifdef XAWBUG
57 /* At some point it seemed like the Toggle widget (really, the Command widget)
58    didn't provide a GetValues-hook to access the "state" property, so we had
59    to access that slot directly.  Well, this isn't the case with MIT R5 pl25,
60    or with OpenWindows 3.0, so let's try living without it now.
61  */
62 # include <X11/IntrinsicP.h>
63 # include <X11/CoreP.h>
64 # include <X11/Xaw/SimpleP.h>
65 # include <X11/Xaw/CommandP.h>
66 #endif /* XAWBUG */
67 
68 #include "KbdWidgetP.h"
69 #include "KeyWidgetP.h"
70 
71 #include "xkeycaps.h"
72 
73 #include "kbddef.h"
74 
75 #include "vroot.h"	/* This is standard in R5 but not R4 */
76 
77 #ifndef NO_PWD
78 #include <pwd.h>
79 #endif
80 
81 /* We can only do Vendor keysyms in X11r5, because earlier versions
82    didn't provide any way to map over the contents of an xrm database.
83  */
84 #ifdef XtSpecificationRelease
85 # if XtSpecificationRelease >= 5
86 #  define DO_VENDOR_KEYSYMS
87 # endif
88 #endif
89 
90 
91 
92 static int y_or_n_p P((KeyboardWidget widget,
93 		       char *name, char *name0, char *name1, char *name2));
94 
95 static int y_or_n_p_with_args P((KeyboardWidget,
96 				 char *name,
97 				 char *name0, char *name1, char *name2,
98 				 char *arg0, char *arg1, char *arg2,
99 				 char *arg3, char *arg4, char *arg5));
100 
101 static Widget make_button P((Widget parent, char *name, char *string,
102 			     Widget left, Widget top, XtCallbackProc callback,
103 			     XtPointer data, char *menu_name));
104 
105 
106 struct key_menus {
107   Widget popup;
108   Widget popup_kids [10];
109   struct edit_key_box *edit_key_box;
110   struct select_kbd_box *select_kbd_box;
111 };
112 
113 #ifndef isupper
114 # define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
115 #endif
116 #ifndef _tolower
117 # define _tolower(c)  ((c) - 'A' + 'a')
118 #endif
119 
120 int
121 #ifdef __STDC__
string_equal(const char * s1,const char * s2)122 string_equal (const char *s1, const char *s2)
123 #else /* ! __STDC__ */
124 string_equal (s1, s2)
125      const char *s1, *s2;
126 #endif /* ! __STDC__ */
127 {
128   if (s1 == s2) return 1;
129   if (!s1 || !s2) return 0;
130   while (*s1 && *s2)
131     {
132       if ((isupper (*s1) ? _tolower (*s1) : *s1) !=
133 	   (isupper (*s2) ? _tolower (*s2) : *s2))
134 	 return 0;
135        s1++, s2++;
136      }
137   return ((*s1 || *s2) ? 0 : 1);
138 }
139 
140 
141 
142 
143 static Widget
144 #ifdef __STDC__
make_button(Widget parent,char * name,char * string,Widget left,Widget top,XtCallbackProc callback,XtPointer data,char * menu_name)145 make_button (Widget parent,
146 	     char *name, char *string,
147 	     Widget left, Widget top,
148 	     XtCallbackProc callback,
149 	     XtPointer data,
150 	     char *menu_name)
151 #else /* ! __STDC__ */
152 make_button (parent, name, string, left, top, callback, data, menu_name)
153      Widget parent;
154      char *name, *string;
155      Widget left, top;
156      XtCallbackProc callback;
157      XtPointer data;
158      char *menu_name;
159 #endif /* ! __STDC__ */
160 {
161   Widget w = make_label_1 (parent, name, string, left, top,
162 			   (menu_name
163 			    ? menuButtonWidgetClass
164 			    : commandWidgetClass),
165 			   callback, data);
166   if (menu_name)
167     {
168       Arg av [10];
169       int ac = 0;
170       XtSetArg (av [ac], XtNmenuName, menu_name); ac++;
171       XtSetValues (w, av, ac);
172     }
173   return w;
174 }
175 
176 
177 static Widget
178 #ifdef __STDC__
make_toggle(Widget parent,char * name,Widget left,Widget top,int state,XtCallbackProc callback,XtPointer data,char * label,Widget radio_group,XtPointer radio_data)179 make_toggle (Widget parent, char *name, Widget left, Widget top, int state,
180 	     XtCallbackProc callback,
181 	     XtPointer data, char *label, Widget radio_group,
182 	     XtPointer radio_data)
183 #else /* ! __STDC__ */
184 make_toggle (parent, name, left, top, state, callback, data, label,
185 	     radio_group, radio_data)
186      Widget parent;
187      char *name;
188      Widget left, top;
189      int state;
190      void (*callback) ();
191      XtPointer data;
192      char *label;
193      Widget radio_group;
194      XtPointer radio_data;
195 #endif /* ! __STDC__ */
196 {
197   Arg av [20];
198   int ac = 0;
199   Widget w;
200   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
201   XtSetArg (av[ac], XtNright, XtChainLeft); ac++;
202   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
203   XtSetArg (av[ac], XtNbottom, XtChainTop); ac++;
204   XtSetArg (av[ac], XtNjustify, XtJustifyLeft); ac++;
205   XtSetArg (av[ac], XtNstate, (state ? True : False)); ac++;
206   if (left) XtSetArg (av[ac], XtNfromHoriz, left),  ac++;
207   if (top) XtSetArg (av[ac], XtNfromVert, top),  ac++;
208   if (label) XtSetArg (av[ac], XtNlabel, label),  ac++;
209   if (radio_group) XtSetArg (av[ac], XtNradioGroup, radio_group),  ac++;
210   if (radio_data) XtSetArg (av[ac], XtNradioData, radio_data),  ac++;
211   w = XtCreateManagedWidget (name, toggleWidgetClass, parent, av, ac);
212   if (callback) XtAddCallback (w, XtNcallback, callback, data);
213   return w;
214 }
215 
216 
217 
218 
219 static void
220 #ifdef __STDC__
button_quit(Widget widget,XtPointer client_data,XtPointer call_data)221 button_quit (Widget widget, XtPointer client_data, XtPointer call_data)
222 #else /* ! __STDC__ */
223 button_quit (widget, client_data, call_data)
224      Widget widget;
225      XtPointer client_data, call_data;
226 #endif /* ! __STDC__ */
227 {
228   exit (0);
229 }
230 
231 
232 static int modify_keyboard_modifiers P((KeyboardWidget, XModifierKeymap *));
233 static int modify_keyboard P((KeyboardWidget, int first_keycode,
234 			      int keysyms_per_keycode, KeySym *keysyms,
235 			      int num_codes, XModifierKeymap *modmap));
236 
237 static void
238 #ifdef __STDC__
button_restore(Widget button,XtPointer client_data,XtPointer call_data)239 button_restore (Widget button, XtPointer client_data, XtPointer call_data)
240 #else /* ! __STDC__ */
241 button_restore (button, client_data, call_data)
242      Widget button;
243      XtPointer client_data, call_data;
244 #endif /* ! __STDC__ */
245 {
246   KeyboardWidget widget = *((KeyboardWidget *) client_data);
247   KeySym *keysyms;
248   KeyCode lowest = 255, highest = 0;
249   XModifierKeymap *modmap;
250   int per_code = widget->keyboard.default_keysyms_per_code;
251   int i, j, k;
252 
253   if (0 != y_or_n_p (widget, "restoreQuery", "yes", "no", 0))
254     {
255       message (widget, "Aborted.");
256       return;
257     }
258   keysyms = (KeySym *) calloc (sizeof (KeySym), per_code * 256);
259   modmap = XNewModifiermap (2); /* It'll grow */
260   memset (modmap->modifiermap, 0, modmap->max_keypermod * 8);
261 
262   for (i = 0; i < widget->keyboard.nrows; i++)
263     {
264       struct KeyWidget_row *row = &widget->keyboard.rows [i];
265       for (j = 0; j < row->nkeys; j++)
266 	{
267 	  KeyWidget key = row->keys [j];
268 	  if (key->key.keycode)
269 	    {
270 	      if (key->key.keycode < lowest)
271 		lowest = key->key.keycode;
272 	      if (key->key.keycode > highest)
273 		highest = key->key.keycode;
274 	      for (k = 0; k < per_code; k++)
275 		keysyms [key->key.keycode * per_code + k] =
276 		  key->key.default_keysyms [k];
277 	      if (key->key.default_mods)
278 		for (k = 0; k < 8; k++)
279 		  if (key->key.default_mods & (1<<k))
280 		    modmap = XInsertModifiermapEntry (modmap,
281 						      key->key.keycode,
282 						      k);
283 	    }
284 	}
285     }
286   if (highest <= lowest) exit (-69); /* can't happen */
287 
288   if (! modify_keyboard (widget, lowest, per_code,
289 			 keysyms + (lowest * per_code),
290 			 highest - lowest, modmap))
291     message (widget, "Keyboard restored to default state.");
292   XFreeModifiermap (modmap);
293   free (keysyms);
294 }
295 
296 
297 static FILE *
298 #ifdef __STDC__
open_output_file(KeyboardWidget widget,char ** name)299 open_output_file(KeyboardWidget widget, char **name)
300 #else /* ! __STDC__ */
301 open_output_file(widget, name)
302      KeyboardWidget widget;
303      char **name;
304 #endif /* ! __STDC__ */
305 {
306   const char *home = getenv("HOME");
307   const char *base = ".xmodmap";
308   int L = strlen(home) + strlen(base) + 2;
309   char *target = 0;
310   struct stat st;
311   FILE *out = 0;
312 
313 #ifndef NO_UNAME
314   struct utsname uts;
315   if (uname (&uts) >= 0)
316     L += strlen(uts.nodename) + 1;
317   else
318     uts.nodename[0] = 0;
319 #endif
320 
321   target = (char *) malloc(L+1);
322   strcpy(target, home);
323   if (target[strlen(target)-1] != '/')
324     strcat(target, "/");
325 
326   strcat(target, base);
327 
328 #ifndef NO_UNAME
329   if (uts.nodename)
330     {
331       strcat(target, "-");
332       strcat(target, uts.nodename);
333     }
334 #endif
335 
336   if (!stat(target, &st))
337     {
338       char *t2;
339       if (y_or_n_p_with_args(widget,
340 			     "overwriteQuery",
341 			     "ok", "cancel", 0,
342 			     target, 0, 0, 0, 0, 0))
343 	goto DONE;
344 
345       t2 = (char *) malloc (strlen(target) + 10);
346       strcpy (t2, target);
347       strcat (t2, ".BAK");
348       rename (target, t2);
349       free (t2);
350     }
351 
352   out = fopen(target, "w");
353  DONE:
354   *name = 0;
355   if (out)
356     *name = target;
357   else
358     free (target);
359   return out;
360 }
361 
362 
363 void
364 #ifdef __STDC__
make_long_kbd_name(const char * vendor,const char * kbd_style,char * buf)365 make_long_kbd_name (const char *vendor, const char *kbd_style, char *buf)
366 #else /* ! __STDC__ */
367 make_long_kbd_name (vendor, kbd_style, buf)
368 	const char *vendor;
369 	const char *kbd_style;
370 	char *buf;
371 #endif /* ! __STDC__ */
372 {
373   strcpy(buf, (vendor ? vendor : ""));
374   if (kbd_style && *kbd_style)
375     {
376       strcat(buf, " ");
377       strcat(buf, kbd_style);
378     }
379 }
380 
381 
382 static char *bit_names[] = { "Shift", "Lock", "Control", "Mod1",
383 			      "Mod2", "Mod3", "Mod4", "Mod5" };
384 
385 static void
386 #ifdef __STDC__
button_write(Widget button,XtPointer client_data,XtPointer call_data)387 button_write (Widget button, XtPointer client_data, XtPointer call_data)
388 #else /* ! __STDC__ */
389 button_write (button, client_data, call_data)
390      Widget button;
391      XtPointer client_data, call_data;
392 #endif /* ! __STDC__ */
393 {
394   char *filename = 0;
395   FILE *out;
396   KeyboardWidget widget = *((KeyboardWidget *) client_data);
397   XModifierKeymap *current_modmap, *default_modmap;
398   int per_code = widget->keyboard.default_keysyms_per_code;
399   struct { KeyWidget key; int count; char *names[8]; }
400      all [256], differences [256];
401   int all_count = 0, diff_count = 0;
402   KeySym *keysyms;
403   int count, i, j, k;
404   int partial = y_or_n_p (widget, "writeQuery", "full", "partial", "abort");
405   time_t now = time ((time_t *) 0);
406 #ifdef NO_PWD
407   char *userid = 0;
408 #else
409   struct passwd *pw = (struct passwd *) getpwuid (getuid ());
410   char *userid = (pw ? pw->pw_name : 0);
411 #endif
412   KeyCode added [8][255];
413   KeyCode subtracted [8][255];
414   int added_count, subtracted_count;
415   int cmkpm, dmkpm;
416   int any_mod_changes = 0;
417 
418   if (partial >= 2)
419     {
420       message (widget, "Aborted.");
421       return;
422     }
423 
424   current_modmap = XGetModifierMapping (XtDisplay (widget));
425   default_modmap = XNewModifiermap (2); /* It'll grow */
426   memset (default_modmap->modifiermap, 0, default_modmap->max_keypermod * 8);
427 
428   out = open_output_file(widget, &filename);
429   if (!out) return;
430 
431   for (i = 0; i < widget->keyboard.nrows; i++)
432     {
433       struct KeyWidget_row *row = &widget->keyboard.rows [i];
434       for (j = 0; j < row->nkeys; j++)
435 	{
436 	  KeyWidget key = row->keys [j];
437 	  if (key->key.keycode)
438 	    {
439 	      unsigned long bits = key->key.modifier_bits;
440 	      keysyms = XGetKeyboardMapping (XtDisplay (widget),
441 					     key->key.keycode,
442 					     1, &count);
443 	      if (! keysyms) count = 0;
444 	      all [all_count].key = key;
445 	      for (; count > 0; count--)
446 		if (keysyms [count-1]) break;
447 	      if (count == 0)
448 		{
449 		  all [all_count].names [0] = "NoSymbol";
450 		  count = 1;
451 		}
452 	      else
453 		for (k = 0; k < count; k++)
454 		  {
455 		    char *str = "NoSymbol";
456 		    if (keysyms [k])
457 		      {
458 			str = XKeysymToString (keysyms [k]);
459 			if (! str)
460 			  {
461 			    /* core leak, but this shouldn't ever happen
462 			       unless there's a bug in libX11.a, or the
463 			       user did something stupid with xmodmap.
464 			     */
465 			    str = (char *) malloc (255);
466 			    sprintf (str, "0x%02X", (int) keysyms [k]);
467 			  }
468 		      }
469 		    all [all_count].names [k] = str;
470 		  }
471 	      all [all_count].count = count;
472 	      if (! keysyms) count = 0;
473 	      if (count > per_code ||
474 		  ((!partial) && (bits != key->key.default_mods)) ||
475 		  (count > 0 && keysyms[0] != key->key.default_keysyms[0]) ||
476 		  (count > 1 && keysyms[1] != key->key.default_keysyms[1]) ||
477 		  (count > 2 && keysyms[2] != key->key.default_keysyms[2]) ||
478 		  (count > 3 && keysyms[3] != key->key.default_keysyms[3]) ||
479 		  (count > 4 && keysyms[4] != key->key.default_keysyms[4]) ||
480 		  (count > 5 && keysyms[5] != key->key.default_keysyms[5]) ||
481 		  (count > 6 && keysyms[6] != key->key.default_keysyms[6]) ||
482 		  (count > 7 && keysyms[7] != key->key.default_keysyms[7]))
483 		differences [diff_count++] = all [all_count];
484 	      all_count++;
485 	      for (k = 0; k < 8; k++)
486 		{
487 		  if (key->key.default_mods & (1<<k))
488 		    default_modmap =
489 		      XInsertModifiermapEntry (default_modmap,
490 					       key->key.keycode, k);
491 		  if (bits & (1<<k))
492 		    current_modmap =
493 		      XInsertModifiermapEntry (current_modmap,
494 					       key->key.keycode, k);
495 		}
496 	      if (keysyms) XFree ((char *) keysyms);
497 	    }
498 	}
499     }
500 
501   /* I'd just like to take this moment to point out that C has all
502      the expressive power of two dixie cups and a string.
503    */
504   cmkpm = current_modmap->max_keypermod;
505   dmkpm = default_modmap->max_keypermod;
506   memset (added, 0, sizeof (added));
507   memset (subtracted, 0, sizeof (subtracted));
508 
509   for (i = 0; i < 8; i++)
510     {
511       KeyCode kc1, kc2 = 0;
512       added_count = subtracted_count = 0;
513       if (partial)
514 	{
515 	  for (j = 0; j < cmkpm; j++)
516 	    {
517 	      kc1 = current_modmap->modifiermap [i * cmkpm + j];
518 	      if (!kc1) continue;
519 	      for (k = 0; k < dmkpm; k++)
520 		{
521 		  kc2 = default_modmap->modifiermap [i * dmkpm + k];
522 		  if (kc1 == kc2) break;
523 		}
524 	      if (kc1 != kc2) added [i][added_count++] = kc1;
525 	    }
526 	  for (j = 0; j < dmkpm; j++)
527 	    {
528 	      kc1 = default_modmap->modifiermap [i * dmkpm + j];
529 	      if (!kc1) continue;
530 	      for (k = 0; k < cmkpm; k++)
531 		{
532 		  kc2 = current_modmap->modifiermap [i * cmkpm + k];
533 		  if (kc1 == kc2) break;
534 		}
535 	      if (kc1 != kc2) subtracted [i][subtracted_count++] = kc1;
536 	    }
537 	  if (added_count || subtracted_count) any_mod_changes = 1;
538 	}
539       else
540 	{
541 	  for (j = 0; j < cmkpm; j++)
542 	    {
543 	      kc1 = current_modmap->modifiermap [i * cmkpm + j];
544 	      if (kc1)
545 		added [i][added_count++] = kc1;
546 	    }
547 	}
548     }
549 
550   {
551     char *t;
552     char s[1024];
553     make_long_kbd_name(widget->keyboard.vendor, widget->keyboard.kbd_style, s);
554     fprintf (out, "!\n! This is an `xmodmap' input file for %s%s keyboards.\n",
555 	     ((strlen(s) > 40) ? "\n!   " : ""), s);
556 
557     t = ctime (&now);
558     t [strlen (t) - 1] = 0; /* bastards */
559     fprintf (out, "! Automatically generated on %s", t);
560   }
561   if (userid)
562     fprintf (out, " by %s", userid);
563   fprintf (out, " with\n! %s.\n", short_version);
564   fprintf (out, "! http://www.jwz.org/xkeycaps/\n");
565   fprintf (out, "!\n");
566 
567   if (partial && any_mod_changes)
568     {
569       fprintf (out, "! This file presupposes that the keyboard is in the ");
570       fprintf (out,
571 	       "default state, and\n! may malfunction if it is not.\n!\n");
572     }
573   else if (! partial)
574     {
575       if (diff_count)
576 	fprintf (out, "! This file makes the following changes:\n!\n");
577       else
578 	fprintf (out, "! This file encodes the default state.\n!\n");
579     }
580 
581   /* If we're going to write out "remove" commands, do it before writing
582      out any "keycode" statements, since xmodmap is so lame.  We only
583      generate "remove" statements in "partial" mode.
584      http://catalog.com/hopkins/images/smegmas.gif
585    */
586   any_mod_changes = 0;
587   if (partial)
588     for (i = 0; i < 8; i++)
589       {
590 	char *str;
591 	KeySym ks;
592 	if (subtracted [i][0])
593 	  {
594 	    fprintf (out, "remove %-8s=", bit_names [i]);
595 	    for (j = 0; j < sizeof (subtracted [0]); j++)
596 	      {
597 		KeyWidget kw;
598 		if (! subtracted [i][j]) break;
599 		any_mod_changes = 1;
600 		/* note: we don't use the *current* keysym corresponding to the
601 		   keycode being removed here, but the *default* one...
602 		 */
603 		kw = keycode_to_key (widget, subtracted [i][j]);
604 		ks = kw->key.default_keysyms [0];
605 		str = XKeysymToString (ks);
606 		if (str)
607 		  fprintf (out, " %s", str);
608 		else
609 		  fprintf (out, " 0x%04X", subtracted [i][j]);
610 	      }
611 	    fprintf (out, "\n");
612 	  }
613       }
614   if (any_mod_changes) fprintf (out, "\n");
615 
616   /* Write out the differences.  This happens in both "partial" and "full"
617      modes, but in "full" mode it's in the form of a descriptive comment
618      instead of xmodmap commands.
619    */
620   for (i = 0; i < diff_count; i++)
621     {
622       if (partial)
623 	fprintf (out, "keycode 0x%02X =\t", differences[i].key->key.keycode);
624       else
625 	fprintf (out, "! The \"%s\" key generates ",
626 		differences[i].key->key.key_name);
627       for (j = 0; j < differences[i].count; j++)
628 	{
629 	  fprintf (out, "%s", differences[i].names[j]);
630 	  if (j+1 == differences[i].count) continue;
631 	  if (partial)
632 	    {
633 	      fprintf (out, "\t");
634 	      if (strlen (differences[i].names[j]) < 8) putchar ('\t');
635 	    }
636 	  else
637 	    {
638 	      if (j+1 == differences[i].count-1)
639 		fprintf (out, "%s", (j == 0) ? " and " : ", and ");
640 	      else
641 		fprintf (out, ", ");
642 	    }
643 	}
644       /* write the diffs of the modifier bits in the full-mode comment. */
645       if (!partial &&
646 	  differences[i].key->key.default_mods !=
647 	  differences[i].key->key.modifier_bits)
648 	{
649 	  unsigned long bits = differences[i].key->key.modifier_bits;
650 	  int this_mod_count = 0;
651 	  if (! bits)
652 	    fprintf (out, ", and has no modifiers\n");
653 	  else
654 	    {
655 	      fprintf (out, ", and the ");
656 	      for (k = 0; k < 8; k++)
657 		{
658 		  if (bits & (1<<k))
659 		    {
660 		      if (this_mod_count++) fprintf (out, "/");
661 		      fprintf (out, "%s", bit_names [k]);
662 		    }
663 		}
664 	      fprintf (out, " modifier%s\n", (this_mod_count>1 ? "s" : ""));
665 	    }
666 	}
667       else
668 	fprintf (out, "\n");
669     }
670 
671   /* In "full" mode, write out all the "keycode" commands.  This is the
672      first actual xmodmap command text in full mode.
673    */
674   if (!partial)
675     {
676       fprintf (out, "\n");
677       for (i = 0; i < all_count; i++)
678 	{
679 	  fprintf (out, "keycode 0x%02X =\t", all [i].key->key.keycode);
680 	  for (j = 0; j < all[i].count; j++)
681 	    {
682 	      fprintf (out, "%s", all[i].names[j]);
683 	      if (j == all[i].count - 1) continue;
684 	      fprintf (out, "\t");
685 	      if (strlen (all[i].names[j]) < 8) fprintf (out, "\t");
686 	    }
687 	  fprintf (out, "\n");
688 	}
689       fprintf (out, "\n");
690       fprintf (out, "clear Shift\nclear Lock\nclear Control\nclear Mod1\n");
691       fprintf (out, "clear Mod2\nclear Mod3\nclear Mod4\nclear Mod5\n");
692     }
693 
694   /* In partial mode, write out any "add" commands.  This is after any
695      "keycode" commands have already been output (and any "remove" commands
696      before them.)  In full mode, the "add" commands are the whole story.
697    */
698   fprintf (out, "\n");
699   for (i = 0; i < 8; i++)
700     {
701       char *str;
702       KeySym ks;
703       if (added [i][0])
704 	{
705 	  fprintf (out, "add    %-8s=", bit_names [i]);
706 	  for (j = 0; j < sizeof (added [0]); j++)
707 	    {
708 	      if (! added [i][j]) break;
709 	      ks = XKeycodeToKeysym (XtDisplay (widget), added [i][j], 0);
710 	      str = XKeysymToString (ks);
711 	      if (str)
712 		fprintf (out, " %s", str);
713 	      else
714 		fprintf (out, " 0x%04X", added [i][j]);
715 	    }
716 	  fprintf (out, "\n");
717 	}
718     }
719   fclose (out);
720   y_or_n_p_with_args (widget, "wroteFileMessage",
721 		      "ok", 0, 0,
722 		      (filename ? filename : "???"), 0, 0, 0, 0, 0);
723   if (filename) free (filename);
724 }
725 
726 
727 static Window
728 #ifdef __STDC__
lowest_window(Display * dpy,Window window,Window limit,int x,int y)729 lowest_window (Display *dpy, Window window, Window limit, int x, int y)
730 #else /* ! __STDC__ */
731 lowest_window (dpy, window, limit, x, y)
732      Display *dpy;
733      Window window, limit;
734      int x, y;
735 #endif /* ! __STDC__ */
736 {
737   XWindowAttributes xgwa;
738   XGetWindowAttributes (dpy, window, &xgwa);
739 
740   /* Ignore all windows which are not at or below `limit'.  This prevents
741      us from assigning focus to windows which are part of the WM decoration,
742      since `limit' is the result of XmuClientWindow() -- it limits us to
743      descending the tree of the client proper.
744    */
745   if (window == limit) limit = 0;
746 
747   if (xgwa.x <= x &&
748       xgwa.y <= y &&
749       xgwa.x + xgwa.width > x &&
750       xgwa.y + xgwa.height > y)
751     {
752       Window root, parent, *kids;
753       unsigned int nkids;
754       if (!XQueryTree (dpy, window, &root, &parent, &kids, &nkids))
755 	abort ();
756 
757       if (kids)
758 	{
759 	  unsigned int i;
760 	  Window kid = 0;
761 	  for (i = 0; i < nkids; i++)
762 	    {
763 	      kid = lowest_window (dpy, kids[i], limit,
764 				   x - xgwa.x, y - xgwa.y);
765 	      if (kid) break;
766 	    }
767 	  XFree ((char *)kids);
768 	  if (kid) return kid;
769 	}
770       /* Don't accept windows outside of the client tree. */
771       if (limit) return 0;
772       /* Don't accept windows which don't take KeyPress. */
773       if (! (xgwa.all_event_masks & KeyPressMask)) return 0;
774       return window;
775     }
776   else
777     return 0;
778 }
779 
780 static void
781 #ifdef __STDC__
button_pick_window(Widget button,XtPointer client_data,XtPointer call_data)782 button_pick_window (Widget button, XtPointer client_data, XtPointer call_data)
783 #else /* ! __STDC__ */
784 button_pick_window (button, client_data, call_data)
785      Widget button;
786      XtPointer client_data, call_data;
787 #endif /* ! __STDC__ */
788 {
789   KeyboardWidget keyboard = *((KeyboardWidget *) client_data);
790   Widget topmost, target;
791   Display *dpy = XtDisplay (keyboard);
792   Window root = RootWindowOfScreen (keyboard->core.screen);
793   Window window = 0;
794   Window wm_window;
795   int click_x = 0, click_y = 0;
796   int buttons = 0;
797   int once = 0;
798   XEvent event;
799 
800   message (keyboard, "Please select the window to type at:");
801 
802   if (XGrabPointer (dpy, root, False, ButtonPressMask | ButtonReleaseMask,
803 		    GrabModeSync, GrabModeAsync, root,
804 		    keyboard->keyboard.select_cursor, CurrentTime))
805     {
806       XBell (dpy, 0);
807       message (keyboard, "Grab failed.");
808       return;
809     }
810 
811   while (window == 0 || buttons != 0)
812     {
813       /* allow one more event */
814       XAllowEvents (dpy, SyncPointer, CurrentTime);
815       XWindowEvent (dpy, root, ButtonPressMask|ButtonReleaseMask, &event);
816       switch (event.type)
817 	{
818 	case ButtonPress:
819 	  once = 1;
820 	  if (window == 0 && event.xbutton.subwindow)
821 	    {
822 	      window = event.xbutton.subwindow; /* window selected */
823 	      click_x = event.xbutton.x;
824 	      click_y = event.xbutton.y;
825 	    }
826 	  buttons++;
827 	  break;
828 	case ButtonRelease:
829 	  if (buttons > 0) buttons--;
830 	  break;
831 	}
832     }
833   XUngrabPointer(dpy, CurrentTime);
834   XSync (dpy, 0);
835 
836   wm_window = window;
837   if (window && window != root) window = XmuClientWindow (dpy, window);
838   topmost = (Widget) keyboard;
839   while (XtParent (topmost)) topmost = XtParent (topmost);
840   target = XtWindowToWidget (XtDisplay (topmost), window);
841   if (window == XtWindow (topmost)) target = topmost;
842   if (target || window == root) window = 0;
843   if (window)
844     {
845       char buf [255];
846       char buf2 [100];
847       char *string1 = 0, *string2 = 0, *string3 = 0;
848       char *name;
849       XClassHint classhint;
850 
851       Window lowest = lowest_window (dpy, wm_window, window, click_x, click_y);
852       if (! lowest)
853 	{
854 	  /* Maybe they clicked in the wrong place in the app.  Let's try
855 	     again by picking the exact center of the frame and looking
856 	     there for something that accepts keyboard input.
857 	   */
858 	  XWindowAttributes xgwa;
859 	  XGetWindowAttributes (dpy, wm_window, &xgwa);
860 	  lowest = lowest_window (dpy, wm_window, window,
861 				  xgwa.x + (xgwa.width / 2),
862 				  xgwa.y + (xgwa.height / 2));
863 	  if (! lowest)
864 	    {
865 	      /* Still couldn't find one; give up. */
866 	      XBell (dpy, 0);
867 	      message (keyboard,
868 		       "No window there that accepts keyboard input!");
869 	      goto done;
870 	    }
871 	}
872 
873       classhint.res_name = classhint.res_class = 0;
874       if (! XGetClassHint (dpy, window, &classhint))
875 	classhint.res_name = classhint.res_class = 0;
876 
877       string1 = classhint.res_name;
878       string2 = classhint.res_class;
879       XFetchName (dpy, window, &string3);
880       name = string3;
881       if (string2 && string3 && string_equal (string2, string3)) string3 = 0;
882       if (string1 && string3 && string_equal (string1, string3)) string3 = 0;
883       if (string1 && string2 && string_equal (string1, string2)) string2 = 0;
884       if (!string2) string2 = string3, string3 = 0;
885       if (!string1) string1 = string2, string2 = 0;
886       if (string1 && string2 && string3)
887 	sprintf (buf2, "%s / %s / %s", string1, string2, string3);
888       else if (string1 && string2)
889 	sprintf (buf2, "%s / %s", string1, string2);
890       else if (string1)
891 	sprintf (buf2, "%s", string1);
892       else
893 	sprintf (buf2, "unnamed");
894 
895       if (window == lowest)
896 	sprintf (buf, "Keyboard focus locked on window 0x%X (%s)",
897 		 (int) window, buf2);
898       else
899 	sprintf (buf, "Keyboard focus locked on window 0x%X <- 0x%X (%s)",
900 		 (int) lowest, (int) window, buf2);
901       message (keyboard, buf);
902 
903       if (!classhint.res_class)
904 	;
905       else if (string_equal (classhint.res_class, "xterm"))
906 	message2 (keyboard,
907 	      "Remember to select \"Allow SendEvents\" from the XTerm menu.");
908       else if (string_equal (classhint.res_class, "cmdtool") ||
909 	       string_equal (classhint.res_class, "shelltool") ||
910 	       string_equal (classhint.res_class, "textedit"))
911 	message2 (keyboard,
912  "Did you remember to use the -defeateventsecurity option when launching it?");
913 
914       if (classhint.res_name) XFree (classhint.res_name);
915       if (classhint.res_class) XFree (classhint.res_class);
916       if (name) XFree (name);
917       window = lowest;
918     }
919   else
920     message (keyboard, "Keyboard-focus cleared.");
921 
922  done:
923   keyboard->keyboard.target_window = window;
924 }
925 
926 
927 
928 static int
929 #ifdef __STDC__
modify_keyboard_modifiers(KeyboardWidget widget,XModifierKeymap * modmap)930 modify_keyboard_modifiers (KeyboardWidget widget, XModifierKeymap *modmap)
931 #else /* ! __STDC__ */
932 modify_keyboard_modifiers (widget, modmap)
933      KeyboardWidget widget;
934      XModifierKeymap *modmap;
935 #endif /* ! __STDC__ */
936 {
937   Display *display = XtDisplay ((Widget) widget);
938   int retries, timeout;
939   char buf [255];
940   for (retries = 4, timeout = 2; retries > 0; retries--, timeout *= 2)
941     {
942       int result;
943       result = XSetModifierMapping (display, modmap);
944       switch (result)
945 	{
946 	case MappingSuccess:
947 	  mappingNotify_event_expected = 1;
948 	  return 0;
949 	case MappingBusy:
950 	  sprintf (buf, "please release all keys withing %d seconds", timeout);
951 	  /* Calling message() doesn't work because exposes don't get
952 	     processed while we're sleeping.
953 	   */
954 	  message (widget, buf);
955 	  fprintf (stderr, "%s: %s\n", progname, buf);
956 	  XSync (display, 0);
957 	  sleep (timeout);
958 	  continue;
959 	case MappingFailed:
960 	  message (widget, "XSetModifierMapping() failed");
961 	  XBell (display, 0);
962 	  return -1;
963 	default:
964 	  sprintf (buf, "unknown return code %d from XSetModifierMapping()",
965 		   result);
966 	  message (widget, buf);
967 	  XBell (display, 0);
968 	  return -1;
969 	}
970     }
971   sprintf (buf, "XSetModifierMapping() failed");
972   message (widget, buf);
973   XBell (display, 0);
974   return -1;
975 }
976 
977 
978 /* We install this as an error handler around the call to
979    XChangeKeyboardMapping(), so that we can trap errors that that
980    operation generates.  Gotta love this 1960's condition system...
981  */
982 static int XChangeKeyboardMapping_error = 0;
983 
984 static int
985 #ifdef __STDC__
modify_keyboard_error_handler(Display * dpy,XErrorEvent * error)986 modify_keyboard_error_handler (Display *dpy, XErrorEvent *error)
987 #else /* ! __STDC__ */
988 modify_keyboard_error_handler (dpy, error)
989      Display *dpy;
990      XErrorEvent *error;
991 #endif /* ! __STDC__ */
992 {
993   switch (error->request_code)
994     {
995     case X_ChangeKeyboardMapping:
996       XChangeKeyboardMapping_error = 1;
997       return 0;
998     default:
999       XmuPrintDefaultErrorMessage (dpy, error, stderr);
1000       exit (-1);
1001     }
1002 }
1003 
1004 static int
1005 #ifdef __STDC__
modify_keyboard(KeyboardWidget widget,int first_keycode,int keysyms_per_keycode,KeySym * keysyms,int num_codes,XModifierKeymap * modmap)1006 modify_keyboard (KeyboardWidget widget, int first_keycode,
1007 		 int keysyms_per_keycode, KeySym *keysyms,
1008 		 int num_codes, XModifierKeymap *modmap)
1009 #else /* ! __STDC__ */
1010 modify_keyboard (widget, first_keycode, keysyms_per_keycode, keysyms,
1011 		 num_codes, modmap)
1012      KeyboardWidget widget;
1013      int first_keycode;
1014      int keysyms_per_keycode;
1015      KeySym *keysyms;
1016      int num_codes;
1017      XModifierKeymap *modmap;
1018 #endif /* ! __STDC__ */
1019 {
1020   Display *display = XtDisplay ((Widget) widget);
1021   XErrorHandler old_handler;
1022   if (keysyms_per_keycode == 0) keysyms_per_keycode = 1;
1023   XSync (display, 0);
1024   mappingNotify_event_expected = 1;
1025   XChangeKeyboardMapping_error = 0;
1026   old_handler = XSetErrorHandler (modify_keyboard_error_handler);
1027   XChangeKeyboardMapping (display, first_keycode, keysyms_per_keycode,
1028 			  keysyms, num_codes);
1029   /* Is there a race condition here?  Are we guarenteed that by calling
1030      XSync() we will get back an error generated by the previously-sent
1031      request?
1032    */
1033   XSync (XtDisplay ((Widget) widget), 0);
1034   XSetErrorHandler (old_handler);
1035   if (XChangeKeyboardMapping_error)
1036     {
1037       mappingNotify_event_expected = 0;
1038       message (widget, "XChangeKeyboardMapping() failed.");
1039       XBell (display, 0);
1040       return -1;
1041     }
1042   if (modmap)
1043     return modify_keyboard_modifiers (widget, modmap);
1044   return 0;
1045 }
1046 
1047 
1048 static void
1049 #ifdef __STDC__
restore_key_default(Widget parent,XtPointer client_data,XtPointer call_data)1050 restore_key_default (Widget parent, XtPointer client_data, XtPointer call_data)
1051 #else /* ! __STDC__ */
1052 restore_key_default (parent, client_data, call_data)
1053      Widget parent;
1054      XtPointer client_data, call_data;
1055 #endif /* ! __STDC__ */
1056 {
1057   KeyboardWidget widget = (KeyboardWidget) client_data;
1058   KeyWidget key = widget->keyboard.key_under_mouse;
1059   KeySym *keysyms = key->key.default_keysyms;
1060   int per_code = widget->keyboard.default_keysyms_per_code;
1061   KeyCode code = key->key.keycode;
1062   unsigned long bits = key->key.default_mods;
1063   XModifierKeymap *modmap;
1064   int i, error;
1065 
1066   if (! code)
1067     {
1068       y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1069       return;
1070     }
1071 
1072   modmap = XGetModifierMapping (XtDisplay (widget));
1073   for (i = 0; i < 8; i++)
1074     if (bits & (1<<i))
1075       modmap = XInsertModifiermapEntry (modmap, code, i);
1076     else
1077       modmap = XDeleteModifiermapEntry (modmap, code, i);
1078 
1079   XSync (XtDisplay (widget), 0);
1080   error = modify_keyboard (widget, code, per_code, keysyms, 1, modmap);
1081   XFreeModifiermap (modmap);
1082 
1083   if (! error)
1084     {
1085       char *k, buf [255], buf2 [255], *b = buf;
1086       for (i = 0; i < per_code; i++)
1087 	{
1088 	  if (i) *b++ = ',', *b++ = ' ';
1089 	  k = XKeysymToString (keysyms [i]);
1090 	  if (keysyms [i] && !k)
1091 	    {
1092 	      sprintf (b, "0x%04X", (int) keysyms [i]);
1093 	      k = b;
1094 	    }
1095 	  else
1096 	    {
1097 	      if (! k) k = "NoSymbol";
1098 	      strcpy (b, k);
1099 	    }
1100 	  b += strlen (k);
1101 	}
1102       sprintf (buf2, "KeyCode 0x%02X restored to default state (%s)",
1103 	       key->key.keycode, buf);
1104       message (widget, buf2);
1105     }
1106   XSync (XtDisplay (widget), 0);
1107 }
1108 
1109 
1110 static void
1111 #ifdef __STDC__
swap_key(Widget parent,XtPointer client_data,XtPointer call_data)1112 swap_key (Widget parent, XtPointer client_data, XtPointer call_data)
1113 #else /* ! __STDC__ */
1114 swap_key (parent, client_data, call_data)
1115      Widget parent;
1116      XtPointer client_data, call_data;
1117 #endif /* ! __STDC__ */
1118 {
1119   KeyboardWidget widget = (KeyboardWidget) client_data;
1120   XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1121   KeyWidget source_key = widget->keyboard.key_under_mouse;
1122   KeyWidget target_key;
1123   KeySym *source_keysyms;
1124   KeySym *target_keysyms;
1125   int source_count, target_count;
1126   unsigned long source_bits = source_key->key.modifier_bits;
1127   unsigned long target_bits;
1128   KeyCode source_code = source_key->key.keycode;
1129   KeyCode target_code;
1130   char buf [255];
1131   int i, error;
1132 
1133   if (source_key->key.keycode == 0)
1134     {
1135       y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1136       return;
1137     }
1138 
1139   sprintf (buf, "Click on the key to swap with 0x%02X (%s)",
1140 	   source_key->key.keycode,
1141 	   source_key->key.key_name);
1142   target_key = prompt_for_key (widget, buf);
1143   if (! target_key) return;
1144 
1145   target_bits = target_key->key.modifier_bits;
1146   target_code = target_key->key.keycode;
1147 
1148   if (target_code == 0)
1149     {
1150       y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1151       return;
1152     }
1153 
1154   if (source_code == target_code)
1155     {
1156       XBell (XtDisplay (widget), 0);
1157       message (widget, "Those keys are the same!");
1158       return;
1159     }
1160 
1161   for (i = 0; i < 8; i++)
1162     {
1163       if (source_bits & (1<<i))
1164 	modmap = XInsertModifiermapEntry (modmap, target_code, i);
1165       else
1166 	modmap = XDeleteModifiermapEntry (modmap, target_code, i);
1167 
1168       if (target_bits & (1<<i))
1169 	modmap = XInsertModifiermapEntry (modmap, source_code, i);
1170       else
1171 	modmap = XDeleteModifiermapEntry (modmap, source_code, i);
1172     }
1173 
1174   source_keysyms = XGetKeyboardMapping (XtDisplay (widget), source_code,
1175 					1, &source_count);
1176   target_keysyms = XGetKeyboardMapping (XtDisplay (widget), target_code,
1177 					1, &target_count);
1178 
1179   error = modify_keyboard (widget, target_code,
1180 			   source_count, source_keysyms, 1, modmap);
1181   if (error) return;
1182   error = modify_keyboard (widget, source_code,
1183 			   target_count, target_keysyms, 1, 0);
1184   if (error) return;
1185 
1186   sprintf (buf, "Keys 0x%02x (%s) and 0x%02x (%s) swapped.",
1187 	   source_key->key.keycode, source_key->key.key_name,
1188 	   target_key->key.keycode, target_key->key.key_name);
1189   message (widget, buf);
1190 
1191   if (source_keysyms) XFree ((char *) source_keysyms);
1192   if (target_keysyms) XFree ((char *) target_keysyms);
1193   if (modmap) XFreeModifiermap (modmap);
1194 }
1195 
1196 
1197 static void
1198 #ifdef __STDC__
clone_key(Widget parent,XtPointer client_data,XtPointer call_data)1199 clone_key (Widget parent, XtPointer client_data, XtPointer call_data)
1200 #else /* ! __STDC__ */
1201 clone_key (parent, client_data, call_data)
1202      Widget parent;
1203      XtPointer client_data, call_data;
1204 #endif /* ! __STDC__ */
1205 {
1206   KeyboardWidget widget = (KeyboardWidget) client_data;
1207   XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1208   KeyWidget source_key = widget->keyboard.key_under_mouse;
1209   KeyWidget target_key;
1210   KeySym *source_keysyms;
1211   int source_count;
1212   unsigned long source_bits = source_key->key.modifier_bits;
1213   KeyCode source_code = source_key->key.keycode;
1214   KeyCode target_code;
1215   char buf [255];
1216   int i, error;
1217 
1218   if (source_key->key.keycode == 0)
1219     {
1220       y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1221       return;
1222     }
1223 
1224   sprintf (buf, "Click on the key to turn into a copy of 0x%02X (%s)",
1225 	   source_key->key.keycode,
1226 	   source_key->key.key_name);
1227   target_key = prompt_for_key (widget, buf);
1228   if (! target_key) return;
1229 
1230   target_code = target_key->key.keycode;
1231 
1232   if (target_code == 0)
1233     {
1234       y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1235       return;
1236     }
1237 
1238   if (source_code == target_code)
1239     {
1240       XBell (XtDisplay (widget), 0);
1241       message (widget, "Those keys are the same!");
1242       return;
1243     }
1244   for (i = 0; i < 8; i++)
1245     {
1246       if (source_bits & (1<<i))
1247 	modmap = XInsertModifiermapEntry (modmap, target_code, i);
1248       else
1249 	modmap = XDeleteModifiermapEntry (modmap, target_code, i);
1250     }
1251 
1252   source_keysyms = XGetKeyboardMapping (XtDisplay (widget), source_code,
1253 					1, &source_count);
1254   error = modify_keyboard (widget, target_code,
1255 			   source_count, source_keysyms, 1, modmap);
1256   if (source_keysyms) XFree ((char *) source_keysyms);
1257   if (modmap) XFreeModifiermap (modmap);
1258   if (error) return;
1259 
1260   sprintf (buf, "Keys 0x%02x (%s) and 0x%02x (%s) are now the same.",
1261 	   source_key->key.keycode, source_key->key.key_name,
1262 	   target_key->key.keycode, target_key->key.key_name);
1263   message (widget, buf);
1264 }
1265 
1266 
1267 
1268 static void
1269 #ifdef __STDC__
disable_key(Widget parent,XtPointer client_data,XtPointer call_data)1270 disable_key (Widget parent, XtPointer client_data, XtPointer call_data)
1271 #else /* ! __STDC__ */
1272 disable_key (parent, client_data, call_data)
1273      Widget parent;
1274      XtPointer client_data, call_data;
1275 #endif /* ! __STDC__ */
1276 {
1277   KeyboardWidget widget = (KeyboardWidget) client_data;
1278   KeyWidget key = widget->keyboard.key_under_mouse;
1279   KeyCode code = key->key.keycode;
1280   KeySym keysym = 0;
1281   int i, error;
1282   char buf [255];
1283   XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1284   if (code == 0)
1285     {
1286       y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
1287       return;
1288     }
1289   for (i = 0; i < 8; i++)
1290     modmap = XDeleteModifiermapEntry (modmap, code, i);
1291   error = modify_keyboard (widget, code, 1, &keysym, 1, modmap);
1292   XFreeModifiermap (modmap);
1293   if (! error)
1294     {
1295       sprintf (buf, "KeyCode 0x%02X (%s) disabled.", key->key.keycode,
1296 	       key->key.key_name);
1297       message (widget, buf);
1298     }
1299   XSync (XtDisplay (widget), 0);
1300 }
1301 
1302 
1303 
1304 static struct edit_key_box * make_edit_key_dbox P((KeyboardWidget));
1305 static struct select_kbd_box * make_select_kbd_dbox P((KeyboardWidget));
1306 static void pop_up_key_dbox P((Widget, XtPointer, XtPointer));
1307 
1308 
1309 struct key_menus *
1310 #ifdef __STDC__
make_key_menus(KeyboardWidget * kbd)1311 make_key_menus (KeyboardWidget *kbd)
1312 #else /* ! __STDC__ */
1313 make_key_menus (kbd)
1314      KeyboardWidget *kbd;
1315 #endif /* ! __STDC__ */
1316 {
1317   KeyboardWidget widget = *kbd;
1318   Arg av [20];
1319   int ac = 0, i = 0;
1320   Widget menu, item;
1321   struct key_menus *key_menus = (struct key_menus *)
1322     malloc (sizeof (struct key_menus));
1323   memset (key_menus->popup_kids, 0, sizeof (key_menus->popup_kids));
1324 
1325   XawSimpleMenuAddGlobalActions (XtWidgetToApplicationContext((Widget)widget));
1326 
1327   XtSetArg (av[ac], XtNlabel, "keyMenu"); ac++;
1328   menu = XtCreatePopupShell ("keyMenu", simpleMenuWidgetClass,
1329 			     (Widget) widget, av, ac);
1330   XtAddCallback (menu, XtNpopupCallback, key_menu_pre_popup_hook,
1331 		 (XtPointer) widget);
1332   key_menus->popup = menu;
1333   ac = 0;
1334   item = XtCreateManagedWidget ("editKeysyms", smeBSBObjectClass, menu, av,ac);
1335   XtAddCallback (item, XtNcallback, pop_up_key_dbox, (XtPointer) widget);
1336   key_menus->popup_kids [i++] = item;
1337 
1338   item = XtCreateManagedWidget ("swapKey", smeBSBObjectClass, menu, av, ac);
1339   XtAddCallback (item, XtNcallback, swap_key, (XtPointer) widget);
1340   key_menus->popup_kids [i++] = item;
1341 
1342   item = XtCreateManagedWidget ("cloneKey", smeBSBObjectClass, menu, av, ac);
1343   XtAddCallback (item, XtNcallback, clone_key, (XtPointer) widget);
1344   key_menus->popup_kids [i++] = item;
1345 
1346   item = XtCreateManagedWidget ("disableKey", smeBSBObjectClass, menu, av, ac);
1347   XtAddCallback (item, XtNcallback, disable_key, (XtPointer) widget);
1348   key_menus->popup_kids [i++] = item;
1349 
1350   item = XtCreateManagedWidget ("restoreKey", smeBSBObjectClass, menu, av, ac);
1351   XtAddCallback (item, XtNcallback, restore_key_default, (XtPointer) widget);
1352   key_menus->popup_kids [i++] = item;
1353 
1354   key_menus->edit_key_box = make_edit_key_dbox (widget);
1355   key_menus->select_kbd_box = make_select_kbd_dbox (widget);
1356   return key_menus;
1357 }
1358 
1359 void
1360 #ifdef __STDC__
sensitize_menu(KeyboardWidget widget,Widget menu,Bool sensitive)1361 sensitize_menu (KeyboardWidget widget, Widget menu, Bool sensitive)
1362 #else /* ! __STDC__ */
1363 sensitize_menu (widget, menu, sensitive)
1364      KeyboardWidget widget;
1365      Widget menu;
1366      Bool sensitive;
1367 #endif /* ! __STDC__ */
1368 {
1369   Arg av [10];
1370   int ac = 0, i = 0;
1371   struct key_menus *key_menus = widget->keyboard.key_menus;
1372   if (menu != key_menus->popup) return;
1373   XtSetArg (av [ac], XtNsensitive, sensitive); ac++;
1374   for (i = 0; i < sizeof (key_menus->popup_kids); i++)
1375     if (! key_menus->popup_kids [i]) return;
1376     else XtSetValues (key_menus->popup_kids [i], av, ac);
1377 }
1378 
1379 
1380 
1381 Widget
1382 #ifdef __STDC__
make_command_widgets(Widget parent,Widget * kbd)1383 make_command_widgets (Widget parent, Widget *kbd)
1384 #else /* ! __STDC__ */
1385 make_command_widgets (parent, kbd)
1386      Widget parent;
1387      Widget *kbd;
1388 #endif /* ! __STDC__ */
1389 {
1390   Widget box, top;
1391   Arg av [20];
1392   int ac = 0;
1393   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
1394   XtSetArg (av[ac], XtNright, XtChainLeft); ac++;
1395   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
1396   XtSetArg (av[ac], XtNbottom, XtChainTop); ac++;
1397   box = XtCreateManagedWidget ("buttons", formWidgetClass, parent, av, ac);
1398   top = 0;
1399   top = make_button (box, "quit", NULL, 0, top, button_quit, kbd, 0);
1400   top = make_button (box, "keyboard", NULL, 0, top, pop_up_kbd_dbox, kbd, 0);
1401   top = make_button (box, "focus", NULL, 0, top, button_pick_window, kbd, 0);
1402   top = make_button (box, "restore", NULL, 0, top, button_restore, kbd, 0);
1403   top = make_button (box, "write", NULL, 0, top, button_write, kbd, 0);
1404 
1405   return box;
1406 }
1407 
1408 
1409 
1410 /* These are used to compute the default sizes of the windows.  Hack hack.
1411  */
1412 #define LONGEST_KEYSYM_NAME "Greek_upsilonaccentdieresis"
1413 #define MEDIUM_LENGTH_KEYSYM_NAME "Greek_IOTAdiaresis"
1414 
1415 struct keyset_names {
1416   const char *name;	/* The name of this keyset (for the dialog box) */
1417   unsigned int number;	/* The top two bytes of corresponding keysym values */
1418 }
1419 
1420 static all_keyset_names[] = {
1421   { "Latin1",		0x00 },
1422   { "Latin2",		0x01 },
1423   { "Latin3",		0x02 },
1424   { "Latin4",		0x03 },
1425   { "Katakana",		0x04 },
1426   { "Arabic",		0x05 },
1427   { "Cyrillic",		0x06 },
1428   { "Greek",		0x07 },
1429   { "Technical",	0x08 },
1430   { "Special",		0x09 },
1431   { "Publishing",	0x0A },
1432   { "APL",		0x0B },
1433   { "Hebrew",		0x0C },
1434   { "Thai",		0x0D },
1435   { "Korean",		0x0E },
1436   { "ISO",		0xFE },	/* "ISO 9995 Function and Modifier Keys" */
1437   { "Keyboard",		0xFF },
1438 #ifdef DO_VENDOR_KEYSYMS
1439   { "Vendor",	      0xFFFF }, /* special-case hack */
1440 #endif
1441   { 0, 0 }
1442 };
1443 
1444 static char **keysym_name_buffer = 0;
1445 static int keysym_name_buffer_size = 0;
1446 
1447 static void
1448 #ifdef __STDC__
ensure_keysym_name_buffer(int size)1449 ensure_keysym_name_buffer (int size)
1450 #else /* ! __STDC__ */
1451 ensure_keysym_name_buffer (size)
1452      int size;
1453 #endif /* ! __STDC__ */
1454 {
1455   if (keysym_name_buffer_size >= size)
1456     return;
1457   if (keysym_name_buffer) free ((char *) keysym_name_buffer);
1458   keysym_name_buffer_size = size;
1459   keysym_name_buffer = (char **) malloc (sizeof (char *) * size);
1460 }
1461 
1462 
1463 #ifdef DO_VENDOR_KEYSYMS
1464 struct vendor_keysym {
1465   char *name;
1466   KeySym keysym;
1467   int index;
1468 };
1469 
1470 static struct vendor_keysym *vendor_keysyms = 0;
1471 static int n_vendor_keysyms = 0;
1472 
1473 static XrmDatabase vendor_keysym_db = 0;
1474 
1475 static Bool
1476 #ifdef __STDC__
init_vendor_keysyms_mapper(XrmDatabase * db,XrmBindingList bindings,XrmQuarkList quarks,XrmRepresentation * type,XrmValue * value,XPointer closure)1477 init_vendor_keysyms_mapper (XrmDatabase *db,
1478 			    XrmBindingList bindings,
1479 			    XrmQuarkList quarks,
1480 			    XrmRepresentation *type,
1481 			    XrmValue *value,
1482 			    XPointer closure)
1483 #else /* ! __STDC__ */
1484 init_vendor_keysyms_mapper (db, bindings, quarks, type, value, closure)
1485      XrmDatabase *db;
1486      XrmBindingList bindings;
1487      XrmQuarkList quarks;
1488      XrmRepresentation *type;
1489      XrmValue *value;
1490      XPointer closure;
1491 #endif /* ! __STDC__ */
1492 {
1493   KeySym keysym;
1494   char c;
1495   int i;
1496   int *count = (int *) closure;
1497   if (quarks [1]) /* should only be one level deep. */
1498     abort ();
1499 
1500   if (! value->addr || value->size <= 1)
1501     return False;
1502 
1503   keysym = 0;
1504   for (i = 0; i < value->size - 1; i++)
1505     {
1506       c = ((char *) value->addr) [i];
1507       if ('0' <= c && c <= '9') keysym = (keysym<<4)+c-'0';
1508       else if ('a' <= c && c <= 'z') keysym = (keysym<<4)+c-'a'+10;
1509       else if ('A' <= c && c <= 'Z') keysym = (keysym<<4)+c-'A'+10;
1510       else
1511 	{
1512 	  fprintf (stderr, "%s: unparsable entry in XKeysymDB: \"%s: %s\"\n",
1513 		   progname, XrmQuarkToString (quarks [0]),
1514 		   (char *) value->addr);
1515 	  return False;
1516 	}
1517     }
1518 
1519   if (n_vendor_keysyms <= *count)
1520     {
1521       n_vendor_keysyms *= 2;
1522       vendor_keysyms = (struct vendor_keysym *)
1523 	realloc (vendor_keysyms, sizeof (struct vendor_keysym) *
1524 		 n_vendor_keysyms);
1525     }
1526   vendor_keysyms [*count].index = -1; /* we fill this in later */
1527   vendor_keysyms [*count].keysym = keysym;
1528   vendor_keysyms [*count].name = (char *) XrmQuarkToString (quarks [0]);
1529   (*count)++;
1530   return False;
1531 }
1532 
1533 
1534 static int
1535 #ifdef __STDC__
sort_vendor_keysyms_1(int left,int right)1536 sort_vendor_keysyms_1 (int left, int right)
1537 #else /* ! __STDC__ */
1538 sort_vendor_keysyms_1 (left, right)
1539      int left, right;
1540 #endif /* ! __STDC__ */
1541 {
1542   int L = left, R = right, middle;
1543   struct vendor_keysym swap;
1544   KeySym pivot = vendor_keysyms [left].keysym;
1545   while (L < R)
1546     {
1547       while (vendor_keysyms [L].keysym <= pivot && L <= right)
1548 	L++;
1549       while (vendor_keysyms [R].keysym > pivot && R >= left)
1550 	R--;
1551       if (L < R)
1552 	{
1553 	  swap = vendor_keysyms [L];
1554 	  vendor_keysyms [L] = vendor_keysyms [R];
1555 	  vendor_keysyms [R] = swap;
1556 	}
1557     }
1558   middle = R;
1559   swap = vendor_keysyms [left];
1560   vendor_keysyms [left] = vendor_keysyms [middle];
1561   vendor_keysyms [middle] = swap;
1562   if (left < middle - 1)
1563     middle = sort_vendor_keysyms_1 (left, middle - 1);
1564   if (middle + 1 < right)
1565     middle = sort_vendor_keysyms_1 (middle + 1, right);
1566   return middle;
1567 }
1568 
1569 
1570 static void
sort_vendor_keysyms(void)1571 sort_vendor_keysyms P((void))
1572 {
1573   int i;
1574   sort_vendor_keysyms_1 (0, n_vendor_keysyms - 1);
1575   for (i = 0; i < n_vendor_keysyms; i++)
1576     {
1577       if (i > 0 && vendor_keysyms [i].keysym < vendor_keysyms [i-1].keysym)
1578 	abort ();
1579       vendor_keysyms [i].index = i;
1580     }
1581 }
1582 
1583 
1584 #ifndef NO_XInitKeysymDB
1585 extern XrmDatabase _XInitKeysymDB P((void));
1586 #endif
1587 
1588 static void
1589 #ifdef __STDC__
init_vendor_keysyms(KeyboardWidget widget)1590 init_vendor_keysyms (KeyboardWidget widget)
1591 #else /* ! __STDC__ */
1592 init_vendor_keysyms (widget)
1593      KeyboardWidget widget;
1594 #endif /* ! __STDC__ */
1595 {
1596   static int done = 0;
1597   int count = 0;
1598   XrmName name = { 0 };
1599   XrmClass class = { 0 };
1600 
1601   if (done) return;
1602   done = 1;
1603 
1604   if (! vendor_keysym_db)
1605     {
1606       char *dbname = (char *) getenv ("XKEYSYMDB");
1607 #ifdef KEYSYMDB
1608       if (! dbname) dbname = KEYSYMDB;
1609 #endif /*  KEYSYMDB */
1610 
1611 #ifdef NO_XInitKeysymDB
1612       if (dbname)
1613 	vendor_keysym_db = XrmGetFileDatabase (dbname);
1614 #else  /* we have _XInitKeysymDB(), so let Xlib be clever for us. */
1615       vendor_keysym_db = _XInitKeysymDB ();
1616 #endif /* _XInitKeysymDB */
1617 
1618       if (! vendor_keysym_db) /* still don't have it... */
1619 	{
1620 	  if (dbname)
1621 	    y_or_n_p_with_args (widget, "noKeysymDBError", "ok", 0, 0,
1622 				dbname, 0, 0, 0, 0, 0);
1623 	  else
1624 	    y_or_n_p (widget, "unknownKeysymDBError", "ok", 0, 0);
1625 	  return;
1626 	}
1627     }
1628 
1629   n_vendor_keysyms = 255; /* probably not more than this; it's realloc'd. */
1630   vendor_keysyms = (struct vendor_keysym *)
1631     malloc (n_vendor_keysyms * sizeof (struct vendor_keysym));
1632 
1633   XrmEnumerateDatabase (vendor_keysym_db, &name, &class,
1634 			XrmEnumOneLevel, init_vendor_keysyms_mapper,
1635 			(XtPointer) &count);
1636 
1637   if (count < n_vendor_keysyms) /* might as well shrink it */
1638     {
1639       n_vendor_keysyms = count;
1640       vendor_keysyms = (struct vendor_keysym *)
1641 	realloc (vendor_keysyms, count * sizeof (struct vendor_keysym));
1642     }
1643   else if (! count)
1644     {
1645       free ((char *) vendor_keysyms);
1646       n_vendor_keysyms = 0;
1647       vendor_keysyms = 0;
1648       return;
1649     }
1650   /* Hash order isn't very pretty; sort them by keysym numeric value. */
1651   sort_vendor_keysyms ();
1652 }
1653 
1654 static void
1655 #ifdef __STDC__
fill_keysym_name_buffer_with_vendor_keysyms(KeyboardWidget keyboard)1656 fill_keysym_name_buffer_with_vendor_keysyms (KeyboardWidget keyboard)
1657 #else /* ! __STDC__ */
1658 fill_keysym_name_buffer_with_vendor_keysyms (keyboard)
1659      KeyboardWidget keyboard;
1660 #endif /* ! __STDC__ */
1661 {
1662   int i;
1663   if (! vendor_keysyms) init_vendor_keysyms (keyboard);
1664   ensure_keysym_name_buffer (n_vendor_keysyms + 1);
1665   for (i = 0; i < n_vendor_keysyms; i++)
1666     keysym_name_buffer [i] = vendor_keysyms [i].name;
1667   keysym_name_buffer [i] = 0;
1668 }
1669 
1670 
1671 static int
1672 #ifdef __STDC__
vendor_keysym_to_small_index(KeyboardWidget keyboard,KeySym keysym)1673 vendor_keysym_to_small_index (KeyboardWidget keyboard, KeySym keysym)
1674 #else /* ! __STDC__ */
1675 vendor_keysym_to_small_index (keyboard, keysym)
1676      KeyboardWidget keyboard;
1677      KeySym keysym;
1678 #endif /* ! __STDC__ */
1679 {
1680   int i;
1681   char buf [255];
1682   if (! vendor_keysyms) init_vendor_keysyms (keyboard);
1683   for (i = 0; i < n_vendor_keysyms; i++)
1684     if (keysym == vendor_keysyms [i].keysym)
1685       return vendor_keysyms [i].index;
1686   sprintf (buf, "Unrecognised vendor keysym 0x%08X.", (int) keysym);
1687   XBell (XtDisplay ((Widget) keyboard), 0);
1688   message (keyboard, buf);
1689   fprintf (stderr, "%s: %s\n", progname, buf);
1690   return 0;
1691 }
1692 
1693 #endif /* DO_VENDOR_KEYSYMS */
1694 
1695 
1696 struct edit_key_box {
1697   KeyboardWidget keyboard;
1698   Widget shell;
1699   Widget label;
1700   Widget keysym_buttons [8];
1701   Widget mod_buttons [8];
1702   Widget keyset_list, keysym_list;
1703   Widget autorepeat_widget;
1704   int autorepeat;
1705 };
1706 
1707 
1708 static void
1709 #ifdef __STDC__
keyset_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)1710 keyset_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1711 #else /* ! __STDC__ */
1712 keyset_list_cb (widget, client_data, call_data)
1713      Widget widget;
1714      XtPointer client_data, call_data;
1715 #endif /* ! __STDC__ */
1716 {
1717   XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
1718   struct edit_key_box *box = (struct edit_key_box *) client_data;
1719   int set = 0;
1720   int i, j = 0;
1721   int set_start = 0;
1722 
1723   set = -1;
1724   for (i = 0; i < sizeof(all_keyset_names)/sizeof(*all_keyset_names); i++)
1725     if (lr->list_index == i)
1726       {
1727 	set = all_keyset_names[i].number;
1728 	break;
1729       }
1730 
1731   if (set != 0) set_start = 1; /* Latin1 is the only set that has NoSymbol */
1732 
1733 #ifdef DO_VENDOR_KEYSYMS
1734   if (set == 0xFFFF)	/* FFFF means "vendor keysym" */
1735     fill_keysym_name_buffer_with_vendor_keysyms (box->keyboard);
1736   else
1737 #endif
1738   if (set == -1)
1739     {
1740       ensure_keysym_name_buffer (256);
1741       keysym_name_buffer [0] = 0;
1742     }
1743   else
1744     {
1745       ensure_keysym_name_buffer (256);
1746       for (i = set_start; i < 256; i++)
1747 	{
1748 	  char *name = XKeysymToString ((set << 8) | i);
1749 	  if (! name && i == 0) name = "NoSymbol";
1750 	  if (name)
1751 	    keysym_name_buffer [j++] = name;
1752 	}
1753       keysym_name_buffer [j++] = 0;
1754     }
1755   XawListChange (box->keysym_list, keysym_name_buffer, 0, 0, True);
1756 }
1757 
1758 
1759 static void
1760 #ifdef __STDC__
keysym_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)1761 keysym_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1762 #else /* ! __STDC__ */
1763 keysym_list_cb (widget, client_data, call_data)
1764      Widget widget;
1765      XtPointer client_data, call_data;
1766 #endif /* ! __STDC__ */
1767 {
1768   XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
1769   struct edit_key_box *box = (struct edit_key_box *) client_data;
1770   int i = (int) XawToggleGetCurrent (box->keysym_buttons [0]);
1771   if (i > 0)
1772     {
1773       Widget button = box->keysym_buttons [i-1];
1774       /* If the string is wider than the parent of the button, setting the
1775 	 label will leave it at the size it was before.  So, first stretch
1776 	 it to the max width, and then let SetValues (maybe) resize it
1777 	 smaller.  What a piece of junk. */
1778       XtResizeWidget (button,
1779 		      XtParent (button)->core.width,
1780 		      button->core.height,
1781 		      button->core.border_width);
1782       XtVaSetValues (button, XtNlabel, lr->string, 0);
1783     }
1784 }
1785 
1786 
1787 static void
1788 #ifdef __STDC__
autorepeat_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)1789 autorepeat_button_cb (Widget widget, XtPointer client_data,
1790 		      XtPointer call_data)
1791 #else /* ! __STDC__ */
1792 autorepeat_button_cb (widget, client_data, call_data)
1793      Widget widget;
1794      XtPointer client_data, call_data;
1795 #endif /* ! __STDC__ */
1796 {
1797   struct edit_key_box *box = (struct edit_key_box *) client_data;
1798   Arg av [10];
1799   int ac = 0;
1800   box->autorepeat = !box->autorepeat;
1801   XtSetArg (av [ac], XtNlabel, (box->autorepeat ? "Yes" : "No")); ac++;
1802   XtSetValues (widget, av, ac);
1803 }
1804 
1805 
1806 static void
1807 #ifdef __STDC__
abort_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)1808 abort_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1809 #else /* ! __STDC__ */
1810 abort_button_cb (widget, client_data, call_data)
1811      Widget widget;
1812      XtPointer client_data, call_data;
1813 #endif /* ! __STDC__ */
1814 {
1815   struct edit_key_box *box = (struct edit_key_box *) client_data;
1816   XtPopdown (box->shell);
1817   message (box->keyboard, "Aborted.");
1818 }
1819 
1820 
1821 static int stop_the_insanity P((KeyboardWidget,
1822 				int keycode, KeySym *keysyms, int count,
1823 				unsigned long modbits,
1824 				XModifierKeymap *modmap));
1825 
1826 
1827 static void
1828 #ifdef __STDC__
ok_button_cb(Widget button,XtPointer client_data,XtPointer call_data)1829 ok_button_cb (Widget button, XtPointer client_data, XtPointer call_data)
1830 #else /* ! __STDC__ */
1831 ok_button_cb (button, client_data, call_data)
1832      Widget button;
1833      XtPointer client_data, call_data;
1834 #endif /* ! __STDC__ */
1835 {
1836   struct edit_key_box *box = (struct edit_key_box *) client_data;
1837   KeyboardWidget widget = box->keyboard;
1838   KeyWidget key = widget->keyboard.key_under_mouse;
1839   KeyCode code = key->key.keycode;
1840   KeySym keysyms [8];
1841   int keysym_count;
1842   unsigned long modbits = 0;
1843   XModifierKeymap *modmap = XGetModifierMapping (XtDisplay (widget));
1844   int i, error;
1845   Arg av [10];
1846   int ac = 0;
1847   char *str;
1848 
1849   ac = 0;
1850   XtSetArg (av [ac], XtNlabel, &str); ac++;
1851   for (i = 0; i < 8; i++)
1852     {
1853       XtGetValues (box->keysym_buttons [i], av, ac);
1854       if (str && !strcmp (str, "NoSymbol")) str = 0;
1855       if (! str)
1856 	keysyms [i] = 0;
1857       else
1858 	{
1859 	  keysyms [i] = XStringToKeysym (str);
1860 	  if (! keysyms [i])
1861 	    fprintf (stderr,
1862 		     "%s: ERROR: XStringToKeysym(\"%s\") returned 0\n",
1863 		     progname, str);
1864 	}
1865     }
1866   for (keysym_count = 8; keysym_count > 0; keysym_count--)
1867     if (keysyms [keysym_count-1]) break;
1868 
1869   for (i = 0; i < 8; i++)
1870     {
1871 #ifndef XAWBUG
1872       Boolean state = 0;
1873       XtVaGetValues (box->mod_buttons[i], XtNstate, &state, NULL);
1874 #else /* XAWBUG */
1875       int state = ((CommandWidget) (box->mod_buttons [i]))->command.set;
1876 #endif
1877       modbits |= ((!!state) << i);
1878       if (state)
1879 	modmap = XInsertModifiermapEntry (modmap, code, i);
1880       else
1881 	modmap = XDeleteModifiermapEntry (modmap, code, i);
1882     }
1883 
1884   if (stop_the_insanity (widget, code, keysyms, keysym_count, modbits, modmap))
1885     return;
1886 
1887   XSync (XtDisplay (widget), 0);
1888   error = modify_keyboard (widget, code, keysym_count,
1889 			   keysyms, 1, modmap);
1890   XFreeModifiermap (modmap);
1891 
1892   if (!error && box->autorepeat != key->key.auto_repeat_p)
1893     {
1894       XKeyboardControl values;
1895       values.key = key->key.keycode;
1896       values.auto_repeat_mode =
1897 	(box->autorepeat ? AutoRepeatModeOn : AutoRepeatModeOff);
1898       XChangeKeyboardControl (XtDisplay (widget), KBKey | KBAutoRepeatMode,
1899 			      &values);
1900     }
1901 
1902   XtPopdown (box->shell);
1903 
1904   if (! error) message (box->keyboard, "Modified.");
1905 }
1906 
1907 
1908 static void
1909 #ifdef __STDC__
move_scrollbar(Widget list,float percent)1910 move_scrollbar (Widget list, float percent)
1911 #else /* ! __STDC__ */
1912 move_scrollbar (list, percent)
1913      Widget list;
1914      float percent;
1915 #endif /* ! __STDC__ */
1916 {
1917   Widget vp = XtParent (list);
1918   Widget scrollbar = XtNameToWidget (vp, "vertical");
1919   float visible_fraction = (((float) vp->core.height) /
1920 			    ((float) list->core.height));
1921   if (visible_fraction < 1.0)
1922     percent -= (visible_fraction / 2.0);
1923   XawScrollbarSetThumb (scrollbar, 0.0, -1.0);
1924   XtCallCallbacks (scrollbar, XtNjumpProc, (XtPointer) &percent);
1925 }
1926 
1927 
1928 static void
1929 #ifdef __STDC__
keysym_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)1930 keysym_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
1931 #else /* ! __STDC__ */
1932 keysym_button_cb (widget, client_data, call_data)
1933      Widget widget;
1934      XtPointer client_data, call_data;
1935 #endif /* ! __STDC__ */
1936 {
1937   struct edit_key_box *box = (struct edit_key_box *) client_data;
1938   KeyboardWidget keyboard = box->keyboard;
1939   char *keysym_name = 0;
1940   KeySym real_keysym;
1941   int list_index = 0;
1942   int keyset = 0, keysym = 0, index = 0, list_size = 0;
1943   Arg av[10];
1944   int ac = 0;
1945   int i;
1946 
1947   if (call_data == 0)	/* we're being toggled off */
1948     return;
1949 
1950   XtSetArg (av[ac], XtNlabel, &keysym_name); ac++;
1951   XtGetValues (widget, av, ac);
1952   real_keysym = XStringToKeysym (keysym_name);
1953   /* Get the one that's in the list */
1954   keysym_name = XKeysymToString (real_keysym);
1955 
1956   if (real_keysym > 0xFFFF)
1957     {
1958 #ifdef DO_VENDOR_KEYSYMS
1959       int i;
1960       keysym = 0;
1961       for (i = 0; i < sizeof(all_keyset_names)/sizeof(*all_keyset_names); i++)
1962 	if (!strcmp(all_keyset_names[i].name, "Vendor"))
1963 	  {
1964 	    keysym = i;
1965 	    break;
1966 	  }
1967       if (keysym == 0) abort();
1968       keysym = vendor_keysym_to_small_index (keyboard, real_keysym);
1969 #else
1970       XBell (XtDisplay (keyboard), 0);
1971       message (keyboard,
1972 	       "XKeyCaps was compiled without support for Vendor keysyms.");
1973       message2 (keyboard, "Consider upgrading to X11r5...");
1974       keyset = 0;
1975       keysym = 0;
1976 #endif
1977     }
1978   else
1979     {
1980       keyset = (real_keysym >> 8);
1981       keysym = (real_keysym & 0xff);
1982     }
1983 
1984   list_size = (sizeof (all_keyset_names) / sizeof (all_keyset_names[0]));
1985 
1986   list_index = -1;
1987   for (i = 0; i < sizeof(all_keyset_names)/sizeof(*all_keyset_names); i++)
1988     if (all_keyset_names[i].number == keyset)
1989       {
1990 	list_index = i;
1991 	break;
1992       }
1993 
1994   if (list_index < 0)
1995     {
1996       XawListUnhighlight(box->keyset_list);
1997       move_scrollbar (box->keyset_list, 0.0);
1998     }
1999   else
2000     {
2001       XawListHighlight (box->keyset_list, list_index);
2002       move_scrollbar (box->keyset_list,
2003 		      (((float) list_index) / ((float) list_size)));
2004     }
2005   keyset_list_cb (box->keyset_list, box,
2006 		  XawListShowCurrent (box->keyset_list));
2007 
2008   index = 256;
2009   for (list_size = 0; list_size < 256; list_size++)
2010     if (keysym_name_buffer [list_size] == keysym_name)
2011       index = list_size;
2012     else if (! keysym_name_buffer [list_size])
2013       break;
2014   if (! keysym_name) index = 0;
2015   if (index < 256)
2016     {
2017       XawListHighlight (box->keysym_list, index);
2018       move_scrollbar (box->keysym_list,
2019 		      (((float) index) / ((float) list_size)));
2020     }
2021   else
2022     {
2023       XawListUnhighlight (box->keysym_list);
2024     }
2025 }
2026 
2027 
2028 static void
2029 #ifdef __STDC__
undo_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)2030 undo_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2031 #else /* ! __STDC__ */
2032 undo_button_cb (widget, client_data, call_data)
2033      Widget widget;
2034      XtPointer client_data, call_data;
2035 #endif /* ! __STDC__ */
2036 {
2037   struct edit_key_box *box = (struct edit_key_box *) client_data;
2038   KeyboardWidget keyboard = box->keyboard;
2039   KeyWidget key = keyboard->keyboard.key_under_mouse;
2040   KeySym *keysyms;
2041   int syms_per_code = 0;
2042   char buf [255];
2043   Arg av[20];
2044   int ac = 0;
2045   int i;
2046 
2047   keysyms = XGetKeyboardMapping (XtDisplay (widget), key->key.keycode,
2048 				 1, &syms_per_code);
2049 
2050   sprintf (buf, "Definition of key 0x%02X (%s)", key->key.keycode,
2051 	   key->key.key_name);
2052   XtSetArg (av[ac], XtNlabel, buf); ac++;
2053   XtSetValues (box->label, av, ac);
2054   ac = 0;
2055 
2056   for (i = 0; i < syms_per_code; i++)
2057     {
2058       char *sym;
2059       char buf [255];
2060       if (!keysyms || !keysyms[i])
2061 	sym = "NoSymbol";
2062       else
2063 	sym = XKeysymToString (keysyms [i]);
2064       if (! sym)
2065 	{
2066 	  sprintf (buf, "0x%04X", (int) keysyms [i]);
2067 	  sym = buf;
2068 	}
2069       ac = 0;
2070       XtSetArg (av[ac], XtNlabel, sym); ac++;
2071       XtSetValues (box->keysym_buttons [i], av, ac);
2072     }
2073   if (keysyms) XFree ((char *) keysyms);
2074   ac = 0;
2075   XtSetArg (av[ac], XtNlabel, "NoSymbol"); ac++;
2076   for (; i < 8; i++)
2077     XtSetValues (box->keysym_buttons [i], av, ac);
2078 
2079   for (i = 0; i < 8; i++)
2080     {
2081       ac = 0;
2082       XtSetArg (av[ac], XtNstate,
2083 		((key->key.modifier_bits & 1<<i) ? True : False)); ac++;
2084       XtSetValues (box->mod_buttons [i], av, ac);
2085     }
2086 
2087   XawToggleSetCurrent (box->keysym_buttons [0], (XtPointer) 1);
2088   keysym_button_cb (box->keysym_buttons [0], box, (void *) 1);
2089   box->autorepeat = !key->key.auto_repeat_p;
2090   autorepeat_button_cb (box->autorepeat_widget, box, 0);
2091 }
2092 
2093 
2094 static struct edit_key_box *
2095 #ifdef __STDC__
make_edit_key_dbox(KeyboardWidget widget)2096 make_edit_key_dbox (KeyboardWidget widget)
2097 #else /* ! __STDC__ */
2098 make_edit_key_dbox (widget)
2099      KeyboardWidget widget;
2100 #endif /* ! __STDC__ */
2101 {
2102   struct edit_key_box *box = (struct edit_key_box *)
2103     malloc (sizeof (struct edit_key_box));
2104   Arg av [20];
2105   int ac = 0;
2106   Widget toplevel, box1, box2;
2107   Widget keysym_box, button_box, keyset_box, keyset_syms_box, mod_box;
2108   Widget line_box, prev, prev_tog;
2109   Widget set_list, sym_list;
2110   Widget set_vp, sym_vp;
2111 
2112   toplevel = XtCreatePopupShell ("editKey", transientShellWidgetClass,
2113 				 (Widget) widget, av, ac);
2114   box1 = XtCreateManagedWidget ("vertical", panedWidgetClass, toplevel, av,ac);
2115   box->label = make_label (box1, "label", 0, 0, 0);
2116   ac = 0;
2117   XtSetArg (av[ac], XtNorientation, "horizontal"); ac++;
2118   box2 = XtCreateManagedWidget ("horizontal", panedWidgetClass, box1, av, ac);
2119 
2120   ac = 0;
2121   keysym_box = XtCreateManagedWidget ("keysymBox", formWidgetClass, box2,
2122 				      av, ac);
2123   prev = make_label (keysym_box, "symsOfCode", 0, 0, 0);
2124   prev = make_label (keysym_box, "spacer", "", 0, prev);
2125   ac = 0;
2126   prev_tog = 0;
2127   line_box = prev;
2128 #define TOG(var, name, index) \
2129    { ac = 0; \
2130      XtSetArg (av[ac], XtNorientation, "horizontal"); ac++; \
2131      XtSetArg (av [ac], XtNfromVert, line_box); ac++; \
2132      XtSetArg (av[ac], XtNtop, XtChainTop); ac++; \
2133      XtSetArg (av[ac], XtNbottom, XtChainTop); ac++; \
2134      line_box = XtCreateManagedWidget ("keysymLine", boxWidgetClass, \
2135 				       keysym_box, av, ac); \
2136      var = make_label (line_box, name, 0, 0, prev); \
2137      if (index) \
2138        var = make_toggle (line_box, "keysymValue" ,var, prev, 0, \
2139 			  keysym_button_cb, box, MEDIUM_LENGTH_KEYSYM_NAME, \
2140 			  prev_tog, (XtPointer) index); \
2141      else \
2142        var = make_button (line_box, "autoRepeatValue", "Yes", var, prev, \
2143 			  autorepeat_button_cb, box, 0); \
2144        prev_tog = prev = var; }
2145   TOG (box->keysym_buttons [0], "keysym1", 1);
2146   TOG (box->keysym_buttons [1], "keysym2", 2);
2147   TOG (box->keysym_buttons [2], "keysym3", 3);
2148   TOG (box->keysym_buttons [3], "keysym4", 4);
2149   TOG (box->keysym_buttons [4], "keysym5", 5);
2150   TOG (box->keysym_buttons [5], "keysym6", 6);
2151   TOG (box->keysym_buttons [6], "keysym7", 7);
2152   TOG (box->keysym_buttons [7], "keysym8", 8);
2153   prev = prev_tog = 0;
2154   line_box = make_label (keysym_box, "spacer2", "", 0, line_box);
2155   TOG (box->autorepeat_widget, "autoRepeat", 0);
2156 #undef TOG
2157 
2158   ac = 0;
2159   mod_box = XtCreateManagedWidget ("modifierBox", formWidgetClass,
2160 				   box2, av, ac);
2161   prev = make_label (mod_box, "modifiers", 0, 0, 0);
2162   prev = make_label (mod_box, "spacer", "", 0, prev);
2163 #define TOG(var, name) \
2164    { var = make_toggle (mod_box, name, 0, prev, 0, 0, 0, 0, 0, 0); \
2165      prev = var; }
2166   TOG (box->mod_buttons [0], "modShift");
2167   TOG (box->mod_buttons [1], "modLock");
2168   TOG (box->mod_buttons [2], "modControl");
2169   TOG (box->mod_buttons [3], "mod1");
2170   TOG (box->mod_buttons [4], "mod2");
2171   TOG (box->mod_buttons [5], "mod3");
2172   TOG (box->mod_buttons [6], "mod4");
2173   TOG (box->mod_buttons [7], "mod5");
2174 #undef TOG
2175 
2176   ac = 0;
2177   keyset_box = XtCreateManagedWidget("keysetBox", formWidgetClass,
2178 				     box2, av, ac);
2179   prev = make_label (keyset_box, "allKeySets", 0, 0, 0);
2180   ac = 0;
2181   XtSetArg (av[ac], XtNfromVert, prev); ac++;
2182   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2183   XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2184   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2185   XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2186   set_vp = XtCreateManagedWidget ("keysetsVp", viewportWidgetClass,
2187 				  keyset_box, av, ac);
2188   ac = 0;
2189   {
2190     static const char *list[sizeof(all_keyset_names) /
2191 			    sizeof(*all_keyset_names)];
2192     int i = 0;
2193     for (i = 0; i < sizeof(list)/sizeof(*list); i++)
2194       list[i] = all_keyset_names[i].name;
2195     XtSetArg (av[ac], XtNlist, list); ac++;
2196   }
2197 
2198   set_list = XtCreateManagedWidget ("keysets", listWidgetClass, set_vp,av,ac);
2199   XtAddCallback (set_list, XtNcallback, keyset_list_cb, (XtPointer) box);
2200 
2201   /* Gag!  These lists won't size themselves correctly. */
2202   XtVaSetValues (set_list, XtNwidth, set_list->core.width + 20, 0);
2203 
2204   ac = 0;
2205   keyset_syms_box = XtCreateManagedWidget ("keysetSymsBox", formWidgetClass,
2206 					   box2, av, ac);
2207   prev = make_label (keyset_syms_box, "keySymsOfSet", 0, 0, 0);
2208   ac = 0;
2209   XtSetArg (av[ac], XtNfromVert, prev); ac++;
2210   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2211   XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2212   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2213   XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2214   sym_vp = XtCreateManagedWidget ("keysymsVp", viewportWidgetClass,
2215 				  keyset_syms_box, av, ac);
2216   ensure_keysym_name_buffer (256);
2217 
2218 #if 0
2219   memcpy (keysym_name_buffer, all_keyset_names, sizeof (all_keyset_names));
2220 #endif
2221 
2222   keysym_name_buffer [0] = LONGEST_KEYSYM_NAME;
2223   keysym_name_buffer [1] = 0;
2224 
2225   ac = 0;
2226   XtSetArg (av[ac], XtNlist, keysym_name_buffer); ac++;
2227   sym_list = XtCreateManagedWidget ("keysyms", listWidgetClass, sym_vp,av,ac);
2228   XtAddCallback (sym_list, XtNcallback, keysym_list_cb, (XtPointer) box);
2229 
2230   /* Gag!  These lists won't size themselves correctly. */
2231   XtVaSetValues (sym_list, XtNwidth, sym_list->core.width + 20, 0);
2232 
2233   ac = 0;
2234   XtSetArg (av[ac], XtNskipAdjust, True); ac++;
2235   button_box = XtCreateManagedWidget ("buttons", boxWidgetClass, box1, av, ac);
2236 
2237   prev = make_button (button_box, "undo",  0,    0, 0, undo_button_cb, box, 0);
2238   prev = make_button (button_box, "abort", 0, prev, 0, abort_button_cb, box,0);
2239   prev = make_button (button_box, "ok",    0, prev, 0, ok_button_cb, box, 0);
2240 
2241   box->keyboard = widget;
2242   box->shell = toplevel;
2243   box->keyset_list = set_list;
2244   box->keysym_list = sym_list;
2245   return box;
2246 }
2247 
2248 static void
2249 #ifdef __STDC__
pop_up_key_dbox(Widget parent,XtPointer client_data,XtPointer call_data)2250 pop_up_key_dbox (Widget parent, XtPointer client_data, XtPointer call_data)
2251 #else /* ! __STDC__ */
2252 pop_up_key_dbox  (parent, client_data, call_data)
2253      Widget parent;
2254      XtPointer client_data, call_data;
2255 #endif /* ! __STDC__ */
2256 {
2257   KeyboardWidget widget = (KeyboardWidget) client_data;
2258   struct edit_key_box *edit_key_box =
2259     widget->keyboard.key_menus->edit_key_box;
2260 
2261   if (widget->keyboard.key_under_mouse->key.keycode == 0)
2262     {
2263       y_or_n_p (widget, "magicKeyError", "ok", 0, 0);
2264       return;
2265     }
2266 
2267   {
2268     Widget topmost = parent;
2269     int x, y, w, h;
2270     XtRealizeWidget (edit_key_box->shell);
2271     w = edit_key_box->shell->core.width;
2272     h = edit_key_box->shell->core.height;
2273     while (topmost->core.parent)
2274       topmost = topmost->core.parent;
2275     if (topmost->core.width < w) x = topmost->core.x;
2276     else x = topmost->core.x + ((topmost->core.width - w) / 2);
2277     if (topmost->core.height < h) y = topmost->core.y;
2278     else y = topmost->core.y + ((topmost->core.height - h) / 2);
2279     XtMoveWidget (edit_key_box->shell, x, y);
2280   }
2281   XtPopup (edit_key_box->shell, XtGrabNonexclusive);
2282   undo_button_cb (edit_key_box->shell, edit_key_box, 0);
2283 }
2284 
2285 
2286 
2287 static struct keyboard_set {
2288   int kbd_index;
2289   const char *vendor;
2290   char *type;
2291   char **maps;		/* short names of maps */
2292   char **full_maps;	/* long names (vendor+kbd+map) */
2293   int map_count;
2294 } *keyboard_sets;
2295 
2296 int keyboard_set_count;
2297 int vendor_count;
2298 static char const **vendors;
2299 static char **keyboard_types;	/* compared to keyboard_sets[i].type[j] */
2300 static char *longest_type;	/* longest of all keyboard_sets[i].type */
2301 static char *longest_map;	/* longest of all keyboard_sets[i].maps[j] */
2302 
2303 struct select_kbd_box {
2304   KeyboardWidget keyboard;
2305   Widget shell;
2306   Widget label;
2307   Widget label2;
2308   Widget icon;
2309   Widget vendor_list, keyboard_list, keymap_list;
2310   struct keyboard_set *set;
2311   const char *map;
2312 };
2313 
2314 
2315 static char *default_maps[] = { "default", 0 };
2316 
2317 static void
make_kbd_lists(void)2318 make_kbd_lists P((void))
2319 {
2320   int kbd_count = 0;
2321   int i, j;
2322 
2323   i = 0;
2324   vendor_count = 0;
2325   while (all_kbds[i].vendor)
2326     {
2327       const char *v = all_kbds[i].vendor;
2328       vendor_count++;
2329       i++;
2330       while (all_kbds[i].vendor &&
2331 	     !strcmp(v, all_kbds[i].vendor))
2332 	i++;
2333     }
2334 
2335   vendors = (const char **) malloc (sizeof(*vendors) * (vendor_count+1));
2336   i = 0;
2337   j = 0;
2338   while (all_kbds[i].vendor)
2339     {
2340       const char *v = all_kbds[i].vendor;
2341       vendors[j++] = v;
2342       i++;
2343       while (all_kbds[i].vendor &&
2344 	     !strcmp(v, all_kbds[i].vendor))
2345 	i++;
2346     }
2347   vendors[j] = 0;
2348 
2349 
2350   for (kbd_count = 0; all_kbds [kbd_count].short_name; kbd_count++)
2351     ;
2352   keyboard_sets = (struct keyboard_set *)
2353     malloc (sizeof (struct keyboard_set) * kbd_count);
2354   longest_type = 0;
2355   longest_map = 0;
2356 
2357   i = 0;
2358   j = 0;
2359   while (i < kbd_count)
2360     {
2361       char last_style [255];
2362       char full [255];
2363 
2364       char *tail;
2365       strcpy (last_style, all_kbds[i].kbd_style);
2366       make_long_kbd_name (all_kbds[i].vendor, last_style, full);
2367 
2368       tail = (char *) strchr (last_style, '(');
2369       if (tail) *tail = 0;
2370 
2371       tail = (char *) strchr (full, '(');
2372       keyboard_sets [j].kbd_index = i;
2373       keyboard_sets [j].map_count = 0;
2374       keyboard_sets [j].vendor = all_kbds[i].vendor;
2375 
2376       if (tail)
2377 	{
2378 	  int L;
2379 	  int count = 0;
2380 	  int k;
2381 
2382 	  /* Edit out the parens (but not the trailing space) */
2383 	  *tail = 0;
2384 	  tail++;
2385 	  tail [strlen (tail) - 1] = 0;
2386 
2387 	  L = strlen (full);
2388 	  count = 0;
2389 	  while (1)
2390 	    {
2391 	      char name[255];
2392 	      make_long_kbd_name(all_kbds[i+count].vendor,
2393 				 all_kbds[i+count].kbd_style,
2394 				 name);
2395 	      if (strlen (name) < L ||
2396 		  !!strncmp (full, name, L))
2397 		break;
2398 	      count++;
2399 	    }
2400 
2401 	  keyboard_sets [j].maps = (char **)
2402 	    malloc (sizeof (char *) * (count+1));
2403 	  keyboard_sets [j].full_maps = (char **)
2404 	    malloc (sizeof (char *) * (count+1));
2405 	  for (k = 0; k < count; k++)
2406 	    {
2407 	      char full[255];
2408 	      const char *map;
2409 	      char *map_name = 0;
2410 	      int ML;
2411 	      make_long_kbd_name(all_kbds [i+k].vendor,
2412 				 all_kbds [i+k].kbd_style,
2413 				 full);
2414 	      map = strchr(full, '(');
2415 	      if (!map) abort();
2416 	      map++;
2417 	      ML = strlen (map);
2418 	      map_name = (char *) malloc (ML);
2419 	      memcpy (map_name, map, ML);
2420 	      map_name [--ML] = 0;
2421 	      keyboard_sets [j].maps[k] = map_name;
2422 	      keyboard_sets [j].full_maps[k] = strdup(full);
2423 	      if (!longest_map || strlen (longest_map) < ML)
2424 		longest_map = keyboard_sets [j].maps[k];
2425 	    }
2426 	  keyboard_sets [j].maps[k] = 0;
2427 	  i += count;
2428 	  keyboard_sets [j].map_count = count;
2429 	}
2430       else
2431 	{
2432 	  keyboard_sets [j].maps = default_maps;
2433 	  keyboard_sets [j].full_maps = (char **) malloc (sizeof (char *) * 2);
2434 	  keyboard_sets [j].full_maps [0] = strdup(full);
2435 	  keyboard_sets [j].full_maps [1] = 0;
2436 	  keyboard_sets [j].map_count = 1;
2437 	  i++;
2438 	}
2439 
2440       keyboard_sets [j].type = (char *) malloc (strlen (last_style) + 1);
2441       memcpy (keyboard_sets [j].type, last_style, strlen (last_style) + 1);
2442 
2443       if (!longest_type ||
2444 	  strlen (longest_type) < strlen(keyboard_sets [j].type))
2445 	longest_type = keyboard_sets [j].type;
2446 
2447       j++;
2448     }
2449   keyboard_set_count = j;
2450 
2451   {
2452     int max = 0;
2453     keyboard_types = (char **) malloc (sizeof (char *) * (j + 1));
2454     for (i = 0; i < j; i++)
2455       {
2456 	keyboard_types [i] = keyboard_sets [i].type;
2457 	if (keyboard_sets [i].map_count > max)
2458 	  max = keyboard_sets [i].map_count;
2459       }
2460     keyboard_types[i] = 0;
2461   }
2462 }
2463 
2464 static void
2465 #ifdef __STDC__
kbd_abort_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)2466 kbd_abort_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2467 #else /* ! __STDC__ */
2468 kbd_abort_button_cb (widget, client_data, call_data)
2469      Widget widget;
2470      XtPointer client_data, call_data;
2471 #endif /* ! __STDC__ */
2472 {
2473   struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2474   Widget shell = box->shell;
2475   XtPopdown (shell);
2476 }
2477 
2478 static void
2479 #ifdef __STDC__
kbd_ok_button_cb(Widget button,XtPointer client_data,XtPointer call_data)2480 kbd_ok_button_cb (Widget button, XtPointer client_data, XtPointer call_data)
2481 #else /* ! __STDC__ */
2482 kbd_ok_button_cb (button, client_data, call_data)
2483      Widget button;
2484      XtPointer client_data, call_data;
2485 #endif /* ! __STDC__ */
2486 {
2487   struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2488   KeyboardWidget kbd = box->keyboard;
2489   const char *map = box->map;
2490   kbd_abort_button_cb (button, client_data, call_data);
2491   replace_keyboard (kbd, map);
2492 }
2493 
2494 static void
2495 #ifdef __STDC__
keymap_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)2496 keymap_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2497 #else /* ! __STDC__ */
2498 keymap_list_cb (widget, client_data, call_data)
2499      Widget widget;
2500      XtPointer client_data, call_data;
2501 #endif /* ! __STDC__ */
2502 {
2503   XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
2504   struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2505   struct keyboard_set *set = box->set;
2506   box->map = set->full_maps [lr->list_index];
2507 }
2508 
2509 static int current_vendor_offset = 0;
2510 
2511 static void
2512 #ifdef __STDC__
keyboard_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)2513 keyboard_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2514 #else /* ! __STDC__ */
2515 keyboard_list_cb (widget, client_data, call_data)
2516      Widget widget;
2517      XtPointer client_data, call_data;
2518 #endif /* ! __STDC__ */
2519 {
2520   XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
2521   struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2522   int kbd = lr->list_index + current_vendor_offset;
2523   int map = 0;
2524   int i = 0;
2525 
2526   while (strcmp (keyboard_sets [i].type, keyboard_types [kbd]))
2527     i++;
2528   box->set = &keyboard_sets [i];
2529   XawListChange (box->keymap_list, (char **) box->set->maps, 0, 0, True);
2530   for (i = 0; i < box->set->map_count; i++)
2531     {
2532       char buf[255];
2533       make_long_kbd_name(box->keyboard->keyboard.vendor,
2534 			 box->keyboard->keyboard.kbd_style,
2535 			 buf);
2536       if (!strcmp (box->set->full_maps[i], buf))
2537 	{
2538 	  map = i;
2539 	  break;
2540 	}
2541     }
2542   XawListHighlight (box->keymap_list, map);
2543   lr->list_index = map;
2544   keymap_list_cb (widget, client_data, call_data);
2545   move_scrollbar (box->keymap_list,
2546 		  (((float) map) / ((float) box->set->map_count)));
2547   {
2548     int w, h;
2549     Pixmap p = get_keyboard_icon (XtDisplay (widget),
2550 				  &all_kbds [box->set->kbd_index], &w, &h);
2551     XtVaSetValues (box->icon, XtNbitmap, p, XtNheight, h, 0);
2552   }
2553 }
2554 
2555 
2556 static void
2557 #ifdef __STDC__
vendor_list_cb(Widget widget,XtPointer client_data,XtPointer call_data)2558 vendor_list_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2559 #else /* ! __STDC__ */
2560 vendor_list_cb (widget, client_data, call_data)
2561      Widget widget;
2562      XtPointer client_data, call_data;
2563 #endif /* ! __STDC__ */
2564 {
2565   XawListReturnStruct *lr = (XawListReturnStruct *) call_data;
2566   struct select_kbd_box *box = (struct select_kbd_box *) client_data;
2567   int vendor = lr->list_index;
2568   const char *v = vendors[vendor];
2569   static char *list[255];
2570   int kbd;
2571   int i, j;
2572 
2573   for (i = 0; i < keyboard_set_count; i++)
2574     if (!strcmp(v, keyboard_sets[i].vendor))
2575       break;
2576 
2577   current_vendor_offset = i;
2578 
2579   j = 0;
2580   while (keyboard_sets[i].type &&
2581 	 !strcmp(v, keyboard_sets[i].vendor))
2582     list[j++] = keyboard_sets[i++].type;
2583   list [j] = 0;
2584 
2585   kbd = 0;
2586   if (box->set)
2587     {
2588       char *s1 = strdup (box->keyboard->keyboard.kbd_style);
2589       char *s2 = strchr (s1, '(');
2590       if (s2) *s2 = 0;
2591       for (i = 0; list[i]; i++)
2592 	if (!strcmp (s1, list[i]))
2593 	  {
2594 	    kbd = i;
2595 	    break;
2596 	  }
2597       free (s1);
2598     }
2599 
2600   XawListChange (box->keyboard_list, list, 0, 0, True);
2601   XawListHighlight (box->keyboard_list, kbd);
2602   lr->list_index = kbd;
2603 
2604   keyboard_list_cb (widget, client_data, call_data);
2605 }
2606 
2607 
2608 static struct select_kbd_box *
2609 #ifdef __STDC__
make_select_kbd_dbox(KeyboardWidget widget)2610 make_select_kbd_dbox (KeyboardWidget widget)
2611 #else /* ! __STDC__ */
2612 make_select_kbd_dbox (widget)
2613      KeyboardWidget widget;
2614 #endif /* ! __STDC__ */
2615 {
2616   struct select_kbd_box *box = (struct select_kbd_box *)
2617     malloc (sizeof (struct select_kbd_box));
2618   Arg av [20];
2619   int ac = 0;
2620   Widget toplevel, box1, box2;
2621   Widget button_box, vendor_box, keyboard_box, keymap_box;
2622   Widget prev;
2623   Widget vendor_list, kbd_list, map_list;
2624   Widget vendor_vp, kbd_vp, map_vp;
2625 
2626   make_kbd_lists ();
2627 
2628   toplevel = XtCreatePopupShell ("selectKbd", transientShellWidgetClass,
2629 				 XtParent ((Widget) widget), av, ac);
2630   box1 = XtCreateManagedWidget ("vertical", panedWidgetClass, toplevel, av,ac);
2631   box->label = make_label (box1, "label", 0, 0, 0);
2632   box->label2 = make_label (box1, "label2", "", 0, 0);
2633   ac = 0;
2634   XtSetArg (av[ac], XtNorientation, "horizontal"); ac++;
2635   box2 = XtCreateManagedWidget ("horizontal", panedWidgetClass, box1, av, ac);
2636 
2637   ac = 0;
2638   vendor_box = XtCreateManagedWidget ("vendorBox", formWidgetClass,
2639 					box2, av, ac);
2640   prev = make_label (vendor_box, "vendors", 0, 0, 0);
2641   ac = 0;
2642   XtSetArg (av[ac], XtNfromVert, prev); ac++;
2643   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2644   XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2645   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2646   XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2647   vendor_vp = XtCreateManagedWidget ("vendorsVp", viewportWidgetClass,
2648 				     vendor_box, av, ac);
2649   ac = 0;
2650   XtSetArg (av[ac], XtNlist, vendors); ac++;
2651   vendor_list = XtCreateManagedWidget ("vendorsList", listWidgetClass,
2652 				       vendor_vp, av, ac);
2653   XtAddCallback (vendor_list, XtNcallback, vendor_list_cb, (XtPointer) box);
2654 
2655   /* Gag!  These lists won't size themselves correctly. */
2656   XtVaSetValues (vendor_list, XtNwidth, vendor_list->core.width + 20, 0);
2657 
2658   ac = 0;
2659   keyboard_box = XtCreateManagedWidget ("keyboardBox", formWidgetClass,
2660 					box2, av, ac);
2661   prev = make_label (keyboard_box, "keyboards", 0, 0, 0);
2662   ac = 0;
2663   XtSetArg (av[ac], XtNfromVert, prev); ac++;
2664   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2665   XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2666   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2667   XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2668   kbd_vp = XtCreateManagedWidget ("keyboardsVp", viewportWidgetClass,
2669 				  keyboard_box, av, ac);
2670   ac = 0;
2671 
2672 
2673   {
2674     static char *dummy[2];
2675     dummy[0] = longest_type;
2676     dummy[1] = 0;
2677     ac = 0;
2678     XtSetArg (av[ac], XtNlist, dummy); ac++;
2679     kbd_list = XtCreateManagedWidget ("keyboardsList", listWidgetClass, kbd_vp,
2680 				      av, ac);
2681     XtAddCallback (kbd_list, XtNcallback, keyboard_list_cb, (XtPointer) box);
2682 
2683     /* Gag!  These lists won't size themselves correctly. */
2684     XtVaSetValues (kbd_list, XtNwidth, kbd_list->core.width + 20, 0);
2685   }
2686 
2687   ac = 0;
2688   keymap_box = XtCreateManagedWidget ("keymapBox", formWidgetClass,
2689 				      box2, av, ac);
2690   prev = make_label (keymap_box, "keymaps", 0, 0, 0);
2691   ac = 0;
2692   XtSetArg (av[ac], XtNfromVert, prev); ac++;
2693   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
2694   XtSetArg (av[ac], XtNright, XtChainRight); ac++;
2695   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
2696   XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
2697   map_vp = XtCreateManagedWidget ("keymapsVp", viewportWidgetClass,
2698 				  keymap_box, av, ac);
2699   {
2700     static char *dummy[2];
2701     dummy[0] = longest_map;
2702     dummy[1] = 0;
2703     ac = 0;
2704     XtSetArg (av[ac], XtNlist, dummy); ac++;
2705     map_list = XtCreateManagedWidget ("keymapsList", listWidgetClass, map_vp,
2706 				      av, ac);
2707     XtAddCallback (map_list, XtNcallback, keymap_list_cb, (XtPointer) box);
2708 
2709     /* Gag!  These lists won't size themselves correctly. */
2710     XtVaSetValues (map_list, XtNwidth, map_list->core.width + 20, 0);
2711   }
2712   ac = 0;
2713   XtSetArg (av[ac], XtNskipAdjust, True); ac++;
2714   button_box = XtCreateManagedWidget ("buttons", boxWidgetClass, box1, av, ac);
2715 
2716   prev = make_button (button_box, "abort", 0, prev, 0, kbd_abort_button_cb,
2717 		      box, 0);
2718   prev = make_button (button_box, "ok",    0, prev, 0, kbd_ok_button_cb,
2719 		      box, 0);
2720   prev = make_label (button_box, "spacer", "", 0, prev);
2721   box->icon = make_label (button_box, "kbd_icon", 0, prev, 0);
2722 
2723   box->keyboard = 0;
2724   box->shell = toplevel;
2725   box->vendor_list = vendor_list;
2726   box->keyboard_list = kbd_list;
2727   box->keymap_list = map_list;
2728   box->set = 0;
2729   box->map = 0;
2730   return box;
2731 }
2732 
2733 void
2734 #ifdef __STDC__
pop_up_kbd_dbox(Widget parent,XtPointer client_data,XtPointer call_data)2735 pop_up_kbd_dbox (Widget parent, XtPointer client_data, XtPointer call_data)
2736 #else /* ! __STDC__ */
2737 pop_up_kbd_dbox (parent, client_data, call_data)
2738      Widget parent;
2739      XtPointer client_data, call_data;
2740 #endif /* ! __STDC__ */
2741 {
2742   KeyboardWidget widget = *((KeyboardWidget *) client_data);
2743   struct select_kbd_box *select_kbd_box =
2744     widget->keyboard.key_menus->select_kbd_box;
2745 
2746   select_kbd_box->keyboard = widget;
2747   XtVaSetValues (select_kbd_box->label2, XtNlabel, choose_kbd_message, 0);
2748   choose_kbd_dubious_p = 0;
2749   choose_kbd_message [0] = 0;
2750 
2751   {
2752     Widget topmost = parent;
2753     int x, y, w, h;
2754     XtRealizeWidget (select_kbd_box->shell);
2755     /* #### It'd be nice to wait here until it was mapped... */
2756     w = select_kbd_box->shell->core.width;
2757     h = select_kbd_box->shell->core.height;
2758     while (topmost->core.parent)
2759       topmost = topmost->core.parent;
2760     if (topmost->core.width < w) x = topmost->core.x;
2761     else x = topmost->core.x + ((topmost->core.width - w) / 2);
2762     if (topmost->core.height < h) y = topmost->core.y;
2763     else y = topmost->core.y + ((topmost->core.height - h) / 2);
2764     XtMoveWidget (select_kbd_box->shell, x, y);
2765   }
2766 
2767   {
2768     XawListReturnStruct lr;
2769     int this_vendor = 0;
2770     int this_kbd = 0;
2771     int this_vendor_start = 0;
2772     int i, j;
2773     char buf[255];
2774     const char *last_vendor = 0;
2775 
2776     make_long_kbd_name(widget->keyboard.vendor,
2777 		       widget->keyboard.kbd_style,
2778 		       buf);
2779     for (i = 0; i <= keyboard_set_count; i++)
2780       {
2781 	if (last_vendor && !!strcmp(last_vendor, keyboard_sets[i].vendor))
2782 	  {
2783 	    this_vendor_start = i;
2784 	    this_vendor++;
2785 	    this_kbd = 0;
2786 	  }
2787 	last_vendor = keyboard_sets[i].vendor;
2788 
2789 	for (j = 0; j < keyboard_sets[i].map_count; j++)
2790 	  if (!strcmp (keyboard_sets[i].full_maps[j], buf))
2791 	    {
2792 	      this_kbd = i - this_vendor_start;
2793 	      goto out;
2794 	    }
2795       }
2796   out:
2797     lr.list_index = this_vendor;
2798     XawListHighlight (select_kbd_box->vendor_list, this_vendor);
2799     move_scrollbar (select_kbd_box->vendor_list,
2800 		    (((float) this_vendor) / ((float) vendor_count)));
2801     vendor_list_cb ((Widget) widget,
2802 		    (void *) select_kbd_box,
2803 		    (void *) &lr);
2804 
2805     lr.list_index = this_kbd;
2806     XawListHighlight (select_kbd_box->keyboard_list, this_kbd);
2807 /*    move_scrollbar (select_kbd_box->keyboard_list,
2808 		     (((float) this_kbd) / ((float) keyboard_set_count)));
2809  */
2810     keyboard_list_cb ((Widget) widget,
2811 		      (void *) select_kbd_box,
2812 		      (void *) &lr);
2813   }
2814   XtPopup (select_kbd_box->shell, XtGrabNonexclusive);
2815 }
2816 
2817 
2818 
2819 static void
2820 #ifdef __STDC__
yorn_button_cb(Widget widget,XtPointer client_data,XtPointer call_data)2821 yorn_button_cb (Widget widget, XtPointer client_data, XtPointer call_data)
2822 #else /* ! __STDC__ */
2823 yorn_button_cb (widget, client_data, call_data)
2824      Widget widget;
2825      XtPointer client_data, call_data;
2826 #endif /* ! __STDC__ */
2827 {
2828   *((int *) client_data) = 1;
2829 }
2830 
2831 
2832 static int
2833 #ifdef __STDC__
y_or_n_p_with_args(KeyboardWidget widget,char * name,char * name0,char * name1,char * name2,char * arg0,char * arg1,char * arg2,char * arg3,char * arg4,char * arg5)2834 y_or_n_p_with_args (KeyboardWidget widget,
2835 		    char *name,
2836 		    char *name0, char *name1, char *name2,
2837 		    char *arg0, char *arg1, char *arg2, char *arg3,
2838 		    char *arg4, char *arg5)
2839 #else /* ! __STDC__ */
2840 y_or_n_p_with_args (widget, name,
2841 		    name0, name1, name2,
2842 		    arg0, arg1, arg2, arg3, arg4, arg5)
2843      KeyboardWidget widget;
2844      char *name;
2845      char *name0, *name1, *name2;
2846      char *arg0, *arg1, *arg2, *arg3, *arg4, *arg5;
2847 #endif /* ! __STDC__ */
2848 {
2849   XtAppContext app = XtWidgetToApplicationContext ((Widget) widget);
2850   Widget topmost = (Widget) widget;
2851   Widget label;
2852   XEvent event;
2853   int x, y, w, h;
2854   Arg av [10];
2855   int ac = 0;
2856   Widget shell, box1, box2, prev;
2857   int ans [3];
2858 
2859   shell = XtCreatePopupShell (name, transientShellWidgetClass,
2860 			      (Widget) widget, av, ac);
2861   box1 = XtCreateManagedWidget ("paned", panedWidgetClass, shell, av, ac);
2862   label = make_label (box1, "label", 0, 0, 0);
2863   if (arg0)  /* format into the label if desired. */
2864     {
2865       char *old_string;
2866       char new_string [4000];
2867       ac = 0;
2868       XtSetArg (av [ac], XtNlabel, &old_string); ac++;
2869       XtGetValues (label, av, ac);
2870       if (!strcmp (old_string, XtName (label)))
2871 	strcpy (new_string, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
2872       else
2873 	sprintf (new_string, old_string, arg0, arg1, arg2, arg3, arg4, arg5);
2874       ac = 0;
2875       XtSetArg (av [ac], XtNlabel, new_string); ac++;
2876       XtSetValues (label, av, ac);
2877     }
2878   ac = 0;
2879   XtSetArg (av[ac], XtNorientation, "horizontal"); ac++;
2880   box2 = XtCreateManagedWidget ("buttons", boxWidgetClass, box1, av, ac);
2881   prev = 0;
2882   if (name0) prev = make_button (box2,name0,0,prev,0,yorn_button_cb,&ans[0],0);
2883   if (name1) prev = make_button (box2,name1,0,prev,0,yorn_button_cb,&ans[1],0);
2884   if (name2) prev = make_button (box2,name2,0,prev,0,yorn_button_cb,&ans[2],0);
2885   XtRealizeWidget (shell);
2886   w = shell->core.width;
2887   h = shell->core.height;
2888   while (topmost->core.parent)
2889     topmost = topmost->core.parent;
2890   if (topmost->core.width < w) x = topmost->core.x;
2891   else x = topmost->core.x + ((topmost->core.width - w) / 2);
2892   if (topmost->core.height < h) y = topmost->core.y;
2893   else y = topmost->core.y + ((topmost->core.height - h) / 2);
2894   XtMoveWidget (shell, x, y);
2895 
2896   XtPopup (shell, XtGrabNonexclusive);
2897   memset (ans, 0, sizeof (ans));
2898   while (! (ans[0] || ans[1] || ans[2]))
2899     {
2900       XtAppNextEvent (app, &event);
2901       if (event.xany.type == KeymapNotify)
2902 	keyboard_handle_keymap_notify ((Widget) widget, 0, &event, 0);
2903       else if (event.xany.type == MappingNotify)
2904 	keyboard_handle_mapping_notify ((Widget) widget, 0, &event, 0);
2905       XtDispatchEvent (&event);
2906     }
2907   XtPopdown (shell);
2908   XtDestroyWidget (shell);
2909   if (ans[0]) return 0;
2910   if (ans[1]) return 1;
2911   if (ans[2]) return 2;
2912   exit (-69);
2913 }
2914 
2915 static int
2916 #ifdef __STDC__
y_or_n_p(KeyboardWidget widget,char * name,char * name0,char * name1,char * name2)2917 y_or_n_p (KeyboardWidget widget,
2918 	  char *name, char *name0, char *name1, char *name2)
2919 #else /* ! __STDC__ */
2920 y_or_n_p (widget, name, name0, name1, name2)
2921      KeyboardWidget widget;
2922      char *name, *name0, *name1, *name2;
2923 #endif /* ! __STDC__ */
2924 {
2925   return y_or_n_p_with_args (widget, name, name0, name1, name2, 0,0,0,0,0,0);
2926 }
2927 
2928 
2929 KeyWidget
2930 #ifdef __STDC__
prompt_for_key(KeyboardWidget keyboard,char * msg)2931 prompt_for_key (KeyboardWidget keyboard, char *msg)
2932 #else /* ! __STDC__ */
2933 prompt_for_key (keyboard, msg)
2934      KeyboardWidget keyboard;
2935      char *msg;
2936 #endif /* ! __STDC__ */
2937 {
2938   XtAppContext app = XtWidgetToApplicationContext ((Widget) keyboard);
2939   KeyWidget key;
2940   XEvent event;
2941   message (keyboard, msg);
2942 
2943   if (XGrabPointer (XtDisplay (keyboard), XtWindow (keyboard), True,
2944 		    ButtonPressMask | ButtonReleaseMask,
2945 		    GrabModeAsync, GrabModeAsync, 0,
2946 		    keyboard->keyboard.select_cursor,
2947 		    CurrentTime))
2948     {
2949       XBell (XtDisplay (keyboard), 0);
2950       message (keyboard, "Grab failed.");
2951       return 0;
2952     }
2953 
2954   while (1)
2955     {
2956       XtAppNextEvent (app, &event);
2957 
2958       if (event.xany.type == ButtonPress)
2959 	{
2960 	  XUngrabPointer (XtDisplay (keyboard), CurrentTime);
2961 	  if ((key = keyboard->keyboard.key_under_mouse))
2962 	    return key;
2963 	  XBell (XtDisplay (keyboard), 0);
2964 	  message (keyboard, "You must click on a key.");
2965 	  return 0;
2966 	}
2967       else if (event.xany.type == ButtonRelease ||
2968 	       event.xany.type == KeyPress ||
2969 	       event.xany.type == KeyRelease)
2970 	{
2971 	  XUngrabPointer (XtDisplay (keyboard), CurrentTime);
2972 	  XBell (XtDisplay (keyboard), 0);
2973 	  XPutBackEvent (XtDisplay (keyboard), &event);
2974 	  message (keyboard, "Aborted.");
2975 	  return 0;
2976 	}
2977       else
2978 	{
2979 	  if (event.xany.type == KeymapNotify)
2980 	    keyboard_handle_keymap_notify ((Widget) keyboard, 0, &event, 0);
2981 	  else if (event.xany.type == MappingNotify)
2982 	    keyboard_handle_mapping_notify ((Widget) keyboard, 0, &event, 0);
2983 	  XtDispatchEvent (&event);
2984 	}
2985     }
2986 }
2987 
2988 
2989 /* What a mess the X keyboard model is... */
2990 
2991 #include <X11/keysym.h>
2992 
2993 static char *
2994 #ifdef __STDC__
index_to_name(int index)2995 index_to_name (int index)
2996 #else /* ! __STDC__ */
2997 index_to_name (index)
2998      int index;
2999 #endif /* ! __STDC__ */
3000 {
3001   return (index == ShiftMapIndex ? "Shift" :
3002 	  index == LockMapIndex ? "Lock" :
3003 	  index == ControlMapIndex ? "Control" :
3004 	  index == Mod1MapIndex ? "1" :
3005 	  index == Mod2MapIndex ? "2" :
3006 	  index == Mod3MapIndex ? "3" :
3007 	  index == Mod4MapIndex ? "4" :
3008 	  index == Mod5MapIndex ? "5" :
3009 	  "???");
3010 }
3011 
3012 static char *
3013 #ifdef __STDC__
keysym_to_name(KeySym keysym)3014 keysym_to_name (KeySym keysym)
3015 #else /* ! __STDC__ */
3016 keysym_to_name (keysym)
3017      KeySym keysym;
3018 #endif /* ! __STDC__ */
3019 {
3020   char *n = XKeysymToString (keysym);
3021   if (! n) /* ought not happen, but does if XKeysymDB isn't installed right */
3022     {
3023       n = (char *) malloc (20); /* leaks! */
3024       sprintf (n, "Unknown-KeySym-0x%X", (int) keysym);
3025     }
3026   return n;
3027 }
3028 
3029 static int
3030 #ifdef __STDC__
stop_the_insanity(KeyboardWidget widget,int keycode,KeySym * keysyms,int count,unsigned long modbits,XModifierKeymap * modmap)3031 stop_the_insanity (KeyboardWidget widget,
3032 		   int keycode,
3033 		   KeySym *keysyms,
3034 		   int count,
3035 		   unsigned long modbits,
3036 		   XModifierKeymap *modmap)
3037 #else /* ! __STDC__ */
3038 stop_the_insanity (widget, keycode, keysyms, count, modbits, modmap)
3039      KeyboardWidget widget;
3040      int keycode;
3041      KeySym *keysyms;
3042      int count;
3043      unsigned long modbits;
3044      XModifierKeymap *modmap;
3045 #endif /* ! __STDC__ */
3046 {
3047   int i;
3048   KeySym type = 0;		/* The canonical modifier keysym on this key */
3049   KeySym basic_keysym = 0;	/* The non-canonical version */
3050   KeySym companion = 0;		/* The "other" version of this key */
3051 
3052   /* Check that the keysyms that are attached to this key are compatible:
3053      It is incorrect to put Control_[LR] and Meta_[LR] on the same key.
3054    */
3055   {
3056     KeySym conflict = 0;
3057     KeySym nonmod = 0;
3058     for (i = 0; i < count && !conflict; i++)
3059       switch ((int) keysyms [i])
3060 	{
3061 #define check(k)				\
3062 	case k:					\
3063 	  if (type && type != k)		\
3064 	    conflict = keysyms [i];		\
3065 	  else					\
3066 	    type = k,				\
3067 	    basic_keysym = keysyms[i];		\
3068 	  break
3069 	case XK_Meta_R:    check (XK_Meta_L);
3070 	case XK_Super_R:   check (XK_Super_L);
3071 	case XK_Hyper_R:   check (XK_Hyper_L);
3072 	case XK_Alt_R:     check (XK_Alt_L);
3073 	case XK_Control_R: check (XK_Control_L);
3074 	case XK_Shift_R:   check (XK_Shift_L);
3075 	check (XK_Shift_Lock);
3076 	check (XK_Caps_Lock);
3077 	check (XK_Mode_switch);
3078 #undef check
3079 	default:
3080 	  nonmod = keysyms [i];
3081 	  break;
3082 	}
3083 
3084     switch ((int) basic_keysym)
3085       {
3086       case XK_Meta_L:    companion = XK_Meta_R;    break;
3087       case XK_Super_L:   companion = XK_Super_R;   break;
3088       case XK_Hyper_L:   companion = XK_Hyper_R;   break;
3089       case XK_Alt_L:     companion = XK_Alt_R;     break;
3090       case XK_Control_L: companion = XK_Control_R; break;
3091       case XK_Shift_L:   companion = XK_Shift_R;   break;
3092       case XK_Meta_R:    companion = XK_Meta_L;    break;
3093       case XK_Super_R:   companion = XK_Super_L;   break;
3094       case XK_Hyper_R:   companion = XK_Hyper_L;   break;
3095       case XK_Alt_R:     companion = XK_Alt_L;     break;
3096       case XK_Control_R: companion = XK_Control_L; break;
3097       case XK_Shift_R:   companion = XK_Shift_L;   break;
3098       }
3099 
3100     if (nonmod && type)	/* all modifier syms and non-mod syms conflict. */
3101       {
3102 	conflict = type;
3103 	type = nonmod;
3104       }
3105     if (conflict)
3106       return (y_or_n_p_with_args (widget, "keysymConflictWarning",
3107 				  "ok", "cancel", 0,
3108 				  keysym_to_name (type),
3109 				  keysym_to_name (conflict),
3110 				  0, 0, 0, 0));
3111   }
3112 
3113 
3114   /* Check that the modifier bits are compatible with the keysyms:
3115      It is incorrect to put ModControl on a key with any keysym other
3116      than Control_L or Control_R.
3117    */
3118   {
3119     int losing = 0;
3120     int bad_index = 0;
3121     if (modbits & ControlMask && type != XK_Control_L)
3122       losing = 1, bad_index = ControlMapIndex;
3123     else if (modbits & ShiftMask && type != XK_Shift_L)
3124       losing = 1, bad_index = ShiftMapIndex;
3125     else if (modbits & LockMask && type != XK_Caps_Lock &&
3126 				   type != XK_Shift_Lock)
3127       losing = 1, bad_index = LockMapIndex;
3128 
3129     if (losing)
3130       return (y_or_n_p_with_args (widget, "badModifiersWarning",
3131 				  "ok", "cancel", 0,
3132 				  index_to_name (bad_index),
3133 				  (bad_index == ShiftMapIndex ? "Shift_L" :
3134 				   bad_index == LockMapIndex ? "Caps_Lock" :
3135 				   bad_index == ControlMapIndex ? "Control_L" :
3136 				   "<<INTERNAL ERROR>>"),
3137 				  (bad_index == ShiftMapIndex ? "Shift_R" :
3138 				   bad_index == LockMapIndex ? "Shift_Lock" :
3139 				   bad_index == ControlMapIndex ? "Control_R" :
3140 				   "<<INTERNAL ERROR>>"),
3141 				  index_to_name (bad_index),
3142 				  0, 0));
3143   }
3144 
3145   /* Do the opposite check - the previous code checked for the case of
3146      attaching ModControl to Meta_L, but this checks for attaching Mod1
3147      to Control_L. */
3148   if ((type == XK_Shift_L || type == XK_Control_L ||
3149        type == XK_Shift_Lock || type == XK_Caps_Lock) &&
3150       (modbits & (~ (ShiftMask | LockMask | ControlMask))))
3151     return (y_or_n_p_with_args (widget, "badModifiersWarning2",
3152 				"ok", "cancel", 0,
3153 				keysym_to_name (basic_keysym),
3154 				(type == XK_Shift_L ? "Shift" :
3155 				 type == XK_Control_L ? "Control" :
3156 				 type == XK_Shift_Lock ? "Lock" :
3157 				 type == XK_Caps_Lock ? "Lock" :
3158 				 "<<INTERNAL ERROR>>"),
3159 				(type == XK_Shift_L ? "Shift" :
3160 				 type == XK_Control_L ? "Control" :
3161 				 type == XK_Shift_Lock ? "Shift_Lock" :
3162 				 type == XK_Caps_Lock ? "Caps_Lock" :
3163 				 "<<INTERNAL ERROR>>"),
3164 				0, 0, 0));
3165 
3166   /* Check that the key is generating at most one modifier bit.
3167      The behavior of more than one modifier bit is undefined.
3168      If this is a modifier keysym, warn if it has no modifier bits
3169      at all (which has defined behavior, and may be what is desired,
3170      but which novices are likely to do by accident.)
3171    */
3172   {
3173     int bitcount = 0;
3174     int i;
3175     for (i = 0; i < 8; i++)
3176       if (modbits & (1<<i)) bitcount++;
3177     if (bitcount > 1)
3178       return (y_or_n_p (widget, "multipleModifiersWarning",
3179 			"ok", "cancel", 0));
3180     else if (bitcount == 0 && type != 0)
3181       return (y_or_n_p_with_args (widget, "noModifiersWarning",
3182 				  "ok", "cancel", 0,
3183 				  keysym_to_name (type), 0, 0, 0, 0, 0));
3184   }
3185 
3186 
3187   /* Check that some other (incompatible) key is not generating the same
3188      modifiers as this key. */
3189   {
3190     Display *dpy = XtDisplay ((Widget) widget);
3191 
3192     unsigned long conflict_code = 0;
3193     KeySym conflict_sym = 0;
3194     int conflict_bit = 0;
3195     int this_bit = 0;
3196 
3197     int modifier_index, modifier_key;
3198     int mkpm = modmap->max_keypermod;
3199 
3200     for (modifier_index = 0; modifier_index < 8; modifier_index++)
3201       /* Ignore modifier bits which this key does not generate. */
3202       if ((1 << modifier_index) & modbits)
3203 	for (modifier_key = 0; modifier_key < mkpm; modifier_key++)
3204 	  {
3205 	    int column;
3206 	    KeySym last_sym = 0;
3207 	    for (column = 0; column < 4; column += 2)
3208 	      {
3209 		KeyCode code2 = modmap->modifiermap [modifier_index * mkpm
3210 						     + modifier_key];
3211 		KeySym sym = (code2
3212 			      ? XKeycodeToKeysym (dpy, code2, column)
3213 			      : 0);
3214 		KeySym this = 0;
3215 		if (!sym) continue;
3216 		if (sym == last_sym) continue;
3217 		last_sym = sym;
3218 		switch ((int) sym)
3219 		  {
3220 		  case XK_Meta_R:    this = XK_Meta_L; break;
3221 		  case XK_Super_R:   this = XK_Super_R; break;
3222 		  case XK_Hyper_R:   this = XK_Hyper_L; break;
3223 		  case XK_Alt_R:     this = XK_Alt_L; break;
3224 		  case XK_Control_R: this = XK_Control_L; break;
3225 		  case XK_Shift_R:   this = XK_Shift_L; break;
3226 		  default:           this = sym; break;
3227 		  }
3228 
3229 		if (this != type &&		/* conflicting keysyms */
3230 		    /* but ignore conflicts with the previous version of
3231 		       this very key! */
3232 		    code2 != keycode)
3233 		  {
3234 		    conflict_code = code2;
3235 		    conflict_sym = sym;
3236 		    conflict_bit = modifier_index;
3237 		    goto DONE;
3238 		  }
3239 	      }
3240 	  }
3241   DONE:
3242     if (conflict_code)
3243       {
3244 	KeyWidget kw = keycode_to_key (widget, conflict_code);
3245 	return (y_or_n_p_with_args (widget, "modifiersConflictWarning",
3246 				    "ok", "cancel", 0,
3247 				    keysym_to_name (basic_keysym),
3248 				    index_to_name (conflict_bit),
3249 				    (char *) conflict_code,
3250 				    (kw ? kw->key.key_name : "???"),
3251 				    keysym_to_name (conflict_sym),
3252 				    0));
3253       }
3254 
3255 
3256     /* Check that the semantically equivalent keys do not generate
3257        different modifier bits than this one. */
3258 
3259     conflict_sym = 0;
3260     conflict_bit = 0;
3261     conflict_code = 0;
3262 
3263     for (modifier_index = 0; modifier_index < 8; modifier_index++)
3264       /* Ignore modifier bits which this key generates. */
3265       if ((1 << modifier_index) & modbits)
3266 	this_bit = modifier_index;
3267       else if (conflict_code)
3268 	;
3269       else
3270 	for (modifier_key = 0; modifier_key < mkpm; modifier_key++)
3271 	  {
3272 	    int column;
3273 	    for (column = 0; column < 4; column += 2)
3274 	      {
3275 		KeyCode code2 = modmap->modifiermap [modifier_index * mkpm
3276 						     + modifier_key];
3277 		KeySym sym = (code2
3278 			      ? XKeycodeToKeysym (dpy, code2, column)
3279 			      : 0);
3280 		if (sym &&
3281 		    !conflict_code &&
3282 		    (sym == basic_keysym || sym == companion) &&
3283 		    code2 != keycode)
3284 		  {
3285 		    conflict_code = code2;
3286 		    conflict_sym = sym;
3287 		    conflict_bit = modifier_index;
3288 		    /* keep going to find this_bit */
3289 		    break;
3290 		  }
3291 	      }
3292 	  }
3293 
3294     if (conflict_code)
3295       {
3296 	KeyWidget kw = keycode_to_key (widget, conflict_code);
3297 	return (y_or_n_p_with_args (widget, "modifiersConflictWarning2",
3298 				    "ok", "cancel", 0,
3299 				    keysym_to_name (basic_keysym),
3300 				    index_to_name (this_bit),
3301 				    (char *) conflict_code,
3302 				    (kw ? kw->key.key_name : "???"),
3303 				    keysym_to_name (conflict_sym),
3304 				    index_to_name (conflict_bit)
3305 				    ));
3306       }
3307   }
3308 
3309   /* Should we also issue a message along the lines of
3310 
3311        This key is not normally a `chording' key (that is, a key that is
3312        held down to modify some other keypress.)  It is unlikely that
3313        attaching a modifier to it will do anything sensible.  If you want
3314        this to be a {Control,Shift,Lock,Meta} key, change its keysym to
3315        ***_L or ***_R.
3316 
3317      That wouldn't be appropriate for the default layout of the OpenWound
3318      keyboard, which attaches modifiers to random function keys (I imagine
3319      this has something to do with drag-and-drop, but I don't know how it
3320      works.)
3321 
3322      Actually maybe a different message would be appropriate for Multi_key,
3323      since people sometimes misinterpret the description of that key as being
3324      a modifier key, when in fact it's a prefix key and shouldn't have any
3325      modifier bits on it.
3326 
3327    */
3328 
3329   return 0;
3330 }
3331