1 /* xkeycaps, Copyright (c) 1991, 1992, 1993, 1995, 1996, 1997, 1998
2  * 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 #include "version.h"
14 
15 #include <stdio.h>
16 #include <ctype.h>
17 #include <X11/X.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xproto.h>
20 #include <X11/Intrinsic.h>
21 #include <X11/Shell.h>
22 #include <X11/Xaw/Simple.h>
23 #include <X11/Xaw/Paned.h>
24 #include <X11/Xaw/Form.h>
25 #include <X11/Xaw/Box.h>
26 #include <X11/Xmu/Error.h>
27 
28 #include "KbdWidgetP.h"
29 #include "KeyWidgetP.h"
30 
31 #include "xkeycaps.h"
32 
33 char *progname;
34 char *short_version;
35 
36 #ifdef __STDC__
37 # define P(x)x
38 #else /* !__STDC__ */
39 # define P(x)()
40 #endif
41 
42 
43 static char *xkeycapsDefaults[] = {
44 # include "XKeyCaps_ad.h"
45  0
46 };
47 
48 
49 static XrmOptionDescRec options [] = {
50   { "-foreground",	"*Foreground",			XrmoptionSepArg, 0 },
51   { "-background",	"*Background",			XrmoptionSepArg, 0 },
52   { "-fg",		"*Foreground",			XrmoptionSepArg, 0 },
53   { "-bg",		"*Background",			XrmoptionSepArg, 0 },
54   { "-gutterwidth",	"*Keyboard.Key.gutterWidth",	XrmoptionSepArg, 0 },
55   { "-gw",		"*Keyboard.Key.gutterWidth",	XrmoptionSepArg, 0 },
56   { "-font",		"*Keyboard.Key.keycapFont",	XrmoptionSepArg, 0 },
57   { "-fn",		"*Keyboard.Key.keycapFont",	XrmoptionSepArg, 0 },
58 #ifdef HAVE_XTRAP
59   { "-xtrap",		"*useXTrap",			XrmoptionNoArg, "on" },
60   { "-use-xtrap",	"*useXTrap",			XrmoptionNoArg, "on" },
61   { "-use_xtrap",	"*useXTrap",			XrmoptionNoArg, "on" },
62   { "-no-xtrap",	"*useXTrap",			XrmoptionNoArg,"off" },
63   { "-no_xtrap",	"*useXTrap",			XrmoptionNoArg,"off" },
64 #endif
65   { "-keyboard",	"*Keyboard.keyboard",		XrmoptionSepArg, 0 },
66   { "-kbd",		"*Keyboard.keyboard",		XrmoptionSepArg, 0 }
67 };
68 
69 
70 
71 static KeyboardWidget make_keyboard P((Widget box, Widget box2,
72 				       struct info_labels *info,
73 				       const char *name));
74 static void maybe_relabel_window P((KeyboardWidget keyboard));
75 static KeyboardWidget xkeycaps_main_loop P((KeyboardWidget keyboard,
76 					    XtAppContext app));
77 
78 
79 Window XSendEvent_BadWindow = 0;
80 
81 static int
82 #ifdef __STDC__
xkeycaps_error_handler(Display * dpy,XErrorEvent * error)83 xkeycaps_error_handler (Display *dpy, XErrorEvent *error)
84 #else /* ! __STDC__ */
85 xkeycaps_error_handler (dpy, error)
86      Display *dpy;
87      XErrorEvent *error;
88 #endif /* ! __STDC__ */
89 {
90   switch (error->request_code)
91     {
92     case X_GetKeyboardMapping:
93       return 0;
94     case X_SendEvent:
95       if (error->error_code == BadWindow && !XSendEvent_BadWindow)
96 	XSendEvent_BadWindow = error->resourceid;
97       else
98 	XmuPrintDefaultErrorMessage (dpy, error, stderr);
99       return 0;
100     default:
101       XmuPrintDefaultErrorMessage (dpy, error, stderr);
102       exit (-1);
103     }
104 }
105 
106 
107 static KeyboardWidget
108 #ifdef __STDC__
make_keyboard(Widget box,Widget box2,struct info_labels * info,const char * name)109 make_keyboard (Widget box, Widget box2, struct info_labels *info,
110 	       const char *name)
111 #else /* ! __STDC__ */
112 make_keyboard (box, box2, info, name)
113      Widget box, box2;
114      struct info_labels *info;
115      const char *name;
116 #endif /* ! __STDC__ */
117 {
118   Arg av[20];
119   int ac = 0;
120   KeyboardWidget keyboard;
121   XtSetArg (av[ac], XtNfromVert, box2); ac++;
122   XtSetArg (av[ac], XtNleft, XtChainLeft); ac++;
123   XtSetArg (av[ac], XtNright, XtChainRight); ac++;
124   XtSetArg (av[ac], XtNtop, XtChainTop); ac++;
125   XtSetArg (av[ac], XtNbottom, XtChainBottom); ac++;
126   if (name) XtSetArg (av[ac], "keyboard", name), ac++;
127   keyboard = (KeyboardWidget)
128     XtCreateManagedWidget ("keyboard", keyboardWidgetClass, box, av, ac);
129   keyboard->keyboard.label_widgets = info;
130   keyboard->keyboard.key_menus = make_key_menus ((KeyboardWidget *) &keyboard);
131   return keyboard;
132 }
133 
134 
135 static void
136 #ifdef __STDC__
maybe_relabel_window(KeyboardWidget keyboard)137 maybe_relabel_window (KeyboardWidget keyboard)
138 #else /* ! __STDC__ */
139 maybe_relabel_window (keyboard)
140      KeyboardWidget keyboard;
141 #endif /* ! __STDC__ */
142 {
143   /* If the user hasn't specified the -title option, set the window title
144      to be something more informative.
145    */
146   Widget toplevel = (Widget) keyboard;
147   char buf1 [100], buf2 [100];
148   XrmValue value;
149   char *type;
150   XrmDatabase db = XtDatabase (XtDisplay (keyboard));
151   char *name, *class;
152   while (XtParent (toplevel)) toplevel = XtParent (toplevel);
153   XtGetApplicationNameAndClass (XtDisplay (keyboard), &name, &class);
154   sprintf (buf1, "%s.title", name);
155   sprintf (buf2, "%s.Title", class);
156   if (XrmGetResource (db, buf1, buf2, &type, &value)) return;
157   sprintf (buf1, "%s; %s%s%s keyboard", class,
158 	   keyboard->keyboard.vendor,
159 	   (keyboard->keyboard.kbd_style ? " " : ""),
160 	   keyboard->keyboard.kbd_style);
161   XStoreName (XtDisplay (toplevel), XtWindow (toplevel), buf1);
162 }
163 
164 
165 /* Kludge to tell the main loop to reset some variables... */
166 KeyboardWidget new_kbd_selected = 0;
167 
168 void
169 #ifdef __STDC__
replace_keyboard(KeyboardWidget keyboard,const char * name)170 replace_keyboard (KeyboardWidget keyboard, const char *name)
171 #else /* ! __STDC__ */
172 replace_keyboard (keyboard, name)
173      KeyboardWidget keyboard;
174      const char *name;
175 #endif /* ! __STDC__ */
176 {
177   /* Doing this seems to leak about 8k each time, but I really don't care. */
178   Widget box, box2;
179   KeyboardWidget new_kbd;
180   Widget toplevel;
181   Arg av[20];
182   int ac = 0;
183   toplevel = box = XtParent (keyboard);
184   while (XtParent (toplevel)) toplevel = XtParent (toplevel);
185   box2 = 0;
186   XtSetArg (av[ac], XtNfromVert, &box2); ac++;
187   XtGetValues ((Widget) keyboard, av, ac);
188   /*  if (! box2) abort ();*  #### wtf? */
189   new_kbd = make_keyboard (box, box2, keyboard->keyboard.label_widgets, name);
190   XtUnmanageChild ((Widget) keyboard);
191   XtDestroyWidget ((Widget) keyboard);
192   new_kbd_selected = new_kbd; /* kludge... */
193   XtSetKeyboardFocus (toplevel, (Widget) new_kbd);
194   maybe_relabel_window (new_kbd);
195 }
196 
197 
198 void
199 #ifdef __STDC__
xkeycaps_DispatchEvent_hook(KeyboardWidget keyboard,XEvent * event)200 xkeycaps_DispatchEvent_hook (KeyboardWidget keyboard, XEvent *event)
201 #else /* ! __STDC__ */
202 xkeycaps_DispatchEvent_hook (keyboard, event)
203      KeyboardWidget keyboard;
204      XEvent *event;
205 #endif /* ! __STDC__ */
206 {
207   /* MappingNotify and KeymapNotify events don't have an associated
208      window, so there's no way to register an event-handler function
209      for one of these with Xt.  Lose, lose.
210    */
211   if (event->xany.type == KeymapNotify)
212     keyboard_handle_keymap_notify ((Widget) keyboard, 0, event, 0);
213   else if (event->xany.type == MappingNotify)
214     keyboard_handle_mapping_notify ((Widget) keyboard, 0, event, 0);
215 }
216 
217 
218 static KeyboardWidget
219 #ifdef __STDC__
xkeycaps_main_loop(KeyboardWidget keyboard,XtAppContext app)220 xkeycaps_main_loop (KeyboardWidget keyboard, XtAppContext app)
221 #else /* ! __STDC__ */
222 xkeycaps_main_loop (keyboard, app)
223      KeyboardWidget keyboard;
224      XtAppContext app;
225 #endif /* ! __STDC__ */
226 {
227   XEvent event;
228   while (1)
229     {
230       XtAppNextEvent (app, &event);
231       xkeycaps_DispatchEvent_hook (keyboard, &event);
232       XtDispatchEvent (&event);
233 
234       /* Kludge to prevent us from using a freed keyboard...
235 	 I think we had actually been allocating the second one out
236 	 of the *same space* as the first one and not losing?? */
237       if (new_kbd_selected)
238 	return new_kbd_selected;
239     }
240 }
241 
242 int
243 #ifdef __STDC__
main(int argc,char ** argv)244 main (int argc, char **argv)
245 #else /* ! __STDC__ */
246 main (argc, argv)
247      int argc;
248      char **argv;
249 #endif /* ! __STDC__ */
250 {
251   char *class = "XKeyCaps";
252   XtAppContext app;
253   Widget toplevel, box, box2, buttons;
254   struct info_labels *info;
255   KeyboardWidget keyboard = 0;
256   Arg av [20];
257   int ac = 0;
258   char version_buf [255];
259 
260   {
261     int index;
262     int i2 = strlen (version) - 3;
263     char *v2 = (char *) malloc (i2);
264     memcpy (v2, version+4, i2);
265     version = v2;
266     for (index = 0;; index++)
267       if (!strncmp ("Copyright (c)", version+index, 13)) break;
268     for (v2 = version+index+13; *v2; v2++)
269       if (*v2 == '(') *v2 = '<';
270       else if (*v2 == ')') *v2 = '>';
271     memcpy (version_buf, version, i2 = index);
272     version_buf [index] = '\251';
273     strcpy (version_buf + index + 1, version + index + 13);
274     for (;; index++)
275       if (isdigit(version[index]) && isdigit(version[index+1]) &&
276 	  isdigit(version[index+2]) && isdigit(version[index+3]) &&
277 	  version[index+4] != ',')
278 	break;
279     short_version = (char *) malloc(i2 + 14 + strlen (version + index) + 1);
280     memcpy (short_version, version, i2 + 14);
281     strcpy (short_version +         i2 + 14, version + index);
282   }
283 
284   toplevel = XtAppInitialize (&app, class, options, XtNumber (options),
285 			      &argc, argv, xkeycapsDefaults, NULL, 0);
286 
287   XtGetApplicationNameAndClass (XtDisplay (toplevel), &progname, &class);
288 
289   if (argc > 1)
290     {
291       int ok = (!strcmp (argv[1], "-help") ||
292 		!strcmp (argv[1], "--help") ||
293 		!strcmp (argv[1], "-version") ||
294 		!strcmp (argv[1], "--version") ||
295 		!strcmp (argv[1], "-v") ||
296 		!strcmp (argv[1], "-h"));
297       FILE *out = (ok ? stdout : stderr);
298       if (!ok)
299 	fprintf (out, "%s: unknown option %s\n", progname, argv [1]);
300 
301       fprintf (out, "\n%s\n", short_version);
302       fprintf (out, "\n\
303 	Use the -keyboard (or -kbd) option to specify a keyboard,\n\
304 	or use the `Select Keyboard' dialog box.  Use the -help\n\
305 	option to list recognised arguments to -kbd.  See the man\n\
306 	page for more details.\n\n\
307 	For updates, check http://www.jwz.org/xkeycaps/\n\n");
308 
309       if (!ok)
310 	{
311 	  exit(-1);
312 	}
313       else
314 	{
315 	  fprintf(out, "Recognised keyboard names:\n\n");
316 	  print_kbd_choices();
317 	  exit(0);
318 	}
319     }
320 
321   create_icon_pixmaps (XtDisplay (toplevel));
322 
323   ac = 0;
324   box = XtCreateManagedWidget ("vertical", panedWidgetClass, toplevel, av, ac);
325   ac = 0;
326   XtSetArg (av[ac], XtNorientation, "horizontal"); ac++;
327   box2 = XtCreateManagedWidget ("horizontal", panedWidgetClass, box, av, ac);
328   buttons = make_command_widgets (box2, (Widget *) &keyboard);
329   info = make_info_widget (box2, buttons);
330 
331   keyboard = make_keyboard (box, box2, info, 0);
332 
333   XtAddEventHandler ((Widget) keyboard, KeymapStateMask, False,
334 		     keyboard_handle_keymap_notify, 0);
335   XtAddEventHandler ((Widget) keyboard, 0, True,
336 		     keyboard_handle_mapping_notify, 0);
337   XtRealizeWidget (toplevel);
338 
339   XtSetKeyboardFocus (toplevel, (Widget) keyboard);
340   maybe_relabel_window (keyboard);
341   XSetErrorHandler (xkeycaps_error_handler);
342 
343   message (keyboard, "");
344   message2 (keyboard, version_buf);
345 
346   if (choose_kbd_dubious_p)
347     pop_up_kbd_dbox (toplevel, (void *) &keyboard, 0);
348 
349 #ifdef HAVE_XTRAP
350   if (keyboard->keyboard.trap_data)
351     xkeycaps_xtrap_main_loop (keyboard, app);
352   else
353 #endif
354     while (1)
355       keyboard = xkeycaps_main_loop (keyboard, app);
356 }
357