1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18     Last edit by hansen on Tue Feb  3 10:24:32 2009
19 ****************************************************************************/
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <signal.h>
25 #include "tkgate.h"
26 
27 extern int sync_Xserver;
28 extern int did_interface_resize;
29 
30 /*
31  * This is a kludge to prevent a problem that can occur when a hyperlink leads
32  * to a file that has a hyperlink in the same location such as the <PREVIOUS
33  * and NEXT> links in the tutorial.  If the user starts click NEXT> too quickly,
34  * it can count as a double click after loading the file.  To prevent this, we
35  * clear the flag when reading a new circuit, then increment it each time we click
36  * on the canvas.  The flag must be at least 2 to recognize a double click
37  */
38 int click_count = 0;
39 
40 void doScroll(int dx,int dy);
41 
42 int gat_scope(ClientData d,Tcl_Interp *tcl,int argc,const char *argv[]);
43 
44 /*****************************************************************************
45  *
46  * Top global variable with tkgate state.
47  *
48  *****************************************************************************/
49 TkGateParams TkGate;
50 
51 static int did_doubleclick = 0;	/* Did we just do a double click */
52 
53 static Tk_ConfigSpec configSpecs[] = {
54   {TK_CONFIG_COLOR, "-background", "background", "Background",     		"white", Tk_Offset(TkgGateWin,bgColor), 0, 0},
55   {TK_CONFIG_SYNONYM,"-bg", "background", 0, 0, 0, 0, 0},
56   {TK_CONFIG_SYNONYM,"-fg", "foreground", 0, 0, 0, 0, 0},
57   {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",     		"black", Tk_Offset(TkgGateWin,fgColor), 0, 0},
58   {TK_CONFIG_INT,    "-height", "height", "Height",		     		STR(TKG_GATEWIN_HEIGHT), Tk_Offset(TkgGateWin,height), 0, 0},
59   {TK_CONFIG_INT,    "-width", "width", "Width",		     		STR(TKG_GATEWIN_WIDTH), Tk_Offset(TkgGateWin,width), 0, 0},
60   {TK_CONFIG_STRING, "-xscrollcommand", "xscrollcommand",  "Xscrollcommand",    "", Tk_Offset(TkgGateWin,xscroll), 0, 0},
61   {TK_CONFIG_STRING, "-yscrollcommand", "yscrollcommand",  "Yscrollcommand",	"", Tk_Offset(TkgGateWin,yscroll), 0, 0},
62   {TK_CONFIG_STRING, "-takefocus", "takefocus",  "Takefocus", 			"", Tk_Offset(TkgGateWin,takefocus), 0, 0},
63   {TK_CONFIG_END, 0, 0, 0, 0, 0, 0, 0}
64 };
65 int numConfigSpecs = sizeof(configSpecs)/sizeof(configSpecs[0]);
66 
67 /*****************************************************************************
68  *
69  * Return the code for the current major mode
70  *
71  *****************************************************************************/
tkgate_currentMode()72 MajorMode tkgate_currentMode()
73 {
74   return TkGate.ed->major_mode;
75 }
76 
77 /*****************************************************************************
78  *
79  * Changes the major mode opening/closing any windows or connections necessary
80  * to do so.
81  *
82  *****************************************************************************/
tkgate_setMajorMode(MajorMode requestedMode)83 void tkgate_setMajorMode(MajorMode requestedMode)
84 {
85   MajorMode currentMode;
86 
87   if (!TkGate.circuit || !TkGate.circuit->es) return;
88 
89   currentMode = tkgate_currentMode();
90 
91   /*
92    * No change in mode, but we might want to issue a message.
93    */
94   if (requestedMode == currentMode)
95 
96     /* Gen. error message if simulator is already running */
97     if (currentMode == MM_SIMULATE) {
98       message(0,msgLookup("err.sim.isrun"));
99     return;
100   }
101 
102   if (requestedMode == MM_SIMULATE || requestedMode == MM_ANALYZE) {
103     GModuleDef *R;
104 
105     ob_begin_framef("-RCheck",FF_TRANSPARENT);
106     R = GModuleDef_isRecursive(TkGate.circuit->es->env);
107     ob_end_frame();
108 
109     if (R) {
110       message(1,msgLookup("sim.recursive"),R->m_name);
111       FlagRedraw(MF_ALL);
112       return;
113     }
114   }
115 
116   /*
117    * Transition to MM_EDIT before changing to new mode.
118    */
119   switch (currentMode) {
120   case MM_EDIT :
121     break;
122   case MM_SIMULATE :
123     if (TkGate.circuit->simulator.active) {
124       SimInterface_end(&TkGate.circuit->simulator);
125       FlagRedraw();
126     }
127     break;
128   case MM_ANALYZE :
129     cpath_close();
130     break;
131   }
132 
133   /* Always reset edit mode when changing major modes */
134   setEditMode(TkGate.circuit->es,MODE_MOVE);
135 #if TOUCH_XGATE_ED
136   ob_touch(TkGate.ed);
137 #endif
138   TkGate.ed->major_mode = requestedMode;
139 
140   switch (requestedMode) {
141   case MM_EDIT :
142     DoTcl("tkg_editLogo");
143     ob_set_mode(OM_ENABLED);
144     break;
145   case MM_SIMULATE :
146     ob_set_mode(OM_DISABLED);
147     ob_clear();
148     TkGate.circuit->simulator.no_scope = 0;
149     SimInterface_begin(&TkGate.circuit->simulator);
150     DoTcl("tkg_resetLogo");
151     break;
152   case MM_ANALYZE :
153     ob_set_mode(OM_DISABLED);
154     ob_clear();
155     cpath_open();
156     DoTcl("tkg_analysisLogo");
157     break;
158   }
159   SetModified(MF_MODULE|MF_SYNCONLY);
160 }
161 
162 /*****************************************************************************
163  *
164  * Show the name of the selected object on the status line.
165  *
166  *****************************************************************************/
showSelectedName()167 void showSelectedName()
168 {
169   if (TkGate.circuit->es && TkGate.circuit->es->isInterface) {
170     if (TkGate.circuit->nsel) {
171       GWire *w = TkGate.circuit->wsel;
172       GCElement *g;
173 
174       if (w->name)
175 	g = w->gate;
176       else {
177 	w = wire_other(w);
178 	g = w->gate;
179       }
180 
181       if (w && g && w->name && GCElement_isModule(g))
182 	message(0,msgLookup("msg.iselwire"),w->name,g->u.block.moduleName);
183     } else if (TkGate.circuit->select) {
184       if (!GCElement_isModule(TkGate.circuit->select)) {
185 	/* should be impossible */
186 	message(0,msgLookup("msg.iselgate"),
187 		TkGate.circuit->select->typeinfo->name,
188 		TkGate.circuit->select->ename);
189       } else {
190 	message(0,msgLookup("msg.iselblock"),
191 		TkGate.circuit->select->u.block.moduleName);
192       }
193     }
194   } else {
195     if (TkGate.circuit->nsel) {
196       message(0,msgLookup("msg.selwire"),GNet_getVType(TkGate.circuit->nsel),
197 	      TkGate.circuit->nsel->n_signame);				/* Selected wire named '%s'. */
198     } else if (TkGate.circuit->select) {
199       if (!GCElement_isModule(TkGate.circuit->select)) {
200 	message(0,msgLookup("msg.selgate"), 				/* Selected %s named '%s'. */
201 		TkGate.circuit->select->typeinfo->name,
202 		TkGate.circuit->select->ename);
203       } else {
204 	message(0,msgLookup("msg.selblock"), 				/* "Selected %s block named '%s'." */
205 		TkGate.circuit->select->u.block.moduleName,
206 		TkGate.circuit->select->ename);
207       }
208     }
209   }
210 }
211 
212 /*****************************************************************************
213  *
214  * Return the pixel value for a named color.
215  *
216  *****************************************************************************/
Tkg_GetColor(const char * name)217 int Tkg_GetColor(const char *name)
218 {
219   XColor XC,eXC;
220 
221   XAllocNamedColor(TkGate.D,TkGate.CM,name,&XC,&eXC);
222   return XC.pixel;
223 }
224 
225 /*****************************************************************************
226  *
227  * Create a graphic context (GC) with the given transfer function, color
228  * and font.
229  *
230  *****************************************************************************/
Tkg_createGC(int func,char * colorName,XFontStruct * font)231 GC Tkg_createGC(int func,char *colorName,XFontStruct *font)
232 {
233   unsigned mask;
234   XGCValues values;
235   int color, white;
236 
237   white = XWhitePixelOfScreen(TkGate.S);
238   color  = Tkg_GetColor(colorName);
239 
240   mask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
241 
242   if (func == GXxor) {
243     mask |= GCPlaneMask;
244     values.function = GXxor;
245     values.foreground = color ^ white;
246     values.background = 0;
247     values.plane_mask = color ^ white;
248   } else {
249     values.function = func;
250     values.foreground = color;
251     values.background = white;
252   }
253 
254   values.graphics_exposures = False;
255 
256   if (font) {
257     values.font = font->fid;
258     mask |= GCFont;
259   }
260 
261   return XCreateGC(TkGate.D,TkGate.root,mask,&values);
262 }
263 
264 /*****************************************************************************
265  *
266  * Set initial color for a GC
267  *
268  *****************************************************************************/
Tkg_setColor(GC gc,int func,const char * colorName)269 static void Tkg_setColor(GC gc,int func, const char *colorName)
270 {
271   unsigned mask;
272   XGCValues values;
273   int color, white;
274 
275   if (!colorName) return;
276 
277   white = XWhitePixelOfScreen(TkGate.S);
278   color  = Tkg_GetColor(colorName);
279 
280   mask = GCForeground | GCBackground;
281 
282   if (func == GXxor) {
283     mask |= GCPlaneMask;
284     values.foreground = color ^ white;
285     values.background = 0;
286     values.plane_mask = color ^ white;
287   } else {
288     values.foreground = color;
289     values.background = white;
290   }
291 
292   XChangeGC(TkGate.D,gc,mask,&values);
293 }
294 
295 /*****************************************************************************
296  *
297  * Change the color of a GC
298  *
299  *****************************************************************************/
Tkg_changeColor(GC gc,int func,int pixel)300 void Tkg_changeColor(GC gc,int func,int pixel)
301 {
302   XGCValues values;
303   unsigned mask;
304   int white;
305 
306   white = XWhitePixelOfScreen(TkGate.S);
307   mask = GCForeground | GCBackground;
308 
309   if (func == GXxor) {
310     mask |= GCPlaneMask;
311     values.foreground = pixel ^ white;
312     values.background = 0;
313     values.plane_mask = pixel ^ white;
314   } else {
315     values.foreground = pixel;
316     values.background = white;
317   }
318 
319   XChangeGC(TkGate.D,gc,mask,&values);
320 }
321 
322 /*****************************************************************************
323  *
324  * Load Japanese fonts if we have not already done so.
325  *
326  *****************************************************************************/
initJapanese()327 void initJapanese()
328 {
329   if (TkGate.D && !TkGate.ktextXF)
330     TkGate.ktextXF = GetXFonts(FF_KANJI,FP_ROMAN,FS_SMALL);
331 }
332 
333 /*****************************************************************************
334  *
335  * Set up all of the initial colors in the GCs used by tkgate.
336  *
337  *****************************************************************************/
setGCcolors()338 void setGCcolors()
339 {
340   const char *bgcolor = Tcl_GetVar(TkGate.tcl,"tkg_backgroundColor",TCL_GLOBAL_ONLY);
341   int bgcolor_pixel = Tkg_GetColor(bgcolor);
342 
343   Tk_SetWindowBackground(TkGate.gw->win, bgcolor_pixel);
344 
345   Tkg_setColor(TkGate.instGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_instColor",TCL_GLOBAL_ONLY));
346   Tkg_setColor(TkGate.moduleGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_moduleColor",TCL_GLOBAL_ONLY));
347   Tkg_setColor(TkGate.modportGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_modulePortColor",TCL_GLOBAL_ONLY));
348   Tkg_setColor(TkGate.frameGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_frameColor",TCL_GLOBAL_ONLY));
349   Tkg_setColor(GatePainterContext_gc(TkGate.commentContext),
350       GXxor, Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
351   Tkg_setColor(TkGate.imageGC,		GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
352   Tkg_setColor(TkGate.hyperlinkGC,	GXxor, Tcl_GetVar(TkGate.tcl,"tkg_hyperlinkColor",TCL_GLOBAL_ONLY));
353   Tkg_setColor(TkGate.wireGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_wireColor",TCL_GLOBAL_ONLY));
354   Tkg_setColor(TkGate.busGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_busColor",TCL_GLOBAL_ONLY));
355   Tkg_setColor(TkGate.selWireGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_wireColor",TCL_GLOBAL_ONLY));
356   Tkg_setColor(TkGate.selBusGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_busColor",TCL_GLOBAL_ONLY));
357   Tkg_setColor(TkGate.toolGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_toolColor",TCL_GLOBAL_ONLY));
358   Tkg_setColor(TkGate.cpathGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_cpathColor",TCL_GLOBAL_ONLY));
359   Tkg_setColor(TkGate.kanjiGC,		GXxor, Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
360 
361   /*  Tkg_setColor(TkGate.scopeSelectGC,	GXxor,  Tcl_GetVar(TkGate.tcl,"tkg_gridColor",TCL_GLOBAL_ONLY));*/
362   Tkg_setColor(TkGate.scopeXHairGC,	GXxor,  Tcl_GetVar(TkGate.tcl,"tkg_gridColor",TCL_GLOBAL_ONLY));
363   Tkg_setColor(TkGate.scopeGridGC,	GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_gridColor",TCL_GLOBAL_ONLY));
364   Tkg_setColor(TkGate.scopeOneGC,	GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_oneColor",TCL_GLOBAL_ONLY));
365   Tkg_setColor(TkGate.scopeZeroGC,	GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_zeroColor",TCL_GLOBAL_ONLY));
366   Tkg_setColor(TkGate.scopeFloatGC,	GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_floatColor",TCL_GLOBAL_ONLY));
367   Tkg_setColor(TkGate.scopeUnknownGC,	GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_unknownColor",TCL_GLOBAL_ONLY));
368 
369   TkGate.inst_pixel       = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_instColor",TCL_GLOBAL_ONLY));
370   TkGate.ledoff_pixel     = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_offLedColor",TCL_GLOBAL_ONLY));
371   TkGate.ledon_pixel      = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_onLedColor",TCL_GLOBAL_ONLY));
372   TkGate.ledunknown_pixel = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_zLedColor",TCL_GLOBAL_ONLY));
373 }
374 
375 /*****************************************************************************
376  *
377  *  Allocate GCs for main window
378  *
379  *****************************************************************************/
initGCs()380 void initGCs()
381 {
382   unsigned mask;
383   XGCValues values;
384   Pixmap bitPM;
385 
386   /*
387      Do font set up
388    */
389   TkGate.textXF  = GetXFonts(FF_COURIER,FP_ROMAN,FS_NORMAL);
390   TkGate.textbXF = GetXFonts(FF_COURIER,FP_BOLD,FS_NORMAL);
391   TkGate.stextXF = GetXFonts(FF_COURIER,FP_ROMAN,FS_SMALL);
392   TkGate.stextbXF = GetXFonts(FF_COURIER,FP_BOLD,FS_SMALL);
393   if (TkGate.japaneseMode)
394     TkGate.ktextXF = GetXFonts(FF_KANJI,FP_ROMAN,FS_SMALL);
395   else
396     TkGate.ktextXF = 0;
397 
398   TkGate.inst_pixel = Tkg_GetColor("blue");
399   TkGate.ledoff_pixel = Tkg_GetColor("firebrick4");
400   TkGate.ledon_pixel = Tkg_GetColor("red");
401   TkGate.ledunknown_pixel = Tkg_GetColor("yellow");
402 
403   TkGate.instGC       = Tkg_createGC(GXxor,"blue",TkGate.textXF[1]);
404   TkGate.moduleGC     = Tkg_createGC(GXxor,"magenta4",TkGate.textXF[1]);
405   TkGate.modportGC    = Tkg_createGC(GXxor,"cyan4",TkGate.textXF[1]);
406   TkGate.frameGC      = Tkg_createGC(GXxor,"tan4",TkGate.textXF[1]);
407   TkGate.imageGC      = Tkg_createGC(GXcopy,"tan4",TkGate.textXF[1]);
408   TkGate.hyperlinkGC  = Tkg_createGC(GXxor,"tan4",TkGate.textXF[1]);
409   TkGate.wireGC       = Tkg_createGC(GXxor,"green4",TkGate.stextXF[1]);
410   TkGate.busGC        = Tkg_createGC(GXxor,"red",TkGate.stextXF[1]);
411   TkGate.selWireGC    = Tkg_createGC(GXxor,"green4",TkGate.stextbXF[1]);
412   TkGate.selBusGC     = Tkg_createGC(GXxor,"red",TkGate.stextbXF[1]);
413   TkGate.toolGC       = Tkg_createGC(GXxor,"black",TkGate.textXF[1]);
414   TkGate.cpathGC      = Tkg_createGC(GXxor,"red",TkGate.textXF[1]);
415   TkGate.kanjiGC      = Tkg_createGC(GXxor,"tan4",TkGate.ktextXF ? TkGate.ktextXF[1] : 0);
416 
417   TkGate.copyGC       = Tkg_createGC(GXcopy,"black",TkGate.textXF[1]);
418   XSetGraphicsExposures(TkGate.D,TkGate.copyGC,True);
419 
420   TkGate.scopeXHairGC   = Tkg_createGC(GXxor,"black",TkGate.textXF[1]);
421   TkGate.scopeSelectGC  = Tkg_createGC(GXxor,"grey90",TkGate.textXF[1]);
422   TkGate.scopeGridGC    = Tkg_createGC(GXcopy,"black",TkGate.textXF[1]);
423   TkGate.scopeOneGC     = Tkg_createGC(GXcopy,"green4",TkGate.stextXF[1]);
424   TkGate.scopeZeroGC    = Tkg_createGC(GXcopy,"magenta",TkGate.stextXF[1]);
425   TkGate.scopeFloatGC   = Tkg_createGC(GXcopy,"blue",TkGate.stextXF[1]);
426   TkGate.scopeUnknownGC = Tkg_createGC(GXcopy,"red",TkGate.stextXF[1]);
427   TkGate.scopeClearGC   = Tkg_createGC(GXcopy,"white",TkGate.stextXF[1]);
428 
429   XSetLineAttributes(TkGate.D,TkGate.busGC,2,LineSolid,CapButt,JoinMiter);
430   XSetLineAttributes(TkGate.D,TkGate.selBusGC,3,LineSolid,CapButt,JoinMiter);
431   XSetLineAttributes(TkGate.D,TkGate.selWireGC,2,LineSolid,CapButt,JoinMiter);
432 
433   mask = GCLineStyle | GCDashList;
434   values.line_style = LineOnOffDash;
435   values.dashes = DASH_LENGTH/2;
436   XChangeGC(TkGate.D,TkGate.frameGC, mask, &values);
437 
438   mask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
439   values.foreground = 1;
440   values.background = 1;
441   values.function = GXcopy;
442   values.graphics_exposures = False;
443 
444   bitPM = XCreatePixmap(TkGate.D,TkGate.root,8,8,1);
445   TkGate.bitGC = XCreateGC(TkGate.D,bitPM,mask,&values);
446   XFreePixmap(TkGate.D,bitPM);
447 }
448 
449 /*****************************************************************************
450  *
451  * The TkGateParms object is the top-level data structure used in the
452  * original xgate program.  Since there is too much depending on it,
453  * just initialize it appropriately for now.
454  *
455  *****************************************************************************/
initGateParms(TkgGateWin * gw,TkGateParams * P)456 static void initGateParms(TkgGateWin *gw,TkGateParams *P)
457 {
458   Tk_MakeWindowExist(gw->win);
459 
460   P->W = Tk_WindowId(gw->win);
461 
462   P->painterW = (GatePainter*)new_GatePainterXlib();
463   GatePainter_init(P->painterW, P->D, P->W); /* Initializing editing window painter */
464   P->commentContext = GatePainter_createContext(P->painterW);
465   *GatePainterContext_gcRef(TkGate.commentContext) =
466       Tkg_createGC(GXxor,"tan4",TkGate.textXF[1]);
467 
468   P->comment_color = GatePainter_getColor(P->painterW,
469       Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
470   P->hyperlink_color = GatePainter_getColor(P->painterW,
471       Tcl_GetVar(TkGate.tcl,"tkg_hyperlinkColor",TCL_GLOBAL_ONLY));
472 
473   P->painterScopeW = (GatePainter*)new_GatePainterXlib();
474   GatePainter_init(P->painterScopeW, P->D, None); /* Initializing scope window painter */
475 
476   P->circuit->es = new_EditState();
477   TkGate.circuit->no_set_modify = 1;
478   P->circuit->es->env = env_defineModule("main",1);
479   editstate_setCurrent(P->circuit->es);
480   TkGate.circuit->root_mod = P->circuit->es->env;
481   TkGate.circuit->no_set_modify = 0;
482   TkGate_setOrigin(0,0);
483   ClearModified();
484 }
485 
486 /*****************************************************************************
487  *
488  * gateCleanUp - This function is called when exiting tkgate to cleanup any
489  * data structures that need to be explicitly released before we exit.
490  *
491  *****************************************************************************/
gateCleanUp()492 void gateCleanUp()
493 {
494   UnloadAllFonts();			/* Free all font structures */
495 }
496 
497 /*****************************************************************************
498  *
499  * Rescan all HDL modules
500  *
501  * This function is called as an idle task while in edit mode.  It looks for
502  * any HDL modules that have been modified since the last scan and does a scan
503  * on them by running the simulator in scan mode.
504  *
505  *****************************************************************************/
RescanHDLModules()506 void RescanHDLModules()
507 {
508   HashElem *e;
509   SHash *modules = TkGate.circuit->moduleTable;
510   int anyscanned = 0;
511 
512   for (e = Hash_first(modules);e;e = Hash_next(modules,e)) {
513     GModuleDef *M = (GModuleDef*) HashElem_obj(e);
514     if (GModuleDef_getType(M) == MT_TEXTHDL && M->m_needScan) {
515       if (!anyscanned)
516 	ob_begin_framef("ScanMod",FF_TRANSPARENT|FF_BACKGROUND);
517       GModuleDef_scanHDLModule(M);
518       anyscanned = 1;
519     }
520   }
521 
522   if (anyscanned) {
523     SetModified(MF_MODULE|MF_SYNCONLY);
524     ob_end_frame();
525   }
526 }
527 
528 
529 /*****************************************************************************
530  *
531  * This function is called when the tk event queue becomes idle.
532  *
533  *****************************************************************************/
idleGateWin(ClientData data)534 void idleGateWin(ClientData data)
535 {
536   extern int want_exit;
537   MajorMode cm = tkgate_currentMode();
538 
539   if (want_exit) {
540     switch (cm) {
541     case MM_SIMULATE :
542       if (TkGate.circuit->simulator.active)
543 	SimInterface_end(&TkGate.circuit->simulator);
544       break;
545     case MM_ANALYZE :
546       cpath_close();
547       break;
548     case MM_EDIT :
549       break;
550     }
551     DoTcl("File::closeApplication");
552     want_exit = 0;
553   }
554 
555 #if TOUCH_XGATE_ED
556   ob_begin_framef("-Idle",FF_TRANSPARENT);
557 #endif
558 
559   if (TkGate.idle_ev.scroll_area) {
560     ob_begin_framef("Scroll",FF_STICKY);
561     doScroll(wtoc_x(TkGate.idle_ev.scroll_new_x),
562 	     wtoc_y(TkGate.idle_ev.scroll_new_y));
563     ob_end_frame();
564 
565     TkGate.idle_ev.scroll_new_x = TkGate.circuit->org_x;
566     TkGate.idle_ev.scroll_new_y = TkGate.circuit->org_y;
567     TkGate.idle_ev.scroll_area = 0;
568     TkGate.idle_ev.redraw = 0;
569   } else {
570     if (TkGate.idle_ev.redraw) {
571       editstate_fullUpdate(TkGate.circuit->es);
572       TkGate.idle_ev.redraw = 0;
573     }
574   }
575 
576   if (TkGate.idle_ev.scope_redraw || TkGate.idle_ev.trace_redraw) {
577     extern GScope *Scope;
578     if (Scope)
579       GScope_fullUpdate(Scope);
580     TkGate.idle_ev.scope_redraw = 0;
581     TkGate.idle_ev.trace_redraw = 0;
582   }
583 
584 #if TOUCH_XGATE_ED
585   ob_end_frame();
586 #endif
587 
588   /*
589    * Synchronize main tabs with actual edit state.
590    */
591   switch (cm) {
592   case MM_SIMULATE :
593     DoTcl("syncMainTabs Simulate");
594     break;
595   case MM_ANALYZE :
596     DoTcl("syncMainTabs CriticalPath");
597     break;
598   case MM_EDIT :
599     {
600       EditState *es = TkGate.circuit->es;
601       if (es && es->isInterface)
602 	DoTcl("syncMainTabs EditInterfaces");
603       else
604 	DoTcl("syncMainTabs Edit");
605     }
606     RescanHDLModules();
607     break;
608   }
609 
610   SynchronizeInterface();
611 
612   TkGate.idle_ev.pending = 0;
613 }
614 
615 /*****************************************************************************
616  *
617  * This function is called to request that a redraw be performed the
618  * next time the tk event queue becomes empty.
619  *
620  *****************************************************************************/
FlagRedraw()621 void FlagRedraw()
622 {
623   TkGate.idle_ev.redraw = 1;
624   TkGate.idle_ev.scroll_area = 0;
625 
626   if (!TkGate.idle_ev.pending) {
627     TkGate.idle_ev.pending = 1;
628     Tk_DoWhenIdle(idleGateWin,0);
629   }
630 }
631 
632 /*****************************************************************************
633  *
634  * This function is called to request that scrolling be done the next time
635  * the tk event queue becomes empty.  Calls to this function accumulate
636  * x and y change, and when the action is performed the combined scrolling
637  * action is performed.
638  *
639  *****************************************************************************/
FlagScrolling(void)640 void FlagScrolling(void)
641 {
642   if (!TkGate.idle_ev.redraw) {
643     TkGate.idle_ev.redraw = 1;
644     TkGate.idle_ev.scroll_area = 1;
645   }
646 
647   if (!TkGate.idle_ev.pending) {
648     TkGate.idle_ev.pending = 1;
649     Tk_DoWhenIdle(idleGateWin,0);
650   }
651 }
652 
653 /*****************************************************************************
654  *
655  * Handle an X event for the main tkgate window (primarily Exposure events)
656  * that hasn't already been handled elsewhere.
657  *
658  *****************************************************************************/
gateWinEvent(ClientData data,XEvent * E)659 static void gateWinEvent(ClientData data, XEvent *E)
660 {
661 #if TOUCH_XGATE_ED
662   ob_begin_framef("-WEvent",FF_TRANSPARENT);
663 #endif
664 
665   switch (E->type) {
666   case DestroyNotify :
667     gateCleanUp();
668     break;
669   case GraphicsExpose :
670     if (TkGate.regionUpdate) {
671       XGraphicsExposeEvent *xE = &E->xgraphicsexpose;
672       editstate_regionUpdate(TkGate.circuit->es,xE->x,xE->y,xE->x+xE->width,xE->y+xE->height);
673     } else {
674       FlagRedraw();
675     }
676     break;
677   case Expose :
678     if (TkGate.regionUpdate) {
679       XExposeEvent *xE = &E->xexpose;
680       editstate_regionUpdate(TkGate.circuit->es,xE->x,xE->y,xE->x+xE->width,xE->y+xE->height);
681     } else {
682       FlagRedraw();
683     }
684     break;
685   case NoExpose :
686     break;
687   default :
688     FlagRedraw();
689   }
690 #if TOUCH_XGATE_ED
691   ob_end_frame();
692 #endif
693 }
694 
695 /*****************************************************************************
696  *
697  * Update the positions of the scroll bars to reflect the new window visiblity.
698  *
699  *****************************************************************************/
scrollbar_update()700 void scrollbar_update()
701 {
702   int width = TkGate.width/TkGate.circuit->zoom_factor;
703   int height = TkGate.height/TkGate.circuit->zoom_factor;
704   int x0 = -TkGate.circuit->org_x;
705   int y0 = -TkGate.circuit->org_y;
706   int min_x = TkGate.ed->min_x;
707   int min_y = TkGate.ed->min_y;
708   int max_x = TkGate.ed->max_x;
709   int max_y = TkGate.ed->max_y;
710   double range_x = 1.0/(double)imax(10,max_x-min_x);
711   double range_y = 1.0/(double)imax(10,max_y-min_y);
712   double xb = 0.0;
713   double xe = 1.0;
714   double yb = 0.0;
715   double ye = 1.0;
716 
717   xb = (x0          - min_x)*range_x;
718   xe = (x0 + width  - min_x)*range_x;
719   yb = (y0          - min_y)*range_y;
720   ye = (y0 + height - min_y)*range_y;
721 
722   if (xb < 0) xb = 0;
723   if (xe > 1) xe = 1;
724   if (yb < 0) yb = 0;
725   if (ye > 1) ye = 1;
726 
727   if (min_x >= max_x) {
728     xb = yb = 0;
729     xe = ye = 1;
730   }
731 
732   DoTcl("%s %lf %lf",TkGate.gw->xscroll,xb,xe);
733   DoTcl("%s %lf %lf",TkGate.gw->yscroll,yb,ye);
734 #if 0
735   printf("Y-Scroll: [%d..%d] (%d..%d) --> %s %lf %lf\n",min_y,max_y,y0,y0+TkGate.height,TkGate.gw->yscroll,yb,ye);
736   printf("X-Scroll: [%d..%d] (%d..%d) --> %s %lf %lf\n",min_x,max_x,x0,x0+TkGate.width ,TkGate.gw->xscroll,xb,xe);
737 #endif
738 }
739 
740 /*****************************************************************************
741  *
742  * Get the bounding box and update the scroll bars to reflect it.
743  *
744  *****************************************************************************/
scrollbar_bbx_update()745 void scrollbar_bbx_update()
746 {
747 #if TOUCH_XGATE_ED
748   ob_touch(TkGate.ed);
749 #endif
750   GModuleDef_getBBX(TkGate.circuit->es->env, TD_X11,
751 		    &TkGate.ed->min_x,&TkGate.ed->max_x,
752 		    &TkGate.ed->min_y,&TkGate.ed->max_y);
753   scrollbar_update();
754 }
755 
756 
757 /*****************************************************************************
758  *
759  * Parse a scroll distance specification.
760  *
761  *****************************************************************************/
parseScrollDistance(int argc,const char * argv[],int org,int min_c,int max_c,int range_c,int * new_org_c)762 static int parseScrollDistance(int argc,const char *argv[],int org,int min_c,int max_c,int range_c,int *new_org_c)
763 {
764   int len = max_c - min_c;
765   int old_new_org_c = *new_org_c;				/* Old value of coordinate update value */
766   int x;
767 
768   if (argc == 1) {						/* n */
769     sscanf(argv[0],"%d",&x);
770   } else if (argc == 2 && strcmp(argv[0],"press") == 0) {	/* press n */
771     int b;
772     sscanf(argv[1],"%d",&b);
773 
774     scrollbar_update();
775 
776     TkGate.ed->scr_x = TkGate.circuit->org_x;
777     TkGate.ed->scr_y = TkGate.circuit->org_y;
778   } else if (argc == 2 && strcmp(argv[0],"moveto") == 0) {	/* moveto n */
779     double dx;
780     sscanf(argv[1],"%lf",&dx);
781 
782     *new_org_c = -(min_c + (int) (dx*len)) - imin(0,-org-min_c);
783 
784 
785   } else if (argc == 3 && strcmp(argv[0],"scroll") == 0		/* scroll n pages */
786 	     && strcmp(argv[2],"pages") == 0) {
787     double dx;
788     sscanf(argv[1],"%lf",&dx);
789 
790     *new_org_c -= (int) (dx*len);
791   } else if (argc == 3 && strcmp(argv[0],"scroll") == 0		/* scroll n units */
792 	     && strcmp(argv[2],"units") == 0) {
793     double dx;
794     sscanf(argv[1],"%lf",&dx);
795 
796     *new_org_c -= (int) (dx*50);
797   } else if (argc == 3 && strcmp(argv[0],"scroll") == 0		/* scroll n pixels */
798 	     && strcmp(argv[2],"pixels") == 0) {
799     double dx;
800     sscanf(argv[1],"%lf",&dx);
801 
802     *new_org_c -= (int) (dx);
803   }
804 
805   if (-*new_org_c > max_c + SCROLL_LIMIT)
806     *new_org_c = -(max_c + SCROLL_LIMIT);
807   if (-*new_org_c < min_c - range_c - SCROLL_LIMIT)
808     *new_org_c = -(min_c - range_c - SCROLL_LIMIT);
809 
810 
811   return old_new_org_c != *new_org_c;
812 }
813 
814 /*****************************************************************************
815  *
816  * Parse an X distance scroll specification
817  *
818  *****************************************************************************/
parseXScrollDistance(int argc,const char * argv[])819 static int parseXScrollDistance(int argc,const char *argv[])
820 {
821   int x0 = TkGate.ed->scr_x;
822   int min_x = TkGate.ed->min_x;
823   int max_x = imax(TkGate.ed->max_x,TkGate.ed->min_x+TkGate.width/TkGate.circuit->zoom_factor);
824 
825   return parseScrollDistance(argc,argv,x0,min_x,max_x,TkGate.width/TkGate.circuit->zoom_factor,
826 			     &TkGate.idle_ev.scroll_new_x);
827 }
828 
829 /*****************************************************************************
830  *
831  * Parse an Y distance scroll specification
832  *
833  *****************************************************************************/
parseYScrollDistance(int argc,const char * argv[])834 static int parseYScrollDistance(int argc,const char *argv[])
835 {
836   int y0 = TkGate.ed->scr_y;
837   int min_y = TkGate.ed->min_y;
838   int max_y = imax(TkGate.ed->max_y,TkGate.ed->min_y+TkGate.height/TkGate.circuit->zoom_factor);
839 
840   return parseScrollDistance(argc,argv,y0,min_y,max_y,TkGate.height/TkGate.circuit->zoom_factor,&TkGate.idle_ev.scroll_new_y);
841 }
842 
843 /*
844  * Do a scrolling update in the circuit window.
845  */
doScroll(int dx,int dy)846 void doScroll(int dx,int dy)
847 {
848   /*
849    * If circuit is empty, return to default position.
850    */
851   if (TkGate.ed->min_x >= TkGate.ed->max_x) {
852     TkGate_setOrigin(0,0);
853     return;
854   }
855 
856   if (dx != 0) {
857     int x1,y1,w,h,x2,y2;
858     int delta = -dx*TkGate.circuit->zoom_factor;
859 
860     h = TkGate.height;
861     w = TkGate.width;
862     y1 = y2 = 0;
863     if (delta > 0) {
864       x1 = delta;
865       x2 = 0;
866     } else {
867       x1 = 0;
868       x2 = -delta;
869     }
870 
871     XCopyArea(TkGate.D,TkGate.W,TkGate.W,TkGate.copyGC,x1,y1,w,h,x2,y2);
872 
873     TkGate_setOrigin(TkGate.circuit->org_x + dx,TkGate.circuit->org_y);
874     if (delta > 0) {
875       editstate_regionUpdate(TkGate.circuit->es,w-delta-1,0,w+1,h+1);
876     } else {
877       editstate_regionUpdate(TkGate.circuit->es,0,0,-delta+1,h+1);
878     }
879   }
880   if (dy != 0) {
881     int x1,y1,w,h,x2,y2;
882     int delta = -dy*TkGate.circuit->zoom_factor;
883 
884     h = TkGate.height;
885     w = TkGate.width;
886     x1 = x2 = 0;
887     if (delta > 0) {
888       y1 = delta;
889       y2 = 0;
890     } else {
891       y1 = 0;
892       y2 = -delta;
893     }
894 
895     XCopyArea(TkGate.D,TkGate.W,TkGate.W,TkGate.copyGC,x1,y1,w,h,x2,y2);
896 
897     TkGate_setOrigin(TkGate.circuit->org_x,TkGate.circuit->org_y + dy);
898     if (delta > 0) {
899       editstate_regionUpdate(TkGate.circuit->es,0,h-delta-1,w+1,h+1);
900     } else {
901       editstate_regionUpdate(TkGate.circuit->es,0,0,w+1,-delta+1);
902     }
903   }
904 }
905 
906 /*****************************************************************************
907  *
908  * Respond to a tcl "window" command on the main edit window.  Normally this
909  * is a scroll bar change notice.
910  *
911  *****************************************************************************/
gateWinCommand(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])912 static int gateWinCommand(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
913 {
914   TkgGateWin *gw = (TkgGateWin*) data;
915 
916 
917   if (strcmp(argv[1],"xview") == 0) {
918     TkGate.idle_ev.scroll_new_x = TkGate.circuit->org_x;
919     TkGate.idle_ev.scroll_new_y = TkGate.circuit->org_y;
920     if (parseXScrollDistance(argc-2,argv+2)) {
921       if (TkGate.smoothScroll) {
922 	FlagScrolling();
923       } else {
924 	ob_begin_framef("Scroll",FF_TRANSPARENT);
925 	TkGate_setOrigin(TkGate.idle_ev.scroll_new_x,TkGate.circuit->org_y);
926 	ob_end_frame();
927 	FlagRedraw();
928       }
929     }
930   } else if (strcmp(argv[1],"yview") == 0) {
931     TkGate.idle_ev.scroll_new_x = TkGate.circuit->org_x;
932     TkGate.idle_ev.scroll_new_y = TkGate.circuit->org_y;
933     if (parseYScrollDistance(argc-2,argv+2)) {
934       if (TkGate.smoothScroll) {
935 	FlagScrolling();
936       } else {
937 	ob_begin_framef("Scroll",FF_TRANSPARENT);
938 	TkGate_setOrigin(TkGate.circuit->org_x, TkGate.idle_ev.scroll_new_y);
939 	ob_end_frame();
940 	FlagRedraw();
941       }
942     }
943   } else if (argc == 3 && strcmp(argv[1],"cget") == 0) {
944     int i;
945 
946     for (i = 0;i < numConfigSpecs;i++) {
947       Tk_ConfigSpec *C = &configSpecs[i];
948       if (C->type == TK_CONFIG_STRING && strcmp(C->argvName,argv[2]) == 0) {
949 	char *value = *(char**)(((char*)gw) + C->offset);
950     Tcl_SetResult(tcl, value, TCL_VOLATILE);
951 	break;
952       }
953     }
954   }
955 
956   return TCL_OK;
957 }
958 
959 /*****************************************************************************
960  *
961  * Called if our call to Tk_ConfigureWidget failed.  It seems to be broken
962  * in some tcl/tk versions.
963  *
964  *****************************************************************************/
configWarning(int p)965 void configWarning(int p)
966 {
967   printf("\n- FATAL ERROR -\n\n");
968   printf("If you get this message, it probably means that Tk_ConfigureWidget is\n");
969   printf("broken on your machine.  Try recompiling with TKGATE_BROKENCONFIGWIDGET\n");
970   printf("set to 1 in the top-level file config.h.\n");
971 
972   exit(1);
973 }
974 
975 /*****************************************************************************
976  *
977  * Callback function that is called when the size of the main window is changed
978  * by the user, normally be resizing with the mouse.
979  *
980  *****************************************************************************/
tkg_configMain(ClientData data,Tcl_Interp * tcl,int argc,const char ** argv)981 static int tkg_configMain(ClientData data, Tcl_Interp *tcl, int argc, const char **argv)
982 {
983   TkgGateWin *gw = (TkgGateWin *) data;
984 
985 #if TKGATE_BROKENCONFIGWIDGET
986   char *wstr = Tcl_GetVar(TkGate.tcl,"tkg_initialWidth",TCL_GLOBAL_ONLY);
987   char *hstr = Tcl_GetVar(TkGate.tcl,"tkg_initialHeight",TCL_GLOBAL_ONLY);
988   if (wstr) sscanf(wstr,"%d",&gw->width);
989   if (hstr) sscanf(hstr,"%d",&gw->height);
990   gw->xscroll = ".horz set";
991   gw->yscroll = ".vert set";
992   gw->takefocus = 0;
993 
994   Tk_SetWindowBackground(gw->win, XWhitePixelOfScreen(TkGate.S));
995 #else
996   signal(SIGBUS,configWarning);
997   signal(SIGSEGV,configWarning);
998 
999   if (Tk_ConfigureWidget(tcl, gw->win, configSpecs, argc, argv, (char*) gw, 0) != TCL_OK)
1000     return TCL_ERROR;
1001 
1002   Tk_SetWindowBackground(gw->win, gw->bgColor->pixel);
1003 
1004   signal(SIGBUS,SIG_DFL);
1005   signal(SIGSEGV,SIG_DFL);
1006 #endif
1007 
1008   Tk_GeometryRequest(gw->win,gw->width,gw->height);
1009 
1010   if (gw->gc == None) {
1011     XGCValues gcv;
1012 
1013     gcv.function = GXxor;
1014     gcv.graphics_exposures = False;
1015     gw->gc = Tk_GetGC(gw->win,GCFunction|GCGraphicsExposures, &gcv);
1016 
1017   }
1018 
1019   did_interface_resize = 1;
1020 
1021   return TCL_OK;
1022 }
1023 
1024 /*****************************************************************************
1025  *
1026  * Called when tkgate window is externally destroyed.
1027  *
1028  *****************************************************************************/
gateWinDestroy(ClientData data)1029 static void gateWinDestroy(ClientData data)
1030 {
1031 }
1032 
1033 /*****************************************************************************
1034  * Process the command for creating the main tkgate circuit editing window.
1035  *
1036  * Usage: gatewin .w
1037  *
1038  *****************************************************************************/
tkg_gateWin(ClientData data,Tcl_Interp * tcl,int argc,const char ** argv)1039 static int tkg_gateWin(ClientData data, Tcl_Interp *tcl, int argc, const char **argv)
1040 {
1041   Tk_Window root = (Tk_Window) data;
1042   TkgGateWin *gw;
1043   Tk_Window w;
1044 
1045   if (argc < 2) {
1046     Tcl_AppendResult(tcl, "wrong # args: should be \"",argv[0], " pathName ?options?\"", 0);
1047     return TCL_ERROR;
1048   }
1049 
1050   w = Tk_CreateWindowFromPath(tcl, root, argv[1], 0);
1051   if (!w) return TCL_ERROR;
1052   Tk_SetClass(w, "GateWin");
1053 
1054   gw = (TkgGateWin*) ob_malloc(sizeof(TkgGateWin),"TkgGateWin");
1055   gw->win = w;
1056   gw->d = Tk_Display(w);
1057   gw->tcl = tcl;
1058   gw->width = TKG_GATEWIN_WIDTH;
1059   gw->height = TKG_GATEWIN_HEIGHT;
1060   gw->gc = None;
1061   gw->bgColor = gw->fgColor = 0;
1062   gw->parms = &TkGate;
1063   gw->xscroll = 0;
1064   gw->yscroll = 0;
1065   gw->takefocus = 0;
1066   TkGate.gw = gw;
1067 
1068   initGateParms(gw,&TkGate);
1069 
1070   Tk_CreateEventHandler(w, ExposureMask|StructureNotifyMask,
1071 			gateWinEvent, gw);
1072   Tcl_CreateCommand(tcl, Tk_PathName(w), gateWinCommand, gw, gateWinDestroy);
1073   if (tkg_configMain(gw, tcl, argc-2, argv+2) != TCL_OK) {
1074     Tk_DestroyWindow(w);
1075     return TCL_ERROR;
1076   }
1077 
1078   setGCcolors();
1079 
1080   Tcl_SetResult(tcl, Tk_PathName(w), TCL_STATIC);
1081 
1082   return TCL_OK;
1083 }
1084 
1085 /*****************************************************************************
1086  *
1087  * Do a tcl/tk script command.  Arguments act like printf and are used to
1088  * construct the command before execution.
1089  *
1090  *****************************************************************************/
DoTcl(const char * str,...)1091 int DoTcl(const char *str,...)
1092 {
1093   char buf[1024];
1094   int r;
1095   va_list ap;
1096 
1097   /*
1098    * Ignore tcl commands invoked before starting up the editor.
1099    */
1100   if (!TkGate.tcl) return TCL_OK;
1101 
1102   va_start(ap,str);
1103 
1104   vsprintf(buf,str,ap);
1105   r = Tcl_Eval(TkGate.tcl,buf);
1106   va_end(ap);
1107 
1108   if (r != TCL_OK) {
1109     printf("DoTCL Error: %s\n",Tcl_GetStringResult(TkGate.tcl));
1110     //    printf("DoTCL Error: %s\n",TkGate.tcl->result);
1111     printf("   while executing: %s\n",buf);
1112   }
1113 
1114   return r;
1115 }
1116 
1117 /*****************************************************************************
1118  *
1119  * Do a tcl/tk script command constructed from string objects.
1120  *
1121  *****************************************************************************/
DoTclL(const char * cmd,...)1122 int DoTclL(const char *cmd,...)
1123 {
1124   Tcl_Obj *objv[50];
1125   int n;
1126   int r;
1127   va_list ap;
1128 
1129   objv[0] = Tcl_NewStringObj(cmd,strlen(cmd));
1130 
1131   va_start(ap,cmd);
1132   for (n = 1;n < 50;n++) {
1133     char *s = va_arg(ap,char*);
1134     if (!s) break;
1135     objv[n] = Tcl_NewStringObj(s,strlen(s));
1136   }
1137   va_end(ap);
1138 
1139   r = Tcl_EvalObjv(TkGate.tcl, n, objv, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
1140   /* Are the objects freed here? */
1141 
1142   if (r != TCL_OK) {
1143     printf("tkgate: DoTclL Error - %s\n",Tcl_GetStringResult(TkGate.tcl));
1144     printf("   while executing: %s\n",cmd);
1145   }
1146 
1147 
1148   return r;
1149 }
1150 
1151 /*****************************************************************************
1152  *
1153  * Do a tcl/tk script command constructed from string objects.
1154  *
1155  *****************************************************************************/
DoTclV(const char * cmd,int nargs,const char ** args)1156 int DoTclV(const char *cmd,int nargs,const char **args)
1157 {
1158   Tcl_Obj *objv[50];
1159   int n;
1160   int r;
1161 
1162   objv[0] = Tcl_NewStringObj(cmd,strlen(cmd));
1163 
1164   for (n = 1;n < 50;n++) {
1165     if (nargs-- <= 0) break;
1166     objv[n] = Tcl_NewStringObj(args[n-1],strlen(args[n-1]));
1167   }
1168 
1169   r = Tcl_EvalObjv(TkGate.tcl, n, objv, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
1170   /* Are the objects freed here? */
1171 
1172   if (r != TCL_OK) {
1173     printf("DoTclV Error: %s\n",Tcl_GetStringResult(TkGate.tcl));
1174     printf("   while executing: %s\n",cmd);
1175   }
1176 
1177 
1178   return r;
1179 }
1180 
1181 
1182 
1183 /*****************************************************************************
1184  *
1185  * Handler function for button down events in the tkgate edit window.
1186  *
1187  *****************************************************************************/
tkg_buttonPress(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1188 static int tkg_buttonPress(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1189 {
1190   EditState *es = TkGate.circuit->es;
1191   int x,y,state,button;
1192 
1193   click_count++;
1194 
1195   DoTcl("tkg_cancel");
1196   DoTcl("tkg_undoSelections gate");
1197 
1198   sscanf(argv[2],"%d",&x);
1199   sscanf(argv[3],"%d",&y);
1200   sscanf(argv[4],"%d",&state);
1201   sscanf(argv[5],"%d",&button);
1202 
1203   if (button == 2) {
1204     TkGate.ed->saved_mode = EditState_getMode();
1205     DoTcl("ToolBar::selectTool 3");
1206     button = 1;
1207   }
1208 
1209   TkGate.ed->rx = x;
1210   TkGate.ed->ry = y;
1211 
1212   x /= TkGate.circuit->zoom_factor;
1213   y /= TkGate.circuit->zoom_factor;
1214 
1215   TkGate.state = state;
1216   TkGate.button = button;
1217 
1218 #if TOUCH_XGATE_ED
1219   ob_touch(TkGate.ed);
1220 #endif
1221   TkGate.ed->lx = TkGate.ed->tx;
1222   TkGate.ed->ly = TkGate.ed->ty;
1223   TkGate.ed->tx = wtoc_x(x);
1224   TkGate.ed->ty = wtoc_y(y);
1225 
1226   /*
1227    * Check to see if we are selecting a hyperlink.
1228    */
1229   if (!(state & (ShiftMask|ControlMask))
1230       && (EditState_getMode() == MODE_MOVE)
1231       && Hyperlink_selectAt(TkGate.ed->tx,TkGate.ed->ty)) {
1232     return TCL_OK;
1233   }
1234 
1235   /*
1236    * Special handling for scrolling mode
1237    */
1238   if (EditState_getMode() == MODE_SCROLL) {
1239     HandScroll_set(es);
1240     return TCL_OK;
1241   }
1242 
1243   switch (tkgate_currentMode()) {
1244   case MM_SIMULATE :
1245     SimInterface_hit(&TkGate.circuit->simulator,TkGate.ed->tx,TkGate.ed->ty,0);
1246     break;
1247   case MM_ANALYZE :
1248     cpath_mouseDown(es);
1249     break;
1250   case MM_EDIT :
1251     ClearErrorMark();
1252     mark_unpost();
1253     EditState_selectobject(es);
1254     mark_post();
1255     break;
1256   }
1257 
1258 
1259   showSelectedName();
1260 
1261   return TCL_OK;
1262 }
1263 
1264 /*****************************************************************************
1265  *
1266  * Handler function for double clicks in the tkgate edit window.
1267  *
1268  *****************************************************************************/
tkg_buttonDoublePress(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1269 static int tkg_buttonDoublePress(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1270 {
1271   if (click_count < 1) return TCL_OK;
1272 
1273   switch (tkgate_currentMode()) {
1274   case MM_SIMULATE :
1275     SimInterface_hit(&TkGate.circuit->simulator,TkGate.ed->tx,TkGate.ed->ty,1);
1276     break;
1277   case MM_ANALYZE :
1278     break;
1279   case MM_EDIT :
1280     if (EditState_getMode() == MODE_MOVE) {
1281       did_doubleclick = 1;
1282     }
1283     break;
1284   }
1285 
1286   return TCL_OK;
1287 }
1288 
1289 /*****************************************************************************
1290  *
1291  * Generate a checkpoint file name from the specified base filename.
1292  *
1293  *****************************************************************************/
getCheckpointFilename(char * checkPointFile,const char * fileName,size_t size)1294 int getCheckpointFilename(char *checkPointFile,const char *fileName,size_t size)
1295 {
1296   const char *p;
1297   char *q;
1298   /** @TODO to remove */
1299   /*
1300   int n;
1301   */
1302 
1303   if (!fileName) {
1304       strcpy(checkPointFile,"#checkpoint#");
1305       return 0;
1306   }
1307 
1308   if (strlen(fileName)+2 >= size)
1309     return -1;
1310 
1311   /*
1312    * Start with a copy of the file name.
1313    */
1314   strcpy(checkPointFile,fileName);
1315 
1316   /*
1317    * Find the base name of the file.
1318    */
1319   p = strrchr(fileName,'/');
1320   if (p) {
1321     p++;
1322     q = checkPointFile+(p-fileName);
1323   } else {
1324     p = fileName;
1325     q = checkPointFile;
1326   }
1327 
1328   /*
1329    * The filename part of the path was empty (this condition
1330    * is probably not possible).
1331    */
1332   if (!*p) return -1;
1333 
1334   /*
1335    * We are editing a checkpoint file, do not create further checkpoints.
1336    */
1337   if (*p == '#' && p[strlen(p)-1] == '#')
1338     return -1;
1339 
1340 
1341   /*
1342    * Create the checkpoint file name.
1343    */
1344   sprintf(q,"#%s#",p);
1345 
1346   return 0;
1347 }
1348 
1349 /*****************************************************************************
1350  *
1351  * Test if we want to write the checkpoint file and if so, write it.
1352  *
1353  *****************************************************************************/
doCheckpointTest()1354 static void doCheckpointTest()
1355 {
1356   extern int wantCheckpoint,checkpointenabled;
1357   const char *currentFile = CurrentFile_path(TkGate.circuit->currentFile);
1358 
1359   if (wantCheckpoint && checkpointenabled && TkGate.changedp
1360       && !TkGate.circuit->discardChanges && currentFile) {
1361     char buf[STRMAX];
1362 
1363     /* Generate checkpoint file name */
1364     if (getCheckpointFilename(buf,currentFile,STRMAX) == 0) {
1365       message(0,msgLookup("msg.wroteckpt"),buf);  /* Checkpointed to %s... */
1366       VerilogWriteModules(buf,VSO_NOHDLCHECK);	  /* Write the checkpoint file */
1367     }
1368   }
1369 
1370   wantCheckpoint = 0;
1371 }
1372 
checkMouseoverAction(int x,int y)1373 static void checkMouseoverAction(int x,int y)
1374 {
1375   EditState *es = TkGate.circuit->es;
1376   int tx = wtoc_x(x);
1377   int ty = wtoc_y(y);
1378   const char *link = 0;
1379   static const char *visible_link = 0;
1380 
1381   if (EditState_getMode() == MODE_MOVE)
1382     link = Hyperlink_getAt(tx,ty);
1383 
1384   if (link) {
1385     MouseoverCursor(HYPERLINKCURSOR);
1386   } else if (tkgate_currentMode() == MM_EDIT && EditState_getMode() == MODE_MOVE) {
1387     GCElement *g = gate_hit(es->env,tx,ty);
1388     GWireNode *n = wire_hit(tx,ty,es->env->m_wires);
1389 
1390     int pside = PSIDE_UNKNOWN;
1391 
1392     if (!n && g && GCElement_getType(g) == GC_BLOCK) {
1393       pside = Block_HitEdge(g,tx,ty);
1394     }
1395 
1396     switch (pside) {
1397     case PSIDE_LEFT :
1398       MouseoverCursor(ADDPORTLEFT);
1399       break;
1400     case PSIDE_RIGHT :
1401       MouseoverCursor(ADDPORTRIGHT);
1402       break;
1403     case PSIDE_BOTTOM :
1404       MouseoverCursor(ADDPORTBOTTOM);
1405       break;
1406     case PSIDE_TOP :
1407       MouseoverCursor(ADDPORTTOP);
1408       break;
1409     default :
1410       MouseoverCursor(CANCELMOUSEOVER);
1411       break;
1412     }
1413   } else
1414     MouseoverCursor(CANCELMOUSEOVER);
1415 
1416 
1417   /*
1418    * Update the status line if mouse is over a link
1419    */
1420   if (link != visible_link) {
1421     if (link)
1422       message(0,link);
1423     else
1424       message(0,"");
1425 
1426     visible_link = link;
1427   }
1428 }
1429 
1430 
1431 /*****************************************************************************
1432  *
1433  * Handler function for button release events in the tkgate edit window.
1434  *
1435  *****************************************************************************/
tkg_buttonRelease(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1436 static int tkg_buttonRelease(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1437 {
1438   EditState *es = TkGate.circuit->es;
1439   int x,y,state;
1440   int ret = TCL_OK;
1441 
1442   DoTcl("tkg_hideTempMessage");
1443 
1444   sscanf(argv[2],"%d",&x);
1445   sscanf(argv[3],"%d",&y);
1446   sscanf(argv[4],"%d",&state);
1447 
1448   TkGate.ed->rx = x;
1449   TkGate.ed->ry = y;
1450 
1451   x /= TkGate.circuit->zoom_factor;
1452   y /= TkGate.circuit->zoom_factor;
1453 
1454   TkGate.state = state;
1455   TkGate.button = -1;
1456 #if TOUCH_XGATE_ED
1457   ob_touch(TkGate.ed);
1458 #endif
1459   TkGate.ed->lx = TkGate.ed->tx;
1460   TkGate.ed->ly = TkGate.ed->ty;
1461   TkGate.ed->tx = wtoc_x(x);
1462   TkGate.ed->ty = wtoc_y(y);
1463 
1464   if (TkGate.circuit->select || TkGate.circuit->nsel)
1465     message(0,"");
1466 
1467   if (EditState_getMode() == MODE_SCROLL) {
1468     HandScroll_drop(es);
1469     wm_SetCursor(SCROLLCURSOR);
1470 
1471     if (TkGate.ed->saved_mode >= 0) {
1472       DoTcl("ToolBar::selectTool %d",TkGate.ed->saved_mode);
1473       TkGate.ed->saved_mode = -1;
1474     }
1475     return TCL_OK;
1476   }
1477 
1478   switch (tkgate_currentMode()) {
1479   case MM_SIMULATE :
1480     SimInterface_hitRelease(&TkGate.circuit->simulator);
1481     ret = TCL_OK;
1482     break;
1483   case MM_ANALYZE :
1484     cpath_mouseUp(es);
1485     ret = TCL_OK;
1486     break;
1487   case MM_EDIT :
1488     mark_unpost();
1489 
1490     EditState_dropobject(es);
1491     ob_touch(TkGate.circuit);
1492     TkGate.circuit->wnsel = NULL;
1493     TkGate.circuit->wsel = NULL;
1494 
1495     if (es->isInterface && did_interface_resize) {
1496       modint_arrange(es);
1497       FlagRedraw();
1498       did_interface_resize = 0;
1499     }
1500 
1501     if (did_doubleclick && EditState_getMode() == MODE_MOVE) {
1502       GCElement *g;
1503       GWire *w;
1504       EditState_selectobject(es);
1505       g = TkGate.circuit->select;
1506       w = TkGate.circuit->wsel;
1507       EditState_dropobject(es);
1508       mark_unpost();
1509 
1510       if (g) {
1511 	ob_suggest_name("EditProps");
1512 	DoTcl("gat_editProps");
1513       } else if (w) {
1514 	if (!es->isInterface) {
1515 	  ob_suggest_name("EditProps");
1516 	  net_editProps(w->net,TkGate.ed->tx,TkGate.ed->ty);
1517 	}
1518       }
1519     }
1520 
1521     did_doubleclick = 0;
1522 
1523     doCheckpointTest();
1524 
1525     scrollbar_bbx_update();
1526 
1527     ret = TCL_OK;
1528     break;
1529   }
1530 
1531   if (debugContinuousVerify)
1532     verify_circuit();
1533 
1534   SynchronizeInterface();
1535 
1536   checkMouseoverAction(x,y);
1537 
1538   Hyperlink_confirmAt(TkGate.ed->tx,TkGate.ed->ty);
1539 
1540   return ret;
1541 }
1542 
1543 
1544 /*****************************************************************************
1545  *
1546  * Handler function for button motion events in the tkgate edit window.
1547  *
1548  *****************************************************************************/
tkg_buttonMotion(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1549 static int tkg_buttonMotion(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1550 {
1551   EditState *es = TkGate.circuit->es;
1552   int x,y,state;
1553 
1554   if (Hyperlink_isPending()) return TCL_OK;
1555 
1556   sscanf(argv[2],"%d",&x);
1557   sscanf(argv[3],"%d",&y);
1558   sscanf(argv[4],"%d",&state);
1559 
1560   TkGate.ed->rx = x;
1561   TkGate.ed->ry = y;
1562 
1563   x /= TkGate.circuit->zoom_factor;
1564   y /= TkGate.circuit->zoom_factor;
1565 
1566   /*
1567    * Mouseover cursor handling if no buttons are pressed
1568    */
1569   if (!(state & (Button1Mask|Button2Mask|Button3Mask))) {
1570     checkMouseoverAction(x,y);
1571     return TCL_OK;
1572   }
1573 
1574   /*
1575    * Only track button 1 or 2 motin
1576    */
1577   if (!(state & (Button1Mask|Button2Mask)))
1578     return TCL_OK;
1579 
1580 
1581   /*
1582    * Special handling for scrolling
1583    */
1584   if (EditState_getMode() == MODE_SCROLL) {
1585     HandScroll_move(es);
1586     return TCL_OK;
1587   }
1588 
1589   switch (tkgate_currentMode()) {
1590   case MM_SIMULATE :
1591     break;
1592   case MM_ANALYZE :
1593     break;
1594   case MM_EDIT :
1595     TkGate.state = state;
1596 #if TOUCH_XGATE_ED
1597     ob_touch(TkGate.ed);
1598 #endif
1599     TkGate.ed->lx = TkGate.ed->tx;
1600     TkGate.ed->ly = TkGate.ed->ty;
1601     TkGate.ed->tx = wtoc_x(x);
1602     TkGate.ed->ty = wtoc_y(y);
1603 
1604     EditState_moveobject(es);
1605 
1606     break;
1607   }
1608 
1609   return TCL_OK;
1610 }
1611 
1612 /*****************************************************************************
1613  *
1614  * Clear the selection.
1615  *
1616  *****************************************************************************/
TkGate_clearSelection()1617 void TkGate_clearSelection()
1618 {
1619 #if TOUCH_XGATE_ED
1620   ob_touch(TkGate.ed);
1621 #endif
1622   TkGate.ed->tx = TkGate.ed->ty = TkGate.ed->lx = TkGate.ed->ly = TkGate.ed->sx = TkGate.ed->sy = 0;
1623   TkGate.circuit->select = 0;
1624   TkGate.circuit->last = 0;
1625   TkGate.circuit->wsel = 0;
1626   TkGate.circuit->wnsel = 0;
1627   TkGate.circuit->nsel = 0;
1628 }
1629 
1630 /*****************************************************************************
1631  *
1632  * Set up widget for the main tkgate window.
1633  *
1634  *****************************************************************************/
init_mainWindow(Tcl_Interp * tcl)1635 void init_mainWindow(Tcl_Interp *tcl)
1636 {
1637   Tk_Window root = Tk_MainWindow(tcl);
1638   Tk_MakeWindowExist(root);
1639 
1640   TkGate.circuit = new_Circuit();
1641   TkGate.ed = (EditData*) ob_malloc(sizeof(EditData),"EditData");
1642   TkGate.ed->mark_vis = 0;
1643   TkGate.ed->mark_posted = 0;
1644   TkGate.ed->major_mode = MM_EDIT;
1645   TkGate.ed->saved_mode = -1;
1646   TkGate.errl = new_ErrorList();
1647   TkGate.tcl = tcl;
1648   TkGate.D = Tk_Display(root);
1649   TkGate.root = Tk_WindowId(root);
1650   TkGate.S = XDefaultScreenOfDisplay(TkGate.D);
1651   TkGate.CM = DefaultColormapOfScreen(TkGate.S);
1652   TkGate.ScopeW = None;
1653   TkGate.bitorder = XBitmapBitOrder(TkGate.D);
1654   TkGate.byteorder = XImageByteOrder(TkGate.D);
1655   TkGate.rdb = XrmGetDatabase(TkGate.D);
1656   TkGate.ErrorMarkTimeout = 0;
1657 
1658   TkGate_clearSelection();
1659 
1660   SimInterface_init(&TkGate.circuit->simulator);
1661 
1662   if (sync_Xserver) {
1663     printf("[synchronized X11 connection]\n");
1664     XSynchronize(TkGate.D,True);
1665   }
1666 
1667   initGCs();
1668 
1669   Tcl_CreateCommand(tcl,"gat_scope"
1670 		    ,gat_scope
1671 		    ,(ClientData)root
1672 		    ,0);
1673 
1674   Tcl_CreateCommand(tcl,"tkg_gatewin"
1675 		    ,tkg_gateWin
1676 		    ,(ClientData)root
1677 		    ,0);
1678 
1679   Tcl_CreateCommand(tcl,"tkg_configMain"
1680 		    ,tkg_configMain
1681 		    ,(ClientData)root
1682 		    ,0);
1683 
1684   Tcl_CreateCommand(tcl,"tkg_buttonPress"
1685 		    ,tkg_buttonPress
1686 		    ,(ClientData)root
1687 		    ,0);
1688 
1689   Tcl_CreateCommand(tcl,"tkg_buttonDoublePress"
1690 		    ,tkg_buttonDoublePress
1691 		    ,(ClientData)root
1692 		    ,0);
1693 
1694   Tcl_CreateCommand(tcl,"tkg_buttonRelease"
1695 		    ,tkg_buttonRelease
1696 		    ,(ClientData)root
1697 		    ,0);
1698 
1699   Tcl_CreateCommand(tcl,"tkg_buttonMotion"
1700 		    ,tkg_buttonMotion
1701 		    ,(ClientData)root
1702 		    ,0);
1703 }
1704 
1705