1 /*
2  * Copyright (c) 1993-2009, 2014-2015, 2018-2020 Paul Mattes.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of Paul Mattes nor his contributors may be used
14  *       to endorse or promote products derived from this software without
15  *       specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  *	keypad.c
32  *		This module handles the keypad with buttons for each of the
33  *		3270 function keys.
34  */
35 
36 #include "globals.h"
37 #include "xglobals.h"
38 
39 #include <X11/Shell.h>
40 #include <X11/StringDefs.h>
41 #include <X11/Xaw/Command.h>
42 #include "appres.h"
43 #include "resources.h"
44 
45 #include "actions.h"
46 #include "kybd.h"
47 #include "names.h"
48 #include "popups.h"
49 #include "utils.h"
50 #include "xappres.h"
51 #include "xkeypad.h"
52 #include "xmenubar.h"
53 #include "xscreen.h"
54 #include "xpopups.h"
55 
56 #include "keypad.bm"
57 
58 enum kp_placement kp_placement;
59 
60 #define NUM_ROWS	4
61 #define NUM_VROWS	15
62 #define BORDER		rescale(1)
63 #define TOP_MARGIN	rescale(6)
64 #define BOTTOM_MARGIN	rescale(6)
65 
66 #define SPACING		rescale(2)
67 #define FAT_SPACING	rescale(3)
68 #define VGAP		rescale(4)
69 #define HGAP		rescale(4)
70 #define SIDE_MARGIN	rescale(4)
71 
72 #define HORIZ_WIDTH \
73 	(SIDE_MARGIN + \
74 	 12*(pf_width+2*BORDER) + \
75 	 11*SPACING + \
76 	 HGAP + \
77 	 3*(pa_width+2*BORDER) + \
78 	 2*SPACING + \
79 	 SIDE_MARGIN)
80 
81 #define VERT_WIDTH \
82 	(SIDE_MARGIN + \
83 	 3*(pa_width+2*BORDER) + \
84 	 2*SPACING + \
85 	 SIDE_MARGIN)
86 
87 /*
88  * Table of 3278 key labels and actions
89  */
90 struct button_list {
91     const char *label;
92     const char *name;
93     const char *bits;
94     int width;
95     int height;
96     const char *action_name;
97     const char *parm;
98 };
99 
100 bool keypad_changed = false;
101 
102 static char Lg[] = "large";
103 static char Bm[] = "bm";
104 static char Sm[] = "small";
105 
106 enum scaled_button {
107     BTAB, DEL, DOWN, HOME, INS, LEFT, RIGHT, TAB, NEWLINE, UP, NUM_SCALED
108 };
109 
110 struct button_list scaled_list[NUM_SCALED] = {
111     { "Btab",  Bm, NULL, 0, 0, AnBackTab,  NULL },
112     { "Del",   Bm, NULL, 0, 0, AnDelete,   NULL },
113     { "Down",  Bm, NULL, 0, 0, AnDown,     NULL },
114     { "Home",  Bm, NULL, 0, 0, AnHome,     NULL },
115     { "Ins",   Bm, NULL, 0, 0, AnInsert,   NULL },
116     { "Left",  Bm, NULL, 0, 0, AnLeft,     NULL },
117     { "Right", Bm, NULL, 0, 0, AnRight,    NULL },
118     { "Tab",   Bm, NULL, 0, 0, AnTab,      NULL },
119     { "Tab",   Bm, NULL, 0, 0, AnNewline,  NULL },
120     { "Up" ,   Bm, NULL, 0, 0, AnUp,       NULL },
121 };
122 
123 enum unscaled_button {
124     NONE,
125     PF1, PF2, PF3, PF4, PF5, PF6, PF7, PF8, PF9, PF10, PF11, PF12,
126     PF13, PF14, PF15, PF16, PF17, PF18, PF19, PF20, PF21, PF22, PF23, PF24,
127     PA1, PA2, PA3,
128     CLEAR, RESET, ERASE_EOF, ERASE_INPUT, DUP, FIELD_MARK, SYS_REQ,
129     CURSOR_SELECT, ATTN, COMPOSE, ENTER, NUM_UNSCALED
130 };
131 
132 struct button_list unscaled_list[NUM_UNSCALED] = {
133     { NULL,		NULL, NULL, 0, 0, NULL,     NULL },
134     { "PF1",            Lg, NULL, 0, 0, AnPF,       "1" },
135     { "PF2",            Lg, NULL, 0, 0, AnPF,       "2" },
136     { "PF3",            Lg, NULL, 0, 0, AnPF,       "3" },
137     { "PF4",            Lg, NULL, 0, 0, AnPF,       "4" },
138     { "PF5",            Lg, NULL, 0, 0, AnPF,       "5" },
139     { "PF6",            Lg, NULL, 0, 0, AnPF,       "6" },
140     { "PF7",            Lg, NULL, 0, 0, AnPF,       "7" },
141     { "PF8",            Lg, NULL, 0, 0, AnPF,       "8" },
142     { "PF9",            Lg, NULL, 0, 0, AnPF,       "9" },
143     { "PF10",           Lg, NULL, 0, 0, AnPF,       "10" },
144     { "PF11",           Lg, NULL, 0, 0, AnPF,       "11" },
145     { "PF12",           Lg, NULL, 0, 0, AnPF,       "12" },
146     { "PF13",           Lg, NULL, 0, 0, AnPF,       "13" },
147     { "PF14",           Lg, NULL, 0, 0, AnPF,       "14" },
148     { "PF15",           Lg, NULL, 0, 0, AnPF,       "15" },
149     { "PF16",           Lg, NULL, 0, 0, AnPF,       "16" },
150     { "PF17",           Lg, NULL, 0, 0, AnPF,       "17" },
151     { "PF18",           Lg, NULL, 0, 0, AnPF,       "18" },
152     { "PF19",           Lg, NULL, 0, 0, AnPF,       "19" },
153     { "PF20",           Lg, NULL, 0, 0, AnPF,       "20" },
154     { "PF21",           Lg, NULL, 0, 0, AnPF,       "21" },
155     { "PF22",           Lg, NULL, 0, 0, AnPF,       "22" },
156     { "PF23",           Lg, NULL, 0, 0, AnPF,       "23" },
157     { "PF24",           Lg, NULL, 0, 0, AnPF,       "24" },
158     { "PA1",            Lg, NULL, 0, 0, AnPA,       "1" },
159     { "PA2",            Lg, NULL, 0, 0, AnPA,       "2" },
160     { "PA3",            Lg, NULL, 0, 0, AnPA,       "3" },
161     { "Clear",          Sm, NULL, 0, 0, AnClear,    NULL },
162     { "Reset",          Sm, NULL, 0, 0, AnReset,    NULL },
163     { "Erase\nEOF",     Sm, NULL, 0, 0, AnEraseEOF, NULL },
164     { "Erase\nInput",   Sm, NULL, 0, 0, AnEraseInput,NULL },
165     { "Dup",            Sm, NULL, 0, 0, AnDup,      NULL },
166     { "Field\nMark",    Sm, NULL, 0, 0, AnFieldMark,NULL },
167     { "Sys\nReq",       Sm, NULL, 0, 0, AnSysReq,   NULL },
168     { "Cursor\nSelect", Sm, NULL, 0, 0, AnCursorSelect,NULL },
169     { "Attn",           Sm, NULL, 0, 0, AnAttn,     NULL },
170     { "Compose",        Sm, NULL, 0, 0, AnCompose,  NULL },
171     { "Enter",          Sm, NULL, 0, 0, AnEnter,    NULL },
172 };
173 
174 static struct button_list *pf_list[] = {
175     &unscaled_list[PF13],
176     &unscaled_list[PF14],
177     &unscaled_list[PF15],
178     &unscaled_list[PF16],
179     &unscaled_list[PF17],
180     &unscaled_list[PF18],
181     &unscaled_list[PF19],
182     &unscaled_list[PF20],
183     &unscaled_list[PF21],
184     &unscaled_list[PF22],
185     &unscaled_list[PF23],
186     &unscaled_list[PF24],
187     &unscaled_list[PF1],
188     &unscaled_list[PF2],
189     &unscaled_list[PF3],
190     &unscaled_list[PF4],
191     &unscaled_list[PF5],
192     &unscaled_list[PF6],
193     &unscaled_list[PF7],
194     &unscaled_list[PF8],
195     &unscaled_list[PF9],
196     &unscaled_list[PF10],
197     &unscaled_list[PF11],
198     &unscaled_list[PF12],
199 };
200 #define PF_SZ (sizeof(pf_list)/sizeof(pf_list[0]))
201 
202 static struct button_list *pad_list[] = {
203     &unscaled_list[PA1],
204     &unscaled_list[PA2],
205     &unscaled_list[PA3],
206     &unscaled_list[NONE],
207     &scaled_list[UP],
208     &unscaled_list[NONE],
209     &scaled_list[LEFT],
210     &scaled_list[HOME],
211     &scaled_list[RIGHT],
212     &unscaled_list[NONE],
213     &scaled_list[DOWN],
214     &unscaled_list[NONE],
215 };
216 #define PAD_SZ (sizeof(pad_list)/sizeof(pad_list[0]))
217 
218 static struct button_list *lower_list[] = {
219     &unscaled_list[CLEAR],
220     &unscaled_list[RESET],
221     &scaled_list[INS],
222     &scaled_list[DEL],
223     &unscaled_list[ERASE_EOF],
224     &unscaled_list[ERASE_INPUT],
225     &unscaled_list[DUP],
226     &unscaled_list[FIELD_MARK],
227     &unscaled_list[SYS_REQ],
228     &unscaled_list[CURSOR_SELECT],
229     &unscaled_list[ATTN],
230     &unscaled_list[COMPOSE],
231     &scaled_list[BTAB],
232     &scaled_list[TAB],
233     &scaled_list[NEWLINE],
234     &unscaled_list[ENTER],
235 };
236 #define LOWER_SZ (sizeof(lower_list)/sizeof(lower_list[0]))
237 
238 static struct button_list *vpf_list[] = {
239     &unscaled_list[PF1],
240     &unscaled_list[PF2],
241     &unscaled_list[PF3],
242     &unscaled_list[PF4],
243     &unscaled_list[PF5],
244     &unscaled_list[PF6],
245     &unscaled_list[PF7],
246     &unscaled_list[PF8],
247     &unscaled_list[PF9],
248     &unscaled_list[PF10],
249     &unscaled_list[PF11],
250     &unscaled_list[PF12],
251 };
252 #define VPF_SZ (sizeof(vpf_list)/sizeof(vpf_list[0]))
253 
254 static struct button_list *vspf_list[] = {
255     &unscaled_list[PF13],
256     &unscaled_list[PF14],
257     &unscaled_list[PF15],
258     &unscaled_list[PF16],
259     &unscaled_list[PF17],
260     &unscaled_list[PF18],
261     &unscaled_list[PF19],
262     &unscaled_list[PF20],
263     &unscaled_list[PF21],
264     &unscaled_list[PF22],
265     &unscaled_list[PF23],
266     &unscaled_list[PF24],
267 };
268 static Widget vpf_w[2][VPF_SZ];
269 
270 static struct button_list *vpad_list[] = {
271     &unscaled_list[NONE],
272     &scaled_list[UP],
273     &unscaled_list[NONE],
274     &scaled_list[LEFT],
275     &scaled_list[HOME],
276     &scaled_list[RIGHT],
277     &scaled_list[INS],
278     &scaled_list[DOWN],
279     &scaled_list[DEL],
280     &unscaled_list[PA1],
281     &unscaled_list[PA2],
282     &unscaled_list[PA3],
283 };
284 #define VPAD_SZ (sizeof(vpad_list)/sizeof(vpad_list[0]))
285 
286 static struct button_list *vfn_list[] = {
287     &scaled_list[BTAB],
288     &scaled_list[TAB],
289     &unscaled_list[CLEAR],
290     &unscaled_list[RESET],
291     &unscaled_list[ERASE_EOF],
292     &unscaled_list[ERASE_INPUT],
293     &unscaled_list[DUP],
294     &unscaled_list[FIELD_MARK],
295     &unscaled_list[SYS_REQ],
296     &unscaled_list[CURSOR_SELECT],
297     &unscaled_list[ATTN],
298     &unscaled_list[COMPOSE],
299     &scaled_list[NEWLINE],
300     &unscaled_list[ENTER],
301 };
302 #define VFN_SZ (sizeof(vfn_list)/sizeof(vfn_list[0]))
303 
304 static Dimension pf_width;
305 static Dimension key_height;
306 static Dimension pa_width;
307 static Dimension key_width;
308 static Dimension large_key_width;
309 
310 static Widget keypad_container = (Widget) NULL;
311 static Widget key_pad = NULL;
312 static XtTranslations keypad_t00 = (XtTranslations) NULL;
313 static XtTranslations keypad_t0 = (XtTranslations) NULL;
314 static XtTranslations saved_xt = (XtTranslations) NULL;
315 
316 /* Initialize the keypad placement from the keypad resource. */
317 void
keypad_placement_init(void)318 keypad_placement_init(void)
319 {
320     if (!strcmp(xappres.keypad, KpLeft)) {
321 	kp_placement = kp_left;
322     } else if (!strcmp(xappres.keypad, KpRight)) {
323 	kp_placement = kp_right;
324     } else if (!strcmp(xappres.keypad, KpBottom)) {
325 	kp_placement = kp_bottom;
326     } else if (!strcmp(xappres.keypad, KpIntegral)) {
327 	kp_placement = kp_integral;
328     } else if (!strcmp(xappres.keypad, KpInsideRight)) {
329 	kp_placement = kp_inside_right;
330     } else {
331 	xs_error("Unknown value for %s", ResKeypad);
332     }
333 }
334 
335 /*
336  * Callback for keypad buttons.  Simply calls the function pointed to by the
337  * client data.
338  */
339 static void
callfn(Widget w _is_unused,XtPointer client_data,XtPointer call_data _is_unused)340 callfn(Widget w _is_unused, XtPointer client_data, XtPointer
341 	call_data _is_unused)
342 {
343     struct button_list *keyd = (struct button_list *) client_data;
344 
345     run_action(keyd->action_name, IA_KEYPAD, keyd->parm, NULL);
346 }
347 
348 /*
349  * Create a button.
350  */
351 static Widget
make_a_button(Widget container,Position x,Position y,Dimension w,Dimension h,struct button_list * keyd)352 make_a_button(Widget container, Position x, Position y, Dimension w,
353 	Dimension h, struct button_list *keyd)
354 {
355     Widget command;
356     Pixmap pixmap;
357 
358     if (!keyd->label) {
359 	return (Widget) 0;
360     }
361 
362     command = XtVaCreateManagedWidget(
363 	    keyd->name, commandWidgetClass, container,
364 	    XtNx, x,
365 	    XtNy, y,
366 	    XtNwidth, w,
367 	    XtNheight, h,
368 	    XtNresize, False,
369 	    NULL);
370     XtAddCallback(command, XtNcallback, callfn, (XtPointer)keyd);
371     if (keyd->bits) {
372 	pixmap = XCreateBitmapFromData(display, root_window, keyd->bits,
373 		keyd->width, keyd->height);
374 	XtVaSetValues(command, XtNbitmap, pixmap, NULL);
375     } else {
376 	XtVaSetValues(command, XtNlabel, keyd->label, NULL);
377     }
378     return command;
379 }
380 
381 /*
382  * Create the keys for a horizontal keypad
383  */
384 static void
keypad_keys_horiz(Widget container)385 keypad_keys_horiz(Widget container)
386 {
387     unsigned i;
388     Position row, col;
389     Position x0, y0;
390 
391     /* PF Keys */
392     row = col = 0;
393     x0 = SIDE_MARGIN;
394     y0 = TOP_MARGIN;
395     for (i = 0; i < PF_SZ; i++) {
396 	make_a_button(container,
397 		(Position)(x0 + (col*(pf_width+2*BORDER+SPACING))),
398 		(Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
399 		pf_width,
400 		key_height,
401 		pf_list[i]);
402 	if (++col >= 12) {
403 	    col = 0;
404 	    row++;
405 	}
406     }
407 
408     /* Keypad */
409     row = col = 0;
410     x0 = SIDE_MARGIN + 12*(pf_width+2*BORDER+SPACING) + HGAP;
411     y0 = TOP_MARGIN;
412     for (i = 0; i < PAD_SZ; i++) {
413 	make_a_button(container,
414 		(Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
415 		(Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
416 		pa_width,
417 		key_height,
418 		pad_list[i]);
419 	if (++col >= 3) {
420 	    col = 0;
421 	    if (++row == 1) {
422 		y0 += VGAP;
423 	    }
424 	}
425     }
426 
427     /* Bottom */
428     row = col = 0;
429     x0 = SIDE_MARGIN;
430     y0 = TOP_MARGIN + 2*(key_height+2*BORDER+SPACING) + VGAP;
431 
432     for (i = 0; i < LOWER_SZ; i++) {
433 	make_a_button(container,
434 		(Position)(x0 + (col*(key_width+2*BORDER+FAT_SPACING))),
435 		(Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
436 		key_width,
437 		key_height,
438 		lower_list[i]);
439 	if (++row >= 2) {
440 	    ++col;
441 	    row = 0;
442 	}
443     }
444 }
445 
446 static bool vert_keypad = false;
447 static Widget spf_container;
448 
449 /*
450  * Create the keys for a vertical keypad.
451  */
452 static void
keypad_keys_vert(Widget container)453 keypad_keys_vert(Widget container)
454 {
455     unsigned i;
456     Position row, col;
457     Position x0, y0;
458     Widget c1, c2;
459 
460     vert_keypad = true;
461 
462     /* Container for shifted PF keys */
463     spf_container = XtVaCreateManagedWidget(
464 	    "shift", compositeWidgetClass, container,
465 	    XtNmappedWhenManaged, False,
466 	    XtNborderWidth, 0,
467 	    XtNwidth, VERT_WIDTH,
468 	    XtNheight, TOP_MARGIN+4*(key_height+2*BORDER)+3*SPACING,
469 	    NULL);
470     if (appres.interactive.mono) {
471 	XtVaSetValues(spf_container, XtNbackgroundPixmap, gray, NULL);
472     } else {
473 	XtVaSetValues(spf_container, XtNbackground, keypadbg_pixel, NULL);
474     }
475 
476     /* PF keys */
477     if (xappres.invert_kpshift) {
478 	c1 = spf_container;
479 	c2 = container;
480     } else {
481 	c1 = container;
482 	c2 = spf_container;
483     }
484     row = col = 0;
485     x0 = SIDE_MARGIN;
486     y0 = TOP_MARGIN;
487     for (i = 0; i < VPF_SZ; i++) {
488 	vpf_w[0][i] = make_a_button(c1,
489 		(Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
490 		(Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
491 		pa_width,
492 		key_height,
493 		vpf_list[i]);
494 	vpf_w[1][i] = make_a_button(c2,
495 		(Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
496 		(Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
497 		pa_width,
498 		key_height,
499 		vspf_list[i]);
500 	if (++col >= 3) {
501 	    col = 0;
502 	    row++;
503 	}
504     }
505 
506     /* Cursor and PA keys */
507     for (i = 0; i < VPAD_SZ; i++) {
508 	make_a_button(container,
509 		(Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
510 		(Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
511 		pa_width,
512 		key_height,
513 		vpad_list[i]);
514 	if (++col >= 3) {
515 	    col = 0;
516 	    row++;
517 	}
518     }
519 
520     /* Other keys */
521     for (i = 0; i < VFN_SZ; i++) {
522 	make_a_button(container,
523 		(Position)(x0 + (col*(large_key_width+2*BORDER+SPACING))),
524 		(Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
525 		large_key_width,
526 		key_height,
527 		vfn_list[i]);
528 	if (++col >= 2) {
529 	    col = 0;
530 	    row++;
531 	}
532     }
533 }
534 
535 static Dimension
get_keypad_dimension(const char * name)536 get_keypad_dimension(const char *name)
537 {
538     char *d;
539     long v;
540 
541     if ((d = get_fresource("%s.%s", ResKeypad, name)) == NULL) {
542 	xs_error("Cannot find %s resource", ResKeypad);
543     }
544     if ((v = strtol(d, (char **)0, 0)) <= 0) {
545 	xs_error("Illegal %s resource", ResKeypad);
546     }
547     return rescale((Dimension)v);
548 }
549 
550 static void
init_keypad_dimensions(void)551 init_keypad_dimensions(void)
552 {
553     static bool done = false;
554 
555     if (done) {
556 	return;
557     }
558     key_height = get_keypad_dimension(ResKeyHeight);
559     key_width = get_keypad_dimension(ResKeyWidth);
560     pf_width = get_keypad_dimension(ResPfWidth);
561     pa_width = get_keypad_dimension(ResPaWidth);
562     large_key_width = get_keypad_dimension(ResLargeKeyWidth);
563 
564     if (rescale(btab_width) >= btab20_width) {
565 	scaled_list[BTAB].bits = (char *)btab20_bits;
566 	scaled_list[BTAB].width = btab20_width;
567 	scaled_list[BTAB].height = btab20_height;
568 	scaled_list[DEL].bits = (char *)del20_bits;
569 	scaled_list[DEL].width = del20_width;
570 	scaled_list[DEL].height = del20_height;
571 	scaled_list[DOWN].bits = (char *)down20_bits;
572 	scaled_list[DOWN].width = down20_width;
573 	scaled_list[DOWN].height = down20_height;
574 	scaled_list[HOME].bits = (char *)home20_bits;
575 	scaled_list[HOME].width = home20_width;
576 	scaled_list[HOME].height = home20_height;
577 	scaled_list[INS].bits = (char *)ins20_bits;
578 	scaled_list[INS].width = ins20_width;
579 	scaled_list[INS].height = ins20_height;
580 	scaled_list[LEFT].bits = (char *)left20_bits;
581 	scaled_list[LEFT].width = left20_width;
582 	scaled_list[LEFT].height = left20_height;
583 	scaled_list[NEWLINE].bits = (char *)newline20_bits;
584 	scaled_list[NEWLINE].width = newline20_width;
585 	scaled_list[NEWLINE].height = newline20_height;
586 	scaled_list[RIGHT].bits = (char *)right20_bits;
587 	scaled_list[RIGHT].width = right20_width;
588 	scaled_list[RIGHT].height = right20_height;
589 	scaled_list[TAB].bits = (char *)tab20_bits;
590 	scaled_list[TAB].width = tab20_width;
591 	scaled_list[TAB].height = tab20_height;
592 	scaled_list[UP].bits = (char *)up20_bits;
593 	scaled_list[UP].width = up20_width;
594 	scaled_list[UP].height = up20_height;
595     } else if (rescale(btab_width) >= btab15_width) {
596 	scaled_list[BTAB].bits = (char *)btab15_bits;
597 	scaled_list[BTAB].width = btab15_width;
598 	scaled_list[BTAB].height = btab15_height;
599 	scaled_list[DEL].bits = (char *)del15_bits;
600 	scaled_list[DEL].width = del15_width;
601 	scaled_list[DEL].height = del15_height;
602 	scaled_list[DOWN].bits = (char *)down15_bits;
603 	scaled_list[DOWN].width = down15_width;
604 	scaled_list[DOWN].height = down15_height;
605 	scaled_list[HOME].bits = (char *)home15_bits;
606 	scaled_list[HOME].width = home15_width;
607 	scaled_list[HOME].height = home15_height;
608 	scaled_list[INS].bits = (char *)ins15_bits;
609 	scaled_list[INS].width = ins15_width;
610 	scaled_list[INS].height = ins15_height;
611 	scaled_list[LEFT].bits = (char *)left15_bits;
612 	scaled_list[LEFT].width = left15_width;
613 	scaled_list[LEFT].height = left15_height;
614 	scaled_list[NEWLINE].bits = (char *)newline15_bits;
615 	scaled_list[NEWLINE].width = newline15_width;
616 	scaled_list[NEWLINE].height = newline15_height;
617 	scaled_list[RIGHT].bits = (char *)right15_bits;
618 	scaled_list[RIGHT].width = right15_width;
619 	scaled_list[RIGHT].height = right15_height;
620 	scaled_list[TAB].bits = (char *)tab15_bits;
621 	scaled_list[TAB].width = tab15_width;
622 	scaled_list[TAB].height = tab15_height;
623 	scaled_list[UP].bits = (char *)up15_bits;
624 	scaled_list[UP].width = up15_width;
625 	scaled_list[UP].height = up15_height;
626     } else {
627 	scaled_list[BTAB].bits = (char *)btab_bits;
628 	scaled_list[BTAB].width = btab_width;
629 	scaled_list[BTAB].height = btab_height;
630 	scaled_list[DEL].bits = (char *)del_bits;
631 	scaled_list[DEL].width = del_width;
632 	scaled_list[DEL].height = del_height;
633 	scaled_list[DOWN].bits = (char *)down_bits;
634 	scaled_list[DOWN].width = down_width;
635 	scaled_list[DOWN].height = down_height;
636 	scaled_list[HOME].bits = (char *)home_bits;
637 	scaled_list[HOME].width = home_width;
638 	scaled_list[HOME].height = home_height;
639 	scaled_list[INS].bits = (char *)ins_bits;
640 	scaled_list[INS].width = ins_width;
641 	scaled_list[INS].height = ins_height;
642 	scaled_list[LEFT].bits = (char *)left_bits;
643 	scaled_list[LEFT].width = left_width;
644 	scaled_list[LEFT].height = left_height;
645 	scaled_list[NEWLINE].bits = (char *)newline_bits;
646 	scaled_list[NEWLINE].width = newline_width;
647 	scaled_list[NEWLINE].height = newline_height;
648 	scaled_list[RIGHT].bits = (char *)right_bits;
649 	scaled_list[RIGHT].width = right_width;
650 	scaled_list[RIGHT].height = right_height;
651 	scaled_list[TAB].bits = (char *)tab_bits;
652 	scaled_list[TAB].width = tab_width;
653 	scaled_list[TAB].height = tab_height;
654 	scaled_list[UP].bits = (char *)up_bits;
655 	scaled_list[UP].width = up_width;
656 	scaled_list[UP].height = up_height;
657     }
658 
659     done = true;
660 }
661 
662 Dimension
min_keypad_width(void)663 min_keypad_width(void)
664 {
665     init_keypad_dimensions();
666     return HORIZ_WIDTH;
667 }
668 
669 Dimension
keypad_qheight(void)670 keypad_qheight(void)
671 {
672     init_keypad_dimensions();
673     return TOP_MARGIN +
674 	(NUM_ROWS*(key_height+2*BORDER)) + (NUM_ROWS-1)*SPACING + VGAP +
675 	BOTTOM_MARGIN;
676 }
677 
678 /*
679  * Create a keypad.
680  */
681 Widget
keypad_init(Widget container,Dimension voffset,Dimension screen_width,bool floating,bool vert)682 keypad_init(Widget container, Dimension voffset, Dimension screen_width,
683 	bool floating, bool vert)
684 {
685     Dimension height;
686     Dimension width = screen_width;
687     Dimension hoffset;
688 
689     init_keypad_dimensions();
690 
691     /* Figure out what dimensions to use */
692     if (vert) {
693 	width = VERT_WIDTH;
694     } else {
695 	width = HORIZ_WIDTH;
696     }
697 
698     if (vert) {
699 	height = TOP_MARGIN +
700 	    (NUM_VROWS*(key_height+2*BORDER)) + (NUM_VROWS-1)*SPACING +
701 	    BOTTOM_MARGIN;
702     } else {
703 	height = keypad_qheight();
704     }
705 
706     /* Create a container */
707     if (screen_width > width) {
708 	hoffset = ((screen_width - width) / (unsigned) 2) & ~1;
709     } else {
710 	hoffset = 0;
711     }
712     if (voffset & 1) {
713 	voffset++;
714     }
715     if (key_pad == NULL) {
716 	key_pad = XtVaCreateManagedWidget(
717 		"keyPad", compositeWidgetClass, container,
718 		XtNx, hoffset,
719 		XtNy, voffset,
720 		XtNborderWidth, (Dimension) (floating ? 1 : 0),
721 		XtNwidth, width,
722 		XtNheight, height,
723 		NULL);
724 	if (appres.interactive.mono) {
725 	    XtVaSetValues(key_pad, XtNbackgroundPixmap, gray, NULL);
726 	} else {
727 	    XtVaSetValues(key_pad, XtNbackground, keypadbg_pixel, NULL);
728 	}
729 
730 	/* Create the keys */
731 	if (vert) {
732 	    keypad_keys_vert(key_pad);
733 	} else {
734 	    keypad_keys_horiz(key_pad);
735 	}
736     } else {
737 	XtVaSetValues(key_pad,
738 		XtNx, hoffset,
739 		XtNy, voffset,
740 		NULL);
741     }
742 
743     return key_pad;
744 }
745 
746 /*
747  * Swap PF1-12 and PF13-24 on the vertical popup keypad, by mapping or
748  * unmapping the window containing the shifted keys.
749  */
750 void
keypad_shift(void)751 keypad_shift(void)
752 {
753     if (!vert_keypad ||
754 	    (spf_container == NULL) ||
755 	    !XtIsRealized(spf_container)) {
756 	return;
757     }
758 
759     if (shifted) {
760 	XtMapWidget(spf_container);
761     } else {
762 	XtUnmapWidget(spf_container);
763     }
764 }
765 
766 /*
767  * Keypad popup
768  */
769 Widget keypad_shell = NULL;
770 bool keypad_popped = false;
771 
772 static bool TrueD = true;
773 static bool *TrueP = &TrueD;
774 static bool FalseD = false;
775 static bool *FalseP = &FalseD;
776 static enum placement *pp;
777 
778 /*
779  * Called when the main screen is first exposed, to pop up the keypad the
780  * first time
781  */
782 void
keypad_first_up(void)783 keypad_first_up(void)
784 {
785     if (!xappres.keypad_on || kp_placement == kp_integral) {
786 	return;
787     }
788     keypad_popup_init();
789     popup_popup(keypad_shell, XtGrabNone);
790 }
791 
792 /* Called when the keypad popup pops up or down */
793 static void
keypad_updown(Widget w _is_unused,XtPointer client_data,XtPointer call_data)794 keypad_updown(Widget w _is_unused, XtPointer client_data, XtPointer call_data)
795 {
796     xappres.keypad_on = keypad_popped = *(bool *)client_data;
797     if (!keypad_popped) {
798 	XtDestroyWidget(keypad_shell);
799 	keypad_shell = NULL;
800 	keypad_container = NULL;
801 	key_pad = NULL;
802 	spf_container = NULL;
803     }
804 
805     if (xappres.keypad_on) {
806 	place_popup(w, (XtPointer)pp, call_data);
807     }
808     menubar_keypad_changed();
809 }
810 
811 /* Create the pop-up keypad */
812 void
keypad_popup_init(void)813 keypad_popup_init(void)
814 {
815     Widget w;
816     Dimension height, width, border;
817     bool vert = false;
818 
819     if (keypad_shell != NULL) {
820 	return;
821     }
822 
823     switch (kp_placement) {
824     case kp_left:
825 	vert = true;
826 	pp = LeftP;
827 	break;
828     case kp_right:
829 	vert = true;
830 	pp = RightP;
831 	break;
832     case kp_bottom:
833 	vert = false;
834 	pp = BottomP;
835 	break;
836     case kp_integral:	/* can't happen */
837 	return;
838     case kp_inside_right:
839 	vert = true;
840 	pp = InsideRightP;
841 	break;
842     }
843 
844     /* Create a popup shell */
845 
846     keypad_shell = XtVaCreatePopupShell(
847 	    "keypadPopup", transientShellWidgetClass, toplevel,
848 	    NULL);
849     /*XtAddCallback(keypad_shell, XtNpopupCallback, place_popup,
850 	(XtPointer)pp);*/
851     XtAddCallback(keypad_shell, XtNpopupCallback, keypad_updown,
852 	    (XtPointer) TrueP);
853     XtAddCallback(keypad_shell, XtNpopdownCallback, keypad_updown,
854 	    (XtPointer) FalseP);
855 
856     /* Create a keypad in the popup */
857 
858     keypad_container = XtVaCreateManagedWidget(
859 	    "container", compositeWidgetClass, keypad_shell,
860 	    XtNborderWidth, 0,
861 	    XtNheight, 10,
862 	    XtNwidth, 10,
863 	    NULL);
864     w = keypad_init(keypad_container, 0, 0, true, vert);
865 
866     /* Fix the window size */
867 
868     XtVaGetValues(w,
869 	    XtNheight, &height,
870 	    XtNwidth, &width,
871 	    XtNborderWidth, &border,
872 	    NULL);
873     height += 2*border;
874     width += 2*border;
875     XtVaSetValues(keypad_container,
876 	    XtNheight, height,
877 	    XtNwidth, width,
878 	    NULL);
879     XtVaSetValues(keypad_shell,
880 	    XtNheight, height,
881 	    XtNwidth, width,
882 	    XtNbaseHeight, height,
883 	    XtNbaseWidth, width,
884 	    XtNminHeight, height,
885 	    XtNminWidth, width,
886 	    XtNmaxHeight, height,
887 	    XtNmaxWidth, width,
888 	    NULL);
889 
890     /* Make keystrokes in the popup apply to the main window */
891 
892     save_00translations(keypad_container, &keypad_t00);
893     set_translations(keypad_container, NULL, &keypad_t0);
894     if (saved_xt != (XtTranslations) NULL) {
895 	XtOverrideTranslations(keypad_container, saved_xt);
896 	saved_xt = (XtTranslations) NULL;
897     }
898 }
899 
900 /* Set a temporary keymap. */
901 void
keypad_set_temp_keymap(XtTranslations trans)902 keypad_set_temp_keymap(XtTranslations trans)
903 {
904     if (keypad_container != (Widget) NULL) {
905 	if (trans == NULL) {
906 	    trans = keypad_t0;
907 	    XtUninstallTranslations(keypad_container);
908 	}
909 	XtOverrideTranslations(keypad_container, trans);
910 	saved_xt = (XtTranslations) NULL;
911     } else {
912 	saved_xt = trans;
913     }
914 }
915 
916 /* Change the baseleve keymap. */
917 void
keypad_set_keymap(void)918 keypad_set_keymap(void)
919 {
920     if (keypad_container == NULL) {
921 	return;
922     }
923     XtUninstallTranslations(keypad_container);
924     set_translations(keypad_container, &keypad_t00, &keypad_t0);
925 }
926 
927 /* Move the keypad. */
928 void
keypad_move(void)929 keypad_move(void)
930 {
931     if (!keypad_popped) {
932 	    return;
933     }
934 
935     move_popup(keypad_shell, pp, NULL);
936 }
937 
938 void
keypad_popdown(bool * was_up)939 keypad_popdown(bool *was_up)
940 {
941     if (keypad_popped) {
942 	*was_up = true;
943 	XtPopdown(keypad_shell);
944     } else {
945 	*was_up = false;
946     }
947 }
948 
949 void
keypad_popup(void)950 keypad_popup(void)
951 {
952 #if 0
953     if (keypad_shell != NULL) {
954 	XtPopup(keypad_shell, XtGrabNone);
955     }
956 #endif
957     xappres.keypad_on = True;
958     keypad_first_up();
959 }
960 
961 void
ikeypad_destroy(void)962 ikeypad_destroy(void)
963 {
964     if (key_pad != NULL) {
965 	XtDestroyWidget(key_pad);
966 	key_pad = NULL;
967     }
968 }
969