/*----------------------------------------------------------------------*/ /* xcircuit.c --- An X-windows program for drawing circuit diagrams */ /* Copyright (c) 2002 R. Timothy Edwards */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to: */ /* Free Software Foundation, Inc. */ /* 59 Temple Place, Suite 330 */ /* Boston, MA 02111-1307 USA */ /* */ /* See file ./README for contact information */ /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /* Uses the Xw widget set (see directory Xw) */ /* Xcircuit written by Tim Edwards beginning 8/13/93 */ /*----------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #ifndef XC_WIN32 #include /* for unlink() */ #include #include #include #include #include #include #include #endif #ifdef TCL_WRAPPER #include #else #ifndef XC_WIN32 #include "Xw/Xw.h" #include "Xw/Form.h" #include "Xw/WorkSpace.h" #include "Xw/PButton.h" #include "Xw/SText.h" #include "Xw/Cascade.h" #include "Xw/PopupMgr.h" #include "Xw/MenuBtn.h" #include "Xw/BBoard.h" #include "Xw/TextEdit.h" #include "Xw/Toggle.h" #endif #endif #if defined(XC_WIN32) && defined(TCL_WRAPPER) #include #include #include #include #endif #ifndef P_tmpdir #define P_tmpdir TMPDIR #endif /*----------------------------------------------------------------------*/ /* Local includes */ /*----------------------------------------------------------------------*/ #include "xcircuit.h" #include "cursors.h" #include "colordefs.h" #include "menudep.h" /*----------------------------------------------------------------------*/ /* Function prototype declarations */ /*----------------------------------------------------------------------*/ #include "prototypes.h" #ifdef HAVE_XPM #ifndef XC_WIN32 #include #endif #include "lib/pixmaps/xcircuit.xpm" #endif /*----------------------------------------------------------------------*/ /* Global Variable definitions */ /*----------------------------------------------------------------------*/ char _STR2[250]; /* Specifically for text returned from the popup prompt */ char _STR[150]; /* Generic multipurpose string */ short popups; /* total number of popup widgets on the screen */ Boolean pressmode; /* Whether we are in a press & hold state */ #ifndef TCL_WRAPPER xcWidget message1, message2, message3, top, toolbar, overlay = NULL; xcWidget menuwidgets[MaxMenuWidgets]; #endif xcWidget wschema, wsymb, netbutton; XtAppContext app; Display *dpy; /* Works well to make this globally accessible */ Colormap cmap; Pixmap STIPPLE[STIPPLES]; /* Polygon fill-style stipple patterns */ Atom wprot, wmprop[2]; #ifndef OPENGL static #endif char STIPDATA[STIPPLES][4] = { "\000\004\000\001", "\000\005\000\012", "\001\012\005\010", "\005\012\005\012", "\016\005\012\007", "\017\012\017\005", "\017\012\017\016", "\000\000\000\000" }; Cursor appcursors[NUM_CURSORS]; ApplicationData appdata; Clientdata areastruct; Globaldata xobjs; int *appcolors; int number_colors; colorindex *colorlist; short menusize; xcIntervalId printtime_id; short beeper; short fontcount; fontinfo *fonts; extern short eventmode, textpos; #ifndef TCL_WRAPPER extern short help_up; extern menustruct TopButtons[]; #ifdef HAVE_XPM extern toolbarstruct ToolBar[]; extern short toolbuttons; #endif extern short maxbuttons; #endif extern Pixmap helppix; extern aliasptr aliastop; extern float version; #ifdef TCL_WRAPPER extern Tcl_Interp *xcinterp; #endif #ifdef DOUBLEBUFFER extern Pixmap dbuf; #endif /* Bad hack for problems with the DECstation. . . don't know why */ #ifdef UniqueContextProblem #undef XUniqueContext XContext XUniqueContext() { return XrmUniqueQuark(); } #endif /* End of bad hack. . . */ /*----------------------------------------------------------------------*/ /* Initial Resource Management */ /*----------------------------------------------------------------------*/ #ifndef TCL_WRAPPER #ifndef XC_WIN32 static XtResource resources[] = { /* schematic layout colors */ { "globalpincolor", "GlobalPinColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, globalcolor), XtRString, "Orange2"}, { "localpincolor", "LocalPinColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, localcolor), XtRString, "Red"}, { "infolabelcolor", "InfoLabelColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, infocolor), XtRString, "SeaGreen"}, { "ratsnestcolor", "RatsNestColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, ratsnestcolor), XtRString, "Tan4"}, /* non-schematic layout colors */ { "bboxcolor", "BBoxColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, bboxpix), XtRString, "greenyellow"}, /* GUI Color scheme 1 */ { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, fg), XtRString, "Black"}, { XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, bg), XtRString, "White"}, { "gridcolor", "GridColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, gridpix), XtRString, "Gray95"}, { "snapcolor", "SnapColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, snappix), XtRString, "Red"}, { "selectcolor", "SelectColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, selectpix), XtRString, "Gold3"}, { "querycolor", "QueryColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, querypix), XtRString, "Turquoise"}, { "filtercolor", "FilterColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, filterpix), XtRString, "SteelBlue3"}, { "axescolor", "AxesColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, axespix), XtRString, "Antique White"}, { "offbuttoncolor", "OffButtonColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, buttonpix), XtRString, "Gray85"}, { "auxiliarycolor", "AuxiliaryColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, auxpix), XtRString, "Green3"}, { "barcolor", "BarColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, barpix), XtRString, "Tan"}, { "paramcolor", "ParamColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, parampix), XtRString, "Plum3"}, /* GUI Color scheme 2 */ { "foreground2", XtCForeground, XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, fg2), XtRString, "White"}, { "background2", XtCBackground, XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, bg2), XtRString, "DarkSlateGray"}, { "gridcolor2", "GridColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, gridpix2), XtRString, "Gray40"}, { "snapcolor2", "SnapColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, snappix2), XtRString, "Red"}, { "selectcolor2", "SelectColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, selectpix2), XtRString, "Gold"}, { "querycolor2", "QueryColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, querypix2), XtRString, "Turquoise"}, { "filtercolor2", "FilterColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, filterpix2), XtRString, "SteelBlue1"}, { "axescolor2", "AxesColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, axespix2), XtRString, "NavajoWhite4"}, { "offbuttoncolor2", "OffButtonColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, buttonpix2), XtRString, "Gray50"}, { "auxiliarycolor2", "AuxiliaryColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, auxpix2), XtRString, "Green"}, { "barcolor2", "BarColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, barpix2), XtRString, "Tan"}, { "paramcolor2", "ParamColor", XtRPixel, sizeof(Pixel), XtOffset(ApplicationDataPtr, parampix2), XtRString, "Plum3"}, /* Other XDefaults-set properties */ { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), XtOffset(ApplicationDataPtr, xcfont), XtRString, "-*-times-bold-r-normal--14-*"}, { "helpfont", XtCFont, XtRFontStruct, sizeof(XFontStruct *), XtOffset(ApplicationDataPtr, helpfont), XtRString, "-*-helvetica-medium-r-normal--10-*"}, { "filelistfont", XtCFont, XtRFontStruct, sizeof(XFontStruct *), XtOffset(ApplicationDataPtr, filefont), XtRString, "-*-helvetica-medium-r-normal--14-*"}, { "textfont", XtCFont, XtRFontStruct, sizeof(XFontStruct *), XtOffset(ApplicationDataPtr, textfont), XtRString, "-*-courier-medium-r-normal--14-*"}, { "titlefont", XtCFont, XtRFontStruct, sizeof(XFontStruct *), XtOffset(ApplicationDataPtr, titlefont), XtRString, "-*-times-bold-i-normal--14-*"}, { XtNwidth, XtCWidth, XtRInt, sizeof(int), XtOffset(ApplicationDataPtr, width), XtRString, "950"}, { XtNheight, XtCHeight, XtRInt, sizeof(int), XtOffset(ApplicationDataPtr, height), XtRString, "760"}, { "timeout", "TimeOut", XtRInt, sizeof(int), XtOffset(ApplicationDataPtr, timeout), XtRString, "10"} }; #endif #endif /* !TCL_WRAPPER */ #ifdef OPENGL /*----------------------------------------------------------------------*/ /* Get RGB values for a color index. */ /* Note: We need a true reverse mapping here. . . */ /*----------------------------------------------------------------------*/ void getRGBcolor(int cval, int *red, int *green, int *blue) { int i; for (i = 0; i < number_colors; i++) { if (colorlist[i].color.pixel == cval) { *red = (int)colorlist[i].color.red; *green = (int)colorlist[i].color.green; *blue = (int)colorlist[i].color.blue; break; } } /* No color found---fill in values with black */ *red = 0; *green = 0; *blue = 0; } #endif /* OPENGL */ /*----------------------------------------------------------------------*/ /* Update the list of colors in the colormap */ /*----------------------------------------------------------------------*/ void addtocolorlist(xcWidget button, int cvalue) { number_colors++; colorlist = (colorindex *)realloc(colorlist, number_colors * sizeof(colorindex)); colorlist[number_colors - 1].cbutton = button; colorlist[number_colors - 1].color.pixel = cvalue; /* Get and store the RGB values of the new color */ XQueryColors(dpy, cmap, &(colorlist[number_colors - 1].color), 1); } /*----------------------------------------------------------------------*/ /* Add a new color button to the color menu */ /* called if new color button needs to be made */ /*----------------------------------------------------------------------*/ void addnewcolorentry(int ccolor) { xcWidget colormenu, newbutton; #ifndef TCL_WRAPPER Arg wargs[2]; #endif int i, n = 0; /* check to see if entry is already in the color list */ for (i = 0; i < number_colors; i++) if (colorlist[i].color.pixel == ccolor) break; /* make new entry in the menu */ if (i == number_colors) { #ifndef TCL_WRAPPER colormenu = xcParent(ColorAddNewColorButton); XtnSetArg(XtNlabelType, XwRECT); XtnSetArg(XtNrectColor, ccolor); newbutton = XtCreateWidget("NewColor", XwmenubuttonWidgetClass, colormenu, wargs, n); XtAddCallback (newbutton, XtNselect, (XtCallbackProc)setcolor, NULL); XtManageChild(newbutton); #endif addtocolorlist(newbutton, ccolor); #ifdef TCL_WRAPPER sprintf(_STR2, "xcircuit::newcolorbutton %d %d %d %d", colorlist[i].color.red, colorlist[i].color.green, colorlist[i].color.blue, i); Tcl_Eval(xcinterp, _STR2); #endif } } /*----------------------------------------------------------------------*/ /* This recursive function looks down the button menu hierarchy and */ /* creates the necessary buttons and submenus. */ /* Menu entries are marked if the corresponding "size" entry in the */ /* menu structure is > 0. */ /*----------------------------------------------------------------------*/ #ifndef TCL_WRAPPER void makesubmenu(char *menuname, char *attachname, menuptr buttonmenu, int arraysize, xcWidget manager) { #ifndef XC_WIN32 short i, n = 0; int cval; xcWidget popupshell, cascade; Arg wargs[6]; menuptr p; char popupname[30]; sprintf(popupname, "popup%s", menuname); popupshell = XtCreatePopupShell (popupname, transientShellWidgetClass, manager, NULL, 0); XtnSetArg(XtNattachTo, attachname); XtnSetArg(XtNfont, appdata.titlefont); cascade = XtCreateManagedWidget (menuname, XwcascadeWidgetClass, popupshell, wargs, n); for (p = buttonmenu, i = 0; p < buttonmenu + arraysize; p++, i++) { n = 0; if (p->size > 0 && p->submenu == NULL) { /* This denotes a marked entry */ XtnSetArg(XtNsetMark, True); } XtnSetArg(XtNfont, appdata.xcfont); if (p->submenu != NULL) { xcWidget newbutton = XtCreateWidget(p->name, XwmenubuttonWidgetClass, cascade, wargs, n); makesubmenu(p->name, p->name, p->submenu, p->size, manager); XtManageChild (newbutton); } else if (p->name[0] == ' ') { /* This is a separator, made from a PushButton widget */ xcWidget newbutton = XtCreateWidget(p->name, XwmenuButtonWidgetClass, cascade, wargs, n); n = 0; XtManageChild (newbutton); XtnSetArg(XtNheight, 5); XtnSetArg(XtNsensitive, False); XtSetValues(newbutton, wargs, n); } else { if (p->name[0] == '_') { /* Color button */ cval = xc_alloccolor(p->name + 1); XtnSetArg(XtNlabelType, XwRECT); XtnSetArg(XtNrectColor, cval); } else if (p->name[0] == ':') { /* Stipple button */ XtnSetArg(XtNlabelType, XwRECT); if (((pointertype)(p->passeddata) == (OPAQUE | FILLED | FILLSOLID))) { XtnSetArg(XtNrectColor, BlackPixel(dpy,DefaultScreen(dpy))); } else { XtnSetArg(XtNrectStipple, STIPPLE[((pointertype)(p->passeddata) & FILLSOLID) >> 5]); } } menuwidgets[++menusize] = XtCreateWidget(p->name, XwmenubuttonWidgetClass, cascade, wargs, n); XtAddCallback (menuwidgets[menusize], XtNselect, (XtCallbackProc)p->func, p->passeddata); if (p->name[0] == '_') { /* For color buttons, maintain a list of Widgets and color values */ addtocolorlist(menuwidgets[menusize], cval); } if (strcmp(p->name, "Enable XSchema") || !areastruct.schemon) XtManageChild (menuwidgets[menusize]); } } #endif } #endif /* !TCL_WRAPPER */ #ifdef HAVE_XPM /*----------------------------------------------------------------------*/ /* Toolbar Creator */ /*----------------------------------------------------------------------*/ #ifndef TCL_WRAPPER void createtoolbar (xcWidget abform, Widget aform) { #ifndef XC_WIN32 int i, n = 0; Arg wargs[12]; XImage *iret; XpmAttributes attr; XtnSetArg(XtNxRefWidget, aform); XtnSetArg(XtNxAddWidth, True); XtnSetArg(XtNxAttachRight, True); XtnSetArg(XtNyAttachBottom, True); XtnSetArg(XtNborderWidth, 0); XtnSetArg(XtNxOffset, 2); XtnSetArg(XtNyOffset, 2); XtnSetArg(XtNxResizable, False); XtnSetArg(XtNyResizable, True); XtnSetArg(XtNlayout, XwIGNORE); toolbar = XtCreateManagedWidget("ToolBar", XwbulletinWidgetClass, abform, wargs, n); n = 0; /* Fix for limited-color capability video. Thanks to */ /* Frankie Liu */ attr.valuemask = XpmSize | XpmCloseness; attr.closeness = 65536; for (i = 0; i < toolbuttons; i++) { XpmCreateImageFromData(dpy, ToolBar[i].icon_data, &iret, NULL, &attr); XtnSetArg(XtNlabelType, XwIMAGE); XtnSetArg(XtNlabelImage, iret); XtnSetArg(XtNwidth, attr.width + 4); XtnSetArg(XtNheight, attr.height + 4); XtnSetArg(XtNborderWidth, TBBORDER); XtnSetArg(XtNnoPad, True); XtnSetArg(XtNhint, ToolBar[i].hint); XtnSetArg(XtNhintProc, Wprintf); menuwidgets[++menusize] = XtCreateManagedWidget(ToolBar[i].name, XwmenuButtonWidgetClass, toolbar, wargs, n); n = 0; XtAddCallback(menuwidgets[menusize], XtNselect, (XtCallbackProc)ToolBar[i].func, ToolBar[i].passeddata); } #endif } #endif /* !TCL_WRAPPER */ /*----------------------------------------------------------------------*/ /* Toolbar Resize */ /*----------------------------------------------------------------------*/ #ifdef TCL_WRAPPER void resizetoolbar() { } #else void resizetoolbar() { int i, n = 0, bcol = 0; int max_width = 0, max_height = 0, tot_width = 0; Arg wargs[4]; xcWidget bwptr, lbwptr, bmax, lbmax; Dimension t_height, bheight, bwidth; xcWidget *tool_list = NULL; int pytools = 0; if (!xcIsRealized(toolbar)) return; /* Avoid recursive calls to self and extra calls to the main draw routine */ XtRemoveCallback(areastruct.area, XtNresize, (XtCallbackProc)resizetoolbar, NULL); XtRemoveCallback(areastruct.area, XtNresize, (XtCallbackProc)resizearea, NULL); /* Find the height of the toolbar from the parent widget */ XtnSetArg(XtNheight, &t_height); XtGetValues(xcParent(toolbar), wargs, n); n = 0; #ifdef HAVE_PYTHON tool_list = pytoolbuttons(&pytools); #endif /* Realign the tool buttons inside the fixed space */ for (i = 0; i < toolbuttons + pytools; i++) { #ifdef HAVE_PYTHON if (i >= toolbuttons) bwptr = tool_list[i - toolbuttons]; else #endif bwptr = XtNameToWidget(toolbar, ToolBar[i].name); if (bwptr == (Widget)NULL) break; XtnSetArg(XtNheight, &bheight); XtnSetArg(XtNwidth, &bwidth); XtGetValues(bwptr, wargs, n); n = 0; bheight += (TBBORDER << 1); max_height += bheight; if (max_height > t_height) { bcol++; lbmax = bmax; tot_width += max_width; max_width = 0; max_height = (int)bheight; } if (bwidth > max_width) { max_width = (int)bwidth; bmax = bwptr; } XtnSetArg(XtNx, tot_width); XtnSetArg(XtNy, max_height - bheight); XtSetValues(bwptr, wargs, n); n = 0; lbwptr = bwptr; } XtnSetArg(XtNwidth, tot_width + max_width); XtSetValues(toolbar, wargs, n); n = 0; /* Reinstate callbacks */ XtAddCallback(areastruct.area, XtNresize, (XtCallbackProc)resizetoolbar, NULL); XtAddCallback(areastruct.area, XtNresize, (XtCallbackProc)resizearea, NULL); #ifdef HAVE_PYTHON if (tool_list != NULL) free(tool_list); #endif } #endif /* HAVE_XPM */ #endif /* !TCL_WRAPPER */ /*----------------------------------------------------------------------*/ /* Hierarchical Menu Creator */ /* This function creates the top level of buttons which are arranged */ /* across the top starting at the left edge. For each button */ /* that has a submenu, a Popup manager is created, and then menu */ /* panes are attached to the manager in a hierarchical fashion. */ /* Note: Returns widget for last button on top level */ /*----------------------------------------------------------------------*/ #ifdef TCL_WRAPPER void createmenus (xcWidget form, xcWidget *firstbutton, xcWidget *lastbutton) { } #else void createmenus (xcWidget form, xcWidget *firstbutton, xcWidget *lastbutton) { #ifndef XC_WIN32 int i, maxmgrs = 0, n = 0, j = 0; WidgetList buttonw, mgr_shell, menu_mgr; Arg wargs[6]; menusize = -1; for (i = 0; i < maxbuttons; i++) if (TopButtons[i].submenu != NULL) maxmgrs++; buttonw = (WidgetList) XtMalloc(maxbuttons * sizeof(Widget)); mgr_shell = (WidgetList) XtMalloc(maxmgrs * sizeof(Widget)); menu_mgr = (WidgetList) XtMalloc(maxmgrs * sizeof(Widget)); for (i = 0; i < maxbuttons; i++) { XtnSetArg(XtNheight, ROWHEIGHT); XtnSetArg(XtNlabel, TopButtons[i].name); XtnSetArg(XtNfont, appdata.xcfont); if (i > 0) { XtnSetArg(XtNxRefWidget, buttonw[i - 1]); XtnSetArg(XtNxAddWidth, True); } buttonw[i] = XtCreateWidget(TopButtons[i].name, XwmenuButtonWidgetClass, form, wargs, n); n = 0; if (!strcmp(TopButtons[i].name, "Netlist")) { netbutton = buttonw[i]; if (areastruct.schemon) XtManageChild(buttonw[i]); } else XtManageChild(buttonw[i]); if(TopButtons[i].submenu == NULL) XtAddCallback(buttonw[i], XtNselect, (XtCallbackProc)TopButtons[i].func, NULL); else { mgr_shell[j] = XtCreatePopupShell("mgr_shell", shellWidgetClass, buttonw[i], NULL, 0); menu_mgr[j] = XtCreateManagedWidget("menu_mgr", XwpopupmgrWidgetClass, mgr_shell[j], NULL, 0); makesubmenu(TopButtons[i].name, "menu_mgr", TopButtons[i].submenu, TopButtons[i].size, menu_mgr[j]); j++; } } *firstbutton = buttonw[0]; *lastbutton = buttonw[i - 1]; #endif } #endif /* !TCL_WRAPPER */ /*---------------*/ /* Quit xcircuit */ /*---------------*/ void quit(xcWidget w, caddr_t nulldata) { int i; Matrixptr curmatrix, dmatrix; /* free up CTM Matrix Stack */ curmatrix = areastruct.MatStack; while (curmatrix != NULL) { dmatrix = curmatrix->nextmatrix; free(curmatrix); curmatrix = dmatrix; } areastruct.MatStack = NULL; /* free the colormap if a new one has been installed */ if (dpy != NULL) if (cmap != DefaultColormap(dpy, DefaultScreen(dpy))) XFreeColormap(dpy, cmap); /* exit ghostscript if background rendering was enabled */ exit_gs(); #ifdef TCL_WRAPPER /* exit ngspice if the simulator is still running */ exit_spice(); #endif /* remove any temporary files created for background rendering */ for (i = 0; i < xobjs.pages; i++) { if (xobjs.pagelist[i]->pageinst != NULL) if (xobjs.pagelist[i]->background.name != (char *)NULL) if (*(xobjs.pagelist[i]->background.name) == '@') unlink(xobjs.pagelist[i]->background.name + 1); } /* remove the temporary file and free the filename memory */ /* if w = NULL, quit() was reached from Ctrl-C. Don't */ /* remove the temporary file; instead, notify user of the */ /* filename. */ if (xobjs.tempfile != NULL) { if (w != NULL) { #ifndef XC_WIN32 if (unlink(xobjs.tempfile) < 0) Fprintf(stderr, "Error %d unlinking file \"%s\"\n", errno, xobjs.tempfile); #else if (DeleteFile(xobjs.tempfile) != TRUE) Fprintf(stderr, "Error %d unlinking file \"%s\"\n", GetLastError(), xobjs.tempfile); #endif } else Fprintf(stderr, "Ctrl-C exit: reload workspace from \"%s\"\n", xobjs.tempfile); } free(xobjs.tempfile); #if defined(HAVE_PYTHON) /* exit by exiting the Python interpreter, if enabled */ exit_interpreter(); #elif defined(TCL_WRAPPER) exit(0); /* For now, exit. Later, clear all pages and return to interp. */ #elif defined(XC_WIN32) PostQuitMessage(0); #else exit(0); #endif } /*--------------------------------------------------------------*/ /* Check to see if any objects in xcircuit have been modified */ /* without saving. */ /*--------------------------------------------------------------*/ u_short countchanges(char **promptstr) { int slen = 1, i, j; u_short changes = 0, words = 1; objectptr thisobj; if (promptstr != NULL) slen += strlen(*promptstr); for (i = 0; i < xobjs.pages; i++) { if (xobjs.pagelist[i]->pageinst != NULL) { thisobj = xobjs.pagelist[i]->pageinst->thisobject; if (thisobj->changes > 0) { if (promptstr != NULL) { slen += strlen(thisobj->name) + 2; *promptstr = (char *)realloc(*promptstr, slen); if ((words % 8) == 0) strcat(*promptstr, ",\n"); else if (changes > 0) strcat(*promptstr, ", "); strcat(*promptstr, thisobj->name); words++; } changes += thisobj->changes; } } } /* Check all library objects for unsaved changes */ for (i = 0; i < xobjs.numlibs; i++) { for (j = 0; j < xobjs.userlibs[i].number; j++) { thisobj = *(xobjs.userlibs[i].library + j); if (thisobj->changes > 0) { if (promptstr != NULL) { slen += strlen(thisobj->name) + 2; *promptstr = (char *)realloc(*promptstr, slen); if ((words % 8) == 0) strcat(*promptstr, ",\n"); else if (changes > 0) strcat(*promptstr, ", "); strcat(*promptstr, thisobj->name); words++; } changes += thisobj->changes; } } } return changes; } /*----------------------------------------------*/ /* Check for conditions to approve program exit */ /*----------------------------------------------*/ void quitcheck(xcWidget w, caddr_t clientdata, caddr_t calldata) { char *promptstr; Boolean doprompt = False; buttonsave *savebutton; /* enable default interrupt signal handler during this time, so that */ /* a double Control-C will ALWAYS exit. */ signal(SIGINT, SIG_DFL); #ifdef TCL_WRAPPER promptstr = (char *)malloc(60); strcpy(promptstr, ".query.title.field configure -text \"Unsaved changes in: "); #else promptstr = (char *)malloc(22); strcpy(promptstr, "Unsaved changes in: "); #endif /* Check all page objects for unsaved changes */ doprompt = (countchanges(&promptstr) > 0) ? True : False; /* If any changes have not been saved, generate a prompt */ if (doprompt) { promptstr = (char *)realloc(promptstr, strlen(promptstr) + 15); strcat(promptstr, "\nQuit anyway?"); #ifdef TCL_WRAPPER strcat(promptstr, "\""); Tcl_Eval(xcinterp, promptstr); Tcl_Eval(xcinterp, ".query.bbar.okay configure -command {quitnocheck}"); Tcl_Eval(xcinterp, "wm deiconify .query"); #else savebutton = (buttonsave *)malloc(sizeof(buttonsave)); getgeneric(savebutton, w, quitcheck, NULL); popupprompt(w, promptstr, NULL, quit, savebutton, NULL); #endif free(promptstr); } else { free(promptstr); quit(areastruct.area, NULL); } } /*--------------------------------------*/ /* A gentle Ctrl-C shutdown */ /*--------------------------------------*/ void dointr(int signum) { quitcheck(NULL, NULL, NULL); } /*--------------*/ /* Null routine */ /*--------------*/ void DoNothing(xcWidget w, caddr_t clientdata, caddr_t calldata) { /* Nothing here! */ } /*-------------------------------------------------------------------------*/ /* Popup dialog box routines */ /*-------------------------------------------------------------------------*/ /* Propogate any key event from the dialog box into the textedit widget */ /*-------------------------------------------------------------------------*/ #ifndef TCL_WRAPPER #ifndef XC_WIN32 void propevent(xcWidget w, xcWidget editwidget, XEvent *event) { Window ewin = xcWindow(editwidget); event->xany.window = ewin; XSendEvent(dpy, ewin, False, KeyPressMask, event); } #endif #endif /*-------------------------------------------------------------------------*/ /* Destroy an interactive text-editing popup box */ /*-------------------------------------------------------------------------*/ #ifdef TCL_WRAPPER /* Just pop it down. . . */ void destroypopup(xcWidget button, popupstruct *callstruct, caddr_t calldata) { Tk_UnmapWindow(callstruct->popup); popups--; /* free the allocated structure space */ free(callstruct->buttonptr); if (callstruct->filter != NULL) free(callstruct->filter); free(callstruct); /* in the case of "quitcheck", we want to make sure that the signal */ /* handler is reset to default behavior if the quit command is */ /* canceled from inside the popup prompt window. */ signal(SIGINT, dointr); } #else void destroypopup(xcWidget button, popupstruct *callstruct, caddr_t calldata) { #ifndef XC_WIN32 Arg wargs[1]; if(XtNameToWidget(callstruct->popup, "help2") != NULL) { help_up = False; XFreePixmap(dpy, helppix); helppix = (Pixmap)NULL; } if (callstruct->buttonptr->button != NULL) { /* return the button to its normal state */ XtSetArg(wargs[0], XtNforeground, callstruct->buttonptr->foreground); XtSetValues(callstruct->buttonptr->button, wargs, 1); XtAddCallback(callstruct->buttonptr->button, XtNselect, (XtCallbackProc)callstruct->buttonptr->buttoncall, callstruct->buttonptr->dataptr); } XtDestroyWidget(callstruct->popup); popups--; /* free the allocated structure space */ free(callstruct->buttonptr); if (callstruct->filter != NULL) free(callstruct->filter); free(callstruct); /* in the case of "quitcheck", we want to make sure that the signal */ /* handler is reset to default behavior if the quit command is */ /* canceled from inside the popup prompt window. */ signal(SIGINT, dointr); #endif } /*----------------------------------------------------------------------*/ /* Toggle button showing number of pages of output. */ /* Erase the filename and set everything accordingly. */ /*----------------------------------------------------------------------*/ void linkset(xcWidget button, propstruct *callstruct, caddr_t calldata) { Arg wargs[1]; free(xobjs.pagelist[areastruct.page]->filename); xobjs.pagelist[areastruct.page]->filename = (char *)malloc(1); xobjs.pagelist[areastruct.page]->filename[0] = '\0'; XwTextClearBuffer(callstruct->textw); getproptext(button, callstruct, calldata); /* Change the select button back to "Apply" */ XtSetArg(wargs[0], XtNlabel, "Apply"); XtSetValues(callstruct->buttonw, wargs, 1); /* Pop down the toggle button */ XtUnmanageChild(button); } /*----------------------------------------------------------------------*/ /* Pull text from the popup prompt buffer into a global string variable */ /*----------------------------------------------------------------------*/ #ifndef XC_WIN32 void xcgettext(xcWidget button, popupstruct *callstruct, caddr_t calldata) { if (callstruct->textw != NULL) { sprintf(_STR2, "%.249s", XwTextCopyBuffer(callstruct->textw)); /* functions which use the file selector should look for directory name */ /* in string rather than a file name, and take appropriate action. */ if (callstruct->filew != NULL) { if (lookdirectory(_STR2)) { newfilelist(callstruct->filew, callstruct); return; } } } /* Pop down the widget now (for functions like execscript() which */ /* may want to interactively control the window contents), but do */ /* not destroy it until the function has returned. */ XtPopdown(callstruct->popup); /* call the function which sets the variable according to type */ /* This is in format (function)(calling-widget, ptr-to-data) */ (*(callstruct->setvalue))(callstruct->buttonptr->button, callstruct->buttonptr->dataptr); if (callstruct->filew != NULL) newfilelist(callstruct->filew, callstruct); destroypopup(button, callstruct, calldata); } #endif /*-------------------------------------------------------------------------*/ /* Grab text from the "output properties" window */ /*-------------------------------------------------------------------------*/ void getproptext(xcWidget button, propstruct *callstruct, caddr_t calldata) { /* xobjs.pagelist[areastruct.page]->filename can be realloc'd by the */ /* call to *(callstruct->setvalue), so callstruct->dataptr may no */ /* longer be pointing to the data. */ #ifndef TCL_WRAPPER Arg wargs[1]; #endif short file_yes = (callstruct->setvalue == setfilename); sprintf(_STR2, "%.249s", XwTextCopyBuffer(callstruct->textw)); (*(callstruct->setvalue))(button, callstruct->dataptr); /* special stuff for filename changes */ if (file_yes) { char blabel[1024]; short num_linked; xcWidget wrbutton, ltoggle; struct stat statbuf; /* get updated file information */ if (strstr(xobjs.pagelist[areastruct.page]->filename, ".") == NULL) sprintf(blabel, "%s.ps", xobjs.pagelist[areastruct.page]->filename); else sprintf(blabel, "%s", xobjs.pagelist[areastruct.page]->filename); if (stat(blabel, &statbuf) == 0) { sprintf(blabel, " Overwrite File "); if (beeper) XBell(dpy, 100); Wprintf(" Warning: File exists"); } else { sprintf(blabel, " Write File "); if (errno == ENOTDIR) Wprintf("Error: Incorrect pathname"); else if (errno == EACCES) Wprintf("Error: Path not readable"); Wprintf(" "); } wrbutton = XtNameToWidget(xcParent(button), "Write File"); XtSetArg(wargs[0], XtNlabel, blabel); XtSetValues(wrbutton, wargs, 1); num_linked = pagelinks(areastruct.page); if (num_linked > 1) { ltoggle = XtNameToWidget(xcParent(button), "LToggle"); sprintf(blabel, "%d Pages", num_linked); XtSetArg(wargs[0], XtNlabel, blabel); XtSetValues(ltoggle, wargs, 1); XtManageChild(ltoggle); } } /* topobject->name is not malloc'd, so is not changed by call to */ /* *(callstruct->setvalue). */ else if (callstruct->dataptr == topobject->name) { printname(topobject); renamepage(areastruct.page); } /* Button title changes from "Apply" to "Okay" */ XtSetArg(wargs[0], XtNlabel, "Okay"); XtSetValues(callstruct->buttonw, wargs, 1); } /*----------------------------------------------------------------------*/ /* Update scale, width, and height in response to change of one of them */ /*----------------------------------------------------------------------*/ void updatetext(xcWidget button, xcWidgetList callstruct, caddr_t calldata) { float oscale, psscale; char edit[3][50]; short i, n, posit; char *pdptr; Arg wargs[2]; int width, height; /* auto-fit may override any changes to the scale */ autoscale(areastruct.page); writescalevalues(edit[0], edit[1], edit[2]); for (i = 0; i < 3; i++) { n = 0; XtnSetArg(XtNstring, edit[i]); pdptr = strchr(edit[i], '.'); posit = (pdptr != NULL) ? (short)(pdptr - edit[i]) : strlen(edit[i]); XtnSetArg(XtNinsertPosition, posit); XtSetValues(callstruct[i + 2], wargs, n); } } #endif /* !TCL_WRAPPER */ /*-------------------------------------------------------------------------*/ /* Update the object name in response to a change in filename */ /*-------------------------------------------------------------------------*/ void updatename(xcWidget button, xcWidgetList callstruct, caddr_t calldata) { short n, posit; char *rootptr; #ifndef TCL_WRAPPER Arg wargs[2]; #endif if (strstr(topobject->name, "Page ") != NULL || strstr(topobject->name, "Page_") != NULL || topobject->name[0] == '\0') { rootptr = strrchr(xobjs.pagelist[areastruct.page]->filename, '/'); if (rootptr == NULL) rootptr = xobjs.pagelist[areastruct.page]->filename; else rootptr++; sprintf(topobject->name, "%.79s", rootptr); n = 0; posit = strlen(topobject->name); #ifndef TCL_WRAPPER XtnSetArg(XtNstring, topobject->name); XtnSetArg(XtNinsertPosition, posit); XtSetValues(callstruct[1], wargs, n); #endif printname(topobject); renamepage(areastruct.page); } } /*-------------------------------------------------------------------------*/ /* Create a popup window with "OK" and "Cancel" buttons, */ /* and text and label fields. */ /*-------------------------------------------------------------------------*/ #ifdef TCL_WRAPPER void popupprompt(xcWidget button, char *request, char *current, void (*function)(), buttonsave *datastruct, const char *filter) { Tk_Window popup; popup = Tk_NameToWindow(xcinterp, ".dialog", Tk_MainWindow(xcinterp)); Tk_MapWindow(popup); } #else #ifndef XC_WIN32 void popupprompt(xcWidget button, char *request, char *current, void (*function)(), buttonsave *datastruct, const char *filter) { Arg wargs[9]; xcWidget popup, dialog, okbutton, cancelbutton, entertext; xcWidget staticarea; XWMHints *wmhints; /* for proper input focus */ Position xpos, ypos; short n = 0; Dimension height, width, areawidth, areaheight, bwidth, owidth; static char defaultTranslations[] = "Return: execute()"; popupstruct *okaystruct; height = (current == NULL) ? ROWHEIGHT * 4 : ROWHEIGHT * 5; if (filter) height += LISTHEIGHT; width = XTextWidth(appdata.xcfont, request, strlen(request)) + 20; bwidth = XTextWidth(appdata.xcfont, "Cancel", strlen("Cancel")) + 50; owidth = XTextWidth(appdata.xcfont, "Okay", strlen("Okay")) + 50; if (width < 400) width = 400; XtnSetArg(XtNwidth, &areawidth); XtnSetArg(XtNheight, &areaheight); XtGetValues(areastruct.area, wargs, n); n = 0; XtTranslateCoords(areastruct.area, (Position) (areawidth / 2 - width / 2 + popups * 20), (Position) (areaheight / 2 - height / 2 + popups * 20), &xpos, &ypos); XtnSetArg(XtNx, xpos); XtnSetArg(XtNy, ypos); popup = XtCreatePopupShell("prompt", transientShellWidgetClass, button == NULL ? areastruct.area : button, wargs, n); n = 0; popups++; XtnSetArg(XtNlayout, XwIGNORE); XtnSetArg(XtNwidth, width); XtnSetArg(XtNheight, height); dialog = XtCreateManagedWidget("dialog", XwbulletinWidgetClass, popup, wargs, n); n = 0; XtnSetArg(XtNx, 20); XtnSetArg(XtNy, ROWHEIGHT - 10 + (filter ? LISTHEIGHT : 0)); XtnSetArg(XtNstring, request); XtnSetArg(XtNborderWidth, 0); XtnSetArg(XtNgravity, WestGravity); XtnSetArg(XtNfont, appdata.xcfont); staticarea = XtCreateManagedWidget("static", XwstaticTextWidgetClass, dialog, wargs, n); n = 0; XtnSetArg(XtNx, 20); XtnSetArg(XtNy, height - ROWHEIGHT - 10); XtnSetArg(XtNwidth, owidth); XtnSetArg(XtNfont, appdata.xcfont); okbutton = XtCreateManagedWidget("Okay", XwmenuButtonWidgetClass, dialog, wargs, n); n = 0; okaystruct = (popupstruct *) malloc(sizeof(popupstruct)); okaystruct->buttonptr = datastruct; okaystruct->popup = popup; okaystruct->filter = (filter == NULL) ? NULL : strdup(filter); okaystruct->setvalue = function; okaystruct->textw = NULL; okaystruct->filew = NULL; XtnSetArg(XtNx, width - bwidth - 20); XtnSetArg(XtNy, height - ROWHEIGHT - 10); XtnSetArg(XtNwidth, bwidth); XtnSetArg(XtNfont, appdata.xcfont); cancelbutton = XtCreateManagedWidget("Cancel", XwmenuButtonWidgetClass, dialog, wargs, n); n = 0; XtAddCallback(cancelbutton, XtNselect, (XtCallbackProc)destroypopup, okaystruct); /* Event handler for WM_DELETE_WINDOW message. */ XtAddEventHandler(popup, NoEventMask, True, (XtEventHandler)delwin, okaystruct); if (current != NULL) { /* A Text Edit widget is required */ char *pdptr; short posit; XtnSetArg(XtNx, 20); XtnSetArg(XtNy, ROWHEIGHT + 10 + (filter ? LISTHEIGHT : 0)); XtnSetArg(XtNheight, ROWHEIGHT + 5); XtnSetArg(XtNwidth, width - 40); XtnSetArg(XtNstring, current); pdptr = strchr(current, '.'); posit = (pdptr != NULL) ? (short)(pdptr - current) : strlen(current); XtnSetArg(XtNinsertPosition, posit); XtnSetArg(XtNscroll, XwAutoScrollHorizontal); XtnSetArg(XtNwrap, XwWrapOff); XtnSetArg(XtNfont, appdata.textfont); entertext = XtCreateManagedWidget("Edit", XwtextEditWidgetClass, dialog, wargs, n); n = 0; okaystruct->textw = entertext; XtAddEventHandler(dialog, KeyPressMask, False, (XtEventHandler)propevent, entertext); XtAddEventHandler(staticarea, KeyPressMask, False, (XtEventHandler)propevent, entertext); XtOverrideTranslations(entertext, XtParseTranslationTable (defaultTranslations)); XtAddCallback(entertext, XtNexecute, (XtCallbackProc)xcgettext, okaystruct); /* Generate file prompting widget */ if (filter) genfilelist(dialog, okaystruct, width); } XtAddCallback(okbutton, XtNselect, (XtCallbackProc)xcgettext, okaystruct); XtPopup(popup, XtGrabNone); /* set the input focus for the window */ wmhints = XGetWMHints(dpy, xcWindow(popup)); wmhints->flags |= InputHint; wmhints->input = True; XSetWMHints(dpy, xcWindow(popup), wmhints); XSetTransientForHint(dpy, xcWindow(popup), xcWindow(top)); XFree(wmhints); if (current != NULL) XDefineCursor(dpy, xcWindow(entertext), TEXTPTR); } #endif #endif /*-----------------------------------------------------------------------*/ /* Write page scale (overall scale, and X and Y dimensions) into strings */ /*-----------------------------------------------------------------------*/ void writescalevalues(char *scdest, char *xdest, char *ydest) { float oscale, psscale; int width, height; Pagedata *curpage; curpage = xobjs.pagelist[areastruct.page]; oscale = curpage->outscale; psscale = getpsscale(oscale, areastruct.page); width = toplevelwidth(curpage->pageinst, NULL); height = toplevelheight(curpage->pageinst, NULL); sprintf(scdest, "%6.5f", oscale); if (curpage->coordstyle == CM) { sprintf(xdest, "%6.5f", (width * psscale) / IN_CM_CONVERT); sprintf(ydest, "%6.5f", (height * psscale) / IN_CM_CONVERT); } else { sprintf(xdest, "%6.5f", (width * psscale) / 72.0); sprintf(ydest, "%6.5f", (height * psscale) / 72.0); } } /*-------------------------------------------------------------------------*/ /* Create a popup window for property changes */ /*-------------------------------------------------------------------------*/ #define MAXPROPS 7 #define MARGIN 15 propstruct okstruct[MAXPROPS], fpokstruct; #ifdef TCL_WRAPPER void outputpopup(xcWidget button, caddr_t clientdata, caddr_t calldata) { Tcl_Eval(xcinterp, "wm deiconify .output"); } #else #ifndef XC_WIN32 void outputpopup(xcWidget button, caddr_t clientdata, caddr_t calldata) { buttonsave *savebutton; Arg wargs[9]; xcWidget popup, dialog, okbutton, titlearea, wrbutton; xcWidget fpentertext, fpokay, autobutton, allpages; xcWidgetList staticarea, entertext, okays; XWMHints *wmhints; /* for proper input focus */ short num_linked; Position xpos, ypos; short n = 0; Dimension height, width, areawidth, areaheight, bwidth, owidth, wwidth; Pagedata *curpage; char *pdptr; short posit, i; popupstruct *donestruct; void (*function[MAXPROPS])(); void (*update[MAXPROPS])(); char statics[MAXPROPS][50], edit[MAXPROPS][75], request[150]; char fpedit[75], outname[75], pstr[20]; void *data[MAXPROPS]; struct stat statbuf; static char defaultTranslations[] = "Return: execute()"; if (is_page(topobject) == -1) { Wprintf("Can only save a top-level page!"); return; } savebutton = (buttonsave *)malloc(sizeof(buttonsave)); if (button == NULL) button = FileWriteXcircuitPSButton; getgeneric(savebutton, button, outputpopup, NULL); curpage = xobjs.pagelist[areastruct.page]; sprintf(request, "PostScript output properties (Page %d):", areastruct.page + 1); sprintf(statics[0], "Filename:"); sprintf(statics[1], "Page label:"); sprintf(statics[2], "Scale:"); if (curpage->coordstyle == CM) { sprintf(statics[3], "X Size (cm):"); sprintf(statics[4], "Y Size (cm):"); } else { sprintf(statics[3], "X Size (in):"); sprintf(statics[4], "Y Size (in):"); } sprintf(statics[5], "Orientation:"); sprintf(statics[6], "Mode:"); sprintf(edit[0], "%s", curpage->filename); sprintf(edit[1], "%s", topobject->name); /* recompute bounding box and auto-scale, if set */ calcbbox(areastruct.topinstance); if (curpage->pmode & 2) autoscale(areastruct.page); writescalevalues(edit[2], edit[3], edit[4]); sprintf(edit[5], "%s", (curpage->orient == 0) ? "Portrait" : "Landscape"); sprintf(edit[6], "%s", (curpage->pmode & 1) ? "Full page" : "Embedded (EPS)"); function[0] = setfilename; function[1] = setpagelabel; function[2] = setfloat; function[3] = setscalex; function[4] = setscaley; function[5] = setorient; function[6] = setpmode; update[0] = updatename; update[1] = update[6] = NULL; update[2] = updatetext; update[3] = updatetext; update[4] = updatetext; update[5] = updatetext; data[0] = &(curpage->filename); data[1] = topobject->name; data[2] = data[3] = data[4] = &(curpage->outscale); data[5] = &(curpage->orient); data[6] = &(curpage->pmode); entertext = (xcWidgetList) XtMalloc (7 * sizeof (xcWidget)); staticarea = (xcWidgetList) XtMalloc (7 * sizeof (xcWidget)); okays = (xcWidgetList) XtMalloc (6 * sizeof (xcWidget)); /* get file information */ if (strstr(edit[0], ".") == NULL) sprintf(outname, "%s.ps", edit[0]); else sprintf(outname, "%s", edit[0]); if (stat(outname, &statbuf) == 0) { sprintf(outname, "Overwrite File"); Wprintf(" Warning: File exists"); } else { sprintf(outname, "Write File"); if (errno == ENOTDIR) Wprintf("Error: Incorrect pathname"); else if (errno == EACCES) Wprintf("Error: Path not readable"); else Wprintf(" "); } height = ROWHEIGHT * 17; /* 3 + (2 * MAXPROPS) */ width = XTextWidth(appdata.xcfont, request, strlen(request)) + 20; bwidth = XTextWidth(appdata.xcfont, "Close", strlen("Close")) + 50; owidth = XTextWidth(appdata.xcfont, "Apply", strlen("Apply")) + 50; wwidth = XTextWidth(appdata.xcfont, outname, strlen(outname)) + 80; if (width < 500) width = 500; XtnSetArg(XtNwidth, &areawidth); XtnSetArg(XtNheight, &areaheight); XtGetValues(areastruct.area, wargs, n); n = 0; XtTranslateCoords(areastruct.area, (Position) (areawidth / 2 - width / 2 + popups * 20), (Position) (areaheight / 2 - height / 2 + popups * 20), &xpos, &ypos); XtnSetArg(XtNx, xpos); XtnSetArg(XtNy, ypos); popup = XtCreatePopupShell("prompt", transientShellWidgetClass, areastruct.area, wargs, n); n = 0; popups++; XtnSetArg(XtNlayout, XwIGNORE); XtnSetArg(XtNwidth, width); XtnSetArg(XtNheight, height); dialog = XtCreateManagedWidget("dialog", XwbulletinWidgetClass, popup, wargs, n); n = 0; XtnSetArg(XtNx, 20); XtnSetArg(XtNy, ROWHEIGHT - 10); XtnSetArg(XtNstring, request); XtnSetArg(XtNborderWidth, 0); XtnSetArg(XtNgravity, WestGravity); XtnSetArg(XtNbackground, BARCOLOR); XtnSetArg(XtNfont, appdata.xcfont); titlearea = XtCreateManagedWidget("title", XwstaticTextWidgetClass, dialog, wargs, n); n = 0; XtnSetArg(XtNx, 20); XtnSetArg(XtNy, height - ROWHEIGHT - 10); XtnSetArg(XtNwidth, owidth); XtnSetArg(XtNfont, appdata.xcfont); okbutton = XtCreateManagedWidget("Close", XwmenuButtonWidgetClass, dialog, wargs, n); n = 0; XtnSetArg(XtNx, width - wwidth - 20); XtnSetArg(XtNy, height - ROWHEIGHT - 10); XtnSetArg(XtNwidth, wwidth); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNlabel, outname); wrbutton = XtCreateManagedWidget("Write File", XwmenuButtonWidgetClass, dialog, wargs, n); n = 0; for (i = 0; i < MAXPROPS; i++) { XtnSetArg(XtNx, 20); XtnSetArg(XtNy, ROWHEIGHT + MARGIN + 5 + (i * 2 * ROWHEIGHT)); XtnSetArg(XtNstring, statics[i]); XtnSetArg(XtNborderWidth, 0); XtnSetArg(XtNgravity, WestGravity); XtnSetArg(XtNfont, appdata.xcfont); staticarea[i] = XtCreateManagedWidget("static", XwstaticTextWidgetClass, dialog, wargs, n); n = 0; XtnSetArg(XtNx, 150); XtnSetArg(XtNy, ROWHEIGHT + MARGIN + (i * 2 * ROWHEIGHT)); if (i < 5) { XtnSetArg(XtNheight, ROWHEIGHT + 5); XtnSetArg(XtNstring, edit[i]); XtnSetArg(XtNwidth, width - owidth - 190); pdptr = strchr(edit[i], '.'); posit = (pdptr != NULL) ? (short)(pdptr - edit[i]) : strlen(edit[i]); XtnSetArg(XtNinsertPosition, posit); XtnSetArg(XtNscroll, XwAutoScrollHorizontal); XtnSetArg(XtNwrap, XwWrapOff); XtnSetArg(XtNfont, appdata.textfont); entertext[i] = XtCreateManagedWidget("Edit", XwtextEditWidgetClass, dialog, wargs, n); n = 0; XtnSetArg(XtNx, width - owidth - 20); XtnSetArg(XtNy, ROWHEIGHT + MARGIN + (i * 2 * ROWHEIGHT)); XtnSetArg(XtNwidth, owidth); XtnSetArg(XtNfont, appdata.xcfont); okays[i] = XtCreateManagedWidget("Apply", XwmenuButtonWidgetClass, dialog, wargs, n); n = 0; okstruct[i].textw = entertext[i]; okstruct[i].buttonw = okays[i]; okstruct[i].setvalue = function[i]; okstruct[i].dataptr = data[i]; XtAddCallback(okays[i], XtNselect, (XtCallbackProc)getproptext, &okstruct[i]); if (update[i] != NULL) XtAddCallback(okays[i], XtNselect, (XtCallbackProc)update[i], entertext); XtOverrideTranslations(entertext[i], XtParseTranslationTable (defaultTranslations)); XtAddCallback(entertext[i], XtNexecute, (XtCallbackProc)getproptext, &okstruct[i]); if (update[i] != NULL) XtAddCallback(entertext[i], XtNexecute, (XtCallbackProc)update[i], entertext); } else { XtnSetArg(XtNlabel, edit[i]); XtnSetArg(XtNfont, appdata.xcfont); entertext[i] = XtCreateManagedWidget("Toggle", XwpushButtonWidgetClass, dialog, wargs, n); n = 0; XtAddCallback(entertext[i], XtNselect, (XtCallbackProc)function[i], data[i]); if (update[i] != NULL) XtAddCallback(entertext[i], XtNselect, (XtCallbackProc)update[i], entertext); } } /* If this filename is linked to other pages (multi-page output), add a button */ /* which will unlink the page name from the other pages when toggled. */ num_linked = pagelinks(areastruct.page); XtnSetArg(XtNx, width - wwidth - 20); XtnSetArg(XtNy, ROWHEIGHT - 10); XtnSetArg(XtNset, True); XtnSetArg(XtNsquare, True); XtnSetArg(XtNborderWidth, 0); XtnSetArg(XtNfont, appdata.xcfont); sprintf(pstr, "%d Pages", num_linked); XtnSetArg(XtNlabel, pstr); allpages = XtCreateWidget("LToggle", XwtoggleWidgetClass, dialog, wargs, n); n = 0; XtAddCallback(allpages, XtNrelease, (XtCallbackProc)linkset, &okstruct[0]); /* If full-page pmode is chosen, there is an additional text structure. Make this text structure always but allow it to be managed and unmanaged as necessary. */ XtnSetArg(XtNx, 240); XtnSetArg(XtNy, ROWHEIGHT + MARGIN + (10 * ROWHEIGHT)); XtnSetArg(XtNset, (curpage->pmode & 2) ? True : False); XtnSetArg(XtNsquare, True); XtnSetArg(XtNborderWidth, 0); XtnSetArg(XtNfont, appdata.xcfont); autobutton = XtCreateWidget("Auto-fit", XwtoggleWidgetClass, dialog, wargs, n); n = 0; if (curpage->coordstyle == CM) { sprintf(fpedit, "%3.2f x %3.2f cm", (float)curpage->pagesize.x / IN_CM_CONVERT, (float)curpage->pagesize.y / IN_CM_CONVERT); } else { sprintf(fpedit, "%3.2f x %3.2f in", (float)curpage->pagesize.x / 72.0, (float)curpage->pagesize.y / 72.0); } XtnSetArg(XtNx, 240); XtnSetArg(XtNy, ROWHEIGHT + MARGIN + (12 * ROWHEIGHT)); XtnSetArg(XtNheight, ROWHEIGHT + 5); XtnSetArg(XtNstring, fpedit); XtnSetArg(XtNwidth, width - owidth - 280); pdptr = strchr(fpedit, '.'); posit = (pdptr != NULL) ? (short)(pdptr - fpedit) : strlen(fpedit); XtnSetArg(XtNscroll, XwAutoScrollHorizontal); XtnSetArg(XtNwrap, XwWrapOff); XtnSetArg(XtNfont, appdata.textfont); XtnSetArg(XtNinsertPosition, posit); fpentertext = XtCreateWidget("fpedit", XwtextEditWidgetClass, dialog, wargs, n); n = 0; XtnSetArg(XtNx, width - owidth - 20); XtnSetArg(XtNy, ROWHEIGHT + MARGIN + (12 * ROWHEIGHT)); XtnSetArg(XtNwidth, owidth); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNlabel, "Apply"); fpokay = XtCreateWidget("fpokay", XwmenuButtonWidgetClass, dialog, wargs, n); n = 0; fpokstruct.textw = fpentertext; fpokstruct.buttonw = fpokay; fpokstruct.setvalue = setpagesize; fpokstruct.dataptr = &(curpage->pagesize); XtAddCallback(fpokay, XtNselect, (XtCallbackProc)getproptext, &fpokstruct); XtAddCallback(fpokay, XtNselect, (XtCallbackProc)updatetext, entertext); XtOverrideTranslations(fpentertext, XtParseTranslationTable (defaultTranslations)); XtAddCallback(fpentertext, XtNexecute, (XtCallbackProc)getproptext, &fpokstruct); XtAddCallback(fpentertext, XtNexecute, (XtCallbackProc)updatetext, entertext); XtAddCallback(autobutton, XtNselect, (XtCallbackProc)autoset, entertext); XtAddCallback(autobutton, XtNrelease, (XtCallbackProc)autostop, NULL); if (curpage->pmode & 1) { XtManageChild(fpentertext); XtManageChild(fpokay); XtManageChild(autobutton); } if (num_linked > 1) { XtManageChild(allpages); } /* end of pagesize extra Widget definitions */ donestruct = (popupstruct *) malloc(sizeof(popupstruct)); donestruct->popup = popup; donestruct->buttonptr = savebutton; donestruct->filter = NULL; XtAddCallback(okbutton, XtNselect, (XtCallbackProc)destroypopup, donestruct); /* Send setfile() the widget entertext[0] in case because user sometimes forgets to type "okay" but buffer contains the expected filename */ XtAddCallback(wrbutton, XtNselect, (XtCallbackProc)setfile, entertext[0]); /* Begin Popup */ XtPopup(popup, XtGrabNone); /* set the input focus for the window */ wmhints = XGetWMHints(dpy, xcWindow(popup)); wmhints->flags |= InputHint; wmhints->input = True; XSetWMHints(dpy, xcWindow(popup), wmhints); XSetTransientForHint(dpy, xcWindow(popup), xcWindow(top)); XFree(wmhints); for (i = 0; i < 5; i++) XDefineCursor(dpy, xcWindow(entertext[i]), TEXTPTR); } #endif #endif /* !TCL_WRAPPER */ /*-------------------------------------------------*/ /* Print a string to the message widget. */ /* Note: Widget message must be a global variable. */ /* For formatted strings, format first into _STR */ /*-------------------------------------------------*/ #ifdef TCL_WRAPPER xcTimeOutProc clrmessage(caddr_t clientdata) #else xcTimeOutProc clrmessage(caddr_t clientdata, xcIntervalId *id) #endif { char buf1[50], buf2[50]; /* Don't write over the report of the edit string contents, */ /* if we're in one of the label edit modes */ if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) charreport(TOLABEL(EDITPART)); else { measurestr(xobjs.pagelist[areastruct.page]->gridspace, buf1); measurestr(xobjs.pagelist[areastruct.page]->snapspace, buf2); sprintf(_STR, "Grid %.50s : Snap %.50s", buf1, buf2); Wprintf(_STR); } } #ifndef TCL_WRAPPER /*------------------------------------------------------------------------------*/ void W1printf(char *string) { Arg wargs[1]; XtSetArg(wargs[0], XtNstring, string); XtSetValues(message1, wargs, 1); XtSetArg(wargs[0], XtNheight, ROWHEIGHT); XtSetValues(message1, wargs, 1); } /*------------------------------------------------------------------------------*/ void W2printf(char *string) { Arg wargs[1]; XtSetArg(wargs[0], XtNstring, string); XtSetValues(message2, wargs, 1); XtSetArg(wargs[0], XtNheight, ROWHEIGHT); XtSetValues(message2, wargs, 1); } /*------------------------------------------------------------------------------*/ void Wprintf(char *string) { Arg wargs[1]; if (printtime_id != 0) { xcRemoveTimeOut(printtime_id); printtime_id = 0; } XtSetArg(wargs[0], XtNstring, string); XtSetValues(message3, wargs, 1); XtSetArg(wargs[0], XtNheight, ROWHEIGHT); XtSetValues(message3, wargs, 1); /* 10 second timeout */ printtime_id = xcAddTimeOut(app, 10000, (xcTimeOutProc)clrmessage, NULL); } #endif /* !TCL_WRAPPER */ /*------------------------------------------------------------------------------*/ /* diagnostic tool for translating the event mode into a string and printing */ /* to stderr (for debugging only). */ /*------------------------------------------------------------------------------*/ void printeventmode() { Fprintf(stderr, "eventmode is \'"); switch(eventmode) { case NORMAL_MODE: Fprintf(stderr, "NORMAL"); break; case MOVE_MODE: Fprintf(stderr, "MOVE"); break; case COPY_MODE: Fprintf(stderr, "COPY"); break; case SELAREA_MODE: Fprintf(stderr, "SELAREA"); break; case CATALOG_MODE: Fprintf(stderr, "CATALOG"); break; case CATTEXT_MODE: Fprintf(stderr, "CATTEXT"); break; case FONTCAT_MODE: Fprintf(stderr, "FONTCAT"); break; case EFONTCAT_MODE: Fprintf(stderr, "EFONTCAT"); break; case TEXT_MODE: Fprintf(stderr, "TEXT"); break; case ETEXT_MODE: Fprintf(stderr, "ETEXT"); break; case WIRE_MODE: Fprintf(stderr, "WIRE"); break; case BOX_MODE: Fprintf(stderr, "BOX"); break; case EPOLY_MODE: Fprintf(stderr, "EPOLY"); break; case ARC_MODE: Fprintf(stderr, "ARC"); break; case EARC_MODE: Fprintf(stderr, "EARC"); break; case SPLINE_MODE: Fprintf(stderr, "SPLINE"); break; case ESPLINE_MODE: Fprintf(stderr, "ESPLINE"); break; case EPATH_MODE: Fprintf(stderr, "EPATH"); break; case ASSOC_MODE: Fprintf(stderr, "ASSOC"); break; case RESCALE_MODE: Fprintf(stderr, "RESCALE"); break; case PAN_MODE: Fprintf(stderr, "PAN"); break; default: Fprintf(stderr, "(unknown)"); break; } Fprintf(stderr, "_MODE\'\n"); } /*------------------------------------------------------------------------------*/ #ifndef TCL_WRAPPER #ifndef XC_WIN32 void getcommand(xcWidget cmdw, caddr_t clientdata, caddr_t calldata) { sprintf(_STR2, "%.249s", XwTextCopyBuffer(cmdw)); #ifdef HAVE_PYTHON execcommand(0, _STR2 + 4); #else execcommand(0, _STR2 + 2); #endif XtRemoveEventHandler(areastruct.area, KeyPressMask, False, (XtEventHandler)propevent, cmdw); XtAddCallback(areastruct.area, XtNkeyDown, (XtCallbackProc)keyhandler, NULL); XtAddCallback(areastruct.area, XtNkeyUp, (XtCallbackProc)keyhandler, NULL); XtUnmanageChild(cmdw); } #endif #endif /* !TCL_WRAPPER */ #ifdef TCL_WRAPPER /*------------------------------------------------------------------------------*/ /* "docommand" de-iconifies the TCL console. */ /*------------------------------------------------------------------------------*/ void docommand() { Tcl_Eval(xcinterp, "catch xcircuit::raiseconsole"); } #else /* !TCL_WRAPPER */ /*------------------------------------------------------------------------------*/ /* "docommand" overlays the message3 widget temporarily with a TextEdit widget. */ /*------------------------------------------------------------------------------*/ #ifndef XC_WIN32 void docommand() { Arg wargs[12]; int n = 0; Dimension w; Position x, y; static char defaultTranslations[] = "Return: execute()"; if (overlay == NULL) { XtnSetArg(XtNy, &y); XtnSetArg(XtNx, &x); XtnSetArg(XtNwidth, &w); XtGetValues(message3, wargs, n); n = 0; XtnSetArg(XtNy, y); XtnSetArg(XtNx, x); XtnSetArg(XtNheight, ROWHEIGHT); XtnSetArg(XtNwidth, w); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNwrap, XwWrapOff); overlay = XtCreateManagedWidget("Command", XwtextEditWidgetClass, top, wargs, n); n = 0; XtOverrideTranslations(overlay, XtParseTranslationTable(defaultTranslations)); XtAddCallback(overlay, XtNexecute, (XtCallbackProc)getcommand, NULL); } else { XtManageChild(overlay); } XwTextClearBuffer(overlay); #ifdef HAVE_PYTHON XwTextInsert(overlay, ">>> "); #else XwTextInsert(overlay, "? "); #endif /* temporarily redirect all text into the overlay widget */ XtRemoveCallback(areastruct.area, XtNkeyDown, (XtCallbackProc)keyhandler, NULL); XtRemoveCallback(areastruct.area, XtNkeyUp, (XtCallbackProc)keyhandler, NULL); XtAddEventHandler(areastruct.area, KeyPressMask, False, (XtEventHandler)propevent, overlay); } #endif /* !XC_WIN32 */ #endif /* !TCL_WRAPPER */ /*------------------------------------------------------------------------------*/ /* When all else fails, install your own colormap */ /*------------------------------------------------------------------------------*/ #if !defined(XC_WIN32) || defined(TCL_WRAPPER) int installowncmap() { Colormap newcmap; Fprintf(stdout, "Installing my own colormap\n"); /* allocate a new colormap */ newcmap = XCopyColormapAndFree(dpy, cmap); if (newcmap == (Colormap)NULL) return (-1); cmap = newcmap; #ifndef TCL_WRAPPER if (areastruct.area != (xcWidget)NULL) { if (xcIsRealized(areastruct.area)) { xcWidget colormenu = xcParent(ColorAddNewColorButton); XSetWindowColormap(dpy, xcWindow(top), cmap); XSetWindowColormap(dpy, areastruct.areawin, cmap); if (colormenu != (xcWidget)NULL) XSetWindowColormap(dpy, xcWindow(colormenu), cmap); } } #endif return(1); } /*------------------------------------------------------------------------------*/ /* Find the nearest color in the colormap to cvexact and return its pixel value */ /*------------------------------------------------------------------------------*/ int findnearcolor(XColor *cvexact) { /* find the nearest-matching color in the colormap */ int i, ncolors = DisplayCells(dpy, DefaultScreen(dpy)); XColor *cmcolors; long rdist, bdist, gdist; u_long dist, mindist; int minidx; cmcolors = (XColor *)malloc(ncolors * sizeof(XColor)); for (i = 0; i < ncolors; i++) { cmcolors[i].pixel = i; cmcolors[i].flags = DoRed | DoGreen | DoBlue; } XQueryColors(dpy, cmap, cmcolors, ncolors); mindist = ULONG_MAX; for (i = 0; i < ncolors; i++) { rdist = (cmcolors[i].red - cvexact->red); bdist = (cmcolors[i].blue - cvexact->blue); gdist = (cmcolors[i].green - cvexact->green); dist = rdist * rdist + bdist * bdist + gdist * gdist; if (dist < mindist) { mindist = dist; minidx = i; } } free(cmcolors); /* if we can't get the right color or something reasonably close, */ /* then allocate our own colormap. If we've allocated so many */ /* colors that the new colormap is full, then we give up and use */ /* whatever color was closest, no matter how far away it was. */ /* findnearcolor already used 512 per component, so to match that, */ /* 3 * (512 * 512) = 786432 ~= 750000 */ if (dist > 750000) { if (installowncmap() > 0) { if (XAllocColor(dpy, cmap, cvexact) != 0) minidx = cvexact->pixel; } } return minidx; } #endif /*------------------------------------------------------------------------------*/ /* Layout colors which are defined from the Xdefaults (BBOXCOLOR, schematic */ /* label colors) may be duplicated in the colormap. This routine takes a color */ /* index of a color and returns the index of any color in the layout colormap */ /* which matches it within the tolerance used by "rgb_alloccolor". This will */ /* be used to remap the Xdefault-supplied colors to the layout color table, so */ /* we don't get duplicate entries. */ /*------------------------------------------------------------------------------*/ int xc_getlayoutcolor(int cidx) { XColor loccolor; int i, locidx; loccolor.pixel = cidx; loccolor.flags = DoRed | DoGreen | DoBlue; XQueryColors(dpy, cmap, &loccolor, 1); locidx = rgb_alloccolor(loccolor.red, loccolor.green, loccolor.blue); return locidx; } /*-------------------------------------------------------------------------*/ /* Hack on the resource database Color allocation */ /* */ /* This overrides the built-in routine. The difference is that if a */ /* color cell cannot be allocated (colormap is full), then the color */ /* map is searched for the closest RGB value to the named color. */ /* */ /* This code depends on Display *dpy being set: Do not install the */ /* converter until after XtInitialize(). */ /*-------------------------------------------------------------------------*/ #if defined(TCL_WRAPPER) || !defined(XC_WIN32) #ifdef TCL_WRAPPER caddr_t #else XtConverter #endif CvtStringToPixel(XrmValuePtr args, int *nargs, XrmValuePtr fromVal, XrmValuePtr toVal) { static XColor cvcolor; XColor cvexact; if (dpy == NULL) return NULL; if (*nargs != 0) Fprintf(stderr, "String to Pixel conversion takes no arguments"); /* Color defaults to black if name is not found */ if (XAllocNamedColor(dpy, cmap, (char *)fromVal->addr, &cvcolor, &cvexact) == 0) { if (XLookupColor(dpy, cmap, (char *)fromVal->addr, &cvexact, &cvcolor) == 0) cvcolor.pixel = BlackPixel(dpy, DefaultScreen(dpy)); else cvcolor.pixel = findnearcolor(&cvexact); } toVal->size = sizeof(u_long); toVal->addr = (caddr_t) &(cvcolor.pixel); return NULL; } #endif /*-------------------------------------------------------------------------*/ /* Allocate new color using the CvtStringToPixel routine */ /*-------------------------------------------------------------------------*/ int xc_alloccolor(char *name) { #if defined(XC_WIN32) && !defined(TCL_WRAPPER) return WinNamedColor(name); #else XrmValue fromC, toC; int zval = 0, pixval; fromC.size = strlen(name); fromC.addr = name; CvtStringToPixel(NULL, &zval, &fromC, &toC); pixval = (int)(*((u_long *)toC.addr)); return pixval; #endif } /*-------------------------------------------------------------------------*/ /* Allocate new color from RGB values (e.g., from PS file "scb" command) */ /*-------------------------------------------------------------------------*/ int rgb_alloccolor(int red, int green, int blue) { #if defined(XC_WIN32) && !defined(TCL_WRAPPER) return RGB(red>>8, green>>8, blue>>8); #else XColor newcolor; int i, pixval = -1; /* first check if color within RGB roundoff error exists in the list */ /* Assume 24-bit color, in which resolution can be no less than 256 */ /* for each color component. Visual acuity is a bit less than 24- */ /* bit color, so assume difference should be no less than 512 per */ /* component for colors to be considered "different". */ /* Psychologically, we should really find the just-noticable-diff. */ /* for each color component separately! But that's too complicated */ /* for this simple routine. */ for (i = 0; i < number_colors; i++) { if (abs(colorlist[i].color.red - red) < 512 && abs(colorlist[i].color.green - green) < 512 && abs(colorlist[i].color.blue - blue) < 512) { pixval = colorlist[i].color.pixel; break; } } /* if color is not already in list, try to allocate it; if allocation */ /* fails, grab the closest match in the colormap. */ if (pixval < 0) { newcolor.red = red; newcolor.green = green; newcolor.blue = blue; newcolor.flags = DoRed | DoGreen | DoBlue; if (XAllocColor(dpy, cmap, &newcolor) == 0) pixval = findnearcolor(&newcolor); else pixval = newcolor.pixel; } return pixval; #endif } /*-------------------------------------------------------------------------*/ /* Make the cursors from the cursor bit data */ /*-------------------------------------------------------------------------*/ void makecursors() { XColor fgcolor, bgcolor; Window win = areastruct.areawin; #ifdef TCL_WRAPPER Tk_Uid fg_uid, bg_uid; #endif bgcolor.pixel = BACKGROUND; fgcolor.pixel = FOREGROUND; XQueryColors(dpy, cmap, &fgcolor, 1); XQueryColors(dpy, cmap, &bgcolor, 1); #ifdef TCL_WRAPPER fg_uid = Tk_GetUid(Tk_NameOfColor(&fgcolor)); bg_uid = Tk_GetUid(Tk_NameOfColor(&bgcolor)); #ifdef _MSC_VER #define Tk_GetCursorFromData CreateW32Cursor #endif ARROW = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), arrow_bits, arrowmask_bits, arrow_width, arrow_height, arrow_x_hot, arrow_y_hot, fg_uid, bg_uid); CROSS = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), cross_bits, crossmask_bits, cross_width, cross_height, cross_x_hot, cross_y_hot, fg_uid, bg_uid); SCISSORS = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), scissors_bits, scissorsmask_bits, scissors_width, scissors_height, scissors_x_hot, scissors_y_hot, fg_uid, bg_uid); EDCURSOR = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), exx_bits, exxmask_bits, exx_width, exx_height, exx_x_hot, exx_y_hot, fg_uid, bg_uid); COPYCURSOR = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), copy_bits, copymask_bits, copy_width, copy_height, copy_x_hot, copy_y_hot, fg_uid, bg_uid); ROTATECURSOR = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), rot_bits, rotmask_bits, rot_width, rot_height, circle_x_hot, circle_y_hot, fg_uid, bg_uid); QUESTION = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), question_bits, questionmask_bits, question_width, question_height, question_x_hot, question_y_hot, fg_uid, bg_uid); CIRCLE = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), circle_bits, circlemask_bits, circle_width, circle_height, circle_x_hot, circle_y_hot, fg_uid, bg_uid); HAND = (Cursor)Tk_GetCursorFromData(xcinterp, Tk_IdToWindow(dpy, win), hand_bits, handmask_bits, hand_width, hand_height, hand_x_hot, hand_y_hot, fg_uid, bg_uid); #ifdef _MSC_VER #undef Tk_GetCursorFromData #endif #else ARROW = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, arrow_bits, arrow_width, arrow_height), XCreateBitmapFromData(dpy, win, arrowmask_bits, arrow_width, arrow_height), &fgcolor, &bgcolor, arrow_x_hot, arrow_y_hot); CROSS = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, cross_bits, cross_width, cross_height), XCreateBitmapFromData(dpy, win, crossmask_bits, cross_width, cross_height), &fgcolor, &bgcolor, cross_x_hot, cross_y_hot); SCISSORS = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, scissors_bits, scissors_width, scissors_height), XCreateBitmapFromData(dpy, win, scissorsmask_bits, scissors_width, scissors_height), &fgcolor, &bgcolor, scissors_x_hot, scissors_y_hot); EDCURSOR = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, exx_bits, exx_width, exx_height), XCreateBitmapFromData(dpy, win, exxmask_bits, exx_width, exx_height), &fgcolor, &bgcolor, exx_x_hot, exx_y_hot); COPYCURSOR = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, copy_bits, copy_width, copy_height), XCreateBitmapFromData(dpy, win, copymask_bits, copy_width, copy_height), &fgcolor, &bgcolor, copy_x_hot, copy_y_hot); ROTATECURSOR = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, rot_bits, rot_width, rot_height), XCreateBitmapFromData(dpy, win, rotmask_bits, rot_width, rot_height), &fgcolor, &bgcolor, circle_x_hot, circle_y_hot); QUESTION = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, question_bits, question_width, question_height), XCreateBitmapFromData(dpy, win, questionmask_bits, question_width, question_height), &fgcolor, &bgcolor, question_x_hot, question_y_hot); CIRCLE = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, circle_bits, circle_width, circle_height), XCreateBitmapFromData(dpy, win, circlemask_bits, circle_width, circle_height), &fgcolor, &bgcolor, circle_x_hot, circle_y_hot); HAND = XCreatePixmapCursor(dpy, XCreateBitmapFromData(dpy, win, hand_bits, hand_width, hand_height), XCreateBitmapFromData(dpy, win, handmask_bits, hand_width, hand_height), &fgcolor, &bgcolor, hand_x_hot, hand_y_hot); #endif /* TCL_WRAPPER */ TEXTPTR = XCreateFontCursor(dpy, XC_xterm); WAITFOR = XCreateFontCursor(dpy, XC_watch); XRecolorCursor(dpy, TEXTPTR, &fgcolor, &bgcolor); } #ifndef TCL_WRAPPER /*----------------------------------------------------------------------*/ /* Event handler for input focus */ /*----------------------------------------------------------------------*/ #ifdef INPUT_FOCUS void mappinghandler(xcWidget w, caddr_t clientdata, XEvent *event) { if (!xcIsRealized(w)) return; switch(event->type) { case MapNotify: /* Fprintf(stderr, "Window top was mapped. Setting input focus\n"); */ areastruct.mapped = True; XSetInputFocus(dpy, xcWindow(w), RevertToPointerRoot, CurrentTime); break; case UnmapNotify: /* Fprintf(stderr, "Window top was unmapped\n"); */ areastruct.mapped = False; break; } } #endif /*----------------------------------------------------------------------*/ void clientmessagehandler(xcWidget w, caddr_t clientdata, XEvent *event) { if (!xcIsRealized(w)) return; if (event->type == ClientMessage) { if (render_client(event) == False) return; #ifdef INPUT_FOCUS if (areastruct.mapped == True) { /* Fprintf(stderr, "Forcing input focus\n"); */ XSetInputFocus(dpy, xcWindow(w), RevertToPointerRoot, CurrentTime); } #endif } } /*----------------------------------------------------------------------*/ /* Event handler for WM_DELETE_WINDOW message. */ /*----------------------------------------------------------------------*/ void delwin(xcWidget w, popupstruct *bstruct, XClientMessageEvent *event) { if (event->type != ClientMessage) return; if((event->message_type == wprot) && (event->data.l[0] == wmprop[0])) { if (w == top) quitcheck(w, NULL, NULL); else destroypopup(w, bstruct, NULL); } } #endif /* !TCL_WRAPPER */ /*----------------------------------------------------------------------*/ /* Preparatory initialization (to be run before setting up the GUI) */ /*----------------------------------------------------------------------*/ void pre_initialize() { short i, page; /*-------------------------------------------------------------*/ /* Force LC_NUMERIC locale to en_US for decimal point = period */ /* notation. The environment variable LC_NUMERIC overrides if */ /* it is set explicitly, so it has to be unset first to allow */ /* setlocale() to work. */ /*-------------------------------------------------------------*/ #ifdef HAVE_PUTENV putenv("LC_ALL=en_US"); putenv("LC_NUMERIC=en_US"); putenv("LANG=POSIX"); #else unsetenv("LC_ALL"); unsetenv("LC_NUMERIC"); setenv("LANG", "POSIX", 1); #endif setlocale(LC_ALL, "en_US"); #ifdef HAVE_XPM areastruct.toolbar_on = True; #endif /*---------------------------*/ /* initialize user variables */ /*---------------------------*/ version = PROG_VERSION; aliastop = NULL; xobjs.pagelist = (Pagedata **) malloc(PAGES * sizeof(Pagedata *)); for (page = 0; page < PAGES; page++) { xobjs.pagelist[page] = (Pagedata *) malloc(sizeof(Pagedata)); xobjs.pagelist[page]->pageinst = NULL; } /* Set values for the first page */ xobjs.pagelist[0]->wirewidth = 2.0; xobjs.pagelist[0]->outscale = 1.0; xobjs.pagelist[0]->background.name = (char *)NULL; xobjs.pagelist[0]->pmode = 0; xobjs.pagelist[0]->orient = 0; xobjs.pagelist[0]->gridspace = DEFAULTGRIDSPACE; xobjs.pagelist[0]->snapspace = DEFAULTSNAPSPACE; xobjs.pagelist[0]->drawingscale.x = xobjs.pagelist[0]->drawingscale.y = 1; xobjs.pagelist[0]->coordstyle = FRAC_INCH; xobjs.pagelist[0]->pagesize.x = 612; xobjs.pagelist[0]->pagesize.y = 792; xobjs.new_changes = 0; xobjs.do_replace = -1; /* default: replace NONE */ xobjs.tempfile = NULL; signal(SIGINT, dointr); printtime_id = 0; xobjs.undostack = NULL; xobjs.redostack = NULL; /* Set the temporary directory name as compiled, unless overridden by */ /* environment variable "TMPDIR". */ xobjs.tempdir = getenv("TMPDIR"); if (xobjs.tempdir == NULL) xobjs.tempdir = strdup(TEMP_DIR); areastruct.area = (xcWidget)NULL; areastruct.mapped = False; areastruct.psfont = 0; areastruct.justify = FLIPINV; areastruct.page = 0; areastruct.MatStack = NULL; areastruct.textscale = 1.0; areastruct.linewidth = 1.0; areastruct.zoomfactor = SCALEFAC; areastruct.style = UNCLOSED; areastruct.invert = False; areastruct.axeson = True; areastruct.snapto = True; areastruct.gridon = True; areastruct.center = True; areastruct.bboxon = False; areastruct.filter = ALL_TYPES; areastruct.filefilter = True; areastruct.editinplace = True; areastruct.selects = 0; areastruct.selectlist = NULL; areastruct.lastlibrary = 0; areastruct.manhatn = False; areastruct.boxedit = MANHATTAN; areastruct.lastbackground = NULL; areastruct.editstack = (objectptr) malloc(sizeof(object)); areastruct.stack = NULL; /* at the top of the hierarchy */ areastruct.hierstack = NULL; initmem(areastruct.editstack); areastruct.pinpointon = False; areastruct.schemon = False; areastruct.buschar = '('; /* Vector notation for buses */ areastruct.defaultcursor = &CROSS; xobjs.numlibs = LIBS - LIBRARY - 1; xobjs.fontlib.number = 0; xobjs.userlibs = (Library *) malloc(xobjs.numlibs * sizeof(Library)); for (i = 0; i < xobjs.numlibs; i++) { xobjs.userlibs[i].filename = NULL; xobjs.userlibs[i].library = (objectptr *) malloc(sizeof(objectptr)); xobjs.userlibs[i].instlist = NULL; xobjs.userlibs[i].number = 0; } xobjs.imagelist = NULL; xobjs.images = 0; xobjs.pages = PAGES; fontcount = 0; fonts = (fontinfo *) malloc(sizeof(fontinfo)); /* Initialization of objects requires values for the window width and height, */ /* so set up the widgets and realize them first. */ popups = 0; /* no popup windows yet */ beeper = 1; /* Ring bell on certain warnings or errors */ pressmode = FALSE; /* not in a button press & hold mode yet */ initsplines(); /* create lookup table of spline parameters */ } #ifndef TCL_WRAPPER /*----------------------------------------------------------------------*/ /* GUI_init() --- generate the widget structures, allocate colormaps */ /* and graphics contexts, generate menus and toolbar, and assign */ /* callback functions and event handlers. */ /*----------------------------------------------------------------------*/ #ifndef XC_WIN32 void GUI_init(int argc, char *argv[]) { #ifdef HAVE_XPM xcWidget abform; #endif xcWidget form, aform, firstbutton, lastbutton, corner; XGCValues values; XWMHints *wmhints; /* for proper input focus */ Arg wargs[12]; Pixmap icon; Window win; short i, n = 0; char *argfb[] = { /* Fallback resources */ "xcircuit*foreground : brown4", /* These are the values that */ "xcircuit*background : beige", /* not or cannot be explicitly */ "xcircuit.foreground : black", /* initialized by */ "xcircuit.background : white", /* XtGetApplicationResources() */ "xcircuit*borderWidth : 2", /* below. */ "xcircuit*borderColor : Red", NULL /* Sentinel */ }; XtSetLanguageProc(NULL, NULL, NULL); /*-------------------------------------------------------------------*/ /* Set pointer to own XDefaults file, but allow an external override */ /*-------------------------------------------------------------------*/ #ifdef HAVE_PUTENV if (getenv("XAPPLRESDIR") == NULL) putenv("XAPPLRESDIR=" RESOURCES_DIR); #else setenv("XAPPLRESDIR", RESOURCES_DIR, 0); #endif /*-----------------------------*/ /* Create the widget hierarchy */ /*-----------------------------*/ top = XtOpenApplication(&app, "XCircuit", NULL, 0, &argc, argv, argfb, applicationShellWidgetClass, NULL, 0); dpy = XtDisplay(top); win = DefaultRootWindow(dpy); cmap = DefaultColormap(dpy, DefaultScreen(dpy)); /*-------------------------*/ /* Create stipple patterns */ /*-------------------------*/ for (i = 0; i < STIPPLES; i++) STIPPLE[i] = XCreateBitmapFromData(dpy, win, STIPDATA[i], 4, 4); /*----------------------------------------*/ /* Allocate space for the basic color map */ /*----------------------------------------*/ number_colors = 0; colorlist = (colorindex *)malloc(sizeof(colorindex)); appcolors = (int *) malloc(NUMBER_OF_COLORS * sizeof(int)); /*-----------------------------------------------------------*/ /* Xw must add these translations for the popup manager */ /*-----------------------------------------------------------*/ XwAppInitialize(app); /*-------------------------------*/ /* Get the application resources */ /*-------------------------------*/ XtAppAddConverter(app, XtRString, XtRPixel, (XtConverter)CvtStringToPixel, NULL, 0); XtGetApplicationResources(top, &appdata, resources, XtNumber(resources), NULL, 0); n = 0; XtnSetArg(XtNwidth, appdata.width); XtnSetArg(XtNheight, appdata.height); XtnSetArg(XtNforeground, appdata.fg); XtnSetArg(XtNbackground, appdata.bg); XtnSetArg(XtNcolormap, cmap); XtSetValues(top, wargs, n); n = 0; form = XtCreateManagedWidget("Form", XwformWidgetClass, top, NULL, 0); /* Set up the buttons and Graphics drawing area */ createmenus(form, &firstbutton, &lastbutton); XtnSetArg(XtNxRefWidget, lastbutton); XtnSetArg(XtNyRefWidget, form); XtnSetArg(XtNxAddWidth, True); XtnSetArg(XtNxAttachRight, True); XtnSetArg(XtNheight, ROWHEIGHT); sprintf(_STR, " Welcome to Xcircuit Version %2.1f", PROG_VERSION); XtnSetArg(XtNstring, _STR); XtnSetArg(XtNxResizable, True); XtnSetArg(XtNgravity, WestGravity); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNwrap, False); XtnSetArg(XtNstrip, False); message1 = XtCreateManagedWidget("Message1", XwstaticTextWidgetClass, form, wargs, n); n = 0; #ifdef HAVE_XPM /*-------------------------------------------------------------------*/ /* An extra form divides the main window from the toolbar */ /*-------------------------------------------------------------------*/ XtnSetArg(XtNyRefWidget, firstbutton); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNyOffset, 2); XtnSetArg(XtNxAttachRight, True); XtnSetArg(XtNyResizable, True); XtnSetArg(XtNxResizable, True); XtnSetArg(XtNborderWidth, 0); abform = XtCreateManagedWidget("ABForm", XwformWidgetClass, form, wargs, n); n = 0; /*-------------------------------------------------------------------*/ /* The main window and its scrollbars rest in a separate form window */ /*-------------------------------------------------------------------*/ XtnSetArg(XtNyResizable, True); XtnSetArg(XtNxResizable, True); XtnSetArg(XtNyAttachBottom, True); aform = XtCreateManagedWidget("AForm", XwformWidgetClass, abform, wargs, n); n = 0; #else #define abform aform /*-------------------------------------------------------------------*/ /* The main window and its scrollbars rest in a separate form window */ /*-------------------------------------------------------------------*/ XtnSetArg(XtNyRefWidget, firstbutton); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNxAttachRight, True); XtnSetArg(XtNyResizable, True); XtnSetArg(XtNxResizable, True); aform = XtCreateManagedWidget("AForm", XwformWidgetClass, form, wargs, n); n = 0; #endif /*------------------------*/ /* add scrollbar widget */ /*------------------------*/ XtnSetArg(XtNxResizable, False); XtnSetArg(XtNyResizable, True); XtnSetArg(XtNwidth, SBARSIZE); XtnSetArg(XtNborderWidth, 1); areastruct.scrollbarv = XtCreateManagedWidget("SBV", XwworkSpaceWidgetClass, aform, wargs, n); n = 0; /*----------------------------------------------------------*/ /* A button in the scrollbar corner for the sake of beauty. */ /*----------------------------------------------------------*/ XtnSetArg(XtNyRefWidget, areastruct.scrollbarv); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNyAttachBottom, True); XtnSetArg(XtNheight, SBARSIZE); XtnSetArg(XtNwidth, SBARSIZE); XtnSetArg(XtNborderWidth, 1); XtnSetArg(XtNlabel, ""); corner = XtCreateManagedWidget("corner", XwpushButtonWidgetClass, aform, wargs, n); n = 0; /*-------------------------*/ /* The main drawing window */ /*-------------------------*/ XtnSetArg(XtNxOffset, SBARSIZE); XtnSetArg(XtNxResizable, True); XtnSetArg(XtNyResizable, True); XtnSetArg(XtNxAttachRight, True); areastruct.area = XtCreateManagedWidget("Area", XwworkSpaceWidgetClass, aform, wargs, n); n = 0; /*-------------------------*/ /* and the other scrollbar */ /*-------------------------*/ XtnSetArg(XtNyRefWidget, areastruct.area); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNxRefWidget, areastruct.scrollbarv); XtnSetArg(XtNxAddWidth, True); XtnSetArg(XtNxAttachRight, True); XtnSetArg(XtNheight, SBARSIZE); XtnSetArg(XtNyResizable, False); XtnSetArg(XtNxResizable, True); XtnSetArg(XtNborderWidth, 1); areastruct.scrollbarh = XtCreateManagedWidget("SBH", XwworkSpaceWidgetClass, aform, wargs, n); n = 0; /*------------------------------------------------*/ /* Supplementary message widgets go at the bottom */ /*------------------------------------------------*/ XtnSetArg(XtNxResizable, False); XtnSetArg(XtNyRefWidget, abform); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNyOffset, -5); XtnSetArg(XtNheight, ROWHEIGHT); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNforeground, appdata.buttonpix); XtnSetArg(XtNbackground, appdata.buttonpix); wsymb = XtCreateWidget("Symbol", XwpushButtonWidgetClass, form, wargs, n); n = 0; if (areastruct.schemon) XtManageChild(wsymb); XtnSetArg(XtNxRefWidget, wsymb); XtnSetArg(XtNxAddWidth, True); XtnSetArg(XtNxResizable, False); XtnSetArg(XtNyRefWidget, abform); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNyOffset, -5); XtnSetArg(XtNheight, ROWHEIGHT); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNforeground, appdata.bg); XtnSetArg(XtNbackground, appdata.snappix); wschema = XtCreateWidget("Schematic", XwpushButtonWidgetClass, form, wargs, n); n = 0; if (areastruct.schemon) XtManageChild(wschema); XtnSetArg(XtNxRefWidget, wschema); XtnSetArg(XtNxAddWidth, True); XtnSetArg(XtNyRefWidget, abform); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNyOffset, -5); XtnSetArg(XtNheight, ROWHEIGHT); XtnSetArg(XtNstring, "Editing: Page 1"); XtnSetArg(XtNxResizable, False); XtnSetArg(XtNgravity, WestGravity); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNwrap, False); message2 = XtCreateManagedWidget("Message2", XwstaticTextWidgetClass, form, wargs, n); n = 0; XtnSetArg(XtNyRefWidget, abform); XtnSetArg(XtNyAddHeight, True); XtnSetArg(XtNyOffset, -5); XtnSetArg(XtNxAttachRight, True); XtnSetArg(XtNxRefWidget, message2); XtnSetArg(XtNxAddWidth, True); XtnSetArg(XtNheight, ROWHEIGHT); XtnSetArg(XtNxResizable, True); XtnSetArg(XtNfont, appdata.xcfont); XtnSetArg(XtNwrap, False); XtnSetArg(XtNgravity, WestGravity); XtnSetArg(XtNstring, "Don't Panic"); message3 = XtCreateManagedWidget("Message3", XwstaticTextWidgetClass, form, wargs, n); n = 0; /*-------------------------------*/ /* optional Toolbar on the right */ /*-------------------------------*/ #ifdef HAVE_XPM createtoolbar(abform, aform); XtAddCallback(areastruct.area, XtNresize, (XtCallbackProc)resizetoolbar, NULL); #endif /* Setup callback routines for the area widget */ /* Use Button1Press event to add the callback which tracks motion; this */ /* will reduce the number of calls serviced during normal operation */ XtAddCallback(areastruct.area, XtNexpose, (XtCallbackProc)drawarea, NULL); XtAddCallback(areastruct.area, XtNresize, (XtCallbackProc)resizearea, NULL); XtAddCallback(areastruct.area, XtNselect, (XtCallbackProc)buttonhandler, NULL); XtAddCallback(areastruct.area, XtNrelease, (XtCallbackProc)buttonhandler, NULL); XtAddCallback(areastruct.area, XtNkeyDown, (XtCallbackProc)keyhandler, NULL); XtAddCallback(areastruct.area, XtNkeyUp, (XtCallbackProc)keyhandler, NULL); XtAddEventHandler(areastruct.area, Button1MotionMask | Button2MotionMask, False, (XtEventHandler)xlib_drag, NULL); /* Setup callback routines for the scrollbar widgets */ XtAddEventHandler(areastruct.scrollbarh, ButtonMotionMask, False, (XtEventHandler)panhbar, NULL); XtAddEventHandler(areastruct.scrollbarv, ButtonMotionMask, False, (XtEventHandler)panvbar, NULL); XtAddCallback(areastruct.scrollbarh, XtNrelease, (XtCallbackProc)endhbar, NULL); XtAddCallback(areastruct.scrollbarv, XtNrelease, (XtCallbackProc)endvbar, NULL); XtAddCallback(areastruct.scrollbarh, XtNexpose, (XtCallbackProc)drawhbar, NULL); XtAddCallback(areastruct.scrollbarv, XtNexpose, (XtCallbackProc)drawvbar, NULL); XtAddCallback(areastruct.scrollbarh, XtNresize, (XtCallbackProc)drawhbar, NULL); XtAddCallback(areastruct.scrollbarv, XtNresize, (XtCallbackProc)drawvbar, NULL); /* Event handler for WM_DELETE_WINDOW message. */ XtAddEventHandler(top, NoEventMask, True, (XtEventHandler)delwin, NULL); XtAddCallback(corner, XtNselect, (XtCallbackProc)zoomview, Number(1)); XtAddCallback (wsymb, XtNselect, (XtCallbackProc)xlib_swapschem, Number(0)); XtAddCallback (wschema, XtNselect, (XtCallbackProc)xlib_swapschem, Number(0)); /*--------------------*/ /* Realize the Widget */ /*--------------------*/ XtRealizeWidget(top); wprot = XInternAtom(dpy, "WM_PROTOCOLS", False); wmprop[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wmprop[1] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); XSetWMProtocols(dpy, xcWindow(top), wmprop, 2); /*----------------------------------------------------*/ /* Let the window manager set the input focus for the */ /* window and inform the window manager of the icon */ /* pixmap (which may or may not be useful, depending */ /* on the particular window manager). */ /*----------------------------------------------------*/ wmhints = XGetWMHints(dpy, xcWindow(top)); wmhints->input = True; #ifdef HAVE_XPM /* Create the xcircuit icon pixmap */ XpmCreatePixmapFromData(dpy, win, xcircuit_xpm, &icon, NULL, NULL); wmhints->flags |= InputHint | IconPixmapHint; wmhints->icon_pixmap = icon; #else wmhints->flags |= InputHint; #endif XSetWMHints(dpy, xcWindow(top), wmhints); XFree(wmhints); /* Don't know why this is necessary, but otherwise keyboard input focus */ /* is screwed up under the WindowMaker window manager and possibly others. */ #ifdef INPUT_FOCUS XtAddEventHandler(top, SubstructureNotifyMask, TRUE, (XtEventHandler)mappinghandler, NULL); #endif XtAddEventHandler(top, NoEventMask, TRUE, (XtEventHandler)clientmessagehandler, NULL); /*---------------------------------------------------*/ /* Define basic display variables */ /* Redefine win to be just the drawing area window */ /*---------------------------------------------------*/ areastruct.areawin = xcWindow(areastruct.area); /*-----------------------------*/ /* Create the Graphics Context */ /*-----------------------------*/ values.foreground = BlackPixel(dpy, DefaultScreen(dpy)); values.background = WhitePixel(dpy, DefaultScreen(dpy)); values.font = appdata.xcfont->fid; areastruct.gc = XCreateGC(dpy, areastruct.areawin, GCForeground | GCBackground | GCFont, &values); /* set the area widget width and height, center userspace (0,0) on screen */ XtSetArg(wargs[0], XtNwidth, &areastruct.width); XtSetArg(wargs[1], XtNheight, &areastruct.height); XtGetValues(areastruct.area, wargs, 2); } #endif #endif /* #endif for #ifndef TCL_WRAPPER */ #ifdef TCL_WRAPPER /*----------------------------------------------------------------------*/ /* Create a new Handle object in Tcl */ /*----------------------------------------------------------------------*/ static void UpdateStringOfHandle _ANSI_ARGS_((Tcl_Obj *objPtr)); static int SetHandleFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static Tcl_ObjType tclHandleType = { "handle", /* name */ (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ UpdateStringOfHandle, /* updateStringProc */ SetHandleFromAny /* setFromAnyProc */ }; /*----------------------------------------------------------------------*/ static void UpdateStringOfHandle(objPtr) register Tcl_Obj *objPtr; /* Int object whose string rep to update. */ { char buffer[TCL_INTEGER_SPACE]; register int len; sprintf(buffer, "H%08lX", objPtr->internalRep.longValue); len = strlen(buffer); objPtr->bytes = Tcl_Alloc((u_int)len + 1); strcpy(objPtr->bytes, buffer); objPtr->length = len; } /*----------------------------------------------------------------------*/ static int SetHandleFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *end; int length; register char *p; long newLong; pushlistptr newstack = NULL; string = Tcl_GetStringFromObj(objPtr, &length); errno = 0; for (p = string; isspace((u_char)(*p)); p++); nexthier: if (*p++ != 'H') { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "handle is identified by leading H and hexidecimal value only", -1); TclCheckBadOctal(interp, string); } free_stack(&newstack); return TCL_ERROR; } else { newLong = strtoul(p, &end, 16); } if (end == p) { badHandle: if (interp != NULL) { /* * Must copy string before resetting the result in case a caller * is trying to convert the interpreter's result to an int. */ char buf[100]; sprintf(buf, "expected handle but got \"%.50s\"", string); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); TclCheckBadOctal(interp, string); } free_stack(&newstack); return TCL_ERROR; } if (errno == ERANGE) { if (interp != NULL) { char *s = "handle value too large to represent"; Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); } free_stack(&newstack); return TCL_ERROR; } /* * Make sure that the string has no garbage after the end of the handle. */ while ((end < (string+length)) && isspace((u_char)(*end))) end++; if (end != (string+length)) { /* Check for handles separated by slashes. If present, */ /* then generate a hierstack. */ if ((end != NULL) && (*end == '/')) { objinstptr refinst, chkinst; genericptr *rgen; *end = '\0'; newLong = strtoul(p, &end, 16); p = end + 1; *end = '/'; refinst = (newstack == NULL) ? areastruct.topinstance : newstack->thisinst; chkinst = (objinstptr)((pointertype)(newLong)); /* Ensure that chkinst is in the plist of */ /* refinst->thisobject, and that it is type objinst. */ for (rgen = refinst->thisobject->plist; rgen < refinst->thisobject->plist + refinst->thisobject->parts; rgen++) { if ((objinstptr)(*rgen) == chkinst) { if (ELEMENTTYPE(*rgen) != OBJINST) { free_stack(&newstack); Tcl_SetResult(interp, "Hierarchical element handle " "component is not an object instance.", NULL); return TCL_ERROR; } break; } } if (rgen == refinst->thisobject->plist + refinst->thisobject->parts) { Tcl_SetResult(interp, "Bad component in hierarchical " "element handle.", NULL); free_stack(&newstack); return TCL_ERROR; } push_stack(&newstack, chkinst); goto nexthier; } else goto badHandle; } /* Note that this check won't prevent a hierarchical selection from */ /* being added to a non-hierarchical selection. */ if (areastruct.hierstack != NULL) { if ((newstack == NULL) || (newstack->thisinst != areastruct.hierstack->thisinst)) { Tcl_SetResult(interp, "Attempt to select components in different " "objects.", NULL); free_stack(&newstack); return TCL_ERROR; } } free_stack(&areastruct.hierstack); areastruct.hierstack = newstack; /* * The conversion to handle succeeded. Free the old internalRep before * setting the new one. We do this as late as possible to allow the * conversion code, in particular Tcl_GetStringFromObj, to use that old * internalRep. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.longValue = newLong; objPtr->typePtr = &tclHandleType; return TCL_OK; } /*----------------------------------------------------------------------*/ Tcl_Obj * Tcl_NewHandleObj(optr) register void *optr; /* Int used to initialize the new object. */ { register Tcl_Obj *objPtr; objPtr = Tcl_NewObj(); objPtr->bytes = NULL; objPtr->internalRep.longValue = (long)(optr); objPtr->typePtr = &tclHandleType; return objPtr; } /*----------------------------------------------------------------------*/ int Tcl_GetHandleFromObj(interp, objPtr, handlePtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object from which to get a int. */ register void **handlePtr; /* Place to store resulting int. */ { register long l; int result; if (objPtr->typePtr != &tclHandleType) { result = SetHandleFromAny(interp, objPtr); if (result != TCL_OK) { return result; } } l = objPtr->internalRep.longValue; if (((long)((int)l)) == l) { *handlePtr = (void *)objPtr->internalRep.longValue; return TCL_OK; } if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "value too large to represent as handle", -1); } return TCL_ERROR; } #endif /*----------------------------------------------------------------------*/ /* Routine to initialize variables after the GUI has been set up */ /*----------------------------------------------------------------------*/ void post_initialize() { short i; /*--------------------------------------------------*/ /* Setup the (simple) colormap and make the cursors */ /*--------------------------------------------------*/ setcolorscheme(True); areastruct.color = DEFAULTCOLOR; LOCALPINCOLOR = appdata.localcolor; GLOBALPINCOLOR = appdata.globalcolor; INFOLABELCOLOR = appdata.infocolor; RATSNESTCOLOR = appdata.ratsnestcolor; BBOXCOLOR = appdata.bboxpix; /* Now that we have values for the window width and height, we can initialize */ /* the page objects. */ xobjs.libtop = (objinstptr *)malloc(LIBS * sizeof(objinstptr)); for (i = 0; i < LIBS; i++) { objectptr newlibobj = (objectptr) malloc(sizeof(object)); initmem(newlibobj); xobjs.libtop[i] = newpageinst(newlibobj); } /* Give names to the five default libraries */ strcpy(xobjs.libtop[FONTLIB]->thisobject->name, "Font Character List"); strcpy(xobjs.libtop[PAGELIB]->thisobject->name, "Page Directory"); strcpy(xobjs.libtop[LIBLIB]->thisobject->name, "Library Directory"); strcpy(xobjs.libtop[USERLIB]->thisobject->name, "User Library"); renamelib(USERLIB); changepage(0); /* Centering the view is not required here because the default values */ /* set in initmem() should correctly position the empty page in the */ /* middle of the viewing window. */ #ifdef DOUBLEBUFFER if (dbuf == (Pixmap)NULL) dbuf = XCreatePixmap(dpy, areastruct.areawin, areastruct.width, areastruct.height, DefaultDepthOfScreen(xcScreen(areastruct.area))); #endif #ifdef TCL_WRAPPER /* Set up fundamentally necessary colors black and white */ addnewcolorentry(xc_alloccolor("Black")); addnewcolorentry(xc_alloccolor("White")); /* Set up new Tcl type "handle" for element handles */ Tcl_RegisterObjType(&tclHandleType); #endif /*-----------------------------------------------------*/ /* Set the cursor as a crosshair for the area widget. */ /*-----------------------------------------------------*/ XDefineCursor (dpy, areastruct.areawin, DEFAULTCURSOR); /*---------------------------------------------------*/ /* Set up a timeout for automatic save to a tempfile */ /*---------------------------------------------------*/ xobjs.save_interval = appdata.timeout; xobjs.timeout_id = xcAddTimeOut(app, (u_long)60000 * xobjs.save_interval, (xcTimeOutProc)savetemp, NULL); } #ifndef TCL_WRAPPER /*----------------------------------------------------------------------*/ /* When not using ToolScript, this is the standard X loop (XtMainLoop())*/ /*----------------------------------------------------------------------*/ int local_xloop() { XtAppMainLoop(app); return EXIT_SUCCESS; } /*----------------------------------------------------------------------*/ /* Main entry point when used as a standalone program */ /*----------------------------------------------------------------------*/ int main(int argc, char **argv) { char *argv0; /* find root of argv[0] */ short initargc = argc; /* because XtInitialize() absorbs the */ /* -schem flag and renumbers argc! (bug?) */ short k = 0; /*-----------------------------------------------------------*/ /* Find the root of the command called from the command line */ /*-----------------------------------------------------------*/ argv0 = strrchr(argv[0], '/'); if (argv0 == NULL) argv0 = argv[0]; else argv0++; pre_initialize(); /*---------------------------*/ /* Check for schematic flag */ /*---------------------------*/ for (k = argc - 1; k > 0; k--) { if (!strncmp(argv[k], "-schem", 6)) { areastruct.schemon = True; break; } if (!strncmp(argv[k], "-2", 2)) { pressmode = True; /* 2-button mouse indicator */ break; } } GUI_init(argc, argv); post_initialize(); /*-------------------------------------*/ /* Initialize the ghostscript renderer */ /*-------------------------------------*/ ghostinit(); /*----------------------------------------------------------*/ /* Check home directory for initial settings & other loads; */ /* Load the (default) built-in set of objects */ /*----------------------------------------------------------*/ #ifdef HAVE_PYTHON init_interpreter(); #endif loadrcfile(); pressmode = False; /* Done using this to mark 2-button mouse mode */ composelib(PAGELIB); /* make sure we have a valid page list */ composelib(LIBLIB); /* and library directory */ /*----------------------------------------------------*/ /* Parse the command line for initial file to load. */ /* Otherwise, look for possible crash-recovery files. */ /*----------------------------------------------------*/ if (argc == 2 + (k != 0) || initargc == 2 + (k != 0)) { strcpy(_STR2, argv[(k == 1) ? 2 : 1]); startloadfile(); } else { findcrashfiles(); } return local_xloop(); /* No return---exit through quit() callback */ } #endif /* #endif for #ifndef TCL_WRAPPER */ /*----------------------------------------------------------------------*/