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