1 /*----------------------------------------------------------------------*/
2 /* xcircuit.c --- An X-windows program for drawing circuit diagrams */
3 /* Copyright (c) 2002 R. Timothy Edwards */
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. */
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. */
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 */
21 /* See file ./README for contact information */
22 /*----------------------------------------------------------------------*/
24 /*----------------------------------------------------------------------*/
25 /* Uses the Xw widget set (see directory Xw) */
26 /* Xcircuit written by Tim Edwards beginning 8/13/93 */
27 /*----------------------------------------------------------------------*/
34 #include <sys/types.h>
41 #include <unistd.h> /* for unlink() */
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>
59 #include "Xw/WorkSpace.h"
60 #include "Xw/PButton.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"
71 #if defined(XC_WIN32) && defined(TCL_WRAPPER)
73 #include <X11/Xutil.h>
74 #include <X11/cursorfont.h>
75 #include <X11/Xatom.h>
79 #define P_tmpdir TMPDIR
82 /*----------------------------------------------------------------------*/
84 /*----------------------------------------------------------------------*/
88 #include "colordefs.h"
91 /*----------------------------------------------------------------------*/
92 /* Function prototype declarations */
93 /*----------------------------------------------------------------------*/
94 #include "prototypes.h"
96 /*----------------------------------------------------------------------*/
97 /* Global Variable definitions */
98 /*----------------------------------------------------------------------*/
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 */
105 Pixmap STIPPLE
[STIPPLES
]; /* Polygon fill-style stipple patterns */
106 Cursor appcursors
[NUM_CURSORS
];
107 ApplicationData appdata
;
108 XCWindowData
*areawin
;
111 colorindex
*colorlist
;
113 xcIntervalId printtime_id
;
118 short popups
; /* total number of popup widgets on the screen */
120 /*----------------------------------------------------------------------*/
121 /* Externally defined variables */
122 /*----------------------------------------------------------------------*/
124 extern aliasptr aliastop
;
125 extern char version
[];
128 extern Tcl_Interp
*xcinterp
;
130 extern XtAppContext app
;
133 #if !defined(HAVE_CAIRO)
137 /* Bad hack for problems with the DECstation. . . don't know why */
138 #ifdef UniqueContextProblem
139 #undef XUniqueContext
140 XContext
XUniqueContext()
142 return XrmUniqueQuark();
145 /* End of bad hack. . . */
147 /*----------------------------------------------------------------------*/
148 /* Update the list of colors in the colormap */
149 /*----------------------------------------------------------------------*/
151 void addtocolorlist(xcWidget button
, int cvalue
)
154 colorlist
= (colorindex
*)realloc(colorlist
, number_colors
*
156 colorlist
[number_colors
- 1].cbutton
= button
;
157 colorlist
[number_colors
- 1].color
.pixel
= cvalue
;
159 /* Get and store the RGB values of the new color */
161 if (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);
167 XQueryColors(dpy
, cmap
, &(colorlist
[number_colors
- 1].color
), 1);
170 /*----------------------------------------------------------------------*/
171 /* Add a new color button to the color menu */
172 /* called if new color button needs to be made */
173 /*----------------------------------------------------------------------*/
177 int addnewcolorentry(int ccolor
)
179 xcWidget newbutton
= (xcWidget
)NULL
;
182 /* check to see if entry is already in the color list */
184 for (i
= NUMBER_OF_COLORS
; i
< number_colors
; i
++)
185 if (colorlist
[i
].color
.pixel
== ccolor
) break;
187 /* make new entry in the menu */
189 if (i
== number_colors
) {
190 addtocolorlist(newbutton
, ccolor
);
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
);
200 #endif /* TCL_WRAPPER */
206 void quit(xcWidget w
, caddr_t nulldata
)
209 Matrixptr curmatrix
, dmatrix
;
211 /* free up CTM Matrix Stack */
212 if (areawin
!= NULL
) {
213 curmatrix
= areawin
->MatStack
;
214 while (curmatrix
!= NULL
) {
215 dmatrix
= curmatrix
->nextmatrix
;
219 areawin
->MatStack
= NULL
;
222 /* free the colormap if a new one has been installed */
225 if (cmap
!= DefaultColormap(dpy
, DefaultScreen(dpy
)))
226 XFreeColormap(dpy
, cmap
);
228 /* exit ghostscript if background rendering was enabled */
233 /* exit ngspice if the simulator is still running */
238 /* remove any temporary files created for background rendering */
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);
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 */
252 if (xobjs
.tempfile
!= NULL
) {
255 if (unlink(xobjs
.tempfile
) < 0)
256 Fprintf(stderr
, "Error %d unlinking file \"%s\"\n", errno
, xobjs
.tempfile
);
258 if (DeleteFile(xobjs
.tempfile
) != TRUE
)
259 Fprintf(stderr
, "Error %d unlinking file \"%s\"\n",
260 GetLastError(), xobjs
.tempfile
);
264 Fprintf(stderr
, "Ctrl-C exit: reload workspace from \"%s\"\n",
266 free(xobjs
.tempfile
);
267 xobjs
.tempfile
= NULL
;
270 #if defined(HAVE_PYTHON)
271 /* exit by exiting the Python interpreter, if enabled */
273 #elif defined(TCL_WRAPPER)
274 /* Let Tcl/Tk handle exit */
276 #elif defined(XC_WIN32)
284 /*--------------------------------------------------------------*/
285 /* Check for changes in an object and all of its descendents */
286 /*--------------------------------------------------------------*/
288 u_short
getchanges(objectptr thisobj
)
292 u_short changes
= thisobj
->changes
;
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
);
303 /*--------------------------------------------------------------*/
304 /* Check to see if any objects in xcircuit have been modified */
305 /* without saving. */
306 /*--------------------------------------------------------------*/
308 u_short
countchanges(char **promptstr
)
310 int slen
= 1, i
; /* , j; (jdk) */
311 u_short locchanges
, changes
= 0, words
= 1;
316 if (promptstr
!= NULL
) slen
+= strlen(*promptstr
);
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
);
331 changes
+= locchanges
;
336 /* Check all library objects for unsaved changes */
338 for (ns
= xobjs
.technologies
; ns
!= NULL
; ns
= ns
->next
) {
339 tech_set_changes(ns
);
340 if ((ns
->flags
& TECH_CHANGED
) != 0) {
342 if (promptstr
!= NULL
) {
343 fname
= ns
->filename
;
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
);
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 */
363 /*----------------------------------------------*/
367 int quitcheck(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
370 Boolean doprompt
= False
;
372 /* enable default interrupt signal handler during this time, so that */
373 /* a double Control-C will ALWAYS exit. */
375 signal(SIGINT
, SIG_DFL
);
377 promptstr
= (char *)malloc(60);
378 strcpy(promptstr
, ".query.title.field configure -text \"Unsaved changes in: ");
380 /* Check all page objects for unsaved changes */
382 doprompt
= (countchanges(&promptstr
) > 0) ? True
: False
;
384 /* If any changes have not been saved, generate a prompt */
387 promptstr
= (char *)realloc(promptstr
, strlen(promptstr
) + 15);
388 strcat(promptstr
, "\nQuit anyway?");
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");
400 quit(w
, NULL
); // preparation for quit
401 if (calldata
!= (caddr_t
)NULL
)
402 Tcl_Eval(xcinterp
, "quitnocheck intr");
404 Tcl_Eval(xcinterp
, "quitnocheck"); // actual quit
405 return 1; // not reached
411 /*--------------------------------------*/
412 /* A gentle Ctrl-C shutdown */
413 /*--------------------------------------*/
415 void dointr(int signum
)
417 quitcheck(NULL
, NULL
, (caddr_t
)1);
424 void DoNothing(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
429 /*-----------------------------------------------------------------------*/
430 /* Write page scale (overall scale, and X and Y dimensions) into strings */
431 /*-----------------------------------------------------------------------*/
433 void writescalevalues(char *scdest
, char *xdest
, char *ydest
)
435 float oscale
, psscale
;
439 curpage
= xobjs
.pagelist
[areawin
->page
];
440 oscale
= curpage
->outscale
;
441 psscale
= getpsscale(oscale
, areawin
->page
);
443 width
= toplevelwidth(curpage
->pageinst
, NULL
);
444 height
= toplevelheight(curpage
->pageinst
, NULL
);
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
);
452 sprintf(xdest
, "%6.5f", (width
* psscale
) / 72.0);
453 sprintf(ydest
, "%6.5f", (height
* psscale
) / 72.0);
457 /*-------------------------------------------------------------------------*/
458 /* Destroy an interactive text-editing popup box */
459 /*-------------------------------------------------------------------------*/
463 /* Just pop it down. . . */
465 void destroypopup(xcWidget button
, popupstruct
*callstruct
, caddr_t calldata
)
467 Tk_UnmapWindow(callstruct
->popup
);
470 /* free the allocated structure space */
472 free(callstruct
->buttonptr
);
473 if (callstruct
->filter
!= NULL
) free(callstruct
->filter
);
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. */
480 signal(SIGINT
, dointr
);
483 /*-------------------------------------------------------------------------*/
484 /* Create a popup window with "OK" and "Cancel" buttons, */
485 /* and text and label fields. */
486 /*-------------------------------------------------------------------------*/
488 void popupprompt(xcWidget button
, char *request
, char *current
, void (*function
)(),
489 buttonsave
*datastruct
, const char *filter
)
493 popup
= Tk_NameToWindow(xcinterp
, ".dialog", Tk_MainWindow(xcinterp
));
497 /*----------------------------------------------------------------------*/
498 /* Create a popup window for property changes */
499 /*----------------------------------------------------------------------*/
501 void outputpopup(xcWidget button
, caddr_t clientdata
, caddr_t calldata
)
503 Tcl_Eval(xcinterp
, "wm deiconify .output");
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. */
512 /* Note that this routine does not go so far as to handle non-square */
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 /*----------------------------------------------------------------------*/
527 char *resource_manager
;
531 resource_manager
= XResourceManagerString(dpy
);
533 if (resource_manager
!= NULL
) {
534 db
= XrmGetStringDatabase(resource_manager
);
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)
543 x
= DisplayWidth(dpy
, DefaultScreen(dpy
));
544 xmm
= DisplayWidthMM(dpy
, DefaultScreen(dpy
));
545 dpi
= (int)(((float)x
+ 0.5) / (float)(xmm
/ 25.4));
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 /*-------------------------------------------------*/
555 /* XXX it looks like this routine is an orphan */
556 void clrmessage(caddr_t clientdata
)
558 char buf1
[50], buf2
[50];
560 /* Don't write over the report of the edit string contents, */
561 /* if we're in one of the label edit modes */
563 if (eventmode
== TEXT_MODE
|| eventmode
== ETEXT_MODE
)
564 charreport(TOLABEL(EDITPART
));
566 measurestr(xobjs
.pagelist
[areawin
->page
]->gridspace
, buf1
);
567 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buf2
);
568 Wprintf("Grid %.50s : Snap %.50s", buf1
, buf2
);
572 #endif /* TCL_WRAPPER */
574 /*------------------------------------------------------------------------------*/
575 /* diagnostic tool for translating the event mode into a string and printing */
576 /* to stderr (for debugging only). */
577 /*------------------------------------------------------------------------------*/
579 void printeventmode() {
580 Fprintf(stderr
, "eventmode is \'");
583 Fprintf(stderr
, "NORMAL");
586 Fprintf(stderr
, "MOVE");
589 Fprintf(stderr
, "COPY");
592 Fprintf(stderr
, "SELAREA");
595 Fprintf(stderr
, "CATALOG");
598 Fprintf(stderr
, "CATTEXT");
601 Fprintf(stderr
, "CATMOVE");
604 Fprintf(stderr
, "FONTCAT");
607 Fprintf(stderr
, "EFONTCAT");
610 Fprintf(stderr
, "TEXT");
613 Fprintf(stderr
, "ETEXT");
616 Fprintf(stderr
, "WIRE");
619 Fprintf(stderr
, "BOX");
622 Fprintf(stderr
, "EPOLY");
625 Fprintf(stderr
, "ARC");
628 Fprintf(stderr
, "EARC");
631 Fprintf(stderr
, "SPLINE");
634 Fprintf(stderr
, "ESPLINE");
637 Fprintf(stderr
, "EPATH");
640 Fprintf(stderr
, "EINST");
643 Fprintf(stderr
, "ASSOC");
646 Fprintf(stderr
, "RESCALE");
649 Fprintf(stderr
, "PAN");
652 Fprintf(stderr
, "(unknown)");
655 Fprintf(stderr
, "_MODE\'\n");
658 /*------------------------------------------------------------------------------*/
662 /*------------------------------------------------------------------------------*/
663 /* "docommand" de-iconifies the TCL console. */
664 /*------------------------------------------------------------------------------*/
668 Tcl_Eval(xcinterp
, "catch xcircuit::raiseconsole");
671 /*------------------------------------------------------------------------------*/
672 /* When all else fails, install your own colormap */
673 /*------------------------------------------------------------------------------*/
679 Fprintf(stdout
, "Installing my own colormap\n");
681 /* allocate a new colormap */
683 newcmap
= XCopyColormapAndFree(dpy
, cmap
);
684 if (newcmap
== (Colormap
)NULL
) return (-1);
689 #endif /* TCL_WRAPPER */
691 /*------------------------------------------------------------------------------*/
692 /* Find the nearest color in the colormap to cvexact and return its pixel value */
693 /*------------------------------------------------------------------------------*/
695 #if defined(TCL_WRAPPER) || !defined(XC_WIN32)
697 int findnearcolor(XColor
*cvexact
)
699 /* find the nearest-matching color in the colormap */
701 int i
, ncolors
= DisplayCells(dpy
, DefaultScreen(dpy
));
703 long rdist
, bdist
, gdist
;
704 u_long dist
, mindist
;
707 cmcolors
= (XColor
*)malloc(ncolors
* sizeof(XColor
));
709 for (i
= 0; i
< ncolors
; i
++) {
710 cmcolors
[i
].pixel
= i
;
711 cmcolors
[i
].flags
= DoRed
| DoGreen
| DoBlue
;
713 XQueryColors(dpy
, cmap
, cmcolors
, ncolors
);
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
) {
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. */
733 /* findnearcolor already used 512 per component, so to match that, */
734 /* 3 * (512 * 512) = 786432 ~= 750000 */
737 if (installowncmap() > 0) {
738 if (XAllocColor(dpy
, cmap
, cvexact
) != 0)
739 minidx
= cvexact
->pixel
;
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 /*----------------------------------------------------------------------*/
755 int xc_getlayoutcolor(int cidx
)
757 return colorlist
[cidx
].color
.pixel
;
760 /*----------------------------------------------------------------------*/
761 /* Obtain red, green and blue values from a color index */
762 /* the colour values range from 0 to 65535 */
763 /*----------------------------------------------------------------------*/
765 void xc_get_color_rgb(unsigned long cidx
, unsigned short *red
,
766 unsigned short *green
, unsigned short *blue
)
770 .flags
= DoRed
| DoGreen
| DoBlue
772 if (areawin
->area
== NULL
) {
773 loccolor
.red
= cidx
& 0xff;
774 loccolor
.green
= (cidx
>> 8) & 0xff;
775 loccolor
.blue
= (cidx
>> 16) & 0xff;
778 XQueryColors(dpy
, cmap
, &loccolor
, 1);
780 *green
= loccolor
.green
;
781 *blue
= loccolor
.blue
;
785 /*-------------------------------------------------------------------------*/
786 /* Hack on the resource database Color allocation */
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. */
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 /*-------------------------------------------------------------------------*/
796 #if defined(TCL_WRAPPER) || !defined(XC_WIN32)
798 caddr_t
CvtStringToPixel(XrmValuePtr args
, int *nargs
, XrmValuePtr fromVal
,
801 static XColor cvcolor
;
804 if (dpy
== NULL
) return NULL
;
807 Fprintf(stderr
, "String to Pixel conversion takes no arguments");
809 /* Color defaults to black if name is not found */
811 if (XAllocNamedColor(dpy
, cmap
, (char *)fromVal
->addr
, &cvcolor
, &cvexact
)
813 if (XLookupColor(dpy
, cmap
, (char *)fromVal
->addr
, &cvexact
, &cvcolor
) == 0)
814 cvcolor
.pixel
= BlackPixel(dpy
, DefaultScreen(dpy
));
816 cvcolor
.pixel
= findnearcolor(&cvexact
);
819 toVal
->size
= sizeof(u_long
);
820 toVal
->addr
= (caddr_t
) &(cvcolor
.pixel
);
826 /*-------------------------------------------------------------------------*/
827 /* Allocate new color using the CvtStringToPixel routine */
828 /*-------------------------------------------------------------------------*/
830 #if defined(XC_WIN32) && !defined(TCL_WRAPPER)
832 int xc_alloccolor(char *name
)
834 return WinNamedColor(name
);
839 int xc_alloccolor(char *name
)
842 int zval
= 0, pixval
;
844 fromC
.size
= strlen(name
);
848 CvtStringToPixel(NULL
, &zval
, &fromC
, &toC
);
849 pixval
= (int)(*((u_long
*)toC
.addr
));
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;
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;
867 else if (sscanf(name
, "%d", &pixval
) != 1) {
868 if (!strcasecmp(name
, "red")) {
873 else if (!strcasecmp(name
, "green")) {
878 else if (!strcasecmp(name
, "blue")) {
883 else if (!strcasecmp(name
, "white")) {
888 else if (!strcasecmp(name
, "gray")) {
893 else if (!strcasecmp(name
, "yellow")) {
898 else if (!strcasecmp(name
, "gray40")) {
903 else if (!strcasecmp(name
, "gray60")) {
908 else if (!strcasecmp(name
, "gray80")) {
913 else if (!strcasecmp(name
, "gray90")) {
918 else if (!strcasecmp(name
, "green2")) {
923 else if (!strcasecmp(name
, "purple")) {
928 else if (!strcasecmp(name
, "steelblue2")) {
933 else if (!strcasecmp(name
, "red3")) {
938 else if (!strcasecmp(name
, "tan")) {
943 else if (!strcasecmp(name
, "brown")) {
948 else if (!strcasecmp(name
, "pink")) {
959 pixval
= r
+ g
* 256 + b
* 65536;
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 */
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 /*----------------------------------------------------------------------*/
983 int rgb_querycolor(int red
, int green
, int blue
, int *pixval
)
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) {
992 *pixval
= colorlist
[i
].color
.pixel
;
1000 /*-----------------------------------------------------------------------*/
1001 /* Allocate new color from RGB values (e.g., from PS file "scb" command) */
1002 /*-----------------------------------------------------------------------*/
1004 #if defined(XC_WIN32) && !defined(TCL_WRAPPER)
1006 int rgb_alloccolor(int red
, int green
, int blue
)
1009 // XCircuit version 3.9: This no longer works. Need to
1010 // allocate the color and return an index into colorlist[].
1012 return RGB(red
>> 8, green
>> 8, blue
>> 8);
1017 int rgb_alloccolor(int red
, int green
, int blue
)
1020 int pixval
, tableidx
; /* i, (jdk) */
1022 /* if color is not already in list, try to allocate it; if allocation */
1023 /* fails, grab the closest match in the colormap. */
1025 tableidx
= rgb_querycolor(red
, green
, blue
, &pixval
);
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
);
1036 pixval
= newcolor
.pixel
;
1039 // No graphics mode: Force pixel to be 24 bit RGB
1040 pixval
= (red
& 0xff) | ((blue
& 0xff) << 8) | ((green
& 0xff) << 16);
1043 // Add this to the colormap
1044 tableidx
= addnewcolorentry(pixval
);
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 /*----------------------------------------------------------------------*/
1058 int query_named_color(char *cname
)
1060 XColor cvcolor
, cvexact
;
1061 int tableidx
, result
= 0;
1064 result
= XLookupColor(dpy
, cmap
, cname
, &cvexact
, &cvcolor
);
1066 if (result
== 0) return BADCOLOR
;
1068 tableidx
= rgb_querycolor(cvcolor
.red
, cvcolor
.green
, cvcolor
.blue
, NULL
);
1072 /*-------------------------------------------------------------------------*/
1073 /* Make the cursors from the cursor bit data */
1074 /*-------------------------------------------------------------------------*/
1078 XColor fgcolor
, bgcolor
;
1079 Window win
= areawin
->window
;
1081 Tk_Uid fg_uid
, bg_uid
;
1084 if (areawin
->area
== NULL
) return;
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);
1094 #define Tk_GetCursorFromData CreateW32Cursor
1097 fg_uid
= Tk_GetUid(Tk_NameOfColor(&fgcolor
));
1098 bg_uid
= Tk_GetUid(Tk_NameOfColor(&bgcolor
));
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
,
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
,
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
,
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
,
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
,
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
,
1129 #undef Tk_GetCursorFromData
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
);
1164 TEXTPTR
= XCreateFontCursor(dpy
, XC_xterm
);
1165 WAITFOR
= XCreateFontCursor(dpy
, XC_watch
);
1167 XRecolorCursor(dpy
, TEXTPTR
, &fgcolor
, &bgcolor
);
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 /*----------------------------------------------------------------------*/
1175 void delete_window(XCWindowData
*window
)
1177 XCWindowData
*searchwin
, *lastwin
= NULL
;
1179 if (xobjs
.windowlist
->next
== NULL
) {
1180 quitcheck((window
== NULL
) ? NULL
: window
->area
, NULL
, NULL
);
1184 for (searchwin
= xobjs
.windowlist
; searchwin
!= NULL
; searchwin
=
1186 if (searchwin
== window
) {
1189 /* Free any select list */
1190 if (searchwin
->selects
> 0) free(searchwin
->selectlist
);
1192 /* Free the matrix and pushlist stacks */
1194 while (searchwin
->MatStack
!= NULL
) {
1195 thismat
= searchwin
->MatStack
;
1196 searchwin
->MatStack
= searchwin
->MatStack
->nextmatrix
;
1199 free_stack(&searchwin
->hierstack
);
1200 free_stack(&searchwin
->stack
);
1203 XFreeGC(dpy
, searchwin
->gc
);
1205 if (lastwin
!= NULL
)
1206 lastwin
->next
= searchwin
->next
;
1208 xobjs
.windowlist
= searchwin
->next
;
1211 lastwin
= searchwin
;
1214 if (searchwin
== NULL
) {
1215 Wprintf("No such window in list!\n");
1218 if (areawin
== searchwin
) areawin
= xobjs
.windowlist
;
1223 /*----------------------------------------------------------------------*/
1224 /* Create a new window structure and initialize it. */
1225 /* Return a pointer to the new window. */
1226 /*----------------------------------------------------------------------*/
1228 XCWindowData
*create_new_window()
1230 XCWindowData
*newwindow
;
1232 newwindow
= (XCWindowData
*)malloc(sizeof(XCWindowData
));
1236 newwindow
->toolbar_on
= True
;
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
;
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;
1296 /* Prepend to linked window list in global data (xobjs) */
1297 newwindow
->next
= xobjs
.windowlist
;
1298 xobjs
.windowlist
= newwindow
;
1303 /*----------------------------------------------------------------------*/
1304 /* Preparatory initialization (to be run before setting up the GUI) */
1305 /*----------------------------------------------------------------------*/
1307 void pre_initialize()
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 /*-------------------------------------------------------------*/
1319 putenv("LC_ALL=en_US");
1320 putenv("LC_NUMERIC=en_US");
1321 putenv("LANG=POSIX");
1324 unsetenv("LC_NUMERIC");
1325 setenv("LANG", "POSIX", 1);
1327 setlocale(LC_ALL
, "en_US");
1329 /*---------------------------*/
1330 /* initialize user variables */
1331 /*---------------------------*/
1333 strcpy(version
, PROG_VERSION
);
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
;
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;
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
);
1366 xobjs
.technologies
= NULL
;
1367 xobjs
.undostack
= NULL
;
1368 xobjs
.redostack
= NULL
;
1370 /* Set the temporary directory name as compiled, unless overridden by */
1371 /* environment variable "TMPDIR". */
1373 xobjs
.tempdir
= getenv("TMPDIR");
1374 if (xobjs
.tempdir
== NULL
) xobjs
.tempdir
= strdup(TEMP_DIR
);
1376 xobjs
.windowlist
= (XCWindowDataPtr
)NULL
;
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;
1387 xobjs
.imagelist
= NULL
;
1389 xobjs
.pages
= PAGES
;
1391 xobjs
.libsearchpath
= (char *)NULL
;
1392 xobjs
.filesearchpath
= (char *)NULL
;
1395 fonts
= (fontinfo
*) malloc(sizeof(fontinfo
));
1396 fonts
[0].encoding
= NULL
; /* To prevent segfaults */
1397 fonts
[0].psname
= NULL
;
1398 fonts
[0].family
= NULL
;
1400 /* Initialization of objects requires values for the window width and height, */
1401 /* so set up the widgets and realize them first. */
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 */
1411 /*----------------------------------------------------------------------*/
1412 /* Create a new Handle object in Tcl */
1413 /*----------------------------------------------------------------------*/
1415 static void UpdateStringOfHandle
_ANSI_ARGS_((Tcl_Obj
*objPtr
));
1416 static int SetHandleFromAny
_ANSI_ARGS_((Tcl_Interp
*interp
, Tcl_Obj
*objPtr
));
1418 static Tcl_ObjType tclHandleType
= {
1419 "handle", /* name */
1420 (Tcl_FreeInternalRepProc
*) NULL
, /* freeIntRepProc */
1421 (Tcl_DupInternalRepProc
*) NULL
, /* dupIntRepProc */
1422 UpdateStringOfHandle
, /* updateStringProc */
1423 SetHandleFromAny
/* setFromAnyProc */
1426 /*----------------------------------------------------------------------*/
1429 UpdateStringOfHandle(objPtr
)
1430 Tcl_Obj
*objPtr
; /* Int object whose string rep to update. */
1432 char buffer
[TCL_INTEGER_SPACE
];
1435 sprintf(buffer
, "H%08lX", objPtr
->internalRep
.longValue
);
1436 len
= strlen(buffer
);
1438 objPtr
->bytes
= Tcl_Alloc((u_int
)len
+ 1);
1439 strcpy(objPtr
->bytes
, buffer
);
1440 objPtr
->length
= len
;
1443 /*----------------------------------------------------------------------*/
1446 SetHandleFromAny(interp
, objPtr
)
1447 Tcl_Interp
*interp
; /* Used for error reporting if not NULL. */
1448 Tcl_Obj
*objPtr
; /* The object to convert. */
1450 Tcl_ObjType
*oldTypePtr
= (Tcl_ObjType
*)objPtr
->typePtr
;
1455 pushlistptr newstack
= NULL
;
1457 string
= Tcl_GetStringFromObj(objPtr
, &length
);
1459 for (p
= string
; isspace((u_char
)(*p
)); p
++);
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);
1469 free_stack(&newstack
);
1472 newLong
= strtoul(p
, &end
, 16);
1476 if (interp
!= NULL
) {
1478 * Must copy string before resetting the result in case a caller
1479 * is trying to convert the interpreter's result to an int.
1483 sprintf(buf
, "expected handle but got \"%.50s\"", string
);
1484 Tcl_ResetResult(interp
);
1485 Tcl_AppendToObj(Tcl_GetObjResult(interp
), buf
, -1);
1487 free_stack(&newstack
);
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
);
1497 free_stack(&newstack
);
1501 * Make sure that the string has no garbage after the end of the handle.
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. */
1509 if ((end
!= NULL
) && (*end
== '/')) {
1510 objinstptr refinst
, chkinst
;
1514 newLong
= strtoul(p
, &end
, 16);
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
);
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
);
1539 push_stack(&newstack
, chkinst
, NULL
);
1546 /* Note that this check won't prevent a hierarchical selection from */
1547 /* being added to a non-hierarchical selection. */
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 "
1554 free_stack(&newstack
);
1558 free_stack(&areawin
->hierstack
);
1559 areawin
->hierstack
= newstack
;
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
1568 if ((oldTypePtr
!= NULL
) && (oldTypePtr
->freeIntRepProc
!= NULL
)) {
1569 oldTypePtr
->freeIntRepProc(objPtr
);
1572 objPtr
->internalRep
.longValue
= newLong
;
1573 objPtr
->typePtr
= &tclHandleType
;
1577 /*----------------------------------------------------------------------*/
1580 Tcl_NewHandleObj(optr
)
1581 void *optr
; /* Int used to initialize the new object. */
1585 objPtr
= Tcl_NewObj();
1586 objPtr
->bytes
= NULL
;
1588 objPtr
->internalRep
.longValue
= (long)(optr
);
1589 objPtr
->typePtr
= &tclHandleType
;
1593 /*----------------------------------------------------------------------*/
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. */
1604 if (objPtr
->typePtr
!= &tclHandleType
) {
1605 result
= SetHandleFromAny(interp
, objPtr
);
1606 if (result
!= TCL_OK
) {
1610 l
= objPtr
->internalRep
.longValue
;
1611 if (((long)((int)l
)) == l
) {
1612 *handlePtr
= (void *)objPtr
->internalRep
.longValue
;
1615 if (interp
!= NULL
) {
1616 Tcl_ResetResult(interp
);
1617 Tcl_AppendToObj(Tcl_GetObjResult(interp
),
1618 "value too large to represent as handle", -1);
1626 /*----------------------------------------------------------------------*/
1627 /* Routine to initialize variables after the GUI has been set up */
1628 /*----------------------------------------------------------------------*/
1630 void post_initialize()
1634 /*--------------------------------------------------*/
1635 /* Setup the (simple) colormap and make the cursors */
1636 /*--------------------------------------------------*/
1638 setcolorscheme(True
);
1641 /* Now that we have values for the window width and height, we can initialize */
1642 /* the page objects. */
1644 xobjs
.libtop
= (objinstptr
*)malloc(LIBS
* sizeof(objinstptr
));
1645 for (i
= 0; i
< LIBS
; i
++) {
1646 objectptr newlibobj
= (objectptr
) malloc(sizeof(object
));
1648 xobjs
.libtop
[i
] = newpageinst(newlibobj
);
1651 /* Give names to the five default libraries */
1652 strcpy(xobjs
.libtop
[FONTLIB
]->thisobject
->name
, "Font Character List");
1653 strcpy(xobjs
.libtop
[PAGELIB
]->thisobject
->name
, "Page Directory");
1654 strcpy(xobjs
.libtop
[LIBLIB
]->thisobject
->name
, "Library Directory");
1655 strcpy(xobjs
.libtop
[USERLIB
]->thisobject
->name
, "User Library");
1660 /* Centering the view is not required here because the default values */
1661 /* set in initmem() should correctly position the empty page in the */
1662 /* middle of the viewing window. */
1664 #if !defined(HAVE_CAIRO)
1665 if ((dbuf
== (Pixmap
)NULL
) && areawin
->area
)
1666 dbuf
= XCreatePixmap(dpy
, areawin
->window
, areawin
->width
,
1667 areawin
->height
, DefaultDepthOfScreen(xcScreen(areawin
->area
)));
1670 /* Set up fundamentally necessary colors black and white */
1672 addnewcolorentry(xc_alloccolor("Black"));
1673 addnewcolorentry(xc_alloccolor("White"));
1677 /* Set up new Tcl type "handle" for element handles */
1678 Tcl_RegisterObjType(&tclHandleType
);
1682 /*-----------------------------------------------------*/
1683 /* Set the cursor as a crosshair for the area widget. */
1684 /* If areawin->area is NULL, then xcircuit is running */
1685 /* in batch mode, and no automatic save will be done. */
1686 /*-----------------------------------------------------*/
1688 if (areawin
->area
!= NULL
) {
1689 XDefineCursor (dpy
, areawin
->window
, DEFAULTCURSOR
);
1691 /*---------------------------------------------------*/
1692 /* Set up a timeout for automatic save to a tempfile */
1693 /*---------------------------------------------------*/
1695 xobjs
.save_interval
= appdata
.timeout
;
1696 xobjs
.timeout_id
= xcAddTimeOut(app
, 60000 * xobjs
.save_interval
,
1701 /*----------------------------------------------------------------------*/