Check-in [e5dc71ed9d]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:merge with trunk
Timelines: family | ancestors | descendants | both | wtf-8-experiment
Files: files | file ages | folders
SHA1: e5dc71ed9d706421da5c7b179e088bdcda25af2c
User & Date: chw 2019-06-22 06:24:11
Context
2019-06-22
16:59
merge with trunk check-in: f09819c350 user: chw tags: wtf-8-experiment
06:24
merge with trunk check-in: e5dc71ed9d user: chw tags: wtf-8-experiment
06:15
prepare for release check-in: 6e2085e6e4 user: chw tags: trunk, Eppur si muove
2019-06-21
09:29
merge with trunk check-in: cc15b9f12f user: chw tags: wtf-8-experiment
Changes

Changes to assets/VERSION.

1
Asteroid Day (2018-06-30)
|
1
Eppur si muove (2019-06-22)

Changes to jni/sdl2tk/macosx/README.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
...
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
- Please report bugs with Tk on macOS to the tracker:
	http://core.tcl.tk/tk/reportlist

2. Using Tcl/Tk on macOS
---------------------------

- There are two versions of Tk available on macOS: TkAqua using the native
aqua widgets and look&feel, and TkX11 using the traditional unix X11 wigets.
TkX11 requires an X11 server to be installed, such as Apple's X11 (which is
available as an optional or default install on recent macOS).
TkAqua and TkX11 can be distinguished at runtime via [tk windowingsystem].

- At a minimum, macOS 10.3 is required to run Tcl and TkX11.
TkAqua requires macOS 10.6 or later.

................................................................................
all assume that an autorelease pool is in scope and will be drained
when the event processing cycle ends.

The macOS Tk application does not call the [NSApp run] method at
all.  Instead it uses the event loop built in to Tk.  So the
application must take care to replicate the important features of the
method ourselves.  The way that autorelease pools are handled is
discussed in 4.2 below.  Here we discuss the event handling itself.

The Tcl event loop simply consists of repeated calls to TclDoOneEvent.
Each call to TclDoOneEvent begins by collecting all pending events from
an "event source", converting them to Tcl events and adding them
to the Tcl event queue. For macOS, the event source is the NSApp
object, which maintains an event queue even though its run method
will never be called to process them.  The NSApp provides methods for
................................................................................


5.2 Autorelease pools
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In order to carry out the job of managing autorelease pools, which
would normally be handled by the [NSApp run] method, a private
NSAUtoreleasePool* property is added to the TkApplication subclass of
NSApplication. The TkpInit function calls [NSApp _setup] which
initializes this property by creating an NSAutoreleasePool prior to
calling [NSApp finishLaunching].  This mimics the behavior of the
[NSApp run] method, which calls [NSApp finishLaunching] just before
starting the event loop.

Since the CheckProc function gets called for every Tk event, it is an
................................................................................
gets posted by a Tk Application.  To address this, the NSApp object
also implements a semaphore to prevent draining the autorelease pool
in nested calls to CheckProc.

One additional minor caveat for developers is that there are several
steps of the Tk initialization which precede the call to TkpInit.
Notably, the font package is initialized first.  Since there is no
NSAUtoreleasePool in scope prior to calling TkpInit, the functions
called in these preliminary stages need to create and drain their own
NSAutoreleasePools whenever they call methods of Appkit objects
(e.g. NSFont).

5.3 Clipping regions and "ghost windows"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

................................................................................
of the window with a rectangle removed for each subwindow and for each
sibling window at a higher stacking level.  The drawRgn is the
intersection of the visRgn with the clipping rectangle of the
window. (Normally, the clipping rectangle is the same as the bounding
rectangle, but drawing can be clipped to a smaller rectangle by
calling TkpClipDrawableToRect.) The aboveVisRgn is the intersection of
the window's bounding rectangle with the bounding rectangle of the
parent window.  Much of the code in tkMacOSXSubindows.c is devoted to
rebuilding these clipping regions whenever something changes in the
layout of the windows.  This turns out to be a tricky thing to do and
it is extremely prone to errors which can be difficult to trace.

It is not entirely clear what the original reason for using these
clipping regions was.  But one benefit is that if they are correctly
maintained then it allows windows to be drawn in any order.  You do







|







 







|







 







|







 







|







 







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
...
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
- Please report bugs with Tk on macOS to the tracker:
	http://core.tcl.tk/tk/reportlist

2. Using Tcl/Tk on macOS
---------------------------

- There are two versions of Tk available on macOS: TkAqua using the native
aqua widgets and look&feel, and TkX11 using the traditional unix X11 widgets.
TkX11 requires an X11 server to be installed, such as Apple's X11 (which is
available as an optional or default install on recent macOS).
TkAqua and TkX11 can be distinguished at runtime via [tk windowingsystem].

- At a minimum, macOS 10.3 is required to run Tcl and TkX11.
TkAqua requires macOS 10.6 or later.

................................................................................
all assume that an autorelease pool is in scope and will be drained
when the event processing cycle ends.

The macOS Tk application does not call the [NSApp run] method at
all.  Instead it uses the event loop built in to Tk.  So the
application must take care to replicate the important features of the
method ourselves.  The way that autorelease pools are handled is
discussed in 5.2 below.  Here we discuss the event handling itself.

The Tcl event loop simply consists of repeated calls to TclDoOneEvent.
Each call to TclDoOneEvent begins by collecting all pending events from
an "event source", converting them to Tcl events and adding them
to the Tcl event queue. For macOS, the event source is the NSApp
object, which maintains an event queue even though its run method
will never be called to process them.  The NSApp provides methods for
................................................................................


5.2 Autorelease pools
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In order to carry out the job of managing autorelease pools, which
would normally be handled by the [NSApp run] method, a private
NSAutoreleasePool* property is added to the TkApplication subclass of
NSApplication. The TkpInit function calls [NSApp _setup] which
initializes this property by creating an NSAutoreleasePool prior to
calling [NSApp finishLaunching].  This mimics the behavior of the
[NSApp run] method, which calls [NSApp finishLaunching] just before
starting the event loop.

Since the CheckProc function gets called for every Tk event, it is an
................................................................................
gets posted by a Tk Application.  To address this, the NSApp object
also implements a semaphore to prevent draining the autorelease pool
in nested calls to CheckProc.

One additional minor caveat for developers is that there are several
steps of the Tk initialization which precede the call to TkpInit.
Notably, the font package is initialized first.  Since there is no
NSAutoreleasePool in scope prior to calling TkpInit, the functions
called in these preliminary stages need to create and drain their own
NSAutoreleasePools whenever they call methods of Appkit objects
(e.g. NSFont).

5.3 Clipping regions and "ghost windows"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

................................................................................
of the window with a rectangle removed for each subwindow and for each
sibling window at a higher stacking level.  The drawRgn is the
intersection of the visRgn with the clipping rectangle of the
window. (Normally, the clipping rectangle is the same as the bounding
rectangle, but drawing can be clipped to a smaller rectangle by
calling TkpClipDrawableToRect.) The aboveVisRgn is the intersection of
the window's bounding rectangle with the bounding rectangle of the
parent window.  Much of the code in tkMacOSXSubwindows.c is devoted to
rebuilding these clipping regions whenever something changes in the
layout of the windows.  This turns out to be a tricky thing to do and
it is extremely prone to errors which can be difficult to trace.

It is not entirely clear what the original reason for using these
clipping regions was.  But one benefit is that if they are correctly
maintained then it allows windows to be drawn in any order.  You do

Changes to jni/sdl2tk/macosx/Wish.sdef.

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
			<direct-parameter description="Script to execute" type="text">
				<type type="text"/>
			</direct-parameter>
			<result description="Result">
				<type type="text"/>
			</result>
		</command>
		<command name="open location" code="GURLGURL" description="Open a URL.">

		<direct-parameter description="URL" type="text">
			<type type="text"/>
		</direct-parameter>
		<result description="Result">
			<type type="text"/>
		</result>
		</command>
	</suite>
</dictionary>







|
>
|
|
|
|
|
|



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
			<direct-parameter description="Script to execute" type="text">
				<type type="text"/>
			</direct-parameter>
			<result description="Result">
				<type type="text"/>
			</result>
		</command>
			<command name="open location" code="GURLGURL"
				 description="Open a URL.">
			<direct-parameter description="URL" type="text">
				<type type="text"/>
			</direct-parameter>
			<result description="Result">
				<type type="text"/>
			</result>
		</command>
	</suite>
</dictionary>

Changes to jni/sdl2tk/macosx/tkMacOSXConstants.h.

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
#define NSCursorUpdate NSEventTypeCursorUpdate
#define NSTexturedBackgroundWindowMask NSWindowStyleMaskTexturedBackground
#define NSCompositeCopy NSCompositingOperationCopy
#define NSWarningAlertStyle NSAlertStyleWarning
#define NSInformationalAlertStyle NSAlertStyleInformational
#define NSCriticalAlertStyle NSAlertStyleCritical
#define NSCenterTextAlignment NSTextAlignmentCenter
#define NSDeviceIndependentModifierFlagsMask NSEventModifierFlagDeviceIndependentFlagsMask
#define NSCommandKeyMask NSEventModifierFlagCommand
#define NSShiftKeyMask NSEventModifierFlagShift
#define NSAlphaShiftKeyMask NSEventModifierFlagCapsLock
#define NSAlternateKeyMask NSEventModifierFlagOption
#define NSControlKeyMask NSEventModifierFlagControl
#define NSNumericPadKeyMask NSEventModifierFlagNumericPad
#define NSFunctionKeyMask NSEventModifierFlagFunction
#define NSKeyUp NSEventTypeKeyUp
#define NSKeyDown NSEventTypeKeyDown
#define NSFlagsChanged NSEventTypeFlagsChanged
#define NSAlphaShiftKeyMask NSEventModifierFlagCapsLock
#define NSShiftKeyMask NSEventModifierFlagShift
#define NSAnyEventMask NSEventMaskAny
#define NSApplicationDefinedMask NSEventMaskApplicationDefined
#define NSTexturedBackgroundWindowMask NSWindowStyleMaskTexturedBackground
#define NSUtilityWindowMask NSWindowStyleMaskUtilityWindow
#define NSNonactivatingPanelMask NSWindowStyleMaskNonactivatingPanel
#define NSDocModalWindowMask NSWindowStyleMaskDocModalWindow
#define NSHUDWindowMask NSWindowStyleMaskHUDWindow
#define NSTitledWindowMask NSWindowStyleMaskTitled
#define NSClosableWindowMask NSWindowStyleMaskClosable
#define NSResizableWindowMask NSWindowStyleMaskResizable







<
<
<
<
<
<
<
<
<
<
<
<
<


<







75
76
77
78
79
80
81













82
83

84
85
86
87
88
89
90
#define NSCursorUpdate NSEventTypeCursorUpdate
#define NSTexturedBackgroundWindowMask NSWindowStyleMaskTexturedBackground
#define NSCompositeCopy NSCompositingOperationCopy
#define NSWarningAlertStyle NSAlertStyleWarning
#define NSInformationalAlertStyle NSAlertStyleInformational
#define NSCriticalAlertStyle NSAlertStyleCritical
#define NSCenterTextAlignment NSTextAlignmentCenter













#define NSAnyEventMask NSEventMaskAny
#define NSApplicationDefinedMask NSEventMaskApplicationDefined

#define NSUtilityWindowMask NSWindowStyleMaskUtilityWindow
#define NSNonactivatingPanelMask NSWindowStyleMaskNonactivatingPanel
#define NSDocModalWindowMask NSWindowStyleMaskDocModalWindow
#define NSHUDWindowMask NSWindowStyleMaskHUDWindow
#define NSTitledWindowMask NSWindowStyleMaskTitled
#define NSClosableWindowMask NSWindowStyleMaskClosable
#define NSResizableWindowMask NSWindowStyleMaskResizable

Changes to undroid/tsb/tsb.tcl.

400
401
402
403
404
405
406









407
408
409
410
411
412
413
...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
...
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
...
941
942
943
944
945
946
947

948
949
950
951
952
953
954
955
....
1017
1018
1019
1020
1021
1022
1023

1024





1025
1026
1027



1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
....
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
....
1104
1105
1106
1107
1108
1109
1110
1111


1112
1113
1114
1115
1116









1117
1118
1119
1120
1121
1122
1123
....
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
....
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
}

# Evaluate field.

proc ::tsb::eval {id} {
    tailcall $::W call Feval $id
}










# Print page; on Windows seems not to work, but pressing
# <Control-p> opens the printer dialog at least.

proc ::tsb::print {} {
    tailcall $::W call window.print
}
................................................................................

# A minimal canvas emulation for plotchart. The svg method
# produces SVG into the current (output) field.
#
#  set C [::tsb::canvas ...]
#  $C create line 10 10 20 20 -fill black ...
#  ...
#  $C svg
#  $C destroy

namespace eval ::tsb {

    variable C
    array set C {cid 0}

................................................................................
	    white-space: -o-pre-wrap;
	    word-wrap: break-word;
	}
	pre, code {
	    font-family: Consolas, Roboto Mono, Liberation Mono, monospace;
	    font-size: 90%;
	}
	img {
	    max-width: 95%;
	}
	.field {
	    border: 1px solid transparent;
	}
	.field:hover {
	    border: 1px dotted #AAAAAA;
................................................................................

	/* The 2nd sin: this drives the Tcl event loop. */
	var Gtimer = window.setInterval(function() {
	    window.external.invoke("0 ::tsb::ping");
	}, 20);

	var Wclear = function(id, later) {

	    if (later) {
		needsClear[id] = true;
		return;
	    }
	    if (!needsClear[id]) {
		return;
	    }
	    var output =
................................................................................
		}
	    }
	    needsClear[id] = null;
	};

	var Inhide = function(id, hide) {
	    var input = document.getElementById('in' + id);

	    var output = document.getElementById('out' + id + '-raw');





	    if (hide) {
		input.style.display = 'none';
		output.addEventListener('dblclick', function(event) {



		    Inhide(id, 0);
		});
	    } else {
		output.removeEventListener('dblclick', null);

		input.style.display = 'inline';
	    }
	};

	var Winput = function(id, str) {
	    var input = document.getElementById('code' + id);
	    input.value = str;
................................................................................
	    needsClear[id] = true;
	    RunTcl("" + id + " " + input.value);
	};

	var Field = function(id) {
	    var div = document.createElement('div');
	    div.className = 'field';
	    var html = '\n <a href="#in' + id + '"></a>';
	    html += '\n <div class="infield" id="in' + id + '">';
	    html += '\n  <label class="tlabel"';
	    html += ' for="code' + id + '">in(' + id + ')</label>';
	    html += '\n  <textarea class="tin" id="code' + id + '" rows="1"';
	    html += '></textarea>\n </div>';
	    html += '\n <a href="#out' + id + '"></a>';
	    html += '\n <div id="out' + id + '-pre">';
	    html += '<pre></pre></div>';
	    html += '\n <div id="out' + id + '-raw"></div>\n';
	    div.innerHTML = html;
	    document.body.appendChild(div);
	    /* For better readability only. */
	    document.body.appendChild(document.createTextNode('\n'));
................................................................................
	    input.value = str;
	    var lines = str.split(/\r?\n|\r/);
	    var nlines = (lines.length < 50) ? lines.length : 50;
	    input.rows = nlines;
	};

	var GotoTop = function() {
	    window.location.href = "#top";


	};

	var GotoField = function(id, isout) {
	    var href = (isout ? "#out" : "#in") + id;
	    window.location.href = href;









	};

	var ClearFields = function() {
	    while (1) {
		var fields = document.getElementsByClassName('field');
		if (fields.length > 0) {
		    fields[0].parentNode.removeChild(fields[0]);
................................................................................

	</script>
    }

    # Assemble pieces with empty BODY.
    set D $D_head
    append D $D_style $D_script \
	{</head><body><a href="#top"></a></body></html>}

    # The URL to be displayed.
    # Windows:   data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # MacOS:     data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # WebkitGtk: data:text/html,<html><head><script>window.webkit.messageHandlers.extern.postMessage("0 ::tsb::reload");</script></head></html>

    variable U
................................................................................
}

# Initialize webview; document is loaded indirectly via the URL
# which triggers ::tsb::reload which does the rest, but see
# the ::tsb::ready block below.

set W [::twv::new -width 800 -height 600 -title $::tsb::title \
	   -url $::tsb::U -resizable 1 -debug 0 \
	   -callback ::tsb::call_from_js]

# On Windows this seems the way to load, maybe timing?

if {($tcl_platform(platform) eq "windows") && !$::tsb::ready} {
    after cancel ::tsb::reload0
    ::tsb::reload0







>
>
>
>
>
>
>
>
>







 







|







 







|







 







>
|







 







>
|
>
>
>
>
>
|

|
>
>
>



|
>







 







<
|




<







 







|
>
>



|
|
>
>
>
>
>
>
>
>
>







 







|







 







|







400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
...
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
...
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
...
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
....
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
....
1066
1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077

1078
1079
1080
1081
1082
1083
1084
....
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
....
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
....
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
}

# Evaluate field.

proc ::tsb::eval {id} {
    tailcall $::W call Feval $id
}

# Goto field.

proc ::tsb::goto {{id {}}} {
    if {$id eq ""} {
	tailcall $::W call GotoTop
    }
    tailcall $::W call GotoField $id 0
}

# Print page; on Windows seems not to work, but pressing
# <Control-p> opens the printer dialog at least.

proc ::tsb::print {} {
    tailcall $::W call window.print
}
................................................................................

# A minimal canvas emulation for plotchart. The svg method
# produces SVG into the current (output) field.
#
#  set C [::tsb::canvas ...]
#  $C create line 10 10 20 20 -fill black ...
#  ...
#  $C svg ?viewbox?
#  $C destroy

namespace eval ::tsb {

    variable C
    array set C {cid 0}

................................................................................
	    white-space: -o-pre-wrap;
	    word-wrap: break-word;
	}
	pre, code {
	    font-family: Consolas, Roboto Mono, Liberation Mono, monospace;
	    font-size: 90%;
	}
	img, svg {
	    max-width: 95%;
	}
	.field {
	    border: 1px solid transparent;
	}
	.field:hover {
	    border: 1px dotted #AAAAAA;
................................................................................

	/* The 2nd sin: this drives the Tcl event loop. */
	var Gtimer = window.setInterval(function() {
	    window.external.invoke("0 ::tsb::ping");
	}, 20);

	var Wclear = function(id, later) {
	    /* Type coercion! */
	    if (later == true) {
		needsClear[id] = true;
		return;
	    }
	    if (!needsClear[id]) {
		return;
	    }
	    var output =
................................................................................
		}
	    }
	    needsClear[id] = null;
	};

	var Inhide = function(id, hide) {
	    var input = document.getElementById('in' + id);
	    var outpre = document.getElementById('out' + id + '-pre');
	    var outraw = document.getElementById('out' + id + '-raw');
	    if ((outpre.clientWidth == 0 || outpre.clientHeight == 0) &&
	        (outraw.clientWidth == 0 || outraw.clientHeight == 0)) {
		hide = false;
	    }
	    /* Type coercion! */
	    if (hide == true) {
		input.style.display = 'none';
		outpre.addEventListener('dblclick', function(event) {
		    Inhide(id, 0);
		});
		outraw.addEventListener('dblclick', function(event) {
		    Inhide(id, 0);
		});
	    } else {
		outraw.removeEventListener('dblclick', null);
		outpre.removeEventListener('dblclick', null);
		input.style.display = 'inline';
	    }
	};

	var Winput = function(id, str) {
	    var input = document.getElementById('code' + id);
	    input.value = str;
................................................................................
	    needsClear[id] = true;
	    RunTcl("" + id + " " + input.value);
	};

	var Field = function(id) {
	    var div = document.createElement('div');
	    div.className = 'field';

	    var html = '\n <div class="infield" id="in' + id + '">';
	    html += '\n  <label class="tlabel"';
	    html += ' for="code' + id + '">in(' + id + ')</label>';
	    html += '\n  <textarea class="tin" id="code' + id + '" rows="1"';
	    html += '></textarea>\n </div>';

	    html += '\n <div id="out' + id + '-pre">';
	    html += '<pre></pre></div>';
	    html += '\n <div id="out' + id + '-raw"></div>\n';
	    div.innerHTML = html;
	    document.body.appendChild(div);
	    /* For better readability only. */
	    document.body.appendChild(document.createTextNode('\n'));
................................................................................
	    input.value = str;
	    var lines = str.split(/\r?\n|\r/);
	    var nlines = (lines.length < 50) ? lines.length : 50;
	    input.rows = nlines;
	};

	var GotoTop = function() {
	    var elem = document.getElementById('top');
	    elem.focus();
	    elem.scrollIntoView();
	};

	var GotoField = function(id, isout) {
	    var elem;
	    /* Type coercion! */
	    if (isout == true) {
		elem = document.getElementById('out' + id + '-pre');
	    } else {
		elem = document.getElementById('in' + id);
		if (elem.style.display === 'none') {
		    elem = document.getElementById('out' + id + '-pre');
		}
	    }
	    elem.scrollIntoView();
	};

	var ClearFields = function() {
	    while (1) {
		var fields = document.getElementsByClassName('field');
		if (fields.length > 0) {
		    fields[0].parentNode.removeChild(fields[0]);
................................................................................

	</script>
    }

    # Assemble pieces with empty BODY.
    set D $D_head
    append D $D_style $D_script \
	{</head><body><div id="top" tabindex="0"></div></body></html>}

    # The URL to be displayed.
    # Windows:   data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # MacOS:     data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # WebkitGtk: data:text/html,<html><head><script>window.webkit.messageHandlers.extern.postMessage("0 ::tsb::reload");</script></head></html>

    variable U
................................................................................
}

# Initialize webview; document is loaded indirectly via the URL
# which triggers ::tsb::reload which does the rest, but see
# the ::tsb::ready block below.

set W [::twv::new -width 800 -height 600 -title $::tsb::title \
	   -url $::tsb::U -resizable 1 -debug 1 \
	   -callback ::tsb::call_from_js]

# On Windows this seems the way to load, maybe timing?

if {($tcl_platform(platform) eq "windows") && !$::tsb::ready} {
    after cancel ::tsb::reload0
    ::tsb::reload0