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