diff --git a/bumblebee/engine.py b/bumblebee/engine.py index f515470..f441269 100644 --- a/bumblebee/engine.py +++ b/bumblebee/engine.py @@ -71,7 +71,7 @@ class Module(object): return widget def errorWidget(self): - msg = self.error + msg = self.error or "n/a" if len(msg) > 10: msg = "{}...".format(msg[0:7]) return bumblebee.output.Widget(full_text="error: {}".format(msg)) @@ -264,14 +264,37 @@ class Engine(object): def run(self): """Start the event loop""" self._output.start() + event = None + last_full = time.time() + interval = float(self._config.get("interval", 1)) while self.running(): - self.write_output() + if event and time.time() - last_full < interval: + log.debug("partial output update ({} {} {})".format(event, time.time(), last_full)) + self.patch_output(event) + else: + log.debug("full update: {} {} ({})".format(time.time(), last_full, time.time() - last_full)) + last_full = time.time() + self.write_output() if self.running(): - self.input.wait(float(self._config.get("interval", 1))) + event = self.input.wait(interval) self._output.stop() self.input.stop() + def patch_output(self, event): + for module in self._modules: + widget = module.widget_by_id(event["instance"]) + if not widget: continue + # this widget was affected by the event -> update + module.update_wrapper(module.widgets()) + widget = module.errorWidget() + if module.error is None: + widget = module.widget_by_id(event["instance"]) + widget.link_module(module) + self._output.replace(event, module, widget) + self._output.flush() + self._output.end() + def write_output(self): self._output.begin() for module in self._modules: diff --git a/bumblebee/input.py b/bumblebee/input.py index 5fb3032..77c0693 100644 --- a/bumblebee/input.py +++ b/bumblebee/input.py @@ -45,6 +45,7 @@ def read_input(inp): try: event = json.loads(line) if "instance" in event: + inp.event = event inp.callback(event) inp.redraw() else: @@ -66,6 +67,7 @@ class I3BarInput(object): self.global_id = str(uuid.uuid4()) self.need_event = False self.has_event = False + self.event = None self._condition = threading.Condition() def start(self): @@ -87,6 +89,10 @@ class I3BarInput(object): def wait(self, timeout): self._condition.wait(timeout) + rv = self.event if self.has_event else None + log.debug("received input event: {}".format(rv)) + self.has_event = False + return rv def _wait(self): while not self.has_event: diff --git a/bumblebee/output.py b/bumblebee/output.py index 5c6ff92..169f6e1 100644 --- a/bumblebee/output.py +++ b/bumblebee/output.py @@ -105,6 +105,10 @@ class I3BarOutput(object): self._started = False self._config = config + def replace(self, event, module, new_widget): + data = self.widget_data(module, new_widget) + self._widgets = [w if not "instance" in w or w["instance"] != event["instance"] else data for w in self._widgets] + def started(self): return self._started @@ -117,22 +121,40 @@ class I3BarOutput(object): """Finish i3bar protocol""" sys.stdout.write("]\n") + def widget_data(self, module, widget): + full_text = widget.full_text() + padding = self._theme.padding(widget) + prefix = self._theme.prefix(widget, padding) + suffix = self._theme.suffix(widget, padding) + if prefix: + full_text = u"{}{}".format(prefix, full_text) + if suffix: + full_text = u"{}{}".format(full_text, suffix) + separator = self._theme.separator(widget) + width = self._theme.minwidth(widget) + + if width: + full_text = full_text.ljust(len(width) + len(prefix) + len(suffix)) + return { + u"full_text": full_text, + "color": self._theme.fg(widget), + "background": self._theme.bg(widget), + "separator_block_width": self._theme.separator_block_width(widget), + "separator": True if separator is None else False, + "min_width": None, + "align": self._theme.align(widget), + "instance": widget.id, + "name": module.id, + } + + def draw(self, widget, module=None, engine=None): """Draw a single widget""" - full_text = widget.full_text() if widget.get_module() and widget.get_module().hidden(): return if widget.get_module() and widget.get_module().name in self._config.autohide(): if not any(state in widget.state() for state in ["warning", "critical"]): return - padding = self._theme.padding(widget) - prefix = self._theme.prefix(widget, padding) - suffix = self._theme.suffix(widget, padding) - - if prefix: - full_text = u"{}{}".format(prefix, full_text) - if suffix: - full_text = u"{}{}".format(full_text, suffix) separator = self._theme.separator(widget) if separator: @@ -143,23 +165,8 @@ class I3BarOutput(object): "background": self._theme.separator_bg(widget), "separator_block_width": self._theme.separator_block_width(widget), }) - width = self._theme.minwidth(widget) - if width: - full_text = full_text.ljust(len(width) + len(prefix) + len(suffix)) - - self._widgets.append({ - u"full_text": full_text, - "color": self._theme.fg(widget), - "background": self._theme.bg(widget), - "separator_block_width": self._theme.separator_block_width(widget), - "separator": True if separator is None else False, - "min_width": None, -# "min_width": width + "A"*(len(prefix) + len(suffix)) if width else None, - "align": self._theme.align(widget), - "instance": widget.id, - "name": module.id, - }) + self._widgets.append(self.widget_data(module, widget)) def begin(self): """Start one output iteration""" diff --git a/bumblebee/util.py b/bumblebee/util.py index f3545ac..d41d024 100644 --- a/bumblebee/util.py +++ b/bumblebee/util.py @@ -20,7 +20,6 @@ def asbool(val): return val in ("t", "true", "y", "yes", "on", "1") def execute(cmd, wait=True): - logging.info("executing command '{}'".format(cmd)) args = shlex.split(cmd) proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) rv = None @@ -35,7 +34,6 @@ def execute(cmd, wait=True): else: rv = out - logging.info(u"command returned '{}'".format("" if not rv else rv)) return rv def bytefmt(num):