diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 8d95d41..0000000 --- a/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -#start with a Python 3.x container -FROM python:3 - -#grab repository from github -RUN git clone --recursive https://github.com/tobi-wan-kenobi/bumblebee-status.git /var/bumblebee-status -#run the statusline with no modules or themes specified -CMD python3 /var/bumblebee-status/bumblebee-status diff --git a/Makefile b/Makefile deleted file mode 100644 index b542958..0000000 --- a/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -DEBIAN_ROOT = build/debian/bumblebee-status/ - -deb: - mkdir -p $(DEBIAN_ROOT)/DEBIAN - mkdir -p $(DEBIAN_ROOT)/usr/share/bumblebee-status/modules - mkdir -p $(DEBIAN_ROOT)/usr/share/bumblebee-status/themes - cp build/debian/control $(DEBIAN_ROOT)/DEBIAN/ - cp bumblebee-status $(DEBIAN_ROOT)/usr/share/bumblebee-status/ - cp bumblebee/modules/*.py $(DEBIAN_ROOT)/usr/share/bumblebee-status/modules/ - cp -r themes/* $(DEBIAN_ROOT)/usr/share/bumblebee-status/themes - cp LICENSE $(DEBIAN_ROOT)/usr/share/bumblebee-status/ - dpkg-deb --build $(DEBIAN_ROOT) - cp build/debian/bumblebee-status.deb . - -clean: - rm -rf $(DEBIAN_ROOT) - rm -f build/debian/*.deb - rm -f *.deb diff --git a/bin/load-i3-bars.sh b/bin/load-i3-bars.sh deleted file mode 100755 index 6292f75..0000000 --- a/bin/load-i3-bars.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -if [ ! -f ~/.config/i3/config.template ]; then - cp ~/.config/i3/config ~/.config/i3/config.template -else - cp ~/.config/i3/config.template ~/.config/i3/config -fi - -if [ -f ~/.config/i3/config.template.private ]; then - cat ~/.config/i3/config.template.private >> ~/.config/i3/config -fi - -screens=$(xrandr -q|grep ' connected'| grep -P '\d+x\d+' |cut -d' ' -f1) - -echo "screens: $screens" - -while read -r line; do - screen=$(echo $line | cut -d' ' -f1) - others=$(echo $screens|tr ' ' '\n'|grep -v $screen|tr '\n' '-'|sed 's/.$//') - - if [ -f ~/.config/i3/config.$screen-$others ]; then - cat ~/.config/i3/config.$screen-$others >> ~/.config/i3/config - else - if [ -f ~/.config/i3/config.$screen ]; then - cat ~/.config/i3/config.$screen >> ~/.config/i3/config - fi - fi -done <<< "$screens" - -i3-msg restart diff --git a/bin/pacman-updates b/bin/pacman-updates deleted file mode 100755 index baf0b93..0000000 --- a/bin/pacman-updates +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/bash - -if ! type -P fakeroot >/dev/null; then - error 'Cannot find the fakeroot binary.' - exit 1 -fi - -if [[ -z $CHECKUPDATES_DB ]]; then - CHECKUPDATES_DB="${TMPDIR:-/tmp}/checkup-db-${USER}/" -fi - -trap 'rm -f $CHECKUPDATES_DB/db.lck' INT TERM EXIT - -DBPath="${DBPath:-/var/lib/pacman/}" -eval $(awk -F' *= *' '$1 ~ /DBPath/ { print $1 "=" $2 }' /etc/pacman.conf) - -mkdir -p "$CHECKUPDATES_DB" -ln -s "${DBPath}/local" "$CHECKUPDATES_DB" &> /dev/null -fakeroot -- pacman -Sy --dbpath "$CHECKUPDATES_DB" --logfile /dev/null &> /dev/null -fakeroot pacman -Su -p --dbpath "$CHECKUPDATES_DB" - -exit 0 diff --git a/bin/toggle-display.sh b/bin/toggle-display.sh deleted file mode 100755 index 18a0b71..0000000 --- a/bin/toggle-display.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -echo $(dirname $(readlink -f "$0")) - -i3bar_update=$(dirname $(readlink -f "$0"))/load-i3-bars.sh - -xrandr "$@" - -if [ -f $i3bar_update ]; then - sleep 1 - if [ -f ~/.config/i3/images/background.png ]; then - feh --bg-fill ~/.config/i3/images/background.png - fi - $i3bar_update -fi diff --git a/build/debian/control b/build/debian/control deleted file mode 100644 index 02526ce..0000000 --- a/build/debian/control +++ /dev/null @@ -1,5 +0,0 @@ -Package: bumblebee-status -Version: 0 -Maintainer: tobi-wan-kenobi -Architecture: all -Description: bumblebee-status is a modular, theme-able status line generator for the i3 window manager. diff --git a/build/debian/postinst b/build/debian/postinst deleted file mode 100755 index 640378b..0000000 --- a/build/debian/postinst +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -ln -s /usr/share/bumblebee-status/bumblebee-status /usr/local/bin/bumblebee-status - - diff --git a/bumblebee-status b/bumblebee-status index bb31f94..c6a4850 100755 --- a/bumblebee-status +++ b/bumblebee-status @@ -1,80 +1,21 @@ #!/usr/bin/env python -import os import sys -import logging -import signal -import bumblebee.theme -import bumblebee.engine -import bumblebee.config -import bumblebee.output -import bumblebee.input -import bumblebee.modules.error - -try: - reload(sys) - sys.setdefaultencoding('UTF8') -except Exception: - pass - +import core.output def main(): - def sig_USR1_handler(signum,stack): - engine.write_output() + output = core.output.i3() + modules = [] +# modules = core.module.modules() + sys.stdout.write(output.start()) + while True: + sys.stdout.write(output.begin_status_line()) + for module in modules: +# module.update() + sys.stdout.write(output.draw(module)) + sys.stdout.write(output.end_status_line()) + sys.stdout.write(output.stop()) - config = bumblebee.config.Config(sys.argv[1:]) - - if config.debug(): - if config.logfile() in ["stdout", "stderr"]: - logging.basicConfig( - level=logging.DEBUG, - format="[%(asctime)s] %(levelname)-8s %(message)s", - stream=sys.stdout if config.logfile() == "stdout" else sys.stderr - ) - else: - logging.basicConfig( - level=logging.DEBUG, - format="[%(asctime)s] %(levelname)-8s %(message)s", - filename=config.logfile() - ) - - theme = bumblebee.theme.Theme(config.theme(), config.iconset()) - output = bumblebee.output.I3BarOutput(theme=theme, config=config) - inp = bumblebee.input.I3BarInput() - engine = None - - try: - engine = bumblebee.engine.Engine( - config=config, - output=output, - inp=inp, - theme=theme, - ) - signal.signal(10,sig_USR1_handler) - engine.run() - except KeyboardInterrupt as error: - inp.stop() - sys.exit(0) - except BaseException as e: - if not engine: raise - module = engine.current_module() - logging.exception(e) - if output.started(): - output.flush() - output.end() - else: - output.start() - import time - while True: - output.begin() - error = bumblebee.modules.error.Module(engine, config) - error.set("exception occurred: {} in {}".format(e, module)) - widget = error.widgets()[0] - widget.link_module(error) - output.draw(widget, error) - output.flush() - output.end() - time.sleep(1) if __name__ == "__main__": main() diff --git a/bumblebee/__init__.py b/bumblebee/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/bumblebee/config.py b/bumblebee/config.py deleted file mode 100644 index f9c766a..0000000 --- a/bumblebee/config.py +++ /dev/null @@ -1,132 +0,0 @@ -"""Configuration handling - -This module provides configuration information (loaded modules, -module parameters, etc.) to all other components -""" - -import os -import sys -import logging -import argparse -import textwrap -import importlib -import bumblebee.store - -MODULE_HELP = "Specify a space-separated list of modules to load. The order of the list determines their order in the i3bar (from left to right). Use : to provide an alias in case you want to load the same module multiple times, but specify different parameters." -THEME_HELP = "Specify the theme to use for drawing modules" -PARAMETER_HELP = "Provide configuration parameters in the form of .=" -LIST_HELP = "Display a list of either available themes or available modules along with their parameters." -DEBUG_HELP = "Enable debug log, This will create '~/bumblebee-status-debug.log' by default, can be changed with the '-f' option" - -class print_usage(argparse.Action): - def __init__(self, option_strings, dest, nargs=None, **kwargs): - argparse.Action.__init__(self, option_strings, dest, nargs, **kwargs) - self._indent = " "*2 - - def __call__(self, parser, namespace, value, option_string=None): - if value == "modules": - self._args = namespace - self.print_modules() - elif value == "themes": - self.print_themes() - sys.exit(0) - - def print_themes(self): - print(", ".join(bumblebee.theme.themes())) - - def print_modules(self): - if self._args.list_format == "markdown": - print("# Table of modules") - print("|Name |Description |") - print("|-----|------------|") - - for m in bumblebee.engine.all_modules(): - try: - mod = importlib.import_module("bumblebee.modules.{}".format(m["name"])) - if self._args.list_format == "markdown": - print("|{} |{} |".format(m["name"], mod.__doc__.replace("\n", "
"))) - else: - print(textwrap.fill("{}:".format(m["name"]), 80, - initial_indent=self._indent*2, subsequent_indent=self._indent*2)) - for line in mod.__doc__.split("\n"): - print(textwrap.fill(line, 80, - initial_indent=self._indent*3, subsequent_indent=self._indent*6)) - except: - pass - -def create_parser(): - """Create the argument parser""" - parser = argparse.ArgumentParser(description="display system data in the i3bar") - parser.add_argument("-m", "--modules", nargs="+", action='append', default=[], - help=MODULE_HELP) - parser.add_argument("-t", "--theme", default="default", help=THEME_HELP) - parser.add_argument("--markup", default="none", help="Specify the markup type of the output (e.g. 'pango')") - parser.add_argument("-p", "--parameters", nargs="+", action='append', default=[], - help=PARAMETER_HELP) - parser.add_argument("-l", "--list", choices=["modules", "themes"], action=print_usage, - help=LIST_HELP) - parser.add_argument("--list-format", choices=["plain", "markdown"], help="output format of -l, *must* be specified before -l") - parser.add_argument("-d", "--debug", action="store_true", - help=DEBUG_HELP) - parser.add_argument("-r", "--right-to-left", action="store_true", - help="Draw widgets from right to left, rather than left to right (which is the default)") - parser.add_argument("-f", "--logfile", default="~/bumblebee-status-debug.log", - help="Location of the debug log file") - parser.add_argument("-i", "--iconset", default="auto", - help="Specify the name of an iconset to use (overrides theme default)") - parser.add_argument("-a", "--autohide", nargs="+", default=[], - help="Specify a list of modules to hide when not in warning/error state") - - return parser - -class Config(bumblebee.store.Store): - """Top-level configuration class - - Parses commandline arguments and provides non-module - specific configuration information. - """ - def __init__(self, args=None): - super(Config, self).__init__() - parser = create_parser() - self._args = parser.parse_args(args if args else []) - - if not self._args.debug: - logging.getLogger().disabled = True - - parameters = [item for sub in self._args.parameters for item in sub] - for param in parameters: - key, value = param.split("=", 1) - self.set(key, value) - - def modules(self): - modules = [item for sub in self._args.modules for item in sub] - """Return a list of all activated modules""" - return [{ - "module": x.split(":")[0], - "name": x if not ":" in x else x.split(":")[1], - } for x in modules] - - def theme(self): - """Return the name of the selected theme""" - return self._args.theme - - def iconset(self): - """Return the name of a user-specified icon-set""" - return self._args.iconset - - def debug(self): - return self._args.debug - - def reverse(self): - return self._args.right_to_left - - def logfile(self): - return os.path.expanduser(self._args.logfile) - - def autohide(self): - return self._args.autohide - - def markup(self): - return self._args.markup - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/engine.py b/bumblebee/engine.py deleted file mode 100644 index 1159884..0000000 --- a/bumblebee/engine.py +++ /dev/null @@ -1,306 +0,0 @@ -"""Core application engine""" - -import os -import json -import time -import pkgutil -import logging -import importlib -import bumblebee.error -import bumblebee.modules - -log = logging.getLogger(__name__) - -try: - from ConfigParser import RawConfigParser -except ImportError: - from configparser import RawConfigParser - -def all_modules(): - """Return a list of available modules""" - result = [] - path = os.path.dirname(bumblebee.modules.__file__) - for mod in [name for _, name, _ in pkgutil.iter_modules([path])]: - result.append({ - "name": mod - }) - return result - -class Module(object): - """Module instance base class - - Objects of this type represent the modules that - the user configures. Concrete module implementations - (e.g. CPU utilization, disk usage, etc.) derive from - this base class. - """ - def __init__(self, engine, config={}, widgets=[]): - self.name = config.get("name", self.__module__.split(".")[-1]) - self._config = config - self.id = self.name - self.error = None - self._next = int(time.time()) - self._default_interval = 0 - self._interval_factor = 1 - self._engine = engine - - self._configFile = None - for cfg in [os.path.expanduser("~/.bumblebee-status.conf"), os.path.expanduser("~/.config/bumblebee-status.conf")]: - if os.path.exists(cfg): - self._configFile = RawConfigParser() - self._configFile.read(cfg) - log.debug("reading configuration file {}".format(cfg)) - break - - if self._configFile is not None and self._configFile.has_section("module-parameters"): - log.debug(self._configFile.items("module-parameters")) - self._widgets = [] - if widgets: - self._widgets = widgets if isinstance(widgets, list) else [widgets] - - def theme(self): - return self._engine.theme() - - def widgets(self, widgets=None): - """Return the widgets to draw for this module""" - if widgets: - self._widgets = widgets if isinstance(widgets, list) else [widgets] - return self._widgets - - def hidden(self): - return False - - def widget(self, name): - for widget in self._widgets: - if widget.name == name: - return widget - - def errorWidget(self): - msg = self.error - if len(msg) > 10: - msg = "{}...".format(msg[0:7]) - return bumblebee.output.Widget(full_text="error: {}".format(msg)) - - def widget_by_id(self, uid): - for widget in self._widgets: - if widget.id == uid: - return widget - return None - - def update(self, widgets): - """By default, update() is a NOP""" - pass - - def update_wrapper(self, widgets): - if self._next > int(time.time()): - return - try: - self.error = None - self.update(self._widgets) - except Exception as e: - log.error("error updating '{}': {}".format(self.name, str(e))) - self.error = str(e) - self._next += int(self.parameter("interval", self._default_interval))*self._interval_factor - - def interval_factor(self, factor): - self._interval_factor = factor - - def interval(self, intvl): - self._default_interval = intvl - self._next = int(time.time()) - - def update_all(self): - self.update_wrapper(self._widgets) - - def has_parameter(self, name): - v = self.parameter(name) - return v is not None - - def parameter(self, name, default=None): - """Return the config parameter 'name' for this module""" - module_name = "{}.{}".format(self.__module__.split(".")[-1], name) - name = "{}.{}".format(self.name, name) - value = self._config["config"].get(module_name, default) - value = self._config["config"].get(name, value) - if value == default: - try: - value = self._configFile.get("module-parameters", name) - except: - pass - return value - - def threshold_state(self, value, warn, crit): - if value > float(self.parameter("critical", crit)): - return "critical" - if value > float(self.parameter("warning", warn)): - return "warning" - return None - -class Engine(object): - """Engine for driving the application - - This class connects input/output, instantiates all - required modules and drives the "event loop" - """ - def __init__(self, config, output=None, inp=None, theme=None): - self._output = output - self._config = config - self._running = True - self._modules = [] - self.input = inp - self._aliases = self._aliases() - self.load_modules(config.modules()) - self._current_module = None - self._theme = theme - - if bumblebee.util.asbool(config.get("engine.workspacewheel", "true")): - if bumblebee.util.asbool(config.get("engine.workspacewrap", "true")): - self.input.register_callback(None, bumblebee.input.WHEEL_UP, - "i3-msg workspace prev_on_output") - self.input.register_callback(None, bumblebee.input.WHEEL_DOWN, - "i3-msg workspace next_on_output") - else: - self.input.register_callback(None, bumblebee.input.WHEEL_UP, - cmd=self._prev_workspace) - self.input.register_callback(None, bumblebee.input.WHEEL_DOWN, - cmd=self._next_workspace) - if bumblebee.util.asbool(config.get("engine.collapsible", "true")): - self.input.register_callback(None, bumblebee.input.MIDDLE_MOUSE, - cmd=self._toggle_minimize) - - self.input.start() - - def theme(self): - return self._theme - - def _toggle_minimize(self, event): - for module in self._modules: - widget = module.widget_by_id(event["instance"]) - if widget: - log.debug("module {} found - toggle minimize".format(module.id)) - widget.toggle_minimize() - - def _prev_workspace(self, event): - self._change_workspace(-1) - - def _next_workspace(self, event): - self._change_workspace(1) - - def _change_workspace(self, amount): - try: - active_output = None - active_index = -1 - output_workspaces = {} - data = json.loads(bumblebee.util.execute("i3-msg -t get_workspaces")) - for workspace in data: - output_workspaces.setdefault(workspace["output"], []).append(workspace) - if workspace["focused"]: - active_output = workspace["output"] - active_index = len(output_workspaces[workspace["output"]]) - 1 - if (active_index + amount) < 0: - return - if (active_index + amount) >= len(output_workspaces[active_output]): - return - - while amount != 0: - if amount > 0: - bumblebee.util.execute("i3-msg workspace next_on_output") - amount = amount - 1 - if amount < 0: - bumblebee.util.execute("i3-msg workspace prev_on_output") - amount = amount + 1 - except Exception as e: - log.error("failed to change workspace: {}".format(e)) - - def modules(self): - return self._modules - - def load_modules(self, modules): - """Load specified modules and return them as list""" - for module in modules: - mod = self._load_module(module["module"], module["name"]) - self._modules.append(mod) - self._register_module_callbacks(mod) - return self._modules - - def _register_module_callbacks(self, module): - buttons = [ - {"name": "left-click", "id": bumblebee.input.LEFT_MOUSE}, - {"name": "middle-click", "id": bumblebee.input.MIDDLE_MOUSE}, - {"name": "right-click", "id": bumblebee.input.RIGHT_MOUSE}, - {"name": "wheel-up", "id": bumblebee.input.WHEEL_UP}, - {"name": "wheel-down", "id": bumblebee.input.WHEEL_DOWN}, - ] - for button in buttons: - if module.parameter(button["name"], None): - self.input.register_callback(obj=module, - button=button["id"], cmd=module.parameter(button["name"])) - - def _aliases(self): - return { - 'date': 'datetime', - 'time': 'datetime', - 'datetz': 'datetimetz', - 'timetz': 'datetimetz', - 'pasink': 'pulseaudio', - 'pasource': 'pulseaudio', - 'test-alias': 'test', - } - - def _load_module(self, module_name, config_name=None): - """Load specified module and return it as object""" - if module_name in self._aliases: - config_name is config_name if config_name else module_name - module_name = self._aliases[module_name] - if config_name is None: - config_name = module_name - err = None - try: - module = importlib.import_module("bumblebee.modules.{}".format(module_name)) - except ImportError as error: - err = error - log.fatal("failed to import {}: {}".format(module_name, str(error))) - if err: - raise bumblebee.error.ModuleLoadError("unable to load module {}: {}".format(module_name, str(err))) - return getattr(module, "Module")(self, { - "name": config_name, - "config": self._config - }) - - def running(self): - """Check whether the event loop is running""" - return self._running - - def stop(self): - """Stop the event loop""" - self._running = False - - def current_module(self): - return self._current_module.__module__ - - def run(self): - """Start the event loop""" - self._output.start() - while self.running(): - self.write_output() - if self.running(): - self.input.wait(float(self._config.get("interval", 1))) - - self._output.stop() - self.input.stop() - - def write_output(self): - self._output.begin() - for module in self._modules: - self._current_module = module - module.update_wrapper(module.widgets()) - if module.error is None: - for widget in module.widgets(): - widget.link_module(module) - self._output.draw(widget=widget, module=module, engine=self) - else: - self._output.draw(widget=module.errorWidget(), module=module, engine=self) - self._output.flush() - self._output.end() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/error.py b/bumblebee/error.py deleted file mode 100644 index 129f02d..0000000 --- a/bumblebee/error.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Collection of all exceptions raised by this tool""" - -class BaseError(Exception): - """Base class for all exceptions generated by this tool""" - pass - -class ModuleLoadError(BaseError): - """Raised whenever loading a module fails""" - pass - -class ThemeLoadError(BaseError): - """Raised whenever loading a theme fails""" - pass - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/input.py b/bumblebee/input.py deleted file mode 100644 index af86757..0000000 --- a/bumblebee/input.py +++ /dev/null @@ -1,149 +0,0 @@ -"""Input classes""" - -import sys -import json -import uuid -import time -import select -import logging -import threading -import bumblebee.util - -log = logging.getLogger(__name__) - -LEFT_MOUSE = 1 -MIDDLE_MOUSE = 2 -RIGHT_MOUSE = 3 -WHEEL_UP = 4 -WHEEL_DOWN = 5 - -def is_terminated(): - for thread in threading.enumerate(): - if thread.name == "MainThread" and not thread.is_alive(): - return True - return False - -def read_input(inp): - """Read i3bar input and execute callbacks""" - poll = select.poll() - poll.register(sys.stdin.fileno(), select.POLLIN) - log.debug("starting click event processing") - while inp.running: - if is_terminated(): - return - - try: - events = poll.poll(1000) - except Exception: - continue - for fileno, event in events: - line = "[" - while line.startswith("["): - line = sys.stdin.readline().strip(",").strip() - log.debug("new event: {}".format(line)) - inp.has_event = True - try: - event = json.loads(line) - if "instance" in event: - inp.callback(event) - inp.redraw() - else: - log.debug("field 'instance' missing in input, not processing the event") - except ValueError as e: - log.debug("failed to parse event: {}".format(e)) - log.debug("exiting click event processing") - poll.unregister(sys.stdin.fileno()) - 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 - try: - if callable(cmd): - cmd(event) - else: - bumblebee.util.execute(cmd, False) - except Exception: - # fall back to global default - if not "__fallback" in event: - return self.callback({"name": None, "instance": None, "__fallback": True, "button": event["button"]}) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/__init__.py b/bumblebee/modules/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/bumblebee/modules/amixer.py b/bumblebee/modules/amixer.py deleted file mode 100644 index 3a4ead6..0000000 --- a/bumblebee/modules/amixer.py +++ /dev/null @@ -1,42 +0,0 @@ -"""get volume level - -""" -import re - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.volume) - ) - self._level = "0" - self._muted = True - device = self.parameter("device", "Master,0") - self._cmdString = "amixer get {}".format(device) - - def volume(self, widget): - m = re.search(r'([\d]+)\%', self._level) - self._muted = True - if m: - if m.group(1) != "0" and "[on]" in self._level: - self._muted = False - return "{}%".format(m.group(1)) - else: - return "0%" - - def update(self, widgets): - level = "" - try: - level = bumblebee.util.execute(self._cmdString) - except Exception as e: - level = "" - - self._level = level - - def state(self, widget): - if self._muted: - return ["warning", "muted"] - return ["unmuted"] diff --git a/bumblebee/modules/apt.py b/bumblebee/modules/apt.py deleted file mode 100644 index 99c7819..0000000 --- a/bumblebee/modules/apt.py +++ /dev/null @@ -1,81 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays APT package update information (/) -Requires the following debian packages: - * python-parse - * aptitude - -""" - -import threading -from parse import * - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -APT_CHECK_PATH = ("aptitude full-upgrade --simulate --assume-yes") -PATTERN = "{} packages upgraded, {} newly installed, {} to remove and {} not upgraded." - -def parse_result(to_parse): - # We want to line with the iforamtion about package upgrade - line_to_parse = to_parse.split("\n")[-4] - - result = parse(PATTERN, line_to_parse) - - return int(result[0]), int(result[2]) - -def get_apt_check_info(widget): - try: - res = bumblebee.util.execute(APT_CHECK_PATH) - widget.set("error", None) - except (RuntimeError, FileNotFoundError) as e: - widget.set("error", "unable to query APT: {}".format(e)) - return - - to_upgrade = 0 - to_remove = 0 - try: - to_upgrade, to_remove = parse_result(res) - except e: - widget.set("error", "parse error: {}".format(e)) - return - - widget.set("to_upgrade", to_upgrade) - widget.set("to_remove", to_remove) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.updates) - super(Module, self).__init__(engine, config, widget) - self.interval_factor(60) - self.interval(30) - - def updates(self, widget): - result = [] - if widget.get("error"): - return widget.get("error") - for t in ["to_upgrade", "to_remove"]: - result.append(str(widget.get(t, 0))) - return "/".join(result) - - def update(self, widgets): - thread = threading.Thread(target=get_apt_check_info, args=(widgets[0],)) - thread.start() - - def state(self, widget): - cnt = 0 - ret = "good" - for t in ["to_upgrade", "to_remove"]: - cnt += widget.get(t, 0) - if cnt > 50: - ret = "critical" - elif cnt > 0: - ret = "warning" - if widget.get("error"): - ret = "critical" - - return ret - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/arch-update.py b/bumblebee/modules/arch-update.py deleted file mode 100644 index faae680..0000000 --- a/bumblebee/modules/arch-update.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Check updates to Arch Linux. -""" - - -import subprocess -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.utilization) - super(Module, self).__init__(engine, config, widget) - self.packages = self.check_updates() - - def check_updates(self): - p = subprocess.Popen( - "checkupdates", stdout=subprocess.PIPE, shell=True) - - p_status = p.wait() - - if p_status == 0: - (output, err) = p.communicate() - - output = output.decode('utf-8') - packages = output.split('\n') - packages.pop() - - return len(packages) - return 0 - - @property - def _format(self): - return self.parameter("format", "Update Arch: {}") - - def utilization(self, widget): - return self._format.format(self.packages) - - def hidden(self): - return self.check_updates() == 0 - - def update(self, widgets): - self.packages = self.check_updates() - - def state(self, widget): - return self.threshold_state(self.packages, 1, 100) diff --git a/bumblebee/modules/battery-upower.py b/bumblebee/modules/battery-upower.py deleted file mode 100644 index 24efecf..0000000 --- a/bumblebee/modules/battery-upower.py +++ /dev/null @@ -1,270 +0,0 @@ -# UPowerManger Class Copyright (C) 2017 Oscar Svensson (wogscpar) under MIT licence from upower-python - -"""Displays battery status, remaining percentage and charging information. - -Parameters: - * battery-upower.warning : Warning threshold in % of remaining charge (defaults to 20) - * battery-upower.critical : Critical threshold in % of remaining charge (defaults to 10) - * battery-upower.showremaining : If set to true (default) shows the remaining time until the batteries are completely discharged -""" - -import dbus -import logging - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util - -class UPowerManager(): - - def __init__(self): - self.UPOWER_NAME = "org.freedesktop.UPower" - self.UPOWER_PATH = "/org/freedesktop/UPower" - - self.DBUS_PROPERTIES = "org.freedesktop.DBus.Properties" - self.bus = dbus.SystemBus() - - def detect_devices(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH) - upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME) - - devices = upower_interface.EnumerateDevices() - return devices - - def get_display_device(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH) - upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME) - - dispdev = upower_interface.GetDisplayDevice() - return dispdev - - def get_critical_action(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH) - upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME) - - critical_action = upower_interface.GetCriticalAction() - return critical_action - - def get_device_percentage(self, battery): - battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery) - battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES) - - return battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Percentage") - - def get_full_device_information(self, battery): - battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery) - battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES) - - hasHistory = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "HasHistory") - hasStatistics = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "HasStatistics") - isPresent = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IsPresent") - isRechargable = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IsRechargeable") - online = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Online") - powersupply = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "PowerSupply") - capacity = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Capacity") - energy = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Energy") - energyempty = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyEmpty") - energyfull = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyFull") - energyfulldesign = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyFullDesign") - energyrate = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyRate") - luminosity = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Luminosity") - percentage = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Percentage") - temperature = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Temperature") - voltage = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Voltage") - timetoempty = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "TimeToEmpty") - timetofull = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "TimeToFull") - iconname = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IconName") - model = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Model") - nativepath = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "NativePath") - serial = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Serial") - vendor = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Vendor") - state = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State") - technology = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Technology") - battype = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Type") - warninglevel = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "WarningLevel") - updatetime = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "UpdateTime") - - information_table = { - 'HasHistory': hasHistory, - 'HasStatistics': hasStatistics, - 'IsPresent': isPresent, - 'IsRechargeable': isRechargable, - 'Online': online, - 'PowerSupply': powersupply, - 'Capacity': capacity, - 'Energy': energy, - 'EnergyEmpty': energyempty, - 'EnergyFull': energyfull, - 'EnergyFullDesign': energyfulldesign, - 'EnergyRate': energyrate, - 'Luminosity': luminosity, - 'Percentage': percentage, - 'Temperature': temperature, - 'Voltage': voltage, - 'TimeToEmpty': timetoempty, - 'TimeToFull': timetofull, - 'IconName': iconname, - 'Model': model, - 'NativePath': nativepath, - 'Serial': serial, - 'Vendor': vendor, - 'State': state, - 'Technology': technology, - 'Type': battype, - 'WarningLevel': warninglevel, - 'UpdateTime': updatetime - } - - return information_table - - def is_lid_present(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH) - upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES) - - is_lid_present = bool(upower_interface.Get(self.UPOWER_NAME, 'LidIsPresent')) - return is_lid_present - - def is_lid_closed(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH) - upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES) - - is_lid_closed = bool(upower_interface.Get(self.UPOWER_NAME, 'LidIsClosed')) - return is_lid_closed - - def on_battery(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH) - upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES) - - on_battery = bool(upower_interface.Get(self.UPOWER_NAME, 'OnBattery')) - return on_battery - - def has_wakeup_capabilities(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups") - upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES) - - has_wakeup_capabilities = bool(upower_interface.Get(self.UPOWER_NAME + '.Wakeups', 'HasCapability')) - return has_wakeup_capabilities - - def get_wakeups_data(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups") - upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + '.Wakeups') - - data = upower_interface.GetData() - return data - - def get_wakeups_total(self): - upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups") - upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + '.Wakeups') - - data = upower_interface.GetTotal() - return data - - def is_loading(self, battery): - battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery) - battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES) - - state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State")) - - if (state == 1): - return True - else: - return False - - def get_state(self, battery): - battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery) - battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES) - - state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State")) - - if (state == 0): - return "Unknown" - elif (state == 1): - return "Loading" - elif (state == 2): - return "Discharging" - elif (state == 3): - return "Empty" - elif (state == 4): - return "Fully charged" - elif (state == 5): - return "Pending charge" - elif (state == 6): - return "Pending discharge" - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, bumblebee.output.Widget(full_text=self.capacity)) - try: - self.power = UPowerManager() - self.device = self.power.get_display_device() - except Exception as e: - logging.exception("unable to get battery display device: {}".format(str(e))) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="gnome-power-statistics") - - self._showremaining = bumblebee.util.asbool( - self.parameter("showremaining", True)) - - def capacity(self, widget): - widget.set("capacity", -1) - widget.set("ac", False) - output = "n/a" - try: - capacity = int(self.power.get_device_percentage(self.device)) - capacity = capacity if capacity < 100 else 100 - widget.set("capacity", capacity) - output = "{}%".format(capacity) - widget.set("theme.minwidth", "100%") - except Exception as e: - logging.exception("unable to get battery capacity: {}".format(str(e))) - - if self._showremaining: - try: - p = self.power # an alias to make each line of code shorter - proxy = p.bus.get_object(p.UPOWER_NAME, self.device) - interface = dbus.Interface(proxy, p.DBUS_PROPERTIES) - state = int(interface.Get(p.UPOWER_NAME+".Device", "State")) - # state: 1 => charging, 2 => discharging, other => don't care - remain = int(interface.Get( - p.UPOWER_NAME+".Device", ["TimeToFull", "TimeToEmpty"][state-1])) - remain = bumblebee.util.durationfmt(remain, shorten=True, suffix=True) - output = "{} {}".format(output, remain) - except IndexError: - pass - except Exception as e: - logging.exception("unable to get battery remaining time: {}".format(str(e))) - - return output - - def state(self, widget): - state = [] - capacity = widget.get("capacity") - if capacity < 0: - return ["critical", "unknown"] - - if capacity < int(self.parameter("critical", 10)): - state.append("critical") - elif capacity < int(self.parameter("warning", 20)): - state.append("warning") - - if widget.get("ac"): - state.append("AC") - else: - charge = "Unknown" - try: - charge = self.power.get_state(self.device) - except Exception as e: - logging.exception("unable to get charge value: {}".format(str(e))) - if charge == "Discharging": - state.append("discharging-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity)))) - elif charge == "Unknown": - state.append("unknown-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity)))) - else: - if capacity > 95: - state.append("charged") - else: - state.append("charging") - - return state diff --git a/bumblebee/modules/battery.py b/bumblebee/modules/battery.py deleted file mode 100644 index f6f6c51..0000000 --- a/bumblebee/modules/battery.py +++ /dev/null @@ -1,140 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays battery status, remaining percentage and charging information. - -Parameters: - * battery.device : Comma-separated list of battery devices to read information from (defaults to auto for auto-detection) - * battery.warning : Warning threshold in % of remaining charge (defaults to 20) - * battery.critical : Critical threshold in % of remaining charge (defaults to 10) - * battery.showdevice : If set to "true", add the device name to the widget (defaults to False) - * battery.decorate : If set to "false", hides additional icons (charging, etc.) (defaults to True) - * battery.showpowerconsumption: If set to "true", show current power consumption (defaults to False) -""" - -import os -import glob - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util - -try: - import power -except ImportError: - pass - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - super(Module, self).__init__(engine, config, widgets) - self._batteries = self.parameter("device", "auto").split(",") - if self._batteries[0] == "auto": - self._batteries = glob.glob("/sys/class/power_supply/BAT*") - else: - self._batteries = ["/sys/class/power_supply/{}".format(b) for b in self._batteries] - if len(self._batteries) == 0: - self._batteries = ["/sys/class/power_supply/BAT0"] - self.update(widgets) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="gnome-power-statistics") - - def update(self, widgets): - new_widgets = [] - for path in self._batteries: - widget = self.widget(path) - if not widget: - widget = bumblebee.output.Widget(full_text=self.capacity, name=path) - new_widgets.append(widget) - self.capacity(widget) - while len(widgets) > 0: del widgets[0] - for widget in new_widgets: - if bumblebee.util.asbool(self.parameter("decorate", True)) == False: - widget.set("theme.exclude", "suffix") - widgets.append(widget) - self._widgets = widgets - - def remaining(self): - estimate = 0.0 - try: - estimate = power.PowerManagement().get_time_remaining_estimate() - # do not show remaining if on AC - if estimate == power.common.TIME_REMAINING_UNLIMITED: - return None - if estimate == power.common.TIME_REMAINING_UNKNOWN: - return "" - except Exception: - return "" - return bumblebee.util.durationfmt(estimate*60, shorten=True, suffix=True) # estimate is in minutes - - def capacity(self, widget): - widget.set("capacity", -1) - widget.set("ac", False) - if not os.path.exists(widget.name): - widget.set("capacity", 100) - widget.set("ac", True) - return "ac" - capacity = 100 - try: - with open("{}/capacity".format(widget.name)) as f: - capacity = int(f.read()) - except IOError: - return "n/a" - - capacity = capacity if capacity < 100 else 100 - widget.set("capacity", capacity) - - # Read power conumption - if bumblebee.util.asbool(self.parameter("showpowerconsumption", False)): - r=open(widget.name + '/power_now', "r") - output = "{}% ({})".format(capacity,str(int(r.read())/1000000) + "W") - else: - output = "{}%".format(capacity) - - widget.set("theme.minwidth", "100%") - if bumblebee.util.asbool(self.parameter("showremaining", True))\ - and self.getCharge(widget) == "Discharging": - output = "{} {}".format(output, self.remaining()) - - if bumblebee.util.asbool(self.parameter("showdevice", False)): - output = "{} ({})".format(output, os.path.basename(widget.name)) - - return output - - def state(self, widget): - state = [] - capacity = widget.get("capacity") - - if capacity < 0: - return ["critical", "unknown"] - - if capacity < int(self.parameter("critical", 10)): - state.append("critical") - elif capacity < int(self.parameter("warning", 20)): - state.append("warning") - - if widget.get("ac"): - state.append("AC") - else: - charge = self.getCharge(widget) - if charge == "Discharging": - state.append("discharging-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity)))) - elif charge == "Unknown": - state.append("unknown-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity)))) - else: - if capacity > 95: - state.append("charged") - else: - state.append("charging") - - return state - - def getCharge(self, widget): - charge = "" - try: - with open("{}/status".format(widget.name)) as f: - charge = f.read().strip() - except IOError: - pass - return charge -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/battery_all.py b/bumblebee/modules/battery_all.py deleted file mode 100644 index 2fe965c..0000000 --- a/bumblebee/modules/battery_all.py +++ /dev/null @@ -1,130 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays battery status, remaining percentage and charging information. - -Parameters: - * battery.device : Comma-separated list of battery devices to read information from (defaults to auto for auto-detection) - * battery.warning : Warning threshold in % of remaining charge (defaults to 20) - * battery.critical : Critical threshold in % of remaining charge (defaults to 10) - * batter.showremaining : If set to true (default) shows the remaining time until the batteries are completely discharged -""" - -import os -import glob -import logging - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util - -try: - import power -except ImportError: - pass - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - self._batteries = [] - try: - for battery in os.listdir('/sys/class/power_supply/'): - if not any(i in battery for i in ['AC', 'hidpp']): - self._batteries.append("/sys/class/power_supply/" + battery) - except Exception as e: - logging.exception("unable to detect batteries: {}".format(str(e))) - - super(Module, self).__init__(engine, config, bumblebee.output.Widget(full_text=self.capacity)) - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="gnome-power-statistics") - - def remaining(self): - estimate = 0.0 - power_now = 0.0 - try: - estimate = power.PowerManagement().get_time_remaining_estimate() - # do not show remaining if on AC - if estimate == power.common.TIME_REMAINING_UNLIMITED: - return None - elif estimate == power.common.TIME_REMAINING_UNKNOWN: - return "" - except Exception: - return "" - return bumblebee.util.durationfmt(estimate*60, shorten=True, suffix=True) # estimate is in minutes - - def capacity(self, widget): - widget.set("capacity", -1) - widget.set("ac", False) - capacity = 100 - self.energy_now = 0 - self.energy_full = 0 - errors = 0 - for path in self._batteries: - try: - with open("{}/energy_full".format(path)) as f: - self.energy_full += int(f.read()) - with open("{}/energy_now".format(path)) as o: - self.energy_now += int(o.read()) - except IOError: - return "n/a" - except Exception: - errors += 1 - - if errors == len(self._batteries): - return "n/a" - - capacity = int( float(self.energy_now) / float(self.energy_full) * 100.0) - capacity = capacity if capacity < 100 else 100 - widget.set("capacity", capacity) - output = "{}%".format(capacity) - widget.set("theme.minwidth", "100%") - - if bumblebee.util.asbool(self.parameter("showremaining", True))\ - and self.getCharge(widget) == "Discharging": - output = "{} {}".format(output, self.remaining()) - - return output - - - def state(self, widget): - state = [] - capacity = widget.get("capacity") - - if capacity < 0: - return ["critical", "unknown"] - - if capacity < int(self.parameter("critical", 10)): - state.append("critical") - elif capacity < int(self.parameter("warning", 20)): - state.append("warning") - - if widget.get("ac"): - state.append("AC") - else: - charge = self.getCharge(widget) - if charge == "Discharging": - state.append("discharging-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity)))) - elif charge == "Unknown": - state.append("unknown-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity)))) - else: - if capacity > 95: - state.append("charged") - else: - state.append("charging") - - return state - - def getCharge(self, widget): - charge = "" - charge_list = [] - for x in range(len(self._batteries)): - try: - with open("{}/status".format(self._batteries[x])) as f: - charge_list.append(f.read().strip()) - except IOError: - pass - for x in range(len(charge_list)): - if charge_list[x] == "Discharging": - charge = charge_list[x] - break - return charge diff --git a/bumblebee/modules/bluetooth.py b/bumblebee/modules/bluetooth.py deleted file mode 100644 index fc5d5b5..0000000 --- a/bumblebee/modules/bluetooth.py +++ /dev/null @@ -1,131 +0,0 @@ -"""Displays bluetooth status (Bluez). Left mouse click launches manager app, -right click toggles bluetooth. Needs dbus-send to toggle bluetooth state. - -Parameters: - * bluetooth.device : the device to read state from (default is hci0) - * bluetooth.manager : application to launch on click (blueman-manager) - * bluetooth.dbus_destination : dbus destination (defaults to org.blueman.Mechanism) - * bluetooth.dbus_destination_path : dbus destination path (defaults to /) - * bluetooth.right_click_popup : use popup menu when right-clicked (defaults to True) - -""" - - -import os -import re -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util -import bumblebee.popup -import logging - - -class Module(bumblebee.engine.Module): - """Bluetooth module.""" - - def __init__(self, engine, config): - """Initialize.""" - super(Module, self).__init__(engine, config, - bumblebee.output.Widget( - full_text=self.status)) - - device = self.parameter("device", "hci0") - self.manager = self.parameter("manager", "blueman-manager") - self._path = "/sys/class/bluetooth/{}".format(device) - self._status = "Off" - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.manager) - - # determine whether to use pop-up menu or simply toggle the device on/off - right_click_popup = bumblebee.util.asbool( - self.parameter("right_click_popup", True)) - - if right_click_popup: - engine.input.register_callback(self, - button=bumblebee.input.RIGHT_MOUSE, - cmd=self.popup) - else: - engine.input.register_callback(self, - button=bumblebee.input.RIGHT_MOUSE, - cmd=self._toggle) - - def status(self, widget): - """Get status.""" - return self._status - - def update(self, widgets): - """Update current state.""" - if not os.path.exists(self._path): - self._status = "?" - return - - # search for whichever rfkill directory available - try: - dirnames = next(os.walk(self._path))[1] - for dirname in dirnames: - m = re.match(r"rfkill[0-9]+", dirname) - if m is not None: - with open(os.path.join(self._path, - dirname, - 'state'), 'r') as f: - state = int(f.read()) - if state == 1: - self._status = "On" - else: - self._status = "Off" - return - - except IOError: - self._status = "?" - - def manager(self, widget): - """Launch manager.""" - bumblebee.util.execute(self.manager) - - def popup(self, widget): - """Show a popup menu.""" - menu = bumblebee.popup.PopupMenu() - if self._status == "On": - menu.add_menuitem('Disable Bluetooth') - elif self._status == "Off": - menu.add_menuitem('Enable Bluetooth') - else: - return - - # show menu and get return code - ret = menu.show(widget) - if ret == 0: - # first (and only) item selected. - self._toggle() - - def _toggle(self, widget=None): - """Toggle bluetooth state.""" - if self._status == "On": - state = "false" - else: - state = "true" - - dst = self.parameter("dbus_destination", "org.blueman.Mechanism") - dst_path = self.parameter("dbus_destination_path", "/") - - cmd = "dbus-send --system --print-reply --dest={}"\ - " {} org.blueman.Mechanism.SetRfkillState"\ - " boolean:{}".format(dst, dst_path, state) - - logging.debug('bt: toggling bluetooth') - bumblebee.util.execute(cmd) - - def state(self, widget): - """Get current state.""" - state = [] - - if self._status == "?": - state = ["unknown"] - elif self._status == "On": - state = ["ON"] - else: - state = ["OFF"] - - return state diff --git a/bumblebee/modules/brightness.py b/bumblebee/modules/brightness.py deleted file mode 100644 index 729d05d..0000000 --- a/bumblebee/modules/brightness.py +++ /dev/null @@ -1,63 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the brightness of a display - -Parameters: - * brightness.step: The amount of increase/decrease on scroll in % (defaults to 2) - * brightness.device_path: The device path (defaults to /sys/class/backlight/intel_backlight), can contain wildcards (in this case, the first matching path will be used) - -""" - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -import glob - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.brightness)) - self._brightness = 0 - - self._device_path = self.find_device(self.parameter("device_path", "/sys/class/backlight/intel_backlight")) - step = self.parameter("step", 2) - - if bumblebee.util.which("light"): - self.register_cmd(engine, "light -A {}%".format(step), - "light -U {}%".format(step)) - elif bumblebee.util.which("brightnessctl"): - self.register_cmd(engine, "brightnessctl s {}%+".format(step), - "brightnessctl s {}%-".format(step)) - else: - self.register_cmd(engine, "xbacklight +{}%".format(step), - "xbacklight -{}%".format(step)) - - def find_device(self, device_path): - res = glob.glob(device_path) - if len(res) == 0: - return device_path - return res[0] - - def register_cmd(self, engine, upCmd, downCmd): - engine.input.register_callback(self, button=bumblebee.input.WHEEL_UP, cmd=upCmd) - engine.input.register_callback(self, button=bumblebee.input.WHEEL_DOWN, cmd=downCmd) - - def brightness(self, widget): - if isinstance(self._brightness, float): - return "{:3.0f}%".format(self._brightness).strip() - else: - return "n/a" - - def update(self, widgets): - try: - with open("{}/brightness".format(self._device_path)) as f: - backlight = int(f.readline()) - with open("{}/max_brightness".format(self._device_path)) as f: - max_brightness = int(f.readline()) - self._brightness = float(backlight * 100 / max_brightness) - except: - return "Error" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/caffeine.py b/bumblebee/modules/caffeine.py deleted file mode 100644 index ed9633c..0000000 --- a/bumblebee/modules/caffeine.py +++ /dev/null @@ -1,102 +0,0 @@ -#pylint: disable=C0111,R0903,W0212 - -"""Enable/disable automatic screen locking. - -Requires the following executables: - * xdg-screensaver - * xdotool - * xprop (as dependency for xdotool) - * notify-send -""" - -import logging -import os -import psutil -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text="") - ) - self._active = False - self._xid = None - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self._toggle - ) - - def _check_requirements(self): - requirements = ['xdotool', 'xprop', 'xdg-screensaver'] - missing = [] - for tool in requirements: - if not bumblebee.util.which(tool): - missing.append(tool) - return missing - - def _get_i3bar_xid(self): - xid = bumblebee.util.execute("xdotool search --class \"i3bar\"").partition('\n')[0].strip() - if xid.isdigit(): - return xid - logging.warning("Module caffeine: xdotool couldn't get X window ID of \"i3bar\".") - return None - - def _notify(self): - if not bumblebee.util.which('notify-send'): - return - - if self._active: - bumblebee.util.execute("notify-send \"Consuming caffeine\"") - else: - bumblebee.util.execute("notify-send \"Out of coffee\"") - - def _suspend_screensaver(self): - self._xid = self._get_i3bar_xid() - if self._xid is None: - return False - - pid = os.fork() - if pid == 0: - os.setsid() - bumblebee.util.execute("xdg-screensaver suspend {}".format(self._xid)) - os._exit(0) - else: - os.waitpid(pid, 0) - return True - - def _resume_screensaver(self): - success = True - xprop_path = bumblebee.util.which('xprop') - pids = [ p.pid for p in psutil.process_iter() if p.cmdline() == [xprop_path, '-id', str(self._xid), '-spy'] ] - for pid in pids: - try: - os.kill(pid, 9) - except OSError: - success = False - return success - - def state(self, _): - if self._active: - return "activated" - return "deactivated" - - def _toggle(self, _): - missing = self._check_requirements() - if missing: - logging.warning('Could not run caffeine - missing %s!', ", ".join(missing)) - return - - self._active = not self._active - if self._active: - success = self._suspend_screensaver() - else: - success = self._resume_screensaver() - - if success: - self._notify() - else: - self._active = not self._active - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/cmus.py b/bumblebee/modules/cmus.py deleted file mode 100644 index 94e7bae..0000000 --- a/bumblebee/modules/cmus.py +++ /dev/null @@ -1,120 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays information about the current song in cmus. - -Requires the following executable: - * cmus-remote - -Parameters: - * cmus.format: Format string for the song information. Tag values can be put in curly brackets (i.e. {artist}) - Additional tags: - * {file} - full song file name - * {file1} - song file name without path prefix - if {file} = '/foo/bar.baz', then {file1} = 'bar.baz' - * {file2} - song file name without path prefix and extension suffix - if {file} = '/foo/bar.baz', then {file2} = 'bar' - * cmus.layout: Space-separated list of widgets to add. Possible widgets are the buttons/toggles cmus.prev, cmus.next, cmus.shuffle and cmus.repeat, and the main display with play/pause function cmus.main. -""" - -from collections import defaultdict - -import os -import string - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from bumblebee.output import scrollable - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, []) - - self._layout = self.parameter("layout", "cmus.prev cmus.main cmus.next cmus.shuffle cmus.repeat") - self._fmt = self.parameter("format", "{artist} - {title} {position}/{duration}") - self._status = None - self._shuffle = False - self._repeat = False - self._tags = defaultdict(lambda: '') - - # Create widgets - widget_list = [] - widget_map = {} - for widget_name in self._layout.split(): - widget = bumblebee.output.Widget(name=widget_name) - widget_list.append(widget) - - if widget_name == "cmus.prev": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "cmus-remote -r"} - elif widget_name == "cmus.main": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "cmus-remote -u"} - widget.full_text(self.description) - elif widget_name == "cmus.next": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "cmus-remote -n"} - elif widget_name == "cmus.shuffle": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "cmus-remote -S"} - elif widget_name == "cmus.repeat": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "cmus-remote -R"} - else: - raise KeyError("The cmus module does not support a {widget_name!r} widget".format(widget_name=widget_name)) - self.widgets(widget_list) - - # Register input callbacks - for widget, callback_options in widget_map.items(): - engine.input.register_callback(widget, **callback_options) - - def hidden(self): - return self._status is None - - @scrollable - def description(self, widget): - return string.Formatter().vformat(self._fmt, (), self._tags) - - def update(self, widgets): - self._load_song() - - def state(self, widget): - returns = { - "cmus.shuffle": "shuffle-on" if self._shuffle else "shuffle-off", - "cmus.repeat": "repeat-on" if self._repeat else "repeat-off", - "cmus.prev": "prev", - "cmus.next": "next", - } - return returns.get(widget.name, self._status) - - def _eval_line(self, line): - if line.startswith("file "): - full_file = line[5:] - file1 = os.path.basename(full_file) - file2 = os.path.splitext(file1)[0] - self._tags.update({"file": full_file}) - self._tags.update({"file1": file1}) - self._tags.update({"file2": file2}) - return - name, key, value = (line.split(" ", 2) + [None, None])[:3] - - if name == "status": - self._status = key - if name == "tag": - self._tags.update({key: value}) - if name in ["duration", "position"]: - self._tags.update({name: bumblebee.util.durationfmt(int(key))}) - if name == "set" and key == "repeat": - self._repeat = value == "true" - if name == "set" and key == "shuffle": - self._shuffle = value == "true" - - def _load_song(self): - info = "" - try: - info = bumblebee.util.execute("cmus-remote -Q") - except RuntimeError: - self._status = None - - self._tags = defaultdict(lambda: '') - for line in info.split("\n"): - self._eval_line(line) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/cpu.py b/bumblebee/modules/cpu.py deleted file mode 100644 index 780c008..0000000 --- a/bumblebee/modules/cpu.py +++ /dev/null @@ -1,42 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays CPU utilization across all CPUs. - -Parameters: - * cpu.warning : Warning threshold in % of CPU usage (defaults to 70%) - * cpu.critical: Critical threshold in % of CPU usage (defaults to 80%) - * cpu.format : Format string (defaults to "{:.01f}%") -""" - -try: - import psutil -except ImportError: - pass - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.utilization) - super(Module, self).__init__(engine, config, widget) - widget.set("theme.minwidth", self._format.format(10.0-10e-20)) - self._utilization = psutil.cpu_percent(percpu=False) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="gnome-system-monitor") - - @property - def _format(self): - return self.parameter("format", "{:.01f}%") - - def utilization(self, _): - return self._format.format(self._utilization) - - def update(self, widgets): - self._utilization = psutil.cpu_percent(percpu=False) - - def state(self, _): - return self.threshold_state(self._utilization, 70, 80) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/cpu2.py b/bumblebee/modules/cpu2.py deleted file mode 100644 index d7e83b5..0000000 --- a/bumblebee/modules/cpu2.py +++ /dev/null @@ -1,157 +0,0 @@ -"""Multiwidget CPU module - -Can display any combination of: - - * max CPU frequency - * total CPU load in percents (integer value) - * per-core CPU load as graph - either mono or colored - * CPU temperature (in Celsius degrees) - * CPU fan speed - -Requirements: - - * the psutil Python module for the first three items from the list above - * sensors executable for the rest - -Parameters: - * cpu2.layout: Space-separated list of widgets to add. - Possible widgets are: - * cpu2.maxfreq - * cpu2.cpuload - * cpu2.coresload - * cpu2.temp - * cpu2.fanspeed - * cpu2.colored: 1 for colored per core load graph, 0 for mono (default) - if this is set to 1, use --markup=pango - * cpu2.temp_pattern: pattern to look for in the output of 'sensors -u'; - required if cpu2.temp widged is used - * cpu2.fan_pattern: pattern to look for in the output of 'sensors -u'; - required if cpu2.fanspeed widged is used - -Note: if you are getting "n/a" for CPU temperature / fan speed, then you're -lacking the aforementioned pattern settings or they have wrong values. - -""" - -try: - import psutil -except ImportError: - pass - -import bumblebee.engine -import bumblebee.util -import bumblebee.output - - -class Module(bumblebee.engine.Module): - - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, []) - self._layout = self.parameter("layout", "cpu2.maxfreq cpu2.cpuload cpu2.coresload cpu2.temp cpu2.fanspeed") - self._widget_names = self._layout.split() - widget_list = [] - for widget_name in self._widget_names: - if widget_name == "cpu2.maxfreq": - widget = bumblebee.output.Widget( - name=widget_name, full_text=self.maxfreq) - widget.set("type", "freq") - elif widget_name == "cpu2.cpuload": - widget = bumblebee.output.Widget( - name=widget_name, full_text=self.cpuload) - widget.set("type", "load") - elif widget_name == "cpu2.coresload": - widget = bumblebee.output.Widget( - name=widget_name, full_text=self.coresload) - widget.set("type", "loads") - elif widget_name == "cpu2.temp": - widget = bumblebee.output.Widget( - name=widget_name, full_text=self.temp) - widget.set("type", "temp") - elif widget_name == "cpu2.fanspeed": - widget = bumblebee.output.Widget( - name=widget_name, full_text=self.fanspeed) - widget.set("type", "fan") - widget_list.append(widget) - self.widgets(widget_list) - self._colored = bumblebee.util.asbool(self.parameter("colored", 0)) - self._temp_pattern = self.parameter("temp_pattern") - if self._temp_pattern is None: - self._temp = "n/a" - self._fan_pattern = self.parameter("fan_pattern") - if self._fan_pattern is None: - self._fan = "n/a" - # maxfreq is loaded only once at startup - if "cpu2.maxfreq" in self._widget_names: - self._maxfreq = psutil.cpu_freq().max / 1000 - self.update(widget_list) - - def maxfreq(self, _): - return "{:.2f}GHz".format(self._maxfreq) - - def cpuload(self, _): - return "{}%".format(self._cpuload) - - @staticmethod - def add_color(bar): - """add color as pango markup to a bar""" - if bar in ["▁", "▂"]: - color = "green" - elif bar in ["▃", "▄"]: - color = "yellow" - elif bar in ["▅", "▆"]: - color = "orange" - elif bar in ["▇", "█"]: - color = "red" - colored_bar = "{}".format(color, bar) - return colored_bar - - def coresload(self, _): - mono_bars = [bumblebee.output.hbar(x) for x in self._coresload] - if not self._colored: - return "".join(mono_bars) - colored_bars = [self.add_color(x) for x in mono_bars] - return "".join(colored_bars) - - def temp(self, _): - if self._temp == "n/a" or self._temp == 0: - return "n/a" - return "{}°C".format(self._temp) - - def fanspeed(self, _): - if self._fanspeed == "n/a": - return "n/a" - return "{}RPM".format(self._fanspeed) - - def _parse_sensors_output(self): - output = bumblebee.util.execute("sensors -u") - lines = output.split("\n") - temp = "n/a" - fan = "n/a" - temp_line = None - fan_line = None - for line in lines: - if self._temp_pattern is not None and self._temp_pattern in line: - temp_line = line - if self._fan_pattern is not None and self._fan_pattern in line: - fan_line = line - if temp_line is not None and fan_line is not None: - break - if temp_line is not None: - temp = round(float(temp_line.split(":")[1].strip())) - if fan_line is not None: - fan = int(fan_line.split(":")[1].strip()[:-4]) - return temp, fan - - def update(self, _): - if "cpu2.maxfreq" in self._widget_names: - self._maxfreq = psutil.cpu_freq().max / 1000 - if "cpu2.cpuload" in self._widget_names: - self._cpuload = round(psutil.cpu_percent(percpu=False)) - if "cpu2.coresload" in self._widget_names: - self._coresload = psutil.cpu_percent(percpu=True) - if "cpu2.temp" in self._widget_names or "cpu2.fanspeed" in self._widget_names: - self._temp, self._fanspeed = self._parse_sensors_output() - - def state(self, widget): - """for having per-widget icons""" - return [widget.get("type", "")] diff --git a/bumblebee/modules/currency.py b/bumblebee/modules/currency.py deleted file mode 100644 index dd4f1ce..0000000 --- a/bumblebee/modules/currency.py +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: UTF-8 -*- -# pylint: disable=C0111,R0903 - -"""Displays currency exchange rates. Currently, displays currency between GBP and USD/EUR only. - -Requires the following python packages: - * requests - -Parameters: - * currency.interval: Interval in minutes between updates, default is 1. - * currency.source: Source currency (ex. "GBP", "EUR"). Defaults to "auto", which infers the local one from IP address. - * currency.destination: Comma-separated list of destination currencies (defaults to "USD,EUR") - * currency.sourceformat: String format for source formatting; Defaults to "{}: {}" and has two variables, - the base symbol and the rate list - * currency.destinationdelimiter: Delimiter used for separating individual rates (defaults to "|") - -Note: source and destination names right now must correspond to the names used by the API of https://markets.ft.com -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -try: - import requests -except ImportError: - pass -try: - from babel.numbers import format_currency -except ImportError: - format_currency = None -import json -import os - -SYMBOL = { - "GBP": u"£", "EUR": u"€", "USD": u"$", "JPY": u"¥", "KRW": u"₩" -} -DEFAULT_DEST = "USD,EUR,auto" -DEFAULT_SRC = "GBP" - -API_URL = "https://markets.ft.com/data/currencies/ajax/conversion?baseCurrency={}&comparison={}" -LOCATION_URL = "https://ipvigilante.com/" - - -def get_local_country(): - r = requests.get(LOCATION_URL) - location = r.json() - return location['data']['country_name'] - - -def load_country_to_currency(): - fname = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'data', 'country-by-currency-code.json') - with open(fname, 'r') as f: - data = json.load(f) - country2curr = {} - for dt in data: - country2curr[dt['country']] = dt['currency_code'] - - return country2curr - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.price) - ) - self._data = [] - self.interval_factor(60) - self.interval(1) - self._nextcheck = 0 - - src = self.parameter("source", DEFAULT_SRC) - if src == "auto": - self._base = self.find_local_currency() - else: - self._base = src - - self._symbols = [] - for d in self.parameter("destination", DEFAULT_DEST).split(","): - if d == 'auto': - new = self.find_local_currency() - else: - new = d - if new != self._base: - self._symbols.append(new) - - def price(self, widget): - if len(self._data) == 0: - return "?" - - rates = [] - for sym, rate in self._data: - rate_float = float(rate.replace(',','')) - if format_currency: - rates.append(format_currency(rate_float, sym)) - else: - rate = self.fmt_rate(rate) - rates.append(u"{}{}".format(rate, SYMBOL[sym] if sym in SYMBOL else sym)) - - basefmt = u"{}".format(self.parameter("sourceformat", "{}={}")) - ratefmt = u"{}".format(self.parameter("destinationdelimiter", "=")) - - if format_currency: - base_val = format_currency(1, self._base) - else: - base_val = '1{}'.format(SYMBOL[self._base] if self._base in SYMBOL else self._base) - - return basefmt.format(base_val, ratefmt.join(rates)) - - def update(self, widgets): - self._data = [] - for symbol in self._symbols: - url = API_URL.format(self._base, symbol) - try: - response = requests.get(url).json() - self._data.append((symbol, response['data']['exchangeRate'])) - except Exception: - pass - - def find_local_currency(self): - '''Use geolocation lookup to find local currency''' - try: - country = get_local_country() - currency_map = load_country_to_currency() - return currency_map.get(country, DEFAULT_SRC) - except: - return DEFAULT_SRC - - def fmt_rate(self, rate): - float_rate = float(rate.replace(',', '')) - if not 0.01 < float_rate < 100: - ret = rate - else: - ret = "%.3g" % float_rate - - return ret - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/data/country-by-currency-code.json b/bumblebee/modules/data/country-by-currency-code.json deleted file mode 100644 index d29a3d7..0000000 --- a/bumblebee/modules/data/country-by-currency-code.json +++ /dev/null @@ -1,974 +0,0 @@ -[ - { - "country": "Afghanistan", - "currency_code": "AFN" - }, - { - "country": "Albania", - "currency_code": "ALL" - }, - { - "country": "Algeria", - "currency_code": "DZD" - }, - { - "country": "American Samoa", - "currency_code": "USD" - }, - { - "country": "Andorra", - "currency_code": "EUR" - }, - { - "country": "Angola", - "currency_code": "AOA" - }, - { - "country": "Anguilla", - "currency_code": "XCD" - }, - { - "country": "Antarctica", - "currency_code": "XCD" - }, - { - "country": "Antigua and Barbuda", - "currency_code": "XCD" - }, - { - "country": "Argentina", - "currency_code": "ARS" - }, - { - "country": "Armenia", - "currency_code": "AMD" - }, - { - "country": "Aruba", - "currency_code": "AWG" - }, - { - "country": "Australia", - "currency_code": "AUD" - }, - { - "country": "Austria", - "currency_code": "EUR" - }, - { - "country": "Azerbaijan", - "currency_code": "AZN" - }, - { - "country": "Bahamas", - "currency_code": "BSD" - }, - { - "country": "Bahrain", - "currency_code": "BHD" - }, - { - "country": "Bangladesh", - "currency_code": "BDT" - }, - { - "country": "Barbados", - "currency_code": "BBD" - }, - { - "country": "Belarus", - "currency_code": "BYR" - }, - { - "country": "Belgium", - "currency_code": "EUR" - }, - { - "country": "Belize", - "currency_code": "BZD" - }, - { - "country": "Benin", - "currency_code": "XOF" - }, - { - "country": "Bermuda", - "currency_code": "BMD" - }, - { - "country": "Bhutan", - "currency_code": "BTN" - }, - { - "country": "Bolivia", - "currency_code": "BOB" - }, - { - "country": "Bosnia and Herzegovina", - "currency_code": "BAM" - }, - { - "country": "Botswana", - "currency_code": "BWP" - }, - { - "country": "Bouvet Island", - "currency_code": "NOK" - }, - { - "country": "Brazil", - "currency_code": "BRL" - }, - { - "country": "British Indian Ocean Territory", - "currency_code": "USD" - }, - { - "country": "Brunei", - "currency_code": "BND" - }, - { - "country": "Bulgaria", - "currency_code": "BGN" - }, - { - "country": "Burkina Faso", - "currency_code": "XOF" - }, - { - "country": "Burundi", - "currency_code": "BIF" - }, - { - "country": "Cambodia", - "currency_code": "KHR" - }, - { - "country": "Cameroon", - "currency_code": "XAF" - }, - { - "country": "Canada", - "currency_code": "CAD" - }, - { - "country": "Cape Verde", - "currency_code": "CVE" - }, - { - "country": "Cayman Islands", - "currency_code": "KYD" - }, - { - "country": "Central African Republic", - "currency_code": "XAF" - }, - { - "country": "Chad", - "currency_code": "XAF" - }, - { - "country": "Chile", - "currency_code": "CLP" - }, - { - "country": "China", - "currency_code": "CNY" - }, - { - "country": "Christmas Island", - "currency_code": "AUD" - }, - { - "country": "Cocos (Keeling) Islands", - "currency_code": "AUD" - }, - { - "country": "Colombia", - "currency_code": "COP" - }, - { - "country": "Comoros", - "currency_code": "KMF" - }, - { - "country": "Congo", - "currency_code": "XAF" - }, - { - "country": "Cook Islands", - "currency_code": "NZD" - }, - { - "country": "Costa Rica", - "currency_code": "CRC" - }, - { - "country": "Croatia", - "currency_code": "HRK" - }, - { - "country": "Cuba", - "currency_code": "CUP" - }, - { - "country": "Cyprus", - "currency_code": "EUR" - }, - { - "country": "Czech Republic", - "currency_code": "CZK" - }, - { - "country": "Denmark", - "currency_code": "DKK" - }, - { - "country": "Djibouti", - "currency_code": "DJF" - }, - { - "country": "Dominica", - "currency_code": "XCD" - }, - { - "country": "Dominican Republic", - "currency_code": "DOP" - }, - { - "country": "East Timor", - "currency_code": "USD" - }, - { - "country": "Ecuador", - "currency_code": "ECS" - }, - { - "country": "Egypt", - "currency_code": "EGP" - }, - { - "country": "El Salvador", - "currency_code": "SVC" - }, - { - "country": "England", - "currency_code": "GBP" - }, - { - "country": "Equatorial Guinea", - "currency_code": "XAF" - }, - { - "country": "Eritrea", - "currency_code": "ERN" - }, - { - "country": "Estonia", - "currency_code": "EUR" - }, - { - "country": "Ethiopia", - "currency_code": "ETB" - }, - { - "country": "Falkland Islands", - "currency_code": "FKP" - }, - { - "country": "Faroe Islands", - "currency_code": "DKK" - }, - { - "country": "Fiji Islands", - "currency_code": "FJD" - }, - { - "country": "Finland", - "currency_code": "EUR" - }, - { - "country": "France", - "currency_code": "EUR" - }, - { - "country": "French Guiana", - "currency_code": "EUR" - }, - { - "country": "French Polynesia", - "currency_code": "XPF" - }, - { - "country": "French Southern territories", - "currency_code": "EUR" - }, - { - "country": "Gabon", - "currency_code": "XAF" - }, - { - "country": "Gambia", - "currency_code": "GMD" - }, - { - "country": "Georgia", - "currency_code": "GEL" - }, - { - "country": "Germany", - "currency_code": "EUR" - }, - { - "country": "Ghana", - "currency_code": "GHS" - }, - { - "country": "Gibraltar", - "currency_code": "GIP" - }, - { - "country": "Greece", - "currency_code": "EUR" - }, - { - "country": "Greenland", - "currency_code": "DKK" - }, - { - "country": "Grenada", - "currency_code": "XCD" - }, - { - "country": "Guadeloupe", - "currency_code": "EUR" - }, - { - "country": "Guam", - "currency_code": "USD" - }, - { - "country": "Guatemala", - "currency_code": "QTQ" - }, - { - "country": "Guinea", - "currency_code": "GNF" - }, - { - "country": "Guinea-Bissau", - "currency_code": "CFA" - }, - { - "country": "Guyana", - "currency_code": "GYD" - }, - { - "country": "Haiti", - "currency_code": "HTG" - }, - { - "country": "Heard Island and McDonald Islands", - "currency_code": "AUD" - }, - { - "country": "Holy See (Vatican City State)", - "currency_code": "EUR" - }, - { - "country": "Honduras", - "currency_code": "HNL" - }, - { - "country": "Hong Kong", - "currency_code": "HKD" - }, - { - "country": "Hungary", - "currency_code": "HUF" - }, - { - "country": "Iceland", - "currency_code": "ISK" - }, - { - "country": "India", - "currency_code": "INR" - }, - { - "country": "Indonesia", - "currency_code": "IDR" - }, - { - "country": "Iran", - "currency_code": "IRR" - }, - { - "country": "Iraq", - "currency_code": "IQD" - }, - { - "country": "Ireland", - "currency_code": "EUR" - }, - { - "country": "Israel", - "currency_code": "ILS" - }, - { - "country": "Italy", - "currency_code": "EUR" - }, - { - "country": "Ivory Coast", - "currency_code": "XOF" - }, - { - "country": "Jamaica", - "currency_code": "JMD" - }, - { - "country": "Japan", - "currency_code": "JPY" - }, - { - "country": "Jordan", - "currency_code": "JOD" - }, - { - "country": "Kazakhstan", - "currency_code": "KZT" - }, - { - "country": "Kenya", - "currency_code": "KES" - }, - { - "country": "Kiribati", - "currency_code": "AUD" - }, - { - "country": "Kuwait", - "currency_code": "KWD" - }, - { - "country": "Kyrgyzstan", - "currency_code": "KGS" - }, - { - "country": "Laos", - "currency_code": "LAK" - }, - { - "country": "Latvia", - "currency_code": "LVL" - }, - { - "country": "Lebanon", - "currency_code": "LBP" - }, - { - "country": "Lesotho", - "currency_code": "LSL" - }, - { - "country": "Liberia", - "currency_code": "LRD" - }, - { - "country": "Libyan Arab Jamahiriya", - "currency_code": "LYD" - }, - { - "country": "Liechtenstein", - "currency_code": "CHF" - }, - { - "country": "Lithuania", - "currency_code": "LTL" - }, - { - "country": "Luxembourg", - "currency_code": "EUR" - }, - { - "country": "Macao", - "currency_code": "MOP" - }, - { - "country": "North Macedonia", - "currency_code": "MKD" - }, - { - "country": "Madagascar", - "currency_code": "MGF" - }, - { - "country": "Malawi", - "currency_code": "MWK" - }, - { - "country": "Malaysia", - "currency_code": "MYR" - }, - { - "country": "Maldives", - "currency_code": "MVR" - }, - { - "country": "Mali", - "currency_code": "XOF" - }, - { - "country": "Malta", - "currency_code": "EUR" - }, - { - "country": "Marshall Islands", - "currency_code": "USD" - }, - { - "country": "Martinique", - "currency_code": "EUR" - }, - { - "country": "Mauritania", - "currency_code": "MRO" - }, - { - "country": "Mauritius", - "currency_code": "MUR" - }, - { - "country": "Mayotte", - "currency_code": "EUR" - }, - { - "country": "Mexico", - "currency_code": "MXN" - }, - { - "country": "Micronesia, Federated States of", - "currency_code": "USD" - }, - { - "country": "Moldova", - "currency_code": "MDL" - }, - { - "country": "Monaco", - "currency_code": "EUR" - }, - { - "country": "Mongolia", - "currency_code": "MNT" - }, - { - "country": "Montserrat", - "currency_code": "XCD" - }, - { - "country": "Morocco", - "currency_code": "MAD" - }, - { - "country": "Mozambique", - "currency_code": "MZN" - }, - { - "country": "Myanmar", - "currency_code": "MMR" - }, - { - "country": "Namibia", - "currency_code": "NAD" - }, - { - "country": "Nauru", - "currency_code": "AUD" - }, - { - "country": "Nepal", - "currency_code": "NPR" - }, - { - "country": "Netherlands", - "currency_code": "EUR" - }, - { - "country": "Netherlands Antilles", - "currency_code": "ANG" - }, - { - "country": "New Caledonia", - "currency_code": "XPF" - }, - { - "country": "New Zealand", - "currency_code": "NZD" - }, - { - "country": "Nicaragua", - "currency_code": "NIO" - }, - { - "country": "Niger", - "currency_code": "XOF" - }, - { - "country": "Nigeria", - "currency_code": "NGN" - }, - { - "country": "Niue", - "currency_code": "NZD" - }, - { - "country": "Norfolk Island", - "currency_code": "AUD" - }, - { - "country": "North Korea", - "currency_code": "KPW" - }, - { - "country": "Northern Ireland", - "currency_code": "GBP" - }, - { - "country": "Northern Mariana Islands", - "currency_code": "USD" - }, - { - "country": "Norway", - "currency_code": "NOK" - }, - { - "country": "Oman", - "currency_code": "OMR" - }, - { - "country": "Pakistan", - "currency_code": "PKR" - }, - { - "country": "Palau", - "currency_code": "USD" - }, - { - "country": "Palestine", - "currency_code": null - }, - { - "country": "Panama", - "currency_code": "PAB" - }, - { - "country": "Papua New Guinea", - "currency_code": "PGK" - }, - { - "country": "Paraguay", - "currency_code": "PYG" - }, - { - "country": "Peru", - "currency_code": "PEN" - }, - { - "country": "Philippines", - "currency_code": "PHP" - }, - { - "country": "Pitcairn", - "currency_code": "NZD" - }, - { - "country": "Poland", - "currency_code": "PLN" - }, - { - "country": "Portugal", - "currency_code": "EUR" - }, - { - "country": "Puerto Rico", - "currency_code": "USD" - }, - { - "country": "Qatar", - "currency_code": "QAR" - }, - { - "country": "Reunion", - "currency_code": "EUR" - }, - { - "country": "Romania", - "currency_code": "RON" - }, - { - "country": "Russian Federation", - "currency_code": "RUB" - }, - { - "country": "Rwanda", - "currency_code": "RWF" - }, - { - "country": "Saint Helena", - "currency_code": "SHP" - }, - { - "country": "Saint Kitts and Nevis", - "currency_code": "XCD" - }, - { - "country": "Saint Lucia", - "currency_code": "XCD" - }, - { - "country": "Saint Pierre and Miquelon", - "currency_code": "EUR" - }, - { - "country": "Saint Vincent and the Grenadines", - "currency_code": "XCD" - }, - { - "country": "Samoa", - "currency_code": "WST" - }, - { - "country": "San Marino", - "currency_code": "EUR" - }, - { - "country": "Sao Tome and Principe", - "currency_code": "STD" - }, - { - "country": "Saudi Arabia", - "currency_code": "SAR" - }, - { - "country": "Scotland", - "currency_code": "GBP" - }, - { - "country": "Senegal", - "currency_code": "XOF" - }, - { - "country": "Seychelles", - "currency_code": "SCR" - }, - { - "country": "Sierra Leone", - "currency_code": "SLL" - }, - { - "country": "Singapore", - "currency_code": "SGD" - }, - { - "country": "Slovakia", - "currency_code": "EUR" - }, - { - "country": "Slovenia", - "currency_code": "EUR" - }, - { - "country": "Solomon Islands", - "currency_code": "SBD" - }, - { - "country": "Somalia", - "currency_code": "SOS" - }, - { - "country": "South Africa", - "currency_code": "ZAR" - }, - { - "country": "South Georgia and the South Sandwich Islands", - "currency_code": "GBP" - }, - { - "country": "South Korea", - "currency_code": "KRW" - }, - { - "country": "South Sudan", - "currency_code": "SSP" - }, - { - "country": "Spain", - "currency_code": "EUR" - }, - { - "country": "SriLanka", - "currency_code": "LKR" - }, - { - "country": "Sudan", - "currency_code": "SDG" - }, - { - "country": "Suriname", - "currency_code": "SRD" - }, - { - "country": "Svalbard and Jan Mayen", - "currency_code": "NOK" - }, - { - "country": "Swaziland", - "currency_code": "SZL" - }, - { - "country": "Sweden", - "currency_code": "SEK" - }, - { - "country": "Switzerland", - "currency_code": "CHF" - }, - { - "country": "Syria", - "currency_code": "SYP" - }, - { - "country": "Tajikistan", - "currency_code": "TJS" - }, - { - "country": "Tanzania", - "currency_code": "TZS" - }, - { - "country": "Thailand", - "currency_code": "THB" - }, - { - "country": "The Democratic Republic of Congo", - "currency_code": "CDF" - }, - { - "country": "Togo", - "currency_code": "XOF" - }, - { - "country": "Tokelau", - "currency_code": "NZD" - }, - { - "country": "Tonga", - "currency_code": "TOP" - }, - { - "country": "Trinidad and Tobago", - "currency_code": "TTD" - }, - { - "country": "Tunisia", - "currency_code": "TND" - }, - { - "country": "Turkey", - "currency_code": "TRY" - }, - { - "country": "Turkmenistan", - "currency_code": "TMT" - }, - { - "country": "Turks and Caicos Islands", - "currency_code": "USD" - }, - { - "country": "Tuvalu", - "currency_code": "AUD" - }, - { - "country": "Uganda", - "currency_code": "UGX" - }, - { - "country": "Ukraine", - "currency_code": "UAH" - }, - { - "country": "United Arab Emirates", - "currency_code": "AED" - }, - { - "country": "United Kingdom", - "currency_code": "GBP" - }, - { - "country": "United States", - "currency_code": "USD" - }, - { - "country": "United States Minor Outlying Islands", - "currency_code": "USD" - }, - { - "country": "Uruguay", - "currency_code": "UYU" - }, - { - "country": "Uzbekistan", - "currency_code": "UZS" - }, - { - "country": "Vanuatu", - "currency_code": "VUV" - }, - { - "country": "Venezuela", - "currency_code": "VEF" - }, - { - "country": "Vietnam", - "currency_code": "VND" - }, - { - "country": "Virgin Islands, British", - "currency_code": "USD" - }, - { - "country": "Virgin Islands, U.S.", - "currency_code": "USD" - }, - { - "country": "Wales", - "currency_code": "GBP" - }, - { - "country": "Wallis and Futuna", - "currency_code": "XPF" - }, - { - "country": "Western Sahara", - "currency_code": "MAD" - }, - { - "country": "Yemen", - "currency_code": "YER" - }, - { - "country": "Yugoslavia", - "currency_code": null - }, - { - "country": "Zambia", - "currency_code": "ZMW" - }, - { - "country": "Zimbabwe", - "currency_code": "ZWD" - } -] diff --git a/bumblebee/modules/datetime.py b/bumblebee/modules/datetime.py deleted file mode 100644 index 8899c4a..0000000 --- a/bumblebee/modules/datetime.py +++ /dev/null @@ -1,50 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the current date and time. - -Parameters: - * datetime.format: strftime()-compatible formatting string - * date.format : alias for datetime.format - * time.format : alias for datetime.format - * datetime.locale: locale to use rather than the system default - * date.locale : alias for datetime.locale - * time.locale : alias for datetime.locale -""" - -from __future__ import absolute_import -import datetime -import locale -import bumblebee.engine - -def default_format(module): - default = "%x %X" - if module == "date": - default = "%x" - if module == "time": - default = "%X" - return default - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.get_time)) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="calendar") - self._fmt = self.parameter("format", default_format(self.name)) - l = locale.getdefaultlocale() - if not l or l == (None, None): - l = ('en_US', 'UTF-8') - lcl = self.parameter("locale", ".".join(l)) - try: - locale.setlocale(locale.LC_TIME, lcl.split(".")) - except Exception as e: - locale.setlocale(locale.LC_TIME, ('en_US', 'UTF-8')) - - def get_time(self, widget): - enc = locale.getpreferredencoding() - retval = datetime.datetime.now().strftime(self._fmt) - if hasattr(retval, "decode"): - return retval.decode(enc) - return retval - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/datetimetz.py b/bumblebee/modules/datetimetz.py deleted file mode 100644 index c778be9..0000000 --- a/bumblebee/modules/datetimetz.py +++ /dev/null @@ -1,93 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the current date and time with timezone options. - -Parameters: - * datetimetz.format : strftime()-compatible formatting string - * datetimetz.timezone : IANA timezone name - * datetz.format : alias for datetimetz.format - * timetz.format : alias for datetimetz.format - * timetz.timezone : alias for datetimetz.timezone - * datetimetz.locale : locale to use rather than the system default - * datetz.locale : alias for datetimetz.locale - * timetz.locale : alias for datetimetz.locale - * timetz.timezone : alias for datetimetz.timezone -""" - -from __future__ import absolute_import -import datetime -import locale -import logging -try: - import pytz - import tzlocal -except: - pass -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -def default_format(module): - default = "%x %X %Z" - if module == "datetz": - default = "%x %Z" - if module == "timetz": - default = "%X %Z" - return default - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.get_time)) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, cmd=self.next_tz) - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd=self.prev_tz) - self._fmt = self.parameter("format", default_format(self.name)) - default_timezone = "" - try: - default_timezone = tzlocal.get_localzone().zone - except Exception as e: - logging.error('unable to get default timezone: {}'.format(str(e))) - try: - self._timezones = self.parameter("timezone", default_timezone).split(",") - except: - self._timezones = [default_timezone] - self._current_tz = 0 - - l = locale.getdefaultlocale() - if not l or l == (None, None): - l = ('en_US', 'UTF-8') - lcl = self.parameter("locale", ".".join(l)) - try: - locale.setlocale(locale.LC_TIME, lcl.split(".")) - except Exception: - locale.setlocale(locale.LC_TIME, ('en_US', 'UTF-8')) - - def get_time(self, widget): - try: - try: - tz = pytz.timezone(self._timezones[self._current_tz].strip()) - retval = datetime.datetime.now(tz=tzlocal.get_localzone()).astimezone(tz).strftime(self._fmt) - except pytz.exceptions.UnknownTimeZoneError: - retval = "[Unknown timezone: {}]".format(self._timezones[self._current_tz].strip()) - except Exception as e: - logging.error('unable to get time: {}'.format(str(e))) - retval = "[n/a]" - - enc = locale.getpreferredencoding() - if hasattr(retval, "decode"): - return retval.decode(enc) - return retval - - def next_tz(self, event): - next_timezone = self._current_tz + 1 - if next_timezone >= len(self._timezones): - next_timezone = 0 # wraparound - self._current_tz = next_timezone - - def prev_tz(self, event): - previous_timezone = self._current_tz - 1 - if previous_timezone < 0: - previous_timezone = 0 # wraparound - self._current_tz = previous_timezone - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/deadbeef.py b/bumblebee/modules/deadbeef.py deleted file mode 100644 index 5b74933..0000000 --- a/bumblebee/modules/deadbeef.py +++ /dev/null @@ -1,143 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the current song being played in DeaDBeeF and provides -some media control bindings. -Left click toggles pause, scroll up skips the current song, scroll -down returns to the previous song. - -Requires the following library: - * subprocess -Parameters: - * deadbeef.format: Format string (defaults to "{artist} - {title}") - Available values are: {artist}, {title}, {album}, {length}, - {trackno}, {year}, {comment}, - {copyright}, {time} - This is deprecated, but much simpler. - * deadbeef.tf_format: A foobar2000 title formatting-style format string. - These can be much more sophisticated than the standard - format strings. This is off by default, but specifying - any tf_format will enable it. If both deadbeef.format - and deadbeef.tf_format are specified, deadbeef.tf_format - takes priority. - * deadbeef.tf_format_if_stopped: Controls whether or not the tf_format format - string should be displayed even if no song is paused or - playing. This could be useful if you want to implement - your own stop strings with the built in logic. Any non- - null value will enable this (by default the module will - hide itself when the player is stopped). - * deadbeef.previous: Change binding for previous song (default is left click) - * deadbeef.next: Change binding for next song (default is right click) - * deadbeef.pause: Change binding for toggling pause (default is middle click) - Available options for deadbeef.previous, deadbeef.next and deadbeef.pause are: - LEFT_CLICK, RIGHT_CLICK, MIDDLE_CLICK, SCROLL_UP, SCROLL_DOWN - -""" -import sys - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from bumblebee.output import scrollable - -try: - import subprocess -except ImportError: - pass - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.deadbeef) - ) - buttons = {"LEFT_CLICK": bumblebee.input.LEFT_MOUSE, - "RIGHT_CLICK": bumblebee.input.RIGHT_MOUSE, - "MIDDLE_CLICK": bumblebee.input.MIDDLE_MOUSE, - "SCROLL_UP": bumblebee.input.WHEEL_UP, - "SCROLL_DOWN": bumblebee.input.WHEEL_DOWN, - } - - self._song = "" - self._format = self.parameter("format", "{artist} - {title}") - self._tf_format = self.parameter("tf_format", "") - self._show_tf_when_stopped = bool(self.parameter("tf_format_if_stopped", "")) - prev_button = self.parameter("previous", "LEFT_CLICK") - next_button = self.parameter("next", "RIGHT_CLICK") - pause_button = self.parameter("pause", "MIDDLE_CLICK") - - self.now_playing = ["deadbeef", "--nowplaying", "%a;%t;%b;%l;%n;%y;%c;%r;%e"] - self.now_playing_tf = ["deadbeef", "--nowplaying-tf", ""] - cmd = "deadbeef " - - engine.input.register_callback(self, button=buttons[prev_button], - cmd=cmd + "--prev") - engine.input.register_callback(self, button=buttons[next_button], - cmd=cmd + "--next") - engine.input.register_callback(self, button=buttons[pause_button], - cmd=cmd + "--play-pause") - - # modify the tf_format if we don't want it to show on stop - # this adds conditions to the query itself, rather than - # polling to see if deadbeef is running - # doing this reduces the number of calls we have to make - if self._tf_format and not self._show_tf_when_stopped: - self._tf_format = "$if($or(%isplaying%,%ispaused%),{query})".format(query=self._tf_format) - - @scrollable - def deadbeef(self, widget): - return self.string_song - - def hidden(self): - return self.string_song == "" - - def update(self, widgets): - try: - if self._tf_format == "": # no tf format set, use the old style - return self.update_standard(widgets) - return self.update_tf(widgets) - except Exception: - self._song = "error" - - def update_tf(self, widgets): - ## ensure that deadbeef is actually running - ## easiest way to do this is to check --nowplaying for - ## the string "nothing" - if read_process(self.now_playing) == "nothing": - self._song = "" - return - ## perform the actual query -- these can be much more sophisticated - self.now_playing_tf[-1] = self._tf_format - data = read_process(self.now_playing_tf) - self._song = data - - def update_standard(self, widgets): - data = read_process(self.now_playing) - if data == "nothing": - self._song = "" - else: - data = data.split(";") - self._song = self._format.format(artist=data[0], - title=data[1], - album=data[2], - length=data[3], - trackno=data[4], - year=data[5], - comment=data[6], - copyright=data[7], - time=data[8]) - - @property - def string_song(self): - """\ -Returns the current song as a string, either as a unicode() (Python < -3) or a regular str() (Python >= 3) - """ - if sys.version_info.major < 3: - return unicode(self._song) - return str(self._song) - -def read_process(command): - proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - return proc.stdout.read() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/deezer.py b/bumblebee/modules/deezer.py deleted file mode 100644 index 582c7fc..0000000 --- a/bumblebee/modules/deezer.py +++ /dev/null @@ -1,77 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the current song being played -Requires the following library: - * python-dbus -Parameters: - * deezer.format: Format string (defaults to "{artist} - {title}") - Available values are: {album}, {title}, {artist}, {trackNumber}, {playbackStatus} - * deezer.previous: Change binding for previous song (default is left click) - * deezer.next: Change binding for next song (default is right click) - * deezer.pause: Change binding for toggling pause (default is middle click) - Available options for deezer.previous, deezer.next and deezer.pause are: - LEFT_CLICK, RIGHT_CLICK, MIDDLE_CLICK, SCROLL_UP, SCROLL_DOWN -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from bumblebee.output import scrollable - -try: - import dbus -except ImportError: - pass - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.deezer) - ) - buttons = {"LEFT_CLICK":bumblebee.input.LEFT_MOUSE, - "RIGHT_CLICK":bumblebee.input.RIGHT_MOUSE, - "MIDDLE_CLICK":bumblebee.input.MIDDLE_MOUSE, - "SCROLL_UP":bumblebee.input.WHEEL_UP, - "SCROLL_DOWN":bumblebee.input.WHEEL_DOWN, - } - - self._song = "" - self._format = self.parameter("format", "{artist} - {title}") - prev_button = self.parameter("previous", "LEFT_CLICK") - next_button = self.parameter("next", "RIGHT_CLICK") - pause_button = self.parameter("pause", "MIDDLE_CLICK") - - cmd = "dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.deezer \ - /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player." - engine.input.register_callback(self, button=buttons[prev_button], - cmd=cmd + "Previous") - engine.input.register_callback(self, button=buttons[next_button], - cmd=cmd + "Next") - engine.input.register_callback(self, button=buttons[pause_button], - cmd=cmd + "PlayPause") - -## @scrollable - def deezer(self, widget): - return str(self._song) - - def hidden(self): - return str(self._song) == "" - - def update(self, widgets): - try: - bus = dbus.SessionBus() - deezer = bus.get_object("org.mpris.MediaPlayer2.deezer", "/org/mpris/MediaPlayer2") - deezer_iface = dbus.Interface(deezer, 'org.freedesktop.DBus.Properties') - props = deezer_iface.Get('org.mpris.MediaPlayer2.Player', 'Metadata') - playback_status = str(deezer_iface.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus')) - self._song = self._format.format(album=str(props.get('xesam:album')), - title=str(props.get('xesam:title')), - artist=','.join(props.get('xesam:artist')), - trackNumber=str(props.get('xesam:trackNumber')), - playbackStatus=u"\u25B6" if playback_status=="Playing" else u"\u258D\u258D" if playback_status=="Paused" else "",) - except Exception: - self._song = "" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/disk.py b/bumblebee/modules/disk.py deleted file mode 100644 index db4d522..0000000 --- a/bumblebee/modules/disk.py +++ /dev/null @@ -1,88 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Shows free diskspace, total diskspace and the percentage of free disk space. - -Parameters: - * disk.warning: Warning threshold in % of disk space (defaults to 80%) - * disk.critical: Critical threshold in % of disk space (defaults ot 90%) - * disk.path: Path to calculate disk usage from (defaults to /) - * disk.open: Which application / file manager to launch (default xdg-open) - * disk.format: Format string, tags {path}, {used}, {left}, {size} and {percent} (defaults to "{path} {used}/{size} ({percent:05.02f}%)") - * (deprecated) disk.showUsed: Show used space (defaults to yes) - * (deprecated) disk.showSize: Show total size (defaults to yes) - * (deprecated) disk.showPercent: Show usage percentage (defaults to yes) -""" - -import os - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.diskspace) - ) - self._path = self.parameter("path", "/") - self._format = self.parameter("format", "{used}/{size} ({percent:05.02f}%)") - self._app = self.parameter("open", "xdg-open") - - self._used = 0 - self._left = 0 - self._size = 0 - self._percent = 0 - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="{} {}".format(self._app, - self._path)) - - - def diskspace(self, widget): - used_str = bumblebee.util.bytefmt(self._used) - size_str = bumblebee.util.bytefmt(self._size) - left_str = bumblebee.util.bytefmt(self._left) - percent_str = self._percent - - sused = self.has_parameter("showUsed") - ssize = self.has_parameter("showSize") - spercent = self.has_parameter("showPercent") - - if all(not param for param in (sused, ssize, spercent)): - return self._format.format(path=self._path, - used=used_str, - left=left_str, - size=size_str, - percent=percent_str) - else: - rv = "" - sused = bumblebee.util.asbool(self.parameter("showUsed", True)) - ssize = bumblebee.util.asbool(self.parameter("showSize", True)) - spercent = bumblebee.util.asbool(self.parameter("showPercent", True)) - - if sused: - rv = "{}{}".format(rv, used_str) - if sused and ssize: - rv = "{}/".format(rv) - if ssize: - rv = "{}{}".format(rv, size_str) - if spercent: - if not sused and not ssize: - rv = "{:05.02f}%".format(percent_str) - else: - rv = "{} ({:05.02f}%)".format(rv, percent_str) - return rv - - - def update(self, widgets): - st = os.statvfs(self._path) - self._size = st.f_blocks * st.f_frsize - self._used = (st.f_blocks - st.f_bfree) * st.f_frsize - self._left = self._size - self._used; - self._percent = 100.0 * self._used/self._size - - def state(self, widget): - return self.threshold_state(self._percent, 80, 90) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/dnf.py b/bumblebee/modules/dnf.py deleted file mode 100644 index d3ceebf..0000000 --- a/bumblebee/modules/dnf.py +++ /dev/null @@ -1,77 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays DNF package update information (///) - -Requires the following executable: - * dnf - -Parameters: - * dnf.interval: Time in minutes between two consecutive update checks (defaults to 30 minutes) - -""" - -import threading - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -def get_dnf_info(widget): - try: - res = bumblebee.util.execute("dnf updateinfo") - except RuntimeError: - pass - - security = 0 - bugfixes = 0 - enhancements = 0 - other = 0 - for line in res.split("\n"): - - if not line.startswith(" "): continue - elif "ecurity" in line: - for s in line.split(): - if s.isdigit(): security += int(s) - elif "ugfix" in line: - for s in line.split(): - if s.isdigit(): bugfixes += int(s) - elif "hancement" in line: - for s in line.split(): - if s.isdigit(): enhancements += int(s) - else: - for s in line.split(): - if s.isdigit(): other += int(s) - - widget.set("security", security) - widget.set("bugfixes", bugfixes) - widget.set("enhancements", enhancements) - widget.set("other", other) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.updates) - super(Module, self).__init__(engine, config, widget) - self.interval_factor(60) - self.interval(30) - - def updates(self, widget): - result = [] - for t in ["security", "bugfixes", "enhancements", "other"]: - result.append(str(widget.get(t, 0))) - return "/".join(result) - - def update(self, widgets): - thread = threading.Thread(target=get_dnf_info, args=(widgets[0],)) - thread.start() - - def state(self, widget): - cnt = 0 - for t in ["security", "bugfixes", "enhancements", "other"]: - cnt += widget.get(t, 0) - if cnt == 0: - return "good" - if cnt > 50 or widget.get("security", 0) > 0: - return "critical" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/docker_ps.py b/bumblebee/modules/docker_ps.py deleted file mode 100644 index c36c0e7..0000000 --- a/bumblebee/modules/docker_ps.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- - -"""Displays the number of docker containers running - -Requires the following python packages: - * docker - -""" - -try: - import docker -except ImportError: - pass - -from requests.exceptions import ConnectionError - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.status) - super(Module, self).__init__(engine, config, widget) - self._status = self.status - - def update(self, widgets): - self._status = self.status - - def status(self, _): - try: - cli = docker.DockerClient(base_url='unix://var/run/docker.sock') - cli.ping() - except ConnectionError: - return "Daemon off" - except Exception: - return "n/a" - return "OK - {}".format(len(cli.containers.list(filters={'status': "running"}))) diff --git a/bumblebee/modules/dunst.py b/bumblebee/modules/dunst.py deleted file mode 100644 index e805ef5..0000000 --- a/bumblebee/modules/dunst.py +++ /dev/null @@ -1,39 +0,0 @@ -#pylint: disable=C0111,R0903 - -"""Toggle dunst notifications.""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text="") - ) - self._paused = False - # Make sure that dunst is currently not paused - try: - bumblebee.util.execute("killall -SIGUSR2 dunst") - except: - pass - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.toggle_status - ) - - def toggle_status(self, event): - self._paused = not self._paused - - try: - if self._paused: - bumblebee.util.execute("killall -SIGUSR1 dunst") - else: - bumblebee.util.execute("killall -SIGUSR2 dunst") - except: - self._paused = not self._paused # toggling failed - - def state(self, widget): - if self._paused: - return ["muted", "warning"] - return ["unmuted"] diff --git a/bumblebee/modules/error.py b/bumblebee/modules/error.py deleted file mode 100644 index 16d3834..0000000 --- a/bumblebee/modules/error.py +++ /dev/null @@ -1,26 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Draws an error widget. -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.text) - ) - self._text = "" - - def set(self, text): - self._text = text - - def text(self, widget): - return self._text - - def state(self, widget): - return ["critical"] - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/getcrypto.py b/bumblebee/modules/getcrypto.py deleted file mode 100644 index d75b373..0000000 --- a/bumblebee/modules/getcrypto.py +++ /dev/null @@ -1,75 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the price of a cryptocurrency. - -Requires the following python packages: - * requests - -Parameters: - * getcrypto.interval: Interval in seconds for updating the price, default is 120, less than that will probably get your IP banned. - * getcrypto.getbtc: 0 for not getting price of BTC, 1 for getting it (default). - * getcrypto.geteth: 0 for not getting price of ETH, 1 for getting it (default). - * getcrypto.getltc: 0 for not getting price of LTC, 1 for getting it (default). - * getcrypto.getcur: Set the currency to display the price in, usd is the default. -""" - -import requests -import time -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine -from requests.exceptions import RequestException -def getfromkrak(coin, currency): - abbrev = { - "Btc": ["xbt", "XXBTZ"], - "Eth": ["eth", "XETHZ"], - "Ltc": ["ltc", "XLTCZ"], - } - data = abbrev.get(coin, None) - if not data: return - epair = "{}{}".format(data[0], currency) - tickname = "{}{}".format(data[1], currency.upper()) - try: - krakenget = requests.get('https://api.kraken.com/0/public/Ticker?pair='+epair).json() - except (RequestException, Exception): - return "No connection" - if not 'result' in krakenget: - return "No data" - kethusdask = float(krakenget['result'][tickname]['a'][0]) - kethusdbid = float(krakenget['result'][tickname]['b'][0]) - return coin+": "+str((kethusdask+kethusdbid)/2)[0:6] - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.curprice) - ) - self._curprice = "" - self._nextcheck = 0 - self._interval = int(self.parameter("interval", "120")) - self._getbtc = bumblebee.util.asbool(self.parameter("getbtc", True)) - self._geteth = bumblebee.util.asbool(self.parameter("geteth", True)) - self._getltc = bumblebee.util.asbool(self.parameter("getltc", True)) - self._getcur = self.parameter("getcur", "usd") - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="xdg-open https://cryptowat.ch/") - - def curprice(self, widget): - return self._curprice - - def update(self, widgets): - if self._nextcheck < int(time.time()): - self._nextcheck = int(time.time()) + self._interval - currency = self._getcur - btcprice, ethprice, ltcprice = "", "", "" - if self._getbtc: - btcprice = getfromkrak('Btc', currency) - if self._geteth: - ethprice = getfromkrak('Eth', currency) - if self._getltc: - ltcprice = getfromkrak('Ltc', currency) - self._curprice = btcprice+" "*(self._getbtc*self._geteth)+ethprice+" "*(self._getltc*max(self._getbtc, self._geteth))+ltcprice - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/git.py b/bumblebee/modules/git.py deleted file mode 100644 index 468d174..0000000 --- a/bumblebee/modules/git.py +++ /dev/null @@ -1,81 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Print the branch and git status for the -currently focused window. - -Requires: - * xcwd - * Python module 'pygit2' -""" - -import os -import string -import logging -try: - import pygit2 -except ImportError: - pass - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - super(Module, self).__init__(engine, config, widgets) - self._engine = engine - self._error = False - self.update(self.widgets()) - - def hidden(self): - return self._error - - def update(self, widgets): - state = {} - new_widgets = [] - try: - directory = bumblebee.util.execute("xcwd").strip() - directory = self._get_git_root(directory) - repo = pygit2.Repository(directory) - - new_widgets.append(bumblebee.output.Widget(name='git.main', full_text=repo.head.shorthand)) - - for filepath, flags in repo.status().items(): - if flags == pygit2.GIT_STATUS_WT_NEW or \ - flags == pygit2.GIT_STATUS_INDEX_NEW: - state['new'] = True - if flags == pygit2.GIT_STATUS_WT_DELETED or \ - flags == pygit2.GIT_STATUS_INDEX_DELETED: - state['deleted'] = True - if flags == pygit2.GIT_STATUS_WT_MODIFIED or \ - flags == pygit2.GIT_STATUS_INDEX_MODIFIED: - state['modified'] = True - self._error = False - if 'new' in state: - new_widgets.append(bumblebee.output.Widget(name='git.new')) - if 'modified' in state: - new_widgets.append(bumblebee.output.Widget(name='git.modified')) - if 'deleted' in state: - new_widgets.append(bumblebee.output.Widget(name='git.deleted')) - - while len(widgets) > 0: - del widgets[0] - for widget in new_widgets: - widgets.append(widget) - - except Exception as e: - self._error = True - - def state(self, widget): - return widget.name.split('.')[1] - - def _get_git_root(self, directory): - while len(directory) > 1: - if os.path.exists(os.path.join(directory, ".git")): - return directory - directory = "/".join(directory.split("/")[0:-1]) - return "/" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/github.py b/bumblebee/modules/github.py deleted file mode 100644 index 3a3d097..0000000 --- a/bumblebee/modules/github.py +++ /dev/null @@ -1,56 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the unread GitHub notifications for a GitHub user - -Requires the following library: - * requests - -Parameters: - * github.token: GitHub user access token, the token needs to have the 'notifications' scope. - * github.interval: Interval in minutes between updates, default is 5. -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -try: - import requests -except ImportError: - pass - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.github) - ) - self._count = 0 - self.interval_factor(60) - self.interval(5) - self._requests = requests.Session() - self._requests.headers.update({"Authorization":"token {}".format(self.parameter("token", ""))}) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="x-www-browser https://github.com/notifications") - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd=self.update) - - def github(self, _): - return str(self._count) - - def update(self, _): - try: - self._count = 0 - url = "https://api.github.com/notifications" - while True: - notifications = self._requests.get(url) - self._count += len(list(filter(lambda notification: notification['unread'], notifications.json()))) - next_link = notifications.links.get('next') - if next_link is not None: - url = next_link.get('url') - else: - break - - except Exception: - self._count = "n/a" - - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/gpmdp.py b/bumblebee/modules/gpmdp.py deleted file mode 100644 index 922145f..0000000 --- a/bumblebee/modules/gpmdp.py +++ /dev/null @@ -1,56 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays information about the current song in Google Play music player. - -Requires the following executable: - * gpmdp-remote -""" - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [ - bumblebee.output.Widget(name="gpmdp.prev"), - bumblebee.output.Widget(name="gpmdp.main", full_text=self.description), - bumblebee.output.Widget(name="gpmdp.next"), - ] - super(Module, self).__init__(engine, config, widgets) - - engine.input.register_callback(widgets[0], button=bumblebee.input.LEFT_MOUSE, - cmd="playerctl previous") - engine.input.register_callback(widgets[1], button=bumblebee.input.LEFT_MOUSE, - cmd="playerctl play-pause") - engine.input.register_callback(widgets[2], button=bumblebee.input.LEFT_MOUSE, - cmd="playerctl next") - - self._status = None - self._tags = None - - def description(self, widget): - return self._tags if self._tags else "n/a" - - def update(self, widgets): - self._load_song() - - def state(self, widget): - if widget.name == "gpmdp.prev": - return "prev" - if widget.name == "gpmdp.next": - return "next" - return self._status - - def _load_song(self): - info = "" - try: - info = bumblebee.util.execute("gpmdp-remote current") - status = bumblebee.util.execute("gpmdp-remote status") - except RuntimeError: - pass - self._status = status.split("\n")[0].lower() - self._tags = info.split("\n")[0] - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/hddtemp.py b/bumblebee/modules/hddtemp.py deleted file mode 100644 index 86800c1..0000000 --- a/bumblebee/modules/hddtemp.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- - -"""Fetch hard drive temeperature data from a hddtemp daemon -that runs on localhost and default port (7634) -""" - -import socket - -import bumblebee.engine -import bumblebee.output - -HOST = "localhost" -PORT = 7634 - -CHUNK_SIZE = 1024 -RECORD_SIZE = 5 -SEPARATOR = "|" - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.hddtemps) - super(Module, self).__init__(engine, config, widget) - self._hddtemps = self._get_hddtemps() - - def hddtemps(self, __): - return self._hddtemps - - def _fetch_data(self): - """fetch data from hddtemp service""" - try: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - sock.connect((HOST, PORT)) - data = "" - while True: - chunk = sock.recv(CHUNK_SIZE) - if chunk: - data += str(chunk) - else: - break - return data - except (AttributeError, socket.error) as e: - pass - - @staticmethod - def _get_parts(data): - """ - split data using | separator and remove first item - (because the first item is empty) - """ - parts = data.split("|")[1:] - return parts - - @staticmethod - def _partition_parts(parts): - """ - partition parts: one device record is five (5) items - """ - per_disk = [parts[i:i+RECORD_SIZE] - for i in range(len(parts))[::RECORD_SIZE]] - return per_disk - - @staticmethod - def _get_name_and_temp(device_record): - """ - get device name (without /dev part, to save space on bar) - and temperature (in °C) as tuple - """ - device_name = device_record[0].split("/")[-1] - device_temp = device_record[2] - return (device_name, device_temp) - - @staticmethod - def _get_hddtemp(device_record): - name, temp = device_record - hddtemp = "{}+{}°C".format(name, temp) - return hddtemp - - def _get_hddtemps(self): - data = self._fetch_data() - if data is None: - return "n/a" - parts = self._get_parts(data) - per_disk = self._partition_parts(parts) - names_and_temps = [self._get_name_and_temp(x) for x in per_disk] - hddtemps = [self._get_hddtemp(x) for x in names_and_temps] - return SEPARATOR.join(hddtemps) - - def update(self, __): - self._hddtemps = self._get_hddtemps() diff --git a/bumblebee/modules/hostname.py b/bumblebee/modules/hostname.py deleted file mode 100644 index 4b0f987..0000000 --- a/bumblebee/modules/hostname.py +++ /dev/null @@ -1,24 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the system hostname.""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.output) - ) - self._hname = "" - - def output(self, _): - return self._hname+" "+u"\uf233" - - def update(self, widgets): - with open('/proc/sys/kernel/hostname', 'r') as f: - self._hname = f.readline().split()[0] - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/http_status.py b/bumblebee/modules/http_status.py deleted file mode 100644 index ae84655..0000000 --- a/bumblebee/modules/http_status.py +++ /dev/null @@ -1,68 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Display HTTP status code - -Parameters: - * http_status.label: Prefix label (optional) - * http_status.target: Target to retrieve the HTTP status from - * http_status.expect: Expected HTTP status -""" - -from requests import head - -import psutil -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - UNK = "UNK" - - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.output) - super(Module, self).__init__(engine, config, widget) - - self._label = self.parameter("label") - self._target = self.parameter("target") - self._expect = self.parameter("expect", "200") - self._status = self.getStatus() - self._output = self.getOutput() - - def labelize(self, s): - if self._label is None: - return s - return "{}: {}".format(self._label, s) - - def getStatus(self): - try: - res = head(self._target) - except Exception: - return self.UNK - else: - status = str(res.status_code) - self._status = status - return status - - def getOutput(self): - if self._status == self._expect: - return self.labelize(self._status) - else: - reason = " != {}".format(self._expect) - return self.labelize("{}{}".format(self._status, reason)) - - def output(self, widget): - return self._output - - def update(self, widgets): - self.getStatus() - self._output = self.getOutput() - - def state(self, widget): - if self._status == self.UNK: - return "warning" - if self._status != self._expect: - return "critical" - return self._output - - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/indicator.py b/bumblebee/modules/indicator.py deleted file mode 100644 index 3b57e33..0000000 --- a/bumblebee/modules/indicator.py +++ /dev/null @@ -1,51 +0,0 @@ -#pylint: disable=C0111,R0903 - -"""Displays the indicator status, for numlock, scrolllock and capslock - -Parameters: - * indicator.include: Comma-separated list of interface prefixes to include (defaults to "numlock,capslock") - * indicator.signalstype: If you want the signali type color to be "critical" or "warning" (defaults to "warning") -""" - - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - self.status = False - super(Module,self).__init__(engine, config, widgets) - self._include = tuple(filter(len, self.parameter("include", "NumLock,CapsLock").split(","))) - self._signalType = self.parameter("signaltype") if not self.parameter("signaltype") is None else "warning" - - def update(self, widgets): - self._update_widgets(widgets) - - def state(self, widget): - states = [] - if widget.status: - states.append(self._signalType) - elif not widget.status: - states.append("normal") - return states - - def _update_widgets(self, widgets): - status_line = "" - for line in bumblebee.util.execute("xset q").replace(" ", "").split("\n"): - if "capslock" in line.lower(): - status_line = line - break - - for indicator in self._include: - widget = self.widget(indicator) - if not widget: - widget = bumblebee.output.Widget(name=indicator) - widgets.append(widget) - - widget.status = True if indicator.lower()+":on" in status_line.lower() else False - widget.full_text(indicator) - - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/kernel.py b/bumblebee/modules/kernel.py deleted file mode 100644 index 761fa8c..0000000 --- a/bumblebee/modules/kernel.py +++ /dev/null @@ -1,21 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Shows Linux kernel version information""" - -import platform - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.output) - ) - self._release_name = platform.release() - - def output(self, widget): - return self._release_name - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/layout-xkb.py b/bumblebee/modules/layout-xkb.py deleted file mode 100644 index 04f4114..0000000 --- a/bumblebee/modules/layout-xkb.py +++ /dev/null @@ -1,65 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the current keyboard layout using libX11 - -Requires the following library: - * libX11.so.6 -and python module: - * xkbgroup - -Parameters: - * layout-xkb.showname: Boolean that indicate whether the full name should be displayed. Defaults to false (only the symbol will be displayed) - * layout-xkb.show_variant: Boolean that indecates whether the variant name should be displayed. Defaults to true. -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -has_xkb = True -try: - from xkbgroup import * -except ImportError: - has_xkb = False - -import logging -log = logging.getLogger(__name__) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.current_layout) - ) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self._next_keymap) - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, - cmd=self._prev_keymap) - self._show_variant = bumblebee.util.asbool(self.parameter("show_variant", "true")) - - def _next_keymap(self, event): - self._set_keymap(1) - - def _prev_keymap(self, event): - self._set_keymap(-1) - - def _set_keymap(self, rotation): - if not has_xkb: return - - xkb = XKeyboard() - if xkb.groups_count < 2: return # nothing to doA - layouts = xkb.groups_symbols - idx = layouts.index(xkb.group_symbol) - xkb.group_symbol = str(layouts[(idx + rotation) % len(layouts)]) - - def current_layout(self, widget): - try: - xkb = XKeyboard() - log.debug("group num: {}".format(xkb.group_num)) - name = xkb.group_name if bumblebee.util.asbool(self.parameter("showname")) else xkb.group_symbol - if self._show_variant: - return "{} ({})".format(name, xkb.group_variant) if xkb.group_variant else name - return name - except Exception: - return "n/a" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/layout-xkbswitch.py b/bumblebee/modules/layout-xkbswitch.py deleted file mode 100644 index e65d30a..0000000 --- a/bumblebee/modules/layout-xkbswitch.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Displays and changes the current keyboard layout - -Requires the following executable: - * xkb-switch -""" - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.current_layout) - super(Module, self).__init__(engine, config, widget) - engine.input.register_callback( - self, - button=bumblebee.input.LEFT_MOUSE, - cmd=self._next_keymap) - self._current_layout = self._get_current_layout() - - def current_layout(self, __): - return self._current_layout - - def _next_keymap(self, event): - try: - bumblebee.util.execute("xkb-switch -n") - except RuntimeError: - pass - - def _get_current_layout(self): - try: - res = bumblebee.util.execute("xkb-switch") - return res.split("\n")[0] - except RuntimeError: - return ["n/a"] - - def update(self, __): - self._current_layout = self._get_current_layout() diff --git a/bumblebee/modules/layout.py b/bumblebee/modules/layout.py deleted file mode 100644 index 49c59a4..0000000 --- a/bumblebee/modules/layout.py +++ /dev/null @@ -1,72 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays and changes the current keyboard layout - -Requires the following executable: - * setxkbmap -""" - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.current_layout) - ) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self._next_keymap) - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, - cmd=self._prev_keymap) - - def _next_keymap(self, event): - self._set_keymap(1) - - def _prev_keymap(self, event): - self._set_keymap(-1) - - def _set_keymap(self, rotation): - layouts = self.get_layouts() - if len(layouts) == 1: return # nothing to do - layouts = layouts[rotation:] + layouts[:rotation] - - layout_list = [] - variant_list = [] - for l in layouts: - tmp = l.split(":") - layout_list.append(tmp[0]) - variant_list.append(tmp[1] if len(tmp) > 1 else "") - - try: - bumblebee.util.execute("setxkbmap -layout {} -variant {}".format(",".join(layout_list), ",".join(variant_list))) - except RuntimeError: - pass - - def get_layouts(self): - try: - res = bumblebee.util.execute("setxkbmap -query") - except RuntimeError: - return ["n/a"] - layouts = [] - variants = [] - for line in res.split("\n"): - if not line: continue - if "layout" in line: - layouts = line.split(":")[1].strip().split(",") - if "variant" in line: - variants = line.split(":")[1].strip().split(",") - - result = [] - for idx, layout in enumerate(layouts): - if len(variants) > idx and variants[idx]: - layout = "{}:{}".format(layout, variants[idx]) - result.append(layout) - return result if len(result) > 0 else ["n/a"] - - def current_layout(self, widget): - layouts = self.get_layouts() - return layouts[0] - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/load.py b/bumblebee/modules/load.py deleted file mode 100644 index 4d94ee1..0000000 --- a/bumblebee/modules/load.py +++ /dev/null @@ -1,41 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays system load. - -Parameters: - * load.warning : Warning threshold for the one-minute load average (defaults to 70% of the number of CPUs) - * load.critical: Critical threshold for the one-minute load average (defaults to 80% of the number of CPUs) -""" - -import os -import multiprocessing - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.load) - ) - self._load = [0, 0, 0] - try: - self._cpus = multiprocessing.cpu_count() - except NotImplementedError as e: - self._cpus = 1 - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="gnome-system-monitor") - - def load(self, widget): - return "{:.02f}/{:.02f}/{:.02f}".format( - self._load[0], self._load[1], self._load[2] - ) - - def update(self, widgets): - self._load = os.getloadavg() - - def state(self, widget): - return self.threshold_state(self._load[0], self._cpus*0.7, self._cpus*0.8) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/memory.py b/bumblebee/modules/memory.py deleted file mode 100644 index 1ff2f25..0000000 --- a/bumblebee/modules/memory.py +++ /dev/null @@ -1,72 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays available RAM, total amount of RAM and percentage available. - -Parameters: - * memory.warning : Warning threshold in % of memory used (defaults to 80%) - * memory.critical: Critical threshold in % of memory used (defaults to 90%) - * memory.format: Format string (defaults to "{used}/{total} ({percent:05.02f}%)") - * memory.usedonly: Only show the amount of RAM in use (defaults to False). Same as memory.format="{used}" -""" - -import re - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Container(object): - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.memory_usage) - ) - self.update(None) - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="gnome-system-monitor") - - @property - def _format(self): - if bumblebee.util.asbool(self.parameter("usedonly", False)): - return "{used}" - else: - return self.parameter("format", "{used}/{total} ({percent:05.02f}%)") - - def memory_usage(self, widget): - return self._format.format(**self._mem) - - def update(self, widgets): - data = {} - with open("/proc/meminfo", "r") as f: - for line in f: - tmp = re.split(r"[:\s]+", line) - value = int(tmp[1]) - if tmp[2] == "kB": value = value*1024 - if tmp[2] == "mB": value = value*1024*1024 - if tmp[2] == "gB": value = value*1024*1024*1024 - data[tmp[0]] = value - if "MemAvailable" in data: - used = data["MemTotal"] - data["MemAvailable"] - else: - used = data["MemTotal"] - data["MemFree"] - data["Buffers"] - data["Cached"] - data["Slab"] - self._mem = { - "total": bumblebee.util.bytefmt(data["MemTotal"]), - "available": bumblebee.util.bytefmt(data["MemAvailable"]), - "free": bumblebee.util.bytefmt(data["MemFree"]), - "used": bumblebee.util.bytefmt(used), - "percent": float(used)/float(data["MemTotal"])*100.0 - } - - def state(self, widget): - if self._mem["percent"] > float(self.parameter("critical", 90)): - return "critical" - if self._mem["percent"] > float(self.parameter("warning", 80)): - return "warning" - return None - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/mocp.py b/bumblebee/modules/mocp.py deleted file mode 100644 index 3063f50..0000000 --- a/bumblebee/modules/mocp.py +++ /dev/null @@ -1,60 +0,0 @@ -# pylint: disable=C0111,R0903 -# -*- coding: utf-8 -*- - -"""Displays information about the current song in mocp. Left click toggles play/pause. Right click toggles shuffle. - -Requires the following executable: - * mocp - -Parameters: - * mocp.format: Format string for the song information. Replace string sequences with the actual information: - %state State - %file File - %title Title, includes track, artist, song title and album - %artist Artist - %song SongTitle - %album Album - %tt TotalTime - %tl TimeLeft - %ts TotalSec - %ct CurrentTime - %cs CurrentSec - %b Bitrate - %r Sample rate -""" - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from bumblebee.output import scrollable - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(name="mocp.main", full_text=self.description) - ) - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="mocp -G") - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, - cmd="mocp -t shuffle") - self._format = self.parameter("format", "%state %artist - %song | %ct/%tt") - self._running = 0 - - #@scrollable - def description(self, widget): - return self._info if self._running == 1 else "Music On Console Player" - - def update(self, widgets): - self._load_song() - - def _load_song(self): - try: - self._info = bumblebee.util.execute("mocp -Q '" + self._format + "'" ).strip() - self._running = 1 - except RuntimeError: - self._running = 0 - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/mpd.py b/bumblebee/modules/mpd.py deleted file mode 100644 index 8b2650d..0000000 --- a/bumblebee/modules/mpd.py +++ /dev/null @@ -1,181 +0,0 @@ -# pylint: disable=C0111,R0903 -# -*- coding: utf-8 -*- - -"""Displays information about the current song in mpd. - -Requires the following executable: - * mpc - -Parameters: - * mpd.format: Format string for the song information. - Supported tags (see `man mpc` for additional information) - * {name} - * {artist} - * {album} - * {albumartist} - * {comment} - * {composer} - * {date} - * {originaldate} - * {disc} - * {genre} - * {performer} - * {title} - * {track} - * {time} - * {file} - * {id} - * {prio} - * {mtime} - * {mdate} - Additional tags: - * {position} - position of currently playing song - not to be confused with %position% mpc tag - * {duration} - duration of currently playing song - * {file1} - song file name without path prefix - if {file} = '/foo/bar.baz', then {file1} = 'bar.baz' - * {file2} - song file name without path prefix and extension suffix - if {file} = '/foo/bar.baz', then {file2} = 'bar' - * mpd.host: MPD host to connect to. (mpc behaviour by default) - * mpd.layout: Space-separated list of widgets to add. Possible widgets are the buttons/toggles mpd.prev, mpd.next, mpd.shuffle and mpd.repeat, and the main display with play/pause function mpd.main. -""" - -from collections import defaultdict - -import string -import os - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from bumblebee.output import scrollable - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, []) - - self._layout = self.parameter("layout", "mpd.prev mpd.main mpd.next mpd.shuffle mpd.repeat") - - self._fmt = self.parameter("format", "{artist} - {title} {position}/{duration}") - self._status = None - self._shuffle = False - self._repeat = False - self._tags = defaultdict(lambda: '') - - if not self.parameter("host"): - self._hostcmd = "" - else: - self._hostcmd = " -h " + self.parameter("host") - - # Create widgets - widget_list = [] - widget_map = {} - for widget_name in self._layout.split(): - widget = bumblebee.output.Widget(name=widget_name) - widget_list.append(widget) - - if widget_name == "mpd.prev": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc prev" + self._hostcmd} - elif widget_name == "mpd.main": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc toggle" + self._hostcmd} - widget.full_text(self.description) - elif widget_name == "mpd.next": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc next" + self._hostcmd} - elif widget_name == "mpd.shuffle": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc random" + self._hostcmd} - elif widget_name == "mpd.repeat": - widget_map[widget] = {"button": bumblebee.input.LEFT_MOUSE, "cmd": "mpc repeat" + self._hostcmd} - else: - raise KeyError("The mpd module does not support a {widget_name!r} widget".format(widget_name=widget_name)) - self.widgets(widget_list) - - # Register input callbacks - for widget, callback_options in widget_map.items(): - engine.input.register_callback(widget, **callback_options) - - def hidden(self): - return self._status is None - - @scrollable - def description(self, widget): - return string.Formatter().vformat(self._fmt, (), self._tags) - - def update(self, widgets): - self._load_song() - - def state(self, widget): - if widget.name == "mpd.shuffle": - return "shuffle-on" if self._shuffle else "shuffle-off" - if widget.name == "mpd.repeat": - return "repeat-on" if self._repeat else "repeat-off" - if widget.name == "mpd.prev": - return "prev" - if widget.name == "mpd.next": - return "next" - return self._status - - def _load_song(self): - info = "" - try: - tags = ['name', - 'artist', - 'album', - 'albumartist', - 'comment', - 'composer', - 'date', - 'originaldate', - 'disc', - 'genre', - 'performer', - 'title', - 'track', - 'time', - 'file', - 'id', - 'prio', - 'mtime', - 'mdate'] - joinedtags = "\n".join(["tag {0} %{0}%".format(tag) for tag in tags]) - info = bumblebee.util.execute('mpc -f ' + '"' + joinedtags + '"' + self._hostcmd) - except RuntimeError: - pass - self._tags = defaultdict(lambda: '') - self._status = None - for line in info.split("\n"): - if line.startswith("[playing]"): - self._status = "playing" - elif line.startswith("[paused]"): - self._status = "paused" - - if line.startswith("["): - timer = line.split()[2] - position = timer.split("/")[0] - dur = timer.split("/")[1] - duration = dur.split(" ")[0] - self._tags.update({'position': position}) - self._tags.update({'duration': duration}) - - if line.startswith("volume"): - value = line.split(" ", 2)[1:] - for option in value: - if option.startswith("repeat: on"): - self._repeat = True - elif option.startswith("repeat: off"): - self._repeat = False - elif option.startswith("random: on"): - self._shuffle = True - elif option.startswith("random: off"): - self._shuffle = False - if line.startswith("tag"): - key, value = line.split(" ", 2)[1:] - self._tags.update({key: value}) - if key == "file": - self._tags.update({"file1": os.path.basename(value)}) - self._tags.update( - {"file2": - os.path.splitext(os.path.basename(value))[0]}) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/network_traffic.py b/bumblebee/modules/network_traffic.py deleted file mode 100644 index f15a19f..0000000 --- a/bumblebee/modules/network_traffic.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Displays network traffic - * No extra configuration needed -""" - -import psutil -import netifaces - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util - -WIDGET_NAME = 'network_traffic' - -class Module(bumblebee.engine.Module): - """Bumblebee main module """ - - def __init__(self, engine, config): - super(Module, self).__init__(engine, config) - - try: - self._bandwidth = BandwidthInfo() - - self._bytes_recv = self._bandwidth.bytes_recv() - self._bytes_sent = self._bandwidth.bytes_sent() - except Exception: - """ We do not want do explode anything """ - pass - - @classmethod - def state(cls, widget): - """Return the widget state""" - - if widget.name == '{}.rx'.format(WIDGET_NAME): - return 'rx' - elif widget.name == '{}.tx'.format(WIDGET_NAME): - return 'tx' - - return None - - def update(self, widgets): - try: - bytes_recv = self._bandwidth.bytes_recv() - bytes_sent = self._bandwidth.bytes_sent() - - download_rate = (bytes_recv - self._bytes_recv) - upload_rate = (bytes_sent - self._bytes_sent) - - self.update_widgets(widgets, download_rate, upload_rate) - - self._bytes_recv, self._bytes_sent = bytes_recv, bytes_sent - except Exception: - """ We do not want do explode anything """ - pass - - @classmethod - def update_widgets(cls, widgets, download_rate, upload_rate): - """Update tx/rx widgets with new rates""" - del widgets[:] - - widgets.extend(( - TrafficWidget(text=download_rate, direction='rx'), - TrafficWidget(text=upload_rate, direction='tx') - )) - - -class BandwidthInfo(object): - """Get received/sent bytes from network adapter""" - - def bytes_recv(self): - """Return received bytes""" - return self.bandwidth().bytes_recv - - def bytes_sent(self): - """Return sent bytes""" - return self.bandwidth().bytes_sent - - def bandwidth(self): - """Return bandwidth information""" - io_counters = self.io_counters() - return io_counters[self.default_network_adapter()] - - @classmethod - def default_network_adapter(cls): - """Return default active network adapter""" - gateway = netifaces.gateways()['default'] - - if not gateway: - raise 'No default gateway found' - - return gateway[netifaces.AF_INET][1] - - @classmethod - def io_counters(cls): - """Return IO counters""" - return psutil.net_io_counters(pernic=True) - -class TrafficWidget(object): - """Create a traffic widget with humanized bytes string with proper icon (up/down)""" - def __new__(cls, text, direction): - widget = bumblebee.output.Widget(name='{0}.{1}'.format(WIDGET_NAME, direction)) - widget.set('theme.minwidth', '0000000KiB/s') - widget.full_text(cls.humanize(text)) - - return widget - - @staticmethod - def humanize(text): - """Return humanized bytes""" - humanized_byte_format = bumblebee.util.bytefmt(text) - return '{0}/s'.format(humanized_byte_format) diff --git a/bumblebee/modules/nic.py b/bumblebee/modules/nic.py deleted file mode 100644 index 2023985..0000000 --- a/bumblebee/modules/nic.py +++ /dev/null @@ -1,119 +0,0 @@ -#pylint: disable=C0111,R0903 - -"""Displays the name, IP address(es) and status of each available network interface. - -Requires the following python module: - * netifaces - -Parameters: - * nic.exclude: Comma-separated list of interface prefixes to exclude (defaults to "lo,virbr,docker,vboxnet,veth,br") - * nic.include: Comma-separated list of interfaces to include - * nic.states: Comma-separated list of states to show (prefix with "^" to invert - i.e. ^down -> show all devices that are not in state down) - * nic.format: Format string (defaults to "{intf} {state} {ip} {ssid}") -""" - -import netifaces -import subprocess - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - super(Module, self).__init__(engine, config, widgets) - self._exclude = tuple(filter(len, self.parameter("exclude", "lo,virbr,docker,vboxnet,veth,br").split(","))) - self._include = self.parameter("include", "").split(",") - - self._states = {} - self._states["include"] = [] - self._states["exclude"] = [] - for state in tuple(filter(len, self.parameter("states", "").split(","))): - if state[0] == "^": - self._states["exclude"].append(state[1:]) - else: - self._states["include"].append(state) - self._format = self.parameter("format","{intf} {state} {ip} {ssid}"); - self._update_widgets(widgets) - self.iwgetid = bumblebee.util.which("iwgetid") - - - def update(self, widgets): - self._update_widgets(widgets) - - def state(self, widget): - states = [] - - if widget.get("state") == "down": - states.append("critical") - elif widget.get("state") != "up": - states.append("warning") - - intf = widget.get("intf") - iftype = "wireless" if self._iswlan(intf) else "wired" - iftype = "tunnel" if self._istunnel(intf) else iftype - - states.append("{}-{}".format(iftype, widget.get("state"))) - - return states - - def _iswlan(self, intf): - # wifi, wlan, wlp, seems to work for me - if intf.startswith("w"): return True - return False - - def _istunnel(self, intf): - return intf.startswith("tun") or intf.startswith("wg") - - def get_addresses(self, intf): - retval = [] - try: - for ip in netifaces.ifaddresses(intf).get(netifaces.AF_INET, []): - if ip.get("addr", "") != "": - retval.append(ip.get("addr")) - except Exception: - return [] - return retval - - def _update_widgets(self, 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" - for ip in self.get_addresses(intf): - addr.append(ip) - state = "up" - - if len(self._states["exclude"]) > 0 and state in self._states["exclude"]: continue - if len(self._states["include"]) > 0 and state not in self._states["include"]: continue - - widget = self.widget(intf) - if not widget: - widget = bumblebee.output.Widget(name=intf) - widgets.append(widget) - # join/split is used to get rid of multiple whitespaces (in case SSID is not available, for instance - widget.full_text(" ".join(self._format.format(ip=", ".join(addr),intf=intf,state=state,ssid=self.get_ssid(intf)).split())) - 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): - try: - return subprocess.check_output([self.iwgetid,"-r",intf]).strip().decode('utf-8') - except: - return "" - return "" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/notmuch_count.py b/bumblebee/modules/notmuch_count.py deleted file mode 100644 index 821118a..0000000 --- a/bumblebee/modules/notmuch_count.py +++ /dev/null @@ -1,51 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the result of a notmuch count query - default : unread emails which path do not contained "Trash" (notmuch count "tag:unread AND NOT path:/.*Trash.*/") - -Parameters: - * notmuch_count.query: notmuch count query to show result - -Errors: - if the notmuch query failed, the shown value is -1 - -Dependencies: - notmuch (https://notmuchmail.org/) -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import os - -class Module(bumblebee.engine.Module): - - - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.output) - ) - self._notmuch_count_query = self.parameter("query", "tag:unread AND NOT path:/.*Trash.*/") - self._notmuch_count = self.count_notmuch() - - - def output(self, widget): - self._notmuch_count = self.count_notmuch() - return str(self._notmuch_count) - - - def state(self, widgets): - if self._notmuch_count == 0: - return "empty" - return "items" - - - def count_notmuch(self): - try: - notmuch_count_cmd = "notmuch count " + self._notmuch_count_query - notmuch_count = int(bumblebee.util.execute(notmuch_count_cmd)) - return notmuch_count - except Exception: - return -1 - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/nvidiagpu.py b/bumblebee/modules/nvidiagpu.py deleted file mode 100644 index 2ce7d38..0000000 --- a/bumblebee/modules/nvidiagpu.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- - -"""Displays GPU name, temperature and memory usage. - -Parameters: - * nvidiagpu.format: Format string (defaults to "{name}: {temp}°C %{usedmem}/{totalmem} MiB") - Available values are: {name} {temp} {mem_used} {mem_total} {fanspeed} {clock_gpu} {clock_mem} - -Requires nvidia-smi -""" - -import subprocess -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, bumblebee.output.Widget(full_text=self.utilization)) - self._utilization = "Not found: 0 0/0" - - def utilization(self, widget): - return self._utilization - - def update(self, widgets): - sp = subprocess.Popen(['nvidia-smi', '-q'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out_str = sp.communicate() - out_list = out_str[0].decode("utf-8").split('\n') - - title = "" - usedMem = "" - totalMem = "" - temp = "" - name = "not found" - clockMem = "" - clockGpu = "" - fanspeed = "" - for item in out_list: - try: - key, val = item.split(':') - key, val = key.strip(), val.strip() - if title == "Clocks": - if key == "Graphics": - clockGpu = val.split(" ")[0] - elif key == "Memory": - clockMem = val.split(" ")[0] - if title == "FB Memory Usage": - if key == "Total": - totalMem = val.split(" ")[0] - elif key == "Used": - usedMem = val.split(" ")[0] - elif key == "GPU Current Temp": - temp = val.split(" ")[0] - elif key == "Product Name": - name = val - elif key == "Fan Speed": - fanspeed = val.split(" ")[0] - - except: - title = item.strip() - - str_format = self.parameter("format", '{name}: {temp}°C {mem_used}/{mem_total} MiB') - self._utilization = str_format.format( - name = name, - temp = temp, - mem_used = usedMem, - mem_total = totalMem, - clock_gpu = clockGpu, - clock_mem = clockMem, - fanspeed = fanspeed, - ) diff --git a/bumblebee/modules/pacman.py b/bumblebee/modules/pacman.py deleted file mode 100644 index 546c43a..0000000 --- a/bumblebee/modules/pacman.py +++ /dev/null @@ -1,76 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays update information per repository for pacman. - -Parameters: - * pacman.sum: If you prefere displaying updates with a single digit (defaults to "False") - -Requires the following executables: - * fakeroot - * pacman -""" - -import os -import threading - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -#list of repositories. -#the last one should always be other -repos = ["core", "extra", "community", "multilib", "testing", "other"] - -def get_pacman_info(widget, path): - try: - result = bumblebee.util.execute("{}/../../bin/pacman-updates".format(path)) - except: - pass - - count = len(repos)*[0] - - for line in result.splitlines(): - if line.startswith(("http", "rsync")): - for i in range(len(repos)-1): - if "/" + repos[i] + "/" in line: - count[i] += 1 - break - else: - result[-1] += 1 - - for i in range(len(repos)): - widget.set(repos[i], count[i]) - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.updates) - ) - self._count = 0 - - def updates(self, widget): - if bumblebee.util.asbool(self.parameter("sum")): - return str(sum(map(lambda x: widget.get(x, 0), repos))) - return '/'.join(map(lambda x: str(widget.get(x, 0)), repos)) - - def update(self, widgets): - path = os.path.dirname(os.path.abspath(__file__)) - if self._count == 0: - thread = threading.Thread(target=get_pacman_info, args=(widgets[0], path)) - thread.start() - - # TODO: improve this waiting mechanism a bit - self._count += 1 - self._count = 0 if self._count > 300 else self._count - - def state(self, widget): - weightedCount = sum(map(lambda x: (len(repos)-x[0]) * widget.get(x[1], 0), enumerate(repos))) - - if weightedCount < 10: - return "good" - - return self.threshold_state(weightedCount, 100, 150) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/pihole.py b/bumblebee/modules/pihole.py deleted file mode 100644 index 00fbd22..0000000 --- a/bumblebee/modules/pihole.py +++ /dev/null @@ -1,68 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the pi-hole status (up/down) together with the number of ads that were blocked today -Parameters: - * pihole.address : pi-hole address (e.q: http://192.168.1.3) - * pihole.pwhash : pi-hole webinterface password hash (can be obtained from the /etc/pihole/SetupVars.conf file) -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import requests - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.pihole_status) - ) - - buttons = {"LEFT_CLICK":bumblebee.input.LEFT_MOUSE} - self._pihole_address = self.parameter("address", "") - - self._pihole_pw_hash = self.parameter("pwhash", "") - self._pihole_status = None - self._ads_blocked_today = "-" - self.update_pihole_status() - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.toggle_pihole_status) - - def pihole_status(self, widget): - if self._pihole_status is None: - return "pi-hole unknown" - return "pi-hole " + ("up/" + self._ads_blocked_today if self._pihole_status else "down") - - def update_pihole_status(self): - try: - data = requests.get(self._pihole_address + "/admin/api.php?summary").json() - self._pihole_status = True if data["status"] == "enabled" else False - self._ads_blocked_today = data["ads_blocked_today"] - except: - self._pihole_status = None - - def toggle_pihole_status(self, widget): - if self._pihole_status is not None: - try: - req = None - if self._pihole_status: - req = requests.get(self._pihole_address + "/admin/api.php?disable&auth=" + self._pihole_pw_hash) - else: - req = requests.get(self._pihole_address + "/admin/api.php?enable&auth=" + self._pihole_pw_hash) - if req is not None: - if req.status_code == 200: - status = req.json()["status"] - self._pihole_status = False if status == "disabled" else True - except: - pass - - - def update(self, widgets): - self.update_pihole_status() - - def state(self, widget): - if self._pihole_status is None: - return [] - elif self._pihole_status: - return ["enabled"] - return ["disabled", "warning"] diff --git a/bumblebee/modules/ping.py b/bumblebee/modules/ping.py deleted file mode 100644 index 0a1419b..0000000 --- a/bumblebee/modules/ping.py +++ /dev/null @@ -1,84 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Periodically checks the RTT of a configurable host using ICMP echos - -Requires the following executable: - * ping - -Parameters: - * ping.interval: Time in seconds between two RTT checks (defaults to 60) - * ping.address : IP address to check - * ping.timeout : Timeout for waiting for a reply (defaults to 5.0) - * ping.probes : Number of probes to send (defaults to 5) - * ping.warning : Threshold for warning state, in seconds (defaults to 1.0) - * ping.critical: Threshold for critical state, in seconds (defaults to 2.0) -""" - -import re -import time -import threading - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -def get_rtt(module, widget): - try: - widget.set("rtt-unreachable", False) - res = bumblebee.util.execute("ping -n -q -c {} -W {} {}".format( - widget.get("rtt-probes"), widget.get("rtt-timeout"), widget.get("address") - )) - - for line in res.split("\n"): - if line.startswith("{} packets transmitted".format(widget.get("rtt-probes"))): - m = re.search(r'(\d+)% packet loss', line) - - widget.set('packet-loss', m.group(1)) - - if not line.startswith("rtt"): continue - m = re.search(r'([0-9\.]+)/([0-9\.]+)/([0-9\.]+)/([0-9\.]+)\s+(\S+)', line) - - widget.set("rtt-min", float(m.group(1))) - widget.set("rtt-avg", float(m.group(2))) - widget.set("rtt-max", float(m.group(3))) - widget.set("rtt-unit", m.group(5)) - except Exception as e: - widget.set("rtt-unreachable", True) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.rtt) - super(Module, self).__init__(engine, config, widget) - - widget.set("address", self.parameter("address", "8.8.8.8")) - widget.set("interval", self.parameter("interval", 60)) - widget.set("rtt-probes", self.parameter("probes", 5)) - widget.set("rtt-timeout", self.parameter("timeout", 5.0)) - widget.set("rtt-avg", 0.0) - widget.set("rtt-unit", "") - widget.set('packet-loss', 0) - - self._next_check = 0 - - def rtt(self, widget): - if widget.get("rtt-unreachable"): - return "{}: unreachable".format(widget.get("address")) - return "{}: {:.1f}{} ({}%)".format( - widget.get("address"), - widget.get("rtt-avg"), - widget.get("rtt-unit"), - widget.get('packet-loss') - ) - - def state(self, widget): - if widget.get("rtt-unreachable"): return ["critical"] - return self.threshold_state(widget.get("rtt-avg"), 1000.0, 2000.0) - - def update(self, widgets): - if int(time.time()) < self._next_check: - return - thread = threading.Thread(target=get_rtt, args=(self, widgets[0],)) - thread.start() - self._next_check = int(time.time()) + int(widgets[0].get("interval")) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/pomodoro.py b/bumblebee/modules/pomodoro.py deleted file mode 100644 index 64f1514..0000000 --- a/bumblebee/modules/pomodoro.py +++ /dev/null @@ -1,119 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Display and run a Pomodoro timer. -Left click to start timer, left click again to pause. -Right click will cancel the timer. - -Parameters: - * pomodoro.work: The work duration of timer in minutes (defaults to 25) - * pomodoro.break: The break duration of timer in minutes (defaults to 5) - * pomodoro.format: Timer display format with "%m" and "%s" for minutes and seconds (defaults to "%m:%s") - Examples: "%m min %s sec", "%mm", "", "timer" - * pomodoro.notify: Notification command to run when timer ends/starts (defaults to nothing) - Example: 'notify-send "Time up!"' -""" - -from __future__ import absolute_import -import datetime -from math import ceil - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = bumblebee.output.Widget(full_text=self.text) - - super(Module, self).__init__(engine, config, widgets) - - # Parameters - self._work_period = int(self.parameter("work", 25)) - self._break_period = int(self.parameter("break", 5)) - self._time_format = self.parameter("format", "%m:%s") - self._notify_cmd = self.parameter("notify", "") - - # TODO: Handle time formats more gracefully. This is kludge. - self.display_seconds_p = False - self.display_minutes_p = False - if "%s" in self._time_format: - self.display_seconds_p = True - if "%m" in self._time_format: - self.display_minutes_p = True - - self.remaining_time = datetime.timedelta(minutes=self._work_period) - - self.time = None - self.pomodoro = { "state":"OFF", "type": ""} - self._text = self.remaining_time_str() + self.pomodoro["type"] - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.timer_play_pause) - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, - cmd=self.timer_reset) - - def remaining_time_str(self): - - if self.display_seconds_p and self.display_minutes_p: - minutes, seconds = divmod(self.remaining_time.seconds, 60) - if not self.display_seconds_p: - minutes = ceil(self.remaining_time.seconds / 60) - seconds = 0 - if not self.display_minutes_p: - minutes = 0 - seconds = self.remaining_time.seconds - - minutes = "{:2d}".format(minutes) - seconds = "{:02d}".format(seconds) - return self._time_format.replace("%m",minutes).replace("%s",seconds)+" " - - def text(self, widget): - return "{}".format(self._text) - - def update(self, widget): - if self.pomodoro["state"] == "ON": - timediff = (datetime.datetime.now() - self.time) - if timediff.seconds >= 0: - self.remaining_time -= timediff - self.time = datetime.datetime.now() - - if self.remaining_time.seconds <= 0: - self.notify() - if self.pomodoro["type"] == "Work": - self.pomodoro["type"] = "Break" - self.remaining_time = datetime.timedelta(minutes=self._break_period) - elif self.pomodoro["type"] == "Break": - self.pomodoro["type"] = "Work" - self.remaining_time = datetime.timedelta(minutes=self._work_period) - - self._text = self.remaining_time_str() + self.pomodoro["type"] - - def notify(self): - if self._notify_cmd: - bumblebee.util.execute(self._notify_cmd) - - def timer_play_pause(self, widget): - if self.pomodoro["state"] == "OFF": - self.pomodoro = {"state": "ON", "type": "Work"} - self.remaining_time = datetime.timedelta(minutes=self._work_period) - self.time = datetime.datetime.now() - elif self.pomodoro["state"] == "ON": - self.pomodoro["state"] = "PAUSED" - self.remaining_time -= (datetime.datetime.now() - self.time) - self.time = datetime.datetime.now() - elif self.pomodoro["state"] == "PAUSED": - self.pomodoro["state"] = "ON" - self.time = datetime.datetime.now() - - def timer_reset(self, widget): - if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "PAUSED": - self.pomodoro = {"state":"OFF", "type": "" } - self.remaining_time = datetime.timedelta(minutes=self._work_period) - - def state(self, widget): - state = []; - state.append(self.pomodoro["state"].lower()) - if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "OFF": - state.append(self.pomodoro["type"].lower()) - - return state diff --git a/bumblebee/modules/prime.py b/bumblebee/modules/prime.py deleted file mode 100644 index 542ae20..0000000 --- a/bumblebee/modules/prime.py +++ /dev/null @@ -1,69 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays and changes the current selected prime video card - -Left click will call 'sudo prime-select nvidia' -Right click will call 'sudo prime-select nvidia' - -Running these commands without a password requires editing your sudoers file -(always use visudo, it's very easy to make a mistake and get locked out of your computer!) - -sudo visudo -f /etc/sudoers.d/prime - -Then put a line like this in there: - - user ALL=(ALL) NOPASSWD: /usr/bin/prime-select - -If you can't figure out the sudoers thing, then don't worry, it's still really useful. - -Parameters: - * prime.nvidiastring: String to use when nvidia is selected (defaults to "intel") - * prime.intelstring: String to use when intel is selected (defaults to "intel") - -Requires the following executable: - * prime-select - -""" - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.query) - ) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self._chooseNvidia) - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, - cmd=self._chooseIntel) - - self.nvidiastring = self.parameter("nvidiastring", "nv") - self.intelstring = self.parameter("intelstring", "it") - - def _chooseNvidia(self, event): - bumblebee.util.execute("sudo prime-select nvidia") - - def _chooseIntel(self, event): - bumblebee.util.execute("sudo prime-select intel") - - def _prev_keymap(self, event): - self._set_keymap(-1) - - def query(self, widget): - try: - res = bumblebee.util.execute("prime-select query") - except RuntimeError: - return "n/a" - - for line in res.split("\n"): - if not line: continue - if "nvidia" in line: - return self.nvidiastring - if "intel" in line: - return self.intelstring - return "n/a" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/progress.py b/bumblebee/modules/progress.py deleted file mode 100644 index 79396ca..0000000 --- a/bumblebee/modules/progress.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Show progress for cp, mv, dd, ... - -Parameters: - * progress.placeholder: Text to display while no process is running (defaults to "n/a") - * progress.barwidth: Width of the progressbar if it is used (defaults to 8) - * progress.format: Format string (defaults to "{bar} {cmd} {arg}") - Available values are: {bar} {pid} {cmd} {arg} {percentage} {quantity} {speed} {time} - * progress.barfilledchar: Character used to draw the filled part of the bar (defaults to "#"), notice that it can be a string - * progress.baremptychar: Character used to draw the empty part of the bar (defaults to "-"), notice that it can be a string - -Requires the following executable: - * progress -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -import re - - -class Module(bumblebee.engine.Module): - - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.get_progress_text) - ) - - def get_progress_text(self, widget): - if self.update_progress_info(widget): - width = self.parameter("barwidth", 8) - count = round((width * widget.get("per")) / 100) - filledchar = self.parameter("barfilledchar", "#") - emptychar = self.parameter("baremptychar", "-") - - bar = "[{}{}]".format( - filledchar * count, - emptychar * (width - count) - ) - - str_format = self.parameter("format", '{bar} {cmd} {arg}') - return str_format.format( - bar = bar, - pid = widget.get("pid"), - cmd = widget.get("cmd"), - arg = widget.get("arg"), - percentage = widget.get("per"), - quantity = widget.get("qty"), - speed = widget.get("spd"), - time = widget.get("tim") - ) - else: - return self.parameter("placeholder", 'n/a') - - def update_progress_info(self, widget): - """Update widget's informations about the copy""" - - # These regex extracts following groups: - # 1. pid - # 2. command - # 3. arguments - # 4. progress (xx.x formated) - # 5. quantity (.. unit / .. unit formated) - # 6. speed - # 7. time remaining - extract_nospeed = re.compile("\[ *(\d*)\] ([a-zA-Z]*) (.*)\n\t(\d*\.*\d*)% \((.*)\)\n.*") - extract_wtspeed = re.compile('\[ *(\d*)\] ([a-zA-Z]*) (.*)\n\t(\d*\.*\d*)% \((.*)\) (\d*\.\d .*) remaining (\d*:\d*:\d*)\n.*') - - try: - raw = bumblebee.util.execute("progress -qW 0.1") - result = extract_wtspeed.match(raw) - - if not result: - # Abord speed measures - raw = bumblebee.util.execute("progress -q") - result = extract_nospeed.match(raw) - - widget.set("spd", "???.? B/s") - widget.set("tim", "??:??:??") - else: - widget.set("spd", result.group(6)) - widget.set("tim", result.group(7)) - - widget.set("pid", int(result.group(1))) - widget.set("cmd", result.group(2)) - widget.set("arg", result.group(3)) - widget.set("per", float(result.group(4))) - widget.set("qty", result.group(5)) - return True - except Exception: - return False - - def state(self, widget): - if self._active(): - return "copying" - return "pending" - - def _active(self): - """Checks wether a copy is running or not""" - raw = bumblebee.util.execute("progress -q") - return bool(raw) - diff --git a/bumblebee/modules/publicip.py b/bumblebee/modules/publicip.py deleted file mode 100644 index 73c19d1..0000000 --- a/bumblebee/modules/publicip.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Displays public IP address - -Requires the following python packages: - * requests - -Parameters: - * publicip.region: us-central (default), us-east, us-west, uk, de, pl, nl - * publicip.service: web address that returns plaintext ip address (ex. "http://l2.io/ip") -""" - -try: - from requests import get -except ImportError: - pass - -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.public_ip) - ) - self._avail_regions = {"us-east":"http://checkip.amazonaws.com", - "us-central":"http://whatismyip.akamai.com", - "us-west":"http://ipv4bot.whatismyipaddress.com", - "pl":"http://ip.42.pl/raw", - "de":"http://myexternalip.com/raw", - "nl":"http://tnx.nl/ip", - "uk":"http://ident.me"} - self._region = self.parameter("region", "us-central") - self._service = self.parameter("service", "") - self._ip = "" - - - def public_ip(self, widget): - return self._ip - - def update(self, widgets): - try: - if self._service: - self.address = self._service - else: - self.address = self._avail_regions[self._region] - self._ip = get(self.address).text.rstrip() - except Exception: - self._ip = "No Connection" diff --git a/bumblebee/modules/pulseaudio.py b/bumblebee/modules/pulseaudio.py deleted file mode 100644 index a30b9d5..0000000 --- a/bumblebee/modules/pulseaudio.py +++ /dev/null @@ -1,183 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays volume and mute status and controls for PulseAudio devices. Use wheel up and down to change volume, left click mutes, right click opens pavucontrol. - -Aliases: pasink (use this to control output instead of input), pasource - -Parameters: - * pulseaudio.autostart: If set to "true" (default is "false"), automatically starts the pulseaudio daemon if it is not running - * pulseaudio.percent_change: How much to change volume by when scrolling on the module (default is 2%) - * pulseaudio.limit: Upper limit for setting the volume (default is 0%, which means "no limit") - Note: If the left and right channels have different volumes, the limit might not be reached exactly. - * pulseaudio.showbars: 1 for showing volume bars, requires --markup=pango; - 0 for not showing volume bars (default) - -Requires the following executable: - * pulseaudio - * pactl - * pavucontrol -""" - -import re - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.volume) - ) - try: - if bumblebee.util.asbool(self.parameter("autostart", False)): - bumblebee.util.execute("pulseaudio --start") - except Exception: - pass - - self._change = 2 - self._change = int(self.parameter("percent_change", "2%").strip("%")) - if self._change < 0 or self._change > 100: - self._change = 2 - - self._limit = 0 - self._limit = int(self.parameter("limit", "0%").strip("%s")) - if self._limit < 0: - self._limit = 0 - - self._left = 0 - self._right = 0 - self._mono = 0 - self._mute = False - self._failed = False - self._channel = "sink" if self.name == "pasink" else "source" - self._showbars = bumblebee.util.asbool(self.parameter("showbars", 0)) - - self._patterns = [ - {"expr": "Name:", "callback": (lambda line: False)}, - {"expr": "Mute:", "callback": (lambda line: self.mute(False if " no" in line.lower() else True))}, - {"expr": "Volume:", "callback": self.getvolume}, - ] - - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd="pavucontrol") - - events = [ - {"type": "mute", "action": self.toggle, "button": bumblebee.input.LEFT_MOUSE}, - {"type": "volume", "action": self.increase_volume, "button": bumblebee.input.WHEEL_UP}, - {"type": "volume", "action": self.decrease_volume, "button": bumblebee.input.WHEEL_DOWN}, - ] - - for event in events: - engine.input.register_callback(self, button=event["button"], cmd=event["action"]) - - def set_volume(self, amount): - bumblebee.util.execute("pactl set-{}-{} @DEFAULT_{}@ {}".format( - self._channel, "volume", self._channel.upper(), amount)) - - def increase_volume(self, event): - if self._limit > 0: # we need to check the limit - left = int(self._left) - right = int(self._right) - if left + self._change >= self._limit or right + self._change >= self._limit: - if left == right: - # easy case, just set to limit - self.set_volume("{}%".format(self._limit)) - return - else: - # don't adjust anymore, since i don't know how to update only one channel - return - - self.set_volume("+{}%".format(self._change)) - - def decrease_volume(self, event): - self.set_volume("-{}%".format(self._change)) - - def toggle(self, event): - bumblebee.util.execute("pactl set-{}-{} @DEFAULT_{}@ {}".format( - self._channel, "mute", self._channel.upper(), "toggle")) - - def mute(self, value): - self._mute = value - - def getvolume(self, line): - if "mono" in line: - m = re.search(r'mono:.*\s*\/\s*(\d+)%', line) - if m: - self._mono = m.group(1) - else: - m = re.search(r'left:.*\s*\/\s*(\d+)%.*right:.*\s*\/\s*(\d+)%', line) - if m: - self._left = m.group(1) - self._right = m.group(2) - return True - - def _default_device(self): - output = bumblebee.util.execute("pactl info") - pattern = "Default {}: ".format("Sink" if self.name == "pasink" else "Source") - for line in output.split("\n"): - if line.startswith(pattern): - return line.replace(pattern, "") - return "n/a" - - def volume(self, widget): - if self._failed == True: - return "n/a" - if int(self._mono) > 0: - vol = "{}%".format(self._mono) - if self._showbars: - vol = "{} {}".format( - vol, bumblebee.output.hbar(float(self._mono))) - return vol - elif self._left == self._right: - vol = "{}%".format(self._left) - if self._showbars: - vol = "{} {}".format( - vol, bumblebee.output.hbar(float(self._left))) - return vol - else: - if self._showbars: - vol = "{} {}{}".format( - vol, - bumblebee.output.hbar(float(self._left)), - bumblebee.output.hbar(float(self._right))) - vol = "{}%/{}%".format(self._left, self._right) - return vol - - def update(self, widgets): - try: - self._failed = False - channel = "sinks" if self.name == "pasink" else "sources" - device = self._default_device() - - result = bumblebee.util.execute("pactl list {}".format(channel)) - found = False - - for line in result.split("\n"): - if "Name: {}".format(device) in line: - found = True - continue - if found is False: - continue - for pattern in self._patterns: - if not pattern["expr"] in line: - continue - if pattern["callback"](line) is False and found == True: - return - except Exception: - self._failed = True - if bumblebee.util.asbool(self.parameter("autostart", False)): - try: - bumblebee.util.execute("pulseaudio --start") - self.update(widgets) - except Exception: - pass - - def state(self, widget): - if self._mute: - return ["warning", "muted"] - if int(self._left) > int(100): - return ["critical", "unmuted"] - return ["unmuted"] - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/redshift.py b/bumblebee/modules/redshift.py deleted file mode 100644 index f6f16c7..0000000 --- a/bumblebee/modules/redshift.py +++ /dev/null @@ -1,129 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the current color temperature of redshift - -Requires the following executable: - * redshift - -Parameters: - * redshift.location : location provider, either of "geoclue2" (default), \ -"ipinfo" (requires the requests package), or "manual" - * redshift.lat : latitude if location is set to "manual" - * redshift.lon : longitude if location is set to "manual" -""" - -import threading -try: - import requests -except ImportError: - pass - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -def is_terminated(): - for thread in threading.enumerate(): - if thread.name == "MainThread" and not thread.is_alive(): - return True - return False - - -def get_redshift_value(widget, location, lat, lon): - while True: - if is_terminated(): - return - widget.get("condition").acquire() - while True: - try: - widget.get("condition").wait(1) - except RuntimeError: - continue - break - widget.get("condition").release() - - command = ["redshift", "-p", "-l"] - if location == "manual": - command.append(lat + ":" + lon) - else: - command.append("geoclue2") - - try: - res = bumblebee.util.execute(" ".join(command)) - except Exception: - res = "" - widget.set("temp", "n/a") - widget.set("transition", None) - widget.set("state", "day") - for line in res.split("\n"): - line = line.lower() - if "temperature" in line: - widget.set("temp", line.split(" ")[2]) - if "period" in line: - state = line.split(" ")[1] - if "day" in state: - widget.set("state", "day") - elif "night" in state: - widget.set("state", "night") - else: - widget.set("state", "transition") - widget.set("transition", " ".join(line.split(" ")[2:])) - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.text) - super(Module, self).__init__(engine, config, widget) - - self._location = self.parameter("location", "geoclue2") - self._lat = self.parameter("lat", None) - self._lon = self.parameter("lon", None) - - # Even if location method is set to manual, if we have no lat or lon, - # fall back to the geoclue2 method. - if self._location == "manual" and (self._lat is None - or self._lon is None): - self._location == "geoclue2" - - if self._location == "ipinfo": - try: - location_url = "http://ipinfo.io/json" - location = requests.get(location_url).json() - self._lat, self._lon = location["loc"].split(",") - self._lat = str(float(self._lat)) - self._lon = str(float(self._lon)) - self._location = "manual" - except Exception: - # Fall back to geoclue2. - self._location = "geoclue2" - - self._text = "" - self._condition = threading.Condition() - widget.set("condition", self._condition) - self._thread = threading.Thread(target=get_redshift_value, - args=(widget, self._location, - self._lat, self._lon)) - self._thread.start() - self._condition.acquire() - self._condition.notify() - self._condition.release() - - def text(self, widget): - return "{}".format(self._text) - - def update(self, widgets): - widget = widgets[0] - self._condition.acquire() - self._condition.notify() - self._condition.release() - temp = widget.get("temp", "n/a") - self._text = temp - transition = widget.get("transition", None) - if transition: - self._text = "{} {}".format(temp, transition) - - def state(self, widget): - return widget.get("state", None) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/rotation.py b/bumblebee/modules/rotation.py deleted file mode 100644 index 23552d0..0000000 --- a/bumblebee/modules/rotation.py +++ /dev/null @@ -1,61 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Shows a widget for each connected screen and allows the user to loop through different orientations. - -Requires the following executable: - * xrandr -""" - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -possible_orientations = ["normal", "left", "inverted", "right"] - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - self._engine = engine - super(Module, self).__init__(engine, config, widgets) - self.update_widgets(widgets) - - def update_widgets(self, widgets): - for line in bumblebee.util.execute("xrandr -q").split("\n"): - if not " connected" in line: - continue - display = line.split(" ", 2)[0] - - orientation = "normal" - for curr_orient in possible_orientations: - if((line.split(" ")).count(curr_orient) > 1): - orientation = curr_orient - break - - widget = self.widget(display) - if not widget: - widget = bumblebee.output.Widget(full_text=display, name=display) - self._engine.input.register_callback(widget, button=bumblebee.input.LEFT_MOUSE, cmd=self._toggle) - widget.set("orientation", orientation) - widgets.append(widget) - - def update(self, widgets): - if len(widgets) <= 0: - self.update_widgets(widgets) - - def state(self, widget): - return widget.get("orientation", "normal") - - def _toggle(self, event): - widget = self.widget_by_id(event["instance"]) - - # compute new orientation based on current orientation - idx = possible_orientations.index(widget.get("orientation")) - idx = (idx + 1) % len(possible_orientations) - new_orientation = possible_orientations[idx] - - widget.set("orientation", new_orientation) - - bumblebee.util.execute("xrandr --output {} --rotation {}".format(widget.name, new_orientation)) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/rss.py b/bumblebee/modules/rss.py deleted file mode 100644 index 2a27d27..0000000 --- a/bumblebee/modules/rss.py +++ /dev/null @@ -1,312 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""RSS news ticker - -Fetches rss news items and shows these as a news ticker. -Left-clicking will open the full story in a browser. -New stories are highlighted. - -Parameters: - * rss.feeds : Space-separated list of RSS URLs - * rss.length : Maximum length of the module, default is 60 -""" - -try: - import feedparser - DEPENDENCIES_OK = True -except ImportError: - DEPENDENCIES_OK = False - -import webbrowser -import time -import os -import tempfile -import logging -import random -import re -import json - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -# pylint: disable=too-many-instance-attributes -class Module(bumblebee.engine.Module): - REFRESH_DELAY = 600 - SCROLL_SPEED = 3 - LAYOUT_STYLES_ITEMS = [[1,1,1],[3,3,2],[2,3,3],[3,2,3]] - HISTORY_FILENAME = ".config/i3/rss.hist" - - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.ticker_update if DEPENDENCIES_OK else self._show_error) - ) - # Use BBC newsfeed as demo: - self._feeds = self.parameter('feeds', 'https://www.espn.com/espn/rss/news').split(" ") - self._feeds_to_update = [] - self._response = "" - - self._max_title_length = int(self.parameter("length", 60)) - - self._items = [] - self._current_item = None - - self._ticker_offset = 0 - self._pre_delay = 0 - self._post_delay = 0 - - self._state = [] - - self._newspaper_filename = tempfile.mktemp('.html') - - self._last_refresh = 0 - self._last_update = 0 - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, cmd=self._open) - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd=self._create_newspaper) - - self._history = {'ticker': {}, 'newspaper': {}} - self._load_history() - - def _load_history(self): - if os.path.isfile(self.HISTORY_FILENAME): - self._history = json.loads(open(self.HISTORY_FILENAME, "r").read()) - - def _update_history(self, group): - sources = set([i['source'] for i in self._items]) - self._history[group] = dict([[s, [i['title'] for i in self._items if i['source'] == s]] for s in sources]) - - def _save_history(self): - if not os.path.exists(os.path.dirname(self.HISTORY_FILENAME)): - os.makedirs(os.path.dirname(self.HISTORY_FILENAME)) - open(self.HISTORY_FILENAME, "w").write(json.dumps(self._history)) - - def _check_history(self, items, group): - for i in items: - i['new'] = not (i['source'] in self._history[group] and i['title'] in self._history[group][i['source']]) - - def _open(self, _): - if self._current_item: - webbrowser.open(self._current_item['link']) - - def _check_for_image(self, entry): - image = next(iter([l['href'] for l in entry['links'] if l['rel'] == 'enclosure']), None) - if not image and 'media_content' in entry: - try: - media = sorted(entry['media_content'], key=lambda i: i['height'] if 'height' in i else 0, reverse=True) - image = next(iter([i['url'] for i in media if i['medium'] == 'image']), None) - except Exception: - pass - if not image: - match = re.search(r']*src\s*=["\']*([^\s^>^"^\']*)["\']*', entry['summary']) - if match: - image = match.group(1) - return image if image else '' - - def _remove_tags(self, txt): - return re.sub('<[^>]*>', '', txt) - - def _create_item(self, entry, url, feed): - return {'title': self._remove_tags(entry['title'].replace('\n', ' ')), - 'link': entry['link'], - 'new': True, - 'source': url, - 'summary': self._remove_tags(entry['summary']), - 'feed': feed, - 'image': self._check_for_image(entry), - 'published': time.mktime(entry.published_parsed) if hasattr(entry, 'published_parsed') else 0} - - def _update_items_from_feed(self, url): - parser = feedparser.parse(url) - new_items = [self._create_item(entry, url, parser['feed']['title']) for entry in parser['entries']] - # Check history - self._check_history(new_items, 'ticker') - # Remove the previous items - self._items = [i for i in self._items if i['source'] != url] - # Add the new items - self._items.extend(new_items) - # Sort the items on publish date - self._items.sort(key=lambda i: i['published'], reverse=True) - - def _check_for_refresh(self): - if self._feeds_to_update: - # Update one feed at a time to not overload this update cycle - url = self._feeds_to_update.pop() - self._update_items_from_feed(url) - - if not self._feeds_to_update: - self._update_history('ticker') - self._save_history() - - if not self._current_item: - self._next_item() - elif time.time()-self._last_refresh >= self.REFRESH_DELAY: - # Populate the list with feeds to update - self._feeds_to_update = self._feeds[:] - # Update the refresh time - self._last_refresh = time.time() - - def _next_item(self): - self._ticker_offset = 0 - self._pre_delay = 2 - self._post_delay = 4 - - if not self._items: - return - - # Index of the current element - idx = self._items.index(self._current_item) if self._current_item in self._items else - 1 - - # First show new items, else show next - new_items = [i for i in self._items if i['new']] - self._current_item = next(iter(new_items), self._items[(idx+1) % len(self._items)]) - - def _check_scroll_done(self): - # Check if the complete title has been shown - if self._ticker_offset + self._max_title_length > len(self._current_item['title']): - # Do not immediately show next item after scroll - self._post_delay -= 1 - if self._post_delay == 0: - self._current_item['new'] = False - # Mark the previous item as 'old' - self._next_item() - else: - # Increase scroll position - self._ticker_offset += self.SCROLL_SPEED - - def _show_error(self, _): - return "Please install feedparser first" - - def ticker_update(self, _): - # Only update the ticker once a second - now = time.time() - if now-self._last_update < 1: - return self._response - - self._last_update = now - - self._check_for_refresh() - - # If no items were retrieved, return an empty string - if not self._current_item: - return " "*self._max_title_length - - # Prepare a substring of the item title - self._response = self._current_item['title'][self._ticker_offset:self._ticker_offset+self._max_title_length] - # Add spaces if too short - self._response = self._response.ljust(self._max_title_length) - - # Do not immediately scroll - if self._pre_delay > 0: - # Change state during pre_delay for new items - if self._current_item['new']: - self._state = ['warning'] - self._pre_delay -= 1 - return self._response - - self._state = [] - self._check_scroll_done() - - return self._response - - def update(self, widgets): - pass - - def state(self, _): - return self._state - - def _create_news_element(self, item, overlay_title): - try: - timestr = "" if item['published'] == 0 else str(time.ctime(item['published'])) - except Exception as exc: - logging.error(str(exc)) - raise e - element = "
" - element += "
" - element += " " - element += "
"+("" if item['new'] else "")+item['title']+"
" - element += "
" - element += "
"+item['summary']+"
" - element += "
"+item['feed']+""+timestr+"
" - element += "
" - return element - - def _create_news_section(self, newspaper_items): - style = random.randint(0, 3) - section = "" - for i in range(0, 3): - section += "" - section += "
" - for _ in range(0, self.LAYOUT_STYLES_ITEMS[style][i]): - if newspaper_items: - section += self._create_news_element(newspaper_items[0], self.LAYOUT_STYLES_ITEMS[style][i] != 3) - del newspaper_items[0] - section += "
" - return section - - def _create_newspaper(self, _): - content = "" - newspaper_items = self._items[:] - self._check_history(newspaper_items, 'newspaper') - - # Make sure new items are always listed first, independent of publish date - newspaper_items.sort(key=lambda i: i['published']+(10000000 if i['new'] else 0), reverse=True) - - while newspaper_items: - content += self._create_news_section(newspaper_items) - open(self._newspaper_filename, "w").write(HTML_TEMPLATE.replace("[[CONTENT]]", content)) - webbrowser.open("file://"+self._newspaper_filename) - self._update_history('newspaper') - self._save_history() - -HTML_TEMPLATE = """ - - - - - - -
-
Bumblebee Daily
- [[CONTENT]] -
- -""" -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/sensors.py b/bumblebee/modules/sensors.py deleted file mode 100644 index 8ad86a3..0000000 --- a/bumblebee/modules/sensors.py +++ /dev/null @@ -1,128 +0,0 @@ -# -*- coding: UTF-8 -*- -# pylint: disable=C0111,R0903 - -"""Displays sensor temperature - -Parameters: - * sensors.path: path to temperature file (default /sys/class/thermal/thermal_zone0/temp). - * sensors.json: if set to "true", interpret sensors.path as JSON "path" in the output - of "sensors -j" (i.e. //.../), for example, path could - be: "coretemp-isa-00000/Core 0/temp1_input" (defaults to "false") - * sensors.match: (fallback) Line to match against output of 'sensors -u' (default: temp1_input) - * sensors.match_pattern: (fallback) Line to match against before temperature is read (no default) - * sensors.match_number: (fallback) which of the matches you want (default -1: last match). - * sensors.show_freq: whether to show CPU frequency. (default: true) -""" - -import re -import json -import logging - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -log = logging.getLogger(__name__) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.temperature)) - self._temperature = "unknown" - self._mhz = "n/a" - self._match_number = int(self.parameter("match_number", "-1")) - self._match_pattern = self.parameter("match_pattern", None) - self._pattern = re.compile(r"^\s*{}:\s*([\d.]+)$".format(self.parameter("match", "temp1_input")), re.MULTILINE) - self._json = bumblebee.util.asbool(self.parameter("json", "false")) - self._freq = bumblebee.util.asbool(self.parameter("show_freq", "true")) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, cmd="xsensors") - self.determine_method() - - def determine_method(self): - if self.parameter("path") != None and self._json == False: - self.use_sensors = False # use thermal zone - else: - # try to use output of sensors -u - try: - output = bumblebee.util.execute("sensors -u") - self.use_sensors = True - log.debug("Sensors command available") - except FileNotFoundError as e: - log.info("Sensors command not available, using /sys/class/thermal/thermal_zone*/") - self.use_sensors = False - - def _get_temp_from_sensors(self): - if self._json == True: - try: - output = json.loads(bumblebee.util.execute("sensors -j")) - for key in self.parameter("path").split("/"): - output = output[key] - return int(float(output)) - except Exception as e: - logging.error("unable to read sensors: {}".format(str(e))) - return "unknown" - else: - output = bumblebee.util.execute("sensors -u") - if self._match_pattern: - temp_pattern = self.parameter("match", "temp1_input") - match = re.search(r"{}.+{}:\s*([\d.]+)$".format(self._match_pattern, temp_pattern), output.replace("\n", "")) - if match: - return int(float(match.group(1))) - else: - return "unknown" - match = self._pattern.findall(output) - if match: - return int(float(match[self._match_number])) - return "unknown" - - def get_temp(self): - if self.use_sensors: - temperature = self._get_temp_from_sensors() - log.debug("Retrieve temperature from sensors -u") - else: - try: - temperature = open(self.parameter("path", "/sys/class/thermal/thermal_zone0/temp")).read()[:2] - log.debug("retrieved temperature from /sys/class/") - # TODO: Iterate through all thermal zones to determine the correct one and use its value - # https://unix.stackexchange.com/questions/304845/discrepancy-between-number-of-cores-and-thermal-zones-in-sys-class-thermal - - except IOError: - temperature = "unknown" - log.info("Can not determine temperature, please install lm-sensors") - - return temperature - - def get_mhz(self): - mhz = None - try: - output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read() - mhz = int(float(output)/1000.0) - except: - output = open("/proc/cpuinfo").read() - m = re.search(r"cpu MHz\s+:\s+(\d+)", output) - if m: - mhz = int(m.group(1)) - else: - m = re.search(r"BogoMIPS\s+:\s+(\d+)", output) - if m: - return "{} BogoMIPS".format(int(m.group(1))) - if not mhz: - return "n/a" - - if mhz < 1000: - return "{} MHz".format(mhz) - else: - return "{:0.01f} GHz".format(float(mhz)/1000.0) - - def temperature(self, _): - if self._freq: - return u"{}°c @ {}".format(self._temperature, self._mhz) - else: - return u"{}°c".format(self._temperature) - def update(self, widgets): - self._temperature = self.get_temp() - if self._freq: - self._mhz = self.get_mhz() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/sensors2.py b/bumblebee/modules/sensors2.py deleted file mode 100644 index 3bd245a..0000000 --- a/bumblebee/modules/sensors2.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: UTF-8 -*- - -"""Displays sensor temperature and CPU frequency - -Parameters: - - * sensors2.chip: "sensors -u" compatible filter for chip to display (default to empty - show all chips) - * sensors2.showcpu: Enable or disable CPU frequency display (default: true) - * sensors2.showtemp: Enable or disable temperature display (default: true) - * sensors2.showfan: Enable or disable fan display (default: true) - * sensors2.showother: Enable or display "other" sensor readings (default: false) - * sensors2.showname: Enable or disable show of sensor name (default: false) -""" - -import re - -import bumblebee.util -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, None) - self._chip = self.parameter("chip", "") - self._data = {} - self._update() - - self.widgets(self._create_widgets()) - - def update(self, widgets): - self._update() - for widget in widgets: - self._update_widget(widget) - - def state(self, widget): - widget_type = widget.get("type", "") - try: - data = self._data[widget.get("adapter")][widget.get("package")][widget.get("field")] - if "crit" in data and float(data["input"]) > float(data["crit"]): - return ["critical", widget_type] - if "max" in data and float(data["input"]) > float(data["max"]): - return ["warning", widget_type] - except: - pass - return [widget_type] - - def _create_widgets(self): - widgets = [] - show_temp = bumblebee.util.asbool(self.parameter("showtemp", "true")) - show_fan = bumblebee.util.asbool(self.parameter("showfan", "true")) - show_other = bumblebee.util.asbool(self.parameter("showother", "false")) - - if bumblebee.util.asbool(self.parameter("showcpu", "true")): - widget = bumblebee.output.Widget(full_text=self._cpu) - widget.set("type", "cpu") - widgets.append(widget) - - for adapter in self._data: - for package in self._data[adapter]: - if bumblebee.util.asbool(self.parameter("showname", "false")): - widget = bumblebee.output.Widget(full_text=package) - widget.set("data", self._data[adapter][package]) - widget.set("package", package) - widget.set("field", "") - widget.set("adapter", adapter) - widgets.append(widget) - for field in self._data[adapter][package]: - widget = bumblebee.output.Widget() - widget.set("package", package) - widget.set("field", field) - widget.set("adapter", adapter) - if "temp" in field and show_temp: - # seems to be a temperature - widget.set("type", "temp") - widgets.append(widget) - if "fan" in field and show_fan: - # seems to be a fan - widget.set("type", "fan") - widgets.append(widget) - elif show_other: - # everything else - widget.set("type", "other") - widgets.append(widget) - return widgets - - def _update_widget(self, widget): - if widget.get("field", "") == "": - return # nothing to do - data = self._data[widget.get("adapter")][widget.get("package")][widget.get("field")] - if "temp" in widget.get("field"): - widget.full_text(u"{:0.01f}°C".format(data["input"])) - elif "fan" in widget.get("field"): - widget.full_text(u"{:0.0f}RPM".format(data["input"])) - else: - widget.full_text(u"{:0.0f}".format(data["input"])) - - def _update(self): - output = bumblebee.util.execute("sensors -u {}".format(self._chip)) - self._data = self._parse(output) - - def _parse(self, data): - output = {} - package = "" - adapter = None - chip = None - for line in data.split("\n"): - if "Adapter" in line: - # new adapter - line = line.replace("Adapter: ", "") - output[chip + " " + line] = {} - adapter = chip + " " + line - chip = line #default - line before adapter is always the chip - if not adapter: continue - key, value = (line.split(":") + ["", ""])[:2] - if not line.startswith(" "): - # assume this starts a new package - if package in output[adapter] and output[adapter][package] == {}: - del output[adapter][package] - output[adapter][key] = {} - package = key - else: - # feature for this chip - try: - name, variant = (key.strip().split("_", 1) + ["",""])[:2] - if not name in output[adapter][package]: - output[adapter][package][name] = { } - if variant: - output[adapter][package][name][variant] = {} - output[adapter][package][name][variant] = float(value) - except Exception as e: - pass - return output - - def _cpu(self, _): - mhz = None - try: - output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read() - mhz = int(float(output)/1000.0) - except: - output = open("/proc/cpuinfo").read() - m = re.search(r"cpu MHz\s+:\s+(\d+)", output) - if m: - mhz = int(m.group(1)) - else: - m = re.search(r"BogoMIPS\s+:\s+(\d+)", output) - if m: - return "{} BogoMIPS".format(int(m.group(1))) - if not mhz: - return "n/a" - - if mhz < 1000: - return "{} MHz".format(mhz) - else: - return "{:0.01f} GHz".format(float(mhz)/1000.0) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/shell.py b/bumblebee/modules/shell.py deleted file mode 100644 index 038e519..0000000 --- a/bumblebee/modules/shell.py +++ /dev/null @@ -1,93 +0,0 @@ -# pylint: disable=C0111,R0903,W1401 - -""" Execute command in shell and print result - -Few command examples: - 'ping 1.1.1.1 -c 1 | grep -Po "(?<=time=)\d+(\.\d+)? ms"' - 'echo "BTC=$(curl -s rate.sx/1BTC | grep -Po \"^\d+\")USD"' - 'curl -s https://wttr.in/London?format=%l+%t+%h+%w' - 'pip3 freeze | wc -l' - 'any_custom_script.sh | grep arguments' - -Parameters: - * shell.command: Command to execute - Use single parentheses if evaluating anything inside (sh-style) - For example shell.command='echo $(date +"%H:%M:%S")' - But NOT shell.command="echo $(date +'%H:%M:%S')" - Second one will be evaluated only once at startup - * shell.interval: Update interval in seconds - (defaults to 1s == every bumblebee-status update) - * shell.async: Run update in async mode. Won't run next thread if - previous one didn't finished yet. Useful for long - running scripts to avoid bumblebee-status freezes - (defaults to False) -""" - -import os -import subprocess -import threading - -import bumblebee.engine -import bumblebee.input -import bumblebee.output - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widget = bumblebee.output.Widget(full_text=self.get_output) - super(Module, self).__init__(engine, config, widget) - - if self.parameter('interval'): - self.interval(self.parameter('interval')) - - self._command = self.parameter('command') - self._async = bumblebee.util.asbool(self.parameter('async')) - if self._async: - self._output = 'Computing...' - self._current_thread = None - else: - self._output = '' - - # LMB and RMB will update output regardless of timer - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd=self.update) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, cmd=self.update) - - def get_output(self, _): - return self._output - - def update(self, _): - # if requested then run not async version and just execute command in this thread - if not self._async: - self._output = self._get_command_output_or_error(self._command) - return - - # if previous thread didn't end yet then don't do anything - if self._current_thread: - return - - # spawn new thread to execute command and pass callback method to get output from it - self._current_thread = threading.Thread(target=self._run_command_in_thread, - args=(self._command, self._output_function)) - self._current_thread.start() - - @staticmethod - def _get_command_output_or_error(command): - try: - command_output = subprocess.check_output(command, - executable=os.environ.get('SHELL'), - shell=True, - stderr=subprocess.STDOUT) - return command_output.decode('utf-8').strip() - except subprocess.CalledProcessError as exception: - exception_output = exception.output.decode('utf-8').replace('\n', '') - return 'Status:{} output:{}'.format(exception.returncode, exception_output) - - def _run_command_in_thread(self, command, output_callback): - output_callback(self._get_command_output_or_error(command)) - - def _output_function(self, text): - self._output = text - # clear this thread data, so next update will spawn a new one - self._current_thread = None - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/shortcut.py b/bumblebee/modules/shortcut.py deleted file mode 100644 index 5c25cfb..0000000 --- a/bumblebee/modules/shortcut.py +++ /dev/null @@ -1,70 +0,0 @@ -# pylint: disable=C0112,R0903 - -"""Shows a widget per user-defined shortcut and allows to define the behaviour -when clicking on it. - -For more than one shortcut, the commands and labels are strings separated by -a demiliter (; semicolon by default). - -For example in order to create two shortcuts labeled A and B with commands -cmdA and cmdB you could do: - - ./bumblebee-status -m shortcut -p shortcut.cmd="ls;ps" shortcut.label="A;B" - -Parameters: - * shortcut.cmds : List of commands to execute - * shortcut.labels: List of widgets' labels (text) - * shortcut.delim : Commands and labels delimiter (; semicolon by default) -""" - -import logging -import bumblebee.engine -import bumblebee.output -import bumblebee.input - -LINK = "https://github.com/tobi-wan-kenobi/bumblebee-status/wiki" -LABEL = "Click me" - -class Module(bumblebee.engine.Module): - """ Shortcut module.""" - - def __init__(self, engine, config): - widgets = [] - self._engine = engine - super(Module, self).__init__(engine, config, widgets) - - self._labels = self.parameter("labels", "{}".format(LABEL)) - self._cmds = self.parameter("cmds", "firefox {}".format(LINK)) - self._delim = self.parameter("delim", ";") - - self.update_widgets(widgets) - - def update_widgets(self, widgets): - """ Creates a set of widget per user define shortcut.""" - - cmds = self._cmds.split(self._delim) - labels = self._labels.split(self._delim) - - # to be on the safe side create as many widgets as there are data (cmds or labels) - num_shortcuts = min(len(cmds), len(labels)) - - # report possible problem as a warning - if len(cmds) is not len(labels): - logging.warning("shortcut: the number of commands does not match "\ - "the number of provided labels.") - logging.warning("cmds : %s, labels : %s", cmds, labels) - - for idx in range(0, num_shortcuts): - cmd = cmds[idx] - label = labels[idx] - - widget = bumblebee.output.Widget(full_text=label) - self._engine.input.register_callback(widget, button=bumblebee.input.LEFT_MOUSE, cmd=cmd) - - widgets.append(widget) - - def update(self, widgets): - if len(widgets) <= 0: - self.update_widgets(widgets) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/spaceapi.py b/bumblebee/modules/spaceapi.py deleted file mode 100644 index 42ff495..0000000 --- a/bumblebee/modules/spaceapi.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# pylint: disable=C0111,R0903 - -"""Displays the state of a Space API endpoint -Space API is an API for hackspaces based on JSON. See spaceapi.io for -an example. - -Requires the following libraries: - * requests - * regex - -Parameters: - * spaceapi.url: String representation of the api endpoint - * spaceapi.format: Format string for the output - -Format Strings: - * Format strings are indicated by double %% - * They represent a leaf in the JSON tree, layers seperated by "." - * Boolean values can be overwritten by appending "%true%false" - in the format string - * Example: to reference "open" in "{"state":{"open": true}}" - you would write "%%state.open%%", if you also want - to say "Open/Closed" depending on the boolean you - would write "%%state.open%Open%Closed%%" -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -import requests -import threading -import re -import json - - -def formatStringBuilder(s, json): - """ - Parses Format Strings - Parameter: - s -> format string - json -> the spaceapi response object - """ - identifiers = re.findall("%%.*?%%", s) - for i in identifiers: - ic = i[2:-2] # Discard %% - j = ic.split("%") - - # Only neither of, or both true AND false may be overwritten - if len(j) != 3 and len(j) != 1: - return "INVALID FORMAT STRING" - - if len(j) == 1: # no overwrite - s = s.replace(i, json[j[0]]) - elif json[j[0]]: # overwrite for True - s = s.replace(i, j[1]) - else: # overwrite for False - s = s.replace(i, j[2]) - return s - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__( - engine, config, bumblebee.output.Widget(full_text=self.getState) - ) - - engine.input.register_callback( - self, button=bumblebee.input.LEFT_MOUSE, cmd=self.__forceReload - ) - - self._data = {} - self._error = None - - self._threadingCount = 0 - - # The URL representing the api endpoint - self._url = self.parameter("url", default="http://club.entropia.de/spaceapi") - self._format = self.parameter( - "format", default=u" %%space%%: %%state.open%Open%Closed%%" - ) - - def state(self, widget): - try: - if self._error is not None: - return ["critical"] - elif self._data["state.open"]: - return ["warning"] - else: - return [] - except KeyError: - return ["critical"] - - def update(self, widgets): - if self._threadingCount == 0: - thread = threading.Thread(target=self.get_api_async, args=()) - thread.start() - self._threadingCount = ( - 0 if self._threadingCount > 300 else self._threadingCount + 1 - ) - - def getState(self, widget): - text = self._format - if self._error is not None: - text = self._error - else: - try: - text = formatStringBuilder(self._format, self._data) - except KeyError: - text = "KeyError" - return text - - def get_api_async(self): - try: - with requests.get(self._url, timeout=10) as request: - # Can't implement error handling for python2.7 if I use - # request.json() as it uses simplejson in newer versions - self._data = self.__flatten(json.loads(request.text)) - self._error = None - except requests.exceptions.Timeout: - self._error = "Timeout" - except requests.exceptions.HTTPError: - self._error = "HTTP Error" - except ValueError: - self._error = "Not a JSON response" - - # left_mouse_button handler - def __forceReload(self, event): - self._threadingCount += 300 - self._error = "RELOADING" - - # Flattens the JSON structure recursively, e.g. ["space"]["open"] - # becomes ["space.open"] - def __flatten(self, json): - out = {} - for key in json: - value = json[key] - if type(value) is dict: - flattened_key = self.__flatten(value) - for fk in flattened_key: - out[key + "." + fk] = flattened_key[fk] - else: - out[key] = value - return out - - -# Author: Tobias Manske -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/spacer.py b/bumblebee/modules/spacer.py deleted file mode 100644 index b89c233..0000000 --- a/bumblebee/modules/spacer.py +++ /dev/null @@ -1,23 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Draws a widget with configurable text content. - -Parameters: - * spacer.text: Widget contents (defaults to empty string) -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.text) - ) - self._text = self.parameter("text", "") - - def text(self, widget): - return self._text - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/spotify.py b/bumblebee/modules/spotify.py deleted file mode 100644 index abc12bd..0000000 --- a/bumblebee/modules/spotify.py +++ /dev/null @@ -1,87 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the current song being played -Requires the following library: - * python-dbus -Parameters: - * spotify.format: Format string (defaults to "{artist} - {title}") - Available values are: {album}, {title}, {artist}, {trackNumber}, {playbackStatus} - * spotify.previous: Change binding for previous song (default is left click) - * spotify.next: Change binding for next song (default is right click) - * spotify.pause: Change binding for toggling pause (default is middle click) - Available options for spotify.previous, spotify.next and spotify.pause are: - LEFT_CLICK, RIGHT_CLICK, MIDDLE_CLICK, SCROLL_UP, SCROLL_DOWN -""" - -import sys - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from bumblebee.output import scrollable - -try: - import dbus -except ImportError: - pass - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.spotify) - ) - buttons = {"LEFT_CLICK":bumblebee.input.LEFT_MOUSE, - "RIGHT_CLICK":bumblebee.input.RIGHT_MOUSE, - "MIDDLE_CLICK":bumblebee.input.MIDDLE_MOUSE, - "SCROLL_UP":bumblebee.input.WHEEL_UP, - "SCROLL_DOWN":bumblebee.input.WHEEL_DOWN, - } - - self._song = "" - self._format = self.parameter("format", "{artist} - {title}") - prev_button = self.parameter("previous", "LEFT_CLICK") - next_button = self.parameter("next", "RIGHT_CLICK") - pause_button = self.parameter("pause", "MIDDLE_CLICK") - - cmd = "dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.spotify \ - /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player." - engine.input.register_callback(self, button=buttons[prev_button], - cmd=cmd + "Previous") - engine.input.register_callback(self, button=buttons[next_button], - cmd=cmd + "Next") - engine.input.register_callback(self, button=buttons[pause_button], - cmd=cmd + "PlayPause") - - @scrollable - def spotify(self, widget): - return self.string_song - - def hidden(self): - return self.string_song == "" - - def update(self, widgets): - try: - bus = dbus.SessionBus() - spotify = bus.get_object("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2") - spotify_iface = dbus.Interface(spotify, 'org.freedesktop.DBus.Properties') - props = spotify_iface.Get('org.mpris.MediaPlayer2.Player', 'Metadata') - playback_status = str(spotify_iface.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus')) - self._song = self._format.format(album=str(props.get('xesam:album')), - title=str(props.get('xesam:title')), - artist=','.join(props.get('xesam:artist')), - trackNumber=str(props.get('xesam:trackNumber')), - playbackStatus=u"\u25B6" if playback_status=="Playing" else u"\u258D\u258D" if playback_status=="Paused" else "",) - - except Exception: - self._song = "" - - @property - def string_song(self): - if sys.version_info.major < 3: - return unicode(self._song) - return str(self._song) - - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/stock.py b/bumblebee/modules/stock.py deleted file mode 100644 index 5333700..0000000 --- a/bumblebee/modules/stock.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: UTF-8 -*- -# pylint: disable=C0111,R0903 - -"""Display a stock quote from worldtradingdata.com - -Requires the following python packages: - * requests - -Parameters: - * stock.symbols : Comma-separated list of symbols to fetch - * stock.change : Should we fetch change in stock value (defaults to True) -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.util - -import json -import requests - -import logging - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.value) - ) - self._symbols = self.parameter('symbols', '') - self._change = bumblebee.util.asbool(self.parameter('change', True)) - self._value = None - self.interval_factor(60) - self.interval(60) - - def value(self, widget): - results = [] - if not self._value: - return 'n/a' - data = json.loads(self._value) - - for symbol in data['quoteResponse']['result']: - valkey = 'regularMarketChange' if self._change else 'regularMarketPrice' - sym = 'n/a' if not 'symbol' in symbol else symbol['symbol'] - currency = 'USD' if not 'currency' in symbol else symbol['currency'] - val = 'n/a' if not valkey in symbol else '{:.2f}'.format(symbol[valkey]) - results.append('{} {} {}'.format(sym, val, currency)) - return u' '.join(results) - - def fetch(self): - if self._symbols: - url = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols=' - url += self._symbols + '&fields=regularMarketPrice,currency,regularMarketChange' - return requests.get(url).text.strip() - else: - logging.error('unable to retrieve stock exchange rate') - return None - - def update(self, widgets): - self._value = self.fetch() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/sun.py b/bumblebee/modules/sun.py deleted file mode 100644 index e27d750..0000000 --- a/bumblebee/modules/sun.py +++ /dev/null @@ -1,111 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays sunrise and sunset times - -Parameters: - * cpu.lat : Latitude of your location - * cpu.lon : Longitude of your location -""" - -try: - from suntime import Sun, SunTimeException -except ImportError: - pass -try: - import requests -except ImportError: - pass -try: - from dateutil.tz import tzlocal -except ImportError: - pass - -import datetime - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__( - engine, config, - bumblebee.output.Widget(full_text=self.suntimes) - ) - self.interval(3600) - self._lat = self.parameter("lat", None) - self._lon = self.parameter("lon", None) - try: - if not self._lat or not self._lon: - location_url = "http://ipinfo.io/json" - location = requests.get(location_url).json() - self._lat, self._lon = location["loc"].split(",") - self._lat = float(self._lat) - self._lon = float(self._lon) - except Exception: - pass - self.update(None) - - def suntimes(self, _): - if self._sunset and self._sunrise: - if self._isup: - return u"\u21A7{} \u21A5{}".format( - self._sunset.strftime('%H:%M'), - self._sunrise.strftime('%H:%M')) - return u"\u21A5{} \u21A7{}".format(self._sunrise.strftime('%H:%M'), - self._sunset.strftime('%H:%M')) - return "?" - - def _calculate_times(self): - self._isup = False - try: - sun = Sun(self._lat, self._lon) - except Exception: - self._sunrise = None - self._sunset = None - return - - order_matters = True - - try: - self._sunrise = sun.get_local_sunrise_time() - except SunTimeException: - self._sunrise = "no sunrise" - order_matters = False - - try: - self._sunset = sun.get_local_sunset_time() - except SunTimeException: - self._sunset = "no sunset" - order_matters = False - - if not order_matters: - return - - now = datetime.datetime.now(tz=tzlocal()) - if now > self._sunset: - tomorrow = (now + datetime.timedelta(days=1)).date() - try: - self._sunrise = sun.get_local_sunrise_time(tomorrow) - self._sunset = sun.get_local_sunset_time(tomorrow) - except SunTimeException: - self._sunrise = "no sunrise" - self._sunset = "no sunset" - - elif now > self._sunrise: - tomorrow = (now + datetime.timedelta(days=1)).date() - try: - self._sunrise = sun.get_local_sunrise_time(tomorrow) - except SunTimeException: - self._sunrise = "no sunrise" - return - self._isup = True - - def update(self, widgets): - if not self._lat or not self._lon: - self._sunrise = None - self._sunset = None - self._calculate_times() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/system.py b/bumblebee/modules/system.py deleted file mode 100644 index e2f296a..0000000 --- a/bumblebee/modules/system.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -# pylint: disable=C0111,R0903 - -""" system module - -adds the possibility to - * shutdown - * reboot -the system. - -Per default a confirmation dialog is shown before the actual action is performed. - -Parameters: - * system.confirm: show confirmation dialog before performing any action (default: true) - * system.reboot: specify a reboot command (defaults to 'reboot') - * system.shutdown: specify a shutdown command (defaults to 'shutdown -h now') - * system.logout: specify a logout command (defaults to 'i3exit logout') - * system.switch_user: specify a command for switching the user (defaults to 'i3exit switch_user') - * system.lock: specify a command for locking the screen (defaults to 'i3exit lock') - * system.suspend: specify a command for suspending (defaults to 'i3exit suspend') - * system.hibernate: specify a command for hibernating (defaults to 'i3exit hibernate') -""" - -import logging -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import bumblebee.popup_v2 -import functools - -try: - import Tkinter as tk - import tkMessageBox as tkmessagebox -except ImportError: - # python 3 - try: - import tkinter as tk - from tkinter import messagebox as tkmessagebox - except ImportError: - logging.warning("failed to import tkinter - bumblebee popups won't work!") - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.text) - ) - - self._confirm = True - if self.parameter("confirm", "true") == "false": - self._confirm = False - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.popup) - - def update(self, widgets): - pass - - def text(self, widget): - return "" - - def _on_command(self, header, text, command): - do_it = True - if self._confirm: - root = tk.Tk() - root.withdraw() - root.focus_set() - - do_it = tkmessagebox.askyesno(header, text) - root.destroy() - - if do_it: - bumblebee.util.execute(command) - - - def popup(self, widget): - menu = bumblebee.popup_v2.PopupMenu() - reboot_cmd = self.parameter("reboot", "reboot") - shutdown_cmd = self.parameter("shutdown", "shutdown -h now") - logout_cmd = self.parameter("logout", "i3exit logout") - switch_user_cmd = self.parameter("switch_user", "i3exit switch_user") - lock_cmd = self.parameter("lock", "i3exit lock") - suspend_cmd = self.parameter("suspend", "i3exit suspend") - hibernate_cmd = self.parameter("hibernate", "i3exit hibernate") - - menu.add_menuitem("shutdown", callback=functools.partial(self._on_command, "Shutdown", "Shutdown?", shutdown_cmd)) - menu.add_menuitem("reboot", callback=functools.partial(self._on_command, "Reboot", "Reboot?", reboot_cmd)) - menu.add_menuitem("log out", callback=functools.partial(self._on_command, "Log out", "Log out?", "i3exit logout")) - # don't ask for these - menu.add_menuitem("switch user", callback=functools.partial(bumblebee.util.execute, switch_user_cmd)) - menu.add_menuitem("lock", callback=functools.partial(bumblebee.util.execute, lock_cmd)) - menu.add_menuitem("suspend", callback=functools.partial(bumblebee.util.execute, suspend_cmd)) - menu.add_menuitem("hibernate", callback=functools.partial(bumblebee.util.execute, hibernate_cmd)) - - menu.show(widget) - - def state(self, widget): - return [] diff --git a/bumblebee/modules/taskwarrior.py b/bumblebee/modules/taskwarrior.py deleted file mode 100644 index a61ccb2..0000000 --- a/bumblebee/modules/taskwarrior.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Displays the number of pending tasks in TaskWarrior. - -Requires the following library: - * taskw - -Parameters: - * taskwarrior.taskrc : path to the taskrc file (defaults to ~/.taskrc) -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -try: - from taskw import TaskWarrior -except: - pass - - -class Module(bumblebee.engine.Module): - """TaskWarrior module.""" - - def __init__(self, engine, config): - """Initialize taskwarrior module.""" - super(Module, self).__init__(engine, config, - bumblebee.output.Widget( - full_text=self.output)) - self._pending_tasks_count = "0" - - def update(self, widgets): - """Return a string with the number of pending tasks from TaskWarrior.""" - try: - taskrc = self.parameter("taskrc", "~/.taskrc") - w = TaskWarrior(config_filename=taskrc) - pending_tasks = w.filter_tasks({'status': 'pending'}) - self._pending_tasks_count = str(len(pending_tasks)) - except: - self._pending_tasks_count = 'Error' - - def output(self, _): - """Format the task counter to output in bumblebee.""" - return "{}".format(self._pending_tasks_count) diff --git a/bumblebee/modules/test.py b/bumblebee/modules/test.py deleted file mode 100644 index 5e92e0e..0000000 --- a/bumblebee/modules/test.py +++ /dev/null @@ -1,14 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Test module -""" - -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text="test") - ) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/title.py b/bumblebee/modules/title.py deleted file mode 100644 index 2316e9b..0000000 --- a/bumblebee/modules/title.py +++ /dev/null @@ -1,85 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays focused i3 window title. - -Requirements: - * i3ipc - -Parameters: - * title.max : Maximum character length for title before truncating. Defaults to 64. - * title.placeholder : Placeholder text to be placed if title was truncated. Defaults to "...". - * title.scroll : Boolean flag for scrolling title. Defaults to False -""" - -import threading - -try: - import i3ipc -except ImportError: - pass - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from bumblebee.output import scrollable - -_no_title = "n/a" - -class Module(bumblebee.engine.Module): - """Window title module.""" - - def __init__(self, engine, config): - super(Module, self).__init__( - engine, - config - ) - - # parsing of parameters - self._scroll = bumblebee.util.asbool(self.parameter("scroll", False)) - self._max = int(self.parameter("max", 64)) - self._placeholder = self.parameter("placeholder", "...") - - # set output of the module - self.widgets(bumblebee.output.Widget(full_text= - self._scrolling_focused_title if self._scroll else self._focused_title)) - - # create a connection with i3ipc - try: - self._i3 = i3ipc.Connection() - # event is called both on focus change and title change - self._i3.on("window", lambda _p_i3, _p_e: self._pollTitle()) - # begin listening for events - threading.Thread(target=self._i3.main).start() - except: - pass - - # initialize the first title - self._pollTitle() - - def _focused_title(self, widget): - return self._title - - @scrollable - def _scrolling_focused_title(self, widget): - return self._full_title - - def _pollTitle(self): - """Updating current title.""" - try: - self._full_title = self._i3.get_tree().find_focused().name - except: - self._full_title = _no_title - if self._full_title is None: - self._full_title = _no_title - - if not self._scroll: - # cut the text if it is too long - if len(self._full_title) > self._max: - self._title = self._full_title[0:self._max - len(self._placeholder)] - self._title = "{}{}".format(self._title, self._placeholder) - else: - self._title = self._full_title - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/todo.py b/bumblebee/modules/todo.py deleted file mode 100644 index 04cd256..0000000 --- a/bumblebee/modules/todo.py +++ /dev/null @@ -1,45 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the number of todo items from a text file - -Parameters: - * todo.file: File to read TODOs from (defaults to ~/Documents/todo.txt) -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import os.path - - -class Module(bumblebee.engine.Module): - - - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.output) - ) - self._doc = os.path.expanduser(self.parameter("file", "~/Documents/todo.txt")) - self._todos = self.count_items() - - - def output(self, widget): - self._todos = self.count_items() - return str(self._todos) - - - def state(self, widgets): - if self._todos == 0: - return "empty" - return "items" - - - def count_items(self): - try: - i = -1 - with open(self._doc) as f: - for i, l in enumerate(f): - pass - return i+1 - except Exception: - return 0 diff --git a/bumblebee/modules/traffic.py b/bumblebee/modules/traffic.py deleted file mode 100644 index 2eac453..0000000 --- a/bumblebee/modules/traffic.py +++ /dev/null @@ -1,110 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays network IO for interfaces. - -Parameters: - * traffic.exclude: Comma-separated list of interface prefixes to exclude (defaults to "lo,virbr,docker,vboxnet,veth") - * traffic.states: Comma-separated list of states to show (prefix with "^" to invert - i.e. ^down -> show all devices that are not in state down) - * traffic.showname: If set to False, hide network interface name (defaults to True) -""" - -import time -import psutil -import netifaces - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - super(Module, self).__init__(engine, config, widgets) - self._exclude = tuple(filter(len, self.parameter("exclude", "lo,virbr,docker,vboxnet,veth").split(","))) - self._status = "" - - self._showname = bumblebee.util.asbool(self.parameter("showname", True)) - self._prev = {} - self._states = {} - self._lastcheck = 0 - self._states["include"] = [] - self._states["exclude"] = [] - for state in tuple(filter(len, self.parameter("states", "").split(","))): - if state[0] == "^": - self._states["exclude"].append(state[1:]) - else: - self._states["include"].append(state) - self._update_widgets(widgets) - - def state(self, widget): - if "traffic.rx" in widget.name: - return "rx" - if "traffic.tx" in widget.name: - return "tx" - return self._status - - def update(self, widgets): - self._update_widgets(widgets) - - def create_widget(self, widgets, name, txt=None, attributes={}): - widget = bumblebee.output.Widget(name=name) - widget.full_text(txt) - widgets.append(widget) - - for key in attributes: - widget.set(key, attributes[key]) - - return widget - - def get_addresses(self, intf): - retval = [] - try: - for ip in netifaces.ifaddresses(intf).get(netifaces.AF_INET, []): - if ip.get("addr", "") != "": - retval.append(ip.get("addr")) - except Exception: - return [] - return retval - - def _update_widgets(self, widgets): - interfaces = [i for i in netifaces.interfaces() if not i.startswith(self._exclude)] - - del widgets[:] - - counters = psutil.net_io_counters(pernic=True) - now = time.time() - timediff = now - (self._lastcheck if self._lastcheck else now) - if timediff <= 0: timediff = 1 - self._lastcheck = now - for interface in interfaces: - if not interface: interface = "lo" - state = "down" - if len(self.get_addresses(interface)) > 0: - state = "up" - elif bumblebee.util.asbool(self.parameter("hide_down", True)): - continue - - if len(self._states["exclude"]) > 0 and state in self._states["exclude"]: continue - if len(self._states["include"]) > 0 and state not in self._states["include"]: continue - - data = { - "rx": counters[interface].bytes_recv, - "tx": counters[interface].bytes_sent, - } - - name = "traffic-{}".format(interface) - - if self._showname: - self.create_widget(widgets, name, interface) - - for direction in ["rx", "tx"]: - name = "traffic.{}-{}".format(direction, interface) - widget = self.create_widget(widgets, name, attributes={"theme.minwidth": "1000.00MB"}) - prev = self._prev.get(name, 0) - speed = bumblebee.util.bytefmt((int(data[direction]) - int(prev))/timediff) - txtspeed ='{0}/s'.format(speed) - widget.full_text(txtspeed) - self._prev[name] = data[direction] - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/twmn.py b/bumblebee/modules/twmn.py deleted file mode 100644 index 1ebb61c..0000000 --- a/bumblebee/modules/twmn.py +++ /dev/null @@ -1,39 +0,0 @@ -#pylint: disable=C0111,R0903 - -"""Toggle twmn notifications.""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text="") - ) - self._paused = False - # Make sure that twmn is currently not paused - try: - bumblebee.util.execute("killall -SIGUSR2 twmnd") - except: - pass - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.toggle_status - ) - - def toggle_status(self, event): - self._paused = not self._paused - - try: - if self._paused: - bumblebee.util.execute("systemctl --user start twmnd") - else: - bumblebee.util.execute("systemctl --user stop twmnd") - except: - self._paused = not self._paused # toggling failed - - def state(self, widget): - if self._paused: - return ["muted"] - return ["unmuted"] diff --git a/bumblebee/modules/uptime.py b/bumblebee/modules/uptime.py deleted file mode 100644 index 34e4085..0000000 --- a/bumblebee/modules/uptime.py +++ /dev/null @@ -1,30 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Displays the system uptime.""" - -# Use absolute_import because there's already a datatime module -# in the same directory -from __future__ import absolute_import - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -from datetime import timedelta - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.output) - ) - self._uptime = "" - - def output(self, _): - return "{}".format(self._uptime) - - def update(self, widgets): - with open('/proc/uptime', 'r') as f: - uptime_seconds = int(float(f.readline().split()[0])) - self._uptime = timedelta(seconds = uptime_seconds) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/vault.py b/bumblebee/modules/vault.py deleted file mode 100644 index 6505dc2..0000000 --- a/bumblebee/modules/vault.py +++ /dev/null @@ -1,81 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Copy passwords from a password store into the clipboard (currently supports only "pass") - -Many thanks to [@bbernhard](https://github.com/bbernhard) for the idea! - -Parameters: - * vault.duration: Duration until password is cleared from clipboard (defaults to 30) - * vault.location: Location of the password store (defaults to ~/.password-store) - * vault.offx: x-axis offset of popup menu (defaults to 0) - * vault.offy: y-axis offset of popup menu (defaults to 0) -""" - - -# TODO: -# - support multiple backends by abstracting the menu structure into a tree -# - build the menu and the actions based on that abstracted tree -# - -import os -import time -import threading -import bumblebee.util -import bumblebee.popup_v2 -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -def build_menu(parent, current_directory, callback): - with os.scandir(current_directory) as it: - for entry in it: - if entry.name.startswith("."): continue - if entry.is_file(): - name = entry.name[:entry.name.rfind(".")] - parent.add_menuitem(name, callback=lambda : callback(os.path.join(current_directory, name))) - - else: - submenu = bumblebee.popup_v2.PopupMenu(parent, leave=False) - build_menu(submenu, os.path.join(current_directory, entry.name), callback) - parent.add_cascade(entry.name, submenu) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.text) - ) - self._duration = int(self.parameter("duration", 30)) - self._offx = int(self.parameter("offx", 0)) - self._offy = int(self.parameter("offy", 0)) - self._path = os.path.expanduser(self.parameter("location", "~/.password-store/")) - self._reset() - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.popup) - - def popup(self, widget): - menu = bumblebee.popup_v2.PopupMenu(leave=False) - - build_menu(menu, self._path, self._callback) - menu.show(widget, offset_x=self._offx, offset_y=self._offy) - - def _reset(self): - self._timer = None - self._text = str(self.parameter("text", "")) - - def _callback(self, secret_name): - secret_name = secret_name.replace(self._path, "") # remove common path - if self._timer: - self._timer.cancel() - # bumblebee.util.execute hangs for some reason - os.system("PASSWORD_STORE_CLIP_TIME={} pass -c {} > /dev/null 2>&1".format(self._duration, secret_name)) - self._timer = threading.Timer(self._duration, self._reset) - self._timer.start() - self._start = int(time.time()) - self._text = secret_name - - def text(self, widget): - if self._timer: - return "{} ({}s)".format(self._text, self._duration - (int(time.time()) - self._start)) - return self._text - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/vpn.py b/bumblebee/modules/vpn.py deleted file mode 100644 index a43e36b..0000000 --- a/bumblebee/modules/vpn.py +++ /dev/null @@ -1,97 +0,0 @@ -# pylint: disable=C0111,R0903 - -""" Displays the VPN profile that is currently in use. - - Left click opens a popup menu that lists all available VPN profiles and allows to establish - a VPN connection using that profile. - - Prerequisites: - * nmcli needs to be installed and configured properly. - To quickly test, whether nmcli is working correctly, type "nmcli -g NAME,TYPE,DEVICE con" which - lists all the connection profiles that are configured. Make sure that your VPN profile is in that list! - - e.g: to import a openvpn profile via nmcli: - sudo nmcli connection import type openvpn file -""" - -import logging -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import functools - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.vpn_status) - ) - - self._connected_vpn_profile = None - self._selected_vpn_profile = None - - res = bumblebee.util.execute("nmcli -g NAME,TYPE c") - lines = res.splitlines() - - self._vpn_profiles = [] - for line in lines: - info = line.split(':') - try: - if info[1] == "vpn": - self._vpn_profiles.append(info[0]) - except: - pass - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd=self.popup) - - def update(self, widgets): - try: - res = bumblebee.util.execute("nmcli -g NAME,TYPE,DEVICE con") - lines = res.splitlines() - self._connected_vpn_profile = None - for line in lines: - info = line.split(':') - if info[1] == "vpn" and info[2] != "": - self._connected_vpn_profile = info[0] - - except Exception as e: - logging.exception("Couldn't get VPN status") - self._connected_vpn_profile = None - - def vpn_status(self, widget): - if self._connected_vpn_profile is None: - return "off" - return self._connected_vpn_profile - - def _on_vpn_disconnect(self): - try: - bumblebee.util.execute("nmcli c down \"{vpn}\"" - .format(vpn=self._connected_vpn_profile)) - self._connected_vpn_profile = None - except Exception as e: - logging.exception("Couldn't disconnect VPN connection") - - def _on_vpn_connect(self, name): - self._selected_vpn_profile = name - - try: - bumblebee.util.execute("nmcli c up \"{vpn}\"" - .format(vpn=self._connected_vpn_profile)) - self._connected_vpn_profile = name - except Exception as e: - logging.exception("Couldn't establish VPN connection") - self._connected_vpn_profile = None - - def popup(self, widget): - menu = bumblebee.popup_v2.PopupMenu() - - if self._connected_vpn_profile is not None: - menu.add_menuitem("Disconnect", callback=self._on_vpn_disconnect) - for vpn_profile in self._vpn_profiles: - if self._connected_vpn_profile is not None and self._connected_vpn_profile == vpn_profile: - continue - menu.add_menuitem(vpn_profile, callback=functools.partial(self._on_vpn_connect, vpn_profile)) - menu.show(widget) - - def state(self, widget): - return [] diff --git a/bumblebee/modules/weather.py b/bumblebee/modules/weather.py deleted file mode 100644 index a86f44f..0000000 --- a/bumblebee/modules/weather.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: UTF-8 -*- -# pylint: disable=C0111,R0903 - -"""Displays the temperature on the current location based on the ip - -Requires the following python packages: - * requests - -Parameters: - * weather.location: Set location, defaults to 'auto' for getting location from http://ipinfo.io - If set to a comma-separated list, left-click and right-click can be used to rotate the locations. - Locations should be city names or city ids. - * weather.unit: metric (default), kelvin, imperial - * weather.showcity: If set to true, show location information, otherwise hide it (defaults to true) - * weather.showminmax: If set to true, show the minimum and maximum temperature, otherwise hide it (defaults to false) - * weather.apikey: API key from http://api.openweathermap.org -""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine -import re - -try: - import requests - from requests.exceptions import RequestException -except ImportError: - pass - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.output) - ) - self._temperature = 0 - self._apikey = self.parameter("apikey", "af7bfe22287c652d032a3064ffa44088") - self._location = self.parameter("location", "auto") - if "," in self._location: - self._location = self._location.split(",") - else: - self._location = [self._location] - self._index = 0 - self._showcity = bumblebee.util.asbool(self.parameter("showcity", True)) - self._showminmax = bumblebee.util.asbool(self.parameter("showminmax", False)) - self._unit = self.parameter("unit", "metric") - self._valid = False - self.interval_factor(60) - self.interval(15) - - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, cmd=self._next_location) - engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd=self._prev_location) - - def _next_location(self, event): - self._index = 0 if self._index >= len(self._location) - 1 else self._index + 1 - self.update(self.widgets()) - - def _prev_location(self, event): - self._index = len(self._location)-1 if self._index <= 0 else self._index - 1 - self.update(self.widgets()) - - def _unit_suffix(self): - if self._unit == "metric": - return "C" - if self._unit == "kelvin": - return "K" - if self._unit == "imperial": - return "F" - return "" - - def temperature(self): - return u"{}°{}".format(self._temperature, self._unit_suffix()) - - def tempmin(self): - return u"{}°{}".format(self._tempmin, self._unit_suffix()) - - def tempmax(self): - return u"{}°{}".format(self._tempmax, self._unit_suffix()) - - def city(self): - city = re.sub('[_-]', ' ', self._city) - return u"{} ".format(city) - - def output(self, widget): - if not self._valid: - return u"?" - if self._showminmax: - self._showcity=False - return self.city() + self.temperature() + " Hi:" + self.tempmax() + " Lo:" + self.tempmin() - elif self._showcity: - return self.city() + self.temperature() - else: - return self.temperature() - - def state(self, widget): - if self._valid: - if "thunderstorm" in self._weather: - return ['thunder'] - elif "drizzle" in self._weather: - return ['rain'] - elif "rain" in self._weather: - return ['rain'] - elif "snow" in self._weather: - return ['snow'] - elif "sleet" in self._weather: - return ['sleet'] - elif "clear" in self._weather: - return ['clear'] - elif "cloud" in self._weather: - return ['clouds'] - else: - return [] - - return [] - - def update(self, widgets): - try: - weather_url = "http://api.openweathermap.org/data/2.5/weather?appid={}".format(self._apikey) - weather_url = "{}&units={}".format(weather_url, self._unit) - if self._location[self._index] == "auto": - location_url = "http://ipinfo.io/json" - location = requests.get(location_url).json() - coord = location["loc"].split(",") - weather_url = "{url}&lat={lat}&lon={lon}".format(url=weather_url, lat=coord[0], lon=coord[1]) - elif self._location[self._index].isdigit(): - weather_url = "{url}&id={id}".format(url=weather_url, id=self._location[self._index]) - else: - weather_url = "{url}&q={city}".format(url=weather_url, city=self._location[self._index]) - weather = requests.get(weather_url).json() - self._city = weather['name'] - self._temperature = int(weather['main']['temp']) - self._tempmin = int(weather['main']['temp_min']) - self._tempmax = int(weather['main']['temp_max']) - self._weather = weather['weather'][0]['main'].lower() - self._valid = True - except Exception: - self._valid = False - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/xkcd.py b/bumblebee/modules/xkcd.py deleted file mode 100644 index 143e590..0000000 --- a/bumblebee/modules/xkcd.py +++ /dev/null @@ -1,17 +0,0 @@ -#pylint: disable=C0111,R0903 - -"""Opens a random xkcd comic in the browser.""" - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text="xkcd") - ) - engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, - cmd="xdg-open https://c.xkcd.com/random/comic/" - ) diff --git a/bumblebee/modules/xrandr.py b/bumblebee/modules/xrandr.py deleted file mode 100644 index b9e5cd7..0000000 --- a/bumblebee/modules/xrandr.py +++ /dev/null @@ -1,118 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Shows a widget for each connected screen and allows the user to enable/disable screens. - -Parameters: - * xrandr.overwrite_i3config: If set to 'true', this module assembles a new i3 config - every time a screen is enabled or disabled by taking the file "~/.config/i3/config.template" - and appending a file "~/.config/i3/config." for every screen. - * xrandr.autoupdate: If set to 'false', does *not* invoke xrandr automatically. Instead, the - module will only refresh when displays are enabled or disabled (defaults to true) - -Requires the following python module: - * (optional) i3 - if present, the need for updating the widget list is auto-detected - -Requires the following executable: - * xrandr -""" - -import os -import re -import sys - -import bumblebee.util -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -try: - import i3 -except: - pass - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - self._engine = engine - super(Module, self).__init__(engine, config, widgets) - self._autoupdate = bumblebee.util.asbool(self.parameter("autoupdate", True)) - self._needs_update = True - - try: - i3.Subscription(self._output_update, "output") - except: - pass - - def _output_update(self, event, data, _): - self._needs_update = True - - def update_widgets(self, widgets): - new_widgets = [] - - if self._autoupdate == False and self._needs_update == False: - return - - self._needs_update = False - - for line in bumblebee.util.execute("xrandr -q").split("\n"): - if not " connected" in line: - continue - display = line.split(" ", 2)[0] - m = re.search(r'\d+x\d+\+(\d+)\+\d+', line) - - widget = self.widget(display) - if not widget: - widget = bumblebee.output.Widget(full_text=display, name=display) - self._engine.input.register_callback(widget, button=1, cmd=self._toggle) - self._engine.input.register_callback(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) - - while len(widgets) > 0: - del widgets[0] - for widget in new_widgets: - widgets.append(widget) - - if self._autoupdate == False: - widget = bumblebee.output.Widget(full_text="") - widget.set("state", "refresh") - self._engine.input.register_callback(widget, button=1, cmd=self._refresh) - widgets.append(widget) - - def update(self, widgets): - self.update_widgets(widgets) - - def state(self, widget): - return widget.get("state", "off") - - def _refresh(self, event): - self._needs_update = True - - def _toggle(self, event): - self._needs_update = True - path = os.path.dirname(os.path.abspath(__file__)) - - if bumblebee.util.asbool(self.parameter("overwrite_i3config", False)) == True: - toggle_cmd = "{}/../../bin/toggle-display.sh".format(path) - else: - toggle_cmd = "xrandr" - - widget = self.widget_by_id(event["instance"]) - - if widget.get("state") == "on": - bumblebee.util.execute("{} --output {} --off".format(toggle_cmd, widget.name)) - else: - first_neighbor = next((widget for widget in self.widgets() if widget.get("state") == "on"), None) - last_neighbor = next((widget for widget in reversed(self.widgets()) if widget.get("state") == "on"), None) - - neighbor = first_neighbor if event["button"] == bumblebee.input.LEFT_MOUSE else last_neighbor - - if neighbor is None: - bumblebee.util.execute("{} --output {} --auto".format(toggle_cmd, widget.name)) - else: - bumblebee.util.execute("{} --output {} --auto --{}-of {}".format(toggle_cmd, widget.name, - "left" if event.get("button") == bumblebee.input.LEFT_MOUSE else "right", - neighbor.name)) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/yubikey.py b/bumblebee/modules/yubikey.py deleted file mode 100644 index db32843..0000000 --- a/bumblebee/modules/yubikey.py +++ /dev/null @@ -1,33 +0,0 @@ -# pylint: disable=C0111,R0903 - -"""Shows yubikey information - -Requires: https://github.com/Yubico/python-yubico - -The output indicates that a YubiKey is not connected or it displays -the corresponding serial number. - -""" - -import yubico - -import bumblebee.input -import bumblebee.output -import bumblebee.engine - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - super(Module, self).__init__(engine, config, - bumblebee.output.Widget(full_text=self.keystate)) - self._keystate = "No YubiKey" - - def keystate(self, widget): - return self._keystate - - def update(self, widget): - try: - self._keystate = "YubiKey: " + str(yubico.find_yubikey(debug=False).serial()) - except yubico.yubico_exception.YubicoError: - self._keystate = "No YubiKey" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/zpool.py b/bumblebee/modules/zpool.py deleted file mode 100644 index 1f3e897..0000000 --- a/bumblebee/modules/zpool.py +++ /dev/null @@ -1,187 +0,0 @@ -"""Displays info about zpools present on the system - -Parameters: - * zpool.list: Comma-separated list of zpools to display info for. If empty, info for all zpools - is displayed. (Default: "") - * zpool.format: Format string, tags {name}, {used}, {left}, {size}, {percentfree}, {percentuse}, - {status}, {shortstatus}, {fragpercent}, {deduppercent} are supported. - (Default: "{name} {used}/{size} ({percentfree}%)") - * zpool.showio: Show also widgets detailing current read and write I/O (Default: true) - * zpool.ioformat: Format string for I/O widget, tags {ops} (operations per seconds) and {band} - (bandwidth) are supported. (Default: "{band}") - * zpool.warnfree: Warn if free space is below this percentage (Default: 10) - * zpool.sudo: Use sudo when calling the `zpool` binary. (Default: false) - -Option `zpool.sudo` is intended for Linux users using zfsonlinux older than 0.7.0: In pre-0.7.0 -releases of zfsonlinux regular users couldn't invoke even informative commands such as -`zpool list`. If this option is true, command `zpool list` is invoked with sudo. If this option -is used, the following (or ekvivalent) must be added to the `sudoers(5)`: - -``` - ALL = (root) NOPASSWD: /usr/bin/zpool list -``` - -Be aware of security implications of doing this! -""" - -import time -import logging -from pkg_resources import parse_version -import bumblebee.engine -from bumblebee.util import execute, bytefmt, asbool - -log = logging.getLogger(__name__) - -class Module(bumblebee.engine.Module): - def __init__(self, engine, config): - widgets = [] - super(Module, self).__init__(engine, config, widgets) - - self._includelist = set(filter(lambda x: len(x) > 0, - self.parameter("list", default="").split(','))) - self._format = self.parameter("format", default="{name} {shortstatus} {used}/{size} " + - "({percentfree}%)") - self._usesudo = asbool(self.parameter("sudo", default=False)) - self._showio = asbool(self.parameter("showio", default=True)) - self._ioformat = self.parameter("ioformat", default="{band}") - self._warnfree = int(self.parameter("warnfree", default=10)) - - self._update_widgets(widgets) - - def update(self, widgets): - self._update_widgets(widgets) - - def state(self, widget): - if widget.name.endswith("__read"): - return "poolread" - elif widget.name.endswith("__write"): - return "poolwrite" - - state = widget.get("state") - if state == "FAULTED": - return [state, "critical"] - elif state == "DEGRADED" or widget.get("percentfree") < self._warnfree: - return [state, "warning"] - - return state - - def _update_widgets(self, widgets): - zfs_version_path = "/sys/module/zfs/version" - # zpool list -H: List all zpools, use script mode (no headers and tabs as separators). - try: - with open(zfs_version_path, 'r') as zfs_mod_version: - zfs_version = zfs_mod_version.readline().rstrip().split('-')[0] - except IOError: - # ZFS isn't installed or the module isn't loaded, stub the version - zfs_version = "0.0.0" - logging.error("ZFS version information not found at {}, check the module is loaded.".format(zfs_version_path)) - - raw_zpools = execute(('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+ - if parse_version(zfs_version) < parse_version("0.8.0"): - name, size, alloc, free, _, frag, cap, dedup, health, _ = raw_zpool.split('\t') - else: - name, size, alloc, free, _, _, frag, cap, dedup, health, _ = raw_zpool.split('\t') - cap = cap.rstrip('%') - percentuse=int(cap) - percentfree=100-percentuse - # There is a command, zpool iostat, which is however blocking and was therefore - # causing issues. - # Instead, we read file `/proc/spl/kstat/zfs//io` which contains - # cumulative I/O statistics since boot (or pool creation). We store these values - # (and timestamp) during each widget update, and during the next widget update we - # use them to compute delta of transferred bytes, and using the last and current - # timestamp the rate at which they have been transferred. - with open("/proc/spl/kstat/zfs/{}/io".format(name), "r") as f: - # Third row provides data we need, we are interested in the first 4 values. - # More info about this file can be found here: - # https://github.com/zfsonlinux/zfs/blob/master/lib/libspl/include/sys/kstat.h#L580 - # The 4 values are: - # nread, nwritten, reads, writes - iostat = list(map(int, f.readlines()[2].split()[:4])) - except (ValueError, IOError): - # Unable to parse info about this pool, skip it - continue - - if self._includelist and name not in self._includelist: - continue - - widget = self.widget(name) - if not widget: - widget = bumblebee.output.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) - - # From docs: - # > Note that even though the time is always returned as a floating point number, not - # > all systems provide time with a better precision than 1 second. - # Be aware that that may affect the precision of reported I/O - # Also, during one update cycle the reported I/O may be garbage if the system time - # was changed. - timestamp = time.time() - delta_timestamp = widget.get("last_timestamp") - timestamp - widget.set("last_timestamp", time.time()) - - # abs is there because sometimes the result is -0 - rate_iostat = [abs(x / delta_timestamp) for x in delta_iostat] - nread, nwritten, reads, writes = rate_iostat - - # theme.minwidth is not set since these values are not expected to change - # rapidly - widget.full_text(self._format.format(name=name, used=alloc, left=free, size=size, - percentfree=percentfree, percentuse=percentuse, - status=health, - shortstatus=self._shortstatus(health), - fragpercent=frag, deduppercent=dedup)) - widget.set("state", health) - widget.set("percentfree", percentfree) - widget.set("visited", True) - - if self._showio: - wname, rname = [name + x for x in ["__write", "__read"]] - widget_w = self.widget(wname) - widget_r = self.widget(rname) - if not widget_w or not widget_r: - widget_r = bumblebee.output.Widget(name=rname) - widget_w = bumblebee.output.Widget(name=wname) - widgets.extend([widget_r, widget_w]) - for w in [widget_r, widget_w]: - w.set("theme.minwidth", self._ioformat.format(ops=9999, - band=bytefmt(999.99*(1024**2)))) - w.set("visited", True) - widget_w.full_text(self._ioformat.format(ops=round(writes), - band=bytefmt(nwritten))) - widget_r.full_text(self._ioformat.format(ops=round(reads), - band=bytefmt(nread))) - - for widget in widgets: - if widget.get("visited") is False: - widgets.remove(widget) - - @staticmethod - def _shortstatus(status): - # From `zpool(8)`, section Device Failure and Recovery: - # A pool's health status is described by one of three states: online, degraded, or faulted. - # An online pool has all devices operating normally. A degraded pool is one in which one - # or more devices have failed, but the data is still available due to a redundant - # configuration. A faulted pool has corrupted metadata, or one or more faulted devices, and - # insufficient replicas to continue functioning. - shortstate = { - "DEGRADED": "DEG", - "FAULTED": "FLT", - "ONLINE": "ONL", - } - try: - return shortstate[status] - except KeyError: - return "" diff --git a/bumblebee/output.py b/bumblebee/output.py deleted file mode 100644 index 10c13e0..0000000 --- a/bumblebee/output.py +++ /dev/null @@ -1,324 +0,0 @@ -# pylint: disable=R0201 - -"""Output classes""" - -import sys -import json -import uuid -import logging - -import bumblebee.store -import bumblebee.util - -MAX_PERCENTS = 100. -CHARS = 8 -HBARS = [ - u"\u2581", - u"\u2582", - u"\u2583", - u"\u2584", - u"\u2585", - u"\u2586", - u"\u2587", - u"\u2588"] -VBARS = [ - u"\u258f", - u"\u258e", - u"\u258d", - u"\u258c", - u"\u258b", - u"\u258a", - u"\u2589", - u"\u2588"] - -log = logging.getLogger(__name__) - -def scrollable(func): - def wrapper(module, widget): - text = func(module, widget) - if not text: - return text - width = widget.get("theme.width", int(module.parameter("width", 30))) - if bumblebee.util.asbool(module.parameter("scrolling.makewide", "true")): - widget.set("theme.minwidth", "A"*width) - if width < 0: - return text - if len(text) <= width: - return text - # we need to shorten - - try: - bounce = int(module.parameter("scrolling.bounce", 1)) - except ValueError: - bounce = 1 - try: - scroll_speed = int(module.parameter("scrolling.speed", 1)) - except ValueError: - scroll_speed = 1 - start = widget.get("scrolling.start", -1) - direction = widget.get("scrolling.direction", "right") - start += scroll_speed if direction == "right" else -(scroll_speed) - - if width + start > len(text) + (scroll_speed -1): - if bounce: - widget.set("scrolling.direction", "left") - else: - start = 0 - elif start <= 0: - if bounce: - widget.set("scrolling.direction", "right") - else: - start = len(text) - widget.set("scrolling.start", start) - text = text[start:width+start] - - return text - return wrapper - - -class Bar(object): - """superclass""" - bars = None - - def __init__(self, value): - """ - Args: - - value (float): value between 0. and 100. meaning percents - """ - self.value = value - - -class HBar(Bar): - """horizontal bar (1 char)""" - bars = HBARS - - def __init__(self, value): - """ - Args: - - value (float): value between 0. and 100. meaning percents - """ - super(HBar, self).__init__(value) - self.step = MAX_PERCENTS / CHARS - - def get_char(self): - """ - Decide which char to draw - - Return: str - """ - for i in range(CHARS): - left = i * self.step - right = (i + 1) * self.step - if left <= self.value < right: - return self.bars[i] - return self.bars[-1] - - -def hbar(value): - """wrapper function""" - return HBar(value).get_char() - - -class VBar(Bar): - """vertical bar (can be more than 1 char)""" - bars = VBARS - - def __init__(self, value, width=1): - """ - Args: - - value (float): value between 0. and 100. meaning percents - - width (int): width - """ - super(VBar, self).__init__(value) - self.step = MAX_PERCENTS / (CHARS * width) - self.width = width - - def get_chars(self): - """ - Decide which char to draw - - Return: str - """ - if self.value == 100: - return self.bars[-1] * self.width - if self.width == 1: - for i in range(CHARS): - left = i * self.step - right = (i + 1) * self.step - if left <= self.value < right: - return self.bars[i] - else: - full_parts = int(self.value // (self.step * CHARS)) - remainder = self.value - full_parts * self.step * CHARS - empty_parts = self.width - full_parts - if remainder >= 0: - empty_parts -= 1 - part_vbar = VBar(remainder * self.width) # scale to width - chars = self.bars[-1] * full_parts - chars += part_vbar.get_chars() - chars += " " * empty_parts - return chars - - -def vbar(value, width): - """wrapper function""" - return VBar(value, width).get_chars() - - -class Widget(bumblebee.store.Store): - """Represents a single visible block in the status bar""" - def __init__(self, full_text="", name=""): - super(Widget, self).__init__() - self._full_text = full_text - self.module = None - self._module = None - self._minimized = False - self.name = name - self.id = str(uuid.uuid4()) - - def get_module(self): - return self._module - - def toggle_minimize(self): - self._minimized = not self._minimized - - def link_module(self, module): - """Set the module that spawned this widget - - This is done outside the constructor to avoid having to - pass in the module name in every concrete module implementation""" - self.module = module.name - self._module = module - - def cls(self): - if not self._module: - return None - return self._module.__module__.replace("bumblebee.modules.", "") - - def state(self): - """Return the widget's state""" - if self._module and hasattr(self._module, "state"): - states = self._module.state(self) - if not isinstance(states, list): - return [states] - return states - return [] - - def full_text(self, value=None): - """Set or retrieve the full text to display in the widget""" - if value: - self._full_text = value - else: - if self._minimized: - return u"\u2026" - if callable(self._full_text): - return self._full_text(self) - else: - return self._full_text - -class I3BarOutput(object): - """Manage output according to the i3bar protocol""" - def __init__(self, theme, config=None): - self._theme = theme - self._widgets = [] - self._started = False - self._config = config - - def started(self): - return self._started - - def start(self): - """Print start preamble for i3bar protocol""" - self._started = True - sys.stdout.write(json.dumps({"version": 1, "click_events": True}) + "\n[\n") - - def stop(self): - """Finish i3bar protocol""" - sys.stdout.write("]\n") - - 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 self._config.markup() == "pango": - # add prefix/suffix colors - fg = self._theme.prefix_fg(widget) - bg = self._theme.prefix_bg(widget) - prefix = "{}".format( - "foreground='{}'".format(fg) if fg else "", - "background='{}'".format(bg) if bg else "", - prefix - ) - - 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: - self._widgets.append({ - u"full_text": separator, - "separator": False, - "color": self._theme.separator_fg(widget), - "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)) - - markup = "none" if not self._config else self._config.markup() - - if markup == "pango": - full_text = full_text.replace("&", "&") - - 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, - "markup": markup, - }) - - def begin(self): - """Start one output iteration""" - self._widgets = [] - self._theme.reset() - - def flush(self): - """Flushes output""" - widgets = self._widgets - if self._config and self._config.reverse(): - widgets = list(reversed(widgets)) - sys.stdout.write(json.dumps(widgets)) - if len(self._config.unused_keys()) > 0: - for key in self._config.unused_keys(): - log.warning("unused parameter {} - please check the documentation of the affected module to ensure the parameter exists".format(key)) - - def end(self): - """Finalizes output""" - sys.stdout.write(",\n") - sys.stdout.flush() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/popup.py b/bumblebee/popup.py deleted file mode 100644 index 46d6a30..0000000 --- a/bumblebee/popup.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Pop-up menus.""" - -import logging - -try: - import Tkinter as tk -except ImportError: - # python 3 - try: - import tkinter as tk - except ImportError: - logging.warning("failed to import tkinter - bumblebee popups won't work!") - -class PopupMenu: - """The popup-menu.""" - - def __init__(self): - """Initialize.""" - # menu widget - self.root = tk.Tk() - self.root.withdraw() - self.menu = tk.Menu(self.root) - - # internal state - self._item_count = 0 - self._clicked_item = None - self._active = False - - # bind event of popup getting closed by clicking outside of its area - self.menu.bind('', - lambda event: self.root.after_idle( - self._dismiss_callback)) - - def add_menuitem(self, menuitem, callback=None): - """Add menu items.""" - item_count = self._item_count - - def click_callback(): - # call internal callback with item index - self._item_callback(item_count) - - # default to internal callback - if callback is None: - callback = click_callback - self.menu.add_command(label=menuitem, - command=callback) - - # track item index - self._item_count += 1 - - def _item_callback(self, which_item): - """Menu item click callback.""" - logging.debug('popup: item callback: {}'.format(which_item)) - self._clicked_item = which_item - self.root.destroy() - self._active = False - - def _dismiss_callback(self): - """Menu dismissed.""" - logging.debug('popup: menu dismissed') - if self._active is True: - self._clicked_item = None - self.root.destroy() - - def show(self, event): - """Show popup.""" - self._clicked_item = None - self.menu.tk_popup(event['x'], event['y']-50) - self._active = True - self.root.mainloop() - return self._clicked_item - - -def create_and_show_menu(event, *menuitems): - """Create a menu object and show.""" - menu_obj = PopupMenu() - for menuitem in menuitems: - menu_obj.add_menuitem(*menuitem) - - return menu_obj.show(event) diff --git a/bumblebee/popup_v2.py b/bumblebee/popup_v2.py deleted file mode 100644 index 4d08c73..0000000 --- a/bumblebee/popup_v2.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Pop-up menus.""" - -import logging - -try: - import Tkinter as tk -except ImportError: - # python 3 - try: - import tkinter as tk - except ImportError: - logging.warning("failed to import tkinter - bumblebee popups won't work!") - -import functools - -class PopupMenu(object): - def __init__(self, parent=None, leave=True): - - if not parent: - self._root = tk.Tk() - self._root.withdraw() - self._menu = tk.Menu(self._root, tearoff=0) - self._menu.bind("", self._on_focus_out) - else: - self._root = parent.root() - self._root.withdraw() - self._menu = tk.Menu(self._root, tearoff=0) - self._menu.bind("", self._on_focus_out) - if leave: - self._menu.bind("", self._on_focus_out) - - def root(self): - return self._root - - def menu(self): - return self._menu - - def _on_focus_out(self, event=None): - self._root.destroy() - - def _on_click(self, callback): - self._root.destroy() - callback() - - def add_cascade(self, menuitem, submenu): - self._menu.add_cascade(label=menuitem, menu=submenu.menu()) - - def add_menuitem(self, menuitem, callback): - self._menu.add_command(label=menuitem, command=functools.partial(self._on_click, callback)) - - def show(self, event, offset_x=0, offset_y=0): - try: - self._menu.tk_popup(event['x'] + offset_x, event['y'] + offset_y) - finally: - self._menu.grab_release() - self._root.mainloop() diff --git a/bumblebee/store.py b/bumblebee/store.py deleted file mode 100644 index 6b35347..0000000 --- a/bumblebee/store.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Store interface - -Allows arbitrary classes to offer a simple get/set -store interface by deriving from the Store class in -this module -""" - -class Store(object): - """Interface for storing and retrieving simple values""" - def __init__(self): - self._data = {} - self._unused = {} - - def set(self, key, value): - """Set 'key' to 'value', overwriting 'key' if it exists already""" - self._data[key] = value - self._unused[key] = value - - def unused_keys(self): - return self._unused.keys() - - def get(self, key, default=None): - """Return the current value of 'key', or 'default' if 'key' is not set""" - self._unused.pop(key, None) - return self._data.get(key, default) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/theme.py b/bumblebee/theme.py deleted file mode 100644 index 2b52f73..0000000 --- a/bumblebee/theme.py +++ /dev/null @@ -1,310 +0,0 @@ -# pylint: disable=C0103 - -"""Theme support""" - -import os -import glob -import copy -import json -import io -import re -import logging - -try: - import requests - from requests.exceptions import RequestException -except ImportError: - pass - -import bumblebee.error - -def theme_path(): - """Return the path of the theme directory""" - return [ - os.path.dirname("{}/../themes/".format(os.path.dirname(os.path.realpath(__file__)))), - os.path.dirname(os.path.expanduser("~/.config/bumblebee-status/themes/")), - ] - -def themes(): - themes = {} - - for path in theme_path(): - for filename in glob.iglob("{}/*.json".format(path)): - if "test" not in filename: - themes[os.path.basename(filename).replace(".json", "")] = 1 - result = list(themes.keys()) - result.sort() - return result - -class Theme(object): - """Represents a collection of icons and colors""" - def __init__(self, name, iconset="auto"): - self._widget = None - self._cycle_idx = 0 - self._cycle = {} - self._prevbg = None - self._colorset = {} - self._iconset = iconset - - self.load_symbols() - - data = self.load(name) - if not data: - raise bumblebee.error.ThemeLoadError("no such theme") - self._init(data) - - def load_symbols(self): - self._symbols = {} - path = os.path.expanduser("~/.config/bumblebee-status/") - try: - os.makedirs(path) - except Exception: - pass - try: - if os.path.exists("{}/symbols.json".format(path)): - data = json.load(io.open("{}/symbols.json".format(path))) - self._symbols = {} - for icon in data["icons"]: - code = int(icon["unicode"], 16) - try: - code = unichr(code) - except Exception: - code = chr(code) - self._symbols["${{{}}}".format(icon["id"])] = code - self._symbols["${{{}}}".format(icon["name"])] = code - except Exception as e: - logging.error("failed to load symbols: {}".format(str(e))) - - def _init(self, data): - """Initialize theme from data structure""" - self._theme = data - if self._iconset != "auto": - self._merge(data, self._load_icons(self._iconset)) - else: - for iconset in data.get("icons", []): - self._merge(data, self._load_icons(iconset)) - for colorset in data.get("colors", []): - self._merge(self._colorset, self._load_colors(colorset)) - self._defaults = data.get("defaults", {}) - self._cycles = self._theme.get("cycle", []) - self.reset() - - def data(self): - """Return the raw theme data""" - return self._theme - - def reset(self): - """Reset theme to initial state""" - self._cycle = self._cycles[0] if len(self._cycles) > 0 else {} - self._cycle_idx = 0 - self._widget = None - self._prevbg = None - - def icon(self, widget): - icon = self._get(widget, "icon", None) - if icon is None: - return self._get(widget, "prefix", None) - - def get(self, widget, attribute, default_value=""): - return self._get(widget, attribute, default_value) - - def padding(self, widget): - """Return padding for widget""" - return self._get(widget, "padding", "") - - def prefix(self, widget, default=None): - """Return the theme prefix for a widget's full text""" - padding = self.padding(widget) - pre = self._get(widget, "prefix", None) - return u"{}{}{}".format(padding, pre, padding) if pre else default - - def prefix_fg(self, widget): - """Return the foreground color for the prefix""" - return self._get(widget, "prefixfg", None) - - def prefix_bg(self, widget): - """Return the background color for the prefix""" - return self._get(widget, "prefixbg", None) - - def suffix_fg(self, widget): - """Return the foreground color for the suffix""" - return self._get(widget, "suffixfg", None) - - def suffix_bg(self, widget): - """Return the background color for the suffix""" - return self._get(widget, "suffixbg", None) - - def symbol(self, widget, name, default=None): - return self._get(widget, name, default) - - def suffix(self, widget, default=None): - """Return the theme suffix for a widget's full text""" - padding = self._get(widget, "padding", "") - suf = self._get(widget, "suffix", None) - return u"{}{}{}".format(padding, suf, padding) if suf else default - - def fg(self, widget): - """Return the foreground color for this widget""" - return self._get(widget, "fg", None) - - def bg(self, widget): - """Return the background color for this widget""" - return self._get(widget, "bg", None) - - def align(self, widget): - """Return the widget alignment""" - return self._get(widget, "align", None) - - def minwidth(self, widget): - """Return the minimum width string for this widget""" - return self._get(widget, "minwidth", "") - - def separator(self, widget): - """Return the separator between widgets""" - return self._get(widget, "separator", None) - - def separator_fg(self, widget): - """Return the separator's foreground/text color""" - return self.bg(widget) - - def separator_bg(self, widget): - """Return the separator's background color""" - return self._prevbg - - def separator_block_width(self, widget): - """Return the SBW""" - return self._get(widget, "separator-block-width", None) - - def _load_wal_colors(self): - walfile = os.path.expanduser("~/.cache/wal/colors.json") - result = {} - with io.open(walfile) as data: - colors = json.load(data) - for field in ["special", "colors"]: - for key in colors[field]: - result[key] = colors[field][key] - return result - - def _load_colors(self, name): - """Load colors for a theme""" - try: - if name == "wal": - return self._load_wal_colors() - except Exception as e: - logging.error("failed to load colors: {}".format(str(e))) - - def _load_icons(self, name): - """Load icons for a theme""" - result = {} - for path in theme_path(): - self._merge(result, self.load(name, path="{}/icons/".format(path))) - - return self._replace_symbols(result) - - def _replace_symbols(self, data): - rep = json.dumps(data) - tokens = re.findall(r"\${[^}]+}", rep) - for token in tokens: - rep = rep.replace(token, self._symbols[token]) - return json.loads(rep) - - def load(self, name, path=theme_path()): - """Load and parse a theme file""" - result = None - - full_name = os.path.expanduser(name) - if os.path.isfile(full_name): - path = os.path.dirname(full_name) - name = os.path.basename(full_name) - name,_,_ = name.rpartition(".json") - return self.load(name, path) - - if not isinstance(path, list): - path = [path] - for p in path: - themefile = "{}/{}.json".format(p, name) - - if os.path.isfile(themefile): - try: - with io.open(themefile, encoding="utf-8") as data: - if result is None: - result = json.load(data) - else: - self._merge(result, json.load(data)) - except ValueError as exception: - raise bumblebee.error.ThemeLoadError("JSON error: {}".format(exception)) - - return result - - def _get(self, widget, name, default=None): - """Return the config value 'name' for 'widget'""" - - if not self._widget: - self._widget = widget - - if name in bumblebee.util.aslist(self._widget.get("theme.exclude", "")): - return None - - if self._widget != widget: - self._prevbg = self.bg(self._widget) - self._widget = widget - if len(self._cycles) > 0: - self._cycle_idx = (self._cycle_idx + 1) % len(self._cycles) - self._cycle = self._cycles[self._cycle_idx] - - module_theme = self._theme.get(widget.module, {}) - class_theme = self._theme.get(widget.cls(), {}) - - state_themes = [] - # avoid infinite recursion - states = widget.state() - if name not in states: - for state in states: - if state: - state_themes.append(self._get(widget, state, {})) - - value = self._defaults.get(name, default) - value = widget.get("theme.{}".format(name), value) - value = self._cycle.get(name, value) - value = class_theme.get(name, value) - value = module_theme.get(name, value) - - for theme in state_themes: - value = theme.get(name, value) - - if isinstance(value, list): - key = "{}-idx".format(name) - idx = widget.get(key, 0) - widget.set(key, (idx + 1) % len(value)) - value = value[idx] - - mod = widget.get_module() - if mod and not mod.parameter("is-unittest"): - value = widget.get_module().parameter("theme.{}".format(name), value) - - if isinstance(value, list) or isinstance(value, dict): - return value - return self._colorset.get(value, value) - - # algorithm copied from - # http://blog.impressiver.com/post/31434674390/deep-merge-multiple-python-dicts - # nicely done :) - def _merge(self, target, *args): - """Merge two arbitrarily nested data structures""" - if len(args) > 1: - for item in args: - self._merge(item) - return target - - item = args[0] - if not isinstance(item, dict): - return item - for key, value in item.items(): - if key in target and isinstance(target[key], dict): - self._merge(target[key], value) - else: - if not key in target: - target[key] = copy.deepcopy(value) - return target - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/util.py b/bumblebee/util.py deleted file mode 100644 index 5f4ae44..0000000 --- a/bumblebee/util.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- - -import shlex -import logging -import subprocess - -try: - from exceptions import RuntimeError -except ImportError: - # Python3 doesn't require this anymore - pass - - -def asbool(val): - if val is None: - return False - if isinstance(val, bool): - return val - val = str(val).strip().lower() - return val in ("t", "true", "y", "yes", "on", "1") - -def aslist(val): - if val is None: - return [] - if isinstance(val, list): - return val - return str(val).replace(' ', '').split(',') - -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 - - if wait: - out, _ = proc.communicate() - if proc.returncode != 0: - raise RuntimeError("{} exited with {}".format(cmd, proc.returncode)) - - if hasattr(out, "decode"): - rv = out.decode("utf-8", "ignore") - else: - rv = out - - logging.info(u"command returned '{}'".format("" if not rv else rv)) - return rv - -def bytefmt(num, fmt="{:.2f}"): - """ - format a value of bytes to a more human readable pattern - example: 15 * 1024 becomes 15KiB - - Args: - - num (int): bytes - - fmt (string): format - - Return: string - """ - for unit in ["", "Ki", "Mi", "Gi"]: - if num < 1024.0: - return "{}{}B".format(fmt, unit).format(num) - num /= 1024.0 - return "{}GiB".format(fmt).format(num*1024.0) - -def durationfmt(duration, shorten=False, suffix=False): - duration = int(duration) - minutes, seconds = divmod(duration, 60) - hours, minutes = divmod(minutes, 60) - suf = "m" - res = "{:02d}:{:02d}".format(minutes, seconds) - if hours > 0: - if shorten: - res = "{:02d}:{:02d}".format(hours, minutes) - else: - res = "{:02d}:{}".format(hours, res) - suf = "h" - - return "{}{}".format(res, suf if suffix else "") - -def which(program): - import os - def is_exe(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - - fpath, fname = os.path.split(program) - if fpath: - if is_exe(program): - return program - else: - localPATH = os.environ["PATH"].split(os.pathsep) - localPATH += ["/sbin", "/usr/sbin/", "/usr/local/sbin"] - for path in localPATH: - exe_file = os.path.join(path, program) - if is_exe(exe_file): - return exe_file - - return None - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/core/output.py b/core/output.py new file mode 100644 index 0000000..c0355c9 --- /dev/null +++ b/core/output.py @@ -0,0 +1,16 @@ +import json + +class i3(object): + def start(self): + return '{}\n'.format(json.dumps({ 'version': 1, 'click_events': True })) + + def stop(self): + return ']\n' + + def begin_status_line(self): + return '[' + + def end_status_line(self): + return '],\n' + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/runlint.sh b/runlint.sh deleted file mode 100755 index 6902ce9..0000000 --- a/runlint.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -find . -name "*.py"|xargs pylint --disable=R0903,R0201,C0330 diff --git a/runtests.sh b/runtests.sh deleted file mode 100755 index 549eb4a..0000000 --- a/runtests.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -echo "testing with $(python2 -V 2>&1)" -python2 $(which nosetests) -v --with-coverage --cover-erase tests/ - -if test $? -eq 0 ; then - echo - - echo "testing with $(python3 -V 2>&1)" - python3 $(which nosetests) -v --with-coverage --cover-erase tests/ -fi diff --git a/screenshots/amixer.png b/screenshots/amixer.png deleted file mode 100644 index 0da57c5..0000000 Binary files a/screenshots/amixer.png and /dev/null differ diff --git a/screenshots/battery.png b/screenshots/battery.png deleted file mode 100644 index bdbafee..0000000 Binary files a/screenshots/battery.png and /dev/null differ diff --git a/screenshots/bluetooth.png b/screenshots/bluetooth.png deleted file mode 100644 index 3a9ddff..0000000 Binary files a/screenshots/bluetooth.png and /dev/null differ diff --git a/screenshots/brightness.png b/screenshots/brightness.png deleted file mode 100644 index 298abf3..0000000 Binary files a/screenshots/brightness.png and /dev/null differ diff --git a/screenshots/caffeine.png b/screenshots/caffeine.png deleted file mode 100644 index 5444777..0000000 Binary files a/screenshots/caffeine.png and /dev/null differ diff --git a/screenshots/cmus.png b/screenshots/cmus.png deleted file mode 100644 index 52c0b51..0000000 Binary files a/screenshots/cmus.png and /dev/null differ diff --git a/screenshots/cpu.png b/screenshots/cpu.png deleted file mode 100644 index 0b5527c..0000000 Binary files a/screenshots/cpu.png and /dev/null differ diff --git a/screenshots/currency.png b/screenshots/currency.png deleted file mode 100644 index ffcc549..0000000 Binary files a/screenshots/currency.png and /dev/null differ diff --git a/screenshots/date.png b/screenshots/date.png deleted file mode 100644 index 36621e7..0000000 Binary files a/screenshots/date.png and /dev/null differ diff --git a/screenshots/datetime.png b/screenshots/datetime.png deleted file mode 100644 index 0c15843..0000000 Binary files a/screenshots/datetime.png and /dev/null differ diff --git a/screenshots/datetimetz.gif b/screenshots/datetimetz.gif deleted file mode 100644 index ae926eb..0000000 Binary files a/screenshots/datetimetz.gif and /dev/null differ diff --git a/screenshots/disk.png b/screenshots/disk.png deleted file mode 100644 index 7a659b8..0000000 Binary files a/screenshots/disk.png and /dev/null differ diff --git a/screenshots/dnf.png b/screenshots/dnf.png deleted file mode 100644 index 4992416..0000000 Binary files a/screenshots/dnf.png and /dev/null differ diff --git a/screenshots/dunst.png b/screenshots/dunst.png deleted file mode 100644 index 1932b4d..0000000 Binary files a/screenshots/dunst.png and /dev/null differ diff --git a/screenshots/getcrypto.png b/screenshots/getcrypto.png deleted file mode 100644 index e3cd95e..0000000 Binary files a/screenshots/getcrypto.png and /dev/null differ diff --git a/screenshots/git.png b/screenshots/git.png deleted file mode 100644 index 69f786b..0000000 Binary files a/screenshots/git.png and /dev/null differ diff --git a/screenshots/github.png b/screenshots/github.png deleted file mode 100644 index fb573b7..0000000 Binary files a/screenshots/github.png and /dev/null differ diff --git a/screenshots/http_status.png b/screenshots/http_status.png deleted file mode 100644 index 5a72719..0000000 Binary files a/screenshots/http_status.png and /dev/null differ diff --git a/screenshots/indicator.png b/screenshots/indicator.png deleted file mode 100644 index e7d0382..0000000 Binary files a/screenshots/indicator.png and /dev/null differ diff --git a/screenshots/kernel.png b/screenshots/kernel.png deleted file mode 100644 index 9d20cdc..0000000 Binary files a/screenshots/kernel.png and /dev/null differ diff --git a/screenshots/layout.png b/screenshots/layout.png deleted file mode 100644 index d09250e..0000000 Binary files a/screenshots/layout.png and /dev/null differ diff --git a/screenshots/load.png b/screenshots/load.png deleted file mode 100644 index e136e7e..0000000 Binary files a/screenshots/load.png and /dev/null differ diff --git a/screenshots/memory.png b/screenshots/memory.png deleted file mode 100644 index db0c59b..0000000 Binary files a/screenshots/memory.png and /dev/null differ diff --git a/screenshots/mpd.png b/screenshots/mpd.png deleted file mode 100644 index a332b00..0000000 Binary files a/screenshots/mpd.png and /dev/null differ diff --git a/screenshots/network_traffic.gif b/screenshots/network_traffic.gif deleted file mode 100644 index 2cc0144..0000000 Binary files a/screenshots/network_traffic.gif and /dev/null differ diff --git a/screenshots/nic.png b/screenshots/nic.png deleted file mode 100644 index d1512c0..0000000 Binary files a/screenshots/nic.png and /dev/null differ diff --git a/screenshots/pacman.png b/screenshots/pacman.png deleted file mode 100644 index 8f4169e..0000000 Binary files a/screenshots/pacman.png and /dev/null differ diff --git a/screenshots/pasink.png b/screenshots/pasink.png deleted file mode 100644 index 2fd6359..0000000 Binary files a/screenshots/pasink.png and /dev/null differ diff --git a/screenshots/pasource.png b/screenshots/pasource.png deleted file mode 100644 index ae2ee77..0000000 Binary files a/screenshots/pasource.png and /dev/null differ diff --git a/screenshots/ping.png b/screenshots/ping.png deleted file mode 100644 index 1c8bf2b..0000000 Binary files a/screenshots/ping.png and /dev/null differ diff --git a/screenshots/pulseaudio.png b/screenshots/pulseaudio.png deleted file mode 100644 index b38a4aa..0000000 Binary files a/screenshots/pulseaudio.png and /dev/null differ diff --git a/screenshots/redshift.png b/screenshots/redshift.png deleted file mode 100644 index 999328f..0000000 Binary files a/screenshots/redshift.png and /dev/null differ diff --git a/screenshots/sensors.png b/screenshots/sensors.png deleted file mode 100644 index 69d2554..0000000 Binary files a/screenshots/sensors.png and /dev/null differ diff --git a/screenshots/sensors2.png b/screenshots/sensors2.png deleted file mode 100644 index f2840d2..0000000 Binary files a/screenshots/sensors2.png and /dev/null differ diff --git a/screenshots/shortcut.png b/screenshots/shortcut.png deleted file mode 100644 index 96bce8c..0000000 Binary files a/screenshots/shortcut.png and /dev/null differ diff --git a/screenshots/spacer.png b/screenshots/spacer.png deleted file mode 100644 index 5200d0f..0000000 Binary files a/screenshots/spacer.png and /dev/null differ diff --git a/screenshots/spotify.png b/screenshots/spotify.png deleted file mode 100644 index d51ca22..0000000 Binary files a/screenshots/spotify.png and /dev/null differ diff --git a/screenshots/stock.png b/screenshots/stock.png deleted file mode 100644 index 427f7cf..0000000 Binary files a/screenshots/stock.png and /dev/null differ diff --git a/screenshots/taskwarrior.png b/screenshots/taskwarrior.png deleted file mode 100644 index 6f20147..0000000 Binary files a/screenshots/taskwarrior.png and /dev/null differ diff --git a/screenshots/themes/default.png b/screenshots/themes/default.png deleted file mode 100644 index c2680bd..0000000 Binary files a/screenshots/themes/default.png and /dev/null differ diff --git a/screenshots/themes/dracula-powerline.png b/screenshots/themes/dracula-powerline.png deleted file mode 100644 index 4898587..0000000 Binary files a/screenshots/themes/dracula-powerline.png and /dev/null differ diff --git a/screenshots/themes/gruvbox-light.png b/screenshots/themes/gruvbox-light.png deleted file mode 100644 index 272fd9d..0000000 Binary files a/screenshots/themes/gruvbox-light.png and /dev/null differ diff --git a/screenshots/themes/gruvbox-powerline-light.png b/screenshots/themes/gruvbox-powerline-light.png deleted file mode 100644 index d1e8bf7..0000000 Binary files a/screenshots/themes/gruvbox-powerline-light.png and /dev/null differ diff --git a/screenshots/themes/gruvbox.png b/screenshots/themes/gruvbox.png deleted file mode 100644 index 2f2c385..0000000 Binary files a/screenshots/themes/gruvbox.png and /dev/null differ diff --git a/screenshots/themes/iceberg-dark-powerline.png b/screenshots/themes/iceberg-dark-powerline.png deleted file mode 100644 index fa64e75..0000000 Binary files a/screenshots/themes/iceberg-dark-powerline.png and /dev/null differ diff --git a/screenshots/themes/iceberg-powerline.png b/screenshots/themes/iceberg-powerline.png deleted file mode 100644 index aa94b06..0000000 Binary files a/screenshots/themes/iceberg-powerline.png and /dev/null differ diff --git a/screenshots/themes/iceberg-rainbow.png b/screenshots/themes/iceberg-rainbow.png deleted file mode 100644 index 763739b..0000000 Binary files a/screenshots/themes/iceberg-rainbow.png and /dev/null differ diff --git a/screenshots/themes/iceberg.png b/screenshots/themes/iceberg.png deleted file mode 100644 index 36ca0db..0000000 Binary files a/screenshots/themes/iceberg.png and /dev/null differ diff --git a/screenshots/themes/onedark-powerline.png b/screenshots/themes/onedark-powerline.png deleted file mode 100644 index e38d8fa..0000000 Binary files a/screenshots/themes/onedark-powerline.png and /dev/null differ diff --git a/screenshots/themes/powerline-greyish.png b/screenshots/themes/powerline-greyish.png deleted file mode 100644 index 3064822..0000000 Binary files a/screenshots/themes/powerline-greyish.png and /dev/null differ diff --git a/screenshots/themes/powerline-gruvbox.png b/screenshots/themes/powerline-gruvbox.png deleted file mode 100644 index 5b80ff3..0000000 Binary files a/screenshots/themes/powerline-gruvbox.png and /dev/null differ diff --git a/screenshots/themes/powerline-solarized.png b/screenshots/themes/powerline-solarized.png deleted file mode 100644 index 5be0b16..0000000 Binary files a/screenshots/themes/powerline-solarized.png and /dev/null differ diff --git a/screenshots/themes/powerline.png b/screenshots/themes/powerline.png deleted file mode 100644 index 1bd551a..0000000 Binary files a/screenshots/themes/powerline.png and /dev/null differ diff --git a/screenshots/themes/solarized.png b/screenshots/themes/solarized.png deleted file mode 100644 index a15d08c..0000000 Binary files a/screenshots/themes/solarized.png and /dev/null differ diff --git a/screenshots/time.png b/screenshots/time.png deleted file mode 100644 index 39d5210..0000000 Binary files a/screenshots/time.png and /dev/null differ diff --git a/screenshots/title.png b/screenshots/title.png deleted file mode 100644 index 1089a0b..0000000 Binary files a/screenshots/title.png and /dev/null differ diff --git a/screenshots/todo.png b/screenshots/todo.png deleted file mode 100644 index 87b6bfc..0000000 Binary files a/screenshots/todo.png and /dev/null differ diff --git a/screenshots/traffic.png b/screenshots/traffic.png deleted file mode 100644 index bcb27da..0000000 Binary files a/screenshots/traffic.png and /dev/null differ diff --git a/screenshots/uptime.png b/screenshots/uptime.png deleted file mode 100644 index 489b212..0000000 Binary files a/screenshots/uptime.png and /dev/null differ diff --git a/screenshots/vault.png b/screenshots/vault.png deleted file mode 100644 index be9d1b7..0000000 Binary files a/screenshots/vault.png and /dev/null differ diff --git a/screenshots/weather.png b/screenshots/weather.png deleted file mode 100644 index 1efee83..0000000 Binary files a/screenshots/weather.png and /dev/null differ diff --git a/screenshots/xrandr.png b/screenshots/xrandr.png deleted file mode 100644 index ec1c6de..0000000 Binary files a/screenshots/xrandr.png and /dev/null differ diff --git a/screenshots/zpool.png b/screenshots/zpool.png deleted file mode 100644 index c88bc0f..0000000 Binary files a/screenshots/zpool.png and /dev/null differ diff --git a/testjson.sh b/testjson.sh deleted file mode 100755 index 28e65a9..0000000 --- a/testjson.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -find themes/ -name "*.json"|grep -v invalid| -while read f; do - cat "$f" | json_verify 2>&1 > /dev/null | sed "1 s@\(.*error\)@\nError in $f\n\1@g" -done diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/mocks.py b/tests/mocks.py deleted file mode 100644 index 38f1583..0000000 --- a/tests/mocks.py +++ /dev/null @@ -1,141 +0,0 @@ -# pylint: disable=C0103,C0111 - -import mock -import json -import shlex -import random -import subprocess - -from bumblebee.input import I3BarInput -from bumblebee.output import Widget -from bumblebee.config import Config - -def rand(cnt): - return "".join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for i in range(cnt)) - -def setup_test(test, Module): - test._stdin, test._select, test.stdin, test.select = poll_mock("bumblebee.input") - - test.popen = MockPopen() - - test.config = Config() - test.input = I3BarInput() - test.engine = mock.Mock() - test.engine.input = test.input - test.input.need_event = True - test.module = Module(engine=test.engine, config={ "config": test.config }) - for widget in test.module.widgets(): - widget.link_module(test.module) - test.anyWidget = widget - -def teardown_test(test): - test._stdin.stop() - test._select.stop() - test.popen.cleanup() - -def poll_mock(module=""): - if len(module) > 0: module = "{}.".format(module) - - stdin = mock.patch("{}sys.stdin".format(module)) - select = mock.patch("{}select".format(module)) - poll = mock.Mock() - - stdin_mock = stdin.start() - select_mock = select.start() - - stdin_mock.fileno.return_value = 1 - select_mock.poll.return_value = poll - poll.poll.return_value = [(stdin_mock.fileno.return_value, 100)] - - return stdin, select, stdin_mock, select_mock - -def mouseEvent(stdin, button, inp, module=None, instance=None): - stdin.readline.return_value = json.dumps({ - "name": module.id if module else rand(10), - "button": button, - "instance": instance - }) - inp.start() - inp.stop() - stdin.readline.assert_any_call() - -class MockPopen(object): - def __init__(self, module=""): - if len(module) > 0: module = "{}.".format(module) - self._patch = mock.patch("{}subprocess.Popen".format(module)) - self._popen = self._patch.start() - self.mock = mock.Mock() - # for a nicer, more uniform interface - self.mock.popen = self._popen - # for easier command execution checks - self.mock.popen.assert_call = self.assert_call - self._popen.return_value = self.mock - - self.mock.communicate.return_value = [ "", None ] - self.mock.returncode = 0 - - def assert_call(self, cmd): - self.mock.popen.assert_any_call(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - - def cleanup(self): - self._patch.stop() - -class MockInput(object): - def __init__(self): - self._callbacks = {} - def start(self): - pass - - def stop(self): - pass - - def get_callback(self, uid): - return self._callbacks.get(uid, None) - - def register_callback(self, obj, button, cmd): - if not obj: - return - self._callbacks[obj.id] = { - "button": button, - "command": cmd, - } - -class MockOutput(object): - def start(self): - pass - - def stop(self): - pass - - def draw(self, widget, engine, module): - engine.stop() - - def begin(self): - pass - - def flush(self): - pass - - def end(self): - pass - -class MockEngine(object): - def __init__(self): - self.input = MockInput() - -class MockWidget(Widget): - def __init__(self, text): - super(MockWidget, self).__init__(text) - self.module = None - self.attr_state = ["state-default"] - self.id = rand(10) - - self.full_text(text) - -# def state(self): -# return self.attr_state - - def update(self, widgets): - pass - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/__init__.py b/tests/modules/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/modules/test_battery.py b/tests/modules/test_battery.py deleted file mode 100644 index 6d0ec0a..0000000 --- a/tests/modules/test_battery.py +++ /dev/null @@ -1,109 +0,0 @@ -# pylint: disable=C0103,C0111 - -import sys -import mock -import unittest - -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -import tests.mocks as mocks - -from bumblebee.modules.battery import Module -from bumblebee.config import Config - -class TestBatteryModule(unittest.TestCase): - def setUp(self): - self._stdout = mock.patch("sys.stdout", new_callable=StringIO) - self._exists = mock.patch("bumblebee.modules.battery.os.path.exists") - self._open = mock.patch("bumblebee.modules.battery.open", create=True) - - self.stdout = self._stdout.start() - self.exists = self._exists.start() - self.open = self._open.start() - self.file = mock.Mock() - self.file.__enter__ = lambda x: self.file - self.file.__exit__ = lambda x, a, b, c: "" - self.file.read.return_value = "120" - self.open.return_value = self.file - - self.exists.return_value = True - self.engine = mock.Mock() - self.config = Config() - self.config.set("battery.showremaining", "false") - self.module = Module(engine=self.engine, config={"config":self.config}) - - self.config.set("battery.critical", "20") - self.config.set("battery.warning", "25") - self.criticalValue = "19" - self.warningValue = "21" - self.normalValue = "26" - self.chargedValue = "96" - - self.module.widgets()[0] - - def tearDown(self): - self._stdout.stop() - self._exists.stop() - self._open.stop() - - def test_format(self): - for widget in self.module.widgets(): - self.assertEquals(len(widget.full_text()), len("100%")) - - def test_critical(self): - self.file.read.return_value = self.criticalValue - self.module.update_all() - self.assertTrue("critical" in self.module.state(self.module.widgets()[0])) - - def test_warning(self): - self.file.read.return_value = self.warningValue - self.module.update_all() - self.assertTrue("warning" in self.module.state(self.module.widgets()[0])) - - def test_normal(self): - self.file.read.return_value = self.normalValue - self.module.update_all() - self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0])) - self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0])) - - def test_overload(self): - self.file.read.return_value = "120" - self.module.update_all() - self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0])) - self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0])) - self.assertEquals(self.module.capacity(self.module.widgets()[0]), "100%") - - def test_ac(self): - self.exists.return_value = False - self.file.read.return_value = "120" - self.module.update_all() - self.assertEquals(self.module.capacity(self.module.widgets()[0]), "ac") - self.assertTrue("AC" in self.module.state(self.module.widgets()[0])) - - def test_error(self): - self.file.read.side_effect = IOError("failed to read") - self.module.update_all() - self.assertEquals(self.module.capacity(self.module.widgets()[0]), "n/a") - self.assertTrue("critical" in self.module.state(self.module.widgets()[0])) - self.assertTrue("unknown" in self.module.state(self.module.widgets()[0])) - - def test_charging(self): - self.file.read.return_value = self.chargedValue - self.module.update_all() - self.assertTrue("charged" in self.module.state(self.module.widgets()[0])) - self.file.read.return_value = self.normalValue - self.module.update_all() - self.assertTrue("charging" in self.module.state(self.module.widgets()[0])) - - def test_discharging(self): - for limit in [ 10, 25, 50, 80, 100 ]: - value = limit - 1 - self.file.read.return_value = str(value) - self.module.update_all() - self.file.read.return_value = "Discharging" - self.assertTrue("discharging-{}".format(limit) in self.module.state(self.module.widgets()[0])) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_brightness.py b/tests/modules/test_brightness.py deleted file mode 100644 index 54cc253..0000000 --- a/tests/modules/test_brightness.py +++ /dev/null @@ -1,69 +0,0 @@ -# pylint: disable=C0103,C0111 - -import mock -import unittest - -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -try: - FileNotFoundError -except NameError: - FileNotFoundError = IOError - -import tests.mocks as mocks - -import bumblebee.util -from bumblebee.config import Config -from bumblebee.input import WHEEL_UP, WHEEL_DOWN -from bumblebee.modules.brightness import Module - -class TestBrightnessModule(unittest.TestCase): - def setUp(self): - mocks.setup_test(self, Module) - self.tool = "" - self.up = "" - self.down = "" - if bumblebee.util.which("light"): - self.tool = "light" - self.up = "-A {}%" - self.down = "-U {}%" - elif bumblebee.util.which("brightnessctl"): - self.tool = "brightnessctl" - self.up = "s {}%+" - self.down = "s {}%-" - else: - self.tool = "xbacklight" - self.up = "+{}%" - self.down = "-{}%" - - def tearDown(self): - mocks.teardown_test(self) - - # def test_format(self): - # for widget in self.module.widgets(): - # self.assertEquals(len(widget.full_text()), len("100%")) - - def test_wheel_up(self): - mocks.mouseEvent(stdin=self.stdin, button=WHEEL_UP, inp=self.input, module=self.module) - self.popen.assert_call("{} {}".format(self.tool, self.up.format(2))) - - def test_wheel_down(self): - mocks.mouseEvent(stdin=self.stdin, button=WHEEL_DOWN, inp=self.input, module=self.module) - self.popen.assert_call("{} {}".format(self.tool, self.down.format(2))) - - def test_custom_step(self): - self.config.set("brightness.step", "10") - module = Module(engine=self.engine, config={"config": self.config}) - mocks.mouseEvent(stdin=self.stdin, button=WHEEL_DOWN, inp=self.input, module=module) - self.popen.assert_call("{} {}".format(self.tool, self.down.format(10))) - - @mock.patch('bumblebee.modules.brightness.open', create=True) - def test_error(self,mock_open): - mock_open.side_effect = FileNotFoundError - self.module.update_all() - self.assertEquals(self.module.brightness(self.anyWidget), "n/a") - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_caffeine.py b/tests/modules/test_caffeine.py deleted file mode 100644 index ad0cf00..0000000 --- a/tests/modules/test_caffeine.py +++ /dev/null @@ -1,50 +0,0 @@ -# pylint: disable=C0103,C0111 - -import unittest -from mock import patch -import tests.mocks as mocks - -from bumblebee.input import LEFT_MOUSE -from bumblebee.modules.caffeine import Module - -class TestCaffeineModule(unittest.TestCase): - def setUp(self): - mocks.setup_test(self, Module) - - def tearDown(self): - mocks.teardown_test(self) - - def test_check_requirements(self): - with patch('bumblebee.util.which', side_effect=['', 'xprop', 'xdg-screensaver']): - self.assertTrue(['xdotool'] == self.module._check_requirements()) - - def test_get_i3bar_xid_returns_digit(self): - self.popen.mock.communicate.return_value = ("8388614", None) - self.assertTrue(self.module._get_i3bar_xid().isdigit()) - - def test_get_i3bar_xid_returns_error_string(self): - self.popen.mock.communicate.return_value = ("Some error message", None) - self.assertTrue(self.module._get_i3bar_xid() is None) - - def test_get_i3bar_xid_returns_empty_string(self): - self.popen.mock.communicate.return_value = ("", None) - self.assertTrue(self.module._get_i3bar_xid() is None) - - def test_suspend_screensaver_success(self): - with patch.object(self.module, '_get_i3bar_xid', return_value=8388614): - mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module) - self.assertTrue(self.module._suspend_screensaver() is True) - - def test_suspend_screensaver_fail(self): - with patch.object(self.module, '_get_i3bar_xid', return_value=None): - self.module._active = False - mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module) - self.assertTrue(self.module._suspend_screensaver() is False) - - def test_resume_screensaver(self): - with patch.object(self.module, '_check_requirements', return_value=[]): - self.module._active = True - mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module) - self.assertTrue(self.module._resume_screensaver() is True) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_cmus.py b/tests/modules/test_cmus.py deleted file mode 100644 index ce1f77c..0000000 --- a/tests/modules/test_cmus.py +++ /dev/null @@ -1,114 +0,0 @@ -# pylint: disable=C0103,C0111 - -import mock -import unittest - -import tests.mocks as mocks - -from bumblebee.input import LEFT_MOUSE -from bumblebee.modules.cmus import Module - -class TestCmusModule(unittest.TestCase): - def setUp(self): - mocks.setup_test(self, Module) - - self.songTemplate = """ -status {status} -file /path/to/file -duration {duration} -position {position} -tag title {title} -tag artist {artist} -tag album {album} -tag tracknumber 1 -tag date 1984 -tag comment comment - """ - - def tearDown(self): - mocks.teardown_test(self) - - def test_read_song(self): - self.popen.mock.communicate.return_value = ("song", None) - self.module.update_all() - self.popen.assert_call("cmus-remote -Q") - - def test_handle_runtimeerror(self): - self.popen.mock.communicate.side_effect = RuntimeError("error loading song") - self.module.update_all() - self.assertEquals(self.module.description(self.anyWidget), " - /") - - def test_format(self): - self.popen.mock.communicate.return_value = (self.songTemplate.format( - artist="an artist", title="a title", duration="100", position="20", - album="an album", status="irrelevant" - ), None) - self.module.update_all() - self.anyWidget.set("theme.width", 1000) - self.assertEquals(self.module.description(self.anyWidget), - "an artist - a title 00:20/01:40" - ) - - def test_scrollable_format(self): - self.popen.mock.communicate.return_value = (self.songTemplate.format( - artist="an artist", title="a title", duration="100", position="20", - album="an album", status="irrelevant" - ), None) - self.module.update_all() - self.anyWidget.set("theme.width", 10) - self.assertEquals(self.module.description(self.anyWidget), - "an artist - a title 00:20/01:40"[:10] - ) - - def test_repeat(self): - self.popen.mock.communicate.return_value = ("set repeat false", None) - self.module.update_all() - self.assertTrue("repeat-off" in self.module.state(self.module.widget("cmus.repeat"))) - self.popen.mock.communicate.return_value = ("set repeat true", None) - self.module.update_all() - self.assertTrue("repeat-on" in self.module.state(self.module.widget("cmus.repeat"))) - - def test_shuffle(self): - self.popen.mock.communicate.return_value = ("set shuffle false", None) - self.module.update_all() - self.assertTrue("shuffle-off" in self.module.state(self.module.widget("cmus.shuffle"))) - self.popen.mock.communicate.return_value = ("set shuffle true", None) - self.module.update_all() - self.assertTrue("shuffle-on" in self.module.state(self.module.widget("cmus.shuffle"))) - - def test_prevnext(self): - self.assertTrue("prev" in self.module.state(self.module.widget("cmus.prev"))) - self.assertTrue("next" in self.module.state(self.module.widget("cmus.next"))) - - def test_main(self): - self.popen.mock.communicate.return_value = ("status paused", None) - self.module.update_all() - self.assertTrue("paused" in self.module.state(self.module.widget("cmus.main"))) - - self.popen.mock.communicate.return_value = ("status playing", None) - self.module.update_all() - self.assertTrue("playing" in self.module.state(self.module.widget("cmus.main"))) - - self.popen.mock.communicate.return_value = ("status stopped", None) - self.module.update_all() - self.assertTrue("stopped" in self.module.state(self.module.widget("cmus.main"))) - - def test_widget(self): - self.assertEquals(len(self.module.widgets()), 5) - - for idx, val in enumerate(["prev", "main", "next", "shuffle", "repeat"]): - self.assertEquals(self.module.widgets()[idx].name, "cmus.{}".format(val)) - - def test_interaction(self): - events = [ - {"widget": "cmus.shuffle", "action": "cmus-remote -S"}, - {"widget": "cmus.repeat", "action": "cmus-remote -R"}, - {"widget": "cmus.next", "action": "cmus-remote -n"}, - {"widget": "cmus.prev", "action": "cmus-remote -r"}, - {"widget": "cmus.main", "action": "cmus-remote -u"}, - ] - for event in events: - mocks.mouseEvent(stdin=self.stdin, inp=self.input, module=self.module, instance=self.module.widget(event["widget"]).id, button=LEFT_MOUSE) - self.popen.assert_call(event["action"]) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_cpu.py b/tests/modules/test_cpu.py deleted file mode 100644 index af9d28d..0000000 --- a/tests/modules/test_cpu.py +++ /dev/null @@ -1,45 +0,0 @@ -# pylint: disable=C0103,C0111 - -import mock -import unittest - -import tests.mocks as mocks - -from bumblebee.input import LEFT_MOUSE -from bumblebee.modules.cpu import Module - -class TestCPUModule(unittest.TestCase): - def setUp(self): - mocks.setup_test(self, Module) - self._psutil = mock.patch("bumblebee.modules.cpu.psutil") - self.psutil = self._psutil.start() - - def tearDown(self): - self._psutil.stop() - mocks.teardown_test(self) - - def test_format(self): - self.psutil.cpu_percent.return_value = 21.0 - self.module.update_all() - for widget in self.module.widgets(): - self.assertEquals(len(widget.full_text()), len("99.0%")) - - def test_leftclick(self): - mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module) - self.popen.assert_call("gnome-system-monitor") - - def test_warning(self): - self.config.set("cpu.critical", "20") - self.config.set("cpu.warning", "18") - self.psutil.cpu_percent.return_value = 19.0 - self.module.update_all() - self.assertTrue("warning" in self.module.state(self.anyWidget)) - - def test_critical(self): - self.config.set("cpu.critical", "20") - self.config.set("cpu.warning", "19") - self.psutil.cpu_percent.return_value = 21.0 - self.module.update_all() - self.assertTrue("critical" in self.module.state(self.anyWidget)) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_disk.py b/tests/modules/test_disk.py deleted file mode 100644 index bc40b2a..0000000 --- a/tests/modules/test_disk.py +++ /dev/null @@ -1,48 +0,0 @@ -# pylint: disable=C0103,C0111 - -import mock -import unittest - -import tests.mocks as mocks - -from bumblebee.input import LEFT_MOUSE -from bumblebee.modules.disk import Module - -class MockVFS(object): - def __init__(self, perc): - self.f_blocks = 1024*1024 - self.f_frsize = 1 - self.f_bfree = self.f_blocks*(1.0 - perc/100.0) - -class TestDiskModule(unittest.TestCase): - def setUp(self): - mocks.setup_test(self, Module) - self._os = mock.patch("bumblebee.modules.disk.os") - self.os = self._os.start() - self.config.set("disk.path", "somepath") - self.config.set("disk.open", "nautilus") - - def tearDown(self): - self._os.stop() - mocks.teardown_test(self) - - def test_leftclick(self): - module = Module(engine=self.engine, config={"config":self.config}) - mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=module) - self.popen.assert_call("nautilus {}".format(self.module.parameter("path"))) - - def test_warning(self): - self.config.set("disk.critical", "80") - self.config.set("disk.warning", "70") - self.os.statvfs.return_value = MockVFS(75.0) - self.module.update_all() - self.assertTrue("warning" in self.module.state(self.anyWidget)) - - def test_critical(self): - self.config.set("disk.critical", "80") - self.config.set("disk.warning", "70") - self.os.statvfs.return_value = MockVFS(85.0) - self.module.update_all() - self.assertTrue("critical" in self.module.state(self.anyWidget)) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_hddtemp.py b/tests/modules/test_hddtemp.py deleted file mode 100644 index e8eb9ca..0000000 --- a/tests/modules/test_hddtemp.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- - -import mock -import unittest - -from bumblebee.config import Config -import bumblebee.modules.hddtemp - - -class TestHddtempModule(unittest.TestCase): - def setUp(self): - config = Config() - self.module = bumblebee.modules.hddtemp.Module( - engine=mock.Mock(), config={"config": config}) - self.data_line = "|/dev/sda|TOSHIBA DT01ACA100 �|35|C||/dev/sdb|TOSHIBA DT01ACA100 �|37|C|" - self.expected_parts = [ - "/dev/sda", - "TOSHIBA DT01ACA100 �", - "35", - "C", - "", - "/dev/sdb", - "TOSHIBA DT01ACA100 �", - "37", - "C", - ""] - self.expected_per_disk = [ - ["/dev/sda", - "TOSHIBA DT01ACA100 �", - "35", - "C", - ""], - ["/dev/sdb", - "TOSHIBA DT01ACA100 �", - "37", - "C", - ""]] - self.device_record = self.expected_per_disk[0] - self.expected_name_and_temp = ("sda", "35") - self.expected_hddtemp = "sda+35°C" - - def test_get_parts(self): - self.assertEqual( - self.expected_parts, self.module._get_parts(self.data_line)) - - def test_partition_parts(self): - self.assertEqual( - self.expected_per_disk, - self.module._partition_parts(self.expected_parts)) - - def test_get_name_and_temp(self): - self.assertEqual( - self.expected_name_and_temp, - self.module._get_name_and_temp(self.device_record)) - - def test_get_hddtemp(self): - self.assertEqual( - self.expected_hddtemp, - self.module._get_hddtemp(self.expected_name_and_temp)) diff --git a/tests/modules/test_http_status.py b/tests/modules/test_http_status.py deleted file mode 100644 index 463884d..0000000 --- a/tests/modules/test_http_status.py +++ /dev/null @@ -1,49 +0,0 @@ -# pylint: disable=C0103,C0111 - -import mock -import unittest - -from bumblebee.modules.http_status import Module -from bumblebee.config import Config - -class TestHttpStatusModule(unittest.TestCase): - def test_status_success(self): - config = Config() - config.set("http_status.target", "http://example.org") - self.module = Module(engine=mock.Mock(), config={"config":config}) - - self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0])) - self.assertTrue(not "critical" in self.module.state(self.module.widgets()[0])) - self.assertEqual(self.module.getStatus(), "200") - self.assertEqual(self.module.getOutput(), "200") - - def test_status_error(self): - config = Config() - config.set("http_status.expect", "not a 200") - config.set("http_status.target", "http://example.org") - self.module = Module(engine=mock.Mock(), config={"config":config}) - - self.assertTrue(not "warning" in self.module.state(self.module.widgets()[0])) - self.assertTrue("critical" in self.module.state(self.module.widgets()[0])) - self.assertEqual(self.module.getStatus(), "200") - self.assertEqual(self.module.getOutput(), "200 != not a 200") - - def test_label(self): - config = Config() - config.set("http_status.label", "example") - config.set("http_status.target", "http://example.org") - self.module = Module(engine=mock.Mock(), config={"config":config}) - - self.assertEqual(self.module.getOutput(), "example: 200") - - def test_unknow(self): - config = Config() - config.set("http_status.target", "invalid target") - self.module = Module(engine=mock.Mock(), config={"config":config}) - - self.assertTrue("warning" in self.module.state(self.module.widgets()[0])) - self.assertEqual(self.module.getStatus(), "UNK") - self.assertEqual(self.module.getOutput(), "UNK != 200") - - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_load.py b/tests/modules/test_load.py deleted file mode 100644 index e57bc2b..0000000 --- a/tests/modules/test_load.py +++ /dev/null @@ -1,57 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import mock -import unittest - -import tests.mocks as mocks - -from bumblebee.input import LEFT_MOUSE -from bumblebee.modules.load import Module - -class TestLoadModule(unittest.TestCase): - def setUp(self): - mocks.setup_test(self, Module) - - self._mp = mock.patch("bumblebee.modules.load.multiprocessing") - self._os = mock.patch("bumblebee.modules.load.os") - - self.mp = self._mp.start() - self.os = self._os.start() - - self.mp.cpu_count.return_value = 1 - - def tearDown(self): - self._mp.stop() - self._os.stop() - mocks.teardown_test(self) - - def test_leftclick(self): - mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module) - self.popen.assert_call("gnome-system-monitor") - - def test_load_format(self): - self.os.getloadavg.return_value = [ 5.9, 1.2, 0.8 ] - self.module.update_all() - self.assertEquals(self.module.load(self.anyWidget), "5.90/1.20/0.80") - - def test_warning(self): - self.config.set("load.critical", "1") - self.config.set("load.warning", "0.8") - self.os.getloadavg.return_value = [ 0.9, 0, 0 ] - self.module.update_all() - self.assertTrue("warning" in self.module.state(self.anyWidget)) - - def test_critical(self): - self.config.set("load.critical", "1") - self.config.set("load.warning", "0.8") - self.os.getloadavg.return_value = [ 1.1, 0, 0 ] - self.module.update_all() - self.assertTrue("critical" in self.module.state(self.anyWidget)) - - def test_assume_single_core(self): - self.mp.cpu_count.side_effect = NotImplementedError - module = Module(engine=self.engine, config={"config": mock.Mock() }) - self.assertEquals(1, module._cpus) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/modules/test_pulseaudio.py b/tests/modules/test_pulseaudio.py deleted file mode 100644 index f8754c6..0000000 --- a/tests/modules/test_pulseaudio.py +++ /dev/null @@ -1,34 +0,0 @@ -# pylint: disable=C0103,C0111 - -import mock -import unittest - -import tests.mocks as mocks - -from bumblebee.input import LEFT_MOUSE, RIGHT_MOUSE, WHEEL_UP, WHEEL_DOWN -from bumblebee.modules.pulseaudio import Module - -class TestPulseAudioModule(unittest.TestCase): - def setUp(self): - mocks.setup_test(self, Module) - - def tearDown(self): - mocks.teardown_test(self) - - def test_leftclick(self): - mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module) - self.popen.assert_call("pactl set-source-mute @DEFAULT_SOURCE@ toggle") - - def test_rightclick(self): - mocks.mouseEvent(stdin=self.stdin, button=RIGHT_MOUSE, inp=self.input, module=self.module) - self.popen.assert_call("pavucontrol") - - def test_wheelup(self): - mocks.mouseEvent(stdin=self.stdin, button=WHEEL_UP, inp=self.input, module=self.module) - self.popen.assert_call("pactl set-source-volume @DEFAULT_SOURCE@ +2%") - - def test_wheeldown(self): - mocks.mouseEvent(stdin=self.stdin, button=WHEEL_DOWN, inp=self.input, module=self.module) - self.popen.assert_call("pactl set-source-volume @DEFAULT_SOURCE@ -2%") - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_config.py b/tests/test_config.py deleted file mode 100644 index 9277a62..0000000 --- a/tests/test_config.py +++ /dev/null @@ -1,70 +0,0 @@ -# pylint: disable=C0103,C0111 - -import unittest -import mock -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -from bumblebee.config import Config -from bumblebee.theme import themes -from bumblebee.engine import all_modules - -class TestConfig(unittest.TestCase): - def setUp(self): - self._stdout = mock.patch("bumblebee.config.sys.stdout", new_callable=StringIO) - self._stderr = mock.patch("bumblebee.config.sys.stderr", new_callable=StringIO) - - self.stdout = self._stdout.start() - self.stderr = self._stderr.start() - - self.defaultConfig = Config() - self.someSimpleModules = ["foo", "bar", "baz"] - self.someAliasModules = ["foo:a", "bar:b", "baz:c"] - self.someTheme = "some-theme" - - def tearDown(self): - self._stdout.stop() - self._stderr.stop() - - def test_no_modules_by_default(self): - self.assertEquals(self.defaultConfig.modules(), []) - - def test_simple_modules(self): - cfg = Config(["-m"] + self.someSimpleModules) - self.assertEquals(cfg.modules(), [{ - "name": x, "module": x - } for x in self.someSimpleModules]) - - def test_alias_modules(self): - cfg = Config(["-m"] + self.someAliasModules) - self.assertEquals(cfg.modules(), [{ - "module": x.split(":")[0], - "name": x.split(":")[1], - } for x in self.someAliasModules]) - - def test_parameters(self): - cfg = Config(["-m", "module", "-p", "module.key=value"]) - self.assertEquals(cfg.get("module.key"), "value") - - def test_theme(self): - cfg = Config(["-t", self.someTheme]) - self.assertEquals(cfg.theme(), self.someTheme) - - def test_notheme(self): - self.assertEquals(self.defaultConfig.theme(), "default") - - def test_list_themes(self): - with self.assertRaises(SystemExit): - cfg = Config(["-l", "themes"]) - result = self.stdout.getvalue() - for theme in themes(): - self.assertTrue(theme in result) - - def test_invalid_list(self): - with self.assertRaises(SystemExit): - cfg = Config(["-l", "invalid"]) - self.assertTrue("invalid choice" in "".join(self.stderr.getvalue())) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_engine.py b/tests/test_engine.py deleted file mode 100644 index 946f604..0000000 --- a/tests/test_engine.py +++ /dev/null @@ -1,90 +0,0 @@ -# pylint: disable=C0103,C0111,W0703,W0212 - -import shlex -import unittest - -from bumblebee.error import ModuleLoadError -from bumblebee.engine import Engine -from bumblebee.config import Config -import bumblebee.input - -from tests.mocks import MockOutput, MockInput - -class TestEngine(unittest.TestCase): - def setUp(self): - self.engine = Engine(config=Config(), output=MockOutput(), inp=MockInput()) - self.testModule = "test" - self.testAlias = "test-alias" - self.singleWidgetModule = [{"module": self.testModule, "name": "a"}] - self.singleWidgetAlias = [{"module": self.testAlias, "name": "a" }] - self.invalidModule = "no-such-module" - self.testModuleSpec = "bumblebee.modules.{}".format(self.testModule) - self.testModules = [ - {"module": "test", "name": "a"}, - {"module": "test", "name": "b"}, - ] - - def test_stop(self): - self.assertTrue(self.engine.running()) - self.engine.stop() - self.assertFalse(self.engine.running()) - - def test_load_module(self): - module = self.engine._load_module(self.testModule) - self.assertEquals(module.__module__, self.testModuleSpec) - - def test_load_invalid_module(self): - with self.assertRaises(ModuleLoadError): - self.engine._load_module(self.invalidModule) - - def test_load_none(self): - with self.assertRaises(ModuleLoadError): - self.engine._load_module(None) - - def test_load_modules(self): - modules = self.engine.load_modules(self.testModules) - self.assertEquals(len(modules), len(self.testModules)) - self.assertEquals( - [module.__module__ for module in modules], - [self.testModuleSpec for module in modules] - ) - - def test_run(self): - self.engine.load_modules(self.singleWidgetModule) - try: - self.engine.run() - except Exception as e: - self.fail(e) - - def test_aliases(self): - modules = self.engine.load_modules(self.singleWidgetAlias) - self.assertEquals(len(modules), 1) - self.assertEquals(modules[0].__module__, self.testModuleSpec) - - def test_custom_cmd(self): - testmodules = [ - { "name": "test", "button": "test.left-click", "action": "echo" }, - { "name": "test:alias", "button": "alias.right-click", "action": "echo2" }, - ] - cmd = "-m" - for test in testmodules: - cmd += " " + test["name"] - cmd += " -p" - for test in testmodules: - cmd += " " + test["button"] + "=" + test["action"] - cfg = Config(shlex.split(cmd)) - inp = MockInput() - engine = Engine(config=cfg, output=MockOutput(), inp=inp) - - i = 0 - for module in engine.modules(): - callback = inp.get_callback(module.id) - self.assertTrue(callback is not None) - self.assertEquals(callback["command"], testmodules[i]["action"]) - if "left" in testmodules[i]["button"]: - self.assertTrue(callback["button"], bumblebee.input.LEFT_MOUSE) - if "right" in testmodules[i]["button"]: - self.assertTrue(callback["button"], bumblebee.input.RIGHT_MOUSE) - i += 1 - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_i3barinput.py b/tests/test_i3barinput.py deleted file mode 100644 index 23ac566..0000000 --- a/tests/test_i3barinput.py +++ /dev/null @@ -1,110 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import mock -import unittest - -import tests.mocks as mocks - -from bumblebee.input import I3BarInput, LEFT_MOUSE, RIGHT_MOUSE - -class TestI3BarInput(unittest.TestCase): - def setUp(self): - self.input = I3BarInput() - self.input.need_event = True - - self._stdin = mock.patch("bumblebee.input.sys.stdin") - self.stdin = self._stdin.start() - self._select = mock.patch("bumblebee.input.select") - self.select = self._select.start() - self.popen = mocks.MockPopen() - - self.stdin.fileno.return_value = 1 - poll = mock.Mock() - self.select.poll.return_value = poll - - poll.poll.return_value = [(self.stdin.fileno.return_value, 2)] - - self.anyModule = mock.Mock() - self.anyModule.id = mocks.rand(10) - self.anotherModule = mock.Mock() - self.anotherModule.id = mocks.rand(10) - self.anyWidget = mocks.MockWidget("some-widget") - self.anotherWidget = mocks.MockWidget("another-widget") - self.anyData = self.invalidData = "any data" - self.invalidEvent = json.dumps({"name": None, "instance": None, "button": 1}) - self.incompleteEvent = json.dumps({"button": 1}) - self.anyCommand = "this is a command with arguments" - - self._called = 0 - - def tearDown(self): - self._stdin.stop() - self._select.stop() - self.popen.cleanup() - - def callback(self, event): - self._called += 1 - - def calls(self): - rv = self._called - self._called = 0 - return rv - - def test_read_event(self): - self.stdin.readline.return_value = self.anyData - self.input.start() - self.input.stop() - self.stdin.readline.assert_any_call() - - def test_ignore_invalid_input(self): - for data in [ self.invalidData, self.incompleteEvent, self.invalidEvent ]: - self.stdin.readline.return_value = data - self.input.start() - self.assertEquals(self.input.alive(), True) - self.assertEquals(self.input.stop(), True) - self.stdin.readline.assert_any_call() - - def test_global_callback(self): - self.input.register_callback(None, button=LEFT_MOUSE, cmd=self.callback) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin) - self.assertTrue(self.calls() > 0) - - def test_remove_global_callback(self): - self.test_global_callback() - self.input.deregister_callbacks(None) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin) - self.assertTrue(self.calls() == 0) - - def test_global_callback_wrong_button(self): - self.input.register_callback(None, button=LEFT_MOUSE, cmd=self.callback) - mocks.mouseEvent(button=RIGHT_MOUSE, inp=self.input, stdin=self.stdin) - self.assertTrue(self.calls() == 0) - - def test_module_callback(self): - self.input.register_callback(self.anyModule, button=LEFT_MOUSE, cmd=self.callback) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyModule) - self.assertTrue(self.calls() > 0) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anotherModule) - self.assertTrue(self.calls() == 0) - - def test_remove_module_callback(self): - self.test_module_callback() - self.input.deregister_callbacks(self.anyModule) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyModule) - self.assertTrue(self.calls() == 0) - - def test_widget_callback(self): - self.input.register_callback(self.anyWidget, button=LEFT_MOUSE, cmd=self.callback) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyWidget) - self.assertTrue(self.calls() > 0) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anotherWidget) - self.assertTrue(self.calls() == 0) - - def test_widget_cmd_callback(self): - self.input.register_callback(self.anyWidget, button=LEFT_MOUSE, cmd=self.anyCommand) - mocks.mouseEvent(button=LEFT_MOUSE, inp=self.input, stdin=self.stdin, module=self.anyWidget) - self.popen.assert_call(self.anyCommand) - - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_i3baroutput.py b/tests/test_i3baroutput.py deleted file mode 100644 index a350ceb..0000000 --- a/tests/test_i3baroutput.py +++ /dev/null @@ -1,138 +0,0 @@ -# pylint: disable=C0103,C0111 - -import json -import mock -import unittest - -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -import tests.mocks as mocks - -from bumblebee.output import I3BarOutput - -class TestI3BarOutput(unittest.TestCase): - def setUp(self): - self.theme = mock.Mock() - self.theme.separator_fg.return_value = "#123456" - self.theme.separator_bg.return_value = "#000000" - self.theme.separator.return_value = "" - self.theme.prefix.return_value = "" - self.theme.suffix.return_value = "" - self.theme.separator_block_width.return_value = 1 - self.theme.fg.return_value = "#ababab" - self.theme.bg.return_value = "#ababab" - self.theme.align.return_value = None - self.theme.minwidth.return_value = "" - - self.config = mock.Mock() - self.config.markup.return_value = "" - self.config.unused_keys.return_value = [] - - self.output = I3BarOutput(self.theme, self.config) - - self._stdout = mock.patch("bumblebee.output.sys.stdout", new_callable=StringIO) - self.stdout = self._stdout.start() - - self.anyWidget = mocks.MockWidget("some text") - self.anyModule = mock.Mock() - self.anyModule.id = mocks.rand(10) - self.anyModule.name = mocks.rand(10) - - self.expectedStart = json.dumps({"version": 1, "click_events": True}) + "\n[\n" - self.expectedStop = "]\n" - - self.anyColor = "#ffffff" - self.anotherColor = "#cdcdcd" - - def tearDown(self): - self._stdout.stop() - - def test_start(self): - self.output.start() - self.assertEquals(self.expectedStart, self.stdout.getvalue()) - - def test_stop(self): - self.output.stop() - self.assertEquals(self.expectedStop, self.stdout.getvalue()) - - def test_draw_single_widget(self): - self.output.draw(self.anyWidget, self.anyModule) - self.output.flush() - result = json.loads(self.stdout.getvalue())[0] - self.assertEquals(result["full_text"], self.anyWidget.full_text()) - - def test_draw_multiple_widgets(self): - for i in range(4): - self.output.draw(self.anyWidget, self.anyModule) - self.output.flush() - result = json.loads(self.stdout.getvalue()) - for res in result: - self.assertEquals(res["full_text"], self.anyWidget.full_text()) - - def test_begin(self): - self.output.begin() - self.assertEquals("", self.stdout.getvalue()) - - def test_end(self): - self.output.end() - self.assertEquals(",\n", self.stdout.getvalue()) - - def test_prefix(self): - self.theme.prefix.return_value = " - " - self.output.draw(self.anyWidget, self.anyModule) - self.output.flush() - result = json.loads(self.stdout.getvalue())[0] - self.assertEquals(result["full_text"], " - {}".format(self.anyWidget.full_text())) - - def test_suffix(self): - self.theme.suffix.return_value = " - " - self.output.draw(self.anyWidget, self.anyModule) - self.output.flush() - result = json.loads(self.stdout.getvalue())[0] - self.assertEquals(result["full_text"], "{} - ".format(self.anyWidget.full_text())) - - def test_bothfix(self): - self.theme.prefix.return_value = "*" - self.theme.suffix.return_value = " - " - self.output.draw(self.anyWidget, self.anyModule) - self.output.flush() - result = json.loads(self.stdout.getvalue())[0] - self.assertEquals(result["full_text"], "*{} - ".format(self.anyWidget.full_text())) - - def test_colors(self): - self.theme.fg.return_value = self.anyColor - self.theme.bg.return_value = self.anotherColor - self.output.draw(self.anyWidget, self.anyModule) - self.output.flush() - result = json.loads(self.stdout.getvalue())[0] - self.assertEquals(result["color"], self.anyColor) - self.assertEquals(result["background"], self.anotherColor) - - def test_widget_link(self): - self.anyWidget.link_module(self.anyModule) - self.assertEquals(self.anyWidget._module, self.anyModule) - self.assertEquals(self.anyWidget.module, self.anyModule.name) - - def test_unlinked_widget_state(self): - state = self.anyWidget.state() - self.assertTrue(type(state) == list) - - def test_linked_widget_state(self): - self.anyWidget.link_module(self.anyModule) - for lst in [ "samplestate", ["a", "b", "c"], [] ]: - self.anyModule.state.return_value = lst - state = self.anyWidget.state() - self.assertEquals(type(state), list) - if type(lst) is not list: lst = [lst] - self.assertEquals(state, lst) - - def test_widget_fulltext(self): - self.anyWidget.full_text("some text") - self.assertEquals(self.anyWidget.full_text(), "some text") - self.anyWidget.full_text(lambda x: "callable fulltext") - self.assertEquals(self.anyWidget.full_text(), "callable fulltext") - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_module.py b/tests/test_module.py deleted file mode 100644 index cf663dc..0000000 --- a/tests/test_module.py +++ /dev/null @@ -1,89 +0,0 @@ -# pylint: disable=C0103,C0111,W0703 - -import unittest - -from bumblebee.engine import Module -from bumblebee.config import Config -from tests.mocks import MockWidget - -class TestModule(unittest.TestCase): - def setUp(self): - self.widgetName = "foo" - self.widget = MockWidget(self.widgetName) - self.config = Config() - self.anyWidgetName = "random-widget-name" - self.noSuchModule = "this-module-does-not-exist" - self.moduleWithoutWidgets = Module(engine=None, widgets=None) - self.moduleWithOneWidget = Module(engine=None, widgets=self.widget, config={"config": self.config}) - self.moduleWithMultipleWidgets = Module(engine=None, - widgets=[self.widget, self.widget, self.widget] - ) - - self.anyConfigName = "cfg" - self.anotherConfigName = "cfg2" - self.anyModule = Module(engine=None, widgets=self.widget, config={ - "name": self.anyConfigName, "config": self.config - }) - self.anotherModule = Module(engine=None, widgets=self.widget, config={ - "name": self.anotherConfigName, "config": self.config - }) - self.anyKey = "some-parameter" - self.anyValue = "value" - self.anotherValue = "another-value" - self.emptyKey = "i-do-not-exist" - self.config.set("{}.{}".format(self.anyConfigName, self.anyKey), self.anyValue) - self.config.set("{}.{}".format(self.anotherConfigName, self.anyKey), self.anotherValue) - - def test_empty_widgets(self): - self.assertEquals(self.moduleWithoutWidgets.widgets(), []) - - def test_single_widget(self): - self.assertEquals(self.moduleWithOneWidget.widgets(), [self.widget]) - - def test_multiple_widgets(self): - for widget in self.moduleWithMultipleWidgets.widgets(): - self.assertEquals(widget, self.widget) - - def test_retrieve_widget_by_name(self): - widget = MockWidget(self.anyWidgetName) - widget.name = self.anyWidgetName - module = Module(engine=None, widgets=[self.widget, widget, self.widget]) - retrievedWidget = module.widget(self.anyWidgetName) - self.assertEquals(retrievedWidget, widget) - - def test_retrieve_widget_by_id(self): - widget = MockWidget(self.anyWidgetName) - widget.id = self.anyWidgetName - module = Module(engine=None, widgets=[self.widget, widget, self.widget]) - retrievedWidget = module.widget_by_id(self.anyWidgetName) - self.assertEquals(retrievedWidget, widget) - - def test_retrieve_missing_widget(self): - module = self.moduleWithMultipleWidgets - - widget = module.widget(self.noSuchModule) - self.assertEquals(widget, None) - - widget = module.widget_by_id(self.noSuchModule) - self.assertEquals(widget, None) - - def test_threshold(self): - module = self.moduleWithOneWidget - module.name = self.widgetName - - self.config.set("{}.critical".format(self.widgetName), 10.0) - self.config.set("{}.warning".format(self.widgetName), 8.0) - self.assertEquals("critical", module.threshold_state(10.1, 0, 0)) - self.assertEquals("warning", module.threshold_state(10.0, 0, 0)) - self.assertEquals(None, module.threshold_state(8.0, 0, 0)) - self.assertEquals(None, module.threshold_state(7.9, 0, 0)) - - def test_parameters(self): - self.assertEquals(self.anyModule.parameter(self.anyKey), self.anyValue) - self.assertEquals(self.anotherModule.parameter(self.anyKey), self.anotherValue) - - def test_default_parameters(self): - self.assertEquals(self.anyModule.parameter(self.emptyKey), None) - self.assertEquals(self.anyModule.parameter(self.emptyKey, self.anyValue), self.anyValue) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_output.py b/tests/test_output.py index 6d094c9..b073d4c 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -1,62 +1,27 @@ import unittest +import json -import bumblebee.output +import core.output - -class TestHBar(unittest.TestCase): - """tests for bumblebee.output.HBar""" +class i3(unittest.TestCase): def setUp(self): - self.value = 1 - self.values = [10, 20, 30, 40, 55, 65, 80, 90] - self.hbar = bumblebee.output.HBar(self.value) + self.i3 = core.output.i3() - def test___init__(self): - """bumblebee.output.HBar.__init__()""" - self.assertEqual( - self.hbar.step, bumblebee.output.MAX_PERCENTS / bumblebee.output.CHARS) + def tearDown(self): + pass - def test_get_char(self): - """bumblebee.output.HBar.get_char()""" - for i in range(bumblebee.output.CHARS): - hbar = bumblebee.output.HBar(self.values[i]) - self.assertEqual(hbar.get_char(), bumblebee.output.HBARS[i]) - # edge case for 100% - hbar = bumblebee.output.HBar(100) - self.assertEqual(hbar.get_char(), bumblebee.output.HBARS[-1]) + def test_start(self): + data = json.loads(self.i3.start()) + self.assertEquals(1, data['version'], 'i3bar protocol version 1 expected') + self.assertTrue(data['click_events'], 'click events should be enabled') + def test_begin_status_line(self): + self.assertEquals('[', self.i3.begin_status_line(), 'each line must be a JSON array') -class TestVBar(unittest.TestCase): - """tests for bumblebee.output.VBar""" - def setUp(self): - self.value = 1 - self.values = [10, 20, 30, 40, 55, 65, 80, 90] - self.vbar = bumblebee.output.VBar(self.value) + def test_end_status_line(self): + self.assertEquals('],\n', self.i3.end_status_line(), 'each line must terminate properly') - def test___init__(self): - """bumblebee.output.VBar.__init__()""" - self.assertEqual( - self.vbar.step, bumblebee.output.MAX_PERCENTS / bumblebee.output.CHARS) + def test_stop(self): + self.assertEquals(']\n', self.i3.stop()) - def test_get_chars(self): - """bumblebee.output.VBar.get_char()""" - for i in range(bumblebee.output.CHARS): - vbar = bumblebee.output.VBar(self.values[i]) - self.assertEqual(vbar.get_chars(), bumblebee.output.VBARS[i]) - # edge case for 100% - vbar = bumblebee.output.VBar(100) - self.assertEqual(vbar.get_chars(), bumblebee.output.VBARS[-1]) - # 0.x chars filled - value = 0.1 - vbar = bumblebee.output.VBar(value, 3) - expected_chars = vbar.bars[0] + " " - self.assertEqual(vbar.get_chars(), expected_chars) - # 1.x chars filled - value = 35 - vbar = bumblebee.output.VBar(value, 3) - expected_chars = vbar.bars[-1] + vbar.bars[0] + " " - self.assertEqual(vbar.get_chars(), expected_chars) - # 2.x chars filled - value = 67 - vbar = bumblebee.output.VBar(value, 3) - expected_chars = vbar.bars[-1] * 2 + vbar.bars[0] - self.assertEqual(vbar.get_chars(), expected_chars) +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_store.py b/tests/test_store.py deleted file mode 100644 index faa1efb..0000000 --- a/tests/test_store.py +++ /dev/null @@ -1,26 +0,0 @@ -# pylint: disable=C0103,C0111,W0703 - -import unittest - -from bumblebee.store import Store - -class TestStore(unittest.TestCase): - def setUp(self): - self.store = Store() - self.anyKey = "some-key" - self.anyValue = "some-value" - self.unsetKey = "invalid-key" - - def test_set_value(self): - self.store.set(self.anyKey, self.anyValue) - self.assertEquals(self.store.get(self.anyKey), self.anyValue) - - def test_get_invalid_value(self): - result = self.store.get(self.unsetKey) - self.assertEquals(result, None) - - def test_get_invalid_with_default_value(self): - result = self.store.get(self.unsetKey, self.anyValue) - self.assertEquals(result, self.anyValue) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_theme.py b/tests/test_theme.py deleted file mode 100644 index ebfe055..0000000 --- a/tests/test_theme.py +++ /dev/null @@ -1,142 +0,0 @@ -# pylint: disable=C0103,C0111,W0703 - -import mock -import unittest -from bumblebee.theme import Theme -from bumblebee.error import ThemeLoadError -from tests.mocks import MockWidget - -class TestTheme(unittest.TestCase): - def setUp(self): - self.nonexistentThemeName = "no-such-theme" - self.invalidThemeName = "test_invalid" - self.validThemeName = "test" - self.validThemeSeparator = " * " - self.themedWidget = MockWidget("bla") - self.theme = Theme(self.validThemeName) - self.cycleTheme = Theme("test_cycle") - self.anyModule = mock.Mock() - self.anyWidget = MockWidget("bla") - self.anotherWidget = MockWidget("blub") - - self.anyModule.state.return_value = "state-default" - - self.anyWidget.link_module(self.anyModule) - self.themedWidget.link_module(self.anyModule) - - data = self.theme.data() - self.widgetTheme = "test-widget" - self.themedWidget.module = self.widgetTheme - self.defaultColor = data["defaults"]["fg"] - self.defaultBgColor = data["defaults"]["bg"] - self.widgetColor = data[self.widgetTheme]["fg"] - self.widgetBgColor = data[self.widgetTheme]["bg"] - self.defaultPrefix = data["defaults"]["prefix"] - self.defaultSuffix = data["defaults"]["suffix"] - self.widgetPrefix = data[self.widgetTheme]["prefix"] - self.widgetSuffix = data[self.widgetTheme]["suffix"] - - def test_load_valid_theme(self): - try: - Theme(self.validThemeName) - except Exception as e: - self.fail(e) - - def test_load_nonexistent_theme(self): - with self.assertRaises(ThemeLoadError): - Theme(self.nonexistentThemeName) - - def test_load_invalid_theme(self): - with self.assertRaises(ThemeLoadError): - Theme(self.invalidThemeName) - - def test_default_prefix(self): - self.assertEquals(self.theme.prefix(self.anyWidget), self.defaultPrefix) - - def test_default_suffix(self): - self.assertEquals(self.theme.suffix(self.anyWidget), self.defaultSuffix) - - def test_widget_prefix(self): - self.assertEquals(self.theme.prefix(self.themedWidget), self.widgetPrefix) - - def test_widget_fg(self): - self.assertEquals(self.theme.fg(self.anyWidget), self.defaultColor) - self.anyWidget.module = self.widgetTheme - self.assertEquals(self.theme.fg(self.anyWidget), self.widgetColor) - - def test_widget_bg(self): - self.assertEquals(self.theme.bg(self.anyWidget), self.defaultBgColor) - self.anyWidget.module = self.widgetTheme - self.assertEquals(self.theme.bg(self.anyWidget), self.widgetBgColor) - - def test_absent_cycle(self): - theme = self.theme - try: - theme.fg(self.anyWidget) - theme.fg(self.anotherWidget) - except Exception as e: - self.fail(e) - - def test_reset(self): - theme = self.cycleTheme - data = theme.data() - theme.reset() - self.assertEquals(theme.fg(self.anyWidget), data["cycle"][0]["fg"]) - self.assertEquals(theme.fg(self.anotherWidget), data["cycle"][1]["fg"]) - theme.reset() - self.assertEquals(theme.fg(self.anyWidget), data["cycle"][0]["fg"]) - - def test_separator_block_width(self): - theme = self.theme - data = theme.data() - - self.assertEquals(theme.separator_block_width(self.anyWidget), - data["defaults"]["separator-block-width"] - ) - - def test_separator(self): - for theme in [self.theme, self.cycleTheme]: - theme.reset() - prev_bg = theme.bg(self.anyWidget) - theme.bg(self.anotherWidget) - - self.assertEquals(theme.separator_fg(self.anotherWidget), theme.bg(self.anotherWidget)) - self.assertEquals(theme.separator_bg(self.anotherWidget), prev_bg) - - def test_state(self): - theme = self.theme - data = theme.data() - - self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["fg"]) - self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["bg"]) - - self.anyModule.state.return_value = "critical" - self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["critical"]["fg"]) - self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["critical"]["bg"]) - self.assertEquals(theme.fg(self.themedWidget), data[self.widgetTheme]["critical"]["fg"]) - # if elements are missing in the state theme, they are taken from the - # widget theme instead (i.e. no fallback to a more general state theme) - self.assertEquals(theme.bg(self.themedWidget), data[self.widgetTheme]["bg"]) - - def test_empty_state(self): - theme = self.theme - data = theme.data() - - self.anyModule.state.return_value = "" - self.assertEquals(theme.fg(self.anyWidget), data["defaults"]["fg"]) - self.assertEquals(theme.bg(self.anyWidget), data["defaults"]["bg"]) - - def test_separator(self): - self.assertEquals(self.validThemeSeparator, self.theme.separator(self.anyWidget)) - - def test_list(self): - theme = self.theme - data = theme.data()[self.widgetTheme]["cycle-test"]["fg"] - self.anyModule.state.return_value = "cycle-test" - self.assertTrue(len(data) > 1) - - for idx in range(0, len(data)): - self.assertEquals(theme.fg(self.themedWidget), data[idx]) - self.assertEquals(theme.fg(self.themedWidget), data[0]) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_util.py b/tests/test_util.py deleted file mode 100644 index 1a7ee07..0000000 --- a/tests/test_util.py +++ /dev/null @@ -1,90 +0,0 @@ -# pylint: disable=C0103,C0111 - -import unittest -import re - -import tests.mocks as mocks - -import bumblebee.util as bu - - -class TestUtil(unittest.TestCase): - def setUp(self): - self.popen = mocks.MockPopen("bumblebee.util") - self.some_command_with_args = "sample-command -a -b -c" - self.some_utf8 = "some string".encode("utf-8") - - def tearDown(self): - self.popen.cleanup() - - def test_bytefmt(self): - self.assertEquals(bu.bytefmt(10), "10.00B") - self.assertEquals(bu.bytefmt(15 * 1024), "15.00KiB") - self.assertEquals(bu.bytefmt(20 * 1024 * 1024), "20.00MiB") - self.assertEquals(bu.bytefmt(22 * 1024 * 1024 * 1024), "22.00GiB") - self.assertEquals(bu.bytefmt(35 * 1024 * 1024 * 1024 * 1024), "35840.00GiB") - - fmt = "{:.0f}" - self.assertEquals(bu.bytefmt(10, fmt), "10B") - self.assertEquals(bu.bytefmt(15 * 1024, fmt), "15KiB") - self.assertEquals(bu.bytefmt(20 * 1024 * 1024, fmt), "20MiB") - self.assertEquals(bu.bytefmt(22 * 1024 * 1024 * 1024, fmt), "22GiB") - self.assertEquals(bu.bytefmt(35 * 1024 * 1024 * 1024 * 1024, fmt), "35840GiB") - - def test_durationfmt(self): - self.assertEquals(bu.durationfmt(00), "00:00") - self.assertEquals(bu.durationfmt(25), "00:25") - self.assertEquals(bu.durationfmt(60), "01:00") - self.assertEquals(bu.durationfmt(119), "01:59") - self.assertEquals(bu.durationfmt(3600), "01:00:00") - self.assertEquals(bu.durationfmt(7265), "02:01:05") - - def test_execute(self): - bu.execute(self.some_command_with_args) - self.assertTrue(self.popen.mock.popen.called) - self.popen.mock.popen.assert_call(self.some_command_with_args) - self.assertTrue(self.popen.mock.communicate.called) - - def test_execute_nowait(self): - bu.execute(self.some_command_with_args, False) - self.assertTrue(self.popen.mock.popen.called) - self.popen.mock.popen.assert_call(self.some_command_with_args) - self.assertFalse(self.popen.mock.communicate.called) - - def test_execute_utf8(self): - self.popen.mock.communicate.return_value = [self.some_utf8, None] - self.test_execute() - - def test_execute_error(self): - self.popen.mock.returncode = 1 - - with self.assertRaises(RuntimeError): - bu.execute(self.some_command_with_args) - - def test_which(self): - # test for a binary that has to be somewhere - print(bu.which("ls")) - self.assertTrue(re.search('/(ls)$', bu.which("ls"))) - - # test for a binary that is not necessarily there - program = "iwgetid" - self.assertTrue( - bu.which(program) is None or - re.search('/(' + program + ')$', bu.which(program)) - ) - - # test if which also works with garbage input - self.assertTrue(bu.which("qwertygarbage") is None) - - def test_asbool(self): - for val in ("t", "true", "y", "yes", "on", "1", 1, True): - self.assertTrue(bu.asbool(val)) - if isinstance(val, str): - self.assertTrue(bu.asbool(val.upper())) - - for val in ("f", "false", "n", "no", "off", "0", 0, False): - self.assertFalse(bu.asbool(val)) - if isinstance(val, str): - self.assertFalse(bu.asbool(val.upper())) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/themes/default.json b/themes/default.json deleted file mode 100644 index ddda5fe..0000000 --- a/themes/default.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "icons": [ "ascii" ], - "defaults": { - "urgent": true, - "fg": "#aabbcc" - } -} diff --git a/themes/dracula-powerline.json b/themes/dracula-powerline.json deleted file mode 100644 index 311f46e..0000000 --- a/themes/dracula-powerline.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#282A36", - "bg": "#E5C07B" - }, - "critical": { - "fg": "#282A36", - "bg": "#FF5555" - } - }, - "cycle": [ - {"fg": "#F8F8F2", "bg": "#6272A4"}, - {"fg": "#F8F8F2", "bg": "#282A36"} - ], - "dnf": { - "good": { - "fg": "#282A36", - "bg": "#50FA7B" - } - }, - "pacman": { - "good": { - "fg": "#282A36", - "bg": "#50FA7B" - } - }, - "battery": { - "charged": { - "fg": "#282A36", - "bg": "#50FA7B" - }, - "AC": { - "fg": "#282A36", - "bg": "#50FA7B" - } - }, - "pomodoro": { - "paused": { - "fg": "#282A36", - "bg": "#F1FA8C" - }, - "work": { - "fg": "#50FA7B", - "bg": "#282A36" - }, - "break": { - "fg": "#282A36", - "bg": "#50FA7B" - } - } - -} diff --git a/themes/firefox-dark-powerline.json b/themes/firefox-dark-powerline.json deleted file mode 100644 index 00e7d95..0000000 --- a/themes/firefox-dark-powerline.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#002b36", - "bg": "#b58900" - }, - "critical": { - "fg": "#002b36", - "bg": "#dc322f" - } - }, - "cycle": [ - { "fg": "#B1B1B3", "bg": "#474749" }, - { "fg": "#BEBEBE", "bg": "#323234" } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "pacman": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "pomodoro": { - "paused": { - "fg": "#002b36", - "bg": "#b58900" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } - - -} diff --git a/themes/greyish-powerline.json b/themes/greyish-powerline.json deleted file mode 100644 index 2e9d9b8..0000000 --- a/themes/greyish-powerline.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#002b36", - "bg": "#b58900" - }, - "critical": { - "fg": "#002b36", - "bg": "#dc322f" - } - }, - "cycle": [ - { "fg": "#EFEFEF", "bg": "#0D0D0D" }, - { "fg": "#EFEFEF", "bg": "#4F4F4F" } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "pacman": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#002b36", - "bg": "#859900" - }, - "AC": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "pomodoro": { - "paused": { - "fg": "#002b36", - "bg": "#b58900" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } - -} diff --git a/themes/gruvbox-light.json b/themes/gruvbox-light.json deleted file mode 100644 index ee4d69e..0000000 --- a/themes/gruvbox-light.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "icons": [ "paxy97", "ascii" ], - "defaults": { - "warning": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "critical": { - "fg": "#fbf1c7", - "bg": "#cc241d" - }, - "default-separators": false, - "separator-block-width": 0 - }, - "cycle": [ - { - "fg": "#1d2021", - "bg": "#ebdbb2" - }, - { - "fg": "#282828", - "bg": "#fbf1c7" - } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "AC": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "bluetooth": { - "ON": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "git": { - "modified": { "bg": "#458588" }, - "deleted": { "bg": "#9d0006" }, - "new": { "bg": "#b16286" } - }, - "pomodoro": { - "paused": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } - -} diff --git a/themes/gruvbox-powerline-light.json b/themes/gruvbox-powerline-light.json deleted file mode 100644 index d515df0..0000000 --- a/themes/gruvbox-powerline-light.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "icons": [ "paxy97", "awesome-fonts" ], - "defaults": { - "warning": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "critical": { - "fg": "#fbf1c7", - "bg": "#cc241d" - }, - "default-separators": false, - "separator-block-width": 0 - }, - "cycle": [ - { - "fg": "#1d2021", - "bg": "#ebdbb2" - }, - { - "fg": "#282828", - "bg": "#fbf1c7" - } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "AC": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "bluetooth": { - "ON": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "git": { - "modified": { "bg": "#458588" }, - "deleted": { "bg": "#9d0006" }, - "new": { "bg": "#b16286" } - }, - "pomodoro": { - "paused": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } -} diff --git a/themes/gruvbox-powerline.json b/themes/gruvbox-powerline.json deleted file mode 100644 index 3481dbc..0000000 --- a/themes/gruvbox-powerline.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "icons": [ "paxy97", "awesome-fonts" ], - "defaults": { - "warning": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "critical": { - "fg": "#fbf1c7", - "bg": "#cc241d" - }, - "default-separators": false, - "separator-block-width": 0 - }, - "cycle": [ - { - "fg": "#ebdbb2", - "bg": "#1d2021" - }, - { - "fg": "#fbf1c7", - "bg": "#282828" - } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "AC": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "bluetooth": { - "ON": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "git": { - "modified": { "bg": "#458588" }, - "deleted": { "bg": "#9d0006" }, - "new": { "bg": "#b16286" } - }, - "pomodoro": { - "paused": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } -} diff --git a/themes/gruvbox.json b/themes/gruvbox.json deleted file mode 100644 index ab71814..0000000 --- a/themes/gruvbox.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "icons": [ "paxy97", "ascii" ], - "defaults": { - "warning": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "critical": { - "fg": "#fbf1c7", - "bg": "#cc241d" - }, - "default-separators": false, - "separator-block-width": 0 - }, - "cycle": [ - { - "fg": "#ebdbb2", - "bg": "#1d2021" - }, - { - "fg": "#fbf1c7", - "bg": "#282828" - } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "AC": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "bluetooth": { - "ON": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - }, - "git": { - "modified": { "bg": "#458588" }, - "deleted": { "bg": "#9d0006" }, - "new": { "bg": "#b16286" } - }, - "pomodoro": { - "paused": { - "fg": "#1d2021", - "bg": "#d79921" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } - -} diff --git a/themes/iceberg-dark-powerline.json b/themes/iceberg-dark-powerline.json deleted file mode 100644 index 1b13b84..0000000 --- a/themes/iceberg-dark-powerline.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#0f1117", - "bg": "#e2a478" - }, - "critical": { - "fg": "#0f1117", - "bg": "#e27878" - } - }, - "cycle": [ - { "fg": "#d2d4de", "bg": "#161821" }, - { "fg": "#d2d4de", "bg": "#262939" }, - { "fg": "#d2d4de", "bg": "#353a50" }, - { "fg": "#d2d4de", "bg": "#454b68" }, - { "fg": "#d2d4de", "bg": "#353a50" }, - { "fg": "#d2d4de", "bg": "#262939" }, - { "fg": "#d2d4de", "bg": "#1e212d" } - ], - "dnf": { - "good": { - "fg": "#b4be82", - "bg": "#161821" - } - }, - "apt": { - "good": { - "fg": "#b4be82", - "bg": "#161821" - } - }, - "pacman": { - "good": { - "fg": "#b4be82", - "bg": "#161821" - } - }, - "battery": { - "charged": { - "fg": "#0f1117", - "bg": "#b4be82" - }, - "charging": { - "fg": "#0f1117", - "bg": "#84a0c6" - } - }, - "pomodoro": { - "paused": { - "fg": "#0f1117", - "bg": "#e2a478" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#b4be82", - "bg": "#161821" - } - } - -} diff --git a/themes/iceberg-powerline.json b/themes/iceberg-powerline.json deleted file mode 100644 index c7dca23..0000000 --- a/themes/iceberg-powerline.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#0f1117", - "bg": "#e2a478" - }, - "critical": { - "fg": "#0f1117", - "bg": "#e27878" - } - }, - "cycle": [ - { "fg": "#696d80", "bg": "#34394e" }, - { "fg": "#17171b", "bg": "#5a5f72" }, - { "fg": "#17171b", "bg": "#818596" }, - { "fg": "#161821", "bg": "#c6c8d1" }, - { "fg": "#17171b", "bg": "#818596" }, - { "fg": "#17171b", "bg": "#5a5f72" } - ], - "dnf": { - "good": { - "fg": "#b4be82", - "bg": "#161821" - } - }, - "apt": { - "good": { - "fg": "#b4be82", - "bg": "#161821" - } - }, - "pacman": { - "good": { - "fg": "b4be82", - "bg": "#161821" - } - }, - "battery": { - "charged": { - "fg": "#0f1117", - "bg": "#b4be82" - }, - "charging": { - "fg": "#0f1117", - "bg": "#84a0c6" - } - }, - "pomodoro": { - "paused": { - "fg": "#0f1117", - "bg": "#e2a478" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#89b8c2", - "bg": "#161821" - } - } -} diff --git a/themes/iceberg-rainbow.json b/themes/iceberg-rainbow.json deleted file mode 100644 index 9c56af6..0000000 --- a/themes/iceberg-rainbow.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#e2a478", - "bg": "#c6c8d1" - }, - "critical": { - "fg": "#e27878", - "bg": "#c6c8d1" - } - }, - "cycle": [ - { "fg": "#161821", "bg": "#e2a478" }, - { "fg": "#161821", "bg": "#e27878" }, - { "fg": "#161821", "bg": "#b4be82" }, - { "fg": "#161821", "bg": "#89b8c2" }, - { "fg": "#161821", "bg": "#84a0c6" }, - { "fg": "#161821", "bg": "#a093c7" } - ], - "dnf": { - "good": { - "fg": "#b4be82", - "bg": "#161821" - } - }, - "apt": { - "good": { - "fg": "#b4be82", - "bg": "#161821" - } - }, - "pacman": { - "good": { - "fg": "b4be82", - "bg": "#161821" - } - }, - "battery": { - "charged": { - "fg": "#b4be82", - "bg": "#161821" - }, - "charging": { - "fg": "#89b8c2", - "bg": "#161821" - } - }, - "pomodoro": { - "paused": { - "fg": "#e2a478", - "bg": "#c6c8d1" - }, - "work": { - "fg": "#89b8c2", - "bg": "#161821" - }, - "break": { - "fg": "#b4be82", - "bg": "#161821" - } - } - -} diff --git a/themes/iceberg.json b/themes/iceberg.json deleted file mode 100644 index 9943eb4..0000000 --- a/themes/iceberg.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "separator": "", - "warning": { - "fg": "#0f1117", - "bg": "#e2a478" - }, - "critical": { - "fg": "#0f1117", - "bg": "#e27878" - }, - "fg": "#c6c8d1", "bg": "#161821" - }, - "dnf": { - "good": { - "fg": "#0f1117", - "bg": "#b4be82" - } - }, - "apt": { - "good": { - "fg": "#0f1117", - "bg": "#b4be82" - } - }, - "pacman": { - "good": { - "fg": "#0f1117", - "bg": "#b4be82" - } - }, - "battery": { - "charged": { - "fg": "#b4be82", - "bg": "#161821" - }, - "charging": { - "fg": "#89b8c2", - "bg": "#161821" - } - }, - "pomodoro": { - "paused": { - "fg": "#0f1117", - "bg": "#e2a478" - }, - "work": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "break": { - "fg": "#89b8c2", - "bg": "#161821" - } - } - -} diff --git a/themes/icons/ascii.json b/themes/icons/ascii.json deleted file mode 100644 index 01aff79..0000000 --- a/themes/icons/ascii.json +++ /dev/null @@ -1,363 +0,0 @@ -{ - "defaults": { - "padding": " " - }, - "memory": { - "prefix": "ram" - }, - "cpu": { - "prefix": "cpu" - }, - "cpu2": { - "freq": { "prefix": "freq" }, - "load": { "prefix": "load" }, - "loads": { "prefix": "" }, - "temp": { "prefix": "temp" }, - "fan": { "prefix": "fan" } - }, - "disk": { - "prefix": "hdd" - }, - "dnf": { - "prefix": "dnf" - }, - "apt": { - "prefix": "apt" - }, - "brightness": { - "prefix": "o" - }, - "cmus": { - "playing": { - "prefix": ">" - }, - "paused": { - "prefix": "||" - }, - "stopped": { - "prefix": "[]" - }, - "prev": { - "prefix": "|<" - }, - "next": { - "prefix": ">|" - }, - "shuffle-on": { - "prefix": "S" - }, - "shuffle-off": { - "prefix": "[s]" - }, - "repeat-on": { - "prefix": "R" - }, - "repeat-off": { - "prefix": "[r]" - } - }, - "pasink": { - "muted": { - "prefix": "audio(mute)" - }, - "unmuted": { - "prefix": "audio" - } - }, - "amixer": { - "muted": { - "prefix": "audio(mute)" - }, - "unmuted": { - "prefix": "audio" - } - }, - "pasource": { - "muted": { - "prefix": "mic(mute)" - }, - "unmuted": { - "prefix": "mic" - } - }, - "nic": { - "wireless-up": { - "prefix": "wifi" - }, - "wireless-down": { - "prefix": "wifi" - }, - "wired-up": { - "prefix": "lan" - }, - "wired-down": { - "prefix": "lan" - }, - "tunnel-up": { - "prefix": "tun" - }, - "tunnel-down": { - "prefix": "tun" - } - }, - "battery-upower": { - "charged": { - "suffix": "full" - }, - "charging": { - "suffix": "chr" - }, - "AC": { - "suffix": "ac" - }, - "discharging-10": { - "prefix": "!", - "suffix": "dis" - }, - "discharging-25": { - "suffix": "dis" - }, - "discharging-50": { - "suffix": "dis" - }, - "discharging-80": { - "suffix": "dis" - }, - "discharging-100": { - "suffix": "dis" - }, - "unknown-25": { - "suffix": "?" - }, - "unknown-50": { - "suffix": "?" - }, - "unknown-80": { - "suffix": "?" - }, - "unknown-100": { - "suffix": "?" - } - }, - "battery": { - "charged": { - "suffix": "full" - }, - "charging": { - "suffix": "chr" - }, - "AC": { - "suffix": "ac" - }, - "discharging-10": { - "prefix": "!", - "suffix": "dis" - }, - "discharging-25": { - "suffix": "dis" - }, - "discharging-50": { - "suffix": "dis" - }, - "discharging-80": { - "suffix": "dis" - }, - "discharging-100": { - "suffix": "dis" - }, - "unknown-25": { - "suffix": "?" - }, - "unknown-50": { - "suffix": "?" - }, - "unknown-80": { - "suffix": "?" - }, - "unknown-100": { - "suffix": "?" - } - }, - "battery_all": { - "charged": { - "suffix": "full" - }, - "charging": { - "suffix": "chr" - }, - "AC": { - "suffix": "ac" - }, - "discharging-10": { - "prefix": "!", - "suffix": "dis" - }, - "discharging-25": { - "suffix": "dis" - }, - "discharging-50": { - "suffix": "dis" - }, - "discharging-80": { - "suffix": "dis" - }, - "discharging-100": { - "suffix": "dis" - }, - "unknown-25": { - "suffix": "?" - }, - "unknown-50": { - "suffix": "?" - }, - "unknown-80": { - "suffix": "?" - }, - "unknown-100": { - "suffix": "?" - } - }, - "caffeine": { - "activated": { - "prefix": "caf-on" - }, - "deactivated": { - "prefix": "caf-off " - } - }, - "xrandr": { - "on": { - "prefix": " off " - }, - "off": { - "prefix": " on " - }, - "refresh": { - "prefix": " refresh " - } - }, - "redshift": { - "day": { - "prefix": "day" - }, - "night": { - "prefix": "night" - }, - "transition": { - "prefix": "trans" - } - }, - "docker_ps": { - "prefix": "containers" - }, - "sensors": { - "prefix": "sensors" - }, - "traffic": { - "rx": { - "prefix": "down" - }, - "tx": { - "prefix": "up" - } - }, - "mpd": { - "playing": { - "prefix": ">" - }, - "paused": { - "prefix": "||" - }, - "stopped": { - "prefix": "[]" - }, - "prev": { - "prefix": "|<" - }, - "next": { - "prefix": ">|" - }, - "shuffle-on": { - "prefix": "S" - }, - "shuffle-off": { - "prefix": "[s]" - }, - "repeat-on": { - "prefix": "R" - }, - "repeat-off": { - "prefix": "[r]" - } - }, - "github": { - "prefix": "github" - }, - "deezer": { - "prefix": "" - }, - "spotify": { - "prefix": "" - }, - "uptime": { - "prefix": "uptime" - }, - "zpool": { - "poolread": { - "prefix": "pool read " - }, - "poolwrite": { - "prefix": "pool write " - }, - "ONLINE": { - "prefix": "pool" - }, - "FAULTED": { - "prefix": "pool (!)" - }, - "DEGRADED": { - "prefix": "pool (!)" - } - }, - "git": { - "main": { - "prefix": "" - }, - "new": { - "prefix": "[n]" - }, - "modified": { - "prefix": "[m]" - }, - "deleted": { - "prefix": "[d]" - } - }, - "dunst": { - "muted": { - "prefix": "dunst(muted)" - }, - "unmuted": { - "prefix": "dunst" - } - }, - "twmn": { - "muted": { - "prefix": "twmn" - }, - "unmuted": { - "prefix": "twmn(muted)" - } - }, - "system": { - "prefix": "system" - }, - "pomodoro": { - "off": { "prefix": "pom" }, - "paused": { "prefix": "||" }, - "on": { "prefix": " >" } - }, - "hddtemp": { - "prefix": "hddtemp" - } -} diff --git a/themes/icons/awesome-fonts.json b/themes/icons/awesome-fonts.json deleted file mode 100644 index 8c6688c..0000000 --- a/themes/icons/awesome-fonts.json +++ /dev/null @@ -1,264 +0,0 @@ -{ - "defaults": { - "separator": "", - "padding": " ", - "unknown": { "prefix": "" } - }, - "date": { "prefix": "" }, - "time": { "prefix": "" }, - "datetime": { "prefix": "" }, - "datetz": { "prefix": "" }, - "timetz": { "prefix": "" }, - "datetimetz": { "prefix": "" }, - "memory": { "prefix": "" }, - "cpu": { "prefix": "" }, - "cpu2": { - "freq": { "prefix": "" }, - "load": { "prefix": "" }, - "loads": { "prefix": "" }, - "temp": { "prefix": "" }, - "fan": { "prefix": "" } - }, - "disk": { "prefix": "" }, - "dnf": { "prefix": "" }, - "apt": { "prefix": "" }, - "pacman": { "prefix": "" }, - "brightness": { "prefix": "" }, - "load": { "prefix": "" }, - "layout": { "prefix": "" }, - "layout-xkb": { "prefix": "" }, - "layout-xkbswitch": { "prefix": "" }, - "notmuch_count": { - "empty": { "prefix": "\uf0e0" }, - "items": { "prefix": "\uf0e0" } - }, - "todo": { - "empty": { "prefix": "" }, - "items": { "prefix": "" }, - "uptime": { "prefix": "" } - }, - "zpool": { - "poolread": { "prefix": "→ " }, - "poolwrite": { "prefix": "← " }, - "ONLINE": { "prefix": "" }, - "FAULTED": { "prefix": "!" }, - "DEGRADED": { "prefix": "!" } - }, - "cmus": { - "playing": { "prefix": "" }, - "paused": { "prefix": "" }, - "stopped": { "prefix": "" }, - "prev": { "prefix": "" }, - "next": { "prefix": "" }, - "shuffle-on": { "prefix": "" }, - "shuffle-off": { "prefix": "" }, - "repeat-on": { "prefix": "" }, - "repeat-off": { "prefix": "" } - }, - "gpmdp": { - "playing": { "prefix": "" }, - "paused": { "prefix": "" }, - "stopped": { "prefix": "" }, - "prev": { "prefix": "" }, - "next": { "prefix": "" } - }, - "pasink": { - "muted": { "prefix": "" }, - "unmuted": { "prefix": "" } - }, - "amixer": { - "muted": { "prefix": "" }, - "unmuted": { "prefix": "" } - }, - "pasource": { - "muted": { "prefix": "" }, - "unmuted": { "prefix": "" } - }, - "kernel": { - "prefix": "\uf17c" - }, - "nic": { - "wireless-up": { "prefix": "" }, - "wireless-down": { "prefix": "" }, - "wired-up": { "prefix": "" }, - "wired-down": { "prefix": "" }, - "tunnel-up": { "prefix": "" }, - "tunnel-down": { "prefix": "" } - }, - "bluetooth": { - "ON": { "prefix": "" }, - "OFF": { "prefix": "" }, - "?": { "prefix": "" } - }, - "battery-upower": { - "charged": { "prefix": "", "suffix": "" }, - "AC": { "suffix": "" }, - "charging": { - "prefix": ["", "", "", "", ""], - "suffix": "" - }, - "discharging-10": { "prefix": "", "suffix": "" }, - "discharging-25": { "prefix": "", "suffix": "" }, - "discharging-50": { "prefix": "", "suffix": "" }, - "discharging-80": { "prefix": "", "suffix": "" }, - "discharging-100": { "prefix": "", "suffix": "" }, - "unlimited": { "prefix": "", "suffix": "" }, - "estimate": { "prefix": "" }, - "unknown-10": { "prefix": "", "suffix": "" }, - "unknown-25": { "prefix": "", "suffix": "" }, - "unknown-50": { "prefix": "", "suffix": "" }, - "unknown-80": { "prefix": "", "suffix": "" }, - "unknown-100": { "prefix": "", "suffix": "" } - }, - "battery": { - "charged": { "prefix": "", "suffix": "" }, - "AC": { "suffix": "" }, - "charging": { - "prefix": ["", "", "", "", ""], - "suffix": "" - }, - "discharging-10": { "prefix": "", "suffix": "" }, - "discharging-25": { "prefix": "", "suffix": "" }, - "discharging-50": { "prefix": "", "suffix": "" }, - "discharging-80": { "prefix": "", "suffix": "" }, - "discharging-100": { "prefix": "", "suffix": "" }, - "unlimited": { "prefix": "", "suffix": "" }, - "estimate": { "prefix": "" }, - "unknown-10": { "prefix": "", "suffix": "" }, - "unknown-25": { "prefix": "", "suffix": "" }, - "unknown-50": { "prefix": "", "suffix": "" }, - "unknown-80": { "prefix": "", "suffix": "" }, - "unknown-100": { "prefix": "", "suffix": "" } - }, - "battery_all": { - "charged": { "prefix": "", "suffix": "" }, - "AC": { "suffix": "" }, - "charging": { - "prefix": ["", "", "", "", ""], - "suffix": "" - }, - "discharging-10": { "prefix": "", "suffix": "" }, - "discharging-25": { "prefix": "", "suffix": "" }, - "discharging-50": { "prefix": "", "suffix": "" }, - "discharging-80": { "prefix": "", "suffix": "" }, - "discharging-100": { "prefix": "", "suffix": "" }, - "unlimited": { "prefix": "", "suffix": "" }, - "estimate": { "prefix": "" }, - "unknown-10": { "prefix": "", "suffix": "" }, - "unknown-25": { "prefix": "", "suffix": "" }, - "unknown-50": { "prefix": "", "suffix": "" }, - "unknown-80": { "prefix": "", "suffix": "" }, - "unknown-100": { "prefix": "", "suffix": "" } - }, - "caffeine": { - "activated": { "prefix": " " }, - "deactivated": { "prefix": " " } - }, - "xrandr": { - "on": { "prefix": " " }, - "off": { "prefix": " " }, - "refresh": { "prefix": "" } - }, - "redshift": { - "day": { "prefix": "" }, - "night": { "prefix": "" }, - "transition": { "prefix": "" } - }, - "docker_ps": { - "prefix": "" - }, - "sensors": { - "prefix": "" - }, - "sensors2": { - "temp": { "prefix": "" }, - "fan": { "prefix": "" }, - "cpu": { "prefix": "" } - }, - "traffic": { - "rx": { "prefix": "" }, - "tx": { "prefix": "" } - }, - "network_traffic": { - "rx": { "prefix": "" }, - "tx": { "prefix": "" } - }, - "mpd": { - "playing": { "prefix": "" }, - "paused": { "prefix": "" }, - "stopped": { "prefix": "" }, - "prev": { "prefix": "" }, - "next": { "prefix": "" }, - "shuffle-on": { "prefix": "" }, - "shuffle-off": { "prefix": "" }, - "repeat-on": { "prefix": "" }, - "repeat-off": { "prefix": "" } - }, - "arch-update": { - "prefix": " " - }, - "github": { - "prefix": "  " - }, - "deezer": { - "prefix": "  " - }, - "spotify": { - "prefix": "  " - }, - "publicip": { - "prefix": "  " - }, - "weather": { - "clouds": { "prefix": "" }, - "rain": { "prefix": "" }, - "snow": { "prefix": "" }, - "clear": { "prefix": "" }, - "thunder": { "prefix": "" } - }, - "taskwarrior": { - "prefix": "  " - }, - "progress": { - "copying": { - "prefix": "" - } - }, - "git": { - "main": { "prefix": "" }, - "new": { "prefix": "" }, - "modified": { "prefix": "" }, - "deleted": { "prefix": "" } - }, - "dunst": { - "muted": { "prefix": "" }, - "unmuted": { "prefix": "" } - }, - "twmn": { - "muted": { "prefix": "" }, - "unmuted": { "prefix": "" } - }, - "pihole": { - "enabled": { "prefix": "" }, - "disabled": { "prefix": "" } - }, - "vpn": { - "prefix": "" - }, - "system": { - "prefix": "  " - }, - "sun": { - "prefix": "" - }, - "rss": { - "prefix": "" - }, - "pomodoro": { - "off": { "prefix": "" }, - "paused": { "prefix": "" }, - "work": { "prefix": "" }, - "break": { "prefix": "" } - }, - "hddtemp": { "prefix": "" } -} diff --git a/themes/icons/ionicons.json b/themes/icons/ionicons.json deleted file mode 100644 index cf7813a..0000000 --- a/themes/icons/ionicons.json +++ /dev/null @@ -1,198 +0,0 @@ -{ - "defaults": { - "separator": "\ue0b2", - "padding": "\u2800", - "unknown": { "prefix": "\uf100" } - }, - "date": { "prefix": "\uf2d1" }, - "time": { "prefix": "\uf3b3" }, - "datetime": { "prefix": "\uf3b3" }, - "memory": { "prefix": "\uf389" }, - "cpu": { "prefix": "\uf4b0" }, - "disk": { "prefix": "\u26c1" }, - "dnf": { "prefix": "\uf2be" }, - "apt": { "prefix": "\uf2be" }, - "pacman": { "prefix": "\uf2be" }, - "brightness": { "prefix": "\u263c" }, - "load": { "prefix": "\uf13d" }, - "layout": { "prefix": "\uf38c" }, - "layout-xkb": { "prefix": "\uf38c" }, - "todo": { - "empty": { "prefix": "\uf453" }, - "items": { "prefix": "\uf454" }, - "uptime": { "prefix": "\uf4c1" } - }, - "zpool": { - "poolread": { "prefix": "\u26c1\uf3d6" }, - "poolwrite": { "prefix": "\u26c1\uf3d5" }, - "ONLINE": { "prefix": "\u26c1" }, - "FAULTED": { "prefix": "\u26c1\uf3bc" }, - "DEGRADED": { "prefix": "\u26c1\uf3bc" } - }, - "cmus": { - "playing": { "prefix": "\uf488" }, - "paused": { "prefix": "\uf210" }, - "stopped": { "prefix": "\uf24f" }, - "prev": { "prefix": "\uf4ab" }, - "next": { "prefix": "\uf4ad" }, - "shuffle-on": { "prefix": "\uf4a8" }, - "shuffle-off": { "prefix": "\uf453" }, - "repeat-on": { "prefix": "\uf459" }, - "repeat-off": { "prefix": "\uf30f" } - }, - "gpmdp": { - "playing": { "prefix": "\uf488" }, - "paused": { "prefix": "\uf210" }, - "stopped": { "prefix": "\uf24f" }, - "prev": { "prefix": "\uf4ab" }, - "next": { "prefix": "\uf4ad" } - }, - "pasink": { - "muted": { "prefix": "\uf3b9" }, - "unmuted": { "prefix": "\uf3ba" } - }, - "amixer": { - "muted": { "prefix": "\uf3b9" }, - "unmuted": { "prefix": "\uf3ba" } - }, - "pasource": { - "muted": { "prefix": "\uf395" }, - "unmuted": { "prefix": "\uf2ec" } - }, - "kernel": { - "prefix": "\uf17c" - }, - "nic": { - "wireless-up": { "prefix": "\uf25c" }, - "wireless-down": { "prefix": "\uf3d0" }, - "wired-up": { "prefix": "\uf270" }, - "wired-down": { "prefix": "\uf271" }, - "tunnel-up": { "prefix": "\uf133" }, - "tunnel-down": { "prefix": "\uf306" } - }, - "bluetooth": { - "ON": { "prefix": "\uf116" }, - "OFF": { "prefix": "\uf116" }, - "?": { "prefix": "\uf116" } - }, - "battery": { - "charged": { "prefix": "\uf113", "suffix": "\uf493" }, - "AC": { "suffix": "\uf493" }, - "charging": { - "prefix": ["\uf112", "\uf115", "\uf114", "", "\uf111"], - "suffix": "\uf493" - }, - "discharging-10": { "prefix": "\uf112", "suffix": "\uf3bc" }, - "discharging-25": { "prefix": "\uf115", "suffix": "\uf3e6" }, - "discharging-50": { "prefix": "\uf115", "suffix": "\uf3e6" }, - "discharging-80": { "prefix": "\uf114", "suffix": "\uf3e6" }, - "discharging-100": { "prefix": "\uf113", "suffix": "\uf3e6" }, - "unknown-10": { "prefix": "\uf112", "suffix": "\uf3bc" }, - "unknown-25": { "prefix": "\uf115", "suffix": "\uf142" }, - "unknown-50": { "prefix": "\uf115", "suffix": "\uf142" }, - "unknown-80": { "prefix": "\uf114", "suffix": "\uf142" }, - "unknown-100": { "prefix": "\uf113", "suffix": "\uf142" }, - "unlimited": { "prefix": "\uf402", "suffix": "\uf493" }, - "estimate": { "prefix": "\uf402" } - }, - "battery_all": { - "charged": { "prefix": "\uf113", "suffix": "\uf493" }, - "AC": { "suffix": "\uf493" }, - "charging": { - "prefix": ["\uf112", "\uf115", "\uf114", "", "\uf111"], - "suffix": "\uf493" - }, - "discharging-10": { "prefix": "\uf112", "suffix": "\uf3bc" }, - "discharging-25": { "prefix": "\uf115", "suffix": "\uf3e6" }, - "discharging-50": { "prefix": "\uf115", "suffix": "\uf3e6" }, - "discharging-80": { "prefix": "\uf114", "suffix": "\uf3e6" }, - "discharging-100": { "prefix": "\uf113", "suffix": "\uf3e6" }, - "unknown-10": { "prefix": "\uf112", "suffix": "\uf3bc" }, - "unknown-25": { "prefix": "\uf115", "suffix": "\uf142" }, - "unknown-50": { "prefix": "\uf115", "suffix": "\uf142" }, - "unknown-80": { "prefix": "\uf114", "suffix": "\uf142" }, - "unknown-100": { "prefix": "\uf113", "suffix": "\uf142" }, - "unlimited": { "prefix": "\uf402", "suffix": "\uf493" }, - "estimate": { "prefix": "\uf402" } - }, - "caffeine": { - "activated": { "prefix": "\uf272\u3000\uf354" }, - "deactivated": { "prefix": "\uf272\u3000\uf355" } - }, - "xrandr": { - "on": { "prefix": "\uf465\u3000\uf354" }, - "off": { "prefix": "\uf465\u3000\uf355" } - }, - "redshift": { - "day": { "prefix": "\uf4b6" }, - "night": { "prefix": "\uf467" }, - "transition": { "prefix": "\uf475" } - }, - "sensors": { - "prefix": "\uf3b6" - }, - "traffic": { - "rx": { "prefix": "\uf365" }, - "tx": { "prefix": "\uf35f" } - }, - "network_traffic": { - "rx": { "prefix": "\uf365" }, - "tx": { "prefix": "\uf35f" } - }, - "mpd": { - "playing": { "prefix": "\uf488" }, - "paused": { "prefix": "\uf210" }, - "stopped": { "prefix": "\uf24f" }, - "prev": { "prefix": "\uf4ab" }, - "next": { "prefix": "\uf4ad" }, - "shuffle-on": { "prefix": "\uf4a8" }, - "shuffle-off": { "prefix": "\uf453" }, - "repeat-on": { "prefix": "\uf459" }, - "repeat-off": { "prefix": "\uf30f" } - }, - "github": { - "prefix": "\uf233" - }, - "deezer": { - "prefix": "\uf305" - }, - "spotify": { - "prefix": "\uf305" - }, - "publicip": { - "prefix": "\uf268" - }, - "weather": { - "clouds": { "prefix": "\uf12b" }, - "rain": { "prefix": "\uf495" }, - "snow": { "prefix": "\uf4ae" }, - "clear": { "prefix": "\uf3b0" }, - "thunder": { "prefix": "\uf4bd" } - }, - "taskwarrior": { - "prefix": "\uf454" - }, - "dunst": { - "muted": { "prefix": "\uf39a" }, - "unmuted": { "prefix": "\uf39b" } - }, - "twmn": { - "muted": { "prefix": "\uf1f6" }, - "unmuted": { "prefix": "\uf0f3" } - }, - "system": { - "prefix": " \uf2a9 " - }, - "sun": { - "prefix": "\uf3b0" - }, - "rss": { - "prefix": "\uf1ea" - }, - "pomodoro": { - "off": { "prefix": "\uf24f" }, - "paused": { "prefix": "\uf210" }, - "on": { "prefix": "\uf488" } - } - -} diff --git a/themes/icons/paxy97.json b/themes/icons/paxy97.json deleted file mode 100644 index 9a889ab..0000000 --- a/themes/icons/paxy97.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "memory": { - "prefix": "  " - } -} diff --git a/themes/icons/test.json b/themes/icons/test.json deleted file mode 100644 index ad17178..0000000 --- a/themes/icons/test.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "test-widget": { - "prefix": "widget-prefix", - "suffix": "widget-suffix" - } -} diff --git a/themes/onedark-powerline.json b/themes/onedark-powerline.json deleted file mode 100644 index d0ca586..0000000 --- a/themes/onedark-powerline.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#282C34", - "bg": "#E5C07B" - }, - "critical": { - "fg": "#282C34", - "bg": "#E06C75" - } - }, - "cycle": [ - {"fg": "#ABB2BF", "bg": "#4B5263"}, - {"fg": "#ABB2BF", "bg": "#282C34"} - ], - "dnf": { - "good": { - "fg": "#282C34", - "bg": "#98C379" - } - }, - "pacman": { - "good": { - "fg": "#282C34", - "bg": "#98C379" - } - }, - "battery": { - "charged": { - "fg": "#282C34", - "bg": "#98C379" - }, - "AC": { - "fg": "#282C34", - "bg": "#98C379" - } - }, - "pomodoro": { - "paused": { - "fg": "#282C34", - "bg": "#E5C07B" - }, - "work": { - "fg": "#98C379", - "bg": "#282C34" - }, - "break": { - "fg": "#282C34", - "bg": "#98C379" - } - } - -} diff --git a/themes/powerline.json b/themes/powerline.json deleted file mode 100644 index b2b603d..0000000 --- a/themes/powerline.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "critical": { - "fg": "#ffffff", - "bg": "#ff0000" - }, - "warning": { - "fg": "#d75f00", - "bg": "#ffd700" - }, - "default_separators": false - }, - "cycle": [ - { - "fg": "#ffd700", - "bg": "#d75f00" - }, - { - "fg": "#ffffff", - "bg": "#0087af" - } - ], - "dnf": { - "good": { - "fg": "#494949", - "bg": "#41db00" - } - }, - "apt": { - "good": { - "fg": "#494949", - "bg": "#41db00" - } - }, - "battery": { - "charged": { - "fg": "#494949", - "bg": "#41db00" - }, - "AC": { - "fg": "#494949", - "bg": "#41db00" - } - }, - "pomodoro": { - "paused": { - "fg": "#d75f00", - "bg": "#ffd700" - }, - "work": { - "fg": "#ffd700", - "bg": "#d75f00" - }, - "break": { - "fg": "#494949", - "bg": "#41db00" - } - } - -} diff --git a/themes/sac_red.json b/themes/sac_red.json deleted file mode 100644 index 7f6be68..0000000 --- a/themes/sac_red.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "icons": [ "paxy97", "awesome-fonts" ], - "defaults": { - "warning": { - "fg": "#FDFFFC", - "bg": "#B91372" - }, - "critical": { - "fg": "#FDFFFC", - "bg": "#FF0022" - }, - "default-separators": false, - "separator-block-width": 0 - }, - "cycle": [ - { - "fg": "#FDFFFC", - "bg": "#990014" - }, - { - "fg": "#FDFFFC", - "bg": "#011627" - } - ], - "battery": { - "charged": { - "fg": "#FDFFFC", - "bg": "#41EAD4" - }, - "AC": { - "fg": "#FDFFFC", - "bg": "#41EAD4" - } - }, - "bluetooth": { - "ON": { - "fg": "#FDFFFC", - "bg": "#41EAD4" - } - }, - "cmus": { - "bg": "#C42021" - }, - "pomodoro": { - "paused": { - "fg": "#FDFFFC", - "bg": "#B91372" - }, - "work": { - "fg": "#FDFFFC", - "bg": "#41EAD4" - }, - "break": { - "fg": "#FDFFFC", - "bg": "#011627" - } - } - -} diff --git a/themes/solarized-dark-awesome.json b/themes/solarized-dark-awesome.json deleted file mode 100644 index 7274dc7..0000000 --- a/themes/solarized-dark-awesome.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "separator": "", - "warning": { - "fg": "#002b36", - "bg": "#b58900" - }, - "critical": { - "fg": "#002b36", - "bg": "#dc322f" - }, - "fg": "#93a1a1", "bg": "#002b36" - }, - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "pacman": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#002b36", - "bg": "#859900" - }, - "AC": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "git": { - "modified": { "bg": "#2aa198" }, - "deleted": { "bg": "#d33682" }, - "new": { "bg": "#859900" } - }, - "pomodoro": { - "paused": { - "fg": "#002b36", - "bg": "#b58900" - }, - "work": { - "fg": "#eee8d5", - "bg": "#586e75" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } -} diff --git a/themes/solarized-powerline.json b/themes/solarized-powerline.json deleted file mode 100644 index 25854f5..0000000 --- a/themes/solarized-powerline.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "separator-block-width": 0, - "warning": { - "fg": "#002b36", - "bg": "#b58900" - }, - "critical": { - "fg": "#002b36", - "bg": "#dc322f" - } - }, - "cycle": [ - { "fg": "#93a1a1", "bg": "#002b36" }, - { "fg": "#eee8d5", "bg": "#586e75" } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "pacman": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#002b36", - "bg": "#859900" - }, - "AC": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "git": { - "modified": { "bg": "#2aa198" }, - "deleted": { "bg": "#d33682" }, - "new": { "bg": "#859900" } - }, - "pomodoro": { - "paused": { - "fg": "#002b36", - "bg": "#b58900" - }, - "work": { - "fg": "#eee8d5", - "bg": "#586e75" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } -} diff --git a/themes/solarized.json b/themes/solarized.json deleted file mode 100644 index e6f0082..0000000 --- a/themes/solarized.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "icons": [ "ascii" ], - "defaults": { - "separator-block-width": 0, - "critical": { - "fg": "#002b36", - "bg": "#dc322f" - }, - "warning": { - "fg": "#002b36", - "bg": "#b58900" - }, - "default_separators": false, - "separator": "" - }, - "cycle": [ - { - "fg": "#93a1a1", - "bg": "#002b36" - }, - { - "fg": "#eee8d5", - "bg": "#586e75" - } - ], - "dnf": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "apt": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "battery": { - "charged": { - "fg": "#002b36", - "bg": "#859900" - }, - "AC": { - "fg": "#002b36", - "bg": "#859900" - } - }, - "git": { - "modified": { "bg": "#2aa198" }, - "deleted": { "bg": "#d33682" }, - "new": { "bg": "#859900" } - }, - "pomodoro": { - "paused": { - "fg": "#002b36", - "bg": "#b58900" - }, - "work": { - "fg": "#eee8d5", - "bg": "#586e75" - }, - "break": { - "fg": "#002b36", - "bg": "#859900" - } - } - -} diff --git a/themes/test.json b/themes/test.json deleted file mode 100644 index 1d457a7..0000000 --- a/themes/test.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "icons": [ "test" ], - "defaults": { - "prefix": "default-prefix", - "suffix": "default-suffix", - "fg": "#000000", - "bg": "#111111", - "separator": " * ", - "separator-block-width": 10, - "critical": { - "fg": "#ffffff", - "bg": "#010101" - } - }, - "test-widget": { - "fg": "#ababab", - "bg": "#222222", - "critical": { - "fg": "#bababa" - }, - "cycle-test": { - "fg": [ "#000000", "#111111" ] - } - } -} diff --git a/themes/test_cycle.json b/themes/test_cycle.json deleted file mode 100644 index 5fd7e1a..0000000 --- a/themes/test_cycle.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "icons": [ "test" ], - "defaults": { - "prefix": "default-prefix", - "suffix": "default-suffix", - "fg": "#000000", - "bg": "#111111" - }, - "cycle": [ - { "fg": "#aa0000" }, - { "fg": "#00aa00" }, - { "fg": "#0000aa" } - ], - "test-widget": { - "fg": "#ababab", - "bg": "#222222" - } -} diff --git a/themes/test_invalid.json b/themes/test_invalid.json deleted file mode 100644 index d510f27..0000000 --- a/themes/test_invalid.json +++ /dev/null @@ -1 +0,0 @@ -this is really not json diff --git a/themes/wal-powerline.json b/themes/wal-powerline.json deleted file mode 100644 index 8b28d3a..0000000 --- a/themes/wal-powerline.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "colors": [ "wal" ], - "defaults": { - "separator-block-width": 0, - "critical": { - "fg": "cursor", - "bg": "color5" - }, - "warning": { - "fg": "cursor", - "bg": "color6" - }, - "default_separators": false - }, - "cycle": [ - { - "fg": "foreground", - "bg": "background" - }, - { - "fg": "background", - "bg": "foreground" - } - ], - "dnf": { - "good": { - "fg": "background", - "bg": "color3" - } - }, - "apt": { - "good": { - "fg": "background", - "bg": "color3" - } - }, - "battery": { - "charged": { - "fg": "background", - "bg": "color3" - }, - "AC": { - "fg": "background", - "bg": "color3" - } - }, - "pomodoro": { - "paused": { - "fg": "cursor", - "bg": "color6" - }, - "work": { - "fg": "background", - "bg": "foreground" - }, - "break": { - "fg": "background", - "bg": "color3" - } - } - -}