1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
|
# testutils.tcl --
#
# This file is sourced by each test file when invoking "tcltest::loadTestedCommands".
# It implements the testutils mechanism which is used to import utility procs
# into test files that need them.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# DOCUMENTATION FOR TEST AUTHORS AND MAINTAINERS
#
# The testutils mechanism is documented in the separate file "testutils.GUIDE",
# which is placed in the same directory as this file "testutils.tcl".
#
namespace eval ::tk::test {
#
# The namespace ::tk::test itself doesn't contain any procs or variables.
# The contents of this namespace exist solely in child namespaces that
# are defined hereafter.
#
# Each child namespace represents a functional area, also called "domain".
#
}
namespace eval ::tk::test::generic {
proc assert {expr} {
if {! [uplevel 1 [list expr $expr]]} {
return -code error "assertion failed: \"[uplevel 1 [list subst -nocommands $expr]]\""
}
}
# controlPointerWarpTiming --
#
# This proc is intended to ensure that the (mouse) pointer has actually
# been moved to its new position after a Tk test issued:
#
# [event generate $w $event -warp 1 ...]
#
# It takes care of the following timing details of pointer warping:
#
# a. Allow pointer warping to happen if it was scheduled for execution at
# idle time. This happens synchronously if $w refers to the
# whole screen or if the -when option to [event generate] is "now".
#
# b. Work around a race condition associated with OS notification of
# mouse motion on Windows.
#
# When calling [event generate $w $event -warp 1 ...], the following
# sequence occurs:
# - At some point in the processing of this command, either via a
# synchronous execution path, or asynchronously at idle time, Tk calls
# an OS function* to carry out the mouse cursor motion.
# - Tk has previously registered a callback function** with the OS, for
# the OS to call in order to notify Tk when a mouse move is completed.
# - Tk doesn't wait for the callback function to receive the notification
# from the OS, but continues processing. This suits most use cases
# because usually the notification arrives fast enough (within a few tens
# of microseconds). However ...
# - A problem arises if Tk performs some processing, immediately following
# up on [event generate $w $event -warp 1 ...], and that processing
# relies on the mouse pointer having actually moved. If such processing
# happens just before the notification from the OS has been received,
# Tk will be using not yet updated info (e.g. mouse coordinates).
#
# Hickup, choke etc ... !
#
# * the function SendInput() of the Win32 API
# ** the callback function is TkWinChildProc()
#
# This timing issue can be addressed by putting the Tk process on hold
# (do nothing at all) for a somewhat extended amount of time, while
# letting the OS complete its job in the meantime. This is what is
# accomplished by calling [after ms].
#
# ----
# For the history of this issue please refer to Tk ticket [69b48f427e],
# specifically the comment on 2019-10-27 14:24:26.
#
#
# Beware: there are cases, not (yet) exercised by the Tk test suite, where
# [controlPointerWarpTiming] doesn't ensure the new position of the pointer.
# For example, when issued under Tk8.7+, if the value for the -when option
# to [event generate $w] is not "now", and $w refers to a Tk window, i.e. not
# the whole screen.
#
proc controlPointerWarpTiming {{duration 50}} {
update idletasks ;# see a. above
if {[tk windowingsystem] eq "win32"} {
after $duration ;# see b. above
}
}
proc deleteWindows {} {
destroy {*}[winfo children .]
# This update is needed to avoid intermittent failures on macOS in unixEmbed.test
# with the (GitHub Actions) CI runner.
# Reason for the failures is unclear but could have to do with window ids being deleted
# after the destroy command returns. The detailed mechanism of such delayed deletions
# is not understood, but it appears that this update prevents the test failures.
update
}
proc fixfocus {} {
catch {destroy .focus}
toplevel .focus
wm geometry .focus +0+0
entry .focus.e
.focus.e insert 0 "fixfocus"
pack .focus.e
update
focus -force .focus.e
destroy .focus
}
proc loadTkCommand {} {
variable TkLoadCmd
if {! [info exists TkLoadCmd]} {
foreach pkg [info loaded] {
if {[lindex $pkg 1] eq "Tk"} {
set TkLoadCmd [list load {*}$pkg]
break
}
}
}
return $TkLoadCmd
}
# Suspend script execution for a given amount of time, but continue
# processing events.
proc pause {ms} {
variable _pause
set num [incr _pause(count)]
set _pause($num) 1
after $ms [list unset [namespace current]::_pause($num)]
vwait [namespace current]::_pause($num)
}
# On macOS windows are not allowed to overlap the menubar at the top of the
# screen or the dock. So tests which move a window and then check whether it
# got moved to the requested location should use a y coordinate larger than the
# height of the menubar (normally 23 pixels) and an x coordinate larger than the
# width of the dock, if it happens to be on the left.
# The C-level command "testmenubarheight" deals with this issue but it may
# not be available on each platform. Therefore, provide a fallback here.
if {[llength [info commands testmenubarheight]] == 0} {
if {[tk windowingsystem] ne "aqua"} {
# Windows may overlap the menubar
proc testmenubarheight {} {
return 0
}
} else {
# Windows may not overlap the menubar
proc testmenubarheight {} {
return 30 ; # arbitrary value known to be larger than the menubar height
}
}
}
# testutils --
#
# Takes care of exporting/importing/forgetting utility procs and any
# associated variables from a specific test domain (functional area).
#
# More information is available in the file "testutils.GUIDE"
#
# Arguments:
# subCmd : "export", "import" or "forget"
# args : a sequence of domains that need to be imported/forgotten,
# unused for "export"
#
proc testutils {subCmd args} {
variable importedDomains
variable importVars
if {$subCmd ni [list export import forget]} {
return -code error "invalid subCmd \"$subCmd\". Usage: [lindex [info level 0] 0] export|import|forget ?domain domain ...?"
}
set argc [llength $args]
if {$subCmd eq "export"} {
if {$argc != 0} {
return -code error "invalid #args. Usage: [lindex [info level 0] 0] export"
}
# export all procs from the invoking domain namespace except "init"
uplevel 1 {
if {[info procs init] eq "init"} {
set exports [info procs]
namespace export {*}[lremove $exports [lsearch $exports "init"]]
unset exports
} else {
namespace export *
}
}
return
}
if {$argc < 1} {
return -code error "invalid #args. Usage: [lindex [info level 0] 0] import|forget domain ?domain ...?"
}
# determine the requesting namespace
set ns [uplevel 1 {namespace current}]
# import/forget domains
foreach domain $args {
if {! [namespace exists ::tk::test::$domain]} {
return -code error "testutils domain \"$domain\" doesn't exist"
}
switch -- $subCmd {
import {
if {[info exists importedDomains($ns)] && ($domain in $importedDomains($ns))} {
return -code error "testutils domain \"$domain\" was already imported"
} else {
# import procs
if {[catch {
uplevel 1 [list namespace import ::tk::test::${domain}::*]
} errMsg]} {
# revert import of procs already done
uplevel 1 [list namespace forget ::tk::test::${domain}::*]
return -code error "import from testutils domain \"$domain\" failed: $errMsg"
}
# import associated namespace variables declared in the init proc
if {"init" in [namespace inscope ::tk::test::$domain {info procs init}]} {
if {[info exists importVars($ns,$domain)]} {
#
# Note [A1]:
# If test files inadvertently leave behind a variable with the same name
# as an upvar'ed namespace variable, its last value will serve as a new
# initial value in case that the init proc declares that variable without
# a value. Also, the result of "info exists varName" would be different
# between test files.
#
# The next unset prevents such artefacts. See also note [A2] below.
#
uplevel 1 [list unset -nocomplain {*}$importVars($ns,$domain)]
}
::tk::test::${domain}::init
if {($ns ne "::") || (! [info exists importVars($ns,$domain)])} {
#
# Importing associated namespace variables into the global namespace where
# tests are normally executing, needs to be done only once because an upvar
# link cannot be removed from a namespace. For other requesting namespaces
# we need to reckon with deletion and re-creation of the namespace in the
# meantime.
#
if {[info exists importVars($ns,$domain)]} {
set associatedVars $importVars($ns,$domain)
} else {
set associatedVars [namespace inscope ::tk::test::$domain {info vars}]
}
foreach varName $associatedVars {
if {[catch {
uplevel 1 [list upvar #0 ::tk::test::${domain}::$varName $varName]
} errMsg]} {
# revert imported procs and partial variable import
uplevel 1 [list unset -nocomplain {*}$associatedVars]
uplevel 1 [list namespace forget ::tk::test::${domain}::*]
return -code error "import from testutils domain \"$domain\" failed: $errMsg"
}
}
set importVars($ns,$domain) $associatedVars
}
}
# register domain as imported
lappend importedDomains($ns) $domain
}
}
forget {
if {(! [info exists importedDomains($ns)]) || ($domain ni $importedDomains($ns))} {
return -code error "testutils domain \"$domain\" was not imported"
}
# remove imported utility procs from the namespace where tests are executing
uplevel 1 [list namespace forget ::tk::test::${domain}::*]
#
# Some namespace variables are meant to persist across test files
# in the entire Tk test suite (notably the variable ImageNames,
# domain "image"). These variables are also not meant to be accessed
# from, and imported into the namespace where tests are executing,
# and they should not be cleaned up here.
#
if {[info exists importVars($ns,$domain)]} {
#
# Remove imported namespace variables.
#
# Note [A2]:
# The upvar link in the namespace where tests are executing cannot be removed.
# Without specific attention, this can cause surprising behaviour upon
# re-initialization. See also note [A1] above.
#
uplevel 1 [list unset -nocomplain {*}$importVars($ns,$domain)]
}
set importedDomains($ns) [lremove $importedDomains($ns) [lsearch $importedDomains($ns) $domain]]
}
}
}
}
testutils export
}
# Import generic utility procs into the global namespace (in which tests are
# normally executing) as a standard policy.
::tk::test::generic::testutils import generic
namespace eval ::tk::test::button {
proc bogusTrace args {
error "trace aborted"
}
testutils export
}
namespace eval ::tk::test::child {
# childTkInterp --
#
# Create a new Tk application in a child interpreter, with
# a given name and class.
#
proc childTkInterp {name args} {
set index [lsearch $args "-safe"]
if {$index >= 0} {
set safe 1
set options [lremove $args $index]
} else {
set safe 0
set options $args
}
if {[llength $options] ni {0 2}} {
return -code error "invalid #args"
}
set cmdArgs [list -name $name]
foreach {key value} $options {
if {$key ne "-class"} {
return -code error "invalid option \"$key\""
}
lappend cmdArgs $key $value
}
if {$safe} {
interp create -safe $name
} else {
interp create $name
}
$name eval [list set argv $cmdArgs]
catch {eval [loadTkCommand] $name}
}
# childTkProcess --
#
# Create a new Tk application in a child process, and enable it to
# evaluate scripts on our behalf.
#
# Suggestion: replace with child interp or thread ?
#
proc childTkProcess {subcmd args} {
variable fd
switch -- $subcmd {
create {
if {[info exists fd] && [string length $fd]} {
childTkProcess exit
}
set fd [open "|[list [::tcltest::interpreter] \
-geometry +0+0 -name tktest] $args" r+]
puts $fd "puts foo; flush stdout"
flush $fd
if {[gets $fd data] < 0} {
error "unexpected EOF from \"[::tcltest::interpreter]\""
}
if {$data ne "foo"} {
error "unexpected output from\
background process: \"$data\""
}
puts $fd [loadTkCommand]
flush $fd
fileevent $fd readable [namespace code {childTkProcess read}]
}
eval {
variable Data
variable Done
set script [lindex $args 0]
set block 0
if {[llength $args] == 2} {
set block [lindex $args 1]
}
if {$block} {
fileevent $fd readable {}
}
puts $fd "[list catch $script msg]; update; puts \$msg;\
puts **DONE**; flush stdout"
flush $fd
set Data {}
if {$block} {
while {![eof $fd]} {
set line [gets $fd]
if {$line eq "**DONE**"} {
break
}
append Data $line
}
} else {
set Done 0
vwait [namespace which -variable Done]
}
return $Data
}
exit {
# catch in case the child process has closed $fd
catch {puts $fd exit}
catch {close $fd}
set fd ""
}
read {
variable Data
variable Done
set x [gets $fd]
if {[eof $fd]} {
fileevent $fd readable {}
set Done 1
} elseif {$x eq "**DONE**"} {
set Done 1
} else {
append Data $x
}
}
}
}
testutils export
}
namespace eval ::tk::test::colors {
# colorsFree --
#
# Returns 1 if there appear to be free colormap entries in a window, 0
# otherwise.
#
# Arguments:
# w : name of window in which to check.
# red, green, blue : intensities to use in a trial color allocation
# to see if there are colormap entries free.
#
proc colorsFree {w {red 31} {green 245} {blue 192}} {
lassign [winfo rgb $w [format "#%02x%02x%02x" $red $green $blue]] r g b
expr {($r/256 == $red) && ($g/256 == $green) && ($b/256 == $blue)}
}
# eatColors --
#
# Creates a toplevel window and allocates enough colors in it to use up all
# the slots in an 8-bit colormap.
#
# Arguments:
# w : name of toplevel window to create.
#
proc eatColors {w} {
catch {destroy $w}
toplevel $w
wm geom $w +0+0
canvas $w.c -width 400 -height 200 -bd 0
pack $w.c
for {set y 0} {$y < 8} {incr y} {
for {set x 0} {$x < 40} {incr x} {
set color [format #%02x%02x%02x [expr {$x*6}] [expr {$y*30}] 0]
$w.c create rectangle [expr {10*$x}] [expr {20*$y}] \
[expr {10*$x + 10}] [expr {20*$y + 20}] -outline {} \
-fill $color
}
}
update
}
testutils export
}
namespace eval ::tk::test::dialog {
# init --
#
# This is a reserved proc that is part of the mechanism that the proc
# testutils employs when making utility procs and associated namespace
# variables available to test files.
#
# Test authors should define and initialize namespace variables here if
# they need to be imported into the namespace in which tests are executing.
# This proc must not be exported.
#
# For more information, see the documentation in the file "testutils.GUIDE"
#
proc init {} {
variable dialogType [file rootname [file tail [info script]]]
variable dialogIsNative [isNative $dialogType]
variable testDialog
variable testDialogFont
}
proc Click {button} {
variable dialogType
variable testDialog
switch -- $dialogType {
"fontchooser" {
if {$button ni "ok cancel apply"} {
return -code error "invalid button name \"$button\""
}
$testDialog.$button invoke
}
"winDialog" {
switch -exact -- $button {
ok { set button 1 }
cancel { set button 2 }
}
testwinevent $testDialog $button WM_LBUTTONDOWN 1 0x000a000b
testwinevent $testDialog $button WM_LBUTTONUP 0 0x000a000b
}
default {
return -code error "invalid dialog type \"$dialogType\""
}
}
}
proc isNative {type} {
switch -- $type {
"choosedir" {
set cmd ::tk_chooseDirectory
}
"clrpick" {
set cmd ::tk_chooseColor
}
"filebox" {
set cmd ::tk_getOpenFile
}
"msgbox" {
set cmd ::tk_messageBox
}
"dialog" -
"fontchooser" -
"winDialog" {
return "N/A"
}
default {
return -code error "invalid dialog type \"$type\""
}
}
return [expr {[info procs $cmd] eq ""}]
}
proc PressButton {btn} {
event generate $btn <Enter>
event generate $btn <Button-1> -x 5 -y 5
event generate $btn <ButtonRelease-1> -x 5 -y 5
}
proc SendButtonPress {parent btn buttonType} {
variable dialogType
switch -- $dialogType {
"choosedir" {
if {$parent eq "."} {
set w .__tk_choosedir
} else {
set w $parent.__tk_choosedir
}
upvar ::tk::dialog::file::__tk_choosedir data
}
"clrpick" {
set w .__tk__color
upvar ::tk::dialog::color::[winfo name $w] data
}
"filebox" {
if {$parent eq "."} {
set w .__tk_filedialog
} else {
set w $parent.__tk_filedialog
}
upvar ::tk::dialog::file::__tk_filedialog data
}
"msgbox" {
if {$parent eq "."} {
set w .__tk__messagebox
} else {
set w $parent.__tk__messagebox
}
}
default {
return -code error "invalid dialog type \"$dialogType\""
}
}
if {$dialogType eq "msgbox"} {
set button $w.$btn
} else {
set button $data($btn\Btn)
}
if {! [winfo ismapped $button]} {
update
}
if {$buttonType eq "mouse"} {
PressButton $button
} else {
event generate $w <Enter>
focus $w
event generate $button <Enter>
event generate $w <Key> -keysym Return
}
}
proc testDialog {stage {script ""}} {
variable testDialogCmd
variable testDialogResult
variable testDialogFont
variable iter_after
variable testDialog; # On MS Windows, this variable is set at the C level
# by SetTestDialog() in tkWinDialog.c
switch -- $stage {
launch {
set iter_after 0
set testDialog {}
if {$::tcl_platform(platform) eq "windows"} {
variable testDialogClass "#32770"
}
after 1 $script
}
onDisplay {
set testDialogCmd $script
set testDialogResult {}
set testDialogFont {}
if {$::tcl_platform(platform) eq "windows"} {
# Do not make the delay too short. The newer Vista dialogs take
# time to come up.
after 500 [list [namespace current]::testDialog onDisplay2]
} else {
testDialog onDisplay2
}
vwait ::tk::test::dialog::testDialogResult
return $testDialogResult
}
onDisplay2 {
set doRepeat 0
if {$::tcl_platform(platform) eq "windows"} {
# On Vista and later, using the new file dialogs we have to
# find the window using its title as testDialog will not be
# set at the C level.
variable testDialogClass
if {[catch {testfindwindow "" $testDialogClass} testDialog]} {
set doRepeat 1
}
} elseif {$testDialog eq ""} {
set doRepeat 1
}
if {$doRepeat} {
if {[incr iter_after] > 30} {
set testDialogResult ">30 iterations waiting for testDialog"
return
}
after 150 [list ::tk::test::dialog::testDialog onDisplay2]
return
}
set testDialogResult [uplevel #0 $testDialogCmd]
}
default {
return -code error "invalid parameter \"$stage\""
}
}
}
proc ToPressButton {parent btn} {
variable dialogIsNative
if {! $dialogIsNative} {
after 100 SendButtonPress $parent $btn mouse
}
}
testutils export
}
namespace eval ::tk::test::entry {
# init --
#
# This is a reserved proc that is part of the mechanism that the proc
# testutils employs when making utility procs and associated namespace
# variables available to test files.
#
# Test authors should define and initialize namespace variables here if
# they need to be imported into the namespace in which tests are executing.
# This proc must not be exported.
#
# For more information, see the documentation in the file "testutils.GUIDE"
#
proc init {} {
variable textVar
variable validationData
}
# Handler for variable trace on namespace variable textVar
proc override args {
variable textVar 12345
}
# Procedures used by widget validation tests
proc validateCommand1 {W d i P s S v V} {
variable validationData [list $W $d $i $P $s $S $v $V]
return 1
}
proc validateCommand2 {W d i P s S v V} {
variable validationData [list $W $d $i $P $s $S $v $V]
variable textVar mydata
return 1
}
proc validateCommand3 {W d i P s S v V} {
variable validationData [list $W $d $i $P $s $S $v $V]
return 0
}
proc validateCommand4 {W d i P s S v V} {
variable validationData [list $W $d $i $P $s $S $v $V]
.e delete 0 end;
.e insert end dovaldata
return 0
}
testutils export
}
namespace eval ::tk::test::geometry {
proc getsize {w} {
update
return "[winfo reqwidth $w] [winfo reqheight $w]"
}
testutils export
}
namespace eval ::tk::test::image {
proc imageCleanup {} {
variable ImageNames
foreach img [image names] {
if {$img ni $ImageNames} {image delete $img}
}
}
proc imageFinish {} {
variable ImageNames
set imgs [lsearch -all -inline -glob -not [lsort [image names]] ::tk::icons::indicator*]
if {$imgs ne $ImageNames} {
return -code error "images remaining: [image names] != $ImageNames"
}
imageCleanup
}
proc imageInit {} {
variable ImageNames
if {![info exists ImageNames]} {
set ImageNames [lsearch -all -inline -glob -not [lsort [image names]] ::tk::icons::indicator*]
}
imageCleanup
if {[lsort [image names]] ne $ImageNames} {
return -code error "IMAGE NAMES mismatch: [image names] != $ImageNames"
}
}
proc imageNames {} {
variable ImageNames
set r {}
foreach img [image names] {
if {$img ni $ImageNames} {lappend r $img}
}
return $r
}
testutils export
}
namespace eval ::tk::test::scroll {
# init --
#
# This is a reserved proc that is part of the mechanism that the proc
# testutils employs when making utility procs and associated namespace
# variables available to test files.
#
# Test authors should define and initialize namespace variables here if
# they need to be imported into the namespace in which tests are executing.
# This proc must not be exported.
#
# For more information, see the documentation in the file "testutils.GUIDE"
#
proc init {} {
variable scrollInfo {}
}
# Used as the scrolling command for widgets, set with "-[xy]scrollcommand".
# It saves the scrolling information in a namespace variable "scrollInfo".
proc setScrollInfo {args} {
variable scrollInfo $args
}
testutils export
}
namespace eval ::tk::test::select {
# init --
#
# This is a reserved proc that is part of the mechanism that the proc
# testutils employs when making utility procs and associated namespace
# variables available to test files.
#
# Test authors should define and initialize namespace variables here if
# they need to be imported into the namespace in which tests are executing.
# This proc must not be exported.
#
# For more information, see the documentation in the file "testutils.GUIDE"
#
proc init {} {
variable selValue {} selInfo {}
variable abortCount
variable pass
}
proc badHandler {path type offset count} {
variable selInfo
variable selValue
selection handle -type $type $path {}
lappend selInfo $path $type $offset $count
set numBytes [expr {[string length $selValue] - $offset}]
if {$numBytes <= 0} {
return ""
}
string range $selValue $offset [expr {$numBytes+$offset}]
}
proc badHandler2 {path type offset count} {
variable abortCount
variable selInfo
variable selValue
incr abortCount -1
if {$abortCount == 0} {
selection handle -type $type $path {}
}
lappend selInfo $path $type $offset $count
set numBytes [expr {[string length $selValue] - $offset}]
if {$numBytes <= 0} {
return ""
}
string range $selValue $offset [expr {$numBytes+$offset}]
}
proc errHandler args {
error "selection handler aborted"
}
proc errIncrHandler {type offset count} {
variable selInfo
variable selValue
variable pass
if {$offset == 4000} {
if {$pass == 0} {
# Just sizing the selection; don't do anything here.
set pass 1
} else {
# Fetching the selection; wait long enough to cause a timeout.
after 6000
}
}
lappend selInfo $type $offset $count
set numBytes [expr {[string length $selValue] - $offset}]
if {$numBytes <= 0} {
return ""
}
string range $selValue $offset [expr $numBytes+$offset]
}
proc handler {type offset count} {
variable selInfo
variable selValue
lappend selInfo $type $offset $count
set numBytes [expr {[string length $selValue] - $offset}]
if {$numBytes <= 0} {
return ""
}
string range $selValue $offset [expr $numBytes+$offset]
}
proc reallyBadHandler {path type offset count} {
variable selInfo
variable selValue
variable pass
if {$offset == 4000} {
if {$pass == 0} {
set pass 1
} else {
selection handle -type $type $path {}
}
}
lappend selInfo $path $type $offset $count
set numBytes [expr {[string length $selValue] - $offset}]
if {$numBytes <= 0} {
return ""
}
string range $selValue $offset [expr {$numBytes+$offset}]
}
proc selectionSetup {{path .f1} {display {}}} {
catch {destroy $path}
if {$display eq ""} {
frame $path
} else {
toplevel $path -screen $display
wm geom $path +0+0
}
selection own $path
}
testutils export
}
namespace eval ::tk::test::text {
# init --
#
# This is a reserved proc that is part of the mechanism that the proc
# testutils employs when making utility procs and associated namespace
# variables available to test files.
#
# Test authors should define and initialize namespace variables here if
# they need to be imported into the namespace in which tests are executing.
# This proc must not be exported.
#
# For more information, see the documentation in the file "testutils.GUIDE"
#
proc init {} {
variable fixedFont {Courier -12}
variable fixedWidth [font measure $fixedFont m]
variable fixedHeight [font metrics $fixedFont -linespace]
variable fixedAscent [font metrics $fixedFont -ascent]
}
# full border size of the text widget, i.e. first x or y coordinate inside the text widget
# warning: -padx is supposed to be the same as -pady (same border size horizontally and
# vertically around the widget)
proc bo {{w .t}} {
return [expr {[$w cget -borderwidth] + [$w cget -highlightthickness] + [$w cget -padx]}]
}
# x-coordinate of the first pixel of $n-th char (count starts at zero), left justified
proc xchar {n {w .t}} {
return [expr {[bo $w] + [xw $n]}]
}
# x-width of $n chars, fixed width font
proc xw {n} {
variable fixedWidth
return [expr {$n * $fixedWidth}]
}
# y-coordinate of the first pixel of $l-th display line (count starts at 1)
proc yline {l {w .t}} {
variable fixedHeight
return [expr {[bo $w] + ($l - 1) * $fixedHeight}]
}
testutils export
}
# EOF
|