bumblebee-status/bumblebee/input.py
Tobi-wan Kenobi 220bb9bf60 [core/input] Ugly hack for responsiveness
Somehow, the fix in the previous commit didn't work, it seems that
sometimes epoll() doesn't trigger, even if there is more data in
sys.stdin. I'm sure I'm doing something horribly wrong here.

Anyhow, as a quick fix, check for the open bracket to be sure to not
buffer the first event too long.
2016-12-17 08:04:21 +01:00

130 lines
3.6 KiB
Python

"""Input classes"""
import sys
import json
import uuid
import time
import select
import threading
import bumblebee.util
LEFT_MOUSE = 1
MIDDLE_MOUSE = 2
RIGHT_MOUSE = 3
WHEEL_UP = 4
WHEEL_DOWN = 5
def read_input(inp):
"""Read i3bar input and execute callbacks"""
epoll = select.epoll()
epoll.register(sys.stdin.fileno(), select.EPOLLIN)
f = open("/tmp/bee.log", "a")
while inp.running:
for thread in threading.enumerate():
if thread.name == "MainThread" and not thread.is_alive():
return
events = epoll.poll(1)
for fileno, event in events:
line = "["
while "[" in line:
line = sys.stdin.readline().strip(",").strip()
inp.has_event = True
try:
event = json.loads(line)
if "instance" in event:
inp.callback(event)
inp.redraw()
except ValueError:
pass
epoll.unregister(sys.stdin.fileno())
epoll.close()
inp.has_event = True
inp.clean_exit = True
class I3BarInput(object):
"""Process incoming events from the i3bar"""
def __init__(self):
self.running = True
self._callbacks = {}
self.clean_exit = False
self.global_id = str(uuid.uuid4())
self.need_event = False
self.has_event = False
self._condition = threading.Condition()
def start(self):
"""Start asynchronous input processing"""
self.has_event = False
self.running = True
self._condition.acquire()
self._thread = threading.Thread(target=read_input, args=(self,))
self._thread.start()
def redraw(self):
self._condition.acquire()
self._condition.notify()
self._condition.release()
def alive(self):
"""Check whether the input processing is still active"""
return self._thread.is_alive()
def wait(self, timeout):
self._condition.wait(timeout)
def _wait(self):
while not self.has_event:
time.sleep(0.1)
self.has_event = False
def stop(self):
"""Stop asynchronous input processing"""
self._condition.release()
if self.need_event:
self._wait()
self.running = False
self._thread.join()
return self.clean_exit
def _uuidstr(self, name, button):
return "{}::{}".format(name, button)
def _uid(self, obj, button):
uid = self.global_id
if obj:
uid = obj.id
return self._uuidstr(uid, button)
def deregister_callbacks(self, obj):
to_delete = []
uid = obj.id if obj else self.global_id
for key in self._callbacks:
if uid in key:
to_delete.append(key)
for key in to_delete:
del self._callbacks[key]
def register_callback(self, obj, button, cmd):
"""Register a callback function or system call"""
uid = self._uid(obj, button)
if uid not in self._callbacks:
self._callbacks[uid] = {}
self._callbacks[uid] = cmd
def callback(self, event):
"""Execute callback action for an incoming event"""
button = event["button"]
cmd = self._callbacks.get(self._uuidstr(self.global_id, button), None)
cmd = self._callbacks.get(self._uuidstr(event["name"], button), cmd)
cmd = self._callbacks.get(self._uuidstr(event["instance"], button), cmd)
if cmd is None:
return
if callable(cmd):
cmd(event)
else:
bumblebee.util.execute(cmd, False)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4