1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design Systems
4  *
5  * File: graphunixx11.c
6  * X Window System interface with Motif/Lesstif widgets
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "database.h"
34 #include "egraphics.h"
35 #include "usr.h"
36 #include "eio.h"
37 #include "usrtrack.h"
38 #include "edialogs.h"
39 #include "config.h"
40 #include <signal.h>
41 #include <errno.h>
42 #include <pwd.h>
43 #include <sys/param.h>
44 #include <sys/stat.h>
45 #include <X11/Xlib.h>
46 #include <X11/Xutil.h>
47 #include <X11/Xatom.h>
48 #include <X11/keysym.h>
49 #include <X11/IntrinsicP.h>
50 #include <X11/Intrinsic.h>
51 #include <X11/StringDefs.h>
52 #include <X11/cursorfont.h>
53 #include <X11/Shell.h>
54 #include <Xm/Xm.h>
55 #include <Xm/BulletinB.h>
56 #include <Xm/CascadeB.h>
57 #include <Xm/CutPaste.h>
58 #include <Xm/Display.h>
59 #include <Xm/DrawingA.h>
60 #include <Xm/FileSB.h>
61 #include <Xm/Label.h>
62 #include <Xm/List.h>
63 #include <Xm/MainW.h>
64 #include <Xm/MwmUtil.h>
65 #include <Xm/Protocols.h>
66 #include <Xm/PushB.h>
67 #include <Xm/RowColumn.h>
68 #include <Xm/ScrollBar.h>
69 #include <Xm/Separator.h>
70 #include <Xm/Text.h>
71 #include <Xm/ToggleB.h>
72 #include <Xm/ToggleBG.h>
73 
74 
75 #ifdef HAVE_PTHREAD
76 #  include <pthread.h>
77 #else
78 #  include <thread.h>
79 #  include <synch.h>
80 #endif
81 
82 #ifdef TRUETYPE
83 #  include "t1lib.h"
84 #endif
85 
86 #ifdef HAVE_SYS_TYPES_H
87 #  include <sys/types.h>
88 #endif
89 
90 #ifdef HAVE_UNISTD_H
91 #  include <unistd.h>
92 #endif
93 
94 #ifdef HAVE_FCNTL_H
95 #  include <fcntl.h>
96 #endif
97 
98 #ifdef HAVE_TERMIOS_H
99 #  include <termios.h>
100 #else
101 #  ifdef HAVE_TERMIO_H
102 #    include <termio.h>
103 #  else
104 #    include <sgtty.h>
105 #  endif
106 #endif
107 
108 #ifdef TIME_WITH_SYS_TIME
109 #  include <sys/time.h>
110 #  include <time.h>
111 #else
112 #  ifdef HAVE_SYS_TIME_H
113 #    include <sys/time.h>
114 #  else
115 #    include <time.h>
116 #  endif
117 #endif
118 
119 #ifdef HAVE_SYS_TIMEB_H
120 #  include <sys/timeb.h>
121 #endif
122 
123 #ifdef HAVE_SYS_WAIT_H
124 #  include <sys/wait.h>
125 #endif
126 
127 #ifdef HAVE_VFORK_H
128 #  include <vfork.h>
129 #endif
130 
131 #ifdef HAVE_DIRENT_H
132 #  include <dirent.h>
133 #  define NAMELEN(dirent) estrlen((dirent)->d_name)
134 #else
135 #  define dirent direct
136 #  define NAMELEN(dirent) (dirent)->d_namelen
137 #  ifdef HAVE_SYS_NDIR_H
138 #    include <sys/ndir.h>
139 #  endif
140 #  ifdef HAVE_SYS_DIR_H
141 #    include <sys/dir.h>
142 #  endif
143 #  ifdef HAVE_NDIR_H
144 #    include <ndir.h>
145 #  endif
146 #endif
147 
148 #if LANGTCL
149 #  include "dblang.h"
150   Tcl_Interp *gra_tclinterp;
151   INTBIG gra_initializetcl(void);
152 #endif
153 
154 #ifdef _UNICODE
155 #  define estat     _wstat
156 #  define eaccess   _waccess
157 #  define egetcwd   _wgetcwd
158 #  define ecreat    _wcreat
159 #else
160 #  define estat     stat
161 #  define eaccess   access
162 #  define egetcwd   getcwd
163 #  define ecreat    creat
164 #endif
165 
166 #define TRUESTRCPY strcpy
167 #define TRUESTRLEN strlen
168 
169 
170 #include <sys/sysctl.h>
171 
172 /****** windows ******/
173 
174 #define WMLEFTBORDER         8					/* size of left border for windows */
175 #define WMTOPBORDER         30					/* size of top border for windows */
176 #define MAXSTATUSLINES       1					/* number of status lines */
177 #define FLUSHTICKS         120					/* ticks between display flushes */
178 #define SBARWIDTH           15					/* size of text-edit scroll bars */
179 #define PALETTEWIDTH       110
180 #define MAXLOCALSTRING     256					/* size of "gra_localstring" */
181 
182 #ifdef __cplusplus
183 #  define VisualClass(v) v->c_class
184 #else
185 #  define VisualClass(v) v->class
186 #endif
187 
188 static XtAppContext  gra_xtapp;					/* the main XT application */
189 static Display      *gra_maindpy;				/* the main X display (edit) */
190 static Display      *gra_altdpy;				/* the alternate X display (messages/other edit) */
191 static INTBIG        gra_mainscreen;
192 static INTBIG        gra_altscreen;
193 static WINDOWDISPLAY gra_mainwd;
194 static WINDOWDISPLAY gra_altwd;
195 static Colormap      gra_maincolmap;			/* main display colormap */
196 static Colormap      gra_altcolmap;				/* alternate display colormap */
197 static INTBIG        gra_mainredshift, gra_maingreenshift, gra_mainblueshift;
198 static INTBIG        gra_altredshift, gra_altgreenshift, gra_altblueshift;
199 static XSizeHints   *gra_editxsh;
200 static INTBIG        gra_editposx;
201 static INTBIG        gra_editposy;
202 static INTBIG        gra_editsizex;
203 static INTBIG        gra_editsizey;
204 static INTBIG        gra_palettewidth;
205 static INTBIG        gra_paletteheight;
206 static INTBIG        gra_palettetop;
207 static INTBIG        gra_shortestscreen;		/* height of shortest screen */
208 static UINTBIG       gra_internalchange;
209 static Pixmap        gra_programicon;
210 static INTBIG        gra_windownumberindex = 0;
211 static INTBIG        gra_windownumber;			/* number of the window that was created */
212 static BOOLEAN       gra_checkinginterrupt;		/* TRUE if checking for interrupt key */
213 static BOOLEAN       gra_tracking;				/* TRUE if tracking the cursor */
214 static INTBIG        gra_status_height;			/* space for lines at bottom of screen */
215 static WINDOWFRAME  *gra_deletethisframe = 0;	/* window that is to be deleted */
216 static Atom          gra_wm_delete_window;		/* to trap window kills */
217 static int           gra_argc;					/* "argc" for display */
218 static CHAR1       **gra_argv;					/* "argv" for display */
219 static CHAR          gra_localstring[MAXLOCALSTRING];
220 XtSignalId           gra_intsignalid;
221 extern GRAPHICS      us_box, us_ebox, us_menutext;
222 
223 #ifndef ANYDEPTH
224   static INTBIG      gra_maphigh;				/* highest entry to use in color map */
225   static BOOLEAN     gra_use_backing;			/* flag if backing store used */
226 #endif
227 static Atom        gra_movedisplayprotocol;
228 static Atom        gra_movedisplaymsg;
229 static INTBIG      gra_windowbeingdeleted = 0;
230 
231 int          gra_xerrors(Display *dpy, XErrorEvent *err);
232 void         gra_xterrors(CHAR1 *msg);
233 void         gra_adjustwindowframeon(Display *dpy, INTBIG screen, INTBIG how);
234 void         gra_finddisplays(BOOLEAN wantmultiscreen, BOOLEAN multiscreendebug);
235 BOOLEAN      gra_buildwindow(Display *dpy, WINDOWDISPLAY *wd, Colormap colmap, WINDOWFRAME *wf,
236 				BOOLEAN floating, BOOLEAN samesize, RECTAREA *r);
237 void         gra_reloadmap(void);
238 void         gra_getwindowattributes(WINDOWFRAME *wf, XWindowAttributes *xwa);
239 void         gra_getwindowinteriorsize(WINDOWFRAME *wf, INTBIG *wid, INTBIG *hei);
240 void         gra_intsignalfunc(void);
241 BOOLEAN      gra_loggetnextaction(CHAR *extramessage);
242 void         gra_logwriteaction(INTBIG inputstate, INTBIG special, INTBIG cursorx,
243 				INTBIG cursory, void *extradata);
244 void         gra_logwritecomment(CHAR *comment);
245 BOOLEAN      gra_logreadline(CHAR *string, INTBIG limit);
246 void         gra_removewindowextent(RECTAREA *r, Widget wnd);
247 BOOLEAN      gra_makewindowdisplaybuffer(WINDOWDISPLAY *wd, Display *dpy);
248 void         gra_getdisplaydepth(Display *dpy, INTBIG *depth, INTBIG *truedepth);
249 void         gra_handlequeuedframedeletion(void);
250 WINDOWFRAME *gra_getframefromindex(INTBIG index);
251 void         gra_movedisplay(Widget w, XtPointer client_data, XtPointer *call_data);
252 INTBIG       gra_nativepopuptif(POPUPMENU **menuptr, BOOLEAN header, INTBIG left, INTBIG top);
253 #ifndef ANYDEPTH
254   void       gra_loadstipple(WINDOWFRAME *wf, UINTSML raster[]);
255   void       gra_setxstate(WINDOWFRAME *wf, GC gc, GRAPHICS *desc);
256 #endif
257 
258 /****** the messages window ******/
259 #define MESLEADING              1				/* extra character spacing */
260 
261 static Display      *gra_topmsgdpy;				/* the X display for the messages widget */
262 static Window        gra_topmsgwin;				/* the X window for the messages widget */
263 static Widget        gra_msgtoplevelwidget;		/* the outer messages widget */
264 static Widget        gra_messageswidget = 0;	/* the inner messages widget */
265 static BOOLEAN       gra_messages_obscured;		/* true if messages window covered */
266 static BOOLEAN       gra_messages_typingin;		/* true if typing into messages window */
267 static BOOLEAN       gra_msgontop;				/* true if messages window has focus */
268 static Colormap      gra_messagescolormap;
269 
270 void gra_makemessageswindow(void);
271 
272 /****** the menus ******/
273 static INTBIG      gra_popupmenuresult;
274 static INTBIG      gra_pulldownmenucount = 0;	/* number of top-level pulldown menus */
275 static POPUPMENU  *gra_pulldowns[50];			/* the current top-level pulldown menus */
276 
277 Widget   gra_makepdmenu(WINDOWFRAME *wf, POPUPMENU *pm, INTBIG value, Widget parent,
278 			INTBIG pindex);
279 void     gra_pulldownindex(WINDOWFRAME *wf, POPUPMENU *pm, INTBIG order, Widget parent);
280 void     gra_menucb(Widget W, int item_number, XtPointer call_data);
281 void     gra_menupcb(Widget w, int item_number, XtPointer call_data);
282 void     gra_nativemenudoone(WINDOWFRAME *wf, INTBIG low, INTBIG high);
283 void     gra_pulldownmenuload(WINDOWFRAME *wf);
284 
285 /****** the dialogs ******/
286 #define MAXSCROLLMULTISELECT 1000
287 #define MAXLOCKS              3   /* maximum locked pairs of scroll lists */
288 #define NOTDIALOG ((TDIALOG *)-1)
289 
290 #define DIALOGNUM            16
291 #define DIALOGDEN            12
292 #define MAXICONS             20
293 
294 typedef struct Itdialog
295 {
296 	Widget      window;
297 	Widget      windowframe;
298 	DIALOG     *itemdesc;
299 	INTBIG      windindex;
300 	INTBIG      defaultbutton;
301 	Widget      items[100];
302 	INTBIG      numlocks, lock1[MAXLOCKS], lock2[MAXLOCKS], lock3[MAXLOCKS];
303 	INTBIG      redrawitem;
304 	void      (*redrawroutine)(RECTAREA*, void*);
305 	INTBIG      opaqueitem;
306 	INTBIG      inix, iniy;
307 	INTBIG      usertextsize;
308 	INTBIG      dialoghit;
309 	CHAR        opaquefield[300];
310 	void      (*diaeachdown)(INTBIG x, INTBIG y);
311 	void      (*modelessitemhit)(void *dia, INTBIG item);
312 	struct Itdialog *nexttdialog;
313 } TDIALOG;
314 
315 INTBIG          gra_dialoggraycol, gra_dialogbackgroundcol;
316 GC              gra_gcdia;
317 UCHAR1         *gra_icontruedata = 0, *gra_iconrowdata;   /* working memory for "gra_makeicon()" */
318 static CHAR    *gra_brokenbuf; /* working memory for DisSetText */
319 static INTBIG   gra_brokenbufsize = 0;
320 
321 /* dialog support routines */
322 void     gra_flushdialog(TDIALOG *dia);
323 void     gra_getdialogcoordinates(RECTAREA *rect, INTBIG *x, INTBIG *y,
324 			INTBIG *wid, INTBIG *hei);
325 INTBIG   gra_scaledialogcoordinate(INTBIG x);
326 INTBIG   gra_makedpycolor(Display *dpy, INTBIG r, INTBIG g, INTBIG b);
327 void     gra_dialogaction(Widget w, XtPointer client_data,
328 			XmSelectionBoxCallbackStruct *call_data);
329 void     gra_vertslider(Widget w, XtPointer client_data,
330 			XmScrollBarCallbackStruct *call_data);
331 void     gra_setscroll(TDIALOG *dia, int item, int value);
332 void     gra_dialogredraw(Widget w, XtPointer client_data,
333 			XmSelectionBoxCallbackStruct *call_data);
334 void     gra_dialogredrawsep(Widget w, XtPointer client_data,
335 			XmSelectionBoxCallbackStruct *call_data);
336 void     gra_dialogopaqueaction(Widget w, XtPointer client_data,
337 			XmTextVerifyCallbackStruct *call_data);
338 void     gra_dialogdraw(Widget widget, XEvent *event, String *args, int *num_args);
339 void     gra_dialogcopywholelist(Widget widget, XEvent *event, String *args, int *num_args);
340 Pixmap   gra_makeicon(UCHAR1 *data, Widget widget);
341 void     gra_dialog_event_handler(Widget w, XtPointer data, XEvent *event, Boolean *cont);
342 TDIALOG *gra_whichdialog(Widget w);
343 TDIALOG *gra_getdialogfromindex(INTBIG index);
344 
345 TDIALOG        *gra_firstactivedialog = NOTDIALOG;
346 TDIALOG        *gra_trackingdialog = 0;
347 
348 static BOOLEAN gra_initdialog(DIALOG *dialog, TDIALOG *dia, BOOLEAN modeless);
349 static INTBIG  gra_dialogstringpos;
350 static BOOLEAN gra_diaeachdownhandler(INTBIG x, INTBIG y);
351 static int     gra_stringposascending(const void *e1, const void *e2);
352 
353 /****** events ******/
354 /* the meaning of "gra_inputstate" */
355 #define CHARREAD             0377			/* character that was read */
356 #define ISKEYSTROKE          0400			/* set if key typed */
357 #define ISBUTTON            07000			/* set if button pushed (or released) */
358 #define ISLEFT              01000			/*    left button */
359 #define ISMIDDLE            02000			/*    middle button */
360 #define ISRIGHT             03000			/*    right button */
361 #define ISWHLFWD            04000			/*    forward on the mouse wheel */
362 #define ISWHLBKW            05000			/*    backward on the mouse wheel */
363 #define BUTTONUP           010000			/* set if button was released */
364 #define SHIFTISDOWN        020000			/* set if shift key was held down */
365 #define CONTROLISDOWN      040000			/* set if control key was held down */
366 #define METAISDOWN        0100000			/* set if meta key was held down */
367 #define DOUBLECL          0200000			/* set if double-click */
368 #define MOTION            0400000			/* set if mouse motion detected */
369 #define WINDOWSIZE       01000000			/* set if window grown */
370 #define WINDOWMOVE       02000000			/* set if window moved */
371 #define MENUEVENT        04000000			/* set if menu entry selected (values in cursor) */
372 #define FILEREPLY       010000000			/* set if file selected in standard file dialog */
373 #define DIAITEMCLICK    020000000			/* set if item clicked in dialog */
374 #define DIASCROLLSEL    040000000			/* set if scroll item selected in dialog */
375 #define DIAEDITTEXT    0100000000			/* set if edit text changed in dialog */
376 #define DIAPOPUPSEL    0200000000			/* set if popup item selected in dialog */
377 #define DIASETCONTROL  0400000000			/* set if control changed in dialog */
378 #define DIAUSERMOUSE  01000000000			/* set if mouse moved in user area of dialog */
379 #define DIAENDDIALOG  02000000000			/* set when dialog terminates */
380 #define POPUPSELECT   04000000000			/* popup selection made */
381 #define NOEVENT                -1			/* set if nothing happened */
382 
383 #define INITIALTIMERDELAY      9			/* ratio of initial repeat to others */
384 #define TICKSPERSECOND        10			/* frequency of timer for repeats */
385 
386 typedef RETSIGTYPE (*SIGNALCAST)(int);
387 
388 struct
389 {
390 	INTBIG x;
391 	INTBIG y;
392 } gra_action;
393 
394 typedef struct
395 {
396 	INTBIG                cursorx, cursory;		/* current position of mouse */
397 	INTBIG                inputstate;			/* current state of device input */
398 	INTBIG                special;				/* special command to do */
399 	UINTBIG               eventtime;			/* time of this event */
400 } MYEVENTQUEUE;
401 
402 #define EVENTQUEUESIZE	100
403 
404 static MYEVENTQUEUE  gra_eventqueue[EVENTQUEUESIZE];
405 static MYEVENTQUEUE *gra_eventqueuehead;		/* points to next event in queue */
406 static MYEVENTQUEUE *gra_eventqueuetail;		/* points to first free event in queue */
407 
408 static INTBIG        gra_inputstate;			/* current state of device input */
409 static INTBIG        gra_inputspecial;			/* current "special" keyboard value */
410 static INTBIG        gra_doublethresh;			/* threshold of double-click */
411 static INTBIG        gra_cursorx, gra_cursory;	/* current position of mouse */
412 static INTBIG        gra_lstcurx, gra_lstcury;	/* former position of mouse */
413 static INTBIG        gra_logrecordcount = 0;	/* count for session flushing */
414 static INTBIG        gra_lastloggedaction = NOEVENT;
415 static INTBIG        gra_lastloggedx, gra_lastloggedy;
416 static INTBIG        gra_lastloggedindex;
417 static UINTBIG       gra_lastplaybacktime = 0;	/* offset to system time */
418 static UINTBIG       gra_logbasetime;
419 static UINTBIG       gra_eventtime;				/* time that the current event was queued */
420 static INTBIG        gra_firstbuttonwait = 0;
421 static INTBIG        gra_lasteventstate = 0;	/* last event state (for repeating) */
422 static INTBIG        gra_lasteventx;			/* X of last event (for repeating) */
423 static INTBIG        gra_lasteventy;			/* Y of last event (for repeating) */
424 static INTBIG        gra_lasteventspecial;		/* special factor of last event (for repeating) */
425 static INTBIG        gra_lasteventtime;			/* time of last event (for repeating) */
426 static UINTBIG       gra_timeoffset = 0;		/* offset to system time */
427 static INTBIG        gra_cureventtime = 0;		/* current time counter (for repeating) */
428 static XEvent        gra_samplemotionevent;		/* fake event for repeating */
429 static XEvent        gra_lastbuttonpressevent;	/* last button press event for popup menus */
430 static Widget        gra_lastwidgetfocused = 0;	/* last widget that got focus (to switch when exposed) */
431 
432 #if 0		/* for debugging X events */
433 static CHAR *eventNames[] =
434 {
435 	x_(""),
436 	x_(""),
437 	x_("KeyPress"),
438 	x_("KeyRelease"),
439 	x_("ButtonPress"),
440 	x_("ButtonRelease"),
441 	x_("MotionNotify"),
442 	x_("EnterNotify"),
443 	x_("LeaveNotify"),
444 	x_("FocusIn"),
445 	x_("FocusOut"),
446 	x_("KeymapNotify"),
447 	x_("Expose"),
448 	x_("GraphicsExpose"),
449 	x_("NoExpose"),
450 	x_("VisibilityNotify"),
451 	x_("CreateNotify"),
452 	x_("DestroyNotify"),
453 	x_("UnmapNotify"),
454 	x_("MapNotify"),
455 	x_("MapRequest"),
456 	x_("ReparentNotify"),
457 	x_("ConfigureNotify"),
458 	x_("ConfigureRequest"),
459 	x_("GravityNotify"),
460 	x_("ResizeRequest"),
461 	x_("CirculateNotify"),
462 	x_("CirculateRequest"),
463 	x_("PropertyNotify"),
464 	x_("SelectionClear"),
465 	x_("SelectionRequest"),
466 	x_("SelectionNotify"),
467 	x_("ColormapNotify"),
468 	x_("ClientMessage"),
469 	x_("MappingNotify")
470 };
471 #endif
472 
473 void         gra_nextevent(void);
474 void         gra_repaint(WINDOWFRAME *wf, BOOLEAN redo);
475 void         gra_recalcsize(WINDOWFRAME *wf, INTBIG wid, INTBIG hei);
476 void         gra_addeventtoqueue(INTBIG state, INTBIG special, INTBIG x, INTBIG y);
477 void         gra_pickupnextevent(void);
478 void         gra_graphics_event_handler(Widget w, XtPointer data, XEvent *event, Boolean *cont);
479 void         gra_messages_event_handler(Widget w, XtPointer data, XEvent *event, Boolean *cont);
480 Boolean      gra_dowork(XtPointer client_data);
481 void         gra_timerticked(XtPointer closure, XtIntervalId *id);
482 INTBIG       gra_translatekey(XEvent *event, INTBIG *special);
483 RETSIGTYPE   gra_sigill_trap(void);
484 RETSIGTYPE   gra_sigfpe_trap(void);
485 RETSIGTYPE   gra_sigbus_trap(void);
486 RETSIGTYPE   gra_sigsegv_trap(void);
487 WINDOWFRAME *gra_getcurrentwindowframe(Widget widget, BOOLEAN set);
488 void         gra_windowdelete(Widget w, XtPointer client_data, XtPointer *call_data);
489 
490 /****** mouse buttons ******/
491 #define BUTTONS     45		/* cannot exceed NUMBUTS in "usr.h" */
492 #define REALBUTS    5		/* actual number of buttons */
493 
494 struct {
495 	CHAR  *name;				/* button name */
496 	INTBIG unique;				/* number of letters that make it unique */
497 } gra_buttonname[BUTTONS] =
498 {
499 	{x_("LEFT"),1},   {x_("MIDDLE"),2},   {x_("RIGHT"),1},   {x_("FORWARD"),1},   {x_("BACKWARD"),1},	/* unshifted */
500 	{x_("SLEFT"),2},  {x_("SMIDDLE"),3},  {x_("SRIGHT"),2},  {x_("SFORWARD"),2},  {x_("SBACKWARD"),2},	/* shift held down */
501 	{x_("CLEFT"),2},  {x_("CMIDDLE"),3},  {x_("CRIGHT"),2},  {x_("CFORWARD"),2},  {x_("CBACKWARD"),2},	/* control held down */
502 	{x_("MLEFT"),2},  {x_("MMIDDLE"),3},  {x_("MRIGHT"),2},  {x_("MFORWARD"),2},  {x_("MBACKWARD"),2},	/* meta held down */
503 	{x_("SCLEFT"),3}, {x_("SCMIDDLE"),4}, {x_("SCRIGHT"),3}, {x_("SCFORWARD"),3}, {x_("SCBACKWARD"),3},	/* shift and control held down*/
504 	{x_("SMLEFT"),3}, {x_("SMMIDDLE"),4}, {x_("SMRIGHT"),3}, {x_("SMFORWARD"),3}, {x_("SMBACKWARD"),3},	/* shift and meta held down */
505 	{x_("CMLEFT"),3}, {x_("CMMIDDLE"),4}, {x_("CMRIGHT"),3}, {x_("CMFORWARD"),3}, {x_("CMBACKWARD"),3},	/* control and meta held down */
506 	{x_("SCMLEFT"),4},{x_("SCMMIDDLE"),4},{x_("SCMRIGHT"),4},{x_("SCMFORWARD"),4},{x_("SCMBACKWARD"),4},/* shift, control, and meta */
507 	{x_("DLEFT"),2},  {x_("DMIDDLE"),2},  {x_("DRIGHT"),2},  {x_("DFORWARD"),2},  {x_("DBACKWARD"),2}	/* double-click */
508 };
509 
510 INTBIG     gra_makebutton(INTBIG);
511 
512 /****** cursors and icons ******/
513 static Cursor        gra_realcursor;
514 static Cursor        gra_nomousecursor;
515 static Cursor        gra_drawcursor;
516 static Cursor        gra_nullcursor;
517 static Cursor        gra_menucursor;
518 static Cursor        gra_handcursor;
519 static Cursor        gra_techcursor;
520 static Cursor        gra_ibeamcursor;
521 static Cursor        gra_lrcursor;
522 static Cursor        gra_udcursor;
523 static XColor        gra_xfc, gra_xbc;			/* cursor color structure  */
524 
525 /* the icon for Electric  */
526 #ifdef sun
527 #  define PROGICONSIZE 32
528   static UINTSML gra_icon[64] =
529   {
530 	0x0000, 0x0000, /*                                  */
531 	0x0000, 0x0000, /*                                  */
532 	0xFF80, 0x01FF, /*        XXXXXXXXXXXXXXXXXX        */
533 	0x0040, 0x0200, /*       X                  X       */
534 	0x0020, 0x0400, /*      X                    X      */
535 	0x0010, 0x0800, /*     X                      X     */
536 	0x0008, 0x1000, /*    X                        X    */
537 	0x0008, 0x1000, /*    X                        X    */
538 	0x0004, 0x2000, /*   X                          X   */
539 	0x0784, 0x21E0, /*   X    XXXX          XXXX    X   */
540 	0x0782, 0x41E0, /*  X     XXXX          XXXX     X  */
541 	0x0782, 0x41E0, /*  X     XXXX          XXXX     X  */
542 	0x0781, 0x81E0, /* X      XXXX          XXXX      X */
543 	0x0781, 0x81E0, /* X      XXXX          XXXX      X */
544 	0x0781, 0x81E0, /* X      XXXX          XXXX      X */
545 	0x0781, 0x81E0, /* X      XXXX          XXXX      X */
546 	0x0781, 0x81E0, /* X      XXXX          XXXX      X */
547 	0x0781, 0x81E0, /* X      XXXX          XXXX      X */
548 	0x0781, 0x8000, /* X      XXXX                    X */
549 	0x0001, 0x8000, /* X                              X */
550 	0x8002, 0x4001, /*  X             XX             X  */
551 	0xC002, 0x4003, /*  X            XXXX            X  */
552 	0xE004, 0x2007, /*   X          XXXXXX          X   */
553 	0xE004, 0x2007, /*   X          XXXXXX          X   */
554 	0xE008, 0x1007, /*    X         XXXXXX         X    */
555 	0xE008, 0x1007, /*    X         XXXXXX         X    */
556 	0x0010, 0x0800, /*     X                      X     */
557 	0x0020, 0x0400, /*      X                    X      */
558 	0x0040, 0x0200, /*       X                  X       */
559 	0xFF80, 0x01FF, /*        XXXXXXXXXXXXXXXXXX        */
560 	0x0000, 0x0000, /*                                  */
561 	0x0000, 0x0000  /*                                  */
562   };
563 #else
564 #  define PROGICONSIZE 64
565   static UINTSML gra_icon[256] =
566   {
567 	0x0000, 0x0000, 0x0000, 0x0000, /*                                                                  */
568 	0x0000, 0x0000, 0x0000, 0x0000, /*                                                                  */
569 	0x0000, 0x0000, 0x0000, 0x0000, /*                                                                  */
570 	0x0000, 0x0000, 0x0000, 0x0000, /*                                                                  */
571 	0xF800, 0xFFFF, 0xFFFF, 0x001F, /*            XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX            */
572 	0x0400, 0x0000, 0x0000, 0x0020, /*           X                                          X           */
573 	0x0200, 0x0000, 0x0000, 0x0040, /*          X                                            X          */
574 	0x0100, 0x0000, 0x0000, 0x0080, /*         X                                              X         */
575 	0x0080, 0x0000, 0x0000, 0x0100, /*        X                                                X        */
576 	0x0080, 0x0000, 0x0000, 0x0100, /*        X                                                X        */
577 	0x0040, 0x0000, 0x0000, 0x0200, /*       X                                                  X       */
578 	0x0040, 0x0000, 0x0000, 0x0200, /*       X                                                  X       */
579 	0x0020, 0x0000, 0x0000, 0x0400, /*      X                                                    X      */
580 	0x0020, 0x0000, 0x0000, 0x0400, /*      X                                                    X      */
581 	0x8010, 0x001F, 0xFC00, 0x0800, /*     X          XXXXXX                     XXXXXX           X     */
582 	0x8010, 0x001F, 0xFC00, 0x0800, /*     X          XXXXXX                     XXXXXX           X     */
583 	0x8008, 0x001F, 0xFC00, 0x1000, /*    X           XXXXXX                     XXXXXX            X    */
584 	0x8008, 0x001F, 0xFC00, 0x1000, /*    X           XXXXXX                     XXXXXX            X    */
585 	0x8004, 0x001F, 0xFC00, 0x2000, /*   X            XXXXXX                     XXXXXX             X   */
586 	0x8004, 0x001F, 0xFC00, 0x2000, /*   X            XXXXXX                     XXXXXX             X   */
587 	0x8004, 0x001F, 0xFC00, 0x2000, /*   X            XXXXXX                     XXXXXX             X   */
588 	0x8002, 0x001F, 0xFC00, 0x4000, /*  X             XXXXXX                     XXXXXX              X  */
589 	0x8002, 0x001F, 0xFC00, 0x4000, /*  X             XXXXXX                     XXXXXX              X  */
590 	0x8002, 0x001F, 0xFC00, 0x4000, /*  X             XXXXXX                     XXXXXX              X  */
591 	0x8002, 0x001F, 0xFC00, 0x4000, /*  X             XXXXXX                     XXXXXX              X  */
592 	0x8002, 0x001F, 0xFC00, 0x4000, /*  X             XXXXXX                     XXXXXX              X  */
593 	0x8001, 0x001F, 0xFC00, 0x8000, /* X              XXXXXX                     XXXXXX               X */
594 	0x8001, 0x001F, 0xFC00, 0x8000, /* X              XXXXXX                     XXXXXX               X */
595 	0x8001, 0x001F, 0xFC00, 0x8000, /* X              XXXXXX                     XXXXXX               X */
596 	0x8001, 0x001F, 0xFC00, 0x8000, /* X              XXXXXX                     XXXXXX               X */
597 	0x8001, 0x001F, 0xFC00, 0x8000, /* X              XXXXXX                     XXXXXX               X */
598 	0x8001, 0x001F, 0xFC00, 0x8000, /* X              XXXXXX                     XXXXXX               X */
599 	0x0001, 0x0000, 0x0000, 0x8000, /* X                                                              X */
600 	0x0001, 0x0000, 0x0000, 0x8000, /* X                                                              X */
601 	0x0001, 0x0000, 0x0000, 0x8000, /* X                                                              X */
602 	0x0001, 0x0000, 0x0000, 0x8000, /* X                                                              X */
603 	0x0001, 0x0000, 0x0000, 0x8000, /* X                                                              X */
604 	0x0001, 0xF000, 0x0007, 0x8000, /* X                           XXXXXXX                            X */
605 	0x0002, 0xF800, 0x000F, 0x4000, /*  X                         XXXXXXXXX                          X  */
606 	0x0002, 0xFC00, 0x001F, 0x4000, /*  X                        XXXXXXXXXXX                         X  */
607 	0x0002, 0xFE00, 0x003F, 0x4000, /*  X                       XXXXXXXXXXXXX                        X  */
608 	0x0002, 0xFE00, 0x003F, 0x4000, /*  X                       XXXXXXXXXXXXX                        X  */
609 	0x0002, 0xFE00, 0x003F, 0x4000, /*  X                       XXXXXXXXXXXXX                        X  */
610 	0x0004, 0xFE00, 0x003F, 0x2000, /*   X                      XXXXXXXXXXXXX                       X   */
611 	0x0004, 0xFE00, 0x003F, 0x2000, /*   X                      XXXXXXXXXXXXX                       X   */
612 	0x0004, 0xFE00, 0x003F, 0x2000, /*   X                      XXXXXXXXXXXXX                       X   */
613 	0x0008, 0xFE00, 0x003F, 0x1000, /*    X                     XXXXXXXXXXXXX                      X    */
614 	0x0008, 0xFE00, 0x003F, 0x1000, /*    X                     XXXXXXXXXXXXX                      X    */
615 	0x0010, 0xFE00, 0x003F, 0x0800, /*     X                    XXXXXXXXXXXXX                     X     */
616 	0x0010, 0xFE00, 0x003F, 0x0800, /*     X                    XXXXXXXXXXXXX                     X     */
617 	0x0020, 0xFE00, 0x003F, 0x0400, /*      X                   XXXXXXXXXXXXX                    X      */
618 	0x0020, 0x0000, 0x0000, 0x0400, /*      X                                                    X      */
619 	0x0040, 0x0000, 0x0000, 0x0200, /*       X                                                  X       */
620 	0x0040, 0x0000, 0x0000, 0x0200, /*       X                                                  X       */
621 	0x0080, 0x0000, 0x0000, 0x0100, /*        X                                                X        */
622 	0x0080, 0x0000, 0x0000, 0x0100, /*        X                                                X        */
623 	0x0100, 0x0000, 0x0000, 0x0080, /*         X                                              X         */
624 	0x0200, 0x0000, 0x0000, 0x0040, /*          X                                            X          */
625 	0x0400, 0x0000, 0x0000, 0x0020, /*           X                                          X           */
626 	0xF800, 0xFFFF, 0xFFFF, 0x001F, /*            XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX            */
627 	0x0000, 0x0000, 0x0000, 0x0000, /*                                                                  */
628 	0x0000, 0x0000, 0x0000, 0x0000, /*                                                                  */
629 	0x0000, 0x0000, 0x0000, 0x0000, /*                                                                  */
630 	0x0000, 0x0000, 0x0000, 0x0000  /*                                                                  */
631   };
632 #endif
633 
634 /* the normal cursor (NORMALCURSOR, an "X") */
635 static UINTSML gra_realcursordata[16] = {
636 	0x0000, /*                  */
637 	0x4002, /*  X            X  */
638 	0x2004, /*   X          X   */
639 	0x1008, /*    X        X    */
640 	0x0810, /*     X      X     */
641 	0x0420, /*      X    X      */
642 	0x0240, /*       X  X       */
643 	0x0180, /*        XX        */
644 	0x0180, /*        XX        */
645 	0x0240, /*       X  X       */
646 	0x0420, /*      X    X      */
647 	0x0810, /*     X      X     */
648 	0x1008, /*    X        X    */
649 	0x2004, /*   X          X   */
650 	0x4002, /*  X            X  */
651 	0x0000  /*                  */
652 };
653 static UINTSML gra_realcursormask[16] = {
654 	0xC003, /* XX            XX */
655 	0xE007, /* XXX          XXX */
656 	0x700E, /*  XXX        XXX  */
657 	0x381C, /*   XXX      XXX   */
658 	0x1C38, /*    XXX    XXX    */
659 	0x0E70, /*     XXX  XXX     */
660 	0x07E0, /*      XXXXXX      */
661 	0x03E0, /*       XXXX       */
662 	0x03E0, /*       XXXX       */
663 	0x07E0, /*      XXXXXX      */
664 	0x0E70, /*     XXX  XXX     */
665 	0x1C38, /*    XXX    XXX    */
666 	0x381C, /*   XXX      XXX   */
667 	0x700E, /*  XXX        XXX  */
668 	0xE007, /* XXX          XXX */
669 	0xC003  /* XX            XX */
670 };
671 
672 /* the "use the TTY" cursor (WANTTTYCURSOR, the word "tty" above keyboard) */
673 static UINTSML gra_nomousecursordata[16] = {
674 	0x7757, /* XXX X X XXX XXX  */
675 	0x1552, /*  X  X X X X X    */
676 	0x3772, /*  X  XXX XXX XX   */
677 	0x1122, /*  X   X  X   X    */
678 	0x7122, /*  X   X  X   XXX  */
679 	0x0000, /*                  */
680 	0xFFFF, /* XXXXXXXXXXXXXXXX */
681 	0x8001, /* X              X */
682 	0x8AA9, /* X  X X X X X   X */
683 	0x9551, /* X   X X X X X  X */
684 	0x8AA9, /* X  X X X X X   X */
685 	0x9551, /* X   X X X X X  X */
686 	0x8001, /* X              X */
687 	0x9FF9, /* X  XXXXXXXXXX  X */
688 	0x8001, /* X              X */
689 	0xFFFF  /* XXXXXXXXXXXXXXXX */
690 };
691 static UINTSML gra_nomousecursormask[16] = {
692 	0xFFFF, /* XXXXXXXXXXXXXXXX */
693 	0xFFFF, /* XXXXXXXXXXXXXXXX */
694 	0xFFFF, /* XXXXXXXXXXXXXXXX */
695 	0xFFFF, /* XXXXXXXXXXXXXXXX */
696 	0xFFFF, /* XXXXXXXXXXXXXXXX */
697 	0x0000, /*                  */
698 	0xFFFF, /* XXXXXXXXXXXXXXXX */
699 	0xFFFF, /* XXXXXXXXXXXXXXXX */
700 	0xFFFF, /* XXXXXXXXXXXXXXXX */
701 	0xFFFF, /* XXXXXXXXXXXXXXXX */
702 	0xFFFF, /* XXXXXXXXXXXXXXXX */
703 	0xFFFF, /* XXXXXXXXXXXXXXXX */
704 	0xFFFF, /* XXXXXXXXXXXXXXXX */
705 	0xFFFF, /* XXXXXXXXXXXXXXXX */
706 	0xFFFF, /* XXXXXXXXXXXXXXXX */
707 	0xFFFF  /* XXXXXXXXXXXXXXXX */
708 };
709 
710 /* the "draw with pen" cursor (PENCURSOR, a pen) */
711 static UINTSML gra_drawcursordata[16] = {
712 	0x3000, /*             XX   */
713 	0x7800, /*            XXXX  */
714 	0xF400, /*           X XXXX */
715 	0xE200, /*          X   XXX */
716 	0x4100, /*         X     X  */
717 	0x2080, /*        X     X   */
718 	0x1040, /*       X     X    */
719 	0x0820, /*      X     X     */
720 	0x0410, /*     X     X      */
721 	0x0208, /*    X     X       */
722 	0x010C, /*   XX    X        */
723 	0x008C, /*   XX   X         */
724 	0x007E, /*  XXXXXX          */
725 	0x003E, /*  XXXXX           */
726 	0x000F, /* XXXX             */
727 	0x0003  /* XX               */
728 };
729 static UINTSML gra_drawcursormask[16] = {
730 	0x7800, /*            XXXX  */
731 	0xFC00, /*           XXXXXX */
732 	0xFE00, /*          XXXXXXX */
733 	0xFF00, /*         XXXXXXXX */
734 	0xFF80, /*        XXXXXXXXX */
735 	0x7FC0, /*       XXXXXXXXX  */
736 	0x3FE0, /*      XXXXXXXXX   */
737 	0x1FF0, /*     XXXXXXXXX    */
738 	0x0FF8, /*    XXXXXXXXX     */
739 	0x07FC, /*   XXXXXXXXX      */
740 	0x03FE, /*  XXXXXXXXX       */
741 	0x01FE, /*  XXXXXXXX        */
742 	0x00FF, /* XXXXXXXX         */
743 	0x007F, /* XXXXXXX          */
744 	0x001F, /* XXXXX            */
745 	0x0007  /* XXX              */
746 };
747 
748 /* the null cursor (NULLCURSOR, an egg timer) */
749 static UINTSML gra_nullcursordata[16] = {
750 	0x1FF8, /*    XXXXXXXXXX    */
751 	0x2004, /*   X          X   */
752 	0x2004, /*   X          X   */
753 	0x2004, /*   X          X   */
754 	0x1AA8, /*    X X X X XX    */
755 	0x0FF0, /*     XXXXXXXX     */
756 	0x07E0, /*      XXXXXX      */
757 	0x03C0, /*       XXXX       */
758 	0x0240, /*       X  X       */
759 	0x0420, /*      X    X      */
760 	0x0810, /*     X      X     */
761 	0x1008, /*    X        X    */
762 	0x2AA4, /*   X  X X X X X   */
763 	0x3FFC, /*   XXXXXXXXXXXX   */
764 	0x3FFC, /*   XXXXXXXXXXXX   */
765 	0x1FF8  /*    XXXXXXXXXX    */
766 };
767 static UINTSML gra_nullcursormask[16] = {
768 	0x3FFC, /*   XXXXXXXXXXXX   */
769 	0x7FFE, /*  XXXXXXXXXXXXXX  */
770 	0x7FFE, /*  XXXXXXXXXXXXXX  */
771 	0x7FFE, /*  XXXXXXXXXXXXXX  */
772 	0x3FFC, /*   XXXXXXXXXXXX   */
773 	0x1FF8, /*    XXXXXXXXXX    */
774 	0x0FF0, /*     XXXXXXXX     */
775 	0x07E0, /*      XXXXXX      */
776 	0x07E0, /*      XXXXXX      */
777 	0x0FF0, /*     XXXXXXXX     */
778 	0x1FF8, /*    XXXXXXXXXX    */
779 	0x3FFC, /*   XXXXXXXXXXXX   */
780 	0x7FFE, /*  XXXXXXXXXXXXXX  */
781 	0x7FFE, /*  XXXXXXXXXXXXXX  */
782 	0x7FFE, /*  XXXXXXXXXXXXXX  */
783 	0x3FFC  /*   XXXXXXXXXXXX   */
784 };
785 
786 /* the menu selection cursor (MENUCURSOR, a sideways arrow) */
787 static UINTSML gra_menucursordata[16] = {
788 	0x0000, /*                  */
789 	0x0000, /*                  */
790 	0x0400, /*           X      */
791 	0x0C00, /*           XX     */
792 	0x1C00, /*           XXX    */
793 	0x3C00, /*           XXXX   */
794 	0x7FFF, /* XXXXXXXXXXXXXXX  */
795 	0xFFFF, /* XXXXXXXXXXXXXXXX */
796 	0x7FFF, /* XXXXXXXXXXXXXXX  */
797 	0x3C00, /*           XXXX   */
798 	0x1C00, /*           XXX    */
799 	0x0C00, /*           XX     */
800 	0x0400, /*           X      */
801 	0x0000, /*                  */
802 	0x0000, /*                  */
803 	0x0000  /*                  */
804 };
805 static UINTSML gra_menucursormask[16] = {
806 	0x0000, /*                  */
807 	0x0400, /*           X      */
808 	0x0E00, /*          XXX     */
809 	0x1E00, /*          XXXX    */
810 	0x3E00, /*          XXXXX   */
811 	0x7EFF, /* XXXXXXXXXXXXXXX  */
812 	0xFFFF, /* XXXXXXXXXXXXXXXX */
813 	0xFFFF, /* XXXXXXXXXXXXXXXX */
814 	0xFFFF, /* XXXXXXXXXXXXXXXX */
815 	0x7EFF, /* XXXXXXXXXXXXXXX  */
816 	0x3E00, /*          XXXXX   */
817 	0x1E00, /*          XXXX    */
818 	0x0E00, /*          XXX     */
819 	0x0400, /*           X      */
820 	0x0000, /*                  */
821 	0x0000  /*                  */
822 };
823 
824 /* the "move" command dragging cursor (HANDCURSOR, a dragging hand) */
825 static UINTSML gra_handcursordata[16] = {
826 	0x0000, /*                  */
827 	0x3F80, /*        XXXXXXX   */
828 	0xC040, /*       X       XX */
829 	0x0380, /*        XXX       */
830 	0x0040, /*       X          */
831 	0x0020, /*      X           */
832 	0x01C0, /*       XXX        */
833 	0x0020, /*      X           */
834 	0x0010, /*     X            */
835 	0x03FE, /*  XXXXXXXXX       */
836 	0x0001, /* X                */
837 	0x0001, /* X                */
838 	0x1FFE, /*  XXXXXXXXXXXX    */
839 	0x8080, /*        X       X */
840 	0x4100, /*         X     X  */
841 	0x3E00  /*          XXXXX   */
842 };
843 static UINTSML gra_handcursormask[16] = {
844 	0x3F80, /*        XXXXXXX   */
845 	0xFFC0, /*       XWWWWWWWXX */
846 	0xFFE0, /*      XWXXXXXXXWW */
847 	0xFFC0, /*       XWWWXXXXXX */
848 	0xFFE0, /*      XWXXXXXXXXX */
849 	0xFFF0, /*     XWXXXXXXXXXX */
850 	0xFFE0, /*      XWWWXXXXXXX */
851 	0xFFF0, /*     XWXXXXXXXXXX */
852 	0xFFFF, /* XXXXWXXXXXXXXXXX */
853 	0xFFFF, /* XWWWWWWWWWXXXXXX */
854 	0xFFFF, /* WXXXXXXXXXXXXXXX */
855 	0xFFFF, /* WXXXXXXXXXXXXXXX */
856 	0xFFFF, /* XWWWWWWWWWWWWXXX */
857 	0xFFFE, /*  XXXXXXWXXXXXXXW */
858 	0xFF80, /*        XWXXXXXWX */
859 	0x7F00  /*         XWWWWWX  */
860 };
861 
862 /* the "technology" command dragging cursor (TECHCURSOR, a "T") */
863 static UINTSML gra_techcursordata[16] = {
864 	0x0100, /*         X        */
865 	0x0380, /*        XXX       */
866 	0x0540, /*       X X X      */
867 	0x0100, /*         X        */
868 	0x0100, /*         X        */
869 	0x3FF8, /*    XXXXXXXXXXX   */
870 	0x3FF8, /*    XXXXXXXXXXX   */
871 	0x2388, /*    X   XXX   X   */
872 	0x0380, /*        XXX       */
873 	0x0380, /*        XXX       */
874 	0x0380, /*        XXX       */
875 	0x0380, /*        XXX       */
876 	0x0380, /*        XXX       */
877 	0x0380, /*        XXX       */
878 	0x07C0, /*       XXXXX      */
879 	0x0000  /*                  */
880 };
881 static UINTSML gra_techcursormask[16] = {
882 	0x0380, /*        XXX       */
883 	0x07C0, /*       XXXXX      */
884 	0x0FE0, /*      XXXXXXX     */
885 	0x0380, /*        XXX       */
886 	0x3FF8, /*    XXXXXXXXXXX   */
887 	0x7FFC, /*   XXXXXXXXXXXXX  */
888 	0x7FFC, /*   XXXXXXXXXXXXX  */
889 	0x7FFC, /*   XXXXXXXXXXXXX  */
890 	0x07C0, /*       XXXXX      */
891 	0x07C0, /*       XXXXX      */
892 	0x07C0, /*       XXXXX      */
893 	0x07C0, /*       XXXXX      */
894 	0x07C0, /*       XXXXX      */
895 	0x07C0, /*       XXXXX      */
896 	0x0EE0, /*      XXXXXXX     */
897 	0x07C0  /*       XXXXX      */
898 };
899 
900 /* the "ibeam" text selection cursor (IBEAMCURSOR, an "I") */
901 static UINTSML gra_ibeamcursordata[16] = {
902 	0x0360, /*      XX XX       */
903 	0x0080, /*        X         */
904 	0x0080, /*        X         */
905 	0x0080, /*        X         */
906 	0x0080, /*        X         */
907 	0x0080, /*        X         */
908 	0x0080, /*        X         */
909 	0x0080, /*        X         */
910 	0x0080, /*        X         */
911 	0x0080, /*        X         */
912 	0x0080, /*        X         */
913 	0x0080, /*        X         */
914 	0x0080, /*        X         */
915 	0x0080, /*        X         */
916 	0x0080, /*        X         */
917 	0x0360  /*      XX XX       */
918 };
919 static UINTSML gra_ibeamcursormask[16] = {
920 	0x07F0, /*     XXXXXXX      */
921 	0x01C0, /*       XXX        */
922 	0x01C0, /*       XXX        */
923 	0x01C0, /*       XXX        */
924 	0x01C0, /*       XXX        */
925 	0x01C0, /*       XXX        */
926 	0x01C0, /*       XXX        */
927 	0x01C0, /*       XXX        */
928 	0x01C0, /*       XXX        */
929 	0x01C0, /*       XXX        */
930 	0x01C0, /*       XXX        */
931 	0x01C0, /*       XXX        */
932 	0x01C0, /*       XXX        */
933 	0x01C0, /*       XXX        */
934 	0x01C0, /*       XXX        */
935 	0x07F0  /*     XXXXXXX      */
936 };
937 
938 /* the "left/right arrow" cursor (LRCURSOR) */
939 static UINTSML gra_lrcursordata[16] = {
940 	0x0000, /*                  */
941 	0x0000, /*                  */
942 	0x0000, /*                  */
943 	0x1008, /*    X        X    */
944 	0x300C, /*   XX        XX   */
945 	0x700E, /*  XXX        XXX  */
946 	0xFFFF, /* XXXXXXXXXXXXXXXX */
947 	0xFFFF, /* XXXXXXXXXXXXXXXX */
948 	0x700E, /*  XXX        XXX  */
949 	0x300C, /*   XX        XX   */
950 	0x1008, /*    X        X    */
951 	0x0000, /*                  */
952 	0x0000, /*                  */
953 	0x0000, /*                  */
954 	0x0000, /*                  */
955 	0x0000  /*                  */
956 };
957 static UINTSML gra_lrcursormask[16] = {
958 	0x0000, /*                  */
959 	0x0000, /*                  */
960 	0x1008, /*    X        X    */
961 	0x381C, /*   XXX      XXX   */
962 	0x781E, /*  XXXX      XXXX  */
963 	0xFFFF, /* XXXXXXXXXXXXXXXX */
964 	0xFFFF, /* XXXXXXXXXXXXXXXX */
965 	0xFFFF, /* XXXXXXXXXXXXXXXX */
966 	0xFFFF, /* XXXXXXXXXXXXXXXX */
967 	0x781E, /*  XXXX      XXXX  */
968 	0x381C, /*   XXX      XXX   */
969 	0x1008, /*    X        X    */
970 	0x0000, /*                  */
971 	0x0000, /*                  */
972 	0x0000, /*                  */
973 	0x0000  /*                  */
974 };
975 
976 /* the "up/down arrow" cursor (UDCURSOR) */
977 static UINTSML gra_udcursordata[16] = {
978 	0x0180, /*        XX        */
979 	0x03C0, /*       XXXX       */
980 	0x07E0, /*      XXXXXX      */
981 	0x0FF0, /*     XXXXXXXX     */
982 	0x0180, /*        XX        */
983 	0x0180, /*        XX        */
984 	0x0180, /*        XX        */
985 	0x0180, /*        XX        */
986 	0x0180, /*        XX        */
987 	0x0180, /*        XX        */
988 	0x0180, /*        XX        */
989 	0x0180, /*        XX        */
990 	0x0FF0, /*     XXXXXXXX     */
991 	0x07E0, /*      XXXXXX      */
992 	0x03C0, /*       XXXX       */
993 	0x0180  /*        XX        */
994 };
995 static UINTSML gra_udcursormask[16] = {
996 	0x03C0, /*       XXXX       */
997 	0x07E0, /*      XXXXXX      */
998 	0x0FF0, /*     XXXXXXXX     */
999 	0x1FF8, /*    XXXXXXXXXX    */
1000 	0x0FF0, /*     XXXXXXXX     */
1001 	0x03C0, /*       XXXX       */
1002 	0x03C0, /*       XXXX       */
1003 	0x03C0, /*       XXXX       */
1004 	0x03C0, /*       XXXX       */
1005 	0x03C0, /*       XXXX       */
1006 	0x03C0, /*       XXXX       */
1007 	0x0FF0, /*     XXXXXXXX     */
1008 	0x1FF8, /*    XXXXXXXXXX    */
1009 	0x0FF0, /*     XXXXXXXX     */
1010 	0x07E0, /*      XXXXXX      */
1011 	0x03C0  /*       XXXX       */
1012 };
1013 
1014 void       gra_recolorcursor(Display *dpy, XColor *fg, XColor *bg);
1015 
1016 /****** fonts ******/
1017 
1018 /*
1019  * Default font - this font MUST exist, or Electric will die.  Best to choose a
1020  * font that is commonly used, so the X server is likely to have it loaded.
1021  */
1022 #define DEFAULTFONTNAME      x_("fixed")
1023 #define FONTLISTSIZE           10
1024 #define FONTHASHSIZE          211		/* must be prime */
1025 #define TRUETYPEITALICSLANT   0.3		/* slant to make text italic */
1026 #define TRUETYPEBOLDEXTEND    1.5		/* extend factor to make text bold */
1027 
1028 typedef struct
1029 {
1030 	XFontStruct *font;
1031 	CHAR        *fontname;
1032 	CHAR        *altfontname;
1033 #ifdef ANYDEPTH
1034 	INTSML       width[128];
1035 	INTSML       height[128];
1036 	UCHAR1      *data[128];
1037 #endif
1038 } FontRec;
1039 
1040 typedef struct
1041 {
1042 	INTBIG   ascent, descent;
1043 	INTBIG   face;
1044 	INTBIG   italic;
1045 	INTBIG   bold;
1046 	INTBIG   size;
1047 	INTBIG   spacewidth;
1048 } FONTHASH;
1049 
1050        FONTHASH      gra_fonthash[FONTHASHSIZE];
1051 static INTBIG        gra_textrotation = 0;
1052 
1053 #ifdef ANYDEPTH
1054 #  define FONTINIT , {0}, {0}, {0}
1055   static UCHAR1     *gra_textbitsdata;				/* buffer for converting text to bits */
1056   static INTBIG      gra_textbitsdatasize = 0;		/* size of "gra_textbitsdata" */
1057   static UCHAR1    **gra_textbitsrowstart;			/* pointers to "gra_textbitsdata" */
1058   static INTBIG      gra_textbitsrowstartsize = 0;	/* size of "gra_textbitsrowstart" */
1059 #else
1060 #  define FONTINIT
1061 #endif
1062 
1063 static FontRec       gra_messages_font = {(XFontStruct *)0, x_("fixed"), x_("fixed") FONTINIT};
1064 static FontRec       gra_defaultFont;
1065 static XFontStruct  *gra_curfont;					/* current writing font */
1066 static INTBIG        gra_curfontnumber;
1067 static INTBIG        gra_truetypesize;				/* true size of current font */
1068 static BOOLEAN       gra_texttoosmall = FALSE;		/* TRUE if the text is too small to draw */
1069 #ifdef TRUETYPE
1070   static INTBIG      gra_truetypeon;				/* nonzero if TrueType initialized */
1071   static INTBIG      gra_truetypeitalic;			/* true italic factor of current font */
1072   static INTBIG      gra_truetypebold;				/* true bold factor of current font */
1073   static INTBIG      gra_truetypeunderline;			/* true underline factor of current font */
1074   static INTBIG      gra_truetypedescent;			/* true descent value of current font */
1075   static INTBIG      gra_truetypeascent;			/* true ascent value of current font */
1076   static INTBIG      gra_spacewidth;				/* true width of space for current font */
1077   static INTBIG      gra_truetypedeffont;			/* default TrueType font */
1078   static INTBIG      gra_truetypefont;				/* current TrueType font */
1079   static INTBIG     *gra_descentcache;				/* cache of maximum descent for font size */
1080   static INTBIG     *gra_ascentcache;				/* cache of maximum ascent for font size */
1081   static INTBIG     *gra_swidthcache;				/* cache of space width for font size */
1082   static INTBIG      gra_descentcachesize = 0;		/* size of ascent/descent cache */
1083   static INTBIG      gra_numfaces = 0;
1084   static CHAR      **gra_facelist;
1085 #endif
1086 
1087 static CHAR *gra_resource_fontname[] =
1088 {
1089 	x_("font0"), x_("font1"), x_("font2"), x_("font3"), x_("font4"), x_("font5"),
1090 	x_("font6"), x_("font7"), x_("font8"), x_("fontmenu"), x_("fontedit"), x_("fontstatus")
1091 };
1092 
1093 static FontRec gra_font[] =
1094 {
1095 	{(XFontStruct *)0,
1096 	 x_("-*-helvetica-medium-r-normal-*-8-*-*-*-*"),				/* 4 points */
1097 	 x_("-*-helvetica-medium-r-normal-*-8-*-*-*-*") FONTINIT},
1098 	{(XFontStruct *)0,
1099 	 x_("-*-helvetica-medium-r-normal-*-10-*-*-*-*"),				/* 6 points */
1100 	 x_("-*-helvetica-medium-r-normal-*-10-*-*-*-*") FONTINIT},
1101 	{(XFontStruct *)0,
1102 	 x_("-*-helvetica-medium-r-normal-*-12-*-*-*-*"),				/* 8 points */
1103 	 x_("-*-helvetica-medium-r-normal-*-12-*-*-*-*") FONTINIT},
1104 	{(XFontStruct *)0,
1105 	 x_("-*-helvetica-medium-r-normal-*-14-*-*-*-*"),				/* 10 points */
1106 	 x_("-*-helvetica-medium-r-normal-*-14-*-*-*-*") FONTINIT},
1107 	{(XFontStruct *)0,
1108 	 x_("-*-helvetica-medium-r-normal-*-17-*-*-*-*"),				/* 12 points */
1109 	 x_("-*-fixed-bold-r-normal-*-16-*-*-*-*") FONTINIT},
1110 	{(XFontStruct *)0,
1111 	 x_("-*-helvetica-medium-r-normal-*-18-*-*-*-*"),				/* 14 points */
1112 	 x_("-*-helvetica-medium-r-normal-*-18-*-*-*-*") FONTINIT},
1113 	{(XFontStruct *)0,
1114 	 x_("-*-helvetica-bold-r-normal-*-20-*-*-*-*"),					/* 16 points */
1115 	 x_("-*-fixed-medium-r-normal-*-20-*-*-*-*") FONTINIT},
1116 	{(XFontStruct *)0,
1117 	 x_("-*-helvetica-medium-r-normal-*-24-*-*-*-*"),				/* 18 points */
1118 	 x_("-*-helvetica-medium-r-normal-*-24-*-*-*-*") FONTINIT},
1119 	{(XFontStruct *)0,
1120 	 x_("-*-helvetica-bold-r-normal-*-25-*-*-*-*"),					/* 20 points */
1121 	 x_("-*-*-medium-r-normal-*-25-*-*-*-*") FONTINIT},
1122 	{(XFontStruct *)0,
1123 	 x_("-*-helvetica-bold-r-normal-*-*-120-*-*-*"),				/* MENU */
1124 	 x_("-*-helvetica-bold-r-normal-*-*-120-*-*-*") FONTINIT},
1125 	{(XFontStruct *)0,
1126 	 x_("-*-fixed-*-*-normal-*-*-120-*-*-*"),						/* EDIT */
1127 	 x_("-*-fixed-*-*-normal-*-*-120-*-*-*") FONTINIT},
1128 	{(XFontStruct *)0,
1129 	 x_("fixed"),													/* STATUS */
1130 	 x_("fixed") FONTINIT},
1131 	{(XFontStruct *)0, NULL, NULL FONTINIT}  					/* terminator */
1132 };
1133 
1134 void     gra_makefontchoices(CHAR1 **fontlist, INTBIG namecount, CHAR *required[14],
1135 			CHAR ****fchoices, INTBIG **fnumchoices, void *dia);
1136 int      gra_sortnumbereascending(const void *e1, const void *e2);
1137 static void gra_settextsize(WINDOWPART *win, INTBIG fnt, INTBIG face, INTBIG italic,
1138 			INTBIG bold, INTBIG underline, INTBIG rotation);
1139 #ifdef TRUETYPE
1140   INTBIG gra_getT1stringsize(CHAR *str, INTBIG *wid, INTBIG *hei);
1141 #endif
1142 
1143 #ifndef ANYDEPTH
1144 /****** rectangle saving ******/
1145 #define NOSAVEDBOX ((SAVEDBOX *)-1)
1146 typedef struct Isavedbox
1147 {
1148 	Pixmap      pix;
1149 	WINDOWPART *win;
1150 	INTBIG      code;
1151 	INTBIG      lx, hx, ly, hy;
1152 	struct Isavedbox *nextsavedbox;
1153 } SAVEDBOX;
1154 
1155 static SAVEDBOX     *gra_firstsavedbox = NOSAVEDBOX;
1156 static INTBIG        gra_savedboxcodes = 0;
1157 #endif
1158 
1159 /****** time ******/
1160 static Time          gra_lasttime = 0;			/* time of last click */
1161 static time_t        gra_timebasesec;
1162 #ifdef HAVE_FTIME
1163   static INTBIG      gra_timebasems;
1164 #endif
1165 
1166 /****** files ******/
1167 static void         *gra_fileliststringarray = 0;
1168 static CHAR          gra_curpath[255] = {0};
1169 static CHAR          gra_requiredextension[20];
1170 static CHAR         *gra_initialdirectory;
1171 static CHAR         *gra_logfile, *gra_logfilesave;
1172 static CHAR        **gra_printerlist;
1173 static INTBIG        gra_printerlistcount = 0;
1174 static INTBIG        gra_printerlisttotal = 0;
1175 static BOOLEAN       gra_fileselectdone;
1176 
1177 int        gra_fileselectall(const struct dirent *a);
1178 BOOLEAN    gra_addfiletolist(CHAR *file);
1179 void       gra_initfilelist(void);
1180 void       gra_setcurrentdirectory(CHAR *path);
1181 BOOLEAN    gra_addprinter(CHAR *buf);
1182 void       gra_fileselectcancel(Widget w, XtPointer client_data,
1183 			XmSelectionBoxCallbackStruct *call_data);
1184 void       gra_fileselectok(Widget w, XtPointer client_data,
1185 			XmSelectionBoxCallbackStruct *call_data);
1186 
1187 /******************** INITIALIZATION ********************/
1188 
main(int argc,CHAR1 * argv[])1189 int main(int argc, CHAR1 *argv[])
1190 {
1191 	/* catch signals if Electric trys to bomb out */
1192 	(void)signal(SIGILL, (SIGNALCAST)gra_sigill_trap);
1193 	(void)signal(SIGFPE, (SIGNALCAST)gra_sigfpe_trap);
1194 	(void)signal(SIGBUS, (SIGNALCAST)gra_sigbus_trap);
1195 	(void)signal(SIGSEGV, (SIGNALCAST)gra_sigsegv_trap);
1196 
1197 	/* primary initialization of Electric */
1198 	osprimaryosinit();
1199 
1200 #if LANGTCL
1201 	/* initialize TCL here */
1202 	if (gra_initializetcl() == TCL_ERROR)
1203 		error(_("Failed to initialize TCL: %s\n"), gra_tclinterp->result);
1204 #endif
1205 
1206 	/* secondary initialization of Electric */
1207 	ossecondaryinit(argc, argv);
1208 
1209 	/* add a timer that ticks TICKSPERSECOND times per second */
1210 	XtAppAddTimeOut(gra_xtapp, 1000/TICKSPERSECOND, gra_timerticked, 0);
1211 
1212 	/* now run Electric */
1213 	(void)XtAppAddWorkProc(gra_xtapp, (XtWorkProc)gra_dowork, 0);
1214 	XtAppMainLoop(gra_xtapp);
1215 	return(0);
1216 }
1217 
1218 /*
1219  * Routine to establish the default display define tty codes.
1220  */
graphicsoptions(CHAR * name,INTBIG * argc,CHAR1 ** argv)1221 void graphicsoptions(CHAR *name, INTBIG *argc, CHAR1 **argv)
1222 {
1223 	INTBIG ttydevice;
1224 
1225 	/* save command arguments */
1226 	gra_argc = *argc;
1227 	gra_argv = argv;
1228 
1229 	/* initialize keyboard input */
1230 	ttydevice = fileno(stdin);
1231 #ifdef HAVE_TERMIOS_H
1232 	{
1233 		struct termios sttybuf;
1234 		tcgetattr(ttydevice, &sttybuf);
1235 		us_erasech = sttybuf.c_cc[VERASE];
1236 		us_killch = sttybuf.c_cc[VKILL];
1237 	}
1238 #else
1239 #  ifdef HAVE_TERMIO_H
1240 	{
1241 		struct termio sttybuf;
1242 		(void)ioctl(ttydevice, TCGETA, &sttybuf);
1243 		us_erasech = sttybuf.c_cc[VERASE];
1244 		us_killch = sttybuf.c_cc[VKILL];
1245 	}
1246 #  else
1247 	{
1248 		struct sgttyb sttybuf;
1249 		(void)gtty(ttydevice, &sttybuf);
1250 		us_erasech = sttybuf.sg_erase;
1251 		us_killch = sttybuf.sg_kill;
1252 	}
1253 #  endif
1254 #endif
1255 }
1256 
1257 /*
1258  * Routine to initialize the display device.
1259  */
initgraphics(BOOLEAN messages)1260 BOOLEAN initgraphics(BOOLEAN messages)
1261 {
1262 	REGISTER INTBIG i, j, ac;
1263 	INTBIG bitmask, depth;
1264 	BOOLEAN wantmultiscreen, multiscreendebug;
1265 	int namecount;
1266 	CHAR *ptr;
1267 	CHAR1 **fontlist;
1268 	CHAR1 *geomSpec;
1269 	Pixmap pixm, pixmm;
1270 	Visual *visual;
1271 	Arg arg[10];
1272 	Widget dpywidget;
1273 #ifdef ANYDEPTH
1274 	GC gc;
1275 	XGCValues gcv;
1276 	XImage *image;
1277 	XFontStruct *thefont;
1278 	XCharStruct xcs;
1279 	int direction, asc, des;
1280 	UCHAR1 *dptr;
1281 	REGISTER INTBIG amt, k;
1282 	INTBIG width, height, x, y;
1283 	Pixmap textmap;
1284 #else
1285 	XVisualInfo vinfo;
1286 #endif
1287 	REGISTER void *infstr;
1288 
1289 	/* remember the initial directory and the log file locations */
1290 	(void)allocstring(&gra_initialdirectory, currentdirectory(), db_cluster);
1291 	infstr = initinfstr();
1292 	addstringtoinfstr(infstr, gra_initialdirectory);
1293 	addstringtoinfstr(infstr, x_(".electric.log"));
1294 	(void)allocstring(&gra_logfile, returninfstr(infstr), db_cluster);
1295 	infstr = initinfstr();
1296 	addstringtoinfstr(infstr, gra_initialdirectory);
1297 	addstringtoinfstr(infstr, x_(".electriclast.log"));
1298 	(void)allocstring(&gra_logfilesave, returninfstr(infstr), db_cluster);
1299 
1300 	/* initialize X and the toolkit */
1301 	(void)XSetErrorHandler(gra_xerrors);
1302 	XtToolkitInitialize();
1303 	gra_xtapp = XtCreateApplicationContext();
1304 	gra_intsignalid = XtAppAddSignal(gra_xtapp, (XtSignalCallbackProc)gra_intsignalfunc, 0);
1305 	gra_checkinginterrupt = FALSE;
1306 	gra_tracking = FALSE;
1307 
1308 	/* on machines with reverse byte ordering, fix the icon and the cursors */
1309 #ifdef BYTES_SWAPPED
1310 	j = PROGICONSIZE * PROGICONSIZE / 16;
1311 	for(i=0; i<j; i++)
1312 		gra_icon[i] = ((gra_icon[i] >> 8) & 0xFF) | ((gra_icon[i] << 8) & 0xFF00);
1313 	for(i=0; i<16; i++)
1314 	{
1315 		gra_realcursordata[i] = ((gra_realcursordata[i] >> 8) & 0xFF) |
1316 			((gra_realcursordata[i] << 8) & 0xFF00);
1317 		gra_realcursormask[i] = ((gra_realcursormask[i] >> 8) & 0xFF) |
1318 			((gra_realcursormask[i] << 8) & 0xFF00);
1319 		gra_nomousecursordata[i] = ((gra_nomousecursordata[i] >> 8) & 0xFF) |
1320 			((gra_nomousecursordata[i] << 8) & 0xFF00);
1321 		gra_nomousecursormask[i] = ((gra_nomousecursormask[i] >> 8) & 0xFF) |
1322 			((gra_nomousecursormask[i] << 8) & 0xFF00);
1323 		gra_drawcursordata[i] = ((gra_drawcursordata[i] >> 8) & 0xFF) |
1324 			((gra_drawcursordata[i] << 8) & 0xFF00);
1325 		gra_drawcursormask[i] = ((gra_drawcursormask[i] >> 8) & 0xFF) |
1326 			((gra_drawcursormask[i] << 8) & 0xFF00);
1327 		gra_nullcursordata[i] = ((gra_nullcursordata[i] >> 8) & 0xFF) |
1328 			((gra_nullcursordata[i] << 8) & 0xFF00);
1329 		gra_nullcursormask[i] = ((gra_nullcursormask[i] >> 8) & 0xFF) |
1330 			((gra_nullcursormask[i] << 8) & 0xFF00);
1331 		gra_menucursordata[i] = ((gra_menucursordata[i] >> 8) & 0xFF) |
1332 			((gra_menucursordata[i] << 8) & 0xFF00);
1333 		gra_menucursormask[i] = ((gra_menucursormask[i] >> 8) & 0xFF) |
1334 			((gra_menucursormask[i] << 8) & 0xFF00);
1335 		gra_handcursordata[i] = ((gra_handcursordata[i] >> 8) & 0xFF) |
1336 			((gra_handcursordata[i] << 8) & 0xFF00);
1337 		gra_handcursormask[i] = ((gra_handcursormask[i] >> 8) & 0xFF) |
1338 			((gra_handcursormask[i] << 8) & 0xFF00);
1339 		gra_techcursordata[i] = ((gra_techcursordata[i] >> 8) & 0xFF) |
1340 			((gra_techcursordata[i] << 8) & 0xFF00);
1341 		gra_techcursormask[i] = ((gra_techcursormask[i] >> 8) & 0xFF) |
1342 			((gra_techcursormask[i] << 8) & 0xFF00);
1343 		gra_ibeamcursordata[i] = ((gra_ibeamcursordata[i] >> 8) & 0xFF) |
1344 			((gra_ibeamcursordata[i] << 8) & 0xFF00);
1345 		gra_ibeamcursormask[i] = ((gra_ibeamcursormask[i] >> 8) & 0xFF) |
1346 			((gra_ibeamcursormask[i] << 8) & 0xFF00);
1347 		gra_lrcursordata[i] = ((gra_lrcursordata[i] >> 8) & 0xFF) |
1348 			((gra_lrcursordata[i] << 8) & 0xFF00);
1349 		gra_lrcursormask[i] = ((gra_lrcursormask[i] >> 8) & 0xFF) |
1350 			((gra_lrcursormask[i] << 8) & 0xFF00);
1351 		gra_udcursordata[i] = ((gra_udcursordata[i] >> 8) & 0xFF) |
1352 			((gra_udcursordata[i] << 8) & 0xFF00);
1353 		gra_udcursormask[i] = ((gra_udcursormask[i] >> 8) & 0xFF) |
1354 			((gra_udcursormask[i] << 8) & 0xFF00);
1355 	}
1356 #endif
1357 
1358 	/* get switch settings */
1359 	wantmultiscreen = multiscreendebug = FALSE;
1360 	geomSpec = b_("");
1361 	for(i=1; i < gra_argc; i++)
1362 	{
1363 		if (gra_argv[i][0] == '-')
1364 		{
1365 			switch (gra_argv[i][1])
1366 			{
1367 				case 'M':
1368 					multiscreendebug = TRUE;
1369 				case 'm':
1370 					wantmultiscreen = TRUE;
1371 					continue;
1372 
1373 				case 'g':       /* Geometry */
1374 					if (++i >= gra_argc) continue;
1375 					geomSpec = gra_argv[i];
1376 					continue;
1377 			}
1378 		}
1379 	}
1380 
1381 	/* find the displays for the edit and messages windows */
1382 	gra_finddisplays(wantmultiscreen, multiscreendebug);
1383 
1384 	/* double-click threshold (in milliseconds) */
1385 	gra_doublethresh = XtGetMultiClickTime(gra_maindpy);
1386 
1387 	/* get the information about the edit display */
1388 	depth = DefaultDepth(gra_maindpy, gra_mainscreen);
1389 	if (depth == 1)
1390 		efprintf(stderr, _("Cannot run on 1-bit deep displays\n"));
1391 	el_colcursor = CURSOR;	/* also done in usr.c later */
1392 #ifdef ANYDEPTH
1393 	el_maplength = 256;
1394 #else
1395 	el_maplength = DisplayCells(gra_maindpy, gra_mainscreen);
1396 	gra_maphigh = el_maplength - 1;
1397 #endif
1398 	resetpaletteparameters();
1399 
1400 	/* Determine initial position and size of edit window */
1401 	gra_editxsh = XAllocSizeHints();
1402 	if (geomSpec == NULL) geomSpec = XGetDefault(gra_maindpy, b_("Electric"), b_("geometry"));
1403 	if (geomSpec[0] != 0)
1404 	{
1405 		/* use defaults from database */
1406 		bitmask = XWMGeometry(gra_maindpy, gra_mainscreen, geomSpec, NULL, 1, gra_editxsh,
1407 			&gra_editxsh->x, &gra_editxsh->y, &gra_editxsh->width, &gra_editxsh->height,
1408 			&gra_editxsh->win_gravity);
1409 		if (bitmask & (XValue | YValue)) gra_editxsh->flags |= USPosition;
1410 		if (bitmask & (WidthValue | HeightValue)) gra_editxsh->flags |= USSize;
1411 	} else
1412 	{
1413 		/* nothing in defaults database */
1414 		gra_editxsh->flags = PPosition | PSize;
1415 		gra_editxsh->height = DisplayHeight(gra_maindpy, gra_mainscreen) - 2;
1416 		gra_editxsh->width = DisplayWidth(gra_maindpy, gra_mainscreen) - PALETTEWIDTH - 8;
1417 		if (gra_maindpy == gra_altdpy)
1418 		{
1419 			/* all on one screen */
1420 			gra_editxsh->height = gra_editxsh->height / 4 * 3;
1421 		} else
1422 		{
1423 			/* two screens */
1424 			gra_editxsh->height = DisplayHeight(gra_maindpy, gra_mainscreen) - 24;
1425 		}
1426 		gra_editxsh->width = gra_editxsh->width / 5 * 4;
1427 		gra_editxsh->height = gra_editxsh->height / 5 * 4;
1428 		gra_editxsh->x = PALETTEWIDTH;
1429 		gra_editxsh->y = 0;
1430 	}
1431 	gra_editposx = gra_editxsh->x;
1432 	gra_editposy = gra_editxsh->y;
1433 	gra_editsizex = gra_editxsh->width;
1434 	gra_editsizey = gra_editxsh->height;
1435 	if (gra_editsizex > gra_editsizey*2)
1436 	{
1437 		/* probably two windows next to each other */
1438 		gra_editsizex /= 2;
1439 	} else if (gra_editsizey > gra_editsizex*2)
1440 	{
1441 		/* probably two windows above each other */
1442 		gra_editsizey /= 2;
1443 	}
1444 	gra_windownumber = 0;
1445 
1446 	/* disable drag-and-drop (because it crashes for some unknown reason) */
1447 	dpywidget = XmGetXmDisplay(gra_maindpy);
1448 	ac = 0;
1449 	XtSetArg(arg[ac], XmNdragInitiatorProtocolStyle, XmDRAG_NONE);   ac++;
1450 	XtSetArg(arg[ac], XmNdragReceiverProtocolStyle, XmDRAG_NONE);   ac++;
1451 	XtSetValues(dpywidget, arg, ac);
1452 	if (gra_altdpy != gra_maindpy)
1453 	{
1454 		dpywidget = XmGetXmDisplay(gra_altdpy);
1455 		ac = 0;
1456 		XtSetArg(arg[ac], XmNdragInitiatorProtocolStyle, XmDRAG_NONE);   ac++;
1457 		XtSetArg(arg[ac], XmNdragReceiverProtocolStyle, XmDRAG_NONE);   ac++;
1458 		XtSetValues(dpywidget, arg, ac);
1459 	}
1460 
1461 	/* get atoms for disabling window kills, switching displays */
1462 	gra_wm_delete_window = XmInternAtom(gra_maindpy, b_("WM_DELETE_WINDOW"), False);
1463 	gra_movedisplayprotocol = XmInternAtom(gra_maindpy, b_("_MOVE_DISPLAYS"), False);
1464 	gra_movedisplaymsg = XmInternAtom(gra_maindpy, b_("_MOTIF_WM_MESSAGES"), False);
1465 
1466 #ifdef ANYDEPTH
1467 	visual = DefaultVisual(gra_maindpy, gra_mainscreen);
1468 	if (VisualClass(visual) == PseudoColor || VisualClass(visual) == StaticColor)
1469 		gra_maincolmap = DefaultColormap(gra_maindpy, gra_mainscreen);
1470 	if (visual->red_mask == 0xFF) gra_mainredshift = 0; else
1471 		if (visual->red_mask == 0xFF00) gra_mainredshift = 8; else
1472 			if (visual->red_mask == 0xFF0000) gra_mainredshift = 16;
1473 	if (visual->green_mask == 0xFF) gra_maingreenshift = 0; else
1474 		if (visual->green_mask == 0xFF00) gra_maingreenshift = 8; else
1475 			if (visual->green_mask == 0xFF0000) gra_maingreenshift = 16;
1476 	if (visual->blue_mask == 0xFF) gra_mainblueshift = 0; else
1477 		if (visual->blue_mask == 0xFF00) gra_mainblueshift = 8; else
1478 			if (visual->blue_mask == 0xFF0000) gra_mainblueshift = 16;
1479 	if (gra_maindpy != gra_altdpy)
1480 	{
1481 		visual = DefaultVisual(gra_altdpy, gra_altscreen);
1482 		if (VisualClass(visual) == PseudoColor || VisualClass(visual) == StaticColor)
1483 			gra_altcolmap = DefaultColormap(gra_altdpy, gra_altscreen);
1484 		if (visual->red_mask == 0xFF) gra_altredshift = 0; else
1485 			if (visual->red_mask == 0xFF00) gra_altredshift = 8; else
1486 				if (visual->red_mask == 0xFF0000) gra_altredshift = 16;
1487 		if (visual->green_mask == 0xFF) gra_altgreenshift = 0; else
1488 			if (visual->green_mask == 0xFF00) gra_altgreenshift = 8; else
1489 				if (visual->green_mask == 0xFF0000) gra_altgreenshift = 16;
1490 		if (visual->blue_mask == 0xFF) gra_altblueshift = 0; else
1491 			if (visual->blue_mask == 0xFF00) gra_altblueshift = 8; else
1492 				if (visual->blue_mask == 0xFF0000) gra_altblueshift = 16;
1493 	}
1494 #else
1495 	/* Some servers change the default screen to StaticColor class, so that
1496 	 * Electric cannot change the color map.  Try to find one that can be used.
1497 	 */
1498 	if (depth > 1)
1499 	{
1500 		visual = DefaultVisual(gra_maindpy, gra_mainscreen);
1501 		if (VisualClass(visual) != PseudoColor)
1502 		{
1503 			/* look for pseudo color only for now */
1504 			if (XMatchVisualInfo(gra_maindpy, gra_mainscreen, depth, PseudoColor, &vinfo))
1505 			{
1506 				visual = vinfo.visual;
1507 			} else
1508 			{
1509 				efprintf(stderr, _("Cannot find 8-bit PseudoColor visual, try building with 'ANYDEPTH'\n"));
1510 			}
1511 		}
1512 	}
1513 #endif
1514 
1515 	/* get fonts */
1516 #ifdef TRUETYPE
1517 	for(i=0; i<FONTHASHSIZE; i++) gra_fonthash[i].descent = 1;
1518 	if (T1_SetBitmapPad(16) == 0 && T1_InitLib(NO_LOGFILE) != 0)
1519 	{
1520 		gra_truetypeon = 1;
1521 
1522 		/* Preload T1 fonts here, because T1_LoadFont spoils memory */
1523 		for(j=0; j<T1_GetNoFonts(); j++) T1_LoadFont(j);
1524 
1525 		gra_truetypedeffont = 0;		/* presume that the first font is good to use */
1526 		ptr = egetenv(x_("ELECTRIC_TRUETYPE_FONT"));
1527 		if (ptr != NULL)
1528 		{
1529 			j = T1_GetNoFonts();
1530 			for(gra_truetypedeffont=0; gra_truetypedeffont<j; gra_truetypedeffont++)
1531 			{
1532 				T1_LoadFont(gra_truetypedeffont);
1533 				if (namesame(ptr, string2byte(T1_GetFontName(gra_truetypedeffont))) == 0) break;
1534 			}
1535 			if (gra_truetypedeffont >= j)
1536 			{
1537 				infstr = initinfstr();
1538 				formatinfstr(infstr,
1539 					_("Warning: environment variable 'ELECTRIC_TRUETYPE_FONT' is '%s' which is not a truetype font.  Choices are:"),
1540 						ptr);
1541 				printf(b_("%s\n"), string1byte(returninfstr(infstr)));
1542 
1543 				for(gra_truetypedeffont=0; gra_truetypedeffont<j; gra_truetypedeffont++)
1544 				{
1545 					T1_LoadFont(gra_truetypedeffont);
1546 					printf(b_("  %s\n"), T1_GetFontName(gra_truetypedeffont));
1547 				}
1548 				gra_truetypedeffont = 0;
1549 			}
1550 		}
1551 	} else
1552 	{
1553 		gra_truetypeon = 0;
1554 		efprintf(stderr, _("Cannot load TrueType, is T1LIB_CONFIG set?\n"));
1555 	}
1556 #endif
1557 	gra_defaultFont.fontname = string2byte(XGetDefault(gra_maindpy, b_("Electric"), b_("font")));
1558 	if (gra_defaultFont.fontname == NULL) gra_defaultFont.fontname = DEFAULTFONTNAME;
1559 	gra_defaultFont.font = XLoadQueryFont(gra_maindpy, string1byte(gra_defaultFont.fontname));
1560 	if (gra_defaultFont.font == NULL)
1561 		efprintf(stderr, _("Cannot open default font \"%s\"\n"), gra_defaultFont.fontname);
1562 	for(i=0; gra_font[i].fontname != 0; i++)
1563 	{
1564 		/*
1565 		 * Check the .Xdefaults or .Xresources file for a value for each of the
1566 		 * requested fonts; they will have resource names .Font4, .Font6,...
1567 		 * .FontStatus. Look for a matching font, if found, use it; otherwise look
1568 		 * for the font that is hard-coded.
1569 		 */
1570 		ptr = string2byte(XGetDefault(gra_maindpy, b_("Electric"), string1byte(gra_resource_fontname[i])));
1571 		if (ptr != NULL)
1572 		{
1573 			fontlist = XListFonts(gra_maindpy, string1byte(ptr), 10, &namecount);
1574 			if (namecount == 0)
1575 			{
1576 				/* server could not find a match */
1577 				efprintf(stderr, _("Cannot find font '%s', using '%s'\n"),
1578 					ptr, gra_font[i].fontname);
1579 			} else
1580 			{
1581 				/* replace the default (this is for debugging only) */
1582 				(void)allocstring(&gra_font[i].fontname, string2byte(fontlist[0]), db_cluster);
1583 			}
1584 		} else
1585 		{
1586 			fontlist = XListFonts(gra_maindpy, string1byte(gra_font[i].fontname), 1, &namecount);
1587 			if (namecount == 0)
1588 			{
1589 				fontlist = XListFonts(gra_maindpy, string1byte(gra_font[i].altfontname), 1, &namecount);
1590 			}
1591 		}
1592 
1593 		if (namecount != 0)
1594 		{
1595 			/* at least one version should have worked */
1596 			gra_font[i].font = XLoadQueryFont(gra_maindpy, fontlist[0]);
1597 			XFreeFontNames(fontlist);
1598 		}
1599 
1600 		if (gra_font[i].font == NULL)
1601 		{
1602 			efprintf(stderr, _("Cannot find font '%s', using default\n"),
1603 				gra_font[i].fontname);
1604 			efprintf(stderr, _("  To avoid this message, add the following line to your .Xdefaults file:\n"));
1605 			efprintf(stderr, M_("    Electric.%s: CORRECT-FONT-NAME\n"), gra_resource_fontname[i]);
1606 			gra_font[i].font = gra_defaultFont.font;
1607 		}
1608 	}
1609 	if (gra_font[11].font != NULL)
1610 	{
1611 		gra_messages_font.font = gra_font[11].font;
1612 		gra_messages_font.fontname = gra_font[11].fontname;
1613 	}
1614 
1615 	/* make the messages window */
1616 	gra_makemessageswindow();
1617 
1618 	/* create the cursors */
1619 	gra_xfc.flags = gra_xbc.flags = DoRed | DoGreen | DoBlue;
1620 	XQueryColor(gra_topmsgdpy, DefaultColormap(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy)),
1621 		&gra_xfc);
1622 	XQueryColor(gra_topmsgdpy, DefaultColormap(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy)),
1623 		&gra_xbc);
1624 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_realcursordata, 16, 16);
1625 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_realcursormask, 16, 16);
1626 	gra_realcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 8, 8);
1627 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_nomousecursordata, 16, 16);
1628 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_nomousecursormask, 16, 16);
1629 	gra_nomousecursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 8, 8);
1630 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_drawcursordata, 16, 16);
1631 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_drawcursormask, 16, 16);
1632 	gra_drawcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc,  &gra_xbc, 0, 16);
1633 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_nullcursordata, 16, 16);
1634 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_nullcursormask, 16, 16);
1635 	gra_nullcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 8, 8);
1636 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_menucursordata, 16, 16);
1637 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_menucursormask, 16, 16);
1638 	gra_menucursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 16, 8);
1639 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_handcursordata, 16, 16);
1640 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_handcursormask, 16, 16);
1641 	gra_handcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 0, 10);
1642 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_techcursordata, 16, 16);
1643 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_techcursormask, 16, 16);
1644 	gra_techcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 8, 0);
1645 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_ibeamcursordata, 16, 16);
1646 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_ibeamcursormask, 16, 16);
1647 	gra_ibeamcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 8, 8);
1648 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_lrcursordata, 16, 16);
1649 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_lrcursormask, 16, 16);
1650 	gra_lrcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 8, 8);
1651 	pixm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_udcursordata, 16, 16);
1652 	pixmm = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin, (const CHAR1 *)gra_udcursormask, 16, 16);
1653 	gra_udcursor = XCreatePixmapCursor(gra_topmsgdpy, pixm, pixmm, &gra_xfc, &gra_xbc, 8, 8);
1654 
1655 #ifdef ANYDEPTH
1656 	/* precache font bits */
1657 	depth = DefaultDepth(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy));
1658 	textmap = XCreatePixmap(gra_topmsgdpy, gra_topmsgwin, 100, 100, depth);
1659 	if (textmap == 0)
1660 	{
1661 		efprintf(stderr, _("Error allocating initial text pixmap\n"));
1662 		exitprogram();
1663 	}
1664 	gcv.foreground = BlackPixel(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy));
1665 	gc = XtGetGC(gra_messageswidget, GCForeground, &gcv);
1666 	for(i=0; gra_font[i].fontname != 0; i++)
1667 	{
1668 		thefont = gra_font[i].font;
1669 		XSetFont(gra_topmsgdpy, gc, thefont->fid);
1670 		for(j=0; j<128; j++)
1671 		{
1672 			gra_localstring[0] = (j < ' ' ? ' ' : (CHAR)j);
1673 			gra_localstring[1] = 0;
1674 			XTextExtents(thefont, string1byte(gra_localstring), 1, &direction, &asc, &des, &xcs);
1675 			width = xcs.width;
1676 			height = thefont->ascent + thefont->descent;
1677 			gra_font[i].width[j] = width;
1678 			gra_font[i].height[j] = height;
1679 			amt = width * height;
1680 			if (amt == 0) { gra_font[i].data[j] = 0;   continue; }
1681 			gra_font[i].data[j] = (UCHAR1 *)emalloc(amt, us_tool->cluster);
1682 			if (gra_font[i].data[j] == 0)
1683 			{
1684 				efprintf(stderr, _("Error allocating %ld bytes for font data\n"), amt);
1685 				exitprogram();
1686 			}
1687 			for(k=0; k<amt; k++) gra_font[i].data[j][k] = 0;
1688 			XSetForeground(gra_topmsgdpy, gc, 0);
1689 			XFillRectangle(gra_topmsgdpy, textmap, gc, 0, 0, 100, 100);
1690 			XSetForeground(gra_topmsgdpy, gc, 0xFFFFFF);
1691 			XDrawString(gra_topmsgdpy, textmap, gc, 0,
1692 				height-thefont->descent, string1byte(gra_localstring), 1);
1693 			image = XGetImage(gra_topmsgdpy, textmap, 0, 0, width, height,
1694 				AllPlanes, ZPixmap);
1695 			if (image == 0)
1696 			{
1697 				efprintf(stderr, _("Error allocating %ldx%ld image for fonts\n"),
1698 					width, height);
1699 				exitprogram();
1700 			}
1701 			dptr = gra_font[i].data[j];
1702 			for(y=0; y<height; y++)
1703 			{
1704 				for(x=0; x<width; x++)
1705 					*dptr++ = (XGetPixel(image, x, y) == 0) ? 0 : 1;
1706 			}
1707 			XDestroyImage(image);
1708 		}
1709 	}
1710 	XtReleaseGC(gra_messageswidget, gc);
1711 #endif
1712 
1713 	/* allocate space for the full-depth buffer on the main display */
1714 	if (gra_makewindowdisplaybuffer(&gra_mainwd, gra_maindpy)) exitprogram();
1715 
1716 	/* allocate space for the full-depth buffer on the alternate display */
1717 	if (gra_maindpy != gra_altdpy)
1718 	{
1719 		if (gra_makewindowdisplaybuffer(&gra_altwd, gra_altdpy)) exitprogram();
1720 	}
1721 
1722 #ifndef ANYDEPTH
1723 	/*
1724 	 * See if there are enought X-Server resources for backing store.
1725 	 * To request this, declare the X resource "Electric.retained:True"
1726 	 * in the .Xdefaults or equivalent file before starting.
1727 	 */
1728 	gra_use_backing = FALSE;
1729 	ptr = XGetDefault(gra_maindpy, x_("Electric"), x_("retained"));
1730 	if (ptr != NULL)
1731 	{
1732 		if (namesamen(ptr, x_("True"), 4) == 0)
1733 		{
1734 			if (DoesBackingStore(ScreenOfDisplay(gra_maindpy, gra_mainscreen)))
1735 				gra_use_backing = TRUE; else
1736 			{
1737 				efprintf(stderr, _("Backing Store is not available.\n"));
1738 				efprintf(stderr, _("  To avoid this message, remove this line from your .Xdefaults file:\n"));
1739 				efprintf(stderr, M_("    Electric.retained:True\n"));
1740 			}
1741 		}
1742 	}
1743 #endif
1744 
1745 	/* initialize the window frames */
1746 	el_firstwindowframe = el_curwindowframe = NOWINDOWFRAME;
1747 
1748 	/* initialize the mouse */
1749 	us_cursorstate = -1;
1750 	us_normalcursor = NORMALCURSOR;
1751 	setdefaultcursortype(us_normalcursor);
1752 	gra_inputstate = NOEVENT;
1753 	gra_eventqueuehead = gra_eventqueuetail = gra_eventqueue;
1754 
1755 	return(FALSE);
1756 }
1757 
1758 /*
1759  * Routine to establish the displays for edit and messages and fill the globals:
1760  *   gra_maindpy
1761  *   gra_altdpy
1762  */
gra_finddisplays(BOOLEAN wantmultiscreen,BOOLEAN multiscreendebug)1763 void gra_finddisplays(BOOLEAN wantmultiscreen, BOOLEAN multiscreendebug)
1764 {
1765 	CHAR displayname[200], maindisplayname[200], altdisplayname[200];
1766 	INTBIG numfiles, maxdispnum, i, j;
1767 	REGISTER INTBIG pixels, bestpixels, secondbestpixels, scr, graphicsheight, graphicswidth, dep;
1768 	CHAR **filelist, *eprogramname;
1769 	int argc;
1770 	Display *dpy;
1771 	CHAR *scrnumpos;
1772 
1773 	/* set default displays for edit and messages windows */
1774 	estrcpy(displayname, string2byte(XDisplayName(NULL)));
1775 	scrnumpos = displayname + estrlen(displayname) - 1;
1776 	estrcpy(maindisplayname, displayname);
1777 	estrcpy(altdisplayname, displayname);
1778 	if (multiscreendebug) printf(b_("Main display is %s\n"), displayname);
1779 
1780 	/* determine the height of the main display */
1781 	dpy = XOpenDisplay(string1byte(displayname));
1782 	if (dpy == NULL) gra_shortestscreen = 600; else
1783 	{
1784 		scr = DefaultScreen(dpy);
1785 		gra_shortestscreen = DisplayHeight(dpy, scr);
1786 	}
1787 
1788 	/* if multiple screens requested, search for them */
1789 	maxdispnum = 0;
1790 	if (wantmultiscreen)
1791 	{
1792 		/* count the number of displays (look for files named "/dev/fb*") */
1793 		numfiles = filesindirectory(x_("/dev"), &filelist);
1794 		for(i=0; i<numfiles; i++)
1795 		{
1796 			if (filelist[i][0] == 'f' && filelist[i][1] == 'b')
1797 			{
1798 				j = eatoi(&filelist[i][2]);
1799 				if (j > maxdispnum) maxdispnum = j;
1800 			}
1801 		}
1802 
1803 		/* if there are multiple displays, select the best for edit and messages */
1804 		if (maxdispnum > 0)
1805 		{
1806 			bestpixels = 0;
1807 			secondbestpixels = 0;
1808 			for(i=0; i<=maxdispnum; i++)
1809 			{
1810 				esnprintf(scrnumpos, 100, x_("%ld"), i);
1811 				dpy = XOpenDisplay(string1byte(displayname));
1812 				if (dpy == NULL) continue;
1813 				scr = DefaultScreen(dpy);
1814 				dep = DefaultDepth(dpy, scr);
1815 				graphicsheight = DisplayHeight(dpy, scr);
1816 				graphicswidth = DisplayWidth(dpy, scr);
1817 				if (graphicsheight < gra_shortestscreen) gra_shortestscreen = graphicsheight;
1818 				if (multiscreendebug)
1819 				{
1820 					Visual *visual;
1821 					CHAR *vistype;
1822 
1823 					visual = DefaultVisual(dpy, scr);
1824 					if (VisualClass(visual) == PseudoColor) vistype = x_("pseudo"); else
1825 						if (VisualClass(visual) == StaticColor) vistype = x_("static"); else
1826 							vistype = x_("direct");
1827 					printf(b_("Display on screen %s(%ld) is %ldx%ld, %ld-bit %s color\n"),
1828 						displayname, scr, graphicswidth, graphicsheight, dep, vistype);
1829 				}
1830 				pixels = graphicsheight * graphicswidth * dep;
1831 				if (pixels > bestpixels)
1832 				{
1833 					if (bestpixels > secondbestpixels)
1834 					{
1835 						secondbestpixels = bestpixels;
1836 						estrcpy(altdisplayname, maindisplayname);
1837 					}
1838 					bestpixels = pixels;
1839 					estrcpy(maindisplayname, displayname);
1840 				} else if (pixels > secondbestpixels)
1841 				{
1842 					secondbestpixels = pixels;
1843 					estrcpy(altdisplayname, displayname);
1844 				}
1845 				XCloseDisplay(dpy);
1846 			}
1847 		}
1848 	}
1849 
1850 	/* open the display for the edit window */
1851 	argc = 0;
1852 #ifdef EPROGRAMNAME
1853 	eprogramname = string2byte(EPROGRAMNAME);
1854 #else
1855 	eprogramname = x_("Electric");
1856 #endif
1857 	gra_maindpy = XtOpenDisplay(gra_xtapp, string1byte(maindisplayname), NULL,
1858 		string1byte(eprogramname), NULL, 0, &argc, NULL);
1859 	if (gra_maindpy == NULL)
1860 	{
1861 		efprintf(stderr, _("Cannot open main display %s\n"), maindisplayname);
1862 		exitprogram();
1863 	}
1864 
1865 	/* open the display for the messages window */
1866 	if (estrcmp(maindisplayname, altdisplayname) == 0) gra_altdpy = gra_maindpy; else
1867 	{
1868 		gra_altdpy = XtOpenDisplay(gra_xtapp, string1byte(altdisplayname), NULL,
1869 			string1byte(eprogramname), NULL, 0, &argc, NULL);
1870 		if (gra_altdpy == NULL)
1871 		{
1872 			efprintf(stderr, _("Cannot open alternate display %s\n"), altdisplayname);
1873 			exitprogram();
1874 		}
1875 	}
1876 	gra_mainscreen = DefaultScreen(gra_maindpy);
1877 	gra_altscreen = DefaultScreen(gra_altdpy);
1878 	if (multiscreendebug)
1879 		printf(b_("So main screen is %s, alternate is %s\n"), maindisplayname, altdisplayname);
1880 }
1881 
1882 /*
1883  * Routine to create the messages window.
1884  */
gra_makemessageswindow(void)1885 void gra_makemessageswindow(void)
1886 {
1887 	XTextProperty swintitle, sicontitle;
1888 	XWMHints *xwmh;
1889 	XSizeHints *xsh;
1890 	Arg arg[10];
1891 	REGISTER INTBIG ac, screenmw, screenmh, j, msgwidth, msgheight;
1892 	CHAR *title;
1893 	CHAR1 *title1, title1byte[200];
1894 	Cursor ibeam;
1895 
1896 	/* Determine initial position and size of messages window */
1897 	screenmw = DisplayWidth(gra_altdpy, gra_altscreen);
1898 	screenmh = DisplayHeight(gra_altdpy, gra_altscreen);
1899 	xsh = XAllocSizeHints();
1900 	j = gra_messages_font.font->descent + gra_messages_font.font->ascent + MESLEADING;
1901 	gra_status_height = MAXSTATUSLINES * j + 4;
1902 	xsh->width = screenmh / 3 * 2;
1903 	xsh->height = screenmh / 4 - 80;
1904 	xsh->x = (screenmw - xsh->width) / 2;
1905 	xsh->y = screenmh - xsh->height - 52;
1906 	xsh->min_width = 0;
1907 	xsh->min_height = 0;
1908 	xsh->flags = (PPosition | PSize | PMinSize);
1909 	msgwidth = xsh->width;
1910 	msgheight = xsh->height;
1911 
1912 	/* make second top-level shell for messages */
1913 	gra_msgtoplevelwidget = XtAppCreateShell(b_("Electric"), b_("electric"),
1914 		applicationShellWidgetClass, gra_altdpy, NULL, 0);
1915 	if (gra_msgtoplevelwidget == 0)
1916 	{
1917 		efprintf(stderr, _("Cannot make messages window\n"));
1918 		exitprogram();
1919 	}
1920 	ac = 0;
1921 	XtSetArg(arg[ac], XtNx, xsh->x);   ac++;
1922 	XtSetArg(arg[ac], XtNy, xsh->y);   ac++;
1923 	XtSetArg(arg[ac], XtNwidth, msgwidth);   ac++;
1924 	XtSetArg(arg[ac], XtNheight, msgheight);   ac++;
1925 	XtSetArg(arg[ac], XmNdeleteResponse,  XmDO_NOTHING);   ac++;
1926 	XtSetArg(arg[ac], XmNmwmFunctions,    MWM_FUNC_RESIZE|MWM_FUNC_MOVE|MWM_FUNC_MINIMIZE|MWM_FUNC_MAXIMIZE);   ac++;
1927 #ifdef ANYDEPTH
1928 	XtSetArg(arg[ac], XtNbackground, WHITE);   ac++;
1929 	XtSetArg(arg[ac], XtNforeground, BLACK);   ac++;
1930 #endif
1931 	XtSetValues(gra_msgtoplevelwidget, arg, ac);
1932 
1933 	/* make text widget for messages */
1934 	ac = 0;
1935 	XtSetArg(arg[ac], XmNeditable,   True);   ac++;
1936 	XtSetArg(arg[ac], XmNeditMode,   XmMULTI_LINE_EDIT);   ac++;
1937 	XtSetArg(arg[ac], XmNcolumns,    80);   ac++;
1938 	XtSetArg(arg[ac], XmNrows,       10);   ac++;
1939 	gra_messageswidget = (Widget)XmCreateScrolledText(gra_msgtoplevelwidget,
1940 		b_("messages"), arg, ac);
1941 	if (gra_messageswidget == 0)
1942 	{
1943 		efprintf(stderr, _("Cannot make messages widget\n"));
1944 		exitprogram();
1945 	}
1946 	XtManageChild(gra_messageswidget);
1947 	XtAddEventHandler(gra_messageswidget, KeyPressMask | VisibilityChangeMask |
1948 		ExposureMask | FocusChangeMask, FALSE, gra_messages_event_handler, NULL);
1949 	XtRealizeWidget(gra_msgtoplevelwidget);
1950 
1951 	gra_topmsgwin = XtWindow(gra_msgtoplevelwidget);
1952 	gra_topmsgdpy = XtDisplay(gra_msgtoplevelwidget);
1953 	gra_messages_obscured = FALSE;
1954 	gra_messages_typingin = FALSE;
1955 #if 0
1956 	{
1957 	XSetWindowAttributes xswa;
1958 	Pixel fg, bg;
1959 	XColor xc;
1960 
1961 	gra_messagescolormap = XCreateColormap(gra_topmsgdpy, gra_topmsgwin,
1962 		DefaultVisual(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy)), AllocNone);
1963 	xswa.colormap = gra_messagescolormap;
1964 	XChangeWindowAttributes(gra_topmsgdpy, gra_topmsgwin, CWColormap, &xswa);
1965 	XtVaGetValues(gra_messageswidget, XtNbackground, &bg, XtNforeground, &fg, NULL);
1966 	printf(b_("initial fg=%d bg=%d\n"), fg, bg);
1967 	xc.flags = DoRed | DoGreen | DoBlue;
1968 	xc.pixel = bg;
1969 	XAllocColor(gra_topmsgdpy, gra_messagescolormap, &xc);
1970 	xc.flags = DoRed | DoGreen | DoBlue;
1971 	xc.pixel = fg;
1972 	XAllocColor(gra_topmsgdpy, gra_messagescolormap, &xc);
1973 	}
1974 #endif
1975 	/* set I-beam cursor */
1976 	ibeam = XCreateFontCursor(gra_topmsgdpy, XC_xterm);
1977 	XDefineCursor(gra_topmsgdpy, gra_topmsgwin, ibeam);
1978 
1979 	/* make the program icon */
1980 	gra_programicon = XCreateBitmapFromData(gra_topmsgdpy, gra_topmsgwin,
1981 		(const CHAR1 *)gra_icon, PROGICONSIZE, PROGICONSIZE);
1982 	if (gra_programicon == 0)
1983 	{
1984 		efprintf(stderr, _("Cannot make program icon\n"));
1985 		exitprogram();
1986 	}
1987 
1988 	/* load window manager information */
1989 #ifdef EPROGRAMNAME
1990 	title = string2byte(EPROGRAMNAME);
1991 #else
1992 	title = x_("Electric");
1993 #endif
1994 	(void)esnprintf(gra_localstring, MAXLOCALSTRING, _("%s Messages"), title);
1995 	strcpy(title1byte, string1byte(gra_localstring));
1996 	title1 = title1byte;
1997 	XStringListToTextProperty(&title1, 1, &swintitle);
1998 
1999 	(void)estrcpy(gra_localstring, _("Messages"));
2000 	strcpy(title1byte, string1byte(gra_localstring));
2001 	title1 = title1byte;
2002 	XStringListToTextProperty(&title1, 1, &sicontitle);
2003 
2004 	xwmh = XAllocWMHints();
2005 	xwmh->input = True;
2006 	xwmh->initial_state = NormalState;
2007 	xwmh->icon_pixmap = xwmh->icon_mask = gra_programicon;
2008 	xwmh->flags = InputHint | StateHint | IconPixmapHint;
2009 	XSetWMProperties(gra_topmsgdpy, gra_topmsgwin, &swintitle, &sicontitle,
2010 		gra_argv, gra_argc, xsh, xwmh, NULL);
2011 	XFree(xsh);
2012 	XFree(xwmh);
2013 
2014 	/* set up to trap window kills */
2015 	XmAddWMProtocolCallback(gra_msgtoplevelwidget, gra_wm_delete_window,
2016 		(XtCallbackProc)gra_windowdelete, (XtPointer)gra_messageswidget);
2017 
2018 #if 0	/* This code used to be part of the !(ANYDEPTH) case (Dmitry Nadezchin) */
2019 	XSetWindowAttributes xswa;
2020 
2021 	/* setup properties of the messages window */
2022 	xswa.background_pixel = WhitePixel(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy));
2023 	xswa.border_pixel = BlackPixel(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy));
2024 	xswa.bit_gravity = NorthWestGravity;
2025 	if (gra_use_backing)
2026 	{
2027 		xswa.backing_store = Always;
2028 		xswa.backing_pixel = xswa.background_pixel;
2029 		xswa.backing_planes = AllPlanes;
2030 	}
2031 	if (DoesSaveUnders(ScreenOfDisplay(gra_altdpy, gra_altscreen)))
2032 		xswa.save_under = True;
2033 	XChangeWindowAttributes(gra_topmsgdpy, gra_topmsgwin, CWColormap, &xswa);
2034 #endif
2035 }
2036 
2037 #if LANGTCL
gra_initializetcl(void)2038 INTBIG gra_initializetcl(void)
2039 {
2040 	INTBIG err;
2041 	CHAR *newArgv[2];
2042 
2043 	/* set the program name/path */
2044 	newArgv[0] = x_("Electric");
2045 	newArgv[1] = NULL;
2046 	(void)Tcl_FindExecutable(newArgv[0]);
2047 
2048 	gra_tclinterp = Tcl_CreateInterp();
2049 	if (gra_tclinterp == 0) error(_("from Tcl_CreateInterp"));
2050 
2051 	/* tell Electric the TCL interpreter handle */
2052 	el_tclinterpreter(gra_tclinterp);
2053 
2054 	/* Make command-line arguments available in the Tcl variables "argc" and "argv" */
2055 	Tcl_SetVar(gra_tclinterp, x_("argv"), x_(""), TCL_GLOBAL_ONLY);
2056 	Tcl_SetVar(gra_tclinterp, x_("argc"), x_("0"), TCL_GLOBAL_ONLY);
2057 	Tcl_SetVar(gra_tclinterp, x_("argv0"), x_("electric"), TCL_GLOBAL_ONLY);
2058 
2059 	/* Set the "tcl_interactive" variable */
2060 	Tcl_SetVar(gra_tclinterp, x_("tcl_interactive"), x_("1"), TCL_GLOBAL_ONLY);
2061 
2062 	/* initialize the interpreter */
2063 	err = Tcl_Init(gra_tclinterp);
2064 	if (err != TCL_OK) error(_("(from Tcl_Init) %s"), gra_tclinterp->result);
2065 	return(err);
2066 }
2067 #endif
2068 
2069 /*
2070  * Routine to establish the library directories from the environment.
2071  */
setupenvironment(void)2072 void setupenvironment(void)
2073 {
2074 	REGISTER CHAR *pt, *buf;
2075 	REGISTER INTBIG len, filestatus;
2076 	REGISTER void *infstr;
2077 
2078 	/* set machine name */
2079 	nextchangequiet();
2080 	(void)setval((INTBIG)us_tool, VTOOL, x_("USER_machine"),
2081 		(INTBIG)x_("UNIX"), VSTRING|VDONTSAVE);
2082 
2083 	pt = egetenv(x_("ELECTRIC_LIBDIR"));
2084 	if (pt != NULL)
2085 	{
2086 		/* environment variable ELECTRIC_LIBDIR is set: use it */
2087 		buf = (CHAR *)emalloc((estrlen(pt)+5) * SIZEOFCHAR, el_tempcluster);
2088 		if (buf == 0)
2089 		{
2090 			efprintf(stderr, _("Cannot make environment buffer\n"));
2091 			exitprogram();
2092 		}
2093 		estrcpy(buf, pt);
2094 		if (buf[estrlen(buf)-1] != '/') estrcat(buf, x_("/"));
2095 		(void)allocstring(&el_libdir, buf, db_cluster);
2096 		efree(buf);
2097 		return;
2098 	}
2099 
2100 	/* try the #defined library directory */
2101 	infstr = initinfstr();
2102 	if (LIBDIR[0] != '/') addstringtoinfstr(infstr, currentdirectory());
2103 	addstringtoinfstr(infstr, LIBDIR);
2104 	addstringtoinfstr(infstr, x_(".cadrc"));
2105 	pt = returninfstr(infstr);
2106 	filestatus = fileexistence(pt);
2107 	if (filestatus == 1 || filestatus == 3)
2108 	{
2109 		len = estrlen(pt);
2110 		pt[len-6] = 0;
2111 		(void)allocstring(&el_libdir, pt, db_cluster);
2112 		return;
2113 	}
2114 
2115 	/* try the current location (look for "lib") */
2116 	infstr = initinfstr();
2117 	addstringtoinfstr(infstr, currentdirectory());
2118 	addstringtoinfstr(infstr, x_("lib/.cadrc"));
2119 	pt = returninfstr(infstr);
2120 	filestatus = fileexistence(pt);
2121 	if (filestatus == 1 || filestatus == 3)
2122 	{
2123 		len = estrlen(pt);
2124 		pt[len-6] = 0;
2125 		(void)allocstring(&el_libdir, pt, db_cluster);
2126 		return;
2127 	}
2128 
2129 	/* no environment, #define, or current directory: look for ".cadrc" */
2130 	filestatus = fileexistence(x_(".cadrc"));
2131 	if (filestatus == 1 || filestatus == 3)
2132 	{
2133 		/* found ".cadrc" in current directory: use that */
2134 		(void)allocstring(&el_libdir, currentdirectory(), db_cluster);
2135 		return;
2136 	}
2137 
2138 	/* look for "~/.cadrc" */
2139 	infstr = initinfstr();
2140 	addstringtoinfstr(infstr, truepath(x_("~/.cadrc")));
2141 	pt = returninfstr(infstr);
2142 	filestatus = fileexistence(pt);
2143 	if (filestatus == 1 || filestatus == 3)
2144 	{
2145 		(void)allocstring(&el_libdir, pt, db_cluster);
2146 		return;
2147 	}
2148 
2149 	ttyputerr(_("Warning: cannot find '.cadrc' startup file"));
2150 	(void)allocstring(&el_libdir, x_("."), db_cluster);
2151 }
2152 
setlibdir(CHAR * libdir)2153 void setlibdir(CHAR *libdir)
2154 {
2155 	REGISTER void *infstr;
2156 
2157 	infstr = initinfstr();
2158 	if (libdir[0] != '/') addstringtoinfstr(infstr, currentdirectory());
2159 	addstringtoinfstr(infstr, libdir);
2160 	if (libdir[estrlen(libdir)-1] != DIRSEP) addtoinfstr(infstr, DIRSEP);
2161 	(void)reallocstring(&el_libdir, returninfstr(infstr), db_cluster);
2162 }
2163 
2164 /******************** TERMINATION ********************/
2165 
termgraphics(void)2166 void termgraphics(void)
2167 {
2168 	REGISTER INTBIG i;
2169 #ifdef ANYDEPTH
2170 	REGISTER INTBIG j;
2171 #endif
2172 
2173 	gra_termgraph();
2174 
2175 	/* deallocate offscreen buffer for displays */
2176 	efree((CHAR *)gra_mainwd.addr);
2177 	efree((CHAR *)gra_mainwd.rowstart);
2178 	if (gra_maindpy != gra_altdpy)
2179 	{
2180 		efree((CHAR *)gra_altwd.addr);
2181 		efree((CHAR *)gra_altwd.rowstart);
2182 	}
2183 
2184 # ifdef TRUETYPE
2185 	if (gra_descentcachesize > 0)
2186 	{
2187 		efree((CHAR *)gra_descentcache);
2188 		efree((CHAR *)gra_ascentcache);
2189 		efree((CHAR *)gra_swidthcache);
2190 	}
2191 	for(i=0; i<gra_numfaces; i++) efree((CHAR *)gra_facelist[i]);
2192 	if (gra_numfaces > 0) efree((CHAR *)gra_facelist);
2193 #endif
2194 
2195 #ifdef ANYDEPTH
2196 	for(i=0; gra_font[i].fontname != 0; i++)
2197 	{
2198 		for(j=0; j<128; j++)
2199 		{
2200 			if (gra_font[i].data[j] != 0)
2201 				efree((CHAR *)gra_font[i].data[j]);
2202 		}
2203 	}
2204 
2205 	if (gra_textbitsdatasize > 0) efree((CHAR *)gra_textbitsdata);
2206 	if (gra_textbitsrowstartsize > 0) efree((CHAR *)gra_textbitsrowstart);
2207 #endif
2208 
2209 	/* free printer list */
2210 	for(i=0; i<gra_printerlistcount; i++)
2211 		efree((CHAR *)gra_printerlist[i]);
2212 	if (gra_printerlisttotal > 0) efree((CHAR *)gra_printerlist);
2213 
2214 	XCloseDisplay(gra_maindpy);
2215 	gra_messageswidget = 0; /* to print messages to stderr */
2216 	if (gra_icontruedata != 0)
2217 	{
2218 		efree((CHAR *)gra_icontruedata);
2219 		efree((CHAR *)gra_iconrowdata);
2220 	}
2221 /*	XtDestroyApplicationContext(gra_xtapp); ...causes a segmentation fault for some reason */
2222 	efree((CHAR *)gra_initialdirectory);
2223 	efree((CHAR *)gra_logfile);
2224 	efree((CHAR *)gra_logfilesave);
2225 
2226 	/* free filelist, brokenbuf */
2227 	if (gra_fileliststringarray != 0) killstringarray(gra_fileliststringarray);
2228 	if (gra_brokenbufsize > 0) efree(gra_brokenbuf);
2229 }
2230 
exitprogram(void)2231 void exitprogram(void)
2232 {
2233 	exit(0);
2234 }
2235 
2236 /******************** WINDOW CONTROL ********************/
2237 
2238 /*
2239  * These routines implement multiple windows on the display (each display window
2240  * is called a "windowframe".
2241  */
2242 
newwindowframe(BOOLEAN floating,RECTAREA * r)2243 WINDOWFRAME *newwindowframe(BOOLEAN floating, RECTAREA *r)
2244 {
2245 	WINDOWFRAME *wf, *oldlisthead;
2246 
2247 	/* allocate one */
2248 	wf = (WINDOWFRAME *)emalloc((sizeof (WINDOWFRAME)), us_tool->cluster);
2249 	if (wf == 0) return(NOWINDOWFRAME);
2250 	wf->numvar = 0;
2251 	wf->firstmenu = 0;
2252 	wf->windindex = gra_windownumberindex++;
2253 
2254 	/* insert window-frame in linked list */
2255 	oldlisthead = el_firstwindowframe;
2256 	wf->nextwindowframe = el_firstwindowframe;
2257 	el_firstwindowframe = wf;
2258 
2259 	/* load an editor window into this frame */
2260 	if (gra_buildwindow(gra_maindpy, &gra_mainwd, gra_maincolmap, wf, floating, FALSE, r))
2261 	{
2262 		efree((CHAR *)wf);
2263 		el_firstwindowframe = oldlisthead;
2264 		return(NOWINDOWFRAME);
2265 	}
2266 
2267 	/* remember that this is the current window frame */
2268 	if (!floating) el_curwindowframe = wf;
2269 
2270 	return(wf);
2271 }
2272 
killwindowframe(WINDOWFRAME * owf)2273 void killwindowframe(WINDOWFRAME *owf)
2274 {
2275 	WINDOWFRAME *wf, *lastwf;
2276 	REGISTER INTBIG i;
2277 
2278 	/* don't do this if window is being deleted from another place */
2279 	if (gra_windowbeingdeleted != 0) return;
2280 
2281 	/* kill the actual window, that will remove the frame, too */
2282 	XtDestroyWidget(owf->toplevelwidget);
2283 
2284 	/* ind this frame in the list */
2285 	lastwf = NOWINDOWFRAME;
2286 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2287 	{
2288 		if (wf == owf) break;
2289 		lastwf = wf;
2290 	}
2291 	if (wf == NOWINDOWFRAME) return;
2292 	if (lastwf == NOWINDOWFRAME) el_firstwindowframe = owf->nextwindowframe; else
2293 		lastwf->nextwindowframe = owf->nextwindowframe;
2294 	if (el_curwindowframe == owf) el_curwindowframe = NOWINDOWFRAME;
2295 
2296 #ifdef ANYDEPTH
2297 	efree((CHAR *)wf->dataaddr8);
2298 	efree((CHAR *)wf->rowstart);
2299 #endif
2300 	for(i=0; i<wf->pulldownmenucount; i++) efree((CHAR *)wf->pulldownmenulist[i]);
2301 	if (wf->pulldownmenucount != 0)
2302 	{
2303 		for(i=0; i<wf->pulldownmenucount; i++) efree(wf->pulldowns[i]);
2304 		efree((CHAR *)wf->pulldownmenus);
2305 		efree((CHAR *)wf->pulldowns);
2306 		efree((CHAR *)wf->pulldownmenusize);
2307 		efree((CHAR *)wf->pulldownmenulist);
2308 	}
2309 	efree((CHAR *)owf);
2310 }
2311 
getwindowframe(BOOLEAN canfloat)2312 WINDOWFRAME *getwindowframe(BOOLEAN canfloat)
2313 {
2314 	return(el_curwindowframe);
2315 }
2316 
2317 /*
2318  * routine to return size of window "win" in "wid" and "hei"
2319  */
getwindowframesize(WINDOWFRAME * wf,INTBIG * wid,INTBIG * hei)2320 void getwindowframesize(WINDOWFRAME *wf, INTBIG *wid, INTBIG *hei)
2321 {
2322 	*wid = wf->swid;
2323 	*hei = wf->shei;
2324 }
2325 
2326 /*
2327  * Routine to get the extent of the messages window.
2328  */
getmessagesframeinfo(INTBIG * top,INTBIG * left,INTBIG * bottom,INTBIG * right)2329 void getmessagesframeinfo(INTBIG *top, INTBIG *left, INTBIG *bottom, INTBIG *right)
2330 {
2331 	Arg arg[4];
2332 	short x, y, wid, hei;
2333 
2334 	XtSetArg(arg[0], XtNx, &x);
2335 	XtSetArg(arg[1], XtNy, &y);
2336 	XtSetArg(arg[2], XtNwidth, &wid);
2337 	XtSetArg(arg[3], XtNheight, &hei);
2338 	XtGetValues(gra_msgtoplevelwidget, arg, 4);
2339 	*top = y;
2340 	*left = x;
2341 	*bottom = y+hei;
2342 	*right = x+wid;
2343 }
2344 
2345 /*
2346  * Routine to set the size and position of the messages window.
2347  */
setmessagesframeinfo(INTBIG top,INTBIG left,INTBIG bottom,INTBIG right)2348 void setmessagesframeinfo(INTBIG top, INTBIG left, INTBIG bottom, INTBIG right)
2349 {
2350 	XtResizeWidget(gra_msgtoplevelwidget, right-left, bottom-top, 0);
2351 	XtMoveWidget(gra_msgtoplevelwidget, left-WMLEFTBORDER, top-WMTOPBORDER);
2352 }
2353 
sizewindowframe(WINDOWFRAME * wf,INTBIG wid,INTBIG hei)2354 void sizewindowframe(WINDOWFRAME *wf, INTBIG wid, INTBIG hei)
2355 {
2356 	XWindowAttributes xwa;
2357 	INTBIG intwid, inthei;
2358 	static WINDOWFRAME *lastwf = 0;
2359 	static INTBIG lastwid, lasthei, repeat;
2360 
2361 	if (wid < 0 || hei < 0) return;
2362 	gra_getwindowattributes(wf, &xwa);
2363 	if (wid == xwa.width && hei == xwa.height) return;
2364 	if (wf == lastwf && wid == lastwid && hei == lasthei)
2365 	{
2366 		repeat++;
2367 		if (repeat > 2) return;
2368 	} else
2369 	{
2370 		lastwf = wf;   lastwid = wid;   lasthei = hei;   repeat = 1;
2371 	}
2372 	gra_internalchange = ticktime();
2373 	XtResizeWidget(wf->toplevelwidget, wid, hei, 0);
2374 	if (wf->floating)
2375 	{
2376 		gra_getwindowinteriorsize(wf, &intwid, &inthei);
2377 		gra_recalcsize(wf, intwid, inthei);
2378 	}
2379 }
2380 
movewindowframe(WINDOWFRAME * wf,INTBIG left,INTBIG top)2381 void movewindowframe(WINDOWFRAME *wf, INTBIG left, INTBIG top)
2382 {
2383 	XWindowAttributes xwa;
2384 
2385 	gra_getwindowattributes(wf, &xwa);
2386 	if (wf->floating) top += gra_palettetop;
2387 	if (left == xwa.x && top == xwa.y) return;
2388 	gra_internalchange = ticktime();
2389 	XtMoveWidget(wf->toplevelwidget, left, top);
2390 }
2391 
gra_getwindowattributes(WINDOWFRAME * wf,XWindowAttributes * xwa)2392 void gra_getwindowattributes(WINDOWFRAME *wf, XWindowAttributes *xwa)
2393 {
2394 	Arg arg[4];
2395 	short x, y, wid, hei;
2396 
2397 	XtSetArg(arg[0], XtNx, &x);
2398 	XtSetArg(arg[1], XtNy, &y);
2399 	XtSetArg(arg[2], XtNwidth, &wid);
2400 	XtSetArg(arg[3], XtNheight, &hei);
2401 	XtGetValues(wf->toplevelwidget, arg, 4);
2402 	xwa->x = x;         xwa->y = y;
2403 	xwa->width = wid;   xwa->height = hei;
2404 }
2405 
gra_getwindowinteriorsize(WINDOWFRAME * wf,INTBIG * wid,INTBIG * hei)2406 void gra_getwindowinteriorsize(WINDOWFRAME *wf, INTBIG *wid, INTBIG *hei)
2407 {
2408 	Arg arg[2];
2409 	short width, height;
2410 
2411 	XtSetArg(arg[0], XtNwidth, &width);
2412 	XtSetArg(arg[1], XtNheight, &height);
2413 	XtGetValues(wf->graphicswidget, arg, 2);
2414 	*wid = width;   *hei = height;
2415 }
2416 
2417 /*
2418  * Routine to close the messages window if it is in front.  Returns true if the
2419  * window was closed.
2420  */
closefrontmostmessages(void)2421 BOOLEAN closefrontmostmessages(void)
2422 {
2423 	return(FALSE);
2424 }
2425 
2426 /*
2427  * Routine to bring window "wf" to the front.
2428  */
bringwindowtofront(WINDOWFRAME * wf)2429 void bringwindowtofront(WINDOWFRAME *wf)
2430 {
2431 	XRaiseWindow(wf->topdpy, wf->topwin);
2432 	XSetInputFocus(wf->topdpy, wf->topwin, RevertToNone, CurrentTime);
2433 }
2434 
2435 /*
2436  * Routine to organize the windows according to "how" (0: tile horizontally,
2437  * 1: tile vertically, 2: cascade).
2438  */
adjustwindowframe(INTBIG how)2439 void adjustwindowframe(INTBIG how)
2440 {
2441 	gra_adjustwindowframeon(gra_maindpy, gra_mainscreen, how);
2442 	if (gra_maindpy != gra_altdpy)
2443 		gra_adjustwindowframeon(gra_altdpy, gra_altscreen, how);
2444 }
2445 
gra_adjustwindowframeon(Display * dpy,INTBIG screen,INTBIG how)2446 void gra_adjustwindowframeon(Display *dpy, INTBIG screen, INTBIG how)
2447 {
2448 	RECTAREA r, wr;
2449 	REGISTER INTBIG children, child, sizex, sizey;
2450 	REGISTER WINDOWFRAME *wf, *compmenu;
2451 
2452 	/* figure out how many windows need to be rearranged */
2453 	children = 0;
2454 	compmenu = 0;
2455 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2456 	{
2457 		if (wf->topdpy != dpy) continue;
2458 		if (!wf->floating) children++; else
2459 			compmenu = wf;
2460 	}
2461 	if (children <= 0) return;
2462 
2463 	/* determine area for windows */
2464 	r.left = 0;   r.right = DisplayWidth(dpy, screen) - WMLEFTBORDER*2;
2465 	r.top = 0;   r.bottom = DisplayHeight(dpy, screen) - WMLEFTBORDER*2;
2466 
2467 	if (compmenu != NULL)
2468 	{
2469 		/* remove component menu from area of tiling */
2470 		gra_removewindowextent(&r, compmenu->toplevelwidget);
2471 	}
2472 	if (dpy == gra_topmsgdpy && gra_msgtoplevelwidget != 0)
2473 	{
2474 		/* remove messages menu from area of tiling */
2475 		gra_removewindowextent(&r, gra_msgtoplevelwidget);
2476 	}
2477 
2478 	/* rearrange the windows */
2479 	child = 0;
2480 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2481 	{
2482 		if (wf->topdpy != dpy) continue;
2483 		if (wf->floating) continue;
2484 		switch (how)
2485 		{
2486 			case 0:		/* tile horizontally */
2487 				wr.left = r.left;
2488 				wr.right = r.right;
2489 				sizey = (r.bottom - r.top) / children;
2490 				wr.top = r.top + child*sizey;
2491 				wr.bottom = wr.top + sizey;
2492 				break;
2493 			case 1:		/* tile vertically */
2494 				wr.top = r.top;
2495 				wr.bottom = r.bottom;
2496 				sizex = (r.right - r.left) / children;
2497 				wr.left = r.left + child*sizex;
2498 				wr.right = wr.left + sizex;
2499 				break;
2500 			case 2:		/* cascade */
2501 				sizex = (r.right - r.left) / children / 2;
2502 				sizey = (r.bottom - r.top) / children / 2;
2503 				wr.left = r.left + child*sizex;
2504 				wr.right = wr.left + (r.right-r.left)/2;
2505 				wr.top = r.top + child*sizey;
2506 				wr.bottom = wr.top + (r.bottom-r.top)/2;
2507 				break;
2508 		}
2509 		wr.right -= WMLEFTBORDER + WMLEFTBORDER;
2510 		wr.bottom -= WMTOPBORDER + WMLEFTBORDER;
2511 		sizewindowframe(wf, wr.right-wr.left, wr.bottom-wr.top);
2512 		gra_repaint(wf, FALSE);
2513 		movewindowframe(wf, wr.left, wr.top);
2514 		child++;
2515 	}
2516 }
2517 
2518 /*
2519  * Helper routine to remove the location of window "wnd" from the rectangle "r".
2520  */
gra_removewindowextent(RECTAREA * r,Widget wnd)2521 void gra_removewindowextent(RECTAREA *r, Widget wnd)
2522 {
2523 	RECTAREA er;
2524 	Arg arg[4];
2525 	short x, y, wid, hei;
2526 
2527 	XtSetArg(arg[0], XtNx, &x);
2528 	XtSetArg(arg[1], XtNy, &y);
2529 	XtSetArg(arg[2], XtNwidth, &wid);
2530 	XtSetArg(arg[3], XtNheight, &hei);
2531 	XtGetValues(wnd, arg, 4);
2532 	er.left = x;   er.right = er.left + wid;
2533 	er.top = y;    er.bottom = er.top + hei;
2534 
2535 	if (er.right-er.left > er.bottom-er.top)
2536 	{
2537 		/* horizontal occluding window */
2538 		if (er.bottom - r->top < r->bottom - er.top)
2539 		{
2540 			/* occluding window on top */
2541 			r->top = er.bottom + WMLEFTBORDER;
2542 		} else
2543 		{
2544 			/* occluding window on bottom */
2545 			r->bottom = er.top - WMTOPBORDER;
2546 		}
2547 	} else
2548 	{
2549 		/* vertical occluding window */
2550 		if (er.right - r->left < r->right - er.left)
2551 		{
2552 			/* occluding window on left */
2553 			r->left = er.right + WMLEFTBORDER;
2554 		} else
2555 		{
2556 			/* occluding window on right */
2557 			r->right = er.left - WMLEFTBORDER;
2558 		}
2559 	}
2560 }
2561 
getpaletteparameters(INTBIG * wid,INTBIG * hei,INTBIG * palettewidth)2562 void getpaletteparameters(INTBIG *wid, INTBIG *hei, INTBIG *palettewidth)
2563 {
2564 	*wid = gra_palettewidth;
2565 	*hei = gra_paletteheight;
2566 	*palettewidth = PALETTEWIDTH;
2567 }
2568 
2569 /*
2570  * Routine called when the component menu has moved to a different location
2571  * on the screen (left/right/top/bottom).  Resets local state of the position.
2572  */
resetpaletteparameters(void)2573 void resetpaletteparameters(void)
2574 {
2575 	gra_palettewidth = DisplayWidth(gra_maindpy, gra_mainscreen) - WMLEFTBORDER;
2576 	gra_paletteheight = DisplayHeight(gra_maindpy, gra_mainscreen) - WMTOPBORDER;
2577 	gra_palettetop = 0;
2578 }
2579 
gra_buildwindow(Display * dpy,WINDOWDISPLAY * wd,Colormap colmap,WINDOWFRAME * wf,BOOLEAN floating,BOOLEAN samesize,RECTAREA * r)2580 BOOLEAN gra_buildwindow(Display *dpy, WINDOWDISPLAY *wd, Colormap colmap, WINDOWFRAME *wf,
2581 	BOOLEAN floating, BOOLEAN samesize, RECTAREA *r)
2582 {
2583 	XTextProperty icontitle, wintitle;
2584 	XWindowAttributes xwa;
2585 	XWMHints *xwmh;
2586 	Arg arg[10];
2587 	int ac;
2588 	CHAR *ptr;
2589 	CHAR1 *title1, title1byte[200];
2590 #ifdef ANYDEPTH
2591 	REGISTER INTBIG amt, i;
2592 #else
2593 	XGCValues gcv;
2594 	Visual *visual;
2595 	XSetWindowAttributes xswa;
2596 	INTBIG planes[8], pixelarray[256];
2597 #endif
2598 
2599 	wf->floating = floating;
2600 	wf->wd = wd;
2601 	wf->colormap = colmap;
2602 
2603 	/* determine window position */
2604 	if (r != 0)
2605 	{
2606 		gra_editxsh->x = r->left;
2607 		gra_editxsh->y = r->top;
2608 		gra_editxsh->width = r->right - r->left;
2609 		gra_editxsh->height = r->bottom - r->top;
2610 	} else
2611 	{
2612 		if (samesize)
2613 		{
2614 			gra_getwindowattributes(wf, &xwa);
2615 			gra_editxsh->x = xwa.x;
2616 			gra_editxsh->y = xwa.y;
2617 			gra_editxsh->width = xwa.width;
2618 			gra_editxsh->height = xwa.height;
2619 		} else
2620 		{
2621 			if (!floating)
2622 			{
2623 				gra_editxsh->x = gra_editposx;
2624 				gra_editxsh->y = gra_editposy;
2625 				gra_editxsh->width = gra_editsizex;
2626 				gra_editxsh->height = gra_editsizey;
2627 				gra_editxsh->x += (gra_windownumber%5) * 40;
2628 				gra_editxsh->y += (gra_windownumber%5) * 40;
2629 				if (gra_editxsh->x + gra_editxsh->width > wd->wid)
2630 					gra_editxsh->width = wd->wid - gra_editxsh->x;
2631 				if (gra_editxsh->y + gra_editxsh->height > wd->hei)
2632 					gra_editxsh->height = wd->hei - gra_editxsh->y;
2633 				gra_windownumber++;
2634 			} else
2635 			{
2636 				gra_editxsh->x = 0;
2637 				gra_editxsh->y = 1 + gra_palettetop;
2638 				gra_editxsh->width = PALETTEWIDTH;
2639 				gra_editxsh->height = wd->hei - 50;
2640 				gra_internalchange = ticktime();
2641 			}
2642 		}
2643 	}
2644 
2645 	/*
2646 	 * make top-level graphics widget
2647 	 * this call may generate warnings like this:
2648 	 *   Warning: Cannot convert string "<Key>Escape,_Key_Cancel" to type VirtualBinding
2649 	 */
2650 	wf->toplevelwidget = XtAppCreateShell(b_("electric"), b_("electric"), applicationShellWidgetClass,
2651 		dpy, NULL, 0);
2652 	if (wf->toplevelwidget == 0)
2653 	{
2654 		efprintf(stderr, _("Could not create top-level window\n"));
2655 		return(TRUE);
2656 	}
2657 	(void)XtAppSetErrorHandler(gra_xtapp, gra_xterrors);
2658 	ac = 0;
2659 	XtSetArg(arg[ac], XtNx, gra_editxsh->x);   ac++;
2660 	XtSetArg(arg[ac], XtNy, gra_editxsh->y);   ac++;
2661 	XtSetArg(arg[ac], XtNwidth, gra_editxsh->width);   ac++;
2662 	XtSetArg(arg[ac], XtNheight, gra_editxsh->height);   ac++;
2663 	XtSetArg(arg[ac], XmNdeleteResponse,  XmDO_NOTHING);   ac++;
2664 	if (floating)
2665 	{
2666 /*		XtSetArg(arg[ac], XmNoverrideRedirect,  True);   ac++;  ...wanted to make component menu float */
2667 		XtSetArg(arg[ac], XmNmwmFunctions, MWM_FUNC_RESIZE|MWM_FUNC_MOVE|
2668 			MWM_FUNC_MINIMIZE|MWM_FUNC_CLOSE);   ac++;
2669 	}
2670 	XtSetValues(wf->toplevelwidget, arg, ac);
2671 
2672 	/* make graphics widget frame */
2673 	ac = 0;
2674 	XtSetArg(arg[ac], XmNwidth, gra_editxsh->width);   ac++;
2675 	XtSetArg(arg[ac], XmNheight, gra_editxsh->height);   ac++;
2676 	wf->intermediategraphics = (Widget)XmCreateMainWindow(wf->toplevelwidget,
2677 		x_("graphics"), arg, ac);
2678 	if (wf->intermediategraphics == 0)
2679 	{
2680 		efprintf(stderr, _("Could not create main window\n"));
2681 		return(TRUE);
2682 	}
2683 	XtManageChild(wf->intermediategraphics);
2684 
2685 	/* make graphics widget drawing area */
2686 	ac = 0;
2687 	XtSetArg(arg[ac], XmNresizePolicy, XmRESIZE_ANY);   ac++;
2688 	wf->graphicswidget = (Widget)XmCreateDrawingArea(wf->intermediategraphics,
2689 		x_("drawing_area"), arg, ac);
2690 	if (wf->graphicswidget == 0)
2691 	{
2692 		efprintf(stderr, _("Could not create main widget\n"));
2693 		return(TRUE);
2694 	}
2695 	XtManageChild(wf->graphicswidget);
2696 
2697 	/* make menus */
2698 	wf->pulldownmenucount = 0;
2699 	if (floating) wf->menubar = 0; else
2700 	{
2701 		wf->menubar = (Widget)XmCreateMenuBar(wf->intermediategraphics, b_("MainWin"), NULL, 0);
2702 		XtManageChild(wf->menubar);
2703 		gra_pulldownmenuload(wf);
2704 	}
2705 	XmMainWindowSetAreas(wf->intermediategraphics, wf->menubar, NULL,
2706 		NULL, NULL, wf->graphicswidget);
2707 
2708 	/* add a window-manager protocol to move displays */
2709 	if (gra_maindpy != gra_altdpy)
2710 	{
2711 		XmAddProtocols(wf->toplevelwidget, gra_movedisplaymsg, &gra_movedisplayprotocol, 1);
2712 		XmAddProtocolCallback(wf->toplevelwidget, gra_movedisplaymsg, gra_movedisplayprotocol,
2713 			(XtCallbackProc)gra_movedisplay, NULL);
2714 		esnprintf(gra_localstring, MAXLOCALSTRING, x_("Move\\ to\\ Other\\ Display _D f.send_msg %d"),
2715 			gra_movedisplayprotocol);
2716 		XtVaSetValues(wf->toplevelwidget, XmNmwmMenu, gra_localstring, NULL);
2717 	}
2718 	XtAddEventHandler(wf->graphicswidget, ButtonPressMask | ButtonReleaseMask |
2719 		KeyPressMask | PointerMotionMask | ExposureMask | StructureNotifyMask |
2720 		FocusChangeMask, FALSE, gra_graphics_event_handler, NULL);
2721 	XtAddEventHandler(wf->toplevelwidget, StructureNotifyMask, FALSE,
2722 		gra_graphics_event_handler, NULL);
2723 	XtRealizeWidget(wf->toplevelwidget);
2724 
2725 	/* get info about this widget */
2726 	wf->topdpy = XtDisplay(wf->toplevelwidget);
2727 	wf->topwin = XtWindow(wf->toplevelwidget);
2728 	wf->win = XtWindow(wf->graphicswidget);
2729 
2730 	/* set up to trap window kills */
2731 	XmAddWMProtocolCallback(wf->toplevelwidget, gra_wm_delete_window,
2732 		(XtCallbackProc)gra_windowdelete, (XtPointer)wf->intermediategraphics);
2733 
2734 	/* build graphics contexts */
2735 #ifndef ANYDEPTH
2736 	gcv.foreground = BlackPixel(wf->topdpy, DefaultScreen(wf->topdpy));
2737 	gcv.graphics_exposures = False;     /* no event after XCopyArea */
2738 	wf->gc = XtGetGC(wf->graphicswidget, GCForeground | GCGraphicsExposures, &gcv);
2739 	gcv.function = GXinvert;
2740 	wf->gcinv = XtGetGC(wf->graphicswidget, GCFunction | GCGraphicsExposures, &gcv);
2741 	gcv.fill_style = FillStippled;
2742 	wf->gcstip = XtGetGC(wf->graphicswidget, GCFillStyle | GCGraphicsExposures, &gcv);
2743 #endif
2744 	/* get window size and depth after creation */
2745 	XGetWindowAttributes(wf->topdpy, wf->win, &xwa);
2746 	wf->swid = xwa.width;
2747 	wf->trueheight = xwa.height;  /* we keep the true height locally */
2748 	wf->shei = wf->trueheight;
2749 	if (!floating) wf->shei -= gra_status_height;
2750 	wf->revy = wf->shei - 1;
2751 
2752 	/* load window manager information */
2753 	if (!floating) (void)estrcpy(gra_localstring, _("Electric")); else
2754 		(void)estrcpy(gra_localstring, _("Components"));
2755 	strcpy(title1byte, string1byte(gra_localstring));
2756 	title1 = title1byte;
2757 	XStringListToTextProperty(&title1, 1, &wintitle);
2758 	XStringListToTextProperty(&title1, 1, &icontitle);
2759 	xwmh = XAllocWMHints();
2760 	xwmh->input = True;
2761 	xwmh->initial_state = NormalState;
2762 	xwmh->icon_pixmap = xwmh->icon_mask = gra_programicon;
2763 	xwmh->flags = InputHint | StateHint | IconPixmapHint;
2764 	XSetWMProperties(wf->topdpy, wf->topwin, &wintitle, &icontitle,
2765 		gra_argv, gra_argc, gra_editxsh, xwmh, NULL);
2766 	XFree(xwmh);
2767 #ifdef ANYDEPTH
2768 	/* allocate space for the 8-bit deep buffer */
2769 	amt = wf->swid * wf->trueheight;
2770 	wf->dataaddr8 = (UCHAR1 *)emalloc(amt, us_tool->cluster);
2771 	if (wf->dataaddr8 == 0)
2772 	{
2773 		efprintf(stderr, _("Could not allocate space for offscreen buffer\n"));
2774 		return(TRUE);
2775 	}
2776 	for(i=0; i<amt; i++) wf->dataaddr8[i] = 0;
2777 	wf->rowstart = (UCHAR1 **)emalloc(wf->trueheight * SIZEOFINTBIG, us_tool->cluster);
2778 	if (wf->rowstart == 0)
2779 	{
2780 		efprintf(stderr, _("Could not allocate space for row pointers\n"));
2781 		return(TRUE);
2782 	}
2783 	for(i=0; i<wf->trueheight; i++)
2784 		wf->rowstart[i] = wf->dataaddr8 + i * wf->swid;
2785 
2786 	/* fill the color map  */
2787 	if (DefaultDepth(wf->topdpy, DefaultScreen(wf->topdpy)) != 1)
2788 	{
2789 		us_getcolormap(el_curtech, COLORSDEFAULT, FALSE);
2790 		gra_reloadmap();
2791 	}
2792 #else
2793 	/* setup properties of the edit window */
2794 	xswa.background_pixel = WhitePixel(wf->topdpy, DefaultScreen(wf->topdpy));
2795 	xswa.border_pixel = BlackPixel(wf->topdpy, DefaultScreen(wf->topdpy));
2796 	if (gra_use_backing)
2797 	{
2798 		xswa.backing_store = WhenMapped;
2799 
2800 		/* load backing store property (Dmitry Nadezchin) */
2801 		XChangeWindowAttributes(wf->topdpy, wf->win, CWBackingStore, &xswa);
2802 
2803 		/* default backing_pixel and backing_planes are not set */
2804 		xswa.backing_pixel = xswa.background_pixel;
2805 		xswa.backing_planes = AllPlanes;
2806 	}
2807 	visual = DefaultVisual(wf->topdpy, DefaultScreen(wf->topdpy));
2808 	wf->colormap = XCreateColormap(wf->topdpy, RootWindow(wf->topdpy, DefaultScreen(wf->topdpy)),
2809 		visual, AllocNone);
2810 	xswa.colormap = wf->colormap;
2811 	XChangeWindowAttributes(wf->topdpy, wf->topwin, CWColormap, &xswa);
2812 
2813 	/* fill the color map  */
2814 	if (DefaultDepth(wf->topdpy, DefaultScreen(wf->topdpy)) != 1)
2815 	{
2816 		if (XAllocColorCells(wf->topdpy, wf->colormap, 1, (unsigned long *)planes, 0,
2817 			(unsigned long *)pixelarray, el_maplength) == 0)
2818 				efprintf(stderr, x_("XAllocColorCells failed\n"));
2819 
2820 		/* load any map the first time to establish the map segment length */
2821 		us_getcolormap(el_curtech, COLORSDEFAULT, FALSE);
2822 		gra_reloadmap();
2823 		gra_xfc.pixel = el_colcursor;
2824 		XQueryColor(wf->topdpy, wf->colormap, &gra_xfc);
2825 		gra_xbc.pixel = 0;
2826 		XQueryColor(wf->topdpy, wf->colormap, &gra_xbc);
2827 		gra_recolorcursor(wf->topdpy, &gra_xfc, &gra_xbc);
2828 	}
2829 #endif
2830 	return(FALSE);
2831 }
2832 
gra_movedisplay(Widget w,XtPointer client_data,XtPointer * call_data)2833 void gra_movedisplay(Widget w, XtPointer client_data, XtPointer *call_data)
2834 {
2835 	Display *dpy;
2836 	REGISTER WINDOWFRAME *wf;
2837 	REGISTER WINDOWDISPLAY *wd;
2838 	Colormap colmap;
2839 
2840 	wf = gra_getcurrentwindowframe(w, FALSE);
2841 	if (wf == NOWINDOWFRAME) return;
2842 	XtDestroyWidget(wf->toplevelwidget);
2843 #ifdef ANYDEPTH
2844 	efree((CHAR *)wf->dataaddr8);
2845 	efree((CHAR *)wf->rowstart);
2846 #endif
2847 	if (wf->topdpy == gra_maindpy)
2848 	{
2849 		dpy = gra_altdpy;
2850 		wd = &gra_altwd;
2851 		colmap = gra_altcolmap;
2852 	} else
2853 	{
2854 		dpy = gra_maindpy;
2855 		wd = &gra_mainwd;
2856 		colmap = gra_maincolmap;
2857 	}
2858 	if (gra_buildwindow(dpy, wd, colmap, wf, wf->floating, TRUE, 0))
2859 		ttyputerr(_("Problem moving the display"));
2860 
2861 	/* redisplay */
2862 	gra_reloadmap();
2863 	us_drawmenu(1, wf);
2864 	us_redostatus(wf);
2865 	us_endbatch();
2866 }
2867 
2868 /******************** MISCELLANEOUS EXTERNAL ROUTINES ********************/
2869 
2870 /*
2871  * return nonzero if the capabilities in "want" are present
2872  */
graphicshas(INTBIG want)2873 BOOLEAN graphicshas(INTBIG want)
2874 {
2875 	if ((want & CANHAVENOWINDOWS) != 0) return(FALSE);
2876 
2877 	/* cannot modify typefaces */
2878 	if ((want&(CANCHOOSEFACES|CANMODIFYFONTS|CANSCALEFONTS)) != 0)
2879 	{
2880 #ifdef TRUETYPE
2881 		if (gra_truetypeon != 0) return(TRUE);
2882 #endif
2883 		return(FALSE);
2884 	}
2885 
2886 	return(TRUE);
2887 }
2888 
2889 /*
2890  * Routine to make sound "sound".  If sounds are turned off, no
2891  * sound is made (unless "force" is TRUE)
2892  */
ttybeep(INTBIG sound,BOOLEAN force)2893 void ttybeep(INTBIG sound, BOOLEAN force)
2894 {
2895 	if ((us_tool->toolstate & TERMBEEP) != 0 || force)
2896 	{
2897 		switch (sound)
2898 		{
2899 			case SOUNDBEEP:
2900 				XBell(gra_maindpy, 100);
2901 				break;
2902 			case SOUNDCLICK:
2903 				if ((us_useroptions&NOEXTRASOUND) != 0) break;
2904 				/* really want to play "click.wav" in the library area */
2905 				break;
2906 		}
2907 	}
2908 }
2909 
2910 DIALOGITEM db_severeerrordialogitems[] =
2911 {
2912  /*  1 */ {0, {80,8,104,72}, BUTTON, N_("Exit")},
2913  /*  2 */ {0, {80,96,104,160}, BUTTON, N_("Save")},
2914  /*  3 */ {0, {80,184,104,256}, BUTTON, N_("Continue")},
2915  /*  4 */ {0, {8,8,72,256}, MESSAGE, x_("")}
2916 };
2917 DIALOG db_severeerrordialog = {{50,75,163,341}, N_("Fatal Error"), 0, 4, db_severeerrordialogitems, 0, 0};
2918 
2919 /* special items for the severe error dialog: */
2920 #define DSVE_EXIT      1		/* Exit (button) */
2921 #define DSVE_SAVE      2		/* Save (button) */
2922 #define DSVE_CONTINUE  3		/* Continue (button) */
2923 #define DSVE_MESSAGE   4		/* Error Message (stat text) */
2924 
error(CHAR * s,...)2925 void error(CHAR *s, ...)
2926 {
2927 	va_list ap;
2928 	CHAR line[500];
2929 	REGISTER INTBIG itemHit, *curstate;
2930 	REGISTER INTBIG retval;
2931 	REGISTER LIBRARY *lib;
2932 	REGISTER void *dia;
2933 
2934 	/* disable any session logging */
2935 	if (us_logplay != NULL)
2936 	{
2937 		xclose(us_logplay);
2938 		us_logplay = NULL;
2939 	}
2940 
2941 	/* build the error message */
2942 	var_start(ap, s);
2943 	evsnprintf(line, 500, s, ap);
2944 	va_end(ap);
2945 
2946 	/* display the severe error dialog box */
2947 	dia = DiaInitDialog(&db_severeerrordialog);
2948 	if (dia == 0) return;
2949 
2950 	/* load the message */
2951 	DiaSetText(dia, DSVE_MESSAGE, line);
2952 
2953 	/* loop until done */
2954 	for(;;)
2955 	{
2956 		itemHit = DiaNextHit(dia);
2957 		if (itemHit == DSVE_EXIT) exitprogram();
2958 		if (itemHit == DSVE_CONTINUE) break;
2959 		if (itemHit == DSVE_SAVE)
2960 		{
2961 			/* save libraries: make sure that backups are kept */
2962 			curstate = io_getstatebits();
2963 			if ((curstate[0]&BINOUTBACKUP) == BINOUTNOBACK)
2964 			{
2965 				curstate[0] |= BINOUTONEBACK;
2966 				io_setstatebits(curstate);
2967 			}
2968 
2969 			/* save each modified library */
2970 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2971 			{
2972 				if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
2973 				if ((lib->userbits&(LIBCHANGEDMAJOR|LIBCHANGEDMINOR)) == 0) continue;
2974 
2975 				/* save the library in binary format */
2976 				makeoptionstemporary(lib);
2977 				retval = asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)x_("binary"));
2978 				restoreoptionstate(lib);
2979 				if (retval != 0) return;
2980 			}
2981 		}
2982 	}
2983 	DiaDoneDialog(dia);
2984 }
2985 
2986 #define TRUEGETENV getenv
2987 
2988 /*
2989  * Routine to get the environment variable "name" and return its value.
2990  */
egetenv(CHAR * name)2991 CHAR *egetenv(CHAR *name)
2992 {
2993 #ifdef _UNICODE
2994 	return(string2byte(TRUEGETENV(string1byte(name))));
2995 #else
2996 	return(TRUEGETENV(name));
2997 #endif
2998 }
2999 
3000 /*
3001  * Routine to get the current language that Electric speaks.
3002  */
elanguage(void)3003 CHAR *elanguage(void)
3004 {
3005 	CHAR *lang;
3006 
3007 	lang = egetenv(x_("LANGUAGE"));
3008 	if (lang == 0) lang = x_("en");
3009 	return(lang);
3010 }
3011 
3012 /*
3013  * Routine to fork a new process.  Returns the child process number if this is the
3014  * parent thread.  Returns 0 if this is the child thread.
3015  * Returns 1 if forking is not possible (process 1 is INIT on UNIX and can't possibly
3016  * be assigned to a normal process).
3017  */
efork(void)3018 INTBIG efork(void)
3019 {
3020 	return(fork());
3021 }
3022 
3023 /*
3024  * Routine to run the string "command" in a shell.
3025  * Returns nonzero if the command cannot be run.
3026  */
esystem(CHAR * command)3027 INTBIG esystem(CHAR *command)
3028 {
3029 	system(string1byte(command));
3030 	return(0);
3031 }
3032 
3033 /*
3034  * Routine to execute the program "program" with the arguments "args"
3035  */
eexec(CHAR * program,CHAR * args[])3036 void eexec(CHAR *program, CHAR *args[])
3037 {
3038 	CHAR1 **myargs;
3039 	INTBIG total, i;
3040 
3041 	/* copy to a local array */
3042 	for(total=0; args[total] != 0; total++) ;
3043 	myargs = (CHAR1 **)emalloc((total+1) * (sizeof (CHAR1 *)), us_tool->cluster);
3044 	if (myargs == 0) return;
3045 	for(i=0; i<total; i++)
3046 	{
3047 		myargs[i] = (CHAR1 *)emalloc(estrlen(args[i])+1, us_tool->cluster);
3048 		TRUESTRCPY(myargs[i], string1byte(args[i]));
3049 	}
3050 	myargs[total] = 0;
3051 
3052 	/* run it */
3053 	execvp(string1byte(program), myargs);
3054 
3055 	/* free the memory */
3056 	for(i=0; i<total; i++) efree((CHAR *)myargs[i]);
3057 	efree((CHAR *)myargs);
3058 }
3059 
3060 /*
3061  * routine to kill process "process".
3062  */
ekill(INTBIG process)3063 INTBIG ekill(INTBIG process)
3064 {
3065 	return(kill(process, SIGKILL));
3066 }
3067 
3068 /*
3069  * routine to wait for the completion of child process "process"
3070  */
ewait(INTBIG process)3071 void ewait(INTBIG process)
3072 {
3073 	REGISTER INTBIG pid;
3074 
3075 	for(;;)
3076 	{
3077 		pid = wait((int *)0);
3078 		if (pid == process) return;
3079 		if (pid == -1)
3080 		{
3081 			perror(b_("Waiting"));
3082 			return;
3083 		}
3084 	}
3085 }
3086 
3087 /*
3088  * Routine to return the number of processors on this machine.
3089  */
enumprocessors(void)3090 INTBIG enumprocessors(void)
3091 {
3092 	INTBIG numproc;
3093 	size_t proclen;
3094 
3095 	proclen = sizeof(numproc);
3096 	if ((sysctlbyname("hw.ncpu", &numproc, &proclen, NULL, 0) < 0) ||
3097 	   (proclen != sizeof(numproc)))
3098 		numproc = 1;
3099 
3100 	return(numproc);
3101 }
3102 
3103 /*
3104  * Routine to create a new thread that calls "function" with "argument".
3105  */
enewthread(void * (* function)(void *),void * argument)3106 void enewthread(void* (*function)(void*), void *argument)
3107 {
3108 #ifdef HAVE_PTHREAD
3109 	pthread_t threadptr;
3110 
3111 	pthread_create(&threadptr, NULL, function, argument);
3112 #else
3113 	thread_t threadid;
3114 
3115 	if (thr_create(NULL, 0, function, argument, THR_BOUND, &threadid) != 0)
3116 		printf(b_("Thread creation failed\n"));
3117 #endif
3118 }
3119 
3120 /*
3121  * Routine that creates a mutual-exclusion object and returns it.
3122  */
emakemutex(void)3123 void *emakemutex(void)
3124 {
3125 #ifdef HAVE_PTHREAD
3126 	pthread_mutex_t *mutex;
3127 
3128 	mutex = (pthread_mutex_t *)calloc(1, sizeof (pthread_mutex_t));
3129 	pthread_mutex_init(mutex, NULL);
3130 	return((void *)mutex);
3131 #else
3132 	mutex_t *mutexid;
3133 
3134 	mutexid = (mutex_t *)calloc(1, sizeof (mutex_t));
3135 	mutex_init(mutexid, USYNC_THREAD, 0);
3136 	return((void *)mutexid);
3137 #endif
3138 }
3139 
3140 /*
3141  * Routine that locks mutual-exclusion object "vmutex".  If the object is already
3142  * locked, the routine blocks until it is unlocked.
3143  */
emutexlock(void * vmutex)3144 void emutexlock(void *vmutex)
3145 {
3146 #ifdef HAVE_PTHREAD
3147 	pthread_mutex_t *mutex;
3148 
3149 	mutex = (pthread_mutex_t *)vmutex;
3150 	pthread_mutex_lock(mutex);
3151 #else
3152 	mutex_t *mutexid;
3153 
3154 	mutexid = (mutex_t *)vmutex;
3155 	mutex_lock(mutexid);
3156 #endif
3157 }
3158 
3159 /*
3160  * Routine that unlocks mutual-exclusion object "vmutex".
3161  */
emutexunlock(void * vmutex)3162 void emutexunlock(void *vmutex)
3163 {
3164 #ifdef HAVE_PTHREAD
3165 	pthread_mutex_t *mutex;
3166 
3167 	mutex = (pthread_mutex_t *)vmutex;
3168 	pthread_mutex_unlock(mutex);
3169 #else
3170 	mutex_t *mutexid;
3171 
3172 	mutexid = (mutex_t *)vmutex;
3173 	mutex_unlock(mutexid);
3174 #endif
3175 }
3176 
3177 /*
3178  * Routine to determine the list of printers and return it.
3179  * The list terminates with a zero.
3180  */
eprinterlist(void)3181 CHAR **eprinterlist(void)
3182 {
3183 	static CHAR *nulllplist[1];
3184 	int pipechans[2];
3185 	CHAR *execargs[5];
3186 	INTBIG process, i, save, bptr;
3187 	CHAR val, buf[200], *pt;
3188 	FILE *io;
3189 
3190 	/* remove former list */
3191 	for(i=0; i<gra_printerlistcount; i++)
3192 		efree((CHAR *)gra_printerlist[i]);
3193 	gra_printerlistcount = 0;
3194 	nulllplist[0] = 0;
3195 
3196 	/* look for "/etc/printcap" */
3197 	io = efopen(x_("/etc/printcap"), x_("r"));
3198 	if (io != 0)
3199 	{
3200 		for(;;)
3201 		{
3202 			if (xfgets(buf, 200, io)) break;
3203 			if (buf[0] == '#' || buf[0] == ' ' || buf[0] == '\t') continue;
3204 			for(pt = buf; *pt != 0; pt++)
3205 				if (*pt == ':') break;
3206 			if (*pt == 0) continue;
3207 			*pt = 0;
3208 			if (gra_addprinter(buf))
3209 				return(nulllplist);
3210 		}
3211 		fclose(io);
3212 		if (gra_printerlistcount <= 0) return(nulllplist);
3213 		return(gra_printerlist);
3214 	}
3215 
3216 	/* no file "/etc/printcap": try to run "lpget" */
3217 	(void)epipe(pipechans);
3218 	process = efork();
3219 	if (process == 1)
3220 		return(nulllplist);
3221 
3222 	/* fork the process */
3223 	if (process == 0)
3224 	{
3225 		save = channelreplacewithchannel(1, pipechans[1]);
3226 		execargs[0] = x_("lpget");
3227 		execargs[1] = x_("list");
3228 		execargs[2] = 0;
3229 		eexec(x_("lpget"), execargs);
3230 		channelrestore(1, save);
3231 		ttyputerr(_("Cannot find 'lpget'"));
3232 		exit(1);
3233 	}
3234 	eclose(pipechans[1]);
3235 
3236 	/* read the list from the program */
3237 	bptr = 0;
3238 	for(;;)
3239 	{
3240 		i = eread(pipechans[0], (UCHAR1 *)&val, SIZEOFCHAR);
3241 		if (i != 1) break;
3242 		if (val == ':')
3243 		{
3244 			if (gra_addprinter(buf))
3245 				return(nulllplist);
3246 		}
3247 		buf[bptr++] = val;   buf[bptr] = 0;
3248 		if (val == '\n' || val == '\r') bptr = 0;
3249 	}
3250 	ewait(process);
3251 	if (gra_printerlistcount <= 0) return(nulllplist);
3252 	return(gra_printerlist);
3253 }
3254 
gra_addprinter(CHAR * buf)3255 BOOLEAN gra_addprinter(CHAR *buf)
3256 {
3257 	CHAR **newlist;
3258 	INTBIG i, j, newtotal;
3259 
3260 	if (estrcmp(buf, x_("_default")) == 0) return(FALSE);
3261 	if (buf[0] == ' ' || buf[0] == '\t') return(FALSE);
3262 
3263 	/* stop if it is already in the list */
3264 	for(i=0; i<gra_printerlistcount; i++)
3265 		if (estrcmp(buf, gra_printerlist[i]) == 0) return(FALSE);
3266 
3267 	/* make room in the list */
3268 	if (gra_printerlistcount >= gra_printerlisttotal-1)
3269 	{
3270 		newtotal = gra_printerlistcount + 10;
3271 		newlist = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)), us_tool->cluster);
3272 		if (newlist == 0) return(TRUE);
3273 		for(i=0; i<gra_printerlistcount; i++)
3274 			newlist[i] = gra_printerlist[i];
3275 		if (gra_printerlisttotal > 0) efree((CHAR *)gra_printerlist);
3276 		gra_printerlist = newlist;
3277 		gra_printerlisttotal = newtotal;
3278 	}
3279 
3280 	/* insert into the list */
3281 	for(i=0; i<gra_printerlistcount; i++)
3282 		if (estrcmp(buf, gra_printerlist[i]) < 0) break;
3283 	for(j=gra_printerlistcount; j>i; j--) gra_printerlist[j] = gra_printerlist[j-1];
3284 	gra_printerlist[i] = (CHAR *)emalloc((estrlen(buf)+1) * SIZEOFCHAR, us_tool->cluster);
3285 	estrcpy(gra_printerlist[i], buf);
3286 	gra_printerlistcount++;
3287 	gra_printerlist[gra_printerlistcount] = 0;
3288 	return(FALSE);
3289 }
3290 
3291 /******************** STATUS BAR ROUTINES ********************/
3292 
3293 /*
3294  * Routine to return the number of status lines on the display.
3295  */
ttynumstatuslines(void)3296 INTBIG ttynumstatuslines(void)
3297 {
3298 	return(MAXSTATUSLINES);
3299 }
3300 
3301 /*
3302  * Routine to free status field object "sf".
3303  */
ttyfreestatusfield(STATUSFIELD * sf)3304 void ttyfreestatusfield(STATUSFIELD *sf)
3305 {
3306 	efree(sf->label);
3307 	efree((CHAR *)sf);
3308 }
3309 
3310 /*
3311  * Routine to display "message" in the status "field" of window "frame" (uses all windows
3312  * if "frame" is zero).  If "cancrop" is false, field cannot be cropped and should be
3313  * replaced with "*" if there isn't room.
3314  */
ttysetstatusfield(WINDOWFRAME * wwf,STATUSFIELD * field,CHAR * message,BOOLEAN cancrop)3315 void ttysetstatusfield(WINDOWFRAME *wwf, STATUSFIELD *field, CHAR *message, BOOLEAN cancrop)
3316 {
3317 	INTBIG len, lx, ly, hx, hy, wid, hei, sizey, i;
3318 	INTBIG oldfont;
3319 	CHAR *ptr;
3320 	CHAR1 *title1, title1byte[200];
3321 	XTextProperty wintitle;
3322 	REGISTER WINDOWFRAME *wf;
3323 	WINDOWPART win;
3324 
3325 	if (field == 0) return;
3326 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
3327 	{
3328 		if (wf->floating) continue;
3329 		if (wwf != NOWINDOWFRAME && wwf != wf) continue;
3330 
3331 		/* make a window that corresponds to this frame */
3332 		win.frame = wf;
3333 		win.screenlx = win.uselx = 0;
3334 		win.screenhx = win.usehx = wf->swid;
3335 		win.screenly = win.usely = -gra_status_height;
3336 		win.screenhy = win.usehy = wf->shei;
3337 		win.state = DISPWINDOW;
3338 		computewindowscale(&win);
3339 
3340 		if (field->line == 0)
3341 		{
3342 			/* should set title bar here */
3343 #ifdef EPROGRAMNAME
3344 			(void)estrcpy(gra_localstring, string2byte(EPROGRAMNAME));
3345 #else
3346 			(void)estrcpy(gra_localstring, _("Electric"));
3347 #endif
3348 			if (estrlen(message) > 0)
3349 			{
3350 				(void)estrcat(gra_localstring, x_(" ("));
3351 				(void)estrcat(gra_localstring, field->label);
3352 				(void)estrcat(gra_localstring, message);
3353 				(void)estrcat(gra_localstring, x_(")"));
3354 			}
3355 			len = estrlen(gra_localstring);
3356 			while (len > 0 && gra_localstring[len-1] == ' ') gra_localstring[--len] = 0;
3357 			strcpy(title1byte, string1byte(gra_localstring));
3358 			title1 = title1byte;
3359 			XStringListToTextProperty(&title1, 1, &wintitle);
3360 			XSetWMName(wf->topdpy, wf->topwin, &wintitle);
3361 			continue;
3362 		}
3363 
3364 		/* construct the status line */
3365 		len = estrlen(field->label);
3366 		if (len + estrlen(message) >= MAXLOCALSTRING)
3367 		{
3368 			estrcpy(gra_localstring, field->label);
3369 			i = MAXLOCALSTRING - len - 1;
3370 			estrncat(gra_localstring, message, i);
3371 			gra_localstring[MAXLOCALSTRING-1] = 0;
3372 		} else
3373 		{
3374 			esnprintf(gra_localstring, MAXLOCALSTRING, x_("%s%s"), field->label, message);
3375 		}
3376 		len = estrlen(gra_localstring);
3377 		while (len > 0 && gra_localstring[len-1] == ' ') gra_localstring[--len] = 0;
3378 
3379 		oldfont = gra_truetypesize;
3380 # ifdef TRUETYPE
3381 		if (gra_truetypeon != 0)
3382 		{
3383 			gra_settextsize(&win, 12, 0, 0, 0, 0, 0);
3384 		} else
3385 #endif
3386 		gra_settextsize(&win, 6, 0, 0, 0, 0, 0);
3387 		sizey = gra_curfont->ascent + gra_curfont->descent;
3388 
3389 		lx = wf->swid * field->startper / 100;
3390 		hx = wf->swid * field->endper / 100;
3391 		ly = - (gra_status_height / field->line);
3392 		hy = ly + sizey;
3393 		while (gra_localstring[0] != 0)
3394 		{
3395 			screengettextsize(&win, gra_localstring, &wid, &hei);
3396 			if (wid <= hx-lx) break;
3397 			gra_localstring[estrlen(gra_localstring)-1] = 0;
3398 		}
3399 		screendrawbox(&win, lx, hx - 1, ly, hy, &us_ebox);
3400 		screendrawtext(&win, lx, ly+1, gra_localstring, &us_menutext);  /* added "+1" */
3401 		gra_settextsize(&win, oldfont, 0, 0, 0, 0, 0);
3402 
3403 		/* draw the separator line between drawing and status areas */
3404 		us_box.col = BLACK;
3405 		screendrawline(&win, 1, -2, wf->swid - 1, -2, &us_box, 0);
3406 	}
3407 }
3408 
3409 /*
3410  * Routine to force the module to return with some event so that the user interface will
3411  * relinquish control and let a slice happen.
3412  */
forceslice(void)3413 void forceslice(void)
3414 {
3415     XSendEvent(gra_samplemotionevent.xmotion.display,
3416 	       gra_samplemotionevent.xmotion.window,
3417 	       True, PointerMotionMask, &gra_samplemotionevent);
3418 }
3419 
3420 /******************** MESSAGES WINDOW ROUTINES ********************/
3421 
3422 /*
3423  * Routine to put the string "s" into the messages window.
3424  * Pops up the messages window if "important" is nonzero.
3425  */
putmessagesstring(CHAR * s,BOOLEAN important)3426 void putmessagesstring(CHAR *s, BOOLEAN important)
3427 {
3428 	XmTextPosition tp;
3429 	XWindowAttributes xwa;
3430 
3431 	/* print to stderr if messages are not initiaized */
3432 	if (gra_messageswidget == 0) {
3433 		efprintf(stderr, x_("%s\n"), s);
3434 		return;
3435 	}
3436 
3437 	/* make sure the window isn't iconified or obscured */
3438 	if (important)
3439 	{
3440 		if (XGetWindowAttributes(gra_topmsgdpy, gra_topmsgwin, &xwa) == 0) return;
3441 		if (xwa.map_state != IsViewable || gra_messages_obscured)
3442 			XMapRaised(gra_topmsgdpy, gra_topmsgwin);
3443 	}
3444 
3445 	tp = XmTextGetLastPosition(gra_messageswidget);
3446 	XmTextInsert(gra_messageswidget, tp, string1byte(s));
3447 	tp = XmTextGetLastPosition(gra_messageswidget);
3448 	XmTextInsert(gra_messageswidget, tp, b_("\n"));
3449 	tp = XmTextGetLastPosition(gra_messageswidget);
3450 	XmTextSetSelection(gra_messageswidget, tp, tp, 0);
3451 	XmTextSetInsertionPosition(gra_messageswidget, tp);
3452 	XmTextShowPosition(gra_messageswidget, tp);
3453 }
3454 
3455 /*
3456  * Routine to return the name of the key that ends a session from the messages window.
3457  */
getmessageseofkey(void)3458 CHAR *getmessageseofkey(void)
3459 {
3460 	return(x_("^D"));
3461 }
3462 
getmessagesstring(CHAR * prompt)3463 CHAR *getmessagesstring(CHAR *prompt)
3464 {
3465 	XmTextPosition tp, starttp;
3466 	CHAR ch[2], *block;
3467 	CHAR1 *block1;
3468 	INTBIG c, total, special;
3469 	REGISTER void *infstr;
3470 
3471 	/* show the prompt */
3472 	tp = XmTextGetLastPosition(gra_messageswidget);
3473 	XmTextInsert(gra_messageswidget, tp, string1byte(prompt));
3474 
3475 	/* get initial text position */
3476 	starttp = XmTextGetLastPosition(gra_messageswidget);
3477 	XmTextSetSelection(gra_messageswidget, starttp, starttp, 0);
3478 	XmTextSetInsertionPosition(gra_messageswidget, starttp);
3479 
3480 	/* loop while typing is done */
3481 	total = 0;
3482 	gra_messages_typingin = TRUE;
3483 	for(;;)
3484 	{
3485 		c = getnxtchar(&special);
3486 		if (c == '\n' || c == '\r' || c == CTRLDKEY) break;
3487 		if (c == DELETEKEY || c == BACKSPACEKEY)
3488 		{
3489 			tp = XmTextGetLastPosition(gra_messageswidget);
3490 			XmTextSetSelection(gra_messageswidget, tp-1, tp, 0);
3491 			XmTextRemove(gra_messageswidget);
3492 			total--;
3493 			continue;
3494 		}
3495 		if (c == us_killch)
3496 		{
3497 			tp = XmTextGetLastPosition(gra_messageswidget);
3498 			XmTextSetSelection(gra_messageswidget, starttp, tp, 0);
3499 			XmTextRemove(gra_messageswidget);
3500 			total = 0;
3501 			continue;
3502 		}
3503 		tp = XmTextGetLastPosition(gra_messageswidget);
3504 		ch[0] = c;
3505 		ch[1] = 0;
3506 		XmTextInsert(gra_messageswidget, tp, string1byte(ch));
3507 		tp = XmTextGetLastPosition(gra_messageswidget);
3508 		XmTextSetSelection(gra_messageswidget, tp, tp, 0);
3509 		total++;
3510 	}
3511 	gra_messages_typingin = FALSE;
3512 
3513 	block1 = (CHAR1 *)emalloc((total+2) * (sizeof (CHAR1)), el_tempcluster);
3514 	if (block1 == 0)
3515 	{
3516 		efprintf(stderr, _("Cannot make type-in buffer\n"));
3517 		return(0);
3518 	}
3519 	XmTextGetSubstring(gra_messageswidget, starttp, total+1, total+2, block1);
3520 	block1[total] = 0;
3521 	infstr = initinfstr();
3522 	addstringtoinfstr(infstr, string2byte(block1));
3523 	efree((CHAR *)block1);
3524 	block = returninfstr(infstr);
3525 
3526 	/* add in final carriage return */
3527 	tp = XmTextGetLastPosition(gra_messageswidget);
3528 	XmTextInsert(gra_messageswidget, tp, b_("\n"));
3529 
3530 	/* return the string (0 on EOF or null) */
3531 	if (*block == 0 && c == 4) return(0);
3532 	return(block);
3533 }
3534 
3535 /* X Font Selection */
3536 DIALOGITEM gra_xfontdialogitems[] =
3537 {
3538  /*  1 */ {0, {312,592,336,652}, BUTTON, N_("OK")},
3539  /*  2 */ {0, {312,312,336,372}, BUTTON, N_("Cancel")},
3540  /*  3 */ {0, {8,8,24,88}, MESSAGE, N_("Foundry")},
3541  /*  4 */ {0, {8,96,24,296}, POPUP, x_("")},
3542  /*  5 */ {0, {32,8,48,88}, MESSAGE, N_("Family")},
3543  /*  6 */ {0, {32,96,48,296}, POPUP, x_("")},
3544  /*  7 */ {0, {56,8,72,88}, MESSAGE, N_("Weight")},
3545  /*  8 */ {0, {56,96,72,296}, POPUP, x_("")},
3546  /*  9 */ {0, {80,8,96,88}, MESSAGE, N_("Slant")},
3547  /* 10 */ {0, {80,96,96,296}, POPUP, x_("")},
3548  /* 11 */ {0, {104,8,120,88}, MESSAGE, N_("S Width")},
3549  /* 12 */ {0, {104,96,120,296}, POPUP, x_("")},
3550  /* 13 */ {0, {128,8,144,88}, MESSAGE, N_("Ad Style")},
3551  /* 14 */ {0, {128,96,144,296}, POPUP, x_("")},
3552  /* 15 */ {0, {152,8,168,88}, MESSAGE, N_("Pixel Size")},
3553  /* 16 */ {0, {152,96,168,296}, POPUP, x_("")},
3554  /* 17 */ {0, {176,8,192,88}, MESSAGE, N_("Point Size")},
3555  /* 18 */ {0, {176,96,192,296}, POPUP, x_("")},
3556  /* 19 */ {0, {200,8,216,88}, MESSAGE, N_("X Resolution")},
3557  /* 20 */ {0, {200,96,216,296}, POPUP, x_("")},
3558  /* 21 */ {0, {224,8,240,88}, MESSAGE, N_("Y Resolution")},
3559  /* 22 */ {0, {224,96,240,296}, POPUP, x_("")},
3560  /* 23 */ {0, {248,8,264,88}, MESSAGE, N_("Spacing")},
3561  /* 24 */ {0, {248,96,264,296}, POPUP, x_("")},
3562  /* 25 */ {0, {272,8,288,88}, MESSAGE, N_("Avg Width")},
3563  /* 26 */ {0, {272,96,288,296}, POPUP, x_("")},
3564  /* 27 */ {0, {296,8,312,88}, MESSAGE, N_("Registry")},
3565  /* 28 */ {0, {296,96,312,296}, POPUP, x_("")},
3566  /* 29 */ {0, {320,8,336,88}, MESSAGE, N_("Encoding")},
3567  /* 30 */ {0, {320,96,336,296}, POPUP, x_("")},
3568  /* 31 */ {0, {8,304,300,656}, SCROLL, x_("")}
3569 };
3570 DIALOG gra_xfontdialog = {{75,75,421,740}, N_("Font Selection"), 0, 31, gra_xfontdialogitems, 0, 0};
3571 
3572 /* special items for the messages window font dialog: */
3573 #define DMSF_FIRSTPOPUP    4		/* first popup (popup) */
3574 #define DMSF_LASTPOPUP    30		/* last popup (popup) */
3575 #define DMSF_FONTLIST     31		/* list of fonts (scroll) */
3576 
3577 /*
3578  * routine to select fonts in the messages window
3579  */
setmessagesfont(void)3580 void setmessagesfont(void)
3581 {
3582 	CHAR1 **fontlist;
3583 	CHAR *required[14], ***choices;
3584 	int namecount;
3585 	INTBIG i, j, k, *numchoices;
3586 	INTBIG itemHit;
3587 	REGISTER void *dia;
3588 	Arg arg[1];
3589 	XmFontListEntry entry;
3590 	XmFontList xfontlist;
3591 
3592 	/* get the list of available fonts */
3593 	fontlist = XListFonts(gra_altdpy, b_("-*-*-*-*-*-*-*-*-*-*-*-*-*-*"),
3594 		2000, &namecount);
3595 
3596 	/* show the dialog */
3597 	dia = DiaInitDialog(&gra_xfontdialog);
3598 	if (dia == 0) return;
3599 	DiaInitTextDialog(dia, DMSF_FONTLIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone,
3600 		-1, SCDOUBLEQUIT|SCSELMOUSE|SCSMALLFONT|SCFIXEDWIDTH|SCHORIZBAR);
3601 
3602 	/* setup so that all fields are possible */
3603 	for(j=0; j<14; j++)
3604 	{
3605 		required[j] = (CHAR *)emalloc(200*SIZEOFCHAR, el_tempcluster);
3606 		if (required[j] == 0)
3607 		{
3608 			efprintf(stderr, _("Cannot make field for dialog\n"));
3609 			return;
3610 		}
3611 		estrcpy(required[j], x_("*"));
3612 	}
3613 
3614 	/* examine all of the fonts and make a lists of choices for each position */
3615 	gra_makefontchoices(fontlist, namecount, required, &choices, &numchoices, dia);
3616 	for(j=0; j<14; j++)
3617 	{
3618 		DiaSetPopup(dia, j*2+DMSF_FIRSTPOPUP, numchoices[j], choices[j]);
3619 		DiaSetPopupEntry(dia, j*2+DMSF_FIRSTPOPUP, 0);
3620 	}
3621 	for(;;)
3622 	{
3623 		itemHit = DiaNextHit(dia);
3624 		if (itemHit == OK || itemHit == CANCEL) break;
3625 		if (itemHit >= DMSF_FIRSTPOPUP && itemHit <= DMSF_LASTPOPUP && (itemHit / 2) * 2 == itemHit)
3626 		{
3627 			/* popup changed */
3628 			for(j=0; j<14; j++)
3629 			{
3630 				i = DiaGetPopupEntry(dia, j*2+DMSF_FIRSTPOPUP);
3631 				estrcpy(required[j], choices[j][i]);
3632 			}
3633 			gra_makefontchoices(fontlist, namecount, required, &choices, &numchoices, dia);
3634 			for(j=0; j<14; j++)
3635 			{
3636 				DiaSetPopup(dia, j*2+DMSF_FIRSTPOPUP, numchoices[j], choices[j]);
3637 				for(i=0; i<numchoices[j]; i++)
3638 					if (namesame(choices[j][i], required[j]) == 0) break;
3639 				DiaSetPopupEntry(dia, j*2+DMSF_FIRSTPOPUP, i);
3640 			}
3641 			continue;
3642 		}
3643 	}
3644 	if (itemHit == OK)
3645 	{
3646 		i = DiaGetCurLine(dia, DMSF_FONTLIST);
3647 		estrcpy(required[0], DiaGetScrollLine(dia, DMSF_FONTLIST, i));
3648 		entry = XmFontListEntryLoad(gra_altdpy, string1byte(required[0]),
3649 			XmFONT_IS_FONT, b_("TAG"));
3650 		xfontlist = XmFontListAppendEntry(NULL, entry);
3651 		XmFontListEntryFree(&entry);
3652 		XtSetArg(arg[0], XmNfontList, xfontlist);
3653 		XtSetValues(gra_messageswidget, arg, 1);
3654 		XmFontListFree(xfontlist);
3655 	}
3656 	DiaDoneDialog(dia);
3657 	XFreeFontPath(fontlist);
3658 
3659 	/* free the memory */
3660 	for(j=0; j<14; j++)
3661 	{
3662 		for(k=0; k<numchoices[j]; k++)
3663 			efree((CHAR *)choices[j][k]);
3664 		efree((CHAR *)required[j]);
3665 	}
3666 }
3667 
gra_makefontchoices(CHAR1 ** fontlist,INTBIG namecount,CHAR * required[14],CHAR **** fchoices,INTBIG ** fnumchoices,void * dia)3668 void gra_makefontchoices(CHAR1 **fontlist, INTBIG namecount, CHAR *required[14],
3669 	CHAR ****fchoices, INTBIG **fnumchoices, void *dia)
3670 {
3671 	CHAR *pt, *start, save, **newchoices;
3672 	INTBIG i, j, k, newsize;
3673 	static INTBIG totalchoices[14], numchoices[14];
3674 	static CHAR **choices[14], *current[14];
3675 	static BOOLEAN inited = FALSE;
3676 
3677 	/* load the return parameters */
3678 	*fchoices = (CHAR ***)choices;
3679 	*fnumchoices = (INTBIG *)numchoices;
3680 
3681 	/* one-time memory allocation and initialization */
3682 	if (!inited)
3683 	{
3684 		inited = TRUE;
3685 		for(j=0; j<14; j++)
3686 		{
3687 			totalchoices[j] = 5;
3688 			choices[j] = (CHAR **)emalloc(5 * (sizeof (CHAR *)),
3689 				el_tempcluster);
3690 			if (choices[j] == 0)
3691 			{
3692 				efprintf(stderr, _("Cannot make choice field for dialog\n"));
3693 				return;
3694 			}
3695 			numchoices[j] = 0;
3696 			current[j] = (CHAR *)emalloc(200*SIZEOFCHAR, el_tempcluster);
3697 			if (current[j] == 0)
3698 			{
3699 				efprintf(stderr, _("Cannot make answer field for dialog\n"));
3700 				return;
3701 			}
3702 		}
3703 	}
3704 
3705 	/* initialize the popup choices */
3706 	for(j=0; j<14; j++)
3707 	{
3708 		/* free former memory */
3709 		for(k=0; k<numchoices[j]; k++)
3710 			efree((CHAR *)choices[j][k]);
3711 		numchoices[j] = 1;
3712 		choices[j][0] = (CHAR *)emalloc(2*SIZEOFCHAR, el_tempcluster);
3713 		if (choices[j][0] == 0)
3714 		{
3715 			efprintf(stderr, _("Cannot make popup for dialog\n"));
3716 			return;
3717 		}
3718 		estrcpy(choices[j][0], x_("*"));
3719 	}
3720 
3721 	/* initialize the scroll area */
3722 	DiaLoadTextDialog(dia, DMSF_FONTLIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1);
3723 
3724 	/* examine each font and build the choice list */
3725 	for(i=0; i<namecount; i++)
3726 	{
3727 		/* break the font name into fields, make sure it matches filter */
3728 		pt = string2byte(fontlist[i]);
3729 		for(j=0; j<14; j++)
3730 		{
3731 			if (*pt == '-') pt++;
3732 			start = pt;
3733 			while (*pt != 0 && *pt != '-') pt++;
3734 			save = *pt;
3735 			*pt = 0;
3736 			if (*start == 0) estrcpy(current[j], x_("(nil)")); else
3737 				estrcpy(current[j], start);
3738 			*pt = save;
3739 			if (required[j][0] == '*') continue;
3740 			if (namesame(required[j], current[j]) != 0) break;
3741 		}
3742 		if (j < 14) continue;
3743 		DiaStuffLine(dia, DMSF_FONTLIST, string2byte(fontlist[i]));
3744 
3745 		/* add this to the list of choices */
3746 		for(j=0; j<14; j++)
3747 		{
3748 			for(k=0; k<numchoices[j]; k++)
3749 				if (namesame(current[j], choices[j][k]) == 0) break;
3750 			if (k < numchoices[j]) continue;
3751 
3752 			/* add this choice */
3753 			if (numchoices[j] >= totalchoices[j])
3754 			{
3755 				newsize = totalchoices[j] * 2;
3756 				newchoices = (CHAR **)emalloc(newsize * (sizeof (CHAR *)),
3757 					el_tempcluster);
3758 				if (newchoices == 0)
3759 				{
3760 					efprintf(stderr, _("Cannot make choice list for dialog\n"));
3761 					return;
3762 				}
3763 				for(k=0; k<numchoices[j]; k++)
3764 					newchoices[k] = choices[j][k];
3765 				efree((CHAR *)choices[j]);
3766 				choices[j] = newchoices;
3767 				totalchoices[j] = newsize;
3768 			}
3769 			choices[j][numchoices[j]] = (CHAR *)emalloc((estrlen(current[j])+1) * SIZEOFCHAR,
3770 				el_tempcluster);
3771 			if (choices[j][numchoices[j]] == 0)
3772 			{
3773 				efprintf(stderr, _("Cannot make choice entry for dialog\n"));
3774 				return;
3775 			}
3776 			estrcpy(choices[j][numchoices[j]], current[j]);
3777 			numchoices[j]++;
3778 		}
3779 	}
3780 
3781 	/* sort the choice lists */
3782 	for(j=0; j<14; j++)
3783 	{
3784 		switch (j)
3785 		{
3786 			case 6:
3787 			case 7:
3788 			case 8:
3789 			case 9:
3790 			case 11:
3791 				esort(&choices[j][1], numchoices[j]-1, sizeof (CHAR *), gra_sortnumbereascending);
3792 				break;
3793 			default:
3794 				esort(&choices[j][1], numchoices[j]-1, sizeof (CHAR *), sort_stringascending);
3795 				break;
3796 		}
3797 	}
3798 	DiaSelectLine(dia, DMSF_FONTLIST, -1);
3799 }
3800 
gra_sortnumbereascending(const void * e1,const void * e2)3801 int gra_sortnumbereascending(const void *e1, const void *e2)
3802 {
3803 	REGISTER CHAR *c1, *c2;
3804 
3805 	c1 = *((CHAR **)e1);
3806 	c2 = *((CHAR **)e2);
3807 	return(eatoi(c1) - eatoi(c2));
3808 }
3809 
3810 /*
3811  * routine to cut text from the messages window if it is current.  Returns true
3812  * if sucessful.
3813  */
cutfrommessages(void)3814 BOOLEAN cutfrommessages(void)
3815 {
3816 	/* stop now if messages window is not on top */
3817 	if (!gra_msgontop) return(FALSE);
3818 
3819 	XmTextCut(gra_messageswidget, CurrentTime);
3820 	return(TRUE);
3821 }
3822 
3823 /*
3824  * routine to copy text from the messages window if it is current.  Returns true
3825  * if sucessful.
3826  */
copyfrommessages(void)3827 BOOLEAN copyfrommessages(void)
3828 {
3829 	/* stop now if messages window is not on top */
3830 	if (!gra_msgontop) return(FALSE);
3831 
3832 	XmTextCopy(gra_messageswidget, CurrentTime);
3833 	return(TRUE);
3834 }
3835 
3836 /*
3837  * routine to paste text to the messages window if it is current.  Returns true
3838  * if sucessful.
3839  */
pastetomessages(void)3840 BOOLEAN pastetomessages(void)
3841 {
3842 	/* stop now if messages window is not on top */
3843 	if (!gra_msgontop) return(FALSE);
3844 
3845 	XmTextPaste(gra_messageswidget);
3846 	return(TRUE);
3847 }
3848 
3849 /*
3850  * routine to get the contents of the system cut buffer
3851  */
getcutbuffer(void)3852 CHAR *getcutbuffer(void)
3853 {
3854 	unsigned long length, got;
3855 	int status;
3856 	CHAR *tmpbuf;
3857 	REGISTER void *infstr;
3858 
3859 	/* determine the amount of data in the clipboard */
3860 	for(;;)
3861 	{
3862 		status = XmClipboardInquireLength(gra_topmsgdpy, gra_topmsgwin, b_("STRING"), &length);
3863 		if (status != ClipboardLocked) break;
3864 	}
3865 	if (length <= 0) return(x_(""));
3866 
3867 	/* get the data */
3868 	tmpbuf = (CHAR *)emalloc((length+1) * SIZEOFCHAR, el_tempcluster);
3869 	if (tmpbuf == 0) return(x_(""));
3870 	for(;;)
3871 	{
3872 		status = XmClipboardRetrieve(gra_topmsgdpy, gra_topmsgwin, b_("STRING"),
3873 			tmpbuf, length+1, &got, NULL);
3874 		if (status != ClipboardLocked) break;
3875 	}
3876 	tmpbuf[got] = 0;
3877 	infstr = initinfstr();
3878 	addstringtoinfstr(infstr, tmpbuf);
3879 	efree((CHAR *)tmpbuf);
3880 	return(returninfstr(infstr));
3881 }
3882 
3883 /*
3884  * routine to set the contents of the system cut buffer to "msg"
3885  */
setcutbuffer(CHAR * msg)3886 void setcutbuffer(CHAR *msg)
3887 {
3888 	XmString label;
3889 	int status;
3890 	static int copycount = 1;
3891 	long itemid = 0;
3892 
3893 	/* open the clipboard */
3894 	label = XmStringCreateLocalized(b_("electric"));
3895 	for(;;)
3896 	{
3897 		status = XmClipboardStartCopy(gra_topmsgdpy, gra_topmsgwin, label,
3898 			CurrentTime, NULL, NULL, &itemid);
3899 		if (status != ClipboardLocked) break;
3900 	}
3901 	XmStringFree(label);
3902 
3903 	/* copy the data */
3904 	copycount++;
3905 	for(;;)
3906 	{
3907 		status = XmClipboardCopy(gra_topmsgdpy, gra_topmsgwin, itemid, b_("STRING"),
3908 			msg, estrlen(msg)+1, copycount, NULL);
3909 		if (status != ClipboardLocked) break;
3910 	}
3911 
3912 	/* close the clipboard */
3913 	for(;;)
3914 	{
3915 		status = XmClipboardEndCopy(gra_topmsgdpy, gra_topmsgwin, itemid);
3916 		if (status != ClipboardLocked) break;
3917 	}
3918 }
3919 
3920 /*
3921  * Routine to clear all text from the messages window.
3922  */
clearmessageswindow(void)3923 void clearmessageswindow(void)
3924 {
3925 	XmTextPosition tp;
3926 
3927 	tp = XmTextGetLastPosition(gra_messageswidget);
3928 	XmTextSetSelection(gra_messageswidget, 0, tp, 0);
3929 	XmTextRemove(gra_messageswidget);
3930 }
3931 
3932 /******************** GRAPHICS CONTROL ROUTINES ********************/
3933 
flushscreen(void)3934 void flushscreen(void)
3935 {
3936 #ifdef ANYDEPTH
3937 	REGISTER INTBIG x, y, lx, hx, ly, hy;
3938 	REGISTER UCHAR1 *srow, *drow, *sval;
3939 	REGISTER UCHAR1 **srowstart, **drowstart;
3940 	REGISTER INTBIG *colorvalue;
3941 	REGISTER WINDOWFRAME *wf;
3942 	REGISTER WINDOWDISPLAY *wd;
3943 	UCHAR1 col[4];
3944 	GC gc;
3945 	XGCValues gcv;
3946 
3947 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
3948 	{
3949 		/* nothing to do if no changes have been made to offscreen buffer */
3950 		if (!wf->offscreendirty) continue;
3951 		wf->offscreendirty = FALSE;
3952 
3953 		/* get bounds of display update */
3954 		lx = wf->copyleft;   hx = wf->copyright;
3955 		ly = wf->copytop;    hy = wf->copybottom;
3956 		if (lx < 0) lx = 0;
3957 		if (hx > wf->swid) hx = wf->swid;
3958 		if (ly < 0) ly = 0;
3959 		if (hy > wf->trueheight) hy = wf->trueheight;
3960 
3961 		/* copy from offscreen buffer to Ximage while doing color mapping */
3962 		wd = wf->wd;
3963 		srowstart = wf->rowstart;
3964 		colorvalue = wd->colorvalue;
3965 		drowstart = wd->rowstart;
3966 		switch (wd->depth)
3967 		{
3968 			case 8:
3969 				for(y=ly; y<hy; y++)
3970 				{
3971 					srow = (UCHAR1 *)(srowstart[y] + lx);
3972 					drow = (UCHAR1 *)(drowstart[y] + lx);
3973 					for(x=lx; x<hx; x++)
3974 						*drow++ = colorvalue[*srow++];
3975 				}
3976 				break;
3977 
3978 			case 16:
3979 				for(y=ly; y<hy; y++)
3980 				{
3981 					srow = (UCHAR1 *)(srowstart[y] + lx);
3982 					drow = (UCHAR1 *)(drowstart[y] + (lx << 1));
3983 					for(x=lx; x<hx; x++)
3984 					{
3985 						sval = (UCHAR1 *)&colorvalue[*srow++];
3986 						*drow++ = sval[0];
3987 						*drow++ = sval[1];
3988 					}
3989 				}
3990 				break;
3991 
3992 			case 24:
3993 			case 32:
3994 				for(y=ly; y<hy; y++)
3995 				{
3996 					srow = (UCHAR1 *)(srowstart[y] + lx);
3997 					drow = (UCHAR1 *)(drowstart[y] + (lx << 2));
3998 					for(x=lx; x<hx; x++)
3999 					{
4000 						sval = (UCHAR1 *)&colorvalue[*srow++];
4001 #if 1
4002 #  ifdef BYTES_SWAPPED
4003 						col[gra_mainredshift>>3] = sval[3];
4004 						col[gra_maingreenshift>>3] = sval[2];
4005 						col[gra_mainblueshift>>3] = sval[1];
4006 						col[3] = sval[0];
4007 #  else
4008 						col[gra_mainredshift>>3] = sval[0];
4009 						col[gra_maingreenshift>>3] = sval[1];
4010 						col[gra_mainblueshift>>3] = sval[2];
4011 						col[3] = sval[3];
4012 #  endif
4013 						*drow++ = col[3];
4014 						*drow++ = col[2];
4015 						*drow++ = col[1];
4016 						*drow++ = col[0];
4017 #else
4018 #  ifdef BYTES_SWAPPED
4019 						*drow++ = sval[0];
4020 						*drow++ = sval[1];
4021 						*drow++ = sval[2];
4022 						*drow++ = sval[3];
4023 #  else
4024 						*drow++ = sval[2];
4025 						*drow++ = sval[1];
4026 						*drow++ = sval[0];
4027 						*drow++ = sval[3];
4028 #  endif
4029 #endif
4030 					}
4031 				}
4032 				break;
4033 		}
4034 
4035 		/* copy XImage to the screen */
4036 		gcv.foreground = BlackPixel(wf->topdpy, DefaultScreen(wf->topdpy));
4037 		gc = XtGetGC(wf->graphicswidget, GCForeground, &gcv);
4038 		XPutImage(wf->topdpy, wf->win, gc, wd->image, lx, ly, lx, ly, hx-lx, hy-ly);
4039 		XtReleaseGC(wf->graphicswidget, gc);
4040 		XFlush(wf->topdpy);
4041 	}
4042 #endif
4043 }
4044 
4045 /*
4046  * Routine to mark an area of the offscreen buffer as "changed".
4047  */
gra_setrect(WINDOWFRAME * wf,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)4048 void gra_setrect(WINDOWFRAME *wf, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
4049 {
4050 	static INTBIG checktimefreq = 0;
4051 
4052 	if (wf->offscreendirty)
4053 	{
4054 		if (lx < wf->copyleft) wf->copyleft = lx;
4055 		if (hx > wf->copyright) wf->copyright = hx;
4056 		if (ly < wf->copytop) wf->copytop = ly;
4057 		if (hy > wf->copybottom) wf->copybottom = hy;
4058 	} else
4059 	{
4060 		wf->copyleft = lx;   wf->copyright = hx;
4061 		wf->copytop = ly;    wf->copybottom = hy;
4062 		wf->offscreendirty = TRUE;
4063 		wf->starttime = ticktime();
4064 	}
4065 
4066 	/* flush the screen every two seconds */
4067 	checktimefreq++;
4068 	if (checktimefreq > 10000)
4069 	{
4070 		checktimefreq = 0;
4071 		if (ticktime() - wf->starttime > FLUSHTICKS) flushscreen();
4072 	}
4073 }
4074 
gra_getdisplaydepth(Display * dpy,INTBIG * depth,INTBIG * truedepth)4075 void gra_getdisplaydepth(Display *dpy, INTBIG *depth, INTBIG *truedepth)
4076 {
4077 	*depth = DefaultDepth(dpy, DefaultScreen(dpy));
4078 	*truedepth = *depth;
4079 	if (*truedepth == 24) *truedepth = 32;
4080 }
4081 
gra_makewindowdisplaybuffer(WINDOWDISPLAY * wd,Display * dpy)4082 BOOLEAN gra_makewindowdisplaybuffer(WINDOWDISPLAY *wd, Display *dpy)
4083 {
4084 	INTBIG amt, i, scr;
4085 	Visual *visual;
4086 
4087 	/* get information about this display */
4088 	gra_getdisplaydepth(dpy, &wd->depth, &wd->truedepth);
4089 	scr = DefaultScreen(dpy);
4090 	wd->wid = DisplayWidth(dpy, scr);
4091 	wd->hei = DisplayHeight(dpy, scr);
4092 	visual = DefaultVisual(dpy, scr);
4093 
4094 	/* allocate data for ximage */
4095 	amt = wd->wid * wd->hei * wd->truedepth / 8;
4096 	wd->addr = (UCHAR1 *)emalloc(amt, us_tool->cluster);
4097 	if (wd->addr == 0)
4098 	{
4099 		efprintf(stderr, _("Error allocating %ld image array\n"), amt);
4100 		return(TRUE);
4101 	}
4102 
4103 	/* make the ximage */
4104 	wd->image = XCreateImage(gra_maindpy, visual, wd->depth, ZPixmap,
4105 		0, (CHAR1 *)wd->addr, wd->wid, wd->hei, wd->truedepth, 0);
4106 	if (wd->image == 0)
4107 	{
4108 		efprintf(stderr, _("Error allocating %ldx%ld image array\n"), wd->wid, wd->hei);
4109 		return(TRUE);
4110 	}
4111 
4112 	/* make the row-start pointers for this image */
4113 	wd->rowstart = (UCHAR1 **)emalloc(wd->hei * SIZEOFINTBIG, us_tool->cluster);
4114 	if (wd->rowstart == 0)
4115 	{
4116 		efprintf(stderr, _("Error allocating %ld-long row pointers\n"), wd->hei);
4117 		return(TRUE);
4118 	}
4119 	for(i=0; i<wd->hei; i++)
4120 		wd->rowstart[i] = wd->addr + i * wd->image->bytes_per_line;
4121 	return(FALSE);
4122 }
4123 
4124 /*
4125  * Routine to change the default cursor (to indicate modes).
4126  */
setnormalcursor(INTBIG curs)4127 void setnormalcursor(INTBIG curs)
4128 {
4129 	us_normalcursor = curs;
4130 	setdefaultcursortype(us_normalcursor);
4131 }
4132 
gra_reloadmap(void)4133 void gra_reloadmap(void)
4134 {
4135 	REGISTER VARIABLE *varred, *vargreen, *varblue;
4136 
4137 	varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
4138 	vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
4139 	varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
4140 	if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE) return;
4141 	colormapload((INTBIG *)varred->addr, (INTBIG *)vargreen->addr, (INTBIG *)varblue->addr, 0, 255);
4142 }
4143 
colormapload(INTBIG * red,INTBIG * green,INTBIG * blue,INTBIG low,INTBIG high)4144 void colormapload(INTBIG *red, INTBIG *green, INTBIG *blue, INTBIG low, INTBIG high)
4145 {
4146 #ifdef ANYDEPTH
4147 	REGISTER INTBIG i;
4148 	REGISTER INTBIG r, g, b, depth;
4149 	XColor xc;
4150 	REGISTER WINDOWFRAME *wf;
4151 	Visual *visual;
4152 
4153 	/* clip to the number of map entries requested */
4154 	if (high >= el_maplength) high = el_maplength - 1;
4155 
4156 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4157 	{
4158 		visual = DefaultVisual(wf->topdpy, DefaultScreen(wf->topdpy));
4159 		for(i=low; i<=high; i++)
4160 		{
4161 			xc.flags = DoRed | DoGreen | DoBlue;
4162 			r = red[i-low];
4163 			g = green[i-low];
4164 			b = blue[i-low];
4165 
4166 			/* always complement the highest color */
4167 			if (low < 255 && i == 255)
4168 			{
4169 				r = 255 - red[i-low];
4170 				g = 255 - green[i-low];
4171 				b = 255 - blue[i-low];
4172 			}
4173 
4174 			/* for 16bpp, crop values to 5 bits */
4175 			xc.red   = r << 8;
4176 			xc.green = g << 8;
4177 			xc.blue  = b << 8;
4178 
4179 			/* if this is color-mapped, get closest entry in that map */
4180 			if (VisualClass(visual) == PseudoColor ||
4181 				VisualClass(visual) == StaticColor)
4182 			{
4183 				XAllocColor(wf->topdpy, wf->colormap, &xc);
4184 				wf->wd->colorvalue[i] = xc.pixel;
4185 			} else
4186 			{
4187 				depth = DefaultDepth(wf->topdpy, DefaultScreen(wf->topdpy));
4188 				if (depth == 16)
4189 				{
4190 					wf->wd->colorvalue[i] = ((r & 0xF8) << 8) |
4191 						((g & 0xF8) << 3) | ((b & 0xF8) >> 3);
4192 				} else
4193 				{
4194 					wf->wd->colorvalue[i] = (b << 16) | (g << 8) | r;
4195 				}
4196 			}
4197 		}
4198 
4199 		/* mark the entire screen for redrawing */
4200 		if (low == 0 && high == 255)
4201 		{
4202 			gra_setrect(wf, 0, wf->swid, 0, wf->trueheight);
4203 			flushscreen();
4204 		}
4205 
4206 		/* set the cursor color */
4207 		if (low == 0 || (low <= el_colcursor && high >= el_colcursor))
4208 		{
4209 			gra_xfc.flags = gra_xbc.flags = DoRed | DoGreen | DoBlue;
4210 			gra_xbc.red = red[0] << 8;
4211 			gra_xbc.green = green[0] << 8;
4212 			gra_xbc.blue = blue[0] << 8;
4213 			gra_xfc.red = red[el_colcursor] << 8;
4214 			gra_xfc.green = green[el_colcursor] << 8;
4215 			gra_xfc.blue = blue[el_colcursor] << 8;
4216 			gra_recolorcursor(wf->topdpy, &gra_xfc, &gra_xbc);
4217 		}
4218 	}
4219 #else
4220 	REGISTER INTBIG i;
4221 	XColor xc[256];
4222 	REGISTER WINDOWFRAME *wf;
4223 
4224 	/* clip to the number of map entries requested */
4225 	if (high > gra_maphigh) high = gra_maphigh;
4226 
4227 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4228 	{
4229 		for(i=low; i<=high; i++)
4230 		{
4231 			xc[i-low].flags = DoRed | DoGreen | DoBlue;
4232 			xc[i-low].pixel = i;
4233 			xc[i-low].red   =   red[i-low] << 8;
4234 			xc[i-low].green = green[i-low] << 8;
4235 			xc[i-low].blue  =  blue[i-low] << 8;
4236 
4237 			/* always complement the highest color */
4238 			if (low < 255 && i == 255)
4239 			{
4240 				xc[i-low].red   = (255 -   red[i-low]) << 8;
4241 				xc[i-low].green = (255 - green[i-low]) << 8;
4242 				xc[i-low].blue  = (255 -  blue[i-low]) << 8;
4243 			}
4244 		}
4245 
4246 		XStoreColors(wf->topdpy, wf->colormap, xc, high-low + 1);
4247 
4248 		if (low == 0 || (low <= el_colcursor && high >= el_colcursor))
4249 		{
4250 			gra_xfc.pixel = el_colcursor;
4251 			XQueryColor(wf->topdpy, wf->colormap, &gra_xfc);
4252 			gra_xbc.pixel = 0;
4253 			XQueryColor(wf->topdpy, wf->colormap, &gra_xbc);
4254 			gra_recolorcursor(wf->topdpy, &gra_xfc, &gra_xbc);
4255 		}
4256 	}
4257 #endif
4258 
4259 	/* change messages window colors */
4260 	if (low == 0 && high == 255 && gra_messageswidget != 0)
4261 	{
4262 		Pixel fg, bg;
4263 #if 0
4264 		XColor xc;
4265 
4266 		XtVaGetValues(gra_messageswidget, XtNbackground, &bg, XtNforeground, &fg, NULL);
4267 		xc.flags = DoRed | DoGreen | DoBlue;
4268 		xc.pixel = bg;
4269 		xc.red = red[0]<<8;   xc.green = green[0]<<8;   xc.blue = blue[0]<<8;
4270 		XStoreColor(gra_topmsgdpy, gra_messagescolormap, &xc);
4271 
4272 		xc.flags = DoRed | DoGreen | DoBlue;
4273 		xc.pixel = bg;
4274 		xc.red = red[CELLTXT]<<8;   xc.green = green[CELLTXT]<<8;   xc.blue = blue[CELLTXT]<<8;
4275 		XStoreColor(gra_topmsgdpy, gra_messagescolormap, &xc);
4276 #else
4277 		Visual *visual;
4278 		visual = DefaultVisual(gra_topmsgdpy, DefaultScreen(gra_topmsgdpy));
4279 		if (VisualClass(visual) != PseudoColor && VisualClass(visual) != StaticColor)
4280 		{
4281 			bg = (blue[0] << 16) | (green[0] << 8) | red[0];
4282 			fg = (blue[CELLTXT] << 16) | (green[CELLTXT] << 8) | red[CELLTXT];
4283 			XtVaSetValues(gra_messageswidget, XmNbackground, bg, XmNforeground, fg, NULL);
4284 			XtVaSetValues(gra_messageswidget, XtNbackground, bg, XtNforeground, fg, NULL);
4285 		}
4286 #endif
4287 	}
4288 }
4289 
4290 /*
4291  * Helper routine to change the cursor color.
4292  * fg and bg are the XColor structures to be used. We will look up the current
4293  * values for the cursor and the background from the installed color map, and
4294  * copy them into bg and fg.
4295  */
gra_recolorcursor(Display * dpy,XColor * fg,XColor * bg)4296 void gra_recolorcursor(Display *dpy, XColor *fg, XColor *bg)
4297 {
4298 	XRecolorCursor(dpy, gra_realcursor, fg, bg);
4299 	XRecolorCursor(dpy, gra_nomousecursor, fg, bg);
4300 	XRecolorCursor(dpy, gra_drawcursor, fg, bg);
4301 	XRecolorCursor(dpy, gra_nullcursor, fg, bg);
4302 	XRecolorCursor(dpy, gra_menucursor, fg, bg);
4303 	XRecolorCursor(dpy, gra_handcursor, fg, bg);
4304 	XRecolorCursor(dpy, gra_techcursor, fg, bg);
4305 	XRecolorCursor(dpy, gra_ibeamcursor, fg, bg);
4306 	XRecolorCursor(dpy, gra_lrcursor, fg, bg);
4307 	XRecolorCursor(dpy, gra_udcursor, fg, bg);
4308 }
4309 
4310 #ifndef ANYDEPTH
4311 /*
4312  * routine to load the global Graphic Context "wf->gcstip" with the
4313  * stipple pattern in "raster"
4314  */
gra_loadstipple(WINDOWFRAME * wf,UINTSML raster[])4315 void gra_loadstipple(WINDOWFRAME *wf, UINTSML raster[])
4316 {
4317 	static Pixmap buildup = (Pixmap)NULL;
4318 	static XImage ximage;
4319 	static INTBIG data[8];
4320 	static GC pgc;
4321 	XGCValues gcv;
4322 	REGISTER INTBIG y, pattern, depth, scr;
4323 	static BOOLEAN reverse = FALSE;   /* for debugging and testing */
4324 
4325 	/* initialize raster structure for patterned write */
4326 	if (buildup == (Pixmap)NULL)
4327 	{
4328 		buildup = XCreatePixmap(wf->topdpy, wf->win, 32, 8, 1);
4329 		scr = DefaultScreen(wf->topdpy);
4330 		depth = DefaultDepth(wf->topdpy, scr);
4331 		if (depth != 1)
4332 		{
4333 			/* choose polarity of stipples */
4334 #ifdef i386
4335 			gcv.background = BlackPixel(wf->topdpy, scr);
4336 			gcv.foreground = WhitePixel(wf->topdpy, scr);
4337 #else
4338 			gcv.foreground = BlackPixel(wf->topdpy, scr);
4339 			gcv.background = WhitePixel(wf->topdpy, scr);
4340 #endif
4341 		} else
4342 		{
4343 			/* monochrome */
4344 			gcv.foreground = BlackPixel(wf->topdpy, scr);
4345 			gcv.background = WhitePixel(wf->topdpy, scr);
4346 		}
4347 		if (reverse)
4348 		{
4349 			y = gcv.foreground;
4350 			gcv.foreground = gcv.background;
4351 			gcv.background = y;
4352 		}
4353 		gcv.fill_style = FillStippled;
4354 		pgc = XCreateGC(wf->topdpy, buildup, GCForeground | GCBackground | GCFillStyle, &gcv);
4355 		ximage.width = 32;
4356 		ximage.height = 8;
4357 		ximage.xoffset = 0;
4358 		ximage.format = XYBitmap;
4359 		ximage.data = (CHAR *)data;
4360 		ximage.byte_order = XImageByteOrder(wf->topdpy);
4361 		ximage.bitmap_unit = XBitmapUnit(wf->topdpy);
4362 		ximage.bitmap_bit_order = XBitmapBitOrder(wf->topdpy);
4363 		ximage.bitmap_pad = XBitmapPad(wf->topdpy);
4364 		ximage.depth = 1;
4365 		ximage.bytes_per_line = 4;
4366 	}
4367 
4368 	for(y=0; y<8; y++)
4369 	{
4370 		pattern = raster[y] & 0xFFFF;
4371 		data[y] = pattern | (pattern << 16);
4372 	}
4373 
4374 	XPutImage(wf->topdpy, buildup, pgc, &ximage, 0, 0, 0, 0, 32, 8);
4375 	XSetStipple(wf->topdpy, wf->gcstip, buildup);
4376 }
4377 
gra_setxstate(WINDOWFRAME * wf,GC gc,GRAPHICS * desc)4378 void gra_setxstate(WINDOWFRAME *wf, GC gc, GRAPHICS *desc)
4379 {
4380 	XSetPlaneMask(wf->topdpy, gc, desc->bits & gra_maphigh);
4381 	XSetForeground(wf->topdpy, gc, desc->col);
4382 }
4383 #endif
4384 
4385 /*
4386  * Helper routine to set the cursor shape to "state".
4387  */
setdefaultcursortype(INTBIG state)4388 void setdefaultcursortype(INTBIG state)
4389 {
4390 	WINDOWFRAME *wf;
4391 
4392 	if (us_cursorstate == state) return;
4393 
4394 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4395 	{
4396 		switch (state)
4397 		{
4398 			case NORMALCURSOR:
4399 				XDefineCursor(wf->topdpy, wf->topwin, gra_realcursor);
4400 				break;
4401 			case WANTTTYCURSOR:
4402 				XDefineCursor(wf->topdpy, wf->topwin, gra_nomousecursor);
4403 				break;
4404 			case PENCURSOR:
4405 				XDefineCursor(wf->topdpy, wf->topwin, gra_drawcursor);
4406 				break;
4407 			case NULLCURSOR:
4408 				XDefineCursor(wf->topdpy, wf->topwin, gra_nullcursor);
4409 				break;
4410 			case MENUCURSOR:
4411 				XDefineCursor(wf->topdpy, wf->topwin, gra_menucursor);
4412 				break;
4413 			case HANDCURSOR:
4414 				XDefineCursor(wf->topdpy, wf->topwin, gra_handcursor);
4415 				break;
4416 			case TECHCURSOR:
4417 				XDefineCursor(wf->topdpy, wf->topwin, gra_techcursor);
4418 				break;
4419 			case IBEAMCURSOR:
4420 				XDefineCursor(wf->topdpy, wf->topwin, gra_ibeamcursor);
4421 				break;
4422 			case LRCURSOR:
4423 				XDefineCursor(wf->topdpy, wf->topwin, gra_lrcursor);
4424 				break;
4425 			case UDCURSOR:
4426 				XDefineCursor(wf->topdpy, wf->topwin, gra_udcursor);
4427 				break;
4428 		}
4429 	}
4430 
4431 	us_cursorstate = state;
4432 }
4433 
4434 /******************** GRAPHICS LINES ********************/
4435 
4436 /*
4437  * Routine to draw a line in the graphics window.
4438  */
screendrawline(WINDOWPART * win,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,GRAPHICS * desc,INTBIG texture)4439 void screendrawline(WINDOWPART *win, INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2, GRAPHICS *desc,
4440 	INTBIG texture)
4441 {
4442 #ifdef ANYDEPTH
4443 	gra_drawline(win, x1, y1, x2, y2, desc, texture);
4444 #else
4445 	static INTBIG on[] =  {0, 1, 6, 1};
4446 	static INTBIG off[] = {0, 3, 2, 7};
4447 	static INTBIG linestyle[] = {LineSolid, LineOnOffDash, LineOnOffDash, LineOnOffDash};
4448 	CHAR dashes[2];
4449 	REGISTER WINDOWFRAME *wf;
4450 
4451 	/* adjust the co-ordinates for display mapping */
4452 	wf = win->frame;
4453 	y1 = wf->revy - y1;
4454 	y2 = wf->revy - y2;
4455 
4456 	gra_setxstate(wf, wf->gc, desc);
4457 #  ifdef sun
4458 	/*
4459 	 * strange OpenWindows bug requires that the width change in order to
4460 	 * also change the line style
4461 	 */
4462 	XSetLineAttributes(wf->topdpy, wf->gc, 1, linestyle[texture], CapButt, JoinMiter);
4463 #  endif
4464 	XSetLineAttributes(wf->topdpy, wf->gc, 0, linestyle[texture], CapButt, JoinMiter);
4465 
4466 	if (texture != 0)
4467 	{
4468 		dashes[0] = on[texture];
4469 		dashes[1] = off[texture];
4470 		XSetDashes(wf->topdpy, wf->gc, 0, dashes, 2);
4471 	}
4472 
4473 	XDrawLine(wf->topdpy, wf->win, wf->gc, x1, y1, x2, y2);
4474 #endif
4475 }
4476 
4477 /*
4478  * Routine to invert bits of the line in the graphics window
4479  */
screeninvertline(WINDOWPART * win,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2)4480 void screeninvertline(WINDOWPART *win, INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2)
4481 {
4482 #ifdef ANYDEPTH
4483 	gra_invertline(win, x1, y1, x2, y2);
4484 #else
4485 	REGISTER WINDOWFRAME *wf;
4486 
4487 	/* adjust the co-ordinates for display mapping */
4488 	wf = win->frame;
4489 	y1 = wf->revy - y1;
4490 	y2 = wf->revy - y2;
4491 
4492 	XSetPlaneMask(wf->topdpy, wf->gcinv, LAYERH & gra_maphigh);
4493 	XSetLineAttributes(wf->topdpy, wf->gcinv, 0, LineSolid, CapButt, JoinMiter);
4494 	XSetForeground(wf->topdpy, wf->gcinv, HIGHLIT);
4495 	XDrawLine(wf->topdpy, wf->win, wf->gcinv, x1, y1, x2, y2);
4496 #endif
4497 }
4498 
4499 /******************** GRAPHICS POLYGONS ********************/
4500 
4501 /*
4502  * Routine to draw a polygon in the graphics window.
4503  */
screendrawpolygon(WINDOWPART * win,INTBIG * x,INTBIG * y,INTBIG count,GRAPHICS * desc)4504 void screendrawpolygon(WINDOWPART *win, INTBIG *x, INTBIG *y, INTBIG count, GRAPHICS *desc)
4505 {
4506 #ifdef ANYDEPTH
4507 	gra_drawpolygon(win, x, y, count, desc);
4508 #else
4509 	static XPoint *pointlist;
4510 	static INTBIG pointcount = 0;
4511 	REGISTER INTBIG i;
4512 	REGISTER WINDOWFRAME *wf;
4513 
4514 	wf = win->frame;
4515 	if (count > pointcount)
4516 	{
4517 		if (pointcount != 0) efree((CHAR *)pointlist);
4518 		pointcount = 0;
4519 		pointlist = (XPoint *)emalloc(count * (sizeof (XPoint)), us_tool->cluster);
4520 		if (pointlist == 0) return;
4521 		pointcount = count;
4522 	}
4523 
4524 	for(i=0; i<count; i++)
4525 	{
4526 		pointlist[i].x = x[i];
4527 		pointlist[i].y = wf->revy - y[i];
4528 	}
4529 
4530 	if ((desc->colstyle & NATURE) == PATTERNED && desc->col != 0)
4531 	{
4532 		gra_loadstipple(wf, desc->raster);
4533 		gra_setxstate(wf, wf->gcstip, desc);
4534 		XFillPolygon(wf->topdpy, wf->win, wf->gcstip, pointlist, count, Complex,
4535 			CoordModeOrigin);
4536 	} else
4537 	{
4538 		gra_setxstate(wf, wf->gc, desc);
4539 		XFillPolygon(wf->topdpy, wf->win, wf->gc, pointlist, count, Complex, CoordModeOrigin);
4540 	}
4541 #endif
4542 }
4543 
4544 /******************** GRAPHICS BOXES ********************/
4545 
4546 /*
4547  * Routine to draw a box in the graphics window.
4548  */
screendrawbox(WINDOWPART * win,INTBIG lowx,INTBIG highx,INTBIG lowy,INTBIG highy,GRAPHICS * desc)4549 void screendrawbox(WINDOWPART *win, INTBIG lowx, INTBIG highx, INTBIG lowy, INTBIG highy,
4550 	GRAPHICS *desc)
4551 {
4552 #ifdef ANYDEPTH
4553 	gra_drawbox(win, lowx, highx, lowy, highy, desc);
4554 #else
4555 	REGISTER WINDOWFRAME *wf;
4556 
4557 	/* special code for patterned writes */
4558 	wf = win->frame;
4559 	if ((desc->colstyle & NATURE) == PATTERNED && desc->col != 0)
4560 	{
4561 		gra_loadstipple(wf, desc->raster);
4562 		gra_setxstate(wf, wf->gcstip, desc);
4563 		XFillRectangle(wf->topdpy, wf->win, wf->gcstip, lowx, wf->revy - highy,
4564 			highx - lowx + 1, highy-lowy + 1);
4565 #ifdef sun
4566 		/*
4567 		 * there seems to be a bug in OpenWindows: the right edge of stipple
4568 		 * patterns goes haywire if the pattern is more than 32 pixels wide
4569 		 */
4570 		if (highx - lowx + 1 > 32)
4571 		{
4572 			XFillRectangle(wf->topdpy, wf->win, wf->gcstip, highx - 31,
4573 				wf->revy - highy, 32, highy - lowy + 1);
4574 		}
4575 #endif
4576 	} else
4577 	{
4578 		gra_setxstate(wf, wf->gc, desc);
4579 		XFillRectangle(wf->topdpy, wf->win, wf->gc, lowx, wf->revy - highy,
4580 			highx - lowx + 1, highy - lowy + 1);
4581 	}
4582 #endif
4583 }
4584 
4585 /*
4586  * routine to invert the bits in the box from (lowx, lowy) to (highx, highy)
4587  */
screeninvertbox(WINDOWPART * win,INTBIG lowx,INTBIG highx,INTBIG lowy,INTBIG highy)4588 void screeninvertbox(WINDOWPART *win, INTBIG lowx, INTBIG highx, INTBIG lowy, INTBIG highy)
4589 {
4590 #ifdef ANYDEPTH
4591 	gra_invertbox(win, lowx, highx, lowy, highy);
4592 #else
4593 	REGISTER WINDOWFRAME *wf;
4594 
4595 	wf = win->frame;
4596 	XSetPlaneMask(wf->topdpy, wf->gcinv, AllPlanes);
4597 	XFillRectangle(wf->topdpy, wf->win, wf->gcinv, lowx, wf->revy - highy,
4598 		highx - lowx + 1, highy - lowy + 1);
4599 #endif
4600 }
4601 
4602 /*
4603  * routine to move bits on the display starting with the area at
4604  * (sx,sy) and ending at (dx,dy).  The size of the area to be
4605  * moved is "wid" by "hei".
4606  */
screenmovebox(WINDOWPART * win,INTBIG sx,INTBIG sy,INTBIG wid,INTBIG hei,INTBIG dx,INTBIG dy)4607 void screenmovebox(WINDOWPART *win, INTBIG sx, INTBIG sy, INTBIG wid, INTBIG hei,
4608 	INTBIG dx, INTBIG dy)
4609 {
4610 #ifdef ANYDEPTH
4611 	gra_movebox(win, sx, sy, wid, hei, dx, dy);
4612 #else
4613 	REGISTER WINDOWFRAME *wf;
4614 
4615 	/* make sure all bit planes are copied */
4616 	wf = win->frame;
4617 	XSetPlaneMask(wf->topdpy, wf->gc, AllPlanes);
4618 
4619 	XCopyArea(wf->topdpy, wf->win, wf->win, wf->gc, sx, wf->revy + 1 - sy - hei,
4620 			  wid, hei, dx, wf->revy + 1 - dy - hei);
4621 #endif
4622 }
4623 
4624 /*
4625  * routine to save the contents of the box from "lx" to "hx" in X and from
4626  * "ly" to "hy" in Y.  A code is returned that identifies this box for
4627  * overwriting and restoring.  The routine returns negative if there is a error.
4628  */
screensavebox(WINDOWPART * win,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)4629 INTBIG screensavebox(WINDOWPART *win, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
4630 {
4631 #ifdef ANYDEPTH
4632 	return(gra_savebox(win, lx, hx, ly, hy));
4633 #else
4634 	REGISTER WINDOWFRAME *wf;
4635 	SAVEDBOX *box;
4636 	REGISTER INTBIG i;
4637 	REGISTER INTBIG depth;
4638 
4639 	wf = win->frame;
4640 	i = ly;
4641 	ly = wf->revy - hy;
4642 	hy = wf->revy - i;
4643 
4644 	box = (SAVEDBOX *)emalloc((sizeof (SAVEDBOX)), us_tool->cluster);
4645 	if (box == 0) return(-1);
4646 	box->win = win;
4647 
4648 	depth = DefaultDepth(wf->topdpy, DefaultScreen(wf->topdpy));
4649 	box->pix = XCreatePixmap(wf->topdpy, wf->win, hx - lx + 1, hy - ly + 1, depth);
4650 	if (box->pix == 0) return(-1);
4651 
4652 	box->nextsavedbox = gra_firstsavedbox;
4653 	gra_firstsavedbox = box;
4654 	gra_savedboxcodes++;
4655 	box->code = gra_savedboxcodes;
4656 	box->lx = lx;
4657 	box->hx = hx;
4658 	box->ly = ly;
4659 	box->hy = hy;
4660 
4661 	/* make sure the whole buffer is accessable */
4662 	XSetPlaneMask(wf->topdpy, wf->gc, AllPlanes);
4663 	XCopyArea(wf->topdpy, wf->win, box->pix, wf->gc, lx, ly, hx - lx + 1, hy - ly + 1, 0, 0);
4664 
4665 	return(box->code);
4666 #endif
4667 }
4668 
4669 /*
4670  * routine to shift the saved box "code" so that it is restored in a different
4671  * lcoation, offset by (dx,dy)
4672  */
screenmovesavedbox(INTBIG code,INTBIG dx,INTBIG dy)4673 void screenmovesavedbox(INTBIG code, INTBIG dx, INTBIG dy)
4674 {
4675 #ifdef ANYDEPTH
4676 	gra_movesavedbox(code, dx, dy);
4677 #else
4678 	REGISTER SAVEDBOX *box;
4679 
4680 	for(box = gra_firstsavedbox; box != NOSAVEDBOX; box = box->nextsavedbox)
4681 		if (box->code == code) break;
4682 	if (box == NOSAVEDBOX) return;
4683 	box->lx += dx;       box->hx += dx;
4684 	box->ly -= dy;       box->hy -= dy;
4685 #endif
4686 }
4687 
4688 /*
4689  * routine to restore saved box "code" to the screen.  "destroy" is:
4690  *  0   restore box, do not free memory
4691  *  1   restore box, free memory
4692  * -1   free memory
4693  */
screenrestorebox(INTBIG code,INTBIG destroy)4694 void screenrestorebox(INTBIG code, INTBIG destroy)
4695 {
4696 #ifdef ANYDEPTH
4697 	(void)gra_restorebox(code, destroy);
4698 #else
4699 	REGISTER WINDOWFRAME *wf;
4700 	REGISTER SAVEDBOX *box, *lbox;
4701 
4702 	/* find the box corresponding to the "code" */
4703 	lbox = NOSAVEDBOX;
4704 	for(box = gra_firstsavedbox; box != NOSAVEDBOX; box = box->nextsavedbox)
4705 	{
4706 		if (box->code == code) break;
4707 		lbox = box;
4708 	}
4709 	if (box == NOSAVEDBOX) return;
4710 	wf = box->win->frame;
4711 
4712 	if (destroy >= 0)
4713 	{
4714 		XSetPlaneMask(wf->topdpy, wf->gc, AllPlanes);
4715 
4716 		/* restore the bits in the box */
4717 		XCopyArea(wf->topdpy, box->pix, wf->win, wf->gc, 0, 0, box->hx - box->lx + 1,
4718 			box->hy - box->ly + 1, box->lx, box->ly);
4719 	}
4720 
4721 	/* destroy this box's memory if requested */
4722 	if (destroy != 0)
4723 	{
4724 		if (lbox == NOSAVEDBOX)
4725 		{
4726 			gra_firstsavedbox = box->nextsavedbox;
4727 		} else
4728 		{
4729 			lbox->nextsavedbox = box->nextsavedbox;
4730 		}
4731 		XFreePixmap(wf->topdpy, box->pix);
4732 		efree((CHAR *)box);
4733 	}
4734 #endif
4735 }
4736 
4737 /******************** GRAPHICS TEXT ********************/
4738 
4739 /*
4740  * Routine to find face with name "facename" and to return
4741  * its index in list of used fonts. If font was not used before,
4742  * then it is appended to list of used fonts.
4743  * If font "facename" is not available on the system, -1 is returned.
4744  */
screenfindface(CHAR * facename)4745 INTBIG screenfindface(CHAR *facename)
4746 {
4747 #ifdef TRUETYPE
4748 	INTBIG i;
4749 
4750 	for (i = 0; i < gra_numfaces; i++)
4751 		if (namesame(facename, gra_facelist[i]) == 0) return(i);
4752 #endif
4753 	return(-1);
4754 }
4755 
4756 /*
4757  * Routine to return the number of typefaces used (when "all" is FALSE)
4758  * or available on the system (when "all" is TRUE)
4759  * and to return their names in the array "list".
4760  */
screengetfacelist(CHAR *** list,BOOLEAN all)4761 INTBIG screengetfacelist(CHAR ***list, BOOLEAN all)
4762 {
4763 #ifdef TRUETYPE
4764 	REGISTER INTBIG i, total, res;
4765 
4766 	if (gra_numfaces == 0)
4767 	{
4768 		total = T1_GetNoFonts();
4769 		gra_numfaces = total + 1;
4770 		gra_facelist = (CHAR **)emalloc(gra_numfaces * (sizeof (CHAR *)), us_tool->cluster);
4771 		if (gra_facelist == 0) return(0);
4772 		(void)allocstring(&gra_facelist[0], _("DEFAULT FACE"), us_tool->cluster);
4773 		for(i=0; i<total; i++)
4774 		{
4775 			res = T1_LoadFont(i);
4776 			(void)allocstring(&gra_facelist[i+1], (CHAR *)(res == 0 ?
4777 				string2byte(T1_GetFontName(i)) : x_("BROKEN")), us_tool->cluster);
4778 		}
4779 	}
4780 	if (gra_numfaces > VTMAXFACE)
4781 	{
4782 		ttyputerr(_("Warning: found %ld fonts, but can only keep track of %d"), gra_numfaces,
4783 			VTMAXFACE);
4784 		gra_numfaces = VTMAXFACE;
4785 	}
4786 	*list = gra_facelist;
4787 	return(gra_numfaces);
4788 #else
4789 	return(0);
4790 #endif
4791 }
4792 
4793 /*
4794  * Routine to return the default typeface used on the screen.
4795  */
screengetdefaultfacename(void)4796 CHAR *screengetdefaultfacename(void)
4797 {
4798 #ifdef TRUETYPE
4799 	if (gra_truetypeon != 0)
4800 	{
4801 		T1_LoadFont(gra_truetypedeffont);
4802 		return(string2byte(T1_GetFontName(gra_truetypedeffont)));
4803 	}
4804 #endif
4805 	/* this isn't right!!! */
4806 	return(x_("Helvetica"));
4807 }
4808 
screensettextinfo(WINDOWPART * win,TECHNOLOGY * tech,UINTBIG * descript)4809 void screensettextinfo(WINDOWPART *win, TECHNOLOGY *tech, UINTBIG *descript)
4810 {
4811 	REGISTER INTBIG face, size;
4812 
4813 	size = TDGETSIZE(descript);
4814 	size = truefontsize(size, win, tech);
4815 	face = TDGETFACE(descript);
4816 	gra_settextsize(win, size, face, TDGETITALIC(descript), TDGETBOLD(descript),
4817 		TDGETUNDERLINE(descript), TDGETROTATION(descript));
4818 }
4819 
gra_settextsize(WINDOWPART * win,INTBIG size,INTBIG face,INTBIG italic,INTBIG bold,INTBIG underline,INTBIG rotation)4820 void gra_settextsize(WINDOWPART *win, INTBIG size, INTBIG face, INTBIG italic, INTBIG bold, INTBIG underline, INTBIG rotation)
4821 {
4822 #ifdef TRUETYPE
4823 	GLYPH *glyph;
4824 	CHAR **facelist;
4825 	INTBIG i, newsize, *newdcache, *newacache, *newswidth, hash;
4826 #endif
4827 
4828 	gra_texttoosmall = FALSE;
4829 	if (size == TXTMENU)
4830 	{
4831 		gra_curfontnumber = 9;
4832 		size = 10;
4833 	} else if (size == TXTEDITOR)
4834 	{
4835 		gra_curfontnumber = 10;
4836 		size = 12;
4837 	} else
4838 	{
4839 		if (size <= 4) gra_curfontnumber = 0; else
4840 			if (size <= 6) gra_curfontnumber = 1; else
4841 				if (size <= 8) gra_curfontnumber = 2; else
4842 					if (size <= 10) gra_curfontnumber = 3; else
4843 						if (size <= 12) gra_curfontnumber = 4; else
4844 							if (size <= 14) gra_curfontnumber = 5; else
4845 								if (size <= 16) gra_curfontnumber = 6; else
4846 									if (size <= 18) gra_curfontnumber = 7; else
4847 										gra_curfontnumber = 8;
4848 	}
4849 	gra_curfont = gra_font[gra_curfontnumber].font;
4850 	gra_textrotation = rotation;
4851 
4852 #ifdef TRUETYPE
4853 	if (gra_truetypeon == 0) return;
4854 
4855 	/* remember TrueType settings */
4856 	if (size < 1)
4857 	{
4858 		gra_texttoosmall = TRUE;
4859 		return;
4860 	}
4861 	if (size < MINIMUMTEXTSIZE) size = MINIMUMTEXTSIZE;
4862 	gra_truetypesize = size;
4863 	if (gra_truetypesize > 500) gra_truetypesize = 500;
4864 	gra_truetypefont = gra_truetypedeffont;
4865 	if (face > 0)
4866 	{
4867 		if (gra_numfaces == 0)
4868 			screengetfacelist(&facelist, FALSE);
4869 		if (face < gra_numfaces)
4870 			gra_truetypefont = face-1;
4871 	}
4872 	gra_truetypeitalic = italic;
4873 	gra_truetypebold = bold;
4874 	gra_truetypeunderline = underline;
4875 
4876 	/* for unusual fonts, remember ascent/descent in hash table */
4877 	if (italic != 0 || bold != 0 || gra_truetypefont != gra_truetypedeffont)
4878 	{
4879 		if (italic != 0) italic = 1;
4880 		if (bold != 0) bold = 1;
4881 		hash = (((size * 2) + italic) * 5 + bold) * 7 + face;
4882 		hash %= FONTHASHSIZE;
4883 		for(i=0; i<FONTHASHSIZE; i++)
4884 		{
4885 			if (gra_fonthash[hash].descent > 0) break;
4886 			if (gra_fonthash[hash].face == face && gra_fonthash[hash].size == size &&
4887 				gra_fonthash[hash].italic == italic && gra_fonthash[hash].bold == bold)
4888 			{
4889 				gra_truetypeascent = gra_fonthash[hash].ascent;
4890 				gra_truetypedescent = gra_fonthash[hash].descent;
4891 				gra_spacewidth = gra_fonthash[hash].spacewidth;
4892 				return;
4893 			}
4894 			hash++;
4895 			if (hash >= FONTHASHSIZE) hash = 0;
4896 		}
4897 		gra_fonthash[hash].face = face;
4898 		gra_fonthash[hash].size = size;
4899 		gra_fonthash[hash].italic = italic;
4900 		gra_fonthash[hash].bold = bold;
4901 		glyph = T1_SetString(gra_truetypefont,
4902 			b_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
4903 			0, 0, T1_KERNING, gra_truetypesize, 0);
4904 		if (glyph != 0)
4905 		{
4906 			gra_fonthash[hash].ascent = glyph->metrics.ascent;
4907 			gra_fonthash[hash].descent = glyph->metrics.descent;
4908 			gra_fonthash[hash].spacewidth = (glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing) / 62;
4909 		}
4910 		glyph = T1_SetString(gra_truetypefont, b_("!@#$%^&?~_+-*/=(){}[]<>|\\`'\",.;:"),
4911 			0, 0, T1_KERNING, gra_truetypesize, 0);
4912 		if (glyph != 0)
4913 		{
4914 			if (glyph->metrics.descent < gra_fonthash[hash].descent)
4915 				gra_fonthash[hash].descent = glyph->metrics.descent;
4916 			if (glyph->metrics.ascent > gra_fonthash[hash].ascent)
4917 				gra_fonthash[hash].ascent = glyph->metrics.ascent;
4918 		}
4919 		glyph = T1_SetString(gra_truetypefont, b_("A"), 0, 0, T1_KERNING, gra_truetypesize, 0);
4920 		if (glyph != 0)
4921 		{
4922 			i = glyph->metrics.leftSideBearing;
4923 			glyph = T1_SetString(gra_truetypefont, b_(" A"), 0, 0, T1_KERNING, gra_truetypesize, 0);
4924 			if (glyph != 0)
4925 				gra_fonthash[hash].spacewidth = glyph->metrics.leftSideBearing - i;
4926 		}
4927 		gra_truetypeascent = gra_fonthash[hash].ascent;
4928 		gra_truetypedescent = gra_fonthash[hash].descent;
4929 		gra_spacewidth = gra_fonthash[hash].spacewidth;
4930 	} else
4931 	{
4932 		/* standard font: cache the maximum ascent / descent value for each font size */
4933 		if (gra_truetypesize >= gra_descentcachesize)
4934 		{
4935 			newsize = gra_truetypesize + 1;
4936 			newdcache = (INTBIG *)emalloc(newsize * SIZEOFINTBIG, us_tool->cluster);
4937 			newacache = (INTBIG *)emalloc(newsize * SIZEOFINTBIG, us_tool->cluster);
4938 			newswidth = (INTBIG *)emalloc(newsize * SIZEOFINTBIG, us_tool->cluster);
4939 			for(i=0; i<gra_descentcachesize; i++)
4940 			{
4941 				newdcache[i] = gra_descentcache[i];
4942 				newacache[i] = gra_ascentcache[i];
4943 				newswidth[i] = gra_swidthcache[i];
4944 			}
4945 			for(i=gra_descentcachesize; i<newsize; i++)
4946 			{
4947 				newdcache[i] = 1;
4948 				newacache[i] = -1;
4949 				newswidth[i] = 0;
4950 			}
4951 			if (gra_descentcachesize > 0)
4952 			{
4953 				efree((CHAR *)gra_descentcache);
4954 				efree((CHAR *)gra_ascentcache);
4955 				efree((CHAR *)gra_swidthcache);
4956 			}
4957 			gra_descentcache = newdcache;
4958 			gra_ascentcache = newacache;
4959 			gra_swidthcache = newswidth;
4960 			gra_descentcachesize = newsize;
4961 		}
4962 		if (gra_descentcache[gra_truetypesize] > 0)
4963 		{
4964 			glyph = T1_SetString(gra_truetypefont,
4965 				b_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
4966 				0, 0, T1_KERNING, gra_truetypesize, 0);
4967 			if (glyph != 0)
4968 			{
4969 				gra_descentcache[gra_truetypesize] = glyph->metrics.descent;
4970 				gra_ascentcache[gra_truetypesize] = glyph->metrics.ascent;
4971 				gra_swidthcache[gra_truetypesize] = (glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing) / 62;
4972 			}
4973 			glyph = T1_SetString(gra_truetypefont, b_("!@#$%^&?~_+-*/=(){}[]<>|\\`'\",.;:"),
4974 				0, 0, T1_KERNING, gra_truetypesize, 0);
4975 			if (glyph != 0)
4976 			{
4977 				if (glyph->metrics.descent < gra_descentcache[gra_truetypesize])
4978 					gra_descentcache[gra_truetypesize] = glyph->metrics.descent;
4979 				if (glyph->metrics.ascent > gra_ascentcache[gra_truetypesize])
4980 					gra_ascentcache[gra_truetypesize] = glyph->metrics.ascent;
4981 			}
4982 			glyph = T1_SetString(gra_truetypefont, b_("A"), 0, 0, T1_KERNING, gra_truetypesize, 0);
4983 			if (glyph != 0)
4984 			{
4985 				i = glyph->metrics.leftSideBearing;
4986 				glyph = T1_SetString(gra_truetypefont, b_(" A"), 0, 0, T1_KERNING, gra_truetypesize, 0);
4987 				if (glyph != 0)
4988 					gra_swidthcache[gra_truetypesize] = glyph->metrics.leftSideBearing - i;
4989 			}
4990 		}
4991 		gra_truetypeascent = gra_ascentcache[gra_truetypesize];
4992 		gra_truetypedescent = gra_descentcache[gra_truetypesize];
4993 		gra_spacewidth = gra_swidthcache[gra_truetypesize];
4994 	}
4995 #endif
4996 }
4997 
screengettextsize(WINDOWPART * win,CHAR * str,INTBIG * x,INTBIG * y)4998 void screengettextsize(WINDOWPART *win, CHAR *str, INTBIG *x, INTBIG *y)
4999 {
5000 #ifdef ANYDEPTH
5001 	INTBIG thechar, i, width, len;
5002 	INTBIG wid, hei;
5003 
5004 	len = estrlen(str);
5005 	if (len == 0 || gra_texttoosmall)
5006 	{
5007 		*x = *y = 0;
5008 		return;
5009 	}
5010 
5011 # ifdef TRUETYPE
5012 	if (gra_truetypeon != 0 &&gra_truetypesize > 0 && gra_curfontnumber <= 8)
5013 	{
5014 		if (gra_getT1stringsize(str, &wid, &hei) != 0)
5015 		{
5016 			static INTBIG errorcount = 0;
5017 
5018 			efprintf(stderr, x_("Warning: cannot calculate screen size of string '%s' at scale %ld\n"),
5019 				str, gra_truetypesize);
5020 			if (errorcount++ > 10)
5021 			{
5022 				efprintf(stderr, x_("Too many errors, turning off TrueType\n"));
5023 				gra_truetypeon = 0;
5024 			}
5025 		} else
5026 		{
5027 			switch (gra_textrotation)
5028 			{
5029 				case 0:			/* normal */
5030 					*x = wid;
5031 					*y = hei;
5032 					break;
5033 				case 1:			/* 90 degrees counterclockwise */
5034 					*x = -hei;
5035 					*y = wid;
5036 					break;
5037 				case 2:			/* 180 degrees */
5038 					*x = -wid;
5039 					*y = -hei;
5040 					break;
5041 				case 3:			/* 90 degrees clockwise */
5042 					*x = hei;
5043 					*y = -wid;
5044 					break;
5045 			}
5046 			return;
5047 		}
5048 	}
5049 # endif
5050 
5051 	width = 0;
5052 	for(i=0; i<len; i++)
5053 	{
5054 		thechar = str[i] & 0377;
5055 		width += gra_font[gra_curfontnumber].width[thechar];
5056 	}
5057 	wid = width;
5058 	hei = gra_font[gra_curfontnumber].height[thechar];
5059 	switch (gra_textrotation)
5060 	{
5061 		case 0:			/* normal */
5062 			*x = wid;
5063 			*y = hei;
5064 			break;
5065 		case 1:			/* 90 degrees counterclockwise */
5066 			*x = -hei;
5067 			*y = wid;
5068 			break;
5069 		case 2:			/* 180 degrees */
5070 			*x = -wid;
5071 			*y = -hei;
5072 			break;
5073 		case 3:			/* 90 degrees clockwise */
5074 			*x = hei;
5075 			*y = -wid;
5076 			break;
5077 	}
5078 #else
5079 	int direction, asc, desc, len;   /* must be "int", and not "INTBIG" */
5080 	XCharStruct xcs;
5081 
5082 	len = estrlen(str);
5083 	XTextExtents(gra_curfont, string1byte(str), len, &direction, &asc, &desc, &xcs);
5084 	*x = xcs.width;
5085 	*y = gra_curfont->ascent + gra_curfont->descent;
5086 #endif
5087 }
5088 
5089 #ifdef TRUETYPE
5090 /*
5091  * Routine to calculate the TrueType size of string "str" and return it in "wid" and "hei".
5092  * Returns nonzero on error.
5093  */
gra_getT1stringsize(CHAR * str,INTBIG * wid,INTBIG * hei)5094 INTBIG gra_getT1stringsize(CHAR *str, INTBIG *wid, INTBIG *hei)
5095 {
5096 #if 0	/* cannot use "T1_GetStringWidth" because it doesn't handle space width properly */
5097 	*wid = T1_GetStringWidth(gra_truetypefont, str, estrlen(str), 0, 0) * gra_truetypesize / 1000;
5098 #else
5099 	GLYPH *glyph;
5100 	CHAR *startpos, *endpos;
5101 	float slant, extend;
5102 	int modflag, len;
5103 	T1_TMATRIX matrix;
5104 
5105 	/* use: gra_truetypeitalic, gra_truetypebold, gra_truetypeunderline */
5106 	modflag = T1_KERNING;
5107 	if (gra_truetypeunderline != 0) modflag |= T1_UNDERLINE;
5108 	*wid = 0;
5109 	for(startpos = str; *startpos != 0; startpos++)
5110 	{
5111 		if (*startpos == ' ')
5112 		{
5113 			*wid += gra_spacewidth;
5114 			continue;
5115 		}
5116 		for(endpos = startpos+1; *endpos != 0; endpos++)
5117 			if (*endpos == ' ') break;
5118 		len = endpos - startpos;
5119 		if (gra_truetypeitalic == 0 && gra_truetypebold == 0)
5120 		{
5121 			glyph = T1_SetString(gra_truetypefont, string1byte(startpos), len, 0,
5122 				modflag, gra_truetypesize, 0);
5123 		} else
5124 		{
5125 			matrix.cxx = matrix.cyy = 1.0;
5126 			matrix.cyx = matrix.cxy = 0.0;
5127 			if (gra_truetypeitalic == 0) slant = 0.0; else slant = TRUETYPEITALICSLANT;
5128 			(void)T1_ShearHMatrix(&matrix, slant);
5129 			if (gra_truetypebold == 0) extend = 1.0; else extend = TRUETYPEBOLDEXTEND;
5130 			(void)T1_ExtendHMatrix(&matrix, extend);
5131 			glyph = T1_SetString(gra_truetypefont, string1byte(startpos), len, 0,
5132 				modflag, gra_truetypesize, &matrix);
5133 		}
5134 		startpos = endpos-1;
5135 		if (glyph == 0) return(1);
5136 		*wid += glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
5137 	}
5138 #endif
5139 	*hei = gra_truetypeascent - gra_truetypedescent;
5140 	if (*hei < gra_truetypesize) *hei = gra_truetypesize;
5141 	return(0);
5142 }
5143 #endif
5144 
5145 /*
5146  * Routine to draw a text on the graphics window
5147  */
screendrawtext(WINDOWPART * win,INTBIG atx,INTBIG aty,CHAR * s,GRAPHICS * desc)5148 void screendrawtext(WINDOWPART *win, INTBIG atx, INTBIG aty, CHAR *s, GRAPHICS *desc)
5149 {
5150 #ifdef ANYDEPTH
5151 	if (gra_texttoosmall) return;
5152 	gra_drawtext(win, atx, aty, gra_textrotation, s, desc);
5153 #else
5154 	INTBIG l;
5155 	REGISTER WINDOWFRAME *wf;
5156 
5157 	wf = win->frame;
5158 	l = estrlen(s);
5159 
5160 	/* we have to wait for the window to be visible */
5161 
5162 	/* special case for highlight layer: always complement the data */
5163 	if (desc->bits == LAYERH)
5164 	{
5165 		XSetPlaneMask(wf->topdpy, wf->gc, AllPlanes);
5166 		XSetFont(wf->topdpy, wf->gcinv, gra_curfont->fid);
5167 		XDrawString(wf->topdpy, wf->win, wf->gcinv, atx,
5168 			wf->revy - aty - gra_curfont->descent, s, l);
5169 		return;
5170 	}
5171 
5172 	gra_setxstate(wf, wf->gc, desc);
5173 	XSetFont(wf->topdpy, wf->gc, gra_curfont->fid);
5174 	XDrawString(wf->topdpy, wf->win, wf->gc, atx,
5175 		wf->revy - aty - gra_curfont->descent, s, l);
5176 #endif
5177 }
5178 
5179 /*
5180  * Routine to convert the string "msg" (to be drawn into window "win") into an
5181  * array of pixels.  The size of the array is returned in "wid" and "hei", and
5182  * the pixels are returned in an array of character vectors "rowstart".
5183  * The routine returns true if the operation cannot be done.
5184  */
gettextbits(WINDOWPART * win,CHAR * msg,INTBIG * wid,INTBIG * hei,UCHAR1 *** rowstart)5185 BOOLEAN gettextbits(WINDOWPART *win, CHAR *msg, INTBIG *wid, INTBIG *hei, UCHAR1 ***rowstart)
5186 {
5187 #ifdef ANYDEPTH
5188 	REGISTER INTBIG i, len, thechar, x, y, atx, height, width, datasize;
5189 	REGISTER UCHAR1 *ptr;
5190 	REGISTER UCHAR1 *dest;
5191 # ifdef TRUETYPE
5192 	INTBIG bytesperline, topoffset, trueheight, xpos, xwid;
5193 	REGISTER CHAR *startpos, *endpos;
5194 	GLYPH *glyph;
5195 	float slant, extend;
5196 	int modflag;
5197 	T1_TMATRIX matrix;
5198 # endif
5199 
5200 	/* quit if string is null */
5201 	*wid = *hei = 0;
5202 	len = estrlen(msg);
5203 	if (len == 0 || gra_texttoosmall) return(FALSE);
5204 
5205 	/* determine the size of the text */
5206 # ifdef TRUETYPE
5207 	if (gra_truetypeon != 0 && gra_truetypesize > 0 && gra_curfontnumber <= 8)
5208 	{
5209 		if (gra_getT1stringsize(msg, wid, hei) != 0) return(TRUE);
5210 	} else
5211 # endif
5212 	{
5213 		for(i=0; i<len; i++)
5214 		{
5215 			thechar = msg[i] & 0377;
5216 			*wid += gra_font[gra_curfontnumber].width[thechar];
5217 			if (gra_font[gra_curfontnumber].height[thechar] > *hei)
5218 				*hei = gra_font[gra_curfontnumber].height[thechar];
5219 		}
5220 	}
5221 
5222 	/* allocate space for this */
5223 	datasize = *wid * *hei;
5224 	if (datasize > gra_textbitsdatasize)
5225 	{
5226 		if (gra_textbitsdatasize > 0) efree((CHAR *)gra_textbitsdata);
5227 		gra_textbitsdatasize = 0;
5228 
5229 		gra_textbitsdata = (UCHAR1 *)emalloc(datasize, us_tool->cluster);
5230 		if (gra_textbitsdata == 0) return(TRUE);
5231 		gra_textbitsdatasize = datasize;
5232 	}
5233 	if (*hei > gra_textbitsrowstartsize)
5234 	{
5235 		if (gra_textbitsrowstartsize > 0) efree((CHAR *)gra_textbitsrowstart);
5236 		gra_textbitsrowstartsize = 0;
5237 		gra_textbitsrowstart = (UCHAR1 **)emalloc(*hei * (sizeof (UCHAR1 *)), us_tool->cluster);
5238 		if (gra_textbitsrowstart == 0) return(TRUE);
5239 		gra_textbitsrowstartsize = *hei;
5240 	}
5241 
5242 	/* load the row start array, clear the data */
5243 	for(y=0; y < *hei; y++)
5244 	{
5245 		gra_textbitsrowstart[y] = &gra_textbitsdata[*wid * y];
5246 		for(x=0; x < *wid; x++)
5247 			gra_textbitsrowstart[y][x] = 0;
5248 	}
5249 	*rowstart = gra_textbitsrowstart;
5250 
5251 # ifdef TRUETYPE
5252 	if (gra_truetypeon != 0 && gra_truetypesize > 0 && gra_curfontnumber <= 8)
5253 	{
5254 		/* load the image array */
5255 		modflag = T1_KERNING;
5256 		if (gra_truetypeunderline != 0) modflag |= T1_UNDERLINE;
5257 		xpos = 0;
5258 		for(startpos = msg; *startpos != 0; startpos++)
5259 		{
5260 			if (*startpos == ' ')
5261 			{
5262 				xpos += gra_spacewidth;
5263 				continue;
5264 			}
5265 			for(endpos = startpos+1; *endpos != 0; endpos++)
5266 				if (*endpos == ' ') break;
5267 			len = endpos - startpos;
5268 			if (gra_truetypeitalic == 0 && gra_truetypebold == 0)
5269 			{
5270 				glyph = T1_SetString(gra_truetypefont, string1byte(startpos), len, 0,
5271 					modflag, gra_truetypesize, 0);
5272 			} else
5273 			{
5274 				matrix.cxx = matrix.cyy = 1.0;
5275 				matrix.cyx = matrix.cxy = 0.0;
5276 				if (gra_truetypeitalic == 0) slant = 0.0; else slant = TRUETYPEITALICSLANT;
5277 				(void)T1_ShearHMatrix(&matrix, slant);
5278 				if (gra_truetypebold == 0) extend = 1.0; else extend = TRUETYPEBOLDEXTEND;
5279 				(void)T1_ExtendHMatrix(&matrix, extend);
5280 				glyph = T1_SetString(gra_truetypefont, string1byte(startpos), len, 0,
5281 					modflag, gra_truetypesize, &matrix);
5282 			}
5283 			if (glyph == 0) return(TRUE);
5284 			startpos = endpos-1;
5285 
5286 			xwid = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
5287 			*hei = gra_truetypeascent - gra_truetypedescent;
5288 			topoffset = gra_truetypeascent - glyph->metrics.ascent;
5289 			trueheight = glyph->metrics.ascent - glyph->metrics.descent;
5290 
5291 			bytesperline = (xwid + 15) / 16 * 2;
5292 			ptr = (UCHAR1 *)glyph->bits;
5293 			if (ptr != 0)
5294 			{
5295 				for(y = 0; y < trueheight; y++)
5296 				{
5297 					dest = gra_textbitsrowstart[y+topoffset];
5298 					for(x = 0; x < xwid; x++)
5299 					{
5300 						i = ptr[x>>3] & (1 << (x&7));
5301 						if (i != 0) dest[x+xpos] = 1;
5302 					}
5303 					ptr += bytesperline;
5304 				}
5305 			}
5306 			xpos += xwid;
5307 		}
5308 	} else
5309 # endif
5310 	{
5311 		/* load the image array */
5312 		atx = 0;
5313 		for(i=0; i<len; i++)
5314 		{
5315 			thechar = msg[i] & 0377;
5316 			width = gra_font[gra_curfontnumber].width[thechar];
5317 			height = gra_font[gra_curfontnumber].height[thechar];
5318 
5319 			ptr = gra_font[gra_curfontnumber].data[thechar];
5320 			for(y=0; y<height; y++)
5321 			{
5322 				dest = gra_textbitsrowstart[y];
5323 				for(x=0; x<width; x++)
5324 				{
5325 					if (*ptr++ != 0) dest[atx + x] = 1;
5326 				}
5327 			}
5328 			atx += width;
5329 		}
5330 	}
5331 	return(FALSE);
5332 #else
5333 	return(TRUE);
5334 #endif
5335 }
5336 
5337 /******************** CIRCLE DRAWING ********************/
5338 
5339 /*
5340  * Routine to draw a circle on the graphics window
5341  */
screendrawcircle(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)5342 void screendrawcircle(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius, GRAPHICS *desc)
5343 {
5344 #ifdef ANYDEPTH
5345 	gra_drawcircle(win, atx, aty, radius, desc);
5346 #else
5347 	REGISTER WINDOWFRAME *wf;
5348 
5349 	wf = win->frame;
5350 	gra_setxstate(wf, wf->gc, desc);
5351 	XDrawArc(wf->topdpy, wf->win, wf->gc, atx - radius, wf->revy - aty - radius,
5352 		radius*2, radius*2, 0, 360*64);
5353 #endif
5354 }
5355 
5356 /*
5357  * Routine to draw a thick circle on the graphics window
5358  */
screendrawthickcircle(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)5359 void screendrawthickcircle(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius,
5360 	GRAPHICS *desc)
5361 {
5362 #ifdef ANYDEPTH
5363 	gra_drawthickcircle(win, atx, aty, radius, desc);
5364 #else
5365 	screendrawcircle(win, atx, aty, radius, desc);
5366 #endif
5367 }
5368 
5369 /******************** DISC DRAWING ********************/
5370 
5371 /*
5372  * routine to draw a filled-in circle of radius "radius"
5373  */
screendrawdisc(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)5374 void screendrawdisc(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius, GRAPHICS *desc)
5375 {
5376 #ifdef ANYDEPTH
5377 	gra_drawdisc(win, atx, aty, radius, desc);
5378 #else
5379 	REGISTER WINDOWFRAME *wf;
5380 
5381 	wf = win->frame;
5382 	if ((desc->colstyle & NATURE) == PATTERNED && desc->col != 0)
5383 	{
5384 		gra_loadstipple(wf, desc->raster);
5385 		gra_setxstate(wf, wf->gcstip, desc);
5386 		XFillArc(wf->topdpy, wf->win, wf->gcstip, atx - radius,
5387 			wf->revy - aty - radius, radius*2, radius*2, 0, 360*64);
5388 	} else
5389 	{
5390 		gra_setxstate(wf, wf->gc, desc);
5391 		XFillArc(wf->topdpy, wf->win, wf->gc, atx - radius, wf->revy - aty - radius,
5392 			radius*2, radius*2, 0, 360*64);
5393 	}
5394 #endif
5395 }
5396 
5397 /******************** ARC DRAWING ********************/
5398 
5399 /*
5400  * draws a thin arc centered at (centerx, centery), clockwise,
5401  * passing by (x1,y1) and (x2,y2)
5402  */
screendrawcirclearc(WINDOWPART * win,INTBIG centerx,INTBIG centery,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,GRAPHICS * desc)5403 void screendrawcirclearc(WINDOWPART *win, INTBIG centerx, INTBIG centery, INTBIG x1, INTBIG y1,
5404 	INTBIG x2, INTBIG y2, GRAPHICS *desc)
5405 {
5406 #ifdef ANYDEPTH
5407 	gra_drawcirclearc(win, centerx, centery, x1, y1, x2, y2, FALSE, desc);
5408 #else
5409 	REGISTER WINDOWFRAME *wf;
5410 	REGISTER INTBIG radius, startangle, endangle;
5411 
5412 	wf = win->frame;
5413 	gra_setxstate(wf, wf->gc, desc);
5414 	radius = computedistance(centerx, wf->revy - centery, x1,
5415 		wf->revy - y1);
5416 	startangle = figureangle(centerx, centery, x1, y1);
5417 	endangle = figureangle(centerx, centery, x2, y2);
5418 	if (startangle < endangle) startangle += 3600;
5419 	XDrawArc(wf->topdpy, wf->win, wf->gc, centerx - radius,
5420 		wf->revy - centery - radius, radius*2, radius*2, (endangle*64 + 5) / 10,
5421 		((startangle - endangle)*64 + 5) / 10);
5422 #endif
5423 }
5424 
5425 /*
5426  * draws a thick arc centered at (centerx, centery), clockwise,
5427  * passing by (x1,y1) and (x2,y2)
5428  */
screendrawthickcirclearc(WINDOWPART * win,INTBIG centerx,INTBIG centery,INTBIG p1_x,INTBIG p1_y,INTBIG p2_x,INTBIG p2_y,GRAPHICS * desc)5429 void screendrawthickcirclearc(WINDOWPART *win, INTBIG centerx, INTBIG centery, INTBIG p1_x, INTBIG p1_y,
5430 	INTBIG p2_x, INTBIG p2_y, GRAPHICS *desc)
5431 {
5432 #ifdef ANYDEPTH
5433 	gra_drawcirclearc(win, centerx, centery, p1_x, p1_y, p2_x, p2_y, TRUE, desc);
5434 #else
5435 	screendrawcirclearc(win, centerx, centery, p1_x, p1_y, p2_x, p2_y, desc);
5436 #endif
5437 }
5438 
5439 /******************** GRID CONTROL ********************/
5440 
5441 /*
5442  * fast grid drawing routine
5443  */
screendrawgrid(WINDOWPART * win,POLYGON * obj)5444 void screendrawgrid(WINDOWPART *win, POLYGON *obj)
5445 {
5446 #ifdef ANYDEPTH
5447 	gra_drawgrid(win, obj);
5448 #else
5449 	REGISTER WINDOWFRAME *wf;
5450 	REGISTER INTBIG i, gridsize;
5451 	REGISTER INTBIG x, y;
5452 	static Pixmap grid_pix;
5453 	static GC grid_gc;
5454 	XGCValues gcv;
5455 	static INTBIG bestsize = 0;
5456 
5457 	/* grid pixrect */
5458 	wf = win->frame;
5459 	gridsize = obj->xv[3] - obj->xv[2];
5460 
5461 	/* for some reason, must always reallocate SEEMS OK NOW: SRP */
5462 	if (wf->swid > bestsize)
5463 	{
5464 		if (bestsize != 0)
5465 		{
5466 			XFreePixmap(wf->topdpy, grid_pix);
5467 			XFreeGC(wf->topdpy, grid_gc);
5468 		}
5469 		grid_pix = XCreatePixmap(wf->topdpy, wf->win, bestsize = wf->swid, 1, 1);
5470 		gcv.background = 0;
5471 		gcv.foreground = 0;
5472 		grid_gc = XCreateGC(wf->topdpy, (Drawable)grid_pix, GCBackground | GCForeground, &gcv);
5473 	}
5474 
5475 	XSetForeground(wf->topdpy, grid_gc, 0);
5476 	XFillRectangle(wf->topdpy, (Drawable)grid_pix, grid_gc, 0, 0, bestsize, 1);
5477 
5478 	/* calculate the horizontal dots position */
5479 	XSetForeground(wf->topdpy, grid_gc, 1);
5480 	for(i = obj->xv[1]; i < obj->xv[5]; i += obj->xv[0])
5481 	{
5482 		x = muldiv(i - obj->xv[4], gridsize, obj->xv[5] - obj->xv[4]) + obj->xv[2];
5483 		XDrawPoint(wf->topdpy, (Drawable)grid_pix, grid_gc, x, 0);
5484 	}
5485 
5486 	/* draw the vertical columns */
5487 	XSetStipple(wf->topdpy, wf->gcstip, grid_pix);
5488 	gra_setxstate(wf, wf->gcstip, obj->desc);
5489 	for(i = obj->yv[1]; i < obj->yv[5]; i += obj->yv[0])
5490 	{
5491 		y = muldiv(i - obj->yv[4], obj->yv[3] - obj->yv[2], obj->yv[5] - obj->yv[4]) +
5492 			obj->yv[2];
5493 		XFillRectangle(wf->topdpy, wf->win, wf->gcstip, obj->xv[2],
5494 			wf->revy - y, gridsize, 1);
5495 	}
5496 #endif
5497 }
5498 
5499 /******************** MOUSE CONTROL ********************/
5500 
5501 /*
5502  * routine to return the number of buttons on the mouse
5503  */
buttoncount(void)5504 INTBIG buttoncount(void)
5505 {
5506 	return(mini(BUTTONS, NUMBUTS));
5507 }
5508 
5509 /*
5510  * routine to tell whether button "but" is a double-click
5511  */
doublebutton(INTBIG b)5512 BOOLEAN doublebutton(INTBIG b)
5513 {
5514 	if (b >= BUTTONS - REALBUTS) return(TRUE);
5515 	return(FALSE);
5516 }
5517 
5518 /*
5519  * routine to tell whether button "but" is a context button (right)
5520  */
contextbutton(INTBIG b)5521 BOOLEAN contextbutton(INTBIG b)
5522 {
5523 	if ((b%5) == 2) return(TRUE);
5524 	return(FALSE);
5525 }
5526 
5527 /*
5528  * routine to tell whether button "but" has the "shift" key held
5529  */
shiftbutton(INTBIG b)5530 BOOLEAN shiftbutton(INTBIG b)
5531 {
5532 	b = b / REALBUTS;
5533 
5534 	/* this "switch" statement is taken from the array "gra_buttonname" */
5535 	switch (b)
5536 	{
5537 		case 0: return(FALSE);	/* no shift keys */
5538 		case 1: return(TRUE);	/* shift */
5539 		case 2: return(FALSE);	/* control */
5540 		case 3: return(FALSE);	/* alt */
5541 		case 4: return(TRUE);	/* shift-control */
5542 		case 5: return(TRUE);	/* shift-alt */
5543 		case 6: return(FALSE);	/* control-alt */
5544 		case 7: return(TRUE);	/* shift-control-alt */
5545 		case 8: return(FALSE);	/* double-click */
5546 	}
5547 	return(FALSE);
5548 }
5549 
5550 /*
5551  * routine to tell whether button "but" is a "mouse wheel" button
5552  */
wheelbutton(INTBIG b)5553 BOOLEAN wheelbutton(INTBIG b)
5554 {
5555 	b = b % REALBUTS;
5556 	if (b == 3 || b == 4) return(TRUE);
5557 	return(FALSE);
5558 }
5559 
5560 /*
5561  * routine to return the name of button "b" (from 0 to "buttoncount()").
5562  * The number of letters unique to the button is placed in "important".
5563  */
buttonname(INTBIG b,INTBIG * important)5564 CHAR *buttonname(INTBIG b, INTBIG *important)
5565 {
5566 	*important = gra_buttonname[b].unique;
5567 	return(gra_buttonname[b].name);
5568 }
5569 
5570 /*
5571  * routine to convert from "gra_inputstate" (the typical input parameter)
5572  * to button numbers (the table "gra_buttonname")
5573  */
gra_makebutton(INTBIG state)5574 INTBIG gra_makebutton(INTBIG state)
5575 {
5576 	REGISTER INTBIG base;
5577 
5578 	switch (state&ISBUTTON)
5579 	{
5580 		case ISLEFT:    base = 0;   break;
5581 		case ISMIDDLE:  base = 1;   break;
5582 		case ISRIGHT:   base = 2;   break;
5583 		case ISWHLFWD:  base = 3;   break;
5584 		case ISWHLBKW:  base = 4;   break;
5585 	}
5586 
5587 	if ((state&DOUBLECL) != 0) return(base+REALBUTS*8);
5588 	switch (state & (SHIFTISDOWN|CONTROLISDOWN|METAISDOWN))
5589 	{
5590 		case SHIFTISDOWN                         : return(base+REALBUTS*1);
5591 		case             CONTROLISDOWN           : return(base+REALBUTS*2);
5592 		case                           METAISDOWN: return(base+REALBUTS*3);
5593 		case SHIFTISDOWN|CONTROLISDOWN           : return(base+REALBUTS*4);
5594 		case SHIFTISDOWN|              METAISDOWN: return(base+REALBUTS*5);
5595 		case             CONTROLISDOWN|METAISDOWN: return(base+REALBUTS*6);
5596 		case SHIFTISDOWN|CONTROLISDOWN|METAISDOWN: return(base+REALBUTS*7);
5597 	}
5598 	return(base);
5599 }
5600 
5601 /*
5602  * routine to wait for a button push and return its index (0 based) in "*but".
5603  * The coordinates of the cursor are placed in "*x" and "*y".  If there is no
5604  * button push, the value of "*but" is negative.
5605  */
waitforbutton(INTBIG * x,INTBIG * y,INTBIG * but)5606 void waitforbutton(INTBIG *x, INTBIG *y, INTBIG *but)
5607 {
5608 	/* now the first button wait has happened: graphics is inited */
5609 	gra_firstbuttonwait = 1;
5610 
5611 	/* if there is a button push pending, return it */
5612 	if ((gra_inputstate != NOEVENT) && ((gra_inputstate & ISBUTTON) != 0) &&
5613 		((gra_inputstate & BUTTONUP) == 0))
5614 	{
5615 		*but = gra_makebutton(gra_inputstate);
5616 		*x = gra_cursorx;
5617 		*y = gra_cursory;
5618 		gra_inputstate = NOEVENT;
5619 		if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(us_normalcursor);
5620 		return;
5621 	}
5622 
5623 	/* get some input (keyboard or mouse) */
5624 	gra_nextevent();
5625 
5626 	/* if a button push was read, return it */
5627 	if ((gra_inputstate != NOEVENT) && ((gra_inputstate & ISBUTTON) != 0) &&
5628 		((gra_inputstate & BUTTONUP) == 0))
5629 	{
5630 		*but = gra_makebutton(gra_inputstate);
5631 		*x = gra_cursorx;
5632 		*y = gra_cursory;
5633 		gra_inputstate = NOEVENT;
5634 		if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(us_normalcursor);
5635 		return;
5636 	}
5637 
5638 	/* no button input yet */
5639 	*but = -1;
5640 }
5641 
5642 /*
5643  * routine to do modal loop, calling "charhandler" for each typed key and "buttonhandler"
5644  * for each pushed button. The "charhandler" routine is called with the character value
5645  * that was typed. The "buttonhandler" routine is called with coordinates of cursor.
5646  * The "charhandler" and "buttonhandler" returns true to abort loop.
5647  * The value of "cursor" determines cursor appearance.
5648  */
modalloop(BOOLEAN (* charhandler)(INTSML chr,INTBIG special),BOOLEAN (* buttonhandler)(INTBIG x,INTBIG y,INTBIG but),INTBIG cursor)5649 void modalloop(BOOLEAN (*charhandler)(INTSML chr, INTBIG special),
5650 	BOOLEAN (*buttonhandler)(INTBIG x, INTBIG y, INTBIG but), INTBIG cursor)
5651 {
5652 	INTBIG oldnormalcursor, special, x, y, but;
5653 	INTSML chr;
5654 
5655 	/* set cursor */
5656 	oldnormalcursor = us_normalcursor;
5657 	setnormalcursor(cursor);
5658 
5659 	for (;;)
5660 	{
5661 		if (ttydataready())
5662 		{
5663 			chr = getnxtchar(&special);
5664 			if ((*charhandler)(chr, special)) break;
5665 		} else
5666 		{
5667 			waitforbutton(&x, &y, &but);
5668 			if (but >= 0 && buttonhandler != 0)
5669 				if ((*buttonhandler)(x, y, but)) break;
5670 		}
5671 	}
5672 
5673 	/* restore cursor */
5674 	setnormalcursor(oldnormalcursor);
5675 }
5676 
5677 /*
5678  * routine to track the cursor until a button is released, calling "whileup" for
5679  * each co-ordinate when the mouse moves before the first button push, calling
5680  * "whendown" once when the button goes down, calling "eachdown" for each
5681  * co-ordinate when the mouse moves after the button is pushed, calling
5682  * "eachchar" for each key that is typed at any time, and calling "done" once
5683  * when done.  The "whendown" and "done" routines are called with no parameters;
5684  * "whileup" and "eachdown" are called with the X and Y coordinates of the
5685  * cursor; and "eachchar" is called with the X, Y, and character value that was
5686  * typed.  The "whileup", "eachdown", and "eachchar" routines return nonzero to
5687  * abort tracking.
5688  * If "waitforpush" is true then the routine will wait for a button to
5689  * actually be pushed before tracking (otherwise it will begin tracking
5690  * immediately).  The value of "purpose" determines what the cursor will look
5691  * like during dragging: 0 for normal (the X cursor), 1 for drawing (a pen),
5692  * 2 for dragging (a hand), 3 for popup menu selection (a horizontal arrow), 4 for
5693  * hierarchical popup menu selection (arrow, stays at end).
5694  */
trackcursor(BOOLEAN waitforpush,BOOLEAN (* whileup)(INTBIG,INTBIG),void (* whendown)(void),BOOLEAN (* eachdown)(INTBIG,INTBIG),BOOLEAN (* eachchar)(INTBIG,INTBIG,INTSML),void (* done)(void),INTBIG purpose)5695 void trackcursor(BOOLEAN waitforpush, BOOLEAN (*whileup)(INTBIG, INTBIG),
5696 	void (*whendown)(void), BOOLEAN (*eachdown)(INTBIG, INTBIG),
5697 	BOOLEAN (*eachchar)(INTBIG, INTBIG, INTSML), void (*done)(void), INTBIG purpose)
5698 {
5699 	REGISTER BOOLEAN keepon;
5700 	REGISTER INTBIG oldcursor, action;
5701 
5702 	/* change the cursor to an appropriate icon */
5703 	oldcursor = us_normalcursor;
5704 	switch (purpose)
5705 	{
5706 		case TRACKDRAWING:    us_normalcursor = PENCURSOR;    break;
5707 		case TRACKDRAGGING:   us_normalcursor = HANDCURSOR;   break;
5708 		case TRACKSELECTING:
5709 		case TRACKHSELECTING: us_normalcursor = MENUCURSOR;   break;
5710 	}
5711 	setdefaultcursortype(us_normalcursor);
5712 
5713 	/* now wait for a button to go down, if requested */
5714 	keepon = FALSE;
5715 	gra_tracking = TRUE;
5716 	if (waitforpush)
5717 	{
5718 		while (!keepon)
5719 		{
5720 			gra_nextevent();
5721 			if (gra_inputstate == NOEVENT) continue;
5722 			action = gra_inputstate;
5723 			gra_inputstate = NOEVENT;
5724 
5725 			/* if button just went down, stop this loop */
5726 			if ((action&ISBUTTON) != 0 && (action & BUTTONUP) == 0) break;
5727 			if ((action&MOTION) != 0)
5728 			{
5729 				keepon = (*whileup)(gra_cursorx, gra_cursory);
5730 			} else if ((action&ISKEYSTROKE) != 0 && gra_inputspecial == 0)
5731 			{
5732 				keepon = (*eachchar)(gra_cursorx, gra_cursory, (INTSML)(action&CHARREAD));
5733 			}
5734 		}
5735 	}
5736 
5737 	/* button is now down, real tracking begins */
5738 	if (!keepon)
5739 	{
5740 		(*whendown)();
5741 		keepon = (*eachdown)(gra_cursorx, gra_cursory);
5742 	}
5743 
5744 	/* now track while the button is down */
5745 	while (!keepon)
5746 	{
5747 		us_endchanges(NOWINDOWPART);
5748 		gra_nextevent();
5749 
5750 		/* for each motion, report the coordinates */
5751 		if (gra_inputstate == NOEVENT) continue;
5752 		action = gra_inputstate;
5753 		gra_inputstate = NOEVENT;
5754 		if ((action&ISBUTTON) != 0 && (action&BUTTONUP) != 0) break;
5755 		if ((action&MOTION) != 0)
5756 		{
5757 			keepon = (*eachdown)(gra_cursorx, gra_cursory);
5758 		} else if ((action&ISKEYSTROKE) != 0 && gra_inputspecial == 0)
5759 		{
5760 			keepon = (*eachchar)(gra_cursorx, gra_cursory, (INTSML)(action&CHARREAD));
5761 		}
5762 		if (el_pleasestop != 0) keepon = TRUE;
5763 	}
5764 
5765 	/* inform the user that all is done */
5766 	(*done)();
5767 
5768 	/* restore the state of the world */
5769 	gra_tracking = FALSE;
5770 	us_normalcursor = oldcursor;
5771 	setdefaultcursortype(us_normalcursor);
5772 }
5773 
5774 /*
5775  * routine to read the current co-ordinates of the tablet and return them in "*x" and "*y"
5776  */
readtablet(INTBIG * x,INTBIG * y)5777 void readtablet(INTBIG *x, INTBIG *y)
5778 {
5779 	*x = gra_cursorx;
5780 	*y = gra_cursory;
5781 }
5782 
5783 /*
5784  * routine to turn off the cursor tracking if it is on
5785  */
stoptablet(void)5786 void stoptablet(void)
5787 {
5788 	if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(us_normalcursor);
5789 }
5790 
5791 /******************** KEYBOARD CONTROL ********************/
5792 
5793 /*
5794  * routine to get the next character from the keyboard
5795  */
getnxtchar(INTBIG * special)5796 INTSML getnxtchar(INTBIG *special)
5797 {
5798 	REGISTER INTSML i;
5799 
5800 	if ((gra_inputstate != NOEVENT) && ((gra_inputstate & ISKEYSTROKE) != 0))
5801 	{
5802 		i = gra_inputstate & CHARREAD;
5803 		*special = gra_inputspecial;
5804 		gra_inputstate = NOEVENT;
5805 		return(i);
5806 	}
5807 	if (us_cursorstate != IBEAMCURSOR)
5808 		setdefaultcursortype(WANTTTYCURSOR);
5809 	for(;;)
5810 	{
5811 		gra_nextevent();
5812 		if ((gra_inputstate != NOEVENT) && (gra_inputstate & ISKEYSTROKE) != 0)
5813 			break;
5814 	}
5815 	i = gra_inputstate & CHARREAD;
5816 	*special = gra_inputspecial;
5817 	gra_inputstate = NOEVENT;
5818 	if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(us_normalcursor);
5819 	return(i);
5820 }
5821 
5822 /* not required with X11 */
checkforinterrupt(void)5823 void checkforinterrupt(void)
5824 {
5825 	XtInputMask mask;
5826 	XEvent event;
5827 
5828 	gra_checkinginterrupt = TRUE;
5829 	for(;;)
5830 	{
5831 		mask = XtAppPending(gra_xtapp);
5832 		if ((mask&XtIMXEvent) != 0)
5833 		{
5834 			XtAppNextEvent(gra_xtapp, &event);
5835 			XtDispatchEvent(&event);
5836 			continue;
5837 		}
5838 		break;
5839 	}
5840 	gra_checkinginterrupt = FALSE;
5841 	setdefaultcursortype(NULLCURSOR);
5842 }
5843 
5844 #define BIT(c, x)   (c[x>>3] & (1<<(x&7)))
5845 
5846 /*
5847  * Routine to return which "bucky bits" are held down (shift, control, etc.)
5848  */
getbuckybits(void)5849 INTBIG getbuckybits(void)
5850 {
5851 	REGISTER INTBIG bits, width, i;
5852 	CHAR1 keys[32];
5853 	static XModifierKeymap *mmap;
5854 	static INTBIG first = 1;
5855 	KeyCode code;
5856 
5857 	if (first != 0)
5858 	{
5859 		first = 0;
5860 		mmap = XGetModifierMapping(gra_maindpy);
5861 	}
5862 
5863 	bits = 0;
5864 
5865 	XQueryKeymap(gra_maindpy, keys);
5866 	width = mmap->max_keypermod;
5867 	for (i=0; i<width; i++)
5868 	{
5869 		code = mmap->modifiermap[ControlMapIndex*width+i];
5870 		if (code != 0 && BIT(keys, code) != 0) bits |= CONTROLDOWN | ACCELERATORDOWN;
5871 
5872 		code = mmap->modifiermap[ShiftMapIndex*width+i];
5873 		if (code != 0 && BIT(keys, code) != 0) bits |= SHIFTDOWN;
5874 
5875 		code = mmap->modifiermap[Mod1MapIndex*width+i];
5876 		if (code != 0 && BIT(keys, code) != 0) bits |= OPTALTMETDOWN;
5877 	}
5878 
5879 	return(bits);
5880 }
5881 
5882 /*
5883  * routine to tell whether data is waiting at the terminal.  Returns true
5884  * if data is ready.
5885  */
ttydataready(void)5886 BOOLEAN ttydataready(void)
5887 {
5888 	/* see if something is already pending */
5889 	if (gra_inputstate != NOEVENT)
5890 	{
5891 		if ((gra_inputstate & ISKEYSTROKE) != 0) return(TRUE);
5892 		return(FALSE);
5893 	}
5894 
5895 	/* wait for something and analyze it */
5896 	if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(us_normalcursor);
5897 	gra_nextevent();
5898 	if ((gra_inputstate != NOEVENT) && (gra_inputstate & ISKEYSTROKE) != 0) return(TRUE);
5899 	return(FALSE);
5900 }
5901 
5902 /****************************** FILES ******************************/
5903 
gra_topoffile(CHAR ** a)5904 BOOLEAN gra_topoffile(CHAR **a)
5905 {
5906 	CHAR *b, **c;
5907 	BOOLEAN retval;
5908 
5909 	b = gra_curpath;
5910 	c = &b;
5911 	retval = topoffile(c);
5912 	requiredextension(gra_requiredextension);
5913 	return(retval);
5914 }
5915 
gra_fileselectcancel(Widget w,XtPointer client_data,XmSelectionBoxCallbackStruct * call_data)5916 void gra_fileselectcancel(Widget w, XtPointer client_data,
5917 	XmSelectionBoxCallbackStruct *call_data)
5918 {
5919 	gra_curpath[0] = 0;
5920 	gra_fileselectdone = TRUE;
5921 }
5922 
gra_fileselectok(Widget w,XtPointer client_data,XmSelectionBoxCallbackStruct * call_data)5923 void gra_fileselectok(Widget w, XtPointer client_data,
5924 	XmSelectionBoxCallbackStruct *call_data)
5925 {
5926 	CHAR1 *filename;
5927 
5928 	gra_curpath[0] = 0;
5929 	if (XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET,
5930 		&filename))
5931 	{
5932 		estrcpy(gra_curpath, string2byte(filename));
5933 		XtFree(filename);
5934 	}
5935 	gra_fileselectdone = TRUE;
5936 }
5937 
5938 /*
5939  * Routine to prompt for multiple files of type "filetype", giving the
5940  * message "msg".  Returns a string that contains all of the file names,
5941  * separated by the NONFILECH (a character that cannot be in a file name).
5942  */
multifileselectin(CHAR * msg,INTBIG filetype)5943 CHAR *multifileselectin(CHAR *msg, INTBIG filetype)
5944 {
5945 	return(fileselect(msg, filetype, x_("")));
5946 }
5947 
5948 DIALOGITEM gra_fileindialogitems[] =   /* File Input */
5949 {
5950  /*  1 */ {0, {128,256,152,336}, BUTTON, N_("Open")},
5951  /*  2 */ {0, {176,256,200,336}, BUTTON, N_("Cancel")},
5952  /*  3 */ {0, {40,8,216,240}, SCROLL, x_("")},
5953  /*  4 */ {0, {8,8,40,336}, MESSAGE, x_("")},
5954  /*  5 */ {0, {80,256,104,336}, BUTTON, N_("Up")}
5955 };
5956 DIALOG gra_fileindialog = {{50,75,278,421}, 0, 0, 5, gra_fileindialogitems, 0, 0};
5957 
5958 /* special items for the file input dialog */
5959 #define DFIN_FILELIST    3		/* File list (scroll) */
5960 #define DFIN_FILENAME    4		/* File name (stat text) */
5961 #define DFIN_UPBUTTON    5		/* Up (button) */
5962 
5963 DIALOGITEM gra_fileoutdialogitems[] =   /* File Output */
5964 {
5965  /*  1 */ {0, {146,256,170,336}, BUTTON, N_("OK")},
5966  /*  2 */ {0, {194,256,218,336}, BUTTON, N_("Cancel")},
5967  /*  3 */ {0, {50,8,218,240}, SCROLL, x_("")},
5968  /*  4 */ {0, {8,8,40,336}, MESSAGE, x_("")},
5969  /*  5 */ {0, {50,256,74,336}, BUTTON, N_("Up")},
5970  /*  6 */ {0, {98,256,122,336}, BUTTON, N_("Down")},
5971  /*  7 */ {0, {226,8,242,336}, EDITTEXT, x_("")}
5972 };
5973 DIALOG gra_fileoutdialog = {{50,75,301,421}, 0, 0, 7, gra_fileoutdialogitems, 0, 0};
5974 
5975 /* special items for the file output dialog */
5976 #define DFOU_FILELIST    3		/* File list (scroll) */
5977 #define DFOU_DIRNAME     4		/* Directory name (stat text) */
5978 #define DFOU_UPBUTTON    5		/* Up (button) */
5979 #define DFOU_DOWNBUTTON  6		/* Down (button) */
5980 #define DFOU_FILENAME    7		/* File name (edit text) */
5981 
5982 /*
5983  * Routine to display a standard file prompt dialog and return the selected file.
5984  * The prompt message is in "msg" and the kind of file is in "filetype".  The default
5985  * output file name is in "defofile" (only used if "filetype" is for output files).
5986  */
fileselect(CHAR * msg,INTBIG filetype,CHAR * defofile)5987 CHAR *fileselect(CHAR *msg, INTBIG filetype, CHAR *defofile)
5988 {
5989 	INTBIG i, l, count, mactype, filestatus;
5990 	BOOLEAN binary;
5991 	CHAR *extension, *winfilter, *shortname, *longname, directory[256], fullmsg[300], *pars[5];
5992 	extern COMCOMP us_yesnop;
5993 	XmString mprompt, mfilter, mtitle, mpattern, mdirectory;
5994 	Widget w, child;
5995 	INTBIG wid, hei, ac, screenw, screenh;
5996 	Arg arg[10];
5997 	XEvent event;
5998 	CHAR filename[256], temp[256], *childmsg;
5999 	REGISTER WINDOWFRAME *wf;
6000 
6001 	if (us_logplay != NULL)
6002 	{
6003 		if (gra_loggetnextaction(gra_curpath)) return(0);
6004 	} else
6005 	{
6006 		if ((filetype&FILETYPEWRITE) == 0)
6007 		{
6008 			/* input file selection: display the file input dialog box */
6009 			describefiletype(filetype, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
6010 			esnprintf(temp, 256, _("%s Selection"), msg);
6011 			mtitle = XmStringCreateLocalized(string1byte(temp));
6012 			mprompt = XmStringCreateLocalized(string1byte(msg));
6013 			estrcpy(temp, winfilter);
6014 			for(i=0; temp[i] != 0; i++) if (temp[i] == ';') break;
6015 			temp[i] = 0;
6016 			mfilter = XmStringCreateLocalized(string1byte(temp));
6017 			wf = el_curwindowframe;
6018 			if (wf == NOWINDOWFRAME) wf = el_firstwindowframe;
6019 			screenw = wf->wd->wid;
6020 			screenh = wf->wd->hei;
6021 			wid = 400;   if (wid > screenw) wid = screenw;
6022 			hei = 480;   if (hei > screenh) hei = screenh;
6023 			estrcpy(directory, currentdirectory());
6024 			mdirectory = XmStringCreateLocalized(string1byte(directory));
6025 			ac = 0;
6026 			XtSetArg(arg[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);   ac++;
6027 			XtSetArg(arg[ac], XmNdirMask, mfilter);   ac++;
6028 			XtSetArg(arg[ac], XmNselectionLabelString, mprompt);   ac++;
6029 			XtSetArg(arg[ac], XmNwidth, 400);   ac++;
6030 			XtSetArg(arg[ac], XmNheight, 480);   ac++;
6031 			XtSetArg(arg[ac], XmNdialogTitle, mtitle);   ac++;
6032 			XtSetArg(arg[ac], XmNdirectory, mdirectory);   ac++;
6033 			estrcpy(gra_localstring, _("File Selection"));
6034 			w = XmCreateFileSelectionDialog(wf->graphicswidget, string1byte(gra_localstring), arg, ac);
6035 			XtAddCallback(w, XmNcancelCallback, (XtCallbackProc)gra_fileselectcancel, NULL);
6036 			XtAddCallback(w, XmNokCallback, (XtCallbackProc)gra_fileselectok, NULL);
6037 			XtManageChild(w);
6038 			XmStringFree(mprompt);
6039 			XmStringFree(mfilter);
6040 			XmStringFree(mtitle);
6041 
6042 			gra_fileselectdone = FALSE;
6043 			while (!gra_fileselectdone)
6044 			{
6045 				XmUpdateDisplay(wf->toplevelwidget);
6046 				XtAppNextEvent(gra_xtapp, &event);
6047 				XtDispatchEvent(&event);
6048 			}
6049 			XtUnmanageChild(w);
6050 			XtDestroyWidget(w);
6051 
6052 			/* set current directory from file path */
6053 			l = estrlen(gra_curpath);
6054 			for(i=l-1; i>0; i--) if (gra_curpath[i] == DIRSEP) break;
6055 			if (i > 0)
6056 			{
6057 				i++;
6058 				(void)estrcpy(directory, gra_curpath);
6059 				directory[i] = 0;
6060 				gra_setcurrentdirectory(directory);
6061 			}
6062 		} else
6063 		{
6064 			/* determine the default directory and file name */
6065 			estrcpy(directory, currentdirectory());
6066 			filename[0] = 0;
6067 			if (defofile[0] != 0)
6068 			{
6069 				l = estrlen(defofile);
6070 				for(i=l-1; i>0; i--) if (defofile[i] == DIRSEP) break;
6071 				if (i > 0)
6072 				{
6073 					i++;
6074 					(void)estrcpy(directory, defofile);
6075 					directory[i] = 0;
6076 				}
6077 				estrcpy(filename, &defofile[i]);
6078 			}
6079 
6080 			describefiletype(filetype, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
6081 			wf = el_curwindowframe;
6082 			if (wf == NOWINDOWFRAME) wf = el_firstwindowframe;
6083 			screenw = wf->wd->wid;
6084 			screenh = wf->wd->hei;
6085 			wid = 400;   if (wid > screenw) wid = screenw;
6086 			hei = 480;   if (hei > screenh) hei = screenh;
6087 			mprompt = XmStringCreateLocalized(string1byte(msg));
6088 			mdirectory = XmStringCreateLocalized(string1byte(directory));
6089 			estrcpy(temp, winfilter);
6090 			for(i=0; temp[i] != 0; i++) if (temp[i] == ';') break;
6091 			temp[i] = 0;
6092 			mpattern = XmStringCreateLocalized(string1byte(temp));
6093 			esnprintf(temp, 256, _("%s Creation"), msg);
6094 			mtitle = XmStringCreateLocalized(string1byte(temp));
6095 			ac = 0;
6096 			XtSetArg(arg[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);   ac++;
6097 			XtSetArg(arg[ac], XmNwidth, 400);   ac++;
6098 			XtSetArg(arg[ac], XmNheight, 480);   ac++;
6099 			XtSetArg(arg[ac], XmNselectionLabelString, mprompt);   ac++;
6100 			XtSetArg(arg[ac], XmNdirectory, mdirectory);   ac++;
6101 			XtSetArg(arg[ac], XmNpattern, mpattern);   ac++;
6102 			XtSetArg(arg[ac], XmNdialogTitle, mtitle);   ac++;
6103 			w = XmCreateFileSelectionDialog(wf->graphicswidget, b_(""), arg, ac);
6104 			XtAddCallback(w, XmNcancelCallback, (XtCallbackProc)gra_fileselectcancel, NULL);
6105 			XtAddCallback(w, XmNokCallback, (XtCallbackProc)gra_fileselectok, NULL);
6106 			XtManageChild(w);
6107 			XmStringFree(mprompt);
6108 			XmStringFree(mdirectory);
6109 			XmStringFree(mpattern);
6110 			XmStringFree(mtitle);
6111 
6112 			/* append the default output file name to the selection path */
6113 			child = XmFileSelectionBoxGetChild(w, XmDIALOG_TEXT);
6114 			childmsg = string2byte(XmTextGetString(child));
6115 			esnprintf(temp, 256, x_("%s%s"), childmsg, filename);
6116 			XmTextSetString(child, string1byte(temp));
6117 
6118 			gra_fileselectdone = FALSE;
6119 			while (!gra_fileselectdone)
6120 			{
6121 				XmUpdateDisplay(wf->toplevelwidget);
6122 				XtAppNextEvent(gra_xtapp, &event);
6123 				XtDispatchEvent(&event);
6124 			}
6125 			XtUnmanageChild(w);
6126 			XtDestroyWidget(w);
6127 
6128 			/* set current directory from file path */
6129 			l = estrlen(gra_curpath);
6130 			for(i=l-1; i>0; i--) if (gra_curpath[i] == DIRSEP) break;
6131 			if (i > 0)
6132 			{
6133 				i++;
6134 				(void)estrcpy(directory, gra_curpath);
6135 				directory[i] = 0;
6136 				gra_setcurrentdirectory(directory);
6137 			}
6138 		}
6139 	}
6140 
6141 	/* log this result */
6142 	gra_logwriteaction(FILEREPLY, 0, 0, 0, gra_curpath);
6143 
6144 	/* if writing a file, check for overwrite */
6145 	if ((filetype&FILETYPEWRITE) != 0)
6146 	{
6147 		/* give warning if creating file that already exists */
6148 		if (gra_curpath[0] != 0)
6149 		{
6150 			filestatus = fileexistence(gra_curpath);
6151 			switch (filestatus)
6152 			{
6153 				case 1:		/* an existing file */
6154 					esnprintf(fullmsg, 300, _("File '%s' exists.  Overwrite? "), gra_curpath);
6155 					count = ttygetparam(fullmsg, &us_yesnop, 2, pars);
6156 					if (count > 0 && namesamen(pars[0], x_("no"), estrlen(pars[0])) == 0)
6157 						gra_curpath[0] = 0;
6158 					break;
6159 				case 2:		/* a directory */
6160 					DiaMessageInDialog(_("'%s' is a directory: cannot write it"), gra_curpath);
6161 					gra_curpath[0] = 0;
6162 					break;
6163 				case 3:		/* a read-only file */
6164 					DiaMessageInDialog(_("'%s' is read-only: cannot overwrite it"), gra_curpath);
6165 					gra_curpath[0] = 0;
6166 					break;
6167 			}
6168 		}
6169 	} else
6170 	{
6171 		/* if a file was selected, make sure it isn't a directory */
6172 		if (gra_curpath[0] != 0)
6173 		{
6174 			if (fileexistence(gra_curpath) == 2) gra_curpath[0] = 0;
6175 		}
6176 	}
6177 
6178 	if (gra_curpath[0] == 0) return((CHAR *)NULL); else
6179 	{
6180 		return(gra_curpath);
6181 	}
6182 }
6183 
6184 /*
6185  * Helper routine to initialize the list of files in a directory.
6186  */
gra_initfilelist(void)6187 void gra_initfilelist(void)
6188 {
6189 	if (gra_fileliststringarray == 0)
6190 	{
6191 		gra_fileliststringarray = newstringarray(db_cluster);
6192 		if (gra_fileliststringarray == 0) return;
6193 	}
6194 	clearstrings(gra_fileliststringarray);
6195 }
6196 
6197 /*
6198  * Helper routine to add "file" to the list of files in a directory.
6199  * Returns true on error.
6200  */
gra_addfiletolist(CHAR * file)6201 BOOLEAN gra_addfiletolist(CHAR *file)
6202 {
6203 	addtostringarray(gra_fileliststringarray, file);
6204 	return(FALSE);
6205 }
6206 
gra_fileselectall(const struct dirent * a)6207 int gra_fileselectall(const struct dirent *a)
6208 {
6209 	REGISTER CHAR *pt;
6210 
6211 	pt = (CHAR *)a->d_name;
6212 	if (estrcmp(pt, x_("..")) == 0) return(0);
6213 	if (estrcmp(pt, x_(".")) == 0) return(0);
6214 	return(1);
6215 }
6216 
6217 /*
6218  * Routine to search for all of the files/directories in directory "directory" and
6219  * return them in the array of strings "filelist".  Returns the number of files found.
6220  */
filesindirectory(CHAR * directory,CHAR *** filelist)6221 INTBIG filesindirectory(CHAR *directory, CHAR ***filelist)
6222 {
6223 	INTBIG len;
6224 	CHAR localname[256];
6225 	struct dirent **filenamelist;
6226 	struct dirent *dir, *result;
6227 	INTBIG total, i;
6228 #ifndef HAVE_SCANDIR
6229 #  define DIRFILECOUNT 2048  /* max number of entries in a directory */
6230 #  ifndef _POSIX_PATH_MAX
6231 #    define _POSIX_PATH_MAX 255
6232 #  endif
6233 	DIR *dirp;
6234 	REGISTER INTBIG tdirsize;
6235 #endif
6236 
6237 	/* make sure there is no ending "/" */
6238 	estrcpy(localname, directory);
6239 	i = estrlen(localname) - 1;
6240 	if (i > 0 && localname[i] == '/') localname[i] = 0;
6241 	if (i == -1) esnprintf(localname, 256, x_("."));
6242 
6243 	/* scan the directory */
6244 #ifdef HAVE_SCANDIR
6245 	/*
6246 	 * On BSD, last arg is: "(int (*)(const void *, const void *))0"
6247 	 * On non-BSD, last arg is: "(int (*)(const __ptr_t, const __ptr_t))0"
6248 	 */
6249 	total = scandir(string1byte(localname), &filenamelist, gra_fileselectall, NULL);
6250 #else
6251 	/* get space for directory */
6252 	filenamelist = (struct dirent **)calloc(DIRFILECOUNT,
6253 		sizeof(struct dirent *));
6254 	if (filenamelist == 0) return(0);
6255 	tdirsize = sizeof (struct dirent);
6256 	dir = (struct dirent *)emalloc(tdirsize + _POSIX_PATH_MAX, us_tool->cluster);
6257 	if (dir == 0) return(0);
6258 
6259 	/* get the directory */
6260 	dirp = opendir(string1byte(localname));
6261 	if (dirp == NULL) return(-1);
6262 
6263 	/* construct the list */
6264 	total = 0;
6265 	for(;;)
6266 	{
6267 #ifdef HAVE_POSIX_READDIR_R
6268 		if (readdir_r(dirp, dir, &result) != 0) break;
6269 #else
6270 		result = (struct dirent *)readdir_r(dirp, dir);
6271 #endif
6272 		if (result == NULL) break;
6273 		if (gra_fileselectall(dir))
6274 		{
6275 			filenamelist[total] = (struct dirent *)emalloc(tdirsize + _POSIX_PATH_MAX,
6276 				us_tool->cluster);
6277 			if (filenamelist[total] == 0) { closedir(dirp);   return(0); }
6278 			memcpy(filenamelist[total], dir, sizeof(dir)+_POSIX_PATH_MAX);
6279 			total++;
6280 		}
6281 	}
6282 	closedir(dirp);
6283 #endif
6284 
6285 	gra_initfilelist();
6286 	for(i=0; i<total; i++)
6287 	{
6288 		dir = filenamelist[i];
6289 		if (gra_addfiletolist(string2byte(dir->d_name))) return(0);
6290 		free((CHAR *)dir);
6291 	}
6292 	free((CHAR *)filenamelist);
6293 	*filelist = getstringarray(gra_fileliststringarray, &len);
6294 	return(len);
6295 }
6296 
6297 /* routine to convert a path name with "~" to a real path */
truepath(CHAR * line)6298 CHAR *truepath(CHAR *line)
6299 {
6300 	static CHAR outline[100], home[50];
6301 	REGISTER CHAR save, *ch;
6302 	static BOOLEAN gothome = FALSE;
6303 	struct passwd *tmp;
6304 
6305 	if (line[0] != '~') return(line);
6306 
6307 	/* if it is the form "~username", figure it out */
6308 	if (line[1] != '/')
6309 	{
6310 		for(ch = &line[1]; *ch != 0 && *ch != '/'; ch++);
6311 		save = *ch;   *ch = 0;
6312 		tmp = getpwnam(string1byte(&line[1]));
6313 		if (tmp == 0) return(line);
6314 		*ch = save;
6315 		(void)estrcpy(outline, string2byte(tmp->pw_dir));
6316 		(void)estrcat(outline, ch);
6317 		return(outline);
6318 	}
6319 
6320 	/* get the user's home directory once only */
6321 	if (!gothome)
6322 	{
6323 		/* get name of user */
6324 		tmp = getpwuid(getuid());
6325 		if (tmp == 0) return(line);
6326 		(void)estrcpy(home, string2byte(tmp->pw_dir));
6327 		gothome = TRUE;
6328 	}
6329 
6330 	/* substitute home directory for the "~" */
6331 	(void)estrcpy(outline, home);
6332 	(void)estrcat(outline, &line[1]);
6333 	return(outline);
6334 }
6335 
6336 /*
6337  * Routine to return the full path to file "file".
6338  */
fullfilename(CHAR * file)6339 CHAR *fullfilename(CHAR *file)
6340 {
6341 	static CHAR fullfile[MAXPATHLEN];
6342 
6343 	if (file[0] == '/') return(file);
6344 	estrcpy(fullfile, currentdirectory());
6345 	estrcat(fullfile, file);
6346 	return(fullfile);
6347 }
6348 
6349 /*
6350  * routine to rename file "file" to "newfile"
6351  * returns nonzero on error
6352  */
erename(CHAR * file,CHAR * newfile)6353 INTBIG erename(CHAR *file, CHAR *newfile)
6354 {
6355 	CHAR1 file1[300], newfile1[300];
6356 
6357 	TRUESTRCPY(file1, string1byte(file));
6358 	TRUESTRCPY(newfile1, string1byte(newfile));
6359 	if (link(file1, newfile1) < 0) return(1);
6360 	if (unlink(file1) < 0) return(1);
6361 	return(0);
6362 }
6363 
6364 /*
6365  * routine to delete file "file"
6366  */
eunlink(CHAR * file)6367 INTBIG eunlink(CHAR *file)
6368 {
6369 	return(unlink(string1byte(file)));
6370 }
6371 
6372 /*
6373  * Routine to return information about the file or directory "name":
6374  *  0: does not exist
6375  *  1: is a file
6376  *  2: is a directory
6377  *  3: is a locked file (read-only)
6378  */
fileexistence(CHAR * name)6379 INTBIG fileexistence(CHAR *name)
6380 {
6381 	struct stat buf;
6382 
6383 	if (estat(name, &buf) < 0) return(0);
6384 	if ((buf.st_mode & S_IFMT) == S_IFDIR) return(2);
6385 
6386 	/* a file: see if it is writable */
6387 	if (eaccess(name, 2) == 0) return(1);
6388 	return(3);
6389 }
6390 
6391 /*
6392  * Routine to create a directory.
6393  * Returns true on error.
6394  */
createdirectory(CHAR * dirname)6395 BOOLEAN createdirectory(CHAR *dirname)
6396 {
6397 	CHAR cmd[256];
6398 
6399 	esnprintf(cmd, 256, x_("mkdir %s"), dirname);
6400 	if (system(string1byte(cmd)) == 0) return(FALSE);
6401 	return(TRUE);
6402 }
6403 
6404 /*
6405  * Routine to return the current directory name
6406  */
currentdirectory(void)6407 CHAR *currentdirectory(void)
6408 {
6409 	static CHAR line[MAXPATHLEN];
6410 	REGISTER INTBIG len;
6411 
6412 #ifdef HAVE_GETCWD
6413 	(void)egetcwd(line, MAXPATHLEN);
6414 #else
6415 #  ifdef HAVE_GETWD
6416 	(void)getwd(line);
6417 #  else
6418 	line[0] = 0;
6419 #  endif
6420 #endif
6421 	len = estrlen(line);
6422 	if (len > 0 && line[len-1] != DIRSEP)
6423 		estrcat(line, DIRSEPSTR);
6424 	return(line);
6425 }
6426 
6427 /*
6428  * Routine to set the current directory name
6429  */
gra_setcurrentdirectory(CHAR * path)6430 void gra_setcurrentdirectory(CHAR *path)
6431 {
6432 	chdir(string1byte(path));
6433 }
6434 
6435 /*
6436  * Routine to return the home directory (returns 0 if it doesn't exist)
6437  */
hashomedir(void)6438 CHAR *hashomedir(void)
6439 {
6440 	return(x_("~/"));
6441 }
6442 
6443 /*
6444  * Routine to return the path to the "options" library.
6445  */
optionsfilepath(void)6446 CHAR *optionsfilepath(void)
6447 {
6448 	return(x_("~/.electricoptions.elib"));
6449 }
6450 
6451 /*
6452  * Routine to obtain the modification date on file "filename".
6453  */
filedate(CHAR * filename)6454 time_t filedate(CHAR *filename)
6455 {
6456 	struct stat buf;
6457 	time_t thetime;
6458 
6459 	estat(filename, &buf);
6460 	thetime = buf.st_mtime;
6461 	thetime -= machinetimeoffset();
6462 	return(thetime);
6463 }
6464 
6465 /*
6466  * Routine to set the date on file "filename" to "date".
6467  * If "moddate" is TRUE, set the modification date.  Otherwise, the creation date.
6468  */
setfiledate(CHAR * filename,time_t date,BOOLEAN moddate)6469 void setfiledate(CHAR *filename, time_t date, BOOLEAN moddate)
6470 {
6471 }
6472 
6473 /*
6474  * Routine to lock a resource called "lockfilename" by creating such a file
6475  * if it doesn't exist.  Returns true if successful, false if unable to
6476  * lock the file.
6477  */
lockfile(CHAR * lockfilename)6478 BOOLEAN lockfile(CHAR *lockfilename)
6479 {
6480 	INTBIG fd;
6481 
6482 	fd = ecreat(lockfilename, 0);
6483 	if (fd == -1 && errno == EACCES) return(FALSE);
6484 	if (fd == -1 || close(fd) == -1) return(FALSE);
6485 	return(TRUE);
6486 }
6487 
6488 /*
6489  * Routine to unlock a resource called "lockfilename" by deleting such a file.
6490  */
unlockfile(CHAR * lockfilename)6491 void unlockfile(CHAR *lockfilename)
6492 {
6493 	if (unlink(string1byte(lockfilename)) == -1)
6494 		ttyputerr(_("Error unlocking %s"), lockfilename);
6495 }
6496 
6497 /*
6498  * Routine to show file "filename" in a browser window.
6499  * Returns true if the operation cannot be done.
6500  */
browsefile(CHAR * filename)6501 BOOLEAN browsefile(CHAR *filename)
6502 {
6503 	CHAR line[300];
6504 
6505 	esnprintf(line, 300, x_("netscape %s&"), filename);
6506 	if (system(string1byte(line)) == 0) return(FALSE);
6507 	return(TRUE);
6508 }
6509 
6510 /****************************** CHANNELS ******************************/
6511 
6512 /*
6513  * routine to create a pipe connection between the channels in "channels"
6514  */
epipe(int channels[2])6515 INTBIG epipe(int channels[2])
6516 {
6517 	return(pipe(channels));
6518 }
6519 
6520 /*
6521  * Routine to set channel "channel" into an appropriate mode for single-character
6522  * interaction (i.e. break mode).
6523  */
setinteractivemode(int channel)6524 void setinteractivemode(int channel)
6525 {
6526 #ifdef HAVE_TERMIOS_H
6527 	struct termios sbuf;
6528 
6529 	tcgetattr(channel, &sbuf);
6530 	sbuf.c_iflag |= (BRKINT|IGNPAR|ISTRIP|IXON);
6531 	sbuf.c_oflag |= OPOST;
6532 	sbuf.c_lflag |= (ICANON|ISIG|ECHO);
6533 	sbuf.c_cc[VMIN] = 1;	/* Input should wait for at least one CHAR */
6534 	sbuf.c_cc[VTIME] = 0;	/* no matter how long that takes. */
6535 	tcsetattr(channel, TCSANOW, &sbuf);
6536 #else
6537 #  ifdef HAVE_TERMIO_H
6538 	struct termio sbuf;
6539 
6540 	(void)ioctl(channel, TCGETA, &sbuf);
6541 	sbuf.c_iflag |= (BRKINT|IGNPAR|ISTRIP|IXON);
6542 	sbuf.c_oflag |= OPOST;
6543 
6544 	/* bogus hp baud rate sanity */
6545 	sbuf.c_cflag = (sbuf.c_cflag & ~CBAUD) | B9600;
6546 	sbuf.c_lflag |= (ICANON|ISIG|ECHO);
6547 	sbuf.c_cc[VMIN] = 1;	/* Input should wait for at least one CHAR */
6548 	sbuf.c_cc[VTIME] = 0;	/* no matter how long that takes. */
6549 	(void)ioctl(channel, TCSETA, &sbuf);
6550 #  else
6551 	struct sgttyb sbuf;
6552 
6553 	(void)gtty(channel, &sbuf);
6554 	sbuf.sg_flags |= CBREAK;
6555 	(void)stty(channel, &sbuf);
6556 #  endif
6557 #endif
6558 }
6559 
6560 /*
6561  * Routine to replace channel "channel" with a pointer to file "file".
6562  * Returns a pointer to the original channel.
6563  */
channelreplacewithfile(int channel,CHAR * file)6564 INTBIG channelreplacewithfile(int channel, CHAR *file)
6565 {
6566 	INTBIG save;
6567 
6568 	save = dup(channel);
6569 	(void)close(channel);
6570 	(void)open(string1byte(file), 1);
6571 	return(save);
6572 }
6573 
6574 /*
6575  * Routine to replace channel "channel" with new channel "newchannel".
6576  * Returns a pointer to the original channel.
6577  */
channelreplacewithchannel(int channel,int newchannel)6578 INTBIG channelreplacewithchannel(int channel, int newchannel)
6579 {
6580 	INTBIG save;
6581 
6582 	save = dup(channel);
6583 	(void)close(channel);
6584 	(void)dup(newchannel);
6585 	return(save);
6586 }
6587 
6588 /*
6589  * Routine to restore channel "channel" to the pointer that was returned
6590  * by "channelreplacewithfile" or "channelreplacewithchannel" (and is in "saved").
6591  */
channelrestore(int channel,INTBIG saved)6592 void channelrestore(int channel, INTBIG saved)
6593 {
6594 	(void)close(channel);
6595 	(void)dup(saved);
6596 }
6597 
6598 /*
6599  * Routine to read "count" bytes from channel "channel" into "addr".
6600  * Returns the number of bytes read.
6601  */
eread(int channel,UCHAR1 * addr,INTBIG count)6602 INTBIG eread(int channel, UCHAR1 *addr, INTBIG count)
6603 {
6604 	return(read(channel, addr, count));
6605 }
6606 
6607 /*
6608  * Routine to write "count" bytes to channel "channel" from "addr".
6609  * Returns the number of bytes written.
6610  */
ewrite(int channel,UCHAR1 * addr,INTBIG count)6611 INTBIG ewrite(int channel, UCHAR1 *addr, INTBIG count)
6612 {
6613 	return(write(channel, addr, count));
6614 }
6615 
6616 /*
6617  * routine to close a channel in "channel"
6618  */
eclose(int channel)6619 INTBIG eclose(int channel)
6620 {
6621 	return(close(channel));
6622 }
6623 
6624 /******************** TIME ROUTINES ********************/
6625 
6626 /*
6627  * This routine returns the amount to add to the operating-system time
6628  * to adjust for a common time format.
6629  */
machinetimeoffset(void)6630 time_t machinetimeoffset(void)
6631 {
6632 	return(0);
6633 }
6634 
6635 /* returns the time at which the current event occurred */
eventtime(void)6636 UINTBIG eventtime(void)
6637 {
6638 	return(gra_eventtime);
6639 }
6640 
6641 /* returns the current time in 60ths of a second */
ticktime(void)6642 UINTBIG ticktime(void)
6643 {
6644 #ifdef HAVE_FTIME
6645 	struct timeb tp;
6646 	static INTBIG basesecs = 0;
6647 	INTBIG ticks;
6648 
6649 	ftime(&tp);
6650 	if (basesecs == 0) basesecs = tp.time;
6651 	ticks = (tp.time-basesecs) * 60 + (tp.millitm * 6 / 100);
6652 	return(ticks + gra_timeoffset);
6653 #else
6654 #  ifdef HAVE_GETTIMEOFDAY
6655 	struct timeval tp;
6656 	struct timezone tzp;
6657 
6658 	gettimeofday(&tp, &tzp);
6659 	return(tp.tv_sec * 60 + tp.tv_usec * 6 / 100000 + gra_timeoffset);
6660 #  else
6661 	static UINTBIG theTime = 0;
6662 
6663 	return(theTime++ + gra_timeoffset);
6664 #  endif
6665 #endif
6666 }
6667 
6668 /* returns the double-click interval in 60ths of a second */
doubleclicktime(void)6669 INTBIG doubleclicktime(void)
6670 {
6671 	INTBIG dct;
6672 
6673 	dct = gra_doublethresh;
6674 	dct = dct * 60 / 1000;
6675 	return(dct);
6676 }
6677 
6678 /*
6679  * Routine to wait "ticks" sixtieths of a second and then return.
6680  */
gotosleep(INTBIG ticks)6681 void gotosleep(INTBIG ticks)
6682 {
6683 	sleep(ticks);
6684 }
6685 
6686 /*
6687  * Routine to start counting time.
6688  */
starttimer(void)6689 void starttimer(void)
6690 {
6691 #ifdef HAVE_FTIME
6692 	struct timeb tp;
6693 
6694 	ftime(&tp);
6695 	gra_timebasesec = tp.time;
6696 	gra_timebasems = tp.millitm;
6697 #else
6698 	gra_timebasesec = time(0);
6699 #endif
6700 }
6701 
6702 /*
6703  * Routine to stop counting time and return the number of elapsed seconds
6704  * since the last call to "starttimer()".
6705  */
endtimer(void)6706 float endtimer(void)
6707 {
6708 	float seconds;
6709 #ifdef HAVE_FTIME
6710 	INTBIG milliseconds;
6711 	struct timeb timeptr;
6712 
6713 	ftime(&timeptr);
6714 	milliseconds = (timeptr.time - gra_timebasesec) * 1000 +
6715 		(timeptr.millitm-gra_timebasems);
6716 	seconds = ((float)milliseconds) / 1000.0;
6717 #else
6718 	seconds = time(0) - gra_timebasesec;
6719 #endif
6720 	return(seconds);
6721 }
6722 
6723 /*************************** EVENT ROUTINES ***************************/
6724 
6725 /*
6726  * Work procedure
6727  */
gra_dowork(XtPointer client_data)6728 Boolean gra_dowork(XtPointer client_data)
6729 {
6730 	tooltimeslice();
6731 	return(False);
6732 }
6733 
6734 /*
6735  * Routine to handle window deletion
6736  */
gra_windowdelete(Widget w,XtPointer client_data,XtPointer * call_data)6737 void gra_windowdelete(Widget w, XtPointer client_data, XtPointer *call_data)
6738 {
6739 	/* simply disable deletion of the messages window */
6740 	if (w == gra_msgtoplevelwidget)
6741 	{
6742 		ttyputerr(_("Cannot delete the messages window"));
6743 		return;
6744 	}
6745 
6746 	/* queue this frame for deletion */
6747 	gra_deletethisframe = gra_getcurrentwindowframe(w, FALSE);
6748 }
6749 
gra_handlequeuedframedeletion(void)6750 void gra_handlequeuedframedeletion(void)
6751 {
6752 	CHAR *par[MAXPARS];
6753 	REGISTER INTBIG windows;
6754 	REGISTER WINDOWFRAME *wf, *delwf;
6755 	REGISTER WINDOWPART *win, *nextw, *neww;
6756 	REGISTER NODEPROTO *np;
6757 
6758 	if (gra_deletethisframe == 0) return;
6759 	delwf = gra_deletethisframe;
6760 	gra_deletethisframe = 0;
6761 
6762 	/* turn off component menu if it was deleted */
6763 	if (delwf->floating)
6764 	{
6765 		par[0] = x_("off");
6766 		us_menu(1, par);
6767 		return;
6768 	}
6769 
6770 	/* make sure there is another window */
6771 	windows = 0;
6772 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
6773 		if (!wf->floating) windows++;
6774 	if (windows < 2)
6775 	{
6776 		/* no other windows: kill the program */
6777 		if (us_preventloss(NOLIBRARY, 0, TRUE)) return;
6778 		bringdown();
6779 	} else
6780 	{
6781 		/* there are other windows: allow this one to be killed (code copied from us_window("delete")) */
6782 
6783 		/* remember that a window is being deleted */
6784 		gra_windowbeingdeleted = 1;
6785 
6786 		/* save highlighting and turn it off */
6787 		us_pushhighlight();
6788 		us_clearhighlightcount();
6789 
6790 		startobjectchange((INTBIG)us_tool, VTOOL);
6791 
6792 		/* kill all editor windows on this frame */
6793 		neww = NOWINDOWPART;
6794 		for(win = el_topwindowpart; win != NOWINDOWPART; win = nextw)
6795 		{
6796 			nextw = win->nextwindowpart;
6797 			if (win->frame != delwf)
6798 			{
6799 				neww = win;
6800 				continue;
6801 			}
6802 
6803 			/* kill this window */
6804 			killwindowpart(win);
6805 		}
6806 		endobjectchange((INTBIG)us_tool, VTOOL);
6807 
6808 		if (neww == NOWINDOWPART) el_curwindowpart = NOWINDOWPART;
6809 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)neww, VWINDOWPART|VDONTSAVE);
6810 		if (neww != NOWINDOWPART) np = neww->curnodeproto; else np = NONODEPROTO;
6811 		(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)np, VNODEPROTO);
6812 
6813 		/* restore highlighting */
6814 		us_pophighlight(FALSE);
6815 
6816 		/* now no widget being deleted, and kill the window properly */
6817 		gra_windowbeingdeleted = 0;
6818 		killwindowframe(delwf);
6819 	}
6820 }
6821 
6822 /*
6823  * Routine called TICKSPERSECOND times each second.  Sees if nothing has happened since
6824  * the last button-down action, and repeats it if appropriate.
6825  */
gra_timerticked(XtPointer closure,XtIntervalId * id)6826 void gra_timerticked(XtPointer closure, XtIntervalId *id)
6827 {
6828 	/* requeue the timer event */
6829 	XtAppAddTimeOut(gra_xtapp, 1000/TICKSPERSECOND, gra_timerticked, 0);
6830 
6831 	/* see if it is time to fake another motion event */
6832 	gra_cureventtime++;
6833 	if (gra_cureventtime > gra_lasteventtime+INITIALTIMERDELAY)
6834 	{
6835 		/* see if the last event was a mouse button going down */
6836 		if ((gra_lasteventstate&ISBUTTON) != 0 && (gra_lasteventstate&BUTTONUP) == 0)
6837 		{
6838 			/* turn it into a null motion */
6839 			gra_addeventtoqueue((gra_lasteventstate & ~ISBUTTON) | MOTION,
6840 				gra_lasteventspecial, gra_lasteventx, gra_lasteventy);
6841 			gra_lasteventtime -= INITIALTIMERDELAY;
6842 			if (el_curwindowframe != NOWINDOWFRAME)
6843 				XSendEvent(gra_samplemotionevent.xmotion.display, gra_samplemotionevent.xmotion.window,
6844 					True, PointerMotionMask, &gra_samplemotionevent);
6845 			return;
6846 		}
6847 
6848 		/* see if the last event was a motion with button down */
6849 		if ((gra_lasteventstate&(MOTION|BUTTONUP)) == MOTION)
6850 		{
6851 			/* repeat the last event */
6852 			gra_addeventtoqueue(gra_lasteventstate, gra_lasteventspecial, gra_lasteventx, gra_lasteventy);
6853 			gra_lasteventtime -= INITIALTIMERDELAY;
6854 			if (el_curwindowframe != NOWINDOWFRAME)
6855 				XSendEvent(gra_samplemotionevent.xmotion.display, gra_samplemotionevent.xmotion.window,
6856 					True, PointerMotionMask, &gra_samplemotionevent);
6857 			return;
6858 		}
6859 	}
6860 }
6861 
6862 /*
6863  * Routine to queue an event of type "state" (with special code "special")
6864  * at (x,y).
6865  */
gra_addeventtoqueue(INTBIG state,INTBIG special,INTBIG x,INTBIG y)6866 void gra_addeventtoqueue(INTBIG state, INTBIG special, INTBIG x, INTBIG y)
6867 {
6868 	MYEVENTQUEUE *next;
6869 
6870 	next = gra_eventqueuetail + 1;
6871 	if (next >= &gra_eventqueue[EVENTQUEUESIZE])
6872 		next = gra_eventqueue;
6873 	if (next == gra_eventqueuehead)
6874 	{
6875 		/* queue is full */
6876 		if (!gra_checkinginterrupt) XBell(gra_maindpy, 100);
6877 		return;
6878 	}
6879 
6880 	gra_lasteventstate = gra_eventqueuetail->inputstate = state;
6881 	gra_eventqueuetail->special = special;
6882 	gra_lasteventspecial = gra_eventqueuetail->special = special;
6883 	gra_lasteventx = gra_eventqueuetail->cursorx = x;
6884 	gra_lasteventy = gra_eventqueuetail->cursory = y;
6885 	gra_eventqueuetail->eventtime = ticktime();
6886 	gra_lasteventtime = gra_cureventtime;
6887 	gra_eventqueuetail = next;
6888 }
6889 
6890 /*
6891  * Routine to dequeue the next event and place it in the globals
6892  * "gra_inputstate", "gra_cursorx", "gra_cusory".  If the event is
6893  * special, handle it.
6894  */
gra_pickupnextevent(void)6895 void gra_pickupnextevent(void)
6896 {
6897 	CHAR *par[2];
6898 	INTBIG special, state;
6899 	INTBIG x, y;
6900 	XmTextPosition tp;
6901 
6902 	/* get the next event from the queue */
6903 	gra_inputstate = NOEVENT;
6904 	while (gra_eventqueuehead != gra_eventqueuetail)
6905 	{
6906 		special = gra_eventqueuehead->special;
6907 		state = gra_eventqueuehead->inputstate;
6908 		x = gra_eventqueuehead->cursorx;
6909 		y = gra_eventqueuehead->cursory;
6910 		gra_eventtime = gra_eventqueuehead->eventtime;
6911 		gra_eventqueuehead++;
6912 		if (gra_eventqueuehead >= &gra_eventqueue[EVENTQUEUESIZE])
6913 			gra_eventqueuehead = gra_eventqueue;
6914 
6915 		/* stop if this is the last event in the queue */
6916 		if (gra_eventqueuehead == gra_eventqueuetail) break;
6917 
6918 		/* stop if this and the next event are not motion */
6919 		if ((state&MOTION) == 0) break;
6920 		if ((gra_eventqueuehead->inputstate&MOTION) == 0) break;
6921 	}
6922 
6923 	/* handle special actions */
6924 	if (special != 0 && (special&SPECIALKEYDOWN) != 0 && !gra_tracking)
6925 	{
6926 		switch ((special&SPECIALKEY)>>SPECIALKEYSH)
6927 		{
6928 			case SPECIALCUT:
6929 				par[0] = x_("cut");
6930 				us_text(1, par);
6931 				return;
6932 			case SPECIALCOPY:
6933 				par[0] = x_("copy");
6934 				us_text(1, par);
6935 				return;
6936 			case SPECIALPASTE:
6937 				par[0] = x_("paste");
6938 				us_text(1, par);
6939 				return;
6940 			case SPECIALUNDO:
6941 				us_undo(0, par);
6942 				return;
6943 			case SPECIALEND:
6944 				/* shift to end of messages window */
6945 				tp = XmTextGetLastPosition(gra_messageswidget);
6946 				XmTextSetSelection(gra_messageswidget, tp, tp, 0);
6947 				XmTextSetInsertionPosition(gra_messageswidget, tp);
6948 				XmTextShowPosition(gra_messageswidget, tp);
6949 				return;
6950 		}
6951 	}
6952 
6953 	gra_inputstate = state;
6954 	gra_inputspecial = special;
6955 	gra_cursorx = x;
6956 	gra_cursory = y;
6957 	us_state &= ~GOTXY;
6958 }
6959 
gra_nextevent(void)6960 void gra_nextevent(void)
6961 {
6962 	XEvent event;
6963 	REGISTER INTBIG windowindex;
6964 	REGISTER INTBIG x, y;
6965 	BOOLEAN verbose;
6966 	POPUPMENU *pm;
6967 	REGISTER WINDOWFRAME *wf;
6968 	REGISTER INTBIG i, j;
6969 
6970 	/* handle any queued window deletions */
6971 	gra_handlequeuedframedeletion();
6972 
6973 	/* flush the screen */
6974 	flushscreen();
6975 
6976 	/* get any event on the queue */
6977 	if (gra_eventqueuehead != gra_eventqueuetail)
6978 	{
6979 		gra_pickupnextevent();
6980 	} else
6981 	{
6982 		for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
6983 			XmUpdateDisplay(wf->toplevelwidget);
6984 
6985 		/* handle any pending event */
6986 		XtAppNextEvent(gra_xtapp, &event);
6987 		XtDispatchEvent(&event);
6988 
6989 		/* get any event on the queue */
6990 		if (gra_eventqueuehead != gra_eventqueuetail)
6991 			gra_pickupnextevent();
6992 	}
6993 
6994 	/* override the event if playing back */
6995 	if (us_logplay != NULL)
6996 	{
6997 		/* playing back log file: get event from disk */
6998 		if (gra_inputstate != NOEVENT || gra_firstactivedialog != NOTDIALOG)
6999 			(void)gra_loggetnextaction(0);
7000 	}
7001 
7002 	/* record valid events */
7003 	if (gra_inputstate != NOEVENT)
7004 	{
7005 		if (gra_inputstate == WINDOWSIZE || gra_inputstate == WINDOWMOVE)
7006 		{
7007 			windowindex = gra_cursorx;
7008 			x = gra_cursory >> 16;
7009 			y = gra_cursory & 0xFFFF;
7010 			gra_logwriteaction(gra_inputstate, 0, x, y, (void *)windowindex);
7011 			gra_inputstate = NOEVENT;
7012 		} else
7013 		{
7014 			windowindex = -1;
7015 			if (el_curwindowframe != NOWINDOWFRAME) windowindex = el_curwindowframe->windindex;
7016 			gra_logwriteaction(gra_inputstate, gra_inputspecial, gra_cursorx, gra_cursory, (void *)windowindex);
7017 		}
7018 
7019 		/* handle menu events */
7020 		if (gra_inputstate == MENUEVENT)
7021 		{
7022 			gra_inputstate = NOEVENT;
7023 			i = gra_cursorx;
7024 			j = gra_cursory;
7025 			for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
7026 				if (!wf->floating) break;
7027 			if (wf != NOWINDOWFRAME && i >= 0 && i < wf->pulldownmenucount)
7028 			{
7029 				pm = us_getpopupmenu(wf->pulldowns[i]);
7030 				if (j >= 0 && j < pm->total)
7031 				{
7032 					us_state |= DIDINPUT;
7033 					us_state &= ~GOTXY;
7034 					setdefaultcursortype(NULLCURSOR);
7035 					us_forceeditchanges();
7036 					if ((us_tool->toolstate&ECHOBIND) != 0) verbose = TRUE; else
7037 						verbose = FALSE;
7038 					us_execute(pm->list[j].response, verbose, TRUE, TRUE);
7039 					db_setcurrenttool(us_tool);
7040 					setactivity(pm->list[j].attribute);
7041 				}
7042 			}
7043 		}
7044 	}
7045 }
7046 
gra_messages_event_handler(Widget w,XtPointer data,XEvent * event,Boolean * cont)7047 void gra_messages_event_handler(Widget w, XtPointer data, XEvent *event, Boolean *cont)
7048 {
7049 	CHAR1 buffer[2];
7050 	REGISTER INTBIG state;
7051 	INTBIG special;
7052 	KeySym key;
7053 
7054 	switch (event->type)
7055 	{
7056 		case VisibilityNotify:
7057 			if (event->xvisibility.state == VisibilityUnobscured)
7058 				gra_messages_obscured = FALSE; else
7059 					gra_messages_obscured = TRUE;
7060 			break;
7061 
7062 		case FocusIn:
7063 			gra_msgontop = TRUE;
7064 			break;
7065 
7066 		case FocusOut:
7067 			gra_msgontop = FALSE;
7068 			break;
7069 
7070 		case KeyPress:
7071 			(void)XLookupString((XKeyEvent *)event, buffer, 2, &key, NULL);
7072 			if ((key == 'c' || key == 'C') && (event->xbutton.state & ControlMask) != 0)
7073 			{
7074 				/* we have to do interrupts here */
7075 				XtNoticeSignal(gra_intsignalid);
7076 				el_pleasestop = 1;
7077 				state = 0;
7078 				special = 0;
7079 			} else state = gra_translatekey(event, &special);
7080 			if (state != 0)
7081 			{
7082 				us_state |= DIDINPUT;
7083 				gra_addeventtoqueue(state, special, 0, 0);
7084 			}
7085 			event->type = 0;     /* disable this event so key doesn't go into window */
7086 			break;
7087 
7088 #if 0		/* for debugging X events */
7089 		default:
7090 			efprintf(stderr, _("Unhandled event %s in messages window\n"),
7091 				eventNames[event->type]);
7092 			break;
7093 #endif
7094 	}
7095 }
7096 
gra_graphics_event_handler(Widget w,XtPointer data,XEvent * event,Boolean * cont)7097 void gra_graphics_event_handler(Widget w, XtPointer data, XEvent *event, Boolean *cont)
7098 {
7099 	BOOLEAN setcursor, inmenu;
7100 	INTBIG wid, hei, special;
7101 	CHAR *str;
7102 	REGISTER INTBIG x, y, state, xfx, xfy;
7103 	REGISTER UINTBIG thetime;
7104 	INTBIG lx, hx, ly, hy;
7105 	REGISTER WINDOWPART *win;
7106 	REGISTER EDITOR *e;
7107 	REGISTER VARIABLE *var;
7108 	REGISTER TDIALOG *dia;
7109 	XWindowAttributes xwa;
7110 	COMMANDBINDING commandbinding;
7111 	REGISTER WINDOWFRAME *wf;
7112 	static BOOLEAN overrodestatus = FALSE;
7113 	extern INTBIG sim_window_wavexbar;
7114 	Window thewin;
7115 	int retval;
7116 
7117 	switch (event->type)
7118 	{
7119 		case ConfigureNotify:
7120 			wf = gra_getcurrentwindowframe(w, FALSE);
7121 			if (wf == NOWINDOWFRAME) return;
7122 			if (w != wf->toplevelwidget) break;
7123 
7124 			gra_getwindowinteriorsize(wf, &wid, &hei);
7125 			gra_getwindowattributes(wf, &xwa);
7126 
7127 			/* update user's positioning of component menu */
7128 			thetime = ticktime();
7129 			if (thetime - 120 > gra_internalchange && wf->floating)
7130 			{
7131 				gra_palettetop = xwa.y;
7132 				if (wid > hei) gra_palettewidth = wid; else
7133 					gra_paletteheight = hei;
7134 			}
7135 			gra_internalchange = thetime;
7136 
7137 			if (wid != wf->swid || hei != wf->trueheight)
7138 			{
7139 				/* window changed size */
7140 				gra_addeventtoqueue(WINDOWSIZE, 0, wf->windindex,
7141 					((xwa.width & 0xFFFF) << 16) | (xwa.height & 0xFFFF));
7142 				gra_repaint(wf, TRUE);
7143 			}
7144 
7145 			x = xwa.x;   y = xwa.y;
7146 			gra_addeventtoqueue(WINDOWMOVE, 0, wf->windindex,
7147 				((x & 0xFFFF) << 16) | (y & 0xFFFF));
7148 			break;
7149 
7150 		case Expose:
7151 			/* ignore partial events */
7152 			if (event->xexpose.count != 0) break;
7153 			if (gra_lastwidgetfocused == w)
7154 				wf = gra_getcurrentwindowframe(w, TRUE); else
7155 					wf = gra_getcurrentwindowframe(w, FALSE);
7156 #ifdef ANYDEPTH
7157 			if (wf != NOWINDOWFRAME)
7158 			{
7159 				wf->copyleft = 0;   wf->copyright = wf->swid;
7160 				wf->copytop = 0;    wf->copybottom = wf->trueheight;
7161 				wf->offscreendirty = TRUE;
7162 			}
7163 			flushscreen();
7164 #else
7165 			if (wf == NOWINDOWFRAME) return;
7166 			gra_repaint(wf, FALSE);
7167 #endif
7168 			break;
7169 
7170 		case FocusIn:
7171 			gra_lastwidgetfocused = w;
7172 			break;
7173 
7174 		case ClientMessage:
7175 			break;
7176 
7177 		case ReparentNotify:
7178 			break;
7179 
7180 		case KeyPress:
7181 			/* ignore this event if there is a modal dialog present */
7182 			for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7183 				if (dia->modelessitemhit == 0) break;
7184 			if (dia != NOTDIALOG) break;
7185 
7186 			wf = gra_getcurrentwindowframe(w, TRUE);
7187 			if (wf == NOWINDOWFRAME) return;
7188 			state = gra_translatekey(event, &special);
7189 			if (state == 0) break;
7190 			us_state |= DIDINPUT;
7191 
7192 			/* don't track in the status window */
7193 			gra_cursorx = event->xkey.x;
7194 			gra_cursory = maxi(wf->revy - event->xkey.y, 0);
7195 			gra_addeventtoqueue(state, special, gra_cursorx, gra_cursory);
7196 			break;
7197 
7198 		case ButtonPress:  /* these are ignored in the messages window */
7199 			if (us_logplay != NULL)
7200 			{
7201 				ttyputerr(_("Session playback aborted by mouse click"));
7202 				xclose(us_logplay);
7203 				us_logplay = NULL;
7204 				break;
7205 			}
7206 			gra_lastbuttonpressevent = *event;
7207 
7208 			/* ignore this event if there is a modal dialog present */
7209 			for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7210 				if (dia->modelessitemhit == 0) break;
7211 			if (dia != NOTDIALOG) break;
7212 
7213 			wf = gra_getcurrentwindowframe(w, TRUE);
7214 			if (wf == NOWINDOWFRAME) return;
7215 			switch (event->xbutton.button)
7216 			{
7217 				case 1: state = ISLEFT;    break;
7218 				case 2: state = ISMIDDLE;  break;
7219 				case 3: state = ISRIGHT;   break;
7220 				case 4: state = ISWHLFWD;  break;
7221 				case 5: state = ISWHLBKW;  break;
7222 			}
7223 			if ((event->xbutton.state & ShiftMask) != 0) state |= SHIFTISDOWN;
7224 			if ((event->xbutton.state & LockMask) != 0) state |= SHIFTISDOWN;
7225 			if ((event->xbutton.state & ControlMask) != 0) state |= CONTROLISDOWN;
7226 			if ((event->xbutton.state & (Mod1Mask|Mod4Mask)) != 0) state |= METAISDOWN;
7227 			gra_cursorx = event->xbutton.x;
7228 			gra_cursory = maxi(wf->revy - event->xbutton.y, 0);
7229 			if ((event->xbutton.time - gra_lasttime) <= gra_doublethresh &&
7230 				(state & (SHIFTISDOWN|CONTROLISDOWN|METAISDOWN)) == 0 &&
7231 				gra_cursorx == gra_lstcurx && gra_cursory == gra_lstcury)
7232 			{
7233 				state |= DOUBLECL;
7234 				gra_lasttime = event->xbutton.time - gra_doublethresh - 1;
7235 			} else
7236 			{
7237 				gra_lasttime = event->xbutton.time;
7238 			}
7239 			gra_addeventtoqueue(state, 0, gra_cursorx, gra_cursory);
7240 			gra_lstcurx = gra_cursorx;
7241 			gra_lstcury = gra_cursory;
7242 			us_state |= DIDINPUT;
7243 			break;
7244 
7245 		case ButtonRelease:
7246 			/* ignore this event if there is a modal dialog present */
7247 			for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7248 				if (dia->modelessitemhit == 0) break;
7249 			if (dia != NOTDIALOG) break;
7250 
7251 			wf = gra_getcurrentwindowframe(w, TRUE);
7252 			if (wf == NOWINDOWFRAME) return;
7253 			switch (event->xbutton.button)
7254 			{
7255 				case 1: state = ISLEFT | BUTTONUP;   break;
7256 				case 2: state = ISMIDDLE | BUTTONUP; break;
7257 				case 3: state = ISRIGHT | BUTTONUP;  break;
7258 			}
7259 			if ((event->xbutton.state & ShiftMask) != 0) state |= SHIFTISDOWN;
7260 			if ((event->xbutton.state & LockMask) != 0) state |= SHIFTISDOWN;
7261 			if ((event->xbutton.state & ControlMask) != 0) state |= CONTROLISDOWN;
7262 			if ((event->xbutton.state & (Mod1Mask|Mod4Mask)) != 0) state |= METAISDOWN;
7263 			gra_cursorx = event->xbutton.x;
7264 			gra_cursory = maxi(wf->revy - event->xbutton.y, 0);
7265 			gra_addeventtoqueue(state, 0, gra_cursorx, gra_cursory);
7266 			us_state |= DIDINPUT;
7267 			break;
7268 
7269 		case MotionNotify:
7270 			/* save this event for faking others */
7271 			gra_samplemotionevent = *event;
7272 
7273 			/* ignore faked events (done to wake up event loop) */
7274 			if (event->xmotion.send_event) break;
7275 
7276 			if (gra_firstbuttonwait == 0) break;
7277 			if ((event->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) == 0)
7278 			{
7279 				/* motion while up considers any window */
7280 				wf = gra_getcurrentwindowframe(w, FALSE);
7281 				if (wf == NOWINDOWFRAME) return;
7282 				gra_cursorx = event->xmotion.x;
7283 				gra_cursory = wf->revy - event->xmotion.y;
7284 				if (gra_cursory < 0) gra_cursory = 0;
7285 
7286 				/* report the menu if over one */
7287 				inmenu = FALSE;
7288 				if (wf->floating)
7289 				{
7290 					x = (gra_cursorx-us_menulx) / us_menuxsz;
7291 					y = (gra_cursory-us_menuly) / us_menuysz;
7292 					if (x >= 0 && y >= 0 && x < us_menux && y < us_menuy)
7293 					{
7294 						var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
7295 						if (var != NOVARIABLE)
7296 						{
7297 							if (us_menupos <= 1) str = ((CHAR **)var->addr)[y * us_menux + x]; else
7298 								str = ((CHAR **)var->addr)[x * us_menuy + y];
7299 							us_parsebinding(str, &commandbinding);
7300 							if (*commandbinding.command != 0)
7301 							{
7302 								if (commandbinding.nodeglyph != NONODEPROTO)
7303 								{
7304 									ttysetstatusfield(NOWINDOWFRAME, us_statusarc,
7305 										describearcproto(us_curarcproto), TRUE);
7306 									ttysetstatusfield(NOWINDOWFRAME, us_statusnode,
7307 										us_describemenunode(&commandbinding), TRUE);
7308 									inmenu = TRUE;
7309 									overrodestatus = TRUE;
7310 								}
7311 								if (commandbinding.arcglyph != NOARCPROTO)
7312 								{
7313 									ttysetstatusfield(NOWINDOWFRAME, us_statusarc,
7314 										describearcproto(commandbinding.arcglyph), TRUE);
7315 									if (us_curnodeproto == NONODEPROTO) str = x_(""); else
7316 										str = describenodeproto(us_curnodeproto);
7317 									ttysetstatusfield(NOWINDOWFRAME, us_statusnode, str, TRUE);
7318 									inmenu = TRUE;
7319 									overrodestatus = TRUE;
7320 								}
7321 							}
7322 							us_freebindingparse(&commandbinding);
7323 						}
7324 					}
7325 				}
7326 				if (!inmenu && overrodestatus)
7327 				{
7328 					ttysetstatusfield(NOWINDOWFRAME, us_statusarc,
7329 						describearcproto(us_curarcproto), TRUE);
7330 					if (us_curnodeproto == NONODEPROTO) str = x_(""); else
7331 						str = describenodeproto(us_curnodeproto);
7332 					ttysetstatusfield(NOWINDOWFRAME, us_statusnode, str, TRUE);
7333 					overrodestatus = FALSE;
7334 				}
7335 
7336 				setcursor = FALSE;
7337 				for(win = el_topwindowpart; win != NOWINDOWPART; win = win->nextwindowpart)
7338 				{
7339 					/* see if the cursor is over a window partition separator */
7340 					if (win->frame != wf) continue;
7341 					us_gettruewindowbounds(win, &lx, &hx, &ly, &hy);
7342 					if (gra_cursorx >= lx-1 && gra_cursorx <= lx+1 && gra_cursory > ly+1 &&
7343 						gra_cursory < hy-1 && us_hasotherwindowpart(lx-10, gra_cursory, win))
7344 					{
7345 						setdefaultcursortype(LRCURSOR);
7346 						setcursor = TRUE;
7347 						break;
7348 					} else if (gra_cursorx >= hx-1 && gra_cursorx <= hx+1 && gra_cursory > ly+1 &&
7349 						gra_cursory < hy-1 && us_hasotherwindowpart(hx+10, gra_cursory, win))
7350 					{
7351 						setdefaultcursortype(LRCURSOR);
7352 						setcursor = TRUE;
7353 						break;
7354 					} else if (gra_cursory >= ly-1 && gra_cursory <= ly+1 && gra_cursorx > lx+1 &&
7355 						gra_cursorx < hx-1 && us_hasotherwindowpart(gra_cursorx, ly-10, win))
7356 					{
7357 						setdefaultcursortype(UDCURSOR);
7358 						setcursor = TRUE;
7359 						break;
7360 					} else if (gra_cursory >= hy-1 && gra_cursory <= hy+1 && gra_cursorx > lx+1 &&
7361 						gra_cursorx < hx-1 && us_hasotherwindowpart(gra_cursorx, hy+10, win))
7362 					{
7363 						setdefaultcursortype(UDCURSOR);
7364 						setcursor = TRUE;
7365 						break;
7366 					}
7367 
7368 					if (gra_cursorx < win->uselx || gra_cursorx > win->usehx ||
7369 						gra_cursory < win->usely || gra_cursory > win->usehy) continue;
7370 					if ((win->state&WINDOWTYPE) == WAVEFORMWINDOW)
7371 					{
7372 						xfx = muldiv(gra_cursorx - win->uselx, win->screenhx - win->screenlx,
7373 							win->usehx - win->uselx) + win->screenlx;
7374 						xfy = muldiv(y - win->usely, win->screenhy - win->screenly,
7375 							win->usehy - win->usely) + win->screenly;
7376 						if (abs(xfx - sim_window_wavexbar) < 2 && xfy >= 560)
7377 						{
7378 							setdefaultcursortype(LRCURSOR);
7379 							setcursor = TRUE;
7380 							break;
7381 						}
7382 					}
7383 					if ((win->state&WINDOWTYPE) == POPTEXTWINDOW ||
7384 						(win->state&WINDOWTYPE) == TEXTWINDOW)
7385 					{
7386 						e = win->editor;
7387 						if ((e->state&EDITORTYPE) == PACEDITOR)
7388 						{
7389 							if (gra_cursorx <= win->usehx - SBARWIDTH &&
7390 								gra_cursory >= win->usely + SBARWIDTH &&
7391 								gra_cursory < e->revy)
7392 							{
7393 								setdefaultcursortype(IBEAMCURSOR);
7394 								setcursor = TRUE;
7395 								break;
7396 							}
7397 						}
7398 					}
7399 				}
7400 				if (!setcursor) setdefaultcursortype(us_normalcursor);
7401 
7402 				/* record the action */
7403 				state = MOTION | BUTTONUP;
7404 				gra_addeventtoqueue(state, 0, gra_cursorx, gra_cursory);
7405 			} else
7406 			{
7407 				/* motion while button down: use last window */
7408 				wf = el_curwindowframe;
7409 				if (wf == NOWINDOWFRAME) return;
7410 				gra_cursorx = event->xmotion.x;
7411 				gra_cursory = wf->revy - event->xmotion.y;
7412 				if (gra_cursory < 0) gra_cursory = 0;
7413 
7414 				/* record the action */
7415 				state = MOTION;
7416 				gra_addeventtoqueue(state, 0, gra_cursorx, gra_cursory);
7417 			}
7418 			break;
7419 
7420 #if 0		/* for debugging X events */
7421 		default:
7422 			efprintf(stderr, _("Unhandled event %s in graphics window.\n"),
7423 				eventNames[event->type]);
7424 			break;
7425 #endif
7426 	}
7427 }
7428 
7429 /*
7430  * routine to determine the current window frame and load the global "el_curwindowframe".
7431  */
gra_getcurrentwindowframe(Widget widget,BOOLEAN set)7432 WINDOWFRAME *gra_getcurrentwindowframe(Widget widget, BOOLEAN set)
7433 {
7434 	WINDOWFRAME *wf;
7435 	WINDOWPART *w;
7436 
7437 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
7438 	{
7439 		if (wf->toplevelwidget == widget) break;
7440 		if (wf->intermediategraphics == widget) break;
7441 		if (wf->graphicswidget == widget) break;
7442 	}
7443 	if (!set) return(wf);
7444 
7445 	el_curwindowframe = wf;
7446 	if (wf == NOWINDOWFRAME) return(NOWINDOWFRAME);
7447 
7448 	/* ignore floating windows */
7449 	if (wf->floating) return(wf);
7450 
7451 	/* see if the change of window frame invalidates the current window */
7452 	if (el_curwindowpart == NOWINDOWPART || el_curwindowpart->frame != wf)
7453 	{
7454 		/* must choose new window (if not broadcasting) */
7455 		if (db_broadcasting == 0)
7456 		{
7457 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
7458 			{
7459 				if (w->frame == wf)
7460 				{
7461 					(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
7462 						VWINDOWPART|VDONTSAVE);
7463 					(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"),
7464 						(INTBIG)w->curnodeproto, VNODEPROTO);
7465 #if 0
7466 					return(NOWINDOWFRAME);
7467 #else
7468 					break;
7469 #endif
7470 				}
7471 			}
7472 		}
7473 	}
7474 	return(el_curwindowframe);
7475 }
7476 
7477 /*
7478  * Routine to translate key symbols to electric state.
7479  * Sets "special" to a nonzero code if a special function key was hit
7480  * Returns 0 if the key is unknown.
7481  */
gra_translatekey(XEvent * event,INTBIG * special)7482 INTBIG gra_translatekey(XEvent *event, INTBIG *special)
7483 {
7484 	CHAR1 buffer[2];
7485 	KeySym key;
7486 	INTBIG state;
7487 
7488 	*special = 0;
7489 	(void)XLookupString((XKeyEvent *)event, buffer, 2, &key, NULL);
7490 	if (key > 0 && key < 0200) state = key; else
7491 	{
7492 		switch (key)
7493 		{
7494 			case XK_KP_0:      state = '0';            break;
7495 			case XK_KP_1:      state = '1';            break;
7496 			case XK_KP_2:      state = '2';            break;
7497 			case XK_KP_3:      state = '3';            break;
7498 			case XK_KP_4:      state = '4';            break;
7499 			case XK_KP_5:      state = '5';            break;
7500 			case XK_KP_6:      state = '6';            break;
7501 			case XK_KP_7:      state = '7';            break;
7502 			case XK_KP_8:      state = '8';            break;
7503 			case XK_KP_9:      state = '9';            break;
7504 			case XK_BackSpace: state = BACKSPACEKEY;   break;
7505 			case XK_Tab:       state = 011;            break;
7506 			case XK_Linefeed:  state = 012;            break;
7507 			case XK_Return:    state = 015;            break;
7508 			case XK_Escape:    state = ESCKEY;         break;
7509 			case XK_Delete:    state = 0177;           break;
7510 			case XK_KP_Enter:  state = 015;            break;
7511 
7512 			case XK_End:
7513 				state = 0;
7514 				*special = SPECIALKEYDOWN|(SPECIALEND<<SPECIALKEYSH);
7515 				break;
7516 			case XK_L4:
7517 				state = 0;
7518 				*special = SPECIALKEYDOWN|(SPECIALUNDO<<SPECIALKEYSH);
7519 				break;
7520 			case XK_L6:
7521 				state = 0;
7522 				*special = SPECIALKEYDOWN|(SPECIALCOPY<<SPECIALKEYSH);
7523 				break;
7524 			case XK_L8:
7525 				state = 0;
7526 				*special = SPECIALKEYDOWN|(SPECIALPASTE<<SPECIALKEYSH);
7527 				break;
7528 			case XK_L10:
7529 				state = 0;
7530 				*special = SPECIALKEYDOWN|(SPECIALCUT<<SPECIALKEYSH);
7531 				break;
7532 
7533 			case XK_Left:
7534 			case XK_KP_Left:
7535 				state = 0;
7536 				*special = SPECIALKEYDOWN|(SPECIALKEYARROWL<<SPECIALKEYSH);
7537 				if ((event->xbutton.state & ShiftMask) != 0) *special |= SHIFTDOWN;
7538 				break;
7539 			case XK_Right:
7540 			case XK_KP_Right:
7541 				state = 0;
7542 				*special = SPECIALKEYDOWN|(SPECIALKEYARROWR<<SPECIALKEYSH);
7543 				if ((event->xbutton.state & ShiftMask) != 0) *special |= SHIFTDOWN;
7544 				break;
7545 			case XK_Up:
7546 			case XK_KP_Up:
7547 				state = 0;
7548 				*special = SPECIALKEYDOWN|(SPECIALKEYARROWU<<SPECIALKEYSH);
7549 				if ((event->xbutton.state & ShiftMask) != 0) *special |= SHIFTDOWN;
7550 				break;
7551 			case XK_Down:
7552 			case XK_KP_Down:
7553 				state = 0;
7554 				*special = SPECIALKEYDOWN|(SPECIALKEYARROWD<<SPECIALKEYSH);
7555 				if ((event->xbutton.state & ShiftMask) != 0) *special |= SHIFTDOWN;
7556 				break;
7557 
7558 			case XK_F1:
7559 				state = 0;
7560 				*special = SPECIALKEYDOWN|(SPECIALKEYF1<<SPECIALKEYSH);
7561 				break;
7562 			case XK_F2:
7563 				state = 0;
7564 				*special = SPECIALKEYDOWN|(SPECIALKEYF2<<SPECIALKEYSH);
7565 				break;
7566 			case XK_F3:
7567 				state = 0;
7568 				*special = SPECIALKEYDOWN|(SPECIALKEYF3<<SPECIALKEYSH);
7569 				break;
7570 			case XK_F4:
7571 				state = 0;
7572 				*special = SPECIALKEYDOWN|(SPECIALKEYF4<<SPECIALKEYSH);
7573 				break;
7574 			case XK_F5:
7575 				state = 0;
7576 				*special = SPECIALKEYDOWN|(SPECIALKEYF5<<SPECIALKEYSH);
7577 				break;
7578 			case XK_F6:
7579 				state = 0;
7580 				*special = SPECIALKEYDOWN|(SPECIALKEYF6<<SPECIALKEYSH);
7581 				break;
7582 			case XK_F7:
7583 				state = 0;
7584 				*special = SPECIALKEYDOWN|(SPECIALKEYF7<<SPECIALKEYSH);
7585 				break;
7586 			case XK_F8:
7587 				state = 0;
7588 				*special = SPECIALKEYDOWN|(SPECIALKEYF8<<SPECIALKEYSH);
7589 				break;
7590 			case XK_F9:
7591 				state = 0;
7592 				*special = SPECIALKEYDOWN|(SPECIALKEYF9<<SPECIALKEYSH);
7593 				break;
7594 			case XK_F10:
7595 				state = 0;
7596 				*special = SPECIALKEYDOWN|(SPECIALKEYF10<<SPECIALKEYSH);
7597 				break;
7598 			case XK_F11:
7599 				state = 0;
7600 				*special = SPECIALKEYDOWN|(SPECIALKEYF11<<SPECIALKEYSH);
7601 				break;
7602 			case XK_F12:
7603 				state = 0;
7604 				*special = SPECIALKEYDOWN|(SPECIALKEYF12<<SPECIALKEYSH);
7605 				break;
7606 
7607 			default:
7608 				state = 0;
7609 				break;
7610 		}
7611 	}
7612 	if (state == 0 && *special == 0) return(0);
7613 
7614 	if ((event->xbutton.state & ControlMask) != 0)
7615 	{
7616 		if (!gra_messages_typingin) *special |= ACCELERATORDOWN; else
7617 		{
7618 			if (state >= 'a' && state <= 'z') state -= 'a' - 1; else
7619 				if (state >= 'A' && state <= 'Z') state -= 'A' - 1;
7620 		}
7621 	}
7622 	state |= ISKEYSTROKE;
7623 	return(state);
7624 }
7625 
gra_repaint(WINDOWFRAME * wf,BOOLEAN redo)7626 void gra_repaint(WINDOWFRAME *wf, BOOLEAN redo)
7627 {
7628 	INTBIG wid, hei;
7629 	static BOOLEAN inrepaint = FALSE;
7630 
7631 	if (inrepaint) return;
7632 	inrepaint = TRUE;
7633 
7634 	gra_getwindowinteriorsize(wf, &wid, &hei);
7635 	gra_recalcsize(wf, wid, hei);
7636 
7637 	if (wf->floating)
7638 	{
7639 		us_startbatch(NOTOOL, FALSE);
7640 		if (redo) us_drawmenu(1, wf); else
7641 			us_drawmenu(-1, wf);
7642 		us_endbatch();
7643 		inrepaint = FALSE;
7644 		return;
7645 	}
7646 
7647 	if (el_topwindowpart != NOWINDOWPART)
7648 	{
7649 		/* mark start of redisplay */
7650 		us_startbatch(NOTOOL, FALSE);
7651 
7652 		/* save and clear highlighting */
7653 		us_pushhighlight();
7654 		us_clearhighlightcount();
7655 
7656 		/* rewrite status area */
7657 		if (redo) us_drawmenu(1, wf); else
7658 			us_drawmenu(-1, wf);
7659 
7660 		/* restore highlighting */
7661 		us_pophighlight(FALSE);
7662 
7663 		/* finish drawing */
7664 		us_endbatch();
7665 
7666 		us_redostatus(wf);
7667 
7668 		/* describe this change */
7669 		setactivity(_("Window Resize"));
7670 	}
7671 	inrepaint = FALSE;
7672 }
7673 
gra_recalcsize(WINDOWFRAME * wf,INTBIG newwid,INTBIG newhei)7674 void gra_recalcsize(WINDOWFRAME *wf, INTBIG newwid, INTBIG newhei)
7675 {
7676 #ifdef ANYDEPTH
7677 	INTBIG i, j;
7678 	XImage *newimage;
7679 	UCHAR1 *newdataaddr8, **newrowstart, *newdataaddr, **newoffrowstart;
7680 	INTBIG depth, truedepth;
7681 	Visual *visual;
7682 
7683 	/* make sure the height isn't too small for the status bar */
7684 	if (wf->floating && newhei < gra_status_height + 2)
7685 	{
7686 		newhei = gra_status_height + 2;
7687 		ttyputmsg(_("Window too short: made minimum height"));
7688 	}
7689 
7690 	if (newwid != wf->swid || newhei != wf->trueheight)
7691 	{
7692 		/* allocate space for the 8-bit deep buffer */
7693 		newdataaddr8 = (UCHAR1 *)emalloc(newwid * newhei, us_tool->cluster);
7694 		if (newdataaddr8 == 0) return;
7695 		newrowstart = (UCHAR1 **)emalloc(newhei * SIZEOFINTBIG, us_tool->cluster);
7696 		if (newrowstart == 0) return;
7697 		for(i=0; i<newhei; i++)
7698 		{
7699 			newrowstart[i] = newdataaddr8 + i * newwid;
7700 			for(j=0; j<newwid; j++)
7701 				newrowstart[i][j] = 0;
7702 		}
7703 
7704 		/* deallocate old buffers and fill in new */
7705 		efree((CHAR *)wf->dataaddr8);
7706 		efree((CHAR *)wf->rowstart);
7707 		wf->dataaddr8 = newdataaddr8;
7708 		wf->rowstart = newrowstart;
7709 
7710 		/* allocate space for the full-depth buffer */
7711 		if (newwid > wf->wd->wid || newhei > wf->wd->hei)
7712 		{
7713 			gra_getdisplaydepth(wf->topdpy, &depth, &truedepth);
7714 			newdataaddr = (UCHAR1 *)emalloc(newwid * newhei *
7715 				truedepth / 8, us_tool->cluster);
7716 			if (newdataaddr == 0) return;
7717 			newoffrowstart = (UCHAR1 **)emalloc(newhei * SIZEOFINTBIG, us_tool->cluster);
7718 			if (newoffrowstart == 0) return;
7719 			visual = DefaultVisual(wf->topdpy, DefaultScreen(wf->topdpy));
7720 			newimage = XCreateImage(wf->topdpy, visual, truedepth,
7721 				ZPixmap, 0, (CHAR1 *)newdataaddr, newwid, newhei, depth, 0);
7722 			if (newimage == 0)
7723 			{
7724 				efprintf(stderr, _("Error allocating new image array that is %ldx%ld\n"),
7725 					newwid, newhei);
7726 				return;
7727 			}
7728 			for(i=0; i<newhei; i++)
7729 				newoffrowstart[i] = newdataaddr + i * newimage->bytes_per_line;
7730 
7731 			/* deallocate old data and set new */
7732 			efree((CHAR *)wf->wd->addr);
7733 			efree((CHAR *)wf->wd->rowstart);
7734 			XFree(wf->wd->image);
7735 			wf->wd->addr = newdataaddr;
7736 			wf->wd->rowstart = newoffrowstart;
7737 			wf->wd->image = newimage;
7738 			wf->wd->wid = newwid;   wf->wd->hei = newhei;
7739 		}
7740 	}
7741 #else
7742 	XClearWindow(wf->topdpy, wf->win);
7743 #endif
7744 	wf->swid = newwid;
7745 	wf->trueheight = newhei;
7746 	wf->shei = wf->trueheight;
7747 	if (!wf->floating) wf->shei -= gra_status_height;
7748 	wf->revy = wf->shei - 1;
7749 }
7750 
7751 /*
7752  * support routine to print any internal errors
7753  */
gra_xerrors(Display * dpy,XErrorEvent * err)7754 int gra_xerrors(Display *dpy, XErrorEvent *err)
7755 {
7756 	CHAR1 buffer[100];
7757 
7758 	XGetErrorText(dpy, err->error_code, buffer, 100);
7759 	/* buffer is now in the "encoding of the current locale" */
7760 	ttyputerr(_("ERROR: X Window System routine %d has %s"), err->request_code,
7761 		string2byte(buffer));
7762 	return(0);
7763 }
7764 
gra_xterrors(CHAR1 * msg)7765 void gra_xterrors(CHAR1 *msg)
7766 {
7767 	ttyputerr(_("ERROR: X Toolkit: %s"), string2byte(msg));
7768 }
7769 
7770 /* error events */
gra_sigill_trap(void)7771 RETSIGTYPE gra_sigill_trap(void)
7772 {
7773 	(void)signal(SIGILL, (SIGNALCAST)gra_sigill_trap);
7774 	error(_("FATAL ERROR: An illegal instruction has been trapped"));
7775 }
7776 
gra_sigfpe_trap(void)7777 RETSIGTYPE gra_sigfpe_trap(void)
7778 {
7779 	(void)signal(SIGFPE, (SIGNALCAST)gra_sigfpe_trap);
7780 	error(_("FATAL ERROR: A numerical error has occurred"));
7781 }
7782 
gra_sigbus_trap(void)7783 RETSIGTYPE gra_sigbus_trap(void)
7784 {
7785 	(void)signal(SIGBUS, (SIGNALCAST)gra_sigbus_trap);
7786 	error(_("FATAL ERROR: A bus error has occurred"));
7787 }
7788 
gra_sigsegv_trap(void)7789 RETSIGTYPE gra_sigsegv_trap(void)
7790 {
7791 	(void)signal(SIGSEGV, (SIGNALCAST)gra_sigsegv_trap);
7792 	error(_("FATAL ERROR: A segmentation violation has occurred"));
7793 }
7794 
gra_intsignalfunc(void)7795 void gra_intsignalfunc(void)
7796 {
7797 	ttyputerr(_("Interrupted..."));
7798 }
7799 
7800 /*************************** SESSION LOGGING ROUTINES ***************************/
7801 
7802 /* Session Playback */
7803 DIALOGITEM gra_sesplaydialogitems[] =
7804 {
7805  /*  1 */ {0, {100,132,124,212}, BUTTON, N_("Yes")},
7806  /*  2 */ {0, {100,8,124,88}, BUTTON, N_("No")},
7807  /*  3 */ {0, {4,8,20,232}, MESSAGE, N_("Electric has found a session log file")},
7808  /*  4 */ {0, {24,8,40,232}, MESSAGE, N_("which may be from a recent crash.")},
7809  /*  5 */ {0, {52,8,68,232}, MESSAGE, N_("Do you wish to replay this session")},
7810  /*  6 */ {0, {72,8,88,232}, MESSAGE, N_("and reconstruct the lost work?")}
7811 };
7812 DIALOG gra_sesplaydialog = {{75,75,208,316}, N_("Replay Log?"), 0, 6, gra_sesplaydialogitems, 0, 0};
7813 
7814 /* special items for the session playback dialog: */
7815 #define DSPL_YES    1		/* Yes (button) */
7816 #define DSPL_NO     2		/* No (button) */
7817 
7818 /*
7819  * routine to create a session logging file
7820  */
logstartrecord(void)7821 void logstartrecord(void)
7822 {
7823 	REGISTER INTBIG itemhit, count, filestatus;
7824 	REGISTER LIBRARY *lib;
7825 	REGISTER WINDOWFRAME *wf;
7826 	REGISTER WINDOWPART *w;
7827 	REGISTER VARIABLE *var;
7828 	XWindowAttributes xwa;
7829 	REGISTER void *dia;
7830 	CHAR1 srcfile1[300], srcfile2[300];
7831 
7832 	/* if there is already a log file, it may be from a previous crash */
7833 	filestatus = fileexistence(gra_logfile);
7834 	if (filestatus == 1 || filestatus == 3)
7835 	{
7836 		dia = DiaInitDialog(&gra_sesplaydialog);
7837 		if (dia == 0) return;
7838 		for(;;)
7839 		{
7840 			itemhit = DiaNextHit(dia);
7841 			if (itemhit == DSPL_YES || itemhit == DSPL_NO) break;
7842 		}
7843 		DiaDoneDialog(dia);
7844 		if (itemhit == DSPL_YES)
7845 		{
7846 			if (fileexistence(gra_logfilesave) == 1)
7847 				eunlink(gra_logfilesave);
7848 			TRUESTRCPY(srcfile1, string1byte(gra_logfile));
7849 			TRUESTRCPY(srcfile2, string1byte(gra_logfilesave));
7850 			rename(srcfile1, srcfile2);
7851 			(void)logplayback(gra_logfilesave);
7852 		}
7853 	}
7854 
7855 	us_logrecord = xcreate(gra_logfile, us_filetypelog, 0, 0);
7856 	if (us_logrecord == 0) return;
7857 	gra_logbasetime = ticktime();
7858 
7859 	/* document the header */
7860 	xprintf(us_logrecord, x_("; ============= The header:\n"));
7861 	xprintf(us_logrecord, x_("; LC n           Library count\n"));
7862 	xprintf(us_logrecord, x_("; LD name file   Library read from disk\n"));
7863 	xprintf(us_logrecord, x_("; LM name file   Library not read from disk\n"));
7864 	xprintf(us_logrecord, x_("; WO n           Window offset currently 'n'\n"));
7865 	xprintf(us_logrecord, x_("; WT n           Window count\n"));
7866 	xprintf(us_logrecord, x_("; WC n x y w h   Component window, index 'n' at (x,y), size (wXh)\n"));
7867 	xprintf(us_logrecord, x_("; WE n x y w h   Edit window, index 'n' at (x,y), size (wXh)\n"));
7868 	xprintf(us_logrecord, x_("; WP n           Window has 'n' partitions\n"));
7869 	xprintf(us_logrecord, x_("; WB lx hx ly hy slx shx sly shy state cell loc    Window partition (background)\n"));
7870 	xprintf(us_logrecord, x_("; WF lx hx ly hy slx shx sly shy state cell loc    Window partition (foreground)\n"));
7871 	xprintf(us_logrecord, x_("; CI n           Current window index\n"));
7872 	xprintf(us_logrecord, x_("; CT tech        Current technology\n"));
7873 
7874 	/* log current libraries */
7875 	count = 0;
7876 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
7877 		if ((lib->userbits&HIDDENLIBRARY) == 0) count++;
7878 	xprintf(us_logrecord, x_("LC %ld\n"), count);
7879 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
7880 	{
7881 		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
7882 		if ((lib->userbits&READFROMDISK) != 0)
7883 		{
7884 			xprintf(us_logrecord, x_("LD %s %s\n"), lib->libname, lib->libfile);
7885 		} else
7886 		{
7887 			xprintf(us_logrecord, x_("LM %s %s\n"), lib->libname, lib->libfile);
7888 		}
7889 	}
7890 
7891 	/* log current windows */
7892 	xprintf(us_logrecord, x_("WO %ld\n"), gra_windownumber);
7893 	count = 0;
7894 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe) count++;
7895 	xprintf(us_logrecord, x_("WT %ld\n"), count);
7896 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
7897 	{
7898 		gra_getwindowattributes(wf, &xwa);
7899 		xwa.x -= WMLEFTBORDER;
7900 		xwa.y -= WMTOPBORDER;
7901 		xwa.width += 2;
7902 		if (wf->floating != 0)
7903 		{
7904 			xprintf(us_logrecord, x_("WC %ld %ld %ld %ld %ld\n"), wf->windindex, xwa.x, xwa.y,
7905 				xwa.width, xwa.height);
7906 		} else
7907 		{
7908 			xprintf(us_logrecord, x_("WE %ld %ld %ld %ld %ld\n"), wf->windindex, xwa.x, xwa.y,
7909 				xwa.width, xwa.height);
7910 		}
7911 
7912 		count = 0;
7913 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
7914 			if (w->frame == wf) count++;
7915 		xprintf(us_logrecord, x_("WP %ld\n"), count);
7916 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
7917 		{
7918 			if (w->frame != wf) continue;
7919 			if (w == el_curwindowpart)
7920 			{
7921 				xprintf(us_logrecord, x_("WF %ld %ld %ld %ld %ld %ld %ld %ld %ld %s %s\n"),
7922 					w->uselx, w->usehx, w->usely, w->usehy, w->screenlx, w->screenhx,
7923 					w->screenly, w->screenhy, w->state, describenodeproto(w->curnodeproto),
7924 					w->location);
7925 			} else
7926 			{
7927 				xprintf(us_logrecord, x_("WB %ld %ld %ld %ld %ld %ld %ld %ld %ld %s %s\n"),
7928 					w->uselx, w->usehx, w->usely, w->usehy, w->screenlx, w->screenhx,
7929 					w->screenly, w->screenhy, w->state, describenodeproto(w->curnodeproto),
7930 					w->location);
7931 			}
7932 		}
7933 	}
7934 	xprintf(us_logrecord, x_("CI %ld\n"), gra_windownumberindex);
7935 
7936 	/* log current technology (macros store this in %H) */
7937 	var = getval((INTBIG)us_tool, VTOOL, VSTRING, x_("USER_local_caph"));
7938 	if (var != NOVARIABLE)
7939 	{
7940 		/* technology name found in local variable */
7941 		xprintf(us_logrecord, x_("CT %s\n"), (CHAR *)var->addr);
7942 	} else
7943 	{
7944 		/* just write the current technology name */
7945 		xprintf(us_logrecord, x_("CT %s\n"), el_curtech->techname);
7946 	}
7947 
7948 	/* document the body */
7949 	xprintf(us_logrecord, x_("; ============= The body:\n"));
7950 	xprintf(us_logrecord, x_("; KT k x y s w t Key 'k' typed at (x,y), special 's', window 'w', time 't'\n"));
7951 	xprintf(us_logrecord, x_("; BP n x y s w t Button 'n' pressed at (x,y), special 's', window 'w', time 't'\n"));
7952 	xprintf(us_logrecord, x_("; BD n x y s w t Button 'n' double-clicked at (x,y), special 's', window 'w', time 't'\n"));
7953 	xprintf(us_logrecord, x_("; BR n x y s w t Button 'n' released at (x,y), special 's', window 'w', time 't'\n"));
7954 	xprintf(us_logrecord, x_("; MP x y s w     Motion with button pressed at (x,y), special 's', window 'w'\n"));
7955 	xprintf(us_logrecord, x_("; MR x y s w     Motion with button released at (x,y), special 's', window 'w'\n"));
7956 	xprintf(us_logrecord, x_("; ME m i t       Invoked menu 'm', item 'i', time 't'\n"));
7957 	xprintf(us_logrecord, x_("; WS n w h t     Window 'n' grows to (wXh), time 't'\n"));
7958 	xprintf(us_logrecord, x_("; WM n x y t     Window 'n' moves to (x,y), time 't'\n"));
7959 	xprintf(us_logrecord, x_("; FS path        File selected is 'path'\n"));
7960 	xprintf(us_logrecord, x_("; PM v t         Popup menu selected 'v', time 't'\n"));
7961 	xprintf(us_logrecord, x_("; DI w i         Item 'i' of dialog selected\n"));
7962 	xprintf(us_logrecord, x_("; DS w i c vals  Dialog 'w' scroll item 'i' selects 'c' lines in 'values'\n"));
7963 	xprintf(us_logrecord, x_("; DE w i hc s    Dialog 'w' edit item 'i' hit character 'hc', text now 's'\n"));
7964 	xprintf(us_logrecord, x_("; DP w i e       Dialog 'w' popup item 'i' set to entry 'e'\n"));
7965 	xprintf(us_logrecord, x_("; DC w i v       Dialog 'w' item 'i' set to value 'v'\n"));
7966 	xprintf(us_logrecord, x_("; DM w x y       Dialog 'w' coordinates at (x,y)\n"));
7967 	xprintf(us_logrecord, x_("; DD w           Dialog 'w' done\n"));
7968 }
7969 
7970 /*
7971  * routine to begin playback of session logging file "file".  The routine
7972  * returns true if there is an error.  If "all" is nonzero, playback
7973  * the entire file with no prompt.
7974  */
logplayback(CHAR * file)7975 BOOLEAN logplayback(CHAR *file)
7976 {
7977 	CHAR *filename, tempstring[300], *pt, *start;
7978 	BOOLEAN cur, fromdisk;
7979 	BOOLEAN floating;
7980 	REGISTER WINDOWFRAME *wf;
7981 	RECTAREA r;
7982 	REGISTER FILE *saveio;
7983 	REGISTER WINDOWPART *w, *nextw;
7984 	REGISTER INTBIG i, j, wcount, count, wid, hei, uselx, usehx, usely, usehy, sindex;
7985 	REGISTER INTBIG screenlx, screenhx, screenly, screenhy, state;
7986 	REGISTER LIBRARY *lib, *firstlib;
7987 
7988 	us_logplay = xopen(file, us_filetypelog, x_(""), &filename);
7989 	if (us_logplay == NULL) return(TRUE);
7990 	ttyputmsg(_("Playing log file..."));
7991 	ttyputmsg(_("   Move mouse continuously to advance playback"));
7992 	ttyputmsg(_("   Click mouse to abort playback"));
7993 	gra_lastplaybacktime = 0;
7994 
7995 	/* get current libraries */
7996 	(void)gra_logreadline(tempstring, 300);
7997 	if (estrncmp(tempstring, x_("LC"), 2) != 0)
7998 	{
7999 		ttyputerr(_("Log file is corrupt (error %d)"), 1);
8000 		return(TRUE);
8001 	}
8002 	count = eatoi(&tempstring[3]);
8003 	firstlib = NOLIBRARY;
8004 	for(i=0; i<count; i++)
8005 	{
8006 		(void)gra_logreadline(tempstring, 300);
8007 		if (estrncmp(tempstring, x_("LD"), 2) == 0)
8008 		{
8009 			fromdisk = TRUE;
8010 		} else if (estrncmp(tempstring, x_("LM"), 2) == 0)
8011 		{
8012 			fromdisk = FALSE;
8013 		} else
8014 		{
8015 			ttyputerr(_("Log file is corrupt (error %d)"), 2);
8016 			return(TRUE);
8017 		}
8018 		start = &tempstring[3];
8019 		for(pt = start; *pt != 0; pt++) if (*pt == ' ') break;
8020 		if (*pt == 0)
8021 		{
8022 			ttyputerr(_("Log file is corrupt (error %d)"), 3);
8023 			return(TRUE);
8024 		}
8025 		*pt++ = 0;
8026 		lib = getlibrary(start);
8027 		if (lib == NOLIBRARY)
8028 		{
8029 			/* read library file */
8030 			lib = newlibrary(start, pt);
8031 			if (lib == NOLIBRARY) continue;
8032 			if (fromdisk)
8033 			{
8034 				saveio = us_logplay;
8035 				us_logplay = 0;
8036 				(void)asktool(io_tool, x_("read"), (INTBIG)lib, (INTBIG)x_("binary"), 0);
8037 				us_logplay = saveio;
8038 			}
8039 		}
8040 		if (firstlib == NOLIBRARY) firstlib = lib;
8041 	}
8042 	selectlibrary(firstlib, TRUE);
8043 
8044 	/* delete all existing windows */
8045 	for(w = el_topwindowpart; w != NOWINDOWPART; w = nextw)
8046 	{
8047 		nextw = w->nextwindowpart;
8048 		db_retractwindowpart(w);
8049 	}
8050 	el_curwindowpart = NOWINDOWPART;
8051 
8052 	/* get current windows */
8053 	(void)gra_logreadline(tempstring, 300);
8054 	if (estrncmp(tempstring, x_("WO"), 2) != 0)
8055 	{
8056 		ttyputerr(_("Log file is corrupt (error %d)"), 4);
8057 		return(TRUE);
8058 	}
8059 	gra_windownumber = eatoi(&tempstring[3]);
8060 
8061 	/* get current windows */
8062 	(void)gra_logreadline(tempstring, 300);
8063 	if (estrncmp(tempstring, x_("WT"), 2) != 0)
8064 	{
8065 		ttyputerr(_("Log file is corrupt (error %d)"), 5);
8066 		return(TRUE);
8067 	}
8068 	count = eatoi(&tempstring[3]);
8069 
8070 	for(i=0; i<count; i++)
8071 	{
8072 		(void)gra_logreadline(tempstring, 300);
8073 		if (estrncmp(tempstring, x_("WC"), 2) == 0)
8074 		{
8075 			floating = 1;
8076 		} else if (estrncmp(tempstring, x_("WE"), 2) == 0)
8077 		{
8078 			floating = 0;
8079 		} else
8080 		{
8081 			ttyputerr(_("Log file is corrupt (error %d)"), 6);
8082 			return(TRUE);
8083 		}
8084 		pt = &tempstring[3];
8085 		sindex = eatoi(getkeyword(&pt, x_(" ")));
8086 		r.left = eatoi(getkeyword(&pt, x_(" ")));
8087 		r.top = eatoi(getkeyword(&pt, x_(" ")));
8088 		wid = eatoi(getkeyword(&pt, x_(" ")));
8089 		hei = eatoi(getkeyword(&pt, x_(" ")));
8090 		r.right = r.left + (INTSML)wid;
8091 		r.bottom = r.top + (INTSML)hei;
8092 		if (floating)
8093 		{
8094 			/* get the floating window frame */
8095 			for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
8096 				if (wf->floating) break;
8097 			if (wf == NOWINDOWFRAME) wf = newwindowframe(TRUE, &r);
8098 		} else
8099 		{
8100 			/* create a new window frame */
8101 			wf = newwindowframe(FALSE, &r);
8102 		}
8103 		wf->windindex = sindex;
8104 
8105 		(void)gra_logreadline(tempstring, 300);
8106 		if (estrncmp(tempstring, x_("WP"), 2) != 0)
8107 		{
8108 			ttyputerr(_("Log file is corrupt (error %d)"), 7);
8109 			return(TRUE);
8110 		}
8111 		wcount = eatoi(&tempstring[3]);
8112 		for(j=0; j<wcount; j++)
8113 		{
8114 			(void)gra_logreadline(tempstring, 300);
8115 			if (estrncmp(tempstring, x_("WB"), 2) == 0)
8116 			{
8117 				cur = FALSE;
8118 			} else if (estrncmp(tempstring, x_("WF"), 2) == 0)
8119 			{
8120 				cur = TRUE;
8121 			} else
8122 			{
8123 				ttyputerr(_("Log file is corrupt (error %d)"), 8);
8124 				return(TRUE);
8125 			}
8126 			pt = &tempstring[3];
8127 			uselx = eatoi(getkeyword(&pt, x_(" ")));
8128 			usehx = eatoi(getkeyword(&pt, x_(" ")));
8129 			usely = eatoi(getkeyword(&pt, x_(" ")));
8130 			usehy = eatoi(getkeyword(&pt, x_(" ")));
8131 			screenlx = eatoi(getkeyword(&pt, x_(" ")));
8132 			screenhx = eatoi(getkeyword(&pt, x_(" ")));
8133 			screenly = eatoi(getkeyword(&pt, x_(" ")));
8134 			screenhy = eatoi(getkeyword(&pt, x_(" ")));
8135 			state = eatoi(getkeyword(&pt, x_(" ")));
8136 			start = getkeyword(&pt, x_(" "));
8137 			while (*pt != 0 && *pt != ' ') pt++;
8138 			if (*pt == ' ') pt++;
8139 
8140 			w = newwindowpart(pt, NOWINDOWPART);
8141 			w->buttonhandler = DEFAULTBUTTONHANDLER;
8142 			w->charhandler = DEFAULTCHARHANDLER;
8143 			w->changehandler = DEFAULTCHANGEHANDLER;
8144 			w->termhandler = DEFAULTTERMHANDLER;
8145 			w->redisphandler = DEFAULTREDISPHANDLER;
8146 			w->uselx = uselx;   w->usehx = usehx;
8147 			w->usely = usely;   w->usehy = usehy;
8148 			w->screenlx = screenlx;   w->screenhx = screenhx;
8149 			w->screenly = screenly;   w->screenhy = screenhy;
8150 			computewindowscale(w);
8151 			w->state = state;
8152 			w->curnodeproto = getnodeproto(start);
8153 			w->frame = wf;
8154 			if (cur) el_curwindowpart = w;
8155 			us_redisplay(w);
8156 		}
8157 	}
8158 	(void)gra_logreadline(tempstring, 300);
8159 	if (estrncmp(tempstring, x_("CI"), 2) != 0)
8160 	{
8161 		ttyputerr(_("Log file is corrupt (error %d)"), 9);
8162 		return(TRUE);
8163 	}
8164 	gra_windownumberindex = eatoi(&tempstring[3]);
8165 
8166 	/* switch to proper technology */
8167 	(void)gra_logreadline(tempstring, 300);
8168 	if (estrncmp(tempstring, x_("CT"), 2) != 0)
8169 	{
8170 		ttyputerr(_("Log file is corrupt (error %d)"), 10);
8171 		return(TRUE);
8172 	}
8173 	us_ensurepropertechnology(NONODEPROTO, &tempstring[3], TRUE);
8174 
8175 	return(FALSE);
8176 }
8177 
8178 /*
8179  * routine to terminate session logging
8180  */
logfinishrecord(void)8181 void logfinishrecord(void)
8182 {
8183 	CHAR1 srcfile1[300], srcfile2[300];
8184 
8185 	if (us_logrecord != NULL)
8186 	{
8187 		xclose(us_logrecord);
8188 		if (fileexistence(gra_logfilesave) == 1)
8189 			eunlink(gra_logfilesave);
8190 		TRUESTRCPY(srcfile1, string1byte(gra_logfile));
8191 		TRUESTRCPY(srcfile2, string1byte(gra_logfilesave));
8192 		rename(srcfile1, srcfile2);
8193 	}
8194 	us_logrecord = NULL;
8195 }
8196 
8197 /*
8198  * Routine to log an event (if logging) of type "inputstate".
8199  * The event has parameters (cursorx,cursory) and "extradata", depending on "inputstate":
8200  *   WINDOWSIZE:    window "extradata" is now "cursorx" x "cursory"
8201  *   WINDOWMOVE:    window "extradata" is now at (cursorx, cursory)
8202  *   MENUEVENT:     selected menu "cursorx", item "cursory"
8203  *   FILEREPLY:     file selected by standard-file dialog is in "extradata"
8204  *   POPUPSELECT:   popup menu returned "cursorx"
8205  *   DIAITEMCLICK:  dialog "special" item "cursorx" clicked
8206  *   DIASCROLLSEL:  dialog "special" scroll item "cursorx" set to "cursory" entries in "extradata"
8207  *   DIAEDITTEXT:   dialog "special" edit item "cursorx" and changed to "extradata"
8208  *   DIAPOPUPSEL:   dialog "special" popup item "cursorx" set to entry "cursory"
8209  *   DIASETCONTROL: dialog "special" control item "cursorx" changed to "cursory"
8210  *   DIAENDDIALOG:  dialog "special" terminated
8211  *   all others:    cursor in (cursorx,cursory) and window index in "extradata"
8212  */
gra_logwriteaction(INTBIG inputstate,INTBIG special,INTBIG cursorx,INTBIG cursory,void * extradata)8213 void gra_logwriteaction(INTBIG inputstate, INTBIG special, INTBIG cursorx, INTBIG cursory,
8214 	void *extradata)
8215 {
8216 	REGISTER CHAR *filename;
8217 	REGISTER INTBIG i, trueItem;
8218 	REGISTER POPUPMENU *pm;
8219 	REGISTER POPUPMENUITEM *mi;
8220 	REGISTER WINDOWFRAME *wf;
8221 
8222 	if (us_logrecord == NULL) return;
8223 
8224 	/* ignore redundant cursor motion */
8225 	if (inputstate == MOTION || inputstate == (MOTION|BUTTONUP))
8226 	{
8227 		i = (INTBIG)extradata;
8228 		if (inputstate == gra_lastloggedaction && cursorx == gra_lastloggedx &&
8229 			cursory == gra_lastloggedy && i == gra_lastloggedindex)
8230 				return;
8231 	}
8232 	gra_lastloggedaction = inputstate;
8233 	gra_lastloggedx = cursorx;
8234 	gra_lastloggedy = cursory;
8235 	gra_lastloggedindex = (INTBIG)extradata;
8236 
8237 	if ((inputstate&MOTION) != 0)
8238 	{
8239 		if ((inputstate&BUTTONUP) != 0)
8240 		{
8241 			xprintf(us_logrecord, x_("MR %ld %ld %ld %ld\n"),
8242 				cursorx, cursory, special, extradata);
8243 		} else
8244 		{
8245 			xprintf(us_logrecord, x_("MP %ld %ld %ld %ld\n"),
8246 				cursorx, cursory, special, extradata);
8247 		}
8248 	} else if ((inputstate&ISKEYSTROKE) != 0)
8249 	{
8250 		xprintf(us_logrecord, x_("KT '%s' %ld %ld %ld %ld\n"),
8251 			us_describeboundkey(inputstate&CHARREAD, special, 1),
8252 				cursorx, cursory, extradata, ticktime()-gra_logbasetime);
8253 	} else if ((inputstate&ISBUTTON) != 0)
8254 	{
8255 		if ((inputstate&BUTTONUP) != 0)
8256 		{
8257 			xprintf(us_logrecord, x_("BR %ld %ld %ld %ld %ld %ld\n"),
8258 				inputstate&(ISBUTTON|SHIFTISDOWN|METAISDOWN|CONTROLISDOWN),
8259 					cursorx, cursory, special, extradata, ticktime()-gra_logbasetime);
8260 		} else
8261 		{
8262 			if ((inputstate&DOUBLECL) != 0)
8263 			{
8264 				xprintf(us_logrecord, x_("BD %ld %ld %ld %ld %ld %ld\n"),
8265 					inputstate&(ISBUTTON|SHIFTISDOWN|METAISDOWN|CONTROLISDOWN),
8266 						cursorx, cursory, special, extradata, ticktime()-gra_logbasetime);
8267 			} else
8268 			{
8269 				xprintf(us_logrecord, x_("BP %ld %ld %ld %ld %ld %ld\n"),
8270 					inputstate&(ISBUTTON|SHIFTISDOWN|METAISDOWN|CONTROLISDOWN),
8271 						cursorx, cursory, special, extradata, ticktime()-gra_logbasetime);
8272 			}
8273 		}
8274 	} else if (inputstate == MENUEVENT)
8275 	{
8276 		xprintf(us_logrecord, x_("ME %ld %ld %ld"), cursorx, cursory,
8277 			ticktime()-gra_logbasetime);
8278 		for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
8279 			if (!wf->floating) break;
8280 		if (wf != NOWINDOWFRAME && cursorx >= 0 && cursorx < wf->pulldownmenucount)
8281 		{
8282 			pm = us_getpopupmenu(wf->pulldowns[cursorx]);
8283 			if (cursory >= 0 && cursory < pm->total)
8284 			{
8285 				mi = &pm->list[cursory];
8286 				xprintf(us_logrecord, x_("   ; command=%s"),
8287 					us_stripampersand(mi->attribute));
8288 			}
8289 		}
8290 		xprintf(us_logrecord, x_("\n"));
8291 	} else if (inputstate == FILEREPLY)
8292 	{
8293 		filename = (CHAR *)extradata;
8294 		xprintf(us_logrecord, x_("FS %s\n"), filename);
8295 	} else if (inputstate == POPUPSELECT)
8296 	{
8297 		xprintf(us_logrecord, x_("PM %ld %ld\n"), cursorx, ticktime()-gra_logbasetime);
8298 	} else if (inputstate == DIAEDITTEXT)
8299 	{
8300 		filename = (CHAR *)extradata;
8301 		xprintf(us_logrecord, x_("DE %ld %ld %s\n"), special, cursorx, filename);
8302 	} else if (inputstate == DIASCROLLSEL)
8303 	{
8304 		xprintf(us_logrecord, x_("DS %ld %ld %ld"), special, cursorx, cursory);
8305 		for(i=0; i<cursory; i++) xprintf(us_logrecord, x_(" %ld"), ((INTBIG *)extradata)[i]);
8306 		xprintf(us_logrecord, x_("\n"));
8307 	} else if (inputstate == DIAPOPUPSEL)
8308 	{
8309 		xprintf(us_logrecord, x_("DP %ld %ld %ld\n"), special, cursorx, cursory);
8310 	} else if (inputstate == DIASETCONTROL)
8311 	{
8312 		xprintf(us_logrecord, x_("DC %ld %ld %ld\n"), special, cursorx, cursory);
8313 	} else if (inputstate == DIAITEMCLICK)
8314 	{
8315 		xprintf(us_logrecord, x_("DI %ld %ld\n"), special, cursorx);
8316 	} else if (inputstate == DIAUSERMOUSE)
8317 	{
8318 		xprintf(us_logrecord, x_("DM %ld %ld %ld\n"), special, cursorx, cursory);
8319 	} else if (inputstate == DIAENDDIALOG)
8320 	{
8321 		xprintf(us_logrecord, x_("DD %ld\n"), special);
8322 	} else if (inputstate == WINDOWMOVE)
8323 	{
8324 		xprintf(us_logrecord, x_("WM %ld %ld %ld %ld\n"), extradata,
8325 			cursorx, cursory, ticktime()-gra_logbasetime);
8326 	} else if (inputstate == WINDOWSIZE)
8327 	{
8328 		xprintf(us_logrecord, x_("WS %ld %ld %ld %ld\n"), extradata,
8329 			cursorx, cursory, ticktime()-gra_logbasetime);
8330 	} else
8331 	{
8332 		ttyputmsg(x_("Unknown event being logged: %ld"), inputstate);
8333 	}
8334 
8335 	/* flush the log file every so often */
8336 	gra_logrecordcount++;
8337 	if (gra_logrecordcount >= us_logflushfreq)
8338 	{
8339 		gra_logrecordcount = 0;
8340 		xflushbuf(us_logrecord);
8341 	}
8342 }
8343 
gra_logwritecomment(CHAR * comment)8344 void gra_logwritecomment(CHAR *comment)
8345 {
8346 	if (us_logrecord == 0) return;
8347 	xprintf(us_logrecord, x_("; %s\n"), comment);
8348 }
8349 
gra_loggetnextaction(CHAR * message)8350 BOOLEAN gra_loggetnextaction(CHAR *message)
8351 {
8352 	REGISTER BOOLEAN eof;
8353 	CHAR tempstring[300], *pt, *start;
8354 	REGISTER WINDOWFRAME *wf;
8355 	REGISTER TDIALOG *dia;
8356 	INTSML boundkey;
8357 	INTBIG sellist[MAXSCROLLMULTISELECT], i, x, y, item, count;
8358 	UINTBIG nowtime;
8359 
8360 	eof = gra_logreadline(tempstring, 300);
8361 	if (stopping(STOPREASONPLAYBACK)) eof = TRUE;
8362 	if (eof)
8363 	{
8364 		/* stop playback */
8365 		ttyputmsg(_("End of session playback file"));
8366 		xclose(us_logplay);
8367 		us_logplay = NULL;
8368 		return(TRUE);
8369 	}
8370 
8371 	/* load the event structure */
8372 	if (estrncmp(tempstring, x_("WS"), 2) == 0)
8373 	{
8374 		gra_inputstate = NOEVENT;
8375 		pt = &tempstring[3];
8376 		x = eatoi(getkeyword(&pt, x_(" ")));
8377 		y = eatoi(getkeyword(&pt, x_(" ")));
8378 		wf = gra_getframefromindex(eatoi(getkeyword(&pt, x_(" "))));
8379 		nowtime = eatoi(getkeyword(&pt, x_(" ")));
8380 		gra_timeoffset += nowtime - gra_lastplaybacktime;
8381 		gra_lastplaybacktime = nowtime;
8382 		if (wf != NOWINDOWFRAME)
8383 			sizewindowframe(wf, x, y);
8384 		return(FALSE);
8385 	}
8386 	if (estrncmp(tempstring, x_("WM"), 2) == 0)
8387 	{
8388 		gra_inputstate = NOEVENT;
8389 		pt = &tempstring[3];
8390 		x = eatoi(getkeyword(&pt, x_(" ")));
8391 		y = eatoi(getkeyword(&pt, x_(" ")));
8392 		wf = gra_getframefromindex(eatoi(getkeyword(&pt, x_(" "))));
8393 		nowtime = eatoi(getkeyword(&pt, x_(" ")));
8394 		gra_timeoffset += nowtime - gra_lastplaybacktime;
8395 		gra_lastplaybacktime = nowtime;
8396 		if (wf != NOWINDOWFRAME)
8397 			movewindowframe(wf, x, y);
8398 		return(FALSE);
8399 	}
8400 	if (estrncmp(tempstring, x_("DI"), 2) == 0)
8401 	{
8402 		gra_inputstate = NOEVENT;
8403 		pt = &tempstring[3];
8404 		dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
8405 		item = eatoi(getkeyword(&pt, x_(" ")));
8406 		if (dia == NOTDIALOG) return(FALSE);
8407 		if (dia->modelessitemhit == 0)
8408 		{
8409 			/* current modal dialog */
8410 			dia->dialoghit = item;
8411 		} else
8412 		{
8413 			/* a modeless dialog */
8414 			(*dia->modelessitemhit)(dia, item);
8415 		}
8416 		return(FALSE);
8417 	}
8418 	if (estrncmp(tempstring, x_("DS"), 2) == 0)
8419 	{
8420 		gra_inputstate = NOEVENT;
8421 		pt = &tempstring[3];
8422 		dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
8423 		if (dia == NOTDIALOG) return(FALSE);
8424 		item = eatoi(getkeyword(&pt, x_(" ")));
8425 		count = eatoi(getkeyword(&pt, x_(" ")));
8426 		for(i=0; i<count; i++) sellist[i] = eatoi(getkeyword(&pt, x_(" ")));
8427 		if (count == 1)
8428 		{
8429 			DiaSelectLine(dia, item, sellist[0]);
8430 		} else
8431 		{
8432 			DiaSelectLines(dia, item, count, sellist);
8433 		}
8434 		return(FALSE);
8435 	}
8436 	if (estrncmp(tempstring, x_("DP"), 2) == 0)
8437 	{
8438 		gra_inputstate = NOEVENT;
8439 		pt = &tempstring[3];
8440 		dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
8441 		if (dia == NOTDIALOG) return(FALSE);
8442 		item = eatoi(getkeyword(&pt, x_(" ")));
8443 		i = eatoi(getkeyword(&pt, x_(" ")));
8444 		DiaSetPopupEntry(dia, item, i);
8445 		return(FALSE);
8446 	}
8447 	if (estrncmp(tempstring, x_("DC"), 2) == 0)
8448 	{
8449 		gra_inputstate = NOEVENT;
8450 		pt = &tempstring[3];
8451 		dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
8452 		if (dia == NOTDIALOG) return(FALSE);
8453 		item = eatoi(getkeyword(&pt, x_(" ")));
8454 		i = eatoi(getkeyword(&pt, x_(" ")));
8455 		DiaSetControl(dia, item, i);
8456 		return(FALSE);
8457 	}
8458 	if (estrncmp(tempstring, x_("DE"), 2) == 0)
8459 	{
8460 		gra_inputstate = NOEVENT;
8461 		pt = &tempstring[3];
8462 		dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
8463 		if (dia == NOTDIALOG) return(FALSE);
8464 		item = eatoi(getkeyword(&pt, x_(" ")));
8465 		while (*pt != 0 && *pt != ' ') pt++;
8466 		if (*pt == ' ') pt++;
8467 		DiaSetText(dia, item, pt);
8468 		if (dia->modelessitemhit == 0)
8469 		{
8470 			/* current modal dialog */
8471 			dia->dialoghit = item;
8472 		} else
8473 		{
8474 			/* a modeless dialog */
8475 			(*dia->modelessitemhit)(dia, item);
8476 		}
8477 		return(FALSE);
8478 	}
8479 	if (estrncmp(tempstring, x_("DM"), 2) == 0)
8480 	{
8481 		gra_inputstate = DIAUSERMOUSE;
8482 		pt = &tempstring[3];
8483 		dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
8484 		if (dia == NOTDIALOG) return(FALSE);
8485 		gra_action.x = eatoi(getkeyword(&pt, x_(" ")));
8486 		gra_action.y = eatoi(getkeyword(&pt, x_(" ")));
8487 		return(FALSE);
8488 	}
8489 	if (estrncmp(tempstring, x_("DD"), 2) == 0)
8490 	{
8491 		gra_inputstate = DIAENDDIALOG;
8492 		pt = &tempstring[3];
8493 		dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
8494 		return(FALSE);
8495 	}
8496 	if (estrncmp(tempstring, x_("ME"), 2) == 0)
8497 	{
8498 		gra_inputstate = MENUEVENT;
8499 		pt = &tempstring[3];
8500 		gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
8501 		gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
8502 		nowtime = eatoi(getkeyword(&pt, x_(" ")));
8503 		gra_timeoffset += nowtime - gra_lastplaybacktime;
8504 		gra_lastplaybacktime = nowtime;
8505 		return(FALSE);
8506 	}
8507 	if (estrncmp(tempstring, x_("FS"), 2) == 0)
8508 	{
8509 		gra_inputstate = FILEREPLY;
8510 		pt = &tempstring[3];
8511 		if (message != 0) estrcpy(message, pt);
8512 		return(FALSE);
8513 	}
8514 	if (estrncmp(tempstring, x_("PM"), 2) == 0)
8515 	{
8516 		gra_inputstate = POPUPSELECT;
8517 		pt = &tempstring[3];
8518 		gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
8519 		nowtime = eatoi(getkeyword(&pt, x_(" ")));
8520 		gra_timeoffset += nowtime - gra_lastplaybacktime;
8521 		gra_lastplaybacktime = nowtime;
8522 		return(FALSE);
8523 	}
8524 
8525 	if (estrncmp(tempstring, x_("MR"), 2) == 0 || estrncmp(tempstring, x_("MP"), 2) == 0)
8526 	{
8527 		pt = &tempstring[3];
8528 		gra_inputstate = MOTION;
8529 		gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
8530 		gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
8531 		gra_inputspecial = eatoi(getkeyword(&pt, x_(" ")));
8532 		i = eatoi(getkeyword(&pt, x_(" ")));
8533 		if (tempstring[1] == 'R') gra_inputstate |= BUTTONUP;
8534 	} else if (estrncmp(tempstring, x_("KT"), 2) == 0)
8535 	{
8536 		start = &tempstring[4];
8537 		for(i = estrlen(start)-1; i>0; i--)
8538 			if (start[i] == '\'') break;
8539 		if (i <= 0) return(FALSE);
8540 		start[i] = 0;
8541 		pt = &start[i+2];
8542 		(void)us_getboundkey(start, &boundkey, &gra_inputspecial);
8543 		gra_inputstate = ISKEYSTROKE | (boundkey & CHARREAD);
8544 		gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
8545 		gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
8546 		i = eatoi(getkeyword(&pt, x_(" ")));
8547 		nowtime = eatoi(getkeyword(&pt, x_(" ")));
8548 		gra_timeoffset += nowtime - gra_lastplaybacktime;
8549 		gra_lastplaybacktime = nowtime;
8550 	} else if (tempstring[0] == 'B')
8551 	{
8552 		pt = &tempstring[3];
8553 		gra_inputstate = eatoi(getkeyword(&pt, x_(" ")));
8554 		gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
8555 		gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
8556 		gra_inputspecial = eatoi(getkeyword(&pt, x_(" ")));
8557 		i = eatoi(getkeyword(&pt, x_(" ")));
8558 		if (tempstring[1] == 'D') gra_inputstate |= DOUBLECL;
8559 		if (tempstring[1] == 'R') gra_inputstate |= BUTTONUP;
8560 		nowtime = eatoi(getkeyword(&pt, x_(" ")));
8561 		gra_timeoffset += nowtime - gra_lastplaybacktime;
8562 		gra_lastplaybacktime = nowtime;
8563 	}
8564 	wf = gra_getframefromindex(i);
8565 	if (wf != NOWINDOWFRAME && wf != el_curwindowframe)
8566 	{
8567 		XMapRaised(wf->topdpy, wf->topwin);
8568 		(void)gra_getcurrentwindowframe(wf->toplevelwidget, TRUE);
8569 	}
8570 	us_state &= ~GOTXY;
8571 	return(FALSE);
8572 }
8573 
gra_logreadline(CHAR * string,INTBIG limit)8574 BOOLEAN gra_logreadline(CHAR *string, INTBIG limit)
8575 {
8576 	for(;;)
8577 	{
8578 		if (xfgets(string, limit, us_logplay) != 0) return(TRUE);
8579 		if (string[0] != ';') break;
8580 	}
8581 	return(FALSE);
8582 }
8583 
gra_getframefromindex(INTBIG index)8584 WINDOWFRAME *gra_getframefromindex(INTBIG index)
8585 {
8586 	REGISTER WINDOWFRAME *wf;
8587 
8588 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
8589 		if (wf->windindex == index) return(wf);
8590 	return(NOWINDOWFRAME);
8591 }
8592 
gra_getdialogfromindex(INTBIG index)8593 TDIALOG *gra_getdialogfromindex(INTBIG index)
8594 {
8595 	REGISTER TDIALOG *dia;
8596 
8597 	for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
8598 		if (dia->windindex == index) return(dia);
8599 	return(NOTDIALOG);
8600 }
8601 
8602 /****************************** MENUS ******************************/
8603 
getacceleratorstrings(CHAR ** acceleratorstring,CHAR ** acceleratorprefix)8604 void getacceleratorstrings(CHAR **acceleratorstring, CHAR **acceleratorprefix)
8605 {
8606 	*acceleratorstring = x_("Ctrl");
8607 	*acceleratorprefix = x_("Ctrl-");
8608 }
8609 
getinterruptkey(void)8610 CHAR *getinterruptkey(void)
8611 {
8612 	return(_("Control-C in Messages Window"));
8613 }
8614 
nativepopupmenu(POPUPMENU ** menuptr,BOOLEAN header,INTBIG left,INTBIG top)8615 INTBIG nativepopupmenu(POPUPMENU **menuptr, BOOLEAN header, INTBIG left, INTBIG top)
8616 {
8617 	INTBIG retval;
8618 
8619 	retval = gra_nativepopuptif(menuptr, header, left, top);
8620 	gra_logwriteaction(POPUPSELECT, 0, retval, 0, 0);
8621 	return(retval);
8622 }
8623 
gra_nativepopuptif(POPUPMENU ** menuptr,BOOLEAN header,INTBIG left,INTBIG top)8624 INTBIG gra_nativepopuptif(POPUPMENU **menuptr, BOOLEAN header, INTBIG left, INTBIG top)
8625 {
8626 	Widget popmenu, child, submenu, subchild, *submenulist;
8627 	Arg arg[10];
8628 	INTBIG ac, i, j, submenuindex, submenus, columns;
8629 	short hei;
8630 	CHAR msg[200], *pt;
8631 	POPUPMENUITEM *mi, *submi;
8632 	POPUPMENU *menu, **subpmlist;
8633 	REGISTER WINDOWFRAME *wf;
8634 	REGISTER USERCOM *uc;
8635 
8636 	while (us_logplay != NULL)
8637 	{
8638 		if (gra_loggetnextaction(0)) break;
8639 		j = gra_inputstate;
8640 		gra_inputstate = NOEVENT;
8641 		if (j == POPUPSELECT) return(gra_cursorx);
8642 	}
8643 
8644 	menu = *menuptr;
8645 	wf = el_curwindowframe;
8646 	ac = 0;
8647 	XtSetArg(arg[ac], XmNpacking, XmPACK_COLUMN);   ac++;
8648 	popmenu = (Widget)XmCreatePopupMenu(wf->graphicswidget, b_("menu"), arg, ac);
8649 	if (header)
8650 	{
8651 		header = 2;
8652 		child = (Widget)XmCreatePushButton(popmenu, string1byte(menu->header), NULL, 0);
8653 		XtManageChild(child);
8654 		XtAddCallback(child, XmNactivateCallback,
8655 			(XtCallbackProc)gra_menupcb, (XtPointer)-2);
8656 		XtVaCreateManagedWidget(b_("sep"), xmSeparatorWidgetClass, popmenu, NULL);
8657 	}
8658 
8659 	/* count the number of submenus */
8660 	submenus = 0;
8661 	for(j=0; j<menu->total; j++)
8662 	{
8663 		mi = &menu->list[j];
8664 		if (*mi->attribute != 0 && mi->response != NOUSERCOM &&
8665 			mi->response->menu != NOPOPUPMENU) submenus++;
8666 	}
8667 	if (submenus > 0)
8668 	{
8669 		subpmlist = (POPUPMENU **)emalloc(submenus * (sizeof (POPUPMENU *)), us_tool->cluster);
8670 		if (subpmlist == 0) return(-1);
8671 		submenulist = (Widget *)emalloc(submenus * (sizeof (Widget)), us_tool->cluster);
8672 		if (submenulist == 0) return(-1);
8673 	}
8674 
8675 	/* load the menus */
8676 	columns = 1;
8677 	submenus = 0;
8678 	for(j=0; j<menu->total; j++)
8679 	{
8680 		mi = &menu->list[j];
8681 		mi->changed = FALSE;
8682 		if (*mi->attribute == 0)
8683 		{
8684 			XtVaCreateManagedWidget(b_("sep"), xmSeparatorWidgetClass, popmenu, NULL);
8685 		} else
8686 		{
8687 			i = 0;
8688 			for(pt = mi->attribute; *pt != 0; pt++)
8689 				if (*pt != '&') msg[i++] = *pt;
8690 			msg[i] = 0;
8691 
8692 			uc = mi->response;
8693 			if (uc != NOUSERCOM && uc->menu != NOPOPUPMENU)
8694 			{
8695 				submenu = (Widget)XmVaCreateSimplePulldownMenu(popmenu, b_("menu"), j+header,
8696 					(XtCallbackProc)gra_menupcb, NULL);
8697 				if (submenu == 0) return(-1);
8698 				submenulist[submenus] = submenu;
8699 				subpmlist[submenus] = uc->menu;
8700 				submenus++;
8701 				XtSetArg(arg[0], XmNsubMenuId, submenu);
8702 				child = XmCreateCascadeButton(popmenu, string1byte(msg), arg, 1);
8703 				XtManageChild(child);
8704 				for(i=0; i<uc->menu->total; i++)
8705 				{
8706 					submi = &uc->menu->list[i];
8707 					subchild = (Widget)XmCreatePushButton(submenu,
8708 						string1byte(submi->attribute), NULL, 0);
8709 					XtManageChild(subchild);
8710 					XtAddCallback(subchild, XmNactivateCallback,
8711 						(XtCallbackProc)gra_menupcb, (XtPointer)((submenus<<16) | i));
8712 				}
8713 			} else
8714 			{
8715 				child = (Widget)XmCreatePushButton(popmenu, string1byte(msg), NULL, 0);
8716 				XtManageChild(child);
8717 				XtAddCallback(child, XmNactivateCallback,
8718 					(XtCallbackProc)gra_menupcb, (XtPointer)j);
8719 			}
8720 		}
8721 		XtSetArg(arg[0], XtNheight, &hei);
8722 		XtGetValues(popmenu, arg, 1);
8723 		if (hei >= gra_shortestscreen - 50)
8724 		{
8725 			columns++;
8726 			XtSetArg(arg[0], XmNnumColumns, columns);
8727 			XtSetValues(popmenu, arg, 1);
8728 		}
8729 	}
8730 	XtAddCallback(popmenu, XmNunmapCallback,
8731 		(XtCallbackProc)gra_menupcb, (XtPointer)-2);
8732 	XmMenuPosition(popmenu, (XButtonPressedEvent *)&gra_lastbuttonpressevent);
8733 	XtManageChild(popmenu);
8734 
8735 	gra_popupmenuresult = -1;
8736 	gra_inputstate = NOEVENT;
8737 	gra_tracking = TRUE;
8738 	while (gra_popupmenuresult == -1)
8739 	{
8740 		gra_nextevent();
8741 		if (gra_inputstate == NOEVENT) continue;
8742 		if ((gra_inputstate & ISBUTTON) != 0 && (gra_inputstate & BUTTONUP) != 0)
8743 		{
8744 			gra_inputstate = NOEVENT;
8745 			break;
8746 		}
8747 	}
8748 	gra_tracking = FALSE;
8749 	XtDestroyWidget(popmenu);
8750 #if 0
8751 	for(j=0; j<submenus; j++)
8752 		XtDestroyWidget(submenulist[j]);
8753 #endif
8754 	if (gra_popupmenuresult >= 0)
8755 	{
8756 		submenuindex = gra_popupmenuresult >> 16;
8757 		if (submenuindex != 0) *menuptr = subpmlist[submenuindex-1];
8758 	}
8759 	if (submenus > 0)
8760 	{
8761 		efree((CHAR *)submenulist);
8762 		efree((CHAR *)subpmlist);
8763 	}
8764 	if (gra_popupmenuresult < 0) return(-1);
8765 	return(gra_popupmenuresult & 0xFFFF);
8766 }
8767 
gra_nativemenudoone(WINDOWFRAME * wf,INTBIG low,INTBIG high)8768 void gra_nativemenudoone(WINDOWFRAME *wf, INTBIG low, INTBIG high)
8769 {
8770 	gra_addeventtoqueue(MENUEVENT, 0, low, high);
8771 }
8772 
nativemenuload(INTBIG count,CHAR * par[])8773 void nativemenuload(INTBIG count, CHAR *par[])
8774 {
8775 	REGISTER INTBIG i;
8776 	REGISTER WINDOWFRAME *wf;
8777 
8778 	/* remember the top-level pulldown menus */
8779 	for(i=0; i<count; i++)
8780 		gra_pulldowns[i] = us_getpopupmenu(par[i]);
8781 	gra_pulldownmenucount = count;
8782 
8783 	/* build the pulldown menu bar */
8784 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
8785 	{
8786 		if (wf->floating) continue;
8787 
8788 		/* delete any dummy menu created during initialization */
8789 		if (wf->firstmenu != 0)
8790 		{
8791 			XtUnmanageChild(wf->firstmenu);
8792 			XtDestroyWidget(wf->firstmenu);
8793 			wf->firstmenu = 0;
8794 		}
8795 
8796 		/* load menus into this window */
8797 		gra_pulldownmenuload(wf);
8798 	}
8799 }
8800 
gra_pulldownmenuload(WINDOWFRAME * wf)8801 void gra_pulldownmenuload(WINDOWFRAME *wf)
8802 {
8803 	REGISTER INTBIG i, j;
8804 	REGISTER INTBIG keysym;
8805 	CHAR myline[256], *pt;
8806 	CHAR mstring[2];
8807 	REGISTER POPUPMENU *pm;
8808 	Widget thismenu, child;
8809 
8810 	if (gra_pulldownmenucount == 0)
8811 	{
8812 		/* no menus defined yet: make a dummy one */
8813 		wf->firstmenu = XtVaCreateManagedWidget(b_("File"), xmCascadeButtonWidgetClass, wf->menubar, NULL);
8814 		return;
8815 	}
8816 
8817 	/* load full menus */
8818 	mstring[1] = 0;
8819 	for(i=0; i<gra_pulldownmenucount; i++)
8820 	{
8821 		pm = gra_pulldowns[i];
8822 		if (pm == NOPOPUPMENU) continue;
8823 
8824 		/* see if there is a mnemonic */
8825 		mstring[0] = 0;
8826 		pt = myline;
8827 		for(j=0; pm->header[j] != 0; j++)
8828 		{
8829 			if (pm->header[j] == '&') mstring[0] = pm->header[j+1]; else
8830 				*pt++ = pm->header[j];
8831 		}
8832 		*pt = 0;
8833 
8834 		child = XtVaCreateManagedWidget(string1byte(myline),
8835 			xmCascadeButtonWidgetClass, wf->menubar, NULL);
8836 		if (mstring[0] != 0)
8837 		{
8838 			keysym = XStringToKeysym(string1byte(mstring));
8839 			XtVaSetValues(child, XmNmnemonic, keysym, NULL);
8840 		}
8841 		thismenu = XmVaCreateSimplePulldownMenu(wf->menubar, b_("menu"), i,
8842 			(XtCallbackProc)gra_menucb, NULL);
8843 		if (thismenu == 0) return;
8844 		gra_pulldownindex(wf, pm, i, thismenu);
8845 	}
8846 }
8847 
nativemenurename(POPUPMENU * pm,INTBIG pindex)8848 void nativemenurename(POPUPMENU *pm, INTBIG pindex)
8849 {
8850 	INTBIG i, j, len, checked, special;
8851 	INTSML key;
8852 	CHAR line[100], *pt, metaline[50];
8853 	Widget w, *newpulllist;
8854 	WidgetClass wc;
8855 	Arg arg[5];
8856 	REGISTER POPUPMENUITEM *mi;
8857 	REGISTER USERCOM *uc;
8858 	XmString label, acctext;
8859 	REGISTER WINDOWFRAME *wf;
8860 
8861 	/* see if there is a mnemonic */
8862 	pt = line;
8863 	for(j=0; pm->list[pindex].attribute[j] != 0; j++)
8864 	{
8865 		if (pm->list[pindex].attribute[j] != '&')
8866 			*pt++ = pm->list[pindex].attribute[j];
8867 	}
8868 	*pt = 0;
8869 
8870 	/* see if there is a check */
8871 	checked = -1;
8872 	len = estrlen(line) - 1;
8873 	if (len > 0 && line[len] == '<')
8874 	{
8875 		line[len] = 0;
8876 		if (line[0] == '>')
8877 		{
8878 			checked = 1;
8879 			estrcpy(line, &line[1]);
8880 		} else
8881 		{
8882 			checked = 0;
8883 		}
8884 	}
8885 
8886 	/* look for accelerators */
8887 	len = estrlen(line);
8888 	metaline[0] = 0;
8889 	for(pt = line; *pt != 0; pt++) if (*pt == '/' || *pt == '\\') break;
8890 	if (*pt != 0)
8891 	{
8892 		if (pt[1] != 0)
8893 		{
8894 			(void)us_getboundkey(pt, &key, &special);
8895 			estrcpy(metaline, us_describeboundkey(key, special, 1));
8896 		}
8897 		*pt = 0;
8898 	}
8899 
8900 	/* set each window's menu */
8901 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
8902 	{
8903 		if (wf->floating) continue;
8904 		for(i=0; i<wf->pulldownmenucount; i++)
8905 			if (namesame(wf->pulldowns[i], pm->name) == 0) break;
8906 		if (i >= wf->pulldownmenucount) continue;
8907 
8908 		/* resize the menu if appropriate */
8909 		if (pm->total != wf->pulldownmenusize[i])
8910 		{
8911 			/* unmanage all objects in the menu */
8912 			for(j=0; j<wf->pulldownmenusize[i]; j++)
8913 			{
8914 				w = wf->pulldownmenulist[i][j];
8915 				if (w != 0) XtDestroyWidget(w);
8916 			}
8917 			newpulllist = (Widget *)emalloc(pm->total * (sizeof (Widget)),
8918 				us_tool->cluster);
8919 			for(j=0; j<pm->total; j++) newpulllist[j] = 0;
8920 			efree((CHAR *)wf->pulldownmenulist[i]);
8921 			wf->pulldownmenulist[i] = newpulllist;
8922 			wf->pulldownmenusize[i] = pm->total;
8923 		}
8924 
8925 		if (pindex < 0 || pindex >= wf->pulldownmenusize[i]) continue;
8926 		w = wf->pulldownmenulist[i][pindex];
8927 		if (w != 0)
8928 		{
8929 			label = XmStringCreateLocalized(string1byte(line));
8930 			XtSetArg(arg[0], XmNlabelString, label);
8931 			XtSetValues(w, arg, 1);
8932 			XmStringFree(label);
8933 			acctext = XmStringCreateLocalized(string1byte(metaline));
8934 			XtSetArg(arg[0], XmNacceleratorText, acctext);
8935 			XtSetValues(w, arg, 1);
8936 			XmStringFree(acctext);
8937 			if (checked == 0)
8938 			{
8939 				XmToggleButtonSetState(w, False, 0);
8940 			} else if (checked == 1)
8941 			{
8942 				XmToggleButtonSetState(w, True, 0);
8943 			}
8944 			continue;
8945 		}
8946 
8947 		/* must create the entry */
8948 		mi = &pm->list[pindex];
8949 		uc = mi->response;
8950 		if (uc->active < 0)
8951 		{
8952 			if (*mi->attribute == 0)
8953 			{
8954 				wf->pulldownmenulist[i][pindex] = XtVaCreateManagedWidget(b_("sep"), xmSeparatorWidgetClass,
8955 					wf->pulldownmenus[i], NULL);
8956 				continue;
8957 			}
8958 		}
8959 		wf->pulldownmenulist[i][pindex] = (Widget)XmCreatePushButton(wf->pulldownmenus[i],
8960 			string1byte(line), NULL, 0);
8961 		if (*metaline != 0)
8962 		{
8963 			acctext = XmStringCreateLocalized(string1byte(metaline));
8964 			XtVaSetValues(wf->pulldownmenulist[i][pindex], XmNacceleratorText, acctext, NULL);
8965 			XmStringFree(acctext);
8966 		}
8967 		XtManageChild(wf->pulldownmenulist[i][pindex]);
8968 		XtAddCallback(wf->pulldownmenulist[i][pindex], XmNactivateCallback,
8969 			(XtCallbackProc)gra_menucb, (XtPointer)pindex);
8970 	}
8971 }
8972 
8973 /*
8974  * Routine to create a pulldown menu from popup menu "pm".
8975  * Returns an index to the table of pulldown menus (-1 on error).
8976  */
gra_pulldownindex(WINDOWFRAME * wf,POPUPMENU * pm,INTBIG order,Widget parent)8977 void gra_pulldownindex(WINDOWFRAME *wf, POPUPMENU *pm, INTBIG order, Widget parent)
8978 {
8979 	REGISTER INTBIG i, pindex, *newpulldownmenucount;
8980 	Widget *newpulldownmenus, **newpulldownmenulist;
8981 	CHAR **newpulldowns;
8982 
8983 	/* see if it is in the list already */
8984 	for(i=0; i<wf->pulldownmenucount; i++)
8985 		if (namesame(wf->pulldowns[i], pm->name) == 0) return;
8986 
8987 	/* allocate new space with one more */
8988 	newpulldownmenus = (Widget *)emalloc((wf->pulldownmenucount+1) *
8989 		(sizeof (Widget)), us_tool->cluster);
8990 	if (newpulldownmenus == 0) return;
8991 	newpulldowns = (CHAR **)emalloc((wf->pulldownmenucount+1) *
8992 		(sizeof (CHAR *)), us_tool->cluster);
8993 	if (newpulldowns == 0) return;
8994 	newpulldownmenucount = (INTBIG *)emalloc((wf->pulldownmenucount+1) *
8995 		SIZEOFINTBIG, us_tool->cluster);
8996 	if (newpulldownmenucount == 0) return;
8997 	newpulldownmenulist = (Widget **)emalloc((wf->pulldownmenucount+1) *
8998 		(sizeof (Widget *)), us_tool->cluster);
8999 	if (newpulldownmenulist == 0) return;
9000 
9001 	/* copy former arrays then delete them */
9002 	for(i=0; i<wf->pulldownmenucount; i++)
9003 	{
9004 		newpulldownmenus[i] = wf->pulldownmenus[i];
9005 		newpulldowns[i] = wf->pulldowns[i];
9006 		newpulldownmenucount[i] = wf->pulldownmenusize[i];
9007 		newpulldownmenulist[i] = wf->pulldownmenulist[i];
9008 	}
9009 	if (wf->pulldownmenucount != 0)
9010 	{
9011 		efree((CHAR *)wf->pulldownmenus);
9012 		efree((CHAR *)wf->pulldowns);
9013 		efree((CHAR *)wf->pulldownmenusize);
9014 		efree((CHAR *)wf->pulldownmenulist);
9015 	}
9016 	wf->pulldownmenus = newpulldownmenus;
9017 	wf->pulldowns = newpulldowns;
9018 	wf->pulldownmenusize = newpulldownmenucount;
9019 	wf->pulldownmenulist = newpulldownmenulist;
9020 
9021 	pindex = wf->pulldownmenucount++;
9022 	wf->pulldownmenus[pindex] = parent;
9023 	(void)allocstring(&wf->pulldowns[pindex], pm->name, us_tool->cluster);
9024 	wf->pulldownmenusize[pindex] = pm->total;
9025 	wf->pulldownmenulist[pindex] = (Widget *)emalloc(pm->total * (sizeof (Widget)),
9026 		us_tool->cluster);
9027 	if (wf->pulldownmenulist[pindex] == 0) return;
9028 
9029 	gra_makepdmenu(wf, pm, order, parent, pindex);
9030 }
9031 
9032 /*
9033  * Routine to create pulldown menu number "value" from the popup menu in "pm" and return
9034  * the menu handle.
9035  */
gra_makepdmenu(WINDOWFRAME * wf,POPUPMENU * pm,INTBIG value,Widget thismenu,INTBIG pindex)9036 Widget gra_makepdmenu(WINDOWFRAME *wf, POPUPMENU *pm, INTBIG value, Widget thismenu, INTBIG pindex)
9037 {
9038 	REGISTER INTBIG i, j, keysym, checked, haveacc, len;
9039 	CHAR myline[256], metaline[50], *pt;
9040 	CHAR mstring[2];
9041 	REGISTER USERCOM *uc;
9042 	REGISTER POPUPMENUITEM *mi;
9043 	Widget submenu, *childlist;
9044 	INTBIG special;
9045 	INTSML key;
9046 	Arg arg[5];
9047 	XmString acctext;
9048 
9049 	/* build the actual menu */
9050 	childlist = wf->pulldownmenulist[pindex];
9051 	mstring[1] = 0;
9052 	for(i=0; i<pm->total; i++)
9053 	{
9054 		childlist[i] = 0;
9055 		mi = &pm->list[i];
9056 
9057 		/* see if there is a mnemonic */
9058 		mstring[0] = 0;
9059 		pt = myline;
9060 		for(j=0; mi->attribute[j] != 0; j++)
9061 		{
9062 			if (mi->attribute[j] == '&') mstring[0] = mi->attribute[j+1]; else
9063 				*pt++ = mi->attribute[j];
9064 		}
9065 		*pt = 0;
9066 
9067 		uc = mi->response;
9068 		if (uc->active < 0)
9069 		{
9070 			if (*mi->attribute == 0)
9071 			{
9072 				/* separator */
9073 				childlist[i] = XtVaCreateManagedWidget(b_("sep"), xmSeparatorWidgetClass, thismenu, NULL);
9074 			} else
9075 			{
9076 				/* dimmed item (DIM IT!!!) */
9077 				childlist[i] = (Widget)XmCreatePushButton(thismenu, string1byte(myline), NULL, 0);
9078 			}
9079 			continue;
9080 		}
9081 
9082 		/* see if this command is another menu */
9083 		if (uc->menu != NOPOPUPMENU)
9084 		{
9085 			submenu = (Widget)XmVaCreateSimplePulldownMenu(thismenu, b_("menu"), i,
9086 				(XtCallbackProc)gra_menucb, NULL);
9087 			if (submenu == 0) return(0);
9088 			XtVaSetValues(submenu, XmNtearOffModel, XmTEAR_OFF_ENABLED, NULL);
9089 			XtSetArg(arg[0], XmNsubMenuId, submenu);
9090 			childlist[i] = XmCreateCascadeButton(thismenu, string1byte(myline), arg, 1);
9091 			if (mstring[0] != 0)
9092 			{
9093 				keysym = XStringToKeysym(string1byte(mstring));
9094 				XtVaSetValues(childlist[i], XmNmnemonic, keysym, NULL);
9095 			}
9096 			XtManageChild(childlist[i]);
9097 			gra_pulldownindex(wf, uc->menu, i, submenu);
9098 			continue;
9099 		}
9100 
9101 		/* see if there is a check */
9102 		checked = -1;
9103 		len = estrlen(myline) - 1;
9104 		if (myline[len] == '<')
9105 		{
9106 			myline[len] = 0;
9107 			if (myline[0] == '>')
9108 			{
9109 				checked = 1;
9110 				estrcpy(myline, &myline[1]);
9111 			} else
9112 			{
9113 				checked = 0;
9114 			}
9115 		}
9116 
9117 		/* get command title and accelerator */
9118 		len = estrlen(myline);
9119 		haveacc = 0;
9120 		for(pt = myline; *pt != 0; pt++) if (*pt == '/' || *pt == '\\') break;
9121 		if (*pt != 0)
9122 		{
9123 			haveacc = 1;
9124 			(void)us_getboundkey(pt, &key, &special);
9125 			estrcpy(metaline, us_describeboundkey(key, special, 1));
9126 			acctext = XmStringCreateLocalized(string1byte(metaline));
9127 			*pt = 0;
9128 		}
9129 		if (checked == -1)
9130 		{
9131 			childlist[i] = (Widget)XmCreatePushButton(thismenu, string1byte(myline), NULL, 0);
9132 		} else
9133 		{
9134 			childlist[i] = (Widget)XmCreateToggleButton(thismenu, string1byte(myline), NULL, 0);
9135 		}
9136 		if (mstring[0] != 0)
9137 			XtVaSetValues(childlist[i], XmNmnemonic, XStringToKeysym(string1byte(mstring)), NULL);
9138 		XtManageChild(childlist[i]);
9139 		if (checked == 0) XmToggleButtonSetState(childlist[i], False, 0); else
9140 			if (checked == 1) XmToggleButtonSetState(childlist[i], True, 0);
9141 		if (haveacc != 0)
9142 		{
9143 			XtVaSetValues(childlist[i], XmNacceleratorText, acctext, NULL);
9144 			XmStringFree(acctext);
9145 		}
9146 		if (checked == -1)
9147 		{
9148 			XtAddCallback(childlist[i], XmNactivateCallback,
9149 				(XtCallbackProc)gra_menucb, (XtPointer)i);
9150 		} else
9151 		{
9152 			XtAddCallback(childlist[i], XmNvalueChangedCallback,
9153 				(XtCallbackProc)gra_menucb, (XtPointer)i);
9154 		}
9155 	}
9156 	return(thismenu);
9157 }
9158 
gra_menucb(Widget w,int item_number,XtPointer call_data)9159 void gra_menucb(Widget w, int item_number, XtPointer call_data)
9160 {
9161 	Widget parent;
9162 	INTBIG i;
9163 	REGISTER WINDOWFRAME *wf;
9164 
9165 	parent = XtParent(w);
9166 	for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
9167 	{
9168 		if (wf->floating) continue;
9169 
9170 		for(i=0; i<wf->pulldownmenucount; i++)
9171 		{
9172 			if (wf->pulldownmenus[i] != parent) continue;
9173 			gra_nativemenudoone(wf, i, item_number);
9174 			return;
9175 		}
9176 	}
9177 }
9178 
gra_menupcb(Widget w,int item_number,XtPointer call_data)9179 void gra_menupcb(Widget w, int item_number, XtPointer call_data)
9180 {
9181 	gra_popupmenuresult = item_number;
9182 }
9183 
9184 
9185 /****************************** DIALOGS ******************************/
9186 
9187 /*
9188  * Routine to initialize a dialog described by "dialog".
9189  * Returns true if dialog cannot be initialized.
9190  */
DiaInitDialog(DIALOG * dialog)9191 void *DiaInitDialog(DIALOG *dialog)
9192 {
9193 	TDIALOG *dia;
9194 
9195 	dia = (TDIALOG *)emalloc(sizeof (TDIALOG), db_cluster);
9196 	if (dia == 0) return(0);
9197 	if (gra_initdialog(dialog, dia, FALSE)) return(0);
9198 	return(dia);
9199 }
9200 
9201 /*
9202  * Routine to initialize dialog "dialog" in modeless style, calling
9203  * "itemhit" for each hit.
9204  */
DiaInitDialogModeless(DIALOG * dialog,void (* itemhit)(void * dia,INTBIG item))9205 void *DiaInitDialogModeless(DIALOG *dialog, void (*itemhit)(void *dia, INTBIG item))
9206 {
9207 	TDIALOG *dia;
9208 
9209 	dia = (TDIALOG *)emalloc(sizeof (TDIALOG), db_cluster);
9210 	if (dia == 0) return(0);
9211 	if (gra_initdialog(dialog, dia, TRUE)) return(0);
9212 	dia->modelessitemhit = itemhit;
9213 	return(dia);
9214 }
9215 
9216 /* Internal routine to initialize dialog structure "dialog" into "dia" */
gra_initdialog(DIALOG * dialog,TDIALOG * dia,BOOLEAN modeless)9217 BOOLEAN gra_initdialog(DIALOG *dialog, TDIALOG *dia, BOOLEAN modeless)
9218 {
9219 	Widget temp, focus, base, vertscroll;
9220 	Arg arg[20];
9221 	CHAR *title, *line;
9222 	CHAR1 **fontnames;
9223 	INTBIG i, j, amt, itemtype, x, y, wid, hei;
9224 	int ac, direction, asc, desc;
9225 	XmString str;
9226 	Display *dpy;
9227 	static XFontStruct *font;
9228 	static INTBIG founddialogfont = 0;
9229 	XFontStruct **fontstructs;
9230 	XCharStruct xcs;
9231 	Window win;
9232 	Pixmap map;
9233 	String translation;
9234 	XtActionsRec actions;
9235 	XmFontList xfontlist;
9236 	XmFontContext fontContext;
9237 	XmFontListEntry fontListEntry;
9238 	XmFontType fonttype;
9239 	GC gc;
9240 	XGCValues gcv;
9241 	static INTBIG userdrawactionset = 0, listcopyactionset = 0;
9242 	REGISTER void *infstr;
9243 	XColor col;
9244 
9245 	/* add this to the list of active dialogs */
9246 	dia->nexttdialog = gra_firstactivedialog;
9247 	gra_firstactivedialog = dia;
9248 
9249 	/* be sure the dialog is translated */
9250 	DiaTranslate(dialog);
9251 
9252 	/* get the current dialog structure */
9253 	if (el_curwindowpart == NOWINDOWPART) base = gra_msgtoplevelwidget; else
9254 		base = el_curwindowpart->frame->toplevelwidget;
9255 
9256 	dpy = XtDisplay(base);
9257 	gra_dialoggraycol = gra_makedpycolor(dpy, 128, 128, 128);
9258 
9259 	dia->windindex = gra_windownumberindex++;
9260 	dia->numlocks = 0;
9261 	dia->modelessitemhit = 0;
9262 
9263 	/* compute size of some items to automatically scale them */
9264 	if (founddialogfont == 0)
9265 	{
9266 		founddialogfont = 1;
9267 		XtSetArg(arg[0], XmNbuttonFontList, &xfontlist);
9268 		XtGetValues(base, arg, 1);
9269 		XmFontListInitFontContext(&fontContext, xfontlist);
9270 		font = 0;
9271 		for(;;)
9272 		{
9273 			fontListEntry = XmFontListNextEntry(fontContext);
9274 			if (fontListEntry == 0) break;
9275 			font = (XFontStruct *)XmFontListEntryGetFont(fontListEntry, &fonttype);
9276 			if (fonttype == XmFONT_IS_FONT) break;
9277 			i = XFontsOfFontSet((XFontSet)font, &fontstructs, &fontnames);
9278 			if (i > 0)
9279 			{
9280 				font = fontstructs[0];
9281 				break;
9282 			}
9283 			font = 0;
9284 		}
9285 		XmFontListFreeFontContext(fontContext);
9286 	}
9287 	if (font != 0)
9288 	{
9289 #ifdef INTERNATIONAL
9290 		for(i=0; i<dialog->items; i++)
9291 		{
9292 			itemtype = dialog->list[i].type & ITEMTYPE;
9293 			switch (itemtype)
9294 			{
9295 				case DEFBUTTON:
9296 				case BUTTON:
9297 				case CHECK:
9298 				case RADIO:
9299 				case MESSAGE:
9300 					line = dialog->list[i].msg;
9301 					XTextExtents(font, string1byte(line), estrlen(line), &direction, &asc, &desc, &xcs);
9302 					j = xcs.width;
9303 					amt = j - (dialog->list[i].r.right - dialog->list[i].r.left);
9304 					if (amt > 0)
9305 					{
9306 						for(j=0; j<dialog->items; j++)
9307 						{
9308 							if (j == i) continue;
9309 							if (dialog->list[j].r.left >= dialog->list[i].r.right &&
9310 								dialog->list[j].r.left < dialog->list[i].r.right+amt)
9311 							{
9312 								dialog->list[j].r.left += amt;
9313 								dialog->list[j].r.right += amt;
9314 							}
9315 						}
9316 						dialog->list[i].r.right += amt;
9317 					}
9318 					break;
9319 			}
9320 		}
9321 #endif
9322 		for(i=0; i<dialog->items; i++)
9323 		{
9324 			j = dialog->list[i].r.right + 9;
9325 			if (j < dialog->windowRect.right - dialog->windowRect.left) continue;
9326 			dialog->windowRect.right = dialog->windowRect.left + j;
9327 		}
9328 	}
9329 
9330 	/* create the dialog */
9331 	title = dialog->movable;
9332 	if (title == 0 || *title == 0) title = x_(" ");
9333 	gra_getdialogcoordinates(&dialog->windowRect, &x, &y, &wid, &hei);
9334 	ac = 0;
9335 	if (modeless)
9336 	{
9337 		XtSetArg(arg[ac], XmNdialogStyle, XmDIALOG_MODELESS);   ac++;
9338 	} else
9339 	{
9340 		XtSetArg(arg[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);   ac++;
9341 	}
9342 	XtSetArg(arg[ac], XmNx,               x);   ac++;
9343 	XtSetArg(arg[ac], XmNy,               y);   ac++;
9344 	XtSetArg(arg[ac], XmNwidth,           wid);   ac++;
9345 	XtSetArg(arg[ac], XmNheight,          hei);   ac++;
9346 	str = XmStringCreateLocalized(string1byte(title));
9347 	XtSetArg(arg[ac], XmNdialogTitle,     str);   ac++;
9348 	XtSetArg(arg[ac], XmNautoUnmanage,    False);   ac++;
9349 	XtSetArg(arg[ac], XmNmarginWidth,     0);   ac++;
9350 	XtSetArg(arg[ac], XmNmarginHeight,    0);   ac++;
9351 	XtSetArg(arg[ac], XmNallowOverlap,    True);   ac++;
9352 	XtSetArg(arg[ac], XmNresizePolicy,    XmRESIZE_NONE);   ac++;
9353 	XtSetArg(arg[ac], XmNdeleteResponse,  XmDO_NOTHING);   ac++;
9354 	XtSetArg(arg[ac], XmNmwmFunctions,    MWM_FUNC_MOVE);   ac++;
9355 	XtSetArg(arg[ac], XmNdefaultPosition, False);   ac++;
9356 	dia->window = (Widget)XmCreateBulletinBoardDialog(base, b_("dialog"), arg, ac);
9357 	dia->redrawroutine = 0;
9358 	dia->itemdesc = dialog;
9359 	dia->opaqueitem = -1;
9360 	dia->usertextsize = 8;
9361 	dia->inix = dia->iniy = -1;
9362 	XtManageChild(dia->window);
9363 	XtAddEventHandler(dia->window, FocusChangeMask,
9364 		FALSE, gra_dialog_event_handler, NULL);
9365 
9366 	gcv.foreground = 0;
9367 	gra_gcdia = XtGetGC(dia->window, GCForeground, &gcv);
9368 
9369 	/* determine the default button */
9370 	dia->defaultbutton = 1;
9371 	for(i=0; i<dialog->items; i++)
9372 	{
9373 		itemtype = dialog->list[i].type;
9374 		if ((itemtype&ITEMTYPE) == DEFBUTTON)
9375 			dia->defaultbutton = i+1;
9376 	}
9377 
9378 	/* load the items */
9379 	focus = 0;
9380 	for(i=0; i<dialog->items; i++)
9381 	{
9382 		gra_getdialogcoordinates(&dialog->list[i].r, &x, &y, &wid, &hei);
9383 		itemtype = dialog->list[i].type;
9384 		switch (itemtype&ITEMTYPE)
9385 		{
9386 			case RADIO:				/* radio buttons seem too low, so raise them */
9387 				y -= 5;
9388 				break;
9389 			case EDITTEXT:			/* raise text and force it to minimum height */
9390 				y -= 5;
9391 				if (hei < 32) hei = 32;
9392 				break;
9393 			case SCROLL:			/* shrink to make room for vertical scrollbar */
9394 			case SCROLLMULTI:
9395 				wid -= 20;
9396 				break;
9397 			case POPUP:				/* popups seem too low, so raise them */
9398 				y -= 7;
9399 				hei += 7;
9400 				break;
9401 		}
9402 		ac = 0;
9403 		XtSetArg(arg[ac], XmNx, x);   ac++;
9404 		XtSetArg(arg[ac], XmNy, y);   ac++;
9405 		XtSetArg(arg[ac], XmNwidth, wid);   ac++;
9406 		XtSetArg(arg[ac], XmNheight, hei);   ac++;
9407 		switch (itemtype&ITEMTYPE)
9408 		{
9409 			case BUTTON:
9410 			case DEFBUTTON:
9411 				dia->items[i] = (Widget)XmCreatePushButton(dia->window,
9412 					string1byte(dialog->list[i].msg), arg, ac);
9413 				XtManageChild(dia->items[i]);
9414 				XtAddCallback(dia->items[i], XmNactivateCallback,
9415 					(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9416 				break;
9417 			case CHECK:
9418 				XtSetArg(arg[ac], XmNalignment, XmALIGNMENT_BEGINNING);   ac++;
9419 				dia->items[i] = (Widget)XmCreateToggleButton(dia->window,
9420 					dialog->list[i].msg, arg, ac);
9421 				XtManageChild(dia->items[i]);
9422 				XtAddCallback(dia->items[i], XmNvalueChangedCallback,
9423 					(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9424 				break;
9425 			case RADIO:
9426 				temp = (Widget)XmCreateRadioBox(dia->window, b_("radio"), arg, ac);
9427 				XtManageChild(temp);
9428 				dia->items[i] = XtVaCreateManagedWidget(string1byte(dialog->list[i].msg),
9429 					xmToggleButtonGadgetClass, temp, XmNindicatorSize, hei-8, NULL);
9430 				XtAddCallback(dia->items[i], XmNvalueChangedCallback,
9431 					(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9432 				break;
9433 			case EDITTEXT:
9434 				dia->items[i] = (Widget)XmCreateText(dia->window, b_("text"),
9435 					arg, ac);
9436 				XtManageChild(dia->items[i]);
9437 				XtAddCallback(dia->items[i], XmNvalueChangedCallback,
9438 					(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9439 				XtVaGetValues(dia->items[i], XmNbackground, &col, NULL);
9440 				gra_dialogbackgroundcol = col.pixel;
9441 				if (focus == 0) focus = dia->items[i];
9442 				break;
9443 			case MESSAGE:
9444 				XtSetArg(arg[ac], XmNalignment, XmALIGNMENT_BEGINNING);   ac++;
9445 				dia->items[i] = (Widget)XmCreateLabel(dia->window,
9446 					dialog->list[i].msg, arg, ac);
9447 				XtManageChild(dia->items[i]);
9448 				break;
9449 			case PROGRESS:
9450 				dia->items[i] = (Widget)XmCreateDrawingArea(dia->window,
9451 					b_("user"), arg, ac);
9452 				XtManageChild(dia->items[i]);
9453 				break;
9454 			case DIVIDELINE:
9455 				dia->items[i] = (Widget)XmCreateDrawingArea(dia->window,
9456 					b_("user"), arg, ac);
9457 				XtManageChild(dia->items[i]);
9458 				XtAddCallback(dia->items[i], XmNexposeCallback,
9459 					(XtCallbackProc)gra_dialogredrawsep, (XtPointer)i);
9460 				dpy = XtDisplay(dia->items[i]);
9461 				win = XtWindow(dia->items[i]);
9462 				gcv.foreground = BlackPixelOfScreen(XtScreen(dia->items[i]));
9463 				gc = XtGetGC(dia->items[i], GCForeground, &gcv);
9464 				XSetForeground(dpy, gc, BlackPixelOfScreen(XtScreen(dia->items[i])));
9465 				XFillRectangle(dpy, win, gc, 0, 0, wid, hei);
9466 				XtReleaseGC(dia->items[i], gc);
9467 				break;
9468 			case USERDRAWN:
9469 				if (userdrawactionset == 0)
9470 				{
9471 					actions.string = b_("draw");
9472 					actions.proc = (XtActionProc)gra_dialogdraw;
9473 					XtAppAddActions(gra_xtapp, &actions, 1);
9474 					userdrawactionset = 1;
9475 				}
9476 				translation = b_("<BtnDown>: draw(down) ManagerGadgetArm()\n<BtnUp>: draw(up) ManagerGadgetActivate()\n<BtnMotion>: draw(motion) ManagerGadgetButtonMotion()");
9477 				XtSetArg(arg[ac], XmNtranslations, XtParseTranslationTable(translation));   ac++;
9478 				dia->items[i] = (Widget)XmCreateDrawingArea(dia->window,
9479 					b_("user"), arg, ac);
9480 				XtManageChild(dia->items[i]);
9481 				XtAddCallback(dia->items[i], XmNexposeCallback,
9482 					(XtCallbackProc)gra_dialogredraw, (XtPointer)i);
9483 				break;
9484 			case POPUP:
9485 				XtSetArg(arg[ac], XmNresizeWidth, False);   ac++;
9486 				XtSetArg(arg[ac], XmNresizeHeight, False);   ac++;
9487 				dia->items[i] = (Widget)XmCreateOptionMenu(dia->window,
9488 					b_("menu"), arg, ac);
9489 				dialog->list[i].data = 0;
9490 				XtAddCallback(dia->items[i], XmNentryCallback,
9491 					(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9492 				break;
9493 			case ICON:
9494 				map = gra_makeicon((UCHAR1 *)dialog->list[i].msg, dia->window);
9495 				if (map == 0) break;
9496 				if ((itemtype&INACTIVE) != 0)
9497 				{
9498 					/* inactive: make it a label */
9499 					XtSetArg(arg[ac], XmNlabelType, XmPIXMAP);   ac++;
9500 					XtSetArg(arg[ac], XmNlabelPixmap, map);   ac++;
9501 					dia->items[i] = (Widget)XmCreateLabel(dia->window,
9502 						dialog->list[i].msg, arg, ac);
9503 				} else
9504 				{
9505 					/* active: make it a pushbutton */
9506 					XtSetArg(arg[ac], XmNlabelType, XmPIXMAP);   ac++;
9507 					XtSetArg(arg[ac], XmNlabelPixmap, map);   ac++;
9508 					XtSetArg(arg[ac], XmNhighlightThickness, 0);   ac++;
9509 					XtSetArg(arg[ac], XmNshadowThickness, 0);   ac++;
9510 					XtSetArg(arg[ac], XmNborderWidth, 0);   ac++;
9511 					dia->items[i] = (Widget)XmCreatePushButton(dia->window,
9512 						string1byte(dialog->list[i].msg), arg, ac);
9513 					XtManageChild(dia->items[i]);
9514 					XtAddCallback(dia->items[i], XmNactivateCallback,
9515 						(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9516 				}
9517 				XtManageChild(dia->items[i]);
9518 				break;
9519 			case SCROLL:
9520 			case SCROLLMULTI:
9521 				if (listcopyactionset == 0)
9522 				{
9523 					actions.string = b_("copywholelist");
9524 					actions.proc = (XtActionProc)gra_dialogcopywholelist;
9525 					XtAppAddActions(gra_xtapp, &actions, 1);
9526 					listcopyactionset = 1;
9527 				}
9528 				translation = b_("#override <Key>osfCopy: copywholelist()");
9529 				XtSetArg(arg[ac], XmNtranslations, XtParseTranslationTable(translation));   ac++;
9530 				if ((itemtype&ITEMTYPE) == SCROLL)
9531 				{
9532 					XtSetArg(arg[ac], XmNselectionPolicy, XmBROWSE_SELECT);
9533 				} else
9534 				{
9535 					XtSetArg(arg[ac], XmNselectionPolicy, XmEXTENDED_SELECT);
9536 				}
9537 				ac++;
9538 				XtSetArg(arg[ac], XmNresizePolicy, XmRESIZE_NONE);   ac++;
9539 				XtSetArg(arg[ac], XmNlistSizePolicy, XmCONSTANT);   ac++;
9540 				dia->items[i] = (Widget)XmCreateScrolledList(dia->window,
9541 					b_("scroll"), arg, ac);
9542 				XtManageChild(dia->items[i]);
9543 
9544 				/* get the vertical scroll bar out of the widget */
9545 				XtSetArg(arg[0], XmNverticalScrollBar, &vertscroll);
9546 				XtGetValues(dia->items[i], arg, 1);
9547 				XtAddCallback(vertscroll, XmNvalueChangedCallback,
9548 					(XtCallbackProc)gra_vertslider, (XtPointer)i);
9549 				XtAddCallback(vertscroll, XmNdecrementCallback,
9550 					(XtCallbackProc)gra_vertslider, (XtPointer)i);
9551 				XtAddCallback(vertscroll, XmNincrementCallback,
9552 					(XtCallbackProc)gra_vertslider, (XtPointer)i);
9553 				XtAddCallback(vertscroll, XmNpageIncrementCallback,
9554 					(XtCallbackProc)gra_vertslider, (XtPointer)i);
9555 				XtAddCallback(vertscroll, XmNpageDecrementCallback,
9556 					(XtCallbackProc)gra_vertslider, (XtPointer)i);
9557 				XtAddCallback(vertscroll, XmNtoTopCallback,
9558 					(XtCallbackProc)gra_vertslider, (XtPointer)i);
9559 				XtAddCallback(vertscroll, XmNtoBottomCallback,
9560 					(XtCallbackProc)gra_vertslider, (XtPointer)i);
9561 
9562 				if ((itemtype&ITEMTYPE) == SCROLL)
9563 				{
9564 #if 0
9565 					XtAddCallback(dia->items[i], XmNbrowseSelectionCallback,
9566 						(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9567 #endif
9568 				} else
9569 				{
9570 					XtAddCallback(dia->items[i], XmNextendedSelectionCallback,
9571 						(XtCallbackProc)gra_dialogaction, (XtPointer)i);
9572 				}
9573 				break;
9574 			default:
9575 				break;
9576 		}
9577 	}
9578 
9579 	/* set focus to first edit text field */
9580 	if (focus != 0)
9581 	{
9582 		XtSetArg(arg[0], XmNinitialFocus, focus);
9583 		XtSetValues(dia->window, arg, 1);
9584 	}
9585 
9586 	/* set default button if appropriate */
9587 	itemtype = dialog->list[dia->defaultbutton-1].type;
9588 	if ((itemtype&ITEMTYPE) == BUTTON || (itemtype&ITEMTYPE) == DEFBUTTON)
9589 	{
9590 		temp = dia->items[dia->defaultbutton-1];
9591 		if (focus == 0)
9592 		{
9593 			XtSetArg(arg[0], XmNinitialFocus, temp);
9594 			XtSetValues(dia->window, arg, 1);
9595 		}
9596 		XtSetArg(arg[0], XmNdefaultButton, temp);
9597 		XtSetValues(dia->window, arg, 1);
9598 		XtSetArg(arg[0], XmNshowAsDefault, 1);
9599 		XtSetValues(temp, arg, 1);
9600 	}
9601 
9602 	if (*title == 0) title = _("UNTITLED");
9603 	infstr = initinfstr();
9604 	formatinfstr(infstr, _("Start dialog %s"), title);
9605 	gra_logwritecomment(returninfstr(infstr));
9606 	dia->dialoghit = -1;
9607 	gra_flushdialog(dia);
9608 	return(FALSE);
9609 }
9610 
9611 /*
9612  * Routine to handle actions and return the next item hit.
9613  */
DiaNextHit(void * vdia)9614 INTBIG DiaNextHit(void *vdia)
9615 {
9616 	INTBIG item;
9617 	TDIALOG *dia;
9618 
9619 	dia = (TDIALOG *)vdia;
9620 	for(;;)
9621 	{
9622 		gra_nextevent();
9623 		if (dia->dialoghit != -1)
9624 		{
9625 			item = dia->dialoghit;
9626 			dia->dialoghit = -1;
9627 			return(item);
9628 		}
9629 	}
9630 }
9631 
DiaDoneDialog(void * vdia)9632 void DiaDoneDialog(void *vdia)
9633 {
9634 	Arg arg[3];
9635 	INTBIG dx, dy;
9636 	short newx, newy;
9637 	TDIALOG *dia, *ldia, *odia;
9638 
9639 	dia = (TDIALOG *)vdia;
9640 
9641 	/* remove this from the list of active dialogs */
9642 	ldia = NOTDIALOG;
9643 	for(odia = gra_firstactivedialog; odia != NOTDIALOG; odia = odia->nexttdialog)
9644 	{
9645 		if (odia == dia) break;
9646 		ldia = odia;
9647 	}
9648 	if (odia != NOTDIALOG)
9649 	{
9650 		if (ldia == NOTDIALOG) gra_firstactivedialog = dia->nexttdialog; else
9651 			ldia->nexttdialog = dia->nexttdialog;
9652 	}
9653 
9654 	/* if playing back, search for end-dialog marker */
9655 	while (us_logplay != NULL)
9656 	{
9657 		if (gra_loggetnextaction(0)) break;
9658 		if (gra_inputstate == DIAENDDIALOG) break;
9659 		gra_inputstate = NOEVENT;
9660 	}
9661 	gra_inputstate = NOEVENT;
9662 	gra_logwriteaction(DIAENDDIALOG, dia->windindex, 0, 0, 0);
9663 
9664 	/* adjust the dialog position if it was moved */
9665 	if (dia->inix != -1 && dia->iniy != -1)
9666 	{
9667 		XtSetArg(arg[0], XtNx, &newx);
9668 		XtSetArg(arg[1], XtNy, &newy);
9669 		XtGetValues(dia->window, arg, 2);
9670 		dx = (newx - dia->inix) * DIALOGDEN / DIALOGNUM;
9671 		dy = (newy - dia->iniy) * DIALOGDEN / DIALOGNUM;
9672 		dia->itemdesc->windowRect.left += dx;
9673 		dia->itemdesc->windowRect.right += dx;
9674 		dia->itemdesc->windowRect.top += dy;
9675 		dia->itemdesc->windowRect.bottom += dy;
9676 	}
9677 
9678 	XtUnmanageChild(dia->window);
9679 	XtDestroyWidget(dia->window);
9680 
9681 	/* free the "dia" structure */
9682 	efree((CHAR *)dia);
9683 }
9684 
9685 /*
9686  * Routine to change the size of the dialog
9687  */
DiaResizeDialog(void * vdia,INTBIG wid,INTBIG hei)9688 void DiaResizeDialog(void *vdia, INTBIG wid, INTBIG hei)
9689 {
9690 	TDIALOG *dia;
9691 	Widget topwindow;
9692 
9693 	dia = (TDIALOG *)vdia;
9694 	wid = gra_scaledialogcoordinate(wid);
9695 	hei = gra_scaledialogcoordinate(hei);
9696 	topwindow = XtParent(dia->window);
9697 
9698 	XtResizeWidget(topwindow, wid, hei, 0);
9699 	gra_flushdialog(dia);
9700 }
9701 
9702 /*
9703  * Force the dialog to be visible.
9704  */
DiaBringToTop(void * vdia)9705 void DiaBringToTop(void *vdia)
9706 {
9707 	TDIALOG *dia;
9708 
9709 	dia = (TDIALOG *)vdia;
9710 }
9711 
9712 /*
9713  * Routine to set the text in item "item" to "msg"
9714  */
DiaSetText(void * vdia,INTBIG item,CHAR * msg)9715 void DiaSetText(void *vdia, INTBIG item, CHAR *msg)
9716 {
9717 	Arg arg[5];
9718 	INTBIG type, highlight;
9719 	XmString str, s1, s2;
9720 	static XmString separator = 0;
9721 	Widget w;
9722 	INTBIG bigitem, count, i, textwid, x, y, itemwid, itemhei, len;
9723 	int direction, asc, desc;
9724 	XmFontList fontlist;
9725 	XmFontListEntry fontentry;
9726 	XmFontContext fontlistcontext;
9727 	XmFontType entrytype;
9728 	XFontSet fontset;
9729 	XtPointer retval;
9730 	CHAR1 **fontnamelist;
9731 	CHAR *pt;
9732 	XFontStruct **fontstructlist;
9733 	XCharStruct xcs;
9734 	static XFontStruct *theFont = 0;
9735 	TDIALOG *dia;
9736 
9737 	dia = (TDIALOG *)vdia;
9738 	highlight = 0;
9739 	if (item < 0)
9740 	{
9741 		item = -item;
9742 		highlight = 1;
9743 	}
9744 	item--;
9745 	w = dia->items[item];
9746 	type = dia->itemdesc->list[item].type;
9747 	if ((type&ITEMTYPE) == EDITTEXT)
9748 	{
9749 		bigitem = (INTBIG)item;
9750 		XtRemoveCallback(w, XmNvalueChangedCallback,
9751 			(XtCallbackProc)gra_dialogaction, (XtPointer)bigitem);
9752 		XmTextSetString(w, string1byte(msg));
9753 		count = XmTextGetLastPosition(w);
9754 		if (highlight != 0)
9755 		{
9756 			XmTextSetSelection(w, 0, count, 0);
9757 			XtSetArg(arg[0], XmNinitialFocus, w);
9758 			XtSetValues(dia->window, arg, 1);
9759 		} else
9760 		{
9761 			XmTextSetSelection(w, count, count, 0);
9762 			XmTextSetInsertionPosition(w, count);
9763 		}
9764 		XtAddCallback(w, XmNvalueChangedCallback,
9765 			(XtCallbackProc)gra_dialogaction, (XtPointer)bigitem);
9766 	} else
9767 	{
9768 		/* cache the font used to draw messages (once only) */
9769 		if (theFont == 0)
9770 		{
9771 			XtSetArg(arg[0], XmNfontList, &fontlist);
9772 			XtGetValues(w, arg, 1);
9773 			if (XmFontListInitFontContext(&fontlistcontext, fontlist))
9774 			{
9775 				fontentry = XmFontListNextEntry(fontlistcontext);
9776 				if (fontentry != 0)
9777 				{
9778 					retval = XmFontListEntryGetFont(fontentry, &entrytype);
9779 					if (entrytype == XmFONT_IS_FONT)
9780 					{
9781 						theFont = (XFontStruct *)retval;
9782 					} else if (entrytype == XmFONT_IS_FONTSET)
9783 					{
9784 						fontset = (XFontSet)retval;
9785 						count = XFontsOfFontSet(fontset, &fontstructlist, &fontnamelist);
9786 						if (count > 0)
9787 							theFont = fontstructlist[0];
9788 					}
9789 				}
9790 				XmFontListFreeFontContext(fontlistcontext);
9791 			}
9792 		}
9793 
9794 		/* see if the text fits */
9795 		if (theFont == 0) textwid = itemwid = 10; else
9796 		{
9797 			XTextExtents(theFont, string1byte(msg), estrlen(msg), &direction, &asc, &desc, &xcs);
9798 			textwid = xcs.width;
9799 			gra_getdialogcoordinates(&dia->itemdesc->list[item].r, &x, &y, &itemwid, &itemhei);
9800 		}
9801 
9802 		if (textwid <= itemwid) str = XmStringCreateLocalized(string1byte(msg)); else
9803 		{
9804 			/* break up the text */
9805 			len = estrlen(msg)+1;
9806 			if (len > gra_brokenbufsize)
9807 			{
9808 				if (gra_brokenbufsize > 0) efree(gra_brokenbuf);
9809 				gra_brokenbufsize = 0;
9810 				gra_brokenbuf = (CHAR *)emalloc(len*SIZEOFCHAR, us_tool->cluster);
9811 				if (gra_brokenbuf == 0) return;
9812 				gra_brokenbufsize = len;
9813 			}
9814 			if (separator == 0) separator = XmStringSeparatorCreate();
9815 			str = XmStringCreateLocalized(b_(""));
9816 			pt = msg;
9817 			for(;;)
9818 			{
9819 				/* look backwards for blank space that fits */
9820 				for(len = estrlen(pt); len > 0; len--)
9821 				{
9822 					if (pt[len] != ' ' && pt[len] != 0) continue;
9823 					XTextExtents(theFont, string1byte(pt), len, &direction, &asc, &desc, &xcs);
9824 					if (xcs.width <= itemwid) break;
9825 				}
9826 				if (len == 0)
9827 				{
9828 					/* no place to break in blank space: break where possible */
9829 					for(len = estrlen(pt)-1; len > 0; len--)
9830 					{
9831 						XTextExtents(theFont, string1byte(pt), len, &direction, &asc, &desc, &xcs);
9832 						if (xcs.width <= itemwid) break;
9833 					}
9834 				}
9835 
9836 				for(i=0; i<len; i++) gra_brokenbuf[i] = pt[i];
9837 				gra_brokenbuf[len] = 0;
9838 				s1 = XmStringCreateLocalized(string1byte(gra_brokenbuf));
9839 				s2 = XmStringConcat(str, s1);
9840 				XmStringFree(s1);
9841 				XmStringFree(str);
9842 				str = s2;
9843 				if (len == estrlen(pt)) break;
9844 				s2 = XmStringConcat(str, separator);
9845 				XmStringFree(str);
9846 				str = s2;
9847 				pt = &pt[len];
9848 				if (*pt == ' ') pt++;
9849 			}
9850 		}
9851 		XtSetArg(arg[0], XmNlabelString, str);
9852 		XtSetValues(w, arg, 1);
9853 		XmStringFree(str);
9854 	}
9855 	gra_flushdialog(dia);
9856 }
9857 
9858 /*
9859  * Routine to return the text in item "item"
9860  */
DiaGetText(void * vdia,INTBIG item)9861 CHAR *DiaGetText(void *vdia, INTBIG item)
9862 {
9863 	Arg arg;
9864 	INTBIG type;
9865 	XmString str;
9866 	CHAR1 *text;
9867 	CHAR *retstring;
9868 	REGISTER void *infstr;
9869 	XmStringContext context;
9870 	XmStringCharSet tag;
9871 	XmStringDirection direction;
9872 	Boolean separator;
9873 	TDIALOG *dia;
9874 
9875 	dia = (TDIALOG *)vdia;
9876 	item--;
9877 	if (dia->opaqueitem == item)
9878 		return(dia->opaquefield);
9879 
9880 	type = dia->itemdesc->list[item].type;
9881 	if ((type&ITEMTYPE) == EDITTEXT)
9882 	{
9883 #ifdef _UNICODE
9884 		static CHAR retstring[300];
9885 
9886 		estrcpy(retstring, string2byte(XmTextGetString(dia->items[item])));
9887 		return(retstring);
9888 #else
9889 		return(XmTextGetString(dia->items[item]));
9890 #endif
9891 	}
9892 
9893 	if ((type&ITEMTYPE) == MESSAGE)
9894 	{
9895 		XtSetArg(arg, XmNlabelString, &str);
9896 		XtGetValues(dia->items[item], &arg, 1);
9897 		infstr = initinfstr();
9898 		XmStringInitContext(&context, str);
9899 		for(;;)
9900 		{
9901 			if (!XmStringGetNextSegment(context, &text, &tag, &direction, &separator)) break;
9902 			addstringtoinfstr(infstr, string2byte(text));
9903 			XtFree(text);
9904 		}
9905 		XmStringFreeContext(context);
9906 		retstring = returninfstr(infstr);
9907 		return(retstring);
9908 	}
9909 	return(x_(""));
9910 }
9911 
9912 /*
9913  * Routine to set the value in item "item" to "value"
9914  */
DiaSetControl(void * vdia,INTBIG item,INTBIG value)9915 void DiaSetControl(void *vdia, INTBIG item, INTBIG value)
9916 {
9917 	TDIALOG *dia;
9918 
9919 	dia = (TDIALOG *)vdia;
9920 	item--;
9921 	XmToggleButtonSetState(dia->items[item], value, False);
9922 	gra_flushdialog(dia);
9923 	gra_logwriteaction(DIASETCONTROL, dia->windindex, item + 1, value, 0);
9924 }
9925 
9926 /*
9927  * Routine to return the value in item "item"
9928  */
DiaGetControl(void * vdia,INTBIG item)9929 INTBIG DiaGetControl(void *vdia, INTBIG item)
9930 {
9931 	INTBIG value;
9932 	TDIALOG *dia;
9933 
9934 	dia = (TDIALOG *)vdia;
9935 	item--;
9936 	value = XmToggleButtonGetState(dia->items[item]);
9937 	return(value);
9938 }
9939 
9940 /*
9941  * Routine to check item "item" to make sure that there is
9942  * text in it.  If so, it returns true.  Otherwise it beeps and returns false.
9943  */
DiaValidEntry(void * vdia,INTBIG item)9944 BOOLEAN DiaValidEntry(void *vdia, INTBIG item)
9945 {
9946 	CHAR *msg;
9947 	TDIALOG *dia;
9948 
9949 	dia = (TDIALOG *)vdia;
9950 	msg = DiaGetText(dia, item);
9951 	while (*msg == ' ' || *msg == '\t') msg++;
9952 	if (*msg != 0) return(TRUE);
9953 	ttybeep(SOUNDBEEP, TRUE);
9954 	return(FALSE);
9955 }
9956 
9957 /*
9958  * Routine to dim item "item"
9959  */
DiaDimItem(void * vdia,INTBIG item)9960 void DiaDimItem(void *vdia, INTBIG item)
9961 {
9962 	REGISTER INTBIG type;
9963 	Arg arg[2];
9964 	TDIALOG *dia;
9965 
9966 	dia = (TDIALOG *)vdia;
9967 	item--;
9968 	type = dia->itemdesc->list[item].type;
9969 	if ((type&ITEMTYPE) == EDITTEXT)
9970 	{
9971 		DiaNoEditControl(dia, item+1);
9972 		XtSetArg(arg[0], XtNbackground, gra_dialoggraycol);
9973 		XtSetValues(dia->items[item], arg, 1);
9974 	} else
9975 		XtSetSensitive(dia->items[item], False);
9976 	gra_flushdialog(dia);
9977 }
9978 
9979 /*
9980  * Routine to un-dim item "item"
9981  */
DiaUnDimItem(void * vdia,INTBIG item)9982 void DiaUnDimItem(void *vdia, INTBIG item)
9983 {
9984 	REGISTER INTBIG type;
9985 	Arg arg[2];
9986 	TDIALOG *dia;
9987 
9988 	dia = (TDIALOG *)vdia;
9989 	item--;
9990 	type = dia->itemdesc->list[item].type;
9991 	if ((type&ITEMTYPE) == EDITTEXT)
9992 	{
9993 		DiaEditControl(dia, item+1);
9994 		XtSetArg(arg[0], XtNbackground, gra_dialogbackgroundcol);
9995 		XtSetValues(dia->items[item], arg, 1);
9996 	} else
9997 		XtSetSensitive(dia->items[item], True);
9998 	gra_flushdialog(dia);
9999 }
10000 
10001 /*
10002  * Routine to change item "item" to be a message rather
10003  * than editable text
10004  */
DiaNoEditControl(void * vdia,INTBIG item)10005 void DiaNoEditControl(void *vdia, INTBIG item)
10006 {
10007 	Widget w;
10008 	Arg arg;
10009 	TDIALOG *dia;
10010 
10011 	dia = (TDIALOG *)vdia;
10012 	item--;
10013 	w = dia->items[item];
10014 	XtSetArg(arg, XmNeditable, False);
10015 	XtSetValues(w, &arg, 1);
10016 }
10017 
10018 /*
10019  * Routine to change item "item" to be editable text rather
10020  * than a message
10021  */
DiaEditControl(void * vdia,INTBIG item)10022 void DiaEditControl(void *vdia, INTBIG item)
10023 {
10024 	Widget w;
10025 	Arg arg;
10026 	TDIALOG *dia;
10027 
10028 	dia = (TDIALOG *)vdia;
10029 	item--;
10030 	w = dia->items[item];
10031 	XtSetArg(arg, XmNeditable, True);
10032 	XtSetValues(w, &arg, 1);
10033 }
10034 
DiaOpaqueEdit(void * vdia,INTBIG item)10035 void DiaOpaqueEdit(void *vdia, INTBIG item)
10036 {
10037 	Widget w;
10038 	TDIALOG *dia;
10039 
10040 	dia = (TDIALOG *)vdia;
10041 	item--;
10042 	dia->opaqueitem = item;
10043 
10044 	w = dia->items[item];
10045 	dia->opaquefield[0] = 0;
10046 	XtAddCallback(w, XmNmodifyVerifyCallback, (XtCallbackProc)gra_dialogopaqueaction, 0);
10047 }
10048 
10049 /*
10050  * Routine to cause item "item" to be the default button
10051  */
DiaDefaultButton(void * vdia,INTBIG item)10052 void DiaDefaultButton(void *vdia, INTBIG item)
10053 {
10054 	Widget newdef, olddef;
10055 	Arg arg[2];
10056 	TDIALOG *dia;
10057 
10058 	dia = (TDIALOG *)vdia;
10059 	if (item == dia->defaultbutton) return;
10060 	olddef = dia->items[dia->defaultbutton-1];
10061 	newdef = dia->items[item-1];
10062 	dia->defaultbutton = item;
10063 
10064 	XtSetArg(arg[0], XmNdefaultButton, newdef);
10065 	XtSetValues(dia->window, arg, 1);
10066 	XtSetArg(arg[0], XmNshowAsDefault, 0);
10067 	XtSetValues(olddef, arg, 1);
10068 	XtSetArg(arg[0], XmNshowAsDefault, 1);
10069 	XtSetValues(newdef, arg, 1);
10070 }
10071 
10072 /*
10073  * Routine to change the icon in item "item" to be the 32x32 bitmap (128 bytes) at "addr".
10074  */
DiaChangeIcon(void * vdia,INTBIG item,UCHAR1 * addr)10075 void DiaChangeIcon(void *vdia, INTBIG item, UCHAR1 *addr)
10076 {
10077 	Widget w;
10078 	Pixmap map;
10079 	Arg arg;
10080 	TDIALOG *dia;
10081 
10082 	dia = (TDIALOG *)vdia;
10083 	item--;
10084 	w = dia->items[item];
10085 	map = gra_makeicon(addr, dia->window);
10086 	if (map == 0) return;
10087 	XtSetArg(arg, XmNlabelPixmap, map);
10088 	XtSetValues(w, &arg, 1);
10089 }
10090 
10091 /*
10092  * Routine to change item "item" into a popup with "count" entries
10093  * in "names".
10094  */
DiaSetPopup(void * vdia,INTBIG item,INTBIG count,CHAR ** names)10095 void DiaSetPopup(void *vdia, INTBIG item, INTBIG count, CHAR **names)
10096 {
10097 	Widget child, menu;
10098 	Arg arg[3];
10099 	INTBIG i, x, y, wid, hei, columns, entriespercolumn;
10100 	short entryheight;
10101 	TDIALOG *dia;
10102 
10103 	dia = (TDIALOG *)vdia;
10104 	item--;
10105 	gra_getdialogcoordinates(&dia->itemdesc->list[item].r, &x, &y, &wid, &hei);
10106 	XtSetArg(arg[0], XmNpacking, XmPACK_COLUMN);
10107 	menu = (Widget)XmCreatePulldownMenu(dia->window, b_("menu"), arg, 1);
10108 	if (count == 0)
10109 	{
10110 		child = (Widget)XmCreatePushButton(menu, b_(""), NULL, 0);
10111 		XtManageChild(child);
10112 	}
10113 	for(i=0; i<count; i++)
10114 	{
10115 		XtSetArg(arg[0], XmNwidth, wid);
10116 		child = (Widget)XmCreatePushButton(menu, string1byte(names[i]), arg, 1);
10117 		XtManageChild(child);
10118 		XtAddCallback(child, XmNactivateCallback,
10119 			(XtCallbackProc)gra_dialogaction, (XtPointer)item);
10120 
10121 		/* adjust the number of columns if necessary */
10122 		if (i == 0)
10123 		{
10124 			XtSetArg(arg[0], XtNheight, &entryheight);
10125 			XtGetValues(menu, arg, 1);
10126 			entriespercolumn = gra_shortestscreen / entryheight;
10127 			columns = (count + entriespercolumn-1) / entriespercolumn;
10128 			if (columns > 1)
10129 			{
10130 				XtSetArg(arg[0], XmNnumColumns, columns);
10131 				XtSetValues(menu, arg, 1);
10132 			}
10133 		}
10134 	}
10135 	XtSetArg(arg[0], XmNsubMenuId, menu);
10136 	XtSetValues(dia->items[item], arg, 1);
10137 
10138 	if (dia->itemdesc->list[item].data == 0)
10139 	{
10140 		dia->itemdesc->list[item].data = 1;
10141 		XtManageChild(dia->items[item]);
10142 	}
10143 
10144 	/* force the width of the popup */
10145 	XtSetArg(arg[0], XmNwidth, wid);
10146 	XtSetValues(dia->items[item], arg, 1);
10147 	gra_flushdialog(dia);
10148 }
10149 
10150 /*
10151  * Routine to change popup item "item" so that the current entry is "entry".
10152  */
DiaSetPopupEntry(void * vdia,INTBIG item,INTBIG entry)10153 void DiaSetPopupEntry(void *vdia, INTBIG item, INTBIG entry)
10154 {
10155 	Widget w, child, *kids;
10156 	Arg arg[1];
10157 	TDIALOG *dia;
10158 
10159 	dia = (TDIALOG *)vdia;
10160 	item--;
10161 	w = dia->items[item];
10162 	XtVaGetValues(w, XmNsubMenuId, &child, NULL);
10163 	XtVaGetValues(child, XmNchildren, &kids, NULL);
10164 	XtSetArg(arg[0], XmNmenuHistory, kids[entry]);
10165 	XtSetValues(w, arg, 1);
10166 	gra_flushdialog(dia);
10167 }
10168 
10169 /*
10170  * Routine to return the current item in popup menu item "item".
10171  */
DiaGetPopupEntry(void * vdia,INTBIG item)10172 INTBIG DiaGetPopupEntry(void *vdia, INTBIG item)
10173 {
10174 	Widget w, child, *kids, kid;
10175 	INTBIG numkids, i;
10176 	TDIALOG *dia;
10177 
10178 	dia = (TDIALOG *)vdia;
10179 	item--;
10180 	w = dia->items[item];
10181 	XtVaGetValues(w, XmNsubMenuId, &child, NULL);
10182 	XtVaGetValues(child, XmNchildren, &kids, NULL);
10183 	XtVaGetValues(child, XmNnumChildren, &numkids, NULL);
10184 	XtVaGetValues(w, XmNmenuHistory, &kid, NULL);
10185 	for(i=0; i<numkids; i++)
10186 		if (kids[i] == kid) break;
10187 	return(i);
10188 }
10189 
DiaInitTextDialog(void * vdia,INTBIG item,BOOLEAN (* toplist)(CHAR **),CHAR * (* nextinlist)(void),void (* donelist)(void),INTBIG sortpos,INTBIG flags)10190 void DiaInitTextDialog(void *vdia, INTBIG item, BOOLEAN (*toplist)(CHAR **), CHAR *(*nextinlist)(void),
10191 	void (*donelist)(void), INTBIG sortpos, INTBIG flags)
10192 {
10193 	Widget w;
10194 	INTBIG bigitem, lines, fontheight;
10195 	Arg arg[2];
10196 	Display *dpy;
10197 	XmFontListEntry entry;
10198 	static XmFontList fontlist;
10199 	static INTBIG havefontlist = 0;
10200 	RECTAREA r;
10201 	TDIALOG *dia;
10202 
10203 	dia = (TDIALOG *)vdia;
10204 	item--;
10205 	w = dia->items[item];
10206 	if ((flags&SCDOUBLEQUIT) != 0)
10207 	{
10208 		XtAddCallback(w, XmNdefaultActionCallback,
10209 			(XtCallbackProc)gra_dialogaction, (XtPointer)0);
10210 	}
10211 	if ((flags&SCREPORT) != 0)
10212 	{
10213 		bigitem = (INTBIG)item;
10214 		XtAddCallback(w, XmNbrowseSelectionCallback,
10215 			(XtCallbackProc)gra_dialogaction, (XtPointer)bigitem);
10216 	}
10217 	if ((flags&SCFIXEDWIDTH) != 0)
10218 	{
10219 		if (havefontlist == 0)
10220 		{
10221 			dpy = XtDisplay(w);
10222 			entry = XmFontListEntryLoad(dpy, string1byte(gra_font[11].fontname),
10223 				XmFONT_IS_FONT, b_("TAG"));
10224 			fontlist = XmFontListAppendEntry(NULL, entry);
10225 			XmFontListEntryFree(&entry);
10226 			havefontlist = 1;
10227 		}
10228 		XtSetArg(arg[0], XmNfontList, fontlist);
10229 		fontheight = gra_font[11].font->ascent + gra_font[11].font->descent;
10230 		r = dia->itemdesc->list[item].r;
10231 		lines = (r.bottom - r.top) / fontheight;
10232 		XtSetArg(arg[1], XmNvisibleItemCount, lines);
10233 		XtSetValues(w, arg, 2);
10234 	}
10235 	gra_flushdialog(dia);
10236 	DiaLoadTextDialog(dia, item+1, toplist, nextinlist, donelist, sortpos);
10237 }
10238 
DiaLoadTextDialog(void * vdia,INTBIG item,BOOLEAN (* toplist)(CHAR **),CHAR * (* nextinlist)(void),void (* donelist)(void),INTBIG sortpos)10239 void DiaLoadTextDialog(void *vdia, INTBIG item, BOOLEAN (*toplist)(CHAR **), CHAR *(*nextinlist)(void),
10240 	void (*donelist)(void), INTBIG sortpos)
10241 {
10242 	Widget w;
10243 	INTBIG i, items;
10244 	CHAR *next, **list, line[256];
10245 	XmString str;
10246 	TDIALOG *dia;
10247 
10248 	dia = (TDIALOG *)vdia;
10249 	item--;
10250 	w = dia->items[item];
10251 
10252 	/* clear the list */
10253 	XmListDeleteAllItems(w);
10254 
10255 	if (sortpos < 0)
10256 	{
10257 		/* unsorted: load the list directly */
10258 		line[0] = 0;
10259 		next = line;
10260 		(void)(*toplist)(&next);
10261 		for(items=0; ; items++)
10262 		{
10263 			next = (*nextinlist)();
10264 			if (next == 0) break;
10265 			str = XmStringCreateLocalized(string1byte(next));
10266 			XmListAddItemUnselected(w, str, 0);
10267 			XmStringFree(str);
10268 		}
10269 		(*donelist)();
10270 	} else
10271 	{
10272 		/* count the number of items to be put in the text editor */
10273 		line[0] = 0;
10274 		next = line;
10275 		(void)(*toplist)(&next);
10276 		for(items=0; ; items++) if ((*nextinlist)() == 0) break;
10277 		(*donelist)();
10278 
10279 		/* allocate space for the strings */
10280 		if (items > 0)
10281 		{
10282 			list = (CHAR **)emalloc(items * (sizeof (CHAR *)), el_tempcluster);
10283 			if (list == 0) return;
10284 		}
10285 
10286 		/* get the list */
10287 		line[0] = 0;
10288 		next = line;
10289 		(void)(*toplist)(&next);
10290 		for(i=0; i<items; i++)
10291 		{
10292 			next = (*nextinlist)();
10293 			if (next == 0) next = x_("???");
10294 			list[i] = (CHAR *)emalloc((estrlen(next)+1) * SIZEOFCHAR, el_tempcluster);
10295 			if (list[i] == 0) return;
10296 			estrcpy(list[i], next);
10297 		}
10298 		(*donelist)();
10299 
10300 		/* sort the list */
10301 		gra_dialogstringpos = sortpos;
10302 		esort(list, items, sizeof (CHAR *), gra_stringposascending);
10303 
10304 		/* stuff the list into the text editor */
10305 		for(i=0; i<items; i++)
10306 		{
10307 			str = XmStringCreateLocalized(string1byte(list[i]));
10308 			XmListAddItemUnselected(w, str, 0);
10309 			XmStringFree(str);
10310 		}
10311 
10312 		/* deallocate the list */
10313 		if (items > 0)
10314 		{
10315 			for(i=0; i<items; i++) efree((CHAR *)list[i]);
10316 			efree((CHAR *)(CHAR *)list);
10317 		}
10318 	}
10319 	if (items > 0) XmListSelectPos(w, 1, False);
10320 	gra_flushdialog(dia);
10321 }
10322 
10323 /*
10324  * Routine to stuff line "line" at the end of the edit buffer.
10325  */
DiaStuffLine(void * vdia,INTBIG item,CHAR * line)10326 void DiaStuffLine(void *vdia, INTBIG item, CHAR *line)
10327 {
10328 	Widget w;
10329 	XmString str;
10330 	TDIALOG *dia;
10331 
10332 	dia = (TDIALOG *)vdia;
10333 	item--;
10334 	w = dia->items[item];
10335 	str = XmStringCreateLocalized(string1byte(line));
10336 	XmListAddItemUnselected(w, str, 0);
10337 	XmStringFree(str);
10338 	gra_flushdialog(dia);
10339 }
10340 
10341 /*
10342  * Routine to select line "line" of scroll item "item".
10343  */
DiaSelectLine(void * vdia,INTBIG item,INTBIG line)10344 void DiaSelectLine(void *vdia, INTBIG item, INTBIG line)
10345 {
10346 	Widget w;
10347 	INTBIG first, visible;
10348 	Arg arg[2];
10349 	TDIALOG *dia;
10350 
10351 	dia = (TDIALOG *)vdia;
10352 	item--;
10353 	w = dia->items[item];
10354 	if (line < 0) XmListDeselectAllItems(w); else
10355 	{
10356 		line++;
10357 		XmListSelectPos(w, line, False);
10358 		XtSetArg(arg[0], XmNtopItemPosition, &first);
10359 		XtSetArg(arg[1], XmNvisibleItemCount, &visible);
10360 		XtGetValues(w, arg, 2);
10361 		if (line < first || line >= first+visible)
10362 		{
10363 			first = line - visible/2;
10364 			if (first < 1) first = 1;
10365 			XmListSetPos(w, first);
10366 		}
10367 	}
10368 	gra_flushdialog(dia);
10369 }
10370 
10371 /*
10372  * Routine to select "count" lines in "lines" of scroll item "item".
10373  */
DiaSelectLines(void * vdia,INTBIG item,INTBIG count,INTBIG * lines)10374 void DiaSelectLines(void *vdia, INTBIG item, INTBIG count, INTBIG *lines)
10375 {
10376 	Widget w;
10377 	INTBIG first, visible, i, low, high, line;
10378 	Arg arg[2];
10379 	TDIALOG *dia;
10380 
10381 	dia = (TDIALOG *)vdia;
10382 	item--;
10383 	w = dia->items[item];
10384 	XmListDeselectAllItems(w);
10385 
10386 	/* temporarily set the selection policy to "multiple" to enable multiple select */
10387 	XtSetArg(arg[0], XmNselectionPolicy, XmMULTIPLE_SELECT);
10388 	XtSetValues(w, arg, 1);
10389 
10390 	/* make the selections */
10391 	for(i=0; i<count; i++)
10392 	{
10393 		line = lines[i] + 1;
10394 		XmListSelectPos(w, line, False);
10395 		if (i == 0) low = high = line; else
10396 		{
10397 			if (line < low) low = line;
10398 			if (line > high) high = line;
10399 		}
10400 	}
10401 
10402 	/* make sure lines are visible */
10403 	XtSetArg(arg[0], XmNtopItemPosition, &first);
10404 	XtSetArg(arg[1], XmNvisibleItemCount, &visible);
10405 	XtGetValues(w, arg, 2);
10406 	if (high < first || low >= first+visible)
10407 	{
10408 		first = low;
10409 		XmListSetPos(w, first);
10410 	}
10411 
10412 	/* restore the selection policy to "extended" */
10413 	XtSetArg(arg[0], XmNselectionPolicy, XmEXTENDED_SELECT);
10414 	XtSetValues(w, arg, 1);
10415 	gra_flushdialog(dia);
10416 }
10417 
10418 /*
10419  * Returns the currently selected line in the scroll list "item".
10420  */
DiaGetCurLine(void * vdia,INTBIG item)10421 INTBIG DiaGetCurLine(void *vdia, INTBIG item)
10422 {
10423 	Widget w;
10424 	INTBIG selected;
10425 	int count, *pos;   /* must be "int", and not "INTBIG" to work on Alpha */
10426 	TDIALOG *dia;
10427 
10428 	dia = (TDIALOG *)vdia;
10429 	item--;
10430 	w = dia->items[item];
10431 	selected = -1;
10432 	if (XmListGetSelectedPos(w, &pos, &count))
10433 	{
10434 		if (count >= 1) selected = pos[0]-1;
10435 		XtFree((char*)pos);
10436 	}
10437 	return(selected);
10438 }
10439 
10440 /*
10441  * Returns the currently selected lines in the scroll list "item".  The returned
10442  * array is terminated with -1.
10443  */
DiaGetCurLines(void * vdia,INTBIG item)10444 INTBIG *DiaGetCurLines(void *vdia, INTBIG item)
10445 {
10446 	Widget w;
10447 	static INTBIG selected[MAXSCROLLMULTISELECT];
10448 	REGISTER INTBIG i;
10449 	int count, *pos;   /* must be "int", and not "INTBIG" to work on Alpha */
10450 	TDIALOG *dia;
10451 
10452 	dia = (TDIALOG *)vdia;
10453 	item--;
10454 	w = dia->items[item];
10455 	selected[0] = -1;
10456 	if (XmListGetSelectedPos(w, &pos, &count))
10457 	{
10458 		for(i=0; i<count; i++)
10459 			selected[i] = pos[i] - 1;
10460 		selected[count] = -1;
10461 		XtFree((char *)pos);
10462 	}
10463 	return(selected);
10464 }
10465 
DiaGetNumScrollLines(void * vdia,INTBIG item)10466 INTBIG DiaGetNumScrollLines(void *vdia, INTBIG item)
10467 {
10468 	Widget w;
10469 	INTBIG count;
10470 	TDIALOG *dia;
10471 
10472 	dia = (TDIALOG *)vdia;
10473 	item--;
10474 	w = dia->items[item];
10475 	XtVaGetValues(w, XmNitemCount, &count, NULL);
10476 	return(count);
10477 }
10478 
DiaGetScrollLine(void * vdia,INTBIG item,INTBIG line)10479 CHAR *DiaGetScrollLine(void *vdia, INTBIG item, INTBIG line)
10480 {
10481 	Widget w;
10482 	INTBIG count;
10483 	XmString *strlist;
10484 	CHAR1 *text;
10485 	CHAR *retstring;
10486 	REGISTER void *infstr;
10487 	TDIALOG *dia;
10488 
10489 	dia = (TDIALOG *)vdia;
10490 	item--;
10491 	if (line < 0) return(x_(""));
10492 	w = dia->items[item];
10493 	XtVaGetValues(w, XmNitemCount, &count, XmNitems, &strlist, NULL);
10494 	if (line >= count) retstring = x_(""); else
10495 	{
10496 		XmStringGetLtoR(strlist[line], XmFONTLIST_DEFAULT_TAG, &text);
10497 		infstr = initinfstr();
10498 		addstringtoinfstr(infstr, string2byte(text));
10499 		retstring = returninfstr(infstr);
10500 		XtFree(text);
10501 	}
10502 	return(retstring);
10503 }
10504 
DiaSetScrollLine(void * vdia,INTBIG item,INTBIG line,CHAR * msg)10505 void DiaSetScrollLine(void *vdia, INTBIG item, INTBIG line, CHAR *msg)
10506 {
10507 	Widget w;
10508 	int count, *pos;   /* must be "int", and not "INTBIG" to work on Alpha */
10509 	INTBIG selected;
10510 	XmString strlist[1];
10511 	TDIALOG *dia;
10512 
10513 	dia = (TDIALOG *)vdia;
10514 	item--;
10515 	w = dia->items[item];
10516 
10517 	/* remember which line was selected */
10518 	selected = 0;
10519 	if (XmListGetSelectedPos(w, &pos, &count))
10520 	{
10521 		if (count == 1) selected = pos[0];
10522 		XtFree((char *)pos);
10523 	}
10524 
10525 	/* change the desired line */
10526 	strlist[0] = XmStringCreateLocalized(string1byte(msg));
10527 	XmListReplaceItemsPosUnselected(w, strlist, 1, line+1);
10528 	XmStringFree(strlist[0]);
10529 
10530 	/* restore the selected line */
10531 	if (selected == 0) XmListDeselectAllItems(w); else
10532 		XmListSelectPos(w, selected, False);
10533 	gra_flushdialog(dia);
10534 }
10535 
DiaSynchVScrolls(void * vdia,INTBIG item1,INTBIG item2,INTBIG item3)10536 void DiaSynchVScrolls(void *vdia, INTBIG item1, INTBIG item2, INTBIG item3)
10537 {
10538 	TDIALOG *dia;
10539 
10540 	dia = (TDIALOG *)vdia;
10541 	if (item1 <= 0 || item1 > dia->itemdesc->items) return;
10542 	if (item2 <= 0 || item2 > dia->itemdesc->items) return;
10543 	if (item3 < 0 || item3 > dia->itemdesc->items) return;
10544 	if (dia->numlocks >= MAXLOCKS) return;
10545 	dia->lock1[dia->numlocks] = item1 - 1;
10546 	dia->lock2[dia->numlocks] = item2 - 1;
10547 	dia->lock3[dia->numlocks] = item3 - 1;
10548 	dia->numlocks++;
10549 }
10550 
DiaUnSynchVScrolls(void * vdia)10551 void DiaUnSynchVScrolls(void *vdia)
10552 {
10553 	TDIALOG *dia;
10554 
10555 	dia = (TDIALOG *)vdia;
10556 	dia->numlocks = 0;
10557 }
10558 
DiaItemRect(void * vdia,INTBIG item,RECTAREA * rect)10559 void DiaItemRect(void *vdia, INTBIG item, RECTAREA *rect)
10560 {
10561 	TDIALOG *dia;
10562 
10563 	dia = (TDIALOG *)vdia;
10564 	if (item <= 0 || item > dia->itemdesc->items) return;
10565 	item--;
10566 	rect->left = dia->itemdesc->list[item].r.left+1;
10567 	rect->right = dia->itemdesc->list[item].r.right-1;
10568 	rect->top = dia->itemdesc->list[item].r.top+1;
10569 	rect->bottom = dia->itemdesc->list[item].r.bottom-1;
10570 }
10571 
DiaPercent(void * vdia,INTBIG item,INTBIG percent)10572 void DiaPercent(void *vdia, INTBIG item, INTBIG percent)
10573 {
10574 	Widget w;
10575 	Display *dpy;
10576 	Window win;
10577 	INTBIG x, y, wid, hei, rwid;
10578 	XGCValues gcv;
10579 	GC gc;
10580 	TDIALOG *dia;
10581 
10582 	dia = (TDIALOG *)vdia;
10583 	item--;
10584 	w = dia->items[item];
10585 	dpy = XtDisplay(w);
10586 	win = XtWindow(w);
10587 
10588 	/* determine size and draw interior bar */
10589 	gra_getdialogcoordinates(&dia->itemdesc->list[item].r, &x, &y, &wid, &hei);
10590 	rwid = wid * percent / 100;
10591 	gcv.foreground = BlackPixelOfScreen(XtScreen(w));
10592 	gc = XtGetGC(w, GCForeground, &gcv);
10593 	XSetForeground(dpy, gc, BlackPixelOfScreen(XtScreen(w)));
10594 	XFillRectangle(dpy, win, gc, 0, 0, rwid, hei);
10595 
10596 	/* draw outline */
10597 	XSetForeground(dpy, gc, BlackPixelOfScreen(XtScreen(w)));
10598 	XDrawLine(dpy, win, gc, 0, 0, wid, 0);
10599 	XDrawLine(dpy, win, gc, wid, 0, wid, hei);
10600 	XDrawLine(dpy, win, gc, wid, hei, 0, hei);
10601 	XDrawLine(dpy, win, gc, 0, hei, 0, 0);
10602 	XtReleaseGC(w, gc);
10603 }
10604 
DiaRedispRoutine(void * vdia,INTBIG item,void (* routine)(RECTAREA *,void *))10605 void DiaRedispRoutine(void *vdia, INTBIG item, void (*routine)(RECTAREA*, void*))
10606 {
10607 	TDIALOG *dia;
10608 
10609 	dia = (TDIALOG *)vdia;
10610 	item--;
10611 	dia->redrawroutine = routine;
10612 	dia->redrawitem = item;
10613 }
10614 
DiaAllowUserDoubleClick(void * vdia)10615 void DiaAllowUserDoubleClick(void *vdia)
10616 {
10617 	TDIALOG *dia;
10618 
10619 	dia = (TDIALOG *)vdia;
10620 }
10621 
DiaDrawRect(void * vdia,INTBIG item,RECTAREA * rect,INTBIG r,INTBIG g,INTBIG b)10622 void DiaDrawRect(void *vdia, INTBIG item, RECTAREA *rect, INTBIG r, INTBIG g, INTBIG b)
10623 {
10624 	Widget w;
10625 	Display *dpy;
10626 	Window win;
10627 	INTBIG xoff, yoff, lx, hx, ly, hy;
10628 	XGCValues gcv;
10629 	GC gc;
10630 	TDIALOG *dia;
10631 
10632 	dia = (TDIALOG *)vdia;
10633 	item--;
10634 	w = dia->items[item];
10635 	xoff = dia->itemdesc->list[item].r.left;
10636 	yoff = dia->itemdesc->list[item].r.top;
10637 	dpy = XtDisplay(w);
10638 	win = XtWindow(w);
10639 
10640 	gcv.foreground = gra_makedpycolor(dpy, r, g, b);
10641 	gc = XtGetGC(w, GCForeground, &gcv);
10642 
10643 	lx = gra_scaledialogcoordinate(rect->left-xoff);
10644 	hx = gra_scaledialogcoordinate(rect->right-xoff);
10645 	ly = gra_scaledialogcoordinate(rect->top-yoff);
10646 	hy = gra_scaledialogcoordinate(rect->bottom-yoff);
10647 	XFillRectangle(dpy, win, gc, lx, ly, hx-lx, hy-ly);
10648 	XtReleaseGC(w, gc);
10649 }
10650 
DiaInvertRect(void * vdia,INTBIG item,RECTAREA * r)10651 void DiaInvertRect(void *vdia, INTBIG item, RECTAREA *r)
10652 {
10653 	Widget w;
10654 	Display *dpy;
10655 	Window win;
10656 	INTBIG xoff, yoff, lx, hx, ly, hy;
10657 	XGCValues gcv;
10658 	GC gc;
10659 	TDIALOG *dia;
10660 
10661 	dia = (TDIALOG *)vdia;
10662 	item--;
10663 	w = dia->items[item];
10664 	xoff = dia->itemdesc->list[item].r.left;
10665 	yoff = dia->itemdesc->list[item].r.top;
10666 	dpy = XtDisplay(w);
10667 	win = XtWindow(w);
10668 
10669 	/* get rectangle bounds */
10670 	lx = gra_scaledialogcoordinate(r->left-xoff);
10671 	hx = gra_scaledialogcoordinate(r->right-xoff);
10672 	ly = gra_scaledialogcoordinate(r->top-yoff);
10673 	hy = gra_scaledialogcoordinate(r->bottom-yoff);
10674 
10675 	/* invert the rectangle */
10676 	gcv.function = GXinvert;
10677 	gc = XtGetGC(w, GCFunction, &gcv);
10678 	XFillRectangle(dpy, win, gc, lx, ly, hx-lx, hy-ly);
10679 	XtReleaseGC(w, gc);
10680 }
10681 
DiaFrameRect(void * vdia,INTBIG item,RECTAREA * r)10682 void DiaFrameRect(void *vdia, INTBIG item, RECTAREA *r)
10683 {
10684 	Widget w;
10685 	Display *dpy;
10686 	Window win;
10687 	INTBIG xoff, yoff, lx, hx, ly, hy;
10688 	XGCValues gcv;
10689 	GC gc;
10690 	TDIALOG *dia;
10691 
10692 	dia = (TDIALOG *)vdia;
10693 	item--;
10694 	w = dia->items[item];
10695 	xoff = dia->itemdesc->list[item].r.left;
10696 	yoff = dia->itemdesc->list[item].r.top;
10697 	dpy = XtDisplay(w);
10698 	win = XtWindow(w);
10699 
10700 	/* get rectangle bounds */
10701 	lx = gra_scaledialogcoordinate(r->left-xoff);
10702 	hx = gra_scaledialogcoordinate(r->right-xoff);
10703 	ly = gra_scaledialogcoordinate(r->top-yoff);
10704 	hy = gra_scaledialogcoordinate(r->bottom-yoff);
10705 
10706 	/* erase the rectangle */
10707 	gcv.foreground = WhitePixelOfScreen(XtScreen(w));
10708 	gc = XtGetGC(w, GCForeground, &gcv);
10709 	XFillRectangle(dpy, win, gc, lx, ly, hx-lx, hy-ly);
10710 	XtReleaseGC(w, gc);
10711 
10712 	/* draw outline */
10713 	gcv.foreground = BlackPixelOfScreen(XtScreen(w));
10714 	gc = XtGetGC(w, GCForeground, &gcv);
10715 	XDrawLine(dpy, win, gc, lx, ly, hx-1, ly);
10716 	XDrawLine(dpy, win, gc, hx-1, ly, hx-1, hy-1);
10717 	XDrawLine(dpy, win, gc, hx-1, hy-1, lx, hy-1);
10718 	XDrawLine(dpy, win, gc, lx, hy-1, lx, ly);
10719 	XtReleaseGC(w, gc);
10720 }
10721 
DiaDrawLine(void * vdia,INTBIG item,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty,INTBIG mode)10722 void DiaDrawLine(void *vdia, INTBIG item, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, INTBIG mode)
10723 {
10724 	Widget w;
10725 	Display *dpy;
10726 	Window win;
10727 	INTBIG xoff, yoff, x1, y1, x2, y2;
10728 	XGCValues gcv;
10729 	GC gc;
10730 	TDIALOG *dia;
10731 
10732 	dia = (TDIALOG *)vdia;
10733 	item--;
10734 	w = dia->items[item];
10735 	xoff = dia->itemdesc->list[item].r.left;
10736 	yoff = dia->itemdesc->list[item].r.top;
10737 	dpy = XtDisplay(w);
10738 	win = XtWindow(w);
10739 
10740 	x1 = gra_scaledialogcoordinate(fx-xoff);
10741 	y1 = gra_scaledialogcoordinate(fy-yoff);
10742 	x2 = gra_scaledialogcoordinate(tx-xoff);
10743 	y2 = gra_scaledialogcoordinate(ty-yoff);
10744 	switch (mode)
10745 	{
10746 		case DLMODEON:
10747 			gcv.foreground = BlackPixelOfScreen(XtScreen(w));
10748 			gc = XtGetGC(w, GCForeground, &gcv);
10749 			break;
10750 		case DLMODEOFF:
10751 			gcv.foreground = WhitePixelOfScreen(XtScreen(w));
10752 			gc = XtGetGC(w, GCForeground, &gcv);
10753 			break;
10754 		case DLMODEINVERT:
10755 			gcv.function = GXinvert;
10756 			gc = XtGetGC(w, GCFunction, &gcv);
10757 			break;
10758 	}
10759 	XDrawLine(dpy, win, gc, x1, y1, x2, y2);
10760 	XtReleaseGC(w, gc);
10761 }
10762 
DiaFillPoly(void * vdia,INTBIG item,INTBIG * xv,INTBIG * yv,INTBIG count,INTBIG r,INTBIG g,INTBIG b)10763 void DiaFillPoly(void *vdia, INTBIG item, INTBIG *xv, INTBIG *yv, INTBIG count, INTBIG r, INTBIG g, INTBIG b)
10764 {
10765 	Widget w;
10766 	Display *dpy;
10767 	Window win;
10768 	INTBIG xoff, yoff, i;
10769 	XPoint pointlist[20];
10770 	XGCValues gcv;
10771 	GC gc;
10772 	TDIALOG *dia;
10773 
10774 	dia = (TDIALOG *)vdia;
10775 	item--;
10776 	w = dia->items[item];
10777 	xoff = dia->itemdesc->list[item].r.left;
10778 	yoff = dia->itemdesc->list[item].r.top;
10779 	dpy = XtDisplay(w);
10780 	win = XtWindow(w);
10781 
10782 	for(i=0; i<count; i++)
10783 	{
10784 		pointlist[i].x = gra_scaledialogcoordinate(xv[i]-xoff);
10785 		pointlist[i].y = gra_scaledialogcoordinate(yv[i]-yoff);
10786 	}
10787 
10788 	/* determine color to use */
10789 	gcv.foreground = gra_makedpycolor(dpy, r, g, b);
10790 	gc = XtGetGC(w, GCForeground, &gcv);
10791 
10792 	XFillPolygon(dpy, win, gc, pointlist, count, Complex, CoordModeOrigin);
10793 	XtReleaseGC(w, gc);
10794 	gra_flushdialog(dia);
10795 }
10796 
DiaPutText(void * vdia,INTBIG item,CHAR * msg,INTBIG x,INTBIG y)10797 void DiaPutText(void *vdia, INTBIG item, CHAR *msg, INTBIG x, INTBIG y)
10798 {
10799 	INTBIG fontnumber, xoff, yoff, xp, yp;
10800 	XFontStruct *font;
10801 	Widget w;
10802 	Display *dpy;
10803 	Window win;
10804 	XGCValues gcv;
10805 	GC gc;
10806 	TDIALOG *dia;
10807 
10808 	dia = (TDIALOG *)vdia;
10809 	item--;
10810 	w = dia->items[item];
10811 	xoff = dia->itemdesc->list[item].r.left;
10812 	yoff = dia->itemdesc->list[item].r.top;
10813 	dpy = XtDisplay(w);
10814 	win = XtWindow(w);
10815 
10816 	fontnumber = (dia->usertextsize - 4) / 2;
10817 	if (fontnumber < 0) fontnumber = 0;
10818 	if (fontnumber > 8) fontnumber = 8;
10819 	font = gra_font[fontnumber].font;
10820 	gcv.foreground = BlackPixelOfScreen(XtScreen(w));
10821 	gc = XtGetGC(w, GCForeground, &gcv);
10822 	XSetFont(dpy, gc, font->fid);
10823 	xp = gra_scaledialogcoordinate(x-xoff);
10824 	yp = gra_scaledialogcoordinate(y-yoff);
10825 	XDrawString(dpy, win, gc, xp, yp+font->ascent+font->descent, string1byte(msg),
10826 		estrlen(msg));
10827 	XtReleaseGC(w, gc);
10828 }
10829 
DiaSetTextSize(void * vdia,INTBIG size)10830 void DiaSetTextSize(void *vdia, INTBIG size)
10831 {
10832 	TDIALOG *dia;
10833 
10834 	dia = (TDIALOG *)vdia;
10835 	dia->usertextsize = size;
10836 }
10837 
DiaGetTextInfo(void * vdia,CHAR * msg,INTBIG * wid,INTBIG * hei)10838 void DiaGetTextInfo(void *vdia, CHAR *msg, INTBIG *wid, INTBIG *hei)
10839 {
10840 	int direction, asc, desc;
10841 	INTBIG len, fontnumber;
10842 	XCharStruct xcs;
10843 	XFontStruct *font;
10844 	TDIALOG *dia;
10845 
10846 	dia = (TDIALOG *)vdia;
10847 	fontnumber = (dia->usertextsize - 4) / 2;
10848 	if (fontnumber < 0) fontnumber = 0;
10849 	if (fontnumber > 8) fontnumber = 8;
10850 	font = gra_font[fontnumber].font;
10851 	len = estrlen(msg);
10852 	XTextExtents(font, string1byte(msg), len, &direction, &asc, &desc, &xcs);
10853 	*wid = xcs.width;
10854 	*hei = font->ascent + font->descent;
10855 }
10856 
DiaTrackCursor(void * vdia,void (* eachdown)(INTBIG x,INTBIG y))10857 void DiaTrackCursor(void *vdia, void (*eachdown)(INTBIG x, INTBIG y))
10858 {
10859 	gra_trackingdialog = (TDIALOG *)vdia;
10860 	gra_trackingdialog->diaeachdown = eachdown;
10861 	trackcursor(FALSE, us_nullup, us_nullvoid, gra_diaeachdownhandler,
10862 		us_nullchar, us_nullvoid, TRACKNORMAL);
10863 }
10864 
gra_diaeachdownhandler(INTBIG ox,INTBIG oy)10865 BOOLEAN gra_diaeachdownhandler(INTBIG ox, INTBIG oy)
10866 {
10867 	INTBIG x, y;
10868 
10869 	DiaGetMouse(gra_trackingdialog, &x, &y);
10870 	(void)((*gra_trackingdialog->diaeachdown)(x, y));
10871 	return(FALSE);
10872 }
10873 
DiaGetMouse(void * vdia,INTBIG * x,INTBIG * y)10874 void DiaGetMouse(void *vdia, INTBIG *x, INTBIG *y)
10875 {
10876 	TDIALOG *dia;
10877 
10878 	dia = (TDIALOG *)vdia;
10879 	if (us_logplay != NULL)
10880 	{
10881 		if (!gra_loggetnextaction(0))
10882 		{
10883 			*x = gra_action.x;
10884 			*y = gra_action.y;
10885 		}
10886 	}
10887 	if (us_logplay == NULL)
10888 	{
10889 		*x = gra_cursorx;
10890 		*y = gra_cursory;
10891 	}
10892 	gra_logwriteaction(DIAUSERMOUSE, dia->windindex, *x, *y, 0);
10893 }
10894 
10895 /****************************** DIALOG SUPPORT ******************************/
10896 
10897 /*
10898  * Routine to make sure that changes to the dialog are on the screen
10899  */
gra_flushdialog(TDIALOG * dia)10900 void gra_flushdialog(TDIALOG *dia)
10901 {
10902 	Display *dpy;
10903 
10904 	dpy = XtDisplay(dia->window);
10905 	XFlush(dpy);
10906 	XmUpdateDisplay(dia->window);
10907 }
10908 
10909 /*
10910  * Routine to convert dialog coordinates
10911  */
gra_getdialogcoordinates(RECTAREA * rect,INTBIG * x,INTBIG * y,INTBIG * wid,INTBIG * hei)10912 void gra_getdialogcoordinates(RECTAREA *rect, INTBIG *x, INTBIG *y, INTBIG *wid, INTBIG *hei)
10913 {
10914 	*x = gra_scaledialogcoordinate(rect->left);
10915 	*y = gra_scaledialogcoordinate(rect->top);
10916 	*wid = gra_scaledialogcoordinate(rect->right - rect->left);
10917 	*hei = gra_scaledialogcoordinate(rect->bottom - rect->top);
10918 }
10919 
gra_scaledialogcoordinate(INTBIG x)10920 INTBIG gra_scaledialogcoordinate(INTBIG x)
10921 {
10922 	return((x * DIALOGNUM + DIALOGDEN/2) / DIALOGDEN);
10923 }
10924 
gra_makedpycolor(Display * dpy,INTBIG r,INTBIG g,INTBIG b)10925 INTBIG gra_makedpycolor(Display *dpy, INTBIG r, INTBIG g, INTBIG b)
10926 {
10927 	XColor xc;
10928 	INTBIG colorvalue, depth, scr, redShift, greenShift, blueShift;
10929 	Visual *visual;
10930 
10931 	/* determine color to use */
10932 	scr = DefaultScreen(dpy);
10933 	visual = DefaultVisual(dpy, scr);
10934 	if (VisualClass(visual) == PseudoColor ||
10935 		VisualClass(visual) == StaticColor)
10936 	{
10937 		xc.red   = r << 8;
10938 		xc.green = g << 8;
10939 		xc.blue  = b << 8;
10940 		XAllocColor(dpy, gra_maincolmap, &xc);
10941 		colorvalue = xc.pixel;
10942 	} else
10943 	{
10944 		depth = DefaultDepth(dpy, scr);
10945 		if (depth == 16)
10946 		{
10947 			colorvalue = ((r & 0xF8) << 8) |
10948 				((g & 0xF8) << 3) | ((b & 0xF8) >> 3);
10949 		} else
10950 		{
10951 			if (visual->red_mask == 0xFF) redShift = 0; else
10952 				if (visual->red_mask == 0xFF00) redShift = 8; else
10953 					if (visual->red_mask == 0xFF0000) redShift = 16;
10954 			if (visual->green_mask == 0xFF) greenShift = 0; else
10955 				if (visual->green_mask == 0xFF00) greenShift = 8; else
10956 					if (visual->green_mask == 0xFF0000) greenShift = 16;
10957 			if (visual->blue_mask == 0xFF) blueShift = 0; else
10958 				if (visual->blue_mask == 0xFF00) blueShift = 8; else
10959 					if (visual->blue_mask == 0xFF0000) blueShift = 16;
10960 			colorvalue = (b << blueShift) | (g << greenShift) | (r << redShift);
10961 		}
10962 	}
10963 	return(colorvalue);
10964 }
10965 
10966 /*
10967  * Routine to make a Pixmap from image data
10968  */
gra_makeicon(UCHAR1 * data,Widget widget)10969 Pixmap gra_makeicon(UCHAR1 *data, Widget widget)
10970 {
10971 	static Pixmap buildupmain[MAXICONS], buildupalt[MAXICONS];
10972 	REGISTER Pixmap *buildup;
10973 	static INTBIG which = 0;
10974 	static INTBIG foreground, background, screen, bgr, bgg, bgb;
10975 	UCHAR1 *tdptr, *setptr;
10976 	Window win;
10977 	Display *dpy;
10978 	Visual *visual;
10979 	INTBIG i, j, wid, hei, bytesperrow, datasize, x, y, byte, bit,
10980 		outx, lastoutx, outy, lastouty, sdep, pad, allocsdep;
10981 	static GC pgc;
10982 	static XImage *ximage;
10983 	Arg arg[2];
10984 	XGCValues gcv;
10985 
10986 	/* determine sizes */
10987 	dpy = XtDisplay(widget);
10988 	if (dpy == gra_maindpy) buildup = buildupmain; else
10989 		if (dpy == gra_altdpy) buildup = buildupalt; else
10990 	{
10991 		ttyputerr(_("Cannot find display for icon"));
10992 		return(0);
10993 	}
10994 	screen = DefaultScreen(dpy);
10995 	wid = gra_scaledialogcoordinate(32);
10996 	hei = gra_scaledialogcoordinate(32);
10997 	sdep = DefaultDepth(dpy, screen);
10998 	allocsdep = sdep;
10999 	if (allocsdep == 24) allocsdep = 32;
11000 	pad = XBitmapPad(dpy);
11001 	bytesperrow = ((wid*allocsdep+pad-1) / pad) * pad / 8;
11002 	datasize = bytesperrow * hei;
11003 
11004 	/* initialize icon storage */
11005 	if (gra_icontruedata == 0)
11006 	{
11007 		for(i=0; i<MAXICONS; i++) buildupmain[i] = buildupalt[i] = 0;
11008 		gra_icontruedata = (UCHAR1 *)emalloc(datasize, us_tool->cluster);
11009 		if (gra_icontruedata == 0) return(0);
11010 		gra_iconrowdata = (UCHAR1 *)emalloc(bytesperrow, us_tool->cluster);
11011 		if (gra_iconrowdata == 0) return(0);
11012 	}
11013 
11014 	/* choose an icon to build */
11015 	which++;
11016 	if (which >= MAXICONS) which = 0;
11017 
11018 	if (buildup[which] == 0)
11019 	{
11020 		win = XtWindow(widget);
11021 		visual = DefaultVisual(dpy, screen);
11022 		buildup[which] = XCreatePixmap(dpy, win, wid, hei, sdep);
11023 		XtSetArg(arg[0], XtNbackground, &gcv.background);
11024 		XtSetArg(arg[1], XtNforeground, &gcv.foreground);
11025 		XtGetValues(widget, arg, 2);
11026 		foreground = gcv.foreground;
11027 		background = gcv.background;
11028 		if (sdep > 16)
11029 		{
11030 			bgr = background & 0xFF;
11031 			bgg = (background >> 8) & 0xFF;
11032 			bgb = (background >> 16) & 0xFF;
11033 		}
11034 		gcv.fill_style = FillStippled;
11035 		pgc = XtGetGC(widget, GCForeground | GCBackground, &gcv);
11036 		ximage = XCreateImage(dpy, visual, sdep, ZPixmap, 0,
11037 			(CHAR1 *)gra_icontruedata, wid, hei, pad, 0);
11038 	}
11039 	lastouty = 0;
11040 	tdptr = gra_icontruedata;
11041 	for(y=0; y<32; y++)
11042 	{
11043 		lastoutx = 0;
11044 		for(i=0; i<bytesperrow; i++) gra_iconrowdata[i] = foreground;
11045 		for(x=0; x<32; x++)
11046 		{
11047 			byte = data[y*4+(x>>3)];
11048 			bit = byte & (0200 >> (x&7));
11049 			if (x == 31) outx = wid-1; else
11050 				outx = gra_scaledialogcoordinate(x);
11051 
11052 			if (bit == 0)
11053 			{
11054 				for(i=lastoutx; i<=outx; i++)
11055 				{
11056 					switch (sdep)
11057 					{
11058 						case 1:
11059 							gra_iconrowdata[i>>3] |= (0200 >> (i&7));
11060 							break;
11061 						case 8:
11062 							gra_iconrowdata[i] = background;
11063 							break;
11064 						case 16:
11065 							((short *)gra_iconrowdata)[i] = background;
11066 							break;
11067 						case 24:
11068 						case 32:
11069 							setptr = &((UCHAR1 *)gra_iconrowdata)[i*4];
11070 #ifdef BYTES_SWAPPED
11071 							*setptr++ = 0;
11072 							*setptr++ = bgb;
11073 							*setptr++ = bgg;
11074 							*setptr++ = bgr;
11075 #else
11076 							*setptr++ = bgb;
11077 							*setptr++ = bgg;
11078 							*setptr++ = bgr;
11079 							*setptr++ = 0;
11080 #endif
11081 							break;
11082 					}
11083 				}
11084 			}
11085 			lastoutx = outx+1;
11086 		}
11087 		if (y == 31) outy = hei-1; else
11088 			outy = gra_scaledialogcoordinate(y);
11089 		for(i=lastouty; i<=outy; i++)
11090 		{
11091 			for(j=0; j<bytesperrow; j++)
11092 				tdptr[j] = gra_iconrowdata[j];
11093 			tdptr += bytesperrow;
11094 		}
11095 		lastouty = outy+1;
11096 	}
11097 	XPutImage(dpy, buildup[which], pgc, ximage, 0, 0, 0, 0, wid, hei);
11098 	return(buildup[which]);
11099 }
11100 
11101 /*
11102  * Routine to handle the focus-change events on dialogs.
11103  */
gra_dialog_event_handler(Widget w,XtPointer data,XEvent * event,Boolean * cont)11104 void gra_dialog_event_handler(Widget w, XtPointer data, XEvent *event, Boolean *cont)
11105 {
11106 	Arg arg[2];
11107 	short inix, iniy;
11108 	TDIALOG *dia;
11109 
11110 	dia = gra_whichdialog(w);
11111 	if (dia == NOTDIALOG) return;
11112 
11113 	/* on the first focus-in, pickup the actual location of the dialog */
11114 	if (event->type != FocusIn) return;
11115 	if (dia->inix != -1 || dia->iniy != -1) return;
11116 	XtSetArg(arg[0], XtNx, &inix);
11117 	XtSetArg(arg[1], XtNy, &iniy);
11118 	XtGetValues(dia->window, arg, 2);
11119 	dia->inix = inix;   dia->iniy = iniy;
11120 }
11121 
11122 /*
11123  * Routine to handle vertical-slider events in a dialog's scroll list.
11124  */
gra_vertslider(Widget w,XtPointer client_data,XmScrollBarCallbackStruct * call_data)11125 void gra_vertslider(Widget w, XtPointer client_data, XmScrollBarCallbackStruct *call_data)
11126 {
11127 	int value, item, i;
11128 	TDIALOG *dia;
11129 
11130 	dia = gra_whichdialog(w);
11131 	if (dia == NOTDIALOG) return;
11132 
11133 	value = call_data->value;
11134 	item = (int)client_data;
11135 	for(i=0; i<dia->numlocks; i++)
11136 	{
11137 		if (dia->lock1[i] == item)
11138 		{
11139 			gra_setscroll(dia, dia->lock2[i], value);
11140 			if (dia->lock3[i] >= 0)
11141 				gra_setscroll(dia, dia->lock3[i], value);
11142 			break;
11143 		}
11144 		if (dia->lock2[i] == item)
11145 		{
11146 			gra_setscroll(dia, dia->lock1[i], value);
11147 			if (dia->lock3[i] >= 0)
11148 				gra_setscroll(dia, dia->lock3[i], value);
11149 			break;
11150 		}
11151 		if (dia->lock3[i] == item)
11152 		{
11153 			gra_setscroll(dia, dia->lock1[i], value);
11154 			gra_setscroll(dia, dia->lock2[i], value);
11155 			break;
11156 		}
11157 	}
11158 }
11159 
gra_setscroll(TDIALOG * dia,int item,int value)11160 void gra_setscroll(TDIALOG *dia, int item, int value)
11161 {
11162 	Widget w, vertscroll;
11163 	int oldvalue, slidersize, increment, pageinc;
11164 
11165 	w = dia->items[item];
11166 	XtVaGetValues(w, XmNverticalScrollBar, &vertscroll, NULL);
11167 	XmScrollBarGetValues(vertscroll, &oldvalue, &slidersize, &increment, &pageinc);
11168 	XmScrollBarSetValues(vertscroll, value, slidersize, increment, pageinc, TRUE);
11169 }
11170 
11171 /*
11172  * Routine to return the dialog object associated with widget "w".
11173  */
gra_whichdialog(Widget w)11174 TDIALOG *gra_whichdialog(Widget w)
11175 {
11176 	TDIALOG *dia;
11177 
11178 	for(;;)
11179 	{
11180 		for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
11181 			if (dia->window == w) return(dia);
11182 		w = XtParent(w);
11183 		if (w == 0) break;
11184 	}
11185 	return(NOTDIALOG);
11186 }
11187 
11188 /*
11189  * Routine to handle events specific to dialog items
11190  */
gra_dialogaction(Widget w,XtPointer client_data,XmSelectionBoxCallbackStruct * call_data)11191 void gra_dialogaction(Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data)
11192 {
11193 	INTBIG item, itemtype, value, count, selected, myselected[1], *selectedlist, i;
11194 	CHAR *line;
11195 	XmPushButtonCallbackStruct *cbspb;
11196 	XEvent *event;
11197 	TDIALOG *dia;
11198 
11199 	dia = gra_whichdialog(w);
11200 	if (dia == NOTDIALOG) return;
11201 
11202 	item = ((int)client_data) & 0xFFFF;
11203 	itemtype = dia->itemdesc->list[item].type;
11204 	item++;
11205 
11206 	if ((itemtype&ITEMTYPE) == BUTTON || (itemtype&ITEMTYPE) == DEFBUTTON)
11207 	{
11208 		XmProcessTraversal(dia->window, XmTRAVERSE_HOME);
11209 		gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
11210 	}
11211 	if ((itemtype&ITEMTYPE) == RADIO)
11212 	{
11213 		gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
11214 	}
11215 	if ((itemtype&ITEMTYPE) == CHECK)
11216 	{
11217 		value = XmToggleButtonGetState(w);
11218 		XmToggleButtonSetState(w, value == 0 ? True : False, 0);
11219 		gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
11220 	}
11221 	if ((itemtype&ITEMTYPE) == ICON)
11222 	{
11223 		cbspb = (XmPushButtonCallbackStruct *)call_data;
11224 		event = cbspb->event;
11225 		gra_cursorx = event->xbutton.x * DIALOGDEN / DIALOGNUM +
11226 			dia->itemdesc->list[item].r.left;
11227 		gra_cursory = event->xbutton.y * DIALOGDEN / DIALOGNUM +
11228 			dia->itemdesc->list[item].r.top;
11229 		gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
11230 	}
11231 	if ((itemtype&ITEMTYPE) == POPUP)
11232 	{
11233 		selected = DiaGetPopupEntry(dia, item);
11234 		gra_logwriteaction(DIAPOPUPSEL, dia->windindex, item, selected, 0);
11235 	}
11236 	if ((itemtype&ITEMTYPE) == SCROLL || (itemtype&ITEMTYPE) == SCROLLMULTI)
11237 	{
11238 		if ((itemtype&ITEMTYPE) == SCROLLMULTI)
11239 		{
11240 			selectedlist = DiaGetCurLines(dia, item);
11241 			for(i=0; selectedlist[i] >= 0; i++) ;
11242 			gra_logwriteaction(DIASCROLLSEL, dia->windindex, item, i, selectedlist);
11243 		} else
11244 		{
11245 			myselected[0] = DiaGetCurLine(dia, item);
11246 			gra_logwriteaction(DIASCROLLSEL, dia->windindex, item, 1, myselected);
11247 		}
11248 	}
11249 	if ((itemtype&ITEMTYPE) == EDITTEXT)
11250 	{
11251 		line = string2byte(XmTextGetString(w));
11252 		gra_logwriteaction(DIAEDITTEXT, dia->windindex, item, 0, line);
11253 	}
11254 	if (dia->modelessitemhit != 0) (*dia->modelessitemhit)(dia, item); else
11255 		dia->dialoghit = item;
11256 }
11257 
11258 /*
11259  * Routine to handle clicks in user-drawn items
11260  */
gra_dialogdraw(Widget widget,XEvent * event,String * args,int * num_args)11261 void gra_dialogdraw(Widget widget, XEvent *event, String *args, int *num_args)
11262 {
11263 	INTBIG i, item;
11264 	TDIALOG *dia;
11265 
11266 	dia = gra_whichdialog(widget);
11267 	if (dia == NOTDIALOG) return;
11268 
11269 	/* see which dialog item this applies to */
11270 	for(i=0; i<dia->itemdesc->items; i++)
11271 		if (widget == dia->items[i]) break;
11272 	if (i >= dia->itemdesc->items) return;
11273 
11274 	/* get cursor coordinates */
11275 	gra_cursorx = event->xbutton.x * DIALOGDEN / DIALOGNUM +
11276 		dia->itemdesc->list[i].r.left;
11277 	gra_cursory = event->xbutton.y * DIALOGDEN / DIALOGNUM +
11278 		dia->itemdesc->list[i].r.top;
11279 
11280 	/* determine type of action */
11281 	if (*num_args != 1) return;
11282 	if (estrcmp(string2byte(args[0]), x_("motion")) == 0)
11283 	{
11284 		gra_inputstate = MOTION;
11285 		if ((event->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) == 0)
11286 			gra_inputstate |= BUTTONUP;
11287 	} else
11288 	{
11289 		switch (event->xbutton.button)
11290 		{
11291 			case 1: gra_inputstate = ISLEFT;    break;
11292 			case 2: gra_inputstate = ISMIDDLE;  break;
11293 			case 3: gra_inputstate = ISRIGHT;   break;
11294 			case 4: gra_inputstate = ISWHLFWD;  break;
11295 			case 5: gra_inputstate = ISWHLBKW;  break;
11296 		}
11297 		if ((event->xbutton.state & ShiftMask) != 0)
11298 			gra_inputstate |= SHIFTISDOWN;
11299 		if ((event->xbutton.state & LockMask) != 0)
11300 			gra_inputstate |= SHIFTISDOWN;
11301 		if ((event->xbutton.state & ControlMask) != 0)
11302 			gra_inputstate |= CONTROLISDOWN;
11303 		if ((event->xbutton.state & (Mod1Mask|Mod4Mask)) != 0)
11304 			gra_inputstate |= METAISDOWN;
11305 		if (estrcmp(string2byte(args[0]), x_("up")) == 0)
11306 			gra_inputstate |= BUTTONUP;
11307 	}
11308 	if (estrcmp(string2byte(args[0]), x_("down")) == 0)
11309 	{
11310 		item = i+1;
11311 		if (dia->modelessitemhit != 0) (*dia->modelessitemhit)(dia, item); else
11312 			dia->dialoghit = item;
11313 		gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
11314 	}
11315 }
11316 
11317 /*
11318  * Routine to handle requests to copy a scroll list
11319  */
gra_dialogcopywholelist(Widget widget,XEvent * event,String * args,int * num_args)11320 void gra_dialogcopywholelist(Widget widget, XEvent *event, String *args, int *num_args)
11321 {
11322 	INTBIG count, i, status, len;
11323 	long itemid;
11324 	XmString *strlist, copylabel;
11325 	CHAR1 *text;
11326 	Display *dpy;
11327 	Window win;
11328 
11329 	dpy = XtDisplay(widget);
11330 	win = XtWindow(widget);
11331 	copylabel = XmStringCreateLocalized(b_("Electric dialog scroll list"));
11332 	for(;;)
11333 	{
11334 		status = XmClipboardStartCopy(dpy, win, copylabel, CurrentTime, widget, NULL, &itemid);
11335 		if (status != ClipboardLocked) break;
11336 	}
11337 	XmStringFree(copylabel);
11338 	XtVaGetValues(widget, XmNitemCount, &count, XmNitems, &strlist, NULL);
11339 	for(i=0; i<count; i++)
11340 	{
11341 		XmStringGetLtoR(strlist[i], XmFONTLIST_DEFAULT_TAG, &text);
11342 		len = TRUESTRLEN(text);
11343 		text[len] = '\n';
11344 		for(;;)
11345 		{
11346 			status = XmClipboardCopy(dpy, win, itemid, b_("STRING"), text, len+1, i, NULL);
11347 			if (status != ClipboardLocked) break;
11348 		}
11349 		text[len] = 0;
11350 		XtFree(text);
11351 	}
11352 	for(;;)
11353 	{
11354 		status = XmClipboardEndCopy(dpy, win, itemid);
11355 		if (status != ClipboardLocked) break;
11356 	}
11357 }
11358 
11359 /*
11360  * Routine to handle keystrokes in an "opaque" item
11361  * (replaces the text with "*")
11362  */
gra_dialogopaqueaction(Widget w,XtPointer client_data,XmTextVerifyCallbackStruct * call_data)11363 void gra_dialogopaqueaction(Widget w, XtPointer client_data,
11364 	XmTextVerifyCallbackStruct *call_data)
11365 {
11366 	INTBIG i;
11367 	TDIALOG *dia;
11368 
11369 	dia = gra_whichdialog(w);
11370 	if (dia == NOTDIALOG) return;
11371 
11372 	if (call_data->startPos < call_data->currInsert)
11373 	{
11374 		call_data->endPos = estrlen(dia->opaquefield);
11375 		dia->opaquefield[call_data->startPos] = 0;
11376 		return;
11377 	}
11378 	if (call_data->text->length > 1)
11379 	{
11380 		call_data->doit = False;
11381 		return;
11382 	}
11383 	estrncat(dia->opaquefield, string2byte(call_data->text->ptr), call_data->text->length);
11384 	dia->opaquefield[call_data->endPos + call_data->text->length] = 0;
11385 
11386 	for(i=0; i<call_data->text->length; i++)
11387 		call_data->text->ptr[i] = '*';
11388 }
11389 
11390 /*
11391  * Routine to redraw user-drawn items (calls the user's callback)
11392  */
gra_dialogredraw(Widget w,XtPointer client_data,XmSelectionBoxCallbackStruct * call_data)11393 void gra_dialogredraw(Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data)
11394 {
11395 	RECTAREA ra;
11396 	TDIALOG *dia;
11397 
11398 	dia = gra_whichdialog(w);
11399 	if (dia == NOTDIALOG) return;
11400 
11401 	if (dia->redrawroutine != 0)
11402 	{
11403 		DiaItemRect(dia, dia->redrawitem + 1, &ra);
11404 		(*dia->redrawroutine)(&ra, dia);
11405 	}
11406 }
11407 
11408 /*
11409  * Routine to redraw separator lines
11410  */
gra_dialogredrawsep(Widget w,XtPointer client_data,XmSelectionBoxCallbackStruct * call_data)11411 void gra_dialogredrawsep(Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data)
11412 {
11413 	Display *dpy;
11414 	Window win;
11415 	INTBIG x, y, wid, hei;
11416 	XGCValues gcv;
11417 	GC gc;
11418 	TDIALOG *dia;
11419 
11420 	dia = gra_whichdialog(w);
11421 	if (dia == NOTDIALOG) return;
11422 
11423 	gra_getdialogcoordinates(&dia->itemdesc->list[(INTBIG)client_data].r,
11424 		&x, &y, &wid, &hei);
11425 	dpy = XtDisplay(w);
11426 	win = XtWindow(w);
11427 	gcv.foreground = BlackPixelOfScreen(XtScreen(w));
11428 	gc = XtGetGC(w, GCForeground, &gcv);
11429 	XSetForeground(dpy, gc, BlackPixelOfScreen(XtScreen(w)));
11430 	XFillRectangle(dpy, win, gc, 0, 0, wid, hei);
11431 	XtReleaseGC(w, gc);
11432 }
11433 
11434 /*
11435  * Helper routine for "DiaLoadTextDialog" that makes strings go in ascending order.
11436  */
gra_stringposascending(const void * e1,const void * e2)11437 int gra_stringposascending(const void *e1, const void *e2)
11438 {
11439 	REGISTER CHAR *c1, *c2;
11440 
11441 	c1 = *((CHAR **)e1);
11442 	c2 = *((CHAR **)e2);
11443 	return(namesame(&c1[gra_dialogstringpos], &c2[gra_dialogstringpos]));
11444 }
11445