Skip to content

Instantly share code, notes, and snippets.

@yyamasak
Created June 21, 2016 05:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yyamasak/a360ae573025016fe3e06e706ffe5066 to your computer and use it in GitHub Desktop.
Save yyamasak/a360ae573025016fe3e06e706ffe5066 to your computer and use it in GitHub Desktop.
Replaces Tcl's after command by twapi::wait_on_handle to use monotonic timer on Windows
package require twapi
if {![namespace exists twapi_timer]} {
namespace eval twapi_timer {
variable ids
array set ids {}
}
}
proc twapi_timer::_timer_handler {script hevent sig} {
cancel $hevent
uplevel #0 $script
}
proc twapi_timer::handle_type {hevent} {
set arg1 [lindex $hevent 0]
set arg2 [lindex $hevent 1]
if {[string is integer -strict $arg1] && "HANDLE" eq $arg2} {
set type "hevent"
} elseif {[string match "after\#*" $hevent]} {
set type "after"
} else {
set type "script"
}
return $type
}
proc twapi_timer::after {args} {
variable ids
set argc [llength $args]
switch -exact -- $argc {
0 {
::tcl_after
}
1 {
set arg0 [lindex $args 0]
switch -exact -- $arg0 {
info {
return [array names ids]
}
default {
set ms $arg0
set hevent [twapi_timer::create_event]
twapi::wait_on_handle $hevent -wait $ms
return
}
}
}
2 {
set arg0 [lindex $args 0]
set arg1 [lindex $args 1]
switch -exact -- $arg0 {
cancel {
switch -exact -- [handle_type $arg1] {
hevent -
after {
set hevent $arg1
cancel $hevent
}
script {
set script $arg1
foreach hevent [array names ids] {
if {$script eq $ids($hevent)} {
cancel $hevent
}
}
}
}
return
}
idle {
set script $arg1
set hevent [::tcl_after idle $script]
return $hevent
}
info {
set hevent [lindex $args 1]
if {[info exists ids($hevent)]} {
set script $ids($hevent)
return [list $script timer]
} else {
return
}
}
default {
set ms $arg0
set script [lindex $args 1]
}
}
}
default {
set arg0 [lindex $args 0]
set script [lrange $args 1 end]
switch -exact -- $arg0 {
cancel {
foreach hevent [array names ids] {
if {$script eq $ids($hevent)} {
cancel $hevent
}
}
return
}
idle {
set hevent [::tcl_after idle $script]
return $hevent
}
default {
set ms $arg0
}
}
}
}
set hevent [twapi_timer::create_event]
twapi::wait_on_handle $hevent -wait $ms -async [namespace code [list _timer_handler $script]]
set ids($hevent) $script
return $hevent
}
proc twapi_timer::create_event {} {
variable ids
set hevent [twapi::create_event]
if {[info exists ids($hevent)]} {
twapi_timer::_close_handle $hevent
set hevent [create_event]
}
return $hevent
}
proc twapi_timer::cancel {hevent} {
variable ids
if {[info exists ids($hevent)]} {
switch [handle_type $hevent] {
hevent {
if {[catch {twapi::cancel_wait_on_handle $hevent} err]} {
log Debg "twapi::cancel_wait_on_handle $hevent -> err=$err"
}
_close_handle $hevent
}
after {
::tcl_after cancel $hevent
}
}
array unset ids $hevent
}
}
proc twapi_timer::_close_handle {hevent} {
if {[catch {twapi::close_handle $hevent} err]} {
log Debg "twapi::close_handle $hevent -> err=$err"
}
}
if {[info commands ::tcl_after] ne "::tcl_after"} {
rename ::after ::tcl_after
interp alias {} ::after {} ::twapi_timer::after
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment