Merge branch 'master' of git://github.com/tobi-wan-kenobi/bumblebee-status
This commit is contained in:
commit
4fdba0be19
13 changed files with 167 additions and 42 deletions
30
README.md
30
README.md
|
@ -69,6 +69,7 @@ bar {
|
||||||
```
|
```
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
|
|
||||||
See [the wiki](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki) for documentation.
|
See [the wiki](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki) for documentation.
|
||||||
|
|
||||||
See [FAQ](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/FAQ) for, well, FAQs.
|
See [FAQ](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/FAQ) for, well, FAQs.
|
||||||
|
@ -79,6 +80,14 @@ Other resources:
|
||||||
* [How to write a theme](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/How-to-write-a-theme)
|
* [How to write a theme](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/How-to-write-a-theme)
|
||||||
* [How to write a module](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/How-to-write-a-module)
|
* [How to write a module](https://github.com/tobi-wan-kenobi/bumblebee-status/wiki/How-to-write-a-module)
|
||||||
|
|
||||||
|
User contributions:
|
||||||
|
|
||||||
|
[@somospocos:bumblebee-status-contrib](https://github.com/somospocos/bumblebee-status-contrib): Collected resources and useful tricks by @somospocos
|
||||||
|
|
||||||
|
[@somospocos:bumblebee-bridge-dwm](https://github.com/somospocos/bumblebee-bridge-dwm): Bridge bumblebee-status output into dwm status bar
|
||||||
|
|
||||||
|
[@somospocos:bumblebee-bridge-dzen2](https://github.com/somospocos/bumblebee-bridge-dzen2): Bridge bumblebee-status output into dzen2
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
```
|
```
|
||||||
$ git clone git://github.com/tobi-wan-kenobi/bumblebee-status
|
$ git clone git://github.com/tobi-wan-kenobi/bumblebee-status
|
||||||
|
@ -183,6 +192,25 @@ For example:
|
||||||
|
|
||||||
`$ bumblebee-status -p disk.left-click="nautilus {instance}"`
|
`$ bumblebee-status -p disk.left-click="nautilus {instance}"`
|
||||||
|
|
||||||
|
Advanced usage:
|
||||||
|
|
||||||
|
You can also "programmatically" trigger click events like this:
|
||||||
|
```
|
||||||
|
$ bumblebee-ctl --button <button> --id <ID of the widget> --module <name of the module>
|
||||||
|
```
|
||||||
|
|
||||||
|
For that to work, you need to know the ID of the widget - this can be configured by adding the `<name>.id` parameter - it's a comma-separated list with one entry per widget (for multi-widget modules).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ bumblebee-status -m cmus -p cmus.id="prev,main,next,shuffle,repeat"
|
||||||
|
# to "simulate" a left-click on "next":
|
||||||
|
$ bumblebee-ctl --button left-mouse --module cmus --id next
|
||||||
|
```
|
||||||
|
|
||||||
|
For a full synopsis, please see `bumblebee-ctl --help`.
|
||||||
|
|
||||||
## Errors
|
## Errors
|
||||||
If errors occur, you should see them in the i3bar itself. If that does not work, or you need more information for troubleshooting, you can activate a debug log using the `-d` or `--debug` switch:
|
If errors occur, you should see them in the i3bar itself. If that does not work, or you need more information for troubleshooting, you can activate a debug log using the `-d` or `--debug` switch:
|
||||||
|
|
||||||
|
@ -235,6 +263,8 @@ Modules and commandline utilities are only required for modules, the core itself
|
||||||
* zpool (for module 'zpool')
|
* zpool (for module 'zpool')
|
||||||
* progress (for module 'progress')
|
* progress (for module 'progress')
|
||||||
* i3exit (for module 'system')
|
* i3exit (for module 'system')
|
||||||
|
* dunst (for module 'dunst')
|
||||||
|
* hddtemp (for module 'hddtemp')
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
Here are some screenshots for all themes that currently exist:
|
Here are some screenshots for all themes that currently exist:
|
||||||
|
|
37
bumblebee-ctl
Executable file
37
bumblebee-ctl
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import glob
|
||||||
|
import socket
|
||||||
|
|
||||||
|
button = {
|
||||||
|
'left-mouse': 1,
|
||||||
|
'middle-mouse': 2,
|
||||||
|
'right-mouse': 3,
|
||||||
|
'wheel-up': 4,
|
||||||
|
'wheel-down': 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='send commands to bumblebee-status')
|
||||||
|
parser.add_argument('-b', '--button', choices=['left-mouse', 'right-mouse', 'middle-mouse', 'wheel-up', 'wheel-down'], help='button to emulate', default='left-mouse')
|
||||||
|
parser.add_argument('-i', '--id', help='ID of widget to trigger', required=True)
|
||||||
|
parser.add_argument('-m', '--module', help='name of the module to trigger', required=True)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
for f in glob.glob('/tmp/.bumblebee-status.*'):
|
||||||
|
print('accessing {}'.format(f))
|
||||||
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
s.connect(f)
|
||||||
|
s.sendall(json.dumps({
|
||||||
|
'name': args.module,
|
||||||
|
'instance': args.id,
|
||||||
|
'button': button[args.button],
|
||||||
|
}).encode('ascii'))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
|
@ -67,7 +67,9 @@ def main():
|
||||||
import time
|
import time
|
||||||
while True:
|
while True:
|
||||||
output.begin()
|
output.begin()
|
||||||
error = bumblebee.modules.error.Module(engine, config)
|
error = bumblebee.modules.error.Module(engine, {
|
||||||
|
"config": config, "name": "error"
|
||||||
|
})
|
||||||
error.set("exception occurred: {} in {}".format(e, module))
|
error.set("exception occurred: {} in {}".format(e, module))
|
||||||
widget = error.widgets()[0]
|
widget = error.widgets()[0]
|
||||||
widget.link_module(error)
|
widget.link_module(error)
|
||||||
|
|
|
@ -295,8 +295,15 @@ class Engine(object):
|
||||||
self._current_module = module
|
self._current_module = module
|
||||||
module.update_wrapper(module.widgets())
|
module.update_wrapper(module.widgets())
|
||||||
if module.error is None:
|
if module.error is None:
|
||||||
|
widget_ids = []
|
||||||
|
if module.parameter('id'):
|
||||||
|
widget_ids = module.parameter('id').split(',')
|
||||||
|
idx = 0
|
||||||
for widget in module.widgets():
|
for widget in module.widgets():
|
||||||
widget.link_module(module)
|
widget.link_module(module)
|
||||||
|
if idx < len(widget_ids):
|
||||||
|
widget.id = widget_ids[idx]
|
||||||
|
idx = idx + 1
|
||||||
self._output.draw(widget=widget, module=module, engine=self)
|
self._output.draw(widget=widget, module=module, engine=self)
|
||||||
else:
|
else:
|
||||||
self._output.draw(widget=module.errorWidget(), module=module, engine=self)
|
self._output.draw(widget=module.errorWidget(), module=module, engine=self)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
"""Input classes"""
|
"""Input classes"""
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
import time
|
import time
|
||||||
|
import socket
|
||||||
import select
|
import select
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
@ -23,10 +25,28 @@ def is_terminated():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
class CommandSocket(object):
|
||||||
|
def __init__(self):
|
||||||
|
self._name = "/tmp/.bumblebee-status.{}".format(os.getpid())
|
||||||
|
self._socket = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
self._socket.bind(self._name)
|
||||||
|
self._socket.listen(5)
|
||||||
|
return self._socket
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
self._socket.close()
|
||||||
|
os.unlink(self._name)
|
||||||
|
|
||||||
def read_input(inp):
|
def read_input(inp):
|
||||||
"""Read i3bar input and execute callbacks"""
|
"""Read i3bar input and execute callbacks"""
|
||||||
|
|
||||||
|
with CommandSocket() as cmdsocket:
|
||||||
poll = select.poll()
|
poll = select.poll()
|
||||||
poll.register(sys.stdin.fileno(), select.POLLIN)
|
poll.register(sys.stdin, select.POLLIN)
|
||||||
|
poll.register(cmdsocket, 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():
|
||||||
|
@ -37,6 +57,12 @@ def read_input(inp):
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
for fileno, event in events:
|
for fileno, event in events:
|
||||||
|
|
||||||
|
if fileno == cmdsocket.fileno():
|
||||||
|
tmp, _ = cmdsocket.accept()
|
||||||
|
line = tmp.recv(4096).decode()
|
||||||
|
tmp.close()
|
||||||
|
else:
|
||||||
line = "["
|
line = "["
|
||||||
while line.startswith("["):
|
while line.startswith("["):
|
||||||
line = sys.stdin.readline().strip(",").strip()
|
line = sys.stdin.readline().strip(",").strip()
|
||||||
|
|
|
@ -240,7 +240,7 @@ class Module(bumblebee.engine.Module):
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
state = []
|
state = []
|
||||||
capacity = widget.get("capacity")
|
capacity = widget.get("capacity", -1)
|
||||||
if capacity < 0:
|
if capacity < 0:
|
||||||
return ["critical", "unknown"]
|
return ["critical", "unknown"]
|
||||||
|
|
||||||
|
|
|
@ -91,17 +91,16 @@ class Module(bumblebee.engine.Module):
|
||||||
def cpuload(self, _):
|
def cpuload(self, _):
|
||||||
return "{}%".format(self._cpuload)
|
return "{}%".format(self._cpuload)
|
||||||
|
|
||||||
@staticmethod
|
def add_color(self, bar):
|
||||||
def add_color(bar):
|
|
||||||
"""add color as pango markup to a bar"""
|
"""add color as pango markup to a bar"""
|
||||||
if bar in ["▁", "▂"]:
|
if bar in ["▁", "▂"]:
|
||||||
color = "green"
|
color = self.theme().color("green", "green")
|
||||||
elif bar in ["▃", "▄"]:
|
elif bar in ["▃", "▄"]:
|
||||||
color = "yellow"
|
color = self.theme().color("yellow", "yellow")
|
||||||
elif bar in ["▅", "▆"]:
|
elif bar in ["▅", "▆"]:
|
||||||
color = "orange"
|
color = self.theme().color("orange", "orange")
|
||||||
elif bar in ["▇", "█"]:
|
elif bar in ["▇", "█"]:
|
||||||
color = "red"
|
color = self.theme().color("red", "red")
|
||||||
colored_bar = "<span foreground='{}'>{}</span>".format(color, bar)
|
colored_bar = "<span foreground='{}'>{}</span>".format(color, bar)
|
||||||
return colored_bar
|
return colored_bar
|
||||||
|
|
||||||
|
|
|
@ -142,12 +142,12 @@ class Module(bumblebee.engine.Module):
|
||||||
vol, bumblebee.output.hbar(float(self._left)))
|
vol, bumblebee.output.hbar(float(self._left)))
|
||||||
return vol
|
return vol
|
||||||
else:
|
else:
|
||||||
|
vol = "{}%/{}%".format(self._left, self._right)
|
||||||
if self._showbars:
|
if self._showbars:
|
||||||
vol = "{} {}{}".format(
|
vol = "{} {}{}".format(
|
||||||
vol,
|
vol,
|
||||||
bumblebee.output.hbar(float(self._left)),
|
bumblebee.output.hbar(float(self._left)),
|
||||||
bumblebee.output.hbar(float(self._right)))
|
bumblebee.output.hbar(float(self._right)))
|
||||||
vol = "{}%/{}%".format(self._left, self._right)
|
|
||||||
return vol
|
return vol
|
||||||
|
|
||||||
def update(self, widgets):
|
def update(self, widgets):
|
||||||
|
|
|
@ -18,6 +18,7 @@ import logging
|
||||||
import bumblebee.input
|
import bumblebee.input
|
||||||
import bumblebee.output
|
import bumblebee.output
|
||||||
import bumblebee.engine
|
import bumblebee.engine
|
||||||
|
import bumblebee.popup_v2
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
class Module(bumblebee.engine.Module):
|
class Module(bumblebee.engine.Module):
|
||||||
|
@ -76,7 +77,7 @@ class Module(bumblebee.engine.Module):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bumblebee.util.execute("nmcli c up \"{vpn}\""
|
bumblebee.util.execute("nmcli c up \"{vpn}\""
|
||||||
.format(vpn=self._connected_vpn_profile))
|
.format(vpn=self._selected_vpn_profile))
|
||||||
self._connected_vpn_profile = name
|
self._connected_vpn_profile = name
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("Couldn't establish VPN connection")
|
logging.exception("Couldn't establish VPN connection")
|
||||||
|
|
|
@ -72,6 +72,12 @@ def scrollable(func):
|
||||||
if width < 0:
|
if width < 0:
|
||||||
return text
|
return text
|
||||||
if len(text) <= width:
|
if len(text) <= width:
|
||||||
|
# do alignment
|
||||||
|
align = module.parameter("theme.align", "left")
|
||||||
|
if align == "right":
|
||||||
|
text = "{:>{}}".format(text, width)
|
||||||
|
if align == "center":
|
||||||
|
text = "{:^{}}".format(text, width)
|
||||||
return text
|
return text
|
||||||
# we need to shorten
|
# we need to shorten
|
||||||
|
|
||||||
|
|
|
@ -186,9 +186,14 @@ class Theme(object):
|
||||||
result[key] = colors[field][key]
|
result[key] = colors[field][key]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def color(self, color_name, default=None):
|
||||||
|
return self._colorset.get(color_name, default)
|
||||||
|
|
||||||
def _load_colors(self, name):
|
def _load_colors(self, name):
|
||||||
"""Load colors for a theme"""
|
"""Load colors for a theme"""
|
||||||
try:
|
try:
|
||||||
|
if isinstance(name, dict):
|
||||||
|
return name
|
||||||
if name.lower() == "wal":
|
if name.lower() == "wal":
|
||||||
return self._load_wal_colors()
|
return self._load_wal_colors()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -285,7 +290,7 @@ class Theme(object):
|
||||||
|
|
||||||
if isinstance(value, (dict, list)):
|
if isinstance(value, (dict, list)):
|
||||||
return value
|
return value
|
||||||
return self._colorset.get(value, value)
|
return self.color(value, value)
|
||||||
|
|
||||||
# algorithm copied from
|
# algorithm copied from
|
||||||
# http://blog.impressiver.com/post/31434674390/deep-merge-multiple-python-dicts
|
# http://blog.impressiver.com/post/31434674390/deep-merge-multiple-python-dicts
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
{
|
{
|
||||||
"icons": [ "paxy97", "awesome-fonts" ],
|
"icons": [ "paxy97", "awesome-fonts" ],
|
||||||
|
"colors": [{
|
||||||
|
"fg0": "#fbf1c7",
|
||||||
|
"bg0_h": "#1d2021",
|
||||||
|
"yellow": "#d79921",
|
||||||
|
"red": "#cc241d"
|
||||||
|
}],
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"warning": {
|
"warning": {
|
||||||
"fg": "#1d2021",
|
"fg": "bg0_h",
|
||||||
"bg": "#d79921"
|
"bg": "yellow"
|
||||||
},
|
},
|
||||||
"critical": {
|
"critical": {
|
||||||
"fg": "#fbf1c7",
|
"fg": "fg0",
|
||||||
"bg": "#cc241d"
|
"bg": "red"
|
||||||
},
|
},
|
||||||
"default-separators": false,
|
"default-separators": false,
|
||||||
"separator-block-width": 0
|
"separator-block-width": 0
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"icons": [ "awesome-fonts" ],
|
"icons": [ "awesome-fonts" ],
|
||||||
|
"colors": [{
|
||||||
|
"red": "#BF616A",
|
||||||
|
"orange": "#D08770",
|
||||||
|
"yellow": "#EBCB8B",
|
||||||
|
"green": "#A3BE8C"
|
||||||
|
}],
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"separator-block-width": 0,
|
"separator-block-width": 0,
|
||||||
"warning": {
|
"warning": {
|
||||||
|
|
Loading…
Reference in a new issue