Check-in [3368bc1809]
Not logged in

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

Overview
Comment:improve vncviewer demo
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3368bc180903502d40385073be8cf51b96a3fe75
User & Date: chw 2020-01-15 19:35:27
Context
2020-01-17
10:34
add tcl upstream changes check-in: abaae02349 user: chw tags: trunk
2020-01-16
05:47
merge with trunk Leaf check-in: 9972f7c57e user: chw tags: wtf-8-experiment
2020-01-15
19:35
improve vncviewer demo check-in: 3368bc1809 user: chw tags: trunk
19:34
improve touch calibration package check-in: 5af8100ac6 user: chw tags: trunk
Changes

Changes to assets/vnc0.4/vncviewer.tcl.

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
..
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
...
139
140
141
142
143
144
145


146
147
148
149
150
151
152
...
155
156
157
158
159
160
161

162
163
164
165
166
167
168
...
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
#
# The "Back" key brings up the option dialog with entries for host,
# password etc. and buttons to exit and connect/disconnect.

package require vnc

if {[info command sdltk] eq "sdltk"} {
    # on SDL2TK
    wm attributes . -fullscreen 1
} else {
    wm geometry . 640x480
}

. configure -bg black

if {[info command borg] eq "borg"} {
    # on Android
    sdltk touchtranslate 13 ;# RMB, pan/zoom, fingers translated
    borg screenorientation landscape
    set ::VNC(android) 1
} else {






    set ::VNC(android) 0
}

array set ::VNCEV {fbits 0 trigger 0}
array set ::VNCSET {host {} pwd {} shared 0 viewonly 0 lifecycle 0}
array set ::VNC {host {} lastconnect 1 connected 0}

# callback on connection status change from VNC widget

proc vnc_info {data} {
    if {$::VNCSET(lifecycle)} {
	return
    }
    array set ::VNC $data
    if {$::VNC(lastconnect) && !$::VNC(connected)} {
	vnc_settings
    } elseif {!$::VNC(lastconnect) && $::VNC(connected)} {
	if {[info command sdltk] eq "sdltk"} {




	    if {[catch {sdltk root $::VNC(width) $::VNC(height)}]} {
		.vnc disconnect
		after idle {vnc_info [.vnc info]}
		return



	    }






































	} else {













	    wm geometry . "$::VNC(width)x$::VNC(height)"
	}
	set ::VNCSET(host) $::VNC(host)
	set ::VNCSET(shared) $::VNC(shared)
	set ::VNCSET(viewonly) $::VNC(viewonly)

	if {![catch {open ~/vnc.set w} f]} {

	    puts $f [array get ::VNCSET]
	    close $f

	}
    }
    set ::VNC(lastconnect) $::VNC(connected)
}

# settings dialog

................................................................................
    grid $w.lp -in $w.f -row 1 -column 0 -sticky e -padx 5 -pady 5
    ttk::entry $w.pwd -textvariable ::VNCSET(pwd) -show "*"
    grid $w.pwd -in $w.f -row 1 -column 1 -sticky ew -padx 5 -pady 5
    ttk::checkbutton $w.shared -variable ::VNCSET(shared) -text "Shared"
    grid $w.shared -in $w.f -row 2 -column 1 -sticky w -padx 5 -pady 5
    ttk::checkbutton $w.vonly -variable ::VNCSET(viewonly) -text "View Only"
    grid $w.vonly -in $w.f -row 3 -column 1 -sticky w -padx 5 -pady 5







    ttk::frame $w.buttons
    grid $w.buttons -in $w.f \
	-row 4 -column 0 -columnspan 2 -sticky ew -padx 5 -pady 5
    if {$::VNC(connected)} {
	ttk::button $w.buttons.a -text "Disconnect" -width 12 \
	    -command [list vnc_command $w disc]
    } else {
	if {![catch {open ~/vnc.set} f]} {
	    catch {array set ::VNCSET [read $f 1024]}
	    close $f


	}

	ttk::button $w.buttons.a -text "Connect" -width 12 \
	    -command [list vnc_command $w conn]
    }
    ttk::button $w.buttons.x -text "Exit" -width 12 -command {
	destroy .vnc
	exit 0
    }
    ttk::button $w.buttons.c -text "Cancel" -width 12 \
	-command [subst {
	    grab release $w
	    focus .vnc
	    destroy $w

	}]
    pack $w.buttons.a $w.buttons.x $w.buttons.c -side left -expand 1 -padx 5
    if {$::VNC(android)} {
	bind $w <Break> [list $w.buttons.c invoke]
    }
    pack $w.f -side top -fill both -expand 1
    ::tk::PlaceWindow $w widget [winfo parent $w]
    grab $w
}



























# perform connect to VNC server

proc vnc_connect {} {
    set args $::VNCSET(host)
    lappend args $::VNCSET(pwd)
    if {$::VNCSET(shared)} {
................................................................................
    if {$::VNCSET(viewonly)} {
	lappend args "-viewonly"
    }
    if {[catch {.vnc connect {*}$args} err]} {
	tk_messageBox -title "Error" -message $err \
	    -type ok -icon error
	after idle vnc_settings


    }
}

# execute connect or disconnect to/from VNC server

proc vnc_command {w what} {
    grab release $w
................................................................................
    destroy $w
    update
    switch -glob -- $what {
	disc* {
	    after idle {
		catch {.vnc disconnect}
	    }

	}
	conn* {
	    after idle vnc_connect
	}
    }
    tk busy forget .
}
................................................................................
	    }
	}
    }
}

vnc .vnc -bd 0 -relief flat -highlightthickness 0 -bg black \
    -infocommand vnc_info





pack .vnc -side top -fill both -expand 1

focus .vnc

if {$::VNC(android)} {
    wm withdraw .
}

# Android App lifecycle
bind . <<WillEnterBackground>> {vnc_lifecycle 1}
bind . <<WillEnterForeground>> {vnc_lifecycle 0}

# SDL2TK viewport and touchscreen
bind . <<ViewportUpdate>> {vnc_vp_finger %W v %x %y %X %Y %s}
bind . <<FingerDown>> {vnc_vp_finger %W d %x %y %X %Y %s}
bind . <<FingerMotion>> {vnc_vp_finger %W m %x %y %X %Y %s}
bind . <<FingerUp>> {vnc_vp_finger %W u %x %y %X %Y %s}

bind VNC <Control-Tab> {}
if {$::VNC(android)} {
    # Android back key
    bind VNC <Break> {vnc_settings ; break}
}
bind VNC <Control-F8> {vnc_settings ; break}







# initially bring up settings dialog












if {$::VNC(android)} {
    after idle {
	wm deiconify .

	vnc_settings



    }



} else {

    vnc_settings
}







<













>
>
>
>
>
>




|
|












>
>
>
>
|
<
<
<
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>





>

>


>







 







>
>
>
>
>
>
>


|







>
>

>










<

>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>







 







>







 







>
>
>
>
>
|
>










|










|
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>




>
|
>
>
>
|
>
>
>

>
|

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
...
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
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
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
#
# The "Back" key brings up the option dialog with entries for host,
# password etc. and buttons to exit and connect/disconnect.

package require vnc

if {[info command sdltk] eq "sdltk"} {

    wm attributes . -fullscreen 1
} else {
    wm geometry . 640x480
}

. configure -bg black

if {[info command borg] eq "borg"} {
    # on Android
    sdltk touchtranslate 13 ;# RMB, pan/zoom, fingers translated
    borg screenorientation landscape
    set ::VNC(android) 1
} else {
    if {[info command sdltk] eq "sdltk"} {
	if {[sdltk maxroot] eq {0 0}} {
	    sdltk touchtranslate 0
	}
	package require touchcal
    }
    set ::VNC(android) 0
}

array set ::VNCEV {fbits 0 trigger 0}
array set ::VNCSET {host {} pwd {} shared 0 viewonly 0 auto 0 lifecycle 0}
array set ::VNC {host {} auto 0 lastconnect 1 connected 0}

# callback on connection status change from VNC widget

proc vnc_info {data} {
    if {$::VNCSET(lifecycle)} {
	return
    }
    array set ::VNC $data
    if {$::VNC(lastconnect) && !$::VNC(connected)} {
	vnc_settings
    } elseif {!$::VNC(lastconnect) && $::VNC(connected)} {
	if {[info command sdltk] eq "sdltk"} {
	    set sw [winfo screenwidth .]
	    set sh [winfo screenheight .]
	    if {[sdltk maxroot] eq {0 0}} {
		set dosb 1
	    } elseif {[catch {sdltk root $::VNC(width) $::VNC(height)}]} {



		set dosb 1
	    } else {
		set dosb 0
	    }
	    if {$dosb} {
		if {$::VNC(width) <= $sw && $::VNC(height) <= $sh} {
		    set dosb 0
		}
	    }
	    if {$dosb} {
		if {$::VNC(width) > $sw - 20} {
		    if {![winfo exists .x]} {
			ttk::scrollbar .x -orient horizontal -takefocus 0 \
			    -command {.vnc xview}
			grid .x -row 1 -column 0 -sticky ew
			.vnc configure -xscrollcommand {.x set}
		    }
		    incr dosb
		} elseif {[winfo exists .x]} {
		    .vnc configure -xscrollcommand {}
		    destroy .x
		}
		if {$::VNC(height) > $sh - 20} {
		    if {![winfo exists .y]} {
			ttk::scrollbar .y -orient vertical -takefocus 0 \
			    -command {.vnc yview}
			grid .y -row 0 -column 1 -sticky ns
			.vnc configure -yscrollcommand {.y set}
		    }
		    incr dosb
		} elseif {[winfo exists .y]} {
		    .vnc configure -yscrollcommand {}
		    destroy .y
		}
		if {$dosb > 2} {
		    if {![winfo exists .f]} {
			frame .f
			grid .f -row 1 -column 1 -sticky nsew
		    }
		} elseif {[winfo exists .f]} {
		    destroy .f
		}
	    } else {
		if {[winfo exists .f]} {
		    destroy .f
		}
		if {[winfo exists .x]} {
		    .vnc configure -xscrollcommand {}
		    destroy .x
		}
		if {[winfo exists .y]} {
		    .vnc configure -yscrollcommand {}
		    destroy .y
		}
	    }
	} else {
	    wm geometry . "$::VNC(width)x$::VNC(height)"
	}
	set ::VNCSET(host) $::VNC(host)
	set ::VNCSET(shared) $::VNC(shared)
	set ::VNCSET(viewonly) $::VNC(viewonly)
	set ::VNCSET(auto) $::VNC(auto)
	if {![catch {open ~/vnc.set w} f]} {
	    catch {set ::VNCSET(pwd) [binary encode base64 $::VNCSET(pwd)]}
	    puts $f [array get ::VNCSET]
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	}
    }
    set ::VNC(lastconnect) $::VNC(connected)
}

# settings dialog

................................................................................
    grid $w.lp -in $w.f -row 1 -column 0 -sticky e -padx 5 -pady 5
    ttk::entry $w.pwd -textvariable ::VNCSET(pwd) -show "*"
    grid $w.pwd -in $w.f -row 1 -column 1 -sticky ew -padx 5 -pady 5
    ttk::checkbutton $w.shared -variable ::VNCSET(shared) -text "Shared"
    grid $w.shared -in $w.f -row 2 -column 1 -sticky w -padx 5 -pady 5
    ttk::checkbutton $w.vonly -variable ::VNCSET(viewonly) -text "View Only"
    grid $w.vonly -in $w.f -row 3 -column 1 -sticky w -padx 5 -pady 5
    ttk::checkbutton $w.auto -variable ::VNCSET(auto) -text "Auto Connect"
    grid $w.auto -in $w.f -row 4 -column 1 -sticky w -padx 5 -pady 5
    if {[info command sdltk] eq "sdltk" && !$::VNC(android)} {
	ttk::button $w.tcal -text "Calibrate Touchscreen ..." \
	    -command [list vnc_touchcal]
	grid $w.tcal -in $w.f -row 5 -column 0 -columnspan 2 -padx 5 -pady 5
    }
    ttk::frame $w.buttons
    grid $w.buttons -in $w.f \
	-row 6 -column 0 -columnspan 2 -sticky ew -padx 5 -pady 5
    if {$::VNC(connected)} {
	ttk::button $w.buttons.a -text "Disconnect" -width 12 \
	    -command [list vnc_command $w disc]
    } else {
	if {![catch {open ~/vnc.set} f]} {
	    catch {array set ::VNCSET [read $f 1024]}
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	    vnc_touchset
	}
	set ::VNCSET(auto) $::VNC(auto)
	ttk::button $w.buttons.a -text "Connect" -width 12 \
	    -command [list vnc_command $w conn]
    }
    ttk::button $w.buttons.x -text "Exit" -width 12 -command {
	destroy .vnc
	exit 0
    }
    ttk::button $w.buttons.c -text "Cancel" -width 12 \
	-command [subst {
	    grab release $w

	    destroy $w
	    focus .vnc
	}]
    pack $w.buttons.a $w.buttons.x $w.buttons.c -side left -expand 1 -padx 5
    if {$::VNC(android)} {
	bind $w <Break> [list $w.buttons.c invoke]
    }
    pack $w.f -side top -fill both -expand 1
    ::tk::PlaceWindow $w widget [winfo parent $w]
    grab $w
}

# perform touchscreen calibration

proc vnc_touchcal {} {
    set data [touchcal::calibrate .tcal]
    if {[llength $data]} {
	set ::VNCSET(touchcal) $data
	if {![catch {open ~/vnc.set w} f]} {
	    catch {set ::VNCSET(pwd) [binary encode base64 $::VNCSET(pwd)]}
	    puts $f [array get ::VNCSET]
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	}
	vnc_touchset
    }
}

# commit touchscreen calibration

proc vnc_touchset {} {
    if {[info command sdltk] eq "sdltk" && !$::VNC(android)} {
	if {[info exists ::VNCSET(touchcal)]} {
	    catch {sdltk touchcalibration {*}$::VNCSET(touchcal)}
	}
    }
}

# perform connect to VNC server

proc vnc_connect {} {
    set args $::VNCSET(host)
    lappend args $::VNCSET(pwd)
    if {$::VNCSET(shared)} {
................................................................................
    if {$::VNCSET(viewonly)} {
	lappend args "-viewonly"
    }
    if {[catch {.vnc connect {*}$args} err]} {
	tk_messageBox -title "Error" -message $err \
	    -type ok -icon error
	after idle vnc_settings
    } else {
	set ::VNC(auto) $::VNCSET(auto)
    }
}

# execute connect or disconnect to/from VNC server

proc vnc_command {w what} {
    grab release $w
................................................................................
    destroy $w
    update
    switch -glob -- $what {
	disc* {
	    after idle {
		catch {.vnc disconnect}
	    }
	    set ::VNC(auto) $::VNCSET(auto)
	}
	conn* {
	    after idle vnc_connect
	}
    }
    tk busy forget .
}
................................................................................
	    }
	}
    }
}

vnc .vnc -bd 0 -relief flat -highlightthickness 0 -bg black \
    -infocommand vnc_info
if {[info command sdltk] eq "sdltk"} {
    grid .vnc -row 0 -column 0 -sticky nsew
    grid rowconfigure . 0 -weight 1
    grid columnconfigure . 0 -weight 1
} else {
    pack .vnc -side top -fill both -expand 1
}
focus .vnc

if {$::VNC(android)} {
    wm withdraw .
}

# Android App lifecycle
bind . <<WillEnterBackground>> {vnc_lifecycle 1}
bind . <<WillEnterForeground>> {vnc_lifecycle 0}

# sdltk viewport and touchscreen
bind . <<ViewportUpdate>> {vnc_vp_finger %W v %x %y %X %Y %s}
bind . <<FingerDown>> {vnc_vp_finger %W d %x %y %X %Y %s}
bind . <<FingerMotion>> {vnc_vp_finger %W m %x %y %X %Y %s}
bind . <<FingerUp>> {vnc_vp_finger %W u %x %y %X %Y %s}

bind VNC <Control-Tab> {}
if {$::VNC(android)} {
    # Android back key
    bind VNC <Break> {vnc_settings ; break}
}
bind VNC <Control-F8> {
    # release control keys
    .vnc sendkey 0 0xFFE3
    .vnc sendkey 0 0xFFE4
    vnc_settings
    break
}

# initially bring up settings dialog or connect

apply {
    {} {
	if {![catch {open ~/vnc.set} f]} {
	    catch {array set ::VNCSET [read $f 1024]}
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	    vnc_touchset
	}
    }
}

if {$::VNC(android)} {
    after idle {
	wm deiconify .
	if {$::VNCSET(host) eq "" || !$::VNCSET(auto)} {
	    vnc_settings
	} else {
	    set ::VNC(lastconnect) 0
	    vnc_connect
	}
    }
} elseif {$::VNCSET(host) eq "" || !$::VNCSET(auto)} {
    vnc_settings
} else {
    set ::VNC(lastconnect) 0
    vnc_connect
}

Changes to jni/tkvnc/demos/vncviewer.tcl.

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
..
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
...
139
140
141
142
143
144
145


146
147
148
149
150
151
152
...
155
156
157
158
159
160
161

162
163
164
165
166
167
168
...
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
#
# The "Back" key brings up the option dialog with entries for host,
# password etc. and buttons to exit and connect/disconnect.

package require vnc

if {[info command sdltk] eq "sdltk"} {
    # on SDL2TK
    wm attributes . -fullscreen 1
} else {
    wm geometry . 640x480
}

. configure -bg black

if {[info command borg] eq "borg"} {
    # on Android
    sdltk touchtranslate 13 ;# RMB, pan/zoom, fingers translated
    borg screenorientation landscape
    set ::VNC(android) 1
} else {






    set ::VNC(android) 0
}

array set ::VNCEV {fbits 0 trigger 0}
array set ::VNCSET {host {} pwd {} shared 0 viewonly 0 lifecycle 0}
array set ::VNC {host {} lastconnect 1 connected 0}

# callback on connection status change from VNC widget

proc vnc_info {data} {
    if {$::VNCSET(lifecycle)} {
	return
    }
    array set ::VNC $data
    if {$::VNC(lastconnect) && !$::VNC(connected)} {
	vnc_settings
    } elseif {!$::VNC(lastconnect) && $::VNC(connected)} {
	if {[info command sdltk] eq "sdltk"} {




	    if {[catch {sdltk root $::VNC(width) $::VNC(height)}]} {
		.vnc disconnect
		after idle {vnc_info [.vnc info]}
		return



	    }






































	} else {













	    wm geometry . "$::VNC(width)x$::VNC(height)"
	}
	set ::VNCSET(host) $::VNC(host)
	set ::VNCSET(shared) $::VNC(shared)
	set ::VNCSET(viewonly) $::VNC(viewonly)

	if {![catch {open ~/vnc.set w} f]} {

	    puts $f [array get ::VNCSET]
	    close $f

	}
    }
    set ::VNC(lastconnect) $::VNC(connected)
}

# settings dialog

................................................................................
    grid $w.lp -in $w.f -row 1 -column 0 -sticky e -padx 5 -pady 5
    ttk::entry $w.pwd -textvariable ::VNCSET(pwd) -show "*"
    grid $w.pwd -in $w.f -row 1 -column 1 -sticky ew -padx 5 -pady 5
    ttk::checkbutton $w.shared -variable ::VNCSET(shared) -text "Shared"
    grid $w.shared -in $w.f -row 2 -column 1 -sticky w -padx 5 -pady 5
    ttk::checkbutton $w.vonly -variable ::VNCSET(viewonly) -text "View Only"
    grid $w.vonly -in $w.f -row 3 -column 1 -sticky w -padx 5 -pady 5







    ttk::frame $w.buttons
    grid $w.buttons -in $w.f \
	-row 4 -column 0 -columnspan 2 -sticky ew -padx 5 -pady 5
    if {$::VNC(connected)} {
	ttk::button $w.buttons.a -text "Disconnect" -width 12 \
	    -command [list vnc_command $w disc]
    } else {
	if {![catch {open ~/vnc.set} f]} {
	    catch {array set ::VNCSET [read $f 1024]}
	    close $f


	}

	ttk::button $w.buttons.a -text "Connect" -width 12 \
	    -command [list vnc_command $w conn]
    }
    ttk::button $w.buttons.x -text "Exit" -width 12 -command {
	destroy .vnc
	exit 0
    }
    ttk::button $w.buttons.c -text "Cancel" -width 12 \
	-command [subst {
	    grab release $w
	    focus .vnc
	    destroy $w

	}]
    pack $w.buttons.a $w.buttons.x $w.buttons.c -side left -expand 1 -padx 5
    if {$::VNC(android)} {
	bind $w <Break> [list $w.buttons.c invoke]
    }
    pack $w.f -side top -fill both -expand 1
    ::tk::PlaceWindow $w widget [winfo parent $w]
    grab $w
}



























# perform connect to VNC server

proc vnc_connect {} {
    set args $::VNCSET(host)
    lappend args $::VNCSET(pwd)
    if {$::VNCSET(shared)} {
................................................................................
    if {$::VNCSET(viewonly)} {
	lappend args "-viewonly"
    }
    if {[catch {.vnc connect {*}$args} err]} {
	tk_messageBox -title "Error" -message $err \
	    -type ok -icon error
	after idle vnc_settings


    }
}

# execute connect or disconnect to/from VNC server

proc vnc_command {w what} {
    grab release $w
................................................................................
    destroy $w
    update
    switch -glob -- $what {
	disc* {
	    after idle {
		catch {.vnc disconnect}
	    }

	}
	conn* {
	    after idle vnc_connect
	}
    }
    tk busy forget .
}
................................................................................
	    }
	}
    }
}

vnc .vnc -bd 0 -relief flat -highlightthickness 0 -bg black \
    -infocommand vnc_info





pack .vnc -side top -fill both -expand 1

focus .vnc

if {$::VNC(android)} {
    wm withdraw .
}

# Android App lifecycle
bind . <<WillEnterBackground>> {vnc_lifecycle 1}
bind . <<WillEnterForeground>> {vnc_lifecycle 0}

# SDL2TK viewport and touchscreen
bind . <<ViewportUpdate>> {vnc_vp_finger %W v %x %y %X %Y %s}
bind . <<FingerDown>> {vnc_vp_finger %W d %x %y %X %Y %s}
bind . <<FingerMotion>> {vnc_vp_finger %W m %x %y %X %Y %s}
bind . <<FingerUp>> {vnc_vp_finger %W u %x %y %X %Y %s}

bind VNC <Control-Tab> {}
if {$::VNC(android)} {
    # Android back key
    bind VNC <Break> {vnc_settings ; break}
}
bind VNC <Control-F8> {vnc_settings ; break}







# initially bring up settings dialog












if {$::VNC(android)} {
    after idle {
	wm deiconify .

	vnc_settings



    }



} else {

    vnc_settings
}







<













>
>
>
>
>
>




|
|












>
>
>
>
|
<
<
<
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>





>

>


>







 







>
>
>
>
>
>
>


|







>
>

>










<

>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>







 







>







 







>
>
>
>
>
|
>










|










|
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>




>
|
>
>
>
|
>
>
>

>
|

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
...
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
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
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
#
# The "Back" key brings up the option dialog with entries for host,
# password etc. and buttons to exit and connect/disconnect.

package require vnc

if {[info command sdltk] eq "sdltk"} {

    wm attributes . -fullscreen 1
} else {
    wm geometry . 640x480
}

. configure -bg black

if {[info command borg] eq "borg"} {
    # on Android
    sdltk touchtranslate 13 ;# RMB, pan/zoom, fingers translated
    borg screenorientation landscape
    set ::VNC(android) 1
} else {
    if {[info command sdltk] eq "sdltk"} {
	if {[sdltk maxroot] eq {0 0}} {
	    sdltk touchtranslate 0
	}
	package require touchcal
    }
    set ::VNC(android) 0
}

array set ::VNCEV {fbits 0 trigger 0}
array set ::VNCSET {host {} pwd {} shared 0 viewonly 0 auto 0 lifecycle 0}
array set ::VNC {host {} auto 0 lastconnect 1 connected 0}

# callback on connection status change from VNC widget

proc vnc_info {data} {
    if {$::VNCSET(lifecycle)} {
	return
    }
    array set ::VNC $data
    if {$::VNC(lastconnect) && !$::VNC(connected)} {
	vnc_settings
    } elseif {!$::VNC(lastconnect) && $::VNC(connected)} {
	if {[info command sdltk] eq "sdltk"} {
	    set sw [winfo screenwidth .]
	    set sh [winfo screenheight .]
	    if {[sdltk maxroot] eq {0 0}} {
		set dosb 1
	    } elseif {[catch {sdltk root $::VNC(width) $::VNC(height)}]} {



		set dosb 1
	    } else {
		set dosb 0
	    }
	    if {$dosb} {
		if {$::VNC(width) <= $sw && $::VNC(height) <= $sh} {
		    set dosb 0
		}
	    }
	    if {$dosb} {
		if {$::VNC(width) > $sw - 20} {
		    if {![winfo exists .x]} {
			ttk::scrollbar .x -orient horizontal -takefocus 0 \
			    -command {.vnc xview}
			grid .x -row 1 -column 0 -sticky ew
			.vnc configure -xscrollcommand {.x set}
		    }
		    incr dosb
		} elseif {[winfo exists .x]} {
		    .vnc configure -xscrollcommand {}
		    destroy .x
		}
		if {$::VNC(height) > $sh - 20} {
		    if {![winfo exists .y]} {
			ttk::scrollbar .y -orient vertical -takefocus 0 \
			    -command {.vnc yview}
			grid .y -row 0 -column 1 -sticky ns
			.vnc configure -yscrollcommand {.y set}
		    }
		    incr dosb
		} elseif {[winfo exists .y]} {
		    .vnc configure -yscrollcommand {}
		    destroy .y
		}
		if {$dosb > 2} {
		    if {![winfo exists .f]} {
			frame .f
			grid .f -row 1 -column 1 -sticky nsew
		    }
		} elseif {[winfo exists .f]} {
		    destroy .f
		}
	    } else {
		if {[winfo exists .f]} {
		    destroy .f
		}
		if {[winfo exists .x]} {
		    .vnc configure -xscrollcommand {}
		    destroy .x
		}
		if {[winfo exists .y]} {
		    .vnc configure -yscrollcommand {}
		    destroy .y
		}
	    }
	} else {
	    wm geometry . "$::VNC(width)x$::VNC(height)"
	}
	set ::VNCSET(host) $::VNC(host)
	set ::VNCSET(shared) $::VNC(shared)
	set ::VNCSET(viewonly) $::VNC(viewonly)
	set ::VNCSET(auto) $::VNC(auto)
	if {![catch {open ~/vnc.set w} f]} {
	    catch {set ::VNCSET(pwd) [binary encode base64 $::VNCSET(pwd)]}
	    puts $f [array get ::VNCSET]
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	}
    }
    set ::VNC(lastconnect) $::VNC(connected)
}

# settings dialog

................................................................................
    grid $w.lp -in $w.f -row 1 -column 0 -sticky e -padx 5 -pady 5
    ttk::entry $w.pwd -textvariable ::VNCSET(pwd) -show "*"
    grid $w.pwd -in $w.f -row 1 -column 1 -sticky ew -padx 5 -pady 5
    ttk::checkbutton $w.shared -variable ::VNCSET(shared) -text "Shared"
    grid $w.shared -in $w.f -row 2 -column 1 -sticky w -padx 5 -pady 5
    ttk::checkbutton $w.vonly -variable ::VNCSET(viewonly) -text "View Only"
    grid $w.vonly -in $w.f -row 3 -column 1 -sticky w -padx 5 -pady 5
    ttk::checkbutton $w.auto -variable ::VNCSET(auto) -text "Auto Connect"
    grid $w.auto -in $w.f -row 4 -column 1 -sticky w -padx 5 -pady 5
    if {[info command sdltk] eq "sdltk" && !$::VNC(android)} {
	ttk::button $w.tcal -text "Calibrate Touchscreen ..." \
	    -command [list vnc_touchcal]
	grid $w.tcal -in $w.f -row 5 -column 0 -columnspan 2 -padx 5 -pady 5
    }
    ttk::frame $w.buttons
    grid $w.buttons -in $w.f \
	-row 6 -column 0 -columnspan 2 -sticky ew -padx 5 -pady 5
    if {$::VNC(connected)} {
	ttk::button $w.buttons.a -text "Disconnect" -width 12 \
	    -command [list vnc_command $w disc]
    } else {
	if {![catch {open ~/vnc.set} f]} {
	    catch {array set ::VNCSET [read $f 1024]}
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	    vnc_touchset
	}
	set ::VNCSET(auto) $::VNC(auto)
	ttk::button $w.buttons.a -text "Connect" -width 12 \
	    -command [list vnc_command $w conn]
    }
    ttk::button $w.buttons.x -text "Exit" -width 12 -command {
	destroy .vnc
	exit 0
    }
    ttk::button $w.buttons.c -text "Cancel" -width 12 \
	-command [subst {
	    grab release $w

	    destroy $w
	    focus .vnc
	}]
    pack $w.buttons.a $w.buttons.x $w.buttons.c -side left -expand 1 -padx 5
    if {$::VNC(android)} {
	bind $w <Break> [list $w.buttons.c invoke]
    }
    pack $w.f -side top -fill both -expand 1
    ::tk::PlaceWindow $w widget [winfo parent $w]
    grab $w
}

# perform touchscreen calibration

proc vnc_touchcal {} {
    set data [touchcal::calibrate .tcal]
    if {[llength $data]} {
	set ::VNCSET(touchcal) $data
	if {![catch {open ~/vnc.set w} f]} {
	    catch {set ::VNCSET(pwd) [binary encode base64 $::VNCSET(pwd)]}
	    puts $f [array get ::VNCSET]
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	}
	vnc_touchset
    }
}

# commit touchscreen calibration

proc vnc_touchset {} {
    if {[info command sdltk] eq "sdltk" && !$::VNC(android)} {
	if {[info exists ::VNCSET(touchcal)]} {
	    catch {sdltk touchcalibration {*}$::VNCSET(touchcal)}
	}
    }
}

# perform connect to VNC server

proc vnc_connect {} {
    set args $::VNCSET(host)
    lappend args $::VNCSET(pwd)
    if {$::VNCSET(shared)} {
................................................................................
    if {$::VNCSET(viewonly)} {
	lappend args "-viewonly"
    }
    if {[catch {.vnc connect {*}$args} err]} {
	tk_messageBox -title "Error" -message $err \
	    -type ok -icon error
	after idle vnc_settings
    } else {
	set ::VNC(auto) $::VNCSET(auto)
    }
}

# execute connect or disconnect to/from VNC server

proc vnc_command {w what} {
    grab release $w
................................................................................
    destroy $w
    update
    switch -glob -- $what {
	disc* {
	    after idle {
		catch {.vnc disconnect}
	    }
	    set ::VNC(auto) $::VNCSET(auto)
	}
	conn* {
	    after idle vnc_connect
	}
    }
    tk busy forget .
}
................................................................................
	    }
	}
    }
}

vnc .vnc -bd 0 -relief flat -highlightthickness 0 -bg black \
    -infocommand vnc_info
if {[info command sdltk] eq "sdltk"} {
    grid .vnc -row 0 -column 0 -sticky nsew
    grid rowconfigure . 0 -weight 1
    grid columnconfigure . 0 -weight 1
} else {
    pack .vnc -side top -fill both -expand 1
}
focus .vnc

if {$::VNC(android)} {
    wm withdraw .
}

# Android App lifecycle
bind . <<WillEnterBackground>> {vnc_lifecycle 1}
bind . <<WillEnterForeground>> {vnc_lifecycle 0}

# sdltk viewport and touchscreen
bind . <<ViewportUpdate>> {vnc_vp_finger %W v %x %y %X %Y %s}
bind . <<FingerDown>> {vnc_vp_finger %W d %x %y %X %Y %s}
bind . <<FingerMotion>> {vnc_vp_finger %W m %x %y %X %Y %s}
bind . <<FingerUp>> {vnc_vp_finger %W u %x %y %X %Y %s}

bind VNC <Control-Tab> {}
if {$::VNC(android)} {
    # Android back key
    bind VNC <Break> {vnc_settings ; break}
}
bind VNC <Control-F8> {
    # release control keys
    .vnc sendkey 0 0xFFE3
    .vnc sendkey 0 0xFFE4
    vnc_settings
    break
}

# initially bring up settings dialog or connect

apply {
    {} {
	if {![catch {open ~/vnc.set} f]} {
	    catch {array set ::VNCSET [read $f 1024]}
	    close $f
	    catch {set ::VNCSET(pwd) [binary decode base64 $::VNCSET(pwd)]}
	    vnc_touchset
	}
    }
}

if {$::VNC(android)} {
    after idle {
	wm deiconify .
	if {$::VNCSET(host) eq "" || !$::VNCSET(auto)} {
	    vnc_settings
	} else {
	    set ::VNC(lastconnect) 0
	    vnc_connect
	}
    }
} elseif {$::VNCSET(host) eq "" || !$::VNCSET(auto)} {
    vnc_settings
} else {
    set ::VNC(lastconnect) 0
    vnc_connect
}