1 /* xkeycaps, Copyright (c) 1991, 1992, 1993, 1996, 1997
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 <X11/cursorfont.h>
14 #include <X11/Intrinsic.h>
15 #include "KbdWidget.h"
16 #include "KeyWidgetP.h"
17 #include <stdio.h>
18
19 #undef MAX
20 #undef MIN
21 #define MAX(a,b) ((a)>(b)?(a):(b))
22 #define MIN(a,b) ((a)<(b)?(a):(b))
23
24 static void KeyRealize P((Widget, XtValueMask *, XSetWindowAttributes *));
25 static void KeyExpose P((Widget, XEvent *, Region));
26 static void KeyInitialize P((Widget, Widget, ArgList, Cardinal*));
27
28 static void KeyHighlightProc P((KeyWidget));
29 static void KeyDehighlightProc P((KeyWidget));
30
31 #define XtNgutterWidth "gutterWidth"
32 #define XtCGutterWidth "GutterWidth"
33 #define XtNkeycapColor "keycapColor"
34 #define XtNkeycodeColor "keycodeColor"
35 #define XtNkeycapFont "keycapFont"
36 #define XtNkeycodeFont "keycodeFont"
37 #define XtNcursorFont "cursorFont"
38
39 #ifndef CURSORFONT
40 #define CURSORFONT "cursor"
41 #endif
42
43 static XtResource key_resources [] = {
44 { XtNhighlight, XtCBackground, XtRPixel, sizeof (String),
45 XtOffset (KeyWidget, key.highlight_pixel), XtRString,
46 XtDefaultBackground },
47 { XtNgutterWidth, XtCGutterWidth, XtRInt, sizeof (int),
48 XtOffset (KeyWidget, key.gutter_width), XtRString, "3" },
49 { XtNkeycapColor, XtCForeground, XtRPixel, sizeof (String),
50 XtOffset (KeyWidget, key.keycap_pixel), XtRString,
51 XtDefaultForeground },
52 { XtNkeycodeColor, XtCForeground, XtRPixel, sizeof (String),
53 XtOffset (KeyWidget, key.keycode_pixel), XtRString,
54 XtDefaultForeground },
55 { XtNkeycapFont, XtCFont, XtRFontStruct, sizeof (String),
56 XtOffset (KeyWidget, key.keycap_font),
57 XtRString, "*-helvetica-bold-r-*-*-*-100-*-*-*-*-*-*" },
58 { XtNkeycodeFont, XtCFont, XtRFontStruct, sizeof (String),
59 XtOffset (KeyWidget, key.keycode_font),
60 XtRString, "*-courier-medium-r-*-*-*-100-*-*-*-*-*-*" },
61 { XtNcursorFont, XtCFont, XtRFontStruct, sizeof (String),
62 XtOffset (KeyWidget, key.cursor_font),
63 XtRString, CURSORFONT }
64 };
65
66 KeyClassRec keyClassRec = {
67 { /*
68 * core fields
69 */
70 /* superclass */ &widgetClassRec,
71 /* class_name */ "Key",
72 /* widget_size */ sizeof (KeyRec),
73 /* class_initialize */ NULL,
74 /* class_part_initialize */ NULL,
75 /* class_inited */ FALSE,
76 /* initialize */ KeyInitialize,
77 /* initialize_hook */ NULL,
78 /* realize */ KeyRealize,
79 /* actions */ NULL,
80 /* num_actions */ 0,
81 /* resources */ key_resources,
82 /* resource_count */ XtNumber (key_resources),
83 /* xrm_class */ NULLQUARK,
84 /* compress_motion */ TRUE,
85 /* compress_exposure */ TRUE,
86 /* compress_enterleave */ TRUE,
87 /* visible_interest */ FALSE,
88 /* destroy */ NULL,
89 /* resize */ XtInheritResize,
90 /* expose */ KeyExpose,
91 /* set_values */ NULL,
92 /* set_values_hook */ NULL,
93 /* set_values_almost */ XtInheritSetValuesAlmost,
94 /* get_values_hook */ NULL,
95 /* accept_focus */ XtInheritAcceptFocus,
96 /* version */ XtVersion,
97 /* callback_private */ NULL,
98 /* tm_table */ NULL,
99 /* query_geometry */ XtInheritQueryGeometry,
100 /* display_accelerator */ XtInheritDisplayAccelerator,
101 /* extension */ NULL
102 },
103 { /*
104 * key_class fields
105 */
106 /* highlight_key */ KeyHighlightProc,
107 /* dehighlight_key */ KeyDehighlightProc
108 }
109 };
110
111 WidgetClass keyWidgetClass = (WidgetClass) &keyClassRec;
112
113 static void
114 #ifdef __STDC__
KeyInitialize(Widget w1,Widget w2,ArgList av,Cardinal * ac)115 KeyInitialize (Widget w1, Widget w2, ArgList av, Cardinal *ac)
116 #else /* ! __STDC__ */
117 KeyInitialize (w1, w2, av, ac)
118 Widget w1, w2;
119 ArgList av;
120 Cardinal ac;
121 #endif /* ! __STDC__ */
122 {
123 KeyWidget new = (KeyWidget) w2;
124
125 if (new->core.width <= 0) new->core.width = 3;
126 if (new->core.height <= 0) new->core.height = 3;
127 /* Initialize the non-resource slots */
128 new->key.x = 0;
129 new->key.y = 0;
130 new->key.highlighted_p = 0;
131 new->key.key_highlighted = 0;
132 new->key.mouse_highlighted = 0;
133 new->key.modifier_bits = 0;
134 new->key.auto_repeat_p = 0;
135 new->key.width = 0;
136 new->key.height = 0;
137 new->key.keysym_1 = 0;
138 new->key.keysym_2 = 0;
139 new->key.keysym_3 = 0;
140 new->key.keycode = 0;
141 new->key.default_mods = 0;
142 memset (new->key.default_keysyms, 0, sizeof (new->key.default_keysyms));
143 }
144
145
146 static void
147 #ifdef __STDC__
KeyRealize(Widget gw,XtValueMask * valuemaskp,XSetWindowAttributes * attr)148 KeyRealize (Widget gw, XtValueMask *valuemaskp, XSetWindowAttributes *attr)
149 #else /* ! __STDC__ */
150 KeyRealize (gw, valuemaskp, attr)
151 Widget gw;
152 XtValueMask *valuemaskp;
153 XSetWindowAttributes *attr;
154 #endif /* ! __STDC__ */
155 {
156 char *b, buf [255];
157 const char *k1, *k2, *k3;
158 XGCValues gcvalues;
159 KeyWidget w = (KeyWidget) gw;
160 XtCreateWindow ((Widget) w, InputOutput, (Visual *)CopyFromParent,
161 *valuemaskp, attr);
162 gcvalues.foreground = w->key.keycap_pixel;
163 gcvalues.font = w->key.keycap_font->fid;
164 w->key.keycap_gc = XtGetGC (gw, (unsigned) GCFont|GCForeground, &gcvalues);
165 gcvalues.font = w->key.cursor_font->fid;
166 w->key.cursor_gc = XtGetGC (gw, (unsigned) GCFont|GCForeground, &gcvalues);
167 gcvalues.foreground = w->key.keycode_pixel;
168 gcvalues.font = w->key.keycode_font->fid;
169 w->key.keycode_gc = XtGetGC (gw, (unsigned) GCFont|GCForeground, &gcvalues);
170
171 k1 = w->key.keysym_1;
172 k2 = w->key.keysym_2;
173 k3 = w->key.keysym_3;
174 if (k1 && !*k1) k1 = 0;
175 if (k2 && !*k2) k2 = 0;
176 if (k3 && !*k3) k3 = 0;
177 b = buf;
178 b[0] = 0;
179 if (k1)
180 {
181 int i = strlen (k1);
182 strncpy (buf, k1, i+1);
183 /* This is the kludge that makes "Caps " "Lock" concat as "CapsLock" */
184 if (i > 1 && (buf [i-1] == ' ' || buf [i-1] == '-'))
185 buf [i-1] = 0, i--;
186 else if (i > 0 && (k2 || k3))
187 buf [i] = ' ', buf [i+1] = 0, i++;
188 b = buf+i;
189 }
190 if (k2)
191 {
192 int i = strlen (k2);
193 strncpy (b, k2, i+1);
194 b += i;
195 if (k3) *b++ = ' ', *b++ = 0;
196 }
197 if (k3)
198 strcpy (b, k3);
199
200 b = buf;
201 if (b[0] == ' ' && b[1] == 0) b = "space";
202 w->key.key_name = XtNewString (b);
203 }
204
205
206 static void draw_key P((KeyWidget));
207
208 static void
209 #ifdef __STDC__
KeyExpose(Widget gw,XEvent * e,Region r)210 KeyExpose (Widget gw, XEvent *e, Region r)
211 #else /* ! __STDC__ */
212 KeyExpose (gw, e, r)
213 Widget gw;
214 XEvent *e;
215 Region r;
216 #endif /* ! __STDC__ */
217 {
218 draw_key ((KeyWidget) gw);
219 }
220
221
222 static int
223 #ifdef __STDC__
string_width(unsigned char * string,XFontStruct * font)224 string_width (unsigned char *string, XFontStruct *font)
225 #else /* ! __STDC__ */
226 string_width (string, font)
227 unsigned char *string;
228 XFontStruct *font;
229 #endif /* ! __STDC__ */
230 {
231 int size = 0;
232 if (!font) return 0;
233 for (; *string; string++)
234 if (font->per_char)
235 size += font->per_char [(*string) - font->min_char_or_byte2].width;
236 else
237 size += font->max_bounds.width;
238 return size;
239 }
240
241
242 static void
243 #ifdef __STDC__
draw_key(KeyWidget w)244 draw_key (KeyWidget w)
245 #else /* ! __STDC__ */
246 draw_key (w)
247 KeyWidget w;
248 #endif /* ! __STDC__ */
249 {
250 Display *dpy = XtDisplay (w);
251 Window window = XtWindow (w);
252 XFontStruct *keycap_font = w->key.keycap_font;
253 XFontStruct *keycode_font = w->key.keycode_font;
254 XFontStruct *cursor_font = w->key.cursor_font;
255 GC keycap_gc = w->key.keycap_gc;
256 GC keycode_gc = w->key.keycode_gc;
257 GC cursor_gc = w->key.cursor_gc;
258 const char *k1 = w->key.keysym_1;
259 const char *k2 = w->key.keysym_2;
260 const char *k3 = w->key.keysym_3;
261 unsigned char *uk1, *uk2, *uk3;
262 XFontStruct *k1_font = cursor_font;
263 XFontStruct *k2_font = cursor_font;
264 XFontStruct *k3_font = cursor_font;
265 GC k1_gc = cursor_gc;
266 GC k2_gc = cursor_gc;
267 GC k3_gc = cursor_gc;
268 int inner_margin = 2;
269 int x, y;
270
271 char left[2], right[2], up[2], down[2];
272 left[1] = right[1] = up[1] = down[1] = 0;
273 left[0] = XC_sb_left_arrow; right[0] = XC_sb_right_arrow;
274 up[0] = XC_sb_up_arrow; down[0] = XC_sb_down_arrow;
275
276 if (k1 && !*k1) k1 = 0;
277 if (k2 && !*k2) k2 = 0;
278 if (k3 && !*k3) k3 = 0;
279
280 if (string_equal (k1, "leftArrow")) k1 = left;
281 else if (string_equal (k1, "rightArrow")) k1 = right;
282 else if (string_equal (k1, "upArrow")) k1 = up;
283 else if (string_equal (k1, "downArrow")) k1 = down;
284 else k1_font = keycap_font, k1_gc = keycap_gc;
285
286 if (string_equal (k2, "leftArrow")) k2 = left;
287 else if (string_equal (k2, "rightArrow")) k2 = right;
288 else if (string_equal (k2, "upArrow")) k2 = up;
289 else if (string_equal (k2, "downArrow")) k2 = down;
290 else k2_font = keycap_font, k2_gc = keycap_gc;
291
292 if (string_equal (k3, "leftArrow")) k3 = left;
293 else if (string_equal (k3, "rightArrow")) k3 = right;
294 else if (string_equal (k3, "upArrow")) k3 = up;
295 else if (string_equal (k3, "downArrow")) k3 = down;
296 else k3_font = keycap_font, k3_gc = keycap_gc;
297
298 uk1 = (unsigned char *) k1;
299 uk2 = (unsigned char *) k2;
300 uk3 = (unsigned char *) k3;
301
302 #define PERCHAR(font,c) \
303 (font->per_char \
304 ? &font->per_char[(c) - font->min_char_or_byte2] \
305 : &font->max_bounds)
306
307 #define STRHEIGHT(font, var) \
308 (font == cursor_font && var != NULL ? PERCHAR (font, var[0])->ascent : font->ascent)
309
310 #define MAXSTRHEIGHT(font, font2, var) \
311 MAX (font->ascent, \
312 (font2 == cursor_font \
313 ? PERCHAR (font2, var[0])->ascent \
314 : font2->ascent))
315
316 XClearWindow (dpy, window);
317 x = y = 0;
318 if (k1)
319 {
320 x = inner_margin - PERCHAR (k1_font, uk1[0])->lbearing;
321 y = inner_margin + STRHEIGHT (k1_font, uk1);
322 XDrawString (dpy, window, k1_gc, x, y, k1, strlen (k1));
323 }
324 if (k2)
325 {
326 x = inner_margin - PERCHAR (k2_font, uk2[0])->lbearing;
327 y = inner_margin
328 + (k1 ? MAXSTRHEIGHT (keycap_font, k2_font, uk1)
329 : keycap_font->ascent)
330 + STRHEIGHT (k2_font, uk2);
331 /* if (y + STRHEIGHT (k2_font, uk2) < w->core.height) */
332 XDrawString (dpy, window, k2_gc, x, y, k2, strlen (k2));
333 }
334 if (k3)
335 {
336 int i = strlen (k3) - 1;
337 x = w->core.width - (w->core.border_width * 2
338 + string_width (uk3, k3_font)
339 + (PERCHAR (k3_font, uk3[i])->width -
340 PERCHAR (k3_font, uk3[i])->rbearing));
341 y = inner_margin + STRHEIGHT (k3_font, uk3);
342 if (k1 == 0 || x >= string_width (uk1, k1_font))
343 XDrawString (dpy, window, k3_gc, x, y, k3, strlen (k3));
344 }
345
346 if (w->key.keycode)
347 {
348 unsigned char buf [100];
349 sprintf ((char *) buf, "%02X", w->key.keycode);
350 x = w->core.width - (w->core.border_width * 2
351 + string_width (buf, keycode_font));
352 y = w->core.height - (w->core.border_width * 2 + keycode_font->descent);
353 if ((x >= inner_margin) &&
354 (y - keycode_font->ascent >= inner_margin) &&
355 (y > ((STRHEIGHT (k1_font, uk1) * 3) / 2)
356 ? (k2 == 0 || x >= string_width (uk2, k2_font))
357 : (k1 == 0 || x >= string_width (uk1, k1_font))))
358 XDrawString (dpy, window, keycode_gc, x, y,
359 (char *) buf, strlen ((char *) buf));
360 }
361 #undef PERCHAR
362 #undef STRHEIGHT
363 #undef MAXSTRHEIGHT
364 }
365
366
367
368 void
369 #ifdef __STDC__
KeyHighlight(KeyWidget keyw)370 KeyHighlight (KeyWidget keyw)
371 #else /* ! __STDC__ */
372 KeyHighlight (keyw)
373 KeyWidget keyw;
374 #endif /* ! __STDC__ */
375 {
376 if (keyw->key.highlighted_p) return;
377 ((KeyWidgetClass) keyw->core.widget_class)->key_class.highlight_key (keyw);
378 keyw->key.highlighted_p = 1;
379 }
380
381 void
382 #ifdef __STDC__
KeyDehighlight(KeyWidget keyw)383 KeyDehighlight (KeyWidget keyw)
384 #else /* ! __STDC__ */
385 KeyDehighlight (keyw)
386 KeyWidget keyw;
387 #endif /* ! __STDC__ */
388 {
389 if (! keyw->key.highlighted_p) return;
390 ((KeyWidgetClass) keyw->core.widget_class)->key_class.dehighlight_key (keyw);
391 keyw->key.highlighted_p = 0;
392 }
393
394
395 #include <X11/bitmaps/gray>
396
397 /* This is a little sleazy: we're caching a pixmap in global space instead
398 of caching it per-display, which means if someone were to include this
399 widget-set in an application that used multiple displays (not bloody
400 likely!) this would have to be fixed. But the alternative is adding
401 a new slot and resource to each and every key, which isn't worth it.
402 */
403 static Pixmap highlight_pixmap = 0;
404
405 static Pixmap
406 #ifdef __STDC__
make_highlight_pixmap(KeyWidget w)407 make_highlight_pixmap (KeyWidget w)
408 #else /* ! __STDC__ */
409 make_highlight_pixmap (w)
410 KeyWidget w;
411 #endif /* ! __STDC__ */
412 {
413 return XCreatePixmapFromBitmapData
414 (XtDisplay (w), XtWindow (w), gray_bits, gray_width, gray_height,
415 w->key.keycap_pixel, w->core.background_pixel,
416 DefaultDepthOfScreen (DefaultScreenOfDisplay (XtDisplay (w))));
417 }
418
419
420 #ifdef LOSE_LIKE_Xt /* Doing this the Xt way is just too damn slow... */
421
422 static void
423 #ifdef __STDC__
KeyHighlightProc(KeyWidget w)424 KeyHighlightProc (KeyWidget w)
425 #else /* ! __STDC__ */
426 KeyHighlightProc (w)
427 KeyWidget w;
428 #endif /* ! __STDC__ */
429 {
430 Arg av [2];
431 int ac = 0;
432 w->key.background_pixel = w->core.background_pixel;
433 if (w->key.background_pixel == w->key.highlight_pixel)
434 {
435 if (! highlight_pixmap) highlight_pixmap = make_hilight_pixmap (w);
436 XtSetArg (av[ac], XtNbackgroundPixmap, highlight_pixmap);
437 }
438 else
439 XtSetArg (av[ac], XtNbackground, w->key.highlight_pixel);
440 ac++;
441 XtSetValues (w, av, ac);
442 }
443
444
445 static void
446 #ifdef __STDC__
KeyDehighlightProc(KeyWidget keyw)447 KeyDehighlightProc (KeyWidget keyw)
448 #else /* ! __STDC__ */
449 KeyDehighlightProc (keyw)
450 KeyWidget keyw;
451 #endif /* ! __STDC__ */
452 {
453 Arg av [2];
454 int ac = 0;
455 if (highlight_pixmap)
456 XtSetArg (av[ac], XtNbackgroundPixmap, XtUnspecifiedPixmap);
457 else
458 XtSetArg (av[ac], XtNbackground, keyw->key.background_pixel);
459 ac++;
460 XtSetValues (keyw, av, ac);
461 }
462
463
464 #else /* !LOSE_LIKE_Xt */
465
466 static void
467 #ifdef __STDC__
KeyHighlightProc(KeyWidget w)468 KeyHighlightProc (KeyWidget w)
469 #else /* ! __STDC__ */
470 KeyHighlightProc (w)
471 KeyWidget w;
472 #endif /* ! __STDC__ */
473 {
474 w->key.background_pixel = w->core.background_pixel;
475 if (w->key.background_pixel == w->key.highlight_pixel)
476 {
477 if (! highlight_pixmap) highlight_pixmap = make_highlight_pixmap (w);
478 XSetWindowBackgroundPixmap (XtDisplay (w), XtWindow (w), highlight_pixmap);
479 }
480 else
481 XSetWindowBackground (XtDisplay (w), XtWindow (w), w->key.highlight_pixel);
482 draw_key (w);
483 }
484
485
486 static void
487 #ifdef __STDC__
KeyDehighlightProc(KeyWidget w)488 KeyDehighlightProc (KeyWidget w)
489 #else /* ! __STDC__ */
490 KeyDehighlightProc (w)
491 KeyWidget w;
492 #endif /* ! __STDC__ */
493 {
494 XSetWindowBackground (XtDisplay (w), XtWindow (w), w->key.background_pixel);
495 draw_key (w);
496 }
497
498 #endif /* !LOSE_LIKE_Xt */
499