Version 48 of bll

Updated 2016-07-05 00:47:42 by bll

brad.lanam.comp _at_ gmail.com

Currently unemployed.

Tcl/Tk, C, perl, php, shell, MySQL/MariaDB, HTML, CSS, porting, legacy systems, system administration.

website:

http://gentoo.com/ (registered 1992-03-26) No, this is not gentoo linux, they're at http://gentoo.org/ (registered 1999-10-04).

projects:

BallroomDJ
A ballroom music player written in tcl/tk.

Created Pages:

Major Contribution:


Bugs filed:

Window screen height/width returns height/width of primary display: [L1 ]

Putting a window into fullscreen mode moves the window to the primary display: [L2 ]

Workaround:

    set vx [winfo vrootx .] ; # so we can tell if monitors are 1-2 or 2-1
    set vy [winfo vrooty .]

    wm state $w zoomed
    set nsh [winfo reqheight $w]
    set nsw [winfo reqwidth $w]
    wm overrideredirect $w yes
    if { $vx < 0 } {
      set nx $vx
    } else {
      set sw [winfo screenwidth .]
      set nx [expr {$sw+1}]
    }
    set ny 0
    wm geometry $w ${nsw}x${nsh}+$nx+0

(fixed) tk_getOpenFile crashes when passed a bad type variable (windows, new file interface) [L3 ]


Workaround for bug in 8.6.3 tk_getOpenFile:

  # work around 8.6.3 bug
  if { $fn == {} || [regexp {^after#} $fn] } {
    return
  }

Notes:


Using update rather than update idletasks prevents windows from putting the tk window into a not responding state.


tcltest's -relateddir doesn't sort the directories. This does not work if the tests are dependent on each other. Unfortunately, mine are. It is also a very poor choice for cross platform testing. This is fixed in a recent change (2016-7).


Windows starts up the tcl scripts with wish, which uses the wish icon. Starting with tclsh uses the icon set using 'wm iconbitmap'. So to get the wanted icon to display, restart the program with tclsh.

package require Tk

set tclsh [info nameofexecutable] 
if { [regexp {wish\d*.exe} $tclsh] } { 
  regsub {wish\d*.exe} $tclsh tclsh.exe tclsh 
  exec $tclsh [info script] & 
  exit 
} 
wm iconbitmap . -default [file join $myimages bdj_icon.ico] 

wm iconphoto only works with .gif files on windows, and only seems to allow a single image (despite the documentation).


ActiveState Tcl/Tk doesn't seem to get a dock icon. Everything seems to work with MacPorts Tcl/Tk.

Mac OSX application name in menubar:

a) Symlink the application name to the wish executable.

a1) It seems that CFBundleExecutable has to be the same name as the application name (this seems a bit odd -- the python examples don't have this issue).

a2) I needed to run wish during the installation to get the real wish executable path. It seems that stdout gets completely lost. I had to open a file and save the output there, then I could retrieve the information from the output file in the postinstall script.

a3) info nameofexecutable will return the symlink in (a).

b) Create Resources/Scripts/AppMain.tcl. This script is executed when (a) is run. Always. So I use:

set script [file normalize [file join \
    [file dirname [file dirname [file dirname [info script]]]] \
    MacOS MyApp.tcl]]

if { $argc > 0 } {
  set script [lindex $::argv 0]
  set ::argv [lrange $::argv 1 end]
}

source $script

so that the appropriate script is run. This does have the advantage that the application name in the menubar stays intact.

In general (from what I've read) it seems that the python users using the symlink trick have fewer problems getting their application name in the menubar. CFBundleExecutable doesn't have to match the application name, there's no startup script. Why is tk more complicated?


Why shrinking a window doesn't shrink the widget you want it to: https://groups.google.com/forum/#!topic/comp.lang.perl.tk/ZYD71t2tYDk

It would be nice if there was a way to configure this. Why doesn't shrinking the window honor the '-expand true' flags?

(Expanding the window honors the weight/expand flags. Shrinking the window uses the packing order of the widgets)


coroutines, the "wait for response" use case, and Tk.

There is a need to handle synchronous processing in Tk and let the event loop continue running. This is an area which is not well supported. There is a need for a parallel vwait, which does not exist at this time.

coroutines are not usable (from a maintenance perspective) for the "wait for response" use case in conjunction with the Tk event loop. It would be a maintenance nightmare.

vwait works, as long as you're aware of the nested vwait problem.

The only other alternative is writing wait loops and having short after timers in conjunction with vwait. Then even if the vwait is nested, the short timers should allow any nested vwaits to continue without much delay.

(I have no interest in people's comments on this. This page is just notes for my own purposes. See also TIP #374 for another example.)

#!/usr/bin/tclsh
#
# a simple echo response server for testing 
#

variable vars

proc mainSocketHandler { handler sock addr port } {
  chan configure $sock -blocking false
  chan configure $sock -buffering none
  fileevent $sock readable [list $handler $sock]
}

proc socketHandler { sock } {
  while { [gets $sock cmd] >= 0 } {
    puts "got $cmd"
    set tm [expr {(round(rand()*3)+1)*1000}]
    puts "waiting $tm"
    after $tm ; # emulate some delay
    puts "sending response to $cmd"
    puts $sock "$cmd response"
  }
}

proc main { } {
  variable vars

  set vars(sock) [socket -myaddr localhost \
      -server [list mainSocketHandler socketHandler] 35000]
}
main
vwait forever
#!/usr/bin/tclsh
#
# test program for synchronous response processing (works with wait loop).
#

package require Tk

variable vars

proc getcheck { sock varnm } {
  variable vars

  gets $sock resp
  if { $resp ne {} } {
    set vars(resp.$sock) $resp
    set $varnm 2
  } else {
    set $varnm 1
  }
}

proc sendget { sock msg } {
  variable vars

  puts $sock $msg
  # wait loop
  set vars(resp.$sock) {}
  while { 1 } {
    set vars(wait.$sock) 0
    after 20 [list getcheck $sock ::vars(wait.$sock)]
    vwait ::vars(wait.$sock)
    if { $vars(wait.$sock) == 2 } {
      set response $vars(resp.$sock)
      break
    }
  }
  return $response
}

proc getstatus { sock } {
  variable vars

  set resp [sendget $sock status]
  puts "getstatus: $resp"
  after 1000 [list getstatus $sock]
}

proc checkfileevent { sock } {
  variable vars

  set junk [read $vars(lsock.fe.in) 10000]
  set resp [sendget $sock fileevent]
  puts "fileevent:$resp"
}

proc localSocketHandler { sock addr port } {
  variable vars

  chan configure $sock -blocking false
  chan configure $sock -buffering line
  set vars(lsock.fe.in) $sock
  fileevent $sock readable [list checkfileevent $vars(sock.fe)]
}

proc douserdata { sock } {
  variable vars

  set resp [sendget $sock $vars(user.data)]
  puts "douserdata:$resp"
  set vars(user.resp) $resp
}

proc main { } {
  variable vars

  # set up some sockets for use by the various processes
  # getstatus will be a test for the after command
  set vars(sock.status) [socket localhost 35000]
  fconfigure $vars(sock.status) -blocking false
  fconfigure $vars(sock.status) -buffering line
  after 1000 [list getstatus $vars(sock.status)]

  # local socket to create fileevents
  set vars(lsock.main) [socket -myaddr localhost \
      -server [list localSocketHandler] 35001]

  set vars(sock.fe) [socket localhost 35000]
  fconfigure $vars(sock.fe) -blocking false
  fconfigure $vars(sock.fe) -buffering line

  set vars(sock.user) [socket localhost 35000]
  fconfigure $vars(sock.user) -blocking false
  fconfigure $vars(sock.user) -buffering line

  ttk::entry .e -textvariable vars(user.data)
  pack .e
  ttk::label .l -textvariable vars(user.resp)
  pack .l
  ttk::button .b -text go -command [list douserdata $vars(sock.user)]
  pack .b
}
main