diff --git a/.gitignore b/.gitignore index a45a1da..e83600f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -irsim +/irsim/irsim +/irsim/gentbl +/irsim/genspktbl irsimexec defs.mak Depend @@ -8,6 +10,7 @@ config.log scripts/defs.mak scripts/config.log scripts/config.status +scripts/autom4te.cache make.log install.log *.o diff --git a/analyzer/ana_glob.h b/analyzer/ana_glob.h index 8170d59..463806f 100644 --- a/analyzer/ana_glob.h +++ b/analyzer/ana_glob.h @@ -67,6 +67,14 @@ extern void EnableInput( /* */ ); extern void DisableAnalyzer( /* */ ); extern void EnableAnalyzer( /* */ ); extern void TerminateAnalyzer( /* */ ); +extern void WindowResize( /* ev */ ); +extern void WindowExposed( /* event */ ); +extern void HandleButton( /* ev */ ); +extern void HandleKey( /* ev */ ); + + /* EXPORTS FROM thread.c */ + +extern int xloop_create( /* */ ); /* EXPORTS FROM defaults.c */ diff --git a/analyzer/analyzer.c b/analyzer/analyzer.c index e81d8a0..460568f 100644 --- a/analyzer/analyzer.c +++ b/analyzer/analyzer.c @@ -138,6 +138,8 @@ public void DisplayTraces( isMapped ) { int change; + if (window == 0) return; /* GUI is built lazily; not ready yet */ + DisableInput(); traces.total += numAdded; diff --git a/analyzer/window.c b/analyzer/window.c index e73f433..8785f4a 100644 --- a/analyzer/window.c +++ b/analyzer/window.c @@ -17,6 +17,7 @@ * */ #include +#include /* for atoi() */ #include /* for strlen() */ #include "ana.h" #include diff --git a/base/config.c b/base/config.c index a1e3b55..2be57f3 100644 --- a/base/config.c +++ b/base/config.c @@ -298,10 +298,13 @@ public int config( cname ) device_names = (DevRec **)malloc(sizeof(DevRec *)); device_names[0] = (DevRec *)NULL; - /* Insert default devices */ - makedevice("nfet", "n-channel", (float)0.0); - makedevice("pfet", "p-channel", (float)0.0); - makedevice("resistor", "resistor", (float)0.0); + /* Insert default devices. The array index must match the implant */ + /* enum used as t->ttype, since transistors are looked up as */ + /* device_names[t->ttype]: NCHAN=0, PCHAN=1, DEP=2, RESIST=3. */ + makedevice("nfet", "n-channel", (float)0.0); /* NCHAN = 0 */ + makedevice("pfet", "p-channel", (float)0.0); /* PCHAN = 1 */ + makedevice("resistor", "resistor", (float)0.0); /* DEP = 2 */ + makedevice("resistor", "resistor", (float)0.0); /* RESIST = 3 */ while( fgetline( line, LSIZE, cfile ) != NULL ) { diff --git a/base/rsim.c b/base/rsim.c index 0572ae4..9189488 100644 --- a/base/rsim.c +++ b/base/rsim.c @@ -21,6 +21,10 @@ #ifdef TCL_IRSIM #include +/* Tcl version 9 compatibility */ +#if TCL_MAJOR_VERSION < 9 +typedef int Tcl_Size; +#endif #endif #include "defs.h" @@ -316,7 +320,8 @@ private void apply (fun, vfunc, arg) #ifdef TCL_IRSIM /* Check for case in which arguments are passed as a list. */ - int start, argc; + int start; + Tcl_Size argc; char **argv; if (targc == applyStart + 1) @@ -4026,6 +4031,13 @@ private int analyzer() if (!InitDisplay(first_file, (*x_display) ? x_display : NULL)) return(0); InitTimes(sim_time0, stepsize, cur_delta, 1); +#else + /* The Tk GUI is built lazily; building it sets up the */ + /* analyzer's X window via start_analyzer(). Do it now, */ + /* before DisplayTraces() touches the window -- otherwise */ + /* we crash on a NULL display / zero window. */ + if (Tcl_Eval(irsiminterp, "irsim::build_gui") != TCL_OK) + return(-1); #endif } diff --git a/base/rsim.h b/base/rsim.h index 442dba8..56946ab 100644 --- a/base/rsim.h +++ b/base/rsim.h @@ -114,4 +114,15 @@ extern int expand(); extern int input(); extern void shift_args(); +#ifndef TCL_IRSIM + /* the Tcl build (tclirsim.c) has its own static finput() */ +extern int finput(); +#endif +extern void InitCmdPath(); +extern void init_commands(); + + /* analyzer display locking, used under HAVE_PTHREADS (see event.c) */ +extern void EnableInput(); +extern void DisableInput(); + #endif /* _RSIM_H */ diff --git a/base/sim.c b/base/sim.c index bf9e529..ecd3eec 100644 --- a/base/sim.c +++ b/base/sim.c @@ -996,7 +996,7 @@ private int input_sim (simfile, has_param_file) break; case 'r': - newtrans(RESIST, 2, targc, targv); + newtrans(RESIST, RESIST, targc, targv); break; case 'x': diff --git a/irsim/Makefile b/irsim/Makefile index e59a8e4..2f6247e 100644 --- a/irsim/Makefile +++ b/irsim/Makefile @@ -25,9 +25,9 @@ tclirsim${SHDLIB_EXT}: ${EXTRA_LIBS} ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} -o $@ ${LDDL_FLAGS} ${LD_RUN_PATH} \ ${EXTRA_LIBS} -lc ${LIBS} ${LD_EXTRA_LIBS} -$(DESTDIR)${INSTALL_BINDIR}/irsim: - ${RM} $(DESTDIR)${INSTALL_BINDIR}/irsim - ${CP} irsim $(DESTDIR)${INSTALL_BINDIR}/irsim +$(DESTDIR)${INSTALL_BINDIR}/${IRSIM_BIN}: + ${RM} $(DESTDIR)${INSTALL_BINDIR}/${IRSIM_BIN} + ${CP} irsim $(DESTDIR)${INSTALL_BINDIR}/${IRSIM_BIN} $(DESTDIR)${INSTALL_BINDIR}/gentbl: ${RM} $(DESTDIR)${INSTALL_BINDIR}/gentbl @@ -43,7 +43,7 @@ gentbl: genspktbl: ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} genspktbl.c -o $@ ${LIBS} -install: $(DESTDIR)${INSTALL_BINDIR}/irsim $(DESTDIR)${INSTALL_BINDIR}/gentbl \ +install: $(DESTDIR)${INSTALL_BINDIR}/${IRSIM_BIN} $(DESTDIR)${INSTALL_BINDIR}/gentbl \ $(DESTDIR)${INSTALL_BINDIR}/genspktbl install-tcl: $(DESTDIR)${INSTALL_TCLDIR}/tclirsim${SHDLIB_EXT} diff --git a/irsim/genspktbl.c b/irsim/genspktbl.c index 38d2287..f938c11 100644 --- a/irsim/genspktbl.c +++ b/irsim/genspktbl.c @@ -49,7 +49,7 @@ double delaytab[ SPIKETBLSIZE + 1 ][ SPIKETBLSIZE + 1 ]; FILE *F; -main( argc, argv ) +int main( argc, argv ) int argc; char *argv[]; { diff --git a/irsim/gentbl.c b/irsim/gentbl.c index b6409ee..68a9b33 100644 --- a/irsim/gentbl.c +++ b/irsim/gentbl.c @@ -35,7 +35,7 @@ FILE *out; /* name of interval */ -char *pinterval( high, low ) +char *pinterval( int high, int low ) { static char temp[100]; @@ -60,14 +60,14 @@ int strength( i ) #define max( A, B ) ( ((A) > (B)) ? (A) : (B) ) /* find the enclosing interval */ -char *span( ihigh, ilow, jhigh, jlow ) +char *span( int ihigh, int ilow, int jhigh, int jlow ) { return( pinterval( min( ihigh, jhigh ), max( ilow, jlow ) ) ); } /* merge two intervals using least-upper bound operation */ -char *merge( ihigh, ilow, jhigh, jlow ) +char *merge( int ihigh, int ilow, int jhigh, int jlow ) { register int ahigh, alow; @@ -94,7 +94,7 @@ char *merge( ihigh, ilow, jhigh, jlow ) /* convert interval to use weak values */ -char *weak( i, j ) +char *weak( int i, int j ) { if( i == 0 ) i = 1; @@ -108,7 +108,7 @@ char *weak( i, j ) } -main() +int main() { register int i, j, k, ii, jj, interval2; diff --git a/irsim/irsim.c b/irsim/irsim.c index 8bd9398..fba2aab 100644 --- a/irsim/irsim.c +++ b/irsim/irsim.c @@ -40,8 +40,7 @@ public void Usage( msg, s1 ) /* Main routine for irsim */ -public main( argc, argv ) - char *argv[]; +int main( int argc, char *argv[] ) { int i, arg1, has_param_file; diff --git a/random/random.c b/random/random.c index c3b2be1..b3ad3ba 100644 --- a/random/random.c +++ b/random/random.c @@ -85,6 +85,11 @@ #include +/* Tcl version 9 compatibility */ +#if TCL_MAJOR_VERSION < 9 +typedef int Tcl_Size; +#endif + /*--------------------------------------------------------------*/ /* return a sample from a unit normal distribution */ /*--------------------------------------------------------------*/ @@ -293,7 +298,7 @@ int do_random(ClientData cl, Tcl_Interp *interp, int argc, char *argv[]) return TCL_ERROR; } else { - int list_count; + Tcl_Size list_count; char **list; if (Tcl_SplitList(interp, argv[3], &list_count, @@ -307,7 +312,7 @@ int do_random(ClientData cl, Tcl_Interp *interp, int argc, char *argv[]) } } else if (strcmp(argv[1], "-permute") == 0) { - int list_count; + Tcl_Size list_count; char *t; char **list; @@ -378,7 +383,7 @@ int do_random(ClientData cl, Tcl_Interp *interp, int argc, char *argv[]) return TCL_ERROR; } else { - int list_count; + Tcl_Size list_count; char *t; char **list; diff --git a/scripts/configure b/scripts/configure index 8f028e7..868d19b 100755 --- a/scripts/configure +++ b/scripts/configure @@ -638,6 +638,7 @@ gr_dflags gr_cflags DIST_DIR cadinstall +irsim_bin programs unused modules @@ -2541,6 +2542,8 @@ _ACEOF ALL_TARGET="standard" INSTALL_TARGET="install-irsim" +irsim_bin="irsim" + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -6234,6 +6237,7 @@ if test $usingTcl ; then extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\"" else programs="$programs irsim" + irsim_bin="cirsim" unused="$unused tcltk" fi @@ -6764,6 +6768,7 @@ fi + ac_config_files="$ac_config_files defs.mak" diff --git a/scripts/configure.in b/scripts/configure.in index 1ce1db6..bb9b045 100644 --- a/scripts/configure.in +++ b/scripts/configure.in @@ -19,6 +19,9 @@ dnl Override default target when compiling under TCL ALL_TARGET="standard" INSTALL_TARGET="install-irsim" +dnl Name of the installed standalone binary (overridden below for non-Tcl) +irsim_bin="irsim" + dnl Checks for programs. AC_PROG_CC AC_PROG_CPP @@ -807,6 +810,7 @@ if test $usingTcl ; then extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\"" else programs="$programs irsim" + irsim_bin="cirsim" unused="$unused tcltk" fi @@ -1266,6 +1270,7 @@ AC_SUBST(sub_extra_libs) AC_SUBST(modules) AC_SUBST(unused) AC_SUBST(programs) +AC_SUBST(irsim_bin) AC_SUBST(cadinstall) AC_SUBST(DIST_DIR) diff --git a/scripts/defs.mak.in b/scripts/defs.mak.in index 53dafc0..8ab35bd 100644 --- a/scripts/defs.mak.in +++ b/scripts/defs.mak.in @@ -55,6 +55,7 @@ SUB_EXTRA_LIBS = @sub_extra_libs@ MODULES += @modules@ UNUSED_MODULES += @unused@ PROGRAMS += @programs@ +IRSIM_BIN = @irsim_bin@ INSTALL_CAD_DIRS += @cadinstall@ RM = rm -f diff --git a/tcltk/irsim.tcl.in b/tcltk/irsim.tcl.in index e53d1c9..986b782 100644 --- a/tcltk/irsim.tcl.in +++ b/tcltk/irsim.tcl.in @@ -262,6 +262,14 @@ set RsimOpts(step) 100.0 set RsimOpts(sstep) 1000.0 set RsimOpts(base) 0 +proc irsim::gui_ready {} { + expr {[info exists ::irsim::gui_built] && $::irsim::gui_built} +} + +proc irsim::build_gui {} { + if {[irsim::gui_ready]} return + load {} Tk + wm withdraw . toplevel .analyzer wm geometry .analyzer 800x350+50+50 wm protocol .analyzer WM_DELETE_WINDOW {wm withdraw .analyzer} @@ -390,6 +398,130 @@ bind $c {irsim::center_slider %x} bind $c {irsim::center_slider %x} bind $c {irsim::grab_slider %x} bind $c {irsim::resize_slider %x} +pack .analyzer.scope.lbuttons.left -side right +pack .analyzer.scope.lbuttons.lleft -side right +pack .analyzer.scope.lbuttons.center -side right +pack .analyzer.scope.rbuttons.right -side left +pack .analyzer.scope.rbuttons.rright -side left + +grid .analyzer.scope.time0 -row 0 -column 0 -sticky news +grid .analyzer.scope.time1 -row 0 -column 1 -sticky news +grid .analyzer.scope.time2 -row 0 -column 2 -sticky news +grid .analyzer.scope.names -row 1 -column 0 -sticky news +grid .analyzer.scope.display -row 1 -column 1 -sticky news +grid .analyzer.scope.values -row 1 -column 2 -sticky news +grid .analyzer.scope.lbuttons -row 2 -column 0 -sticky news +grid .analyzer.scope.scrollx -row 2 -column 1 -sticky news +grid .analyzer.scope.rbuttons -row 2 -column 2 -sticky news +# Button callback for marker +bind .analyzer.scope.display \ + {marker off ; .analyzer.scope.time1 configure -text ""; irsim::no_values} +bind .analyzer.scope.display \ + {if {%x > 0} {marker set [trace cursor %y] [simtime cursor %x];\ + irsim::update_times; irsim::update_values}} +bind .analyzer.scope.display \ + {if {%x > 0} {marker set [trace cursor %y] [simtime cursor %x];\ + irsim::update_times; irsim::update_values}} +bind .analyzer.scope.display \ + {if {%x > 0} {marker 2 move [simtime cursor %x]; irsim::update_times}} +bind .analyzer.scope.display \ + {if {%x > 0} {marker 2 move [simtime cursor %x]; irsim::update_times}} +bind .analyzer.scope.display \ + {if {%x > 0} {marker 2 off; irsim::update_times}} +bind .analyzer.scope.display {irsim::zoom_to_delta} + +bind .analyzer.scope.display {simtime move -$RsimOpts(step)} +bind .analyzer.scope.display {simtime move +$RsimOpts(step)} +bind .analyzer.scope.display {simtime move -$RsimOpts(sstep)} +bind .analyzer.scope.display {simtime move +$RsimOpts(sstep)} +bind .analyzer.scope.display {zoom out} +bind .analyzer.scope.display {zoom in} +bind .analyzer.scope.display \ + {simtime left [simtime begin]; simtime right [simtime end]} + +bind .analyzer.scope.display {focus %W} +bind .analyzer.scope { \ + update idletasks; irsim::update_traces; \ + update idletasks; irsim::update_slider} + +wm withdraw .analyzer +.analyzer.scope.display init ;# force mapping of window +toplevel .nodelist +frame .nodelist.freenodes +frame .nodelist.usednodes +frame .nodelist.freevectors +frame .nodelist.usedvectors +listbox .nodelist.freenodes.list \ + -yscrollcommand {.nodelist.freenodes.sbar set} +scrollbar .nodelist.freenodes.sbar -width 10 -orient vertical \ + -command {.nodelist.freenodes.list yview} +listbox .nodelist.usednodes.list \ + -yscrollcommand {.nodelist.usednodes.sbar set} +scrollbar .nodelist.usednodes.sbar -width 10 -orient vertical \ + -command {.nodelist.usednodes.list yview} +listbox .nodelist.freevectors.list \ + -yscrollcommand {.nodelist.freevectors.sbar set} +scrollbar .nodelist.freevectors.sbar -width 10 -orient vertical \ + -command {.nodelist.freevectors.list yview} +listbox .nodelist.usedvectors.list \ + -yscrollcommand {.nodelist.usedvectors.sbar set} +scrollbar .nodelist.usedvectors.sbar -width 10 -orient vertical \ + -command {.nodelist.usedvectors.list yview} +label .nodelist.freenodes.title -text "Nodes" +label .nodelist.usednodes.title -text "Nodes in Analyzer" +label .nodelist.freevectors.title -text "Vectors" +label .nodelist.usedvectors.title -text "Vectors in Analyzer" + +pack .nodelist.freenodes.title -side top +pack .nodelist.freenodes.list -side left -expand true -fill both +pack .nodelist.freenodes.sbar -side right -fill y +pack .nodelist.usednodes.title -side top +pack .nodelist.usednodes.list -side left -expand true -fill both +pack .nodelist.usednodes.sbar -side right -fill y +pack .nodelist.freevectors.title -side top +pack .nodelist.freevectors.list -side left -expand true -fill both +pack .nodelist.freevectors.sbar -side right -fill y +pack .nodelist.usedvectors.title -side top +pack .nodelist.usedvectors.list -side left -expand true -fill both +pack .nodelist.usedvectors.sbar -side right -fill y + +label .nodelist.title -text "IRSIM node and vector lists" +frame .nodelist.bbar +button .nodelist.bbar.close -text "Close" -command {wm withdraw .nodelist} +pack .nodelist.bbar.close -side bottom -padx 5 -pady 5 + +grid .nodelist.title -row 0 -column 0 -columnspan 2 -sticky news +grid .nodelist.freenodes -row 1 -column 0 -sticky news +grid .nodelist.usednodes -row 1 -column 1 -sticky news +grid .nodelist.freevectors -row 2 -column 0 -sticky news +grid .nodelist.usedvectors -row 2 -column 1 -sticky news +grid .nodelist.bbar -row 3 -column 0 -columnspan 2 -sticky news + +grid columnconfigure .nodelist 0 -weight 1 +grid columnconfigure .nodelist 1 -weight 1 +grid rowconfigure .nodelist 1 -weight 1 +grid rowconfigure .nodelist 2 -weight 1 + +bind .nodelist.freenodes.list {irsim::pushnode %y} +bind .nodelist.usednodes.list {irsim::popnode %y} +bind .nodelist.freevectors.list {irsim::pushvector %y} +bind .nodelist.usedvectors.list {irsim::popvector %y} +wm withdraw .nodelist +toplevel .irsimprompt +label .irsimprompt.message -anchor w +pack .irsimprompt.message -side top -expand true -fill x -padx 10 -pady 5 +entry .irsimprompt.entry -width 40 -background white +pack .irsimprompt.entry -side top -padx 10 +frame .irsimprompt.buttons +button .irsimprompt.buttons.cancel -text "Cancel" -command {wm withdraw .irsimprompt} +button .irsimprompt.buttons.okay -text "Okay" +pack .irsimprompt.buttons.cancel -side left +pack .irsimprompt.buttons.okay -side right +pack .irsimprompt.buttons -side bottom -expand true -fill x -padx 10 -pady 5 +bind .irsimprompt.entry {.irsimprompt.buttons.okay invoke} +wm withdraw .irsimprompt + set ::irsim::gui_built 1 +} # Callback function for Print->Title menu button @@ -413,6 +545,7 @@ proc irsim::set_scrollsstep {value} { } proc irsim::update_slider {} { + if {![irsim::gui_ready]} return set a [simtime begin] set b [simtime end] set w [.analyzer.scope.display width] @@ -493,23 +626,8 @@ proc irsim::center_slider {x} { } } -pack .analyzer.scope.lbuttons.left -side right -pack .analyzer.scope.lbuttons.lleft -side right -pack .analyzer.scope.lbuttons.center -side right -pack .analyzer.scope.rbuttons.right -side left -pack .analyzer.scope.rbuttons.rright -side left - -grid .analyzer.scope.time0 -row 0 -column 0 -sticky news -grid .analyzer.scope.time1 -row 0 -column 1 -sticky news -grid .analyzer.scope.time2 -row 0 -column 2 -sticky news -grid .analyzer.scope.names -row 1 -column 0 -sticky news -grid .analyzer.scope.display -row 1 -column 1 -sticky news -grid .analyzer.scope.values -row 1 -column 2 -sticky news -grid .analyzer.scope.lbuttons -row 2 -column 0 -sticky news -grid .analyzer.scope.scrollx -row 2 -column 1 -sticky news -grid .analyzer.scope.rbuttons -row 2 -column 2 -sticky news - proc irsim::UpdateAnalyzer {args} { + irsim::build_gui # puts stderr "UpdateAnalyzer $args level [info level]" if {[wm state .analyzer] == "withdrawn"} { wm deiconify .analyzer @@ -524,39 +642,6 @@ proc irsim::UpdateAnalyzer {args} { irsim::update_nodelist } -# Button callback for marker -bind .analyzer.scope.display \ - {marker off ; .analyzer.scope.time1 configure -text ""; irsim::no_values} -bind .analyzer.scope.display \ - {if {%x > 0} {marker set [trace cursor %y] [simtime cursor %x];\ - irsim::update_times; irsim::update_values}} -bind .analyzer.scope.display \ - {if {%x > 0} {marker set [trace cursor %y] [simtime cursor %x];\ - irsim::update_times; irsim::update_values}} -bind .analyzer.scope.display \ - {if {%x > 0} {marker 2 move [simtime cursor %x]; irsim::update_times}} -bind .analyzer.scope.display \ - {if {%x > 0} {marker 2 move [simtime cursor %x]; irsim::update_times}} -bind .analyzer.scope.display \ - {if {%x > 0} {marker 2 off; irsim::update_times}} -bind .analyzer.scope.display {irsim::zoom_to_delta} - -bind .analyzer.scope.display {simtime move -$RsimOpts(step)} -bind .analyzer.scope.display {simtime move +$RsimOpts(step)} -bind .analyzer.scope.display {simtime move -$RsimOpts(sstep)} -bind .analyzer.scope.display {simtime move +$RsimOpts(sstep)} -bind .analyzer.scope.display {zoom out} -bind .analyzer.scope.display {zoom in} -bind .analyzer.scope.display \ - {simtime left [simtime begin]; simtime right [simtime end]} - -bind .analyzer.scope.display {focus %W} -bind .analyzer.scope { \ - update idletasks; irsim::update_traces; \ - update idletasks; irsim::update_slider} - -wm withdraw .analyzer -.analyzer.scope.display init ;# force mapping of window irsim::tag analyzer {irsim::UpdateAnalyzer %N} irsim::tag ana {irsim::UpdateAnalyzer %N} @@ -570,6 +655,7 @@ irsim::tag zoom {irsim::update_all} irsim::tag trace {irsim::trace_callback %1 %2} proc irsim::trace_callback {option {name {}}} { + if {![irsim::gui_ready]} return global RsimOpts if {$option == "select"} { set tl [trace list all] @@ -641,6 +727,7 @@ proc irsim::update_if_base_change {{option {}}} { } proc irsim::update_times {} { + if {![irsim::gui_ready]} return .analyzer.scope.time0 configure -text [format "%0.2f" \ [simtime left]] set tmarker [simtime marker] @@ -658,6 +745,7 @@ proc irsim::update_times {} { } proc irsim::update_traces {} { + if {![irsim::gui_ready]} return set tl [trace list all] set minv 0 set minn 0 @@ -712,6 +800,7 @@ proc irsim::update_traces {} { } proc irsim::update_values {} { + if {![irsim::gui_ready]} return set tl [trace list all] foreach tr $tl { set tr2 [string map {. #} $tr] @@ -738,67 +827,6 @@ proc irsim::no_values {} { # Node list window setup #---------------------------------- -toplevel .nodelist -frame .nodelist.freenodes -frame .nodelist.usednodes -frame .nodelist.freevectors -frame .nodelist.usedvectors -listbox .nodelist.freenodes.list \ - -yscrollcommand {.nodelist.freenodes.sbar set} -scrollbar .nodelist.freenodes.sbar -width 10 -orient vertical \ - -command {.nodelist.freenodes.list yview} -listbox .nodelist.usednodes.list \ - -yscrollcommand {.nodelist.usednodes.sbar set} -scrollbar .nodelist.usednodes.sbar -width 10 -orient vertical \ - -command {.nodelist.usednodes.list yview} -listbox .nodelist.freevectors.list \ - -yscrollcommand {.nodelist.freevectors.sbar set} -scrollbar .nodelist.freevectors.sbar -width 10 -orient vertical \ - -command {.nodelist.freevectors.list yview} -listbox .nodelist.usedvectors.list \ - -yscrollcommand {.nodelist.usedvectors.sbar set} -scrollbar .nodelist.usedvectors.sbar -width 10 -orient vertical \ - -command {.nodelist.usedvectors.list yview} -label .nodelist.freenodes.title -text "Nodes" -label .nodelist.usednodes.title -text "Nodes in Analyzer" -label .nodelist.freevectors.title -text "Vectors" -label .nodelist.usedvectors.title -text "Vectors in Analyzer" - -pack .nodelist.freenodes.title -side top -pack .nodelist.freenodes.list -side left -expand true -fill both -pack .nodelist.freenodes.sbar -side right -fill y -pack .nodelist.usednodes.title -side top -pack .nodelist.usednodes.list -side left -expand true -fill both -pack .nodelist.usednodes.sbar -side right -fill y -pack .nodelist.freevectors.title -side top -pack .nodelist.freevectors.list -side left -expand true -fill both -pack .nodelist.freevectors.sbar -side right -fill y -pack .nodelist.usedvectors.title -side top -pack .nodelist.usedvectors.list -side left -expand true -fill both -pack .nodelist.usedvectors.sbar -side right -fill y - -label .nodelist.title -text "IRSIM node and vector lists" -frame .nodelist.bbar -button .nodelist.bbar.close -text "Close" -command {wm withdraw .nodelist} -pack .nodelist.bbar.close -side bottom -padx 5 -pady 5 - -grid .nodelist.title -row 0 -column 0 -columnspan 2 -sticky news -grid .nodelist.freenodes -row 1 -column 0 -sticky news -grid .nodelist.usednodes -row 1 -column 1 -sticky news -grid .nodelist.freevectors -row 2 -column 0 -sticky news -grid .nodelist.usedvectors -row 2 -column 1 -sticky news -grid .nodelist.bbar -row 3 -column 0 -columnspan 2 -sticky news - -grid columnconfigure .nodelist 0 -weight 1 -grid columnconfigure .nodelist 1 -weight 1 -grid rowconfigure .nodelist 1 -weight 1 -grid rowconfigure .nodelist 2 -weight 1 - -bind .nodelist.freenodes.list {irsim::pushnode %y} -bind .nodelist.usednodes.list {irsim::popnode %y} -bind .nodelist.freevectors.list {irsim::pushvector %y} -bind .nodelist.usedvectors.list {irsim::popvector %y} - proc irsim::pushnode {y} { set p_idx [.nodelist.freenodes.list nearest $y] set p_key [.nodelist.freenodes.list get $p_idx] @@ -831,9 +859,8 @@ proc irsim::popvector {y} { trace remove $p_key } -wm withdraw .nodelist - proc irsim::update_nodelist {{state {}}} { + if {![irsim::gui_ready]} return if {$state != "force"} { if {[wm state .nodelist] == "withdrawn"} {return} } @@ -874,21 +901,8 @@ proc irsim::update_nodelist {{state {}}} { # User prompt window setup #---------------------------------- -toplevel .irsimprompt -label .irsimprompt.message -anchor w -pack .irsimprompt.message -side top -expand true -fill x -padx 10 -pady 5 -entry .irsimprompt.entry -width 40 -background white -pack .irsimprompt.entry -side top -padx 10 -frame .irsimprompt.buttons -button .irsimprompt.buttons.cancel -text "Cancel" -command {wm withdraw .irsimprompt} -button .irsimprompt.buttons.okay -text "Okay" -pack .irsimprompt.buttons.cancel -side left -pack .irsimprompt.buttons.okay -side right -pack .irsimprompt.buttons -side bottom -expand true -fill x -padx 10 -pady 5 -bind .irsimprompt.entry {.irsimprompt.buttons.okay invoke} -wm withdraw .irsimprompt - proc GetUserInput {prompt_text default_value action_proc args} { + irsim::build_gui .irsimprompt.message configure -text $prompt_text .irsimprompt.entry delete 0 end .irsimprompt.entry insert 0 $default_value @@ -1067,13 +1081,13 @@ if { $UsingMagic } { } else { # If magic is not active, the command "watchnode" calls "analyzer". - proc watchnode {args} {wm deiconify .analyzer; update idletasks; analyzer $args} + proc watchnode {args} {irsim::build_gui; wm deiconify .analyzer; update idletasks; analyzer $args} # The command "watchtime" is meaningless w/o magic, but if it's called, # then it is assumed that the analyzer window is expected to pop up. - proc watchtime {args} {wm deiconify .analyzer; update idletasks; analyzer} + proc watchtime {args} {irsim::build_gui; wm deiconify .analyzer; update idletasks; analyzer} - if {[string range [wm title .] 0 3] == "wish"} { + if {[llength [info commands wm]] && [string range [wm title .] 0 3] == "wish"} { wm withdraw . } diff --git a/tcltk/irsimexec.c b/tcltk/irsimexec.c index 2bc805a..165b333 100644 --- a/tcltk/irsimexec.c +++ b/tcltk/irsimexec.c @@ -5,8 +5,11 @@ /* This file mainly lifted from the main application routine for */ /* "wish" from the Tk distribution. */ /* */ -/* This is a compact re-write of the "wish" executable that calls */ -/* Tk_MainEx with application-specific processing. Specifically, */ +/* This is a compact re-write of the "tclsh" executable that calls */ +/* Tcl_Main with application-specific processing. Specifically, */ +/* Tk is NOT initialized here; it loads lazily via "package require */ +/* Tk" only when a GUI feature (the analyzer) is first used, so that */ +/* -noconsole mode runs headless with no DISPLAY. */ /* "wish" doesn't allow the startup script (~/.wishrc) to be renamed. */ /* However, for irsim running as an extension of Tcl, we want to source */ /* the irsim.tcl file instead of ~/.wishrc. So, all this file really */ @@ -50,10 +53,11 @@ irsim_AppInit(interp) if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } - if (Tk_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); + /* Register Tk as a statically-linked package, but with a NULL */ + /* interp so it is NOT marked already-loaded. This lets a later */ + /* "load {} Tk" actually run Tk_Init on demand (the analyzer), */ + /* instead of being skipped as already present. */ + Tcl_StaticPackage(NULL, "Tk", Tk_Init, Tk_SafeInit); /* This is where we replace the home ".wishrc" file with */ /* irsim's startup script. */ @@ -71,7 +75,7 @@ main(argc, argv) int argc; char **argv; { - Tk_Main(argc, argv, irsim_AppInit); + Tcl_Main(argc, argv, irsim_AppInit); return 0; } diff --git a/tcltk/tclirsim.c b/tcltk/tclirsim.c index 70e17ef..2a5140d 100644 --- a/tcltk/tclirsim.c +++ b/tcltk/tclirsim.c @@ -9,6 +9,7 @@ #include #include #include +#include #include /* Ctrl-C interrupt handling */ #include diff --git a/tcltk/tkAnalyzer.c b/tcltk/tkAnalyzer.c index 7fe264b..db9e203 100644 --- a/tcltk/tkAnalyzer.c +++ b/tcltk/tkAnalyzer.c @@ -11,6 +11,7 @@ #include #include +#include /* for offsetof() */ #ifdef LINUX #include /* for strncmp() */ @@ -18,6 +19,11 @@ #include +/* Tcl version 9 compatibility */ +#if TCL_MAJOR_VERSION < 9 +typedef int Tcl_Size; +#endif + #include "ana.h" #include "ana_glob.h" #include "rsim.h" @@ -29,8 +35,11 @@ #endif #endif -/* Internal routine used---need to find an alternative! */ +/* Tk 9 exposes the formerly-internal TkpUseWindow as the public Tk_UseWindow. */ +#if TK_MAJOR_VERSION < 9 extern int TkpUseWindow(); +#define Tk_UseWindow TkpUseWindow +#endif /* * A data structure of the following type is kept for each @@ -75,19 +84,19 @@ typedef struct { static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_COLOR, "-background", "background", "Background", - "Black", Tk_Offset(TkAnalyzer, background), 0}, + "Black", offsetof(TkAnalyzer, background), 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, {TK_CONFIG_PIXELS, "-height", "height", "Height", - "0", Tk_Offset(TkAnalyzer, height), 0}, + "0", offsetof(TkAnalyzer, height), 0}, {TK_CONFIG_PIXELS, "-width", "width", "Width", - "0", Tk_Offset(TkAnalyzer, width), 0}, + "0", offsetof(TkAnalyzer, width), 0}, {TK_CONFIG_STRING, "-use", "use", "Use", - "", Tk_Offset(TkAnalyzer, useThis), TK_CONFIG_NULL_OK}, + "", offsetof(TkAnalyzer, useThis), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-exitproc", "exitproc", "ExitProc", - "", Tk_Offset(TkAnalyzer, exitProc), TK_CONFIG_NULL_OK}, + "", offsetof(TkAnalyzer, exitProc), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-data", "data", "Data", - "", Tk_Offset(TkAnalyzer, mydata), TK_CONFIG_NULL_OK}, + "", offsetof(TkAnalyzer, mydata), TK_CONFIG_NULL_OK}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; @@ -96,16 +105,15 @@ static Tk_ConfigSpec configSpecs[] = { * Forward declarations for procedures defined later in this file: */ -static int ConfigureTkAnalyzer _ANSI_ARGS_((Tcl_Interp *interp, +static int ConfigureTkAnalyzer(Tcl_Interp *interp, TkAnalyzer *analyzerPtr, int objc, Tcl_Obj *const objv[], - int flags)); -static void DestroyTkAnalyzer _ANSI_ARGS_((char *memPtr)); -static void TkAnalyzerCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static void TkAnalyzerEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int AnalyzerWidgetObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])); + int flags); +static void DestroyTkAnalyzer(char *memPtr); +static void TkAnalyzerCmdDeletedProc(ClientData clientData); +static void TkAnalyzerEventProc(ClientData clientData, + XEvent *eventPtr); +static int AnalyzerWidgetObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* @@ -134,12 +142,17 @@ TkAnalyzerObjCmd(clientData, interp, objc, objv) int objc; /* Number of arguments. */ Tcl_Obj *const objv[]; /* Argument objects. */ { - Tk_Window tkwin = (Tk_Window) clientData; + /* Fetch the main window live rather than from clientData: the */ + /* "tkanalyzer" command is registered at extension load time, which */ + /* (with lazy Tk init) can precede Tk_Init, so the clientData main */ + /* window may have been NULL. By the time a widget is created, Tk */ + /* is loaded and Tk_MainWindow() is valid. */ + Tk_Window tkwin = Tk_MainWindow(interp); TkAnalyzer *analyzerPtr; - Tk_Window new; + Tk_Window new = NULL; char *arg, *useOption; int i, c; - size_t length; + Tcl_Size length; unsigned int mask; if (objc < 2) { @@ -156,7 +169,7 @@ TkAnalyzerObjCmd(clientData, interp, objc, objv) useOption = NULL; for (i = 2; i < objc; i += 2) { - arg = Tcl_GetStringFromObj(objv[i], (int *) &length); + arg = Tcl_GetStringFromObj(objv[i], &length); if (length < 2) { continue; } @@ -182,7 +195,7 @@ TkAnalyzerObjCmd(clientData, interp, objc, objv) useOption = (char *)Tk_GetOption(new, "use", "Use"); } if (useOption != NULL) { - if (TkpUseWindow(interp, new, useOption) != TCL_OK) { + if (Tk_UseWindow(interp, new, useOption) != TCL_OK) { goto error; } } @@ -266,7 +279,7 @@ AnalyzerWidgetObjCmd(clientData, interp, objc, objv) register TkAnalyzer *analyzerPtr = (TkAnalyzer *) clientData; int result = TCL_OK, idx; int c, i; - size_t length; + Tcl_Size length; Tcl_Obj *robj; if (objc < 2) { @@ -305,7 +318,7 @@ AnalyzerWidgetObjCmd(clientData, interp, objc, objv) (char *) analyzerPtr, Tcl_GetString(objv[2]), 0); } else { for (i = 2; i < objc; i++) { - char *arg = Tcl_GetStringFromObj(objv[i], (int *) &length); + char *arg = Tcl_GetStringFromObj(objv[i], &length); if (length < 2) { continue; } @@ -412,7 +425,13 @@ ConfigureTkAnalyzer(interp, analyzerPtr, objc, objv, flags) int flags; /* Flags to pass to Tk_ConfigureWidget. */ { if (Tk_ConfigureWidget(interp, analyzerPtr->tkwin, configSpecs, - objc, (const char **) objv, (char *) analyzerPtr, + objc, +#if TK_MAJOR_VERSION < 9 + (const char **) objv, +#else + objv, +#endif + (char *) analyzerPtr, flags | TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -476,7 +495,8 @@ TkAnalyzerEventProc(clientData, eventPtr) analyzerPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(analyzerPtr->interp, analyzerPtr->widgetCmd); } - Tcl_EventuallyFree((ClientData) analyzerPtr, DestroyTkAnalyzer); + Tcl_EventuallyFree((ClientData) analyzerPtr, + (Tcl_FreeProc *) DestroyTkAnalyzer); analyzerON = FALSE; break; diff --git a/tcltk/tkcon.tcl b/tcltk/tkcon.tcl index 36c7cf6..b0744e8 100755 --- a/tcltk/tkcon.tcl +++ b/tcltk/tkcon.tcl @@ -60,18 +60,6 @@ foreach pkg [info loaded {}] { } catch {unset pkg file name version} -# Tk 8.4 makes previously exposed stuff private. -# FIX: Update tkcon to not rely on the private Tk code. -# -if {![llength [info globals tkPriv]]} { - ::tk::unsupported::ExposePrivateVariable tkPriv -} -foreach cmd {SetCursor UpDownLine Transpose ScrollPages} { - if {![llength [info commands tkText$cmd]]} { - ::tk::unsupported::ExposePrivateCommand tkText$cmd - } -} - # Initialize the ::tkcon namespace # namespace eval ::tkcon { @@ -746,7 +734,7 @@ proc ::tkcon::EvalCmd {w cmd} { $w tag bind $tag \ [list $w tag configure $tag -underline 0] $w tag bind $tag \ - "if {!\[info exists tkPriv(mouseMoved)\] || !\$tkPriv(mouseMoved)} \ + "if {!\[info exists ::tk::Priv(mouseMoved)\] || !\$::tk::Priv(mouseMoved)} \ {[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}" } else { $w insert output $res\n stderr @@ -2475,7 +2463,7 @@ proc ::tkcon::ErrorHighlight w { $w tag configure $tag -foreground $COLOR(stdout) $w tag bind $tag [list $w tag configure $tag -underline 1] $w tag bind $tag [list $w tag configure $tag -underline 0] - $w tag bind $tag "if {!\$tkPriv(mouseMoved)} \ + $w tag bind $tag "if {!\$::tk::Priv(mouseMoved)} \ {[list edit -attach $app -type proc -find $what -- $cmd]}" } set info [string range $info $c1 end] @@ -2504,7 +2492,7 @@ proc ::tkcon::ErrorHighlight w { $w tag configure $tag -foreground $COLOR(proc) $w tag bind $tag [list $w tag configure $tag -underline 1] $w tag bind $tag [list $w tag configure $tag -underline 0] - $w tag bind $tag "if {!\$tkPriv(mouseMoved)} \ + $w tag bind $tag "if {!\$::tk::Priv(mouseMoved)} \ {[list edit -attach $app -type proc -- $cmd]}" } } @@ -4156,7 +4144,7 @@ proc ::tkcon::Bindings {} { global tcl_platform tk_version #----------------------------------------------------------------------- - # Elements of tkPriv that are used in this file: + # Elements of ::tk::Priv that are used in this file: # # char - Character position on the line; kept in order # to allow moving up or down past short lines while @@ -4392,9 +4380,9 @@ proc ::tkcon::Bindings {} { bind TkConsole { if {[%W compare {limit linestart} == {insert linestart}]} { - tkTextSetCursor %W limit + tk::TextSetCursor %W limit } else { - tkTextSetCursor %W {insert linestart} + tk::TextSetCursor %W {insert linestart} } } bind TkConsole [bind TkConsole ] @@ -4418,14 +4406,14 @@ proc ::tkcon::Bindings {} { } bind TkConsole <> { if {[%W compare {insert linestart} != {limit linestart}]} { - tkTextSetCursor %W [tkTextUpDownLine %W -1] + tk::TextSetCursor %W [tk::TextUpDownLine %W -1] } else { ::tkcon::Event -1 } } bind TkConsole <> { if {[%W compare {insert linestart} != {end-1c linestart}]} { - tkTextSetCursor %W [tkTextUpDownLine %W 1] + tk::TextSetCursor %W [tk::TextUpDownLine %W 1] } else { ::tkcon::Event 1 } @@ -4440,7 +4428,7 @@ proc ::tkcon::Bindings {} { } bind TkConsole <> { ## Transpose current and previous chars - if {[%W compare insert > "limit+1c"]} { tkTextTranspose %W } + if {[%W compare insert > "limit+1c"]} { tk::TextTranspose %W } } bind TkConsole <> { ## Clear command line (Unix shell staple) @@ -4458,10 +4446,10 @@ proc ::tkcon::Bindings {} { ::tkcon::Insert %W $::tkcon::PRIV(tmp) %W see end } - catch {bind TkConsole { tkTextScrollPages %W -1 }} - catch {bind TkConsole { tkTextScrollPages %W -1 }} - catch {bind TkConsole { tkTextScrollPages %W 1 }} - catch {bind TkConsole { tkTextScrollPages %W 1 }} + catch {bind TkConsole { tk::TextScrollPages %W -1 }} + catch {bind TkConsole { tk::TextScrollPages %W -1 }} + catch {bind TkConsole { tk::TextScrollPages %W 1 }} + catch {bind TkConsole { tk::TextScrollPages %W 1 }} bind TkConsole <$PRIV(meta)-d> { if {[%W compare insert >= limit]} { %W delete insert {insert wordend} @@ -4479,7 +4467,7 @@ proc ::tkcon::Bindings {} { } bind TkConsole { if { - (!$tkPriv(mouseMoved) || $tk_strictMotif) && + (!$::tk::Priv(mouseMoved) || $tk_strictMotif) && ![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)] } { if {[%W compare @%x,%y < limit]} {