From 918d7a60466577b729a7b9be16dfde735a5feb0f Mon Sep 17 00:00:00 2001 From: Tobi-wan Kenobi Date: Sat, 10 Dec 2016 10:26:07 +0100 Subject: [PATCH] [core/input] Add callback deregistration Enable components to unregister callbacks (i.e. for dynamic widgets). see #23 --- bumblebee/engine.py | 2 +- bumblebee/input.py | 24 ++++++++++++++++++++++-- tests/test_i3barinput.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/bumblebee/engine.py b/bumblebee/engine.py index caf43a7..f0b6e03 100644 --- a/bumblebee/engine.py +++ b/bumblebee/engine.py @@ -108,7 +108,7 @@ class Engine(object): self._output.flush() self._output.end() if self.running(): - time.sleep(1) + self.input.wait(self._config.get("interval", 1)) self._output.stop() self.input.stop() diff --git a/bumblebee/input.py b/bumblebee/input.py index b9f36f5..e92da99 100644 --- a/bumblebee/input.py +++ b/bumblebee/input.py @@ -18,6 +18,7 @@ def read_input(inp): try: event = json.loads(line) inp.callback(event) + inp.redraw() except ValueError: pass inp.has_event = True @@ -32,18 +33,28 @@ class I3BarInput(object): 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) @@ -51,18 +62,27 @@ class I3BarInput(object): 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 register_callback(self, obj, button, cmd): - """Register a callback function or system call""" + def _uid(self, obj): uid = self.global_id if obj: 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: self._callbacks[uid] = {} self._callbacks[uid][button] = cmd diff --git a/tests/test_i3barinput.py b/tests/test_i3barinput.py index 08fa036..1ae2864 100644 --- a/tests/test_i3barinput.py +++ b/tests/test_i3barinput.py @@ -61,6 +61,20 @@ class TestI3BarInput(unittest.TestCase): mock_input.readline.assert_any_call() 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") def test_global_callback_button_missmatch(self, mock_input): mock_input.readline.return_value = json.dumps({ @@ -87,6 +101,20 @@ class TestI3BarInput(unittest.TestCase): mock_input.readline.assert_any_call() 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") def test_widget_callback(self, mock_input): mock_input.readline.return_value = json.dumps({