1 /*
2  *   Copyright (C) 1989-1992 Yale University
3  *
4  *   This work is distributed in the hope that it will be useful; you can
5  *   redistribute it and/or modify it under the terms of the
6  *   GNU General Public License as published by the Free Software Foundation;
7  *   either version 2 of the License,
8  *   or any later version, on the following conditions:
9  *
10  *   (a) YALE MAKES NO, AND EXPRESSLY DISCLAIMS
11  *   ALL, REPRESENTATIONS OR WARRANTIES THAT THE MANUFACTURE, USE, PRACTICE,
12  *   SALE OR
13  *   OTHER DISPOSAL OF THE SOFTWARE DOES NOT OR WILL NOT INFRINGE UPON ANY
14  *   PATENT OR
15  *   OTHER RIGHTS NOT VESTED IN YALE.
16  *
17  *   (b) YALE MAKES NO, AND EXPRESSLY DISCLAIMS ALL, REPRESENTATIONS AND
18  *   WARRANTIES
19  *   WHATSOEVER WITH RESPECT TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
20  *   INCLUDING,
21  *   BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
22  *   PARTICULAR
23  *   PURPOSE.
24  *
25  *   (c) LICENSEE SHALL MAKE NO STATEMENTS, REPRESENTATION OR WARRANTIES
26  *   WHATSOEVER TO
27  *   ANY THIRD PARTIES THAT ARE INCONSISTENT WITH THE DISCLAIMERS BY YALE IN
28  *   ARTICLE
29  *   (a) AND (b) above.
30  *
31  *   (d) IN NO EVENT SHALL YALE, OR ITS TRUSTEES, DIRECTORS, OFFICERS,
32  *   EMPLOYEES AND
33  *   AFFILIATES BE LIABLE FOR DAMAGES OF ANY KIND, INCLUDING ECONOMIC DAMAGE OR
34  *   INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER YALE SHALL BE
35  *   ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE
36  *   POSSIBILITY OF THE FOREGOING.
37  *
38  */
39 
40 /* -----------------------------------------------------------------
41 FILE:	    menus.c
42 DESCRIPTION:graphic drawing routines for handling menus
43     There are two windows of interest in this file:
44 	wS - parent window is the large TW drawing window.
45 	menuS - INT small window at the top of the large TW window.
46     The name of the menus are displayed in the menuS window but when
47     a menu is selected it is draw in the large wS window.  The
48     variables which have top in their name refer to the menuS window and
49     variable with entry in their name refer to the menu entry pixmaps
50     which are drawn in the large window.
51 CONTENTS:   TWinforMenus( )
52 	    INT TWsaveState()
53 	    TWrestoreState()
54 	    BOOL TWinitMenuWindow( menu_fields, parasite )
55 		TWMENUPTR menu_fields ;
56 		BOOL parasite ;
57 	    TWdrawMenus()
58 	    static set_window_lights( flag )
59 		BOOL flag ;
60 	    static checkwindow_lights()
61 	    INT TWcheckMouse()
62 	    TWgetPt( x, y )
63 		INT *x, *y ;
64 	    TWmessage( message )
65 		char *message ;
66 	    char *TWgetString( directions )
67 		char *directions ;
68 	    BOOL TWgetPt2( x, y )
69 		INT *x, *y ;
70 	    BOOL TWcheckExposure()
71 	    BOOL TWinterupt()
72 	    TWcheckReconfig()
73 	    TWfreeMenuWindows()
74 	    TWMENUPTR TWread_menus( filename )
75 		char *filename ;
76 	    static char *cap_item( sptr )
77 		char *sptr ;
78 	    static debug_menus( menu_field )
79 		TWMENUPTR menu_field ;
80 
81 DATE:	    Jan 25, 1989 - major rewrite of version 1.0
82 REVISIONS:  Jan 31, 1989 - added screen routines.
83 	    Feb 21, 1989 - original version of graphics routines.
84 	    Mar 16, 1989 - turned off XSync in TWinterupt - too slow.
85 	    Mar 22, 1989 - added info.h.
86 	    Mar 23, 1989 - now TWinitMenus returns a boolean value
87 		signifying whether it was sucessful.
88 	    May 10, 1989 - added parasite window properties.
89 	    May 24, 1989 - fixed TWmessage and added TWDIR environ var.
90 	    Jul 31, 1989 - fixed problem with NULL in TWgetPt2.
91 	    Aug 16, 1989 - added user defined fonts and fixed
92 		problem with TWreconfigure and TWcheckExposure so
93 		that reconfigs work properly at least in
94 		nonparasite mode.
95 	    Sep 11, 1989 - added subwindows for top menu window to make
96 		more user friendly.
97 	    Sep 16, 1989 - all debug directed to stderr.
98 	    Oct  6, 1989 - now menus can be compiled into program.
99 	    Sep 15, 1990 - made a compromise fix for TWcheckExposure.
100 	    Oct 11, 1990 - added sleep so that program won't spend much
101 		time in TWcheckMouse if nothing is going on for 10 secs.
102 	    Oct 12, 1990 - Rewrote draw routines to use 4 windows
103 		and added pixmap for fast redraws.
104 	    Oct 21, 1990 - fixed parasite resizing.
105 	    Dec 27, 1990 - fixed multiple redraws on TWcheckReconfig.
106 	    Dec 28, 1990 - worked on multiple redraws on slow nodes.
107 	    Mon Jan  7 18:17:44 CST 1991 - made SAFE_WAIT_TIME
108 		user programmable for slow machines.
109 	    Fri Jan 25 16:17:21 PST 1991 - now look for backspace
110 		or delete key when in window.
111 	    Sat Feb 16 15:34:23 EST 1991 - now set input focus for
112 		TWgetString.
113 	    Sun Feb 17 17:13:23 EST 1991 - added TWmouse_tracking
114 		routines for 3D graphics.
115 	    Thu Mar  7 01:26:56 EST 1991 - tried to fix a SUN race
116 		condition.
117 	    Thu Mar 28 14:36:22 EST 1991 - added three button mouse
118 		option.
119 	    Wed Apr 17 23:38:31 EDT 1991 - put back missing Xselect
120 		input.
121 	    Sun Apr 28 22:06:15 EDT 1991 - set colors right for
122 		reverse video.
123 	    Wed Jul 24 15:59:59 CDT 1991 - added message window timeout.
124 	    Sun Nov  3 12:53:20 EST 1991 - fixed gcc complaints.
125 	    Thu Jan 30 00:10:58 EST 1992 - made expert mode for three button
126 		mouse key.
127 	    Wed Feb 26 03:54:12 EST 1992 - added persistent windows and
128 		added dim features.
129 ----------------------------------------------------------------- */
130 
131 #ifndef NOGRAPHICS
132 
133 #include <stdio.h>
134 #include <string.h>
135 #include <unistd.h>
136 #include <X11/Xlib.h>
137 #include <X11/Xatom.h>
138 #include <X11/Xutil.h>
139 
140 #include <yalecad/base.h>
141 #include <yalecad/file.h>
142 #include <yalecad/message.h>
143 #include <yalecad/hash.h>
144 #include <yalecad/string.h>
145 #include <yalecad/debug.h>
146 #include <yalecad/draw.h>
147 #include <yalecad/colors.h>
148 #include <yalecad/timer.h>
149 #include <yalecad/time.h>
150 #include "info.h"
151 
152 #define DEFAULT_TIMEOUT      10 * 1000       /* 10 seconds to timeout on message window */
153 
154 /* data record for menu information */
155 typedef struct {
156     Window   top_window ;            /* heading window for menu */
157     Window   *window ;               /* window for each menu entry */
158     char     *name ;                 /* the name of this menu */
159     INT      xpos ;                  /* x pos of entry menu in messageW */
160     INT      name_len ;              /* name length of top menu */
161     INT      pix_len ;               /* pixlength of top menu entry */
162     INT      entry_wid ;             /* width in pix of max menu entry */
163     INT      numentries ;            /* number of entries in menu */
164     INT      *function ;             /* function number of each entry */
165     char     **entry ;               /* name of each menu entry */
166     INT      *entry_len ;            /* len of each menu entry */
167     INT      *xpos_adj ;             /* position of each menu entry str */
168     INT      width ;                 /* width of menu entry */
169     BOOL     *bool_entry ;           /* tells whether entry is boolean */
170     BOOL     *state ;                /* state of this window entry */
171     INT      *function2 ;            /* alternate function for boolean */
172     char     **entry2 ;              /* for Boolean entries */
173     INT      *xpos_adj2 ;            /* position of alternate menu entry*/
174     INT      *entry_len2 ;           /* len of each menu entry */
175     BOOL     *enabled ;              /* whether menu item is enable or not */
176 } MENUBOX, *MENUPTR ;
177 
178 static TWINFOPTR    infoS ;          /* information about main details */
179 static Display      *dpyS;           /* the display */
180 static Window       menuS;           /* the current menu window */
181 static Window       drawS;           /* the main draw window */
182 static Window       backS;           /* the backing window */
183 static Window       messageS;        /* the message display window */
184 static GC           menuGCS ;        /* graphics context for menus */
185 static GC           menuRGCS ;       /* reverse gc for turning on menus */
186 static INT          screenS ;        /* the current screen */
187 static UNSIGNED_INT backgrdS ;
188 static UNSIGNED_INT foregrdS ;
189 static INT          winwidthS ;      /* window width */
190 static MENUPTR      *menuArrayS ;    /* contains info about menus */
191 static XFontStruct  *fontinfoS ;     /* font information */
192 static Font         fontS ;          /* current font */
193 static INT          numMenuS ;       /* number of menus */
194 static INT          stepsizeS ;      /* spacing between menus in x direction */
195 static BOOL         parasiteS=FALSE; /* whether this menu init is a parasite */
196 static Pixmap       pixmapS ;        /* offscreen copy of data */
197 static BOOL         three_button_mouseS ; /* whether 3 button mouse */
198 static INT          message_timeoutS ;/* how long to wait in message window */
199 static char persistent_messageS[LRECL];/* stores persistent message */
200 static BOOL persistenceS = TRUE ;    /* whether message is persistent */
201 
202 #define MENUKEYWORD "MENU"
203 #define MENUBORDER  20               /* give menu extra pixels in width */
204 #define MENUYPOS    14               /* y position of top menu strings */
205 #define POS         5                /* start of MSG in pixels*/
206 #define WHITE       1                /* white parent gc is one in array */
207 #define BLACK       2                /* black parent gc is two in array */
208 #define CANCEL      0                /* code for cancel menu activity */
209 #define NUMWINDOWS  3                /* number of windows normally shown*/
210 #define DELETE_CH   '\177'           /* delete character */
211 #define BACKSPACE   '\010'           /* backspace character */
212 #define RETURN      '\015'           /* return charachter */
213 #define COMMENT     '#'              /* comment character in first col */
214 #define SLEEPTIME   (unsigned) 2     /* sleep for two seconds */
215 
216 /* define static functions */
217 static void set_window_lights( P1(BOOL flag) ) ;
218 static void resize_windows( P2( INT winwidth, INT winheight ) ) ;
219 static void debug_menus( P1(TWMENUPTR menu_field) ) ;
220 static void draw_persistent_message( P1(char *message) ) ;
221 
222 void TWcheckReconfig();
223 
224 /* get information from main draw routine and set it */
TWinforMenus()225 void TWinforMenus( )
226 {
227     TWINFOPTR TWgetDrawInfo() ;
228 
229     infoS = TWgetDrawInfo() ;
230     /* save display info for future use */
231     dpyS = infoS->dpy ;
232     screenS = infoS->screen ;
233     drawS = infoS->drawWindow ;
234     backS = infoS->backWindow ;
235     pixmapS = infoS->pixmap ;
236     fontinfoS = infoS->fontinfo ;
237     fontS = fontinfoS->fid ;
238     winwidthS = infoS->winwidth ;
239 
240 } /* end set StaticInfo */
241 
TWsaveState()242 INT TWsaveState()
243 {
244     /* turn off all event reporting to these windows */
245     XSelectInput(dpyS,drawS,NoEventMask) ;
246     XSelectInput(dpyS,backS,NoEventMask) ;
247     XSelectInput(dpyS,menuS,NoEventMask) ;
248     XSelectInput(dpyS,messageS,NoEventMask) ;
249     set_window_lights( FALSE ) ;
250     /* next flush event queue by calling XSync with discard true */
251     XSync( dpyS, TRUE ) ;
252     return( (INT) backS ) ;
253 } /* end TWgetWindowId */
254 
TWrestoreState()255 void TWrestoreState()
256 {
257     long event_mask ;  /* used to set input selection to window */
258     XWindowAttributes wattr;  /* get the window attributes */
259 
260     /* restore normal state to all the windows */
261     event_mask = ButtonPressMask ;
262     XSelectInput(dpyS,menuS,event_mask);
263     event_mask = StructureNotifyMask | SubstructureNotifyMask
264 	    | VisibilityChangeMask ;
265     if( three_button_mouseS ){
266 	event_mask |= ButtonPressMask ;
267     }
268     XSelectInput(dpyS,backS,event_mask);
269     event_mask = ExposureMask | ButtonPressMask ;
270     XSelectInput(dpyS,drawS,event_mask);
271     XSelectInput(dpyS,messageS,NoEventMask) ;
272     set_window_lights( TRUE ) ;
273     /* next flush event queue by calling XSync with discard true */
274     XSync( dpyS, TRUE ) ;
275     /* now see if the user resized window in parasite */
276     TWinforMenus() ;
277     XGetWindowAttributes( dpyS, backS, &wattr ) ;
278     wattr.height -= 2 * MENUHEIGHT ;
279     if( wattr.width != infoS->winwidth ||
280         wattr.height != infoS->winheight ){
281 	resize_windows( wattr.width, wattr.height ) ;
282     }
283 
284 } /* end TWgetWindowId */
285 
286 /* retrieve the window information only occurs during a parasite */
TWgetWindowId(dpy,backwindow)287 Window TWgetWindowId( dpy, backwindow )
288 Display *dpy ;
289 Window backwindow ;
290 {
291     Atom menuAtom ; /* need to store menu property */
292     Atom messageAtom ; /* need to store message property */
293     Atom drawAtom ;    /* need to store draw property */
294     Atom actual ;      /* actual atom return from XGetWindowProperty */
295     char windowIdString[LRECL] ; /* buffer for window id string */
296     unsigned char *prop; /* used to retrieve the property added to window */
297     int junk1 ;
298     unsigned long junk2 ; /* ignore junk */
299     unsigned long length ; /* length of string */
300 
301     backS = backwindow ;
302     parasiteS = TRUE ; /* save for future use */
303     menuAtom    = XInternAtom( dpy, "menuWindowId", FALSE ) ;
304     messageAtom = XInternAtom( dpy, "messageWindowId", FALSE ) ;
305     drawAtom = XInternAtom( dpy, "drawWindowId", FALSE ) ;
306     /* if parasite get windows back by looking at menu and */
307     /* message properties stores in main window. Were stored */
308     /* there on creation of those windows during normal case */
309     XGetWindowProperty(dpy, backS, menuAtom, 0L, 200L, False,
310 	XA_STRING, &actual, &junk1, &junk2, &length, &prop);
311     if( !(menuS = atoi( prop ))){
312 	M( ERRMSG,"TWinitMenus","Could not find menu property\n" ) ;
313 	return( FALSE ) ;
314     }
315     XGetWindowProperty(dpy, backS, messageAtom, 0, 200, False,
316 	XA_STRING, &actual, &junk1, &junk2, &length, &prop);
317     if( !(messageS = atoi( prop ))){
318 	M( ERRMSG,"TWinitMenus","Could not find message property\n") ;
319 	return( FALSE ) ;
320     }
321     XGetWindowProperty(dpy, backS, drawAtom, 0, 200, False,
322 	XA_STRING, &actual, &junk1, &junk2, &length, &prop);
323     if( !(drawS = atoi( prop ))){
324 	M( ERRMSG,"TWinitMenus","Could not find draw property\n") ;
325 	return( FALSE ) ;
326     }
327     /* new to return draw window */
328     return( drawS ) ;
329 } /* end TWgetWindowId */
330 
331 /* perform initialization of menu windows */
TWinitMenuWindow(menu_fields)332 BOOL TWinitMenuWindow( menu_fields )
333 TWMENUPTR menu_fields ;
334 {
335     MENUPTR menuptr ;  /* temporary for speed */
336     TWMENUPTR mptr ;   /* current field of the menu fields */
337     UNSIGNED_INT white, black ;
338     INT  menu ; /* counter for menus */
339     INT  items ; /* counter for menu items */
340     INT  length ; /* length of string */
341     INT  i, j ;   /* counters */
342     INT  strwidth ; /* temp for calculating width of string in pixels */
343     INT  xpos ;      /* temp to calculate xposition of menu */
344     INT  halfstep ;       /* half the calculated stepsize */
345     INT  entry_width ;    /* size of entry pixmap in pixels */
346     INT  entry ;          /* keep count of entries in each menu */
347     long event_mask ;     /* set up event catching with this mask */
348     Atom menuAtom ; /* need to store menu property */
349     Atom messageAtom ; /* need to store message property */
350     Atom drawAtom ;    /* need to store draw property */
351     Atom actual ;      /* actual atom return from XGetWindowProperty */
352     char windowIdString[LRECL] ; /* buffer for window id string */
353     char *prop;       /* used to retrieve the property added to window */
354     INT junk1, junk2 ; /* ignore junk */
355     char *reply ;      /* reply back from Xdefaults */
356 
357     /* get static information from main draw module */
358     /* try to do crude object oriented programming */
359     TWinforMenus() ;
360 
361     black = BlackPixel(dpyS,screenS);
362     white = WhitePixel(dpyS,screenS);
363     backgrdS = black ;
364     foregrdS = white ;
365 
366     menuAtom    = XInternAtom( dpyS, "menuWindowId", FALSE ) ;
367     messageAtom = XInternAtom( dpyS, "messageWindowId", FALSE ) ;
368     drawAtom = XInternAtom( dpyS, "drawWindowId", FALSE ) ;
369     if( parasiteS == FALSE ){
370 	/* normal case - need to create menu window */
371 	menuS = XCreateSimpleWindow( dpyS, backS, 1, 1,
372 	    infoS->winwidth, MENUHEIGHT, 1L, white, backgrdS ) ;
373 
374 	/* now raise menu window so we can see it */
375 	XMapWindow( dpyS, menuS ) ;
376 
377 	/* now create a message window below main window */
378 	messageS = XCreateSimpleWindow( dpyS, backS,
379 	    1, infoS->winheight + MENUHEIGHT,
380 	    infoS->winwidth, MENUHEIGHT,1L,white,backgrdS ) ;
381 	/* now raise message window so we can see it */
382 	XMapWindow( dpyS, messageS ) ;
383 	XClearWindow( dpyS, messageS ) ;
384 
385 	/* store the windowIds of the two window so that a parasite */
386 	/* can find its way later */
387 	sprintf( windowIdString, "%d", drawS ) ; /* store as a string */
388 	XChangeProperty( dpyS, backS, drawAtom, XA_STRING, 8, PropModeAppend,
389 	    (unsigned char *) windowIdString, strlen(windowIdString) ) ;
390 	sprintf( windowIdString, "%d", menuS ) ; /* store as a string */
391 	XChangeProperty( dpyS, backS, menuAtom, XA_STRING, 8, PropModeAppend,
392 	    (unsigned char *) windowIdString, strlen(windowIdString) ) ;
393 	sprintf( windowIdString, "%d", messageS ) ;/* store as a string */
394 	XChangeProperty( dpyS, backS, messageAtom, XA_STRING, 8,
395 	    PropModeAppend, (unsigned char *) windowIdString,
396 	    strlen(windowIdString) ) ;
397     } /* end normal case */
398 
399     /* set graphic contexts */
400     menuGCS = infoS->graphicContext[WHITE] ;
401     menuRGCS = infoS->graphicContext[BLACK] ;
402 
403     /* user deliberately gave us a NULL menu so we have no more work */
404     if( !(menu_fields) ){
405 	return( TRUE ) ;
406     }
407 
408     if( XGetDefault( dpyS, GRAPHICS, "three_button_mouse" )){
409         three_button_mouseS = TRUE ;
410 	event_mask = StructureNotifyMask | SubstructureNotifyMask
411 	    | VisibilityChangeMask | ButtonPressMask ;
412 	XSelectInput(dpyS,backS,event_mask) ;
413     } else {
414         three_button_mouseS = FALSE ;
415     }
416 
417     if( reply = XGetDefault( dpyS, GRAPHICS, "message_timeout" )){
418 	/* time is in milliseconds */
419 	message_timeoutS = atoi( reply ) * 1000 ;
420     } else {
421 	message_timeoutS = DEFAULT_TIMEOUT ;
422     }
423 
424     /* count number of menus and menu items */
425     numMenuS = 0 ;
426     items = 0 ;
427     for( i=0; menu_fields[i].item ; i++ ){
428 	if( menu_fields[i].menuNotItem ){
429 	    numMenuS++ ;
430 	}
431 	items++ ;
432     }
433 
434     /* allocate memory for menu data */
435     menuArrayS = YMALLOC( numMenuS, MENUPTR ) ;
436     for( i=0; i< numMenuS; i++ ){
437 	menuArrayS[i] = YCALLOC( 1, MENUBOX ) ;
438     }
439 
440 
441     menu = -1 ;
442     for( i=0; i < items; i++ ){
443 	mptr = &(menu_fields[i]) ;
444 	if( mptr->menuNotItem ){  /* start of a new menu */
445 
446 	    /* increment menu count */
447 	    menuptr = menuArrayS[++menu] ;
448 	    /* find width of menu string in characters */
449 	    length = strlen( mptr->item ) ;
450 	    menuptr->name_len = length ;
451 	    /* find width of menu in pixels */
452 	    menuptr->pix_len =
453 		XTextWidth( fontinfoS, mptr->item, length ) ;
454 	    /* save menu name */
455 	    menuptr->name = Ystrclone( mptr->item ) ;
456 
457 	} else if( menu >= 0 ){ /* avoid obvious error if menu -1 */
458 	    /* add to number of entries */
459 	    menuArrayS[menu]->numentries++ ;
460 	    /* find maximum length of entries of this menu */
461 	    length  = strlen( mptr->item ) ;
462 	    strwidth = XTextWidth( fontinfoS, mptr->item, length ) ;
463 	    menuArrayS[menu]->entry_wid =
464 		MAX( menuArrayS[menu]->entry_wid, strwidth ) ;
465 
466 	    if( mptr->bool_item ){ /* also check the complement */
467 		length  = strlen( mptr->bool_item ) ;
468 		strwidth = XTextWidth( fontinfoS,mptr->bool_item,length );
469 		menuArrayS[menu]->entry_wid =
470 		    MAX( menuArrayS[menu]->entry_wid, strwidth ) ;
471 	    }
472 	}
473     }
474     if( numMenuS < 0 || numMenuS != ++menu ){
475 	M( ERRMSG, "initMenus", "Problems with menu array\n" ) ;
476 	return( FALSE ) ;
477     }
478 
479     /* first calculate position of the menus based on equal spacing */
480     stepsizeS = winwidthS / numMenuS ;
481     halfstep = stepsizeS / 2 ;
482     xpos = halfstep ;  /* placement of first menu */
483 
484     /* build menus */
485     menu = -1 ;
486     for( i=0; i < items; i++ ){
487 	mptr = &(menu_fields[i]) ;
488 
489 	if( mptr->menuNotItem ){  /* start of a new menu */
490 	    /* increment menu count */
491 	    menuptr = menuArrayS[++menu] ;
492 	    /* save where to draw menu title in menu window */
493 	    menuptr->xpos = halfstep - menuptr->pix_len / 2 ;
494 	    menuptr->width = entry_width = menuptr->entry_wid +
495 		MENUBORDER ;
496 
497 	    /* create a top subwindow */
498 	    menuptr->top_window = XCreateSimpleWindow( dpyS, menuS,
499 		    xpos - halfstep, 0,
500 		    stepsizeS, MENUHEIGHT, 0L, black, backgrdS ) ;
501 	    /* now raise window so we can see it */
502 	    XMapWindow( dpyS, menuptr->top_window ) ;
503 
504 	    /* set the events for top subwindow */
505 	    event_mask = EnterWindowMask | LeaveWindowMask ;
506 	    XSelectInput(dpyS,menuptr->top_window,event_mask) ;
507 
508 
509 	    /* create an array of simple windows for menus */
510 	    menuptr->window = YMALLOC( menuptr->numentries, Window ) ;
511 	    for( j=0; j< menuptr->numentries; j++ ){
512 		menuptr->window[j] = XCreateSimpleWindow( dpyS, backS,
513 		    xpos - menuptr->width / 2,
514 		    (j+1) * MENUHEIGHT,
515 		    entry_width,
516 		    MENUHEIGHT, 1L, black, backgrdS ) ;
517 	    }
518 
519 	    /* now create entry array for each menu entry string */
520 	    menuptr->entry = YMALLOC( menuptr->numentries, char * ) ;
521 	    /* now create function array for each entry window */
522 	    menuptr->function = YMALLOC( menuptr->numentries, INT ) ;
523 	    /* now create adjusted position array for each menu entry */
524 	    menuptr->xpos_adj = YMALLOC( menuptr->numentries, INT ) ;
525 	    /* now create name len array for each menu entry */
526 	    menuptr->entry_len = YMALLOC( menuptr->numentries, INT ) ;
527 	    /* now create enabled array for each entry window */
528 	    menuptr->enabled = YMALLOC( menuptr->numentries, BOOL ) ;
529 
530 	    /* now create second version of arrays for Boolean */
531 	    /* complementary state */
532 	    menuptr->bool_entry = YMALLOC( menuptr->numentries, BOOL ) ;
533 	    menuptr->state = YMALLOC( menuptr->numentries, BOOL ) ;
534 	    menuptr->entry2 = YMALLOC( menuptr->numentries, char * ) ;
535 	    menuptr->function2 = YCALLOC( menuptr->numentries, INT ) ;
536 	    menuptr->xpos_adj2 = YMALLOC( menuptr->numentries, INT ) ;
537 	    /* now create name len array for each menu entry */
538 	    menuptr->entry_len2 = YMALLOC( menuptr->numentries, INT ) ;
539 	    entry = 0 ; /* reset entry */
540 	    /* now update position of next menu */
541 	    xpos += stepsizeS ;
542 
543 	} else {
544 
545 	    length = strlen( mptr->item ) ;
546 	    /* save string in array */
547 	    menuptr->entry[entry] = Ystrclone( mptr->item ) ;
548 	    /* save string len in array */
549 	    menuptr->entry_len[entry] = length ;
550 	    /* save function number - last token */
551 	    menuptr->function[entry] = mptr->action_index ;
552 	    menuptr->enabled[entry] = TRUE ;
553 
554 	    strwidth = XTextWidth( fontinfoS, mptr->item, length ) ;
555 	    /* save where to draw string */
556 	    menuptr->xpos_adj[entry] = (menuptr->width-strwidth) / 2 ;
557 	    if( mptr->bool_item ){
558 		menuptr->bool_entry[entry] = TRUE ;
559 		length  = strlen( mptr->bool_item ) ;
560 		/* save string in array */
561 		menuptr->entry2[entry] = Ystrclone( mptr->bool_item ) ;
562 		/* save string len in array */
563 		menuptr->entry_len2[entry] = length ;
564 		/* save function number - last token */
565 		menuptr->function2[entry] = mptr->action_indexb ;
566 		strwidth = XTextWidth( fontinfoS,mptr->bool_item,length );
567 		/* save where to draw string */
568 		menuptr->xpos_adj2[entry] =
569 		    (menuptr->width - strwidth) / 2 ;
570 		/* set initial state 1 means first entry set active */
571 		menuptr->state[entry] = mptr->bool_init ;
572 
573 	    } else { /* number of tokens == 2 */
574 		menuptr->bool_entry[entry] = FALSE ;
575 	    }
576 	    /* increment entry for next string */
577 	    entry++ ;
578 	}
579 
580     } /* end for loop */
581 
582     /* now enable it so we can see mouse button in this window */
583     event_mask = ButtonPressMask ;
584     XSelectInput(dpyS,menuS,event_mask);
585 
586     /* sucessful if we got to here */
587     return( TRUE ) ;
588 
589 
590 } /* end TWinitMenuWindow */
591 
TWdrawMenus()592 void TWdrawMenus()
593 {
594     INT i ;
595     MENUPTR menuptr ;
596 
597     XClearWindow( dpyS, menuS ) ;
598     for( i = 0; i< numMenuS ; i++ ){
599 	menuptr = menuArrayS[i] ;
600 	XClearWindow( dpyS, menuptr->top_window ) ;
601 	XDrawString( dpyS, menuptr->top_window, menuGCS,
602 	    menuptr->xpos, MENUYPOS,
603 	    menuptr->name, menuptr->name_len ) ;
604     }
605     XFlush( dpyS ) ;
606 
607 } /* end TWdrawMenus */
608 
609 /* turn top window entering and leaving lights */
set_window_lights(flag)610 static void set_window_lights( flag )
611 BOOL flag ;
612 {
613     INT i ;            /* window counter */
614     MENUPTR menuptr ;  /* pointer to current window */
615     long event_mask ;  /* used to set input selection to window */
616 
617     if( flag ){
618 	/* turn on menu subwindows */
619 	event_mask = EnterWindowMask | LeaveWindowMask ;
620 	for( i = 0; i< numMenuS ; i++ ){
621 	    menuptr = menuArrayS[i] ;
622 	    XSelectInput(dpyS,menuptr->top_window,event_mask) ;
623 	}
624     } else {
625 	/* turn off menu subwindows */
626 	for( i = 0; i< numMenuS ; i++ ){
627 	    menuptr = menuArrayS[i] ;
628 	    XSelectInput(dpyS,menuptr->top_window,NoEventMask) ;
629 	}
630     }
631 } /* end set_window_lights */
632 
633 /* draw whether cursor is entering window */
checkwindow_lights()634 static BOOL checkwindow_lights()
635 {
636     long event_mask ;  /* used to set input selection to window */
637     INT i ;            /* window counter */
638     MENUPTR menuptr ;  /* menu pointer */
639     Window win ;       /* match window */
640     BOOL foundWindow;  /* flag to match window */
641     XEvent event ;     /* describes entering or leaving event */
642 
643     event_mask = EnterWindowMask | LeaveWindowMask ;
644     foundWindow = FALSE ;
645 
646     if( XCheckMaskEvent( dpyS, event_mask, &event ) ){
647 	switch( event.type ){
648 	case EnterNotify:
649 	    /* light up window */
650 	    /* find window match */
651 	    win = event.xcrossing.window ;
652 	    foundWindow = FALSE ;
653 	    for( i = 0; i < numMenuS; i++ ){
654 		if( win == menuArrayS[i]->top_window ){
655 		    menuptr = menuArrayS[i] ;
656 		    foundWindow = TRUE ;
657 		    break ;
658 		}
659 	    } /* end search for window */
660 
661 	    if( foundWindow ){ /* a match light up window */
662 		XFillRectangle( dpyS,win, menuGCS,
663 		    2,2,
664 		    stepsizeS-2, MENUHEIGHT-4 ) ;
665 		XDrawImageString( dpyS, win, menuRGCS,
666 		    menuptr->xpos, MENUYPOS,
667 		    menuptr->name, menuptr->name_len ) ;
668 	    }
669 	    break ;
670 
671 	case LeaveNotify:
672 	    /* turn off window */
673 	    /* find window match */
674 	    win = event.xcrossing.window ;
675 	    foundWindow = FALSE ;
676 	    for( i = 0; i < numMenuS; i++ ){
677 		if( win == menuArrayS[i]->top_window ){
678 		    menuptr = menuArrayS[i] ;
679 		    foundWindow = TRUE ;
680 		    break ;
681 		}
682 	    } /* end search for window */
683 
684 	    if( foundWindow ){ /* turn off window */
685 		XClearWindow( dpyS, win ) ;
686 		XDrawString( dpyS, win, menuGCS,
687 		    menuptr->xpos, MENUYPOS,
688 		    menuptr->name, menuptr->name_len ) ;
689 	    }
690 	    break ;
691 	} /* end switch */
692     }
693     return( foundWindow ) ;
694 } /* end checkwindow_lights */
695 
696 
697 /* check to see mouse button was click.  If true put up appropriate */
698 /* menu and return value to user */
TWcheckMouse()699 INT TWcheckMouse()
700 {
701     BOOL foundWindow ;      /* used in window search to find match */
702     XEvent event ;          /* describes button event */
703     INT i ;                 /* menu desired by user */
704     INT x ;                 /* pixel location button was pushed */
705     INT menu_requested ;    /* the menu the user requested */
706     long event_mask ;       /* setup menus */
707     Window win ;            /* temporary for selected menu window */
708     MENUPTR menuptr ;       /* temporary for selected menu record */
709     BOOL press ;            /* tells whether button has been pushed */
710     GC menu_GC ;            /* normal menu graphics context */
711     GC reverse_menuGC ;     /* reverse menu context */
712     static INT last_timeL=0;/* the last time we interupted */
713     static INT last_commandL = CANCEL ; /* the last command issued */
714     static INT countL = 0 ; 		/* the last command issued */
715 
716     INT cur_time ;          /* the current time since start of process */
717 
718     /* now avoid looking for interuptions all the time */
719     /* it take too much time*/
720     Ytimer_elapsed( &cur_time ) ;
721     if( cur_time - last_timeL > 10000 ){
722 	sleep( (UNSIGNED_INT) 1 ) ;
723     }
724 
725     /* always set window lights on in this routine */
726     set_window_lights( TRUE ) ;
727 
728     /* always check for window reconfiguration calls */
729     TWcheckReconfig() ;
730 
731     if( checkwindow_lights() ){
732 	last_timeL = cur_time ;
733     }
734 
735     /* check if there is any mouse activity */
736     if( three_button_mouseS ){
737 
738 	press = XCheckMaskEvent( dpyS, ButtonPressMask,&event ) ;
739 	D( "TWcheckMouse",
740 	    if( press ){
741 		fprintf( stderr, "window = %d\n", event.xbutton.window ) ;
742 	    }
743 	) ;
744 	if(!(press)){
745 	    /* nothin' shakin' */
746 	    return( CANCEL ) ;
747 	} else if( event.xbutton.window != menuS ){
748 	    if( event.xbutton.button == 2 ){
749 		if( last_commandL != CANCEL ){
750 		    TWmessage( "Repeating last command..." ) ;
751 		    if( ++countL <= 3 ){
752 			(VOID) sleep( (unsigned) 2 ) ;
753 		    }
754 		    return( last_commandL ) ;
755 		}
756 	    }
757 	    /* nothin' shakin' */
758 	    return( CANCEL ) ;
759 	}
760     } else {
761 	/* a one button mouse */
762 	press = XCheckTypedWindowEvent( dpyS,menuS,ButtonPress,&event ) ;
763 	if(!(press)){
764 	    /* nothin' shakin' */
765 	    return( CANCEL ) ;
766 	}
767     }
768     last_timeL = cur_time ;
769 
770     /* ****** otherwise process the mouse button press ******** */
771     D( "TWcheckMouse",
772 	fprintf( stderr,"Button event-button:%d\n",event.xbutton.button);
773     ) ;
774 
775     /* now disable top menu so we cant get false clicks */
776     event_mask = NoEventMask ;
777     XSelectInput(dpyS,menuS,event_mask);
778 
779     /* now disable main window clicks so we cant get false clicks */
780     event_mask = NoEventMask ;
781     XSelectInput(dpyS,drawS,event_mask) ;
782 
783     /* now draw menus */
784     TWdrawMenus() ;
785 
786     /* determine which menu has been selected */
787     x = event.xbutton.x ;
788     i = x / stepsizeS ;
789     /* make sure we are in range */
790     if( i >= numMenuS ){
791 	i = numMenuS - 1 ;
792     }
793     /* pick window and menu for speed */
794     menuptr = menuArrayS[i] ;
795 
796     /* show all windows for this menu and initialize input selection*/
797     /* next draw the menu entry string */
798     event_mask = ButtonPressMask | EnterWindowMask | LeaveWindowMask ;
799     for( i = 0 ; i < menuptr->numentries; i++ ){
800 	XMapRaised( dpyS, menuptr->window[i] ) ;
801 	XSelectInput(dpyS,menuptr->window[i],event_mask);
802 	XClearWindow( dpyS, menuptr->window[i] ) ;
803 	/* check to see if we have a boolean menu entry */
804 	if( menuptr->enabled[i] ){
805 	    menu_GC = menuGCS ;
806 	} else {
807 	    menu_GC = infoS->graphicContext[TWGRAY] ;
808 	}
809 	if( menuptr->bool_entry[i] ){
810 	    /* see what state we are in */
811 	    if( menuptr->state[i] ){
812 		/* always draw what to change to */
813 		XDrawString( dpyS, menuptr->window[i], menu_GC,
814 		    menuptr->xpos_adj2[i], MENUYPOS,
815 		    menuptr->entry2[i], menuptr->entry_len2[i] ) ;
816 	    } else {  /* draw the complement */
817 		XDrawString( dpyS, menuptr->window[i], menu_GC,
818 		    menuptr->xpos_adj[i], MENUYPOS,
819 		    menuptr->entry[i], menuptr->entry_len[i] ) ;
820 	    }
821 	} else { /* regular menu entry */
822 	    XDrawString( dpyS, menuptr->window[i], menu_GC,
823 		menuptr->xpos_adj[i], MENUYPOS,
824 		menuptr->entry[i], menuptr->entry_len[i] ) ;
825 	}
826     }
827     /* now draw menus */
828     XFlush( dpyS ) ;
829 
830     /* now look for button press */
831     press = FALSE ;
832     menu_requested = -1 ;
833 
834     while(!(press )){
835 	if( XCheckMaskEvent( dpyS, event_mask, &event ) ){
836 	    switch( event.type ){
837 	    case ButtonPress:
838 		/* how we exit */
839 		win = event.xbutton.window ; /* window event occurred */
840 		for( i = 0; i < menuptr->numentries; i++ ){
841 		    if( win == menuptr->window[i] && menuptr->enabled[i] ){
842 			menu_requested = i ;
843 			press = TRUE ;
844 		    }
845 		}
846 		break ;
847 	    case EnterNotify:
848 		/* light up window */
849 		/* find window match */
850 		win = event.xcrossing.window ;
851 		foundWindow = FALSE ;
852 		for( i = 0; i < menuptr->numentries; i++ ){
853 		    if( win == menuptr->window[i] ){
854 			/* a match if enabled */
855 			foundWindow = TRUE ;
856 			break ;
857 		    }
858 		} /* end search for window */
859 
860 
861 		if( foundWindow ){ /* a match - light up window */
862 		    if( menuptr->enabled[i] ){
863 			menu_GC = menuGCS ;
864 			reverse_menuGC = menuRGCS ;
865 		    } else {
866 			menu_GC = infoS->graphicContext[TWGRAY] ;
867 			reverse_menuGC = infoS->graphicContext[TWGRAY] ;
868 		    }
869 		    XFillRectangle( dpyS,event.xcrossing.window,
870 			menu_GC,
871 			0,0,menuptr->width,MENUHEIGHT ) ;
872 		    /* check for boolean entry */
873 		    if( menuptr->bool_entry[i] ){
874 			/* see what state we are in */
875 			if( menuptr->state[i] ){
876 			    /* always draw what to change to */
877 			    XDrawImageString( dpyS, menuptr->window[i],
878 				reverse_menuGC,
879 				menuptr->xpos_adj2[i], MENUYPOS,
880 				menuptr->entry2[i],
881 				menuptr->entry_len2[i]) ;
882 			} else {  /* draw the complement */
883 			    XDrawImageString( dpyS, menuptr->window[i],
884 				reverse_menuGC, menuptr->xpos_adj[i], MENUYPOS,
885 				menuptr->entry[i],menuptr->entry_len[i]) ;
886 			}
887 		    } else { /* regular menu entry */
888 			XDrawImageString( dpyS, menuptr->window[i],
889 			    reverse_menuGC, menuptr->xpos_adj[i], MENUYPOS,
890 			    menuptr->entry[i], menuptr->entry_len[i] ) ;
891 		    }
892 		}
893 		break ;
894 
895 	    case LeaveNotify:
896 		/* turn off window */
897 		/* find window match */
898 		win = event.xcrossing.window ;
899 		foundWindow = FALSE ;
900 		for( i = 0; i < menuptr->numentries; i++ ){
901 		    if( win == menuptr->window[i] ){
902 			foundWindow = TRUE ;
903 			break ;
904 		    }
905 		} /* end search for window */
906 
907 		if( foundWindow ){ /* turn off window */
908 		    XClearWindow( dpyS, menuptr->window[i] ) ;
909 		    /* check for boolean entry */
910 		    if( menuptr->enabled[i] ){
911 			menu_GC = menuGCS ;
912 		    } else {
913 			menu_GC = infoS->graphicContext[TWGRAY] ;
914 		    }
915 		    if( menuptr->bool_entry[i] ){
916 			/* see what state we are in */
917 			if( menuptr->state[i] ){
918 			    /* always draw what to change to */
919 			    XDrawString( dpyS, menuptr->window[i],
920 				menu_GC, menuptr->xpos_adj2[i], MENUYPOS,
921 				menuptr->entry2[i],
922 				menuptr->entry_len2[i]) ;
923 			} else {  /* draw the complement */
924 			    XDrawString( dpyS, menuptr->window[i],
925 				menu_GC, menuptr->xpos_adj[i], MENUYPOS,
926 				menuptr->entry[i],menuptr->entry_len[i]) ;
927 			}
928 		    } else { /* regular menu entry */
929 			XDrawString( dpyS, menuptr->window[i],
930 			    menu_GC, menuptr->xpos_adj[i], MENUYPOS,
931 			    menuptr->entry[i], menuptr->entry_len[i] ) ;
932 		    }
933 		}
934 		break ;
935 	    }
936 	}
937     }
938 
939     /* we got an answer unmap window and turn off events for these */
940     /* windows */
941     event_mask = NoEventMask ;
942     for( i = 0 ; i < menuptr->numentries; i++ ){
943 	XUnmapWindow( dpyS, menuptr->window[i] ) ;
944 	XSelectInput(dpyS,menuptr->window[i],event_mask);
945     }
946 
947     /* now again enable top menu so we can get clicks */
948     event_mask = ButtonPressMask ;
949     XSelectInput(dpyS,menuS,event_mask);
950 
951     /* turn on the drawing window */
952     event_mask = ExposureMask | ButtonPressMask ;
953     XSelectInput(dpyS,drawS,event_mask);
954 
955     XCopyArea( dpyS, pixmapS, drawS, menuGCS, 0L, 0L, infoS->winwidth,
956 	infoS->winheight, 0L, 0L ) ;
957 
958     /* determine which menu entry has been selected */
959     if( menu_requested >= 0 ){
960 	/* we need to set the state to complement if boolean menu */
961 	if( menuptr->bool_entry[menu_requested] ){
962 	    if( menuptr->state[menu_requested] ){
963 		/* was true change to false */
964 		menuptr->state[menu_requested] = FALSE ;
965 		last_commandL = menuptr->function2[menu_requested] ;
966 
967 		D( "TWcheckMouse",fprintf( stderr,"return %d\n",
968 		    last_commandL ) ) ;
969 		return( last_commandL ) ;
970 	    } else {
971 		/* was false change to true */
972 		menuptr->state[menu_requested] = TRUE ;
973 		last_commandL = menuptr->function[menu_requested] ;
974 		D( "TWcheckMouse",fprintf( stderr, "return %d\n",
975 		    last_commandL ) ) ;
976 		return( last_commandL ) ;
977 	    }
978 	}
979 	last_commandL = menuptr->function[menu_requested] ;
980 	D( "TWcheckMouse",
981 	    fprintf( stderr, "return %d\n", last_commandL ) ) ;
982 	return( last_commandL ) ;
983     }
984 
985     /* outside windows return cancel */
986     return( CANCEL ) ;
987 
988 } /* end TWcheckMouse */
989 
TWdisableMenu(menu_item)990 void TWdisableMenu( menu_item )
991 INT menu_item ;
992 {
993     INT      menu ;            /* counter */
994     INT      entry ;           /* counter */
995     MENUPTR menuptr ;          /* temporary for selected menu record */
996 
997     for( menu = 0 ; menu < numMenuS; menu++ ){
998 	menuptr = menuArrayS[menu] ;
999 	for( entry = 0 ; entry < menuptr->numentries; entry++ ){
1000 	    if( menu_item == menuptr->function[entry] ){
1001 		menuptr->enabled[entry] = FALSE ;
1002 		return ;
1003 	    }
1004 	    if( menu_item == menuptr->function2[entry] ){
1005 		menuptr->enabled[entry] = FALSE ;
1006 		return ;
1007 	    }
1008 	}
1009     }
1010 } /* end TWdisableMenu() */
1011 
TWenableMenu(menu_item)1012 void TWenableMenu( menu_item )
1013 INT menu_item ;
1014 {
1015     INT      menu ;            /* counter */
1016     INT      entry ;           /* counter */
1017     MENUPTR menuptr ;          /* temporary for selected menu record */
1018 
1019     for( menu = 0 ; menu < numMenuS; menu++ ){
1020 	menuptr = menuArrayS[menu] ;
1021 	for( entry = 0 ; entry < menuptr->numentries; entry++ ){
1022 	    if( menu_item == menuptr->function[entry] ){
1023 		menuptr->enabled[entry] = TRUE ;
1024 		return ;
1025 	    }
1026 	    if( menu_item == menuptr->function2[entry] ){
1027 		menuptr->enabled[entry] = TRUE ;
1028 		return ;
1029 	    }
1030 	}
1031     }
1032 } /* end TWenableMenu() */
1033 
TWgetPt(x,y)1034 void TWgetPt( x, y )
1035 INT *x, *y ;
1036 {
1037     BOOL press ;            /* tells whether button has been pushed */
1038     XEvent event ;          /* describes button event */
1039     INT xtemp, ytemp ;      /* pixel location button was pushed */
1040     long event_mask ;       /* setup menus */
1041 
1042     /* turn on event mask for main drawing window - known as drawS */
1043     event_mask = ExposureMask | ButtonPressMask ;
1044     XSelectInput(dpyS,drawS,event_mask);
1045 
1046     /* now disable top menu so we cant get false clicks */
1047     event_mask = NoEventMask ;
1048     XSelectInput(dpyS,menuS,event_mask);
1049 
1050     /* now look for button press */
1051     press = FALSE ;
1052     while(!(press )){
1053 	press = XCheckTypedWindowEvent( dpyS,drawS,ButtonPress,&event );
1054 	if( press ){
1055 	    /* now disable window so we can ignore extraneous clicks */
1056 	    event_mask = ExposureMask ;
1057 	    XSelectInput(dpyS,drawS,event_mask);
1058 
1059 	    /* determine which menu entry has been selected */
1060 	    xtemp = event.xbutton.x ;
1061 	    ytemp = event.xbutton.y ;
1062 	    /* account for inversion of y axis */
1063 	    ytemp = infoS->winheight - ytemp ;
1064 	    /* now reverse scale of coordinates */
1065 	    xtemp = (INT) ( (DOUBLE) xtemp / infoS->scaleFactor ) ;
1066 	    ytemp = (INT) ( (DOUBLE) ytemp / infoS->scaleFactor ) ;
1067 	    /* now apply data offset */
1068 	    *x = xtemp - infoS->xoffset ;
1069 	    *y = ytemp - infoS->yoffset ;
1070 	    D( "TWgetPt", fprintf( stderr, "pt = (%d,%d)\n", *x, *y ) ) ;
1071 	}
1072     }
1073     /* now again enable top menu so we can get clicks */
1074     event_mask = ButtonPressMask ;
1075     XSelectInput(dpyS,menuS,event_mask);
1076 
1077 } /* end TWgetPt */
1078 
TWmessage(message)1079 void TWmessage( message )
1080 char *message ;
1081 {
1082     if( persistenceS ){
1083 	if( message ){
1084 	    strcpy( persistent_messageS, message ) ;
1085 	} else {
1086 	    persistent_messageS[0] = EOS ;
1087 	}
1088     }
1089     draw_persistent_message( message ) ;
1090 
1091 } /* end TWmessage */
1092 
TWmessagePersistence(flag)1093 void TWmessagePersistence(flag)
1094 BOOL flag ;
1095 {
1096     persistenceS = flag ;
1097     if( flag ){
1098 	/* if turning on the flag again draw persistent message */
1099 	draw_persistent_message( NULL ) ;
1100     }
1101 } /* end TWmessagePersistence() */
1102 
draw_persistent_message(non_persistent_message)1103 static void draw_persistent_message( non_persistent_message )
1104 char *non_persistent_message ;
1105 {
1106     INT fwidth ; /* font width */
1107     char *message ;   /* message to output */
1108 
1109     XClearWindow( dpyS, messageS ) ;
1110     XDrawString( dpyS, messageS, infoS->graphicContext[WHITE],
1111 	POS,MENUYPOS, "MSG>", 4 ) ;
1112     if( non_persistent_message ){
1113 	message = non_persistent_message ;
1114     } else if( persistenceS && persistent_messageS[0] ){
1115 	message = persistent_messageS ;
1116     } else {
1117 	message = NULL ;
1118     }
1119     if( message ){
1120 	fwidth = XTextWidth( fontinfoS, "MSG>", 4 ) + POS ;
1121 	XDrawString( dpyS, messageS, infoS->graphicContext[WHITE],
1122 	    POS+fwidth,MENUYPOS,message,strlen(message));
1123     }
1124     XFlush( dpyS ) ;
1125 } /* end draw_persistent_message() */
1126 
TWgetString(directions)1127 char *TWgetString( directions )
1128 char *directions ;
1129 {
1130     BOOL press ;            /* tells whether keyboard has been pushed */
1131     BOOL finish ;           /* tells whether we have received a return */
1132     XEvent event ;          /* describes button event */
1133     long event_mask ;       /* setup menus */
1134     char buffer[LRECL] ;    /* used for keyboard translation */
1135     char curMsg[LRECL] ;    /* current value of message window */
1136     static char data[LRECL];/* current value of users input */
1137     KeySym keysym ;         /* return of keysym from user */
1138     XComposeStatus status ; /* where a compose key was pressed */
1139     INT strwidth ;          /* width of string in pixels */
1140     INT dataCount ;         /* number of characters in user input */
1141     INT cur_time ;          /* the current time */
1142     INT start_time ;        /* the start or last activity time */
1143 
1144     event_mask = KeyPressMask ;
1145     XSelectInput(dpyS,messageS,event_mask);
1146 
1147     TWmessage( directions ) ;
1148 
1149     /* now move pointer to line after directions to receive data */
1150     strwidth = XTextWidth( fontinfoS, directions, strlen(directions)) ;
1151     /* now warp pointer to message window */
1152     XWarpPointer( dpyS, None, messageS, 0, 0, 0, 0,
1153 	strwidth+40, MENUYPOS ) ;
1154     XSetInputFocus( dpyS, messageS, RevertToPointerRoot, CurrentTime ) ;
1155 
1156     /* initialize string buffers */
1157     data[0] = EOS ;
1158     dataCount = 0 ;
1159 
1160     /* now look for keyboard action */
1161     finish = FALSE ;
1162     /* get the starting time for timeout */
1163     Ytimer_elapsed( &start_time ) ;
1164     while(!(finish )){
1165 	press = XCheckTypedWindowEvent( dpyS,messageS,KeyPress,&event );
1166 	if( press ){
1167 	    /* initialize buffer */
1168 	    buffer[0] = EOS ;
1169 	    /* activity reset the timer */
1170 	    Ytimer_elapsed( &start_time ) ;
1171 	    /* find what the user entered */
1172 	    XLookupString( &(event.xkey), buffer,LRECL,&keysym, &status );
1173 	    buffer[1] = EOS ; /* only get one character at a time */
1174 	    D( "TWgetString",fprintf( stderr, "string:%s\n", buffer ) ) ;
1175 
1176 	    /* look to see if we got a return */
1177 	    if( buffer[0] == RETURN ){
1178 		finish = TRUE ;
1179 	    } else {
1180 		/* look for more data */
1181 		/* but first copy the data we have */
1182 		if( buffer[0] == BACKSPACE || buffer[0] == DELETE_CH ){
1183 		    /* look for backspace or delete */
1184 		    if( dataCount > 0 ){
1185 			dataCount-- ;
1186 		    }
1187 		    data[dataCount] = EOS ;
1188 
1189 		} else {
1190 		    /* save data */
1191 		    strcat( data, buffer ) ;
1192 		    dataCount += strlen( buffer ) ;
1193 		}
1194 		/* now echo to screen */
1195 		/* build current msg */
1196 		/* initialize curMsg */
1197 		curMsg[0] = EOS ;
1198 		strcat( curMsg, directions ) ;
1199 		strcat( curMsg, data ) ;
1200 		TWmessage( curMsg ) ;
1201 	    }
1202 
1203 	} else {
1204 	    /* check for no activity */
1205 	    Ytimer_elapsed( &cur_time ) ;
1206 	    if( cur_time - start_time > message_timeoutS ){
1207 		TWmessage( "No activity timeout" ) ;
1208 		data[0] = EOS ;
1209 		break ; /* jump out of while loop */
1210 	    }
1211 	}
1212     }
1213     /* now again disable message window so we dont get false info */
1214     event_mask = NoEventMask ;
1215     XSelectInput(dpyS,messageS,event_mask);
1216     XSetInputFocus( dpyS, PointerRoot, RevertToParent, CurrentTime );
1217 
1218     /* clear message window */
1219     TWmessage( NULL ) ;
1220 
1221     /* if no data was entered return NULL otherwise return data */
1222     if( data[0] == EOS ){
1223 	return( NULL ) ;
1224     } else {
1225 	return(data) ;
1226     }
1227 
1228 } /* end TWgetString() */
1229 
1230 
1231 /* TWgetPt2 allows the user to get a point from either the keyboard */
1232 /* or from the using the mouse */
1233 /* returns TRUE if entered from keyboard, false from mouse */
TWgetPt2(x,y)1234 BOOL TWgetPt2( x, y )
1235 INT *x, *y ;
1236 {
1237     BOOL press ;                /* tells whether button has been pushed */
1238     BOOL ok ;                     /* whether keyboard input is ok */
1239     BOOL method ;                 /* input is from keyboard or not? */
1240     XEvent event ;                /* describes button event */
1241     long event_mask ;             /* setup input */
1242     char **tokens;                /* for parsing keyboard data */
1243     INT numtokens ;               /* number of tokens in keyboard str */
1244     char *reply ;                 /* answer from user */
1245 
1246     /* turn on event mask for main drawing window - known as wS */
1247     event_mask = ExposureMask | ButtonPressMask ;
1248     XSelectInput(dpyS,drawS,event_mask);
1249 
1250     /* also look for events in message window */
1251     event_mask = KeyPressMask ;
1252     XSelectInput(dpyS,messageS,event_mask);
1253 
1254     /* now disable top menu so we cant get false clicks */
1255     event_mask = NoEventMask ;
1256     XSelectInput(dpyS,menuS,event_mask);
1257 
1258     /* now look for either event - button press or keyboard */
1259     press = FALSE ;
1260     while(!(press )){
1261 	/* check for user input from keyboard */
1262 	if( press=XCheckTypedWindowEvent(dpyS,messageS,KeyPress,&event)){
1263 	    /* we have an event from the keyboard */
1264 	    /* put event back on queue  and call TWgetString */
1265 	    XPutBackEvent( dpyS, &event ) ;
1266 	    ok = FALSE ;
1267 	    reply = TWgetString( "Pick or enter point:" ) ;
1268 	    while(!(ok)){
1269 		/* now we need to parse back reply */
1270 		tokens = Ystrparser( reply, ", \t\n", &numtokens );
1271 		if( numtokens == 2 ){
1272 		    *x = atoi( tokens[0] ) ;
1273 		    *y = atoi( tokens[1] ) ;
1274 		    /* now again enable top menu so we can get clicks */
1275 		    event_mask = ButtonPressMask ;
1276 		    XSelectInput(dpyS,menuS,event_mask);
1277 		    ok = TRUE ;
1278 		    method = TRUE ;
1279 		} else {
1280 		    reply = TWgetString(
1281 		    "Invalid input - please enter again! eg. 10, 20<cr>");
1282 		}
1283 	    } /* end keyboard processing loop */
1284 
1285          /* other wise - check mouse */
1286 	} else if( press = XCheckTypedWindowEvent( dpyS,drawS,
1287 		ButtonPress,&event ) ){
1288 	    /* we have an event from the pointer */
1289 	    /* put event back on queue  and call TWgetPt */
1290 	    XPutBackEvent( dpyS, &event ) ;
1291 	    TWgetPt( x, y ) ;
1292 	    method = FALSE ;
1293 	} /* otherwise continue to loop */
1294     } /* end wait loop for user response */
1295 
1296     /* now again disable message window so we dont get false info */
1297     event_mask = NoEventMask ;
1298     XSelectInput(dpyS,messageS,event_mask);
1299 
1300     /* now disable window so we can ignore extraneous clicks */
1301     event_mask = ExposureMask ;
1302     XSelectInput(dpyS,drawS,event_mask);
1303 
1304     return( method ) ;
1305 
1306 } /* end TWgetPt2 */
1307 
1308 /* start receiving events concerning mouse tracking */
TWmouse_tracking_start()1309 void TWmouse_tracking_start()
1310 {
1311     long event_mask ;         /* set events */
1312 
1313     /* turn on event mask for main drawing window - known as wS */
1314     event_mask = StructureNotifyMask | SubstructureNotifyMask
1315 	| VisibilityChangeMask | ExposureMask | ButtonPressMask |
1316 	PointerMotionMask ;
1317     XSelectInput(dpyS,drawS,event_mask);
1318 
1319 } /* end TWmouse_tracking_start */
1320 
1321 /* get the current mouse position */
1322 /* returns true if position has changed */
TWmouse_tracking_pt(INT * x,INT * y)1323 BOOL TWmouse_tracking_pt( INT *x, INT *y )
1324 {
1325     XEvent event ;            /* describes event */
1326     INT xtemp, ytemp ;        /* current position of pointer */
1327     BOOL changed ;            /* whether position has changed */
1328     static INT xoldL, yoldL;  /* position from previous call */
1329 
1330     xtemp = xoldL ;           /* restore old point */
1331     ytemp = yoldL ;           /* restore old point */
1332     while( XCheckTypedWindowEvent( dpyS,drawS, MotionNotify,&event ) ){
1333 	/* avoid to many events to screen wait 50 msec.*/
1334 	xtemp = event.xmotion.x ;
1335 	ytemp = event.xmotion.y ;
1336     } /* end while loop */
1337 
1338     if( xtemp == xoldL && ytemp == yoldL ){
1339 	/* nothing has changed */
1340 	changed = FALSE ;
1341     } else {
1342 	/* position has changed */
1343 	changed = TRUE ;
1344     }
1345     xoldL = xtemp ;     /* save current position for next call */
1346     yoldL = ytemp ;
1347 
1348     /* account for inversion of y axis */
1349     ytemp = infoS->winheight - ytemp ;
1350     /* now reverse scale of coordinates */
1351     xtemp = (INT) ( (DOUBLE) xtemp / infoS->scaleFactor ) ;
1352     ytemp = (INT) ( (DOUBLE) ytemp / infoS->scaleFactor ) ;
1353     /* now apply data offset */
1354     *x = xtemp - infoS->xoffset ;
1355     *y = ytemp - infoS->yoffset ;
1356     D( "TWmouse_tracking_pt", fprintf( stderr,"pt = (%d,%d)\n", *x, *y ));
1357     XFlush( dpyS ) ;
1358 
1359     return( changed ) ;
1360 
1361 } /* end TWmouse_tracking_pt */
1362 
TWmouse_tracking_end()1363 BOOL TWmouse_tracking_end()
1364 {
1365     long event_mask ;         /* set events */
1366     XEvent event ;            /* describes event */
1367 
1368 
1369     if( XCheckTypedWindowEvent( dpyS, drawS, ButtonPress,&event ) ){
1370 	/* turn off motion notify events for mouse */
1371 	event_mask = StructureNotifyMask | SubstructureNotifyMask
1372 	    | VisibilityChangeMask | ExposureMask | ButtonPressMask ;
1373 	XSelectInput(dpyS,drawS,event_mask);
1374 	return( TRUE ) ;
1375     } else {
1376 	return( FALSE ) ;
1377     }
1378 
1379 } /* end TWmouse_tracking_end */
1380 
1381 /* check to see if main window has been covered by another window */
TWcheckExposure()1382 BOOL TWcheckExposure()
1383 {
1384 
1385 
1386     BOOL exposed ;          /* tells whether window has been covered */
1387     XEvent event ;          /* describes event */
1388     INT time ;              /* current time */
1389     static INT lasttimeL ;  /* last time of exposure event */
1390 
1391     exposed = FALSE ;
1392     /* XSync( dpyS, FALSE ) ;*/ /* allow program to catch up */
1393 
1394     /* check if there was any exposed event activity */
1395     while( XCheckTypedWindowEvent( dpyS, drawS, Expose, &event ) ){
1396 	/* if there is more than one expose event flush from queue */
1397 	/* look at count to find only last expose event */
1398 	if( event.xexpose.count == 0 ){
1399 	    exposed = TRUE ;
1400 	}
1401     }
1402     /* window managers sometimes send us too many exposure events */
1403     /* therefore check time and make multiple exposures invalid */
1404     if( exposed ){
1405 	(void) YcurTime( &time ) ;
1406 	if( event.xexpose.send_event == True ){
1407 	    /* if we got a TWforceRedraw always redraw screen */
1408 	    lasttimeL = time ;
1409 	    D( "TWcheckExposure",
1410 		fprintf( stderr,"Exposure:f @time = %d\n",time);
1411 	    ) ;
1412 	    if( exposed ){
1413 		draw_persistent_message( NULL ) ;
1414 	    }
1415 	    return( exposed ) ;
1416 	}
1417 	if( time - lasttimeL < TWsafe_wait_timeG ){
1418 	    exposed = FALSE ;
1419 	} else {
1420 	    lasttimeL = time ;
1421 	}
1422 	D( "TWcheckExposure",
1423 	    fprintf( stderr,"Exposure:%d @time = %d\n",exposed,time);
1424 	) ;
1425     }
1426     if( exposed ){
1427 	draw_persistent_message( NULL ) ;
1428     }
1429     return( exposed ) ;
1430 } /* end TWcheckExpose */
1431 
1432 /* returns true if user has clicked in menu window */
1433 /* flushes all remaining button presses in this window */
1434 /* also sets entering and leaving window lighting for subwindows */
1435 /* if we are using TWinterupt we which to turn off menu subwindows */
TWinterupt()1436 BOOL TWinterupt()
1437 {
1438     static INT last_timeL=0; /* the last time we interupted */
1439     INT cur_time ;          /* the current time since start of process */
1440     BOOL press ;            /* tells whether button has been pushed */
1441     XEvent event ;          /* describes button event */
1442 
1443     /* now avoid looking for interuptions all the time */
1444     /* it take too much time*/
1445     Ytimer_elapsed( &cur_time ) ;
1446     if( cur_time - last_timeL < 1000 ){
1447 	return( FALSE ) ;
1448     }
1449     last_timeL = cur_time ;
1450     press = FALSE ;
1451     /* XSync( dpyS, FALSE ) ; */ /* allow program to catch up */
1452     /* check if there is any mouse activity */
1453     while( XCheckTypedWindowEvent( dpyS, menuS, ButtonPress, &event ) ){
1454 	/* if there is more than one button event flush from queue */
1455 	press = TRUE ;
1456     }
1457     set_window_lights( press ) ;
1458     return( press ) ;
1459 
1460 } /* end TWinterupt */
1461 
1462 /* update windows if configuration changes */
TWcheckReconfig()1463 void TWcheckReconfig()
1464 {
1465     INT height ;              /* height of current backing window */
1466     XEvent event ;            /* describes configuration event */
1467     INT winwidth, winheight ; /* size of window */
1468     BOOL redraw = FALSE ;     /* whether to redraw or not */
1469 
1470     height = infoS->winheight + 2 * MENUHEIGHT ;
1471     /* since all windows are children of backS only check backS */
1472     while( XCheckTypedEvent( dpyS, ConfigureNotify, &event ) ){
1473 	if( event.xconfigure.window == backS ){
1474 	    if( event.xconfigure.override_redirect ){
1475 		/* window manager is telling us to leave it alone */
1476 		continue ;
1477 	    }
1478 	    winheight = event.xconfigure.height ;
1479 	    winwidth = event.xconfigure.width ;
1480 	    if( winheight == height &&
1481 		winwidth == infoS->winwidth ){
1482 		/* nothing changed avoid the work */
1483 		continue ;
1484 	    }
1485 	    /* if window changes size need to send expose */
1486 	    /* event so you know to redraw event - this is cause */
1487 	    redraw = TRUE ;
1488 
1489 	    winheight -= 2 * MENUHEIGHT ;
1490 	    resize_windows( winwidth, winheight ) ;
1491 	}
1492     }
1493     if( redraw ){
1494 	D( "TWcheckReconfig",
1495 	    {   INT time ;
1496 		(void) YcurTime( &time ) ;
1497 		fprintf( stderr,"TWcheckReconfig redraw:@time = %d\n",
1498 		time);
1499 	    }
1500 	) ;
1501 
1502 	/* remove any exposure events */
1503 	/* ????
1504 	TWcheckExposure() ;
1505 	TWforceRedraw() ;
1506 	*/
1507     }
1508 } /* end TWcheckReconfig */
1509 
1510 
resize_windows(INT winwidth,INT winheight)1511 static void resize_windows( INT winwidth, INT winheight )
1512 {
1513     INT halfstep ;            /* menu half spacing */
1514     INT xpos ;                /* position of menu */
1515     INT i, j ;                /* counters */
1516     MENUPTR menuptr ;       /* temporary for selected menu record */
1517 
1518     /* change size of draw window */
1519     XMoveResizeWindow( dpyS, drawS,
1520 	0, MENUHEIGHT, winwidth, winheight ) ;
1521 
1522     /* create a new pixmap */
1523     /* off screen copy of the data */
1524     /* free the old one first */
1525     XFreePixmap( dpyS, pixmapS ) ;
1526     pixmapS = XCreatePixmap( dpyS, drawS,
1527 	(unsigned)winwidth, (unsigned)winheight,
1528 	XDefaultDepth(dpyS,screenS) ) ;
1529 
1530     /* change size of menu window */
1531     XMoveResizeWindow( dpyS, menuS, 1, 1,
1532 	winwidth, MENUHEIGHT ) ;
1533 
1534     /* change size of message window */
1535     /* winy takes care of border */
1536     XMoveResizeWindow( dpyS, messageS,
1537 	1, winheight + MENUHEIGHT,
1538 	winwidth, MENUHEIGHT ) ;
1539 
1540     /* tell main draw routines what has happened */
1541     TWsetDrawInfo( winheight, winwidth, pixmapS ) ;
1542 
1543     /* reposition the menu window titles */
1544     /* calculate position of the menus based on equal spacing */
1545     stepsizeS = winwidth / numMenuS ;
1546     halfstep = stepsizeS / 2 ;
1547     xpos = halfstep ;  /* placement of first menu */
1548     for( i=0;i< numMenuS; i++ ){
1549 	menuptr = menuArrayS[i] ;
1550 	/* save where to draw menu title in menu window */
1551 	menuptr->xpos = halfstep - menuptr->pix_len / 2 ;
1552 
1553 	/* fix top window */
1554 	XMoveResizeWindow( dpyS, menuptr->top_window,
1555 		xpos - halfstep, 0,
1556 		stepsizeS, MENUHEIGHT ) ;
1557 
1558 	/* move the subwindows */
1559 	for( j=0; j< menuptr->numentries; j++ ){
1560 	    XMoveResizeWindow( dpyS, menuptr->window[j],
1561 		xpos - menuptr->width / 2,
1562 		(j+1) * MENUHEIGHT,
1563 		menuptr->width,
1564 		MENUHEIGHT ) ;
1565 	}
1566 	xpos += stepsizeS ;
1567     }
1568     /* redraw menus and initialize message window */
1569     TWdrawMenus() ;
1570     TWmessage( NULL ) ;
1571 
1572 } /* end TWcheckReconfig */
1573 
1574 
TWfreeMenuWindows()1575 void TWfreeMenuWindows()
1576 {
1577     INT i, j ;              /* counters */
1578     MENUPTR menuptr ;       /* temporary for selected menu record */
1579 
1580     for( i = 0; i < numMenuS ; i++ ){
1581 	/* pick window and menu for speed */
1582 	menuptr = menuArrayS[i] ;
1583 	for( j = 0 ; j < menuptr->numentries; j++ ){
1584 	    /* would nice to be able to use XDestroySubWindows */
1585 	    /* but we would destroy the parents copy too.  Therefore */
1586 	    /* we must free window this way */
1587 	    XDestroyWindow( dpyS, menuptr->window[j] ) ;
1588 	}
1589     }
1590     /* turn off all event reporting to these windows */
1591     XSelectInput(dpyS,drawS,NoEventMask) ;
1592     XSelectInput(dpyS,backS,NoEventMask) ;
1593     XSelectInput(dpyS,menuS,NoEventMask) ;
1594     XSelectInput(dpyS,messageS,NoEventMask) ;
1595     /* next flush event queue by calling XSync */
1596     XSync( dpyS, FALSE ) ;
1597 
1598 } /* end TWfreeMenuWindow */
1599 
1600 
TWread_menus(filename)1601 TWMENUPTR TWread_menus( filename )
1602 char *filename ;
1603 {
1604     char buffer[LRECL], *bufferptr ;
1605     char **tokens ;         /* for parsing menu file */
1606     INT  numtokens ;        /* number of tokens on the line */
1607     INT  line ;             /* count lines in input file */
1608     INT  item ;             /* number of menu fields */
1609     FILE *fp ;              /* open file pointer */
1610     TWMENUPTR menu_fields;  /* array of menu information */
1611     TWMENUPTR mptr;         /* current menu item */
1612 
1613     /* parse menu file */
1614     line = 0 ;
1615     item = 0 ;
1616     fp = TWOPEN( filename, "r", ABORT ) ;
1617     while( bufferptr=fgets(buffer,LRECL,fp )){
1618 	/* parse file */
1619 	line ++ ; /* increment line number */
1620 	/* skip comments */
1621 	if( *bufferptr == COMMENT ){
1622 	    continue ;
1623 	}
1624 	tokens = Ystrparser( bufferptr, ",\t\n", &numtokens );
1625 
1626 	if( numtokens == 0 ){
1627 	    /* skip over empty lines */
1628 	    continue ;
1629 	} else if( strcmp( tokens[0], MENUKEYWORD ) == STRINGEQ){
1630 	    /* look at first field for menu keyword */
1631 	    /* there better be only two tokens on this line */
1632 	    if( numtokens != 2 ){
1633 		sprintf( YmsgG, "Syntax error on line:%d\n", line ) ;
1634 		M(ERRMSG, "TWread_menus", YmsgG ) ;
1635 	    }
1636 	    /* increment menu count */
1637 	    item++ ;
1638 	} else { /* menu item */
1639 	    if( numtokens == 2 || numtokens == 5 ){
1640 		item++ ;
1641 	    } else {
1642 		sprintf( YmsgG, "Problem parsing line:%d in menu file\n",
1643 		    line ) ;
1644 		M( ERRMSG,"TWread_menus", YmsgG ) ;
1645 	    }
1646 	}
1647     }
1648     if( item <= 0 ){
1649 	sprintf( YmsgG,"Couldn't find any menu data in file:%s\n",
1650 	    filename ) ;
1651 	M( ERRMSG,"TWread_menus", YmsgG ) ;
1652 	return( NULL ) ;
1653     }
1654 
1655     /* now allocate array */
1656     menu_fields = YCALLOC( ++item, TWMENUBOX ) ;
1657 
1658     /* reread file building menus */
1659     item = -1 ;
1660     line = 0 ;
1661     rewind( fp ) ;
1662     while( bufferptr=fgets(buffer,LRECL,fp )){
1663 	/* parse file */
1664 	line++ ;
1665 	/* skip comments */
1666 	if( *bufferptr == COMMENT ){
1667 	    continue ;
1668 	}
1669 	tokens = Ystrparser( bufferptr, ",\t\n", &numtokens );
1670 	if( numtokens == 0 ){
1671 	    /* skip over empty lines */
1672 	    continue ;
1673 	} else if( strcmp( tokens[0], MENUKEYWORD ) == STRINGEQ){
1674 	    mptr = &( menu_fields[++item] ) ;
1675 	    mptr->item = Ystrclone( tokens[1] ) ;
1676 	    mptr->bool_item = NULL ;
1677 	    mptr->bool_init = 0 ;
1678 	    mptr->menuNotItem = TRUE ;
1679 	    mptr->action_index = 0 ;
1680 	    mptr->action_indexb = 0 ;
1681 	} else if( item >=  0 ){  /* avoid obvious errors */
1682 	    if( numtokens == 2 || numtokens == 5 ){
1683 		mptr = &( menu_fields[++item] ) ;
1684 		mptr->item = Ystrclone( tokens[0] ) ;
1685 		mptr->menuNotItem = FALSE ;
1686 		mptr->action_index = atoi( tokens[1] ) ;
1687 		if( numtokens == 5 ){ /* also check the complement */
1688 		    mptr->bool_item = Ystrclone( tokens[2] ) ;
1689 		    mptr->action_indexb = atoi( tokens[3] ) ;
1690 		    /* set initial state 1 means first entry set active */
1691 		    mptr->bool_init = atoi( tokens[4] ) ;
1692 		} else { /* number of tokens == 2 */
1693 		    mptr->bool_item = NULL ;
1694 		    mptr->bool_init = 0 ;
1695 		    mptr->action_indexb = 0 ;
1696 		}
1697 	    } else {
1698 		sprintf( YmsgG, "Problem parsing line:%d in menu file\n",
1699 		    line ) ;
1700 		M( ERRMSG,"TWread_menus", YmsgG ) ;
1701 	    }
1702 	} else {
1703 	    sprintf( YmsgG, "Problem parsing line:%d in menu file\n",
1704 		line ) ;
1705 	    M( ERRMSG,"TWread_menus", YmsgG ) ;
1706 	}
1707     } /* end parsing loop */
1708 
1709     TWCLOSE( fp ) ;
1710 
1711 #ifdef DEBUG
1712     debug_menus( menu_fields ) ;
1713 #endif /* DEBUG */
1714 
1715     return( menu_fields ) ;
1716 
1717 } /* end TWread_menus */
1718 
1719 
1720 #ifdef DEBUG
1721 
1722 #include <ctype.h>
1723 
cap_item(sptr)1724 static char *cap_item( sptr )
1725 char *sptr ;
1726 {
1727     static char bufferL[LRECL] ;
1728     INT len ;                 /* string length */
1729     INT j ;                   /* counter */
1730     INT pos ;                 /* position in buffer */
1731 
1732     /* always capitialize the item */
1733     len = strlen( sptr ) ;
1734     pos = 0 ; /* beginning of string */
1735     for( j = 0 ; j < len; j++ ){
1736 	if( sptr[j] == '.' ){
1737 	    /* don't do anything */
1738 	} else if( sptr[j] == ' ' ){
1739 	    bufferL[pos++] = '_' ;
1740 	} else if( islower(sptr[j]) ){
1741 	    bufferL[pos++] = toupper(sptr[j]) ;
1742 	} else {
1743 	    /* in other cases just copy */
1744 	    bufferL[pos++] = sptr[j] ;
1745 	}
1746     }
1747     bufferL[pos] = EOS ;
1748     return( bufferL ) ;
1749 } /* end cap_item */
1750 
debug_menus(menu_field)1751 static void debug_menus( menu_field )
1752 TWMENUPTR menu_field ;
1753 {
1754     INT i ;                   /* counter */
1755     INT count ;               /* number of fields */
1756     char label[LRECL] ;       /* copy of the menu item */
1757     FILE *fp ;                /* file pointer */
1758     TWMENUPTR mptr ;        /* temporary pointer */
1759 
1760     fp = TWOPEN( "menus.h", "w", ABORT ) ;
1761 
1762     count = 0 ;
1763     for( i=0 ; menu_field[i].item ; i++ ){
1764 	count++ ;
1765     }
1766 
1767     /* write out the define statements */
1768     fprintf( fp, "\n/* TWmenu definitions */  \n" ) ;
1769     fprintf( fp, "#define TWNUMMENUS\t\t%d\n", count ) ;
1770     for( i=0 ; menu_field[i].item; i++ ){
1771 	mptr = &(menu_field[i]) ;
1772 	if(mptr->menuNotItem){
1773 	    continue ;
1774 	}
1775 	fprintf( fp, "#define %s\t\t%d\n",
1776 	    cap_item(mptr->item), mptr->action_index ) ;
1777 	if( mptr->bool_item ){
1778 	    fprintf( fp, "#define %s\t\t%d\n",
1779 		cap_item(mptr->bool_item),
1780 		mptr->action_indexb ) ;
1781 	}
1782     }
1783     fprintf( fp, "\n\n" ) ;
1784 
1785 
1786     fprintf( fp, "static TWMENUBOX menuS[%d] = {\n", count+1 ) ;
1787 
1788     for( i=0 ; menu_field[i].item; i++ ){
1789 	mptr = &(menu_field[i]) ;
1790 	fprintf( fp, "    \"%s\",", mptr->item ) ;
1791 	if( mptr->bool_item ){
1792 	    fprintf( fp, "\"%s\",", mptr->bool_item ) ;
1793 	} else {
1794 	    fprintf( fp, "0," ) ;
1795 	}
1796 	fprintf( fp, "%d,%d,%d,%d,\n",
1797 	    mptr->bool_init,mptr->menuNotItem,
1798 	    mptr->action_index, mptr->action_indexb ) ;
1799     }
1800     fprintf( fp, "    0,0,0,0,0,0\n" ) ;
1801     fprintf( fp, "} ;\n\n" ) ;
1802     TWCLOSE(fp) ;
1803 } /* end debug_dialog() */
1804 
1805 #endif /* DEBUG */
1806 
1807 #endif /* no graphics */
1808