File: idletime.tcl

package info (click to toggle)
coccinella 0.96.20-7
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 13,108 kB
  • ctags: 5,908
  • sloc: tcl: 124,744; xml: 206; makefile: 66; sh: 62
file content (188 lines) | stat: -rw-r--r-- 3,859 bytes parent folder | download | duplicates (4)
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
# idletime.tcl ---
#
#       Set global idle time callbacks.
#       
#  Copyright (c) 2007-2008
#  
#  This file is distributed under BSD style license.
#  
#  $Id: idletime.tcl,v 1.11 2008-07-30 13:23:59 matben Exp $

package require Tk 8.5
package provide idletime 1.0

namespace eval ::idletime {

    variable lastmouse [winfo pointerxy .]
    variable state
    variable status "stop"
    
    # Keep a 2 secs resolution which should be enough for autoaway.
    variable pollms 2000
    variable tclidlems 0
    variable inactiveProc
    
    # Fallback pure tcl method.
    set inactiveProc [namespace code tclinactive]

    if {[catch {tk inactive}] || ([tk inactive] < 0)} {

	switch -- $::tcl_platform(platform) {
	    unix {
		if {$::tcl_platform(os) eq "Darwin"} {
		    if {[catch {package require carbon 0.2}]} {
			set inactiveProc [namespace code AquaIdleTime]
		    } else {
			set inactiveProc {carbon::inactive}			
		    }
		} else {
		    if {![catch {package require tkinactive}]} {
			set inactiveProc tkinactive
		    }
		}
	    }
	    windows {
		if {![catch {package require tkinactive}]} {
		    set inactiveProc tkinactive
		}
	    }
	}
    } else {
	set inactiveProc {tk inactive}
    }
}

proc ::idletime::init {} {
    variable inactiveProc
    variable status 
    
    # Protect from multiple calls.
    if {$status eq "run"} {
	return
    }
    set status "run"
    if {$inactiveProc eq [namespace code tclinactive]} {
	tcltimer
    }
    poll
}

proc ::idletime::stop {} {
    variable afterID
    variable status 
    
    set status "stop"
    foreach key {poll tcl} {
	if {[info exists afterID($key)]} {
	    after cancel $afterID($key)
	    unset afterID($key)
	}
    }
}

# idletime::add --
# 
#       Adds or replaces a callback.

proc ::idletime::add {procName secs} {
    variable state
    variable shot
    
    set state($procName) $secs
    set shot($procName) 0
}

proc ::idletime::remove {procName} {
    variable state
    variable shot
    
    unset -nocomplain state($procName)
    unset -nocomplain shot($procName)    
}

proc ::idletime::poll {} {
    variable state
    variable shot
    variable pollms
    variable inactiveProc
    variable afterID
    variable status 
    
    set idlesecs [expr {[eval $inactiveProc]/1000}]
   
    foreach {name secs} [array get state] {
	
	# Protect for the situation where any handler is removed when
	# doing the callback! [Bug #196306]
	if {![info exists state($name)]} {
	    continue
	}
	if {$idlesecs >= $secs} {
	    
	    # Fire!
	    if {!$shot($name)} {
		set shot($name) 1
		uplevel #0 $name idle
	    }
	} else {
	    if {$shot($name)} {
		set shot($name) 0
		uplevel #0 $name active
	    }
	}
    }
    
    # We might have been stopped from a callback!
    if {$status eq "run"} {
	set afterID(poll) [after $pollms [namespace code poll]]
    }
}

# Pure tcl implementation that handles mouse moves only.

proc ::idletime::tclinactive {} {
    variable tclidlems
    return [expr {$tclidlems/1000}]
}

proc ::idletime::tcltimer {} {
    variable lastmouse
    variable pollms
    variable tclidlems
    variable afterID
    
    set mouse [winfo pointerxy .]
    if {$mouse eq $lastmouse} {
	incr tclidlems $pollms
    } else {
	set tclidlems 0
    }
    set lastmouse $mouse
    set afterID(tcl) [after $pollms [namespace code tcltimer]]
}

# idletime::AquaIdleTime --
# 
#       Returns the idle time in seconds. Better to use carbon::inactive.

proc ::idletime::AquaIdleTime {} {
    
    if {[catch { 
	set fd [open {|ioreg -x -c IOHIDSystem}]
	set line [read $fd] 
	close $fd
    }]} {
	return 0
    }
    set minms 1000000
    set match [regexp -all -inline {"HIDIdleTime" = (?:0x|<)([[:xdigit:]]+)} $line]
    foreach {m nsecs} $match {
	set ms [expr {"0x$nsecs"/1000000}]
	if {$ms < $minms} {
	    set minms $ms
	}
    }
    return $minms
}