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