diff --git a/core/module.py b/core/module.py index 07403ab..618cd6a 100644 --- a/core/module.py +++ b/core/module.py @@ -28,6 +28,7 @@ def load(module_name, config=core.config.Config([]), theme=None): ) return getattr(mod, "Module")(config, theme) except ImportError as e: + log.debug("failed to import {}: {}".format(module_name, e)) error = e log.fatal("failed to import {}: {}".format(module_name, error)) return Error(config=config, module=module_name, error=error) @@ -76,11 +77,12 @@ class Module(core.input.Object): self.__widgets = [module.widget()] self.update = module.update - def widgets(self, widgets=None): - if widgets: - self.__widgets = widgets + def widgets(self): return self.__widgets + def clear_widgets(self): + del self.__widgets[:] + def add_widget(self, full_text="", name=None): widget = core.widget.Widget(full_text=full_text, name=name, module=self) self.widgets().append(widget) diff --git a/docs/development/module.rst b/docs/development/module.rst index 816d8bf..6c1a6b5 100644 --- a/docs/development/module.rst +++ b/docs/development/module.rst @@ -72,7 +72,8 @@ Otherwise, you have a number of ways to handle widgets: - During the ``super().init__(...)`` inside the module’s constructor, you can specify a **list** of widgets, and those will comprise the widgets (in ordered fashion) - During runtime, you can set a new list of widgets by using -the ``self.widgets()`` method of the module +the ``self.add_widget()`` method of the module to add new widgets and +``self.clear_widgets()`` method to remove all widgets. Adding widgets at runtime ------------------------- diff --git a/docs/other/NOTES.md b/docs/other/NOTES.md index 81c6bf4..74cb652 100644 --- a/docs/other/NOTES.md +++ b/docs/other/NOTES.md @@ -16,10 +16,8 @@ ## TODO - themes: use colors to improve theme readability - convert some stuff to simple attributes to reduce LOCs -- use add_widget() instead of core.widget.Widget() - use widget index for bumblebee-ctl as alternative (??) # documentation Add info about error widget and events for error logging -- add module contributor doc - which location APIs are used? diff --git a/modules/contrib/battery.py b/modules/contrib/battery.py index 7843684..2428a25 100644 --- a/modules/contrib/battery.py +++ b/modules/contrib/battery.py @@ -26,7 +26,6 @@ except ImportError: log.warning('unable to import module "power": Time estimates will not be available') import core.module -import core.widget import core.input import util.format @@ -105,8 +104,7 @@ class BatteryManager(object): class Module(core.module.Module): def __init__(self, config, theme): - widgets = [] - super().__init__(config, theme, widgets) + super().__init__(config, theme, []) self.__manager = BatteryManager() @@ -123,17 +121,15 @@ class Module(core.module.Module): ) if util.format.asbool(self.parameter("compact-devices", False)): - widget = core.widget.Widget( - full_text=self.capacity, name="all-batteries", module=self + widget = self.add_widget( + full_text=self.capacity, name="all-batteries" ) - widgets.append(widget) else: for battery in self._batteries: log.debug("adding new widget for {}".format(battery)) - widget = core.widget.Widget( - full_text=self.capacity, name=battery, module=self + widget = self.add_widget( + full_text=self.capacity, name=battery ) - widgets.append(widget) for w in self.widgets(): if util.format.asbool(self.parameter("decorate", True)) == False: widget.set("theme.exclude", "suffix") diff --git a/modules/contrib/cmus.py b/modules/contrib/cmus.py index 093c367..c79e308 100644 --- a/modules/contrib/cmus.py +++ b/modules/contrib/cmus.py @@ -27,7 +27,6 @@ import os import string import core.module -import core.widget import core.input import core.decorators @@ -51,11 +50,9 @@ class Module(core.module.Module): self._tags = defaultdict(lambda: "") # Create widgets - widget_list = [] widget_map = {} for widget_name in self._layout.split(): - widget = core.widget.Widget(name=widget_name, module=self) - widget_list.append(widget) + widget = self.add_widget(name=widget_name) self._cmd = "cmus-remote" if self._server is not None: self._cmd = "{cmd} --server {server}".format( @@ -98,7 +95,6 @@ class Module(core.module.Module): widget_name=widget_name ) ) - self.widgets(widget_list) # Register input callbacks for widget, callback_options in widget_map.items(): diff --git a/modules/contrib/cpu2.py b/modules/contrib/cpu2.py index e03a140..1512681 100644 --- a/modules/contrib/cpu2.py +++ b/modules/contrib/cpu2.py @@ -37,7 +37,6 @@ contributed by `somospocos `_ - many thanks! import psutil import core.module -import core.widget import util.cli import util.graph @@ -53,27 +52,24 @@ class Module(core.module.Module): ) self.__widget_names = self.__layout.split() self.__colored = util.format.asbool(self.parameter("colored", False)) - widget_list = [] for widget_name in self.__widget_names: if widget_name == "cpu2.maxfreq": - widget = core.widget.Widget(name=widget_name, full_text=self.maxfreq) + widget = self.add_widget(name=widget_name, full_text=self.maxfreq) widget.set("type", "freq") elif widget_name == "cpu2.cpuload": - widget = core.widget.Widget(name=widget_name, full_text=self.cpuload) + widget = self.add_widget(name=widget_name, full_text=self.cpuload) widget.set("type", "load") elif widget_name == "cpu2.coresload": - widget = core.widget.Widget(name=widget_name, full_text=self.coresload) + widget = self.add_widget(name=widget_name, full_text=self.coresload) widget.set("type", "loads") elif widget_name == "cpu2.temp": - widget = core.widget.Widget(name=widget_name, full_text=self.temp) + widget = self.add_widget(name=widget_name, full_text=self.temp) widget.set("type", "temp") elif widget_name == "cpu2.fanspeed": - widget = core.widget.Widget(name=widget_name, full_text=self.fanspeed) + widget = self.add_widget(name=widget_name, full_text=self.fanspeed) widget.set("type", "fan") if self.__colored: widget.set("pango", True) - widget_list.append(widget) - self.widgets(widget_list) self.__temp_pattern = self.parameter("temp_pattern") if self.__temp_pattern is None: self.__temp = "n/a" diff --git a/modules/contrib/indicator.py b/modules/contrib/indicator.py index 25fc6d7..6b01c41 100644 --- a/modules/contrib/indicator.py +++ b/modules/contrib/indicator.py @@ -10,7 +10,6 @@ contributed by `freed00m `_ - many thanks! """ import core.module -import core.widget import util.cli import util.format @@ -42,8 +41,7 @@ class Module(core.module.Module): for indicator in self.__include: widget = self.widget(indicator) if not widget: - widget = core.widget.Widget(name=indicator, module=self) - self.widgets().append(widget) + widget = self.add_widget(name=indicator, full_text=indicator) widget.set( "status", @@ -51,7 +49,6 @@ class Module(core.module.Module): if "{}:on".format(indicator.lower()) in status_line.lower() else False, ) - widget.full_text(indicator) def state(self, widget): states = [] diff --git a/modules/contrib/mpd.py b/modules/contrib/mpd.py index 0b335ec..3efffff 100644 --- a/modules/contrib/mpd.py +++ b/modules/contrib/mpd.py @@ -53,7 +53,6 @@ import string import os import core.module -import core.widget import core.input import core.decorators @@ -80,11 +79,9 @@ class Module(core.module.Module): self._hostcmd = " -h " + self.parameter("host") # Create widgets - widget_list = [] widget_map = {} for widget_name in self._layout.split(): - widget = core.widget.Widget(name=widget_name, module=self) - widget_list.append(widget) + widget = self.add_widget(name=widget_name) if widget_name == "mpd.prev": widget_map[widget] = { @@ -118,7 +115,6 @@ class Module(core.module.Module): widget_name=widget_name ) ) - self.widgets(widget_list) # Register input callbacks for widget, callback_options in widget_map.items(): diff --git a/modules/contrib/rotation.py b/modules/contrib/rotation.py index dc7f317..13f656e 100644 --- a/modules/contrib/rotation.py +++ b/modules/contrib/rotation.py @@ -7,7 +7,6 @@ Requires the following executable: """ import core.module -import core.widget import core.input import util.cli @@ -34,7 +33,7 @@ class Module(core.module.Module): widget = self.widget(display) if not widget: - widget = core.widget.Widget(full_text=display, name=display) + widget = self.add_widget(full_text=display, name=display) core.input.register( widget, button=core.input.LEFT_MOUSE, cmd=self.__toggle ) diff --git a/modules/contrib/shortcut.py b/modules/contrib/shortcut.py index 1ffe9d0..4ea0a7c 100644 --- a/modules/contrib/shortcut.py +++ b/modules/contrib/shortcut.py @@ -26,7 +26,6 @@ LINK = "https://github.com/tobi-wan-kenobi/bumblebee-status/wiki" LABEL = "Click me" import core.module -import core.widget import core.input import core.decorators @@ -45,8 +44,6 @@ class Module(core.module.Module): def update_widgets(self): """ Creates a set of widget per user define shortcut.""" - widgets = self.widgets() - cmds = self.__cmds.split(self.__delim) labels = self.__labels.split(self.__delim) @@ -65,10 +62,8 @@ class Module(core.module.Module): cmd = cmds[idx] label = labels[idx] - widget = core.widget.Widget(full_text=label) + widget = self.add_widget(full_text=label) core.input.register(widget, button=core.input.LEFT_MOUSE, cmd=cmd) - widgets.append(widget) - # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/modules/contrib/smartstatus.py b/modules/contrib/smartstatus.py index 0d65422..2b886e3 100644 --- a/modules/contrib/smartstatus.py +++ b/modules/contrib/smartstatus.py @@ -16,7 +16,6 @@ import os import shutil import core.module -import core.widget import core.decorators import util.cli @@ -32,26 +31,22 @@ class Module(core.module.Module): self.display = self.parameter("display", "combined") self.drives = self.parameter("drives", "sda") self.show_names = util.format.asbool(self.parameter("show_names", True)) - self.widgets(self.create_widgets()) + self.create_widgets() def create_widgets(self): - widgets = [] if self.display == "combined": - widget = core.widget.Widget(module=self) + widget = self.add_widget() widget.set("device", "combined") widget.set("assessment", self.combined()) self.output(widget) - widgets.append(widget) else: for device in self.devices: if self.display == "singles" and device not in self.drives: continue - widget = core.widget.Widget(module=self) + widget = self.add_widget() widget.set("device", device) widget.set("assessment", self.smart(device)) self.output(widget) - widgets.append(widget) - return widgets def update(self): for widget in self.widgets(): diff --git a/modules/contrib/title.py b/modules/contrib/title.py index 30a3be6..33af47a 100644 --- a/modules/contrib/title.py +++ b/modules/contrib/title.py @@ -24,7 +24,6 @@ except ImportError: no_title = "n/a" import core.module -import core.widget import core.decorators import util.format @@ -41,14 +40,10 @@ class Module(core.module.Module): self.__title = "" # set output of the module - self.widgets( - [ - core.widget.Widget( - full_text=self.__scrolling_focused_title - if self.__scroll - else self.__focused_title - ) - ] + self.add_widget( + full_text=self.__scrolling_focused_title + if self.__scroll + else self.__focused_title ) # create a connection with i3ipc diff --git a/modules/contrib/traffic.py b/modules/contrib/traffic.py index 63e327b..42199c6 100644 --- a/modules/contrib/traffic.py +++ b/modules/contrib/traffic.py @@ -21,7 +21,6 @@ import psutil import netifaces import core.module -import core.widget import util.format import util.graph @@ -29,8 +28,7 @@ import util.graph class Module(core.module.Module): def __init__(self, config, theme): - widgets = [] - super().__init__(config, theme, widgets) + super().__init__(config, theme, []) self._exclude = tuple( filter( @@ -60,7 +58,7 @@ class Module(core.module.Module): if self._graphlen > 0: self._graphdata = {} self._first_run = True - self._update_widgets(widgets) + self._update_widgets() def state(self, widget): if "traffic.rx" in widget.name: @@ -70,12 +68,10 @@ class Module(core.module.Module): return self._status def update(self): - self._update_widgets(self.widgets()) + self._update_widgets() - def create_widget(self, widgets, name, txt=None, attributes={}): - widget = core.widget.Widget(name=name, module=self) - widget.full_text(txt) - widgets.append(widget) + def create_widget(self, name, txt=None, attributes={}): + widget = self.add_widget(name=name, full_text=txt) for key in attributes: widget.set(key, attributes[key]) @@ -114,12 +110,12 @@ class Module(core.module.Module): minwidth_str += "KiB/s" return minwidth_str - def _update_widgets(self, widgets): + def _update_widgets(self): interfaces = [ i for i in netifaces.interfaces() if not i.startswith(self._exclude) ] - del widgets[:] + self.clear_widgets() counters = psutil.net_io_counters(pernic=True) now = time.time() @@ -158,12 +154,11 @@ class Module(core.module.Module): name = "traffic-{}".format(interface) if self._showname: - self.create_widget(widgets, name, interface) + self.create_widget(name, interface) for direction in ["rx", "tx"]: name = "traffic.{}-{}".format(direction, interface) widget = self.create_widget( - widgets, name, attributes={"theme.minwidth": self.get_minwidth_str()}, ) diff --git a/modules/contrib/zpool.py b/modules/contrib/zpool.py index 504a027..8104819 100644 --- a/modules/contrib/zpool.py +++ b/modules/contrib/zpool.py @@ -33,7 +33,6 @@ from pkg_resources import parse_version log = logging.getLogger(__name__) import core.module -import core.widget import util.cli import util.format @@ -58,7 +57,7 @@ class Module(core.module.Module): self._warnfree = int(self.parameter("warnfree", default=10)) def update(self): - widgets = self.widgets() + self.clear_widgets() zfs_version_path = "/sys/module/zfs/version" # zpool list -H: List all zpools, use script mode (no headers and tabs as separators). try: @@ -77,9 +76,6 @@ class Module(core.module.Module): ("sudo " if self._usesudo else "") + "zpool list -H" ).split("\n") - for widget in widgets: - widget.set("visited", False) - for raw_zpool in raw_zpools: try: # Ignored fields (assigned to _) are 'expandsz' and 'altroot', also 'ckpoint' in ZFS 0.8.0+ @@ -136,10 +132,9 @@ class Module(core.module.Module): widget = self.widget(name) if not widget: - widget = core.widget.Widget(name=name) + widget = self.add_widget(name=name) widget.set("last_iostat", [0, 0, 0, 0]) widget.set("last_timestamp", 0) - widgets.append(widget) delta_iostat = [b - a for a, b in zip(iostat, widget.get("last_iostat"))] widget.set("last_iostat", iostat) @@ -183,9 +178,8 @@ class Module(core.module.Module): widget_w = self.widget(wname) widget_r = self.widget(rname) if not widget_w or not widget_r: - widget_r = core.widget.Widget(name=rname) - widget_w = core.widget.Widget(name=wname) - widgets.extend([widget_r, widget_w]) + widget_r = self.add_widget(name=rname) + widget_w = self.add_widget(name=wname) for w in [widget_r, widget_w]: w.set( "theme.minwidth", @@ -193,7 +187,6 @@ class Module(core.module.Module): ops=9999, band=util.format.bytefmt(999.99 * (1024 ** 2)) ), ) - w.set("visited", True) widget_w.full_text( self._ioformat.format( ops=round(writes), band=util.format.bytefmt(nwritten) @@ -205,10 +198,6 @@ class Module(core.module.Module): ) ) - for widget in widgets: - if widget.get("visited") is False: - widgets.remove(widget) - self.widgets(widgets) def state(self, widget): if widget.name.endswith("__read"): diff --git a/modules/core/git.py b/modules/core/git.py index e9966f6..c38f4a8 100644 --- a/modules/core/git.py +++ b/modules/core/git.py @@ -12,7 +12,6 @@ import os import pygit2 import core.module -import core.widget import util.cli @@ -28,15 +27,13 @@ class Module(core.module.Module): def update(self): state = {} - new_widgets = [] + self.clear_widgets() try: directory = util.cli.execute("xcwd").strip() directory = self.__get_git_root(directory) repo = pygit2.Repository(directory) - new_widgets.append( - core.widget.Widget(name="git.main", full_text=repo.head.shorthand) - ) + self.add_widget(name="git.main", full_text=repo.head.shorthand) for filepath, flags in repo.status().items(): if ( @@ -56,14 +53,12 @@ class Module(core.module.Module): state["modified"] = True self.__error = False if "new" in state: - new_widgets.append(core.widget.Widget(name="git.new")) + self.add_widget(name="git.new") if "modified" in state: - new_widgets.append(core.widget.Widget(name="git.modified")) + self.add_widget(name="git.modified") if "deleted" in state: - new_widgets.append(core.widget.Widget(name="git.deleted")) + self.add_widget(name="git.deleted") - self.widgets().clear() - self.widget(new_widgets) except Exception as e: self.__error = True diff --git a/modules/core/nic.py b/modules/core/nic.py index c92b7d3..a5f26b0 100644 --- a/modules/core/nic.py +++ b/modules/core/nic.py @@ -16,7 +16,6 @@ import shutil import netifaces import subprocess -import core.widget import core.module import core.decorators import util.cli @@ -87,14 +86,12 @@ class Module(core.module.Module): return retval def _update_widgets(self, widgets): + self.clear_widgets() interfaces = [ i for i in netifaces.interfaces() if not i.startswith(self._exclude) ] interfaces.extend([i for i in netifaces.interfaces() if i in self._include]) - for widget in widgets: - widget.set("visited", False) - for intf in interfaces: addr = [] state = "down" @@ -112,8 +109,7 @@ class Module(core.module.Module): widget = self.widget(intf) if not widget: - widget = core.widget.Widget(name=intf, module=self) - widgets.append(widget) + widget = self.add_widget(name=intf) # join/split is used to get rid of multiple whitespaces (in case SSID is not available, for instance widget.full_text( " ".join( @@ -127,11 +123,6 @@ class Module(core.module.Module): ) widget.set("intf", intf) widget.set("state", state) - widget.set("visited", True) - - for widget in widgets: - if widget.get("visited") is False: - widgets.remove(widget) def get_ssid(self, intf): if self._iswlan(intf) and self.iwgetid: diff --git a/modules/core/xrandr.py b/modules/core/xrandr.py index 8ca0167..7337fe5 100644 --- a/modules/core/xrandr.py +++ b/modules/core/xrandr.py @@ -21,7 +21,6 @@ import re import sys import core.module -import core.widget import core.input import core.decorators @@ -52,7 +51,7 @@ class Module(core.module.Module): self._needs_update = True def update(self): - new_widgets = [] + self.clear_widgets() if self._autoupdate == False and self._needs_update == False: return @@ -67,22 +66,18 @@ class Module(core.module.Module): widget = self.widget(display) if not widget: - widget = core.widget.Widget( - full_text=display, name=display, module=self + widget = self.add_widget( + full_text=display, name=display ) core.input.register(widget, button=1, cmd=self._toggle) core.input.register(widget, button=3, cmd=self._toggle) - new_widgets.append(widget) widget.set("state", "on" if m else "off") widget.set("pos", int(m.group(1)) if m else sys.maxsize) - self.widgets(new_widgets) - if self._autoupdate == False: - widget = core.widget.Widget(full_text="", module=self) + widget = self.add_widget(full_text="") widget.set("state", "refresh") core.input.register(widget, button=1, cmd=self._refresh) - self.widgets().append(widget) def state(self, widget): return widget.get("state", "off")