1 /*LINTLIBRARY*/
2 /*
3  * Mini-Toolbox
4  *
5  * David Harrison
6  * University of California, Berkeley
7  * 1988, 1989
8  *
9  * This file contains routines which implement simple display widgets
10  * which can be used to construct simple dialog boxes.
11  * A mini-toolbox has been written here (overkill but I didn't
12  * want to use any of the standards yet -- they are too unstable).
13  */
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <X11/Xos.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xutil.h>
20 #include "xtb.h"
21 
22 extern void abort();
23 
24 #define MAXKEYS		10
25 
26 #ifdef __STDC__
27 #define FNPTR(fname, rtn, args)	rtn (*fname)args
28 #include <stdarg.h>
29 #define VARARGS(func, rtn, args)	rtn func args
30 #else
31 #define FNPTR(fname, rtn, args)	rtn (*fname)()
32 #include <varargs.h>
33 #define VARARGS(func, rtn, args)	/*VARARGS1*/ rtn func(va_alist) va_dcl
34 #endif
35 
36 struct h_info {
37     FNPTR(func, xtb_hret, (XEvent *evt, xtb_data info)); /* Function to call */
38     xtb_data info;		/* Additional info  */
39 };
40 
41 static Display *t_disp;		/* Display          */
42 static int t_scrn;		/* Screen           */
43 
44 static unsigned long norm_pix;	/* Foreground color */
45 static unsigned long back_pix;	/* Background color */
46 
47 static XFontStruct *norm_font;	/* Normal font      */
48 
49 /* extern char *malloc(); */
50 #define STRDUP(str)	(strcpy(malloc((unsigned) (strlen(str)+1)), (str)))
51 /* extern char *strcpy(); */
52 /* extern void free(); */
53 
54 
55 
xtb_init(disp,scrn,foreground,background,font)56 void xtb_init(disp, scrn, foreground, background, font)
57 Display *disp;			/* Display          */
58 int scrn;			/* Screen number    */
59 unsigned long foreground;	/* Foreground color */
60 unsigned long background;	/* Background color */
61 XFontStruct *font;		/* Normal font      */
62 /*
63  * Sets default parameters used by the mini-toolbox.
64  */
65 {
66     t_disp = disp;
67     t_scrn = scrn;
68     norm_pix = foreground;
69     back_pix = background;
70     norm_font = font;
71 }
72 
73 
74 #define gray_width 32
75 #define gray_height 32
76 static char gray_bits[] = {
77    0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
78    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
79    0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
80    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
81    0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
82    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
83    0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
84    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
85    0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
86    0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
87    0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa};
88 
make_stipple(disp,able,bits,width,height)89 static Pixmap make_stipple(disp, able, bits, width, height)
90 Display *disp;
91 Drawable able;
92 char *bits;
93 int width, height;
94 {
95     int w, h;
96     Pixmap stipple;
97     int bitmap_pad;
98     GC image_gc;
99     XGCValues image_vals;
100     XImage *stip_image;
101 
102     if (!XQueryBestStipple(disp, able, width, height, &w, &h)) {
103 	/* Can't query best stipple */
104 	return (Pixmap) 0;
105     }
106     if ((w > width) || (h > height)) {
107 	/* Given pattern is too small */
108 	return (Pixmap) 0;
109     }
110     if (!(stipple = XCreatePixmap(disp, able, w, h, 1))) {
111 	/* Can't create pixmap image */
112 	return (Pixmap) 0;
113     }
114     bitmap_pad = 8;
115     stip_image = XCreateImage(disp, DefaultVisual(disp, DefaultScreen(disp)),
116 			      1, XYPixmap, 0, bits, width, height,
117 			      bitmap_pad, 0);
118     if (!stip_image) return (Pixmap) 0;
119     image_gc = XCreateGC(disp, stipple, (unsigned long) 0, &image_vals);
120     XPutImage(disp, stipple, image_gc, stip_image, 0, 0, 0, 0, w, h);
121     return stipple;
122 }
123 
124 
gray_map(win)125 static Pixmap gray_map(win)
126 Window win;
127 /*
128  * Returns a gray pixmap suitable for stipple fill.
129  */
130 {
131     static Pixmap map = (Pixmap) 0;
132 
133     if (!map) {
134 	map = make_stipple(t_disp, win, gray_bits, gray_width, gray_height);
135     }
136     return map;
137 }
138 
set_gc(win,fg,bg,font,gray_p)139 static GC set_gc(win, fg, bg, font, gray_p)
140 Window win;			/* For creating GC  */
141 unsigned long fg;		/* Foreground pixel */
142 unsigned long bg;		/* Background pixel */
143 Font font;			/* Font             */
144 int gray_p;			/* Gray if set      */
145 /*
146  * Sets and returns the fields listed above in a global graphics context.
147  * If graphics context does not exist,  it is created.
148  */
149 {
150     static GC t_gc = (GC) 0;
151     XGCValues gcvals;
152     unsigned long gcmask;
153 
154     gcvals.foreground = fg;
155     gcvals.background = bg;
156     gcvals.font = font;
157     gcvals.stipple = gray_map(win);
158     gcvals.fill_style = (gray_p ? FillStippled : FillSolid);
159     gcmask = GCForeground | GCBackground | GCFont | GCFillStyle | GCStipple;
160     if (t_gc == (GC) 0) {
161 	t_gc = XCreateGC(t_disp, win, gcmask, &gcvals);
162     } else {
163 	XChangeGC(t_disp, t_gc, gcmask, &gcvals);
164     }
165     return t_gc;
166 }
167 
168 
169 
170 static XContext h_context = (XContext) 0;
171 
xtb_register(win,func,info)172 void xtb_register(win, func, info)
173 Window win;
174 FNPTR( func, xtb_hret, (XEvent *evt, xtb_data info) );
175 xtb_data info;
176 /*
177  * Associates the event handling function `func' with the window
178  * `win'.  Additional information `info' will be passed to `func'.
179  * The routine should return one of the return codes given above.
180  */
181 {
182     struct h_info *new_info;
183 
184     if (h_context == (XContext) 0) {
185 	h_context = XUniqueContext();
186     }
187     new_info = (struct h_info *) malloc(sizeof(struct h_info));
188     new_info->func = func;
189     new_info->info = info;
190     XSaveContext(t_disp, win, h_context, (caddr_t) new_info);
191 }
192 
xtb_lookup(win)193 xtb_data xtb_lookup(win)
194 Window win;
195 /*
196  * Returns the associated data with window `win'.
197  */
198 {
199     xtb_data data;
200 
201     if (!XFindContext(t_disp, win, h_context, (XPointer*)&data)) {
202 	return ((struct h_info *) data)->info;
203     } else {
204 	return (xtb_data) 0;
205     }
206 }
207 
xtb_dispatch(evt)208 xtb_hret xtb_dispatch(evt)
209 XEvent *evt;
210 /*
211  * Dispatches an event to a handler if its ours.  Returns one of
212  * the return codes given above (XTB_NOTDEF, XTB_HANDLED, or XTB_STOP).
213  */
214 {
215     struct h_info *info;
216 
217     if (!XFindContext(t_disp, evt->xany.window, h_context, (caddr_t *) &info)) {
218 	if (info->func) return (*info->func)(evt, info->info);
219 	else return XTB_NOTDEF;
220     } else return XTB_NOTDEF;
221 }
222 
xtb_unregister(win,info)223 int xtb_unregister(win, info)
224 Window win;
225 xtb_data *info;
226 /*
227  * Removes `win' from the dialog association table.  `info' is
228  * returned to allow the user to delete it (if desired).  Returns
229  * a non-zero status if the association was found and properly deleted.
230  */
231 {
232     struct h_info *hi;
233 
234     if (!XFindContext(t_disp, win, h_context, (caddr_t *) &hi)) {
235 	(void) XDeleteContext(t_disp, win, h_context);
236 	*info = hi->info;
237 	free((char *) hi);
238 	return 1;
239     } else return 0;
240 }
241 
242 
243 
244 #define BT_HPAD	3
245 #define BT_VPAD	2
246 #define BT_LPAD	3
247 #define BT_BRDR	1
248 
249 struct b_info {
250     FNPTR( func, xtb_hret, (Window win, int state, xtb_data val) );
251 				/* Function to call */
252     char *text;			/* Text of button   */
253     int flag;			/* State of button  */
254     int na;			/* Non-zero if not active */
255     int line_y, line_w;		/* Entry/Exit line  */
256     xtb_data val;		/* User defined info */
257 };
258 
bt_draw(win,ri)259 static void bt_draw(win, ri)
260 Window win;
261 struct b_info *ri;
262 /*
263  * Draws a button window
264  */
265 {
266     if (ri->flag) {
267 	XDrawImageString(t_disp, win,
268 			 set_gc(win, back_pix, norm_pix, norm_font->fid, 0),
269 			 BT_HPAD, BT_VPAD+norm_font->ascent,
270 			 ri->text, strlen(ri->text));
271     } else {
272 	XDrawImageString(t_disp, win,
273 			 set_gc(win, norm_pix, back_pix, norm_font->fid, 0),
274 			 BT_HPAD, BT_VPAD+norm_font->ascent,
275 			 ri->text, strlen(ri->text));
276     }
277     if (ri->na) {
278 	Window root;
279 	int x, y;
280 	unsigned int w, h, b, d;
281 
282 	XGetGeometry(t_disp, win, &root, &x, &y, &w, &h, &b, &d);
283 	XFillRectangle(t_disp, win,
284 		       set_gc(win, (ri->flag ? norm_pix : back_pix),
285 			      back_pix, norm_font->fid, 1),
286 		       0, 0, w, h);
287     }
288 }
289 
bt_line(win,ri,pix)290 static void bt_line(win, ri, pix)
291 Window win;
292 struct b_info *ri;
293 unsigned long pix;
294 /*
295  * Draws a status line beneath the text to indicate the
296  * user has moved into the button.
297  */
298 {
299     XDrawLine(t_disp, win,
300 	      set_gc(win, pix, back_pix, norm_font->fid, ri->na),
301 	      BT_HPAD, ri->line_y, BT_HPAD+ri->line_w, ri->line_y);
302 }
303 
bt_h(evt,info)304 static xtb_hret bt_h(evt, info)
305 XEvent *evt;
306 xtb_data info;
307 /*
308  * Handles button events.
309  */
310 {
311     Window win = evt->xany.window;
312     struct b_info *ri = (struct b_info *) info;
313     xtb_hret rtn;
314 
315     switch (evt->type) {
316     case Expose:
317 	bt_draw(win, ri);  rtn = XTB_HANDLED;
318 	break;
319     case EnterNotify:
320 	if (!ri->na) bt_line(win, ri, norm_pix);  rtn = XTB_HANDLED;
321 	break;
322     case LeaveNotify:
323 	if (!ri->na) bt_line(win, ri, back_pix);  rtn = XTB_HANDLED;
324 	break;
325     case ButtonPress:
326 	/* Nothing - just wait for button up */
327 	rtn = XTB_HANDLED;
328 	break;
329     case ButtonRelease:
330 	if (!ri->na) rtn = (*ri->func)(win, ri->flag, ri->val);
331 	break;
332     default:
333 	rtn = XTB_NOTDEF;
334     }
335     return rtn;
336 }
337 
xtb_bt_new(win,text,func,val,frame)338 void xtb_bt_new(win, text, func, val, frame)
339 Window win;			/* Parent window     */
340 char *text;			/* Text in button    */
341 FNPTR( func, xtb_hret, (Window, int, xtb_data) ); /* Callback */
342 xtb_data val;			/* User data         */
343 xtb_frame *frame;		/* Size (RETURN)     */
344 /*
345  * Makes a new button under `win' with the text `text'.  The
346  * window, size, and position of the button are returned in `frame'.
347  * The initial position is always (0, 0).  When the
348  * button is pressed,  `func' will be called with the button
349  * window,  the current state of the button,  and `val'.
350  * It is up to `func' to change the state of the button (if desired).
351  * The routine should return XTB_HANDLED normally and XTB_STOP if the
352  * dialog should stop.  The window will be automatically mapped.
353  */
354 {
355     XCharStruct bb;
356     struct b_info *info;
357     int dir, ascent, descent;
358 
359     XTextExtents(norm_font, text, strlen(text), &dir, &ascent, &descent, &bb);
360     frame->width = bb.width + 2*BT_HPAD;
361     frame->height = norm_font->ascent + norm_font->descent + BT_VPAD + BT_LPAD;
362     frame->x_loc = frame->y_loc = 0;
363     frame->win = XCreateSimpleWindow(t_disp, win,
364 				     frame->x_loc, frame->y_loc,
365 				     frame->width, frame->height,
366 				     BT_BRDR, norm_pix, back_pix);
367     XSelectInput(t_disp, frame->win, ExposureMask|
368 		 ButtonPressMask|ButtonReleaseMask|
369 		 EnterWindowMask|LeaveWindowMask);
370     info = (struct b_info *) malloc(sizeof(struct b_info));
371     info->func = func;
372     info->text = STRDUP(text);
373     info->flag = 0;
374     info->na = 0;
375     info->val = val;
376     info->line_y = frame->height - 2;
377     info->line_w = frame->width - 2*BT_HPAD;
378     xtb_register(frame->win, bt_h, (xtb_data) info);
379     XMapWindow(t_disp, frame->win);
380     frame->width += (2*BT_BRDR);
381     frame->height += (2*BT_BRDR);
382 }
383 
xtb_bt_get(win,stuff,na)384 int xtb_bt_get(win, stuff, na)
385 Window win;
386 xtb_data *stuff;
387 int *na;
388 /*
389  * Returns the state of button `win'.  If provided,  the button
390  * specific info is returned in `info' and the active state
391  * of the button is returned in `na'.
392  */
393 {
394     struct b_info *info = (struct b_info *) xtb_lookup(win);
395 
396     if (stuff) *stuff = info->val;
397     if (na) *na = info->na;
398     return info->flag;
399 }
400 
xtb_bt_set(win,val,stuff,na)401 int xtb_bt_set(win, val, stuff, na)
402 Window win;
403 int val;
404 xtb_data stuff;
405 int na;
406 /*
407  * Changes the value of a button and returns the new state.
408  * The button is drawn.  If set,  the button specific info
409  * will be set to `info'.  This doesn't allow you to set
410  * the state to zero, but that may not be important.  If
411  * `na' is non-zero,  the button will be deactivated (no
412  * activity will be allowed). The change in button appearance
413  * will be immediate.
414  */
415 {
416     struct b_info *info = (struct b_info *) xtb_lookup(win);
417 
418     info->flag = (val != 0);
419     info->na = (na != 0);
420     if (stuff) info->val = stuff;
421     bt_draw(win, info);
422     XFlush(t_disp);
423     return info->flag;
424 }
425 
xtb_bt_del(win,info)426 void xtb_bt_del(win, info)
427 Window win;
428 xtb_data *info;
429 /*
430  * Deletes the button `win' and returns the user defined information
431  * in `info' for destruction.
432  */
433 {
434     struct b_info *bi;
435 
436     if (xtb_unregister(win, (xtb_data *) &bi)) {
437 	*info = bi->val;
438 	free((char *) bi->text);
439 	free((char *) bi);
440 	XDestroyWindow(t_disp, win);
441     }
442 }
443 
444 
445 
446 #define BR_XPAD		2
447 #define BR_YPAD		2
448 #define BR_INTER	2
449 
450 struct br_info {
451     Window main_win;		/* Main button row    */
452     int which_one;		/* Which button is on */
453     int btn_cnt;		/* How many buttons   */
454     FNPTR( func, xtb_hret, (Window win, int prev, int this, xtb_data val) );
455     xtb_data val;		/* User data          */
456     Window *btns;		/* Button windows     */
457 };
458 
459 /*ARGSUSED*/
br_h(win,val,info)460 static xtb_hret br_h(win, val, info)
461 Window win;
462 int val;
463 xtb_data info;
464 /*
465  * This handles events for button rows.  When a button is pressed,
466  * it turns off the button selected in `which_one' and turns itself
467  * on.
468  */
469 {
470     struct br_info *real_info = (struct br_info *) info;
471     int i, prev;
472 
473     prev = real_info->which_one;
474     if ((prev >= 0) && (prev < real_info->btn_cnt)) {
475 	(void) xtb_bt_set(real_info->btns[prev], 0, (xtb_data) 0, 0);
476     }
477     for (i = 0;  i < real_info->btn_cnt;  i++) {
478 	if (win == real_info->btns[i]) {
479 	    real_info->which_one = i;
480 	    break;
481 	}
482     }
483     (void) xtb_bt_set(win, 1, (xtb_data) 0, 0);
484     /* Callback */
485     if (real_info->func) {
486 	return (*real_info->func)(real_info->main_win,
487 				  prev, real_info->which_one,
488 				  real_info->val);
489     } else {
490 	return XTB_HANDLED;
491     }
492 }
493 
494 
xtb_br_new(win,cnt,lbls,init,func,val,frame)495 void xtb_br_new(win, cnt, lbls, init, func, val, frame)
496 Window win;			/* Parent window    */
497 int cnt;			/* Count of buttons */
498 char *lbls[];			/* Button labels    */
499 int init;			/* Initial button   */
500 FNPTR( func, xtb_hret, (Window, int, int, xtb_data) ); /* Callback */
501 xtb_data val;			/* User data        */
502 xtb_frame *frame;		/* Returned size    */
503 /*
504  * This routine makes a new row of buttons in the window `win'
505  * and returns a frame containing all of these buttons.  These
506  * buttons are designed so that only one of them will be active
507  * at a time.  Initially,  button `init' will be activated (if
508  * init is less than zero,  none will be initially activated).
509  * Whenever a button is pushed, `func' will be called with the
510  * button row window,  the index of the previous button (-1 if
511  * none),  the index of the current button,  and the user data, `val'.
512  * The function is optional (if zero,  no function will be called).
513  * The size of the row is returned in `frame'.  The window
514  * will be automatically mapped.  Initially,  the window containing
515  * the buttons will be placed at 0,0 in the parent window.
516  */
517 {
518     struct br_info *info;
519     xtb_frame sub_frame;
520     int i, x, y;
521 
522     frame->width = frame->height = 0;
523     frame->x_loc = frame->y_loc = 0;
524     frame->win = XCreateSimpleWindow(t_disp, win, 0, 0, 1, 1,
525 				     0, back_pix, back_pix);
526     info = (struct br_info *) malloc(sizeof(struct br_info));
527     info->main_win = frame->win;
528     info->btns = (Window *) malloc((unsigned) (sizeof(Window) * cnt));
529     info->btn_cnt = cnt;
530     info->which_one = init;
531     info->func = func;
532     info->val = val;
533     /* the handler is used simply to get information out */
534     xtb_register(frame->win, (xtb_hret (*)()) 0, (xtb_data) info);
535     x = BR_XPAD;  y = BR_YPAD;
536     for (i = 0;  i < cnt;  i++) {
537 	xtb_bt_new(frame->win, lbls[i], br_h, (xtb_data) info, &sub_frame);
538 	info->btns[i] = sub_frame.win;
539 	XMoveWindow(t_disp, info->btns[i], x, y);
540 	x += (BR_INTER + sub_frame.width);
541 	if (sub_frame.height > frame->height) frame->height = sub_frame.height;
542 	if (i == init) (void) xtb_bt_set(info->btns[i], 1, (xtb_data) 0, 0);
543     }
544     frame->width = x - BR_INTER + BR_XPAD;
545     frame->height += (2 * BR_YPAD);
546     XResizeWindow(t_disp, frame->win, frame->width, frame->height);
547     XMapWindow(t_disp, frame->win);
548 }
549 
xtb_br_get(win)550 int xtb_br_get(win)
551 Window win;
552 /*
553  * This routine returns the index of the currently selected item of
554  * the button row given by the window `win'.  Note:  no checking
555  * is done to make sure `win' is a button row.
556  */
557 {
558     struct br_info *info = (struct br_info *) xtb_lookup(win);
559 
560     return info->which_one;
561 }
562 
xtb_br_del(win)563 void xtb_br_del(win)
564 Window win;
565 /*
566  * Deletes a button row.  All resources are reclaimed.
567  */
568 {
569     struct br_info *info;
570     int i;
571 
572     if (xtb_unregister(win, (xtb_data *) &info)) {
573 	for (i = 0;  i < info->btn_cnt;  i++) {
574 	    xtb_bt_del(info->btns[i], (xtb_data *) &info);
575 	}
576 	free((char *) info->btns);
577 	free((char *) info);
578 	XDestroyWindow(t_disp, win);
579     }
580 }
581 
582 
583 
584 /* Text widget */
585 
586 #define TO_HPAD	1
587 #define TO_VPAD	1
588 
589 struct to_info {
590     char *text;			/* Text to display */
591     XFontStruct *ft;		/* Font to use     */
592 };
593 
to_draw(win,ri)594 static void to_draw(win, ri)
595 Window win;
596 struct to_info *ri;
597 /*
598  * Draws the text for a widget
599  */
600 {
601     XDrawImageString(t_disp, win,
602 		     set_gc(win, norm_pix, back_pix, ri->ft->fid, 0),
603 		     TO_HPAD, TO_VPAD+ri->ft->ascent,
604 		     ri->text, strlen(ri->text));
605 }
606 
to_h(evt,info)607 static xtb_hret to_h(evt, info)
608 XEvent *evt;
609 xtb_data info;
610 /*
611  * Handles text widget events
612  */
613 {
614     Window win = evt->xany.window;
615     struct to_info *ri = (struct to_info *) info;
616 
617     switch (evt->type) {
618     case Expose:
619 	to_draw(win, ri);
620 	return XTB_HANDLED;
621     default:
622 	return XTB_NOTDEF;
623     }
624 }
625 
xtb_to_new(win,text,ft,frame)626 void xtb_to_new(win, text, ft, frame)
627 Window win;			/* Parent window */
628 char *text;			/* Text          */
629 XFontStruct *ft;		/* Font to use   */
630 xtb_frame *frame;		/* Returned size */
631 /*
632  * Makes a new text widget under `win' with the text `text'.
633  * The size of the widget is returned in `w' and `h'.  The
634  * window is created and mapped at 0,0 in `win'.  The font
635  * used for the text is given in `ft'.
636  */
637 {
638     struct to_info *info;
639 
640     frame->width = XTextWidth(ft, text, strlen(text)) + 2*TO_HPAD;
641     frame->height = ft->ascent + ft->descent + 2*TO_VPAD;
642     frame->x_loc = frame->y_loc = 0;
643     frame->win = XCreateSimpleWindow(t_disp, win, 0, 0,
644 				     frame->width, frame->height, 0,
645 				     back_pix, back_pix);
646     XSelectInput(t_disp, frame->win, ExposureMask);
647     info = (struct to_info *) malloc(sizeof(struct to_info));
648     info->text = STRDUP(text);
649     info->ft = ft;
650     xtb_register(frame->win, to_h, (xtb_data) info);
651     XMapWindow(t_disp, frame->win);
652 }
653 
xtb_to_del(win)654 void xtb_to_del(win)
655 Window win;
656 /*
657  * Deletes an output only text widget.
658  */
659 {
660     struct to_info *info;
661 
662     if (xtb_unregister(win, (xtb_data *) &info)) {
663 	free((char *) info->text);
664 	free((char *) info);
665 	XDestroyWindow(t_disp, win);
666     }
667 }
668 
669 
670 /*
671  * Input text widget
672  */
673 
674 #define TI_HPAD	2
675 #define TI_VPAD	2
676 #define TI_LPAD	3
677 #define TI_BRDR 2
678 #define TI_CRSP	1
679 
680 struct ti_info {
681     FNPTR( func, xtb_hret, (Window win, int ch, char *textcopy, xtb_data *val) );
682     				/* Function to call   */
683     int maxlen;			/* Maximum characters */
684     int curidx;			/* Current index pos  */
685     int curxval;		/* Current draw loc   */
686     char text[MAXCHBUF];	/* Current text array */
687     int line_y, line_w;		/* Entry/Exit line    */
688     int focus_flag;		/* If on, we have focus */
689     xtb_data val;		/* User info          */
690 };
691 
text_width(font,str,len)692 static int text_width(font, str, len)
693 XFontStruct *font;		/* What font       */
694 char *str;			/* Character array */
695 int len;			/* Length of array */
696 /*
697  * Returns the width of a string using XTextExtents.
698  */
699 {
700     XCharStruct bb;
701     int dir, ascent, descent;
702 
703     XTextExtents(font, str, len, &dir, &ascent, &descent, &bb);
704     return bb.width;
705 }
706 
ti_cursor_on(win,ri)707 static void ti_cursor_on(win, ri)
708 Window win;
709 struct ti_info *ri;
710 /*
711  * Draws the cursor for the window.  Uses pixel `pix'.
712  */
713 {
714     XFillRectangle(t_disp, win,
715 		   set_gc(win, norm_pix, back_pix, norm_font->fid, 0),
716 		   ri->curxval + TI_HPAD + TI_CRSP, TI_VPAD,
717 		   (ri->focus_flag ? 2 : 1),
718 		   norm_font->ascent + norm_font->descent - 1);
719 }
720 
ti_cursor_off(win,ri)721 static void ti_cursor_off(win, ri)
722 Window win;
723 struct ti_info *ri;
724 /*
725  * Draws the cursor for the window.  Uses pixel `pix'.
726  */
727 {
728     XFillRectangle(t_disp, win,
729 		   set_gc(win, back_pix, back_pix, norm_font->fid, 0),
730 		   ri->curxval + TI_HPAD + TI_CRSP, TI_VPAD,
731 		   (ri->focus_flag ? 2 : 1),
732 		   norm_font->ascent + norm_font->descent - 1);
733 }
734 
ti_draw(win,ri,c_flag)735 static void ti_draw(win, ri, c_flag)
736 Window win;
737 struct ti_info *ri;
738 int c_flag;
739 /*
740  * Draws the indicated text widget.  This includes drawing the
741  * text and cursor.  If `c_flag' is set,  the window will
742  * be cleared first.
743  */
744 {
745     if (c_flag) XClearWindow(t_disp, win);
746     /* Text */
747     XDrawImageString(t_disp, win,
748 		     set_gc(win, norm_pix, back_pix, norm_font->fid, 0),
749 		     TI_HPAD, TI_VPAD+norm_font->ascent,
750 		     ri->text, strlen(ri->text));
751     /* Cursor */
752     ti_cursor_on(win, ri);
753 }
754 
ti_line(win,ri,pix)755 static void ti_line(win, ri, pix)
756 Window win;
757 struct ti_info *ri;
758 unsigned long pix;
759 /*
760  * Draws a status line beneath the text in a text widget to indicate
761  * the user has moved into the text field.
762  */
763 {
764     XDrawLine(t_disp, win,
765 	      set_gc(win, pix, back_pix, norm_font->fid, 0),
766 	      TI_HPAD, ri->line_y, TI_HPAD+ri->line_w, ri->line_y);
767 }
768 
769 /* For debugging */
focus_evt(evt)770 focus_evt(evt)
771 XEvent *evt;
772 {
773     switch (evt->xfocus.mode) {
774     case NotifyNormal:
775 	printf("NotifyNormal");
776 	break;
777     case NotifyGrab:
778 	printf("NotifyGrab");
779 	break;
780     case NotifyUngrab:
781 	printf("NotifyUngrab");
782 	break;
783     }
784     printf(", detail = ");
785     switch (evt->xfocus.detail) {
786     case NotifyAncestor:
787 	printf("NotifyAncestor");
788 	break;
789     case NotifyVirtual:
790 	printf("NotifyVirtual");
791 	break;
792     case NotifyInferior:
793 	printf("NotifyInferior");
794 	break;
795     case NotifyNonlinear:
796 	printf("NotifyNonLinear");
797 	break;
798     case NotifyNonlinearVirtual:
799 	printf("NotifyNonLinearVirtual");
800 	break;
801     case NotifyPointer:
802 	printf("NotifyPointer");
803 	break;
804     case NotifyPointerRoot:
805 	printf("NotifyPointerRoot");
806 	break;
807     case NotifyDetailNone:
808 	printf("NotifyDetailNone");
809 	break;
810     }
811     printf("\n");
812 }
813 
814 
815 
ti_h(evt,info)816 static xtb_hret ti_h(evt, info)
817 XEvent *evt;
818 xtb_data info;
819 /*
820  * Handles text input events.
821  */
822 {
823     Window win = evt->xany.window;
824     struct ti_info *ri = (struct ti_info *) info;
825     char keys[MAXKEYS], textcopy[MAXCHBUF];
826     xtb_hret rtn;
827     int nbytes, i;
828 
829     switch (evt->type) {
830     case Expose:
831 	ti_draw(win, ri, 0);  rtn = XTB_HANDLED;
832 	break;
833     case KeyPress:
834 	nbytes = XLookupString(&evt->xkey, keys, MAXKEYS,
835 			       (KeySym *) 0, (XComposeStatus *) 0);
836 	for (i = 0;  i < nbytes;  i++) {
837 	    (void) strcpy(textcopy, ri->text);
838 	    if ((rtn = (*ri->func)(win, (int) keys[i],
839 				   textcopy, ri->val)) == XTB_STOP)
840 	      break;
841 	}
842 	break;
843     case FocusIn:
844 focus_evt(evt);
845 	if (evt->xfocus.detail != NotifyPointer) {
846 	    ti_cursor_off(win, ri);
847 	    ri->focus_flag = 1;
848 	    ti_cursor_on(win, ri);
849 	}
850 	break;
851     case FocusOut:
852 focus_evt(evt);
853 	if (evt->xfocus.detail != NotifyPointer) {
854 	    ti_cursor_off(win, ri);
855 	    ri->focus_flag = 0;
856 	    ti_cursor_on(win, ri);
857 	}
858 	break;
859     case EnterNotify:
860 	ti_line(win, ri, norm_pix);  rtn = XTB_HANDLED;
861 	break;
862     case LeaveNotify:
863 	ti_line(win, ri, back_pix);  rtn = XTB_HANDLED;
864 	break;
865     case ButtonPress:
866 	/* Wait for release */
867 	break;
868     case ButtonRelease:
869 	/* Set input focus */
870 	XSetInputFocus(t_disp, win, RevertToParent, CurrentTime);
871 	break;
872     default:
873 	rtn = XTB_NOTDEF;
874 	break;
875     }
876     return rtn;
877 }
878 
xtb_ti_new(win,text,maxchar,func,val,frame)879 void xtb_ti_new(win, text, maxchar, func, val, frame)
880 Window win;			/* Parent window      */
881 char *text;			/* Initial text       */
882 int maxchar;			/* Maximum characters */
883 FNPTR( func, xtb_hret, (Window, int, char *, xtb_data *) ); /* Callback */
884 xtb_data val;			/* User data          */
885 xtb_frame *frame;		/* Returned size      */
886 /*
887  * This routine creates a new editable text widget under `win'
888  * with the initial text `text'.  The widget contains only
889  * one line of text which cannot exceed `maxchar' characters.
890  * The size of the widget is returned in `frame'.  Each
891  * time a key is pressed in the window,  `func' will be called
892  * with the window, the character, a copy of the text, and `val'.
893  * The state of the widget can be changed by the routines below.
894  * May set window to zero if the maximum overall character width
895  * (MAXCHBUF) is exceeded.
896  */
897 {
898     struct ti_info *info;
899 
900     if (maxchar >= MAXCHBUF) {
901 	frame->win = (Window) 0;
902 	return;
903     }
904     frame->width = XTextWidth(norm_font, "8", 1) * maxchar + 2*TI_HPAD;
905     frame->height = norm_font->ascent + norm_font->descent + TI_VPAD + TI_LPAD;
906     frame->x_loc = frame->y_loc = 0;
907     frame->win = XCreateSimpleWindow(t_disp, win, 0, 0,
908 				     frame->width, frame->height, TI_BRDR,
909 				     norm_pix, back_pix);
910     XSelectInput(t_disp, frame->win, ExposureMask|KeyPressMask|
911 		 EnterWindowMask|LeaveWindowMask|
912 		 FocusChangeMask|ButtonPressMask|
913 		 ButtonReleaseMask);
914     info = (struct ti_info *) malloc(sizeof(struct ti_info));
915     info->func = func;
916     info->val = val;
917     info->maxlen = maxchar;
918     if (text) (void) strcpy(info->text, text);
919     else info->text[0] = '\0';
920     info->curidx = strlen(info->text);
921     info->curxval = text_width(norm_font, info->text, info->curidx);
922     info->line_y = frame->height - 2;
923     info->line_w = frame->width - 2 * TI_HPAD;
924     info->focus_flag = 0;
925     xtb_register(frame->win, ti_h, (xtb_data) info);
926     XMapWindow(t_disp, frame->win);
927     frame->width += (2 * TI_BRDR);
928     frame->height += (2 * TI_BRDR);
929 }
930 
xtb_ti_get(win,text,val)931 void xtb_ti_get(win, text, val)
932 Window win;			/* Widget widnow  */
933 char text[MAXCHBUF];		/* Filled in text */
934 xtb_data *val;			/* User info      */
935 /*
936  * This routine returns the information associated with text
937  * widget `win'.  The text is filled into the passed buffer
938  * `text' which should be MAXCHBUF characters in size.  If
939  * `val' is non-zero,  the user supplied info is returned there.
940  */
941 {
942     struct ti_info *info = (struct ti_info *) xtb_lookup(win);
943 
944     if (val) *val = info->val;
945     (void) strcpy(text, info->text);
946 }
947 
xtb_ti_set(win,text,val)948 int xtb_ti_set(win, text, val)
949 Window win;			/* Widget window    */
950 char *text;			/* Replacement text */
951 xtb_data val;			/* User info        */
952 /*
953  * This routine sets the text of a text widget.  The widget
954  * will be redrawn.  Note:  for incremental changes,  ti_ins and
955  * ti_dch should be used.  If `val' is non-zero,  it will replace
956  * the user information for the widget.  The widget is redrawn.
957  * Will return zero if `text' is too long.
958  */
959 {
960     struct ti_info *info = (struct ti_info *) xtb_lookup(win);
961     int newlen;
962 
963     if (text) {
964 	if ((newlen = strlen(text)) >= info->maxlen) return 0;
965     } else {
966 	newlen = 0;
967     }
968     info->curidx = newlen;
969     if (text) (void) strcpy(info->text, text);
970     else info->text[0] = '\0';
971     info->curxval = text_width(norm_font, info->text, info->curidx);
972     if (val) info->val = val;
973     ti_draw(win, info, 1);
974     return 1;
975 }
976 
xtb_ti_ins(win,ch)977 int xtb_ti_ins(win, ch)
978 Window win;			/* Widget window */
979 int ch;				/* Character     */
980 /*
981  * Inserts the character `ch' onto the end of the text for `win'.
982  * Will return zero if there isn't any more room left.  Does
983  * all appropriate display updates.
984  */
985 {
986     struct ti_info *info = (struct ti_info *) xtb_lookup(win);
987     char lstr[1];
988 
989     if (info->curidx >= info->maxlen-1) return 0;
990     info->text[info->curidx] = ch;
991     info->text[info->curidx+1] = '\0';
992     /* Turn off cursor */
993     ti_cursor_off(win, info);
994     /* Text */
995     lstr[0] = (char) ch;
996     XDrawImageString(t_disp, win,
997 		     set_gc(win, norm_pix, back_pix, norm_font->fid, 0),
998 		     info->curxval+TI_HPAD, TI_VPAD+norm_font->ascent,
999 		     lstr, 1);
1000     info->curidx += 1;
1001     info->curxval += text_width(norm_font, lstr, 1);
1002     ti_cursor_on(win, info);
1003     return 1;
1004 }
1005 
xtb_ti_dch(win)1006 int xtb_ti_dch(win)
1007 Window win;			/* Widget window */
1008 /*
1009  * Deletes the character at the end of the text for `win'.  Will
1010  * return zero if there aren't any characters to delete.  Does
1011  * all appropriate display updates.
1012  */
1013 {
1014     struct ti_info *info = (struct ti_info *) xtb_lookup(win);
1015     int chw;
1016 
1017     if (info->curidx == 0) return 0;
1018     /* Wipe out cursor */
1019     ti_cursor_off(win, info);
1020     info->curidx -= 1;
1021     chw = text_width(norm_font, &(info->text[info->curidx]), 1);
1022     info->curxval -= chw;
1023     /* Wipe out character */
1024     XClearArea(t_disp, win, info->curxval+TI_HPAD, TI_VPAD,
1025 	       (unsigned int) chw + 1,
1026 	       (unsigned int) norm_font->ascent + norm_font->descent,
1027 	       False);
1028     info->text[info->curidx] = '\0';
1029     ti_cursor_on(win, info);
1030     return 1;
1031 }
1032 
xtb_ti_del(win,info)1033 void xtb_ti_del(win, info)
1034 Window win;
1035 xtb_data *info;
1036 /*
1037  * Deletes an input text widget.  User defined data is returned in `info'.
1038  */
1039 {
1040     struct ti_info *ti;
1041 
1042     if (xtb_unregister(win, (xtb_data *) &ti)) {
1043 	*info = ti->val;
1044 	free((char *) ti);
1045 	XDestroyWindow(t_disp, win);
1046     }
1047 }
1048 
1049 
1050 /*
1051  * Simple colored output frame - usually used for drawing lines
1052  */
1053 
xtb_bk_new(win,width,height,frame)1054 void xtb_bk_new(win, width, height, frame)
1055 Window win;			/* Parent window */
1056 unsigned width, height;		/* Size          */
1057 xtb_frame *frame;		/* Returned size */
1058 /*
1059  * This routine creates a new frame that displays a block
1060  * of color whose size is given by `width' and `height'.
1061  * It is usually used to draw lines.  No user interaction
1062  * is defined for the frame.  The color used is the default
1063  * foreground color set in xtb_init().
1064  */
1065 {
1066     frame->x_loc = frame->y_loc = 0;
1067     frame->width = width;
1068     frame->height = height;
1069     frame->win = XCreateSimpleWindow(t_disp, win,
1070 				     frame->x_loc, frame->y_loc,
1071 				     frame->width, frame->height,
1072 				     0, norm_pix, norm_pix);
1073     XMapWindow(t_disp, frame->win);
1074 }
1075 
1076 
xtb_bk_del(win)1077 void xtb_bk_del(win)
1078 Window win;
1079 /*
1080  * Deletes a block frame.
1081  */
1082 {
1083     XDestroyWindow(t_disp, win);
1084 }
1085 
1086 
1087 
1088 
1089 /*
1090  * Formatting support
1091  */
1092 
1093 #define ERROR(msg) printf("%s\n", msg); abort();
1094 
xtb_w(w)1095 xtb_fmt *xtb_w(w)
1096 xtb_frame *w;
1097 /*
1098  * Returns formatting structure for a widget.
1099  */
1100 {
1101     xtb_fmt *ret;
1102 
1103     ret = (xtb_fmt *) malloc((unsigned) sizeof(xtb_fmt));
1104     ret->wid.type = W_TYPE;
1105     ret->wid.w = w;
1106     return ret;
1107 }
1108 
1109 VARARGS(xtb_hort, xtb_fmt *, (xtb_just just, int padding, int interspace, ...))
1110 /*
1111  * Builds a horizontal structure
1112  */
1113 {
1114     va_list ap;
1115     xtb_fmt *ret, *val;
1116 #ifdef __STDC__
1117     va_start(ap, interspace);
1118 #else
1119     xtb_just just;
1120     int padding, interspace;
1121 
1122     va_start(ap);
1123     just = va_arg(ap, xtb_just);
1124     padding = va_arg(ap, int);
1125     interspace = va_arg(ap, int);
1126 #endif
1127     ret = (xtb_fmt *) malloc((unsigned) sizeof(xtb_fmt));
1128     ret->align.type = A_TYPE;
1129     ret->align.dir = HORIZONTAL;
1130     ret->align.just = just;
1131     ret->align.padding = padding;
1132     ret->align.interspace = interspace;
1133     /* Build array of incoming xtb_fmt structures */
1134     ret->align.ni = 0;
1135     while ((val = va_arg(ap, xtb_fmt *)) != (xtb_fmt *) 0) {
1136 	if (ret->align.ni < MAX_BRANCH) {
1137 	    ret->align.items[ret->align.ni] = val;
1138 	    ret->align.ni++;
1139 	} else {
1140 	    ERROR("too many branches\n");
1141 	}
1142     }
1143     return ret;
1144 }
1145 
1146 
1147 VARARGS(xtb_vert, xtb_fmt *, (xtb_just just, int padding, int interspace, ...))
1148 /*
1149  * Builds a vertical structure
1150  */
1151 {
1152     va_list ap;
1153     xtb_fmt *ret, *val;
1154 #ifdef __STDC__
1155     va_start(ap, interspace);
1156 #else
1157     xtb_just just;
1158     int padding, interspace;
1159 
1160     va_start(ap);
1161     just = va_arg(ap, xtb_just);
1162     padding = va_arg(ap, int);
1163     interspace = va_arg(ap, int);
1164 #endif
1165     ret = (xtb_fmt *) malloc((unsigned) sizeof(xtb_fmt));
1166     ret->align.type = A_TYPE;
1167     ret->align.dir = VERTICAL;
1168     ret->align.just = just;
1169     ret->align.padding = padding;
1170     ret->align.interspace = interspace;
1171     /* Build array of incoming xtb_fmt structures */
1172     ret->align.ni = 0;
1173     while ((val = va_arg(ap, xtb_fmt *)) != (xtb_fmt *) 0) {
1174 	if (ret->align.ni < MAX_BRANCH) {
1175 	    ret->align.items[ret->align.ni] = val;
1176 	    ret->align.ni++;
1177 	} else {
1178 	    ERROR("too many branches\n");
1179 	}
1180     }
1181     return ret;
1182 }
1183 
1184 
xtb_fmt_setpos(def,x,y)1185 static void xtb_fmt_setpos(def, x, y)
1186 xtb_fmt *def;
1187 int x, y;
1188 /*
1189  * Sets all position fields of widgets in `def' to x,y.
1190  */
1191 {
1192     int i;
1193 
1194     switch (def->type) {
1195     case W_TYPE:
1196 	def->wid.w->x_loc = x;
1197 	def->wid.w->y_loc = y;
1198 	break;
1199     case A_TYPE:
1200 	for (i = 0;  i < def->align.ni;  i++) {
1201 	    xtb_fmt_setpos(def->align.items[i], x, y);
1202 	}
1203 	break;
1204     default:
1205 	ERROR("bad type");
1206     }
1207 }
1208 
1209 
xtb_fmt_addpos(def,x,y)1210 static void xtb_fmt_addpos(def, x, y)
1211 xtb_fmt *def;
1212 int x, y;
1213 /*
1214  * Adds the offset specified to all position fields of widgets in `def'.
1215  */
1216 {
1217     int i;
1218 
1219     switch (def->type) {
1220     case W_TYPE:
1221 	def->wid.w->x_loc += x;
1222 	def->wid.w->y_loc += y;
1223 	break;
1224     case A_TYPE:
1225 	for (i = 0;  i < def->align.ni;  i++) {
1226 	    xtb_fmt_addpos(def->align.items[i], x, y);
1227 	}
1228 	break;
1229     default:
1230 	ERROR("bad type");
1231     }
1232 }
1233 
xtb_fmt_hort(nd,defs,widths,heights,just,pad,inter,rw,rh)1234 static void xtb_fmt_hort(nd, defs, widths, heights, just, pad, inter, rw, rh)
1235 int nd;				/* Number of children     */
1236 xtb_fmt *defs[];		/* Definitions themselves */
1237 int widths[];			/* Widths of children     */
1238 int heights[];			/* Heights of children    */
1239 xtb_just just;			/* Justification          */
1240 int pad, inter;			/* Padding and interspace */
1241 int *rw, *rh;			/* Returned size          */
1242 /*
1243  * Formats items horizontally subject to the widths and heights
1244  * of the items passed.
1245  */
1246 {
1247     int i;
1248     int max_height = 0;
1249     int tot_width = 0;
1250     int xspot;
1251 
1252     /* Find parameters */
1253     for (i = 0;  i < nd;  i++) {
1254 	if (heights[i] > max_height) max_height = heights[i];
1255 	tot_width += widths[i];
1256     }
1257     /* Place items -- assumes center justification */
1258     xspot = pad;
1259     for (i = 0;  i < nd;  i++) {
1260 	switch (just) {
1261 	case XTB_TOP:
1262 	    xtb_fmt_addpos(defs[i], xspot, pad);
1263 	    break;
1264 	case XTB_BOTTOM:
1265 	    xtb_fmt_addpos(defs[i], xspot, max_height - heights[i] + pad);
1266 	    break;
1267 	case XTB_CENTER:
1268 	default:
1269 	    /* Everyone else center */
1270 	    xtb_fmt_addpos(defs[i], xspot, (max_height - heights[i])/2 + pad);
1271 	    break;
1272 	}
1273 	xspot += (widths[i] + inter);
1274     }
1275     /* Figure out resulting size */
1276     *rw = tot_width + (nd-1)*inter + (2 * pad);
1277     *rh = max_height + (2 * pad);
1278 }
1279 
1280 
xtb_fmt_vert(nd,defs,widths,heights,just,pad,inter,rw,rh)1281 static void xtb_fmt_vert(nd, defs, widths, heights, just, pad, inter, rw, rh)
1282 int nd;				/* Number of children     */
1283 xtb_fmt *defs[];		/* Definitions themselves */
1284 int widths[];			/* Widths of children     */
1285 int heights[];			/* Heights of children    */
1286 xtb_just just;			/* Justification          */
1287 int pad, inter;			/* Padding and interspace */
1288 int *rw, *rh;			/* Returned size          */
1289 /*
1290  * Formats items vertically subject to the widths and heights
1291  * of the items passed.
1292  */
1293 {
1294     int i;
1295     int max_width = 0;
1296     int tot_height = 0;
1297     int yspot;
1298 
1299     /* Find parameters */
1300     for (i = 0;  i < nd;  i++) {
1301 	if (widths[i] > max_width) max_width = widths[i];
1302 	tot_height += heights[i];
1303     }
1304     /* Place items -- assumes center justification */
1305     yspot = pad;
1306     for (i = 0;  i < nd;  i++) {
1307 	switch (just) {
1308 	case XTB_LEFT:
1309 	    xtb_fmt_addpos(defs[i], pad, yspot);
1310 	    break;
1311 	case XTB_RIGHT:
1312 	    xtb_fmt_addpos(defs[i], max_width - widths[i] + pad, yspot);
1313 	    break;
1314 	case XTB_CENTER:
1315 	default:
1316 	    /* Everyone else center */
1317 	    xtb_fmt_addpos(defs[i], (max_width - widths[i])/2 + pad, yspot);
1318 	    break;
1319 	}
1320 	yspot += (heights[i] + inter);
1321     }
1322     /* Figure out resulting size */
1323     *rw = max_width + (2 * pad);
1324     *rh = tot_height + (nd-1)*inter + (2 * pad);
1325 }
1326 
xtb_fmt_top(def,w,h)1327 static void xtb_fmt_top(def, w, h)
1328 xtb_fmt *def;
1329 unsigned *w, *h;
1330 /*
1331  * Recursive portion of formatter
1332  */
1333 {
1334     unsigned widths[MAX_BRANCH];
1335     unsigned heights[MAX_BRANCH];
1336     int i;
1337 
1338     switch (def->type) {
1339     case A_TYPE:
1340 	/* Formatting directive */
1341 	/* place children and determine sizes */
1342 	for (i = 0;  i < def->align.ni;  i++) {
1343 	    xtb_fmt_top(def->align.items[i], &(widths[i]), &(heights[i]));
1344 	}
1345 	/* now format based on direction */
1346 	switch (def->align.dir) {
1347 	case HORIZONTAL:
1348 	    xtb_fmt_hort(def->align.ni, def->align.items, widths, heights,
1349 			 def->align.just, def->align.padding,
1350 			 def->align.interspace, w, h);
1351 	    break;
1352 	case VERTICAL:
1353 	    xtb_fmt_vert(def->align.ni, def->align.items, widths, heights,
1354 			 def->align.just, def->align.padding,
1355 			 def->align.interspace, w, h);
1356 	    break;
1357 	default:
1358 	    ERROR("bad direction");
1359 	}
1360 	break;
1361     case W_TYPE:
1362 	/* Simple widget - return size */
1363 	*w = def->wid.w->width;
1364 	*h = def->wid.w->height;
1365 	break;
1366     default:
1367 	ERROR("bad type");
1368     }
1369 }
1370 
1371 #ifdef DEBUG
xtb_fmt_debug(def)1372 static void xtb_fmt_debug(def)
1373 xtb_fmt *def;
1374 /*
1375  * Dumps formatting structure for debugging purposes.
1376  */
1377 {
1378     int i;
1379 
1380     switch (def->type) {
1381     case W_TYPE:
1382 	printf("%d %d %d %d\n",
1383 	       def->wid.w->x_loc, def->wid.w->y_loc,
1384 	       def->wid.w->width, def->wid.w->height);
1385 	break;
1386     case A_TYPE:
1387 	for (i = 0;  i < def->align.ni;  i++) {
1388 	    xtb_fmt_debug(def->align.items[i]);
1389 	}
1390 	break;
1391     default:
1392 	ERROR("bad type");
1393     }
1394 }
1395 #endif
1396 
xtb_fmt_do(def,w,h)1397 xtb_fmt *xtb_fmt_do(def, w, h)
1398 xtb_fmt *def;
1399 unsigned *w, *h;
1400 /*
1401  * Actually does formatting
1402  */
1403 {
1404     /* First zero out all positions */
1405     xtb_fmt_setpos(def, 0, 0);
1406 
1407     /* Now call recursive portion */
1408     xtb_fmt_top(def, w, h);
1409 
1410 #ifdef DEBUG
1411     xtb_fmt_debug(def);
1412 #endif
1413     return def;
1414 }
1415 
xtb_fmt_free(def)1416 void xtb_fmt_free(def)
1417 xtb_fmt *def;
1418 /*
1419  * Frees resources associated with formatting routines
1420  */
1421 {
1422     int i;
1423 
1424     if (def->type == A_TYPE) {
1425 	for (i = 0;  i < def->align.ni;  i++) {
1426 	    xtb_fmt_free(def->align.items[i]);
1427 	}
1428     }
1429     free((char *) def);
1430 }
1431 
xtb_mv_frames(nf,frames)1432 void xtb_mv_frames(nf, frames)
1433 int nf;				/* Number of frames */
1434 xtb_frame frames[];		/* Array of frames  */
1435 /*
1436  * Moves frames to the location indicated in the frame
1437  * structure for each item.
1438  */
1439 {
1440     int i;
1441 
1442     for (i = 0;  i < nf;  i++) {
1443 	XMoveWindow(t_disp, frames[i].win, frames[i].x_loc, frames[i].y_loc);
1444     }
1445 }
1446 
1447