1 /*----------------------------------------------------------------------*/
2 /* xcircuit.c --- An X-windows program for drawing circuit diagrams	*/
3 /* Copyright (c) 2002  R. Timothy Edwards				*/
4 /*									*/
5 /* This program is free software; you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation; either version 2 of the License, or	*/
8 /* (at your option) any later version.					*/
9 /*									*/
10 /* This program is distributed in the hope that it will be useful,	*/
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of	*/
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the	*/
13 /* GNU General Public License for more details.				*/
14 /*									*/
15 /* You should have received a copy of the GNU General Public License	*/
16 /* along with this program; if not, write to:				*/
17 /*	Free Software Foundation, Inc.					*/
18 /*	59 Temple Place, Suite 330					*/
19 /*	Boston, MA  02111-1307  USA					*/
20 /*									*/
21 /* See file ./README for contact information				*/
22 /*----------------------------------------------------------------------*/
23 
24 /*----------------------------------------------------------------------*/
25 /*      Uses the Xw widget set (see directory Xw)			*/
26 /*      Xcircuit written by Tim Edwards beginning 8/13/93 		*/
27 /*----------------------------------------------------------------------*/
28 
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <locale.h>
39 #include <ctype.h>
40 #ifndef XC_WIN32
41 #include <unistd.h>   /* for unlink() */
42 
43 #include <X11/Xresource.h>
44 #include <X11/Intrinsic.h>
45 #include <X11/StringDefs.h>
46 #include <X11/Shell.h>
47 #include <X11/Xutil.h>
48 #include <X11/cursorfont.h>
49 #include <X11/Xproto.h>
50 #include <X11/Xatom.h>
51 #endif
52 
53 #ifdef TCL_WRAPPER
54 #include <tk.h>
55 #else
56 #ifndef XC_WIN32
57 #include "Xw/Xw.h"
58 #include "Xw/Form.h"
59 #include "Xw/WorkSpace.h"
60 #include "Xw/PButton.h"
61 #include "Xw/SText.h"
62 #include "Xw/Cascade.h"
63 #include "Xw/PopupMgr.h"
64 #include "Xw/MenuBtn.h"
65 #include "Xw/BBoard.h"
66 #include "Xw/TextEdit.h"
67 #include "Xw/Toggle.h"
68 #endif
69 #endif
70 
71 #if defined(XC_WIN32) && defined(TCL_WRAPPER)
72 #include <X11/Xlib.h>
73 #include <X11/Xutil.h>
74 #include <X11/cursorfont.h>
75 #include <X11/Xatom.h>
76 #endif
77 
78 #ifndef P_tmpdir
79 #define P_tmpdir TMPDIR
80 #endif
81 
82 /*----------------------------------------------------------------------*/
83 /* Local includes							*/
84 /*----------------------------------------------------------------------*/
85 
86 #include "xcircuit.h"
87 #include "cursors.h"
88 #include "colordefs.h"
89 #include "menudep.h"
90 
91 /*----------------------------------------------------------------------*/
92 /* Function prototype declarations                                      */
93 /*----------------------------------------------------------------------*/
94 #include "prototypes.h"
95 
96 /*----------------------------------------------------------------------*/
97 /* Global Variable definitions						*/
98 /*----------------------------------------------------------------------*/
99 
100 char	 _STR2[250];  /* Specifically for text returned from the popup prompt */
101 char	 _STR[150];   /* Generic multipurpose string */
102 int	 pressmode;   /* Whether we are in a press & hold state */
103 Display  *dpy = NULL;        /* Works well to make this globally accessible */
104 Colormap cmap;
105 Pixmap   STIPPLE[STIPPLES];  /* Polygon fill-style stipple patterns */
106 Cursor	appcursors[NUM_CURSORS];
107 ApplicationData appdata;
108 XCWindowData *areawin;
109 Globaldata xobjs;
110 int number_colors;
111 colorindex *colorlist;
112 short menusize;
113 xcIntervalId printtime_id;
114 short beeper;
115 short fontcount;
116 int screenDPI;
117 fontinfo *fonts;
118 short	 popups;      /* total number of popup widgets on the screen */
119 
120 /*----------------------------------------------------------------------*/
121 /* Externally defined variables						*/
122 /*----------------------------------------------------------------------*/
123 
124 extern aliasptr aliastop;
125 extern char version[];
126 
127 #ifdef TCL_WRAPPER
128 extern Tcl_Interp *xcinterp;
129 #else
130 extern XtAppContext app;
131 #endif
132 
133 #if !defined(HAVE_CAIRO)
134 extern Pixmap dbuf;
135 #endif
136 
137 /* Bad hack for problems with the DECstation. . . don't know why */
138 #ifdef UniqueContextProblem
139 #undef XUniqueContext
XUniqueContext()140 XContext XUniqueContext()
141 {
142    return XrmUniqueQuark();
143 }
144 #endif
145 /* End of bad hack. . . */
146 
147 /*----------------------------------------------------------------------*/
148 /* Update the list of colors in the colormap				*/
149 /*----------------------------------------------------------------------*/
150 
addtocolorlist(xcWidget button,int cvalue)151 void addtocolorlist(xcWidget button, int cvalue)
152 {
153    number_colors++;
154    colorlist = (colorindex *)realloc(colorlist, number_colors *
155 		sizeof(colorindex));
156    colorlist[number_colors - 1].cbutton = button;
157    colorlist[number_colors - 1].color.pixel = cvalue;
158 
159    /* Get and store the RGB values of the new color */
160 
161    if (areawin && (areawin->area == NULL)) {
162       colorlist[number_colors - 1].color.red = 256 * (cvalue & 0xff);
163       colorlist[number_colors - 1].color.green = 256 * ((cvalue >> 8) & 0xff);
164       colorlist[number_colors - 1].color.blue = 256 * ((cvalue >> 16) & 0xff);
165    }
166    else
167       XQueryColors(dpy, cmap, &(colorlist[number_colors - 1].color), 1);
168 }
169 
170 /*----------------------------------------------------------------------*/
171 /* Add a new color button to the color menu				*/
172 /* 	called if new color button needs to be made 			*/
173 /*----------------------------------------------------------------------*/
174 
175 #ifdef TCL_WRAPPER
176 
addnewcolorentry(int ccolor)177 int addnewcolorentry(int ccolor)
178 {
179   xcWidget newbutton = (xcWidget)NULL;
180   int i;
181 
182    /* check to see if entry is already in the color list */
183 
184    for (i = NUMBER_OF_COLORS; i < number_colors; i++)
185       if (colorlist[i].color.pixel == ccolor) break;
186 
187    /* make new entry in the menu */
188 
189    if (i == number_colors) {
190       addtocolorlist(newbutton, ccolor);
191       sprintf(_STR2,
192 	"xcircuit::newcolorbutton %d %d %d %d",
193 	    colorlist[i].color.red, colorlist[i].color.green,
194 	    colorlist[i].color.blue, i);
195       Tcl_Eval(xcinterp, _STR2);
196    }
197    return i;
198 }
199 
200 #endif /* TCL_WRAPPER */
201 
202 /*---------------*/
203 /* Quit xcircuit */
204 /*---------------*/
205 
quit(xcWidget w,caddr_t nulldata)206 void quit(xcWidget w, caddr_t nulldata)
207 {
208    int i;
209    Matrixptr curmatrix, dmatrix;
210 
211    /* free up CTM Matrix Stack */
212    if (areawin != NULL) {
213       curmatrix = areawin->MatStack;
214       while (curmatrix != NULL) {
215          dmatrix = curmatrix->nextmatrix;
216          free(curmatrix);
217          curmatrix = dmatrix;
218       }
219       areawin->MatStack = NULL;
220    }
221 
222    /* free the colormap if a new one has been installed */
223 
224    if (dpy != NULL)
225       if (cmap != DefaultColormap(dpy, DefaultScreen(dpy)))
226          XFreeColormap(dpy, cmap);
227 
228    /* exit ghostscript if background rendering was enabled */
229 
230    exit_gs();
231 
232 #ifdef TCL_WRAPPER
233    /* exit ngspice if the simulator is still running */
234 
235    exit_spice();
236 #endif
237 
238    /* remove any temporary files created for background rendering */
239 
240    for (i = 0; i < xobjs.pages; i++) {
241       if (xobjs.pagelist[i]->pageinst != NULL)
242          if (xobjs.pagelist[i]->background.name != (char *)NULL)
243 	    if (*(xobjs.pagelist[i]->background.name) == '@')
244 	       unlink(xobjs.pagelist[i]->background.name + 1);
245    }
246 
247    /* remove the temporary file and free the filename memory	*/
248    /* if w = NULL, quit() was reached from Ctrl-C.  Don't 	*/
249    /* remove the temporary file;  instead, notify user of the 	*/
250    /* filename.							*/
251 
252    if (xobjs.tempfile != NULL) {
253       if (w != NULL) {
254 #ifndef XC_WIN32
255          if (unlink(xobjs.tempfile) < 0)
256 	    Fprintf(stderr, "Error %d unlinking file \"%s\"\n", errno, xobjs.tempfile);
257 #else
258          if (DeleteFile(xobjs.tempfile) != TRUE)
259 	    Fprintf(stderr, "Error %d unlinking file \"%s\"\n",
260 			GetLastError(), xobjs.tempfile);
261 #endif
262       }
263       else
264 	 Fprintf(stderr, "Ctrl-C exit:  reload workspace from \"%s\"\n",
265 		xobjs.tempfile);
266       free(xobjs.tempfile);
267       xobjs.tempfile = NULL;
268    }
269 
270 #if defined(HAVE_PYTHON)
271    /* exit by exiting the Python interpreter, if enabled */
272    exit_interpreter();
273 #elif defined(TCL_WRAPPER)
274    /* Let Tcl/Tk handle exit */
275    return;
276 #elif defined(XC_WIN32)
277    PostQuitMessage(0);
278 #else
279    exit(0);
280 #endif
281 
282 }
283 
284 /*--------------------------------------------------------------*/
285 /* Check for changes in an object and all of its descendents	*/
286 /*--------------------------------------------------------------*/
287 
getchanges(objectptr thisobj)288 u_short getchanges(objectptr thisobj)
289 {
290    genericptr *pgen;
291    objinstptr pinst;
292    u_short changes = thisobj->changes;
293 
294    for (pgen = thisobj->plist; pgen < thisobj->plist + thisobj->parts; pgen++) {
295       if (IS_OBJINST(*pgen)) {
296 	 pinst = TOOBJINST(pgen);
297 	 changes += getchanges(pinst->thisobject);
298       }
299    }
300    return changes;
301 }
302 
303 /*--------------------------------------------------------------*/
304 /* Check to see if any objects in xcircuit have been modified	*/
305 /* without saving.						*/
306 /*--------------------------------------------------------------*/
307 
countchanges(char ** promptstr)308 u_short countchanges(char **promptstr)
309 {
310   int slen = 1, i; /* , j; (jdk) */
311    u_short locchanges, changes = 0, words = 1;
312    objectptr thisobj;
313    char *fname;
314    TechPtr ns;
315 
316    if (promptstr != NULL) slen += strlen(*promptstr);
317 
318    for (i = 0; i < xobjs.pages; i++) {
319       if (xobjs.pagelist[i]->pageinst != NULL) {
320 	 thisobj = xobjs.pagelist[i]->pageinst->thisobject;
321 	 locchanges = getchanges(thisobj);
322          if (locchanges > 0) {
323 	    if (promptstr != NULL) {
324 	       slen += strlen(thisobj->name) + 2;
325 	       *promptstr = (char *)realloc(*promptstr, slen);
326 	       if ((words % 8) == 0) strcat(*promptstr, ",\n");
327 	       else if (changes > 0) strcat(*promptstr, ", ");
328 	       strcat(*promptstr, thisobj->name);
329 	       words++;
330 	    }
331 	    changes += locchanges;
332 	 }
333       }
334    }
335 
336    /* Check all library objects for unsaved changes */
337 
338    for (ns = xobjs.technologies; ns != NULL; ns = ns->next) {
339       tech_set_changes(ns);
340       if ((ns->flags & TECH_CHANGED) != 0) {
341 	 changes++;
342 	 if (promptstr != NULL) {
343 	    fname = ns->filename;
344 	    if (fname != NULL) {
345 	       slen += strlen(fname) + 2;
346 	       *promptstr = (char *)realloc(*promptstr, slen);
347 	       if ((words % 8) == 0) strcat(*promptstr, ",\n");
348 	       else if (changes > 0) strcat(*promptstr, ", ");
349 	       strcat(*promptstr, fname);
350 	       words++;
351 	    }
352 	 }
353       }
354    }
355    return changes;
356 }
357 
358 /*----------------------------------------------*/
359 /* Check for conditions to approve program exit */
360 /* Return 0 if prompt "Okay" button ends the	*/
361 /* program, 1 if the program should exit	*/
362 /* immediately.					*/
363 /*----------------------------------------------*/
364 
365 #ifdef TCL_WRAPPER
366 
quitcheck(xcWidget w,caddr_t clientdata,caddr_t calldata)367 int quitcheck(xcWidget w, caddr_t clientdata, caddr_t calldata)
368 {
369    char *promptstr;
370    Boolean doprompt = False;
371 
372    /* enable default interrupt signal handler during this time, so that */
373    /* a double Control-C will ALWAYS exit.				*/
374 
375    signal(SIGINT, SIG_DFL);
376 
377    promptstr = (char *)malloc(60);
378    strcpy(promptstr, ".query.title.field configure -text \"Unsaved changes in: ");
379 
380    /* Check all page objects for unsaved changes */
381 
382    doprompt = (countchanges(&promptstr) > 0) ? True : False;
383 
384    /* If any changes have not been saved, generate a prompt */
385 
386    if (doprompt) {
387       promptstr = (char *)realloc(promptstr, strlen(promptstr) + 15);
388       strcat(promptstr, "\nQuit anyway?");
389 
390       strcat(promptstr, "\"");
391       Tcl_Eval(xcinterp, promptstr);
392       Tcl_Eval(xcinterp, ".query.bbar.okay configure -command {quitnocheck}");
393       Tcl_Eval(xcinterp, "wm deiconify .query");
394       Tcl_Eval(xcinterp, "raise .query");
395       free(promptstr);
396       return 0;
397    }
398    else {
399       free(promptstr);
400       quit(w, NULL);				// preparation for quit
401       if (calldata != (caddr_t)NULL)
402          Tcl_Eval(xcinterp, "quitnocheck intr");
403       else
404          Tcl_Eval(xcinterp, "quitnocheck");	// actual quit
405       return 1;					// not reached
406    }
407 }
408 
409 #endif
410 
411 /*--------------------------------------*/
412 /* A gentle Ctrl-C shutdown		*/
413 /*--------------------------------------*/
414 
dointr(int signum)415 void dointr(int signum)
416 {
417    quitcheck(NULL, NULL, (caddr_t)1);
418 }
419 
420 /*--------------*/
421 /* Null routine */
422 /*--------------*/
423 
DoNothing(xcWidget w,caddr_t clientdata,caddr_t calldata)424 void DoNothing(xcWidget w, caddr_t clientdata, caddr_t calldata)
425 {
426    /* Nothing here! */
427 }
428 
429 /*-----------------------------------------------------------------------*/
430 /* Write page scale (overall scale, and X and Y dimensions) into strings */
431 /*-----------------------------------------------------------------------*/
432 
writescalevalues(char * scdest,char * xdest,char * ydest)433 void writescalevalues(char *scdest, char *xdest, char *ydest)
434 {
435    float oscale, psscale;
436    int width, height;
437    Pagedata    *curpage;
438 
439    curpage = xobjs.pagelist[areawin->page];
440    oscale = curpage->outscale;
441    psscale = getpsscale(oscale, areawin->page);
442 
443    width = toplevelwidth(curpage->pageinst, NULL);
444    height = toplevelheight(curpage->pageinst, NULL);
445 
446    sprintf(scdest, "%6.5f", oscale);
447    if (curpage->coordstyle == CM) {
448       sprintf(xdest, "%6.5f", (width * psscale) / IN_CM_CONVERT);
449       sprintf(ydest, "%6.5f", (height * psscale) / IN_CM_CONVERT);
450    }
451    else {
452       sprintf(xdest, "%6.5f", (width * psscale) / 72.0);
453       sprintf(ydest, "%6.5f", (height * psscale) / 72.0);
454    }
455 }
456 
457 /*-------------------------------------------------------------------------*/
458 /* Destroy an interactive text-editing popup box 			   */
459 /*-------------------------------------------------------------------------*/
460 
461 #ifdef TCL_WRAPPER
462 
463 /* Just pop it down. . . */
464 
destroypopup(xcWidget button,popupstruct * callstruct,caddr_t calldata)465 void destroypopup(xcWidget button, popupstruct *callstruct, caddr_t calldata)
466 {
467    Tk_UnmapWindow(callstruct->popup);
468    popups--;
469 
470    /* free the allocated structure space */
471 
472    free(callstruct->buttonptr);
473    if (callstruct->filter != NULL) free(callstruct->filter);
474    free(callstruct);
475 
476    /* in the case of "quitcheck", we want to make sure that the signal	*/
477    /* handler is reset to default behavior if the quit command is	*/
478    /* canceled from inside the popup prompt window.			*/
479 
480    signal(SIGINT, dointr);
481 }
482 
483 /*-------------------------------------------------------------------------*/
484 /* Create a popup window with "OK" and "Cancel" buttons,		   */
485 /* and text and label fields.						   */
486 /*-------------------------------------------------------------------------*/
487 
popupprompt(xcWidget button,char * request,char * current,void (* function)(),buttonsave * datastruct,const char * filter)488 void popupprompt(xcWidget button, char *request, char *current, void (*function)(),
489 	buttonsave *datastruct, const char *filter)
490 {
491     Tk_Window popup;
492 
493     popup = Tk_NameToWindow(xcinterp, ".dialog", Tk_MainWindow(xcinterp));
494     Tk_MapWindow(popup);
495 }
496 
497 /*----------------------------------------------------------------------*/
498 /* Create a popup window for property changes				*/
499 /*----------------------------------------------------------------------*/
500 
outputpopup(xcWidget button,caddr_t clientdata,caddr_t calldata)501 void outputpopup(xcWidget button, caddr_t clientdata, caddr_t calldata)
502 {
503     Tcl_Eval(xcinterp, "wm deiconify .output");
504 }
505 
506 /*----------------------------------------------------------------------*/
507 /* Get the display resolution.  This is needed especially for retinal	*/
508 /* displays with 4x the DPI of typical displays.  Keeping the DPI value	*/
509 /* around is useful for determing a sane size for fonts, buttons,	*/
510 /* scrollbar widths, etc.						*/
511 /*									*/
512 /* Note that this routine does not go so far as to handle non-square	*/
513 /* pixels.								*/
514 /*									*/
515 /* The first check is to look for Xft.dpi in the X resource database.	*/
516 /* If it is not found, then fall back on the DisplayWidth as reported	*/
517 /* by Xlib (to do:  Override both of these with an environment variable	*/
518 /* such as XCIRCUIT_DPI).						*/
519 /*----------------------------------------------------------------------*/
520 
getscreenDPI()521 int getscreenDPI()
522 {
523     int x, xmm, dpi;
524 
525     XrmDatabase  db;
526     XrmValue	val;
527     char *resource_manager;
528     char *type, *var;
529 
530     XrmInitialize();
531     resource_manager = XResourceManagerString(dpy);
532 
533     if (resource_manager != NULL) {
534 	db = XrmGetStringDatabase(resource_manager);
535 	if (db != NULL) {
536 	    XrmGetResource(db, "Xft.dpi", "String", &type, &val);
537 	    if (val.addr != NULL && !strncmp("String", type, 64))
538 		if (sscanf(val.addr, "%d", &dpi) == 1)
539 		    return dpi;
540 	}
541     }
542 
543     x = DisplayWidth(dpy, DefaultScreen(dpy));
544     xmm = DisplayWidthMM(dpy, DefaultScreen(dpy));
545     dpi = (int)(((float)x + 0.5) / (float)(xmm / 25.4));
546     return dpi;
547 }
548 
549 /*-------------------------------------------------*/
550 /* Print a string to the message widget. 	   */
551 /* Note: Widget message must be a global variable. */
552 /* For formatted strings, format first into _STR   */
553 /*-------------------------------------------------*/
554 
555 /* XXX it looks like this routine is an orphan */
clrmessage(caddr_t clientdata)556 void clrmessage(caddr_t clientdata)
557 {
558    char buf1[50], buf2[50];
559 
560    /* Don't write over the report of the edit string contents,	*/
561    /* if we're in one of the label edit modes 			*/
562 
563    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE)
564       charreport(TOLABEL(EDITPART));
565    else {
566       measurestr(xobjs.pagelist[areawin->page]->gridspace, buf1);
567       measurestr(xobjs.pagelist[areawin->page]->snapspace, buf2);
568       Wprintf("Grid %.50s : Snap %.50s", buf1, buf2);
569    }
570 }
571 
572 #endif /* TCL_WRAPPER */
573 
574 /*------------------------------------------------------------------------------*/
575 /* diagnostic tool for translating the event mode into a string and printing	*/
576 /* to stderr (for debugging only).						*/
577 /*------------------------------------------------------------------------------*/
578 
printeventmode()579 void printeventmode() {
580    Fprintf(stderr, "eventmode is \'");
581    switch(eventmode) {
582       case NORMAL_MODE:
583 	 Fprintf(stderr, "NORMAL");
584 	 break;
585       case MOVE_MODE:
586 	 Fprintf(stderr, "MOVE");
587 	 break;
588       case COPY_MODE:
589 	 Fprintf(stderr, "COPY");
590 	 break;
591       case SELAREA_MODE:
592 	 Fprintf(stderr, "SELAREA");
593 	 break;
594       case CATALOG_MODE:
595 	 Fprintf(stderr, "CATALOG");
596 	 break;
597       case CATTEXT_MODE:
598 	 Fprintf(stderr, "CATTEXT");
599 	 break;
600       case CATMOVE_MODE:
601 	 Fprintf(stderr, "CATMOVE");
602 	 break;
603       case FONTCAT_MODE:
604 	 Fprintf(stderr, "FONTCAT");
605 	 break;
606       case EFONTCAT_MODE:
607 	 Fprintf(stderr, "EFONTCAT");
608 	 break;
609       case TEXT_MODE:
610 	 Fprintf(stderr, "TEXT");
611 	 break;
612       case ETEXT_MODE:
613 	 Fprintf(stderr, "ETEXT");
614 	 break;
615       case WIRE_MODE:
616 	 Fprintf(stderr, "WIRE");
617 	 break;
618       case BOX_MODE:
619 	 Fprintf(stderr, "BOX");
620 	 break;
621       case EPOLY_MODE:
622 	 Fprintf(stderr, "EPOLY");
623 	 break;
624       case ARC_MODE:
625 	 Fprintf(stderr, "ARC");
626 	 break;
627       case EARC_MODE:
628 	 Fprintf(stderr, "EARC");
629 	 break;
630       case SPLINE_MODE:
631 	 Fprintf(stderr, "SPLINE");
632 	 break;
633       case ESPLINE_MODE:
634 	 Fprintf(stderr, "ESPLINE");
635 	 break;
636       case EPATH_MODE:
637 	 Fprintf(stderr, "EPATH");
638 	 break;
639       case EINST_MODE:
640 	 Fprintf(stderr, "EINST");
641 	 break;
642       case ASSOC_MODE:
643 	 Fprintf(stderr, "ASSOC");
644 	 break;
645       case RESCALE_MODE:
646 	 Fprintf(stderr, "RESCALE");
647 	 break;
648       case PAN_MODE:
649 	 Fprintf(stderr, "PAN");
650 	 break;
651       default:
652 	 Fprintf(stderr, "(unknown)");
653 	 break;
654    }
655    Fprintf(stderr, "_MODE\'\n");
656 }
657 
658 /*------------------------------------------------------------------------------*/
659 
660 #ifdef TCL_WRAPPER
661 
662 /*------------------------------------------------------------------------------*/
663 /* "docommand" de-iconifies the TCL console.					*/
664 /*------------------------------------------------------------------------------*/
665 
docommand()666 void docommand()
667 {
668    Tcl_Eval(xcinterp, "catch xcircuit::raiseconsole");
669 }
670 
671 /*------------------------------------------------------------------------------*/
672 /* When all else fails, install your own colormap			 	*/
673 /*------------------------------------------------------------------------------*/
674 
installowncmap()675 int installowncmap()
676 {
677    Colormap newcmap;
678 
679    Fprintf(stdout, "Installing my own colormap\n");
680 
681    /* allocate a new colormap */
682 
683    newcmap = XCopyColormapAndFree(dpy, cmap);
684    if (newcmap == (Colormap)NULL) return (-1);
685    cmap = newcmap;
686    return(1);
687 }
688 
689 #endif /* TCL_WRAPPER */
690 
691 /*------------------------------------------------------------------------------*/
692 /* Find the nearest color in the colormap to cvexact and return its pixel value */
693 /*------------------------------------------------------------------------------*/
694 
695 #if defined(TCL_WRAPPER) || !defined(XC_WIN32)
696 
findnearcolor(XColor * cvexact)697 int findnearcolor(XColor *cvexact)
698 {
699    /* find the nearest-matching color in the colormap */
700 
701    int i, ncolors = DisplayCells(dpy, DefaultScreen(dpy));
702    XColor *cmcolors;
703    long rdist, bdist, gdist;
704    u_long dist, mindist;
705    int minidx;
706 
707    cmcolors = (XColor *)malloc(ncolors * sizeof(XColor));
708 
709    for (i = 0; i < ncolors; i++) {
710       cmcolors[i].pixel = i;
711       cmcolors[i].flags = DoRed | DoGreen | DoBlue;
712    }
713    XQueryColors(dpy, cmap, cmcolors, ncolors);
714 
715    mindist = ULONG_MAX;
716    for (i = 0; i < ncolors; i++) {
717       rdist = (cmcolors[i].red - cvexact->red);
718       bdist = (cmcolors[i].blue - cvexact->blue);
719       gdist = (cmcolors[i].green - cvexact->green);
720       dist = rdist * rdist + bdist * bdist + gdist * gdist;
721       if (dist < mindist) {
722 	 mindist = dist;
723 	 minidx = i;
724       }
725    }
726    free(cmcolors);
727 
728    /* if we can't get the right color or something reasonably close, */
729    /* then allocate our own colormap.  If we've allocated so many    */
730    /* colors that the new colormap is full, then we give up and use  */
731    /* whatever color was closest, no matter how far away it was.     */
732 
733    /* findnearcolor already used 512 per component, so to match that, */
734    /* 3 * (512 * 512) = 786432	~= 750000			      */
735 
736    if (dist > 750000) {
737       if (installowncmap() > 0) {
738          if (XAllocColor(dpy, cmap, cvexact) != 0)
739 	    minidx = cvexact->pixel;
740       }
741    }
742 
743    return minidx;
744 }
745 
746 #endif
747 
748 /*----------------------------------------------------------------------*/
749 /* Return the pixel value of a database color in the colorlist vector	*/
750 /* Since this is generally called by defined name, e.g.,		*/
751 /* xc_getlayoutcolor(RATSNESTCOLOR), it does not check for invalid	*/
752 /* values of cidx.							*/
753 /*----------------------------------------------------------------------*/
754 
xc_getlayoutcolor(int cidx)755 int xc_getlayoutcolor(int cidx)
756 {
757    return colorlist[cidx].color.pixel;
758 }
759 
760 /*----------------------------------------------------------------------*/
761 /* Obtain red, green and blue values from a color index                 */
762 /* the colour values range from 0 to 65535                              */
763 /*----------------------------------------------------------------------*/
764 
xc_get_color_rgb(unsigned long cidx,unsigned short * red,unsigned short * green,unsigned short * blue)765 void xc_get_color_rgb(unsigned long cidx, unsigned short *red,
766       unsigned short *green, unsigned short *blue)
767 {
768    XColor loccolor = {
769          .pixel = cidx,
770          .flags = DoRed | DoGreen | DoBlue
771    };
772    if (areawin->area == NULL) {
773       loccolor.red = cidx & 0xff;
774       loccolor.green = (cidx >> 8) & 0xff;
775       loccolor.blue = (cidx >> 16) & 0xff;
776    }
777    else
778       XQueryColors(dpy, cmap, &loccolor, 1);
779    *red = loccolor.red;
780    *green = loccolor.green;
781    *blue = loccolor.blue;
782 }
783 
784 
785 /*-------------------------------------------------------------------------*/
786 /* Hack on the resource database Color allocation			   */
787 /*									   */
788 /* This overrides the built-in routine.  The difference is that if a	   */
789 /* color cell cannot be allocated (colormap is full), then the color	   */
790 /* map is searched for the closest RGB value to the named color.	   */
791 /*									   */
792 /* This code depends on Display *dpy being set:  Do not install the	   */
793 /* converter until after XtInitialize(), when using the Xt (not Tcl) GUI.  */
794 /*-------------------------------------------------------------------------*/
795 
796 #if defined(TCL_WRAPPER) || !defined(XC_WIN32)
797 
CvtStringToPixel(XrmValuePtr args,int * nargs,XrmValuePtr fromVal,XrmValuePtr toVal)798 caddr_t CvtStringToPixel(XrmValuePtr args, int *nargs, XrmValuePtr fromVal,
799 	XrmValuePtr toVal)
800 {
801    static XColor cvcolor;
802    XColor cvexact;
803 
804    if (dpy == NULL) return NULL;
805 
806    if (*nargs != 0)
807       Fprintf(stderr, "String to Pixel conversion takes no arguments");
808 
809    /* Color defaults to black if name is not found */
810 
811    if (XAllocNamedColor(dpy, cmap, (char *)fromVal->addr, &cvcolor, &cvexact)
812 	 == 0) {
813       if (XLookupColor(dpy, cmap, (char *)fromVal->addr, &cvexact, &cvcolor) == 0)
814 	 cvcolor.pixel = BlackPixel(dpy, DefaultScreen(dpy));
815       else
816 	 cvcolor.pixel = findnearcolor(&cvexact);
817    }
818 
819    toVal->size = sizeof(u_long);
820    toVal->addr = (caddr_t) &(cvcolor.pixel);
821    return NULL;
822 }
823 
824 #endif
825 
826 /*-------------------------------------------------------------------------*/
827 /* Allocate new color using the CvtStringToPixel routine		   */
828 /*-------------------------------------------------------------------------*/
829 
830 #if defined(XC_WIN32) && !defined(TCL_WRAPPER)
831 
xc_alloccolor(char * name)832 int xc_alloccolor(char *name)
833 {
834    return WinNamedColor(name);
835 }
836 
837 #else
838 
xc_alloccolor(char * name)839 int xc_alloccolor(char *name)
840 {
841    XrmValue fromC, toC;
842    int zval = 0, pixval;
843 
844    fromC.size = strlen(name);
845    fromC.addr = name;
846 
847    if (areawin && (areawin->area)) {
848       CvtStringToPixel(NULL, &zval, &fromC, &toC);
849       pixval = (int)(*((u_long *)toC.addr));
850    }
851    else {
852       int r, g, b;
853 
854       /* Graphics-free batch mode.  Handle basic colors plus RGB */
855       if (name[0] == '#' && (strlen(name) == 7)) {
856          sscanf(&name[1], "%2x", &r);
857          sscanf(&name[3], "%2x", &g);
858          sscanf(&name[5], "%2x", &b);
859          pixval = r + g * 256 + b * 65536;
860       }
861       else if (name[0] == '#' && (strlen(name) == 13)) {
862          sscanf(&name[1], "%4x", &r);
863          sscanf(&name[5], "%4x", &g);
864          sscanf(&name[9], "%4x", &b);
865          pixval = (r >> 8) + (g >> 8) * 256 + (b >> 8) * 65536;
866       }
867       else if (sscanf(name, "%d", &pixval) != 1) {
868 	 if (!strcasecmp(name, "red")) {
869 	    r = 255;
870 	    g = 0;
871 	    b = 0;
872 	 }
873 	 else if (!strcasecmp(name, "green")) {
874 	    r = 0;
875 	    g = 255;
876 	    b = 0;
877 	 }
878 	 else if (!strcasecmp(name, "blue")) {
879 	    r = 0;
880 	    g = 0;
881 	    b = 255;
882 	 }
883 	 else if (!strcasecmp(name, "white")) {
884 	    r = 255;
885 	    g = 255;
886 	    b = 255;
887 	 }
888 	 else if (!strcasecmp(name, "gray")) {
889 	    r = 128;
890 	    g = 128;
891 	    b = 128;
892 	 }
893 	 else if (!strcasecmp(name, "yellow")) {
894 	    r = 255;
895 	    g = 255;
896 	    b = 0;
897 	 }
898 	 else if (!strcasecmp(name, "gray40")) {
899 	    r = 102;
900 	    g = 102;
901 	    b = 102;
902 	 }
903 	 else if (!strcasecmp(name, "gray60")) {
904 	    r = 153;
905 	    g = 153;
906 	    b = 153;
907 	 }
908 	 else if (!strcasecmp(name, "gray80")) {
909 	    r = 204;
910 	    g = 204;
911 	    b = 204;
912 	 }
913 	 else if (!strcasecmp(name, "gray90")) {
914 	    r = 229;
915 	    g = 229;
916 	    b = 229;
917 	 }
918 	 else if (!strcasecmp(name, "green2")) {
919 	    r = 0;
920 	    g = 238;
921 	    b = 0;
922 	 }
923 	 else if (!strcasecmp(name, "purple")) {
924 	    r = 160;
925 	    g = 32;
926 	    b = 240;
927 	 }
928 	 else if (!strcasecmp(name, "steelblue2")) {
929 	    r = 92;
930 	    g = 172;
931 	    b = 238;
932 	 }
933 	 else if (!strcasecmp(name, "red3")) {
934 	    r = 205;
935 	    g = 0;
936 	    b = 0;
937 	 }
938 	 else if (!strcasecmp(name, "tan")) {
939 	    r = 210;
940 	    g = 180;
941 	    b = 140;
942 	 }
943 	 else if (!strcasecmp(name, "brown")) {
944 	    r = 165;
945 	    g = 42;
946 	    b = 42;
947 	 }
948 	 else if (!strcasecmp(name, "pink")) {
949 	    r = 255;
950 	    g = 192;
951 	    b = 203;
952 	 }
953          else {
954 	    // Default to black
955 	    r = 0;
956 	    g = 0;
957 	    b = 0;
958 	 }
959          pixval = r + g * 256 + b * 65536;
960       }
961    }
962 
963    return pixval;
964 }
965 
966 #endif
967 
968 /*----------------------------------------------------------------------*/
969 /* Check if color within RGB roundoff error exists in xcircuit's color	*/
970 /* table.  Assume 24-bit color, in which resolution can be no less than	*/
971 /* 256 for each color component.  Visual acuity is a bit less than 24-	*/
972 /* bit color, so assume difference should be no less than 512 per	*/
973 /* component for colors to be considered "different".  Psychologically,	*/
974 /* we should really find the just-noticable-difference for each color	*/
975 /* component separately!  But that's too complicated for this simple	*/
976 /* routine.								*/
977 /*									*/
978 /* Return the table entry of the color, if it is in xcircuit's color	*/
979 /* table, or ERRORCOLOR if not.  If it is in the color table, then	*/
980 /* return the actual pixel value from the table in the "pixval" pointer	*/
981 /*----------------------------------------------------------------------*/
982 
rgb_querycolor(int red,int green,int blue,int * pixval)983 int rgb_querycolor(int red, int green, int blue, int *pixval)
984 {
985    int i;
986 
987    for (i = NUMBER_OF_COLORS; i < number_colors; i++) {
988       if (abs(colorlist[i].color.red - red) < 512 &&
989 	     abs(colorlist[i].color.green - green) < 512 &&
990 	     abs(colorlist[i].color.blue - blue) < 512) {
991 	 if (pixval)
992 	    *pixval = colorlist[i].color.pixel;
993 	 return i;
994 	 break;
995       }
996    }
997    return ERRORCOLOR;
998 }
999 
1000 /*-----------------------------------------------------------------------*/
1001 /* Allocate new color from RGB values (e.g., from PS file "scb" command) */
1002 /*-----------------------------------------------------------------------*/
1003 
1004 #if defined(XC_WIN32) && !defined(TCL_WRAPPER)
1005 
rgb_alloccolor(int red,int green,int blue)1006 int rgb_alloccolor(int red, int green, int blue)
1007 {
1008    ERROR FIXME!
1009    // XCircuit version 3.9:  This no longer works.  Need to
1010    // allocate the color and return an index into colorlist[].
1011 
1012    return RGB(red >> 8, green >> 8, blue >> 8);
1013 }
1014 
1015 #else
1016 
rgb_alloccolor(int red,int green,int blue)1017 int rgb_alloccolor(int red, int green, int blue)
1018 {
1019    XColor newcolor;
1020    int pixval, tableidx; /* i, (jdk) */
1021 
1022    /* if color is not already in list, try to allocate it; if allocation */
1023    /* fails, grab the closest match in the colormap.			 */
1024 
1025    tableidx = rgb_querycolor(red, green, blue, &pixval);
1026 
1027    if (tableidx < 0) {
1028       newcolor.red = red;
1029       newcolor.green = green;
1030       newcolor.blue = blue;
1031       newcolor.flags = DoRed | DoGreen | DoBlue;
1032       if (areawin->area) {
1033          if (XAllocColor(dpy, cmap, &newcolor) == 0)
1034             pixval = findnearcolor(&newcolor);
1035          else
1036 	    pixval = newcolor.pixel;
1037       }
1038       else {
1039 	 // No graphics mode:  Force pixel to be 24 bit RGB
1040 	 pixval = (red & 0xff) | ((blue & 0xff) << 8) | ((green & 0xff) << 16);
1041       }
1042 
1043       // Add this to the colormap
1044       tableidx = addnewcolorentry(pixval);
1045    }
1046    return tableidx;
1047 }
1048 
1049 #endif
1050 
1051 /*----------------------------------------------------------------------*/
1052 /* Query a color by name to see if it is in the color table.		*/
1053 /* Return the table index (NOT the pixel value) of the entry, 		*/
1054 /* ERRORCOLOR if the color is not in the table, and BADCOLOR if the	*/
1055 /* color name could not be parsed by XLookupColor().			*/
1056 /*----------------------------------------------------------------------*/
1057 
query_named_color(char * cname)1058 int query_named_color(char *cname)
1059 {
1060    XColor cvcolor, cvexact;
1061    int tableidx, result = 0;
1062 
1063    if (areawin->area)
1064       result = XLookupColor(dpy, cmap, cname, &cvexact, &cvcolor);
1065 
1066    if (result == 0) return BADCOLOR;
1067 
1068    tableidx = rgb_querycolor(cvcolor.red, cvcolor.green, cvcolor.blue, NULL);
1069    return tableidx;
1070 }
1071 
1072 /*-------------------------------------------------------------------------*/
1073 /* Make the cursors from the cursor bit data				   */
1074 /*-------------------------------------------------------------------------*/
1075 
makecursors()1076 void makecursors()
1077 {
1078    XColor fgcolor, bgcolor;
1079    Window win = areawin->window;
1080 #ifdef TCL_WRAPPER
1081    Tk_Uid fg_uid, bg_uid;
1082 #endif
1083 
1084    if (areawin->area == NULL) return;
1085 
1086    bgcolor.pixel = colorlist[BACKGROUND].color.pixel;
1087    fgcolor.pixel = colorlist[FOREGROUND].color.pixel;
1088    XQueryColors(dpy, cmap, &fgcolor, 1);
1089    XQueryColors(dpy, cmap, &bgcolor, 1);
1090 
1091 #ifdef TCL_WRAPPER
1092 
1093 #ifdef XC_WIN32
1094 #define Tk_GetCursorFromData CreateW32Cursor
1095 #endif
1096 
1097    fg_uid = Tk_GetUid(Tk_NameOfColor(&fgcolor));
1098    bg_uid = Tk_GetUid(Tk_NameOfColor(&bgcolor));
1099 
1100    ARROW = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1101 	arrow_bits, arrowmask_bits, arrow_width, arrow_height, arrow_x_hot, arrow_y_hot,
1102 	fg_uid, bg_uid);
1103    CROSS = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1104 	cross_bits, crossmask_bits, cross_width, cross_height, cross_x_hot, cross_y_hot,
1105 	fg_uid, bg_uid);
1106    SCISSORS = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1107 	scissors_bits, scissorsmask_bits, scissors_width, scissors_height,
1108 	scissors_x_hot, scissors_y_hot, fg_uid, bg_uid);
1109    EDCURSOR = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1110 	exx_bits, exxmask_bits, exx_width, exx_height, exx_x_hot, exx_y_hot,
1111 	fg_uid, bg_uid);
1112    COPYCURSOR = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1113 	copy_bits, copymask_bits, copy_width, copy_height, copy_x_hot, copy_y_hot,
1114 	fg_uid, bg_uid);
1115    ROTATECURSOR = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1116 	rot_bits, rotmask_bits, rot_width, rot_height, circle_x_hot, circle_y_hot,
1117 	fg_uid, bg_uid);
1118    QUESTION = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1119 	question_bits, questionmask_bits, question_width, question_height,
1120 	question_x_hot, question_y_hot, fg_uid, bg_uid);
1121    CIRCLE = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1122 	circle_bits, circlemask_bits, circle_width, circle_height, circle_x_hot,
1123 	circle_y_hot, fg_uid, bg_uid);
1124    HAND = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win),
1125 	hand_bits, handmask_bits, hand_width, hand_height, hand_x_hot, hand_y_hot,
1126 	fg_uid, bg_uid);
1127 
1128 #ifdef XC_WIN32
1129 #undef Tk_GetCursorFromData
1130 #endif
1131 
1132 #else
1133    ARROW = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, arrow_bits,
1134 	arrow_width, arrow_height), XCreateBitmapFromData(dpy, win, arrowmask_bits,
1135 	arrow_width, arrow_height), &fgcolor, &bgcolor, arrow_x_hot, arrow_y_hot);
1136    CROSS = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, cross_bits,
1137 	cross_width, cross_height), XCreateBitmapFromData(dpy, win, crossmask_bits,
1138 	cross_width, cross_height), &fgcolor, &bgcolor, cross_x_hot, cross_y_hot);
1139    SCISSORS = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, scissors_bits,
1140 	scissors_width, scissors_height), XCreateBitmapFromData(dpy, win,
1141 	scissorsmask_bits, scissors_width, scissors_height), &fgcolor,
1142 	&bgcolor, scissors_x_hot, scissors_y_hot);
1143    EDCURSOR = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, exx_bits,
1144 	exx_width, exx_height), XCreateBitmapFromData(dpy, win, exxmask_bits,
1145 	exx_width, exx_height), &fgcolor, &bgcolor, exx_x_hot, exx_y_hot);
1146    COPYCURSOR = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, copy_bits,
1147 	copy_width, copy_height), XCreateBitmapFromData(dpy, win, copymask_bits,
1148 	copy_width, copy_height), &fgcolor, &bgcolor, copy_x_hot, copy_y_hot);
1149    ROTATECURSOR = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, rot_bits,
1150 	rot_width, rot_height), XCreateBitmapFromData(dpy, win, rotmask_bits,
1151 	rot_width, rot_height), &fgcolor, &bgcolor, circle_x_hot, circle_y_hot);
1152    QUESTION = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, question_bits,
1153 	question_width, question_height), XCreateBitmapFromData(dpy, win,
1154 	questionmask_bits, question_width, question_height),
1155 	&fgcolor, &bgcolor, question_x_hot, question_y_hot);
1156    CIRCLE = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, circle_bits,
1157 	circle_width, circle_height), XCreateBitmapFromData(dpy, win, circlemask_bits,
1158 	circle_width, circle_height), &fgcolor, &bgcolor, circle_x_hot, circle_y_hot);
1159    HAND = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, hand_bits,
1160 	hand_width, hand_height), XCreateBitmapFromData(dpy, win, handmask_bits,
1161 	hand_width, hand_height), &fgcolor, &bgcolor, hand_x_hot, hand_y_hot);
1162 #endif
1163 
1164    TEXTPTR = XCreateFontCursor(dpy, XC_xterm);
1165    WAITFOR = XCreateFontCursor(dpy, XC_watch);
1166 
1167    XRecolorCursor(dpy, TEXTPTR, &fgcolor, &bgcolor);
1168 }
1169 
1170 /*----------------------------------------------------------------------*/
1171 /* Remove a window structure and deallocate all memory used by it.	*/
1172 /* If it is the last window, this is equivalent to calling "quit".	*/
1173 /*----------------------------------------------------------------------*/
1174 
delete_window(XCWindowData * window)1175 void delete_window(XCWindowData *window)
1176 {
1177    XCWindowData *searchwin, *lastwin = NULL;
1178 
1179    if (xobjs.windowlist->next == NULL) {
1180       quitcheck((window == NULL) ? NULL : window->area, NULL, NULL);
1181       return;
1182    }
1183 
1184    for (searchwin = xobjs.windowlist; searchwin != NULL; searchwin =
1185 		searchwin->next) {
1186       if (searchwin == window) {
1187 	 Matrixptr thismat;
1188 
1189 	 /* Free any select list */
1190 	 if (searchwin->selects > 0) free(searchwin->selectlist);
1191 
1192 	 /* Free the matrix and pushlist stacks */
1193 
1194 	 while (searchwin->MatStack != NULL) {
1195 	    thismat = searchwin->MatStack;
1196 	    searchwin->MatStack = searchwin->MatStack->nextmatrix;
1197 	    free(thismat);
1198 	 }
1199 	 free_stack(&searchwin->hierstack);
1200 	 free_stack(&searchwin->stack);
1201 
1202 	 /* Free the GC */
1203 	 XFreeGC(dpy, searchwin->gc);
1204 
1205 	 if (lastwin != NULL)
1206 	    lastwin->next = searchwin->next;
1207 	 else
1208 	    xobjs.windowlist = searchwin->next;
1209 	 break;
1210       }
1211       lastwin = searchwin;
1212    }
1213 
1214    if (searchwin == NULL) {
1215       Wprintf("No such window in list!\n");
1216    }
1217    else {
1218       if (areawin == searchwin) areawin = xobjs.windowlist;
1219       free(searchwin);
1220    }
1221 }
1222 
1223 /*----------------------------------------------------------------------*/
1224 /* Create a new window structure and initialize it.			*/
1225 /* Return a pointer to the new window.					*/
1226 /*----------------------------------------------------------------------*/
1227 
create_new_window()1228 XCWindowData *create_new_window()
1229 {
1230    XCWindowData *newwindow;
1231 
1232    newwindow = (XCWindowData *)malloc(sizeof(XCWindowData));
1233 
1234 #ifndef TCL_WRAPPER
1235 #ifdef HAVE_XPM
1236    newwindow->toolbar_on = True;
1237 #endif
1238 #endif
1239 
1240    newwindow->area = (xcWidget)NULL;
1241    newwindow->mapped = False;
1242    newwindow->psfont = 0;
1243    newwindow->anchor = FLIPINV;
1244    newwindow->page = 0;
1245    newwindow->MatStack = NULL;
1246    newwindow->textscale = 1.0;
1247    newwindow->linewidth = 1.0;
1248    newwindow->zoomfactor = SCALEFAC;
1249    newwindow->style = UNCLOSED;
1250    newwindow->invert = False;
1251    newwindow->axeson = True;
1252    newwindow->snapto = True;
1253    newwindow->gridon = True;
1254    newwindow->center = True;
1255    newwindow->bboxon = False;
1256    newwindow->filter = ALL_TYPES;
1257    newwindow->editinplace = True;
1258    newwindow->selects = 0;
1259    newwindow->selectlist = NULL;
1260    newwindow->lastlibrary = 0;
1261    newwindow->manhatn = False;
1262    newwindow->boxedit = MANHATTAN;
1263    newwindow->pathedit = TANGENTS;
1264    newwindow->lastbackground = NULL;
1265    newwindow->editstack = (objectptr) malloc(sizeof(object));
1266    newwindow->stack = NULL;   /* at the top of the hierarchy */
1267    newwindow->hierstack = NULL;
1268    initmem(newwindow->editstack);
1269    newwindow->pinpointon = False;
1270    newwindow->showclipmasks = True;
1271    newwindow->pinattach = False;
1272    newwindow->buschar = '(';	/* Vector notation for buses */
1273    newwindow->defaultcursor = &CROSS;
1274    newwindow->event_mode = NORMAL_MODE;
1275    newwindow->attachto = -1;
1276    newwindow->color = DEFAULTCOLOR;
1277    newwindow->gccolor = 0;
1278    newwindow->time_id = 0;
1279    newwindow->redraw_needed = True;
1280    newwindow->redraw_ongoing = False;
1281 #ifdef HAVE_CAIRO
1282    newwindow->fixed_pixmap = NULL;
1283    newwindow->cr = NULL;
1284 #else /* HAVE_CAIRO */
1285    newwindow->clipmask = (Pixmap)NULL;
1286    newwindow->pbuf = (Pixmap)NULL;
1287    newwindow->cmgc = (GC)NULL;
1288    newwindow->clipped = 0;
1289    newwindow->fixed_pixmap = (Pixmap) NULL;
1290 #endif /* !HAVE_CAIRO */
1291    newwindow->vscale = 1;
1292    newwindow->pcorner.x = newwindow->pcorner.y = 0;
1293    newwindow->topinstance = (objinstptr)NULL;
1294    newwindow->panx = newwindow->pany = 0;
1295 
1296    /* Prepend to linked window list in global data (xobjs) */
1297    newwindow->next = xobjs.windowlist;
1298    xobjs.windowlist = newwindow;
1299 
1300    return newwindow;
1301 }
1302 
1303 /*----------------------------------------------------------------------*/
1304 /* Preparatory initialization (to be run before setting up the GUI)	*/
1305 /*----------------------------------------------------------------------*/
1306 
pre_initialize()1307 void pre_initialize()
1308 {
1309    short i, page;
1310 
1311    /*-------------------------------------------------------------*/
1312    /* Force LC_NUMERIC locale to en_US for decimal point = period */
1313    /* notation.  The environment variable LC_NUMERIC overrides if */
1314    /* it is set explicitly, so it has to be unset first to allow  */
1315    /* setlocale() to work.					  */
1316    /*-------------------------------------------------------------*/
1317 
1318 #ifdef HAVE_PUTENV
1319    putenv("LC_ALL=en_US");
1320    putenv("LC_NUMERIC=en_US");
1321    putenv("LANG=POSIX");
1322 #else
1323    unsetenv("LC_ALL");
1324    unsetenv("LC_NUMERIC");
1325    setenv("LANG", "POSIX", 1);
1326 #endif
1327    setlocale(LC_ALL, "en_US");
1328 
1329    /*---------------------------*/
1330    /* initialize user variables */
1331    /*---------------------------*/
1332 
1333    strcpy(version, PROG_VERSION);
1334    aliastop = NULL;
1335    xobjs.pagelist = (Pagedata **) malloc(PAGES * sizeof(Pagedata *));
1336    for (page = 0; page < PAGES; page++) {
1337       xobjs.pagelist[page] = (Pagedata *) malloc(sizeof(Pagedata));
1338       xobjs.pagelist[page]->pageinst = NULL;
1339       xobjs.pagelist[page]->filename = NULL;
1340    }
1341    /* Set values for the first page */
1342    xobjs.pagelist[0]->wirewidth = 2.0;
1343    xobjs.pagelist[0]->outscale = 1.0;
1344    xobjs.pagelist[0]->background.name = (char *)NULL;
1345    xobjs.pagelist[0]->pmode = 2;	/* set auto-fit ON by default */
1346    xobjs.pagelist[0]->orient = 0;
1347    xobjs.pagelist[0]->gridspace = DEFAULTGRIDSPACE;
1348    xobjs.pagelist[0]->snapspace = DEFAULTSNAPSPACE;
1349    xobjs.pagelist[0]->drawingscale.x = xobjs.pagelist[0]->drawingscale.y = 1;
1350    xobjs.pagelist[0]->coordstyle = INTERNAL;
1351    xobjs.pagelist[0]->pagesize.x = 612;
1352    xobjs.pagelist[0]->pagesize.y = 792;
1353    xobjs.pagelist[0]->margins.x = 72;
1354    xobjs.pagelist[0]->margins.y = 72;
1355 
1356    xobjs.hold = TRUE;
1357    xobjs.showtech = FALSE;
1358    xobjs.suspend = (signed char)0; /* Suspend graphics until finished with startup */
1359    xobjs.new_changes = 0;
1360    xobjs.filefilter = TRUE;
1361    xobjs.tempfile = NULL;
1362    xobjs.retain_backup = False;	/* default: remove backup after file write */
1363    signal(SIGINT, dointr);
1364    printtime_id = 0;
1365 
1366    xobjs.technologies = NULL;
1367    xobjs.undostack = NULL;
1368    xobjs.redostack = NULL;
1369 
1370    /* Set the temporary directory name as compiled, unless overridden by */
1371    /* environment variable "TMPDIR".					 */
1372 
1373    xobjs.tempdir = getenv("TMPDIR");
1374    if (xobjs.tempdir == NULL) xobjs.tempdir = strdup(TEMP_DIR);
1375 
1376    xobjs.windowlist = (XCWindowDataPtr)NULL;
1377    areawin = NULL;
1378 
1379    xobjs.numlibs = LIBS - LIBRARY - 1;
1380    xobjs.fontlib.number = 0;
1381    xobjs.userlibs = (Library *) malloc(xobjs.numlibs * sizeof(Library));
1382    for (i = 0; i < xobjs.numlibs; i++) {
1383       xobjs.userlibs[i].library = (objectptr *) malloc(sizeof(objectptr));
1384       xobjs.userlibs[i].instlist = NULL;
1385       xobjs.userlibs[i].number = 0;
1386    }
1387    xobjs.imagelist = NULL;
1388    xobjs.images = 0;
1389    xobjs.pages = PAGES;
1390 
1391    xobjs.libsearchpath = (char *)NULL;
1392    xobjs.filesearchpath = (char *)NULL;
1393 
1394    fontcount = 0;
1395    fonts = (fontinfo *) malloc(sizeof(fontinfo));
1396    fonts[0].encoding = NULL;	/* To prevent segfaults */
1397    fonts[0].psname = NULL;
1398    fonts[0].family = NULL;
1399 
1400    /* Initialization of objects requires values for the window width and height, */
1401    /* so set up the widgets and realize them first.				 */
1402 
1403    popups = 0;        /* no popup windows yet */
1404    beeper = 1;        /* Ring bell on certain warnings or errors */
1405    pressmode = 0;	/* not in a button press & hold mode yet */
1406    initsplines();	/* create lookup table of spline parameters */
1407 }
1408 
1409 #ifdef TCL_WRAPPER
1410 
1411 /*----------------------------------------------------------------------*/
1412 /* Create a new Handle object in Tcl */
1413 /*----------------------------------------------------------------------*/
1414 
1415 static void UpdateStringOfHandle _ANSI_ARGS_((Tcl_Obj *objPtr));
1416 static int SetHandleFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr));
1417 
1418 static Tcl_ObjType tclHandleType = {
1419     "handle",				/* name */
1420     (Tcl_FreeInternalRepProc *) NULL,	/* freeIntRepProc */
1421     (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
1422     UpdateStringOfHandle,		/* updateStringProc */
1423     SetHandleFromAny			/* setFromAnyProc */
1424 };
1425 
1426 /*----------------------------------------------------------------------*/
1427 
1428 static void
UpdateStringOfHandle(objPtr)1429 UpdateStringOfHandle(objPtr)
1430     Tcl_Obj *objPtr;   /* Int object whose string rep to update. */
1431 {
1432     char buffer[TCL_INTEGER_SPACE];
1433     int len;
1434 
1435     sprintf(buffer, "H%08lX", objPtr->internalRep.longValue);
1436     len = strlen(buffer);
1437 
1438     objPtr->bytes = Tcl_Alloc((u_int)len + 1);
1439     strcpy(objPtr->bytes, buffer);
1440     objPtr->length = len;
1441 }
1442 
1443 /*----------------------------------------------------------------------*/
1444 
1445 static int
SetHandleFromAny(interp,objPtr)1446 SetHandleFromAny(interp, objPtr)
1447     Tcl_Interp *interp;         /* Used for error reporting if not NULL. */
1448     Tcl_Obj *objPtr;   /* The object to convert. */
1449 {
1450     Tcl_ObjType *oldTypePtr = (Tcl_ObjType *)objPtr->typePtr;
1451     char *string, *end;
1452     int length;
1453     char *p;
1454     long newLong;
1455     pushlistptr newstack = NULL;
1456 
1457     string = Tcl_GetStringFromObj(objPtr, &length);
1458     errno = 0;
1459     for (p = string;  isspace((u_char)(*p));  p++);
1460 
1461 nexthier:
1462 
1463     if (*p++ != 'H') {
1464 	if (interp != NULL) {
1465             Tcl_ResetResult(interp);
1466             Tcl_AppendToObj(Tcl_GetObjResult(interp),
1467 		"handle is identified by leading H and hexidecimal value only", -1);
1468         }
1469         free_stack(&newstack);
1470         return TCL_ERROR;
1471     } else {
1472         newLong = strtoul(p, &end, 16);
1473     }
1474     if (end == p) {
1475         badHandle:
1476         if (interp != NULL) {
1477             /*
1478              * Must copy string before resetting the result in case a caller
1479              * is trying to convert the interpreter's result to an int.
1480              */
1481 
1482             char buf[100];
1483             sprintf(buf, "expected handle but got \"%.50s\"", string);
1484             Tcl_ResetResult(interp);
1485             Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
1486         }
1487         free_stack(&newstack);
1488         return TCL_ERROR;
1489     }
1490     if (errno == ERANGE) {
1491         if (interp != NULL) {
1492             char *s = "handle value too large to represent";
1493             Tcl_ResetResult(interp);
1494             Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
1495             Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL);
1496         }
1497         free_stack(&newstack);
1498         return TCL_ERROR;
1499     }
1500     /*
1501      * Make sure that the string has no garbage after the end of the handle.
1502      */
1503 
1504     while ((end < (string+length)) && isspace((u_char)(*end))) end++;
1505     if (end != (string+length)) {
1506        /* Check for handles separated by slashes.  If present,	*/
1507        /* then generate a hierstack.				*/
1508 
1509 	if ((end != NULL) && (*end == '/')) {
1510 	   objinstptr refinst, chkinst;
1511 	   genericptr *rgen;
1512 
1513 	   *end = '\0';
1514            newLong = strtoul(p, &end, 16);
1515 	   p = end + 1;
1516 	   *end = '/';
1517 	   refinst = (newstack == NULL) ? areawin->topinstance : newstack->thisinst;
1518 	   chkinst = (objinstptr)((pointertype)(newLong));
1519 	   /* Ensure that chkinst is in the plist of			*/
1520 	   /* refinst->thisobject, and that it is type objinst.	*/
1521 	   for (rgen = refinst->thisobject->plist; rgen < refinst->thisobject->plist
1522 			+ refinst->thisobject->parts; rgen++) {
1523 	      if ((objinstptr)(*rgen) == chkinst) {
1524 		 if (ELEMENTTYPE(*rgen) != OBJINST) {
1525 		    free_stack(&newstack);
1526 		    Tcl_SetResult(interp, "Hierarchical element handle "
1527 				"component is not an object instance.", NULL);
1528 		    return TCL_ERROR;
1529 		 }
1530 		 break;
1531 	      }
1532 	   }
1533 	   if (rgen == refinst->thisobject->plist + refinst->thisobject->parts) {
1534                Tcl_SetResult(interp, "Bad component in hierarchical "
1535 			"element handle.", NULL);
1536 	       free_stack(&newstack);
1537 	       return TCL_ERROR;
1538 	   }
1539 	   push_stack(&newstack, chkinst, NULL);
1540 	   goto nexthier;
1541         }
1542 	else
1543 	   goto badHandle;
1544     }
1545 
1546     /* Note that this check won't prevent a hierarchical selection from	*/
1547     /* being added to a non-hierarchical selection.			*/
1548 
1549     if (areawin->hierstack != NULL) {
1550        if ((newstack == NULL) || (newstack->thisinst !=
1551 		areawin->hierstack->thisinst)) {
1552 	  Tcl_SetResult(interp, "Attempt to select components in different "
1553 			"objects.", NULL);
1554           free_stack(&newstack);
1555 	  return TCL_ERROR;
1556        }
1557     }
1558     free_stack(&areawin->hierstack);
1559     areawin->hierstack = newstack;
1560 
1561     /*
1562      * The conversion to handle succeeded. Free the old internalRep before
1563      * setting the new one. We do this as late as possible to allow the
1564      * conversion code, in particular Tcl_GetStringFromObj, to use that old
1565      * internalRep.
1566      */
1567 
1568     if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
1569         oldTypePtr->freeIntRepProc(objPtr);
1570     }
1571 
1572     objPtr->internalRep.longValue = newLong;
1573     objPtr->typePtr = &tclHandleType;
1574     return TCL_OK;
1575 }
1576 
1577 /*----------------------------------------------------------------------*/
1578 
1579 Tcl_Obj *
Tcl_NewHandleObj(optr)1580 Tcl_NewHandleObj(optr)
1581     void *optr;      /* Int used to initialize the new object. */
1582 {
1583     Tcl_Obj *objPtr;
1584 
1585     objPtr = Tcl_NewObj();
1586     objPtr->bytes = NULL;
1587 
1588     objPtr->internalRep.longValue = (long)(optr);
1589     objPtr->typePtr = &tclHandleType;
1590     return objPtr;
1591 }
1592 
1593 /*----------------------------------------------------------------------*/
1594 
1595 int
Tcl_GetHandleFromObj(interp,objPtr,handlePtr)1596 Tcl_GetHandleFromObj(interp, objPtr, handlePtr)
1597     Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
1598     Tcl_Obj *objPtr;	/* The object from which to get a int. */
1599     void **handlePtr;	/* Place to store resulting int. */
1600 {
1601     long l;
1602     int result;
1603 
1604     if (objPtr->typePtr != &tclHandleType) {
1605         result = SetHandleFromAny(interp, objPtr);
1606         if (result != TCL_OK) {
1607             return result;
1608         }
1609     }
1610     l = objPtr->internalRep.longValue;
1611 
1612 #if SIZEOF_VOID_P == SIZEOF_UNSIGNED_INT
1613     if (((long)((int)l)) == l) {
1614         *handlePtr = (void *)objPtr->internalRep.longValue;
1615         return TCL_OK;
1616     }
1617 #else
1618 #if SIZEOF_VOID_P == SIZEOF_UNSIGNED_LONG
1619     *handlePtr = (void *)objPtr->internalRep.longValue;
1620     return TCL_OK;
1621 #endif
1622 #endif
1623 
1624     if (interp != NULL) {
1625         Tcl_ResetResult(interp);
1626         Tcl_AppendToObj(Tcl_GetObjResult(interp),
1627                 "value too large to represent as handle", -1);
1628     }
1629     return TCL_ERROR;
1630 }
1631 
1632 
1633 #endif
1634 
1635 /*----------------------------------------------------------------------*/
1636 /* Routine to initialize variables after the GUI has been set up	*/
1637 /*----------------------------------------------------------------------*/
1638 
post_initialize()1639 void post_initialize()
1640 {
1641    short i;
1642 
1643    /*--------------------------------------------------*/
1644    /* Setup the (simple) colormap and make the cursors */
1645    /*--------------------------------------------------*/
1646 
1647    setcolorscheme(True);
1648    makecursors();
1649 
1650    /* Now that we have values for the window width and height, we can initialize */
1651    /* the page objects.								 */
1652 
1653    xobjs.libtop = (objinstptr *)malloc(LIBS * sizeof(objinstptr));
1654    for (i = 0; i < LIBS; i++) {
1655       objectptr newlibobj = (objectptr) malloc(sizeof(object));
1656       initmem(newlibobj);
1657       xobjs.libtop[i] = newpageinst(newlibobj);
1658    }
1659 
1660    /* Give names to the five default libraries */
1661    strcpy(xobjs.libtop[FONTLIB]->thisobject->name, "Font Character List");
1662    strcpy(xobjs.libtop[PAGELIB]->thisobject->name, "Page Directory");
1663    strcpy(xobjs.libtop[LIBLIB]->thisobject->name,  "Library Directory");
1664    strcpy(xobjs.libtop[USERLIB]->thisobject->name, "User Library");
1665    renamelib(USERLIB);
1666 
1667    changepage(0);
1668 
1669    /* Centering the view is not required here because the default values */
1670    /* set in initmem() should correctly position the empty page in the	 */
1671    /* middle of the viewing window.					 */
1672 
1673 #if !defined(HAVE_CAIRO)
1674    if ((dbuf == (Pixmap)NULL) && areawin->area)
1675       dbuf = XCreatePixmap(dpy, areawin->window, areawin->width,
1676 		areawin->height, DefaultDepthOfScreen(xcScreen(areawin->area)));
1677 #endif
1678 
1679    /* Set up fundamentally necessary colors black and white */
1680 
1681    addnewcolorentry(xc_alloccolor("Black"));
1682    addnewcolorentry(xc_alloccolor("White"));
1683 
1684 #ifdef TCL_WRAPPER
1685 
1686    /* Set up new Tcl type "handle" for element handles */
1687    Tcl_RegisterObjType(&tclHandleType);
1688 
1689 #endif
1690 
1691    /*-----------------------------------------------------*/
1692    /* Set the cursor as a crosshair for the area widget.  */
1693    /* If areawin->area is NULL, then xcircuit is running  */
1694    /* in batch mode, and no automatic save will be done.  */
1695    /*-----------------------------------------------------*/
1696 
1697    if (areawin->area != NULL) {
1698       XDefineCursor (dpy, areawin->window, DEFAULTCURSOR);
1699 
1700       /*---------------------------------------------------*/
1701       /* Set up a timeout for automatic save to a tempfile */
1702       /*---------------------------------------------------*/
1703 
1704       xobjs.save_interval = appdata.timeout;
1705       xobjs.timeout_id = xcAddTimeOut(app, 60000 * xobjs.save_interval,
1706 		savetemp, NULL);
1707    }
1708 }
1709 
1710 /*----------------------------------------------------------------------*/
1711