[core/input] Add callback deregistration
Enable components to unregister callbacks (i.e. for dynamic widgets). see #23
This commit is contained in:
parent
761b81970d
commit
918d7a6046
3 changed files with 51 additions and 3 deletions
|
@ -108,7 +108,7 @@ class Engine(object):
|
||||||
self._output.flush()
|
self._output.flush()
|
||||||
self._output.end()
|
self._output.end()
|
||||||
if self.running():
|
if self.running():
|
||||||
time.sleep(1)
|
self.input.wait(self._config.get("interval", 1))
|
||||||
|
|
||||||
self._output.stop()
|
self._output.stop()
|
||||||
self.input.stop()
|
self.input.stop()
|
||||||
|
|
|
@ -18,6 +18,7 @@ def read_input(inp):
|
||||||
try:
|
try:
|
||||||
event = json.loads(line)
|
event = json.loads(line)
|
||||||
inp.callback(event)
|
inp.callback(event)
|
||||||
|
inp.redraw()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
inp.has_event = True
|
inp.has_event = True
|
||||||
|
@ -32,18 +33,28 @@ class I3BarInput(object):
|
||||||
self.global_id = str(uuid.uuid4())
|
self.global_id = str(uuid.uuid4())
|
||||||
self.need_event = False
|
self.need_event = False
|
||||||
self.has_event = False
|
self.has_event = False
|
||||||
|
self._condition = threading.Condition()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start asynchronous input processing"""
|
"""Start asynchronous input processing"""
|
||||||
self.has_event = False
|
self.has_event = False
|
||||||
self.running = True
|
self.running = True
|
||||||
|
self._condition.acquire()
|
||||||
self._thread = threading.Thread(target=read_input, args=(self,))
|
self._thread = threading.Thread(target=read_input, args=(self,))
|
||||||
self._thread.start()
|
self._thread.start()
|
||||||
|
|
||||||
|
def redraw(self):
|
||||||
|
self._condition.acquire()
|
||||||
|
self._condition.notify()
|
||||||
|
self._condition.release()
|
||||||
|
|
||||||
def alive(self):
|
def alive(self):
|
||||||
"""Check whether the input processing is still active"""
|
"""Check whether the input processing is still active"""
|
||||||
return self._thread.is_alive()
|
return self._thread.is_alive()
|
||||||
|
|
||||||
|
def wait(self, timeout):
|
||||||
|
self._condition.wait(timeout)
|
||||||
|
|
||||||
def _wait(self):
|
def _wait(self):
|
||||||
while not self.has_event:
|
while not self.has_event:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
@ -51,18 +62,27 @@ class I3BarInput(object):
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stop asynchronous input processing"""
|
"""Stop asynchronous input processing"""
|
||||||
|
self._condition.release()
|
||||||
if self.need_event:
|
if self.need_event:
|
||||||
self._wait()
|
self._wait()
|
||||||
self.running = False
|
self.running = False
|
||||||
self._thread.join()
|
self._thread.join()
|
||||||
return self.clean_exit
|
return self.clean_exit
|
||||||
|
|
||||||
def register_callback(self, obj, button, cmd):
|
def _uid(self, obj):
|
||||||
"""Register a callback function or system call"""
|
|
||||||
uid = self.global_id
|
uid = self.global_id
|
||||||
if obj:
|
if obj:
|
||||||
uid = obj.id
|
uid = obj.id
|
||||||
|
return uid
|
||||||
|
|
||||||
|
def deregister_callbacks(self, obj):
|
||||||
|
uid = self._uid(obj)
|
||||||
|
if uid in self._callbacks:
|
||||||
|
del self._callbacks[uid]
|
||||||
|
|
||||||
|
def register_callback(self, obj, button, cmd):
|
||||||
|
"""Register a callback function or system call"""
|
||||||
|
uid = self._uid(obj)
|
||||||
if uid not in self._callbacks:
|
if uid not in self._callbacks:
|
||||||
self._callbacks[uid] = {}
|
self._callbacks[uid] = {}
|
||||||
self._callbacks[uid][button] = cmd
|
self._callbacks[uid][button] = cmd
|
||||||
|
|
|
@ -61,6 +61,20 @@ class TestI3BarInput(unittest.TestCase):
|
||||||
mock_input.readline.assert_any_call()
|
mock_input.readline.assert_any_call()
|
||||||
self.assertTrue(self._called > 0)
|
self.assertTrue(self._called > 0)
|
||||||
|
|
||||||
|
@mock.patch("sys.stdin")
|
||||||
|
def test_remove_global_callback(self, mock_input):
|
||||||
|
mock_input.readline.return_value = json.dumps({
|
||||||
|
"name": "somename",
|
||||||
|
"instance": "someinstance",
|
||||||
|
"button": bumblebee.input.LEFT_MOUSE,
|
||||||
|
})
|
||||||
|
self.input.register_callback(None, button=1, cmd=self.callback)
|
||||||
|
self.input.deregister_callbacks(None)
|
||||||
|
self.input.start()
|
||||||
|
self.assertEquals(self.input.stop(), True)
|
||||||
|
mock_input.readline.assert_any_call()
|
||||||
|
self.assertTrue(self._called == 0)
|
||||||
|
|
||||||
@mock.patch("sys.stdin")
|
@mock.patch("sys.stdin")
|
||||||
def test_global_callback_button_missmatch(self, mock_input):
|
def test_global_callback_button_missmatch(self, mock_input):
|
||||||
mock_input.readline.return_value = json.dumps({
|
mock_input.readline.return_value = json.dumps({
|
||||||
|
@ -87,6 +101,20 @@ class TestI3BarInput(unittest.TestCase):
|
||||||
mock_input.readline.assert_any_call()
|
mock_input.readline.assert_any_call()
|
||||||
self.assertTrue(self._called > 0)
|
self.assertTrue(self._called > 0)
|
||||||
|
|
||||||
|
@mock.patch("sys.stdin")
|
||||||
|
def test_remove_module_callback(self, mock_input):
|
||||||
|
mock_input.readline.return_value = json.dumps({
|
||||||
|
"name": self.anyModule.id,
|
||||||
|
"instance": None,
|
||||||
|
"button": bumblebee.input.LEFT_MOUSE,
|
||||||
|
})
|
||||||
|
self.input.register_callback(self.anyModule, button=1, cmd=self.callback)
|
||||||
|
self.input.deregister_callbacks(self.anyModule)
|
||||||
|
self.input.start()
|
||||||
|
self.assertEquals(self.input.stop(), True)
|
||||||
|
mock_input.readline.assert_any_call()
|
||||||
|
self.assertTrue(self._called == 0)
|
||||||
|
|
||||||
@mock.patch("sys.stdin")
|
@mock.patch("sys.stdin")
|
||||||
def test_widget_callback(self, mock_input):
|
def test_widget_callback(self, mock_input):
|
||||||
mock_input.readline.return_value = json.dumps({
|
mock_input.readline.return_value = json.dumps({
|
||||||
|
|
Loading…
Reference in a new issue