diff --git a/README.md b/README.md deleted file mode 100644 index d039179..0000000 --- a/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# bumblebee-status - -bumblebee-status is a modular, theme-able status line generator for the [i3 window manager](https://i3wm.org/). - -Focus is on: -* Ease of use (no configuration files!) -* Theme support -* Extensibility (of course...) - -I hope you like it and appreciate any kind of feedback: Bug reports, Feature requests, etc. :) - -Thanks a lot! - -# Documentation -See [the wiki](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki) for documentation. - -Other resources: - -* A list of [available modules](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/Available-Modules) -* [How to write a theme](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/How-to-write-a-theme) -* [How to write a module](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/How-to-write-a-module) - -# Installation -``` -$ git clone git://github.com/tobi-wan-kenobi/bumblebee-status -``` - -# Usage - -Next, open your i3wm configuration and modify the *status_command* for your i3bar like this: - -``` -bar { - status_command = -m -p -t -} -``` - -You can retrieve a list of modules and themes by entering: -``` -$ cd bumblebee-status -$ ./bumblebee-status -l themes -$ ./bumblebee-status -l modules -``` - -As a simple example, this is what my i3 configuration looks like: - -``` -bar { - font pango:Inconsolata 10 - position top - tray_output none - status_command ~/.i3/bumblebee-status/bumblebee-status -m nic disk:/ cpu memory battery date time pasink pasource dnf -p time.format="%H:%M CW %V" date.format="%a, %b %d %Y" -t solarized-powerline -} - -``` - - -Restart i3wm and - that's it! - - -# Examples -Here are some screenshots for all themes that currently exist: - -Gruvbox Powerline (`-t gruvbox-powerline`) (contributed by [@paxy97](https://github.com/paxy97)): - -![Gruvbox Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-gruvbox.png) - -Solarized Powerline (`-t solarized-powerline`): - -![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png) - -Solarized (`-t solarized`): - -![Solarized](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/solarized.png) - -Powerline (`-t powerline`): - -![Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline.png) - -Default (nothing or `-t default`): - -![Default](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/default.png) diff --git a/bin/customupdates b/bin/customupdates deleted file mode 100755 index 3176c9d..0000000 --- a/bin/customupdates +++ /dev/null @@ -1,21 +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/load-i3-bars.sh b/bin/load-i3-bars.sh deleted file mode 100755 index cbe0e95..0000000 --- a/bin/load-i3-bars.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -if [ ! -f ~/.i3/config.template ]; then - cp ~/.i3/config ~/.i3/config.template -else - cp ~/.i3/config.template ~/.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 ~/.i3/config.$screen-$others ]; then - cat ~/.i3/config.$screen-$others >> ~/.i3/config - else - if [ -f ~/.i3/config.$screen ]; then - cat ~/.i3/config.$screen >> ~/.i3/config - fi - fi -done <<< "$screens" - -i3-msg restart diff --git a/bin/toggle-display.sh b/bin/toggle-display.sh deleted file mode 100755 index bd13a29..0000000 --- a/bin/toggle-display.sh +++ /dev/null @@ -1,12 +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 - $i3bar_update -fi diff --git a/bumblebee-status b/bumblebee-status old mode 100755 new mode 100644 index 42258a4..e69de29 --- a/bumblebee-status +++ b/bumblebee-status @@ -1,18 +0,0 @@ -#!/usr/bin/env python - -import sys -import bumblebee.config -import bumblebee.engine - -def main(): - config = bumblebee.config.Config(sys.argv[1:]) - - engine = bumblebee.engine.Engine(config) - engine.load_modules() - - engine.run() - -if __name__ == "__main__": - main() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/config.py b/bumblebee/config.py index 49005ad..d9c9419 100644 --- a/bumblebee/config.py +++ b/bumblebee/config.py @@ -1,123 +1,19 @@ -import os import argparse -import textwrap -import bumblebee.theme -import bumblebee.module - -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 = " "*4 - - def __call__(self, parser, namespace, value, option_string=None): - if value == "modules": - self.print_modules() - elif value == "themes": - self.print_themes() - else: - parser.print_help() - parser.exit() - - def print_themes(self): - print(textwrap.fill(", ".join(bumblebee.theme.themes()), - 80, initial_indent = self._indent, subsequent_indent = self._indent - )) - - def print_modules(self): - for m in bumblebee.module.modules(): - print(textwrap.fill("{}: {}".format(m.name(), m.description()), - 80, initial_indent=self._indent*2, subsequent_indent=self._indent*3)) - print("{}Parameters:".format(self._indent*2)) - for p in m.parameters(): - print(textwrap.fill("* {}".format(p), - 80, initial_indent=self._indent*3, subsequent_indent=self._indent*4)) - print("") - -class ModuleConfig(object): - def __init__(self, config, name, alias): - self._prefix = alias if alias else name - self._config = config - - def prefix(self): - return self._prefix - - def set(self, name, value): - name = self._prefix + name - return self._config.set(name, value) - - def parameter(self, name, default=None): - name = self._prefix + name - return self._config.parameter(name, default) - - def increase(self, name, limit, default): - name = self._prefix + name - return self._config.increase(name, limit, default) +MODULE_HELP = "" class Config(object): - def __init__(self, args): - self._parser = self._parser() - self._store = {} - - if len(args) == 0: - self._parser.print_help() - self._parser.exit() - - self._args = self._parser.parse_args(args) - - for p in self._args.parameters: - key, value = p.split("=") - self.parameter(key, value) - - def set(self, name, value): - self._store[name] = value - - def parameter(self, name, default=None): - if not name in self._store: - self.set(name, default) - return self._store.get(name, default) - - def increase(self, name, limit, default): - if not name in self._store: - self._store[name] = default - return default - - self._store[name] += 1 - if self._store[name] >= limit: - self._store[name] = default - return self._store[name] - - def theme(self): - return self._args.theme + def __init__(self, args = []): + parser = self._create_parser() + self._args = parser.parse_args(args) def modules(self): - result = [] - for m in self._args.modules: - items = m.split(":") - result.append({ "name": items[0], "alias": items[1] if len(items) > 1 else None }) - return result + return map(lambda x: { "name": x, "module": x }, self._args.modules) - def _parser(self): + def _create_parser(self): parser = argparse.ArgumentParser(description="display system data in the i3bar") - parser.add_argument("-m", "--modules", nargs="+", - help="List of modules to load. The order of the list determines " - "their order in the i3bar (from left to right)", - default=[], - ) - parser.add_argument("-l", "--list", - help="List: 'modules', 'themes' ", - choices = [ "modules", "themes" ], - action=print_usage, - ) - parser.add_argument("-p", "--parameters", nargs="+", - help="Provide configuration parameters to individual modules.", - default=[] - ) - parser.add_argument("-t", "--theme", help="Specify which theme to use for " - "drawing the modules", - default="default", - ) - + parser.add_argument("-m", "--modules", nargs="+", default = [], + help = MODULE_HELP) return parser # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/engine.py b/bumblebee/engine.py deleted file mode 100644 index cc0b7b9..0000000 --- a/bumblebee/engine.py +++ /dev/null @@ -1,38 +0,0 @@ -import importlib -import bumblebee.theme -import bumblebee.output -import bumblebee.config -import bumblebee.modules - -class Engine: - def __init__(self, config): - self._modules = [] - self._config = config - self._theme = bumblebee.theme.Theme(config) - self._output = bumblebee.output.output(config) - - def load_module(self, modulespec): - name = modulespec["name"] - module = importlib.import_module("bumblebee.modules.{}".format(name)) - cfg = bumblebee.config.ModuleConfig(self._config, name, modulespec["alias"]) - obj = getattr(module, "Module")(self._output, cfg) - obj.register_callbacks() - return obj - - def load_modules(self): - for m in self._config.modules(): - self._modules.append(self.load_module(m)) - - def run(self): - self._output.start() - - while True: - self._theme.begin() - for m in self._modules: - self._output.draw(m.widgets(), self._theme) - self._output.flush() - self._output.wait() - - self._output.stop() - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/module.py b/bumblebee/module.py deleted file mode 100644 index 0f497a2..0000000 --- a/bumblebee/module.py +++ /dev/null @@ -1,61 +0,0 @@ -import os -import pkgutil -import importlib - -import bumblebee.modules - -def modules(): - result = [] - path = os.path.dirname(bumblebee.modules.__file__) - for mod in [ name for _, name, _ in pkgutil.iter_modules([path])]: - result.append(ModuleDescription(mod)) - return result - -class ModuleDescription(object): - def __init__(self, name): - self._name = name - self._mod =importlib.import_module("bumblebee.modules.{}".format(name)) - - def name(self): - return str(self._name) - - def description(self): - return getattr(self._mod, "description", lambda: "n/a")() - - def parameters(self): - return getattr(self._mod, "parameters", lambda: [ "n/a" ])() - -class Module(object): - def __init__(self, output, config): - self._output = output - self._config = config - - def register_callbacks(self): - buttons = [ - { "name": "left-click", "id": 1 }, - { "name": "middle-click", "id": 2 }, - { "name": "right-click", "id": 3 }, - { "name": "wheel-up", "id": 4 }, - { "name": "wheel-down", "id": 5 }, - ] - for button in buttons: - if self._config.parameter(button["name"], None): - output.add_callback( - module=self.instance(), - button=button["id"], - cmd=self._config.parameter(button["name"]) - ) - - def critical(self, widget): - return False - - def warning(self, widget): - return False - - def state(self, widget): - return "default" - - def instance(self, widget=None): - return self._config.prefix() - -# 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/battery.py b/bumblebee/modules/battery.py deleted file mode 100644 index 8215693..0000000 --- a/bumblebee/modules/battery.py +++ /dev/null @@ -1,52 +0,0 @@ -import datetime -import bumblebee.module -import os.path - -def description(): - return "Displays battery status, percentage and whether it's charging or discharging." - -def parameters(): - return [ "battery.device: The device to read from (defaults to BAT0)" ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._battery = config.parameter("device", "BAT0") - self._capacity = 100 - self._status = "Unknown" - - def widgets(self): - self._AC = False; - self._path = "/sys/class/power_supply/{}".format(self._battery) - if not os.path.exists(self._path): - self._AC = True; - return bumblebee.output.Widget(self,"AC") - - with open(self._path + "/capacity") as f: - self._capacity = int(f.read()) - self._capacity = self._capacity if self._capacity < 100 else 100 - - return bumblebee.output.Widget(self,"{:02d}%".format(self._capacity)) - - def warning(self, widget): - return self._capacity < self._config.parameter("warning", 20) - - def critical(self, widget): - return self._capacity < self._config.parameter("critical", 10) - - def state(self, widget): - if self._AC: - return "AC" - - with open(self._path + "/status") as f: - self._status = f.read().strip() - - if self._status == "Discharging": - status = "discharging-{}".format(min([ 10, 25, 50, 80, 100] , key=lambda i:abs(i-self._capacity))) - return status - else: - if self._capacity > 95: - return "charged" - return "charging" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/brightness.py b/bumblebee/modules/brightness.py deleted file mode 100644 index 9227ce8..0000000 --- a/bumblebee/modules/brightness.py +++ /dev/null @@ -1,33 +0,0 @@ -import bumblebee.module - -def description(): - return "Displays brightness percentage" - -def parameters(): - return [ - "brightness.step: Steps (in percent) to increase/decrease brightness on scroll (defaults to 2)", - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._brightness = 0 - self._max = 0 - self._percent = 0 - - step = self._config.parameter("step", 2) - - output.add_callback(module=self.instance(), button=4, cmd="xbacklight +{}%".format(step)) - output.add_callback(module=self.instance(), button=5, cmd="xbacklight -{}%".format(step)) - - def widgets(self): - with open("/sys/class/backlight/intel_backlight/brightness") as f: - self._brightness = int(f.read()) - with open("/sys/class/backlight/intel_backlight/max_brightness") as f: - self._max = int(f.read()) - self._brightness = self._brightness if self._brightness < self._max else self._max - self._percent = int(round(self._brightness * 100 / self._max)) - - return bumblebee.output.Widget(self, "{:02d}%".format(self._percent)) - -# 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 d7c2dad..0000000 --- a/bumblebee/modules/caffeine.py +++ /dev/null @@ -1,38 +0,0 @@ -import subprocess -import shlex - -import bumblebee.module - -def description(): - return "Enable/disable auto screen lock." - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._activated = 0 - output.add_callback(module="caffeine.activate", button=1, cmd=[ 'notify-send "Consuming caffeine"', 'xset s off' ]) - output.add_callback(module="caffeine.deactivate", button=1, cmd=[ 'notify-send "Out of coffee"', 'xset s default' ]) - - def widgets(self): - output = subprocess.check_output(shlex.split("xset q")) - xset_out = output.decode().split("\n") - for line in xset_out: - if line.startswith(" timeout"): - timeout = int(line.split(" ")[4]) - if timeout == 0: - self._activated = 1; - else: - self._activated = 0; - break - - if self._activated == 0: - return bumblebee.output.Widget(self, "", instance="caffeine.activate") - elif self._activated == 1: - return bumblebee.output.Widget(self, "", instance="caffeine.deactivate") - - def state(self, widget): - if self._activated == 1: - return "activated" - else: - return "deactivated" - diff --git a/bumblebee/modules/cmus.py b/bumblebee/modules/cmus.py deleted file mode 100644 index de42ecf..0000000 --- a/bumblebee/modules/cmus.py +++ /dev/null @@ -1,78 +0,0 @@ -import string -import datetime -import subprocess -from collections import defaultdict - -import bumblebee.util -import bumblebee.module - -def description(): - return "Displays the current song and artist playing in cmus" - -def parameters(): - return [ - "cmus.format: Format of the displayed song information, arbitrary tags (as available from cmus-remote -Q) can be used (defaults to {artist} - {title} {position}/{duration})" - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._status = "default" - self._fmt = self._config.parameter("format", "{artist} - {title} {position}/{duration}") - - output.add_callback(module="cmus.prev", button=1, cmd="cmus-remote -r") - output.add_callback(module="cmus.next", button=1, cmd="cmus-remote -n") - output.add_callback(module="cmus.shuffle", button=1, cmd="cmus-remote -S") - output.add_callback(module="cmus.repeat", button=1, cmd="cmus-remote -R") - output.add_callback(module=self.instance(), button=1, cmd="cmus-remote -u") - - def _loadsong(self): - process = subprocess.Popen(["cmus-remote", "-Q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - self._query, self._error = process.communicate() - self._query = self._query.decode("utf-8").split("\n") - self._status = "default" - - def _tags(self): - tags = defaultdict(lambda: '') - self._repeat = False - self._shuffle = False - for line in self._query: - if line.startswith("status"): - status = line.split(" ", 2)[1] - self._status = status - if line.startswith("tag"): - key, value = line.split(" ", 2)[1:] - tags.update({ key: value }) - if line.startswith("duration"): - sec = line.split(" ")[1] - tags.update({ "duration": bumblebee.util.durationfmt(int(sec)) }) - if line.startswith("position"): - sec = line.split(" ")[1] - tags.update({ "position": bumblebee.util.durationfmt(int(sec)) }) - if line.startswith("set repeat "): - self._repeat = False if line.split(" ")[2] == "false" else True - if line.startswith("set shuffle "): - self._shuffle = False if line.split(" ")[2] == "false" else True - - return tags - - def widgets(self): - self._loadsong() - tags = self._tags() - - return [ - bumblebee.output.Widget(self, "", instance="cmus.prev"), - bumblebee.output.Widget(self, string.Formatter().vformat(self._fmt, (), tags)), - bumblebee.output.Widget(self, "", instance="cmus.next"), - bumblebee.output.Widget(self, "", instance="cmus.shuffle"), - bumblebee.output.Widget(self, "", instance="cmus.repeat"), - ] - - def state(self, widget): - if widget.instance() == "cmus.shuffle": - return "on" if self._shuffle else "off" - if widget.instance() == "cmus.repeat": - return "on" if self._repeat else "off" - return self._status - -# 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 619019b..0000000 --- a/bumblebee/modules/cpu.py +++ /dev/null @@ -1,30 +0,0 @@ -import bumblebee.module -import psutil - -def description(): - return "Displays CPU utilization across all CPUs." - -def parameters(): - return [ - "cpu.warning: Warning threshold in % of disk usage (defaults to 70%)", - "cpu.critical: Critical threshold in % of disk usage (defaults to 80%)", - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._perc = psutil.cpu_percent(percpu=False) - - output.add_callback(module=self.instance(), button=1, cmd="gnome-system-monitor") - - def widgets(self): - self._perc = psutil.cpu_percent(percpu=False) - return bumblebee.output.Widget(self, "{:05.02f}%".format(self._perc)) - - def warning(self, widget): - return self._perc > self._config.parameter("warning", 70) - - def critical(self, widget): - return self._perc > self._config.parameter("critical", 80) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/date.py b/bumblebee/modules/date.py deleted file mode 120000 index bde6404..0000000 --- a/bumblebee/modules/date.py +++ /dev/null @@ -1 +0,0 @@ -datetime.py \ No newline at end of file diff --git a/bumblebee/modules/datetime.py b/bumblebee/modules/datetime.py deleted file mode 120000 index 5a370f9..0000000 --- a/bumblebee/modules/datetime.py +++ /dev/null @@ -1 +0,0 @@ -time.py \ No newline at end of file diff --git a/bumblebee/modules/disk.py b/bumblebee/modules/disk.py deleted file mode 100644 index 67a79e1..0000000 --- a/bumblebee/modules/disk.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -import bumblebee.util -import bumblebee.module - -def description(): - return "Shows free diskspace, total diskspace and the percentage of free disk space." - -def parameters(): - return [ - "disk.warning: Warning threshold in % (defaults to 80%)", - "disk.critical: Critical threshold in % (defaults to 90%)" - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._path = self._config.parameter("path", "/") - - output.add_callback(module=self.instance(), button=1, cmd="nautilus {}".format(self._path)) - - def widgets(self): - st = os.statvfs(self._path) - - self._size = st.f_frsize*st.f_blocks - self._used = self._size - st.f_frsize*st.f_bavail - self._perc = 100.0*self._used/self._size - - return bumblebee.output.Widget(self, - "{} {}/{} ({:05.02f}%)".format(self._path, - bumblebee.util.bytefmt(self._used), - bumblebee.util.bytefmt(self._size), self._perc) - ) - - def warning(self, widget): - return self._perc > self._config.parameter("warning", 80) - - def critical(self, widget): - return self._perc > self._config.parameter("critical", 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 4101a8c..0000000 --- a/bumblebee/modules/dnf.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import absolute_import - -import time -import shlex -import threading -import subprocess - -import bumblebee.module -import bumblebee.util - -def description(): - return "Checks DNF for updated packages and displays the number of /// pending updates." - -def parameters(): - return [ "dnf.interval: Time in seconds between two checks for updates (defaults to 1800)" ] - -def get_dnf_info(obj): - loops = obj.interval() - - for thread in threading.enumerate(): - if thread.name == "MainThread": - main = thread - - while main.is_alive(): - loops += 1 - if loops < obj.interval(): - time.sleep(1) - continue - - loops = 0 - try: - res = subprocess.check_output(shlex.split("dnf updateinfo")) - except Exception as e: - break - - security = 0 - bugfixes = 0 - enhancements = 0 - other = 0 - for line in res.decode().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) - - obj.set("security", security) - obj.set("bugfixes", bugfixes) - obj.set("enhancements", enhancements) - obj.set("other", other) - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - - self._counter = {} - self._thread = threading.Thread(target=get_dnf_info, args=(self,)) - self._thread.start() - - def interval(self): - return self._config.parameter("interval", 30*60) - - def set(self, what, value): - self._counter[what] = value - - def get(self, what): - return self._counter.get(what, 0) - - def widgets(self): - result = [] - for t in [ "security", "bugfixes", "enhancements", "other" ]: - result.append(str(self.get(t))) - - return bumblebee.output.Widget(self, "/".join(result)) - - def state(self, widget): - total = sum(self._counter.values()) - if total == 0: return "good" - return "default" - - def warning(self, widget): - total = sum(self._counter.values()) - return total > 0 - - def critical(self, widget): - total = sum(self._counter.values()) - return total > 50 or self._counter.get("security", 0) > 0 - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/layout.py b/bumblebee/modules/layout.py deleted file mode 100644 index b317655..0000000 --- a/bumblebee/modules/layout.py +++ /dev/null @@ -1,67 +0,0 @@ -import subprocess -import shlex -import bumblebee.module -import bumblebee.util - -def description(): - return "Showws current keyboard layout and change it on click." - -def parameters(): - return [ - "layout.lang: pipe-separated list of languages to cycle through (e.g. us|rs|de). Default: en" - ] - - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - - self._languages = self._config.parameter("lang", "en").split("|") - self._idx = 0 - - output.add_callback(module=self.instance(), button=1, cmd=self.next_keymap) - output.add_callback(module=self.instance(), button=3, cmd=self.prev_keymap) - - def next_keymap(self, event, widget): - self._idx = self._idx + 1 if self._idx < len(self._languages) - 1 else 0 - self.set_keymap() - - def prev_keymap(self, event, widget): - self._idx = self._idx - 1 if self._idx > 0 else len(self._languages) - 1 - self.set_keymap() - - def set_keymap(self): - tmp = self._languages[self._idx].split(":") - layout = tmp[0] - variant = "" - if len(tmp) > 1: - variant = "-variant {}".format(tmp[1]) - bumblebee.util.execute("setxkbmap -layout {} {}".format(layout, variant)) - - def widgets(self): - res = bumblebee.util.execute("setxkbmap -query") - layout = None - variant = None - for line in res.split("\n"): - if not line: - continue - if "layout" in line: - layout = line.split(":")[1].strip() - if "variant" in line: - variant = line.split(":")[1].strip() - if variant: - layout += ":" + variant - - lang = self._languages[self._idx] - - if lang != layout: - if layout in self._languages: - self._idx = self._languages.index(layout) - else: - self._languages.append(layout) - self._idx = len(self._languages) - 1 - lang = layout - - return bumblebee.output.Widget(self, lang) - -# 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 aad9dfe..0000000 --- a/bumblebee/modules/load.py +++ /dev/null @@ -1,37 +0,0 @@ -import bumblebee.module -import multiprocessing -import os - -def description(): - return "Displays system load." - -def parameters(): - return [ - "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 80% of the number of CPUs)" - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._cpus = 1 - try: - self._cpus = multiprocessing.cpu_count() - except multiprocessing.NotImplementedError as e: - pass - - output.add_callback(module=self.instance(), button=1, cmd="gnome-system-monitor") - - def widgets(self): - self._load = os.getloadavg() - - return bumblebee.output.Widget(self, "{:.02f}/{:.02f}/{:.02f}".format( - self._load[0], self._load[1], self._load[2])) - - def warning(self, widget): - return self._load[0] > self._config.parameter("warning", self._cpus*0.7) - - def critical(self, widget): - return self._load[0] > self._config.parameter("critical", 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 d38ac0f..0000000 --- a/bumblebee/modules/memory.py +++ /dev/null @@ -1,38 +0,0 @@ -import psutil -import bumblebee.module -import bumblebee.util - -def description(): - return "Shows available RAM, total amount of RAM and the percentage of available RAM." - -def parameters(): - return [ - "memory.warning: Warning threshold in % of memory used (defaults to 80%)", - "memory.critical: Critical threshold in % of memory used (defaults to 90%)", - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._mem = psutil.virtual_memory() - - output.add_callback(module=self.instance(), button=1, cmd="gnome-system-monitor") - - def widgets(self): - self._mem = psutil.virtual_memory() - - used = self._mem.total - self._mem.available - - return bumblebee.output.Widget(self, "{}/{} ({:05.02f}%)".format( - bumblebee.util.bytefmt(used), - bumblebee.util.bytefmt(self._mem.total), - self._mem.percent) - ) - - def warning(self, widget): - return self._mem.percent > self._config.parameter("warning", 80) - - def critical(self, widget): - return self._mem.percent > self._config.parameter("critical", 90) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/nic.py b/bumblebee/modules/nic.py deleted file mode 100644 index 0db9e3a..0000000 --- a/bumblebee/modules/nic.py +++ /dev/null @@ -1,62 +0,0 @@ -import netifaces -import bumblebee.module - -def description(): - return "Displays the names, IP addresses and status of each available interface." - -def parameters(): - return [ - "nic.exclude: Comma-separated list of interface prefixes to exlude (defaults to: \"lo,virbr,docker,vboxnet,veth\")" - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._exclude = tuple(filter(len, self._config.parameter("exclude", "lo,virbr,docker,vboxnet,veth").split(","))) - - def widgets(self): - result = [] - interfaces = [ i for i in netifaces.interfaces() if not i.startswith(self._exclude) ] - for intf in interfaces: - addr = [] - state = "down" - try: - if netifaces.AF_INET in netifaces.ifaddresses(intf): - for ip in netifaces.ifaddresses(intf)[netifaces.AF_INET]: - if "addr" in ip and ip["addr"] != "": - addr.append(ip["addr"]) - state = "up" - except Exception as e: - addr = [] - widget = bumblebee.output.Widget(self, "{} {} {}".format( - intf, state, ", ".join(addr) - )) - widget.set("intf", intf) - widget.set("state", state) - result.append(widget) - - return result - - 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") - - def state(self, widget): - intf = widget.get("intf") - - iftype = "wireless" if self._iswlan(intf) else "wired" - iftype = "tunnel" if self._istunnel(intf) else iftype - - return "{}-{}".format(iftype, widget.get("state")) - - def warning(self, widget): - return widget.get("state") != "up" - - def critical(self, widget): - return widget.get("state") == "down" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/pacman.py b/bumblebee/modules/pacman.py deleted file mode 100644 index 3ecb5db..0000000 --- a/bumblebee/modules/pacman.py +++ /dev/null @@ -1,58 +0,0 @@ -import bumblebee.module -import subprocess -import os - -def description(): - return "Displays available updates per repository for pacman." - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - self._count = 0 - - def widgets(self): - path = os.path.dirname(os.path.abspath(__file__)) - if self._count == 0: - self._out = "?/?/?/?" - process = subprocess.Popen([ "{}/../../bin/customupdates".format(path) ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - self._query, self._error = process.communicate() - - if not process.returncode == 0: - self._out = "?/?/?/?" - else: - self._community = 0 - self._core = 0 - self._extra = 0 - self._other = 0 - - for line in self._query.splitlines(): - if line.startswith(b'http'): - if b"community" in line: - self._community += 1 - continue - if b"core" in line: - self._core += 1; - continue - if b"extra" in line: - self._extra += 1 - continue - self._other += 1 - self._out = str(self._core)+"/"+str(self._extra)+"/"+str(self._community)+"/"+str(self._other) - - self._count += 1 - self._count = 0 if self._count > 300 else self._count - return bumblebee.output.Widget(self, "{}".format(self._out)) - - def sumUpdates(self): - return self._core + self._community + self._extra + self._other - - def critical(self, widget): - #return self._sumUpdates(self) - return self.sumUpdates() > 0 - - - - - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/pasink.py b/bumblebee/modules/pasink.py deleted file mode 120000 index 85ea20d..0000000 --- a/bumblebee/modules/pasink.py +++ /dev/null @@ -1 +0,0 @@ -pulseaudio.py \ No newline at end of file diff --git a/bumblebee/modules/pasource.py b/bumblebee/modules/pasource.py deleted file mode 120000 index 85ea20d..0000000 --- a/bumblebee/modules/pasource.py +++ /dev/null @@ -1 +0,0 @@ -pulseaudio.py \ No newline at end of file diff --git a/bumblebee/modules/ping.py b/bumblebee/modules/ping.py deleted file mode 100644 index b523788..0000000 --- a/bumblebee/modules/ping.py +++ /dev/null @@ -1,97 +0,0 @@ -from __future__ import absolute_import - -import re -import time -import shlex -import threading -import subprocess - -import bumblebee.module -import bumblebee.util - -def description(): - return "Periodically checks the RTT of a configurable IP" - -def parameters(): - return [ - "ping.interval: Time in seconds between two RTT checks (defaults to 60)", - "ping.address: IP address to check", - "ping.warning: Threshold for warning state, in seconds (defaults to 1.0)", - "ping.critical: Threshold for critical state, in seconds (defaults to 2.0)", - "ping.timeout: Timeout for waiting for a reply (defaults to 5.0)", - "ping.probes: Number of probes to send (defaults to 5)", - ] - -def get_rtt(obj): - loops = obj.get("interval") - - for thread in threading.enumerate(): - if thread.name == "MainThread": - main = thread - - interval = obj.get("interval") - while main.is_alive(): - loops += 1 - if loops < interval: - time.sleep(1) - continue - - loops = 0 - try: - res = subprocess.check_output(shlex.split("ping -n -q -c {} -W {} {}".format( - obj.get("rtt-probes"), obj.get("rtt-timeout"), obj.get("address") - ))) - obj.set("rtt-unreachable", False) - - for line in res.decode().split("\n"): - if not line.startswith("rtt"): continue - m = re.search(r'([0-9\.]+)/([0-9\.]+)/([0-9\.]+)/([0-9\.]+)\s+(\S+)', line) - - obj.set("rtt-min", float(m.group(1))) - obj.set("rtt-avg", float(m.group(2))) - obj.set("rtt-max", float(m.group(3))) - obj.set("rtt-unit", m.group(5)) - except Exception as e: - obj.set("rtt-unreachable", True) - - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - - self._counter = {} - - self.set("address", self._config.parameter("address", "8.8.8.8")) - self.set("interval", self._config.parameter("interval", 60)) - self.set("rtt-probes", self._config.parameter("probes", 5)) - self.set("rtt-timeout", self._config.parameter("timeout", 5.0)) - - self._thread = threading.Thread(target=get_rtt, args=(self,)) - self._thread.start() - - def set(self, what, value): - self._counter[what] = value - - def get(self, what): - return self._counter.get(what, 0) - - def widgets(self): - text = "{}: {:.1f}{}".format( - self.get("address"), - self.get("rtt-avg"), - self.get("rtt-unit") - ) - - if self.get("rtt-unreachable"): - text = "{}: unreachable".format(self.get("address")) - - return bumblebee.output.Widget(self, text) - - def warning(self, widget): - return self.get("rtt-avg") > float(self._config.parameter("warning", 1.0))*1000.0 - - def critical(self, widget): - if self.get("rtt-unreachable"): return True - return self.get("rtt-avg") > float(self._config.parameter("critical", 2.0))*1000.0 - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/pulseaudio.py b/bumblebee/modules/pulseaudio.py deleted file mode 100644 index 079e07c..0000000 --- a/bumblebee/modules/pulseaudio.py +++ /dev/null @@ -1,92 +0,0 @@ -import re -import shlex -import subprocess - -import bumblebee.module -import bumblebee.util - -def description(): - module = __name__.split(".")[-1] - if module == "pasink": - return "Shows volume and mute status of the default PulseAudio Sink." - if module == "pasource": - return "Shows volume and mute status of the default PulseAudio Source." - return "See 'pasource'." - -def parameters(): - return [ "none" ] - - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - - self._module = self.__module__.split(".")[-1] - self._left = 0 - self._right = 0 - self._mono = 0 - self._mute = False - channel = "sink" if self._module == "pasink" else "source" - - output.add_callback(module=self.instance(), button=3, - cmd="pavucontrol") - output.add_callback(module=self.instance(), button=1, - cmd="pactl set-{}-mute @DEFAULT_{}@ toggle".format(channel, channel.upper())) - output.add_callback(module=self.instance(), button=4, - cmd="pactl set-{}-volume @DEFAULT_{}@ +2%".format(channel, channel.upper())) - output.add_callback(module=self.instance(), button=5, - cmd="pactl set-{}-volume @DEFAULT_{}@ -2%".format(channel, channel.upper())) - - def widgets(self): - res = subprocess.check_output(shlex.split("pactl info")) - channel = "sinks" if self._module == "pasink" else "sources" - name = None - for line in res.decode().split("\n"): - if line.startswith("Default Sink: ") and channel == "sinks": - name = line[14:] - if line.startswith("Default Source: ") and channel == "sources": - name = line[16:] - - res = subprocess.check_output(shlex.split("pactl list {}".format(channel))) - - found = False - for line in res.decode().split("\n"): - if "Name:" in line and found == True: - break - if name in line: - found = True - if "Mute:" in line and found == True: - self._mute = False if " no" in line.lower() else True - - if "Volume:" in line and found == True: - m = None - if "mono" in line: - m = re.search(r'mono:.*\s*\/\s*(\d+)%', line) - else: - m = re.search(r'left:.*\s*\/\s*(\d+)%.*right:.*\s*\/\s*(\d+)%', line) - if not m: continue - - if "mono" in line: - self._mono = m.group(1) - else: - self._left = m.group(1) - self._right = m.group(2) - result = "" - if int(self._mono) > 0: - result = "{}%".format(self._mono) - elif self._left == self._right: - result = "{}%".format(self._left) - else: - result="{}%/{}%".format(self._left, self._right) - return bumblebee.output.Widget(self, result) - - def state(self, widget): - return "muted" if self._mute is True else "unmuted" - - def warning(self, widget): - return self._mute - - def critical(self, widget): - return False - -# 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 f9b88d3..0000000 --- a/bumblebee/modules/spacer.py +++ /dev/null @@ -1,17 +0,0 @@ -import bumblebee.module -import bumblebee.util - -def description(): - return "Draws a widget with configurable content." - -def parameters(): - return [ "spacer.text: Text to draw (defaults to '')" ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - - def widgets(self): - return bumblebee.output.Widget(self, self._config.parameter("text", "")) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/time.py b/bumblebee/modules/time.py deleted file mode 100644 index 68f1beb..0000000 --- a/bumblebee/modules/time.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import absolute_import - -import datetime -import bumblebee.module - -def description(): - return "Displays the current time, using the optional format string as input for strftime." - -def parameters(): - module = __name__.split(".")[-1] - return [ - "{}.format: strftime specification (defaults to {})".format(module, default_format(module)) - ] - -def default_format(module): - default = "%x %X" - if module == "date": - default = "%x" - if module == "time": - default = "%X" - return default - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - - module = self.__module__.split(".")[-1] - - self._fmt = self._config.parameter("format", default_format(module)) - - def widgets(self): - return bumblebee.output.Widget(self, datetime.datetime.now().strftime(self._fmt)) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/xrandr.py b/bumblebee/modules/xrandr.py deleted file mode 100644 index 7817143..0000000 --- a/bumblebee/modules/xrandr.py +++ /dev/null @@ -1,89 +0,0 @@ -import bumblebee.module -import bumblebee.util -import re -import os -import sys -import subprocess - -def description(): - return "Shows all connected screens" - -def parameters(): - return [ - ] - -class Module(bumblebee.module.Module): - def __init__(self, output, config): - super(Module, self).__init__(output, config) - - self._widgets = [] - - def toggle(self, event, widget): - path = os.path.dirname(os.path.abspath(__file__)) - toggle_cmd = "{}/../../bin/toggle-display.sh".format(path) - - if widget.get("state") == "on": - bumblebee.util.execute("{} --output {} --off".format(toggle_cmd, widget.get("display"))) - else: - neighbor = None - for w in self._widgets: - if w.get("state") == "on": - neighbor = w - if event.get("button") == 1: - break - - if neighbor == None: - bumblebee.util.execute("{} --output {} --auto".format(toggle_cmd, - widget.get("display"))) - else: - bumblebee.util.execute("{} --output {} --auto --{}-of {}".format(toggle_cmd, - widget.get("display"), "left" if event.get("button") == 1 else "right", - neighbor.get("display"))) - - def widgets(self): - process = subprocess.Popen([ "xrandr", "-q" ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output, error = process.communicate() - - widgets = [] - - for line in output.split("\n"): - if not " connected" in line: - continue - display = line.split(" ", 2)[0] - m = re.search(r'\d+x\d+\+(\d+)\+\d+', line) - - widget = bumblebee.output.Widget(self, display, instance=display) - widget.set("display", display) - - # not optimal (add callback once per interval), but since - # add_callback() just returns if the callback has already - # been registered, it should be "ok" - self._output.add_callback(module=display, button=1, - cmd=self.toggle) - self._output.add_callback(module=display, button=3, - cmd=self.toggle) - if m: - widget.set("state", "on") - widget.set("pos", int(m.group(1))) - else: - widget.set("state", "off") - widget.set("pos", sys.maxint) - - widgets.append(widget) - - widgets.sort(key=lambda widget : widget.get("pos")) - - self._widgets = widgets - - return widgets - - def state(self, widget): - return widget.get("state", "off") - - def warning(self, widget): - return False - - def critical(self, widget): - return False - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/output.py b/bumblebee/output.py deleted file mode 100644 index cfdc88b..0000000 --- a/bumblebee/output.py +++ /dev/null @@ -1,121 +0,0 @@ -import os -import inspect -import threading -import bumblebee.util - -def output(args): - import bumblebee.outputs.i3 - return bumblebee.outputs.i3.Output(args) - -class Widget(object): - def __init__(self, obj, text, instance=None): - self._obj = obj - self._text = text - self._store = {} - self._instance = instance - - obj._output.register_widget(self.instance(), self) - - def set(self, key, value): - self._store[key] = value - - def get(self, key, default=None): - return self._store.get(key, default) - - def state(self): - return self._obj.state(self) - - def warning(self): - return self._obj.warning(self) - - def critical(self): - return self._obj.critical(self) - - def module(self): - return self._obj.__module__.split(".")[-1] - - def instance(self): - return self._instance if self._instance else getattr(self._obj, "instance")(self) - - def text(self): - return self._text - -class Command(object): - def __init__(self, command, event, widget): - self._command = command - self._event = event - self._widget = widget - - def __call__(self, *args, **kwargs): - if not isinstance(self._command, list): - self._command = [ self._command ] - - for cmd in self._command: - if not cmd: continue - if inspect.ismethod(cmd): - cmd(self._event, self._widget) - else: - c = cmd.format(*args, **kwargs) - bumblebee.util.execute(c, False) - -class Output(object): - def __init__(self, config): - self._config = config - self._callbacks = {} - self._wait = threading.Condition() - self._wait.acquire() - self._widgets = {} - - def register_widget(self, identity, widget): - self._widgets[identity] = widget - - def redraw(self): - self._wait.acquire() - self._wait.notify() - self._wait.release() - - def add_callback(self, cmd, button, module=None): - if module: - module = module.replace("bumblebee.modules.", "") - - if self._callbacks.get((button, module)): return - - self._callbacks[( - button, - module, - )] = cmd - - def callback(self, event): - cb = self._callbacks.get(( - event.get("button", -1), - None, - ), None) - cb = self._callbacks.get(( - event.get("button", -1), - event.get("instance", event.get("module", None)), - ), cb) - - identity = event.get("instance", event.get("module", None)) - return Command(cb, event, self._widgets.get(identity, None)) - - def wait(self): - self._wait.wait(self._config.parameter("interval", 1)) - - def draw(self, widgets, theme): - if not type(widgets) is list: - widgets = [ widgets ] - self._draw(widgets, theme) - - def start(self): - pass - - def _draw(self, widgets, theme): - pass - - def flush(self): - pass - - def stop(self): - pass - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/outputs/__init__.py b/bumblebee/outputs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/bumblebee/outputs/i3.py b/bumblebee/outputs/i3.py deleted file mode 100644 index d9d1894..0000000 --- a/bumblebee/outputs/i3.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import unicode_literals - -import os -import sys -import json -import shlex -import threading -import subprocess -import bumblebee.output - -def read_input(output): - while True: - line = sys.stdin.readline().strip(",").strip() - if line == "[": continue - if line == "]": break - - event = json.loads(line) - cb = output.callback(event) - if cb: - cb( - name=event.get("name", ""), - instance=event.get("instance", ""), - button=event.get("button", -1) - ) - output.redraw() - -class Output(bumblebee.output.Output): - def __init__(self, args): - super(Output, self).__init__(args) - self._data = [] - - self.add_callback("i3-msg workspace prev_on_output", 4) - self.add_callback("i3-msg workspace next_on_output", 5) - - self._thread = threading.Thread(target=read_input, args=(self,)) - self._thread.start() - - def start(self): - print(json.dumps({ "version": 1, "click_events": True }) + "[") - - def _draw(self, widgets, theme): - for widget in widgets: - if theme.separator(widget): - self._data.append({ - u"full_text": theme.separator(widget), - "color": theme.separator_color(widget), - "background": theme.separator_background(widget), - "separator": False, - "separator_block_width": 0, - }) - - self._data.append({ - u"full_text": " {} {} {}".format( - theme.prefix(widget), - widget.text(), - theme.suffix(widget) - ), - "color": theme.color(widget), - "background": theme.background(widget), - "name": widget.module(), - "instance": widget.instance(), - "separator": theme.default_separators(widget, False), - "separator_block_width": theme.separator_block_width(widget, 0), - }) - theme.next_widget() - - def flush(self): - data = json.dumps(self._data) - self._data = [] - print(data + ",") - sys.stdout.flush() - - def stop(self): - return "]" - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/theme.py b/bumblebee/theme.py deleted file mode 100644 index 42e6c01..0000000 --- a/bumblebee/theme.py +++ /dev/null @@ -1,129 +0,0 @@ -import os -import copy -import json -import yaml -import glob - -def getpath(): - return os.path.dirname("{}/../themes/".format(os.path.dirname(os.path.realpath(__file__)))) - -def themes(): - d = getpath() - return [ os.path.basename(f).replace(".json", "") for f in glob.iglob("{}/*.json".format(d)) ] - -class Theme: - def __init__(self, config): - self._config = config - - self._data = self.get_theme(config.theme()) - - for iconset in self._data.get("icons", []): - self.merge(self._data, self.get_theme(iconset)) - - self._defaults = self._data.get("defaults", {}) - self._cycles = self._defaults.get("cycle", []) - self.begin() - - def get_theme(self, name): - for path in [ getpath(), "{}/icons/".format(getpath()) ]: - if os.path.isfile("{}/{}.yaml".format(path, name)): - with open("{}/{}.yaml".format(path, name)) as f: - return yaml.load(f) - if os.path.isfile("{}/{}.json".format(path, name)): - with open("{}/{}.json".format(path, name)) as f: - return json.load(f) - return None - - # algorithm copied from - # http://blog.impressiver.com/post/31434674390/deep-merge-multiple-python-dicts - # nicely done :) - def merge(self, target, *args): - 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: - target[key] = copy.deepcopy(value) - return target - - def begin(self): - self._config.set("theme.cycleidx", 0) - self._cycle = self._cycles[0] if len(self._cycles) > 0 else {} - self._background = [ None, None ] - - def next_widget(self): - self._background[1] = self._background[0] - idx = self._config.increase("theme.cycleidx", len(self._cycles), 0) - self._cycle = self._cycles[idx] if len(self._cycles) > idx else {} - - def prefix(self, widget): - return self._get(widget, "prefix", "") - - def suffix(self, widget): - return self._get(widget, "suffix", "") - - def color(self, widget): - result = self._get(widget, "fg") - if widget.warning(): - result = self._get(widget, "fg-warning") - if widget.critical(): - result = self._get(widget, "fg-critical") - return result - - def background(self, widget): - result = self._get(widget, "bg") - if widget.warning(): - result = self._get(widget, "bg-warning") - if widget.critical(): - result = self._get(widget, "bg-critical") - self._background[0] = result - return result - - def separator(self, widget): - return self._get(widget, "separator") - - def default_separators(self, widget, default): - return self._get(widget, "default-separators", default) - - def separator_color(self, widget): - return self.background(widget) - - def separator_background(self, widget): - return self._background[1] - - def separator_block_width(self, widget, default): - return self._get(widget, "separator-block-width", default) - - def _get(self, widget, name, default = None): - module = widget.module() - state = widget.state() - inst = widget.instance() - inst = inst.replace("{}.".format(module), "") - module_theme = self._data.get(module, {}) - state_theme = module_theme.get("states", {}).get(state, {}) - instance_theme = module_theme.get(inst, {}) - instance_state_theme = instance_theme.get("states", {}).get(state, {}) - - value = None - value = self._defaults.get(name, value) - value = self._cycle.get(name, value) - value = module_theme.get(name, value) - value = state_theme.get(name, value) - value = instance_theme.get(name, value) - value = instance_state_theme.get(name, value) - - if type(value) is list: - key = "{}{}".format(widget.instance(), value) - idx = self._config.increase(key, len(value), 0) - value = value[idx] - - return value if value else default - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/util.py b/bumblebee/util.py deleted file mode 100644 index 3a6a60c..0000000 --- a/bumblebee/util.py +++ /dev/null @@ -1,33 +0,0 @@ -import shlex -import subprocess -try: - from exceptions import RuntimeError -except ImportError: - # Python3 doesn't require this anymore - pass - -def bytefmt(num): - for unit in [ "", "Ki", "Mi", "Gi" ]: - if num < 1024.0: - return "{:.2f}{}B".format(num, unit) - num /= 1024.0 - return "{:05.2f%}{}GiB".format(num) - -def durationfmt(duration): - minutes, seconds = divmod(duration, 60) - hours, minutes = divmod(minutes, 60) - res = "{:02d}:{:02d}".format(minutes, seconds) - if hours > 0: res = "{:02d}:{}".format(hours, res) - - return res - -def execute(cmd, wait=True): - args = shlex.split(cmd) - p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - - if wait: - out, err = p.communicate() - if p.returncode != 0: - raise RuntimeError("{} exited with {}".format(cmd, p.returncode)) - return out.decode("utf-8") - return None 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/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 f160ba2..0000000 Binary files a/screenshots/cpu.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/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/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/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/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/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/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/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/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 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_cpu.py b/tests/modules/test_cpu.py deleted file mode 100644 index 3b3fa65..0000000 --- a/tests/modules/test_cpu.py +++ /dev/null @@ -1,26 +0,0 @@ -import unittest - -import bumblebee.config -import bumblebee.modules.cpu - -class FakeOutput(object): - def add_callback(self, cmd, button, module=None): - pass - -class TestCpuModule(unittest.TestCase): - def setUp(self): - output = FakeOutput() - config = bumblebee.config.Config(["-m", "cpu"]) - self.cpu = bumblebee.modules.cpu.Module(output, config, None) - - def test_documentation(self): - self.assertTrue(hasattr(bumblebee.modules.cpu, "description")) - self.assertTrue(hasattr(bumblebee.modules.cpu, "parameters")) - - def test_warning(self): - self.assertTrue(hasattr(self.cpu, "warning")) - - def test_critical(self): - self.assertTrue(hasattr(self.cpu, "critical")) - -# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_config.py b/tests/test_config.py index 6891eab..66fd1d8 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,10 +1,18 @@ import unittest -import bumblebee.config +from bumblebee.config import Config -class TestConfigCreation(unittest.TestCase): +class TestConfig(unittest.TestCase): def setUp(self): - pass + self.defaultConfig = Config() + self.someSimpleModules = [ "foo", "bar", "baz" ] + def test_no_modules_by_default(self): + self.assertEquals(self.defaultConfig.modules(), []) + + def test_load_simple_modules(self): + cfg = Config([ "-m" ] + self.someSimpleModules) + self.assertEquals(cfg.modules(), + map(lambda x: { "name": x, "module": x }, self.someSimpleModules)) # 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/gruvbox-powerline.json b/themes/gruvbox-powerline.json deleted file mode 100644 index f04bbc7..0000000 --- a/themes/gruvbox-powerline.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "icons": [ "paxy97", "awesome-fonts" ], - "defaults": { - "prefix": " ", - "suffix" : " ", - "cycle": [ - { - "fg": "#ebdbb2", - "bg": "#1d2021" - }, - { - "fg": "#fbf1c7", - "bg": "#282828" - } - ], - "fg-critical": "#fbf1c7", - "bg-critical": "#cc241d", - "fg-warning": "#1d2021", - "bg-warning": "#d79921", - - "default-separators": false, - "separator-block-width": 0 - }, - "dnf": { - "states": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - } - }, - "battery": { - "states": { - "charged": { - "fg": "#1d2021", - "bg": "#b8bb26" - }, - "AC": { - "fg": "#1d2021", - "bg": "#b8bb26" - } - } - } -} diff --git a/themes/icons/ascii.json b/themes/icons/ascii.json deleted file mode 100644 index bd051ce..0000000 --- a/themes/icons/ascii.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "memory": { - "prefix": "ram" - }, - "cpu": { - "prefix": "cpu" - }, - "disk": { - "prefix": "hdd" - }, - "dnf": { - "prefix": "dnf" - }, - "brightness": { - "prefix": "o" - }, - "cmus": { - "states": { - "playing": { - "prefix": ">" - }, - "paused": { - "prefix": "||" - }, - "stopped": { - "prefix": "[]" - } - }, - "prev": { - "prefix": "|<" - }, - "next": { - "prefix": ">|" - }, - "shuffle": { - "states": { "on": { "prefix": "S" }, "off": { "prefix": "[s]" } } - }, - "repeat": { - "states": { "on": { "prefix": "R" }, "off": { "prefix": "[r]" } } - } - }, - "pasink": { - "states": { - "muted": { - "prefix": "audio(mute)" - }, - "unmuted": { - "prefix": "audio" - } - } - }, - "pasource": { - "states": { - "muted": { - "prefix": "mic(mute)" - }, - "unmuted": { - "prefix": "mic" - } - } - }, - "nic": { - "states": { - "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": { - "states": { - "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" - } - } - }, - "caffeine": { - "states": { "activated": {"prefix": "caf-on" }, "deactivated": { "prefix": "caf-off " } } - }, - "xrandr": { - "states": { "on": { "prefix": " off "}, "off": { "prefix": " on "} } - } -} diff --git a/themes/icons/awesome-fonts.json b/themes/icons/awesome-fonts.json deleted file mode 100644 index 62d9294..0000000 --- a/themes/icons/awesome-fonts.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "defaults": { - "separator": "" - }, - "date": { - "prefix": "" - }, - "time": { - "prefix": "" - }, - "memory": { - "prefix": "" - }, - "cpu": { - "prefix": "" - }, - "disk": { - "prefix": "" - }, - "dnf": { - "prefix": "" - }, - "brightness": { - "prefix": "" - }, - "cmus": { - "states": { - "playing": { - "prefix": "" - }, - "paused": { - "prefix": "" - }, - "stopped": { - "prefix": "" - } - }, - "prev": { - "prefix": "" - }, - "next": { - "prefix": "" - }, - "shuffle": { - "states": { "on": { "prefix": "" }, "off": { "prefix": "" } } - }, - "repeat": { - "states": { "on": { "prefix": "" }, "off": { "prefix": "" } } - } - }, - "pasink": { - "states": { - "muted": { - "prefix": "" - }, - "unmuted": { - "prefix": "" - } - } - }, - "pasource": { - "states": { - "muted": { - "prefix": "" - }, - "unmuted": { - "prefix": "" - } - } - }, - "nic": { - "states": { - "wireless-up": { - "prefix": "" - }, - "wireless-down": { - "prefix": "" - }, - "wired-up": { - "prefix": "" - }, - "wired-down": { - "prefix": "" - }, - "tunnel-up": { - "prefix": "" - }, - "tunnel-down": { - "prefix": "" - } - } - }, - "battery": { - "states": { - "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": "" - } - } - }, - "caffeine": { - "states": { "activated": {"prefix": " " }, "deactivated": { "prefix": " " } } - }, - "xrandr": { - "states": { "on": { "prefix": " "}, "off": { "prefix": " "} } - } -} 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/powerline.json b/themes/powerline.json deleted file mode 100644 index bfec776..0000000 --- a/themes/powerline.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "cycle": [ - { - "fg": "#ffd700", - "bg": "#d75f00" - }, - { - "fg": "#ffffff", - "bg": "#0087af" - } - ], - "fg-critical": "#ffffff", - "bg-critical": "#ff0000", - "fg-warning": "#d75f00", - "bg-warning": "#ffd700", - - "default_separators": false - }, - "dnf": { - "states": { - "good": { - "fg": "#494949", - "bg": "#41db00" - } - } - }, - "battery": { - "states": { - "charged": { - "fg": "#494949", - "bg": "#41db00" - }, - "AC": { - "fg": "#494949", - "bg": "#41db00" - } - } - } -} diff --git a/themes/solarized-powerline.json b/themes/solarized-powerline.json deleted file mode 100644 index 998b7f4..0000000 --- a/themes/solarized-powerline.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "icons": [ "awesome-fonts" ], - "defaults": { - "cycle": [ - { - "fg": "#93a1a1", - "bg": "#002b36" - }, - { - "fg": "#eee8d5", - "bg": "#586e75" - } - ], - "fg-critical": "#002b36", - "bg-critical": "#dc322f", - "fg-warning": "#002b36", - "bg-warning": "#b58900", - - "default-separators": false, - "separator-block-width": 0 - }, - "dnf": { - "states": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - } - }, - "battery": { - "states": { - "charged": { - "fg": "#002b36", - "bg": "#859900" - }, - "AC": { - "fg": "#002b36", - "bg": "#859900" - } - } - } -} diff --git a/themes/solarized.json b/themes/solarized.json deleted file mode 100644 index 5cc8f86..0000000 --- a/themes/solarized.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "icons": [ "ascii" ], - "defaults": { - "cycle": [ - { - "fg": "#93a1a1", - "bg": "#002b36" - }, - { - "fg": "#eee8d5", - "bg": "#586e75" - } - ], - "fg-critical": "#002b36", - "bg-critical": "#dc322f", - "fg-warning": "#002b36", - "bg-warning": "#b58900", - - "default_separators": false, - "separator": "" - }, - "dnf": { - "states": { - "good": { - "fg": "#002b36", - "bg": "#859900" - } - } - }, - "battery": { - "states": { - "charged": { - "fg": "#002b36", - "bg": "#859900" - }, - "AC": { - "fg": "#002b36", - "bg": "#859900" - } - } -}