Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
928895befe
33 changed files with 1859 additions and 680 deletions
|
@ -2,7 +2,6 @@ sudo: false
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- "2.7"
|
- "2.7"
|
||||||
- "3.3"
|
|
||||||
- "3.4"
|
- "3.4"
|
||||||
- "3.5"
|
- "3.5"
|
||||||
- "3.6"
|
- "3.6"
|
||||||
|
|
12
PKGBUILD
12
PKGBUILD
|
@ -1,8 +1,9 @@
|
||||||
# Maintainer: Tobias Witek <tobi@tobi-wan-kenobi.at>
|
# Maintainer: Tobias Witek <tobi@tobi-wan-kenobi.at>
|
||||||
# Contributor: Daniel M. Capella <polycitizen@gmail.com>
|
# Contributor: Daniel M. Capella <polycitizen@gmail.com>
|
||||||
|
# Contributor: spookykidmm <https://github.com/spookykidmm>
|
||||||
|
|
||||||
pkgname=bumblebee-status
|
pkgname=bumblebee-status
|
||||||
pkgver=1.4.2
|
pkgver=1.8.0
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc='Modular, theme-able status line generator for the i3 window manager'
|
pkgdesc='Modular, theme-able status line generator for the i3 window manager'
|
||||||
arch=('any')
|
arch=('any')
|
||||||
|
@ -22,9 +23,10 @@ optdepends=('xorg-xbacklight: to display a displays brightness'
|
||||||
'i3ipc-python: display titlebar'
|
'i3ipc-python: display titlebar'
|
||||||
'fakeroot: dependency of the pacman module'
|
'fakeroot: dependency of the pacman module'
|
||||||
'pytz: timezone conversion for datetimetz module'
|
'pytz: timezone conversion for datetimetz module'
|
||||||
'tzlocal: retrieve system timezone for datetimetz module')
|
'tzlocal: retrieve system timezone for datetimetz module'
|
||||||
|
)
|
||||||
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
|
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
|
||||||
sha512sums=('3a66fc469dd3b081337c9e213a1b2262f25f30977ee6ef65b9fa5a8b6aa341637832d1a5dbb74e30d68e2824e0d19d7a911eb3390dc6062707a552f429b483e8')
|
sha512sums=('b985e6619856519a92bd1a9d2a762997e8920a0ef5007f20063fcb2f9afeb193de67e8b0737182576f79ee19b2dd3e6388bb9b987480b7bc19b537f64e9b5685')
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
install -d "$pkgdir"/usr/bin \
|
install -d "$pkgdir"/usr/bin \
|
||||||
|
@ -32,8 +34,8 @@ package() {
|
||||||
ln -s /usr/share/$pkgname/$pkgname "$pkgdir"/usr/bin/$pkgname
|
ln -s /usr/share/$pkgname/$pkgname "$pkgdir"/usr/bin/$pkgname
|
||||||
|
|
||||||
cd $pkgname-$pkgver
|
cd $pkgname-$pkgver
|
||||||
cp -a --parents $pkgname bumblebee/{,modules/}*.py themes/{,icons/}*.json \
|
cp -a --parents $pkgname bumblebee/{,modules/}*.py themes/{,icons/}*.json $pkgdir/usr/share/$pkgname
|
||||||
"$pkgdir"/usr/share/$pkgname
|
cp -r bin $pkgdir/usr/share/$pkgname/
|
||||||
|
|
||||||
install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE
|
install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE
|
||||||
}
|
}
|
||||||
|
|
16
README.md
16
README.md
|
@ -5,7 +5,7 @@
|
||||||
[](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
[](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
|
||||||
[](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
[](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
|
||||||
|
|
||||||
**Many, many thanks to all contributors! As of now, 41 of the modules are from various contributors (!), and only 18 from myself.**
|
**Many, many thanks to all contributors! As of now, 47 of the modules are from various contributors (!), and only 19 from myself.**
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -38,6 +38,10 @@ Explicitly unsupported Python versions: 3.2 (missing unicode literals)
|
||||||
# Arch Linux
|
# Arch Linux
|
||||||
$ sudo pacman -S awesome-terminal-fonts
|
$ sudo pacman -S awesome-terminal-fonts
|
||||||
|
|
||||||
|
# FreeBSD
|
||||||
|
$ sudo pkg install font-awesome
|
||||||
|
$ sudo pkg install py36-tzlocal py36-pytz py36-netifaces py36-psutil py36-requests #for dependencies
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
# see https://github.com/gabrielelana/awesome-terminal-fonts
|
# see https://github.com/gabrielelana/awesome-terminal-fonts
|
||||||
```
|
```
|
||||||
|
@ -76,7 +80,10 @@ In your i3wm configuration, modify the *status_command* for your i3bar like this
|
||||||
|
|
||||||
```
|
```
|
||||||
bar {
|
bar {
|
||||||
status_command <path to bumblebee-status/bumblebee-status> -m <list of modules> -p <list of module parameters> -t <theme>
|
status_command <path to bumblebee-status/bumblebee-status> \
|
||||||
|
-m <list of modules> \
|
||||||
|
-p <list of module parameters> \
|
||||||
|
-t <theme>
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -180,7 +187,7 @@ Modules and commandline utilities are only required for modules, the core itself
|
||||||
|
|
||||||
* psutil (for the modules 'cpu', 'memory', 'traffic')
|
* psutil (for the modules 'cpu', 'memory', 'traffic')
|
||||||
* netifaces (for the modules 'nic', 'traffic')
|
* netifaces (for the modules 'nic', 'traffic')
|
||||||
* requests (for the modules 'weather', 'github', 'getcrypto', 'stock', 'currency')
|
* requests (for the modules 'weather', 'github', 'getcrypto', 'stock', 'currency', 'sun')
|
||||||
* power (for the module 'battery')
|
* power (for the module 'battery')
|
||||||
* dbus (for the module 'spotify')
|
* dbus (for the module 'spotify')
|
||||||
* i3ipc (for the module 'title')
|
* i3ipc (for the module 'title')
|
||||||
|
@ -188,6 +195,8 @@ Modules and commandline utilities are only required for modules, the core itself
|
||||||
* docker (for the module 'docker_ps')
|
* docker (for the module 'docker_ps')
|
||||||
* pytz (for the module 'datetimetz')
|
* pytz (for the module 'datetimetz')
|
||||||
* localtz (for the module 'datetimetz')
|
* localtz (for the module 'datetimetz')
|
||||||
|
* suntime (for the module 'sun')
|
||||||
|
* feedparser (for the module 'rss')
|
||||||
|
|
||||||
# Required commandline utilities
|
# Required commandline utilities
|
||||||
|
|
||||||
|
@ -210,6 +219,7 @@ Modules and commandline utilities are only required for modules, the core itself
|
||||||
* sensors (for module 'sensors', as fallback)
|
* sensors (for module 'sensors', as fallback)
|
||||||
* zpool (for module 'zpool')
|
* zpool (for module 'zpool')
|
||||||
* progress (for module 'progress')
|
* progress (for module 'progress')
|
||||||
|
* i3exit (for module 'system')
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
Here are some screenshots for all themes that currently exist:
|
Here are some screenshots for all themes that currently exist:
|
||||||
|
|
|
@ -84,7 +84,7 @@ class Config(bumblebee.store.Store):
|
||||||
|
|
||||||
parameters = [item for sub in self._args.parameters for item in sub]
|
parameters = [item for sub in self._args.parameters for item in sub]
|
||||||
for param in parameters:
|
for param in parameters:
|
||||||
key, value = param.split("=")
|
key, value = param.split("=", 1)
|
||||||
self.set(key, value)
|
self.set(key, value)
|
||||||
|
|
||||||
def modules(self):
|
def modules(self):
|
||||||
|
|
|
@ -41,6 +41,7 @@ class Module(object):
|
||||||
self.error = None
|
self.error = None
|
||||||
self._next = int(time.time())
|
self._next = int(time.time())
|
||||||
self._default_interval = 0
|
self._default_interval = 0
|
||||||
|
self._engine = engine
|
||||||
|
|
||||||
self._configFile = None
|
self._configFile = None
|
||||||
for cfg in [os.path.expanduser("~/.bumblebee-status.conf"), os.path.expanduser("~/.config/bumblebee-status.conf")]:
|
for cfg in [os.path.expanduser("~/.bumblebee-status.conf"), os.path.expanduser("~/.config/bumblebee-status.conf")]:
|
||||||
|
@ -56,6 +57,9 @@ class Module(object):
|
||||||
if widgets:
|
if widgets:
|
||||||
self._widgets = widgets if isinstance(widgets, list) else [widgets]
|
self._widgets = widgets if isinstance(widgets, list) else [widgets]
|
||||||
|
|
||||||
|
def theme(self):
|
||||||
|
return self._engine.theme()
|
||||||
|
|
||||||
def widgets(self, widgets=None):
|
def widgets(self, widgets=None):
|
||||||
"""Return the widgets to draw for this module"""
|
"""Return the widgets to draw for this module"""
|
||||||
if widgets:
|
if widgets:
|
||||||
|
@ -160,6 +164,9 @@ class Engine(object):
|
||||||
|
|
||||||
self.input.start()
|
self.input.start()
|
||||||
|
|
||||||
|
def theme(self):
|
||||||
|
return self._theme
|
||||||
|
|
||||||
def _toggle_minimize(self, event):
|
def _toggle_minimize(self, event):
|
||||||
for module in self._modules:
|
for module in self._modules:
|
||||||
widget = module.widget_by_id(event["instance"])
|
widget = module.widget_by_id(event["instance"])
|
||||||
|
|
|
@ -25,15 +25,15 @@ def is_terminated():
|
||||||
|
|
||||||
def read_input(inp):
|
def read_input(inp):
|
||||||
"""Read i3bar input and execute callbacks"""
|
"""Read i3bar input and execute callbacks"""
|
||||||
epoll = select.epoll()
|
poll = select.poll()
|
||||||
epoll.register(sys.stdin.fileno(), select.EPOLLIN)
|
poll.register(sys.stdin.fileno(), select.POLLIN)
|
||||||
log.debug("starting click event processing")
|
log.debug("starting click event processing")
|
||||||
while inp.running:
|
while inp.running:
|
||||||
if is_terminated():
|
if is_terminated():
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
events = epoll.poll(1)
|
events = poll.poll(1000)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
for fileno, event in events:
|
for fileno, event in events:
|
||||||
|
@ -52,8 +52,7 @@ def read_input(inp):
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
log.debug("failed to parse event: {}".format(e))
|
log.debug("failed to parse event: {}".format(e))
|
||||||
log.debug("exiting click event processing")
|
log.debug("exiting click event processing")
|
||||||
epoll.unregister(sys.stdin.fileno())
|
poll.unregister(sys.stdin.fileno())
|
||||||
epoll.close()
|
|
||||||
inp.has_event = True
|
inp.has_event = True
|
||||||
inp.clean_exit = True
|
inp.clean_exit = True
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,15 @@ class Module(bumblebee.engine.Module):
|
||||||
return len(packages)
|
return len(packages)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _format(self):
|
||||||
|
return self.parameter("format", "Update Arch: {}")
|
||||||
|
|
||||||
def utilization(self, widget):
|
def utilization(self, widget):
|
||||||
return 'Update Arch: {}'.format(self.packages)
|
return self._format.format(self.packages)
|
||||||
|
|
||||||
def hidden(self):
|
def hidden(self):
|
||||||
return self.check_updates() == 0
|
return self.check_updates() == 0
|
||||||
|
|
||||||
def update(self, widgets):
|
def update(self, widgets):
|
||||||
self.packages = self.check_updates()
|
self.packages = self.check_updates()
|
||||||
|
|
|
@ -7,6 +7,7 @@ Parameters:
|
||||||
* battery.warning : Warning threshold in % of remaining charge (defaults to 20)
|
* battery.warning : Warning threshold in % of remaining charge (defaults to 20)
|
||||||
* battery.critical : Critical threshold in % of remaining charge (defaults to 10)
|
* 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.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)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -47,6 +48,8 @@ class Module(bumblebee.engine.Module):
|
||||||
self.capacity(widget)
|
self.capacity(widget)
|
||||||
while len(widgets) > 0: del widgets[0]
|
while len(widgets) > 0: del widgets[0]
|
||||||
for widget in new_widgets:
|
for widget in new_widgets:
|
||||||
|
if bumblebee.util.asbool(self.parameter("decorate", True)) == False:
|
||||||
|
widget.set("theme.exclude", "suffix")
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
self._widgets = widgets
|
self._widgets = widgets
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,11 @@ Parameters:
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import datetime
|
import datetime
|
||||||
import locale
|
import locale
|
||||||
import pytz
|
try:
|
||||||
import tzlocal
|
import pytz
|
||||||
|
import tzlocal
|
||||||
|
except:
|
||||||
|
pass
|
||||||
import bumblebee.input
|
import bumblebee.input
|
||||||
import bumblebee.output
|
import bumblebee.output
|
||||||
import bumblebee.engine
|
import bumblebee.engine
|
||||||
|
@ -40,7 +43,10 @@ class Module(bumblebee.engine.Module):
|
||||||
engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE, cmd=self.next_tz)
|
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)
|
engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd=self.prev_tz)
|
||||||
self._fmt = self.parameter("format", default_format(self.name))
|
self._fmt = self.parameter("format", default_format(self.name))
|
||||||
self._timezones = self.parameter("timezone", tzlocal.get_localzone().zone).split(",")
|
try:
|
||||||
|
self._timezones = self.parameter("timezone", tzlocal.get_localzone().zone).split(",")
|
||||||
|
except:
|
||||||
|
self._timezones = ""
|
||||||
self._current_tz = 0
|
self._current_tz = 0
|
||||||
|
|
||||||
l = locale.getdefaultlocale()
|
l = locale.getdefaultlocale()
|
||||||
|
@ -54,10 +60,13 @@ class Module(bumblebee.engine.Module):
|
||||||
|
|
||||||
def get_time(self, widget):
|
def get_time(self, widget):
|
||||||
try:
|
try:
|
||||||
tz = pytz.timezone(self._timezones[self._current_tz].strip())
|
try:
|
||||||
retval = datetime.datetime.now(tz=tzlocal.get_localzone()).astimezone(tz).strftime(self._fmt)
|
tz = pytz.timezone(self._timezones[self._current_tz].strip())
|
||||||
except pytz.exceptions.UnknownTimeZoneError:
|
retval = datetime.datetime.now(tz=tzlocal.get_localzone()).astimezone(tz).strftime(self._fmt)
|
||||||
retval = "[Unknown timezone: {}]".format(self._timezones[self._current_tz].strip())
|
except pytz.exceptions.UnknownTimeZoneError:
|
||||||
|
retval = "[Unknown timezone: {}]".format(self._timezones[self._current_tz].strip())
|
||||||
|
except:
|
||||||
|
retval = "[n/a]"
|
||||||
|
|
||||||
enc = locale.getpreferredencoding()
|
enc = locale.getpreferredencoding()
|
||||||
if hasattr(retval, "decode"):
|
if hasattr(retval, "decode"):
|
||||||
|
|
68
bumblebee/modules/http_status.py
Normal file
68
bumblebee/modules/http_status.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
# 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
|
114
bumblebee/modules/network_traffic.py
Normal file
114
bumblebee/modules/network_traffic.py
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#!/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)
|
|
@ -4,21 +4,33 @@
|
||||||
|
|
||||||
Requires the following executable:
|
Requires the following executable:
|
||||||
* redshift
|
* 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
|
import threading
|
||||||
|
try:
|
||||||
|
import requests
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
import bumblebee.input
|
import bumblebee.input
|
||||||
import bumblebee.output
|
import bumblebee.output
|
||||||
import bumblebee.engine
|
import bumblebee.engine
|
||||||
|
|
||||||
|
|
||||||
def is_terminated():
|
def is_terminated():
|
||||||
for thread in threading.enumerate():
|
for thread in threading.enumerate():
|
||||||
if thread.name == "MainThread" and not thread.is_alive():
|
if thread.name == "MainThread" and not thread.is_alive():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_redshift_value(widget):
|
|
||||||
|
def get_redshift_value(widget, location, lat, lon):
|
||||||
while True:
|
while True:
|
||||||
if is_terminated():
|
if is_terminated():
|
||||||
return
|
return
|
||||||
|
@ -31,8 +43,14 @@ def get_redshift_value(widget):
|
||||||
break
|
break
|
||||||
widget.get("condition").release()
|
widget.get("condition").release()
|
||||||
|
|
||||||
|
command = ["redshift", "-p", "-l"]
|
||||||
|
if location == "manual":
|
||||||
|
command.append(lat + ":" + lon)
|
||||||
|
else:
|
||||||
|
command.append("geoclue2")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
res = bumblebee.util.execute("redshift -p")
|
res = bumblebee.util.execute(" ".join(command))
|
||||||
except Exception:
|
except Exception:
|
||||||
res = ""
|
res = ""
|
||||||
widget.set("temp", "n/a")
|
widget.set("temp", "n/a")
|
||||||
|
@ -52,14 +70,40 @@ def get_redshift_value(widget):
|
||||||
widget.set("state", "transition")
|
widget.set("state", "transition")
|
||||||
widget.set("transition", " ".join(line.split(" ")[2:]))
|
widget.set("transition", " ".join(line.split(" ")[2:]))
|
||||||
|
|
||||||
|
|
||||||
class Module(bumblebee.engine.Module):
|
class Module(bumblebee.engine.Module):
|
||||||
def __init__(self, engine, config):
|
def __init__(self, engine, config):
|
||||||
widget = bumblebee.output.Widget(full_text=self.text)
|
widget = bumblebee.output.Widget(full_text=self.text)
|
||||||
super(Module, self).__init__(engine, config, widget)
|
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._text = ""
|
||||||
self._condition = threading.Condition()
|
self._condition = threading.Condition()
|
||||||
widget.set("condition", self._condition)
|
widget.set("condition", self._condition)
|
||||||
self._thread = threading.Thread(target=get_redshift_value, args=(widget,))
|
self._thread = threading.Thread(target=get_redshift_value,
|
||||||
|
args=(widget, self._location,
|
||||||
|
self._lat, self._lon))
|
||||||
self._thread.start()
|
self._thread.start()
|
||||||
self._condition.acquire()
|
self._condition.acquire()
|
||||||
self._condition.notify()
|
self._condition.notify()
|
||||||
|
|
311
bumblebee/modules/rss.py
Normal file
311
bumblebee/modules/rss.py
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
# 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._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'<img[^>]*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 = "<div class='item' onclick=window.open('"+item['link']+"')>"
|
||||||
|
element += "<div class='titlecontainer'>"
|
||||||
|
element += " <img "+("" if item['image'] else "class='noimg' ")+"src='"+item['image']+"'>"
|
||||||
|
element += " <div class='title"+(" overlay" if overlay_title else "")+"'>"+("<span class='star'>★</span>" if item['new'] else "")+item['title']+"</div>"
|
||||||
|
element += "</div>"
|
||||||
|
element += "<div class='summary'>"+item['summary']+"</div>"
|
||||||
|
element += "<div class='info'><span class='author'>"+item['feed']+"</span><span class='published'>"+timestr+"</span></div>"
|
||||||
|
element += "</div>"
|
||||||
|
return element
|
||||||
|
|
||||||
|
def _create_news_section(self, newspaper_items):
|
||||||
|
style = random.randint(0, 3)
|
||||||
|
section = "<table><tr class='style"+str(style)+"'>"
|
||||||
|
for i in range(0, 3):
|
||||||
|
section += "<td><div class='itemcontainer'>"
|
||||||
|
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 += "</div></td>"
|
||||||
|
section += "</tr></table>"
|
||||||
|
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 = """<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
var images = document.getElementsByTagName('img');
|
||||||
|
// Remove very small images
|
||||||
|
for(var i = 0; i < images.length; i++) {
|
||||||
|
if (images[i].naturalWidth<50 || images[i].naturalHeight<50) {
|
||||||
|
images[i].src = ''
|
||||||
|
images[i].className+=' noimg'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
body {background: #eee; font-family: Helvetica neue;}
|
||||||
|
td {background: #fff; height: 100%;}
|
||||||
|
tr.style0 td {width: 33%;}
|
||||||
|
tr.style1 td {width: 20%;}
|
||||||
|
tr.style1 td:last-child {width: 60%;}
|
||||||
|
tr.style2 td {width: 20%;}
|
||||||
|
tr.style2 td:first-child {width: 60%;}
|
||||||
|
tr.style3 td {width: 20%;}
|
||||||
|
tr.style3 td:nth-child(2) {width: 60%;}
|
||||||
|
img {width: 100%; display: block; }
|
||||||
|
img.noimg {min-height:250px; background: #1299c8;}
|
||||||
|
#content {width: 1500px; margin: auto; background: #eee; padding: 1px;}
|
||||||
|
#newspapertitle {text-align: center; font-size: 60px; font-family: Arial Black; background: #1299c8; font-style: Italic; padding: 10px; color: #fff; }
|
||||||
|
.star {color: #ffa515; font-size: 24px;}
|
||||||
|
.section {display: flex;}
|
||||||
|
.column {display: flex;}
|
||||||
|
.itemcontainer {width: 100%; height: 100%; position: relative; display: inline-table;}
|
||||||
|
.item {cursor: pointer; }
|
||||||
|
.titlecontainer {position: relative;}
|
||||||
|
.title.overlay {font-family: Arial; position: absolute; bottom: 10px; color: #fff; font-weight: bold; text-align: right; max-width: 75%; right: 10px; font-size: 23px; text-shadow: 1px 0 0 #000, 0 -1px 0 #000, 0 1px 0 #000, -1px 0 0 #000;}
|
||||||
|
.title:not(.overlay) {font-weight: bold; padding: 0px 10px;}
|
||||||
|
.summary {color: #444; padding: 10px 10px 0px 10px; font-family: Times new roman; font-size: 18px; flex: 1;max-height: 105px; overflow: hidden;}
|
||||||
|
.info {color: #aaa; font-family: arial; font-size: 13px; padding: 10px;}
|
||||||
|
.published {float: right;}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div id='content'>
|
||||||
|
<div id='newspapertitle'>Bumblebee Daily</div>
|
||||||
|
[[CONTENT]]
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>"""
|
||||||
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
111
bumblebee/modules/sun.py
Normal file
111
bumblebee/modules/sun.py
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
# 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
|
83
bumblebee/modules/system.py
Normal file
83
bumblebee/modules/system.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# -*- 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.
|
||||||
|
|
||||||
|
Paramters:
|
||||||
|
* system.confirm: show confirmation dialog before performing any action (default: true)
|
||||||
|
"""
|
||||||
|
|
||||||
|
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()
|
||||||
|
menu.add_menuitem("shutdown", callback=functools.partial(self._on_command, "Shutdown", "Shutdown?", "shutdown -h now"))
|
||||||
|
menu.add_menuitem("reboot", callback=functools.partial(self._on_command, "Reboot", "Reboot?", "reboot"))
|
||||||
|
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, "i3exit switch_user"))
|
||||||
|
menu.add_menuitem("lock", callback=functools.partial(bumblebee.util.execute, "i3exit lock"))
|
||||||
|
menu.add_menuitem("suspend", callback=functools.partial(bumblebee.util.execute, "i3exit suspend"))
|
||||||
|
menu.add_menuitem("hibernate", callback=functools.partial(bumblebee.util.execute, "i3exit hibernate"))
|
||||||
|
|
||||||
|
menu.show(widget)
|
||||||
|
|
||||||
|
def state(self, widget):
|
||||||
|
return []
|
|
@ -103,7 +103,8 @@ class Module(bumblebee.engine.Module):
|
||||||
widget = self.create_widget(widgets, name, attributes={"theme.minwidth": "1000.00MB"})
|
widget = self.create_widget(widgets, name, attributes={"theme.minwidth": "1000.00MB"})
|
||||||
prev = self._prev.get(name, 0)
|
prev = self._prev.get(name, 0)
|
||||||
speed = bumblebee.util.bytefmt((int(data[direction]) - int(prev))/timediff)
|
speed = bumblebee.util.bytefmt((int(data[direction]) - int(prev))/timediff)
|
||||||
widget.full_text(speed)
|
txtspeed ='{0}/s'.format(speed)
|
||||||
|
widget.full_text(txtspeed)
|
||||||
self._prev[name] = data[direction]
|
self._prev[name] = data[direction]
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
39
bumblebee/modules/twmn.py
Normal file
39
bumblebee/modules/twmn.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#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"]
|
81
bumblebee/modules/vault.py
Normal file
81
bumblebee/modules/vault.py
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
# 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 = "<click-for-password>"
|
||||||
|
|
||||||
|
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
|
|
@ -118,8 +118,6 @@ class Module(bumblebee.engine.Module):
|
||||||
self._temperature = int(weather['main']['temp'])
|
self._temperature = int(weather['main']['temp'])
|
||||||
self._weather = weather['weather'][0]['main'].lower()
|
self._weather = weather['weather'][0]['main'].lower()
|
||||||
self._valid = True
|
self._valid = True
|
||||||
except RequestException:
|
|
||||||
self._valid = False
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self._valid = False
|
self._valid = False
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,27 @@ except ImportError:
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
|
|
||||||
class PopupMenu(object):
|
class PopupMenu(object):
|
||||||
def __init__(self):
|
def __init__(self, parent=None, leave=True):
|
||||||
self._root = tk.Tk()
|
|
||||||
self._root.withdraw()
|
if not parent:
|
||||||
self._menu = tk.Menu(self._root)
|
self._root = tk.Tk()
|
||||||
self._menu.bind("<FocusOut>", self._on_focus_out)
|
self._root.withdraw()
|
||||||
|
self._menu = tk.Menu(self._root, tearoff=0)
|
||||||
|
self._menu.bind("<FocusOut>", self._on_focus_out)
|
||||||
|
else:
|
||||||
|
self._root = parent.root()
|
||||||
|
self._root.withdraw()
|
||||||
|
self._menu = tk.Menu(self._root, tearoff=0)
|
||||||
|
self._menu.bind("<FocusOut>", self._on_focus_out)
|
||||||
|
if leave:
|
||||||
|
self._menu.bind("<Leave>", self._on_focus_out)
|
||||||
|
|
||||||
|
def root(self):
|
||||||
|
return self._root
|
||||||
|
|
||||||
|
def menu(self):
|
||||||
|
return self._menu
|
||||||
|
|
||||||
def _on_focus_out(self, event=None):
|
def _on_focus_out(self, event=None):
|
||||||
self._root.destroy()
|
self._root.destroy()
|
||||||
|
@ -28,13 +42,15 @@ class PopupMenu(object):
|
||||||
self._root.destroy()
|
self._root.destroy()
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
def add_cascade(self, menuitem, submenu):
|
||||||
|
self._menu.add_cascade(label=menuitem, menu=submenu.menu())
|
||||||
|
|
||||||
def add_menuitem(self, menuitem, callback):
|
def add_menuitem(self, menuitem, callback):
|
||||||
self._menu.add_command(label=menuitem, command=functools.partial(self._on_click, callback))
|
self._menu.add_command(label=menuitem, command=functools.partial(self._on_click, callback))
|
||||||
|
|
||||||
def show(self, event):
|
def show(self, event, offset_x=0, offset_y=0):
|
||||||
try:
|
try:
|
||||||
self._menu.tk_popup(event['x'], event['y'])
|
self._menu.tk_popup(event['x'] + offset_x, event['y'] + offset_y)
|
||||||
finally:
|
finally:
|
||||||
self._menu.grab_release()
|
self._menu.grab_release()
|
||||||
self._root.mainloop()
|
self._root.mainloop()
|
||||||
|
|
|
@ -105,6 +105,9 @@ class Theme(object):
|
||||||
if icon is None:
|
if icon is None:
|
||||||
return self._get(widget, "prefix", 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):
|
def padding(self, widget):
|
||||||
"""Return padding for widget"""
|
"""Return padding for widget"""
|
||||||
return self._get(widget, "padding", "")
|
return self._get(widget, "padding", "")
|
||||||
|
@ -223,6 +226,9 @@ class Theme(object):
|
||||||
if not self._widget:
|
if not self._widget:
|
||||||
self._widget = widget
|
self._widget = widget
|
||||||
|
|
||||||
|
if self._widget.get("theme.exclude", "") == name:
|
||||||
|
return None
|
||||||
|
|
||||||
if self._widget != widget:
|
if self._widget != widget:
|
||||||
self._prevbg = self.bg(self._widget)
|
self._prevbg = self.bg(self._widget)
|
||||||
self._widget = widget
|
self._widget = widget
|
||||||
|
@ -238,7 +244,8 @@ class Theme(object):
|
||||||
states = widget.state()
|
states = widget.state()
|
||||||
if name not in states:
|
if name not in states:
|
||||||
for state in states:
|
for state in states:
|
||||||
state_themes.append(self._get(widget, state, {}))
|
if state:
|
||||||
|
state_themes.append(self._get(widget, state, {}))
|
||||||
|
|
||||||
value = self._defaults.get(name, default)
|
value = self._defaults.get(name, default)
|
||||||
value = widget.get("theme.{}".format(name), value)
|
value = widget.get("theme.{}".format(name), value)
|
||||||
|
|
BIN
screenshots/http_status.png
Normal file
BIN
screenshots/http_status.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
screenshots/network_traffic.gif
Normal file
BIN
screenshots/network_traffic.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
screenshots/vault.png
Normal file
BIN
screenshots/vault.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
|
@ -14,7 +14,7 @@ def rand(cnt):
|
||||||
return "".join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for i in range(cnt))
|
return "".join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for i in range(cnt))
|
||||||
|
|
||||||
def setup_test(test, Module):
|
def setup_test(test, Module):
|
||||||
test._stdin, test._select, test.stdin, test.select = epoll_mock("bumblebee.input")
|
test._stdin, test._select, test.stdin, test.select = poll_mock("bumblebee.input")
|
||||||
|
|
||||||
test.popen = MockPopen()
|
test.popen = MockPopen()
|
||||||
|
|
||||||
|
@ -33,19 +33,19 @@ def teardown_test(test):
|
||||||
test._select.stop()
|
test._select.stop()
|
||||||
test.popen.cleanup()
|
test.popen.cleanup()
|
||||||
|
|
||||||
def epoll_mock(module=""):
|
def poll_mock(module=""):
|
||||||
if len(module) > 0: module = "{}.".format(module)
|
if len(module) > 0: module = "{}.".format(module)
|
||||||
|
|
||||||
stdin = mock.patch("{}sys.stdin".format(module))
|
stdin = mock.patch("{}sys.stdin".format(module))
|
||||||
select = mock.patch("{}select".format(module))
|
select = mock.patch("{}select".format(module))
|
||||||
epoll = mock.Mock()
|
poll = mock.Mock()
|
||||||
|
|
||||||
stdin_mock = stdin.start()
|
stdin_mock = stdin.start()
|
||||||
select_mock = select.start()
|
select_mock = select.start()
|
||||||
|
|
||||||
stdin_mock.fileno.return_value = 1
|
stdin_mock.fileno.return_value = 1
|
||||||
select_mock.epoll.return_value = epoll
|
select_mock.poll.return_value = poll
|
||||||
epoll.poll.return_value = [(stdin_mock.fileno.return_value, 100)]
|
poll.poll.return_value = [(stdin_mock.fileno.return_value, 100)]
|
||||||
|
|
||||||
return stdin, select, stdin_mock, select_mock
|
return stdin, select, stdin_mock, select_mock
|
||||||
|
|
||||||
|
|
49
tests/modules/test_http_status.py
Normal file
49
tests/modules/test_http_status.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# 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
|
|
@ -20,10 +20,10 @@ class TestI3BarInput(unittest.TestCase):
|
||||||
self.popen = mocks.MockPopen()
|
self.popen = mocks.MockPopen()
|
||||||
|
|
||||||
self.stdin.fileno.return_value = 1
|
self.stdin.fileno.return_value = 1
|
||||||
epoll = mock.Mock()
|
poll = mock.Mock()
|
||||||
self.select.epoll.return_value = epoll
|
self.select.poll.return_value = poll
|
||||||
|
|
||||||
epoll.poll.return_value = [(self.stdin.fileno.return_value, 2)]
|
poll.poll.return_value = [(self.stdin.fileno.return_value, 2)]
|
||||||
|
|
||||||
self.anyModule = mock.Mock()
|
self.anyModule = mock.Mock()
|
||||||
self.anyModule.id = mocks.rand(10)
|
self.anyModule.id = mocks.rand(10)
|
||||||
|
|
|
@ -118,6 +118,14 @@ class TestTheme(unittest.TestCase):
|
||||||
# widget theme instead (i.e. no fallback to a more general state theme)
|
# widget theme instead (i.e. no fallback to a more general state theme)
|
||||||
self.assertEquals(theme.bg(self.themedWidget), data[self.widgetTheme]["bg"])
|
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):
|
def test_separator(self):
|
||||||
self.assertEquals(self.validThemeSeparator, self.theme.separator(self.anyWidget))
|
self.assertEquals(self.validThemeSeparator, self.theme.separator(self.anyWidget))
|
||||||
|
|
||||||
|
|
|
@ -1,133 +1,307 @@
|
||||||
{
|
{
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"padding": " "
|
"padding": " "
|
||||||
},
|
},
|
||||||
"memory": { "prefix": "ram" },
|
"memory": {
|
||||||
"cpu": { "prefix": "cpu" },
|
"prefix": "ram"
|
||||||
"disk": { "prefix": "hdd" },
|
},
|
||||||
"dnf": { "prefix": "dnf" },
|
"cpu": {
|
||||||
"apt": { "prefix": "apt" },
|
"prefix": "cpu"
|
||||||
"brightness": { "prefix": "o" },
|
},
|
||||||
"cmus": {
|
"disk": {
|
||||||
"playing": { "prefix": ">" },
|
"prefix": "hdd"
|
||||||
"paused": { "prefix": "||" },
|
},
|
||||||
"stopped": { "prefix": "[]" },
|
"dnf": {
|
||||||
"prev": { "prefix": "|<" },
|
"prefix": "dnf"
|
||||||
"next": { "prefix": ">|" },
|
},
|
||||||
"shuffle-on": { "prefix": "S" },
|
"apt": {
|
||||||
"shuffle-off": { "prefix": "[s]" },
|
"prefix": "apt"
|
||||||
"repeat-on": { "prefix": "R" },
|
},
|
||||||
"repeat-off": { "prefix": "[r]" }
|
"brightness": {
|
||||||
},
|
"prefix": "o"
|
||||||
"pasink": {
|
},
|
||||||
"muted": { "prefix": "audio(mute)" },
|
"cmus": {
|
||||||
"unmuted": { "prefix": "audio" }
|
"playing": {
|
||||||
},
|
"prefix": ">"
|
||||||
"amixer": {
|
},
|
||||||
"muted": { "prefix": "audio(mute)" },
|
"paused": {
|
||||||
"unmuted": { "prefix": "audio" }
|
"prefix": "||"
|
||||||
},
|
},
|
||||||
"pasource": {
|
"stopped": {
|
||||||
"muted": { "prefix": "mic(mute)" },
|
"prefix": "[]"
|
||||||
"unmuted": { "prefix": "mic" }
|
},
|
||||||
},
|
"prev": {
|
||||||
"nic": {
|
"prefix": "|<"
|
||||||
"wireless-up": { "prefix": "wifi" },
|
},
|
||||||
"wireless-down": { "prefix": "wifi" },
|
"next": {
|
||||||
"wired-up": { "prefix": "lan" },
|
"prefix": ">|"
|
||||||
"wired-down": { "prefix": "lan" },
|
},
|
||||||
"tunnel-up": { "prefix": "tun" },
|
"shuffle-on": {
|
||||||
"tunnel-down": { "prefix": "tun" }
|
"prefix": "S"
|
||||||
},
|
},
|
||||||
"battery": {
|
"shuffle-off": {
|
||||||
"charged": { "suffix": "full" },
|
"prefix": "[s]"
|
||||||
"charging": { "suffix": "chr" },
|
},
|
||||||
"AC": { "suffix": "ac" },
|
"repeat-on": {
|
||||||
"discharging-10": {
|
"prefix": "R"
|
||||||
"prefix": "!",
|
},
|
||||||
"suffix": "dis"
|
"repeat-off": {
|
||||||
},
|
"prefix": "[r]"
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"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" }
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"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": {
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,206 +1,226 @@
|
||||||
{
|
{
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"separator": "", "padding": " ",
|
"separator": "",
|
||||||
"unknown": { "prefix": "" }
|
"padding": " ",
|
||||||
},
|
"unknown": { "prefix": "" }
|
||||||
"date": { "prefix": "" },
|
},
|
||||||
"time": { "prefix": "" },
|
"date": { "prefix": "" },
|
||||||
"datetime": { "prefix": "" },
|
"time": { "prefix": "" },
|
||||||
"datetz": { "prefix": "" },
|
"datetime": { "prefix": "" },
|
||||||
"timetz": { "prefix": "" },
|
"datetz": { "prefix": "" },
|
||||||
"datetimetz": { "prefix": "" },
|
"timetz": { "prefix": "" },
|
||||||
"memory": { "prefix": "" },
|
"datetimetz": { "prefix": "" },
|
||||||
"cpu": { "prefix": "" },
|
"memory": { "prefix": "" },
|
||||||
"disk": { "prefix": "" },
|
"cpu": { "prefix": "" },
|
||||||
"dnf": { "prefix": "" },
|
"disk": { "prefix": "" },
|
||||||
"apt": { "prefix": "" },
|
"dnf": { "prefix": "" },
|
||||||
"pacman": { "prefix": "" },
|
"apt": { "prefix": "" },
|
||||||
"brightness": { "prefix": "" },
|
"pacman": { "prefix": "" },
|
||||||
"load": { "prefix": "" },
|
"brightness": { "prefix": "" },
|
||||||
"layout": { "prefix": "" },
|
"load": { "prefix": "" },
|
||||||
"layout-xkb": { "prefix": "" },
|
"layout": { "prefix": "" },
|
||||||
"notmuch_count": { "empty": {"prefix": "\uf0e0" },
|
"layout-xkb": { "prefix": "" },
|
||||||
"items": {"prefix": "\uf0e0" }
|
"notmuch_count": {
|
||||||
},
|
"empty": { "prefix": "\uf0e0" },
|
||||||
"todo": { "empty": {"prefix": "" },
|
"items": { "prefix": "\uf0e0" }
|
||||||
"items": {"prefix": "" },
|
},
|
||||||
"uptime": {"prefix": "" }
|
"todo": {
|
||||||
},
|
"empty": { "prefix": "" },
|
||||||
"zpool": {
|
"items": { "prefix": "" },
|
||||||
"poolread": {"prefix": "→ "},
|
"uptime": { "prefix": "" }
|
||||||
"poolwrite": {"prefix": "← "},
|
},
|
||||||
"ONLINE": {"prefix": ""},
|
"zpool": {
|
||||||
"FAULTED": {"prefix": "!"},
|
"poolread": { "prefix": "→ " },
|
||||||
"DEGRADED": {"prefix": "!"}
|
"poolwrite": { "prefix": "← " },
|
||||||
},
|
"ONLINE": { "prefix": "" },
|
||||||
"cmus": {
|
"FAULTED": { "prefix": "!" },
|
||||||
"playing": { "prefix": "" },
|
"DEGRADED": { "prefix": "!" }
|
||||||
"paused": { "prefix": "" },
|
},
|
||||||
"stopped": { "prefix": "" },
|
"cmus": {
|
||||||
"prev": { "prefix": "" },
|
"playing": { "prefix": "" },
|
||||||
"next": { "prefix": "" },
|
"paused": { "prefix": "" },
|
||||||
"shuffle-on": { "prefix": "" },
|
"stopped": { "prefix": "" },
|
||||||
"shuffle-off": { "prefix": "" },
|
"prev": { "prefix": "" },
|
||||||
"repeat-on": { "prefix": "" },
|
"next": { "prefix": "" },
|
||||||
"repeat-off": { "prefix": "" }
|
"shuffle-on": { "prefix": "" },
|
||||||
},
|
"shuffle-off": { "prefix": "" },
|
||||||
"gpmdp": {
|
"repeat-on": { "prefix": "" },
|
||||||
"playing": { "prefix": "" },
|
"repeat-off": { "prefix": "" }
|
||||||
"paused": { "prefix": "" },
|
},
|
||||||
"stopped": { "prefix": "" },
|
"gpmdp": {
|
||||||
"prev": { "prefix": "" },
|
"playing": { "prefix": "" },
|
||||||
"next": { "prefix": "" }
|
"paused": { "prefix": "" },
|
||||||
},
|
"stopped": { "prefix": "" },
|
||||||
"pasink": {
|
"prev": { "prefix": "" },
|
||||||
"muted": { "prefix": "" },
|
"next": { "prefix": "" }
|
||||||
"unmuted": { "prefix": "" }
|
},
|
||||||
},
|
"pasink": {
|
||||||
"amixer": {
|
"muted": { "prefix": "" },
|
||||||
"muted": { "prefix": "" },
|
"unmuted": { "prefix": "" }
|
||||||
"unmuted": { "prefix": "" }
|
},
|
||||||
},
|
"amixer": {
|
||||||
"pasource": {
|
"muted": { "prefix": "" },
|
||||||
"muted": { "prefix": "" },
|
"unmuted": { "prefix": "" }
|
||||||
"unmuted": { "prefix": "" }
|
},
|
||||||
},
|
"pasource": {
|
||||||
"kernel": {
|
"muted": { "prefix": "" },
|
||||||
"prefix": "\uf17c"
|
"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": {
|
||||||
|
"charged": { "prefix": "", "suffix": "" },
|
||||||
|
"AC": { "suffix": "" },
|
||||||
|
"charging": {
|
||||||
|
"prefix": ["", "", "", "", ""],
|
||||||
|
"suffix": ""
|
||||||
},
|
},
|
||||||
"nic": {
|
"discharging-10": { "prefix": "", "suffix": "" },
|
||||||
"wireless-up": { "prefix": "" },
|
"discharging-25": { "prefix": "", "suffix": "" },
|
||||||
"wireless-down": { "prefix": "" },
|
"discharging-50": { "prefix": "", "suffix": "" },
|
||||||
"wired-up": { "prefix": "" },
|
"discharging-80": { "prefix": "", "suffix": "" },
|
||||||
"wired-down": { "prefix": "" },
|
"discharging-100": { "prefix": "", "suffix": "" },
|
||||||
"tunnel-up": { "prefix": "" },
|
"unlimited": { "prefix": "", "suffix": "" },
|
||||||
"tunnel-down": { "prefix": "" }
|
"estimate": { "prefix": "" },
|
||||||
},
|
"unknown-10": { "prefix": "", "suffix": "" },
|
||||||
"bluetooth": {
|
"unknown-25": { "prefix": "", "suffix": "" },
|
||||||
"ON": { "prefix": "" },
|
"unknown-50": { "prefix": "", "suffix": "" },
|
||||||
"OFF": { "prefix": "" },
|
"unknown-80": { "prefix": "", "suffix": "" },
|
||||||
"?": { "prefix": "" }
|
"unknown-100": { "prefix": "", "suffix": "" }
|
||||||
|
},
|
||||||
|
"battery_all": {
|
||||||
|
"charged": { "prefix": "", "suffix": "" },
|
||||||
|
"AC": { "suffix": "" },
|
||||||
|
"charging": {
|
||||||
|
"prefix": ["", "", "", "", ""],
|
||||||
|
"suffix": ""
|
||||||
},
|
},
|
||||||
"battery": {
|
"discharging-10": { "prefix": "", "suffix": "" },
|
||||||
"charged": { "prefix": "", "suffix": "" },
|
"discharging-25": { "prefix": "", "suffix": "" },
|
||||||
"AC": { "suffix": "" },
|
"discharging-50": { "prefix": "", "suffix": "" },
|
||||||
"charging": {
|
"discharging-80": { "prefix": "", "suffix": "" },
|
||||||
"prefix": [ "", "", "", "", "" ],
|
"discharging-100": { "prefix": "", "suffix": "" },
|
||||||
"suffix": ""
|
"unlimited": { "prefix": "", "suffix": "" },
|
||||||
},
|
"estimate": { "prefix": "" },
|
||||||
"discharging-10": { "prefix": "", "suffix": "" },
|
"unknown-10": { "prefix": "", "suffix": "" },
|
||||||
"discharging-25": { "prefix": "", "suffix": "" },
|
"unknown-25": { "prefix": "", "suffix": "" },
|
||||||
"discharging-50": { "prefix": "", "suffix": "" },
|
"unknown-50": { "prefix": "", "suffix": "" },
|
||||||
"discharging-80": { "prefix": "", "suffix": "" },
|
"unknown-80": { "prefix": "", "suffix": "" },
|
||||||
"discharging-100": { "prefix": "", "suffix": "" },
|
"unknown-100": { "prefix": "", "suffix": "" }
|
||||||
"unlimited": { "prefix": "", "suffix": "" },
|
},
|
||||||
"estimate": { "prefix": "" },
|
"caffeine": {
|
||||||
"unknown-10": { "prefix": "", "suffix": "" },
|
"activated": { "prefix": " " },
|
||||||
"unknown-25": { "prefix": "", "suffix": "" },
|
"deactivated": { "prefix": " " }
|
||||||
"unknown-50": { "prefix": "", "suffix": "" },
|
},
|
||||||
"unknown-80": { "prefix": "", "suffix": "" },
|
"xrandr": {
|
||||||
"unknown-100": { "prefix": "", "suffix": "" }
|
"on": { "prefix": " " },
|
||||||
},
|
"off": { "prefix": " " },
|
||||||
"battery_all": {
|
"refresh": { "prefix": "" }
|
||||||
"charged": { "prefix": "", "suffix": "" },
|
},
|
||||||
"AC": { "suffix": "" },
|
"redshift": {
|
||||||
"charging": {
|
"day": { "prefix": "" },
|
||||||
"prefix": [ "", "", "", "", "" ],
|
"night": { "prefix": "" },
|
||||||
"suffix": ""
|
"transition": { "prefix": "" }
|
||||||
},
|
},
|
||||||
"discharging-10": { "prefix": "", "suffix": "" },
|
"docker_ps": {
|
||||||
"discharging-25": { "prefix": "", "suffix": "" },
|
"prefix": ""
|
||||||
"discharging-50": { "prefix": "", "suffix": "" },
|
},
|
||||||
"discharging-80": { "prefix": "", "suffix": "" },
|
"sensors": {
|
||||||
"discharging-100": { "prefix": "", "suffix": "" },
|
"prefix": ""
|
||||||
"unlimited": { "prefix": "", "suffix": "" },
|
},
|
||||||
"estimate": { "prefix": "" },
|
"sensors2": {
|
||||||
"unknown-10": { "prefix": "", "suffix": "" },
|
"temp": { "prefix": "" },
|
||||||
"unknown-25": { "prefix": "", "suffix": "" },
|
"fan": { "prefix": "" },
|
||||||
"unknown-50": { "prefix": "", "suffix": "" },
|
"cpu": { "prefix": "" }
|
||||||
"unknown-80": { "prefix": "", "suffix": "" },
|
},
|
||||||
"unknown-100": { "prefix": "", "suffix": "" }
|
"traffic": {
|
||||||
},
|
"rx": { "prefix": "" },
|
||||||
"caffeine": {
|
"tx": { "prefix": "" }
|
||||||
"activated": {"prefix": " " },
|
},
|
||||||
"deactivated": { "prefix": " " }
|
"network_traffic": {
|
||||||
},
|
"rx": { "prefix": "" },
|
||||||
"xrandr": {
|
"tx": { "prefix": "" }
|
||||||
"on": { "prefix": " "},
|
},
|
||||||
"off": { "prefix": " " },
|
"mpd": {
|
||||||
"refresh": { "prefix": "" }
|
"playing": { "prefix": "" },
|
||||||
},
|
"paused": { "prefix": "" },
|
||||||
"redshift": {
|
"stopped": { "prefix": "" },
|
||||||
"day": { "prefix": "" },
|
"prev": { "prefix": "" },
|
||||||
"night": { "prefix": "" },
|
"next": { "prefix": "" },
|
||||||
"transition": { "prefix": "" }
|
"shuffle-on": { "prefix": "" },
|
||||||
},
|
"shuffle-off": { "prefix": "" },
|
||||||
"docker_ps": {
|
"repeat-on": { "prefix": "" },
|
||||||
"prefix": ""
|
"repeat-off": { "prefix": "" }
|
||||||
},
|
},
|
||||||
"sensors": {
|
"arch-update": {
|
||||||
"prefix": ""
|
"prefix": " "
|
||||||
},
|
},
|
||||||
"sensors2": {
|
"github": {
|
||||||
"temp": { "prefix": "" },
|
"prefix": " "
|
||||||
"fan": { "prefix": "" },
|
},
|
||||||
"cpu": { "prefix": "" }
|
"spotify": {
|
||||||
},
|
"prefix": " "
|
||||||
"traffic":{
|
},
|
||||||
"rx": { "prefix": "" },
|
"publicip": {
|
||||||
"tx": { "prefix": "" }
|
"prefix": " "
|
||||||
},
|
},
|
||||||
"mpd": {
|
"weather": {
|
||||||
"playing": { "prefix": "" },
|
"clouds": { "prefix": "" },
|
||||||
"paused": { "prefix": "" },
|
"rain": { "prefix": "" },
|
||||||
"stopped": { "prefix": "" },
|
"snow": { "prefix": "" },
|
||||||
"prev": { "prefix": "" },
|
"clear": { "prefix": "" },
|
||||||
"next": { "prefix": "" },
|
"thunder": { "prefix": "" }
|
||||||
"shuffle-on": { "prefix": "" },
|
},
|
||||||
"shuffle-off": { "prefix": "" },
|
"taskwarrior": {
|
||||||
"repeat-on": { "prefix": "" },
|
"prefix": " "
|
||||||
"repeat-off": { "prefix": "" }
|
},
|
||||||
},
|
"progress": {
|
||||||
"arch-update": {
|
"copying": {
|
||||||
"prefix": " "
|
"prefix": ""
|
||||||
},
|
|
||||||
"github": {
|
|
||||||
"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": "" }
|
|
||||||
},
|
|
||||||
"pihole": {
|
|
||||||
"enabled": { "prefix": "" },
|
|
||||||
"disabled": { "prefix": "" }
|
|
||||||
},
|
|
||||||
"vpn": {
|
|
||||||
"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": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,153 +1,163 @@
|
||||||
{
|
{
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"separator": "\ue0b2", "padding": "\u2800",
|
"separator": "\ue0b2",
|
||||||
"unknown": { "prefix": "\uf100" }
|
"padding": "\u2800",
|
||||||
},
|
"unknown": { "prefix": "\uf100" }
|
||||||
"date": { "prefix": "\uf2d1" },
|
},
|
||||||
"time": { "prefix": "\uf3b3" },
|
"date": { "prefix": "\uf2d1" },
|
||||||
"datetime": { "prefix": "\uf3b3" },
|
"time": { "prefix": "\uf3b3" },
|
||||||
"memory": { "prefix": "\uf389" },
|
"datetime": { "prefix": "\uf3b3" },
|
||||||
"cpu": { "prefix": "\uf4b0" },
|
"memory": { "prefix": "\uf389" },
|
||||||
"disk": { "prefix": "\u26c1" },
|
"cpu": { "prefix": "\uf4b0" },
|
||||||
"dnf": { "prefix": "\uf2be" },
|
"disk": { "prefix": "\u26c1" },
|
||||||
"apt": { "prefix": "\uf2be" },
|
"dnf": { "prefix": "\uf2be" },
|
||||||
"pacman": { "prefix": "\uf2be" },
|
"apt": { "prefix": "\uf2be" },
|
||||||
"brightness": { "prefix": "\u263c" },
|
"pacman": { "prefix": "\uf2be" },
|
||||||
"load": { "prefix": "\uf13d" },
|
"brightness": { "prefix": "\u263c" },
|
||||||
"layout": { "prefix": "\uf38c" },
|
"load": { "prefix": "\uf13d" },
|
||||||
"layout-xkb": { "prefix": "\uf38c" },
|
"layout": { "prefix": "\uf38c" },
|
||||||
"todo": { "empty": {"prefix": "\uf453" },
|
"layout-xkb": { "prefix": "\uf38c" },
|
||||||
"items": {"prefix": "\uf454" },
|
"todo": {
|
||||||
"uptime": {"prefix": "\uf4c1" }
|
"empty": { "prefix": "\uf453" },
|
||||||
},
|
"items": { "prefix": "\uf454" },
|
||||||
"zpool": {
|
"uptime": { "prefix": "\uf4c1" }
|
||||||
"poolread": {"prefix": "\u26c1\uf3d6"},
|
},
|
||||||
"poolwrite": {"prefix": "\u26c1\uf3d5"},
|
"zpool": {
|
||||||
"ONLINE": {"prefix": "\u26c1"},
|
"poolread": { "prefix": "\u26c1\uf3d6" },
|
||||||
"FAULTED": {"prefix": "\u26c1\uf3bc"},
|
"poolwrite": { "prefix": "\u26c1\uf3d5" },
|
||||||
"DEGRADED": {"prefix": "\u26c1\uf3bc"}
|
"ONLINE": { "prefix": "\u26c1" },
|
||||||
},
|
"FAULTED": { "prefix": "\u26c1\uf3bc" },
|
||||||
"cmus": {
|
"DEGRADED": { "prefix": "\u26c1\uf3bc" }
|
||||||
"playing": { "prefix": "\uf488" },
|
},
|
||||||
"paused": { "prefix": "\uf210" },
|
"cmus": {
|
||||||
"stopped": { "prefix": "\uf24f" },
|
"playing": { "prefix": "\uf488" },
|
||||||
"prev": { "prefix": "\uf4ab" },
|
"paused": { "prefix": "\uf210" },
|
||||||
"next": { "prefix": "\uf4ad" },
|
"stopped": { "prefix": "\uf24f" },
|
||||||
"shuffle-on": { "prefix": "\uf4a8" },
|
"prev": { "prefix": "\uf4ab" },
|
||||||
"shuffle-off": { "prefix": "\uf453" },
|
"next": { "prefix": "\uf4ad" },
|
||||||
"repeat-on": { "prefix": "\uf459" },
|
"shuffle-on": { "prefix": "\uf4a8" },
|
||||||
"repeat-off": { "prefix": "\uf30f" }
|
"shuffle-off": { "prefix": "\uf453" },
|
||||||
},
|
"repeat-on": { "prefix": "\uf459" },
|
||||||
"gpmdp": {
|
"repeat-off": { "prefix": "\uf30f" }
|
||||||
"playing": { "prefix": "\uf488" },
|
},
|
||||||
"paused": { "prefix": "\uf210" },
|
"gpmdp": {
|
||||||
"stopped": { "prefix": "\uf24f" },
|
"playing": { "prefix": "\uf488" },
|
||||||
"prev": { "prefix": "\uf4ab" },
|
"paused": { "prefix": "\uf210" },
|
||||||
"next": { "prefix": "\uf4ad" }
|
"stopped": { "prefix": "\uf24f" },
|
||||||
},
|
"prev": { "prefix": "\uf4ab" },
|
||||||
"pasink": {
|
"next": { "prefix": "\uf4ad" }
|
||||||
"muted": { "prefix": "\uf3b9" },
|
},
|
||||||
"unmuted": { "prefix": "\uf3ba" }
|
"pasink": {
|
||||||
},
|
"muted": { "prefix": "\uf3b9" },
|
||||||
"amixer": {
|
"unmuted": { "prefix": "\uf3ba" }
|
||||||
"muted": { "prefix": "\uf3b9" },
|
},
|
||||||
"unmuted": { "prefix": "\uf3ba" }
|
"amixer": {
|
||||||
},
|
"muted": { "prefix": "\uf3b9" },
|
||||||
"pasource": {
|
"unmuted": { "prefix": "\uf3ba" }
|
||||||
"muted": { "prefix": "\uf395" },
|
},
|
||||||
"unmuted": { "prefix": "\uf2ec" }
|
"pasource": {
|
||||||
},
|
"muted": { "prefix": "\uf395" },
|
||||||
|
"unmuted": { "prefix": "\uf2ec" }
|
||||||
|
},
|
||||||
"kernel": {
|
"kernel": {
|
||||||
"prefix": "\uf17c"
|
"prefix": "\uf17c"
|
||||||
},
|
},
|
||||||
"nic": {
|
"nic": {
|
||||||
"wireless-up": { "prefix": "\uf25c" },
|
"wireless-up": { "prefix": "\uf25c" },
|
||||||
"wireless-down": { "prefix": "\uf3d0" },
|
"wireless-down": { "prefix": "\uf3d0" },
|
||||||
"wired-up": { "prefix": "\uf270" },
|
"wired-up": { "prefix": "\uf270" },
|
||||||
"wired-down": { "prefix": "\uf271" },
|
"wired-down": { "prefix": "\uf271" },
|
||||||
"tunnel-up": { "prefix": "\uf133" },
|
"tunnel-up": { "prefix": "\uf133" },
|
||||||
"tunnel-down": { "prefix": "\uf306" }
|
"tunnel-down": { "prefix": "\uf306" }
|
||||||
},
|
},
|
||||||
"bluetooth": {
|
"bluetooth": {
|
||||||
"ON": { "prefix": "\uf116" },
|
"ON": { "prefix": "\uf116" },
|
||||||
"OFF": { "prefix": "\uf116" },
|
"OFF": { "prefix": "\uf116" },
|
||||||
"?": { "prefix": "\uf116" }
|
"?": { "prefix": "\uf116" }
|
||||||
|
},
|
||||||
|
"battery": {
|
||||||
|
"charged": { "prefix": "\uf113", "suffix": "\uf493" },
|
||||||
|
"AC": { "suffix": "\uf493" },
|
||||||
|
"charging": {
|
||||||
|
"prefix": ["\uf112", "\uf115", "\uf114", "", "\uf111"],
|
||||||
|
"suffix": "\uf493"
|
||||||
},
|
},
|
||||||
"battery": {
|
"discharging-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
||||||
"charged": { "prefix": "\uf113", "suffix": "\uf493" },
|
"discharging-25": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
||||||
"AC": { "suffix": "\uf493" },
|
"discharging-50": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
||||||
"charging": {
|
"discharging-80": { "prefix": "\uf114", "suffix": "\uf3e6" },
|
||||||
"prefix": [ "\uf112", "\uf115", "\uf114", "", "\uf111" ],
|
"discharging-100": { "prefix": "\uf113", "suffix": "\uf3e6" },
|
||||||
"suffix": "\uf493"
|
"unknown-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
||||||
},
|
"unknown-25": { "prefix": "\uf115", "suffix": "\uf142" },
|
||||||
"discharging-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
"unknown-50": { "prefix": "\uf115", "suffix": "\uf142" },
|
||||||
"discharging-25": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
"unknown-80": { "prefix": "\uf114", "suffix": "\uf142" },
|
||||||
"discharging-50": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
"unknown-100": { "prefix": "\uf113", "suffix": "\uf142" },
|
||||||
"discharging-80": { "prefix": "\uf114", "suffix": "\uf3e6" },
|
"unlimited": { "prefix": "\uf402", "suffix": "\uf493" },
|
||||||
"discharging-100": { "prefix": "\uf113", "suffix": "\uf3e6" },
|
"estimate": { "prefix": "\uf402" }
|
||||||
"unknown-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
},
|
||||||
"unknown-25": { "prefix": "\uf115", "suffix": "\uf142" },
|
"battery_all": {
|
||||||
"unknown-50": { "prefix": "\uf115", "suffix": "\uf142" },
|
"charged": { "prefix": "\uf113", "suffix": "\uf493" },
|
||||||
"unknown-80": { "prefix": "\uf114", "suffix": "\uf142" },
|
"AC": { "suffix": "\uf493" },
|
||||||
"unknown-100": { "prefix": "\uf113", "suffix": "\uf142" },
|
"charging": {
|
||||||
"unlimited": { "prefix": "\uf402", "suffix": "\uf493" },
|
"prefix": ["\uf112", "\uf115", "\uf114", "", "\uf111"],
|
||||||
"estimate": { "prefix": "\uf402" }
|
"suffix": "\uf493"
|
||||||
},
|
},
|
||||||
"battery_all": {
|
"discharging-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
||||||
"charged": { "prefix": "\uf113", "suffix": "\uf493" },
|
"discharging-25": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
||||||
"AC": { "suffix": "\uf493" },
|
"discharging-50": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
||||||
"charging": {
|
"discharging-80": { "prefix": "\uf114", "suffix": "\uf3e6" },
|
||||||
"prefix": [ "\uf112", "\uf115", "\uf114", "", "\uf111" ],
|
"discharging-100": { "prefix": "\uf113", "suffix": "\uf3e6" },
|
||||||
"suffix": "\uf493"
|
"unknown-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
||||||
},
|
"unknown-25": { "prefix": "\uf115", "suffix": "\uf142" },
|
||||||
"discharging-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
"unknown-50": { "prefix": "\uf115", "suffix": "\uf142" },
|
||||||
"discharging-25": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
"unknown-80": { "prefix": "\uf114", "suffix": "\uf142" },
|
||||||
"discharging-50": { "prefix": "\uf115", "suffix": "\uf3e6" },
|
"unknown-100": { "prefix": "\uf113", "suffix": "\uf142" },
|
||||||
"discharging-80": { "prefix": "\uf114", "suffix": "\uf3e6" },
|
"unlimited": { "prefix": "\uf402", "suffix": "\uf493" },
|
||||||
"discharging-100": { "prefix": "\uf113", "suffix": "\uf3e6" },
|
"estimate": { "prefix": "\uf402" }
|
||||||
"unknown-10": { "prefix": "\uf112", "suffix": "\uf3bc" },
|
},
|
||||||
"unknown-25": { "prefix": "\uf115", "suffix": "\uf142" },
|
"caffeine": {
|
||||||
"unknown-50": { "prefix": "\uf115", "suffix": "\uf142" },
|
"activated": { "prefix": "\uf272\u3000\uf354" },
|
||||||
"unknown-80": { "prefix": "\uf114", "suffix": "\uf142" },
|
"deactivated": { "prefix": "\uf272\u3000\uf355" }
|
||||||
"unknown-100": { "prefix": "\uf113", "suffix": "\uf142" },
|
},
|
||||||
"unlimited": { "prefix": "\uf402", "suffix": "\uf493" },
|
"xrandr": {
|
||||||
"estimate": { "prefix": "\uf402" }
|
"on": { "prefix": "\uf465\u3000\uf354" },
|
||||||
},
|
"off": { "prefix": "\uf465\u3000\uf355" }
|
||||||
"caffeine": {
|
},
|
||||||
"activated": {"prefix": "\uf272\u3000\uf354" }, "deactivated": { "prefix": "\uf272\u3000\uf355" }
|
"redshift": {
|
||||||
},
|
"day": { "prefix": "\uf4b6" },
|
||||||
"xrandr": {
|
"night": { "prefix": "\uf467" },
|
||||||
"on": { "prefix": "\uf465\u3000\uf354"}, "off": { "prefix": "\uf465\u3000\uf355" }
|
"transition": { "prefix": "\uf475" }
|
||||||
},
|
},
|
||||||
"redshift": {
|
|
||||||
"day": { "prefix": "\uf4b6" }, "night": { "prefix": "\uf467" }, "transition": { "prefix": "\uf475" }
|
|
||||||
},
|
|
||||||
"sensors": {
|
"sensors": {
|
||||||
"prefix": "\uf3b6"
|
"prefix": "\uf3b6"
|
||||||
},
|
},
|
||||||
"traffic":{
|
"traffic": {
|
||||||
"rx": { "prefix": "\uf365" },
|
"rx": { "prefix": "\uf365" },
|
||||||
"tx": { "prefix": "\uf35f" }
|
"tx": { "prefix": "\uf35f" }
|
||||||
|
},
|
||||||
|
"network_traffic": {
|
||||||
|
"rx": { "prefix": "\uf365" },
|
||||||
|
"tx": { "prefix": "\uf35f" }
|
||||||
},
|
},
|
||||||
"mpd": {
|
"mpd": {
|
||||||
"playing": { "prefix": "\uf488" },
|
"playing": { "prefix": "\uf488" },
|
||||||
"paused": { "prefix": "\uf210" },
|
"paused": { "prefix": "\uf210" },
|
||||||
"stopped": { "prefix": "\uf24f" },
|
"stopped": { "prefix": "\uf24f" },
|
||||||
"prev": { "prefix": "\uf4ab" },
|
"prev": { "prefix": "\uf4ab" },
|
||||||
"next": { "prefix": "\uf4ad" },
|
"next": { "prefix": "\uf4ad" },
|
||||||
"shuffle-on": { "prefix": "\uf4a8" },
|
"shuffle-on": { "prefix": "\uf4a8" },
|
||||||
"shuffle-off": { "prefix": "\uf453" },
|
"shuffle-off": { "prefix": "\uf453" },
|
||||||
"repeat-on": { "prefix": "\uf459" },
|
"repeat-on": { "prefix": "\uf459" },
|
||||||
"repeat-off": { "prefix": "\uf30f" }
|
"repeat-off": { "prefix": "\uf30f" }
|
||||||
},
|
},
|
||||||
"github": {
|
"github": {
|
||||||
"prefix": "\uf233"
|
"prefix": "\uf233"
|
||||||
},
|
},
|
||||||
"spotify": {
|
"spotify": {
|
||||||
"prefix": "\uf305"
|
"prefix": "\uf305"
|
||||||
},
|
},
|
||||||
"publicip": {
|
"publicip": {
|
||||||
"prefix": "\uf268"
|
"prefix": "\uf268"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"clouds": { "prefix": "\uf12b" },
|
"clouds": { "prefix": "\uf12b" },
|
||||||
|
@ -157,11 +167,23 @@
|
||||||
"thunder": { "prefix": "\uf4bd" }
|
"thunder": { "prefix": "\uf4bd" }
|
||||||
},
|
},
|
||||||
"taskwarrior": {
|
"taskwarrior": {
|
||||||
"prefix": "\uf454"
|
"prefix": "\uf454"
|
||||||
},
|
},
|
||||||
"dunst": {
|
"dunst": {
|
||||||
"muted": { "prefix": "\uf39a"},
|
"muted": { "prefix": "\uf39a" },
|
||||||
"unmuted": { "prefix": "\uf39b" }
|
"unmuted": { "prefix": "\uf39b" }
|
||||||
}
|
},
|
||||||
|
"twmn": {
|
||||||
|
"muted": { "prefix": "\uf1f6" },
|
||||||
|
"unmuted": { "prefix": "\uf0f3" }
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"prefix": " \uf2a9 "
|
||||||
|
},
|
||||||
|
"sun": {
|
||||||
|
"prefix": "\uf3b0"
|
||||||
|
},
|
||||||
|
"rss": {
|
||||||
|
"prefix": "\uf1ea"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue