File size: 5,319 Bytes
288007d |
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 |
#!/bin/sh
# the next line restarts using wish \
exec wish8.6 "$0" ${1+"$@"}
# rmt --
# This script implements a simple remote-control mechanism for
# Tk applications. It allows you to select an application and
# then type commands to that application.
package require Tk
wm title . "Tk Remote Controller"
wm iconname . "Tk Remote"
wm minsize . 1 1
# The global variable below keeps track of the remote application
# that we're sending to. If it's an empty string then we execute
# the commands locally.
set app "local"
# The global variable below keeps track of whether we're in the
# middle of executing a command entered via the text.
set executing 0
# The global variable below keeps track of the last command executed,
# so it can be re-executed in response to !! commands.
set lastCommand ""
# Create menu bar. Arrange to recreate all the information in the
# applications sub-menu whenever it is cascaded to.
. configure -menu [menu .menu]
menu .menu.file
menu .menu.file.apps -postcommand fillAppsMenu
.menu add cascade -label "File" -underline 0 -menu .menu.file
.menu.file add cascade -label "Select Application" -underline 0 \
-menu .menu.file.apps
.menu.file add command -label "Quit" -command "destroy ." -underline 0
# Create text window and scrollbar.
text .t -yscrollcommand ".s set" -setgrid true
scrollbar .s -command ".t yview"
grid .t .s -sticky nsew
grid rowconfigure . 0 -weight 1
grid columnconfigure . 0 -weight 1
# Create a binding to forward commands to the target application,
# plus modify many of the built-in bindings so that only information
# in the current command can be deleted (can still set the cursor
# earlier in the text and select and insert; just can't delete).
bindtags .t {.t Text . all}
bind .t <Return> {
.t mark set insert {end - 1c}
.t insert insert \n
invoke
break
}
bind .t <Delete> {
catch {.t tag remove sel sel.first promptEnd}
if {[.t tag nextrange sel 1.0 end] eq ""} {
if {[.t compare insert < promptEnd]} {
break
}
}
}
bind .t <BackSpace> {
catch {.t tag remove sel sel.first promptEnd}
if {[.t tag nextrange sel 1.0 end] eq ""} {
if {[.t compare insert <= promptEnd]} {
break
}
}
}
bind .t <Control-d> {
if {[.t compare insert < promptEnd]} {
break
}
}
bind .t <Control-k> {
if {[.t compare insert < promptEnd]} {
.t mark set insert promptEnd
}
}
bind .t <Control-t> {
if {[.t compare insert < promptEnd]} {
break
}
}
bind .t <Meta-d> {
if {[.t compare insert < promptEnd]} {
break
}
}
bind .t <Meta-BackSpace> {
if {[.t compare insert <= promptEnd]} {
break
}
}
bind .t <Control-h> {
if {[.t compare insert <= promptEnd]} {
break
}
}
### This next bit *isn't* nice - DKF ###
auto_load tk::TextInsert
proc tk::TextInsert {w s} {
if {$s eq ""} {
return
}
catch {
if {
[$w compare sel.first <= insert] && [$w compare sel.last >= insert]
} then {
$w tag remove sel sel.first promptEnd
$w delete sel.first sel.last
}
}
$w insert insert $s
$w see insert
}
.t configure -font {Courier 12}
.t tag configure bold -font {Courier 12 bold}
# The procedure below is used to print out a prompt at the
# insertion point (which should be at the beginning of a line
# right now).
proc prompt {} {
global app
.t insert insert "$app: "
.t mark set promptEnd {insert}
.t mark gravity promptEnd left
.t tag add bold {promptEnd linestart} promptEnd
}
# The procedure below executes a command (it takes everything on the
# current line after the prompt and either sends it to the remote
# application or executes it locally, depending on "app".
proc invoke {} {
global app executing lastCommand
set cmd [.t get promptEnd insert]
incr executing 1
if {[info complete $cmd]} {
if {$cmd eq "!!\n"} {
set cmd $lastCommand
} else {
set lastCommand $cmd
}
if {$app eq "local"} {
set result [catch [list uplevel #0 $cmd] msg]
} else {
set result [catch [list send $app $cmd] msg]
}
if {$result != 0} {
.t insert insert "Error: $msg\n"
} elseif {$msg ne ""} {
.t insert insert $msg\n
}
prompt
.t mark set promptEnd insert
}
incr executing -1
.t yview -pickplace insert
}
# The following procedure is invoked to change the application that
# we're talking to. It also updates the prompt for the current
# command, unless we're in the middle of executing a command from
# the text item (in which case a new prompt is about to be output
# so there's no need to change the old one).
proc newApp appName {
global app executing
set app $appName
if {!$executing} {
.t mark gravity promptEnd right
.t delete "promptEnd linestart" promptEnd
.t insert promptEnd "$appName: "
.t tag add bold "promptEnd linestart" promptEnd
.t mark gravity promptEnd left
}
return
}
# The procedure below will fill in the applications sub-menu with a list
# of all the applications that currently exist.
proc fillAppsMenu {} {
set m .menu.file.apps
catch {$m delete 0 last}
foreach i [lsort [winfo interps]] {
$m add command -label $i -command [list newApp $i]
}
$m add command -label local -command {newApp local}
}
set app [winfo name .]
prompt
focus .t
# Local Variables:
# mode: tcl
# End:
|