Merge branch 'master' of github.com:tobi-wan-kenobi/bumblebee-status
Pulling
This commit is contained in:
commit
5b53ed5cf3
9 changed files with 221 additions and 10 deletions
|
@ -13,3 +13,4 @@ ratings:
|
|||
- "**.py"
|
||||
exclude_paths:
|
||||
- tests/
|
||||
- thirdparty/
|
||||
|
|
64
bumblebee/modules/layout-xkb.py
Normal file
64
bumblebee/modules/layout-xkb.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
# pylint: disable=C0111,R0903
|
||||
|
||||
"""Displays the current keyboard layout using libX11
|
||||
|
||||
Requires the following library:
|
||||
* libX11.so.6
|
||||
|
||||
Parameters:
|
||||
* layout-xkb.showname: Boolean that indicate whether the full name should be displayed. Defaults to false (only the symbol will be displayed)
|
||||
"""
|
||||
|
||||
import bumblebee.input
|
||||
import bumblebee.output
|
||||
import bumblebee.engine
|
||||
|
||||
has_xkb = True
|
||||
try:
|
||||
from xkbgroup import *
|
||||
except ImportError:
|
||||
has_xkb = False
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class Module(bumblebee.engine.Module):
|
||||
def __init__(self, engine, config):
|
||||
super(Module, self).__init__(engine, config,
|
||||
bumblebee.output.Widget(full_text=self.current_layout)
|
||||
)
|
||||
engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE,
|
||||
cmd=self._next_keymap)
|
||||
engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE,
|
||||
cmd=self._prev_keymap)
|
||||
|
||||
def _next_keymap(self, event):
|
||||
self._set_keymap(1)
|
||||
|
||||
def _prev_keymap(self, event):
|
||||
self._set_keymap(-1)
|
||||
|
||||
def _set_keymap(self, rotation):
|
||||
if not has_xkb: return
|
||||
|
||||
xkb = XKeyboard()
|
||||
if xkb.groups_count < 2: return # nothing to doA
|
||||
|
||||
layouts = xkb.groups_symbols[rotation:] + xkb.groups_symbols[:rotation]
|
||||
variants = xkb.groups_variants[rotation:] + xkb.groups_variants[:rotation]
|
||||
|
||||
try:
|
||||
bumblebee.util.execute("setxkbmap -layout {} -variant {}".format(",".join(layouts), ",".join(variants)))
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def current_layout(self, widget):
|
||||
try:
|
||||
xkb = XKeyboard()
|
||||
log.debug("group num: {}".format(xkb.group_num))
|
||||
name = xkb.group_name if bumblebee.util.asbool(self.parameter("showname")) else xkb.group_symbol
|
||||
return "{} ({})".format(name, xkb.group_variant) if xkb.group_variant else name
|
||||
except Exception:
|
||||
return "n/a"
|
||||
|
||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Displays GPU name, temperature and memory usage.
|
||||
|
|
70
bumblebee/modules/rotation.py
Normal file
70
bumblebee/modules/rotation.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
# pylint: disable=C0111,R0903
|
||||
|
||||
"""Shows a widget for each connected screen and allows the user to loop through different orientations.
|
||||
|
||||
Requires the following executable:
|
||||
* xrandr
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import bumblebee.util
|
||||
import bumblebee.input
|
||||
import bumblebee.output
|
||||
import bumblebee.engine
|
||||
|
||||
possible_orientations = ["normal", "left", "inverted", "right"]
|
||||
|
||||
class Module(bumblebee.engine.Module):
|
||||
def __init__(self, engine, config):
|
||||
widgets = []
|
||||
self._engine = engine
|
||||
super(Module, self).__init__(engine, config, widgets)
|
||||
self.update_widgets(widgets)
|
||||
|
||||
def update_widgets(self, widgets):
|
||||
new_widgets = []
|
||||
for line in bumblebee.util.execute("xrandr -q").split("\n"):
|
||||
if not " connected" in line:
|
||||
continue
|
||||
display = line.split(" ", 2)[0]
|
||||
|
||||
orientation = "normal"
|
||||
for curr_orient in possible_orientations:
|
||||
if((line.split(" ")).count(curr_orient) > 1):
|
||||
orientation = curr_orient
|
||||
break
|
||||
|
||||
widget = self.widget(display)
|
||||
if not widget:
|
||||
widget = bumblebee.output.Widget(full_text=display, name=display)
|
||||
self._engine.input.register_callback(widget, button=bumblebee.input.LEFT_MOUSE, cmd=self._toggle)
|
||||
new_widgets.append(widget)
|
||||
widget.set("orientation", orientation)
|
||||
|
||||
while len(widgets) > 0:
|
||||
del widgets[0]
|
||||
for widget in new_widgets:
|
||||
widgets.append(widget)
|
||||
|
||||
def update(self, widgets):
|
||||
self.update_widgets(widgets)
|
||||
|
||||
def state(self, widget):
|
||||
return widget.get("orientation", "normal")
|
||||
|
||||
def _toggle(self, event):
|
||||
widget = self.widget_by_id(event["instance"])
|
||||
|
||||
# compute new orientation based on current orientation
|
||||
idx = possible_orientations.index(widget.get("orientation"))
|
||||
idx = (idx + 1) % len(possible_orientations)
|
||||
new_orientation = possible_orientations[idx]
|
||||
|
||||
widget.set("orientation", new_orientation)
|
||||
|
||||
bumblebee.util.execute("xrandr --output {} --rotation {}".format(widget.name, new_orientation))
|
||||
|
||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
|
@ -47,9 +47,13 @@ class Module(bumblebee.engine.Module):
|
|||
return temperature
|
||||
|
||||
def get_mhz( self ):
|
||||
output = open("/proc/cpuinfo").read()
|
||||
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
||||
mhz = int(m.group(1))
|
||||
try:
|
||||
output = open("/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq").read()
|
||||
mhz = int(float(output)/1000.0)
|
||||
except:
|
||||
output = open("/proc/cpuinfo").read()
|
||||
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
||||
mhz = int(m.group(1))
|
||||
|
||||
if mhz < 1000:
|
||||
return "{} MHz".format(mhz)
|
||||
|
|
|
@ -16,6 +16,7 @@ Parameters:
|
|||
import bumblebee.input
|
||||
import bumblebee.output
|
||||
import bumblebee.engine
|
||||
import re
|
||||
import json
|
||||
import time
|
||||
try:
|
||||
|
@ -27,11 +28,12 @@ except ImportError:
|
|||
class Module(bumblebee.engine.Module):
|
||||
def __init__(self, engine, config):
|
||||
super(Module, self).__init__(engine, config,
|
||||
bumblebee.output.Widget(full_text=self.temperature)
|
||||
bumblebee.output.Widget(full_text=self.output)
|
||||
)
|
||||
self._temperature = 0
|
||||
self._apikey = self.parameter("apikey", "af7bfe22287c652d032a3064ffa44088")
|
||||
self._location = self.parameter("location", "auto")
|
||||
self._city = self.parameter("location", "")
|
||||
self._interval = int(self.parameter("interval", "15"))
|
||||
self._unit = self.parameter("unit", "metric")
|
||||
self._nextcheck = 0
|
||||
|
@ -46,10 +48,17 @@ class Module(bumblebee.engine.Module):
|
|||
return "F"
|
||||
return ""
|
||||
|
||||
def temperature(self, widget):
|
||||
def temperature(self):
|
||||
return u"{}°{}".format(self._temperature, self._unit_suffix())
|
||||
|
||||
def city(self):
|
||||
self._city = re.sub('[_-]', ' ', self._city)
|
||||
return u"{} ".format(self._city)
|
||||
|
||||
def output(self, widget):
|
||||
if not self._valid:
|
||||
return u"?"
|
||||
return u"{}°{}".format(self._temperature, self._unit_suffix())
|
||||
return self.city() + self.temperature()
|
||||
|
||||
def state( self, widget ):
|
||||
if self._valid:
|
||||
|
@ -83,6 +92,7 @@ class Module(bumblebee.engine.Module):
|
|||
location_url = "http://ipinfo.io/json"
|
||||
location = json.loads(requests.get(location_url).text)
|
||||
coord = location["loc"].split(",")
|
||||
self._city = location["city"]
|
||||
weather_url = "{url}&lat={lat}&lon={lon}".format(url=weather_url, lat=coord[0], lon=coord[1])
|
||||
else:
|
||||
weather_url = "{url}&q={city}".format(url=weather_url, city=self._location)
|
||||
|
|
|
@ -25,17 +25,20 @@ def themes():
|
|||
class Theme(object):
|
||||
"""Represents a collection of icons and colors"""
|
||||
def __init__(self, name):
|
||||
self._init(self.load(name))
|
||||
self._widget = None
|
||||
self._cycle_idx = 0
|
||||
self._cycle = {}
|
||||
self._prevbg = None
|
||||
self._colorset = {}
|
||||
self._init(self.load(name))
|
||||
|
||||
def _init(self, data):
|
||||
"""Initialize theme from data structure"""
|
||||
self._theme = data
|
||||
for iconset in data.get("icons", []):
|
||||
self._merge(data, self._load_icons(iconset))
|
||||
for colorset in data.get("colors", []):
|
||||
self._merge(self._colorset, self._load_colors(colorset))
|
||||
self._defaults = data.get("defaults", {})
|
||||
self._cycles = self._theme.get("cycle", [])
|
||||
self.reset()
|
||||
|
@ -99,6 +102,21 @@ class Theme(object):
|
|||
"""Return the SBW"""
|
||||
return self._get(widget, "separator-block-width", None)
|
||||
|
||||
def _load_wal_colors(self):
|
||||
walfile = os.path.expanduser("~/.cache/wal/colors.json")
|
||||
result = {}
|
||||
with io.open(walfile) as data:
|
||||
colors = json.load(data)
|
||||
for field in ["special", "colors"]:
|
||||
for key in colors[field]:
|
||||
result[key] = colors[field][key]
|
||||
return result
|
||||
|
||||
def _load_colors(self, name):
|
||||
"""Load colors for a theme"""
|
||||
if name == "wal":
|
||||
return self._load_wal_colors()
|
||||
|
||||
def _load_icons(self, name):
|
||||
"""Load icons for a theme"""
|
||||
path = "{}/icons/".format(theme_path())
|
||||
|
@ -110,7 +128,7 @@ class Theme(object):
|
|||
|
||||
if os.path.isfile(themefile):
|
||||
try:
|
||||
with io.open(themefile,encoding="utf-8") as data:
|
||||
with io.open(themefile, encoding="utf-8") as data:
|
||||
return json.load(data)
|
||||
except ValueError as exception:
|
||||
raise bumblebee.error.ThemeLoadError("JSON error: {}".format(exception))
|
||||
|
@ -155,7 +173,9 @@ class Theme(object):
|
|||
widget.set(key, (idx + 1) % len(value))
|
||||
value = value[idx]
|
||||
|
||||
return value
|
||||
if isinstance(value, list) or isinstance(value, dict):
|
||||
return value
|
||||
return self._colorset.get(value, value)
|
||||
|
||||
# algorithm copied from
|
||||
# http://blog.impressiver.com/post/31434674390/deep-merge-multiple-python-dicts
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"brightness": { "prefix": "" },
|
||||
"load": { "prefix": "" },
|
||||
"layout": { "prefix": "" },
|
||||
"layout-xkb": { "prefix": "" },
|
||||
"todo": { "empty": {"prefix": "" },
|
||||
"items": {"prefix": "" }
|
||||
},
|
||||
|
|
42
themes/wal-powerline.json
Normal file
42
themes/wal-powerline.json
Normal file
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"icons": [ "awesome-fonts" ],
|
||||
"colors": [ "wal" ],
|
||||
"defaults": {
|
||||
"separator-block-width": 0,
|
||||
"critical": {
|
||||
"fg": "cursor",
|
||||
"bg": "color5"
|
||||
},
|
||||
"warning": {
|
||||
"fg": "cursor",
|
||||
"bg": "color6"
|
||||
},
|
||||
"default_separators": false
|
||||
},
|
||||
"cycle": [
|
||||
{
|
||||
"fg": "foreground",
|
||||
"bg": "background"
|
||||
},
|
||||
{
|
||||
"fg": "background",
|
||||
"bg": "foreground"
|
||||
}
|
||||
],
|
||||
"dnf": {
|
||||
"good": {
|
||||
"fg": "background",
|
||||
"bg": "color3"
|
||||
}
|
||||
},
|
||||
"battery": {
|
||||
"charged": {
|
||||
"fg": "background",
|
||||
"bg": "color3"
|
||||
},
|
||||
"AC": {
|
||||
"fg": "background",
|
||||
"bg": "color3"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue