--- /dev/null
+#!/usr/bin/env python
+
+# This software is copyright Neil Brown 2009.
+# It is licensed to you under the terms of the
+# GNU General Public License version 2.
+#
+#
+# blank and lock the screen when there is no activity.
+#
+# We detect activity by watching touch screen, power button,
+# aux button
+# After a period with no activity, we drop brightness to 20%
+# and Grab all devices.
+# Any activity at this stage returns us to 100% and no grab
+# Continued inactivity turns display off. After that, require
+# a button (AUX or Power) to reactivate.
+#
+# If the device seems really idle, we suspend with "apm -s"
+# Other applications can disable this by getting a LOCK_SH
+# lock on /var/run/suspend_disabled
+#
+
+import gobject
+import gtk
+import fcntl
+import os
+import sys
+import struct
+import time
+from subprocess import Popen, PIPE
+
+class EvDev:
+ def __init__(self, path, on_event):
+ self.f = os.open(path, os.O_RDWR|os.O_NONBLOCK);
+ self.ev = gobject.io_add_watch(self.f, gobject.IO_IN, self.read)
+ self.on_event = on_event
+ self.grabbed = False
+ self.downlist = []
+ def read(self, x, y):
+ try:
+ str = os.read(self.f, 16)
+ except:
+ return True
+
+ if len(str) != 16:
+ return True
+ (sec,usec,typ,code,value) = struct.unpack_from("IIHHI", str)
+ if typ == 0x01:
+ # KEY event
+ if value == 0:
+ # 'up' - remove from downlist
+ if code in self.downlist:
+ del self.downlist[self.downlist.index(code)]
+ else:
+ # 'down' - add to downlist
+ if code not in self.downlist:
+ self.downlist.append(code)
+ self.on_event(self.down_count(), typ, code, value)
+ return True
+ def down_count(self):
+ return len(self.downlist)
+
+ def grab(self):
+ if self.grabbed:
+ return
+ #print "grab"
+ fcntl.ioctl(self.f, EVIOC_GRAB, 1)
+ self.grabbed = True
+ def ungrab(self):
+ if not self.grabbed:
+ return
+ #print "release"
+ fcntl.ioctl(self.f, EVIOC_GRAB, 0)
+ self.grabbed = False
+
+FBIOBLANK = 0x4611
+FB_BLANK_UNBLANK = 0
+FB_BLANK_POWERDOWN = 4
+
+EVIOC_GRAB = 0x40044590
+
+class Screen:
+ def __init__(self):
+ self.state = "unknown"
+ f = open("/sys/class/backlight/gta02-bl/max_brightness")
+ self.max = int(f.read())
+ f.close()
+ def bright(self, pcent):
+ b = int(pcent * self.max / 100)
+ f = open("/sys/class/backlight/gta02-bl/brightness","w")
+ f.write("%d\n" % b)
+ f.close()
+ def power(self, ioc):
+ f = open("/dev/fb0", "r+")
+ fcntl.ioctl(f, FBIOBLANK, ioc)
+ f.close()
+ def on(self):
+ if self.state != "on":
+ self.power(FB_BLANK_UNBLANK)
+ self.state = "on"
+ self.bright(100)
+ def dim(self):
+ if self.state != "on":
+ self.power(FB_BLANK_UNBLANK)
+ self.state = "on"
+ self.bright(20)
+ def off(self):
+ self.bright(0)
+ if self.state != "off":
+ self.power(FB_BLANK_POWERDOWN)
+ self.state = "off"
+
+def grab_all():
+ global screen, power, aux
+ screen.grab()
+ power.grab()
+ aux.grab()
+
+def release_all():
+ global screen, power, aux
+ screen.ungrab()
+ power.ungrab()
+ aux.ungrab()
+
+timeout = None
+state = "full"
+dimtime = 15
+enable_suspend = True
+def set_timeout():
+ global timeout
+ global state, enable_suspend
+ global dimtime
+ #print "set timeout for", state
+ if timeout != None:
+ gobject.source_remove(timeout)
+ if state == "full":
+ timeout = gobject.timeout_add(dimtime*1000, set_dim)
+ elif state == "dim":
+ timeout = gobject.timeout_add(10*1000, set_off)
+ elif state == "insta-lock":
+ timeout = gobject.timeout_add(1000, set_off)
+ elif state == "off" and enable_suspend:
+ timeout = gobject.timeout_add(30*1000, set_suspend)
+
+ set_ico_file()
+
+def set_dim():
+ global state
+ global aux, power, screen
+ if aux.down_count() + power.down_count() + screen.down_count() > 0:
+ # button still down
+ set_timeout()
+ return
+ display.dim()
+ grab_all()
+ state = "dim"
+ set_timeout()
+
+def set_off():
+ global state, dimtime
+ display.off()
+ state = "off"
+ set_timeout()
+ dimtime = 15
+
+def read_num(filename, default = 0, sep = None):
+ try:
+ f = open(filename)
+ except:
+ f = [ "%d" % default ]
+ num = default
+ for l in f:
+ l = l.split(sep)[0].strip()
+ try:
+ num = float(l)
+ break
+ except:
+ num = default
+ return num
+
+#Active Internet connections (w/o servers)
+#Proto Recv-Q Send-Q Local Address Foreign Address State
+#tcp 0 48 192.168.2.202:22 192.168.2.200:34244 ESTABLISHED
+#tcp 0 0 192.168.2.202:22 192.168.2.200:41473 ESTABLISHED
+def external_tcp():
+ # check for TCP connections to external computers.
+ netstat = Popen(['netstat','-nt'], stdout = PIPE, close_fds = True)
+ for l in netstat.stdout:
+ l = l.strip()
+ f = l.split()
+ if f[0] != "tcp" or f[5] != 'ESTABLISHED':
+ continue
+ a = f[4].split(':')
+ if a[0] != "127.0.0.1":
+ return True
+ return False
+
+def set_suspend():
+ global state, display
+ # Check for lock file
+ try:
+ f = open("/var/run/suspend_disabled", "r+")
+ except:
+ f = None
+ if f:
+ try:
+ fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ except:
+ set_timeout()
+ return
+
+ # Check for loadavg > 0.5
+ load = read_num("/proc/loadavg")
+ if load > 0.5:
+ set_timeout()
+ return
+
+ # Check for USB power, at least 500mA
+ current = read_num("/sys/class/i2c-adapter/i2c-0/0-0073/pcf50633-mbc/usb_curlim")
+ if current >= 500:
+ set_timeout()
+ return
+
+ #if external_tcp():
+ # set_timeout()
+ # return
+
+ os.system("apm -s")
+ if f:
+ f.close()
+ state = "full"
+ set_timeout()
+ display.on()
+
+def wake_all(down_cnt, *rest):
+ global state, dimtime
+ #print "wake all"
+ display.on()
+ if down_cnt == 0:
+ release_all()
+ if state == "dim" and dimtime < 120:
+ dimtime += 15
+ if state != "disable":
+ state = "full"
+ set_timeout()
+
+def wake_dim(down_cnt, *rest):
+ global state
+ #print "wake_dim"
+ if state == "dim" or state == "full":
+ wake_all(down_cnt)
+
+
+ico_file = None
+def set_ico_file():
+ global state, ico_file, ico
+ if state == "disable":
+ file = "lock-no.png"
+ elif state == "full":
+ if enable_suspend:
+ file = "lock-un.png"
+ else:
+ file = "lock-un-nosusp.png"
+ else:
+ if enable_suspend:
+ file = "lock.png"
+ else:
+ file = "lock-nosusp.png"
+ if file != ico_file:
+ ico.set_from_file("/usr/local/pixmaps/" + file)
+ ico_file = file
+
+last_ping = 0
+prev_ping = 0
+def ping(icon):
+ global state, enable_suspend, last_ping, prev_ping
+ if time.time() - prev_ping < 0.8:
+ grab_all()
+ state = "insta-lock"
+ elif state == "disable":
+ enable_suspend = False
+ state = "full"
+ elif not enable_suspend:
+ enable_suspend = True
+ state = "full"
+ else:
+ state = "disable"
+ prev_ping = last_ping
+ last_ping = time.time()
+ set_timeout()
+
+def main():
+ global display, ico
+ global screen, power, aux
+ aux = EvDev("/dev/input/event4", wake_all)
+ power = EvDev("/dev/input/event0", wake_all)
+ screen = EvDev("/dev/input/event1", wake_dim)
+ state = "full"
+ display = Screen()
+ display.on()
+ ico = gtk.StatusIcon()
+ set_timeout()
+ ico.connect("activate", ping)
+
+ gtk.main()
+
+main()