This file contains the code for most of the examples in the book "Tcl and the Tk Toolkit". It follows the order of the book, chapter by chapter. Chapter 1: ---------- set a 44 set a 44 55 Chapter 2: ---------- expr 2 + 2 expr 3 << 2 expr 14.1*6 expr (3 > 4) || (6 <= 7) button .b -text "Hello, world!" -command exit pack .b #!/usr/local/bin/wish -f button .b -text "Hello, world!" -command exit pack .b source hello #!/usr/local/bin/wish -f button .b -text "Hello, world!" -command "puts Good-bye!; exit" pack .b destroy .b source hello set a 44 expr $a*4 set a 44 set b [expr $a*4] set x \$a set newline \n proc power {base p} { set result 1 while {$p>0} { set result [expr $result*$base] set p [expr $p-1] } return $result } power 2 6 power 1.15 5 while (p>0) { result *= base; p -= 1; } while {$p>0} { set result [expr $result*$base] set p [expr $p-1] } set {$p>0} { set result [expr $result*$base] set p [expr $p-1] } #!/usr/local/bin/wish -f proc power {base p} { set result 1 while {$p>0} { set result [expr $result*$base] set p [expr $p-1] } return $result } entry .base -width 6 -relief sunken -textvariable base label .label1 -text "to the power" entry .power -width 6 -relief sunken -textvariable power label .label2 -text "is" label .result -textvariable result pack .base .label1 .power .label2 .result -side left \ -padx 1m -pady 2m bind .base {set result [power $base $power]} bind .power {set result [power $base $power]} bind . {puts "pointer at %x,%y"} exec grep #include tk.h #!/usr/local/bin/wish -f set id 0 entry .entry -width 30 -relief sunken -textvariable cmd pack .entry -padx 1m -pady 1m bind .entry { set id [expr $id + 1] if {$id > 5} { destroy .b[expr $id - 5] } button .b$id -command "exec <@stdin >@stdout $cmd" \ -text $cmd pack .b$id -fill x .b$id invoke .entry delete 0 end } .entry configure -background yellow .b1 configure -foreground brown .b1 flash Chapter 3: ---------- set a 24 set b 15 set a 24; set b 15 set a 122 expr 24/3.2 eval {set a 122} lindex {red green blue purple} 2 string length abracadabra button .b -text Hello -fg red x = 4; y = x+10; set x 4 set y x+10 set x 4 set y [expr $x+10] set kgrams 20 expr $kgrams*2.2046 expr $result*$base foreach num {1 2 3 4 5} { button .b$num } set kgrams 20 set lbs [expr $kgrams*2.2046] set msg Eggs:\ \$2.18/dozen\nGasoline:\ \$1.49/gallon pack .base .label1 .power .label2 .result \ -side left -padx 1m -pady 2m set msg "Eggs: \$2.18/dozen\nGasoline: \$1.49/gallon" set msg "Eggs: \$2.18/dozen Gasoline: \$1.49/gallon" set a 2.1 set msg "a is $a; the square of a is [expr $a*$a]" set name a.out set msg "Couldn`t open file \"$name\"" set msg {Eggs: $2.18/dozen Gasoline: $1.49/gallon} set msg {Eggs: $2.18/dozen\nGasoline: $1.49/gallon} proc occur {value list} { set count 0 foreach el $list { if $el==$value { incr count } } return $count } occur 18 {1 34 18 16 18 72 1994 -3} # This is a comment set a 100 # Not a comment set b 101 ;# This is a comment set state West Virginia expr 3 * (20+4 set x [format {Earnings for July: $%.2f} $earnings] set city "Los Angeles" set bigCity $city exec rm [glob *.o] eval exec rm [glob *.o] Chapter 4: ---------- set a {Four score and seven years ago} set a set a 12.6 set earnings(January) 87966 set earnings(February) 95400 set earnings(January) expr $a+2 set yearTotal 0 foreach month {Jan Feb Mar Apr May Jun Jul Aug Sep \ Oct Nov Dec} { set yearTotal [expr $yearTotal+$earnings($month)] } .canvas configure -width ${size}m unset a earnings(January) b set matrix(1,1) 140 set matrix(1,2) 218 set matrix(1,3) 84 set i 1 set j 2 set cell $matrix($i,$j) set matrix(1, 1) 140 set x 43 incr x 12 set x 43 incr x set msg "" foreach i {1 2 3 4 5} { append msg "$i squared is [expr $i*$i]\n" } set msg append x $piece set x "$x$piece" #!/usr/local/bin/tclsh puts "The command name is \"$argv0\"" puts "There were $argc arguments: $argv" Chapter 5: ---------- expr (8+4) * 6.2 if $x<2 {set x 2} expr 8&&2 expr 8&2 expr {($a < $b) ? $a : $b} expr 2*sin($x) expr hypot($x, $y) + $z expr 2*sin($x) expr {2*sin($x)} set pow 1 while {$pow < $num} { set pow [expr $pow*2] } set x 0 set y 00 if {$x == $y} { ... } expr 1.11111111 + 1.11111111 set tcl_precision 12 expr 1.11111111 + 1.11111111 Chapter 6: ---------- lindex {John Anne Mary Jim} 1 set x {John Anne Mary Jim} lindex {a b {c d e} f} 2 concat {a b c} {d e} f {g h i} set x {a b c} set y {d e} set z [concat $x $y] set z "$x $y" llength {{a b c} {d e} f {g h i}} llength a llength {} set x {a b {c d} e} linsert $x 2 X Y Z linsert $x 0 {X Y} Z lreplace {a b {c d} e} 3 3 lreplace {a b {c d} e} 1 2 {W X} Y Z set x {a b {c d} e} lrange $x 1 3 lrange $x 0 1 set x {a b {c d} e} lappend x XX {YY ZZ} set x lappend x $a $b $c set x "$x [list $a $b $c]" set x {John Anne Mary Jim} lsearch $x Mary lsearch $x Phil lsearch -glob $x A* lsort {John Anne Mary Jim} lsort -decreasing {John Anne Mary Jim} lsort {10 1 2} lsort -integer {10 1 2} set x a/b/c set y /usr/include/sys/types.h split $x / split $y / split xbaybz ab split {a b c} {} join {{} usr include sys types.h} / set x {24 112 5} expr [join $x +] button .b -text "Reset" -command {set x 0} button .b -text "Reset" -command {set x $initValue} button .b -text "Reset" -command "set x $initValue" button .b -text "Reset" -command [list set x $initValue] set x {New York} set initValue {Earnings: $1410.13} list set x $initValue set initValue "{ \\" list set x $initValue Chapter 7: ---------- if {$x < 0} { set x 0 } if {$x < 0} { ... } elseif {$x == 0} { ... } elseif {$x == 1} { ... } else { ... } if {$x < 0} { set x 0 } set b "" set i [expr [llength $a]-1] while {$i >= 0} { lappend b [lindex $a $i] incr i -1 } set b "" for {set i [expr [llength $a]-1]} {$i >= 0} {incr i -1} { lappend b [lindex $a $i] } set b "" foreach i $a { set b [linsert $b 0 $i] } set b "" foreach i $a { if {$i == "ZZZ"} break set b [linsert $b 0 $i] } set b "" foreach i $a { if {$i == "ZZZ"} continue set b [linsert $b 0 $i] } switch $x {a {incr t1} b {incr t2} c {incr t3}} switch $x a {incr t1} b {incr t2} c {incr t3} switch $x { a {incr t1} b {incr t2} c {incr t3} } switch $x \ a {incr t1} \ b {incr t2} \ c {incr t3} set t1 0 set t2 0 set t3 0 foreach i $x { switch -regexp $i { a {incr t1} ^[0-9]*$ {incr t2} default {incr t3} } } switch $x { a - b - c {incr t1} d {incr t2} } set cmd "set a 0" ... eval $cmd set vars {a b c d} foreach i $vars { unset $i } set vars {a b c d} unset $vars set vars {a b c d} eval unset $vars eval unset $vars eval [concat unset $vars] source init.tcl Chapter 8: ---------- proc plus {a b} {expr $a+$b} plus 3 4 plus 3 -1 plus 1 proc fac x { if {$x <= 1} { return 1 } expr $x * [fac [expr $x-1]] } fac 4 fac 0 global x y proc printVars {} { global a b puts "a is $a, b is $b" } proc inc {value {increment 1}} { expr $value+$increment } inc 42 3 inc 42 proc sum args { set s 0 foreach i $args { incr s $i } return $s } sum 1 2 3 4 5 sum proc parray name { upvar $name a foreach el [lsort [array names a]] { puts "$el = $a($el)" } } set info(age) 37 set info(position) "Vice President" parray info upvar #0 other x upvar -2 other x proc do {varName first last body} { upvar $varName v for {set v $first} {$v <= $last} {incr v} { uplevel $body } } set v {} do i 1 5 { lappend v [expr $i*$i] } set v Chapter 9: ---------- set list {44 16 123 98 57} set sum 0 foreach el $list { set sum [expr $sum+$element] } if {($x < 0) || ($x > 100)} { error "x is out of range ($x)" } unset x catch {unset x} catch {unset x} msg set msg catch {return "all done"} string set string return -code return 42 proc do {varName first last body} { global errorInfo errorCode upvar $varName v for {set v $first} {$v <= $last} {incr v} { set code [catch {uplevel $body} string] if {$code == 1} { return -code error -errorinfo $errorInfo \ -errorcode $errorCode $string } elseif {$code == 2} { return -code return $string } else if {$code == 3} { return } else if {$code > 4} { return -code $code $string } } } Chapter 10: ----------- set new {} foreach el $list { if [string match Tcl* $el] { lappend new $el } } ^((0x)?[0-9a-fA-F]+|[0-9]+)$ regexp {^[0-9]+$} 510 regexp {^[0-9]+$} -510 regexp {([0-9]+) *([a-z]+)} "Walk 10 km" a b c regexp {[a-z]} A regexp -nocase {[a-z]} A regexp -indices {([0-9]+) *([a-z]+)} "Walk 10 km" \ a b c regsub there "They live there lives" their x regsub -all a ababa zz x regsub -all a|b axaab && x regsub -all (a+)(ba*) aabaabxab {z\2} x format "The square root of 10 is %.3f" [expr sqrt(10)] set msg [format "%s is %d years old" $name $age] set msg "$name is $age years old" puts "Number Exponential" for {set i 1} {$i <= 10} {incr i} { puts [format "%4d %12.3f" $i [expr exp($i)]] } puts "Integer ASCII" for {set i 95} {$i <= 101} {incr i} { puts [format "%4d %c" $i $i] } scan "16 units, 24.2% margin" "%d units, %f" a b proc next c { scan $c %c i format %c [expr $i+1] } next a next 9 string index "Sample string" 3 string range "Sample string" 3 7 string range "Sample string" 3 end string first th "There is the tub where I bathed today" string last th "There is the tub where I bathed today" string compare Michigan Minnesota string compare Michigan Michigan string length "sample string" string toupper "Watch out!" string tolower "15 Charing Cross Road" string trim aaxxxbab abc Chapter 11: ----------- #!/usr/local/bin/tclsh if {$argc != 2} { error "Usage: tgrep pattern fileName" } set f [open [lindex $argv 1] r] set pat [lindex $argv 0] while {[gets $f line] >= 0} { if [regexp $pat $line] { puts $line } } close $f flush $f seek $f 2000 seek $f -100 end tell $f eof $f glob *.c *.h glob {{src,backup}/*.[ch]} glob {src/*.[ch]} {backup/*.[ch]} glob */ file dirname /a/b/c file dirname main.c file extension src/main.c file rootname src/main.c file rootname foo file tail /a/b/c file tail foo file stat main.c info open bogus set errorCode Chapter 12: ----------- exec rm main.o exec wc /usr/include/stdio.h exec cat << "test data" > foo exec grep #include tclInt.h | wc exec rm *.o exec rm [glob *.o] eval exec rm [glob *.o] exec rm a.o b.o exec sh -c rm *.o set f1 [open {|tbl | ditroff -ms} w] set f2 [open |prog r+] set f [open {| tbl | ditroff -ms} w] pid $f Chapter 13: ----------- set currency(France) franc set "currency(Great Britain)" pound set currency(Germany) mark array size currency array names currency foreach i [array names a] { if {($a($i) == "") || ($a($i) == 0)} { unset a($i) } } set x 24 info exists x unset x info exists x proc test {arg1 arg2} { global global1 set local1 1 set local2 2 puts "info vars is \"[info vars]\"" puts "info globals is \"[info globals]\"" puts "info locals is \"[info locals]\"" puts "info vars *al* is \"[info vars *al*]\"" } proc maybePrint {a b {c 24}} { if {$a < $b} { puts stdout "c is $c" } } info body maybePrint info args maybePrint info default maybePrint a x info default maybePrint c x set x proc printProcs file { set f [open $file w] foreach proc [info procs] { set argList {} foreach arg [info args $proc] { if [info default $proc $arg default] { lappend argList [list $arg $default] } else { lappend argList $arg } } puts $f [list proc $proc $argList \ [info body $proc]] } close $f } proc printStack {} { set level [info level] for {set i 1} {$i < $level} {incr i} { puts "Level $i: [info level $i]" } } time {set a xyz} 10000 trace variable color w pvar trace variable a(length) w pvar proc pvar {name element op} { if {$element != ""} { set name ${name}($element) } upvar $name x puts "Variable $name set to $x" } Variable color set to purple Variable a(length) set to 108 trace variable a w pvar trace variable size w forceInt proc forceInt {name element op} { upvar $name x ${name}_old x_old if ![regexp {^[0-9]*$} $x] { set x $x_old error "value must be a postive integer" } set x_old $x } set size 47 set size red set size trace vdelete color w pvar trace vinfo color foreach cmd {open close read gets puts} { rename $cmd {} } rename exit exit.old proc exit status { application-specific cleanup ... exit.old $status } set x 24 createDatabase library $x unknown createDatabase library 24 proc unknown {name args} { set cmds [info commands $name*] if {[llength $cmds] != 1} { error "unknown command \"$name\"" } uplevel $cmds $args } auto_mkindex . *.tcl set auto_path \ [linsert $auto_path 0 /usr/local/lib/shapes] Chapter 14: ----------- set x 24 set y [expr $x*2.6] incr x history history keep 100 history redo history redo 1 set x "200 illimeters" history substitute ill mill -1 history nextid Chapter 15: ----------- button .b -text "Press me" -foreground red .b configure -foreground blue .b flash .b invoke Chapter 16: ----------- foreach relief {raised sunken flat groove ridge} { frame .$relief -width 15m -height 10m -relief $relief \ -borderwidth 4 pack .$relief -side left -padx 2m -pady 2m } .flat configure -background black label .bitmap -bitmap @$tk_library/demos/bitmaps/flagdown label .label -text "No new mail" pack .bitmap .label proc watch name { toplevel .watch label .watch.label -text "Value of \"$name\": " label .watch.value -textvariable $name pack .watch.label .watch.value -side left } set country Japan watch country set country "Great Britain" button .ok -text OK -command ok button .apply -text Apply -command apply button .cancel -text Cancel -command cancel button .help -text Help -command help pack .ok .apply .cancel .help -side left checkbutton .bold -text Bold -variable bold -anchor w checkbutton .italic -text Italic -variable italic -anchor w checkbutton .underline -text Underline -variable underline \ -anchor w pack .bold .italic .underline -side top -fill x radiobutton .times -text Times -variable font \ -value times -anchor w radiobutton .helvetica -text Helvetica -variable font \ -value helvetica -anchor w radiobutton .courier -text Courier -variable font \ -value courier -anchor w radiobutton .symbol -text Symbol -variable font \ -value symbol -anchor w pack .times .helvetica .courier .symbol -side top -fill x message .msg -width 8c -justify left -relief raised -bd 2 \ -font -Adobe-Helvetica-Medium-R-Normal--*-180-* \ -text "You have made changes to this document\ since the last time it was saved. Is it OK to\ discard the changes?" pack .msg listbox .colors pack .colors set f [open /usr/lib/X11/rgb.txt] while {[gets $f line] >= 0} { .colors insert end [lrange $line 3 end] } close $f bind .colors { .colors configure -background [selection get] } listbox .files -relief raised -borderwidth 2 \ -yscrollcommand ".scroll set" pack .files -side left scrollbar .scroll -command ".files yview" pack .scroll -side right -fill y foreach i [lsort [glob *]] { .files insert end $i } scale .red -label Red -from 0 -to 255 -length 10c \ -orient horizontal -command newColor scale .green -label Green -from 0 -to 255 -length 10c \ -orient horizontal -command newColor scale .blue -label Blue -from 0 -to 255 -length 10c \ -orient horizontal -command newColor frame .sample -height 1.5c -width 6c pack .red .green .blue -side top pack .sample -side bottom -pady 2m proc newColor value { set color [format #%02x%02x%02x [.red get] [.green get] \ [.blue get]] .sample config -background $color } label .label -text "File name:" entry .entry -width 20 -relief sunken -bd 2 -textvariable name pack .label .entry -side left -padx 1m -pady 2m menu .m .m add checkbutton -label Bold -variable bold .m add checkbutton -label Italic -variable italic .m add checkbutton -label Underline -variable underline .m add separator .m add radiobutton -label Times -variable font -value times .m add radiobutton -label Helvetica -variable font \ -value helvetica .m add radiobutton -label Courier -variable font \ -value courier .m add separator .m add command -label "Insert Bullet" -command "insertBullet" .m add command -label "Margins and Tabs..." \ -command "mkMarginPanel" frame .mbar -relief raised -bd 2 frame .dummy -width 10c -height 5c pack .mbar .dummy -side top -fill x menubutton .mbar.file -text File -underline 0 \ -menu .mbar.file.menu menubutton .mbar.edit -text Edit -underline 0 \ -menu .mbar.edit.menu menubutton .mbar.graphics -text Graphics -underline 0 \ -menu .mbar.graphics.menu menubutton .mbar.text -text Text -underline 0 \ -menu .mbar.text.menu menubutton .mbar.view -text View -underline 0 \ -menu .mbar.view.menu menubutton .mbar.help -text Help -underline 0 \ -menu .mbar.help.menu pack .mbar.file .mbar.edit .mbar.graphics .mbar.text \ .mbar.view -side left pack .mbar.help -side right menu .mbar.text.menu .mbar.text.menu add checkbutton -label Bold -variable bold .mbar.text.menu add checkbutton -label Italic -variable italic tk_menuBar .mbar .mbar.file .mbar.edit .mbar.graphics \ .mbar.text .mbar.view .mbar.help focus .mbar frame .mbar -relief raised -bd 2 frame .dummy -width 10c -height 5c pack .mbar .dummy -side top -fill x menubutton .mbar.file -text File -underline 0 \ -menu .mbar.file.menu menubutton .mbar.edit -text Edit -underline 0 \ -menu .mbar.edit.menu menubutton .mbar.graphics -text Graphics -underline 0 \ -menu .mbar.graphics.menu menu .mbar.graphics.menu .mbar.graphics.menu add cascade -label "Line Color" \ -menu .mbar.graphics.menu.color .mbar.graphics.menu add cascade -label "Line Width" \ -menu .mbar.graphics.menu.width menu .mbar.graphics.menu.width .mbar.graphics.menu.width add radiobutton -label "0.25 point" \ -variable lineWidth -value 0.25 menubutton .mbar.text -text Text -underline 0 \ -menu .mbar.text.menu menubutton .mbar.view -text View -underline 0 \ -menu .mbar.view.menu menubutton .mbar.help -text Help -underline 0 \ -menu .mbar.help.menu pack .mbar.file .mbar.edit .mbar.graphics .mbar.text \ .mbar.view -side left pack .mbar.help -side right menu .mbar.text.menu .mbar.text.menu add checkbutton -label Bold -variable bold .mbar.text.menu add checkbutton -label Italic -variable italic tk_menuBar .mbar .mbar.file .mbar.edit .mbar.graphics \ .mbar.text .mbar.view .mbar.help focus .mbar frame .mbar -relief raised -bd 2 frame .dummy -width 10c -height 5c pack .mbar .dummy -side top -fill x menubutton .mbar.file -text File -underline 0 \ -menu .mbar.file.menu menubutton .mbar.edit -text Edit -underline 0 \ -menu .mbar.edit.menu menu .mbar.edit.menu .mbar.edit.menu add command -label "Undo" -underline 0 \ -accelerator "Ctrl+z" -command undo .mbar.edit.menu add command -label "Redo" -underline 0 \ -accelerator "Ctrl+r" -command redo .mbar.edit.menu add command -label "Select All" -underline 7 \ -command allSelect menubutton .mbar.graphics -text Graphics -underline 0 \ -menu .mbar.graphics.menu menubutton .mbar.text -text Text -underline 0 \ -menu .mbar.text.menu menubutton .mbar.view -text View -underline 0 \ -menu .mbar.view.menu menubutton .mbar.help -text Help -underline 0 \ -menu .mbar.help.menu pack .mbar.file .mbar.edit .mbar.graphics .mbar.text \ .mbar.view -side left pack .mbar.help -side right menu .mbar.text.menu .mbar.text.menu add checkbutton -label Bold -variable bold .mbar.text.menu add checkbutton -label Italic -variable italic tk_menuBar .mbar .mbar.file .mbar.edit .mbar.graphics \ .mbar.text .mbar.view .mbar.help focus .mbar .f config -cursor {arrow red white} .f config -cursor {@cursors/bits cursors/mask red white} Chapter 17: ----------- button .ok -text OK button .cancel -text Cancel button .help -text Help pack .ok .cancel .help -side left .cancel configure -text "Cancel Command" pack .ok .cancel .help -side top pack .ok .cancel .help -side left -padx 2m -pady 1m pack .ok .cancel .help -side left -ipadx 2m -ipady 1m pack .ok .cancel .help -side left -padx 2m -pady 2m \ -ipadx 2m -ipady 2m pack .ok .cancel .help -side top -fill x pack .label side top -fill x pack .scrollbar -side right -fill y pack .listbox pack .ok .cancel .help -side left pack .ok .cancel -side left pack .help -side left -expand 1 \ -fill x pack .ok .cancel -side left pack .help -side left -expand 1 pack .ok .cancel .help \ -side left -expand 1 pack .ok .cancel .help -side left \ -expand 1 -fill both pack .ok .cancel .help -side top -anchor w pack .ok .cancel .help -side top -anchor w -padx 2m -pady 1m pack .left -side left -padx 3m -pady 3m pack .right -side right -padx 3m -pady 3m pack .pts8 .pts10 .pts12 .pts18 .pts24 \ -in .left -side top -anchor w pack .bold .italic .underline \ -in .right -side top -anchor w Chapter 18: ----------- bind .entry {.entry delete insert} bind .entry {} bind .entry bind .entry bind Button bind .b {.b config -state active} bind .b {.b config -state normal} bind .entry a {.entry insert insert a} bind .entry {.entry insert insert a} bind . {puts "The keysym is %K"} focus . bind .exit {.status config -text "Exit application"} bind Button {tk_butEnter %W} bind .exit { tk_butEnter %W .status config -text "Exit application" } Chapter 19: ----------- canvas .c pack .c .c create rectangle 1c 2c 4c 4c -width 2m \ -outline blue -fill yellow # ruler: draw a ruler on a canvas canvas .c -width 12c -height 1.5c pack .c .c create line 1c 0.5c 1c 1c 11c 1c 11c 0.5c for {set i 0} {$i < 10} {incr i} { set x [expr $i+1] .c create line ${x}c 1c ${x}c 0.6c .c create line $x.25c 1c $x.25c 0.8c .c create line $x.5c 1c $x.5c 0.7c .c create line $x.75c 1c $x.75c 0.8c .c create text $x.15c .75c -text $i -anchor sw } set circle [.c create oval 1c 1c 2c 2c -fill black \ -outline {}] .c delete $circle .c create oval 1c 1c 2c 2c -fill black -outline {} \ -tags circle .c delete circle .c itemconfigure circle -fill red .c move circle 0 1c .c bind itemOrTag sequence script # graph: simple interactive graph editor canvas .c pack .c proc mkNode {x y} { ;# Create new node at (x,y) global nodeX nodeY edgeFirst edgeSecond set new [.c create oval [expr $x-10] [expr $y-10] \ [expr $x+10] [expr $y+10] -outline black \ -fill white -tags node] set nodeX($new) $x set nodeY($new) $y set edgeFirst($new) {} set edgeSecond($new) {} } proc mkEdge {first second} { ;# Create edge between nodes global nodeX nodeY edgeFirst edgeSecond set edge [.c create line $nodeX($first) $nodeY($first) \ $nodeX($second) $nodeY($second)] .c lower $edge lappend edgeFirst($first) $edge lappend edgeSecond($second) $edge } bind .c {mkNode %x %y} .c bind node { .c itemconfigure current -fill black } .c bind node { .c itemconfigure current -fill white } bind .c 1 {set firstNode [.c find withtag current]} bind .c 2 { set curNode [.c find withtag current] if {($firstNode != "") && ($curNode != "")} { mkEdge $firstNode $curNode } } focus .c proc moveNode {node xDist yDist} { global nodeX nodeY edgeFirst edgeSecond .c move $node $xDist $yDist incr nodeX($node) $xDist incr nodeY($node) $yDist foreach edge $edgeFirst($node) { .c coords $edge $nodeX($node) $nodeY($node) \ [lindex [.c coords $edge] 2] \ [lindex [.c coords $edge] 3] } foreach edge $edgeSecond($node) { .c coords $edge [lindex [.c coords $edge] 0] \ [lindex [.c coords $edge] 1] \ $nodeX($node) $nodeY($node) } } .c bind node { set curX %x set curY %y } .c bind node { moveNode [.c find withtag current] [expr %x-$curX] \ [expr %y-$curY] set curX %x set curY %y } # text: read a file into a text widget text .text -relief raised -bd 2 \ -yscrollcommand ".scroll set" scrollbar .scroll -command ".text yview" pack .scroll -side right -fill y pack .text -side left proc loadFile file { .text delete 1.0 end set f [open $file] while {![eof $f]} { .text insert end [read $f 1000] } close $f } loadFile README .text mark set first 2.3 .text delete insert "insert + 2 chars" proc forAllMatches {w pattern script} { scan [$w index end] %d numLines for {set i 1} {$i < $numLines} {incr i} { $w mark set last $i.0 while {[regexp -indices $pattern \ [$w get last "last lineend"] indices]} { $w mark set first \ "last + [lindex $indices 0] chars" $w mark set last "last + 1 chars \ + [lindex $indices 1] chars" uplevel $script } } } forAllMatches .text Tcl { puts "[.text index first] --> [.text index last]" } forAllMatches .text "the the" { .text delete first "first + 4 chars" } .text tag add x 1.0 1.end .text tag remove x "insert wordstart" "insert wordend" .text tag ranges x forAllMatches .text Tcl { .text tag add big first last } .text tag configure big -background Bisque3 -borderwidth 2 \ -font -Adobe-Helvetica-Medium-R-Normal--*-240-* \ -relief raised .text tag bind big { .text tag configure big -background SeaGreen2 } .text tag bind big { .text tag configure big -background Bisque3 } .text tag bind big { .text delete 1.0 end loadFile /usr/local/src/tcl/tcl7.0/README } Chapter 20: ----------- selection get selection get FILE_NAME selection get LINE proc getSelection {} { set targets [selection get TARGETS] if {[lsearch -exact $targets POSTSCRIPT] >= 0} { return [selection get POSTSCRIPT] } else { return [selection get STRING] } } selection get APPLICATION selection get WINDOW_NAME selection clear . if {[selection own] != ""} { selection clear [selection own] } selection handle .t getFile FILE_NAME proc getFile {offset maxBytes} { global fileName set last [expr $offset+$maxBytes-1] string range $fileName $offset $last } getFile 0 4000 selection handle .a getValue STRING proc getValue {offset maxBytes} { global state set last [expr $offset+$maxBytes-1] string range $state $offset $last } foreach w {.a .b .c} { $w config -command {selection own .a selGone} } proc selGone {} { global state set state {} } Chapter 21: ----------- toplevel .form foreach e {1 2 3 4} { entry .form.e$e .form.e$e insert 0 "Entry $e" } pack .form.e1 .form.e2 .form.e3 .form.e4 set tabList {.form.e1 .form.e2 .form.e3 .form.e4} foreach w $tabList { bind $w {tab $tabList} } proc tab list { set i [lsearch -exact $list [focus]] incr i if {$i >= [llength $list]} { set i 0 } focus [lindex $list $i] } focus default focus default .entry focus default Chapter 22: ----------- wm minsize .w 100 50 wm maxsize .w 400 150 wm minsize .w 1 1 wm minsize .w {} {} wm maxsize .w {} {} wm aspect .w 1 3 4 1 wm geometry .w 300x200 wm geometry .w {} .t configure -setgrid 1 wm geometry . 50x30 wm geometry .w +100+200 wm geometry .w -0-0 wm iconify .w wm iconify .w wm state .w wm title . "Berkeley Introduction" wm protocol . WM_DELETE_WINDOW { puts stdout "I don`t wish to die" } wm transient .w . foreach i {.top2 .top3 .top4} { wm group $i .top1 } wm overrideredirect .popup 1 wm client . sprite.berkeley.edu wm command . {browse /usr/local/bin} Chapter 23: ---------- send tgdb {break tkButton.c 200} winfo name . winfo interps selection get APPLICATION Chapter 24: ----------- grab set .dlg grab release .dlg grab set -global .dlg tkwait window .dlg toplevel .panel button .panel.ok -text OK -command { set label OK destroy .panel } button .panel.cancel -text Cancel -command { set label Cancel destroy .panel } pack .panel.ok -side left pack .panel.cancel -side right grab set .panel tkwait window .panel tkwait visibility .intro tkwait variable x proc waitWindows args { global dead foreach w $args { bind $w "set dead $w" } tkwait variable dead return $dead } Chapter 25: ----------- option add *Button.background Bisque1 option readfile newOptions option get .a.b background Background .button configure -text Quit .button configure -text lindex [.button configure -text] 4 .button configure -bg .button configure Chapter 26: ----------- destroy .dlg1 .dlg2 after 500 after 5000 {puts "Time's up!"} proc blink {w option value1 value2 interval} { $w config $option $value1 after $interval [list blink $w $option \ $value2 $value1 $interval] } blink .b -bg red black 500 update idletasks proc flash {w option value1 value2 interval count} { for {set i 0} {$i < $count} {incr i} { $w config $option $value1 update idletasks after $interval $w config $option $value2 update idletasks after $interval } } winfo exists .w winfo children .menu winfo screenmmheight .dialog winfo class .w raise .w raise .w .x lower .w lower .w .x tk colormodel . monochrome Chapter 27: ----------- proc dialog {w title text bitmap default args} { global button # 1. Create the top-level window and divide it into top # and bottom parts. toplevel $w -class Dialog wm title $w $title wm iconname $w Dialog frame $w.top -relief raised -bd 1 pack $w.top -side top -fill both frame $w.bot -relief raised -bd 1 pack $w.bot -side bottom -fill both # 2. Fill the top part with the bitmap and message. message $w.top.msg -width 3i -text $text\ -font -Adobe-Times-Medium-R-Normal-*-180-* pack $w.top.msg -side right -expand 1 -fill both\ -padx 3m -pady 3m if {$bitmap != ""} { label $w.top.bitmap -bitmap $bitmap pack $w.top.bitmap -side left -padx 3m -pady 3m } # 3. Create a row of buttons at the bottom of the dialog. set i 0 foreach but $args { button $w.bot.button$i -text $but -command\ "set button $i" if {$i == $default} { frame $w.bot.default -relief sunken -bd 1 raise $w.bot.button$i pack $w.bot.default -side left -expand 1\ -padx 3m -pady 2m pack $w.bot.button$i -in $w.bot.default\ -side left -padx 2m -pady 2m\ -ipadx 2m -ipady 1m } else { pack $w.bot.button$i -side left -expand 1\ -padx 3m -pady 3m -ipadx 2m -ipady 1m } incr i } # 4. Set up a binding for , if there`s a default, # set a grab, and claim the focus too. if {$default >= 0} { bind $w "$w.bot.button$default flash; \ set button $default" } set oldFocus [focus] grab set $w focus $w # 5. Wait for the user to respond, then restore the focus # and return the index of the selected button. tkwait variable button destroy $w focus $oldFocus return $button } dialog .d {File Modified} {File "tcl.h" has been modified since\ the last time it was saved. Do you want to save it before\ exiting the application?} warning 0 {Save File} \ {Discard Changes} {Return To Editor} dialog .d {Not Responding} {The file server isn`t responding\ right now; I`ll keep trying.} {} -1 OK #!/usr/local/bin/wish -f # 1. Create basic application structure: menu bar on top of # text widget, scrollbar on right. frame .mBar -relief raised -bd 2 pack .mBar -side top -fill x scrollbar .s -relief flat -command ".t yview" pack .s -side right -fill y text .t -relief raised -bd 2 -yscrollcommand ".s set" \ -setgrid true .t tag configure bold -font \ *-Courier-Bold-R-Normal-*-120-* pack .t -side left -fill both -expand 1 wm title . "Tk Remote Controller" wm iconname . "Tk Remote" wm minsize . 1 1 # 2. Create menu button and menus. menubutton .mBar.file -text File -underline 0\ -menu .mBar.file.m menu .mBar.file.m .mBar.file.m add cascade -label "Select Application" \ -underline 0 -accelerator => -menu .mBar.file.m.apps .mBar.file.m add command -label "Quit" -underline 0 \ -command exit menu .mBar.file.m.apps -postcommand fillAppsMenu pack .mBar.file -side left tk_menuBar .mBar .mBar.file proc fillAppsMenu {} { catch {.mBar.file.m.apps delete 0 last} foreach i [lsort [winfo interps]] { .mBar.file.m.apps add command -label $i \ -command [list newApp $i] } } # 3. Create bindings for text widget to allow commands to # be entered and information to be selected. New characters # can only be added at the end of the text (can't ever move # insertion point). bind .t <1> { set tk_priv(selectMode) char .t mark set anchor @%x,%y if {[lindex [%W config -state] 4] == "normal"} {focus %W} } bind .t { set tk_priv(selectMode) word tk_textSelectTo .t @%x,%y } bind .t { set tk_priv(selectMode) line tk_textSelectTo .t @%x,%y } bind .t {.t insert insert \n; invoke} bind .t backspace bind .t backspace bind .t backspace bind .t { .t insert insert [selection get] .t yview -pickplace insert if [string match *.0 [.t index insert]] { invoke } } # 4. Procedure to backspace over one character, as long as # the character isn't part of the prompt. proc backspace {} { if {[.t index promptEnd] != [.t index {insert - 1 char}]} { .t delete {insert - 1 char} insert .t yview -pickplace insert } } # 5. Procedure that's invoked when return is typed: if # there`s not yet a complete command (e.g. braces are open) # then do nothing. Otherwise, execute command (locally or # remotely), output the result or error message, and issue # a new prompt. proc invoke {} { global app set cmd [.t get {promptEnd + 1 char} insert] if [info complete $cmd] { if {$app == [winfo name .]} { catch [list uplevel #0 $cmd] msg } else { catch [list send $app $cmd] msg } if {$msg != ""} { .t insert insert $msg\n } prompt } .t yview -pickplace insert } proc prompt {} { global app .t insert insert "$app: " .t mark set promptEnd {insert - 1 char} .t tag add bold {insert linestart} promptEnd } # 6. Procedure to select a new application. Also changes # the prompt on the current command line to reflect the new # name. proc newApp appName { global app set app $appName .t delete {promptEnd linestart} promptEnd .t insert promptEnd "$appName:" .t tag add bold {promptEnd linestart} promptEnd } # 7. Miscellaneous initialization. set app [winfo name .] prompt focus .t Chapter 29: ----------- /* simple.c -- Tcl application to evaluate script file. */ #include #include main(int argc, char *argv[]) { Tcl_Interp *interp; int code; if (argc != 2) { fprintf(stderr, "Wrong # arguments: "); fprintf(stderr, "should be \"%s fileName\"\n", argv[0]); exit(1); } interp = Tcl_CreateInterp(); code = Tcl_EvalFile(interp, argv[1]); if (*interp->result != 0) { printf("%s\n", interp->result); } if (code != TCL_OK) { exit(1); } exit(0); } cc simple.c -ltcl -lm a.out test.tcl char cmd[] = "set a 44"; ... code = Tcl_Eval(interp, cmd); code = Tcl_VarEval(interp, "set a ", "44", (char *) NULL); char *script; int code; ... code = Tcl_RecordAndEval(interp, script, 0); char part1[] = "set "; char part2[] = "a "; char part3[] = "44"; Tcl_Eval(interp, part1); Tcl_Eval(interp, part2); Tcl_Eval(interp, part3); code = Tcl_VarEval(interp, part1, part2, part3, (char *) NULL); Tcl_DeleteInterp(interp); Chapter 30: ----------- int EqCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { if (argc != 3) { interp->result = "wrong # args"; return TCL_ERROR; } if (strcmp(argv[1], argv[2]) == 0) { interp->result = "1"; } else { interp->result = "0"; } return TCL_OK; } /* simple2.c -- define new command, then evaluate script. */ #include #include main(int argc, char *argv[]) { Tcl_Interp *interp; int code; if (argc != 2) { fprintf(stderr, "Wrong # arguments: "); fprintf(stderr, "should be \"%s fileName\"\n", argv[0]); exit(1); } interp = Tcl_CreateInterp(); Tcl_CreateCommand(interp, "eq", EqCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); code = Tcl_EvalFile(interp, argv[1]); if (*interp->result != 0) { printf("%s\n", interp->result); } if (code != TCL_OK) { exit(1); } exit(0); } eq abc def eq 1 1 set w .dlg set w2 .dlg.ok eq $w.ok $w2 int NumwordsCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { sprintf(interp->result, "%d", argc); return TCL_OK; } int ConcatCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int i; if (argc == 1) { return TCL_OK; } Tcl_AppendResult(interp, argv[1], (char *) NULL); for (i = 2; i < argc; i++) { Tcl_AppendResult(interp, " ", argv[i], (char *) NULL); } return TCL_OK; } int ListCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) { Tcl_AppendElement(interp, argv[i]); } return TCL_OK; } abc {x y} \} Tcl_CreateCommand(interp, "counter", CounterCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); typedef struct { int value; } Counter; int CounterCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Counter *counterPtr; static int id = 0; if (argc != 1) { interp->result = "wrong # args"; return TCL_ERROR; } counterPtr = (Counter *) malloc(sizeof(Counter)); counterPtr->value = 0; sprintf(interp->result, "ctr%d", id); id++; Tcl_CreateCommand(interp, interp->result, ObjectCmd, (ClientData) counterPtr, DeleteCounter); return TCL_OK; } int ObjectCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Counter *counterPtr = (Counter *) clientData; if (argc != 2) { interp->result = "wrong # args"; return TCL_ERROR; } if (strcmp(argv[1], "get") == 0) { sprintf(interp->result, "%d", counterPtr->value); } else if (strcmp(argv[1], "next") == 0) { counterPtr->value++; } else { Tcl_AppendResult(interp, "bad counter command \"", argv[1], "\": should be get or next", (char *) NULL); return TCL_ERROR; } return TCL_OK; } void DeleteCounter(ClientData clientData) { free((char *) clientData); } counter ctr0 next; ctr0 next; ctr0 get ctr1 get ctr0 clear Tcl_DeleteCommand(interp, "ctr0"); proc inc x {expr $x+1} inc 23 Chapter 31: ----------- int Tcl_AppInit(Tcl_Interp *interp) { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } tcl_RcFileName = "~/.tclshrc"; return TCL_OK; } #include "tcl.h" extern int main(); int *tclDummyMainPtr = (int *) main; int Cmd1Proc(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { ... implementation of cmd1 ... } int Cmd2Proc(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { ... implementation of cmd2 ... } int Tcl_AppInit(Tcl_Interp *interp) { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_CreateCommand(interp, "cmd1", Cmd1Proc, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "cmd2", Cmd2Proc, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); tcl_RcFileName = "~/.myapprc"; return TCL_OK; } cc myAppInit.c -ltk -ltcl -lX11 -lm -o myapp int Rdb_Init(Tcl_Interp *interp) { Tcl_CreateCommand(interp, "rdb_connect", Rdb_ConnectCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "rdb_query", Rdb_QueryCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); ... return Tcl_EvalFile(interp, "/usr/local/lib/rdb/init.tcl"); } int Tcl_AppInit(Tcl_Interp *interp) { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Rdb_Init(interp) == TCL_ERROR) { return TCL_ERROR; } tcl_RcFileName = "~/.myapprc"; return TCL_OK; } typedef struct RdbInfo { int numOpenConnections; ... other state information for interpreter ... } RdbInfo; int Rdb_Init(Tcl_Interp *interp) { RdbInfo *rdbPtr; rdbPtr = (RdbInfo *) malloc(sizeof(RdbInfo)); rdbPtr->numOpenConnections = 0; ... initialize other fields of structure ... Tcl_CreateCommand(interp, "rdb_connect", Rdb_ConnectCmd, (ClientData) rdbPtr, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "rdb_query", Rdb_QueryCmd, (ClientData) rdbPtr, (Tcl_CmdDeleteProc *) NULL); ... register other commands ... return Tcl_EvalFile(interp, "/usr/local/lib/rdb/init.tcl"); } int Rdb_ConnectCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { RdbInfo *rdbPtr; rdbPtr = (RdbInfo *) clientData; ... } ... Chapter 32: ----------- int SumCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int num1, num2; if (argc != 3) { interp->result = "wrong # args"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[1], &num1) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &num2) != TCL_OK) { return TCL_ERROR; } sprintf(interp->result, "%d", num1+num2); return TCL_OK; } sum 2 3 sum 011 0x14 sum 3 6z int ExprCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { if (argc != 2) { interp->result = "wrong # args"; return TCL_ERROR; } return Tcl_ExprString(interp, argv[1]); } int LindexCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int index, listArgc; char **listArgv; if (argc != 3) { interp->result = "wrong # args"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) { return TCL_ERROR; } if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) { return TCL_ERROR; } if ((index >= 0) && (index < listArgc)) { Tcl_SetResult(interp, listArgv[index], TCL_VOLATILE); } free((char *) listArgv); return TCL_OK; } int ListCmd2(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { interp->result = Tcl_Merge(argc-1, argv+1); interp->freeProc = (Tcl_FreeProc *) free; return TCL_OK; } Chapter 33: ----------- int BreakCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { if (argc != 1) { interp->result = "wrong # args"; return TCL_ERROR; } return TCL_BREAK; } int WhileCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int bool; int code; if (argc != 3) { interp->result = "wrong # args"; return TCL_ERROR; } while (1) { Tcl_ResetResult(interp); if (Tcl_ExprBoolean(interp, argv[1], &bool) != TCL_OK) { return TCL_ERROR; } if (bool == 0) { return TCL_OK; } code = Tcl_Eval(interp, argv[2]); if (code == TCL_CONTINUE) { continue; } else if (code == TCL_BREAK) { return TCL_OK; } else if (code != TCL_OK) { return code; } } } break proc badbreak {} {break} badbreak proc longest list { set i [llength $list] while {$i >= 0} { set length [string length [lindex $list $i]] if {$length > $max} { set max $length } incr i -1 } return $max } ... } else if (code != TCL_OK) { if (code == TCL_ERROR) { char msg[50]; sprintf(msg, "\n(\"while\" body line %d)", interp->errorLine); Tcl_AddErrorInfo(interp, msg); } return code; } ... Chapter 34: ----------- int LappendCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int i; char *varValue; if (argc < 3) { interp->result = "wrong # args"; return TCL_ERROR; } for (i = 2; i < argc; i++) { varValue = Tcl_SetVar(interp, argv[1], argv[i], TCL_LIST_ELEMENT|TCL_APPEND_VALUE |TCL_LEAVE_ERR_MSG); if (varValue == NULL) { return TCL_ERROR; } } interp->result = varValue; return TCL_OK; } char *value; ... value = Tcl_GetVar(interp, "a", 0); int IncrCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int value, inc; char *string, *varValue, newValue[20]; if ((argc != 2) && (argc != 3)) { interp->result = "wrong # args"; return TCL_ERROR; } if (argc == 2) { inc = 1; } else if (Tcl_GetInt(interp, argv[2], &inc) != TCL_OK) { return TCL_ERROR; } string = Tcl_GetVar(interp, argv[1], TCL_LEAVE_ERR_MSG); if (string == NULL) { return TCL_ERROR; } if (Tcl_GetInt(interp, string, &value) != TCL_OK) { return TCL_ERROR; } sprintf(newValue, "%d", value + inc); varValue = Tcl_SetVar(interp, argv[1], newValue, TCL_LEAVE_ERR_MSG); if (varValue == NULL) { return TCL_ERROR; } interp->result = varValue; return TCL_OK; } Tcl_UnsetVar(interp, "population(Michigan)", 0); Tcl_UnsetVar2(interp, "population", "Michigan", 0); unset population(Michigan) int value = 32; ... Tcl_LinkVar(interp, "x", (char *) &value, TCL_LINK_INT); set x red Tcl_LinkVar(interp, "x", (char *) &value, TCL_LINK_INT|TCL_LINK_READ_ONLY); Tcl_UnlinkVar(interp, "x"); Tcl_TraceVar(interp, "x", TCL_TRACE_WRITES, WriteProc, (ClientData) NULL); Tcl_UntraceVar(interp, "x", TCL_TRACE_WRITES, WriteProc, (ClientData) NULL); typedef char *Tcl_VarTraceProc(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags); Tcl_TraceVar(interp, "x", TCL_TRACE_WRITES, Print, (ClientData) NULL); ... char *Print(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags) { char *value; value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY); if (value != NULL) { if (name2 == NULL) { printf("new value of %s is %s\n", name1, value); } else { printf("new value of %s(%s) is %s\n", name1, name2, value); } } return NULL; } Tcl_TraceVar(interp, "x", TCL_TRACE_WRITES, Reject, (ClientData) "192"); ... char *Reject(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags) { char *correct = (char *) clientData; Tcl_SetVar2(interp, name1, name2, correct, flags & TCL_GLOBAL_ONLY); return "variable is read-only"; }; ClientData clientData; ... clientData = Tcl_VarTraceInfo(interp, "x", 0, Reject, (ClientData) NULL); ClientData clientData; ... clientData = NULL; while (1) { clientData = Tcl_VarTraceInfo(interp, "x", 0, Reject, clientData); if (clientData == NULL) { break; } ... process trace ... } Chapter 35: ----------- typedef struct Gizmo { ... fields of gizmo object ... } Gizmo; Tcl_HashTable gizmoTable; ... Tcl_InitHashTable(&gizmoTable, TCL_STRING_KEYS); Tcl_DeleteHashTable(&gizmoTable); int GcreateCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { static unsigned int id = 1; int new; Tcl_HashEntry *entryPtr; Gizmo *gizmoPtr; ... check argc, etc ... do { sprintf(interp->result, "gizmo%u", id); id++; entryPtr = Tcl_CreateHashEntry(&gizmoTable, interp->result, &new); } while (!new); gizmoPtr = (Gizmo *) malloc(sizeof(Gizmo)); Tcl_SetHashValue(entryPtr, gizmoPtr); ... initialize *gizmoPtr, etc ... return TCL_OK; } Gizmo *GetGizmo(Tcl_Interp *interp, char *string) { Tcl_HashEntry *entryPtr; entryPtr = Tcl_FindHashEntry(&gizmoTable, string); if (entryPtr == NULL) { Tcl_AppendResult(interp, "no gizmo named \"", string, "\"", (char *) NULL); return NULL; } return (Gizmo *) Tcl_GetHashValue(entryPtr); } int GtwistCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Gizmo *gizmoPtr; ... check argc, etc ... gizmoPtr = GetGizmo(interp, argv[1]); if (gizmoPtr == NULL) { return TCL_ERROR; } ... perform twist operation ... return TCL_OK; } int GsearchCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Tcl_HashEntry *entryPtr; Tcl_HashSearch search; Gizmo *gizmoPtr; ... process arguments to choose search criteria ... for (entryPtr = Tcl_FirstHashEntry(&gizmoTable, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { gizmoPtr = (Gizmo *) Tcl_GetHashValue(entryPtr); if (...object satisfies search criteria...) { Tcl_AppendElement(interp, Tcl_GetHashKey(&gizmoTable, entryPtr)); } } return TCL_OK; } int GdeleteCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Tcl_HashEntry *entryPtr; Gizmo *gizmoPtr; int i; for (i = 1; i < argc; i++) { entryPtr = Tcl_FindHashEntry(&gizmoTable, argv[i]); if (entryPtr == NULL) { continue; } gizmoPtr = (Gizmo *) Tcl_GetHashValue(entryPtr); Tcl_DeleteHashEntry(entryPtr); ... clean up *gizmoPtr ... free((char *) gizmoPtr); } return TCL_OK; } int GstatCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { if (argc != 1) { interp->result = "wrong # args"; return TCL_ERROR; } interp->result = Tcl_HashStats(&gizmoTable); interp->freeProc = (Tcl_FreeProc *) free; return TCL_OK; } Chapter 36: ----------- proc inc x {expr $x+1} map {4 18 16 19 -7} inc proc addz x {return "$x z"} map {a b {a b c}} addz int MapCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Tcl_DString command, newList; int listArgc, i, result; char **listArgv; if (argc != 3) { interp->result = "wrong # args"; return TCL_ERROR; } if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) { return TCL_ERROR; } Tcl_DStringInit(&newList); Tcl_DStringInit(&command); for (i = 0; i < listArgc; i++) { Tcl_DStringAppend(&command, argv[2], -1); Tcl_DStringAppendElement(&command, listArgv[i]); result = Tcl_Eval(interp, Tcl_DStringValue(&command)); Tcl_DStringFree(&command); if (result != TCL_OK) { Tcl_DStringFree(&newList); free((char *) listArgv); return result; } Tcl_DStringAppendElement(&newList, interp->result); } Tcl_DStringResult(interp, &newList); free((char *) listArgv); return TCL_OK; } foreach i {1 2 3 4 5} { puts "$i*$i is [expr $i*$i]" } int DoOneCmd(Tcl_Interp *interp) { char line[200]; Tcl_DString cmd; int code; Tcl_DStringInit(&cmd); while (1) { if (fgets(line, sizeof(line), stdin) == NULL) { break; } Tcl_DStringAppend(&cmd, line, -1); if (Tcl_CommandComplete(Tcl_DStringValue(&cmd))) { break; } } code = Tcl_RecordAndEval(interp, Tcl_DStringValue(&cmd), 0); Tcl_DStringFree(&cmd); return code; } int LsearchCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { int listArgc, i, result; char **listArgv; if (argc != 3) { interp->result = "wrong # args"; return TCL_ERROR; } if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) { return TCL_ERROR; } result = -1; for (i = 0; i < listArgc; i++) { if (Tcl_StringMatch(listArgv[i], argv[2])) { result = i; break; } } sprintf(interp->result, "%d", result); free((char *) listArgv); return TCL_OK; } Chapter 37: ----------- int fd; Tcl_DString buffer; char *fullName; ... fullName = Tcl_TildeSubst(interp, argv[1], &buffer); if (fullName == NULL) { return TCL_ERROR; } fd = open(fullName, ...); Tcl_DStringFree(&buffer); ... FILE *f; ... f = fopen("prolog.ps", "r"); if (f == NULL) { Tcl_AppendResult(interp, "couldn`t open prolog.ps: ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } int Tcl_CreatePipeline(Tcl_Interp *interp, int argc, char *argv[], int **pidPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr) Tcl_DetachPids(int numPids, int *pidPtr); Chapter 38: ----------- proc center {x y} { set a [.s size] .s position [expr $x-($a/2)] [expr $y-($a/2)] } bind .s {center %x %y} bind .s {center %x %y} Chapter 39: ----------- Tk_Window Tk_CreateMainWindow(Tcl_Interp *interp, char *screenName, char *appName, char *className); Tk_Window Tk_CreateWindowFromPath(Tcl_Interp *interp, Tk_Window tkwin, char *pathName, char *screenName); Tk_SetClass(tkwin, "Foo"); Tk_Window Tk_NameToWindow(Tcl_Interp *interp, char *pathName, Tk_Window tkwin); int width; ... width = Tk_Width(tkwin); int SquareCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Tk_Window main = (Tk_Window) clientData; Square *squarePtr; Tk_Window tkwin; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?options?\"", (char *) NULL); return TCL_ERROR; } tkwin = Tk_CreateWindowFromPath(interp, main, argv[1], (char *) NULL); if (tkwin == NULL) { return TCL_ERROR; } Tk_SetClass(tkwin, "Square"); squarePtr = (Square *) malloc(sizeof(Square)); squarePtr->tkwin = tkwin; squarePtr->display = Tk_Display(tkwin); squarePtr->interp = interp; squarePtr->x = squarePtr->y = 0; squarePtr->size = 20; squarePtr->borderWidth = 0; squarePtr->bgBorder = squarePtr->fgBorder = NULL; squarePtr->relief = TK_RELIEF_FLAT; squarePtr->gc = None; squarePtr->updatePending = 0; Tk_CreateEventHandler(tkwin, ExposureMask|StructureNotifyMask, SquareEventProc, (ClientData) squarePtr); Tcl_CreateCommand(interp, Tk_PathName(tkwin), SquareWidgetCmd, (ClientData) squarePtr, (Tcl_CmdDeleteProc *) NULL); if (SquareConfigure(interp, squarePtr, argc-2, argv+2, 0) != TCL_OK) { Tk_DestroyWindow(squarePtr->tkwin); return TCL_ERROR; } interp->result = Tk_PathName(tkwin); return TCL_OK; } typedef struct { Tk_Window tkwin; Display *display; Tcl_Interp *interp; int x, y; int size; int borderWidth; Tk_3DBorder bgBorder; Tk_3DBorder fgBorder; int relief; GC gc; int updatePending; } Square; Chapter 40: ----------- Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_BORDER, "-background", "background", "Background", "#cdb79e", Tk_Offset(Square, bgBorder), TK_CONFIG_COLOR_ONLY, (Tk_CustomOption *) NULL}, {TK_CONFIG_BORDER, "-background", "background", "Background", "white", Tk_Offset(Square, bgBorder), TK_CONFIG_MONO_ONLY, (Tk_CustomOption *) NULL}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, (char *) NULL, 0, 0, (Tk_CustomOption *) NULL}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, (char *) NULL, 0, 0, (Tk_CustomOption *) NULL}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", "0.5m", Tk_Offset(Square, borderWidth), 0, (Tk_CustomOption *) NULL}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, (char *) NULL, 0, 0, (Tk_CustomOption *) NULL}, {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", "#b03060", Tk_Offset(Square, fgBorder), TK_CONFIG_COLOR_ONLY, (Tk_CustomOption *) NULL}, {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", "black", Tk_Offset(Square, fgBorder), TK_CONFIG_MONO_ONLY, (Tk_CustomOption *) NULL}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", "raised", Tk_Offset(Square, relief), 0, (Tk_CustomOption *) NULL}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, (Tk_CustomOption *) NULL} }; Tcl_Interp *interp; Tk_Window tkwin; char *argv[] = {"-relief", "sunken", "-bg", "blue"}; Square *squarePtr; int code; ... code = Tk_ConfigureWidget(interp, tkwin, configSpecs, 4, argv, (char *) squarePtr, 0); code = Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, (char *) squarePtr, TK_CONFIG_ARGV_ONLY); .s configure -background .s configure code = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs, (char *) squarePtr, argv[2], 0); void Tk_FreeOptions(Tk_ConfigSpec *specs, char *widgRec, Display *display, int flags); GC Tk_GetGC(Tk_Window tkwin, unsigned long valueMask, XGCValues *valuePtr); void Tk_FreeGC(Display *display, GC gc); int SquareConfigure(Tcl_Interp *interp, Square *squarePtr, int argc, char *argv[], int flags) { if (Tk_ConfigureWidget(interp, squarePtr->tkwin, configSpecs, argc, argv, (char *) squarePtr, flags) != TCL_OK) { return TCL_ERROR; } Tk_SetWindowBackground(squarePtr->tkwin, Tk_3DBorderColor(squarePtr->bgBorder)->pixel); if (squarePtr->gc == None) { XGCValues gcValues; gcValues.function = GXcopy; gcValues.graphics_exposures = False; squarePtr->gc = Tk_GetGC(squarePtr->tkwin, GCFunction|GCGraphicsExposures, &gcValues); } Tk_GeometryRequest(squarePtr->tkwin, 200, 150); Tk_SetInternalBorder(squarePtr->tkwin, squarePtr->borderWidth); if (!squarePtr->updatePending) { Tk_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); squarePtr->updatePending = 1; } return TCL_OK; } int SquareWidgetCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { Square *squarePtr = (Square *) clientData; int result = TCL_OK; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?\"", (char *) NULL); return TCL_ERROR; } Tk_Preserve((ClientData) squarePtr); if (strcmp(argv[1], "configure") == 0) { if (argc == 2) { result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs, (char *) squarePtr, (char *) NULL, 0); } else if (argc == 3) { result = Tk_ConfigureInfo(interp, squarePtr->tkwin, configSpecs, (char *) squarePtr, argv[2], 0); } else { result = SquareConfigure(interp, squarePtr, argc-2, argv+2, TK_CONFIG_ARGV_ONLY); } } else if (strcmp(argv[1], "position") == 0) { if ((argc != 2) && (argc != 4)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " position ?x y?\"", (char *) NULL); goto error; } if (argc == 4) { if ((Tk_GetPixels(interp, squarePtr->tkwin, argv[2], &squarePtr->x) != TCL_OK) || (Tk_GetPixels(interp, squarePtr->tkwin, argv[3], &squarePtr->y) != TCL_OK)) { goto error; } KeepInWindow(squarePtr); } sprintf(interp->result, "%d %d", squarePtr->x, squarePtr->y); } else if (strcmp(argv[1], "size") == 0) { if ((argc != 2) && (argc != 3)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " size ?amount?\"", (char *) NULL); goto error; } if (argc == 3) { int i; if (Tk_GetPixels(interp, squarePtr->tkwin, argv[2], &i) != TCL_OK) { goto error; } if ((i <= 0) || (i > 100)) { Tcl_AppendResult(interp, "bad size \"", argv[2], "\"", (char *) NULL); goto error; } squarePtr->size = i; KeepInWindow(squarePtr); } sprintf(interp->result, "%d", squarePtr->size); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be configure, position, or size", (char *) NULL); goto error; } if (!squarePtr->updatePending) { Tk_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); squarePtr->updatePending = 1; } Tk_Release((ClientData) squarePtr); return result; error: Tk_Release((ClientData) squarePtr); return TCL_ERROR; } void KeepInWindow(Square *squarePtr) { int gap, bd; bd = 0; if (squarePtr->relief != TK_RELIEF_FLAT) { bd = squarePtr->borderWidth; } gap = (Tk_Width(squarePtr->tkwin) - bd) - (squarePtr->x + squarePtr->size); if (gap < 0) { squarePtr->x += gap; } gap = (Tk_Height(squarePtr->tkwin) - bd) - (squarePtr->y + squarePtr->size); if (gap < 0) { squarePtr->y += gap; } if (squarePtr->x < bd) { squarePtr->x = bd; } if (squarePtr->y < bd) { squarePtr->y = bd; } } Chapter 41: ----------- typedef void Tk_EventProc(ClientData clientData, XEvent *eventPtr); Tk_CreateEventHandler(squarePtr->tkwin, ExposureMask|StructureNotifyMask, SquareEventProc, (ClientData) squarePtr); void SquareEventProc(ClientData clientData, XEvent *eventPtr) { Square *squarePtr = (Square *) clientData; if (eventPtr->type == Expose) { if (!squarePtr->updatePending) { Tk_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); squarePtr->updatePending = 1; } } else if (eventPtr->type == ConfigureNotify) { KeepInWindow(squarePtr); if (!squarePtr->updatePending) { Tk_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); squarePtr->updatePending = 1; } } else if (eventPtr->type == DestroyNotify) { Tcl_DeleteCommand(squarePtr->interp, Tk_PathName(squarePtr->tkwin)); squarePtr->tkwin = NULL; if (squarePtr->updatePending) { Tk_CancelIdleCall(SquareDisplay, (ClientData) squarePtr); } Tk_EventuallyFree((ClientData) squarePtr, SquareDestroy); } } void Tk_DeleteEventHandler(Tk_Window tkwin, unsigned long mask, Tk_EventProc *proc, ClientData clientData); void Tk_CreateFileHandler(int fd, int mask, Tk_FileProc *proc, ClientData clientData); void Tk_DeleteFileHandler(int fd); ... Tcl_DStringInit(&command); Tk_CreateFileHandler(0, TK_READABLE, StdinProc, (ClientData) NULL); ... void StdinProc(ClientData clientData, int mask) { int count, code; char input[1000]; count = read(0, input, 1000); if (count <= 0) { ... handle errors and end of file ... } Tcl_DStringAppend(&command, input, count); if (Tcl_CmdComplete(Tcl_DStringValue(&command)) { code = Tcl_Eval(interp, Tcl_DStringValue(&command)); Tcl_DStringFree(&command); ... } ... } Tk_TimerToken Tk_CreateTimerHandler(int milliseconds, Tk_TimerProc *proc, ClientData clientData); void Tk_TimerProc(ClientData clientData); void Tk_DeleteTimerHandler(Tk_TimerToken token); void Tk_DoWhenIdle(Tk_IdleProc *proc, ClientData clientData); typedef void Tk_IdleProc(ClientData clientData); void Tk_CancelIdleCall(Tk_IdleProc *proc, ClientData clientData); .s configure -foreground purple .s size 2c .s position 1.2c 3.1c if (!squarePtr->updatePending) { Tk_DoWhenIdle(SquareDisplay, (ClientData) squarePtr); squarePtr->updatePending = 1; } void Tk_CreateGenericHandler(Tk_GenericProc *proc, ClientData clientData); typedef int Tk_GenericProc(ClientData clientData, XEvent *eventPtr); Tk_DeleteGenericHandler(Tk_GenericProc *proc, ClientData clientData); int Tk_DoOneEvent(int flags) void Tk_MainLoop(void) { while (tk_NumMainWindows > 0) { Tk_DoOneEvent(0); } } int done; ... Tk_CreateEventHandler(tkwin, StructureNotifyMask, WaitWindowProc, (ClientData) &done); done = 0; while (!done) { Tk_DoOneEvent(0); } ... void WaitWindowProc(ClientData clientData, XEvent *eventPtr) { int *donePtr = (int *) clientData; if (eventPtr->type == DestroyNotify) { *donePtr = 1; } } while (Tk_DoOneEvent(TK_IDLE_EVENTS) != 0) { /* empty loop body */ } Chapter 42: ----------- void SquareDisplay(ClientData clientData) { Square *squarePtr = (Square *) clientData; Tk_Window tkwin = squarePtr->tkwin; Display *display = Tk_Display(tkwin); Pixmap pm; squarePtr->updatePending = 0; if (!Tk_IsMapped(tkwin)) { return; } pm = XCreatePixmap(display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); Tk_Fill3DRectangle(display, pm, squarePtr->bgBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), squarePtr->borderWidth, squarePtr->relief); Tk_Fill3DRectangle(display, pm, squarePtr->fgBorder, squarePtr->x, squarePtr->y, squarePtr->size, squarePtr->size, squarePtr->borderWidth, squarePtr->relief); XCopyArea(display, pm, Tk_WindowId(tkwin), squarePtr->gc, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0); XFreePixmap(Tk_Display(tkwin), pm); } void Tk_Fill3DRectangle(Display *display, Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief); void Tk_Fill3DPolygon(Display *display, Drawable drawable, Tk_3DBorder border, XPoint *pointPtr, int numPoints, int borderWidth, int leftRelief); Chapter 43: ----------- void Tk_DestroyWindow(Tk_Window tkwin); void SquareDestroy(ClientData clientData) { Square *squarePtr = (Square *) clientData; Tk_FreeOptions(configSpecs, (char *) squarePtr, squarePtr->display, 0); if (squarePtr->gc != None) { Tk_FreeGC(squarePtr->display, squarePtr->gc); } free((char *) squarePtr); } void Tk_Preserve(ClientData clientData); void Tk_EventuallyFree(ClientData clientData, Tk_FreeProc *freeProc); Chapter 44: ----------- void Tk_CreateSelHandler(Tk_Window tkwin, Atom target, Tk_SelectionProc *proc, ClientData clientData, Atom format); typedef int Tk_SelectionProc(ClientData clientData, int offset, char *buffer, int maxBytes); Tk_CreateSelHandler(entryPtr->tkwin, XA_STRING, EntryFetchSelection, (ClientData) entryPtr, XA_STRING); int EntryFetchSelection(ClientData clientData, int offset, char *buffer, int maxBytes) { Entry *entryPtr = (Entry *) clientData; int count; if (entryPtr->selectFirst < 0) { return -1; } count = entryPtr->selectLast + 1 - entryPtr->selectFirst - offset; if (count > maxBytes) { count = maxBytes; } if (count <= 0) { count = 0; } else { strncpy(buffer, entryPtr->string + entryPtr->selectFirst + offset, count); } buffer[count] = 0; return count; } void Tk_OwnSelection(Tk_Window tkwin, Tk_LostSelProc *proc, (ClientData) clientData); typedef int Tk_GetSelection(Tcl_Interp *interp, Tk_Window tkwin, Atom target, Tk_GetSelProc *proc, ClientData clientData); typedef int Tk_GetSelProc(ClientData clientData, Tcl_Interp *interp, char *portion); ... if (Tk_GetSelection(interp, tkwin, Tk_InternAtom(tkwin, "STRING"), PrintSel, (ClientData) stdout) != TCL_OK) { ... } ... int PrintSel(ClientData clientData, Tcl_Interp *interp, char *portion) { FILE *f = (FILE *) clientData; fputs(portion, f); return TCL_OK; } Chapter 45: ----------- void Tk_GeometryRequest(Tk_Window tkwin, int width, int height); void Tk_SetGrid(Tk_Window tkwin, int gridWidth, int gridHeight, int widthInc, int heightInc); void Tk_ManageGeometry(Tk_Window tkwin, Tk_GeometryProc *proc, ClientData clientData); typedef void Tk_GeometryProc(ClientData clientData, Tk_Window tkwin); void Tk_MapWindow(Tk_Window tkwin); void Tk_UnmapWindow(Tk_Window tkwin); void Tk_MoveWindow(Tk_Window tkwin, int x, int y); void Tk_ResizeWindow(Tk_Window tkwin, unsigned int width, unsigned int height); void Tk_MoveResizeWindow(Tk_Window tkwin, int x, int y, unsigned int width, unsigned int height); int x, y; Tk_Window slave, master, parent, ancestor; ... for (ancestor = master; ancestor != Tk_Parent(slave); ancestor = Tk_Parent(ancestor)) { x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width; y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width; }