[formatting] reformat using "black -t py34"
getting rid of thinking about consistent formatting...
This commit is contained in:
parent
fa98bcbdd1
commit
30c1f712a6
119 changed files with 3961 additions and 3495 deletions
|
@ -7,34 +7,48 @@ import glob
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
button = {
|
button = {
|
||||||
'left-mouse': 1,
|
"left-mouse": 1,
|
||||||
'middle-mouse': 2,
|
"middle-mouse": 2,
|
||||||
'right-mouse': 3,
|
"right-mouse": 3,
|
||||||
'wheel-up': 4,
|
"wheel-up": 4,
|
||||||
'wheel-down': 5,
|
"wheel-down": 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='send commands to bumblebee-status')
|
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(
|
||||||
parser.add_argument('-i', '--id', help='ID of widget to trigger')
|
"-b",
|
||||||
parser.add_argument('-m', '--module', help='name of the module to trigger', required=True)
|
"--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")
|
||||||
|
parser.add_argument(
|
||||||
|
"-m", "--module", help="name of the module to trigger", required=True
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
for f in glob.glob('/tmp/.bumblebee-status.*'):
|
for f in glob.glob("/tmp/.bumblebee-status.*"):
|
||||||
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
try:
|
try:
|
||||||
s.connect(f)
|
s.connect(f)
|
||||||
s.sendall(json.dumps({
|
s.sendall(
|
||||||
'name': args.module,
|
json.dumps(
|
||||||
'instance': args.id,
|
{
|
||||||
'button': button[args.button],
|
"name": args.module,
|
||||||
}).encode('ascii'))
|
"instance": args.id,
|
||||||
|
"button": button[args.button],
|
||||||
|
}
|
||||||
|
).encode("ascii")
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
os.remove(f)
|
os.remove(f)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -14,9 +14,10 @@ import core.module
|
||||||
import core.input
|
import core.input
|
||||||
import core.event
|
import core.event
|
||||||
|
|
||||||
|
|
||||||
class CommandSocket(object):
|
class CommandSocket(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__name = '/tmp/.bumblebee-status.{}'.format(os.getpid())
|
self.__name = "/tmp/.bumblebee-status.{}".format(os.getpid())
|
||||||
self.__socket = None
|
self.__socket = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
@ -29,6 +30,7 @@ class CommandSocket(object):
|
||||||
self.__socket.close()
|
self.__socket.close()
|
||||||
os.unlink(self.__name)
|
os.unlink(self.__name)
|
||||||
|
|
||||||
|
|
||||||
def handle_input(output):
|
def handle_input(output):
|
||||||
with CommandSocket() as cmdsocket:
|
with CommandSocket() as cmdsocket:
|
||||||
poll = select.poll()
|
poll = select.poll()
|
||||||
|
@ -44,24 +46,25 @@ def handle_input(output):
|
||||||
tmp, _ = cmdsocket.accept()
|
tmp, _ = cmdsocket.accept()
|
||||||
line = tmp.recv(4096).decode()
|
line = tmp.recv(4096).decode()
|
||||||
tmp.close()
|
tmp.close()
|
||||||
logging.debug('socket event {}'.format(line))
|
logging.debug("socket event {}".format(line))
|
||||||
else:
|
else:
|
||||||
line = '['
|
line = "["
|
||||||
while line.startswith('['):
|
while line.startswith("["):
|
||||||
line = sys.stdin.readline().strip(',').strip()
|
line = sys.stdin.readline().strip(",").strip()
|
||||||
logging.info('input event: {}'.format(line))
|
logging.info("input event: {}".format(line))
|
||||||
try:
|
try:
|
||||||
event = json.loads(line)
|
event = json.loads(line)
|
||||||
core.input.trigger(event)
|
core.input.trigger(event)
|
||||||
if 'name' in event:
|
if "name" in event:
|
||||||
modules[event['name']] = True
|
modules[event["name"]] = True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
core.event.trigger('update', modules.keys())
|
core.event.trigger("update", modules.keys())
|
||||||
core.event.trigger('draw')
|
core.event.trigger("draw")
|
||||||
|
|
||||||
poll.unregister(sys.stdin.fileno())
|
poll.unregister(sys.stdin.fileno())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
config = core.config.Config(sys.argv[1:])
|
config = core.config.Config(sys.argv[1:])
|
||||||
|
|
||||||
|
@ -70,28 +73,28 @@ def main():
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=level,
|
level=level,
|
||||||
format="[%(asctime)s] %(module)-16s %(levelname)-8s %(message)s",
|
format="[%(asctime)s] %(module)-16s %(levelname)-8s %(message)s",
|
||||||
filename=os.path.abspath(os.path.expanduser(config.logfile()))
|
filename=os.path.abspath(os.path.expanduser(config.logfile())),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=level,
|
level=level,
|
||||||
format="[%(asctime)s] %(module)-16s %(levelname)-8s %(message)s",
|
format="[%(asctime)s] %(module)-16s %(levelname)-8s %(message)s",
|
||||||
stream=sys.stderr
|
stream=sys.stderr,
|
||||||
)
|
)
|
||||||
|
|
||||||
theme = core.theme.Theme(config.theme(), config.iconset())
|
theme = core.theme.Theme(config.theme(), config.iconset())
|
||||||
output = core.output.i3(theme, config)
|
output = core.output.i3(theme, config)
|
||||||
modules = []
|
modules = []
|
||||||
|
|
||||||
core.input.register(None, core.input.WHEEL_UP, 'i3-msg workspace prev_on_output')
|
core.input.register(None, core.input.WHEEL_UP, "i3-msg workspace prev_on_output")
|
||||||
core.input.register(None, core.input.WHEEL_DOWN, 'i3-msg workspace next_on_output')
|
core.input.register(None, core.input.WHEEL_DOWN, "i3-msg workspace next_on_output")
|
||||||
|
|
||||||
input_thread = threading.Thread(target=handle_input, args=(output,))
|
input_thread = threading.Thread(target=handle_input, args=(output,))
|
||||||
input_thread.daemon = True
|
input_thread.daemon = True
|
||||||
input_thread.start()
|
input_thread.start()
|
||||||
|
|
||||||
if config.debug():
|
if config.debug():
|
||||||
modules.append(core.module.load('debug', config, theme))
|
modules.append(core.module.load("debug", config, theme))
|
||||||
|
|
||||||
for module in config.modules():
|
for module in config.modules():
|
||||||
modules.append(core.module.load(module, config, theme))
|
modules.append(core.module.load(module, config, theme))
|
||||||
|
@ -100,12 +103,13 @@ def main():
|
||||||
modules.reverse()
|
modules.reverse()
|
||||||
|
|
||||||
output.modules(modules)
|
output.modules(modules)
|
||||||
core.event.trigger('start')
|
core.event.trigger("start")
|
||||||
while True:
|
while True:
|
||||||
core.event.trigger('update')
|
core.event.trigger("update")
|
||||||
core.event.trigger('draw')
|
core.event.trigger("draw")
|
||||||
output.wait(config.interval())
|
output.wait(config.interval())
|
||||||
core.event.trigger('stop')
|
core.event.trigger("stop")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -113,9 +117,9 @@ if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
output = core.output.i3()
|
output = core.output.i3()
|
||||||
output.modules(core.module.Error(module='main', error=e))
|
output.modules(core.module.Error(module="main", error=e))
|
||||||
output.draw('start')
|
output.draw("start")
|
||||||
output.update()
|
output.update()
|
||||||
output.draw('statusline')
|
output.draw("statusline")
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
177
core/config.py
177
core/config.py
|
@ -19,58 +19,66 @@ import modules.contrib
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
MODULE_HELP = 'Specify a space-separated list of modules to load. The order of the list determines their order in the i3bar (from left to right). Use <module>:<alias> to provide an alias in case you want to load the same module multiple times, but specify different parameters.'
|
MODULE_HELP = "Specify a space-separated list of modules to load. The order of the list determines their order in the i3bar (from left to right). Use <module>:<alias> to provide an alias in case you want to load the same module multiple times, but specify different parameters."
|
||||||
PARAMETER_HELP = 'Provide configuration parameters in the form of <module>.<key>=<value>'
|
PARAMETER_HELP = (
|
||||||
THEME_HELP = 'Specify the theme to use for drawing modules'
|
"Provide configuration parameters in the form of <module>.<key>=<value>"
|
||||||
|
)
|
||||||
|
THEME_HELP = "Specify the theme to use for drawing modules"
|
||||||
|
|
||||||
|
|
||||||
def all_modules():
|
def all_modules():
|
||||||
"""Return a list of available modules"""
|
"""Return a list of available modules"""
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
for path in [ modules.core.__file__, modules.contrib.__file__ ]:
|
for path in [modules.core.__file__, modules.contrib.__file__]:
|
||||||
path = os.path.dirname(path)
|
path = os.path.dirname(path)
|
||||||
for mod in glob.iglob('{}/*.py'.format(path)):
|
for mod in glob.iglob("{}/*.py".format(path)):
|
||||||
result[os.path.basename(mod).replace('.py', '')] = 1
|
result[os.path.basename(mod).replace(".py", "")] = 1
|
||||||
|
|
||||||
res = list(result.keys())
|
res = list(result.keys())
|
||||||
res.sort()
|
res.sort()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class print_usage(argparse.Action):
|
class print_usage(argparse.Action):
|
||||||
def __init__(self, option_strings, dest, nargs=None, **kwargs):
|
def __init__(self, option_strings, dest, nargs=None, **kwargs):
|
||||||
argparse.Action.__init__(self, option_strings, dest, nargs, **kwargs)
|
argparse.Action.__init__(self, option_strings, dest, nargs, **kwargs)
|
||||||
self._indent = ' '*2
|
self._indent = " " * 2
|
||||||
|
|
||||||
def __call__(self, parser, namespace, value, option_string=None):
|
def __call__(self, parser, namespace, value, option_string=None):
|
||||||
if value == 'modules':
|
if value == "modules":
|
||||||
self._args = namespace
|
self._args = namespace
|
||||||
self._format = 'plain'
|
self._format = "plain"
|
||||||
self.print_modules()
|
self.print_modules()
|
||||||
elif value == 'modules-markdown':
|
elif value == "modules-markdown":
|
||||||
self._args = namespace
|
self._args = namespace
|
||||||
self._format = 'markdown'
|
self._format = "markdown"
|
||||||
self.print_modules()
|
self.print_modules()
|
||||||
elif value == 'themes':
|
elif value == "themes":
|
||||||
self.print_themes()
|
self.print_themes()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def print_themes(self):
|
def print_themes(self):
|
||||||
print(', '.join(core.theme.themes()))
|
print(", ".join(core.theme.themes()))
|
||||||
|
|
||||||
def print_modules(self):
|
def print_modules(self):
|
||||||
if self._format == 'markdown':
|
if self._format == "markdown":
|
||||||
print('# Table of modules')
|
print("# Table of modules")
|
||||||
print('|Name |Description |')
|
print("|Name |Description |")
|
||||||
print('|-----|------------|')
|
print("|-----|------------|")
|
||||||
|
|
||||||
for m in all_modules():
|
for m in all_modules():
|
||||||
try:
|
try:
|
||||||
basepath = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
|
basepath = os.path.abspath(
|
||||||
filename = os.path.join(basepath, 'modules', 'core', '{}.py'.format(m))
|
os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")
|
||||||
|
)
|
||||||
|
filename = os.path.join(basepath, "modules", "core", "{}.py".format(m))
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
filename = os.path.join(basepath, 'modules', 'contrib', '{}.py'.format(m))
|
filename = os.path.join(
|
||||||
|
basepath, "modules", "contrib", "{}.py".format(m)
|
||||||
|
)
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
log.warning('module {} not found'.format(m))
|
log.warning("module {} not found".format(m))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
doc = None
|
doc = None
|
||||||
|
@ -79,72 +87,126 @@ class print_usage(argparse.Action):
|
||||||
doc = ast.get_docstring(tree)
|
doc = ast.get_docstring(tree)
|
||||||
|
|
||||||
if not doc:
|
if not doc:
|
||||||
log.warning('failed to find docstring for {}'.format(m))
|
log.warning("failed to find docstring for {}".format(m))
|
||||||
continue
|
continue
|
||||||
if self._format == 'markdown':
|
if self._format == "markdown":
|
||||||
doc = doc.replace('<', '\<')
|
doc = doc.replace("<", "\<")
|
||||||
doc = doc.replace('>', '\>')
|
doc = doc.replace(">", "\>")
|
||||||
doc = doc.replace('\n', '<br>')
|
doc = doc.replace("\n", "<br>")
|
||||||
print('|{} |{} |'.format(m, doc))
|
print("|{} |{} |".format(m, doc))
|
||||||
else:
|
else:
|
||||||
print(textwrap.fill('{}:'.format(m), 80,
|
print(
|
||||||
initial_indent=self._indent*2, subsequent_indent=self._indent*2))
|
textwrap.fill(
|
||||||
for line in doc.split('\n'):
|
"{}:".format(m),
|
||||||
print(textwrap.fill(line, 80,
|
80,
|
||||||
initial_indent=self._indent*3, subsequent_indent=self._indent*6))
|
initial_indent=self._indent * 2,
|
||||||
|
subsequent_indent=self._indent * 2,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for line in doc.split("\n"):
|
||||||
|
print(
|
||||||
|
textwrap.fill(
|
||||||
|
line,
|
||||||
|
80,
|
||||||
|
initial_indent=self._indent * 3,
|
||||||
|
subsequent_indent=self._indent * 6,
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning(e)
|
log.warning(e)
|
||||||
|
|
||||||
|
|
||||||
class Config(util.store.Store):
|
class Config(util.store.Store):
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
super(Config, self).__init__()
|
super(Config, self).__init__()
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='bumblebee-status is a modular, theme-able status line generator for the i3 window manager. https://github.com/tobi-wan-kenobi/bumblebee-status/wiki')
|
parser = argparse.ArgumentParser(
|
||||||
parser.add_argument('-m', '--modules', nargs='+', action='append', default=[],
|
description="bumblebee-status is a modular, theme-able status line generator for the i3 window manager. https://github.com/tobi-wan-kenobi/bumblebee-status/wiki"
|
||||||
help=MODULE_HELP)
|
)
|
||||||
parser.add_argument('-p', '--parameters', nargs='+', action='append', default=[],
|
parser.add_argument(
|
||||||
help=PARAMETER_HELP)
|
"-m", "--modules", nargs="+", action="append", default=[], help=MODULE_HELP
|
||||||
parser.add_argument('-t', '--theme', default='default', help=THEME_HELP)
|
)
|
||||||
parser.add_argument('-i', '--iconset', default='auto',
|
parser.add_argument(
|
||||||
help='Specify the name of an iconset to use (overrides theme default)')
|
"-p",
|
||||||
parser.add_argument('-a', '--autohide', nargs='+', default=[],
|
"--parameters",
|
||||||
help='Specify a list of modules to hide when not in warning/error state')
|
nargs="+",
|
||||||
parser.add_argument('-d', '--debug', action='store_true',
|
action="append",
|
||||||
help='Add debug fields to i3 output')
|
default=[],
|
||||||
parser.add_argument('-f', '--logfile', help='destination for the debug log file, if -d|--debug is specified; defaults to stderr')
|
help=PARAMETER_HELP,
|
||||||
parser.add_argument('-r', '--right-to-left', action='store_true', help='Draw widgets from right to left, rather than left to right (which is the default)')
|
)
|
||||||
parser.add_argument('-l', '--list', choices=['modules', 'themes', 'modules-markdown'], help='Display a list of available themes or available modules, along with their parameters',
|
parser.add_argument("-t", "--theme", default="default", help=THEME_HELP)
|
||||||
action=print_usage)
|
parser.add_argument(
|
||||||
|
"-i",
|
||||||
|
"--iconset",
|
||||||
|
default="auto",
|
||||||
|
help="Specify the name of an iconset to use (overrides theme default)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--autohide",
|
||||||
|
nargs="+",
|
||||||
|
default=[],
|
||||||
|
help="Specify a list of modules to hide when not in warning/error state",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d", "--debug", action="store_true", help="Add debug fields to i3 output"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--logfile",
|
||||||
|
help="destination for the debug log file, if -d|--debug is specified; defaults to stderr",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-r",
|
||||||
|
"--right-to-left",
|
||||||
|
action="store_true",
|
||||||
|
help="Draw widgets from right to left, rather than left to right (which is the default)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-l",
|
||||||
|
"--list",
|
||||||
|
choices=["modules", "themes", "modules-markdown"],
|
||||||
|
help="Display a list of available themes or available modules, along with their parameters",
|
||||||
|
action=print_usage,
|
||||||
|
)
|
||||||
|
|
||||||
self.__args = parser.parse_args(args)
|
self.__args = parser.parse_args(args)
|
||||||
|
|
||||||
for cfg in [ '~/.bumblebee-status.conf', '~/.config/bumblebee-status.conf', '~/.config/bumblebee-status/config' ]:
|
for cfg in [
|
||||||
|
"~/.bumblebee-status.conf",
|
||||||
|
"~/.config/bumblebee-status.conf",
|
||||||
|
"~/.config/bumblebee-status/config",
|
||||||
|
]:
|
||||||
cfg = os.path.expanduser(cfg)
|
cfg = os.path.expanduser(cfg)
|
||||||
self.load_config(cfg)
|
self.load_config(cfg)
|
||||||
|
|
||||||
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:
|
||||||
if not '=' in param:
|
if not "=" in param:
|
||||||
log.error('missing value for parameter "{}" - ignoring this parameter'.format(param))
|
log.error(
|
||||||
|
'missing value for parameter "{}" - ignoring this parameter'.format(
|
||||||
|
param
|
||||||
|
)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
key, value = param.split('=', 1)
|
key, value = param.split("=", 1)
|
||||||
self.set(key, value)
|
self.set(key, value)
|
||||||
|
|
||||||
def load_config(self, filename):
|
def load_config(self, filename):
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
log.info('loading {}'.format(filename))
|
log.info("loading {}".format(filename))
|
||||||
tmp = RawConfigParser()
|
tmp = RawConfigParser()
|
||||||
tmp.read(filename)
|
tmp.read(filename)
|
||||||
|
|
||||||
if tmp.has_section('module-parameters'):
|
if tmp.has_section("module-parameters"):
|
||||||
for key, value in tmp.items('module-parameters'):
|
for key, value in tmp.items("module-parameters"):
|
||||||
self.set(key, value)
|
self.set(key, value)
|
||||||
|
|
||||||
def modules(self):
|
def modules(self):
|
||||||
return [item for sub in self.__args.modules for item in sub]
|
return [item for sub in self.__args.modules for item in sub]
|
||||||
|
|
||||||
def interval(self, default=1):
|
def interval(self, default=1):
|
||||||
return util.format.seconds(self.get('interval', default))
|
return util.format.seconds(self.get("interval", default))
|
||||||
|
|
||||||
def debug(self):
|
def debug(self):
|
||||||
return self.__args.debug
|
return self.__args.debug
|
||||||
|
@ -164,4 +226,5 @@ class Config(util.store.Store):
|
||||||
def autohide(self, name):
|
def autohide(self, name):
|
||||||
return name in self.__args.autohide
|
return name in self.__args.autohide
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,41 +1,49 @@
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
def never(init):
|
def never(init):
|
||||||
def call_init(obj, *args, **kwargs):
|
def call_init(obj, *args, **kwargs):
|
||||||
init(obj, *args, **kwargs)
|
init(obj, *args, **kwargs)
|
||||||
if obj.parameter('interval') is None:
|
if obj.parameter("interval") is None:
|
||||||
obj.set('interval', 'never')
|
obj.set("interval", "never")
|
||||||
|
|
||||||
return call_init
|
return call_init
|
||||||
|
|
||||||
|
|
||||||
def every(hours=0, minutes=0, seconds=0):
|
def every(hours=0, minutes=0, seconds=0):
|
||||||
def decorator_init(init):
|
def decorator_init(init):
|
||||||
def call_init(obj, *args, **kwargs):
|
def call_init(obj, *args, **kwargs):
|
||||||
init(obj, *args, **kwargs)
|
init(obj, *args, **kwargs)
|
||||||
if obj.parameter('interval') is None:
|
if obj.parameter("interval") is None:
|
||||||
obj.set('interval', hours*3600 + minutes*60 + seconds)
|
obj.set("interval", hours * 3600 + minutes * 60 + seconds)
|
||||||
|
|
||||||
return call_init
|
return call_init
|
||||||
|
|
||||||
return decorator_init
|
return decorator_init
|
||||||
|
|
||||||
|
|
||||||
def scrollable(func):
|
def scrollable(func):
|
||||||
def wrapper(module, widget):
|
def wrapper(module, widget):
|
||||||
text = func(module, widget)
|
text = func(module, widget)
|
||||||
if not text:
|
if not text:
|
||||||
return text
|
return text
|
||||||
width = widget.get('theme.width', util.format.asint(module.parameter('width', 30)))
|
width = widget.get(
|
||||||
if util.format.asbool(module.parameter('scrolling.makewide', True)):
|
"theme.width", util.format.asint(module.parameter("width", 30))
|
||||||
widget.set('theme.minwidth', 'A'*width)
|
)
|
||||||
|
if util.format.asbool(module.parameter("scrolling.makewide", True)):
|
||||||
|
widget.set("theme.minwidth", "A" * width)
|
||||||
if width < 0 or len(text) <= width:
|
if width < 0 or len(text) <= width:
|
||||||
return text
|
return text
|
||||||
|
|
||||||
start = widget.get('scrolling.start', 0)
|
start = widget.get("scrolling.start", 0)
|
||||||
bounce = util.format.asbool(module.parameter('scrolling.bounce', True))
|
bounce = util.format.asbool(module.parameter("scrolling.bounce", True))
|
||||||
scroll_speed = util.format.asint(module.parameter('scrolling.speed', 1))
|
scroll_speed = util.format.asint(module.parameter("scrolling.speed", 1))
|
||||||
direction = widget.get('scrolling.direction', 'right')
|
direction = widget.get("scrolling.direction", "right")
|
||||||
|
|
||||||
if direction == 'left':
|
if direction == "left":
|
||||||
scroll_speed = -scroll_speed
|
scroll_speed = -scroll_speed
|
||||||
if start + scroll_speed <= 0: # bounce back
|
if start + scroll_speed <= 0: # bounce back
|
||||||
widget.set('scrolling.direction', 'right')
|
widget.set("scrolling.direction", "right")
|
||||||
|
|
||||||
next_start = start + scroll_speed
|
next_start = start + scroll_speed
|
||||||
if next_start + width > len(text):
|
if next_start + width > len(text):
|
||||||
|
@ -43,11 +51,13 @@ def scrollable(func):
|
||||||
next_start = 0
|
next_start = 0
|
||||||
else:
|
else:
|
||||||
next_start = start - scroll_speed
|
next_start = start - scroll_speed
|
||||||
widget.set('scrolling.direction', 'left')
|
widget.set("scrolling.direction", "left")
|
||||||
|
|
||||||
widget.set('scrolling.start', next_start)
|
widget.set("scrolling.start", next_start)
|
||||||
|
|
||||||
|
return text[start : start + width]
|
||||||
|
|
||||||
return text[start:start+width]
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
__callbacks = {}
|
__callbacks = {}
|
||||||
|
|
||||||
|
|
||||||
def register(event, callback, *args, **kwargs):
|
def register(event, callback, *args, **kwargs):
|
||||||
cb = callback
|
cb = callback
|
||||||
if len(args) + len(kwargs) > 0:
|
if len(args) + len(kwargs) > 0:
|
||||||
|
@ -8,12 +8,15 @@ def register(event, callback, *args, **kwargs):
|
||||||
|
|
||||||
__callbacks.setdefault(event, []).append(cb)
|
__callbacks.setdefault(event, []).append(cb)
|
||||||
|
|
||||||
|
|
||||||
def clear():
|
def clear():
|
||||||
__callbacks.clear()
|
__callbacks.clear()
|
||||||
|
|
||||||
|
|
||||||
def trigger(event, *args, **kwargs):
|
def trigger(event, *args, **kwargs):
|
||||||
cb = __callbacks.get(event, [])
|
cb = __callbacks.get(event, [])
|
||||||
if len(cb) == 0: return False
|
if len(cb) == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
for callback in cb:
|
for callback in cb:
|
||||||
if len(args) + len(kwargs) == 0:
|
if len(args) + len(kwargs) == 0:
|
||||||
|
@ -22,4 +25,5 @@ def trigger(event, *args, **kwargs):
|
||||||
callback(*args, **kwargs)
|
callback(*args, **kwargs)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -11,45 +11,59 @@ RIGHT_MOUSE = 3
|
||||||
WHEEL_UP = 4
|
WHEEL_UP = 4
|
||||||
WHEEL_DOWN = 5
|
WHEEL_DOWN = 5
|
||||||
|
|
||||||
|
|
||||||
def button_name(button):
|
def button_name(button):
|
||||||
if button == LEFT_MOUSE: return 'left-mouse'
|
if button == LEFT_MOUSE:
|
||||||
if button == RIGHT_MOUSE: return 'right-mouse'
|
return "left-mouse"
|
||||||
if button == MIDDLE_MOUSE: return 'middle-mouse'
|
if button == RIGHT_MOUSE:
|
||||||
if button == WHEEL_UP: return 'wheel-up'
|
return "right-mouse"
|
||||||
if button == WHEEL_DOWN: return 'wheel-down'
|
if button == MIDDLE_MOUSE:
|
||||||
return 'n/a'
|
return "middle-mouse"
|
||||||
|
if button == WHEEL_UP:
|
||||||
|
return "wheel-up"
|
||||||
|
if button == WHEEL_DOWN:
|
||||||
|
return "wheel-down"
|
||||||
|
return "n/a"
|
||||||
|
|
||||||
|
|
||||||
class Object(object):
|
class Object(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Object, self).__init__()
|
super(Object, self).__init__()
|
||||||
self.id = str(uuid.uuid4())
|
self.id = str(uuid.uuid4())
|
||||||
|
|
||||||
|
|
||||||
def __event_id(obj_id, button):
|
def __event_id(obj_id, button):
|
||||||
return '{}::{}'.format(obj_id, button_name(button))
|
return "{}::{}".format(obj_id, button_name(button))
|
||||||
|
|
||||||
|
|
||||||
def __execute(cmd):
|
def __execute(cmd):
|
||||||
try:
|
try:
|
||||||
util.cli.execute(cmd, wait=False)
|
util.cli.execute(cmd, wait=False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error('failed to invoke callback: {}'.format(e))
|
logging.error("failed to invoke callback: {}".format(e))
|
||||||
|
|
||||||
|
|
||||||
def register(obj, button=None, cmd=None):
|
def register(obj, button=None, cmd=None):
|
||||||
event_id = __event_id(obj.id if obj is not None else '', button)
|
event_id = __event_id(obj.id if obj is not None else "", button)
|
||||||
logging.debug('registering callback {}'.format(event_id))
|
logging.debug("registering callback {}".format(event_id))
|
||||||
if callable(cmd):
|
if callable(cmd):
|
||||||
core.event.register(event_id, cmd)
|
core.event.register(event_id, cmd)
|
||||||
else:
|
else:
|
||||||
core.event.register(event_id, lambda _: __execute(cmd))
|
core.event.register(event_id, lambda _: __execute(cmd))
|
||||||
|
|
||||||
|
|
||||||
def trigger(event):
|
def trigger(event):
|
||||||
if not 'button' in event: return
|
if not "button" in event:
|
||||||
|
return
|
||||||
|
|
||||||
triggered = False
|
triggered = False
|
||||||
for field in ['instance', 'name']:
|
for field in ["instance", "name"]:
|
||||||
if not field in event: continue
|
if not field in event:
|
||||||
if core.event.trigger(__event_id(event[field], event['button']), event):
|
continue
|
||||||
|
if core.event.trigger(__event_id(event[field], event["button"]), event):
|
||||||
triggered = True
|
triggered = True
|
||||||
if not triggered:
|
if not triggered:
|
||||||
core.event.trigger(__event_id('', event['button']), event)
|
core.event.trigger(__event_id("", event["button"]), event)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -7,35 +7,41 @@ import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
try:
|
try:
|
||||||
error = ModuleNotFoundError('')
|
error = ModuleNotFoundError("")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ModuleNotFoundError = Exception
|
ModuleNotFoundError = Exception
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def load(module_name, config=core.config.Config([]), theme=None):
|
def load(module_name, config=core.config.Config([]), theme=None):
|
||||||
error = None
|
error = None
|
||||||
module_short, alias = (module_name.split(':') + [module_name])[0:2]
|
module_short, alias = (module_name.split(":") + [module_name])[0:2]
|
||||||
config.set('__alias__', alias)
|
config.set("__alias__", alias)
|
||||||
for namespace in [ 'core', 'contrib' ]:
|
for namespace in ["core", "contrib"]:
|
||||||
try:
|
try:
|
||||||
mod = importlib.import_module('modules.{}.{}'.format(namespace, module_short))
|
mod = importlib.import_module(
|
||||||
log.debug('importing {} from {}.{}'.format(module_short, namespace, module_short))
|
"modules.{}.{}".format(namespace, module_short)
|
||||||
return getattr(mod, 'Module')(config, theme)
|
)
|
||||||
|
log.debug(
|
||||||
|
"importing {} from {}.{}".format(module_short, namespace, module_short)
|
||||||
|
)
|
||||||
|
return getattr(mod, "Module")(config, theme)
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
error = e
|
error = e
|
||||||
log.fatal('failed to import {}: {}'.format(module_name, error))
|
log.fatal("failed to import {}: {}".format(module_name, error))
|
||||||
return Error(config=config, module=module_name, error=error)
|
return Error(config=config, module=module_name, error=error)
|
||||||
|
|
||||||
|
|
||||||
class Module(core.input.Object):
|
class Module(core.input.Object):
|
||||||
def __init__(self, config=core.config.Config([]), theme=None, widgets=[]):
|
def __init__(self, config=core.config.Config([]), theme=None, widgets=[]):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.__config = config
|
self.__config = config
|
||||||
self.__widgets = widgets if isinstance(widgets, list) else [ widgets ]
|
self.__widgets = widgets if isinstance(widgets, list) else [widgets]
|
||||||
|
|
||||||
self.module_name = self.__module__.split('.')[-1]
|
self.module_name = self.__module__.split(".")[-1]
|
||||||
self.name = self.module_name
|
self.name = self.module_name
|
||||||
self.alias = self.__config.get('__alias__', None)
|
self.alias = self.__config.get("__alias__", None)
|
||||||
self.id = self.alias if self.alias else self.name
|
self.id = self.alias if self.alias else self.name
|
||||||
self.next_update = None
|
self.next_update = None
|
||||||
|
|
||||||
|
@ -50,13 +56,13 @@ class Module(core.input.Object):
|
||||||
def parameter(self, key, default=None):
|
def parameter(self, key, default=None):
|
||||||
value = default
|
value = default
|
||||||
|
|
||||||
for prefix in [ self.name, self.module_name, self.alias ]:
|
for prefix in [self.name, self.module_name, self.alias]:
|
||||||
value = self.__config.get('{}.{}'.format(prefix, key), value)
|
value = self.__config.get("{}.{}".format(prefix, key), value)
|
||||||
# TODO retrieve from config file
|
# TODO retrieve from config file
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def set(self, key, value):
|
def set(self, key, value):
|
||||||
self.__config.set('{}.{}'.format(self.name, key), value)
|
self.__config.set("{}.{}".format(self.name, key), value)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
pass
|
pass
|
||||||
|
@ -65,8 +71,8 @@ class Module(core.input.Object):
|
||||||
try:
|
try:
|
||||||
self.update()
|
self.update()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.set('interval', 1)
|
self.set("interval", 1)
|
||||||
module = Error(config=self.__config, module='error', error=str(e))
|
module = Error(config=self.__config, module="error", error=str(e))
|
||||||
self.__widgets = [module.widget()]
|
self.__widgets = [module.widget()]
|
||||||
self.update = module.update
|
self.update = module.update
|
||||||
|
|
||||||
|
@ -75,28 +81,31 @@ class Module(core.input.Object):
|
||||||
self.__widgets = widgets
|
self.__widgets = widgets
|
||||||
return self.__widgets
|
return self.__widgets
|
||||||
|
|
||||||
def add_widget(self, full_text='', name=None):
|
def add_widget(self, full_text="", name=None):
|
||||||
widget = core.widget.Widget(full_text=full_text, name=name, module=self)
|
widget = core.widget.Widget(full_text=full_text, name=name, module=self)
|
||||||
self.widgets().append(widget)
|
self.widgets().append(widget)
|
||||||
return widget
|
return widget
|
||||||
|
|
||||||
def widget(self, name=None):
|
def widget(self, name=None):
|
||||||
if not name: return self.widgets()[0]
|
if not name:
|
||||||
|
return self.widgets()[0]
|
||||||
|
|
||||||
for w in self.widgets():
|
for w in self.widgets():
|
||||||
if w.name == name: return w
|
if w.name == name:
|
||||||
|
return w
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def threshold_state(self, value, warn, crit):
|
def threshold_state(self, value, warn, crit):
|
||||||
if value > float(self.parameter('critical', crit)):
|
if value > float(self.parameter("critical", crit)):
|
||||||
return 'critical'
|
return "critical"
|
||||||
if value > float(self.parameter('warning', warn)):
|
if value > float(self.parameter("warning", warn)):
|
||||||
return 'warning'
|
return "warning"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Error(Module):
|
class Error(Module):
|
||||||
def __init__(self, module, error, config=core.config.Config([]), theme=None):
|
def __init__(self, module, error, config=core.config.Config([]), theme=None):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
||||||
|
@ -104,9 +113,10 @@ class Error(Module):
|
||||||
self.__error = error
|
self.__error = error
|
||||||
|
|
||||||
def full_text(self, widget):
|
def full_text(self, widget):
|
||||||
return '{}: {}'.format(self.__module, self.__error)
|
return "{}: {}".format(self.__module, self.__error)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return ['critical']
|
return ["critical"]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
172
core/output.py
172
core/output.py
|
@ -7,15 +7,17 @@ import core.event
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
def dump_json(obj):
|
def dump_json(obj):
|
||||||
return obj.dict()
|
return obj.dict()
|
||||||
|
|
||||||
|
|
||||||
def assign(src, dst, key, src_key=None, default=None):
|
def assign(src, dst, key, src_key=None, default=None):
|
||||||
if not src_key:
|
if not src_key:
|
||||||
if key.startswith('_'):
|
if key.startswith("_"):
|
||||||
src_key = key
|
src_key = key
|
||||||
else:
|
else:
|
||||||
src_key = key.replace('_', '-') # automagically replace _ with -
|
src_key = key.replace("_", "-") # automagically replace _ with -
|
||||||
|
|
||||||
for k in src_key if isinstance(src_key, list) else [src_key]:
|
for k in src_key if isinstance(src_key, list) else [src_key]:
|
||||||
if k in src:
|
if k in src:
|
||||||
|
@ -24,12 +26,23 @@ def assign(src, dst, key, src_key=None, default=None):
|
||||||
if default is not None:
|
if default is not None:
|
||||||
dst[key] = default
|
dst[key] = default
|
||||||
|
|
||||||
|
|
||||||
class block(object):
|
class block(object):
|
||||||
__COMMON_THEME_FIELDS = [
|
__COMMON_THEME_FIELDS = [
|
||||||
'separator', 'separator-block-width', 'default-separators',
|
"separator",
|
||||||
'border-top', 'border-left', 'border-right', 'border-bottom',
|
"separator-block-width",
|
||||||
'fg', 'bg', 'padding', 'prefix', 'suffix'
|
"default-separators",
|
||||||
|
"border-top",
|
||||||
|
"border-left",
|
||||||
|
"border-right",
|
||||||
|
"border-bottom",
|
||||||
|
"fg",
|
||||||
|
"bg",
|
||||||
|
"padding",
|
||||||
|
"prefix",
|
||||||
|
"suffix",
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, theme, module, widget):
|
def __init__(self, theme, module, widget):
|
||||||
self.__attributes = {}
|
self.__attributes = {}
|
||||||
for key in self.__COMMON_THEME_FIELDS:
|
for key in self.__COMMON_THEME_FIELDS:
|
||||||
|
@ -37,72 +50,85 @@ class block(object):
|
||||||
if tmp is not None:
|
if tmp is not None:
|
||||||
self.__attributes[key] = tmp
|
self.__attributes[key] = tmp
|
||||||
|
|
||||||
self.__attributes['name'] = module.id
|
self.__attributes["name"] = module.id
|
||||||
self.__attributes['instance'] = widget.id
|
self.__attributes["instance"] = widget.id
|
||||||
self.__attributes['prev-bg'] = theme.get('bg', 'previous')
|
self.__attributes["prev-bg"] = theme.get("bg", "previous")
|
||||||
|
|
||||||
def set(self, key, value):
|
def set(self, key, value):
|
||||||
self.__attributes[key] = value
|
self.__attributes[key] = value
|
||||||
|
|
||||||
def is_pango(self, attr):
|
def is_pango(self, attr):
|
||||||
if isinstance(attr, dict) and 'pango' in attr:
|
if isinstance(attr, dict) and "pango" in attr:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def pangoize(self, text):
|
def pangoize(self, text):
|
||||||
if not self.is_pango(text):
|
if not self.is_pango(text):
|
||||||
return text
|
return text
|
||||||
self.__attributes['markup'] = 'pango'
|
self.__attributes["markup"] = "pango"
|
||||||
attr = dict(text['pango'])
|
attr = dict(text["pango"])
|
||||||
text = attr.get('full_text', '')
|
text = attr.get("full_text", "")
|
||||||
if 'full_text' in attr:
|
if "full_text" in attr:
|
||||||
del attr['full_text']
|
del attr["full_text"]
|
||||||
result = '<span'
|
result = "<span"
|
||||||
for key, value in attr.items():
|
for key, value in attr.items():
|
||||||
result = '{} {}="{}"'.format(result, key, value)
|
result = '{} {}="{}"'.format(result, key, value)
|
||||||
result = '{}>{}</span>'.format(result, text)
|
result = "{}>{}</span>".format(result, text)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def dict(self):
|
def dict(self):
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
assign(self.__attributes, result, 'full_text', ['full_text', 'separator'])
|
assign(self.__attributes, result, "full_text", ["full_text", "separator"])
|
||||||
assign(self.__attributes, result, 'separator', 'default-separators')
|
assign(self.__attributes, result, "separator", "default-separators")
|
||||||
|
|
||||||
if '_decorator' in self.__attributes:
|
if "_decorator" in self.__attributes:
|
||||||
assign(self.__attributes, result, 'color', 'bg')
|
assign(self.__attributes, result, "color", "bg")
|
||||||
assign(self.__attributes, result, 'background', 'prev-bg')
|
assign(self.__attributes, result, "background", "prev-bg")
|
||||||
result['_decorator'] = True
|
result["_decorator"] = True
|
||||||
else:
|
else:
|
||||||
assign(self.__attributes, result, 'color', 'fg')
|
assign(self.__attributes, result, "color", "fg")
|
||||||
assign(self.__attributes, result, 'background', 'bg')
|
assign(self.__attributes, result, "background", "bg")
|
||||||
|
|
||||||
if 'full_text' in self.__attributes:
|
if "full_text" in self.__attributes:
|
||||||
result['full_text'] = self.pangoize(result['full_text'])
|
result["full_text"] = self.pangoize(result["full_text"])
|
||||||
result['full_text'] = self.__format(self.__attributes['full_text'])
|
result["full_text"] = self.__format(self.__attributes["full_text"])
|
||||||
|
|
||||||
for k in [
|
for k in [
|
||||||
'name', 'instance', 'separator_block_width', 'border', 'border_top',
|
"name",
|
||||||
'border_bottom', 'border_left', 'border_right', 'markup',
|
"instance",
|
||||||
'_raw', '_suffix', '_prefix', 'min_width'
|
"separator_block_width",
|
||||||
|
"border",
|
||||||
|
"border_top",
|
||||||
|
"border_bottom",
|
||||||
|
"border_left",
|
||||||
|
"border_right",
|
||||||
|
"markup",
|
||||||
|
"_raw",
|
||||||
|
"_suffix",
|
||||||
|
"_prefix",
|
||||||
|
"min_width",
|
||||||
]:
|
]:
|
||||||
assign(self.__attributes, result, k)
|
assign(self.__attributes, result, k)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def __pad(self, text):
|
def __pad(self, text):
|
||||||
padding = self.__attributes.get('padding', '')
|
padding = self.__attributes.get("padding", "")
|
||||||
if not text: return padding
|
if not text:
|
||||||
return '{}{}{}'.format(padding, text, padding)
|
return padding
|
||||||
|
return "{}{}{}".format(padding, text, padding)
|
||||||
|
|
||||||
def __format(self, text):
|
def __format(self, text):
|
||||||
if text is None: return None
|
if text is None:
|
||||||
prefix = self.__pad(self.pangoize(self.__attributes.get('prefix')))
|
return None
|
||||||
suffix = self.__pad(self.pangoize(self.__attributes.get('suffix')))
|
prefix = self.__pad(self.pangoize(self.__attributes.get("prefix")))
|
||||||
self.set('_prefix', prefix)
|
suffix = self.__pad(self.pangoize(self.__attributes.get("suffix")))
|
||||||
self.set('_suffix', suffix)
|
self.set("_prefix", prefix)
|
||||||
self.set('_raw', text)
|
self.set("_suffix", suffix)
|
||||||
return '{}{}{}'.format(prefix, text, suffix)
|
self.set("_raw", text)
|
||||||
|
return "{}{}{}".format(prefix, text, suffix)
|
||||||
|
|
||||||
|
|
||||||
class i3(object):
|
class i3(object):
|
||||||
def __init__(self, theme=core.theme.Theme(), config=core.config.Config([])):
|
def __init__(self, theme=core.theme.Theme(), config=core.config.Config([])):
|
||||||
|
@ -110,10 +136,10 @@ class i3(object):
|
||||||
self.__content = {}
|
self.__content = {}
|
||||||
self.__theme = theme
|
self.__theme = theme
|
||||||
self.__config = config
|
self.__config = config
|
||||||
core.event.register('update', self.update)
|
core.event.register("update", self.update)
|
||||||
core.event.register('start', self.draw, 'start')
|
core.event.register("start", self.draw, "start")
|
||||||
core.event.register('draw', self.draw, 'statusline')
|
core.event.register("draw", self.draw, "statusline")
|
||||||
core.event.register('stop', self.draw, 'stop')
|
core.event.register("stop", self.draw, "stop")
|
||||||
|
|
||||||
def theme(self, new_theme=None):
|
def theme(self, new_theme=None):
|
||||||
if new_theme:
|
if new_theme:
|
||||||
|
@ -123,63 +149,65 @@ class i3(object):
|
||||||
def modules(self, modules=None):
|
def modules(self, modules=None):
|
||||||
if not modules:
|
if not modules:
|
||||||
return self.__modules
|
return self.__modules
|
||||||
self.__modules = modules if isinstance(modules, list) else [ modules ]
|
self.__modules = modules if isinstance(modules, list) else [modules]
|
||||||
|
|
||||||
def draw(self, what, args=None):
|
def draw(self, what, args=None):
|
||||||
cb = getattr(self, what)
|
cb = getattr(self, what)
|
||||||
data = cb(args) if args else cb()
|
data = cb(args) if args else cb()
|
||||||
if 'blocks' in data:
|
if "blocks" in data:
|
||||||
sys.stdout.write(json.dumps(data['blocks'], default=dump_json))
|
sys.stdout.write(json.dumps(data["blocks"], default=dump_json))
|
||||||
if 'suffix' in data:
|
if "suffix" in data:
|
||||||
sys.stdout.write(data['suffix'])
|
sys.stdout.write(data["suffix"])
|
||||||
sys.stdout.write('\n')
|
sys.stdout.write("\n")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
return {
|
return {
|
||||||
'blocks': { 'version': 1, 'click_events': True },
|
"blocks": {"version": 1, "click_events": True},
|
||||||
'suffix': '\n[',
|
"suffix": "\n[",
|
||||||
}
|
}
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
return { 'suffix': '\n]' }
|
return {"suffix": "\n]"}
|
||||||
|
|
||||||
def __separator_block(self, module, widget):
|
def __separator_block(self, module, widget):
|
||||||
if not self.__theme.get('separator'):
|
if not self.__theme.get("separator"):
|
||||||
return []
|
return []
|
||||||
blk = block(self.__theme, module, widget)
|
blk = block(self.__theme, module, widget)
|
||||||
blk.set('_decorator', True)
|
blk.set("_decorator", True)
|
||||||
return [blk]
|
return [blk]
|
||||||
|
|
||||||
def __content_block(self, module, widget):
|
def __content_block(self, module, widget):
|
||||||
blk = block(self.__theme, module, widget)
|
blk = block(self.__theme, module, widget)
|
||||||
minwidth = widget.theme('minwidth')
|
minwidth = widget.theme("minwidth")
|
||||||
if minwidth is not None:
|
if minwidth is not None:
|
||||||
try:
|
try:
|
||||||
blk.set('min-width', '-'*int(minwidth))
|
blk.set("min-width", "-" * int(minwidth))
|
||||||
except:
|
except:
|
||||||
blk.set('min-width', minwidth)
|
blk.set("min-width", minwidth)
|
||||||
blk.set('full_text', self.__content[widget])
|
blk.set("full_text", self.__content[widget])
|
||||||
if widget.get('pango', False):
|
if widget.get("pango", False):
|
||||||
blk.set('markup', 'pango')
|
blk.set("markup", "pango")
|
||||||
if self.__config.debug():
|
if self.__config.debug():
|
||||||
state = module.state(widget)
|
state = module.state(widget)
|
||||||
if isinstance(state, list):
|
if isinstance(state, list):
|
||||||
state = ', '.join(state)
|
state = ", ".join(state)
|
||||||
blk.set('__state', state)
|
blk.set("__state", state)
|
||||||
return blk
|
return blk
|
||||||
|
|
||||||
def blocks(self, module):
|
def blocks(self, module):
|
||||||
blocks = []
|
blocks = []
|
||||||
for widget in module.widgets():
|
for widget in module.widgets():
|
||||||
if widget.module and self.__config.autohide(widget.module.name):
|
if widget.module and self.__config.autohide(widget.module.name):
|
||||||
if not any(state in widget.state() for state in [ 'warning', 'critical']):
|
if not any(
|
||||||
|
state in widget.state() for state in ["warning", "critical"]
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
if module.hidden():
|
if module.hidden():
|
||||||
continue
|
continue
|
||||||
blocks.extend(self.__separator_block(module, widget))
|
blocks.extend(self.__separator_block(module, widget))
|
||||||
blocks.append(self.__content_block(module, widget))
|
blocks.append(self.__content_block(module, widget))
|
||||||
core.event.trigger('next-widget')
|
core.event.trigger("next-widget")
|
||||||
return blocks
|
return blocks
|
||||||
|
|
||||||
# TODO: only updates full text, not the state!?
|
# TODO: only updates full text, not the state!?
|
||||||
|
@ -189,14 +217,16 @@ class i3(object):
|
||||||
if affected_modules and not module.id in affected_modules:
|
if affected_modules and not module.id in affected_modules:
|
||||||
continue
|
continue
|
||||||
if not affected_modules and module.next_update:
|
if not affected_modules and module.next_update:
|
||||||
if module.parameter('interval', '') == 'never':
|
if module.parameter("interval", "") == "never":
|
||||||
continue
|
continue
|
||||||
if now < module.next_update:
|
if now < module.next_update:
|
||||||
continue
|
continue
|
||||||
if not redraw_only:
|
if not redraw_only:
|
||||||
module.update_wrapper()
|
module.update_wrapper()
|
||||||
if module.parameter('interval', '') != 'never':
|
if module.parameter("interval", "") != "never":
|
||||||
module.next_update = now + util.format.seconds(module.parameter('interval', self.__config.interval()))
|
module.next_update = now + util.format.seconds(
|
||||||
|
module.parameter("interval", self.__config.interval())
|
||||||
|
)
|
||||||
for widget in module.widgets():
|
for widget in module.widgets():
|
||||||
self.__content[widget] = widget.full_text()
|
self.__content[widget] = widget.full_text()
|
||||||
|
|
||||||
|
@ -204,12 +234,10 @@ class i3(object):
|
||||||
blocks = []
|
blocks = []
|
||||||
for module in self.__modules:
|
for module in self.__modules:
|
||||||
blocks.extend(self.blocks(module))
|
blocks.extend(self.blocks(module))
|
||||||
return {
|
return {"blocks": blocks, "suffix": ","}
|
||||||
'blocks': blocks,
|
|
||||||
'suffix': ','
|
|
||||||
}
|
|
||||||
|
|
||||||
def wait(self, interval):
|
def wait(self, interval):
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,24 +10,26 @@ import util.algorithm
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
THEME_BASE_DIR=os.path.dirname(os.path.realpath(__file__))
|
THEME_BASE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
PATHS=[
|
PATHS = [
|
||||||
'.',
|
".",
|
||||||
os.path.join(THEME_BASE_DIR, '../themes'),
|
os.path.join(THEME_BASE_DIR, "../themes"),
|
||||||
os.path.expanduser('~/.config/bumblebee-status/themes'),
|
os.path.expanduser("~/.config/bumblebee-status/themes"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def themes():
|
def themes():
|
||||||
themes_dict = {}
|
themes_dict = {}
|
||||||
|
|
||||||
for path in PATHS:
|
for path in PATHS:
|
||||||
for filename in glob.iglob('{}/*.json'.format(path)):
|
for filename in glob.iglob("{}/*.json".format(path)):
|
||||||
if 'test' not in filename:
|
if "test" not in filename:
|
||||||
themes_dict[os.path.basename(filename).replace('.json', '')] = 1
|
themes_dict[os.path.basename(filename).replace(".json", "")] = 1
|
||||||
result = list(themes_dict.keys())
|
result = list(themes_dict.keys())
|
||||||
result.sort()
|
result.sort()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def merge_replace(value, new_value, key):
|
def merge_replace(value, new_value, key):
|
||||||
if not isinstance(value, dict):
|
if not isinstance(value, dict):
|
||||||
return new_value
|
return new_value
|
||||||
|
@ -35,12 +37,13 @@ def merge_replace(value, new_value, key):
|
||||||
util.algorithm.merge(value, new_value)
|
util.algorithm.merge(value, new_value)
|
||||||
return value
|
return value
|
||||||
# right now, merging needs explicit pango support :(
|
# right now, merging needs explicit pango support :(
|
||||||
if 'pango' in value:
|
if "pango" in value:
|
||||||
value['pango']['full_text'] = new_value
|
value["pango"]["full_text"] = new_value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class Theme(object):
|
class Theme(object):
|
||||||
def __init__(self, name='default', iconset='auto', raw_data=None):
|
def __init__(self, name="default", iconset="auto", raw_data=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.__widget_count = 0
|
self.__widget_count = 0
|
||||||
self.__previous = {}
|
self.__previous = {}
|
||||||
|
@ -48,15 +51,15 @@ class Theme(object):
|
||||||
self.__keywords = {}
|
self.__keywords = {}
|
||||||
self.__value_idx = {}
|
self.__value_idx = {}
|
||||||
self.__data = raw_data if raw_data else self.load(name)
|
self.__data = raw_data if raw_data else self.load(name)
|
||||||
for icons in self.__data.get('icons', []):
|
for icons in self.__data.get("icons", []):
|
||||||
util.algorithm.merge(self.__data, self.load(icons, 'icons'))
|
util.algorithm.merge(self.__data, self.load(icons, "icons"))
|
||||||
if iconset != 'auto':
|
if iconset != "auto":
|
||||||
util.algorithm.merge(self.__data, self.load(iconset, 'icons'))
|
util.algorithm.merge(self.__data, self.load(iconset, "icons"))
|
||||||
for colors in self.__data.get('colors', []):
|
for colors in self.__data.get("colors", []):
|
||||||
util.algorithm.merge(self.__keywords, self.load_keywords(colors))
|
util.algorithm.merge(self.__keywords, self.load_keywords(colors))
|
||||||
|
|
||||||
core.event.register('draw', self.__start)
|
core.event.register("draw", self.__start)
|
||||||
core.event.register('next-widget', self.__next_widget)
|
core.event.register("next-widget", self.__next_widget)
|
||||||
|
|
||||||
def keywords(self):
|
def keywords(self):
|
||||||
return self.__keywords
|
return self.__keywords
|
||||||
|
@ -64,17 +67,20 @@ class Theme(object):
|
||||||
def color(self, name, default=None):
|
def color(self, name, default=None):
|
||||||
return self.keywords().get(name, default)
|
return self.keywords().get(name, default)
|
||||||
|
|
||||||
def load(self, name, subdir=''):
|
def load(self, name, subdir=""):
|
||||||
if isinstance(name, dict): return name # support plain data
|
if isinstance(name, dict):
|
||||||
|
return name # support plain data
|
||||||
for path in PATHS:
|
for path in PATHS:
|
||||||
theme_file = os.path.join(path, subdir, '{}.json'.format(name))
|
theme_file = os.path.join(path, subdir, "{}.json".format(name))
|
||||||
result = self.__load_json(theme_file)
|
result = self.__load_json(theme_file)
|
||||||
if result != {}: return result
|
if result != {}:
|
||||||
raise RuntimeError('unable to find theme {}'.format(name))
|
return result
|
||||||
|
raise RuntimeError("unable to find theme {}".format(name))
|
||||||
|
|
||||||
def __load_json(self, filename):
|
def __load_json(self, filename):
|
||||||
filename = os.path.expanduser(filename)
|
filename = os.path.expanduser(filename)
|
||||||
if not os.path.isfile(filename): return {}
|
if not os.path.isfile(filename):
|
||||||
|
return {}
|
||||||
with io.open(filename) as data:
|
with io.open(filename) as data:
|
||||||
return json.load(data)
|
return json.load(data)
|
||||||
|
|
||||||
|
@ -82,15 +88,15 @@ class Theme(object):
|
||||||
try:
|
try:
|
||||||
if isinstance(name, dict):
|
if isinstance(name, dict):
|
||||||
return name
|
return name
|
||||||
if name.lower() == 'wal':
|
if name.lower() == "wal":
|
||||||
wal = self.__load_json('~/.cache/wal/colors.json')
|
wal = self.__load_json("~/.cache/wal/colors.json")
|
||||||
result = {}
|
result = {}
|
||||||
for field in ['special', 'colors']:
|
for field in ["special", "colors"]:
|
||||||
for key in wal.get(field, {}):
|
for key in wal.get(field, {}):
|
||||||
result[key] = wal[field][key]
|
result[key] = wal[field][key]
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error('failed to load colors: {}', e)
|
log.error("failed to load colors: {}", e)
|
||||||
|
|
||||||
def __start(self):
|
def __start(self):
|
||||||
self.__widget_count = 0
|
self.__widget_count = 0
|
||||||
|
@ -107,14 +113,14 @@ class Theme(object):
|
||||||
|
|
||||||
def get(self, key, widget=None, default=None):
|
def get(self, key, widget=None, default=None):
|
||||||
if not widget:
|
if not widget:
|
||||||
widget = core.widget.Widget('')
|
widget = core.widget.Widget("")
|
||||||
# special handling
|
# special handling
|
||||||
if widget == 'previous':
|
if widget == "previous":
|
||||||
return self.__previous.get(key, None)
|
return self.__previous.get(key, None)
|
||||||
|
|
||||||
value = default
|
value = default
|
||||||
|
|
||||||
for option in ['defaults', 'cycle']:
|
for option in ["defaults", "cycle"]:
|
||||||
if option in self.__data:
|
if option in self.__data:
|
||||||
tmp = self.__data[option]
|
tmp = self.__data[option]
|
||||||
if isinstance(tmp, list):
|
if isinstance(tmp, list):
|
||||||
|
@ -127,7 +133,9 @@ class Theme(object):
|
||||||
value = merge_replace(value, self.__data.get(key, value), key)
|
value = merge_replace(value, self.__data.get(key, value), key)
|
||||||
|
|
||||||
if widget.module:
|
if widget.module:
|
||||||
value = merge_replace(value, self.get(widget.module.name, None, {}).get(key, value), key)
|
value = merge_replace(
|
||||||
|
value, self.get(widget.module.name, None, {}).get(key, value), key
|
||||||
|
)
|
||||||
|
|
||||||
if not key in widget.state():
|
if not key in widget.state():
|
||||||
for state in widget.state():
|
for state in widget.state():
|
||||||
|
@ -138,11 +146,12 @@ class Theme(object):
|
||||||
value = self.__keywords.get(value, value)
|
value = self.__keywords.get(value, value)
|
||||||
|
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
idx = self.__value_idx.get('{}::{}'.format(widget.id, key), 0) % len(value)
|
idx = self.__value_idx.get("{}::{}".format(widget.id, key), 0) % len(value)
|
||||||
self.__value_idx['{}::{}'.format(widget.id, key)] = idx
|
self.__value_idx["{}::{}".format(widget.id, key)] = idx
|
||||||
widget.set(key, idx)
|
widget.set(key, idx)
|
||||||
value = value[idx]
|
value = value[idx]
|
||||||
self.__current[key] = value
|
self.__current[key] = value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -4,8 +4,9 @@ import core.decorators
|
||||||
import util.store
|
import util.store
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Widget(util.store.Store, core.input.Object):
|
class Widget(util.store.Store, core.input.Object):
|
||||||
def __init__(self, full_text='', name=None, module=None):
|
def __init__(self, full_text="", name=None, module=None):
|
||||||
super(Widget, self).__init__()
|
super(Widget, self).__init__()
|
||||||
self.__full_text = full_text
|
self.__full_text = full_text
|
||||||
self.module = module
|
self.module = module
|
||||||
|
@ -19,25 +20,27 @@ class Widget(util.store.Store, core.input.Object):
|
||||||
def module(self, module):
|
def module(self, module):
|
||||||
self.__module = module
|
self.__module = module
|
||||||
|
|
||||||
if self.index() < 0: return
|
if self.index() < 0:
|
||||||
|
return
|
||||||
|
|
||||||
if module:
|
if module:
|
||||||
custom_ids = util.format.aslist(module.parameter('id'))
|
custom_ids = util.format.aslist(module.parameter("id"))
|
||||||
if len(custom_ids) > self.index():
|
if len(custom_ids) > self.index():
|
||||||
self.id = custom_ids[self.index()]
|
self.id = custom_ids[self.index()]
|
||||||
|
|
||||||
def index(self):
|
def index(self):
|
||||||
if not self.module: return 0
|
if not self.module:
|
||||||
|
return 0
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
for w in self.module.widgets():
|
for w in self.module.widgets():
|
||||||
if w.id == self.id:
|
if w.id == self.id:
|
||||||
return idx
|
return idx
|
||||||
idx = idx + 1
|
idx = idx + 1
|
||||||
return -1 # not found
|
return -1 # not found
|
||||||
|
|
||||||
def theme(self, attribute):
|
def theme(self, attribute):
|
||||||
attr = 'theme.{}'.format(attribute)
|
attr = "theme.{}".format(attribute)
|
||||||
if self.module:
|
if self.module:
|
||||||
param = util.format.aslist(self.module.parameter(attr))
|
param = util.format.aslist(self.module.parameter(attr))
|
||||||
if param and len(param) > self.index():
|
if param and len(param) > self.index():
|
||||||
|
@ -54,12 +57,13 @@ class Widget(util.store.Store, core.input.Object):
|
||||||
|
|
||||||
def state(self):
|
def state(self):
|
||||||
rv = []
|
rv = []
|
||||||
if self.get('state', None):
|
if self.get("state", None):
|
||||||
tmp = self.get('state')
|
tmp = self.get("state")
|
||||||
rv = tmp[:] if isinstance(tmp, list) else [tmp]
|
rv = tmp[:] if isinstance(tmp, list) else [tmp]
|
||||||
if self.module:
|
if self.module:
|
||||||
tmp = self.module.state(self)
|
tmp = self.module.state(self)
|
||||||
rv.extend(tmp if isinstance(tmp, list) else [tmp])
|
rv.extend(tmp if isinstance(tmp, list) else [tmp])
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,36 +10,40 @@ import core.widget
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.volume))
|
super().__init__(config, theme, core.widget.Widget(self.volume))
|
||||||
|
|
||||||
self.__level = 'n/a'
|
self.__level = "n/a"
|
||||||
self.__muted = True
|
self.__muted = True
|
||||||
device = self.parameter('device', 'Master,0')
|
device = self.parameter("device", "Master,0")
|
||||||
self._cmdString = 'amixer get {}'.format(device)
|
self._cmdString = "amixer get {}".format(device)
|
||||||
|
|
||||||
def volume(self, widget):
|
def volume(self, widget):
|
||||||
if self.__level == 'n/a':
|
if self.__level == "n/a":
|
||||||
return self.__level
|
return self.__level
|
||||||
m = re.search(r'([\d]+)\%', self.__level)
|
m = re.search(r"([\d]+)\%", self.__level)
|
||||||
self.__muted = True
|
self.__muted = True
|
||||||
if m:
|
if m:
|
||||||
if m.group(1) != '0' and '[on]' in self.__level:
|
if m.group(1) != "0" and "[on]" in self.__level:
|
||||||
self.__muted = False
|
self.__muted = False
|
||||||
return '{}%'.format(m.group(1))
|
return "{}%".format(m.group(1))
|
||||||
else:
|
else:
|
||||||
return '0%'
|
return "0%"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
self.__level = util.cli.execute('amixer get {}'.format(self.parameter('device', 'Master,0')))
|
self.__level = util.cli.execute(
|
||||||
|
"amixer get {}".format(self.parameter("device", "Master,0"))
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.__level = 'n/a'
|
self.__level = "n/a"
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self.__muted:
|
if self.__muted:
|
||||||
return ['warning', 'muted']
|
return ["warning", "muted"]
|
||||||
return ['unmuted']
|
return ["unmuted"]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -15,34 +15,39 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
PATTERN = '{} packages upgraded, {} newly installed, {} to remove and {} not upgraded.'
|
PATTERN = "{} packages upgraded, {} newly installed, {} to remove and {} not upgraded."
|
||||||
|
|
||||||
|
|
||||||
def parse_result(to_parse):
|
def parse_result(to_parse):
|
||||||
# We want to line with the iforamtion about package upgrade
|
# We want to line with the iforamtion about package upgrade
|
||||||
line_to_parse = to_parse.split('\n')[-4]
|
line_to_parse = to_parse.split("\n")[-4]
|
||||||
result = re.search('(.+) packages upgraded, (.+) newly installed, (.+) to remove', line_to_parse)
|
result = re.search(
|
||||||
|
"(.+) packages upgraded, (.+) newly installed, (.+) to remove", line_to_parse
|
||||||
|
)
|
||||||
|
|
||||||
return int(result.group(1)), int(result.group(3))
|
return int(result.group(1)), int(result.group(3))
|
||||||
|
|
||||||
|
|
||||||
def get_apt_check_info(module):
|
def get_apt_check_info(module):
|
||||||
widget = module.widget()
|
widget = module.widget()
|
||||||
try:
|
try:
|
||||||
res = util.cli.execute('aptitude full-upgrade --simulate --assume-yes')
|
res = util.cli.execute("aptitude full-upgrade --simulate --assume-yes")
|
||||||
widget.set('error', None)
|
widget.set("error", None)
|
||||||
except (RuntimeError, FileNotFoundError) as e:
|
except (RuntimeError, FileNotFoundError) as e:
|
||||||
widget.set('error', 'unable to query APT: {}'.format(e))
|
widget.set("error", "unable to query APT: {}".format(e))
|
||||||
return
|
return
|
||||||
|
|
||||||
to_upgrade = 0
|
to_upgrade = 0
|
||||||
to_remove = 0
|
to_remove = 0
|
||||||
try:
|
try:
|
||||||
to_upgrade, to_remove = parse_result(res)
|
to_upgrade, to_remove = parse_result(res)
|
||||||
widget.set('to_upgrade', to_upgrade)
|
widget.set("to_upgrade", to_upgrade)
|
||||||
widget.set('to_remove', to_remove)
|
widget.set("to_remove", to_remove)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
widget.set('error', 'parse error: {}'.format(e))
|
widget.set("error", "parse error: {}".format(e))
|
||||||
|
|
||||||
|
core.event.trigger("update", [module.id], redraw_only=True)
|
||||||
|
|
||||||
core.event.trigger('update', [ module.id ], redraw_only=True)
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=30)
|
@core.decorators.every(minutes=30)
|
||||||
|
@ -51,30 +56,32 @@ class Module(core.module.Module):
|
||||||
self.__thread = None
|
self.__thread = None
|
||||||
|
|
||||||
def updates(self, widget):
|
def updates(self, widget):
|
||||||
if widget.get('error'):
|
if widget.get("error"):
|
||||||
return widget.get('error')
|
return widget.get("error")
|
||||||
return '{} to upgrade, {} to remove'.format(
|
return "{} to upgrade, {} to remove".format(
|
||||||
widget.get('to_upgrade', 0), widget.get('to_remove', 0)
|
widget.get("to_upgrade", 0), widget.get("to_remove", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if self.__thread and self.__thread.isAlive(): return
|
if self.__thread and self.__thread.isAlive():
|
||||||
|
return
|
||||||
|
|
||||||
self.__thread = threading.Thread(target=get_apt_check_info, args=(self,))
|
self.__thread = threading.Thread(target=get_apt_check_info, args=(self,))
|
||||||
self.__thread.start()
|
self.__thread.start()
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
cnt = 0
|
cnt = 0
|
||||||
ret = 'good'
|
ret = "good"
|
||||||
for t in ['to_upgrade', 'to_remove']:
|
for t in ["to_upgrade", "to_remove"]:
|
||||||
cnt += widget.get(t, 0)
|
cnt += widget.get(t, 0)
|
||||||
if cnt > 50:
|
if cnt > 50:
|
||||||
ret = 'critical'
|
ret = "critical"
|
||||||
elif cnt > 0:
|
elif cnt > 0:
|
||||||
ret = 'warning'
|
ret = "warning"
|
||||||
if widget.get('error'):
|
if widget.get("error"):
|
||||||
ret = 'critical'
|
ret = "critical"
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,6 +10,7 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -18,7 +19,7 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def __format(self):
|
def __format(self):
|
||||||
return self.parameter('format', 'Update Arch: {}')
|
return self.parameter("format", "Update Arch: {}")
|
||||||
|
|
||||||
def utilization(self, widget):
|
def utilization(self, widget):
|
||||||
return self.__format.format(self.__packages)
|
return self.__format.format(self.__packages)
|
||||||
|
@ -27,10 +28,11 @@ class Module(core.module.Module):
|
||||||
return self.__packages == 0
|
return self.__packages == 0
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
result = util.cli.execute('checkupdates')
|
result = util.cli.execute("checkupdates")
|
||||||
self.__packages = len(result.split('\n')) - 1
|
self.__packages = len(result.split("\n")) - 1
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return self.threshold_state(self.__packages, 1, 100)
|
return self.threshold_state(self.__packages, 1, 100)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -23,30 +23,27 @@ import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
import util.popup
|
import util.popup
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.status))
|
super().__init__(config, theme, core.widget.Widget(self.status))
|
||||||
|
|
||||||
device = self.parameter('device', 'hci0')
|
device = self.parameter("device", "hci0")
|
||||||
self.manager = self.parameter('manager', 'blueman-manager')
|
self.manager = self.parameter("manager", "blueman-manager")
|
||||||
self._path = '/sys/class/bluetooth/{}'.format(device)
|
self._path = "/sys/class/bluetooth/{}".format(device)
|
||||||
self._status = 'Off'
|
self._status = "Off"
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.manager)
|
||||||
cmd=self.manager)
|
|
||||||
|
|
||||||
# determine whether to use pop-up menu or simply toggle the device on/off
|
# determine whether to use pop-up menu or simply toggle the device on/off
|
||||||
right_click_popup = util.format.asbool(
|
right_click_popup = util.format.asbool(
|
||||||
self.parameter('right_click_popup', True))
|
self.parameter("right_click_popup", True)
|
||||||
|
)
|
||||||
|
|
||||||
if right_click_popup:
|
if right_click_popup:
|
||||||
core.input.register(self,
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.popup)
|
||||||
button=core.input.RIGHT_MOUSE,
|
|
||||||
cmd=self.popup)
|
|
||||||
else:
|
else:
|
||||||
core.input.register(self,
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self._toggle)
|
||||||
button=core.input.RIGHT_MOUSE,
|
|
||||||
cmd=self._toggle)
|
|
||||||
|
|
||||||
def status(self, widget):
|
def status(self, widget):
|
||||||
"""Get status."""
|
"""Get status."""
|
||||||
|
@ -55,35 +52,33 @@ class Module(core.module.Module):
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update current state."""
|
"""Update current state."""
|
||||||
if not os.path.exists(self._path):
|
if not os.path.exists(self._path):
|
||||||
self._status = '?'
|
self._status = "?"
|
||||||
return
|
return
|
||||||
|
|
||||||
# search for whichever rfkill directory available
|
# search for whichever rfkill directory available
|
||||||
try:
|
try:
|
||||||
dirnames = next(os.walk(self._path))[1]
|
dirnames = next(os.walk(self._path))[1]
|
||||||
for dirname in dirnames:
|
for dirname in dirnames:
|
||||||
m = re.match(r'rfkill[0-9]+', dirname)
|
m = re.match(r"rfkill[0-9]+", dirname)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
with open(os.path.join(self._path,
|
with open(os.path.join(self._path, dirname, "state"), "r") as f:
|
||||||
dirname,
|
|
||||||
'state'), 'r') as f:
|
|
||||||
state = int(f.read())
|
state = int(f.read())
|
||||||
if state == 1:
|
if state == 1:
|
||||||
self._status = 'On'
|
self._status = "On"
|
||||||
else:
|
else:
|
||||||
self._status = 'Off'
|
self._status = "Off"
|
||||||
return
|
return
|
||||||
|
|
||||||
except IOError:
|
except IOError:
|
||||||
self._status = '?'
|
self._status = "?"
|
||||||
|
|
||||||
def popup(self, widget):
|
def popup(self, widget):
|
||||||
"""Show a popup menu."""
|
"""Show a popup menu."""
|
||||||
menu = util.popup.PopupMenu()
|
menu = util.popup.PopupMenu()
|
||||||
if self._status == 'On':
|
if self._status == "On":
|
||||||
menu.add_menuitem('Disable Bluetooth')
|
menu.add_menuitem("Disable Bluetooth")
|
||||||
elif self._status == 'Off':
|
elif self._status == "Off":
|
||||||
menu.add_menuitem('Enable Bluetooth')
|
menu.add_menuitem("Enable Bluetooth")
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -95,32 +90,35 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def _toggle(self, widget=None):
|
def _toggle(self, widget=None):
|
||||||
"""Toggle bluetooth state."""
|
"""Toggle bluetooth state."""
|
||||||
if self._status == 'On':
|
if self._status == "On":
|
||||||
state = 'false'
|
state = "false"
|
||||||
else:
|
else:
|
||||||
state = 'true'
|
state = "true"
|
||||||
|
|
||||||
dst = self.parameter('dbus_destination', 'org.blueman.Mechanism')
|
dst = self.parameter("dbus_destination", "org.blueman.Mechanism")
|
||||||
dst_path = self.parameter('dbus_destination_path', '/')
|
dst_path = self.parameter("dbus_destination_path", "/")
|
||||||
|
|
||||||
cmd = 'dbus-send --system --print-reply --dest={}'\
|
cmd = (
|
||||||
' {} org.blueman.Mechanism.SetRfkillState'\
|
"dbus-send --system --print-reply --dest={}"
|
||||||
' boolean:{}'.format(dst, dst_path, state)
|
" {} org.blueman.Mechanism.SetRfkillState"
|
||||||
|
" boolean:{}".format(dst, dst_path, state)
|
||||||
|
)
|
||||||
|
|
||||||
logging.debug('bt: toggling bluetooth')
|
logging.debug("bt: toggling bluetooth")
|
||||||
util.cli.execute(cmd)
|
util.cli.execute(cmd)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
"""Get current state."""
|
"""Get current state."""
|
||||||
state = []
|
state = []
|
||||||
|
|
||||||
if self._status == '?':
|
if self._status == "?":
|
||||||
state = ['unknown']
|
state = ["unknown"]
|
||||||
elif self._status == 'On':
|
elif self._status == "On":
|
||||||
state = ['ON']
|
state = ["ON"]
|
||||||
else:
|
else:
|
||||||
state = ['OFF']
|
state = ["OFF"]
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -20,19 +20,18 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.status))
|
super().__init__(config, theme, core.widget.Widget(self.status))
|
||||||
|
|
||||||
self.manager = self.parameter('manager', 'blueman-manager')
|
self.manager = self.parameter("manager", "blueman-manager")
|
||||||
self._status = 'Off'
|
self._status = "Off"
|
||||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||||
self._bus = dbus.SystemBus()
|
self._bus = dbus.SystemBus()
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.manager)
|
||||||
cmd=self.manager)
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self._toggle)
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE,
|
|
||||||
cmd=self._toggle)
|
|
||||||
|
|
||||||
def status(self, widget):
|
def status(self, widget):
|
||||||
"""Get status."""
|
"""Get status."""
|
||||||
|
@ -40,58 +39,63 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update current state."""
|
"""Update current state."""
|
||||||
state = len(subprocess.run(['bluetoothctl', 'list'], stdout=subprocess.PIPE).stdout)
|
state = len(
|
||||||
|
subprocess.run(["bluetoothctl", "list"], stdout=subprocess.PIPE).stdout
|
||||||
|
)
|
||||||
if state > 0:
|
if state > 0:
|
||||||
connected_devices = self.get_connected_devices()
|
connected_devices = self.get_connected_devices()
|
||||||
self._status = 'On - {}'.format(connected_devices)
|
self._status = "On - {}".format(connected_devices)
|
||||||
else:
|
else:
|
||||||
self._status = 'Off'
|
self._status = "Off"
|
||||||
adapters_cmd = 'rfkill list | grep Bluetooth'
|
adapters_cmd = "rfkill list | grep Bluetooth"
|
||||||
if not len(subprocess.run(adapters_cmd, shell=True, stdout=subprocess.PIPE).stdout):
|
if not len(
|
||||||
self._status = 'No Adapter Found'
|
subprocess.run(adapters_cmd, shell=True, stdout=subprocess.PIPE).stdout
|
||||||
|
):
|
||||||
|
self._status = "No Adapter Found"
|
||||||
return
|
return
|
||||||
|
|
||||||
def _toggle(self, widget=None):
|
def _toggle(self, widget=None):
|
||||||
"""Toggle bluetooth state."""
|
"""Toggle bluetooth state."""
|
||||||
if 'On' in self._status:
|
if "On" in self._status:
|
||||||
state = 'false'
|
state = "false"
|
||||||
else:
|
else:
|
||||||
state = 'true'
|
state = "true"
|
||||||
|
|
||||||
cmd = 'dbus-send --system --print-reply --dest=org.blueman.Mechanism /org/blueman/mechanism org.blueman.Mechanism.SetRfkillState boolean:%s' % state
|
cmd = (
|
||||||
|
"dbus-send --system --print-reply --dest=org.blueman.Mechanism /org/blueman/mechanism org.blueman.Mechanism.SetRfkillState boolean:%s"
|
||||||
|
% state
|
||||||
|
)
|
||||||
|
|
||||||
logging.debug('bt: toggling bluetooth')
|
logging.debug("bt: toggling bluetooth")
|
||||||
core.util.execute(cmd)
|
core.util.execute(cmd)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
"""Get current state."""
|
"""Get current state."""
|
||||||
state = []
|
state = []
|
||||||
|
|
||||||
if self._status == 'No Adapter Found':
|
if self._status == "No Adapter Found":
|
||||||
state.append('critical')
|
state.append("critical")
|
||||||
elif self._status == 'On - 0':
|
elif self._status == "On - 0":
|
||||||
state.append('warning')
|
state.append("warning")
|
||||||
elif 'On' in self._status and not(self._status == 'On - 0'):
|
elif "On" in self._status and not (self._status == "On - 0"):
|
||||||
state.append('ON')
|
state.append("ON")
|
||||||
else:
|
else:
|
||||||
state.append('critical')
|
state.append("critical")
|
||||||
return state
|
return state
|
||||||
|
|
||||||
def get_connected_devices(self):
|
def get_connected_devices(self):
|
||||||
devices = 0
|
devices = 0
|
||||||
objects = dbus.Interface(
|
objects = dbus.Interface(
|
||||||
self._bus.get_object('org.bluez', '/'),
|
self._bus.get_object("org.bluez", "/"), "org.freedesktop.DBus.ObjectManager"
|
||||||
'org.freedesktop.DBus.ObjectManager'
|
|
||||||
).GetManagedObjects()
|
).GetManagedObjects()
|
||||||
for path, interfaces in objects.items():
|
for path, interfaces in objects.items():
|
||||||
if 'org.bluez.Device1' in interfaces:
|
if "org.bluez.Device1" in interfaces:
|
||||||
if dbus.Interface(
|
if dbus.Interface(
|
||||||
self._bus.get_object('org.bluez', path),
|
self._bus.get_object("org.bluez", path),
|
||||||
'org.freedesktop.DBus.Properties'
|
"org.freedesktop.DBus.Properties",
|
||||||
).Get(
|
).Get("org.bluez.Device1", "Connected"):
|
||||||
'org.bluez.Device1', 'Connected'
|
|
||||||
):
|
|
||||||
devices += 1
|
devices += 1
|
||||||
return devices
|
return devices
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pylint: disable=C0111,R0903,W0212
|
# pylint: disable=C0111,R0903,W0212
|
||||||
|
|
||||||
"""Enable/disable automatic screen locking.
|
"""Enable/disable automatic screen locking.
|
||||||
|
|
||||||
|
@ -21,10 +21,11 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=10)
|
@core.decorators.every(minutes=10)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(''))
|
super().__init__(config, theme, core.widget.Widget(""))
|
||||||
|
|
||||||
self.__active = False
|
self.__active = False
|
||||||
self.__xid = None
|
self.__xid = None
|
||||||
|
@ -32,7 +33,7 @@ class Module(core.module.Module):
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__toggle)
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__toggle)
|
||||||
|
|
||||||
def __check_requirements(self):
|
def __check_requirements(self):
|
||||||
requirements = ['xdotool', 'xprop', 'xdg-screensaver']
|
requirements = ["xdotool", "xprop", "xdg-screensaver"]
|
||||||
missing = []
|
missing = []
|
||||||
for tool in requirements:
|
for tool in requirements:
|
||||||
if not shutil.which(tool):
|
if not shutil.which(tool):
|
||||||
|
@ -40,20 +41,24 @@ class Module(core.module.Module):
|
||||||
return missing
|
return missing
|
||||||
|
|
||||||
def __get_i3bar_xid(self):
|
def __get_i3bar_xid(self):
|
||||||
xid = util.cli.execute('xdotool search --class \'i3bar\'').partition('\n')[0].strip()
|
xid = (
|
||||||
|
util.cli.execute("xdotool search --class 'i3bar'")
|
||||||
|
.partition("\n")[0]
|
||||||
|
.strip()
|
||||||
|
)
|
||||||
if xid.isdigit():
|
if xid.isdigit():
|
||||||
return xid
|
return xid
|
||||||
logging.warning('Module caffeine: xdotool couldn\'t get X window ID of \'i3bar\'.')
|
logging.warning("Module caffeine: xdotool couldn't get X window ID of 'i3bar'.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __notify(self):
|
def __notify(self):
|
||||||
if not shutil.which('notify-send'):
|
if not shutil.which("notify-send"):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.__active:
|
if self.__active:
|
||||||
util.cli.execute('notify-send \'Consuming caffeine\'')
|
util.cli.execute("notify-send 'Consuming caffeine'")
|
||||||
else:
|
else:
|
||||||
util.cli.execute('notify-send \'Out of coffee\'')
|
util.cli.execute("notify-send 'Out of coffee'")
|
||||||
|
|
||||||
def _suspend_screensaver(self):
|
def _suspend_screensaver(self):
|
||||||
self.__xid = self.__get_i3bar_xid()
|
self.__xid = self.__get_i3bar_xid()
|
||||||
|
@ -63,7 +68,7 @@ class Module(core.module.Module):
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid == 0:
|
if pid == 0:
|
||||||
os.setsid()
|
os.setsid()
|
||||||
util.cli.execute('xdg-screensaver suspend {}'.format(self.__xid))
|
util.cli.execute("xdg-screensaver suspend {}".format(self.__xid))
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
else:
|
else:
|
||||||
os.waitpid(pid, 0)
|
os.waitpid(pid, 0)
|
||||||
|
@ -71,8 +76,12 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def __resume_screensaver(self):
|
def __resume_screensaver(self):
|
||||||
success = True
|
success = True
|
||||||
xprop_path = shutil.which('xprop')
|
xprop_path = shutil.which("xprop")
|
||||||
pids = [ p.pid for p in psutil.process_iter() if p.cmdline() == [xprop_path, '-id', str(self.__xid), '-spy'] ]
|
pids = [
|
||||||
|
p.pid
|
||||||
|
for p in psutil.process_iter()
|
||||||
|
if p.cmdline() == [xprop_path, "-id", str(self.__xid), "-spy"]
|
||||||
|
]
|
||||||
for pid in pids:
|
for pid in pids:
|
||||||
try:
|
try:
|
||||||
os.kill(pid, 9)
|
os.kill(pid, 9)
|
||||||
|
@ -82,13 +91,13 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def state(self, _):
|
def state(self, _):
|
||||||
if self.__active:
|
if self.__active:
|
||||||
return 'activated'
|
return "activated"
|
||||||
return 'deactivated'
|
return "deactivated"
|
||||||
|
|
||||||
def __toggle(self, _):
|
def __toggle(self, _):
|
||||||
missing = self.__check_requirements()
|
missing = self.__check_requirements()
|
||||||
if missing:
|
if missing:
|
||||||
logging.warning('Could not run caffeine - missing %s!', ', '.join(missing))
|
logging.warning("Could not run caffeine - missing %s!", ", ".join(missing))
|
||||||
return
|
return
|
||||||
|
|
||||||
self.__active = not self.__active
|
self.__active = not self.__active
|
||||||
|
@ -102,4 +111,5 @@ class Module(core.module.Module):
|
||||||
else:
|
else:
|
||||||
self.__active = not self.__active
|
self.__active = not self.__active
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -42,90 +42,88 @@ import util.cli
|
||||||
import util.graph
|
import util.graph
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self.__layout = self.parameter('layout', 'cpu2.maxfreq cpu2.cpuload cpu2.coresload cpu2.temp cpu2.fanspeed')
|
self.__layout = self.parameter(
|
||||||
|
"layout", "cpu2.maxfreq cpu2.cpuload cpu2.coresload cpu2.temp cpu2.fanspeed"
|
||||||
|
)
|
||||||
self.__widget_names = self.__layout.split()
|
self.__widget_names = self.__layout.split()
|
||||||
self.__colored = util.format.asbool(self.parameter('colored', False))
|
self.__colored = util.format.asbool(self.parameter("colored", False))
|
||||||
widget_list = []
|
widget_list = []
|
||||||
for widget_name in self.__widget_names:
|
for widget_name in self.__widget_names:
|
||||||
if widget_name == 'cpu2.maxfreq':
|
if widget_name == "cpu2.maxfreq":
|
||||||
widget = core.widget.Widget(
|
widget = core.widget.Widget(name=widget_name, full_text=self.maxfreq)
|
||||||
name=widget_name, full_text=self.maxfreq)
|
widget.set("type", "freq")
|
||||||
widget.set('type', 'freq')
|
elif widget_name == "cpu2.cpuload":
|
||||||
elif widget_name == 'cpu2.cpuload':
|
widget = core.widget.Widget(name=widget_name, full_text=self.cpuload)
|
||||||
widget = core.widget.Widget(
|
widget.set("type", "load")
|
||||||
name=widget_name, full_text=self.cpuload)
|
elif widget_name == "cpu2.coresload":
|
||||||
widget.set('type', 'load')
|
widget = core.widget.Widget(name=widget_name, full_text=self.coresload)
|
||||||
elif widget_name == 'cpu2.coresload':
|
widget.set("type", "loads")
|
||||||
widget = core.widget.Widget(
|
elif widget_name == "cpu2.temp":
|
||||||
name=widget_name, full_text=self.coresload)
|
widget = core.widget.Widget(name=widget_name, full_text=self.temp)
|
||||||
widget.set('type', 'loads')
|
widget.set("type", "temp")
|
||||||
elif widget_name == 'cpu2.temp':
|
elif widget_name == "cpu2.fanspeed":
|
||||||
widget = core.widget.Widget(
|
widget = core.widget.Widget(name=widget_name, full_text=self.fanspeed)
|
||||||
name=widget_name, full_text=self.temp)
|
widget.set("type", "fan")
|
||||||
widget.set('type', 'temp')
|
|
||||||
elif widget_name == 'cpu2.fanspeed':
|
|
||||||
widget = core.widget.Widget(
|
|
||||||
name=widget_name, full_text=self.fanspeed)
|
|
||||||
widget.set('type', 'fan')
|
|
||||||
if self.__colored:
|
if self.__colored:
|
||||||
widget.set('pango', True)
|
widget.set("pango", True)
|
||||||
widget_list.append(widget)
|
widget_list.append(widget)
|
||||||
self.widgets(widget_list)
|
self.widgets(widget_list)
|
||||||
self.__temp_pattern = self.parameter('temp_pattern')
|
self.__temp_pattern = self.parameter("temp_pattern")
|
||||||
if self.__temp_pattern is None:
|
if self.__temp_pattern is None:
|
||||||
self.__temp = 'n/a'
|
self.__temp = "n/a"
|
||||||
self.__fan_pattern = self.parameter('fan_pattern')
|
self.__fan_pattern = self.parameter("fan_pattern")
|
||||||
if self.__fan_pattern is None:
|
if self.__fan_pattern is None:
|
||||||
self.__fan = 'n/a'
|
self.__fan = "n/a"
|
||||||
# maxfreq is loaded only once at startup
|
# maxfreq is loaded only once at startup
|
||||||
if 'cpu2.maxfreq' in self.__widget_names:
|
if "cpu2.maxfreq" in self.__widget_names:
|
||||||
self.__maxfreq = psutil.cpu_freq().max / 1000
|
self.__maxfreq = psutil.cpu_freq().max / 1000
|
||||||
|
|
||||||
def maxfreq(self, _):
|
def maxfreq(self, _):
|
||||||
return '{:.2f}GHz'.format(self.__maxfreq)
|
return "{:.2f}GHz".format(self.__maxfreq)
|
||||||
|
|
||||||
def cpuload(self, _):
|
def cpuload(self, _):
|
||||||
return '{:>3}%'.format(self.__cpuload)
|
return "{:>3}%".format(self.__cpuload)
|
||||||
|
|
||||||
def add_color(self, bar):
|
def add_color(self, bar):
|
||||||
"""add color as pango markup to a bar"""
|
"""add color as pango markup to a bar"""
|
||||||
if bar in ['▁', '▂']:
|
if bar in ["▁", "▂"]:
|
||||||
color = self.theme.color('green', 'green')
|
color = self.theme.color("green", "green")
|
||||||
elif bar in ['▃', '▄']:
|
elif bar in ["▃", "▄"]:
|
||||||
color = self.theme.color('yellow', 'yellow')
|
color = self.theme.color("yellow", "yellow")
|
||||||
elif bar in ['▅', '▆']:
|
elif bar in ["▅", "▆"]:
|
||||||
color = self.theme.color('orange', 'orange')
|
color = self.theme.color("orange", "orange")
|
||||||
elif bar in ['▇', '█']:
|
elif bar in ["▇", "█"]:
|
||||||
color = self.theme.color('red', '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
|
||||||
|
|
||||||
def coresload(self, _):
|
def coresload(self, _):
|
||||||
mono_bars = [util.graph.hbar(x) for x in self.__coresload]
|
mono_bars = [util.graph.hbar(x) for x in self.__coresload]
|
||||||
if not self.__colored:
|
if not self.__colored:
|
||||||
return ''.join(mono_bars)
|
return "".join(mono_bars)
|
||||||
colored_bars = [self.add_color(x) for x in mono_bars]
|
colored_bars = [self.add_color(x) for x in mono_bars]
|
||||||
return ''.join(colored_bars)
|
return "".join(colored_bars)
|
||||||
|
|
||||||
def temp(self, _):
|
def temp(self, _):
|
||||||
if self.__temp == 'n/a' or self.__temp == 0:
|
if self.__temp == "n/a" or self.__temp == 0:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
return '{}°C'.format(self.__temp)
|
return "{}°C".format(self.__temp)
|
||||||
|
|
||||||
def fanspeed(self, _):
|
def fanspeed(self, _):
|
||||||
if self.__fanspeed == 'n/a':
|
if self.__fanspeed == "n/a":
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
return '{}RPM'.format(self.__fanspeed)
|
return "{}RPM".format(self.__fanspeed)
|
||||||
|
|
||||||
def _parse_sensors_output(self):
|
def _parse_sensors_output(self):
|
||||||
output = util.cli.execute('sensors -u')
|
output = util.cli.execute("sensors -u")
|
||||||
lines = output.split('\n')
|
lines = output.split("\n")
|
||||||
temp = 'n/a'
|
temp = "n/a"
|
||||||
fan = 'n/a'
|
fan = "n/a"
|
||||||
temp_line = None
|
temp_line = None
|
||||||
fan_line = None
|
fan_line = None
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
@ -136,23 +134,24 @@ class Module(core.module.Module):
|
||||||
if temp_line is not None and fan_line is not None:
|
if temp_line is not None and fan_line is not None:
|
||||||
break
|
break
|
||||||
if temp_line is not None:
|
if temp_line is not None:
|
||||||
temp = round(float(temp_line.split(':')[1].strip()))
|
temp = round(float(temp_line.split(":")[1].strip()))
|
||||||
if fan_line is not None:
|
if fan_line is not None:
|
||||||
fan = int(fan_line.split(':')[1].strip()[:-4])
|
fan = int(fan_line.split(":")[1].strip()[:-4])
|
||||||
return temp, fan
|
return temp, fan
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if 'cpu2.maxfreq' in self.__widget_names:
|
if "cpu2.maxfreq" in self.__widget_names:
|
||||||
self.__maxfreq = psutil.cpu_freq().max / 1000
|
self.__maxfreq = psutil.cpu_freq().max / 1000
|
||||||
if 'cpu2.cpuload' in self.__widget_names:
|
if "cpu2.cpuload" in self.__widget_names:
|
||||||
self.__cpuload = round(psutil.cpu_percent(percpu=False))
|
self.__cpuload = round(psutil.cpu_percent(percpu=False))
|
||||||
if 'cpu2.coresload' in self.__widget_names:
|
if "cpu2.coresload" in self.__widget_names:
|
||||||
self.__coresload = psutil.cpu_percent(percpu=True)
|
self.__coresload = psutil.cpu_percent(percpu=True)
|
||||||
if 'cpu2.temp' in self.__widget_names or 'cpu2.fanspeed' in self.__widget_names:
|
if "cpu2.temp" in self.__widget_names or "cpu2.fanspeed" in self.__widget_names:
|
||||||
self.__temp, self.__fanspeed = self._parse_sensors_output()
|
self.__temp, self.__fanspeed = self._parse_sensors_output()
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
"""for having per-widget icons"""
|
"""for having per-widget icons"""
|
||||||
return [widget.get('type', '')]
|
return [widget.get("type", "")]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,71 +27,82 @@ import core.input
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
def default_format(module):
|
def default_format(module):
|
||||||
default = '%x %X %Z'
|
default = "%x %X %Z"
|
||||||
if module == 'datetz':
|
if module == "datetz":
|
||||||
default = '%x %Z'
|
default = "%x %Z"
|
||||||
if module == 'timetz':
|
if module == "timetz":
|
||||||
default = '%X %Z'
|
default = "%X %Z"
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.get_time))
|
super().__init__(config, theme, core.widget.Widget(self.get_time))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.next_tz)
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.next_tz)
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.prev_tz)
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.prev_tz)
|
||||||
self.__fmt = self.parameter('format', self.default_format())
|
self.__fmt = self.parameter("format", self.default_format())
|
||||||
|
|
||||||
default_timezone = ''
|
default_timezone = ""
|
||||||
try:
|
try:
|
||||||
default_timezone = tzlocal.get_localzone().zone
|
default_timezone = tzlocal.get_localzone().zone
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error('unable to get default timezone: {}'.format(str(e)))
|
logging.error("unable to get default timezone: {}".format(str(e)))
|
||||||
try:
|
try:
|
||||||
self._timezones = util.format.aslist(self.parameter('timezone', default_timezone))
|
self._timezones = util.format.aslist(
|
||||||
|
self.parameter("timezone", default_timezone)
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
self._timezones = [default_timezone]
|
self._timezones = [default_timezone]
|
||||||
self._current_tz = 0
|
self._current_tz = 0
|
||||||
|
|
||||||
l = locale.getdefaultlocale()
|
l = locale.getdefaultlocale()
|
||||||
if not l or l == (None, None):
|
if not l or l == (None, None):
|
||||||
l = ('en_US', 'UTF-8')
|
l = ("en_US", "UTF-8")
|
||||||
lcl = self.parameter('locale', '.'.join(l))
|
lcl = self.parameter("locale", ".".join(l))
|
||||||
try:
|
try:
|
||||||
locale.setlocale(locale.LC_TIME, lcl.split('.'))
|
locale.setlocale(locale.LC_TIME, lcl.split("."))
|
||||||
except Exception:
|
except Exception:
|
||||||
locale.setlocale(locale.LC_TIME, ('en_US', 'UTF-8'))
|
locale.setlocale(locale.LC_TIME, ("en_US", "UTF-8"))
|
||||||
|
|
||||||
def default_format(self):
|
def default_format(self):
|
||||||
return '%x %X %Z'
|
return "%x %X %Z"
|
||||||
|
|
||||||
def get_time(self, widget):
|
def get_time(self, widget):
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
tz = pytz.timezone(self._timezones[self._current_tz].strip())
|
tz = pytz.timezone(self._timezones[self._current_tz].strip())
|
||||||
retval = datetime.datetime.now(tz=tzlocal.get_localzone()).astimezone(tz).strftime(self.__fmt)
|
retval = (
|
||||||
|
datetime.datetime.now(tz=tzlocal.get_localzone())
|
||||||
|
.astimezone(tz)
|
||||||
|
.strftime(self.__fmt)
|
||||||
|
)
|
||||||
except pytz.exceptions.UnknownTimeZoneError:
|
except pytz.exceptions.UnknownTimeZoneError:
|
||||||
retval = '[Unknown timezone: {}]'.format(self._timezones[self._current_tz].strip())
|
retval = "[Unknown timezone: {}]".format(
|
||||||
|
self._timezones[self._current_tz].strip()
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error('unable to get time: {}'.format(str(e)))
|
logging.error("unable to get time: {}".format(str(e)))
|
||||||
retval = '[n/a]'
|
retval = "[n/a]"
|
||||||
|
|
||||||
enc = locale.getpreferredencoding()
|
enc = locale.getpreferredencoding()
|
||||||
if hasattr(retval, 'decode'):
|
if hasattr(retval, "decode"):
|
||||||
return retval.decode(enc)
|
return retval.decode(enc)
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
def next_tz(self, event):
|
def next_tz(self, event):
|
||||||
next_timezone = self._current_tz + 1
|
next_timezone = self._current_tz + 1
|
||||||
if next_timezone >= len(self._timezones):
|
if next_timezone >= len(self._timezones):
|
||||||
next_timezone = 0 # wraparound
|
next_timezone = 0 # wraparound
|
||||||
self._current_tz = next_timezone
|
self._current_tz = next_timezone
|
||||||
|
|
||||||
def prev_tz(self, event):
|
def prev_tz(self, event):
|
||||||
previous_timezone = self._current_tz - 1
|
previous_timezone = self._current_tz - 1
|
||||||
if previous_timezone < 0:
|
if previous_timezone < 0:
|
||||||
previous_timezone = 0 # wraparound
|
previous_timezone = 0 # wraparound
|
||||||
self._current_tz = previous_timezone
|
self._current_tz = previous_timezone
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,12 +10,14 @@ Parameters:
|
||||||
import core.decorators
|
import core.decorators
|
||||||
from .datetimetz import Module
|
from .datetimetz import Module
|
||||||
|
|
||||||
|
|
||||||
class Module(Module):
|
class Module(Module):
|
||||||
@core.decorators.every(hours=1)
|
@core.decorators.every(hours=1)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme)
|
super().__init__(config, theme)
|
||||||
|
|
||||||
def default_format(self):
|
def default_format(self):
|
||||||
return '%x %Z'
|
return "%x %Z"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -45,66 +45,71 @@ import core.decorators
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.deadbeef))
|
super().__init__(config, theme, core.widget.Widget(self.deadbeef))
|
||||||
|
|
||||||
buttons = {'LEFT_CLICK': core.input.LEFT_MOUSE,
|
buttons = {
|
||||||
'RIGHT_CLICK': core.input.RIGHT_MOUSE,
|
"LEFT_CLICK": core.input.LEFT_MOUSE,
|
||||||
'MIDDLE_CLICK': core.input.MIDDLE_MOUSE,
|
"RIGHT_CLICK": core.input.RIGHT_MOUSE,
|
||||||
'SCROLL_UP': core.input.WHEEL_UP,
|
"MIDDLE_CLICK": core.input.MIDDLE_MOUSE,
|
||||||
'SCROLL_DOWN': core.input.WHEEL_DOWN,
|
"SCROLL_UP": core.input.WHEEL_UP,
|
||||||
}
|
"SCROLL_DOWN": core.input.WHEEL_DOWN,
|
||||||
|
}
|
||||||
|
|
||||||
self._song = ''
|
self._song = ""
|
||||||
self._format = self.parameter('format', '{artist} - {title}')
|
self._format = self.parameter("format", "{artist} - {title}")
|
||||||
self._tf_format = self.parameter('tf_format', '')
|
self._tf_format = self.parameter("tf_format", "")
|
||||||
self._show_tf_when_stopped = util.format.asbool(self.parameter('tf_format_if_stopped', False))
|
self._show_tf_when_stopped = util.format.asbool(
|
||||||
prev_button = self.parameter('previous', 'LEFT_CLICK')
|
self.parameter("tf_format_if_stopped", False)
|
||||||
next_button = self.parameter('next', 'RIGHT_CLICK')
|
)
|
||||||
pause_button = self.parameter('pause', 'MIDDLE_CLICK')
|
prev_button = self.parameter("previous", "LEFT_CLICK")
|
||||||
|
next_button = self.parameter("next", "RIGHT_CLICK")
|
||||||
|
pause_button = self.parameter("pause", "MIDDLE_CLICK")
|
||||||
|
|
||||||
self.now_playing = 'deadbeef --nowplaying %a;%t;%b;%l;%n;%y;%c;%r;%e'
|
self.now_playing = "deadbeef --nowplaying %a;%t;%b;%l;%n;%y;%c;%r;%e"
|
||||||
self.now_playing_tf = 'deadbeef --nowplaying-tf '
|
self.now_playing_tf = "deadbeef --nowplaying-tf "
|
||||||
cmd = 'deadbeef '
|
cmd = "deadbeef "
|
||||||
|
|
||||||
core.input.register(self, button=buttons[prev_button],
|
core.input.register(self, button=buttons[prev_button], cmd=cmd + "--prev")
|
||||||
cmd=cmd + '--prev')
|
core.input.register(self, button=buttons[next_button], cmd=cmd + "--next")
|
||||||
core.input.register(self, button=buttons[next_button],
|
core.input.register(
|
||||||
cmd=cmd + '--next')
|
self, button=buttons[pause_button], cmd=cmd + "--play-pause"
|
||||||
core.input.register(self, button=buttons[pause_button],
|
)
|
||||||
cmd=cmd + '--play-pause')
|
|
||||||
|
|
||||||
# modify the tf_format if we don't want it to show on stop
|
# modify the tf_format if we don't want it to show on stop
|
||||||
# this adds conditions to the query itself, rather than
|
# this adds conditions to the query itself, rather than
|
||||||
# polling to see if deadbeef is running
|
# polling to see if deadbeef is running
|
||||||
# doing this reduces the number of calls we have to make
|
# doing this reduces the number of calls we have to make
|
||||||
if self._tf_format and not self._show_tf_when_stopped:
|
if self._tf_format and not self._show_tf_when_stopped:
|
||||||
self._tf_format = '$if($or(%isplaying%,%ispaused%),{query})'.format(query=self._tf_format)
|
self._tf_format = "$if($or(%isplaying%,%ispaused%),{query})".format(
|
||||||
|
query=self._tf_format
|
||||||
|
)
|
||||||
|
|
||||||
@core.decorators.scrollable
|
@core.decorators.scrollable
|
||||||
def deadbeef(self, widget):
|
def deadbeef(self, widget):
|
||||||
return self.string_song
|
return self.string_song
|
||||||
|
|
||||||
def hidden(self):
|
def hidden(self):
|
||||||
return self.string_song == ''
|
return self.string_song == ""
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
widgets = self.widgets()
|
widgets = self.widgets()
|
||||||
try:
|
try:
|
||||||
if self._tf_format == '': # no tf format set, use the old style
|
if self._tf_format == "": # no tf format set, use the old style
|
||||||
return self.update_standard(widgets)
|
return self.update_standard(widgets)
|
||||||
return self.update_tf(widgets)
|
return self.update_tf(widgets)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception(e)
|
logging.exception(e)
|
||||||
self._song = 'error'
|
self._song = "error"
|
||||||
|
|
||||||
def update_tf(self, widgets):
|
def update_tf(self, widgets):
|
||||||
## ensure that deadbeef is actually running
|
## ensure that deadbeef is actually running
|
||||||
## easiest way to do this is to check --nowplaying for
|
## easiest way to do this is to check --nowplaying for
|
||||||
## the string 'nothing'
|
## the string 'nothing'
|
||||||
if util.cli.execute(self.now_playing) == 'nothing':
|
if util.cli.execute(self.now_playing) == "nothing":
|
||||||
self._song = ''
|
self._song = ""
|
||||||
return
|
return
|
||||||
## perform the actual query -- these can be much more sophisticated
|
## perform the actual query -- these can be much more sophisticated
|
||||||
data = util.cli.execute(self.now_playing_tf + self._tf_format)
|
data = util.cli.execute(self.now_playing_tf + self._tf_format)
|
||||||
|
@ -112,19 +117,21 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def update_standard(self, widgets):
|
def update_standard(self, widgets):
|
||||||
data = util.cli.execute(self.now_playing)
|
data = util.cli.execute(self.now_playing)
|
||||||
if data == 'nothing':
|
if data == "nothing":
|
||||||
self._song = ''
|
self._song = ""
|
||||||
else:
|
else:
|
||||||
data = data.split(';')
|
data = data.split(";")
|
||||||
self._song = self._format.format(artist=data[0],
|
self._song = self._format.format(
|
||||||
title=data[1],
|
artist=data[0],
|
||||||
album=data[2],
|
title=data[1],
|
||||||
length=data[3],
|
album=data[2],
|
||||||
trackno=data[4],
|
length=data[3],
|
||||||
year=data[5],
|
trackno=data[4],
|
||||||
comment=data[6],
|
year=data[5],
|
||||||
copyright=data[7],
|
comment=data[6],
|
||||||
time=data[8])
|
copyright=data[7],
|
||||||
|
time=data[8],
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def string_song(self):
|
def string_song(self):
|
||||||
|
@ -136,4 +143,5 @@ Returns the current song as a string, either as a unicode() (Python <
|
||||||
return unicode(self._song)
|
return unicode(self._song)
|
||||||
return str(self._song)
|
return str(self._song)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -19,51 +19,61 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.deezer))
|
super().__init__(config, theme, core.widget.Widget(self.deezer))
|
||||||
|
|
||||||
buttons = {'LEFT_CLICK':core.input.LEFT_MOUSE,
|
buttons = {
|
||||||
'RIGHT_CLICK':core.input.RIGHT_MOUSE,
|
"LEFT_CLICK": core.input.LEFT_MOUSE,
|
||||||
'MIDDLE_CLICK':core.input.MIDDLE_MOUSE,
|
"RIGHT_CLICK": core.input.RIGHT_MOUSE,
|
||||||
'SCROLL_UP':core.input.WHEEL_UP,
|
"MIDDLE_CLICK": core.input.MIDDLE_MOUSE,
|
||||||
'SCROLL_DOWN':core.input.WHEEL_DOWN,
|
"SCROLL_UP": core.input.WHEEL_UP,
|
||||||
}
|
"SCROLL_DOWN": core.input.WHEEL_DOWN,
|
||||||
|
}
|
||||||
|
|
||||||
self._song = ''
|
self._song = ""
|
||||||
self._format = self.parameter('format', '{artist} - {title}')
|
self._format = self.parameter("format", "{artist} - {title}")
|
||||||
prev_button = self.parameter('previous', 'LEFT_CLICK')
|
prev_button = self.parameter("previous", "LEFT_CLICK")
|
||||||
next_button = self.parameter('next', 'RIGHT_CLICK')
|
next_button = self.parameter("next", "RIGHT_CLICK")
|
||||||
pause_button = self.parameter('pause', 'MIDDLE_CLICK')
|
pause_button = self.parameter("pause", "MIDDLE_CLICK")
|
||||||
|
|
||||||
cmd = 'dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.deezer \
|
cmd = "dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.deezer \
|
||||||
/org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.'
|
/org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player."
|
||||||
core.input.register(self, button=buttons[prev_button],
|
core.input.register(self, button=buttons[prev_button], cmd=cmd + "Previous")
|
||||||
cmd=cmd + 'Previous')
|
core.input.register(self, button=buttons[next_button], cmd=cmd + "Next")
|
||||||
core.input.register(self, button=buttons[next_button],
|
core.input.register(self, button=buttons[pause_button], cmd=cmd + "PlayPause")
|
||||||
cmd=cmd + 'Next')
|
|
||||||
core.input.register(self, button=buttons[pause_button],
|
|
||||||
cmd=cmd + 'PlayPause')
|
|
||||||
|
|
||||||
def deezer(self, widget):
|
def deezer(self, widget):
|
||||||
return str(self._song)
|
return str(self._song)
|
||||||
|
|
||||||
def hidden(self):
|
def hidden(self):
|
||||||
return str(self._song) == ''
|
return str(self._song) == ""
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
bus = dbus.SessionBus()
|
bus = dbus.SessionBus()
|
||||||
deezer = bus.get_object('org.mpris.MediaPlayer2.deezer', '/org/mpris/MediaPlayer2')
|
deezer = bus.get_object(
|
||||||
deezer_iface = dbus.Interface(deezer, 'org.freedesktop.DBus.Properties')
|
"org.mpris.MediaPlayer2.deezer", "/org/mpris/MediaPlayer2"
|
||||||
props = deezer_iface.Get('org.mpris.MediaPlayer2.Player', 'Metadata')
|
)
|
||||||
playback_status = str(deezer_iface.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus'))
|
deezer_iface = dbus.Interface(deezer, "org.freedesktop.DBus.Properties")
|
||||||
self._song = self._format.format(album=str(props.get('xesam:album')),
|
props = deezer_iface.Get("org.mpris.MediaPlayer2.Player", "Metadata")
|
||||||
title=str(props.get('xesam:title')),
|
playback_status = str(
|
||||||
artist=','.join(props.get('xesam:artist')),
|
deezer_iface.Get("org.mpris.MediaPlayer2.Player", "PlaybackStatus")
|
||||||
trackNumber=str(props.get('xesam:trackNumber')),
|
)
|
||||||
playbackStatus=u'\u25B6' if playback_status=='Playing' else u'\u258D\u258D' if playback_status=='Paused' else '',)
|
self._song = self._format.format(
|
||||||
|
album=str(props.get("xesam:album")),
|
||||||
|
title=str(props.get("xesam:title")),
|
||||||
|
artist=",".join(props.get("xesam:artist")),
|
||||||
|
trackNumber=str(props.get("xesam:trackNumber")),
|
||||||
|
playbackStatus="\u25B6"
|
||||||
|
if playback_status == "Playing"
|
||||||
|
else "\u258D\u258D"
|
||||||
|
if playback_status == "Paused"
|
||||||
|
else "",
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
self._song = ''
|
self._song = ""
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -19,34 +19,41 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
def get_dnf_info(widget):
|
def get_dnf_info(widget):
|
||||||
res = util.cli.execute('dnf updateinfo', ignore_errors=True)
|
res = util.cli.execute("dnf updateinfo", ignore_errors=True)
|
||||||
|
|
||||||
security = 0
|
security = 0
|
||||||
bugfixes = 0
|
bugfixes = 0
|
||||||
enhancements = 0
|
enhancements = 0
|
||||||
other = 0
|
other = 0
|
||||||
for line in res.split('\n'):
|
for line in res.split("\n"):
|
||||||
if not line.startswith(' '): continue
|
if not line.startswith(" "):
|
||||||
elif 'ecurity' in line:
|
continue
|
||||||
|
elif "ecurity" in line:
|
||||||
for s in line.split():
|
for s in line.split():
|
||||||
if s.isdigit(): security += int(s)
|
if s.isdigit():
|
||||||
elif 'ugfix' in line:
|
security += int(s)
|
||||||
|
elif "ugfix" in line:
|
||||||
for s in line.split():
|
for s in line.split():
|
||||||
if s.isdigit(): bugfixes += int(s)
|
if s.isdigit():
|
||||||
elif 'hancement' in line:
|
bugfixes += int(s)
|
||||||
|
elif "hancement" in line:
|
||||||
for s in line.split():
|
for s in line.split():
|
||||||
if s.isdigit(): enhancements += int(s)
|
if s.isdigit():
|
||||||
|
enhancements += int(s)
|
||||||
else:
|
else:
|
||||||
for s in line.split():
|
for s in line.split():
|
||||||
if s.isdigit(): other += int(s)
|
if s.isdigit():
|
||||||
|
other += int(s)
|
||||||
|
|
||||||
widget.set('security', security)
|
widget.set("security", security)
|
||||||
widget.set('bugfixes', bugfixes)
|
widget.set("bugfixes", bugfixes)
|
||||||
widget.set('enhancements', enhancements)
|
widget.set("enhancements", enhancements)
|
||||||
widget.set('other', other)
|
widget.set("other", other)
|
||||||
|
|
||||||
|
core.event.trigger("update", [widget.module.id], redraw_only=True)
|
||||||
|
|
||||||
core.event.trigger('update', [ widget.module.id ], redraw_only=True)
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=30)
|
@core.decorators.every(minutes=30)
|
||||||
|
@ -55,9 +62,9 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def updates(self, widget):
|
def updates(self, widget):
|
||||||
result = []
|
result = []
|
||||||
for t in ['security', 'bugfixes', 'enhancements', 'other']:
|
for t in ["security", "bugfixes", "enhancements", "other"]:
|
||||||
result.append(str(widget.get(t, 0)))
|
result.append(str(widget.get(t, 0)))
|
||||||
return '/'.join(result)
|
return "/".join(result)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
thread = threading.Thread(target=get_dnf_info, args=(self.widget(),))
|
thread = threading.Thread(target=get_dnf_info, args=(self.widget(),))
|
||||||
|
@ -65,11 +72,12 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
cnt = 0
|
cnt = 0
|
||||||
for t in ['security', 'bugfixes', 'enhancements', 'other']:
|
for t in ["security", "bugfixes", "enhancements", "other"]:
|
||||||
cnt += widget.get(t, 0)
|
cnt += widget.get(t, 0)
|
||||||
if cnt == 0:
|
if cnt == 0:
|
||||||
return 'good'
|
return "good"
|
||||||
if cnt > 50 or widget.get('security', 0) > 0:
|
if cnt > 50 or widget.get("security", 0) > 0:
|
||||||
return 'critical'
|
return "critical"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -15,29 +15,33 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=5)
|
@core.decorators.every(seconds=5)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.docker_info))
|
super().__init__(config, theme, core.widget.Widget(self.docker_info))
|
||||||
self.__info = ''
|
self.__info = ""
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
state = []
|
state = []
|
||||||
if self.__info == 'OK - 0':
|
if self.__info == "OK - 0":
|
||||||
state.append('warning')
|
state.append("warning")
|
||||||
elif self.__info in ['n/a', 'daemon off']:
|
elif self.__info in ["n/a", "daemon off"]:
|
||||||
state.append('critical')
|
state.append("critical")
|
||||||
return state
|
return state
|
||||||
|
|
||||||
def docker_info(self, widget):
|
def docker_info(self, widget):
|
||||||
try:
|
try:
|
||||||
cli = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
cli = docker.DockerClient(base_url="unix://var/run/docker.sock")
|
||||||
cli.ping()
|
cli.ping()
|
||||||
self.__info = 'OK - {}'.format(len(cli.containers.list(filters={'status': 'running'})))
|
self.__info = "OK - {}".format(
|
||||||
|
len(cli.containers.list(filters={"status": "running"}))
|
||||||
|
)
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
self.__info = 'daemon off'
|
self.__info = "daemon off"
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__info = 'n/a'
|
self.__info = "n/a"
|
||||||
return self.__info
|
return self.__info
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Toggle dunst notifications.'''
|
"""Toggle dunst notifications."""
|
||||||
|
|
||||||
import core.module
|
import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
|
@ -8,28 +8,27 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(''))
|
super().__init__(config, theme, core.widget.Widget(""))
|
||||||
self._paused = False
|
self._paused = False
|
||||||
# Make sure that dunst is currently not paused
|
# Make sure that dunst is currently not paused
|
||||||
util.cli.execute('killall -s SIGUSR2 dunst', ignore_errors=True)
|
util.cli.execute("killall -s SIGUSR2 dunst", ignore_errors=True)
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.toggle_status)
|
||||||
cmd=self.toggle_status
|
|
||||||
)
|
|
||||||
|
|
||||||
def toggle_status(self, event):
|
def toggle_status(self, event):
|
||||||
self._paused = not self._paused
|
self._paused = not self._paused
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self._paused:
|
if self._paused:
|
||||||
util.cli.execute('killall -s SIGUSR1 dunst')
|
util.cli.execute("killall -s SIGUSR1 dunst")
|
||||||
else:
|
else:
|
||||||
util.cli.execute('killall -s SIGUSR2 dunst')
|
util.cli.execute("killall -s SIGUSR2 dunst")
|
||||||
except:
|
except:
|
||||||
self._paused = not self._paused # toggling failed
|
self._paused = not self._paused # toggling failed
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self._paused:
|
if self._paused:
|
||||||
return ['muted', 'warning']
|
return ["muted", "warning"]
|
||||||
return ['unmuted']
|
return ["unmuted"]
|
||||||
|
|
|
@ -24,51 +24,64 @@ import core.decorators
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
def getfromkrak(coin, currency):
|
def getfromkrak(coin, currency):
|
||||||
abbrev = {
|
abbrev = {
|
||||||
'Btc': ['xbt', 'XXBTZ'],
|
"Btc": ["xbt", "XXBTZ"],
|
||||||
'Eth': ['eth', 'XETHZ'],
|
"Eth": ["eth", "XETHZ"],
|
||||||
'Ltc': ['ltc', 'XLTCZ'],
|
"Ltc": ["ltc", "XLTCZ"],
|
||||||
}
|
}
|
||||||
data = abbrev.get(coin, None)
|
data = abbrev.get(coin, None)
|
||||||
if not data: return
|
if not data:
|
||||||
epair = '{}{}'.format(data[0], currency)
|
return
|
||||||
tickname = '{}{}'.format(data[1], currency.upper())
|
epair = "{}{}".format(data[0], currency)
|
||||||
|
tickname = "{}{}".format(data[1], currency.upper())
|
||||||
try:
|
try:
|
||||||
krakenget = requests.get('https://api.kraken.com/0/public/Ticker?pair='+epair).json()
|
krakenget = requests.get(
|
||||||
|
"https://api.kraken.com/0/public/Ticker?pair=" + epair
|
||||||
|
).json()
|
||||||
except (RequestException, Exception):
|
except (RequestException, Exception):
|
||||||
return 'No connection'
|
return "No connection"
|
||||||
if not 'result' in krakenget:
|
if not "result" in krakenget:
|
||||||
return 'No data'
|
return "No data"
|
||||||
kethusdask = float(krakenget['result'][tickname]['a'][0])
|
kethusdask = float(krakenget["result"][tickname]["a"][0])
|
||||||
kethusdbid = float(krakenget['result'][tickname]['b'][0])
|
kethusdbid = float(krakenget["result"][tickname]["b"][0])
|
||||||
return coin+': '+str((kethusdask+kethusdbid)/2)[0:6]
|
return coin + ": " + str((kethusdask + kethusdbid) / 2)[0:6]
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=30)
|
@core.decorators.every(minutes=30)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.curprice))
|
super().__init__(config, theme, core.widget.Widget(self.curprice))
|
||||||
|
|
||||||
self.__curprice = ''
|
self.__curprice = ""
|
||||||
self.__getbtc = util.format.asbool(self.parameter('getbtc', True))
|
self.__getbtc = util.format.asbool(self.parameter("getbtc", True))
|
||||||
self.__geteth = util.format.asbool(self.parameter('geteth', True))
|
self.__geteth = util.format.asbool(self.parameter("geteth", True))
|
||||||
self.__getltc = util.format.asbool(self.parameter('getltc', True))
|
self.__getltc = util.format.asbool(self.parameter("getltc", True))
|
||||||
self.__getcur = self.parameter('getcur', 'usd')
|
self.__getcur = self.parameter("getcur", "usd")
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd='xdg-open https://cryptowat.ch/')
|
self, button=core.input.LEFT_MOUSE, cmd="xdg-open https://cryptowat.ch/"
|
||||||
|
)
|
||||||
|
|
||||||
def curprice(self, widget):
|
def curprice(self, widget):
|
||||||
return self.__curprice
|
return self.__curprice
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
currency = self.__getcur
|
currency = self.__getcur
|
||||||
btcprice, ethprice, ltcprice = '', '', ''
|
btcprice, ethprice, ltcprice = "", "", ""
|
||||||
if self.__getbtc:
|
if self.__getbtc:
|
||||||
btcprice = getfromkrak('Btc', currency)
|
btcprice = getfromkrak("Btc", currency)
|
||||||
if self.__geteth:
|
if self.__geteth:
|
||||||
ethprice = getfromkrak('Eth', currency)
|
ethprice = getfromkrak("Eth", currency)
|
||||||
if self.__getltc:
|
if self.__getltc:
|
||||||
ltcprice = getfromkrak('Ltc', currency)
|
ltcprice = getfromkrak("Ltc", currency)
|
||||||
self.__curprice = btcprice+' '*(self.__getbtc*self.__geteth)+ethprice+' '*(self.__getltc*max(self.__getbtc, self.__geteth))+ltcprice
|
self.__curprice = (
|
||||||
|
btcprice
|
||||||
|
+ " " * (self.__getbtc * self.__geteth)
|
||||||
|
+ ethprice
|
||||||
|
+ " " * (self.__getltc * max(self.__getbtc, self.__geteth))
|
||||||
|
+ ltcprice
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -18,6 +18,7 @@ import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=5)
|
@core.decorators.every(minutes=5)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -25,15 +26,19 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
self.__count = 0
|
self.__count = 0
|
||||||
self.__requests = requests.Session()
|
self.__requests = requests.Session()
|
||||||
self.__requests.headers.update({'Authorization':'token {}'.format(self.parameter('token', ''))})
|
self.__requests.headers.update(
|
||||||
|
{"Authorization": "token {}".format(self.parameter("token", ""))}
|
||||||
|
)
|
||||||
|
|
||||||
cmd = 'xdg-open'
|
cmd = "xdg-open"
|
||||||
if not shutil.which(cmd):
|
if not shutil.which(cmd):
|
||||||
cmd = 'x-www-browser'
|
cmd = "x-www-browser"
|
||||||
|
|
||||||
|
core.input.register(
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
self,
|
||||||
cmd='{} https://github.com/notifications'.format(cmd))
|
button=core.input.LEFT_MOUSE,
|
||||||
|
cmd="{} https://github.com/notifications".format(cmd),
|
||||||
|
)
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.update)
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.update)
|
||||||
|
|
||||||
def github(self, _):
|
def github(self, _):
|
||||||
|
@ -42,17 +47,25 @@ class Module(core.module.Module):
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
self.__count = 0
|
self.__count = 0
|
||||||
url = 'https://api.github.com/notifications'
|
url = "https://api.github.com/notifications"
|
||||||
while True:
|
while True:
|
||||||
notifications = self.__requests.get(url)
|
notifications = self.__requests.get(url)
|
||||||
self.__count += len(list(filter(lambda notification: notification['unread'], notifications.json())))
|
self.__count += len(
|
||||||
next_link = notifications.links.get('next')
|
list(
|
||||||
|
filter(
|
||||||
|
lambda notification: notification["unread"],
|
||||||
|
notifications.json(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
next_link = notifications.links.get("next")
|
||||||
if next_link is not None:
|
if next_link is not None:
|
||||||
url = next_link.get('url')
|
url = next_link.get("url")
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__count = 'n/a'
|
self.__count = "n/a"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -12,42 +12,47 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
widgets = [
|
widgets = [
|
||||||
core.widget.Widget(name='gpmdp.prev'),
|
core.widget.Widget(name="gpmdp.prev"),
|
||||||
core.widget.Widget(name='gpmdp.main', full_text=self.description),
|
core.widget.Widget(name="gpmdp.main", full_text=self.description),
|
||||||
core.widget.Widget(name='gpmdp.next'),
|
core.widget.Widget(name="gpmdp.next"),
|
||||||
]
|
]
|
||||||
super().__init__(config, theme, widgets)
|
super().__init__(config, theme, widgets)
|
||||||
|
|
||||||
core.input.register(widgets[0], button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd='playerctl previous')
|
widgets[0], button=core.input.LEFT_MOUSE, cmd="playerctl previous"
|
||||||
core.input.register(widgets[1], button=core.input.LEFT_MOUSE,
|
)
|
||||||
cmd='playerctl play-pause')
|
core.input.register(
|
||||||
core.input.register(widgets[2], button=core.input.LEFT_MOUSE,
|
widgets[1], button=core.input.LEFT_MOUSE, cmd="playerctl play-pause"
|
||||||
cmd='playerctl next')
|
)
|
||||||
|
core.input.register(
|
||||||
|
widgets[2], button=core.input.LEFT_MOUSE, cmd="playerctl next"
|
||||||
|
)
|
||||||
|
|
||||||
self.__status = None
|
self.__status = None
|
||||||
self.__tags = None
|
self.__tags = None
|
||||||
|
|
||||||
def description(self, widget):
|
def description(self, widget):
|
||||||
return self.__tags if self.__tags else 'n/a'
|
return self.__tags if self.__tags else "n/a"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__load_song()
|
self.__load_song()
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if widget.name == 'gpmdp.prev':
|
if widget.name == "gpmdp.prev":
|
||||||
return 'prev'
|
return "prev"
|
||||||
if widget.name == 'gpmdp.next':
|
if widget.name == "gpmdp.next":
|
||||||
return 'next'
|
return "next"
|
||||||
return self.__status
|
return self.__status
|
||||||
|
|
||||||
def __load_song(self):
|
def __load_song(self):
|
||||||
info = util.cli.execute('gpmdp-remote current', ignore_errors=True)
|
info = util.cli.execute("gpmdp-remote current", ignore_errors=True)
|
||||||
status = util.cli.execute('gpmdp-remote status', ignore_errors=True)
|
status = util.cli.execute("gpmdp-remote status", ignore_errors=True)
|
||||||
self.__status = status.split('\n')[0].lower()
|
self.__status = status.split("\n")[0].lower()
|
||||||
self.__tags = info.split('\n')[0]
|
self.__tags = info.split("\n")[0]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -9,12 +9,13 @@ import socket
|
||||||
import core.module
|
import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
|
|
||||||
HOST = 'localhost'
|
HOST = "localhost"
|
||||||
PORT = 7634
|
PORT = 7634
|
||||||
|
|
||||||
CHUNK_SIZE = 1024
|
CHUNK_SIZE = 1024
|
||||||
RECORD_SIZE = 5
|
RECORD_SIZE = 5
|
||||||
SEPARATOR = '|'
|
SEPARATOR = "|"
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -29,7 +30,7 @@ class Module(core.module.Module):
|
||||||
try:
|
try:
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
sock.connect((HOST, PORT))
|
sock.connect((HOST, PORT))
|
||||||
data = ''
|
data = ""
|
||||||
while True:
|
while True:
|
||||||
chunk = sock.recv(CHUNK_SIZE)
|
chunk = sock.recv(CHUNK_SIZE)
|
||||||
if chunk:
|
if chunk:
|
||||||
|
@ -46,7 +47,7 @@ class Module(core.module.Module):
|
||||||
split data using | separator and remove first item
|
split data using | separator and remove first item
|
||||||
(because the first item is empty)
|
(because the first item is empty)
|
||||||
"""
|
"""
|
||||||
parts = data.split('|')[1:]
|
parts = data.split("|")[1:]
|
||||||
return parts
|
return parts
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -54,8 +55,9 @@ class Module(core.module.Module):
|
||||||
"""
|
"""
|
||||||
partition parts: one device record is five (5) items
|
partition parts: one device record is five (5) items
|
||||||
"""
|
"""
|
||||||
per_disk = [parts[i:i+RECORD_SIZE]
|
per_disk = [
|
||||||
for i in range(len(parts))[::RECORD_SIZE]]
|
parts[i : i + RECORD_SIZE] for i in range(len(parts))[::RECORD_SIZE]
|
||||||
|
]
|
||||||
return per_disk
|
return per_disk
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -64,20 +66,20 @@ class Module(core.module.Module):
|
||||||
get device name (without /dev part, to save space on bar)
|
get device name (without /dev part, to save space on bar)
|
||||||
and temperature (in °C) as tuple
|
and temperature (in °C) as tuple
|
||||||
"""
|
"""
|
||||||
device_name = device_record[0].split('/')[-1]
|
device_name = device_record[0].split("/")[-1]
|
||||||
device_temp = device_record[2]
|
device_temp = device_record[2]
|
||||||
return (device_name, device_temp)
|
return (device_name, device_temp)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __get_hddtemp(device_record):
|
def __get_hddtemp(device_record):
|
||||||
name, temp = device_record
|
name, temp = device_record
|
||||||
hddtemp = '{}+{}°C'.format(name, temp)
|
hddtemp = "{}+{}°C".format(name, temp)
|
||||||
return hddtemp
|
return hddtemp
|
||||||
|
|
||||||
def __get_hddtemps(self):
|
def __get_hddtemps(self):
|
||||||
data = self.__fetch_data()
|
data = self.__fetch_data()
|
||||||
if data is None:
|
if data is None:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
parts = self.__get_parts(data)
|
parts = self.__get_parts(data)
|
||||||
per_disk = self.__partition_parts(parts)
|
per_disk = self.__partition_parts(parts)
|
||||||
names_and_temps = [self.__get_name_and_temp(x) for x in per_disk]
|
names_and_temps = [self.__get_name_and_temp(x) for x in per_disk]
|
||||||
|
@ -87,4 +89,5 @@ class Module(core.module.Module):
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__hddtemps = self.__get_hddtemps()
|
self.__hddtemps = self.__get_hddtemps()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -8,16 +8,18 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.output))
|
super().__init__(config, theme, core.widget.Widget(self.output))
|
||||||
self.__hname = ''
|
self.__hname = ""
|
||||||
|
|
||||||
def output(self, _):
|
def output(self, _):
|
||||||
return self.__hname + ' ' + u'\uf233'
|
return self.__hname + " " + "\uf233"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__hname = platform.node()
|
self.__hname = platform.node()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -16,21 +16,22 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
UNK = 'UNK'
|
UNK = "UNK"
|
||||||
|
|
||||||
@core.decorators.every(seconds=30)
|
@core.decorators.every(seconds=30)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.output))
|
super().__init__(config, theme, core.widget.Widget(self.output))
|
||||||
|
|
||||||
self.__label = self.parameter('label')
|
self.__label = self.parameter("label")
|
||||||
self.__target = self.parameter('target')
|
self.__target = self.parameter("target")
|
||||||
self.__expect = self.parameter('expect', '200')
|
self.__expect = self.parameter("expect", "200")
|
||||||
|
|
||||||
def labelize(self, s):
|
def labelize(self, s):
|
||||||
if self.__label is None:
|
if self.__label is None:
|
||||||
return s
|
return s
|
||||||
return '{}: {}'.format(self.__label, s)
|
return "{}: {}".format(self.__label, s)
|
||||||
|
|
||||||
def getStatus(self):
|
def getStatus(self):
|
||||||
try:
|
try:
|
||||||
|
@ -46,8 +47,8 @@ class Module(core.module.Module):
|
||||||
if self.__status == self.__expect:
|
if self.__status == self.__expect:
|
||||||
return self.labelize(self.__status)
|
return self.labelize(self.__status)
|
||||||
else:
|
else:
|
||||||
reason = ' != {}'.format(self.__expect)
|
reason = " != {}".format(self.__expect)
|
||||||
return self.labelize('{}{}'.format(self.__status, reason))
|
return self.labelize("{}{}".format(self.__status, reason))
|
||||||
|
|
||||||
def output(self, widget):
|
def output(self, widget):
|
||||||
return self.__output
|
return self.__output
|
||||||
|
@ -58,9 +59,10 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self.__status == self.UNK:
|
if self.__status == self.UNK:
|
||||||
return 'warning'
|
return "warning"
|
||||||
if self.__status != self.__expect:
|
if self.__status != self.__expect:
|
||||||
return 'critical'
|
return "critical"
|
||||||
return self.__output
|
return self.__output
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
"""Displays the indicator status, for numlock, scrolllock and capslock
|
"""Displays the indicator status, for numlock, scrolllock and capslock
|
||||||
|
|
||||||
|
@ -13,17 +13,28 @@ import core.widget
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self.__include = tuple(filter(len, util.format.aslist(self.parameter('include', 'NumLock,CapsLock'))))
|
self.__include = tuple(
|
||||||
self.__signalType = self.parameter('signaltype') if not self.parameter('signaltype') is None else 'warning'
|
filter(
|
||||||
|
len, util.format.aslist(self.parameter("include", "NumLock,CapsLock"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.__signalType = (
|
||||||
|
self.parameter("signaltype")
|
||||||
|
if not self.parameter("signaltype") is None
|
||||||
|
else "warning"
|
||||||
|
)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
status_line = ''
|
status_line = ""
|
||||||
for line in util.cli.execute('xset q', ignore_errors=True).replace(' ', '').split('\n'):
|
for line in (
|
||||||
if 'capslock' in line.lower():
|
util.cli.execute("xset q", ignore_errors=True).replace(" ", "").split("\n")
|
||||||
|
):
|
||||||
|
if "capslock" in line.lower():
|
||||||
status_line = line
|
status_line = line
|
||||||
break
|
break
|
||||||
for indicator in self.__include:
|
for indicator in self.__include:
|
||||||
|
@ -32,15 +43,21 @@ class Module(core.module.Module):
|
||||||
widget = core.widget.Widget(name=indicator, module=self)
|
widget = core.widget.Widget(name=indicator, module=self)
|
||||||
self.widgets().append(widget)
|
self.widgets().append(widget)
|
||||||
|
|
||||||
widget.set('status', True if '{}:on'.format(indicator.lower()) in status_line.lower() else False)
|
widget.set(
|
||||||
|
"status",
|
||||||
|
True
|
||||||
|
if "{}:on".format(indicator.lower()) in status_line.lower()
|
||||||
|
else False,
|
||||||
|
)
|
||||||
widget.full_text(indicator)
|
widget.full_text(indicator)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
states = []
|
states = []
|
||||||
if widget.get('status', False):
|
if widget.get("status", False):
|
||||||
states.append(self.__signalType)
|
states.append(self.__signalType)
|
||||||
else:
|
else:
|
||||||
states.append('normal')
|
states.append("normal")
|
||||||
return states
|
return states
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -11,31 +11,30 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=60)
|
@core.decorators.every(seconds=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.current_layout))
|
super().__init__(config, theme, core.widget.Widget(self.current_layout))
|
||||||
|
|
||||||
core.input.register(
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__next_keymap)
|
||||||
self,
|
|
||||||
button=core.input.LEFT_MOUSE,
|
|
||||||
cmd=self.__next_keymap)
|
|
||||||
self.__current_layout = self.__get_current_layout()
|
self.__current_layout = self.__get_current_layout()
|
||||||
|
|
||||||
def current_layout(self, _):
|
def current_layout(self, _):
|
||||||
return self.__current_layout
|
return self.__current_layout
|
||||||
|
|
||||||
def __next_keymap(self, event):
|
def __next_keymap(self, event):
|
||||||
util.cli.execute('xkb-switch -n', ignore_errors=True)
|
util.cli.execute("xkb-switch -n", ignore_errors=True)
|
||||||
|
|
||||||
def __get_current_layout(self):
|
def __get_current_layout(self):
|
||||||
try:
|
try:
|
||||||
res = util.cli.execute('xkb-switch')
|
res = util.cli.execute("xkb-switch")
|
||||||
return res.split('\n')[0]
|
return res.split("\n")[0]
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
return ['n/a']
|
return ["n/a"]
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__current_layout = self.__get_current_layout()
|
self.__current_layout = self.__get_current_layout()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -12,14 +12,13 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.current_layout))
|
super().__init__(config, theme, core.widget.Widget(self.current_layout))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__next_keymap)
|
||||||
cmd=self.__next_keymap)
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.__prev_keymap)
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE,
|
|
||||||
cmd=self.__prev_keymap)
|
|
||||||
|
|
||||||
def __next_keymap(self, event):
|
def __next_keymap(self, event):
|
||||||
self._set_keymap(1)
|
self._set_keymap(1)
|
||||||
|
@ -29,41 +28,49 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def _set_keymap(self, rotation):
|
def _set_keymap(self, rotation):
|
||||||
layouts = self.get_layouts()
|
layouts = self.get_layouts()
|
||||||
if len(layouts) == 1: return # nothing to do
|
if len(layouts) == 1:
|
||||||
|
return # nothing to do
|
||||||
layouts = layouts[rotation:] + layouts[:rotation]
|
layouts = layouts[rotation:] + layouts[:rotation]
|
||||||
|
|
||||||
layout_list = []
|
layout_list = []
|
||||||
variant_list = []
|
variant_list = []
|
||||||
for l in layouts:
|
for l in layouts:
|
||||||
tmp = l.split(':')
|
tmp = l.split(":")
|
||||||
layout_list.append(tmp[0])
|
layout_list.append(tmp[0])
|
||||||
variant_list.append(tmp[1] if len(tmp) > 1 else '')
|
variant_list.append(tmp[1] if len(tmp) > 1 else "")
|
||||||
|
|
||||||
util.cli.execute('setxkbmap -layout {} -variant {}'.format(','.join(layout_list), ','.join(variant_list)), ignore_errors=True)
|
util.cli.execute(
|
||||||
|
"setxkbmap -layout {} -variant {}".format(
|
||||||
|
",".join(layout_list), ",".join(variant_list)
|
||||||
|
),
|
||||||
|
ignore_errors=True,
|
||||||
|
)
|
||||||
|
|
||||||
def get_layouts(self):
|
def get_layouts(self):
|
||||||
try:
|
try:
|
||||||
res = util.cli.execute('setxkbmap -query')
|
res = util.cli.execute("setxkbmap -query")
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
return ['n/a']
|
return ["n/a"]
|
||||||
layouts = []
|
layouts = []
|
||||||
variants = []
|
variants = []
|
||||||
for line in res.split('\n'):
|
for line in res.split("\n"):
|
||||||
if not line: continue
|
if not line:
|
||||||
if 'layout' in line:
|
continue
|
||||||
layouts = line.split(':')[1].strip().split(',')
|
if "layout" in line:
|
||||||
if 'variant' in line:
|
layouts = line.split(":")[1].strip().split(",")
|
||||||
variants = line.split(':')[1].strip().split(',')
|
if "variant" in line:
|
||||||
|
variants = line.split(":")[1].strip().split(",")
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for idx, layout in enumerate(layouts):
|
for idx, layout in enumerate(layouts):
|
||||||
if len(variants) > idx and variants[idx]:
|
if len(variants) > idx and variants[idx]:
|
||||||
layout = '{}:{}'.format(layout, variants[idx])
|
layout = "{}:{}".format(layout, variants[idx])
|
||||||
result.append(layout)
|
result.append(layout)
|
||||||
return result if len(result) > 0 else ['n/a']
|
return result if len(result) > 0 else ["n/a"]
|
||||||
|
|
||||||
def current_layout(self, widget):
|
def current_layout(self, widget):
|
||||||
layouts = self.get_layouts()
|
layouts = self.get_layouts()
|
||||||
return layouts[0]
|
return layouts[0]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -11,18 +11,19 @@ import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=10)
|
@core.decorators.every(seconds=10)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.status))
|
super().__init__(config, theme, core.widget.Widget(self.status))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd="virt-manager")
|
||||||
cmd='virt-manager')
|
|
||||||
|
|
||||||
def status(self, _):
|
def status(self, _):
|
||||||
conn = libvirt.openReadOnly(None)
|
conn = libvirt.openReadOnly(None)
|
||||||
if conn == None:
|
if conn == None:
|
||||||
return 'Failed to open connection to the hypervisor'
|
return "Failed to open connection to the hypervisor"
|
||||||
return 'VMs %s' % (conn.numOfDomains())
|
return "VMs %s" % (conn.numOfDomains())
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -29,17 +29,18 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.description))
|
super().__init__(config, theme, core.widget.Widget(self.description))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd='mocp -G')
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd="mocp -G")
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd='mocp -t shuffle')
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd="mocp -t shuffle")
|
||||||
self.__format = self.parameter('format', '%state %artist - %song | %ct/%tt')
|
self.__format = self.parameter("format", "%state %artist - %song | %ct/%tt")
|
||||||
self.__running = False
|
self.__running = False
|
||||||
|
|
||||||
def description(self, widget):
|
def description(self, widget):
|
||||||
return self.__info if self.__running == True else 'Music On Console Player'
|
return self.__info if self.__running == True else "Music On Console Player"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__load_song()
|
self.__load_song()
|
||||||
|
@ -51,4 +52,5 @@ class Module(core.module.Module):
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
self.__running = False
|
self.__running = False
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -52,22 +52,25 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self._layout = self.parameter('layout', 'mpd.prev mpd.main mpd.next mpd.shuffle mpd.repeat')
|
self._layout = self.parameter(
|
||||||
|
"layout", "mpd.prev mpd.main mpd.next mpd.shuffle mpd.repeat"
|
||||||
|
)
|
||||||
|
|
||||||
self._fmt = self.parameter('format', '{artist} - {title} {position}/{duration}')
|
self._fmt = self.parameter("format", "{artist} - {title} {position}/{duration}")
|
||||||
self._status = None
|
self._status = None
|
||||||
self._shuffle = False
|
self._shuffle = False
|
||||||
self._repeat = False
|
self._repeat = False
|
||||||
self._tags = defaultdict(lambda: '')
|
self._tags = defaultdict(lambda: "")
|
||||||
|
|
||||||
if not self.parameter('host'):
|
if not self.parameter("host"):
|
||||||
self._hostcmd = ''
|
self._hostcmd = ""
|
||||||
else:
|
else:
|
||||||
self._hostcmd = ' -h ' + self.parameter('host')
|
self._hostcmd = " -h " + self.parameter("host")
|
||||||
|
|
||||||
# Create widgets
|
# Create widgets
|
||||||
widget_list = []
|
widget_list = []
|
||||||
|
@ -76,19 +79,38 @@ class Module(core.module.Module):
|
||||||
widget = core.widget.Widget(name=widget_name, module=self)
|
widget = core.widget.Widget(name=widget_name, module=self)
|
||||||
widget_list.append(widget)
|
widget_list.append(widget)
|
||||||
|
|
||||||
if widget_name == 'mpd.prev':
|
if widget_name == "mpd.prev":
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': 'mpc prev' + self._hostcmd}
|
widget_map[widget] = {
|
||||||
elif widget_name == 'mpd.main':
|
"button": core.input.LEFT_MOUSE,
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': 'mpc toggle' + self._hostcmd}
|
"cmd": "mpc prev" + self._hostcmd,
|
||||||
|
}
|
||||||
|
elif widget_name == "mpd.main":
|
||||||
|
widget_map[widget] = {
|
||||||
|
"button": core.input.LEFT_MOUSE,
|
||||||
|
"cmd": "mpc toggle" + self._hostcmd,
|
||||||
|
}
|
||||||
widget.full_text(self.description)
|
widget.full_text(self.description)
|
||||||
elif widget_name == 'mpd.next':
|
elif widget_name == "mpd.next":
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': 'mpc next' + self._hostcmd}
|
widget_map[widget] = {
|
||||||
elif widget_name == 'mpd.shuffle':
|
"button": core.input.LEFT_MOUSE,
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': 'mpc random' + self._hostcmd}
|
"cmd": "mpc next" + self._hostcmd,
|
||||||
elif widget_name == 'mpd.repeat':
|
}
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': 'mpc repeat' + self._hostcmd}
|
elif widget_name == "mpd.shuffle":
|
||||||
|
widget_map[widget] = {
|
||||||
|
"button": core.input.LEFT_MOUSE,
|
||||||
|
"cmd": "mpc random" + self._hostcmd,
|
||||||
|
}
|
||||||
|
elif widget_name == "mpd.repeat":
|
||||||
|
widget_map[widget] = {
|
||||||
|
"button": core.input.LEFT_MOUSE,
|
||||||
|
"cmd": "mpc repeat" + self._hostcmd,
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
raise KeyError('The mpd module does not support a {widget_name!r} widget'.format(widget_name=widget_name))
|
raise KeyError(
|
||||||
|
"The mpd module does not support a {widget_name!r} widget".format(
|
||||||
|
widget_name=widget_name
|
||||||
|
)
|
||||||
|
)
|
||||||
self.widgets(widget_list)
|
self.widgets(widget_list)
|
||||||
|
|
||||||
# Register input callbacks
|
# Register input callbacks
|
||||||
|
@ -106,74 +128,79 @@ class Module(core.module.Module):
|
||||||
self._load_song()
|
self._load_song()
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if widget.name == 'mpd.shuffle':
|
if widget.name == "mpd.shuffle":
|
||||||
return 'shuffle-on' if self._shuffle else 'shuffle-off'
|
return "shuffle-on" if self._shuffle else "shuffle-off"
|
||||||
if widget.name == 'mpd.repeat':
|
if widget.name == "mpd.repeat":
|
||||||
return 'repeat-on' if self._repeat else 'repeat-off'
|
return "repeat-on" if self._repeat else "repeat-off"
|
||||||
if widget.name == 'mpd.prev':
|
if widget.name == "mpd.prev":
|
||||||
return 'prev'
|
return "prev"
|
||||||
if widget.name == 'mpd.next':
|
if widget.name == "mpd.next":
|
||||||
return 'next'
|
return "next"
|
||||||
return self._status
|
return self._status
|
||||||
|
|
||||||
def _load_song(self):
|
def _load_song(self):
|
||||||
info = ''
|
info = ""
|
||||||
tags = ['name',
|
tags = [
|
||||||
'artist',
|
"name",
|
||||||
'album',
|
"artist",
|
||||||
'albumartist',
|
"album",
|
||||||
'comment',
|
"albumartist",
|
||||||
'composer',
|
"comment",
|
||||||
'date',
|
"composer",
|
||||||
'originaldate',
|
"date",
|
||||||
'disc',
|
"originaldate",
|
||||||
'genre',
|
"disc",
|
||||||
'performer',
|
"genre",
|
||||||
'title',
|
"performer",
|
||||||
'track',
|
"title",
|
||||||
'time',
|
"track",
|
||||||
'file',
|
"time",
|
||||||
'id',
|
"file",
|
||||||
'prio',
|
"id",
|
||||||
'mtime',
|
"prio",
|
||||||
'mdate']
|
"mtime",
|
||||||
joinedtags = '\n'.join(['tag {0} %{0}%'.format(tag) for tag in tags])
|
"mdate",
|
||||||
info = util.cli.execute('mpc -f "{}"{}'.format(joinedtags, self._hostcmd), ignore_errors=True)
|
]
|
||||||
|
joinedtags = "\n".join(["tag {0} %{0}%".format(tag) for tag in tags])
|
||||||
|
info = util.cli.execute(
|
||||||
|
'mpc -f "{}"{}'.format(joinedtags, self._hostcmd), ignore_errors=True
|
||||||
|
)
|
||||||
|
|
||||||
self._tags = defaultdict(lambda: '')
|
self._tags = defaultdict(lambda: "")
|
||||||
self._status = None
|
self._status = None
|
||||||
for line in info.split('\n'):
|
for line in info.split("\n"):
|
||||||
if line.startswith('[playing]'):
|
if line.startswith("[playing]"):
|
||||||
self._status = 'playing'
|
self._status = "playing"
|
||||||
elif line.startswith('[paused]'):
|
elif line.startswith("[paused]"):
|
||||||
self._status = 'paused'
|
self._status = "paused"
|
||||||
|
|
||||||
if line.startswith('['):
|
if line.startswith("["):
|
||||||
timer = line.split()[2]
|
timer = line.split()[2]
|
||||||
position = timer.split('/')[0]
|
position = timer.split("/")[0]
|
||||||
dur = timer.split('/')[1]
|
dur = timer.split("/")[1]
|
||||||
duration = dur.split(' ')[0]
|
duration = dur.split(" ")[0]
|
||||||
self._tags.update({'position': position})
|
self._tags.update({"position": position})
|
||||||
self._tags.update({'duration': duration})
|
self._tags.update({"duration": duration})
|
||||||
|
|
||||||
if line.startswith('volume'):
|
if line.startswith("volume"):
|
||||||
value = line.split(' ', 2)[1:]
|
value = line.split(" ", 2)[1:]
|
||||||
for option in value:
|
for option in value:
|
||||||
if option.startswith('repeat: on'):
|
if option.startswith("repeat: on"):
|
||||||
self._repeat = True
|
self._repeat = True
|
||||||
elif option.startswith('repeat: off'):
|
elif option.startswith("repeat: off"):
|
||||||
self._repeat = False
|
self._repeat = False
|
||||||
elif option.startswith('random: on'):
|
elif option.startswith("random: on"):
|
||||||
self._shuffle = True
|
self._shuffle = True
|
||||||
elif option.startswith('random: off'):
|
elif option.startswith("random: off"):
|
||||||
self._shuffle = False
|
self._shuffle = False
|
||||||
if line.startswith('tag'):
|
if line.startswith("tag"):
|
||||||
key, value = line.split(' ', 2)[1:]
|
key, value = line.split(" ", 2)[1:]
|
||||||
self._tags.update({key: value})
|
self._tags.update({key: value})
|
||||||
if key == 'file':
|
if key == "file":
|
||||||
self._tags.update({'file1': os.path.basename(value)})
|
self._tags.update({"file1": os.path.basename(value)})
|
||||||
self._tags.update(
|
self._tags.update(
|
||||||
{'file2':
|
{"file2": os.path.splitext(os.path.basename(value))[0]}
|
||||||
os.path.splitext(os.path.basename(value))[0]})
|
)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -13,24 +13,33 @@ import core.widget
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
WIDGET_NAME = 'network_traffic'
|
WIDGET_NAME = "network_traffic"
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
widgets = [
|
widgets = [
|
||||||
core.widget.Widget(module=self, name='{0}.rx'.format(WIDGET_NAME), full_text=self.download_rate),
|
core.widget.Widget(
|
||||||
core.widget.Widget(module=self, name='{0}.tx'.format(WIDGET_NAME), full_text=self.upload_rate)
|
module=self,
|
||||||
|
name="{0}.rx".format(WIDGET_NAME),
|
||||||
|
full_text=self.download_rate,
|
||||||
|
),
|
||||||
|
core.widget.Widget(
|
||||||
|
module=self,
|
||||||
|
name="{0}.tx".format(WIDGET_NAME),
|
||||||
|
full_text=self.upload_rate,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
super().__init__(config, theme, widgets)
|
super().__init__(config, theme, widgets)
|
||||||
|
|
||||||
self.widgets()[0].set('theme.minwidth', '0000000KiB/s')
|
self.widgets()[0].set("theme.minwidth", "0000000KiB/s")
|
||||||
self.widgets()[1].set('theme.minwidth', '0000000KiB/s')
|
self.widgets()[1].set("theme.minwidth", "0000000KiB/s")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._bandwidth = BandwidthInfo()
|
self._bandwidth = BandwidthInfo()
|
||||||
|
|
||||||
self._rate_recv = '?'
|
self._rate_recv = "?"
|
||||||
self._rate_sent = '?'
|
self._rate_sent = "?"
|
||||||
self._bytes_recv = self._bandwidth.bytes_recv()
|
self._bytes_recv = self._bandwidth.bytes_recv()
|
||||||
self._bytes_sent = self._bandwidth.bytes_sent()
|
self._bytes_sent = self._bandwidth.bytes_sent()
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -40,10 +49,10 @@ class Module(core.module.Module):
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
"""Return the widget state"""
|
"""Return the widget state"""
|
||||||
|
|
||||||
if widget.name == '{}.rx'.format(WIDGET_NAME):
|
if widget.name == "{}.rx".format(WIDGET_NAME):
|
||||||
return 'rx'
|
return "rx"
|
||||||
elif widget.name == '{}.tx'.format(WIDGET_NAME):
|
elif widget.name == "{}.tx".format(WIDGET_NAME):
|
||||||
return 'tx'
|
return "tx"
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -52,8 +61,8 @@ class Module(core.module.Module):
|
||||||
bytes_recv = self._bandwidth.bytes_recv()
|
bytes_recv = self._bandwidth.bytes_recv()
|
||||||
bytes_sent = self._bandwidth.bytes_sent()
|
bytes_sent = self._bandwidth.bytes_sent()
|
||||||
|
|
||||||
self._rate_recv = (bytes_recv - self._bytes_recv)
|
self._rate_recv = bytes_recv - self._bytes_recv
|
||||||
self._rate_sent = (bytes_sent - self._bytes_sent)
|
self._rate_sent = bytes_sent - self._bytes_sent
|
||||||
|
|
||||||
self._bytes_recv, self._bytes_sent = bytes_recv, bytes_sent
|
self._bytes_recv, self._bytes_sent = bytes_recv, bytes_sent
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -61,10 +70,11 @@ class Module(core.module.Module):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def download_rate(self, _):
|
def download_rate(self, _):
|
||||||
return '{}/s'.format(util.format.byte(self._rate_recv))
|
return "{}/s".format(util.format.byte(self._rate_recv))
|
||||||
|
|
||||||
def upload_rate(self, _):
|
def upload_rate(self, _):
|
||||||
return '{}/s'.format(util.format.byte(self._rate_sent))
|
return "{}/s".format(util.format.byte(self._rate_sent))
|
||||||
|
|
||||||
|
|
||||||
class BandwidthInfo(object):
|
class BandwidthInfo(object):
|
||||||
"""Get received/sent bytes from network adapter"""
|
"""Get received/sent bytes from network adapter"""
|
||||||
|
@ -85,10 +95,10 @@ class BandwidthInfo(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def default_network_adapter(cls):
|
def default_network_adapter(cls):
|
||||||
"""Return default active network adapter"""
|
"""Return default active network adapter"""
|
||||||
gateway = netifaces.gateways()['default']
|
gateway = netifaces.gateways()["default"]
|
||||||
|
|
||||||
if not gateway:
|
if not gateway:
|
||||||
raise 'No default gateway found'
|
raise "No default gateway found"
|
||||||
|
|
||||||
return gateway[netifaces.AF_INET][1]
|
return gateway[netifaces.AF_INET][1]
|
||||||
|
|
||||||
|
@ -97,4 +107,5 @@ class BandwidthInfo(object):
|
||||||
"""Return IO counters"""
|
"""Return IO counters"""
|
||||||
return psutil.net_io_counters(pernic=True)
|
return psutil.net_io_counters(pernic=True)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -20,24 +20,30 @@ import core.widget
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.output))
|
super().__init__(config, theme, core.widget.Widget(self.output))
|
||||||
|
|
||||||
self.__notmuch_count_query = self.parameter('query', 'tag:unread AND NOT path:/.*Trash.*/')
|
self.__notmuch_count_query = self.parameter(
|
||||||
|
"query", "tag:unread AND NOT path:/.*Trash.*/"
|
||||||
|
)
|
||||||
|
|
||||||
def output(self, widget):
|
def output(self, widget):
|
||||||
return self.__notmuch_count
|
return self.__notmuch_count
|
||||||
|
|
||||||
def state(self, widgets):
|
def state(self, widgets):
|
||||||
if self.__notmuch_count == 0:
|
if self.__notmuch_count == 0:
|
||||||
return 'empty'
|
return "empty"
|
||||||
return 'items'
|
return "items"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
self.__notmuch_count = util.cli.execute('notmuch count {}'.format(self.__notmuch_count_query)).strip()
|
self.__notmuch_count = util.cli.execute(
|
||||||
|
"notmuch count {}".format(self.__notmuch_count_query)
|
||||||
|
).strip()
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__notmuch_count = 'n/a'
|
self.__notmuch_count = "n/a"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -15,11 +15,12 @@ import core.widget
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.utilization))
|
super().__init__(config, theme, core.widget.Widget(self.utilization))
|
||||||
|
|
||||||
self.__utilization = 'Not found: 0 0/0'
|
self.__utilization = "Not found: 0 0/0"
|
||||||
|
|
||||||
def utilization(self, widget):
|
def utilization(self, widget):
|
||||||
return self.__utilization
|
return self.__utilization
|
||||||
|
@ -28,49 +29,52 @@ class Module(core.module.Module):
|
||||||
return "not found" in self.__utilization
|
return "not found" in self.__utilization
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
sp = util.cli.execute('nvidia-smi -q', ignore_errors=True)
|
sp = util.cli.execute("nvidia-smi -q", ignore_errors=True)
|
||||||
|
|
||||||
title = ''
|
title = ""
|
||||||
usedMem = ''
|
usedMem = ""
|
||||||
totalMem = ''
|
totalMem = ""
|
||||||
temp = ''
|
temp = ""
|
||||||
name = 'not found'
|
name = "not found"
|
||||||
clockMem = ''
|
clockMem = ""
|
||||||
clockGpu = ''
|
clockGpu = ""
|
||||||
fanspeed = ''
|
fanspeed = ""
|
||||||
for item in sp.split('\n'):
|
for item in sp.split("\n"):
|
||||||
try:
|
try:
|
||||||
key, val = item.split(':')
|
key, val = item.split(":")
|
||||||
key, val = key.strip(), val.strip()
|
key, val = key.strip(), val.strip()
|
||||||
if title == 'Clocks':
|
if title == "Clocks":
|
||||||
if key == 'Graphics':
|
if key == "Graphics":
|
||||||
clockGpu = val.split(' ')[0]
|
clockGpu = val.split(" ")[0]
|
||||||
elif key == 'Memory':
|
elif key == "Memory":
|
||||||
clockMem = val.split(' ')[0]
|
clockMem = val.split(" ")[0]
|
||||||
if title == 'FB Memory Usage':
|
if title == "FB Memory Usage":
|
||||||
if key == 'Total':
|
if key == "Total":
|
||||||
totalMem = val.split(' ')[0]
|
totalMem = val.split(" ")[0]
|
||||||
elif key == 'Used':
|
elif key == "Used":
|
||||||
usedMem = val.split(' ')[0]
|
usedMem = val.split(" ")[0]
|
||||||
elif key == 'GPU Current Temp':
|
elif key == "GPU Current Temp":
|
||||||
temp = val.split(' ')[0]
|
temp = val.split(" ")[0]
|
||||||
elif key == 'Product Name':
|
elif key == "Product Name":
|
||||||
name = val
|
name = val
|
||||||
elif key == 'Fan Speed':
|
elif key == "Fan Speed":
|
||||||
fanspeed = val.split(' ')[0]
|
fanspeed = val.split(" ")[0]
|
||||||
|
|
||||||
except:
|
except:
|
||||||
title = item.strip()
|
title = item.strip()
|
||||||
|
|
||||||
str_format = self.parameter('format', '{name}: {temp}°C {mem_used}/{mem_total} MiB')
|
str_format = self.parameter(
|
||||||
|
"format", "{name}: {temp}°C {mem_used}/{mem_total} MiB"
|
||||||
|
)
|
||||||
self.__utilization = str_format.format(
|
self.__utilization = str_format.format(
|
||||||
name = name,
|
name=name,
|
||||||
temp = temp,
|
temp=temp,
|
||||||
mem_used = usedMem,
|
mem_used=usedMem,
|
||||||
mem_total = totalMem,
|
mem_total=totalMem,
|
||||||
clock_gpu = clockGpu,
|
clock_gpu=clockGpu,
|
||||||
clock_mem = clockMem,
|
clock_mem=clockMem,
|
||||||
fanspeed = fanspeed,
|
fanspeed=fanspeed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -27,20 +27,22 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
def get_frame(url):
|
def get_frame(url):
|
||||||
img_bytes = b""
|
img_bytes = b""
|
||||||
stream = urllib.request.urlopen(url)
|
stream = urllib.request.urlopen(url)
|
||||||
while True:
|
while True:
|
||||||
img_bytes += stream.read(1024)
|
img_bytes += stream.read(1024)
|
||||||
a = img_bytes.find(b'\xff\xd8')
|
a = img_bytes.find(b"\xff\xd8")
|
||||||
b = img_bytes.find(b'\xff\xd9')
|
b = img_bytes.find(b"\xff\xd9")
|
||||||
if a != -1 and b != -1:
|
if a != -1 and b != -1:
|
||||||
jpg = img_bytes[a:b+2]
|
jpg = img_bytes[a : b + 2]
|
||||||
img_bytes = img_bytes[b+2:]
|
img_bytes = img_bytes[b + 2 :]
|
||||||
img = Image.open(BytesIO(jpg))
|
img = Image.open(BytesIO(jpg))
|
||||||
return img
|
return img
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class WebcamImagesWorker(threading.Thread):
|
class WebcamImagesWorker(threading.Thread):
|
||||||
def __init__(self, url, queue):
|
def __init__(self, url, queue):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
@ -48,6 +50,7 @@ class WebcamImagesWorker(threading.Thread):
|
||||||
self.__url = url
|
self.__url = url
|
||||||
self.__queue = queue
|
self.__queue = queue
|
||||||
self.__running = True
|
self.__running = True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while self.__running:
|
while self.__running:
|
||||||
img = get_frame(self.__url)
|
img = get_frame(self.__url)
|
||||||
|
@ -56,6 +59,7 @@ class WebcamImagesWorker(threading.Thread):
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.__running = False
|
self.__running = False
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=5)
|
@core.decorators.every(seconds=5)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -75,13 +79,20 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
self.update_status()
|
self.update_status()
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__show_popup)
|
||||||
cmd=self.__show_popup)
|
|
||||||
|
|
||||||
def octoprint_status(self, widget):
|
def octoprint_status(self, widget):
|
||||||
if self.__octoprint_state == "Offline" or self.__octoprint_state == "Unknown":
|
if self.__octoprint_state == "Offline" or self.__octoprint_state == "Unknown":
|
||||||
return self.__octoprint_state
|
return self.__octoprint_state
|
||||||
return self.__octoprint_state + " | B: " + str(self.__printer_bed_temperature) + "°C" + " | T1: " + str(self.__tool1_temperature) + "°C"
|
return (
|
||||||
|
self.__octoprint_state
|
||||||
|
+ " | B: "
|
||||||
|
+ str(self.__printer_bed_temperature)
|
||||||
|
+ "°C"
|
||||||
|
+ " | T1: "
|
||||||
|
+ str(self.__tool1_temperature)
|
||||||
|
+ "°C"
|
||||||
|
)
|
||||||
|
|
||||||
def __get(self, endpoint):
|
def __get(self, endpoint):
|
||||||
url = self.__octoprint_address + "/api/" + endpoint
|
url = self.__octoprint_address + "/api/" + endpoint
|
||||||
|
@ -96,7 +107,10 @@ class Module(core.module.Module):
|
||||||
def __get_printer_bed_temperature(self):
|
def __get_printer_bed_temperature(self):
|
||||||
printer_info, status_code = self.__get("printer")
|
printer_info, status_code = self.__get("printer")
|
||||||
if status_code == 200:
|
if status_code == 200:
|
||||||
return printer_info["temperature"]["bed"]["actual"], printer_info["temperature"]["bed"]["target"]
|
return (
|
||||||
|
printer_info["temperature"]["bed"]["actual"],
|
||||||
|
printer_info["temperature"]["bed"]["target"],
|
||||||
|
)
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
def __get_octoprint_state(self):
|
def __get_octoprint_state(self):
|
||||||
|
@ -122,7 +136,7 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def update_status(self):
|
def update_status(self):
|
||||||
try:
|
try:
|
||||||
self.__octoprint_state = self.__get_octoprint_state()
|
self.__octoprint_state = self.__get_octoprint_state()
|
||||||
|
|
||||||
actual_temp, _ = self.__get_printer_bed_temperature()
|
actual_temp, _ = self.__get_printer_bed_temperature()
|
||||||
if actual_temp is None:
|
if actual_temp is None:
|
||||||
|
@ -149,7 +163,9 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
root.after(5, self.__refresh_image, root, webcam_image, webcam_image_container)
|
root.after(5, self.__refresh_image, root, webcam_image, webcam_image_container)
|
||||||
|
|
||||||
def __refresh_temperatures(self, root, printer_bed_temperature_label, tools_temperature_label):
|
def __refresh_temperatures(
|
||||||
|
self, root, printer_bed_temperature_label, tools_temperature_label
|
||||||
|
):
|
||||||
actual_bed_temp, target_bed_temp = self.__get_printer_bed_temperature()
|
actual_bed_temp, target_bed_temp = self.__get_printer_bed_temperature()
|
||||||
if actual_bed_temp is None:
|
if actual_bed_temp is None:
|
||||||
actual_bed_temp = "-"
|
actual_bed_temp = "-"
|
||||||
|
@ -159,7 +175,6 @@ class Module(core.module.Module):
|
||||||
bed_temp = "Bed: " + str(actual_bed_temp) + "/" + str(target_bed_temp) + " °C"
|
bed_temp = "Bed: " + str(actual_bed_temp) + "/" + str(target_bed_temp) + " °C"
|
||||||
printer_bed_temperature_label.config(text=bed_temp)
|
printer_bed_temperature_label.config(text=bed_temp)
|
||||||
|
|
||||||
|
|
||||||
tool_temperatures = self.__get_tool_temperatures()
|
tool_temperatures = self.__get_tool_temperatures()
|
||||||
tools_temp = "Tools: "
|
tools_temp = "Tools: "
|
||||||
|
|
||||||
|
@ -167,21 +182,29 @@ class Module(core.module.Module):
|
||||||
tools_temp += "-/- °C"
|
tools_temp += "-/- °C"
|
||||||
else:
|
else:
|
||||||
for i, tool_temperature in enumerate(tool_temperatures):
|
for i, tool_temperature in enumerate(tool_temperatures):
|
||||||
tools_temp += str(tool_temperature[0]) + "/" + str(tool_temperature[1]) + "°C"
|
tools_temp += (
|
||||||
if i != len(tool_temperatures)-1:
|
str(tool_temperature[0]) + "/" + str(tool_temperature[1]) + "°C"
|
||||||
|
)
|
||||||
|
if i != len(tool_temperatures) - 1:
|
||||||
tools_temp += "\t"
|
tools_temp += "\t"
|
||||||
tools_temperature_label.config(text=tools_temp)
|
tools_temperature_label.config(text=tools_temp)
|
||||||
|
|
||||||
root.after(500, self.__refresh_temperatures, root, printer_bed_temperature_label, tools_temperature_label)
|
root.after(
|
||||||
|
500,
|
||||||
|
self.__refresh_temperatures,
|
||||||
|
root,
|
||||||
|
printer_bed_temperature_label,
|
||||||
|
tools_temperature_label,
|
||||||
|
)
|
||||||
|
|
||||||
def __show_popup(self, widget):
|
def __show_popup(self, widget):
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.attributes('-type', 'dialog')
|
root.attributes("-type", "dialog")
|
||||||
root.title("Octoprint")
|
root.title("Octoprint")
|
||||||
frame = tk.Frame(root)
|
frame = tk.Frame(root)
|
||||||
if self.__octoprint_webcam:
|
if self.__octoprint_webcam:
|
||||||
|
|
||||||
#load first image synchronous before popup is shown, otherwise tkinter isn't able to layout popup properly
|
# load first image synchronous before popup is shown, otherwise tkinter isn't able to layout popup properly
|
||||||
img = get_frame(self.__webcam_image_url)
|
img = get_frame(self.__webcam_image_url)
|
||||||
webcam_image = ImageTk.PhotoImage(img)
|
webcam_image = ImageTk.PhotoImage(img)
|
||||||
webcam_image_container = tk.Button(frame, image=webcam_image)
|
webcam_image_container = tk.Button(frame, image=webcam_image)
|
||||||
|
@ -189,26 +212,38 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
self.__webcam_images_queue = queue.Queue()
|
self.__webcam_images_queue = queue.Queue()
|
||||||
|
|
||||||
self.__webcam_images_worker = WebcamImagesWorker(self.__webcam_image_url, self.__webcam_images_queue)
|
self.__webcam_images_worker = WebcamImagesWorker(
|
||||||
|
self.__webcam_image_url, self.__webcam_images_queue
|
||||||
|
)
|
||||||
self.__webcam_images_worker.start()
|
self.__webcam_images_worker.start()
|
||||||
else:
|
else:
|
||||||
logging.debug("Not using webcam, as webcam is disabled. Enable with --webcam.")
|
logging.debug(
|
||||||
|
"Not using webcam, as webcam is disabled. Enable with --webcam."
|
||||||
|
)
|
||||||
frame.pack()
|
frame.pack()
|
||||||
|
|
||||||
temperatures_label = tk.Label(frame, text="Temperatures", font=('', 25))
|
temperatures_label = tk.Label(frame, text="Temperatures", font=("", 25))
|
||||||
temperatures_label.pack()
|
temperatures_label.pack()
|
||||||
|
|
||||||
printer_bed_temperature_label = tk.Label(frame, text="Bed: -/- °C", font=('', 15))
|
printer_bed_temperature_label = tk.Label(
|
||||||
|
frame, text="Bed: -/- °C", font=("", 15)
|
||||||
|
)
|
||||||
printer_bed_temperature_label.pack()
|
printer_bed_temperature_label.pack()
|
||||||
|
|
||||||
tools_temperature_label = tk.Label(frame, text="Tools: -/- °C", font=('', 15))
|
tools_temperature_label = tk.Label(frame, text="Tools: -/- °C", font=("", 15))
|
||||||
tools_temperature_label.pack()
|
tools_temperature_label.pack()
|
||||||
|
|
||||||
root.after(10, self.__refresh_image, root, webcam_image, webcam_image_container)
|
root.after(10, self.__refresh_image, root, webcam_image, webcam_image_container)
|
||||||
root.after(500, self.__refresh_temperatures, root, printer_bed_temperature_label, tools_temperature_label)
|
root.after(
|
||||||
|
500,
|
||||||
|
self.__refresh_temperatures,
|
||||||
|
root,
|
||||||
|
printer_bed_temperature_label,
|
||||||
|
tools_temperature_label,
|
||||||
|
)
|
||||||
root.bind("<Destroy>", self.__on_close_popup)
|
root.bind("<Destroy>", self.__on_close_popup)
|
||||||
|
|
||||||
root.eval('tk::PlaceWindow . center')
|
root.eval("tk::PlaceWindow . center")
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
|
|
||||||
def __on_close_popup(self, event):
|
def __on_close_popup(self, event):
|
||||||
|
@ -221,4 +256,5 @@ class Module(core.module.Module):
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -20,22 +20,23 @@ import core.decorators
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
#list of repositories.
|
# list of repositories.
|
||||||
#the last one should always be other
|
# the last one should always be other
|
||||||
repos = ['core', 'extra', 'community', 'multilib', 'testing', 'other']
|
repos = ["core", "extra", "community", "multilib", "testing", "other"]
|
||||||
|
|
||||||
|
|
||||||
def get_pacman_info(widget, path):
|
def get_pacman_info(widget, path):
|
||||||
cmd = '{}/../../bin/pacman-updates'.format(path)
|
cmd = "{}/../../bin/pacman-updates".format(path)
|
||||||
if not os.path.exists(cmd):
|
if not os.path.exists(cmd):
|
||||||
cmd = '/usr/share/bumblebee-status/bin/pacman-update'
|
cmd = "/usr/share/bumblebee-status/bin/pacman-update"
|
||||||
result = util.cli.execute(cmd, ignore_errors=True)
|
result = util.cli.execute(cmd, ignore_errors=True)
|
||||||
|
|
||||||
count = len(repos)*[0]
|
count = len(repos) * [0]
|
||||||
|
|
||||||
for line in result.splitlines():
|
for line in result.splitlines():
|
||||||
if line.startswith(('http', 'rsync')):
|
if line.startswith(("http", "rsync")):
|
||||||
for i in range(len(repos)-1):
|
for i in range(len(repos) - 1):
|
||||||
if '/' + repos[i] + '/' in line:
|
if "/" + repos[i] + "/" in line:
|
||||||
count[i] += 1
|
count[i] += 1
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -43,7 +44,8 @@ def get_pacman_info(widget, path):
|
||||||
|
|
||||||
for i in range(len(repos)):
|
for i in range(len(repos)):
|
||||||
widget.set(repos[i], count[i])
|
widget.set(repos[i], count[i])
|
||||||
core.event.trigger('update', [ widget.module.id ], redraw_only=True)
|
core.event.trigger("update", [widget.module.id], redraw_only=True)
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=30)
|
@core.decorators.every(minutes=30)
|
||||||
|
@ -51,9 +53,9 @@ class Module(core.module.Module):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.updates))
|
super().__init__(config, theme, core.widget.Widget(self.updates))
|
||||||
|
|
||||||
def updates(self, widget):
|
def updates(self, widget):
|
||||||
if util.format.asbool(self.parameter('sum')):
|
if util.format.asbool(self.parameter("sum")):
|
||||||
return str(sum(map(lambda x: widget.get(x, 0), repos)))
|
return str(sum(map(lambda x: widget.get(x, 0), repos)))
|
||||||
return '/'.join(map(lambda x: str(widget.get(x, 0)), repos))
|
return "/".join(map(lambda x: str(widget.get(x, 0)), repos))
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
@ -61,11 +63,14 @@ class Module(core.module.Module):
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
weightedCount = sum(map(lambda x: (len(repos)-x[0]) * widget.get(x[1], 0), enumerate(repos)))
|
weightedCount = sum(
|
||||||
|
map(lambda x: (len(repos) - x[0]) * widget.get(x[1], 0), enumerate(repos))
|
||||||
|
)
|
||||||
|
|
||||||
if weightedCount < 10:
|
if weightedCount < 10:
|
||||||
return 'good'
|
return "good"
|
||||||
|
|
||||||
return self.threshold_state(weightedCount, 100, 150)
|
return self.threshold_state(weightedCount, 100, 150)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -12,30 +12,36 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=1)
|
@core.decorators.every(minutes=1)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.pihole_status))
|
super().__init__(config, theme, core.widget.Widget(self.pihole_status))
|
||||||
|
|
||||||
self._pihole_address = self.parameter('address', '')
|
self._pihole_address = self.parameter("address", "")
|
||||||
self._pihole_pw_hash = self.parameter('pwhash', '')
|
self._pihole_pw_hash = self.parameter("pwhash", "")
|
||||||
self._pihole_status = None
|
self._pihole_status = None
|
||||||
self._ads_blocked_today = '-'
|
self._ads_blocked_today = "-"
|
||||||
self.update_pihole_status()
|
self.update_pihole_status()
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd=self.toggle_pihole_status)
|
self, button=core.input.LEFT_MOUSE, cmd=self.toggle_pihole_status
|
||||||
|
)
|
||||||
|
|
||||||
def pihole_status(self, widget):
|
def pihole_status(self, widget):
|
||||||
if self._pihole_status is None:
|
if self._pihole_status is None:
|
||||||
return 'pi-hole unknown'
|
return "pi-hole unknown"
|
||||||
return 'pi-hole {}'.format('up {} blocked'.format(self._ads_blocked_today) if self._pihole_status else 'down')
|
return "pi-hole {}".format(
|
||||||
|
"up {} blocked".format(self._ads_blocked_today)
|
||||||
|
if self._pihole_status
|
||||||
|
else "down"
|
||||||
|
)
|
||||||
|
|
||||||
def update_pihole_status(self):
|
def update_pihole_status(self):
|
||||||
try:
|
try:
|
||||||
data = requests.get(self._pihole_address + '/admin/api.php?summary').json()
|
data = requests.get(self._pihole_address + "/admin/api.php?summary").json()
|
||||||
self._pihole_status = True if data['status'] == 'enabled' else False
|
self._pihole_status = True if data["status"] == "enabled" else False
|
||||||
self._ads_blocked_today = data['ads_blocked_today']
|
self._ads_blocked_today = data["ads_blocked_today"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._pihole_status = None
|
self._pihole_status = None
|
||||||
|
|
||||||
|
@ -44,17 +50,24 @@ class Module(core.module.Module):
|
||||||
try:
|
try:
|
||||||
req = None
|
req = None
|
||||||
if self._pihole_status:
|
if self._pihole_status:
|
||||||
req = requests.get(self._pihole_address + '/admin/api.php?disable&auth=' + self._pihole_pw_hash)
|
req = requests.get(
|
||||||
|
self._pihole_address
|
||||||
|
+ "/admin/api.php?disable&auth="
|
||||||
|
+ self._pihole_pw_hash
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
req = requests.get(self._pihole_address + '/admin/api.php?enable&auth=' + self._pihole_pw_hash)
|
req = requests.get(
|
||||||
|
self._pihole_address
|
||||||
|
+ "/admin/api.php?enable&auth="
|
||||||
|
+ self._pihole_pw_hash
|
||||||
|
)
|
||||||
if req is not None:
|
if req is not None:
|
||||||
if req.status_code == 200:
|
if req.status_code == 200:
|
||||||
status = req.json()['status']
|
status = req.json()["status"]
|
||||||
self._pihole_status = False if status == 'disabled' else True
|
self._pihole_status = False if status == "disabled" else True
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.update_pihole_status()
|
self.update_pihole_status()
|
||||||
|
|
||||||
|
@ -62,7 +75,8 @@ class Module(core.module.Module):
|
||||||
if self._pihole_status is None:
|
if self._pihole_status is None:
|
||||||
return []
|
return []
|
||||||
elif self._pihole_status:
|
elif self._pihole_status:
|
||||||
return ['enabled']
|
return ["enabled"]
|
||||||
return ['disabled', 'warning']
|
return ["disabled", "warning"]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -26,34 +26,35 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.text))
|
super().__init__(config, theme, core.widget.Widget(self.text))
|
||||||
|
|
||||||
# Parameters
|
# Parameters
|
||||||
self.__work_period = int(self.parameter('work', 25))
|
self.__work_period = int(self.parameter("work", 25))
|
||||||
self.__break_period = int(self.parameter('break', 5))
|
self.__break_period = int(self.parameter("break", 5))
|
||||||
self.__time_format = self.parameter('format', '%m:%s')
|
self.__time_format = self.parameter("format", "%m:%s")
|
||||||
self.__notify_cmd = self.parameter('notify', '')
|
self.__notify_cmd = self.parameter("notify", "")
|
||||||
|
|
||||||
# TODO: Handle time formats more gracefully. This is kludge.
|
# TODO: Handle time formats more gracefully. This is kludge.
|
||||||
self.display_seconds_p = False
|
self.display_seconds_p = False
|
||||||
self.display_minutes_p = False
|
self.display_minutes_p = False
|
||||||
if '%s' in self.__time_format:
|
if "%s" in self.__time_format:
|
||||||
self.display_seconds_p = True
|
self.display_seconds_p = True
|
||||||
if '%m' in self.__time_format:
|
if "%m" in self.__time_format:
|
||||||
self.display_minutes_p = True
|
self.display_minutes_p = True
|
||||||
|
|
||||||
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
||||||
|
|
||||||
self.time = None
|
self.time = None
|
||||||
self.pomodoro = { 'state':'OFF', 'type': ''}
|
self.pomodoro = {"state": "OFF", "type": ""}
|
||||||
self.__text = self.remaining_time_str() + self.pomodoro['type']
|
self.__text = self.remaining_time_str() + self.pomodoro["type"]
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd=self.timer_play_pause)
|
self, button=core.input.LEFT_MOUSE, cmd=self.timer_play_pause
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE,
|
)
|
||||||
cmd=self.timer_reset)
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.timer_reset)
|
||||||
|
|
||||||
def remaining_time_str(self):
|
def remaining_time_str(self):
|
||||||
if self.display_seconds_p and self.display_minutes_p:
|
if self.display_seconds_p and self.display_minutes_p:
|
||||||
|
@ -65,58 +66,62 @@ class Module(core.module.Module):
|
||||||
minutes = 0
|
minutes = 0
|
||||||
seconds = self.remaining_time.seconds
|
seconds = self.remaining_time.seconds
|
||||||
|
|
||||||
minutes = '{:2d}'.format(minutes)
|
minutes = "{:2d}".format(minutes)
|
||||||
seconds = '{:02d}'.format(seconds)
|
seconds = "{:02d}".format(seconds)
|
||||||
return self.__time_format.replace('%m',minutes).replace('%s',seconds)+' '
|
return self.__time_format.replace("%m", minutes).replace("%s", seconds) + " "
|
||||||
|
|
||||||
def text(self, widget):
|
def text(self, widget):
|
||||||
return '{}'.format(self.__text)
|
return "{}".format(self.__text)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if self.pomodoro['state'] == 'ON':
|
if self.pomodoro["state"] == "ON":
|
||||||
timediff = (datetime.datetime.now() - self.time)
|
timediff = datetime.datetime.now() - self.time
|
||||||
if timediff.seconds >= 0:
|
if timediff.seconds >= 0:
|
||||||
self.remaining_time -= timediff
|
self.remaining_time -= timediff
|
||||||
self.time = datetime.datetime.now()
|
self.time = datetime.datetime.now()
|
||||||
|
|
||||||
if self.remaining_time.total_seconds() <= 0:
|
if self.remaining_time.total_seconds() <= 0:
|
||||||
self.notify()
|
self.notify()
|
||||||
if self.pomodoro['type'] == 'Work':
|
if self.pomodoro["type"] == "Work":
|
||||||
self.pomodoro['type'] = 'Break'
|
self.pomodoro["type"] = "Break"
|
||||||
self.remaining_time = datetime.timedelta(minutes=self.__break_period)
|
self.remaining_time = datetime.timedelta(
|
||||||
elif self.pomodoro['type'] == 'Break':
|
minutes=self.__break_period
|
||||||
self.pomodoro['type'] = 'Work'
|
)
|
||||||
|
elif self.pomodoro["type"] == "Break":
|
||||||
|
self.pomodoro["type"] = "Work"
|
||||||
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
||||||
|
|
||||||
self.__text = self.remaining_time_str() + self.pomodoro['type']
|
self.__text = self.remaining_time_str() + self.pomodoro["type"]
|
||||||
|
|
||||||
def notify(self):
|
def notify(self):
|
||||||
if self.__notify_cmd:
|
if self.__notify_cmd:
|
||||||
util.cli.execute(self.__notify_cmd)
|
util.cli.execute(self.__notify_cmd)
|
||||||
|
|
||||||
def timer_play_pause(self, widget):
|
def timer_play_pause(self, widget):
|
||||||
if self.pomodoro['state'] == 'OFF':
|
if self.pomodoro["state"] == "OFF":
|
||||||
self.pomodoro = {'state': 'ON', 'type': 'Work'}
|
self.pomodoro = {"state": "ON", "type": "Work"}
|
||||||
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
||||||
self.time = datetime.datetime.now()
|
self.time = datetime.datetime.now()
|
||||||
elif self.pomodoro['state'] == 'ON':
|
elif self.pomodoro["state"] == "ON":
|
||||||
self.pomodoro['state'] = 'PAUSED'
|
self.pomodoro["state"] = "PAUSED"
|
||||||
self.remaining_time -= (datetime.datetime.now() - self.time)
|
self.remaining_time -= datetime.datetime.now() - self.time
|
||||||
self.time = datetime.datetime.now()
|
self.time = datetime.datetime.now()
|
||||||
elif self.pomodoro['state'] == 'PAUSED':
|
elif self.pomodoro["state"] == "PAUSED":
|
||||||
self.pomodoro['state'] = 'ON'
|
self.pomodoro["state"] = "ON"
|
||||||
self.time = datetime.datetime.now()
|
self.time = datetime.datetime.now()
|
||||||
|
|
||||||
def timer_reset(self, widget):
|
def timer_reset(self, widget):
|
||||||
if self.pomodoro['state'] == 'ON' or self.pomodoro['state'] == 'PAUSED':
|
if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "PAUSED":
|
||||||
self.pomodoro = {'state':'OFF', 'type': '' }
|
self.pomodoro = {"state": "OFF", "type": ""}
|
||||||
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
self.remaining_time = datetime.timedelta(minutes=self.__work_period)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
state = [];
|
state = []
|
||||||
state.append(self.pomodoro['state'].lower())
|
state.append(self.pomodoro["state"].lower())
|
||||||
if self.pomodoro['state'] == 'ON' or self.pomodoro['state'] == 'OFF':
|
if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "OFF":
|
||||||
state.append(self.pomodoro['type'].lower())
|
state.append(self.pomodoro["type"].lower())
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -31,36 +31,37 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.query))
|
super().__init__(config, theme, core.widget.Widget(self.query))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__chooseNvidia)
|
||||||
cmd=self.__chooseNvidia)
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.__chooseIntel)
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE,
|
|
||||||
cmd=self.__chooseIntel)
|
|
||||||
|
|
||||||
self.nvidiastring = self.parameter('nvidiastring', 'nv')
|
self.nvidiastring = self.parameter("nvidiastring", "nv")
|
||||||
self.intelstring = self.parameter('intelstring', 'it')
|
self.intelstring = self.parameter("intelstring", "it")
|
||||||
|
|
||||||
def __chooseNvidia(self, event):
|
def __chooseNvidia(self, event):
|
||||||
util.cli.execute('sudo prime-select nvidia')
|
util.cli.execute("sudo prime-select nvidia")
|
||||||
|
|
||||||
def __chooseIntel(self, event):
|
def __chooseIntel(self, event):
|
||||||
util.cli.execute('sudo prime-select intel')
|
util.cli.execute("sudo prime-select intel")
|
||||||
|
|
||||||
def query(self, widget):
|
def query(self, widget):
|
||||||
try:
|
try:
|
||||||
res = util.cli.execute('prime-select query')
|
res = util.cli.execute("prime-select query")
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
|
|
||||||
for line in res.split('\n'):
|
for line in res.split("\n"):
|
||||||
if not line: continue
|
if not line:
|
||||||
if 'nvidia' in line:
|
continue
|
||||||
|
if "nvidia" in line:
|
||||||
return self.nvidiastring
|
return self.nvidiastring
|
||||||
if 'intel' in line:
|
if "intel" in line:
|
||||||
return self.intelstring
|
return self.intelstring
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -21,6 +21,7 @@ import util.format
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.get_progress_text))
|
super().__init__(config, theme, core.widget.Widget(self.get_progress_text))
|
||||||
|
@ -28,33 +29,31 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def get_progress_text(self, widget):
|
def get_progress_text(self, widget):
|
||||||
if self.update_progress_info(widget):
|
if self.update_progress_info(widget):
|
||||||
width = util.format.asint(self.parameter('barwidth', 8))
|
width = util.format.asint(self.parameter("barwidth", 8))
|
||||||
count = round((width * widget.get('per')) / 100)
|
count = round((width * widget.get("per")) / 100)
|
||||||
filledchar = self.parameter('barfilledchar', '#')
|
filledchar = self.parameter("barfilledchar", "#")
|
||||||
emptychar = self.parameter('baremptychar', '-')
|
emptychar = self.parameter("baremptychar", "-")
|
||||||
|
|
||||||
bar = '[{}{}]'.format(
|
bar = "[{}{}]".format(filledchar * count, emptychar * (width - count))
|
||||||
filledchar * count,
|
|
||||||
emptychar * (width - count)
|
|
||||||
)
|
|
||||||
|
|
||||||
str_format = self.parameter('format', '{bar} {cmd} {arg}')
|
str_format = self.parameter("format", "{bar} {cmd} {arg}")
|
||||||
return str_format.format(
|
return str_format.format(
|
||||||
bar = bar,
|
bar=bar,
|
||||||
pid = widget.get('pid'),
|
pid=widget.get("pid"),
|
||||||
cmd = widget.get('cmd'),
|
cmd=widget.get("cmd"),
|
||||||
arg = widget.get('arg'),
|
arg=widget.get("arg"),
|
||||||
percentage = widget.get('per'),
|
percentage=widget.get("per"),
|
||||||
quantity = widget.get('qty'),
|
quantity=widget.get("qty"),
|
||||||
speed = widget.get('spd'),
|
speed=widget.get("spd"),
|
||||||
time = widget.get('tim')
|
time=widget.get("tim"),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return self.parameter('placeholder', 'n/a')
|
return self.parameter("placeholder", "n/a")
|
||||||
|
|
||||||
def update_progress_info(self, widget):
|
def update_progress_info(self, widget):
|
||||||
"""Update widget's informations about the copy"""
|
"""Update widget's informations about the copy"""
|
||||||
if not self.__active: return
|
if not self.__active:
|
||||||
|
return
|
||||||
|
|
||||||
# These regex extracts following groups:
|
# These regex extracts following groups:
|
||||||
# 1. pid
|
# 1. pid
|
||||||
|
@ -64,39 +63,44 @@ class Module(core.module.Module):
|
||||||
# 5. quantity (.. unit / .. unit formated)
|
# 5. quantity (.. unit / .. unit formated)
|
||||||
# 6. speed
|
# 6. speed
|
||||||
# 7. time remaining
|
# 7. time remaining
|
||||||
extract_nospeed = re.compile('\[ *(\d*)\] ([a-zA-Z]*) (.*)\n\t(\d*\.*\d*)% \((.*)\)\n.*')
|
extract_nospeed = re.compile(
|
||||||
extract_wtspeed = re.compile('\[ *(\d*)\] ([a-zA-Z]*) (.*)\n\t(\d*\.*\d*)% \((.*)\) (\d*\.\d .*) remaining (\d*:\d*:\d*)\n.*')
|
"\[ *(\d*)\] ([a-zA-Z]*) (.*)\n\t(\d*\.*\d*)% \((.*)\)\n.*"
|
||||||
|
)
|
||||||
|
extract_wtspeed = re.compile(
|
||||||
|
"\[ *(\d*)\] ([a-zA-Z]*) (.*)\n\t(\d*\.*\d*)% \((.*)\) (\d*\.\d .*) remaining (\d*:\d*:\d*)\n.*"
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
raw = util.cli.execute('progress -qW 0.1')
|
raw = util.cli.execute("progress -qW 0.1")
|
||||||
result = extract_wtspeed.match(raw)
|
result = extract_wtspeed.match(raw)
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
# Abord speed measures
|
# Abord speed measures
|
||||||
raw = util.cli.execute('progress -q')
|
raw = util.cli.execute("progress -q")
|
||||||
result = extract_nospeed.match(raw)
|
result = extract_nospeed.match(raw)
|
||||||
|
|
||||||
widget.set('spd', '???.? B/s')
|
widget.set("spd", "???.? B/s")
|
||||||
widget.set('tim', '??:??:??')
|
widget.set("tim", "??:??:??")
|
||||||
else:
|
else:
|
||||||
widget.set('spd', result.group(6))
|
widget.set("spd", result.group(6))
|
||||||
widget.set('tim', result.group(7))
|
widget.set("tim", result.group(7))
|
||||||
|
|
||||||
widget.set('pid', int(result.group(1)))
|
widget.set("pid", int(result.group(1)))
|
||||||
widget.set('cmd', result.group(2))
|
widget.set("cmd", result.group(2))
|
||||||
widget.set('arg', result.group(3))
|
widget.set("arg", result.group(3))
|
||||||
widget.set('per', float(result.group(4)))
|
widget.set("per", float(result.group(4)))
|
||||||
widget.set('qty', result.group(5))
|
widget.set("qty", result.group(5))
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__active = bool(util.cli.execute('progress -q'))
|
self.__active = bool(util.cli.execute("progress -q"))
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self.__active:
|
if self.__active:
|
||||||
return 'copying'
|
return "copying"
|
||||||
return 'pending'
|
return "pending"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -7,13 +7,13 @@ import core.decorators
|
||||||
|
|
||||||
import util.location
|
import util.location
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.public_ip))
|
super().__init__(config, theme, core.widget.Widget(self.public_ip))
|
||||||
|
|
||||||
self.__ip = ''
|
self.__ip = ""
|
||||||
|
|
||||||
|
|
||||||
def public_ip(self, widget):
|
def public_ip(self, widget):
|
||||||
return self.__ip
|
return self.__ip
|
||||||
|
@ -22,6 +22,7 @@ class Module(core.module.Module):
|
||||||
try:
|
try:
|
||||||
self.__ip = util.location.public_ip()
|
self.__ip = util.location.public_ip()
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__ip = 'n/a'
|
self.__ip = "n/a"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -12,7 +12,8 @@ import core.input
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
possible_orientations = ['normal', 'left', 'inverted', 'right']
|
possible_orientations = ["normal", "left", "inverted", "right"]
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -20,37 +21,42 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
widgets = self.widgets()
|
widgets = self.widgets()
|
||||||
for line in util.cli.execute('xrandr -q').split('\n'):
|
for line in util.cli.execute("xrandr -q").split("\n"):
|
||||||
if not ' connected' in line:
|
if not " connected" in line:
|
||||||
continue
|
continue
|
||||||
display = line.split(' ', 2)[0]
|
display = line.split(" ", 2)[0]
|
||||||
|
|
||||||
orientation = 'normal'
|
orientation = "normal"
|
||||||
for curr_orient in possible_orientations:
|
for curr_orient in possible_orientations:
|
||||||
if((line.split(' ')).count(curr_orient) > 1):
|
if (line.split(" ")).count(curr_orient) > 1:
|
||||||
orientation = curr_orient
|
orientation = curr_orient
|
||||||
break
|
break
|
||||||
|
|
||||||
widget = self.widget(display)
|
widget = self.widget(display)
|
||||||
if not widget:
|
if not widget:
|
||||||
widget = core.widget.Widget(full_text=display, name=display)
|
widget = core.widget.Widget(full_text=display, name=display)
|
||||||
core.input.register(widget, button=core.input.LEFT_MOUSE, cmd=self.__toggle)
|
core.input.register(
|
||||||
widget.set('orientation', orientation)
|
widget, button=core.input.LEFT_MOUSE, cmd=self.__toggle
|
||||||
|
)
|
||||||
|
widget.set("orientation", orientation)
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return widget.get('orientation', 'normal')
|
return widget.get("orientation", "normal")
|
||||||
|
|
||||||
def __toggle(self, event):
|
def __toggle(self, event):
|
||||||
widget = self.widget_by_id(event['instance'])
|
widget = self.widget_by_id(event["instance"])
|
||||||
|
|
||||||
# compute new orientation based on current orientation
|
# compute new orientation based on current orientation
|
||||||
idx = possible_orientations.index(widget.get('orientation'))
|
idx = possible_orientations.index(widget.get("orientation"))
|
||||||
idx = (idx + 1) % len(possible_orientations)
|
idx = (idx + 1) % len(possible_orientations)
|
||||||
new_orientation = possible_orientations[idx]
|
new_orientation = possible_orientations[idx]
|
||||||
|
|
||||||
widget.set('orientation', new_orientation)
|
widget.set("orientation", new_orientation)
|
||||||
|
|
||||||
|
util.cli.execute(
|
||||||
|
"xrandr --output {} --rotation {}".format(widget.name, new_orientation)
|
||||||
|
)
|
||||||
|
|
||||||
util.cli.execute('xrandr --output {} --rotation {}'.format(widget.name, new_orientation))
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -30,17 +30,19 @@ import core.input
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
REFRESH_DELAY = 600
|
REFRESH_DELAY = 600
|
||||||
SCROLL_SPEED = 3
|
SCROLL_SPEED = 3
|
||||||
LAYOUT_STYLES_ITEMS = [[1,1,1],[3,3,2],[2,3,3],[3,2,3]]
|
LAYOUT_STYLES_ITEMS = [[1, 1, 1], [3, 3, 2], [2, 3, 3], [3, 2, 3]]
|
||||||
HISTORY_FILENAME = '.config/i3/rss.hist'
|
HISTORY_FILENAME = ".config/i3/rss.hist"
|
||||||
|
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.ticker_update))
|
super().__init__(config, theme, core.widget.Widget(self.ticker_update))
|
||||||
|
|
||||||
self._feeds = self.parameter('feeds', 'https://www.espn.com/espn/rss/news').split(' ')
|
self._feeds = self.parameter(
|
||||||
|
"feeds", "https://www.espn.com/espn/rss/news"
|
||||||
|
).split(" ")
|
||||||
self._feeds_to_update = []
|
self._feeds_to_update = []
|
||||||
self._response = ''
|
self._response = ""
|
||||||
|
|
||||||
self._max_title_length = int(self.parameter('length', 60))
|
self._max_title_length = int(self.parameter("length", 60))
|
||||||
|
|
||||||
self._items = []
|
self._items = []
|
||||||
self._current_item = None
|
self._current_item = None
|
||||||
|
@ -51,76 +53,103 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
self._state = []
|
self._state = []
|
||||||
|
|
||||||
self._newspaper_filename = tempfile.mktemp('.html')
|
self._newspaper_filename = tempfile.mktemp(".html")
|
||||||
|
|
||||||
self._last_refresh = 0
|
self._last_refresh = 0
|
||||||
self._last_update = 0
|
self._last_update = 0
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self._open)
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self._open)
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self._create_newspaper)
|
core.input.register(
|
||||||
|
self, button=core.input.RIGHT_MOUSE, cmd=self._create_newspaper
|
||||||
|
)
|
||||||
|
|
||||||
self._history = {'ticker': {}, 'newspaper': {}}
|
self._history = {"ticker": {}, "newspaper": {}}
|
||||||
self._load_history()
|
self._load_history()
|
||||||
|
|
||||||
def _load_history(self):
|
def _load_history(self):
|
||||||
if os.path.isfile(self.HISTORY_FILENAME):
|
if os.path.isfile(self.HISTORY_FILENAME):
|
||||||
self._history = json.loads(open(self.HISTORY_FILENAME, 'r').read())
|
self._history = json.loads(open(self.HISTORY_FILENAME, "r").read())
|
||||||
|
|
||||||
def _update_history(self, group):
|
def _update_history(self, group):
|
||||||
sources = set([i['source'] for i in self._items])
|
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])
|
self._history[group] = dict(
|
||||||
|
[
|
||||||
|
[s, [i["title"] for i in self._items if i["source"] == s]]
|
||||||
|
for s in sources
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def _save_history(self):
|
def _save_history(self):
|
||||||
if not os.path.exists(os.path.dirname(self.HISTORY_FILENAME)):
|
if not os.path.exists(os.path.dirname(self.HISTORY_FILENAME)):
|
||||||
os.makedirs(os.path.dirname(self.HISTORY_FILENAME))
|
os.makedirs(os.path.dirname(self.HISTORY_FILENAME))
|
||||||
open(self.HISTORY_FILENAME, 'w').write(json.dumps(self._history))
|
open(self.HISTORY_FILENAME, "w").write(json.dumps(self._history))
|
||||||
|
|
||||||
def _check_history(self, items, group):
|
def _check_history(self, items, group):
|
||||||
for i in items:
|
for i in items:
|
||||||
i['new'] = not (i['source'] in self._history[group] and i['title'] in self._history[group][i['source']])
|
i["new"] = not (
|
||||||
|
i["source"] in self._history[group]
|
||||||
|
and i["title"] in self._history[group][i["source"]]
|
||||||
|
)
|
||||||
|
|
||||||
def _open(self, _):
|
def _open(self, _):
|
||||||
if self._current_item:
|
if self._current_item:
|
||||||
webbrowser.open(self._current_item['link'])
|
webbrowser.open(self._current_item["link"])
|
||||||
|
|
||||||
def _check_for_image(self, entry):
|
def _check_for_image(self, entry):
|
||||||
image = next(iter([l['href'] for l in entry['links'] if l['rel'] == 'enclosure']), None)
|
image = next(
|
||||||
if not image and 'media_content' in entry:
|
iter([l["href"] for l in entry["links"] if l["rel"] == "enclosure"]), None
|
||||||
|
)
|
||||||
|
if not image and "media_content" in entry:
|
||||||
try:
|
try:
|
||||||
media = sorted(entry['media_content'], key=lambda i: i['height'] if 'height' in i else 0, reverse=True)
|
media = sorted(
|
||||||
image = next(iter([i['url'] for i in media if i['medium'] == 'image']), None)
|
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:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
if not image:
|
if not image:
|
||||||
match = re.search(r"<img[^>]*src\s*=['\']*([^\s^>^'^\']*)['\']*", entry['summary'])
|
match = re.search(
|
||||||
|
r"<img[^>]*src\s*=['\']*([^\s^>^'^\']*)['\']*", entry["summary"]
|
||||||
|
)
|
||||||
if match:
|
if match:
|
||||||
image = match.group(1)
|
image = match.group(1)
|
||||||
return image if image else ''
|
return image if image else ""
|
||||||
|
|
||||||
def _remove_tags(self, txt):
|
def _remove_tags(self, txt):
|
||||||
return re.sub('<[^>]*>', '', txt)
|
return re.sub("<[^>]*>", "", txt)
|
||||||
|
|
||||||
def _create_item(self, entry, url, feed):
|
def _create_item(self, entry, url, feed):
|
||||||
return {'title': self._remove_tags(entry['title'].replace('\n', ' ')),
|
return {
|
||||||
'link': entry['link'],
|
"title": self._remove_tags(entry["title"].replace("\n", " ")),
|
||||||
'new': True,
|
"link": entry["link"],
|
||||||
'source': url,
|
"new": True,
|
||||||
'summary': self._remove_tags(entry['summary']),
|
"source": url,
|
||||||
'feed': feed,
|
"summary": self._remove_tags(entry["summary"]),
|
||||||
'image': self._check_for_image(entry),
|
"feed": feed,
|
||||||
'published': time.mktime(entry.published_parsed) if hasattr(entry, 'published_parsed') else 0}
|
"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):
|
def _update_items_from_feed(self, url):
|
||||||
parser = feedparser.parse(url)
|
parser = feedparser.parse(url)
|
||||||
new_items = [self._create_item(entry, url, parser['feed']['title']) for entry in parser['entries']]
|
new_items = [
|
||||||
|
self._create_item(entry, url, parser["feed"]["title"])
|
||||||
|
for entry in parser["entries"]
|
||||||
|
]
|
||||||
# Check history
|
# Check history
|
||||||
self._check_history(new_items, 'ticker')
|
self._check_history(new_items, "ticker")
|
||||||
# Remove the previous items
|
# Remove the previous items
|
||||||
self._items = [i for i in self._items if i['source'] != url]
|
self._items = [i for i in self._items if i["source"] != url]
|
||||||
# Add the new items
|
# Add the new items
|
||||||
self._items.extend(new_items)
|
self._items.extend(new_items)
|
||||||
# Sort the items on publish date
|
# Sort the items on publish date
|
||||||
self._items.sort(key=lambda i: i['published'], reverse=True)
|
self._items.sort(key=lambda i: i["published"], reverse=True)
|
||||||
|
|
||||||
def _check_for_refresh(self):
|
def _check_for_refresh(self):
|
||||||
if self._feeds_to_update:
|
if self._feeds_to_update:
|
||||||
|
@ -129,12 +158,12 @@ class Module(core.module.Module):
|
||||||
self._update_items_from_feed(url)
|
self._update_items_from_feed(url)
|
||||||
|
|
||||||
if not self._feeds_to_update:
|
if not self._feeds_to_update:
|
||||||
self._update_history('ticker')
|
self._update_history("ticker")
|
||||||
self._save_history()
|
self._save_history()
|
||||||
|
|
||||||
if not self._current_item:
|
if not self._current_item:
|
||||||
self._next_item()
|
self._next_item()
|
||||||
elif time.time()-self._last_refresh >= self.REFRESH_DELAY:
|
elif time.time() - self._last_refresh >= self.REFRESH_DELAY:
|
||||||
# Populate the list with feeds to update
|
# Populate the list with feeds to update
|
||||||
self._feeds_to_update = self._feeds[:]
|
self._feeds_to_update = self._feeds[:]
|
||||||
# Update the refresh time
|
# Update the refresh time
|
||||||
|
@ -149,19 +178,27 @@ class Module(core.module.Module):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Index of the current element
|
# Index of the current element
|
||||||
idx = self._items.index(self._current_item) if self._current_item in self._items else - 1
|
idx = (
|
||||||
|
self._items.index(self._current_item)
|
||||||
|
if self._current_item in self._items
|
||||||
|
else -1
|
||||||
|
)
|
||||||
|
|
||||||
# First show new items, else show next
|
# First show new items, else show next
|
||||||
new_items = [i for i in self._items if i['new']]
|
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)])
|
self._current_item = next(
|
||||||
|
iter(new_items), self._items[(idx + 1) % len(self._items)]
|
||||||
|
)
|
||||||
|
|
||||||
def _check_scroll_done(self):
|
def _check_scroll_done(self):
|
||||||
# Check if the complete title has been shown
|
# Check if the complete title has been shown
|
||||||
if self._ticker_offset + self._max_title_length > len(self._current_item['title']):
|
if self._ticker_offset + self._max_title_length > len(
|
||||||
|
self._current_item["title"]
|
||||||
|
):
|
||||||
# Do not immediately show next item after scroll
|
# Do not immediately show next item after scroll
|
||||||
self._post_delay -= 1
|
self._post_delay -= 1
|
||||||
if self._post_delay == 0:
|
if self._post_delay == 0:
|
||||||
self._current_item['new'] = False
|
self._current_item["new"] = False
|
||||||
# Mark the previous item as 'old'
|
# Mark the previous item as 'old'
|
||||||
self._next_item()
|
self._next_item()
|
||||||
else:
|
else:
|
||||||
|
@ -171,7 +208,7 @@ class Module(core.module.Module):
|
||||||
def ticker_update(self, _):
|
def ticker_update(self, _):
|
||||||
# Only update the ticker once a second
|
# Only update the ticker once a second
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now-self._last_update < 1:
|
if now - self._last_update < 1:
|
||||||
return self._response
|
return self._response
|
||||||
|
|
||||||
self._last_update = now
|
self._last_update = now
|
||||||
|
@ -180,18 +217,20 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
# If no items were retrieved, return an empty string
|
# If no items were retrieved, return an empty string
|
||||||
if not self._current_item:
|
if not self._current_item:
|
||||||
return ' '*self._max_title_length
|
return " " * self._max_title_length
|
||||||
|
|
||||||
# Prepare a substring of the item title
|
# Prepare a substring of the item title
|
||||||
self._response = self._current_item['title'][self._ticker_offset:self._ticker_offset+self._max_title_length]
|
self._response = self._current_item["title"][
|
||||||
|
self._ticker_offset : self._ticker_offset + self._max_title_length
|
||||||
|
]
|
||||||
# Add spaces if too short
|
# Add spaces if too short
|
||||||
self._response = self._response.ljust(self._max_title_length)
|
self._response = self._response.ljust(self._max_title_length)
|
||||||
|
|
||||||
# Do not immediately scroll
|
# Do not immediately scroll
|
||||||
if self._pre_delay > 0:
|
if self._pre_delay > 0:
|
||||||
# Change state during pre_delay for new items
|
# Change state during pre_delay for new items
|
||||||
if self._current_item['new']:
|
if self._current_item["new"]:
|
||||||
self._state = ['warning']
|
self._state = ["warning"]
|
||||||
self._pre_delay -= 1
|
self._pre_delay -= 1
|
||||||
return self._response
|
return self._response
|
||||||
|
|
||||||
|
@ -205,48 +244,76 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def _create_news_element(self, item, overlay_title):
|
def _create_news_element(self, item, overlay_title):
|
||||||
try:
|
try:
|
||||||
timestr = '' if item['published'] == 0 else str(time.ctime(item['published']))
|
timestr = (
|
||||||
|
"" if item["published"] == 0 else str(time.ctime(item["published"]))
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logging.error(str(exc))
|
logging.error(str(exc))
|
||||||
raise e
|
raise e
|
||||||
element = "<div class='item' onclick=window.open('"+item['link']+"')>"
|
element = "<div class='item' onclick=window.open('" + item["link"] + "')>"
|
||||||
element += "<div class='titlecontainer'>"
|
element += "<div class='titlecontainer'>"
|
||||||
element += " <img "+("" if item['image'] else "class='noimg' ")+"src='"+item['image']+"'>"
|
element += (
|
||||||
element += " <div class='title"+(" overlay" if overlay_title else "")+"'>"+("<span class='star'>★</span>" if item['new'] else "")+item['title']+"</div>"
|
" <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>"
|
||||||
element += "<div class='summary'>"+item['summary']+"</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 class='info'><span class='author'>"
|
||||||
|
+ item["feed"]
|
||||||
|
+ "</span><span class='published'>"
|
||||||
|
+ timestr
|
||||||
|
+ "</span></div>"
|
||||||
|
)
|
||||||
element += "</div>"
|
element += "</div>"
|
||||||
return element
|
return element
|
||||||
|
|
||||||
def _create_news_section(self, newspaper_items):
|
def _create_news_section(self, newspaper_items):
|
||||||
style = random.randint(0, 3)
|
style = random.randint(0, 3)
|
||||||
section = "<table><tr class='style"+str(style)+"'>"
|
section = "<table><tr class='style" + str(style) + "'>"
|
||||||
for i in range(0, 3):
|
for i in range(0, 3):
|
||||||
section += "<td><div class='itemcontainer'>"
|
section += "<td><div class='itemcontainer'>"
|
||||||
for _ in range(0, self.LAYOUT_STYLES_ITEMS[style][i]):
|
for _ in range(0, self.LAYOUT_STYLES_ITEMS[style][i]):
|
||||||
if newspaper_items:
|
if newspaper_items:
|
||||||
section += self._create_news_element(newspaper_items[0], self.LAYOUT_STYLES_ITEMS[style][i] != 3)
|
section += self._create_news_element(
|
||||||
|
newspaper_items[0], self.LAYOUT_STYLES_ITEMS[style][i] != 3
|
||||||
|
)
|
||||||
del newspaper_items[0]
|
del newspaper_items[0]
|
||||||
section += "</div></td>"
|
section += "</div></td>"
|
||||||
section += "</tr></table>"
|
section += "</tr></table>"
|
||||||
return section
|
return section
|
||||||
|
|
||||||
def _create_newspaper(self, _):
|
def _create_newspaper(self, _):
|
||||||
content = ''
|
content = ""
|
||||||
newspaper_items = self._items[:]
|
newspaper_items = self._items[:]
|
||||||
self._check_history(newspaper_items, 'newspaper')
|
self._check_history(newspaper_items, "newspaper")
|
||||||
|
|
||||||
# Make sure new items are always listed first, independent of publish date
|
# 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)
|
newspaper_items.sort(
|
||||||
|
key=lambda i: i["published"] + (10000000 if i["new"] else 0), reverse=True
|
||||||
|
)
|
||||||
|
|
||||||
while newspaper_items:
|
while newspaper_items:
|
||||||
content += self._create_news_section(newspaper_items)
|
content += self._create_news_section(newspaper_items)
|
||||||
open(self._newspaper_filename, 'w').write(HTML_TEMPLATE.replace('[[CONTENT]]', content))
|
open(self._newspaper_filename, "w").write(
|
||||||
webbrowser.open('file://'+self._newspaper_filename)
|
HTML_TEMPLATE.replace("[[CONTENT]]", content)
|
||||||
self._update_history('newspaper')
|
)
|
||||||
|
webbrowser.open("file://" + self._newspaper_filename)
|
||||||
|
self._update_history("newspaper")
|
||||||
self._save_history()
|
self._save_history()
|
||||||
|
|
||||||
|
|
||||||
HTML_TEMPLATE = """<!DOCTYPE html>
|
HTML_TEMPLATE = """<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|
|
@ -27,105 +27,119 @@ import core.input
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.temperature))
|
super().__init__(config, theme, core.widget.Widget(self.temperature))
|
||||||
|
|
||||||
self._temperature = 'unknown'
|
self._temperature = "unknown"
|
||||||
self._mhz = 'n/a'
|
self._mhz = "n/a"
|
||||||
self._match_number = int(self.parameter('match_number', '-1'))
|
self._match_number = int(self.parameter("match_number", "-1"))
|
||||||
self._match_pattern = self.parameter('match_pattern', None)
|
self._match_pattern = self.parameter("match_pattern", None)
|
||||||
self._pattern = re.compile(r'^\s*{}:\s*([\d.]+)$'.format(self.parameter('match', 'temp1_input')), re.MULTILINE)
|
self._pattern = re.compile(
|
||||||
self._json = util.format.asbool(self.parameter('json', False))
|
r"^\s*{}:\s*([\d.]+)$".format(self.parameter("match", "temp1_input")),
|
||||||
self._freq = util.format.asbool(self.parameter('show_freq', True))
|
re.MULTILINE,
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd='xsensors')
|
)
|
||||||
|
self._json = util.format.asbool(self.parameter("json", False))
|
||||||
|
self._freq = util.format.asbool(self.parameter("show_freq", True))
|
||||||
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd="xsensors")
|
||||||
self.determine_method()
|
self.determine_method()
|
||||||
|
|
||||||
def determine_method(self):
|
def determine_method(self):
|
||||||
if self.parameter('path') != None and self._json == False:
|
if self.parameter("path") != None and self._json == False:
|
||||||
self.use_sensors = False # use thermal zone
|
self.use_sensors = False # use thermal zone
|
||||||
else:
|
else:
|
||||||
# try to use output of sensors -u
|
# try to use output of sensors -u
|
||||||
try:
|
try:
|
||||||
output = util.cli.execute('sensors -u')
|
output = util.cli.execute("sensors -u")
|
||||||
self.use_sensors = True
|
self.use_sensors = True
|
||||||
log.debug('Sensors command available')
|
log.debug("Sensors command available")
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
log.info('Sensors command not available, using /sys/class/thermal/thermal_zone*/')
|
log.info(
|
||||||
|
"Sensors command not available, using /sys/class/thermal/thermal_zone*/"
|
||||||
|
)
|
||||||
self.use_sensors = False
|
self.use_sensors = False
|
||||||
|
|
||||||
def _get_temp_from_sensors(self):
|
def _get_temp_from_sensors(self):
|
||||||
if self._json == True:
|
if self._json == True:
|
||||||
try:
|
try:
|
||||||
output = json.loads(util.cli.execute('sensors -j'))
|
output = json.loads(util.cli.execute("sensors -j"))
|
||||||
for key in self.parameter('path').split('/'):
|
for key in self.parameter("path").split("/"):
|
||||||
output = output[key]
|
output = output[key]
|
||||||
return int(float(output))
|
return int(float(output))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error('unable to read sensors: {}'.format(str(e)))
|
logging.error("unable to read sensors: {}".format(str(e)))
|
||||||
return 'unknown'
|
return "unknown"
|
||||||
else:
|
else:
|
||||||
output = util.cli.execute('sensors -u')
|
output = util.cli.execute("sensors -u")
|
||||||
if self._match_pattern:
|
if self._match_pattern:
|
||||||
temp_pattern = self.parameter('match', 'temp1_input')
|
temp_pattern = self.parameter("match", "temp1_input")
|
||||||
match = re.search(r'{}.+{}:\s*([\d.]+)$'.format(self._match_pattern, temp_pattern), output.replace('\n', ''))
|
match = re.search(
|
||||||
|
r"{}.+{}:\s*([\d.]+)$".format(self._match_pattern, temp_pattern),
|
||||||
|
output.replace("\n", ""),
|
||||||
|
)
|
||||||
if match:
|
if match:
|
||||||
return int(float(match.group(1)))
|
return int(float(match.group(1)))
|
||||||
else:
|
else:
|
||||||
return 'unknown'
|
return "unknown"
|
||||||
match = self._pattern.findall(output)
|
match = self._pattern.findall(output)
|
||||||
if match:
|
if match:
|
||||||
return int(float(match[self._match_number]))
|
return int(float(match[self._match_number]))
|
||||||
return 'unknown'
|
return "unknown"
|
||||||
|
|
||||||
def get_temp(self):
|
def get_temp(self):
|
||||||
if self.use_sensors:
|
if self.use_sensors:
|
||||||
temperature = self._get_temp_from_sensors()
|
temperature = self._get_temp_from_sensors()
|
||||||
log.debug('Retrieve temperature from sensors -u')
|
log.debug("Retrieve temperature from sensors -u")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
temperature = open(self.parameter('path', '/sys/class/thermal/thermal_zone0/temp')).read()[:2]
|
temperature = open(
|
||||||
log.debug('retrieved temperature from /sys/class/')
|
self.parameter("path", "/sys/class/thermal/thermal_zone0/temp")
|
||||||
|
).read()[:2]
|
||||||
|
log.debug("retrieved temperature from /sys/class/")
|
||||||
# TODO: Iterate through all thermal zones to determine the correct one and use its value
|
# TODO: Iterate through all thermal zones to determine the correct one and use its value
|
||||||
# https://unix.stackexchange.com/questions/304845/discrepancy-between-number-of-cores-and-thermal-zones-in-sys-class-thermal
|
# https://unix.stackexchange.com/questions/304845/discrepancy-between-number-of-cores-and-thermal-zones-in-sys-class-thermal
|
||||||
|
|
||||||
except IOError:
|
except IOError:
|
||||||
temperature = 'unknown'
|
temperature = "unknown"
|
||||||
log.info('Can not determine temperature, please install lm-sensors')
|
log.info("Can not determine temperature, please install lm-sensors")
|
||||||
|
|
||||||
return temperature
|
return temperature
|
||||||
|
|
||||||
def get_mhz(self):
|
def get_mhz(self):
|
||||||
mhz = None
|
mhz = None
|
||||||
try:
|
try:
|
||||||
output = open('/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq').read()
|
output = open(
|
||||||
mhz = int(float(output)/1000.0)
|
"/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq"
|
||||||
|
).read()
|
||||||
|
mhz = int(float(output) / 1000.0)
|
||||||
except:
|
except:
|
||||||
output = open('/proc/cpuinfo').read()
|
output = open("/proc/cpuinfo").read()
|
||||||
m = re.search(r'cpu MHz\s+:\s+(\d+)', output)
|
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
||||||
if m:
|
if m:
|
||||||
mhz = int(m.group(1))
|
mhz = int(m.group(1))
|
||||||
else:
|
else:
|
||||||
m = re.search(r'BogoMIPS\s+:\s+(\d+)', output)
|
m = re.search(r"BogoMIPS\s+:\s+(\d+)", output)
|
||||||
if m:
|
if m:
|
||||||
return '{} BogoMIPS'.format(int(m.group(1)))
|
return "{} BogoMIPS".format(int(m.group(1)))
|
||||||
if not mhz:
|
if not mhz:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
|
|
||||||
if mhz < 1000:
|
if mhz < 1000:
|
||||||
return '{} MHz'.format(mhz)
|
return "{} MHz".format(mhz)
|
||||||
else:
|
else:
|
||||||
return '{:0.01f} GHz'.format(float(mhz)/1000.0)
|
return "{:0.01f} GHz".format(float(mhz) / 1000.0)
|
||||||
|
|
||||||
def temperature(self, _):
|
def temperature(self, _):
|
||||||
if self._freq:
|
if self._freq:
|
||||||
return u'{}°c @ {}'.format(self._temperature, self._mhz)
|
return "{}°c @ {}".format(self._temperature, self._mhz)
|
||||||
else:
|
else:
|
||||||
return u'{}°c'.format(self._temperature)
|
return "{}°c".format(self._temperature)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self._temperature = self.get_temp()
|
self._temperature = self.get_temp()
|
||||||
if self._freq:
|
if self._freq:
|
||||||
self._mhz = self.get_mhz()
|
self._mhz = self.get_mhz()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -33,15 +33,16 @@ import core.input
|
||||||
import util.format
|
import util.format
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.get_output))
|
super().__init__(config, theme, core.widget.Widget(self.get_output))
|
||||||
|
|
||||||
self.__command = self.parameter('command', 'echo "no command configured"')
|
self.__command = self.parameter("command", 'echo "no command configured"')
|
||||||
self.__async = util.format.asbool(self.parameter('async'))
|
self.__async = util.format.asbool(self.parameter("async"))
|
||||||
|
|
||||||
if self.__async:
|
if self.__async:
|
||||||
self.__output = 'please wait...'
|
self.__output = "please wait..."
|
||||||
self.__current_thread = threading.Thread()
|
self.__current_thread = threading.Thread()
|
||||||
|
|
||||||
# LMB and RMB will update output regardless of timer
|
# LMB and RMB will update output regardless of timer
|
||||||
|
@ -66,13 +67,16 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
# spawn new thread to execute command and pass callback method to get output from it
|
# spawn new thread to execute command and pass callback method to get output from it
|
||||||
self.__current_thread = threading.Thread(
|
self.__current_thread = threading.Thread(
|
||||||
target=lambda obj, cmd: obj.set_output(util.cli.execute(cmd, ignore_errors=True)),
|
target=lambda obj, cmd: obj.set_output(
|
||||||
args=(self, self.__command)
|
util.cli.execute(cmd, ignore_errors=True)
|
||||||
|
),
|
||||||
|
args=(self, self.__command),
|
||||||
)
|
)
|
||||||
self.__current_thread.start()
|
self.__current_thread.start()
|
||||||
|
|
||||||
def state(self, _):
|
def state(self, _):
|
||||||
if self.__output == 'no command configured':
|
if self.__output == "no command configured":
|
||||||
return 'warning'
|
return "warning"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -19,22 +19,23 @@ Parameters:
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
LINK = 'https://github.com/tobi-wan-kenobi/bumblebee-status/wiki'
|
LINK = "https://github.com/tobi-wan-kenobi/bumblebee-status/wiki"
|
||||||
LABEL = 'Click me'
|
LABEL = "Click me"
|
||||||
|
|
||||||
import core.module
|
import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self.__labels = self.parameter('labels', '{}'.format(LABEL))
|
self.__labels = self.parameter("labels", "{}".format(LABEL))
|
||||||
self.__cmds = self.parameter('cmds', 'firefox {}'.format(LINK))
|
self.__cmds = self.parameter("cmds", "firefox {}".format(LINK))
|
||||||
self.__delim = self.parameter('delim', ';')
|
self.__delim = self.parameter("delim", ";")
|
||||||
|
|
||||||
self.update_widgets()
|
self.update_widgets()
|
||||||
|
|
||||||
|
@ -51,9 +52,11 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
# report possible problem as a warning
|
# report possible problem as a warning
|
||||||
if len(cmds) is not len(labels):
|
if len(cmds) is not len(labels):
|
||||||
logging.warning('shortcut: the number of commands does not match '\
|
logging.warning(
|
||||||
'the number of provided labels.')
|
"shortcut: the number of commands does not match "
|
||||||
logging.warning('cmds : %s, labels : %s', cmds, labels)
|
"the number of provided labels."
|
||||||
|
)
|
||||||
|
logging.warning("cmds : %s, labels : %s", cmds, labels)
|
||||||
|
|
||||||
for idx in range(0, num_shortcuts):
|
for idx in range(0, num_shortcuts):
|
||||||
cmd = cmds[idx]
|
cmd = cmds[idx]
|
||||||
|
@ -64,4 +67,5 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -20,99 +20,107 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=5)
|
@core.decorators.every(minutes=5)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self.devices = self.list_devices()
|
self.devices = self.list_devices()
|
||||||
self.display = self.parameter('display', 'combined')
|
self.display = self.parameter("display", "combined")
|
||||||
self.drives = self.parameter('drives', 'sda')
|
self.drives = self.parameter("drives", "sda")
|
||||||
self.widgets(self.create_widgets())
|
self.widgets(self.create_widgets())
|
||||||
|
|
||||||
def create_widgets(self):
|
def create_widgets(self):
|
||||||
widgets = []
|
widgets = []
|
||||||
if self.display == 'combined':
|
if self.display == "combined":
|
||||||
widget = core.widget.Widget(module=self)
|
widget = core.widget.Widget(module=self)
|
||||||
widget.set('device', 'combined')
|
widget.set("device", "combined")
|
||||||
widget.set('assessment', self.combined())
|
widget.set("assessment", self.combined())
|
||||||
self.output(widget)
|
self.output(widget)
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
else:
|
else:
|
||||||
for device in self.devices:
|
for device in self.devices:
|
||||||
if self.display == 'singles' and device not in self.drives:
|
if self.display == "singles" and device not in self.drives:
|
||||||
continue
|
continue
|
||||||
widget = core.widget.Widget(module=self)
|
widget = core.widget.Widget(module=self)
|
||||||
widget.set('device', device)
|
widget.set("device", device)
|
||||||
widget.set('assessment', self.smart(device))
|
widget.set("assessment", self.smart(device))
|
||||||
self.output(widget)
|
self.output(widget)
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
return widgets
|
return widgets
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
for widget in self.widgets():
|
for widget in self.widgets():
|
||||||
device = widget.get('device')
|
device = widget.get("device")
|
||||||
if device == 'combined':
|
if device == "combined":
|
||||||
widget.set('assessment', self.combined())
|
widget.set("assessment", self.combined())
|
||||||
self.output(widget)
|
self.output(widget)
|
||||||
else:
|
else:
|
||||||
widget.set('assessment', self.smart(device))
|
widget.set("assessment", self.smart(device))
|
||||||
self.output(widget)
|
self.output(widget)
|
||||||
|
|
||||||
def output(self, widget):
|
def output(self, widget):
|
||||||
device = widget.get('device')
|
device = widget.get("device")
|
||||||
assessment = widget.get('assessment')
|
assessment = widget.get("assessment")
|
||||||
widget.full_text('{}: {}'.format(device, assessment))
|
widget.full_text("{}: {}".format(device, assessment))
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
states = []
|
states = []
|
||||||
assessment = widget.get('assessment')
|
assessment = widget.get("assessment")
|
||||||
if assessment == 'Pre-fail':
|
if assessment == "Pre-fail":
|
||||||
states.append('warning')
|
states.append("warning")
|
||||||
if assessment == 'Fail':
|
if assessment == "Fail":
|
||||||
states.append('critical')
|
states.append("critical")
|
||||||
return states
|
return states
|
||||||
|
|
||||||
def combined(self):
|
def combined(self):
|
||||||
for device in self.devices:
|
for device in self.devices:
|
||||||
result = self.smart(device)
|
result = self.smart(device)
|
||||||
if result == 'Fail':
|
if result == "Fail":
|
||||||
return 'Fail'
|
return "Fail"
|
||||||
if result == 'Pre-fail':
|
if result == "Pre-fail":
|
||||||
return 'Pre-fail'
|
return "Pre-fail"
|
||||||
return 'OK'
|
return "OK"
|
||||||
|
|
||||||
def list_devices(self):
|
def list_devices(self):
|
||||||
for (root, folders, files) in os.walk('/dev'):
|
for (root, folders, files) in os.walk("/dev"):
|
||||||
if root == '/dev':
|
if root == "/dev":
|
||||||
devices = {''.join(filter(lambda i: i.isdigit() == False, file)) for file in files if 'sd' in file}
|
devices = {
|
||||||
nvme = {file for file in files if('nvme0n' in file and 'p' not in file)}
|
"".join(filter(lambda i: i.isdigit() == False, file))
|
||||||
|
for file in files
|
||||||
|
if "sd" in file
|
||||||
|
}
|
||||||
|
nvme = {
|
||||||
|
file for file in files if ("nvme0n" in file and "p" not in file)
|
||||||
|
}
|
||||||
devices.update(nvme)
|
devices.update(nvme)
|
||||||
return devices
|
return devices
|
||||||
|
|
||||||
def smart(self, disk_name):
|
def smart(self, disk_name):
|
||||||
smartctl = shutil.which('smartctl')
|
smartctl = shutil.which("smartctl")
|
||||||
assessment = None
|
assessment = None
|
||||||
|
|
||||||
output = util.cli.execute('sudo {} --health {}'.format(
|
output = util.cli.execute(
|
||||||
smartctl, os.path.join('/dev/', disk_name)
|
"sudo {} --health {}".format(smartctl, os.path.join("/dev/", disk_name))
|
||||||
))
|
)
|
||||||
output = output.split('\n')
|
output = output.split("\n")
|
||||||
line = output[4]
|
line = output[4]
|
||||||
if 'SMART' in line:
|
if "SMART" in line:
|
||||||
if any([i in line for i in ['PASSED', 'OK']]):
|
if any([i in line for i in ["PASSED", "OK"]]):
|
||||||
assessment = 'OK'
|
assessment = "OK"
|
||||||
else:
|
else:
|
||||||
assessment = 'Fail'
|
assessment = "Fail"
|
||||||
|
|
||||||
if assessment == 'OK':
|
if assessment == "OK":
|
||||||
output = util.cli.execute('sudo {} -A {}'.format(
|
output = util.cli.execute(
|
||||||
smartctl, os.path.join('/dev/', disk_name)
|
"sudo {} -A {}".format(smartctl, os.path.join("/dev/", disk_name))
|
||||||
))
|
)
|
||||||
output = output.split('\n')
|
output = output.split("\n")
|
||||||
for line in output:
|
for line in output:
|
||||||
if 'Pre-fail' in line:
|
if "Pre-fail" in line:
|
||||||
assessment = 'Pre-fail'
|
assessment = "Pre-fail"
|
||||||
return assessment
|
return assessment
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -36,6 +36,7 @@ import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
def formatStringBuilder(s, json):
|
def formatStringBuilder(s, json):
|
||||||
"""
|
"""
|
||||||
Parses Format Strings
|
Parses Format Strings
|
||||||
|
@ -43,14 +44,14 @@ def formatStringBuilder(s, json):
|
||||||
s -> format string
|
s -> format string
|
||||||
json -> the spaceapi response object
|
json -> the spaceapi response object
|
||||||
"""
|
"""
|
||||||
identifiers = re.findall('%%.*?%%', s)
|
identifiers = re.findall("%%.*?%%", s)
|
||||||
for i in identifiers:
|
for i in identifiers:
|
||||||
ic = i[2:-2] # Discard %%
|
ic = i[2:-2] # Discard %%
|
||||||
j = ic.split('%')
|
j = ic.split("%")
|
||||||
|
|
||||||
# Only neither of, or both true AND false may be overwritten
|
# Only neither of, or both true AND false may be overwritten
|
||||||
if len(j) != 3 and len(j) != 1:
|
if len(j) != 3 and len(j) != 1:
|
||||||
return 'INVALID FORMAT STRING'
|
return "INVALID FORMAT STRING"
|
||||||
|
|
||||||
if len(j) == 1: # no overwrite
|
if len(j) == 1: # no overwrite
|
||||||
s = s.replace(i, json[j[0]])
|
s = s.replace(i, json[j[0]])
|
||||||
|
@ -66,30 +67,28 @@ class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.getState))
|
super().__init__(config, theme, core.widget.Widget(self.getState))
|
||||||
|
|
||||||
core.input.register(
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__forceReload)
|
||||||
self, button=core.input.LEFT_MOUSE, cmd=self.__forceReload
|
|
||||||
)
|
|
||||||
|
|
||||||
self.__data = {}
|
self.__data = {}
|
||||||
self.__error = None
|
self.__error = None
|
||||||
self.__thread = None
|
self.__thread = None
|
||||||
|
|
||||||
# The URL representing the api endpoint
|
# The URL representing the api endpoint
|
||||||
self.__url = self.parameter('url', default='http://club.entropia.de/spaceapi')
|
self.__url = self.parameter("url", default="http://club.entropia.de/spaceapi")
|
||||||
self._format = self.parameter(
|
self._format = self.parameter(
|
||||||
'format', default=u' %%space%%: %%state.open%Open%Closed%%'
|
"format", default=" %%space%%: %%state.open%Open%Closed%%"
|
||||||
)
|
)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
try:
|
try:
|
||||||
if self.__error is not None:
|
if self.__error is not None:
|
||||||
return ['critical']
|
return ["critical"]
|
||||||
elif self.__data['state.open']:
|
elif self.__data["state.open"]:
|
||||||
return ['warning']
|
return ["warning"]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return ['critical']
|
return ["critical"]
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if not self.__thread or self.__thread.is_alive() == False:
|
if not self.__thread or self.__thread.is_alive() == False:
|
||||||
|
@ -104,7 +103,7 @@ class Module(core.module.Module):
|
||||||
try:
|
try:
|
||||||
text = formatStringBuilder(self._format, self.__data)
|
text = formatStringBuilder(self._format, self.__data)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
text = 'KeyError'
|
text = "KeyError"
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def get_api_async(self):
|
def get_api_async(self):
|
||||||
|
@ -115,19 +114,19 @@ class Module(core.module.Module):
|
||||||
self.__data = self.__flatten(json.loads(request.text))
|
self.__data = self.__flatten(json.loads(request.text))
|
||||||
self.__error = None
|
self.__error = None
|
||||||
except requests.exceptions.Timeout:
|
except requests.exceptions.Timeout:
|
||||||
self.__error = 'Timeout'
|
self.__error = "Timeout"
|
||||||
except requests.exceptions.HTTPError:
|
except requests.exceptions.HTTPError:
|
||||||
self.__error = 'HTTP Error'
|
self.__error = "HTTP Error"
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.__error = 'Not a JSON response'
|
self.__error = "Not a JSON response"
|
||||||
core.event.trigger('update', [ self.id ], redraw_only=True)
|
core.event.trigger("update", [self.id], redraw_only=True)
|
||||||
|
|
||||||
# left_mouse_button handler
|
# left_mouse_button handler
|
||||||
def __forceReload(self, event):
|
def __forceReload(self, event):
|
||||||
if self.__thread:
|
if self.__thread:
|
||||||
self.__thread.raise_exception()
|
self.__thread.raise_exception()
|
||||||
self.__error = 'RELOADING'
|
self.__error = "RELOADING"
|
||||||
core.event.trigger('update', [ self.id ], redraw_only=True)
|
core.event.trigger("update", [self.id], redraw_only=True)
|
||||||
|
|
||||||
# Flattens the JSON structure recursively, e.g. ['space']['open']
|
# Flattens the JSON structure recursively, e.g. ['space']['open']
|
||||||
# becomes ['space.open']
|
# becomes ['space.open']
|
||||||
|
@ -138,7 +137,7 @@ class Module(core.module.Module):
|
||||||
if type(value) is dict:
|
if type(value) is dict:
|
||||||
flattened_key = self.__flatten(value)
|
flattened_key = self.__flatten(value)
|
||||||
for fk in flattened_key:
|
for fk in flattened_key:
|
||||||
out[key + '.' + fk] = flattened_key[fk]
|
out[key + "." + fk] = flattened_key[fk]
|
||||||
else:
|
else:
|
||||||
out[key] = value
|
out[key] = value
|
||||||
return out
|
return out
|
||||||
|
|
|
@ -21,54 +21,63 @@ import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.spotify))
|
super().__init__(config, theme, core.widget.Widget(self.spotify))
|
||||||
|
|
||||||
buttons = {'LEFT_CLICK':core.input.LEFT_MOUSE,
|
buttons = {
|
||||||
'RIGHT_CLICK':core.input.RIGHT_MOUSE,
|
"LEFT_CLICK": core.input.LEFT_MOUSE,
|
||||||
'MIDDLE_CLICK':core.input.MIDDLE_MOUSE,
|
"RIGHT_CLICK": core.input.RIGHT_MOUSE,
|
||||||
'SCROLL_UP':core.input.WHEEL_UP,
|
"MIDDLE_CLICK": core.input.MIDDLE_MOUSE,
|
||||||
'SCROLL_DOWN':core.input.WHEEL_DOWN,
|
"SCROLL_UP": core.input.WHEEL_UP,
|
||||||
}
|
"SCROLL_DOWN": core.input.WHEEL_DOWN,
|
||||||
|
}
|
||||||
|
|
||||||
self.__song = ''
|
self.__song = ""
|
||||||
self.__format = self.parameter('format', '{artist} - {title}')
|
self.__format = self.parameter("format", "{artist} - {title}")
|
||||||
prev_button = self.parameter('previous', 'LEFT_CLICK')
|
prev_button = self.parameter("previous", "LEFT_CLICK")
|
||||||
next_button = self.parameter('next', 'RIGHT_CLICK')
|
next_button = self.parameter("next", "RIGHT_CLICK")
|
||||||
pause_button = self.parameter('pause', 'MIDDLE_CLICK')
|
pause_button = self.parameter("pause", "MIDDLE_CLICK")
|
||||||
|
|
||||||
cmd = 'dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.spotify \
|
cmd = "dbus-send --session --type=method_call --dest=org.mpris.MediaPlayer2.spotify \
|
||||||
/org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.'
|
/org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player."
|
||||||
core.input.register(self, button=buttons[prev_button],
|
core.input.register(self, button=buttons[prev_button], cmd=cmd + "Previous")
|
||||||
cmd=cmd + 'Previous')
|
core.input.register(self, button=buttons[next_button], cmd=cmd + "Next")
|
||||||
core.input.register(self, button=buttons[next_button],
|
core.input.register(self, button=buttons[pause_button], cmd=cmd + "PlayPause")
|
||||||
cmd=cmd + 'Next')
|
|
||||||
core.input.register(self, button=buttons[pause_button],
|
|
||||||
cmd=cmd + 'PlayPause')
|
|
||||||
|
|
||||||
@core.decorators.scrollable
|
@core.decorators.scrollable
|
||||||
def spotify(self, widget):
|
def spotify(self, widget):
|
||||||
return self.string_song
|
return self.string_song
|
||||||
|
|
||||||
def hidden(self):
|
def hidden(self):
|
||||||
return self.string_song == ''
|
return self.string_song == ""
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
bus = dbus.SessionBus()
|
bus = dbus.SessionBus()
|
||||||
spotify = bus.get_object('org.mpris.MediaPlayer2.spotify', '/org/mpris/MediaPlayer2')
|
spotify = bus.get_object(
|
||||||
spotify_iface = dbus.Interface(spotify, 'org.freedesktop.DBus.Properties')
|
"org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2"
|
||||||
props = spotify_iface.Get('org.mpris.MediaPlayer2.Player', 'Metadata')
|
)
|
||||||
playback_status = str(spotify_iface.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus'))
|
spotify_iface = dbus.Interface(spotify, "org.freedesktop.DBus.Properties")
|
||||||
self.__song = self.__format.format(album=str(props.get('xesam:album')),
|
props = spotify_iface.Get("org.mpris.MediaPlayer2.Player", "Metadata")
|
||||||
title=str(props.get('xesam:title')),
|
playback_status = str(
|
||||||
artist=','.join(props.get('xesam:artist')),
|
spotify_iface.Get("org.mpris.MediaPlayer2.Player", "PlaybackStatus")
|
||||||
trackNumber=str(props.get('xesam:trackNumber')),
|
)
|
||||||
playbackStatus=u'\u25B6' if playback_status=='Playing' else u'\u258D\u258D' if playback_status=='Paused' else '',)
|
self.__song = self.__format.format(
|
||||||
|
album=str(props.get("xesam:album")),
|
||||||
|
title=str(props.get("xesam:title")),
|
||||||
|
artist=",".join(props.get("xesam:artist")),
|
||||||
|
trackNumber=str(props.get("xesam:trackNumber")),
|
||||||
|
playbackStatus="\u25B6"
|
||||||
|
if playback_status == "Playing"
|
||||||
|
else "\u258D\u258D"
|
||||||
|
if playback_status == "Paused"
|
||||||
|
else "",
|
||||||
|
)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__song = ''
|
self.__song = ""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def string_song(self):
|
def string_song(self):
|
||||||
|
@ -76,4 +85,5 @@ class Module(core.module.Module):
|
||||||
return unicode(self.__song)
|
return unicode(self.__song)
|
||||||
return str(self.__song)
|
return str(self.__song)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -22,39 +22,44 @@ import core.decorators
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(hours=1)
|
@core.decorators.every(hours=1)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.value))
|
super().__init__(config, theme, core.widget.Widget(self.value))
|
||||||
|
|
||||||
self.__symbols = self.parameter('symbols', '')
|
self.__symbols = self.parameter("symbols", "")
|
||||||
self.__change = util.format.asbool(self.parameter('change', True))
|
self.__change = util.format.asbool(self.parameter("change", True))
|
||||||
self.__value = None
|
self.__value = None
|
||||||
|
|
||||||
def value(self, widget):
|
def value(self, widget):
|
||||||
results = []
|
results = []
|
||||||
if not self.__value:
|
if not self.__value:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
data = json.loads(self.__value)
|
data = json.loads(self.__value)
|
||||||
|
|
||||||
for symbol in data['quoteResponse']['result']:
|
for symbol in data["quoteResponse"]["result"]:
|
||||||
valkey = 'regularMarketChange' if self.__change else 'regularMarketPrice'
|
valkey = "regularMarketChange" if self.__change else "regularMarketPrice"
|
||||||
sym = symbol.get('symbol', 'n/a')
|
sym = symbol.get("symbol", "n/a")
|
||||||
currency = symbol.get('currency', 'USD')
|
currency = symbol.get("currency", "USD")
|
||||||
val = 'n/a' if not valkey in symbol else '{:.2f}'.format(symbol[valkey])
|
val = "n/a" if not valkey in symbol else "{:.2f}".format(symbol[valkey])
|
||||||
results.append('{} {} {}'.format(sym, val, currency))
|
results.append("{} {} {}".format(sym, val, currency))
|
||||||
return u' '.join(results)
|
return " ".join(results)
|
||||||
|
|
||||||
def fetch(self):
|
def fetch(self):
|
||||||
if self.__symbols:
|
if self.__symbols:
|
||||||
url = 'https://query1.finance.yahoo.com/v7/finance/quote?symbols='
|
url = "https://query1.finance.yahoo.com/v7/finance/quote?symbols="
|
||||||
url += self.__symbols + '&fields=regularMarketPrice,currency,regularMarketChange'
|
url += (
|
||||||
|
self.__symbols
|
||||||
|
+ "&fields=regularMarketPrice,currency,regularMarketChange"
|
||||||
|
)
|
||||||
return urllib.request.urlopen(url).read().strip()
|
return urllib.request.urlopen(url).read().strip()
|
||||||
else:
|
else:
|
||||||
logging.error('unable to retrieve stock exchange rate')
|
logging.error("unable to retrieve stock exchange rate")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__value = self.fetch()
|
self.__value = self.fetch()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -23,13 +23,14 @@ import core.decorators
|
||||||
|
|
||||||
import util.location
|
import util.location
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(hours=1)
|
@core.decorators.every(hours=1)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.suntimes))
|
super().__init__(config, theme, core.widget.Widget(self.suntimes))
|
||||||
|
|
||||||
lat = self.parameter('lat', None)
|
lat = self.parameter("lat", None)
|
||||||
lon = self.parameter('lon', None)
|
lon = self.parameter("lon", None)
|
||||||
self.__sun = None
|
self.__sun = None
|
||||||
|
|
||||||
if not lat or not lon:
|
if not lat or not lon:
|
||||||
|
@ -40,12 +41,13 @@ class Module(core.module.Module):
|
||||||
def suntimes(self, _):
|
def suntimes(self, _):
|
||||||
if self.__sunset and self.__sunrise:
|
if self.__sunset and self.__sunrise:
|
||||||
if self.__isup:
|
if self.__isup:
|
||||||
return u'\u21A7{} \u21A5{}'.format(
|
return "\u21A7{} \u21A5{}".format(
|
||||||
self.__sunset.strftime('%H:%M'),
|
self.__sunset.strftime("%H:%M"), self.__sunrise.strftime("%H:%M")
|
||||||
self.__sunrise.strftime('%H:%M'))
|
)
|
||||||
return u'\u21A5{} \u21A7{}'.format(self.__sunrise.strftime('%H:%M'),
|
return "\u21A5{} \u21A7{}".format(
|
||||||
self.__sunset.strftime('%H:%M'))
|
self.__sunrise.strftime("%H:%M"), self.__sunset.strftime("%H:%M")
|
||||||
return 'n/a'
|
)
|
||||||
|
return "n/a"
|
||||||
|
|
||||||
def __calculate_times(self):
|
def __calculate_times(self):
|
||||||
self.__isup = False
|
self.__isup = False
|
||||||
|
@ -55,13 +57,13 @@ class Module(core.module.Module):
|
||||||
try:
|
try:
|
||||||
self.__sunrise = self.__sun.get_local_sunrise_time()
|
self.__sunrise = self.__sun.get_local_sunrise_time()
|
||||||
except SunTimeException:
|
except SunTimeException:
|
||||||
self.__sunrise = 'no sunrise'
|
self.__sunrise = "no sunrise"
|
||||||
order_matters = False
|
order_matters = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.__sunset = self.__sun.get_local_sunset_time()
|
self.__sunset = self.__sun.get_local_sunset_time()
|
||||||
except SunTimeException:
|
except SunTimeException:
|
||||||
self.__sunset = 'no sunset'
|
self.__sunset = "no sunset"
|
||||||
order_matters = False
|
order_matters = False
|
||||||
|
|
||||||
if not order_matters:
|
if not order_matters:
|
||||||
|
@ -74,19 +76,20 @@ class Module(core.module.Module):
|
||||||
self.__sunrise = self.__sun.get_local_sunrise_time(tomorrow)
|
self.__sunrise = self.__sun.get_local_sunrise_time(tomorrow)
|
||||||
self.__sunset = self.__sun.get_local_sunset_time(tomorrow)
|
self.__sunset = self.__sun.get_local_sunset_time(tomorrow)
|
||||||
except SunTimeException:
|
except SunTimeException:
|
||||||
self.__sunrise = 'no sunrise'
|
self.__sunrise = "no sunrise"
|
||||||
self.__sunset = 'no sunset'
|
self.__sunset = "no sunset"
|
||||||
|
|
||||||
elif now > self.__sunrise:
|
elif now > self.__sunrise:
|
||||||
tomorrow = (now + datetime.timedelta(days=1)).date()
|
tomorrow = (now + datetime.timedelta(days=1)).date()
|
||||||
try:
|
try:
|
||||||
self.__sunrise = self.__sun.get_local_sunrise_time(tomorrow)
|
self.__sunrise = self.__sun.get_local_sunrise_time(tomorrow)
|
||||||
except SunTimeException:
|
except SunTimeException:
|
||||||
self.__sunrise = 'no sunrise'
|
self.__sunrise = "no sunrise"
|
||||||
return
|
return
|
||||||
self.__isup = True
|
self.__isup = True
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__calculate_times()
|
self.__calculate_times()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -28,7 +28,7 @@ try:
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import messagebox as tkmessagebox
|
from tkinter import messagebox as tkmessagebox
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logging.warning('failed to import tkinter - bumblebee popups won\'t work!')
|
logging.warning("failed to import tkinter - bumblebee popups won't work!")
|
||||||
|
|
||||||
import core.module
|
import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
|
@ -39,18 +39,18 @@ import util.cli
|
||||||
import util.popup
|
import util.popup
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.text))
|
super().__init__(config, theme, core.widget.Widget(self.text))
|
||||||
|
|
||||||
self.__confirm = util.format.asbool(self.parameter('confirm', True))
|
self.__confirm = util.format.asbool(self.parameter("confirm", True))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.popup)
|
||||||
cmd=self.popup)
|
|
||||||
|
|
||||||
def text(self, widget):
|
def text(self, widget):
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
def __on_command(self, header, text, command):
|
def __on_command(self, header, text, command):
|
||||||
do_it = True
|
do_it = True
|
||||||
|
@ -65,26 +65,49 @@ class Module(core.module.Module):
|
||||||
if do_it:
|
if do_it:
|
||||||
util.cli.execute(command)
|
util.cli.execute(command)
|
||||||
|
|
||||||
|
|
||||||
def popup(self, widget):
|
def popup(self, widget):
|
||||||
menu = util.popup.menu()
|
menu = util.popup.menu()
|
||||||
reboot_cmd = self.parameter('reboot', 'reboot')
|
reboot_cmd = self.parameter("reboot", "reboot")
|
||||||
shutdown_cmd = self.parameter('shutdown', 'shutdown -h now')
|
shutdown_cmd = self.parameter("shutdown", "shutdown -h now")
|
||||||
logout_cmd = self.parameter('logout', 'i3exit logout')
|
logout_cmd = self.parameter("logout", "i3exit logout")
|
||||||
switch_user_cmd = self.parameter('switch_user', 'i3exit switch_user')
|
switch_user_cmd = self.parameter("switch_user", "i3exit switch_user")
|
||||||
lock_cmd = self.parameter('lock', 'i3exit lock')
|
lock_cmd = self.parameter("lock", "i3exit lock")
|
||||||
suspend_cmd = self.parameter('suspend', 'i3exit suspend')
|
suspend_cmd = self.parameter("suspend", "i3exit suspend")
|
||||||
hibernate_cmd = self.parameter('hibernate', 'i3exit hibernate')
|
hibernate_cmd = self.parameter("hibernate", "i3exit hibernate")
|
||||||
|
|
||||||
menu.add_menuitem('shutdown', callback=functools.partial(self.__on_command, 'Shutdown', 'Shutdown?', shutdown_cmd))
|
menu.add_menuitem(
|
||||||
menu.add_menuitem('reboot', callback=functools.partial(self.__on_command, 'Reboot', 'Reboot?', reboot_cmd))
|
"shutdown",
|
||||||
menu.add_menuitem('log out', callback=functools.partial(self.__on_command, 'Log out', 'Log out?', 'i3exit logout'))
|
callback=functools.partial(
|
||||||
|
self.__on_command, "Shutdown", "Shutdown?", shutdown_cmd
|
||||||
|
),
|
||||||
|
)
|
||||||
|
menu.add_menuitem(
|
||||||
|
"reboot",
|
||||||
|
callback=functools.partial(
|
||||||
|
self.__on_command, "Reboot", "Reboot?", reboot_cmd
|
||||||
|
),
|
||||||
|
)
|
||||||
|
menu.add_menuitem(
|
||||||
|
"log out",
|
||||||
|
callback=functools.partial(
|
||||||
|
self.__on_command, "Log out", "Log out?", "i3exit logout"
|
||||||
|
),
|
||||||
|
)
|
||||||
# don't ask for these
|
# don't ask for these
|
||||||
menu.add_menuitem('switch user', callback=functools.partial(util.cli.execute, switch_user_cmd))
|
menu.add_menuitem(
|
||||||
menu.add_menuitem('lock', callback=functools.partial(util.cli.execute, lock_cmd))
|
"switch user", callback=functools.partial(util.cli.execute, switch_user_cmd)
|
||||||
menu.add_menuitem('suspend', callback=functools.partial(util.cli.execute, suspend_cmd))
|
)
|
||||||
menu.add_menuitem('hibernate', callback=functools.partial(util.cli.execute, hibernate_cmd))
|
menu.add_menuitem(
|
||||||
|
"lock", callback=functools.partial(util.cli.execute, lock_cmd)
|
||||||
|
)
|
||||||
|
menu.add_menuitem(
|
||||||
|
"suspend", callback=functools.partial(util.cli.execute, suspend_cmd)
|
||||||
|
)
|
||||||
|
menu.add_menuitem(
|
||||||
|
"hibernate", callback=functools.partial(util.cli.execute, hibernate_cmd)
|
||||||
|
)
|
||||||
|
|
||||||
menu.show(widget, 0, 0)
|
menu.show(widget, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -13,24 +13,26 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.output))
|
super().__init__(config, theme, core.widget.Widget(self.output))
|
||||||
|
|
||||||
self.__pending_tasks = '0'
|
self.__pending_tasks = "0"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Return a string with the number of pending tasks from TaskWarrior."""
|
"""Return a string with the number of pending tasks from TaskWarrior."""
|
||||||
try:
|
try:
|
||||||
taskrc = self.parameter('taskrc', '~/.taskrc')
|
taskrc = self.parameter("taskrc", "~/.taskrc")
|
||||||
w = TaskWarrior(config_filename=taskrc)
|
w = TaskWarrior(config_filename=taskrc)
|
||||||
pending_tasks = w.filter_tasks({'status': 'pending'})
|
pending_tasks = w.filter_tasks({"status": "pending"})
|
||||||
self.__pending_tasks = str(len(pending_tasks))
|
self.__pending_tasks = str(len(pending_tasks))
|
||||||
except:
|
except:
|
||||||
self.__pending_tasks = 'n/a'
|
self.__pending_tasks = "n/a"
|
||||||
|
|
||||||
def output(self, _):
|
def output(self, _):
|
||||||
"""Format the task counter to output in bumblebee."""
|
"""Format the task counter to output in bumblebee."""
|
||||||
return '{}'.format(self.__pending_tasks)
|
return "{}".format(self.__pending_tasks)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,12 +10,14 @@ Parameters:
|
||||||
import core.decorators
|
import core.decorators
|
||||||
from .datetimetz import Module
|
from .datetimetz import Module
|
||||||
|
|
||||||
|
|
||||||
class Module(Module):
|
class Module(Module):
|
||||||
@core.decorators.every(seconds=59) # ensures one update per minute
|
@core.decorators.every(seconds=59) # ensures one update per minute
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme)
|
super().__init__(config, theme)
|
||||||
|
|
||||||
def default_format(self):
|
def default_format(self):
|
||||||
return '%X %Z'
|
return "%X %Z"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -18,7 +18,7 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
no_title = 'n/a'
|
no_title = "n/a"
|
||||||
|
|
||||||
import core.module
|
import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
|
@ -26,24 +26,32 @@ import core.decorators
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
# parsing of parameters
|
# parsing of parameters
|
||||||
self.__scroll = util.format.asbool(self.parameter('scroll', False))
|
self.__scroll = util.format.asbool(self.parameter("scroll", False))
|
||||||
self.__max = int(self.parameter('max', 64))
|
self.__max = int(self.parameter("max", 64))
|
||||||
self.__placeholder = self.parameter('placeholder', '...')
|
self.__placeholder = self.parameter("placeholder", "...")
|
||||||
self.__title = ''
|
self.__title = ""
|
||||||
|
|
||||||
# set output of the module
|
# set output of the module
|
||||||
self.widgets([core.widget.Widget(full_text=
|
self.widgets(
|
||||||
self.__scrolling_focused_title if self.__scroll else self.__focused_title)])
|
[
|
||||||
|
core.widget.Widget(
|
||||||
|
full_text=self.__scrolling_focused_title
|
||||||
|
if self.__scroll
|
||||||
|
else self.__focused_title
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# create a connection with i3ipc
|
# create a connection with i3ipc
|
||||||
self.__i3 = i3ipc.Connection()
|
self.__i3 = i3ipc.Connection()
|
||||||
# event is called both on focus change and title change
|
# event is called both on focus change and title change
|
||||||
self.__i3.on('window', lambda __p_i3, __p_e: self.__pollTitle())
|
self.__i3.on("window", lambda __p_i3, __p_e: self.__pollTitle())
|
||||||
# begin listening for events
|
# begin listening for events
|
||||||
threading.Thread(target=self.__i3.main).start()
|
threading.Thread(target=self.__i3.main).start()
|
||||||
|
|
||||||
|
@ -69,9 +77,12 @@ class Module(core.module.Module):
|
||||||
if not self.__scroll:
|
if not self.__scroll:
|
||||||
# cut the text if it is too long
|
# cut the text if it is too long
|
||||||
if len(self.__full_title) > self.__max:
|
if len(self.__full_title) > self.__max:
|
||||||
self.__title = self.__full_title[0:self.__max - len(self.__placeholder)]
|
self.__title = self.__full_title[
|
||||||
self.__title = '{}{}'.format(self.__title, self.__placeholder)
|
0 : self.__max - len(self.__placeholder)
|
||||||
|
]
|
||||||
|
self.__title = "{}{}".format(self.__title, self.__placeholder)
|
||||||
else:
|
else:
|
||||||
self.__title = self.__full_title
|
self.__title = self.__full_title
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -12,24 +12,27 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.output))
|
super().__init__(config, theme, core.widget.Widget(self.output))
|
||||||
|
|
||||||
self.__doc = os.path.expanduser(self.parameter('file', '~/Documents/todo.txt'))
|
self.__doc = os.path.expanduser(self.parameter("file", "~/Documents/todo.txt"))
|
||||||
self.__todos = self.count_items()
|
self.__todos = self.count_items()
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd='xdg-open {}'.format(self.__doc))
|
core.input.register(
|
||||||
|
self, button=core.input.LEFT_MOUSE, cmd="xdg-open {}".format(self.__doc)
|
||||||
|
)
|
||||||
|
|
||||||
def output(self, widget):
|
def output(self, widget):
|
||||||
return str(self.__todos)
|
return str(self.__todos)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.__todos = self.count_items()
|
self.__todos = self.count_items()
|
||||||
|
|
||||||
def state(self, widgets):
|
def state(self, widgets):
|
||||||
if self.__todos == 0:
|
if self.__todos == 0:
|
||||||
return 'empty'
|
return "empty"
|
||||||
return 'items'
|
return "items"
|
||||||
|
|
||||||
def count_items(self):
|
def count_items(self):
|
||||||
try:
|
try:
|
||||||
|
@ -37,8 +40,9 @@ class Module(core.module.Module):
|
||||||
with open(self.__doc) as f:
|
with open(self.__doc) as f:
|
||||||
for i, l in enumerate(f):
|
for i, l in enumerate(f):
|
||||||
pass
|
pass
|
||||||
return i+1
|
return i + 1
|
||||||
except Exception:
|
except Exception:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -24,37 +24,47 @@ import core.widget
|
||||||
import util.format
|
import util.format
|
||||||
import util.graph
|
import util.graph
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
widgets = []
|
widgets = []
|
||||||
super().__init__(config, theme, widgets)
|
super().__init__(config, theme, widgets)
|
||||||
|
|
||||||
self._exclude = tuple(filter(len, util.format.aslist(self.parameter('exclude', 'lo,virbr,docker,vboxnet,veth'))))
|
self._exclude = tuple(
|
||||||
self._status = ''
|
filter(
|
||||||
|
len,
|
||||||
|
util.format.aslist(
|
||||||
|
self.parameter("exclude", "lo,virbr,docker,vboxnet,veth")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._status = ""
|
||||||
|
|
||||||
self._showname = util.format.asbool(self.parameter('showname', True))
|
self._showname = util.format.asbool(self.parameter("showname", True))
|
||||||
self._format = self.parameter('format', '{:.2f}')
|
self._format = self.parameter("format", "{:.2f}")
|
||||||
self._prev = {}
|
self._prev = {}
|
||||||
self._states = {}
|
self._states = {}
|
||||||
self._lastcheck = 0
|
self._lastcheck = 0
|
||||||
self._states['include'] = []
|
self._states["include"] = []
|
||||||
self._states['exclude'] = []
|
self._states["exclude"] = []
|
||||||
for state in tuple(filter(len, util.format.aslist(self.parameter('states', '')))):
|
for state in tuple(
|
||||||
if state[0] == '^':
|
filter(len, util.format.aslist(self.parameter("states", "")))
|
||||||
self._states['exclude'].append(state[1:])
|
):
|
||||||
|
if state[0] == "^":
|
||||||
|
self._states["exclude"].append(state[1:])
|
||||||
else:
|
else:
|
||||||
self._states['include'].append(state)
|
self._states["include"].append(state)
|
||||||
self._graphlen = int(self.parameter('graphlen', 0))
|
self._graphlen = int(self.parameter("graphlen", 0))
|
||||||
if self._graphlen > 0:
|
if self._graphlen > 0:
|
||||||
self._graphdata = {}
|
self._graphdata = {}
|
||||||
self._first_run = True
|
self._first_run = True
|
||||||
self._update_widgets(widgets)
|
self._update_widgets(widgets)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if 'traffic.rx' in widget.name:
|
if "traffic.rx" in widget.name:
|
||||||
return 'rx'
|
return "rx"
|
||||||
if 'traffic.tx' in widget.name:
|
if "traffic.tx" in widget.name:
|
||||||
return 'tx'
|
return "tx"
|
||||||
return self._status
|
return self._status
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
@ -74,8 +84,8 @@ class Module(core.module.Module):
|
||||||
retval = []
|
retval = []
|
||||||
try:
|
try:
|
||||||
for ip in netifaces.ifaddresses(intf).get(netifaces.AF_INET, []):
|
for ip in netifaces.ifaddresses(intf).get(netifaces.AF_INET, []):
|
||||||
if ip.get('addr', '') != '':
|
if ip.get("addr", "") != "":
|
||||||
retval.append(ip.get('addr'))
|
retval.append(ip.get("addr"))
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
return retval
|
return retval
|
||||||
|
@ -85,66 +95,80 @@ class Module(core.module.Module):
|
||||||
computes theme.minwidth string
|
computes theme.minwidth string
|
||||||
based on traffic.format and traffic.graphlen parameters
|
based on traffic.format and traffic.graphlen parameters
|
||||||
"""
|
"""
|
||||||
minwidth_str = ''
|
minwidth_str = ""
|
||||||
if self._graphlen > 0:
|
if self._graphlen > 0:
|
||||||
graph_len = int(self._graphlen / 2)
|
graph_len = int(self._graphlen / 2)
|
||||||
graph_prefix = '0' * graph_len
|
graph_prefix = "0" * graph_len
|
||||||
minwidth_str += graph_prefix
|
minwidth_str += graph_prefix
|
||||||
minwidth_str += '1000'
|
minwidth_str += "1000"
|
||||||
try:
|
try:
|
||||||
length = int(re.match('{:\.(\d+)f}', self._format).group(1))
|
length = int(re.match("{:\.(\d+)f}", self._format).group(1))
|
||||||
if length > 0:
|
if length > 0:
|
||||||
minwidth_str += '.' + '0' * length
|
minwidth_str += "." + "0" * length
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# return default value
|
# return default value
|
||||||
return '1000.00KiB/s'
|
return "1000.00KiB/s"
|
||||||
finally:
|
finally:
|
||||||
minwidth_str += 'KiB/s'
|
minwidth_str += "KiB/s"
|
||||||
return minwidth_str
|
return minwidth_str
|
||||||
|
|
||||||
def _update_widgets(self, widgets):
|
def _update_widgets(self, widgets):
|
||||||
interfaces = [i for i in netifaces.interfaces() if not i.startswith(self._exclude)]
|
interfaces = [
|
||||||
|
i for i in netifaces.interfaces() if not i.startswith(self._exclude)
|
||||||
|
]
|
||||||
|
|
||||||
del widgets[:]
|
del widgets[:]
|
||||||
|
|
||||||
counters = psutil.net_io_counters(pernic=True)
|
counters = psutil.net_io_counters(pernic=True)
|
||||||
now = time.time()
|
now = time.time()
|
||||||
timediff = now - (self._lastcheck if self._lastcheck else now)
|
timediff = now - (self._lastcheck if self._lastcheck else now)
|
||||||
if timediff <= 0: timediff = 1
|
if timediff <= 0:
|
||||||
|
timediff = 1
|
||||||
self._lastcheck = now
|
self._lastcheck = now
|
||||||
for interface in interfaces:
|
for interface in interfaces:
|
||||||
if self._graphlen > 0:
|
if self._graphlen > 0:
|
||||||
if interface not in self._graphdata:
|
if interface not in self._graphdata:
|
||||||
self._graphdata[interface] = {
|
self._graphdata[interface] = {
|
||||||
'rx': [0] * self._graphlen,
|
"rx": [0] * self._graphlen,
|
||||||
'tx': [0] * self._graphlen}
|
"tx": [0] * self._graphlen,
|
||||||
if not interface: interface = 'lo'
|
}
|
||||||
state = 'down'
|
if not interface:
|
||||||
|
interface = "lo"
|
||||||
|
state = "down"
|
||||||
if len(self.get_addresses(interface)) > 0:
|
if len(self.get_addresses(interface)) > 0:
|
||||||
state = 'up'
|
state = "up"
|
||||||
elif util.format.asbool(self.parameter('hide_down', True)):
|
elif util.format.asbool(self.parameter("hide_down", True)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(self._states['exclude']) > 0 and state in self._states['exclude']: continue
|
if len(self._states["exclude"]) > 0 and state in self._states["exclude"]:
|
||||||
if len(self._states['include']) > 0 and state not in self._states['include']: continue
|
continue
|
||||||
|
if (
|
||||||
|
len(self._states["include"]) > 0
|
||||||
|
and state not in self._states["include"]
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'rx': counters[interface].bytes_recv,
|
"rx": counters[interface].bytes_recv,
|
||||||
'tx': counters[interface].bytes_sent,
|
"tx": counters[interface].bytes_sent,
|
||||||
}
|
}
|
||||||
|
|
||||||
name = 'traffic-{}'.format(interface)
|
name = "traffic-{}".format(interface)
|
||||||
|
|
||||||
if self._showname:
|
if self._showname:
|
||||||
self.create_widget(widgets, name, interface)
|
self.create_widget(widgets, name, interface)
|
||||||
|
|
||||||
for direction in ['rx', 'tx']:
|
for direction in ["rx", "tx"]:
|
||||||
name = 'traffic.{}-{}'.format(direction, interface)
|
name = "traffic.{}-{}".format(direction, interface)
|
||||||
widget = self.create_widget(widgets, name, attributes={'theme.minwidth': self.get_minwidth_str()})
|
widget = self.create_widget(
|
||||||
|
widgets,
|
||||||
|
name,
|
||||||
|
attributes={"theme.minwidth": self.get_minwidth_str()},
|
||||||
|
)
|
||||||
prev = self._prev.get(name, 0)
|
prev = self._prev.get(name, 0)
|
||||||
bspeed = (int(data[direction]) - int(prev))/timediff
|
bspeed = (int(data[direction]) - int(prev)) / timediff
|
||||||
speed = util.format.byte(bspeed, self._format)
|
speed = util.format.byte(bspeed, self._format)
|
||||||
txtspeed = '{0}/s'.format(speed)
|
txtspeed = "{0}/s".format(speed)
|
||||||
if self._graphlen > 0:
|
if self._graphlen > 0:
|
||||||
# skip first value returned by psutil, because it is
|
# skip first value returned by psutil, because it is
|
||||||
# giant and ruins the grapth ratio until it gets pushed
|
# giant and ruins the grapth ratio until it gets pushed
|
||||||
|
@ -152,10 +176,16 @@ class Module(core.module.Module):
|
||||||
if self._first_run is True:
|
if self._first_run is True:
|
||||||
self._first_run = False
|
self._first_run = False
|
||||||
else:
|
else:
|
||||||
self._graphdata[interface][direction] = self._graphdata[interface][direction][1:]
|
self._graphdata[interface][direction] = self._graphdata[
|
||||||
|
interface
|
||||||
|
][direction][1:]
|
||||||
self._graphdata[interface][direction].append(bspeed)
|
self._graphdata[interface][direction].append(bspeed)
|
||||||
txtspeed = '{}{}'.format(util.graph.braille(self._graphdata[interface][direction]), txtspeed)
|
txtspeed = "{}{}".format(
|
||||||
|
util.graph.braille(self._graphdata[interface][direction]),
|
||||||
|
txtspeed,
|
||||||
|
)
|
||||||
widget.full_text(txtspeed)
|
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
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
"""Toggle twmn notifications."""
|
"""Toggle twmn notifications."""
|
||||||
|
|
||||||
|
@ -9,14 +9,15 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(''))
|
super().__init__(config, theme, core.widget.Widget(""))
|
||||||
|
|
||||||
self.__paused = False
|
self.__paused = False
|
||||||
# Make sure that twmn is currently not paused
|
# Make sure that twmn is currently not paused
|
||||||
util.cli.execute('killall -SIGUSR2 twmnd', ignore_errors=True)
|
util.cli.execute("killall -SIGUSR2 twmnd", ignore_errors=True)
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.toggle_status)
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.toggle_status)
|
||||||
|
|
||||||
def toggle_status(self, event):
|
def toggle_status(self, event):
|
||||||
|
@ -24,15 +25,16 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.__paused:
|
if self.__paused:
|
||||||
util.cli.execute('systemctl --user start twmnd')
|
util.cli.execute("systemctl --user start twmnd")
|
||||||
else:
|
else:
|
||||||
util.cli.execute('systemctl --user stop twmnd')
|
util.cli.execute("systemctl --user stop twmnd")
|
||||||
except:
|
except:
|
||||||
self.__paused = not self.__paused # toggling failed
|
self.__paused = not self.__paused # toggling failed
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self.__paused:
|
if self.__paused:
|
||||||
return ['muted']
|
return ["muted"]
|
||||||
return ['unmuted']
|
return ["unmuted"]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -7,17 +7,19 @@ from datetime import timedelta
|
||||||
import core.module
|
import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.output))
|
super().__init__(config, theme, core.widget.Widget(self.output))
|
||||||
self.__uptime = ''
|
self.__uptime = ""
|
||||||
|
|
||||||
def output(self, _):
|
def output(self, _):
|
||||||
return '{}'.format(self.__uptime)
|
return "{}".format(self.__uptime)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
with open('/proc/uptime', 'r') as f:
|
with open("/proc/uptime", "r") as f:
|
||||||
uptime_seconds = int(float(f.readline().split()[0]))
|
uptime_seconds = int(float(f.readline().split()[0]))
|
||||||
self.__uptime = timedelta(seconds = uptime_seconds)
|
self.__uptime = timedelta(seconds=uptime_seconds)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -25,6 +25,7 @@ import core.input
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.popup
|
import util.popup
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.vpn_status))
|
super().__init__(config, theme, core.widget.Widget(self.vpn_status))
|
||||||
|
@ -32,74 +33,82 @@ class Module(core.module.Module):
|
||||||
self.__connected_vpn_profile = None
|
self.__connected_vpn_profile = None
|
||||||
self.__selected_vpn_profile = None
|
self.__selected_vpn_profile = None
|
||||||
|
|
||||||
res = util.cli.execute('nmcli -g NAME,TYPE c')
|
res = util.cli.execute("nmcli -g NAME,TYPE c")
|
||||||
lines = res.splitlines()
|
lines = res.splitlines()
|
||||||
|
|
||||||
self.__vpn_profiles = []
|
self.__vpn_profiles = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
info = line.split(':')
|
info = line.split(":")
|
||||||
try:
|
try:
|
||||||
if self.__isvpn(info[1]):
|
if self.__isvpn(info[1]):
|
||||||
self.__vpn_profiles.append(info[0])
|
self.__vpn_profiles.append(info[0])
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.popup)
|
||||||
cmd=self.popup)
|
|
||||||
|
|
||||||
def __isvpn(self, connection_type):
|
def __isvpn(self, connection_type):
|
||||||
return connection_type in ['vpn', 'wireguard']
|
return connection_type in ["vpn", "wireguard"]
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
res = util.cli.execute('nmcli -g NAME,TYPE,DEVICE con')
|
res = util.cli.execute("nmcli -g NAME,TYPE,DEVICE con")
|
||||||
lines = res.splitlines()
|
lines = res.splitlines()
|
||||||
self.__connected_vpn_profile = None
|
self.__connected_vpn_profile = None
|
||||||
for line in lines:
|
for line in lines:
|
||||||
info = line.split(':')
|
info = line.split(":")
|
||||||
if self.__isvpn(info[1]) and info[2] != '':
|
if self.__isvpn(info[1]) and info[2] != "":
|
||||||
self.__connected_vpn_profile = info[0]
|
self.__connected_vpn_profile = info[0]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception('Could not get VPN status')
|
logging.exception("Could not get VPN status")
|
||||||
self.__connected_vpn_profile = None
|
self.__connected_vpn_profile = None
|
||||||
|
|
||||||
def vpn_status(self, widget):
|
def vpn_status(self, widget):
|
||||||
if self.__connected_vpn_profile is None:
|
if self.__connected_vpn_profile is None:
|
||||||
return 'off'
|
return "off"
|
||||||
return self.__connected_vpn_profile
|
return self.__connected_vpn_profile
|
||||||
|
|
||||||
def __on_vpndisconnect(self):
|
def __on_vpndisconnect(self):
|
||||||
try:
|
try:
|
||||||
util.cli.execute('nmcli c down \'{vpn}\''
|
util.cli.execute(
|
||||||
.format(vpn=self.__connected_vpn_profile))
|
"nmcli c down '{vpn}'".format(vpn=self.__connected_vpn_profile)
|
||||||
|
)
|
||||||
self.__connected_vpn_profile = None
|
self.__connected_vpn_profile = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception('Could not disconnect VPN connection')
|
logging.exception("Could not disconnect VPN connection")
|
||||||
|
|
||||||
def __on_vpnconnect(self, name):
|
def __on_vpnconnect(self, name):
|
||||||
self.__selected_vpn_profile = name
|
self.__selected_vpn_profile = name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
util.cli.execute('nmcli c up \'{vpn}\''
|
util.cli.execute(
|
||||||
.format(vpn=self.__selected_vpn_profile))
|
"nmcli c up '{vpn}'".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('Could not establish VPN connection')
|
logging.exception("Could not establish VPN connection")
|
||||||
self.__connected_vpn_profile = None
|
self.__connected_vpn_profile = None
|
||||||
|
|
||||||
def popup(self, widget):
|
def popup(self, widget):
|
||||||
menu = util.popup.menu()
|
menu = util.popup.menu()
|
||||||
|
|
||||||
if self.__connected_vpn_profile is not None:
|
if self.__connected_vpn_profile is not None:
|
||||||
menu.add_menuitem('Disconnect', callback=self.__on_vpndisconnect)
|
menu.add_menuitem("Disconnect", callback=self.__on_vpndisconnect)
|
||||||
for vpn_profile in self.__vpn_profiles:
|
for vpn_profile in self.__vpn_profiles:
|
||||||
if self.__connected_vpn_profile is not None and self.__connected_vpn_profile == vpn_profile:
|
if (
|
||||||
|
self.__connected_vpn_profile is not None
|
||||||
|
and self.__connected_vpn_profile == vpn_profile
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
menu.add_menuitem(vpn_profile, callback=functools.partial(self.__on_vpnconnect, vpn_profile))
|
menu.add_menuitem(
|
||||||
|
vpn_profile,
|
||||||
|
callback=functools.partial(self.__on_vpnconnect, vpn_profile),
|
||||||
|
)
|
||||||
menu.show(widget)
|
menu.show(widget)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -17,40 +17,42 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.text))
|
super().__init__(config, theme, core.widget.Widget(self.text))
|
||||||
|
|
||||||
self.__tracking = False
|
self.__tracking = False
|
||||||
self.__project = ''
|
self.__project = ""
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.toggle)
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.toggle)
|
||||||
|
|
||||||
def toggle(self, widget):
|
def toggle(self, widget):
|
||||||
self.__project = 'hit'
|
self.__project = "hit"
|
||||||
if self.__tracking:
|
if self.__tracking:
|
||||||
util.cli.execute('watson stop')
|
util.cli.execute("watson stop")
|
||||||
else:
|
else:
|
||||||
util.cli.execute('watson restart')
|
util.cli.execute("watson restart")
|
||||||
self.__tracking = not self.__tracking
|
self.__tracking = not self.__tracking
|
||||||
|
|
||||||
def text(self, widget):
|
def text(self, widget):
|
||||||
if self.__tracking:
|
if self.__tracking:
|
||||||
return self.__project
|
return self.__project
|
||||||
else:
|
else:
|
||||||
return 'Paused'
|
return "Paused"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
output = util.cli.execute('watson status')
|
output = util.cli.execute("watson status")
|
||||||
if re.match('No project started', output):
|
if re.match("No project started", output):
|
||||||
self.__tracking = False
|
self.__tracking = False
|
||||||
return
|
return
|
||||||
|
|
||||||
self.__tracking = True
|
self.__tracking = True
|
||||||
m = re.search(r'Project (.+) started', output)
|
m = re.search(r"Project (.+) started", output)
|
||||||
self.__project = m.group(1)
|
self.__project = m.group(1)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return 'on' if self.__tracking else 'off'
|
return "on" if self.__tracking else "off"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -28,30 +28,37 @@ import re
|
||||||
import requests
|
import requests
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=15)
|
@core.decorators.every(minutes=15)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.output))
|
super().__init__(config, theme, core.widget.Widget(self.output))
|
||||||
|
|
||||||
self.__temperature = 0
|
self.__temperature = 0
|
||||||
self.__apikey = self.parameter('apikey', 'af7bfe22287c652d032a3064ffa44088')
|
self.__apikey = self.parameter("apikey", "af7bfe22287c652d032a3064ffa44088")
|
||||||
self.__location = util.format.aslist(self.parameter('location', 'auto'))
|
self.__location = util.format.aslist(self.parameter("location", "auto"))
|
||||||
|
|
||||||
self.__index = 0
|
self.__index = 0
|
||||||
self.__showcity = util.format.asbool(self.parameter('showcity', True))
|
self.__showcity = util.format.asbool(self.parameter("showcity", True))
|
||||||
self.__showminmax = util.format.asbool(self.parameter('showminmax', False))
|
self.__showminmax = util.format.asbool(self.parameter("showminmax", False))
|
||||||
self.__unit = self.parameter('unit', 'metric')
|
self.__unit = self.parameter("unit", "metric")
|
||||||
self.__valid = False
|
self.__valid = False
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__next_location)
|
core.input.register(
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.__prev_location)
|
self, button=core.input.LEFT_MOUSE, cmd=self.__next_location
|
||||||
|
)
|
||||||
|
core.input.register(
|
||||||
|
self, button=core.input.RIGHT_MOUSE, cmd=self.__prev_location
|
||||||
|
)
|
||||||
|
|
||||||
def __next_location(self, event):
|
def __next_location(self, event):
|
||||||
self.__index = (self.__index + 1) % len(self.__location)
|
self.__index = (self.__index + 1) % len(self.__location)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def __prev_location(self, event):
|
def __prev_location(self, event):
|
||||||
self.__index = len(self.__location) - 1 if self.__index <= 0 else self.__index - 1
|
self.__index = (
|
||||||
|
len(self.__location) - 1 if self.__index <= 0 else self.__index - 1
|
||||||
|
)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def temperature(self):
|
def temperature(self):
|
||||||
|
@ -64,15 +71,22 @@ class Module(core.module.Module):
|
||||||
return util.format.astemperature(self.__tempmax, self.__unit)
|
return util.format.astemperature(self.__tempmax, self.__unit)
|
||||||
|
|
||||||
def city(self):
|
def city(self):
|
||||||
city = re.sub('[_-]', ' ', self.__city)
|
city = re.sub("[_-]", " ", self.__city)
|
||||||
return u'{} '.format(city)
|
return "{} ".format(city)
|
||||||
|
|
||||||
def output(self, widget):
|
def output(self, widget):
|
||||||
if not self.__valid:
|
if not self.__valid:
|
||||||
return u'?'
|
return "?"
|
||||||
if self.__showminmax:
|
if self.__showminmax:
|
||||||
self.__showcity=False
|
self.__showcity = False
|
||||||
return self.city() + self.temperature() + ' Hi:' + self.tempmax() + ' Lo:' + self.tempmin()
|
return (
|
||||||
|
self.city()
|
||||||
|
+ self.temperature()
|
||||||
|
+ " Hi:"
|
||||||
|
+ self.tempmax()
|
||||||
|
+ " Lo:"
|
||||||
|
+ self.tempmin()
|
||||||
|
)
|
||||||
elif self.__showcity:
|
elif self.__showcity:
|
||||||
return self.city() + self.temperature()
|
return self.city() + self.temperature()
|
||||||
else:
|
else:
|
||||||
|
@ -80,42 +94,51 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self.__valid:
|
if self.__valid:
|
||||||
if 'thunderstorm' in self.__weather:
|
if "thunderstorm" in self.__weather:
|
||||||
return ['thunder']
|
return ["thunder"]
|
||||||
elif 'drizzle' in self.__weather:
|
elif "drizzle" in self.__weather:
|
||||||
return ['rain']
|
return ["rain"]
|
||||||
elif 'rain' in self.__weather:
|
elif "rain" in self.__weather:
|
||||||
return ['rain']
|
return ["rain"]
|
||||||
elif 'snow' in self.__weather:
|
elif "snow" in self.__weather:
|
||||||
return ['snow']
|
return ["snow"]
|
||||||
elif 'sleet' in self.__weather:
|
elif "sleet" in self.__weather:
|
||||||
return ['sleet']
|
return ["sleet"]
|
||||||
elif 'clear' in self.__weather:
|
elif "clear" in self.__weather:
|
||||||
return ['clear']
|
return ["clear"]
|
||||||
elif 'cloud' in self.__weather:
|
elif "cloud" in self.__weather:
|
||||||
return ['clouds']
|
return ["clouds"]
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
weather_url = 'http://api.openweathermap.org/data/2.5/weather?appid={}'.format(self.__apikey)
|
weather_url = "http://api.openweathermap.org/data/2.5/weather?appid={}".format(
|
||||||
weather_url = '{}&units={}'.format(weather_url, self.__unit)
|
self.__apikey
|
||||||
if self.__location[self.__index] == 'auto':
|
)
|
||||||
|
weather_url = "{}&units={}".format(weather_url, self.__unit)
|
||||||
|
if self.__location[self.__index] == "auto":
|
||||||
coord = util.location.coordinates()
|
coord = util.location.coordinates()
|
||||||
weather_url = '{url}&lat={lat}&lon={lon}'.format(url=weather_url, lat=coord[0], lon=coord[1])
|
weather_url = "{url}&lat={lat}&lon={lon}".format(
|
||||||
|
url=weather_url, lat=coord[0], lon=coord[1]
|
||||||
|
)
|
||||||
elif self.__location[self.__index].isdigit():
|
elif self.__location[self.__index].isdigit():
|
||||||
weather_url = '{url}&id={id}'.format(url=weather_url, id=self.__location[self.__index])
|
weather_url = "{url}&id={id}".format(
|
||||||
|
url=weather_url, id=self.__location[self.__index]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
weather_url = '{url}&q={city}'.format(url=weather_url, city=self.__location[self.__index])
|
weather_url = "{url}&q={city}".format(
|
||||||
|
url=weather_url, city=self.__location[self.__index]
|
||||||
|
)
|
||||||
weather = requests.get(weather_url).json()
|
weather = requests.get(weather_url).json()
|
||||||
self.__city = weather['name']
|
self.__city = weather["name"]
|
||||||
self.__temperature = int(weather['main']['temp'])
|
self.__temperature = int(weather["main"]["temp"])
|
||||||
self.__tempmin = int(weather['main']['temp_min'])
|
self.__tempmin = int(weather["main"]["temp_min"])
|
||||||
self.__tempmax = int(weather['main']['temp_max'])
|
self.__tempmax = int(weather["main"]["temp_max"])
|
||||||
self.__weather = weather['weather'][0]['main'].lower()
|
self.__weather = weather["weather"][0]["main"].lower()
|
||||||
self.__valid = True
|
self.__valid = True
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__valid = False
|
self.__valid = False
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
"""Opens a random xkcd comic in the browser."""
|
"""Opens a random xkcd comic in the browser."""
|
||||||
|
|
||||||
|
@ -7,12 +7,16 @@ import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.never
|
@core.decorators.never
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget('xkcd'))
|
super().__init__(config, theme, core.widget.Widget("xkcd"))
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd="xdg-open https://c.xkcd.com/random/comic/"
|
self,
|
||||||
|
button=core.input.LEFT_MOUSE,
|
||||||
|
cmd="xdg-open https://c.xkcd.com/random/comic/",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -15,21 +15,25 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=5)
|
@core.decorators.every(seconds=5)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.keystate))
|
super().__init__(config, theme, core.widget.Widget(self.keystate))
|
||||||
self.__keystate = 'No YubiKey'
|
self.__keystate = "No YubiKey"
|
||||||
|
|
||||||
def keystate(self, widget):
|
def keystate(self, widget):
|
||||||
return self.__keystate
|
return self.__keystate
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
self.__keystate = "YubiKey: " + str(yubico.find_yubikey(debug=False).serial())
|
self.__keystate = "YubiKey: " + str(
|
||||||
|
yubico.find_yubikey(debug=False).serial()
|
||||||
|
)
|
||||||
except yubico.yubico_exception.YubicoError:
|
except yubico.yubico_exception.YubicoError:
|
||||||
self.__keystate = "No YubiKey"
|
self.__keystate = "No YubiKey"
|
||||||
except Exception:
|
except Exception:
|
||||||
self.__keystate = 'n/a'
|
self.__keystate = "n/a"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -36,46 +36,81 @@ import core.widget
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self._includelist = set(filter(lambda x: len(x) > 0,
|
self._includelist = set(
|
||||||
util.format.aslist(self.parameter('list', default=''))))
|
filter(
|
||||||
self._format = self.parameter('format', default='{name} {shortstatus} {used}/{size} ' +
|
lambda x: len(x) > 0,
|
||||||
'({percentfree}%)')
|
util.format.aslist(self.parameter("list", default="")),
|
||||||
self._usesudo = util.format.asbool(self.parameter('sudo', default=False))
|
)
|
||||||
self._showio = util.format.asbool(self.parameter('showio', default=True))
|
)
|
||||||
self._ioformat = self.parameter('ioformat', default='{band}')
|
self._format = self.parameter(
|
||||||
self._warnfree = int(self.parameter('warnfree', default=10))
|
"format", default="{name} {shortstatus} {used}/{size} " + "({percentfree}%)"
|
||||||
|
)
|
||||||
|
self._usesudo = util.format.asbool(self.parameter("sudo", default=False))
|
||||||
|
self._showio = util.format.asbool(self.parameter("showio", default=True))
|
||||||
|
self._ioformat = self.parameter("ioformat", default="{band}")
|
||||||
|
self._warnfree = int(self.parameter("warnfree", default=10))
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
widgets = self.widgets()
|
widgets = self.widgets()
|
||||||
zfs_version_path = '/sys/module/zfs/version'
|
zfs_version_path = "/sys/module/zfs/version"
|
||||||
# zpool list -H: List all zpools, use script mode (no headers and tabs as separators).
|
# zpool list -H: List all zpools, use script mode (no headers and tabs as separators).
|
||||||
try:
|
try:
|
||||||
with open(zfs_version_path, 'r') as zfs_mod_version:
|
with open(zfs_version_path, "r") as zfs_mod_version:
|
||||||
zfs_version = zfs_mod_version.readline().rstrip().split('-')[0]
|
zfs_version = zfs_mod_version.readline().rstrip().split("-")[0]
|
||||||
except IOError:
|
except IOError:
|
||||||
# ZFS isn't installed or the module isn't loaded, stub the version
|
# ZFS isn't installed or the module isn't loaded, stub the version
|
||||||
zfs_version = '0.0.0'
|
zfs_version = "0.0.0"
|
||||||
logging.error('ZFS version information not found at {}, check the module is loaded.'.format(zfs_version_path))
|
logging.error(
|
||||||
|
"ZFS version information not found at {}, check the module is loaded.".format(
|
||||||
|
zfs_version_path
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
raw_zpools = util.cli.execute(('sudo ' if self._usesudo else '') + 'zpool list -H').split('\n')
|
raw_zpools = util.cli.execute(
|
||||||
|
("sudo " if self._usesudo else "") + "zpool list -H"
|
||||||
|
).split("\n")
|
||||||
|
|
||||||
for widget in widgets:
|
for widget in widgets:
|
||||||
widget.set('visited', False)
|
widget.set("visited", False)
|
||||||
|
|
||||||
for raw_zpool in raw_zpools:
|
for raw_zpool in raw_zpools:
|
||||||
try:
|
try:
|
||||||
# Ignored fields (assigned to _) are 'expandsz' and 'altroot', also 'ckpoint' in ZFS 0.8.0+
|
# Ignored fields (assigned to _) are 'expandsz' and 'altroot', also 'ckpoint' in ZFS 0.8.0+
|
||||||
if parse_version(zfs_version) < parse_version('0.8.0'):
|
if parse_version(zfs_version) < parse_version("0.8.0"):
|
||||||
name, size, alloc, free, _, frag, cap, dedup, health, _ = raw_zpool.split('\t')
|
(
|
||||||
|
name,
|
||||||
|
size,
|
||||||
|
alloc,
|
||||||
|
free,
|
||||||
|
_,
|
||||||
|
frag,
|
||||||
|
cap,
|
||||||
|
dedup,
|
||||||
|
health,
|
||||||
|
_,
|
||||||
|
) = raw_zpool.split("\t")
|
||||||
else:
|
else:
|
||||||
name, size, alloc, free, _, _, frag, cap, dedup, health, _ = raw_zpool.split('\t')
|
(
|
||||||
cap = cap.rstrip('%')
|
name,
|
||||||
percentuse=int(cap)
|
size,
|
||||||
percentfree=100-percentuse
|
alloc,
|
||||||
|
free,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
frag,
|
||||||
|
cap,
|
||||||
|
dedup,
|
||||||
|
health,
|
||||||
|
_,
|
||||||
|
) = raw_zpool.split("\t")
|
||||||
|
cap = cap.rstrip("%")
|
||||||
|
percentuse = int(cap)
|
||||||
|
percentfree = 100 - percentuse
|
||||||
# There is a command, zpool iostat, which is however blocking and was therefore
|
# There is a command, zpool iostat, which is however blocking and was therefore
|
||||||
# causing issues.
|
# causing issues.
|
||||||
# Instead, we read file `/proc/spl/kstat/zfs/<poolname>/io` which contains
|
# Instead, we read file `/proc/spl/kstat/zfs/<poolname>/io` which contains
|
||||||
|
@ -83,7 +118,7 @@ class Module(core.module.Module):
|
||||||
# (and timestamp) during each widget update, and during the next widget update we
|
# (and timestamp) during each widget update, and during the next widget update we
|
||||||
# use them to compute delta of transferred bytes, and using the last and current
|
# use them to compute delta of transferred bytes, and using the last and current
|
||||||
# timestamp the rate at which they have been transferred.
|
# timestamp the rate at which they have been transferred.
|
||||||
with open('/proc/spl/kstat/zfs/{}/io'.format(name), 'r') as f:
|
with open("/proc/spl/kstat/zfs/{}/io".format(name), "r") as f:
|
||||||
# Third row provides data we need, we are interested in the first 4 values.
|
# Third row provides data we need, we are interested in the first 4 values.
|
||||||
# More info about this file can be found here:
|
# More info about this file can be found here:
|
||||||
# https://github.com/zfsonlinux/zfs/blob/master/lib/libspl/include/sys/kstat.h#L580
|
# https://github.com/zfsonlinux/zfs/blob/master/lib/libspl/include/sys/kstat.h#L580
|
||||||
|
@ -100,12 +135,12 @@ class Module(core.module.Module):
|
||||||
widget = self.widget(name)
|
widget = self.widget(name)
|
||||||
if not widget:
|
if not widget:
|
||||||
widget = core.widget.Widget(name=name)
|
widget = core.widget.Widget(name=name)
|
||||||
widget.set('last_iostat', [0, 0, 0, 0])
|
widget.set("last_iostat", [0, 0, 0, 0])
|
||||||
widget.set('last_timestamp', 0)
|
widget.set("last_timestamp", 0)
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
|
|
||||||
delta_iostat = [b - a for a, b in zip(iostat, widget.get('last_iostat'))]
|
delta_iostat = [b - a for a, b in zip(iostat, widget.get("last_iostat"))]
|
||||||
widget.set('last_iostat', iostat)
|
widget.set("last_iostat", iostat)
|
||||||
|
|
||||||
# From docs:
|
# From docs:
|
||||||
# > Note that even though the time is always returned as a floating point number, not
|
# > Note that even though the time is always returned as a floating point number, not
|
||||||
|
@ -114,8 +149,8 @@ class Module(core.module.Module):
|
||||||
# Also, during one update cycle the reported I/O may be garbage if the system time
|
# Also, during one update cycle the reported I/O may be garbage if the system time
|
||||||
# was changed.
|
# was changed.
|
||||||
timestamp = time.time()
|
timestamp = time.time()
|
||||||
delta_timestamp = widget.get('last_timestamp') - timestamp
|
delta_timestamp = widget.get("last_timestamp") - timestamp
|
||||||
widget.set('last_timestamp', time.time())
|
widget.set("last_timestamp", time.time())
|
||||||
|
|
||||||
# abs is there because sometimes the result is -0
|
# abs is there because sometimes the result is -0
|
||||||
rate_iostat = [abs(x / delta_timestamp) for x in delta_iostat]
|
rate_iostat = [abs(x / delta_timestamp) for x in delta_iostat]
|
||||||
|
@ -123,17 +158,26 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
# theme.minwidth is not set since these values are not expected to change
|
# theme.minwidth is not set since these values are not expected to change
|
||||||
# rapidly
|
# rapidly
|
||||||
widget.full_text(self._format.format(name=name, used=alloc, left=free, size=size,
|
widget.full_text(
|
||||||
percentfree=percentfree, percentuse=percentuse,
|
self._format.format(
|
||||||
status=health,
|
name=name,
|
||||||
shortstatus=self._shortstatus(health),
|
used=alloc,
|
||||||
fragpercent=frag, deduppercent=dedup))
|
left=free,
|
||||||
widget.set('state', health)
|
size=size,
|
||||||
widget.set('percentfree', percentfree)
|
percentfree=percentfree,
|
||||||
widget.set('visited', True)
|
percentuse=percentuse,
|
||||||
|
status=health,
|
||||||
|
shortstatus=self._shortstatus(health),
|
||||||
|
fragpercent=frag,
|
||||||
|
deduppercent=dedup,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
widget.set("state", health)
|
||||||
|
widget.set("percentfree", percentfree)
|
||||||
|
widget.set("visited", True)
|
||||||
|
|
||||||
if self._showio:
|
if self._showio:
|
||||||
wname, rname = [name + x for x in ['__write', '__read']]
|
wname, rname = [name + x for x in ["__write", "__read"]]
|
||||||
widget_w = self.widget(wname)
|
widget_w = self.widget(wname)
|
||||||
widget_r = self.widget(rname)
|
widget_r = self.widget(rname)
|
||||||
if not widget_w or not widget_r:
|
if not widget_w or not widget_r:
|
||||||
|
@ -141,30 +185,40 @@ class Module(core.module.Module):
|
||||||
widget_w = core.widget.Widget(name=wname)
|
widget_w = core.widget.Widget(name=wname)
|
||||||
widgets.extend([widget_r, widget_w])
|
widgets.extend([widget_r, widget_w])
|
||||||
for w in [widget_r, widget_w]:
|
for w in [widget_r, widget_w]:
|
||||||
w.set('theme.minwidth', self._ioformat.format(ops=9999,
|
w.set(
|
||||||
band=util.format.bytefmt(999.99*(1024**2))))
|
"theme.minwidth",
|
||||||
w.set('visited', True)
|
self._ioformat.format(
|
||||||
widget_w.full_text(self._ioformat.format(ops=round(writes),
|
ops=9999, band=util.format.bytefmt(999.99 * (1024 ** 2))
|
||||||
band=util.format.bytefmt(nwritten)))
|
),
|
||||||
widget_r.full_text(self._ioformat.format(ops=round(reads),
|
)
|
||||||
band=util.format.bytefmt(nread)))
|
w.set("visited", True)
|
||||||
|
widget_w.full_text(
|
||||||
|
self._ioformat.format(
|
||||||
|
ops=round(writes), band=util.format.bytefmt(nwritten)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
widget_r.full_text(
|
||||||
|
self._ioformat.format(
|
||||||
|
ops=round(reads), band=util.format.bytefmt(nread)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
for widget in widgets:
|
for widget in widgets:
|
||||||
if widget.get('visited') is False:
|
if widget.get("visited") is False:
|
||||||
widgets.remove(widget)
|
widgets.remove(widget)
|
||||||
self.widgets(widgets)
|
self.widgets(widgets)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if widget.name.endswith('__read'):
|
if widget.name.endswith("__read"):
|
||||||
return 'poolread'
|
return "poolread"
|
||||||
elif widget.name.endswith('__write'):
|
elif widget.name.endswith("__write"):
|
||||||
return 'poolwrite'
|
return "poolwrite"
|
||||||
|
|
||||||
state = widget.get('state')
|
state = widget.get("state")
|
||||||
if state == 'FAULTED':
|
if state == "FAULTED":
|
||||||
return [state, 'critical']
|
return [state, "critical"]
|
||||||
elif state == 'DEGRADED' or widget.get('percentfree') < self._warnfree:
|
elif state == "DEGRADED" or widget.get("percentfree") < self._warnfree:
|
||||||
return [state, 'warning']
|
return [state, "warning"]
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
@ -177,13 +231,14 @@ class Module(core.module.Module):
|
||||||
# configuration. A faulted pool has corrupted metadata, or one or more faulted devices, and
|
# configuration. A faulted pool has corrupted metadata, or one or more faulted devices, and
|
||||||
# insufficient replicas to continue functioning.
|
# insufficient replicas to continue functioning.
|
||||||
shortstate = {
|
shortstate = {
|
||||||
'DEGRADED': 'DEG',
|
"DEGRADED": "DEG",
|
||||||
'FAULTED': 'FLT',
|
"FAULTED": "FLT",
|
||||||
'ONLINE': 'ONL',
|
"ONLINE": "ONL",
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
return shortstate[status]
|
return shortstate[status]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Displays volume and mute status and controls for PulseAudio devices. Use wheel up and down to change volume, left click mutes, right click opens pavucontrol.
|
"""Displays volume and mute status and controls for PulseAudio devices. Use wheel up and down to change volume, left click mutes, right click opens pavucontrol.
|
||||||
|
|
||||||
Aliases: pasink (use this to control output instead of input), pasource
|
Aliases: pasink (use this to control output instead of input), pasource
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ Requires the following executable:
|
||||||
* pulseaudio
|
* pulseaudio
|
||||||
* pactl
|
* pactl
|
||||||
* pavucontrol
|
* pavucontrol
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
|
@ -29,15 +29,18 @@ import util.cli
|
||||||
import util.graph
|
import util.graph
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme, channel):
|
def __init__(self, config, theme, channel):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.volume))
|
super().__init__(config, theme, core.widget.Widget(self.volume))
|
||||||
|
|
||||||
if util.format.asbool(self.parameter('autostart', False)):
|
if util.format.asbool(self.parameter("autostart", False)):
|
||||||
util.cli.execute('pulseaudio --start', ignore_errors=True)
|
util.cli.execute("pulseaudio --start", ignore_errors=True)
|
||||||
|
|
||||||
self._change = util.format.asint(self.parameter('percent_change', '2%').strip('%'), 0, 100)
|
self._change = util.format.asint(
|
||||||
self._limit = util.format.asint(self.parameter('limit', '0%').strip('%'), 0)
|
self.parameter("percent_change", "2%").strip("%"), 0, 100
|
||||||
|
)
|
||||||
|
self._limit = util.format.asint(self.parameter("limit", "0%").strip("%"), 0)
|
||||||
|
|
||||||
self._left = 0
|
self._left = 0
|
||||||
self._right = 0
|
self._right = 0
|
||||||
|
@ -45,131 +48,153 @@ class Module(core.module.Module):
|
||||||
self._mute = False
|
self._mute = False
|
||||||
self._failed = False
|
self._failed = False
|
||||||
self._channel = channel
|
self._channel = channel
|
||||||
self._showbars = util.format.asbool(self.parameter('showbars', 0))
|
self._showbars = util.format.asbool(self.parameter("showbars", 0))
|
||||||
|
|
||||||
self._patterns = [
|
self._patterns = [
|
||||||
{'expr': 'Name:', 'callback': (lambda line: False)},
|
{"expr": "Name:", "callback": (lambda line: False)},
|
||||||
{'expr': 'Mute:', 'callback': (lambda line: self.mute(False if ' no' in line.lower() else True))},
|
{
|
||||||
{'expr': 'Volume:', 'callback': self.getvolume},
|
"expr": "Mute:",
|
||||||
|
"callback": (
|
||||||
|
lambda line: self.mute(False if " no" in line.lower() else True)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{"expr": "Volume:", "callback": self.getvolume},
|
||||||
]
|
]
|
||||||
|
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd='pavucontrol')
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd="pavucontrol")
|
||||||
|
|
||||||
events = [
|
events = [
|
||||||
{'type': 'mute', 'action': self.toggle, 'button': core.input.LEFT_MOUSE},
|
{"type": "mute", "action": self.toggle, "button": core.input.LEFT_MOUSE},
|
||||||
{'type': 'volume', 'action': self.increase_volume, 'button': core.input.WHEEL_UP},
|
{
|
||||||
{'type': 'volume', 'action': self.decrease_volume, 'button': core.input.WHEEL_DOWN},
|
"type": "volume",
|
||||||
|
"action": self.increase_volume,
|
||||||
|
"button": core.input.WHEEL_UP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "volume",
|
||||||
|
"action": self.decrease_volume,
|
||||||
|
"button": core.input.WHEEL_DOWN,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
for event in events:
|
for event in events:
|
||||||
core.input.register(self, button=event['button'], cmd=event['action'])
|
core.input.register(self, button=event["button"], cmd=event["action"])
|
||||||
|
|
||||||
def set_volume(self, amount):
|
def set_volume(self, amount):
|
||||||
util.cli.execute('pactl set-{}-{} @DEFAULT_{}@ {}'.format(
|
util.cli.execute(
|
||||||
self._channel, 'volume', self._channel.upper(), amount))
|
"pactl set-{}-{} @DEFAULT_{}@ {}".format(
|
||||||
|
self._channel, "volume", self._channel.upper(), amount
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def increase_volume(self, event):
|
def increase_volume(self, event):
|
||||||
if self._limit > 0: # we need to check the limit
|
if self._limit > 0: # we need to check the limit
|
||||||
left = int(self._left)
|
left = int(self._left)
|
||||||
right = int(self._right)
|
right = int(self._right)
|
||||||
if left + self._change >= self._limit or right + self._change >= self._limit:
|
if (
|
||||||
|
left + self._change >= self._limit
|
||||||
|
or right + self._change >= self._limit
|
||||||
|
):
|
||||||
if left == right:
|
if left == right:
|
||||||
# easy case, just set to limit
|
# easy case, just set to limit
|
||||||
self.set_volume('{}%'.format(self._limit))
|
self.set_volume("{}%".format(self._limit))
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# don't adjust anymore, since i don't know how to update only one channel
|
# don't adjust anymore, since i don't know how to update only one channel
|
||||||
return
|
return
|
||||||
|
|
||||||
self.set_volume('+{}%'.format(self._change))
|
self.set_volume("+{}%".format(self._change))
|
||||||
|
|
||||||
def decrease_volume(self, event):
|
def decrease_volume(self, event):
|
||||||
self.set_volume('-{}%'.format(self._change))
|
self.set_volume("-{}%".format(self._change))
|
||||||
|
|
||||||
def toggle(self, event):
|
def toggle(self, event):
|
||||||
util.cli.execute('pactl set-{}-mute @DEFAULT_{}@ toggle'.format(
|
util.cli.execute(
|
||||||
self._channel, self._channel.upper()))
|
"pactl set-{}-mute @DEFAULT_{}@ toggle".format(
|
||||||
|
self._channel, self._channel.upper()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def mute(self, value):
|
def mute(self, value):
|
||||||
self._mute = value
|
self._mute = value
|
||||||
|
|
||||||
def getvolume(self, line):
|
def getvolume(self, line):
|
||||||
if 'mono' in line:
|
if "mono" in line:
|
||||||
m = re.search(r'mono:.*\s*\/\s*(\d+)%', line)
|
m = re.search(r"mono:.*\s*\/\s*(\d+)%", line)
|
||||||
if m:
|
if m:
|
||||||
self._mono = m.group(1)
|
self._mono = m.group(1)
|
||||||
else:
|
else:
|
||||||
m = re.search(r'left:.*\s*\/\s*(\d+)%.*right:.*\s*\/\s*(\d+)%', line)
|
m = re.search(r"left:.*\s*\/\s*(\d+)%.*right:.*\s*\/\s*(\d+)%", line)
|
||||||
if m:
|
if m:
|
||||||
self._left = m.group(1)
|
self._left = m.group(1)
|
||||||
self._right = m.group(2)
|
self._right = m.group(2)
|
||||||
|
|
||||||
def _default_device(self):
|
def _default_device(self):
|
||||||
output = util.cli.execute('pactl info')
|
output = util.cli.execute("pactl info")
|
||||||
pattern = 'Default {}: '.format('Sink' if self._channel == 'sink' else 'Source')
|
pattern = "Default {}: ".format("Sink" if self._channel == "sink" else "Source")
|
||||||
for line in output.split('\n'):
|
for line in output.split("\n"):
|
||||||
if line.startswith(pattern):
|
if line.startswith(pattern):
|
||||||
return line.replace(pattern, '')
|
return line.replace(pattern, "")
|
||||||
logging.error('no pulseaudio device found')
|
logging.error("no pulseaudio device found")
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
|
|
||||||
def volume(self, widget):
|
def volume(self, widget):
|
||||||
if self._failed == True:
|
if self._failed == True:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
if int(self._mono) > 0:
|
if int(self._mono) > 0:
|
||||||
vol = '{}%'.format(self._mono)
|
vol = "{}%".format(self._mono)
|
||||||
if self._showbars:
|
if self._showbars:
|
||||||
vol = '{} {}'.format(
|
vol = "{} {}".format(vol, util.graph.hbar(float(self._mono)))
|
||||||
vol, util.graph.hbar(float(self._mono)))
|
|
||||||
return vol
|
return vol
|
||||||
elif self._left == self._right:
|
elif self._left == self._right:
|
||||||
vol = '{}%'.format(self._left)
|
vol = "{}%".format(self._left)
|
||||||
if self._showbars:
|
if self._showbars:
|
||||||
vol = '{} {}'.format(
|
vol = "{} {}".format(vol, util.graph.hbar(float(self._left)))
|
||||||
vol, util.graph.hbar(float(self._left)))
|
|
||||||
return vol
|
return vol
|
||||||
else:
|
else:
|
||||||
vol = '{}%/{}%'.format(self._left, self._right)
|
vol = "{}%/{}%".format(self._left, self._right)
|
||||||
if self._showbars:
|
if self._showbars:
|
||||||
vol = '{} {}{}'.format(
|
vol = "{} {}{}".format(
|
||||||
vol,
|
vol,
|
||||||
util.graph.hbar(float(self._left)),
|
util.graph.hbar(float(self._left)),
|
||||||
util.graph.hbar(float(self._right)))
|
util.graph.hbar(float(self._right)),
|
||||||
|
)
|
||||||
return vol
|
return vol
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
self._failed = False
|
self._failed = False
|
||||||
channel = 'sinks' if self._channel == 'sink' else 'sources'
|
channel = "sinks" if self._channel == "sink" else "sources"
|
||||||
device = self._default_device()
|
device = self._default_device()
|
||||||
|
|
||||||
result = util.cli.execute('pactl list {}'.format(channel))
|
result = util.cli.execute("pactl list {}".format(channel))
|
||||||
found = False
|
found = False
|
||||||
|
|
||||||
for line in result.split('\n'):
|
for line in result.split("\n"):
|
||||||
if 'Name: {}'.format(device) in line:
|
if "Name: {}".format(device) in line:
|
||||||
found = True
|
found = True
|
||||||
continue
|
continue
|
||||||
if found is False:
|
if found is False:
|
||||||
continue
|
continue
|
||||||
for pattern in self._patterns:
|
for pattern in self._patterns:
|
||||||
if not pattern['expr'] in line:
|
if not pattern["expr"] in line:
|
||||||
continue
|
continue
|
||||||
if pattern['callback'](line) is False and found == True:
|
if pattern["callback"](line) is False and found == True:
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._failed = True
|
self._failed = True
|
||||||
logging.exception(e)
|
logging.exception(e)
|
||||||
if util.format.asbool(self.parameter('autostart', False)):
|
if util.format.asbool(self.parameter("autostart", False)):
|
||||||
util.cli.execute('pulseaudio --start', ignore_errors=True)
|
util.cli.execute("pulseaudio --start", ignore_errors=True)
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self._mute:
|
if self._mute:
|
||||||
return ['warning', 'muted']
|
return ["warning", "muted"]
|
||||||
if int(self._left) > int(100):
|
if int(self._left) > int(100):
|
||||||
return ['critical', 'unmuted']
|
return ["critical", "unmuted"]
|
||||||
return ['unmuted']
|
return ["unmuted"]
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -17,7 +17,8 @@ import core.input
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
class UPowerManager():
|
|
||||||
|
class UPowerManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.UPOWER_NAME = "org.freedesktop.UPower"
|
self.UPOWER_NAME = "org.freedesktop.UPower"
|
||||||
self.UPOWER_PATH = "/org/freedesktop/UPower"
|
self.UPOWER_PATH = "/org/freedesktop/UPower"
|
||||||
|
@ -56,64 +57,100 @@ class UPowerManager():
|
||||||
battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery)
|
battery_proxy = self.bus.get_object(self.UPOWER_NAME, battery)
|
||||||
battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES)
|
battery_proxy_interface = dbus.Interface(battery_proxy, self.DBUS_PROPERTIES)
|
||||||
|
|
||||||
hasHistory = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "HasHistory")
|
hasHistory = battery_proxy_interface.Get(
|
||||||
hasStatistics = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "HasStatistics")
|
self.UPOWER_NAME + ".Device", "HasHistory"
|
||||||
isPresent = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IsPresent")
|
)
|
||||||
isRechargable = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IsRechargeable")
|
hasStatistics = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "HasStatistics"
|
||||||
|
)
|
||||||
|
isPresent = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "IsPresent"
|
||||||
|
)
|
||||||
|
isRechargable = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "IsRechargeable"
|
||||||
|
)
|
||||||
online = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Online")
|
online = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Online")
|
||||||
powersupply = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "PowerSupply")
|
powersupply = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "PowerSupply"
|
||||||
|
)
|
||||||
capacity = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Capacity")
|
capacity = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Capacity")
|
||||||
energy = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Energy")
|
energy = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Energy")
|
||||||
energyempty = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyEmpty")
|
energyempty = battery_proxy_interface.Get(
|
||||||
energyfull = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyFull")
|
self.UPOWER_NAME + ".Device", "EnergyEmpty"
|
||||||
energyfulldesign = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyFullDesign")
|
)
|
||||||
energyrate = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "EnergyRate")
|
energyfull = battery_proxy_interface.Get(
|
||||||
luminosity = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Luminosity")
|
self.UPOWER_NAME + ".Device", "EnergyFull"
|
||||||
percentage = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Percentage")
|
)
|
||||||
temperature = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Temperature")
|
energyfulldesign = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "EnergyFullDesign"
|
||||||
|
)
|
||||||
|
energyrate = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "EnergyRate"
|
||||||
|
)
|
||||||
|
luminosity = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "Luminosity"
|
||||||
|
)
|
||||||
|
percentage = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "Percentage"
|
||||||
|
)
|
||||||
|
temperature = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "Temperature"
|
||||||
|
)
|
||||||
voltage = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Voltage")
|
voltage = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Voltage")
|
||||||
timetoempty = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "TimeToEmpty")
|
timetoempty = battery_proxy_interface.Get(
|
||||||
timetofull = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "TimeToFull")
|
self.UPOWER_NAME + ".Device", "TimeToEmpty"
|
||||||
|
)
|
||||||
|
timetofull = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "TimeToFull"
|
||||||
|
)
|
||||||
iconname = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IconName")
|
iconname = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "IconName")
|
||||||
model = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Model")
|
model = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Model")
|
||||||
nativepath = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "NativePath")
|
nativepath = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "NativePath"
|
||||||
|
)
|
||||||
serial = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Serial")
|
serial = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Serial")
|
||||||
vendor = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Vendor")
|
vendor = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Vendor")
|
||||||
state = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State")
|
state = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State")
|
||||||
technology = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Technology")
|
technology = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "Technology"
|
||||||
|
)
|
||||||
battype = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Type")
|
battype = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "Type")
|
||||||
warninglevel = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "WarningLevel")
|
warninglevel = battery_proxy_interface.Get(
|
||||||
updatetime = battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "UpdateTime")
|
self.UPOWER_NAME + ".Device", "WarningLevel"
|
||||||
|
)
|
||||||
|
updatetime = battery_proxy_interface.Get(
|
||||||
|
self.UPOWER_NAME + ".Device", "UpdateTime"
|
||||||
|
)
|
||||||
|
|
||||||
information_table = {
|
information_table = {
|
||||||
'HasHistory': hasHistory,
|
"HasHistory": hasHistory,
|
||||||
'HasStatistics': hasStatistics,
|
"HasStatistics": hasStatistics,
|
||||||
'IsPresent': isPresent,
|
"IsPresent": isPresent,
|
||||||
'IsRechargeable': isRechargable,
|
"IsRechargeable": isRechargable,
|
||||||
'Online': online,
|
"Online": online,
|
||||||
'PowerSupply': powersupply,
|
"PowerSupply": powersupply,
|
||||||
'Capacity': capacity,
|
"Capacity": capacity,
|
||||||
'Energy': energy,
|
"Energy": energy,
|
||||||
'EnergyEmpty': energyempty,
|
"EnergyEmpty": energyempty,
|
||||||
'EnergyFull': energyfull,
|
"EnergyFull": energyfull,
|
||||||
'EnergyFullDesign': energyfulldesign,
|
"EnergyFullDesign": energyfulldesign,
|
||||||
'EnergyRate': energyrate,
|
"EnergyRate": energyrate,
|
||||||
'Luminosity': luminosity,
|
"Luminosity": luminosity,
|
||||||
'Percentage': percentage,
|
"Percentage": percentage,
|
||||||
'Temperature': temperature,
|
"Temperature": temperature,
|
||||||
'Voltage': voltage,
|
"Voltage": voltage,
|
||||||
'TimeToEmpty': timetoempty,
|
"TimeToEmpty": timetoempty,
|
||||||
'TimeToFull': timetofull,
|
"TimeToFull": timetofull,
|
||||||
'IconName': iconname,
|
"IconName": iconname,
|
||||||
'Model': model,
|
"Model": model,
|
||||||
'NativePath': nativepath,
|
"NativePath": nativepath,
|
||||||
'Serial': serial,
|
"Serial": serial,
|
||||||
'Vendor': vendor,
|
"Vendor": vendor,
|
||||||
'State': state,
|
"State": state,
|
||||||
'Technology': technology,
|
"Technology": technology,
|
||||||
'Type': battype,
|
"Type": battype,
|
||||||
'WarningLevel': warninglevel,
|
"WarningLevel": warninglevel,
|
||||||
'UpdateTime': updatetime
|
"UpdateTime": updatetime,
|
||||||
}
|
}
|
||||||
|
|
||||||
return information_table
|
return information_table
|
||||||
|
@ -122,40 +159,48 @@ class UPowerManager():
|
||||||
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
||||||
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
||||||
|
|
||||||
is_lid_present = bool(upower_interface.Get(self.UPOWER_NAME, 'LidIsPresent'))
|
is_lid_present = bool(upower_interface.Get(self.UPOWER_NAME, "LidIsPresent"))
|
||||||
return is_lid_present
|
return is_lid_present
|
||||||
|
|
||||||
def is_lid_closed(self):
|
def is_lid_closed(self):
|
||||||
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
||||||
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
||||||
|
|
||||||
is_lid_closed = bool(upower_interface.Get(self.UPOWER_NAME, 'LidIsClosed'))
|
is_lid_closed = bool(upower_interface.Get(self.UPOWER_NAME, "LidIsClosed"))
|
||||||
return is_lid_closed
|
return is_lid_closed
|
||||||
|
|
||||||
def on_battery(self):
|
def on_battery(self):
|
||||||
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH)
|
||||||
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
||||||
|
|
||||||
on_battery = bool(upower_interface.Get(self.UPOWER_NAME, 'OnBattery'))
|
on_battery = bool(upower_interface.Get(self.UPOWER_NAME, "OnBattery"))
|
||||||
return on_battery
|
return on_battery
|
||||||
|
|
||||||
def has_wakeup_capabilities(self):
|
def has_wakeup_capabilities(self):
|
||||||
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups")
|
upower_proxy = self.bus.get_object(
|
||||||
|
self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups"
|
||||||
|
)
|
||||||
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
upower_interface = dbus.Interface(upower_proxy, self.DBUS_PROPERTIES)
|
||||||
|
|
||||||
has_wakeup_capabilities = bool(upower_interface.Get(self.UPOWER_NAME + '.Wakeups', 'HasCapability'))
|
has_wakeup_capabilities = bool(
|
||||||
|
upower_interface.Get(self.UPOWER_NAME + ".Wakeups", "HasCapability")
|
||||||
|
)
|
||||||
return has_wakeup_capabilities
|
return has_wakeup_capabilities
|
||||||
|
|
||||||
def get_wakeups_data(self):
|
def get_wakeups_data(self):
|
||||||
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups")
|
upower_proxy = self.bus.get_object(
|
||||||
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + '.Wakeups')
|
self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups"
|
||||||
|
)
|
||||||
|
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + ".Wakeups")
|
||||||
|
|
||||||
data = upower_interface.GetData()
|
data = upower_interface.GetData()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get_wakeups_total(self):
|
def get_wakeups_total(self):
|
||||||
upower_proxy = self.bus.get_object(self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups")
|
upower_proxy = self.bus.get_object(
|
||||||
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + '.Wakeups')
|
self.UPOWER_NAME, self.UPOWER_PATH + "/Wakeups"
|
||||||
|
)
|
||||||
|
upower_interface = dbus.Interface(upower_proxy, self.UPOWER_NAME + ".Wakeups")
|
||||||
|
|
||||||
data = upower_interface.GetTotal()
|
data = upower_interface.GetTotal()
|
||||||
return data
|
return data
|
||||||
|
@ -166,7 +211,7 @@ class UPowerManager():
|
||||||
|
|
||||||
state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State"))
|
state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State"))
|
||||||
|
|
||||||
if (state == 1):
|
if state == 1:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -177,21 +222,22 @@ class UPowerManager():
|
||||||
|
|
||||||
state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State"))
|
state = int(battery_proxy_interface.Get(self.UPOWER_NAME + ".Device", "State"))
|
||||||
|
|
||||||
if (state == 0):
|
if state == 0:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
elif (state == 1):
|
elif state == 1:
|
||||||
return "Loading"
|
return "Loading"
|
||||||
elif (state == 2):
|
elif state == 2:
|
||||||
return "Discharging"
|
return "Discharging"
|
||||||
elif (state == 3):
|
elif state == 3:
|
||||||
return "Empty"
|
return "Empty"
|
||||||
elif (state == 4):
|
elif state == 4:
|
||||||
return "Fully charged"
|
return "Fully charged"
|
||||||
elif (state == 5):
|
elif state == 5:
|
||||||
return "Pending charge"
|
return "Pending charge"
|
||||||
elif (state == 6):
|
elif state == 6:
|
||||||
return "Pending discharge"
|
return "Pending discharge"
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.capacity))
|
super().__init__(config, theme, core.widget.Widget(self.capacity))
|
||||||
|
@ -201,11 +247,11 @@ class Module(core.module.Module):
|
||||||
self.device = self.power.get_display_device()
|
self.device = self.power.get_display_device()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("unable to get battery display device: {}".format(str(e)))
|
logging.exception("unable to get battery display device: {}".format(str(e)))
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd="gnome-power-statistics")
|
self, button=core.input.LEFT_MOUSE, cmd="gnome-power-statistics"
|
||||||
|
)
|
||||||
|
|
||||||
self._showremaining = util.format.asbool(
|
self._showremaining = util.format.asbool(self.parameter("showremaining", True))
|
||||||
self.parameter("showremaining", True))
|
|
||||||
|
|
||||||
def capacity(self, widget):
|
def capacity(self, widget):
|
||||||
widget.set("capacity", -1)
|
widget.set("capacity", -1)
|
||||||
|
@ -222,19 +268,25 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
if self._showremaining:
|
if self._showremaining:
|
||||||
try:
|
try:
|
||||||
p = self.power # an alias to make each line of code shorter
|
p = self.power # an alias to make each line of code shorter
|
||||||
proxy = p.bus.get_object(p.UPOWER_NAME, self.device)
|
proxy = p.bus.get_object(p.UPOWER_NAME, self.device)
|
||||||
interface = dbus.Interface(proxy, p.DBUS_PROPERTIES)
|
interface = dbus.Interface(proxy, p.DBUS_PROPERTIES)
|
||||||
state = int(interface.Get(p.UPOWER_NAME+".Device", "State"))
|
state = int(interface.Get(p.UPOWER_NAME + ".Device", "State"))
|
||||||
# state: 1 => charging, 2 => discharging, other => don't care
|
# state: 1 => charging, 2 => discharging, other => don't care
|
||||||
remain = int(interface.Get(
|
remain = int(
|
||||||
p.UPOWER_NAME+".Device", ["TimeToFull", "TimeToEmpty"][state-1]))
|
interface.Get(
|
||||||
|
p.UPOWER_NAME + ".Device",
|
||||||
|
["TimeToFull", "TimeToEmpty"][state - 1],
|
||||||
|
)
|
||||||
|
)
|
||||||
remain = util.format.duration(remain, compact=True, unit=True)
|
remain = util.format.duration(remain, compact=True, unit=True)
|
||||||
output = "{} {}".format(output, remain)
|
output = "{} {}".format(output, remain)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("unable to get battery remaining time: {}".format(str(e)))
|
logging.exception(
|
||||||
|
"unable to get battery remaining time: {}".format(str(e))
|
||||||
|
)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
@ -258,9 +310,17 @@ class Module(core.module.Module):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("unable to get charge value: {}".format(str(e)))
|
logging.exception("unable to get charge value: {}".format(str(e)))
|
||||||
if charge == "Discharging":
|
if charge == "Discharging":
|
||||||
state.append("discharging-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))))
|
state.append(
|
||||||
|
"discharging-{}".format(
|
||||||
|
min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))
|
||||||
|
)
|
||||||
|
)
|
||||||
elif charge == "Unknown":
|
elif charge == "Unknown":
|
||||||
state.append("unknown-{}".format(min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))))
|
state.append(
|
||||||
|
"unknown-{}".format(
|
||||||
|
min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if capacity > 95:
|
if capacity > 95:
|
||||||
state.append("charged")
|
state.append("charged")
|
||||||
|
@ -268,4 +328,5 @@ class Module(core.module.Module):
|
||||||
state.append("charging")
|
state.append("charging")
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -15,6 +15,7 @@ Parameters:
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -28,6 +29,7 @@ import core.input
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class BatteryManager(object):
|
class BatteryManager(object):
|
||||||
def remaining(self):
|
def remaining(self):
|
||||||
try:
|
try:
|
||||||
|
@ -35,26 +37,25 @@ class BatteryManager(object):
|
||||||
# do not show remaining if on AC
|
# do not show remaining if on AC
|
||||||
if estimate == power.common.TIME_REMAINING_UNLIMITED:
|
if estimate == power.common.TIME_REMAINING_UNLIMITED:
|
||||||
return None
|
return None
|
||||||
return estimate*60 # return value in seconds
|
return estimate * 60 # return value in seconds
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return -1
|
return -1
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
def read(self, battery, component, default=None):
|
def read(self, battery, component, default=None):
|
||||||
path = '/sys/class/power_supply/{}'.format(battery)
|
path = "/sys/class/power_supply/{}".format(battery)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
return default
|
return default
|
||||||
try:
|
try:
|
||||||
with open('{}/{}'.format(path, component)) as f:
|
with open("{}/{}".format(path, component)) as f:
|
||||||
return f.read().strip()
|
return f.read().strip()
|
||||||
except IOError:
|
except IOError:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def capacity(self, battery):
|
def capacity(self, battery):
|
||||||
capacity = self.read(battery, 'capacity', 100)
|
capacity = self.read(battery, "capacity", 100)
|
||||||
if capacity != 'n/a':
|
if capacity != "n/a":
|
||||||
capacity = int(capacity)
|
capacity = int(capacity)
|
||||||
|
|
||||||
return capacity if capacity < 100 else 100
|
return capacity if capacity < 100 else 100
|
||||||
|
@ -64,37 +65,41 @@ class BatteryManager(object):
|
||||||
full = 0
|
full = 0
|
||||||
for battery in batteries:
|
for battery in batteries:
|
||||||
try:
|
try:
|
||||||
with open('/sys/class/power_supply/{}/energy_full'.format(battery)) as f:
|
with open(
|
||||||
|
"/sys/class/power_supply/{}/energy_full".format(battery)
|
||||||
|
) as f:
|
||||||
full += int(f.read())
|
full += int(f.read())
|
||||||
with open('/sys/class/power_supply/{}/energy_now'.format(battery)) as f:
|
with open("/sys/class/power_supply/{}/energy_now".format(battery)) as f:
|
||||||
now += int(f.read())
|
now += int(f.read())
|
||||||
except IOError:
|
except IOError:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
return int(float(now)/float(full)*100.0)
|
return int(float(now) / float(full) * 100.0)
|
||||||
|
|
||||||
def isac(self, battery):
|
def isac(self, battery):
|
||||||
path = '/sys/class/power_supply/{}'.format(battery)
|
path = "/sys/class/power_supply/{}".format(battery)
|
||||||
return not os.path.exists(path)
|
return not os.path.exists(path)
|
||||||
|
|
||||||
def isac_any(self, batteries):
|
def isac_any(self, batteries):
|
||||||
for battery in batteries:
|
for battery in batteries:
|
||||||
if self.isac(battery): return True
|
if self.isac(battery):
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def consumption(self, battery):
|
def consumption(self, battery):
|
||||||
consumption = self.read(battery, 'power_now', 'n/a')
|
consumption = self.read(battery, "power_now", "n/a")
|
||||||
if consumption == 'n/a':
|
if consumption == "n/a":
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
return '{}W'.format(int(consumption)/1000000)
|
return "{}W".format(int(consumption) / 1000000)
|
||||||
|
|
||||||
def charge(self, battery):
|
def charge(self, battery):
|
||||||
return self.read(battery, 'status', 'n/a')
|
return self.read(battery, "status", "n/a")
|
||||||
|
|
||||||
def charge_any(self, batteries):
|
def charge_any(self, batteries):
|
||||||
for battery in batteries:
|
for battery in batteries:
|
||||||
if self.charge(battery) == 'Discharging':
|
if self.charge(battery) == "Discharging":
|
||||||
return 'Discharging'
|
return "Discharging"
|
||||||
return 'Charged'
|
return "Charged"
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -103,81 +108,104 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
self.__manager = BatteryManager()
|
self.__manager = BatteryManager()
|
||||||
|
|
||||||
self._batteries = util.format.aslist(self.parameter('device', 'auto'))
|
self._batteries = util.format.aslist(self.parameter("device", "auto"))
|
||||||
if self._batteries[0] == 'auto':
|
if self._batteries[0] == "auto":
|
||||||
self._batteries = [ os.path.basename(battery) for battery in glob.glob('/sys/class/power_supply/BAT*') ]
|
self._batteries = [
|
||||||
|
os.path.basename(battery)
|
||||||
|
for battery in glob.glob("/sys/class/power_supply/BAT*")
|
||||||
|
]
|
||||||
if len(self._batteries) == 0:
|
if len(self._batteries) == 0:
|
||||||
raise Exceptions('no batteries configured/found')
|
raise Exceptions("no batteries configured/found")
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd='gnome-power-statistics')
|
self, button=core.input.LEFT_MOUSE, cmd="gnome-power-statistics"
|
||||||
|
)
|
||||||
|
|
||||||
if util.format.asbool(self.parameter('compact-devices', False)):
|
if util.format.asbool(self.parameter("compact-devices", False)):
|
||||||
widget = core.widget.Widget(full_text=self.capacity, name='all-batteries', module=self)
|
widget = core.widget.Widget(
|
||||||
|
full_text=self.capacity, name="all-batteries", module=self
|
||||||
|
)
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
else:
|
else:
|
||||||
for battery in self._batteries:
|
for battery in self._batteries:
|
||||||
log.debug('adding new widget for {}'.format(battery))
|
log.debug("adding new widget for {}".format(battery))
|
||||||
widget = core.widget.Widget(full_text=self.capacity, name=battery, module=self)
|
widget = core.widget.Widget(
|
||||||
|
full_text=self.capacity, name=battery, module=self
|
||||||
|
)
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
for w in self.widgets():
|
for w in self.widgets():
|
||||||
if util.format.asbool(self.parameter('decorate', True)) == False:
|
if util.format.asbool(self.parameter("decorate", True)) == False:
|
||||||
widget.set('theme.exclude', 'suffix')
|
widget.set("theme.exclude", "suffix")
|
||||||
|
|
||||||
def capacity(self, widget):
|
def capacity(self, widget):
|
||||||
if widget.name == 'all-batteries':
|
if widget.name == "all-batteries":
|
||||||
capacity = self.__manager.capacity_all(self._batteries)
|
capacity = self.__manager.capacity_all(self._batteries)
|
||||||
else:
|
else:
|
||||||
capacity = self.__manager.capacity(widget.name)
|
capacity = self.__manager.capacity(widget.name)
|
||||||
widget.set('capacity', capacity)
|
widget.set("capacity", capacity)
|
||||||
widget.set('ac', self.__manager.isac_any(self._batteries))
|
widget.set("ac", self.__manager.isac_any(self._batteries))
|
||||||
widget.set('theme.minwidth', '100%')
|
widget.set("theme.minwidth", "100%")
|
||||||
|
|
||||||
# Read power conumption
|
# Read power conumption
|
||||||
if util.format.asbool(self.parameter('showpowerconsumption', False)):
|
if util.format.asbool(self.parameter("showpowerconsumption", False)):
|
||||||
output = '{}% ({})'.format(capacity, self.__manager.consumption(widget.name))
|
output = "{}% ({})".format(
|
||||||
|
capacity, self.__manager.consumption(widget.name)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
output = '{}%'.format(capacity)
|
output = "{}%".format(capacity)
|
||||||
|
|
||||||
if util.format.asbool(self.parameter('showremaining', True))\
|
if (
|
||||||
and self.__manager.charge(widget.name) == 'Discharging':
|
util.format.asbool(self.parameter("showremaining", True))
|
||||||
|
and self.__manager.charge(widget.name) == "Discharging"
|
||||||
|
):
|
||||||
remaining = self.__manager.remaining()
|
remaining = self.__manager.remaining()
|
||||||
if remaining >= 0:
|
if remaining >= 0:
|
||||||
output = '{} {}'.format(output, util.format.duration(remaining, compact=True, unit=True))
|
output = "{} {}".format(
|
||||||
|
output, util.format.duration(remaining, compact=True, unit=True)
|
||||||
|
)
|
||||||
|
|
||||||
if util.format.asbool(self.parameter('showdevice', False)):
|
if util.format.asbool(self.parameter("showdevice", False)):
|
||||||
output = '{} ({})'.format(output, widget.name)
|
output = "{} ({})".format(output, widget.name)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
state = []
|
state = []
|
||||||
capacity = widget.get('capacity')
|
capacity = widget.get("capacity")
|
||||||
|
|
||||||
if capacity < 0:
|
if capacity < 0:
|
||||||
log.debug('battery state: {}'.format(state))
|
log.debug("battery state: {}".format(state))
|
||||||
return ['critical', 'unknown']
|
return ["critical", "unknown"]
|
||||||
|
|
||||||
if capacity < int(self.parameter('critical', 10)):
|
if capacity < int(self.parameter("critical", 10)):
|
||||||
state.append('critical')
|
state.append("critical")
|
||||||
elif capacity < int(self.parameter('warning', 20)):
|
elif capacity < int(self.parameter("warning", 20)):
|
||||||
state.append('warning')
|
state.append("warning")
|
||||||
|
|
||||||
if widget.get('ac'):
|
if widget.get("ac"):
|
||||||
state.append('AC')
|
state.append("AC")
|
||||||
else:
|
else:
|
||||||
if widget.name == 'all-batteries':
|
if widget.name == "all-batteries":
|
||||||
charge = self.__manager.charge_any(self._batteries)
|
charge = self.__manager.charge_any(self._batteries)
|
||||||
else:
|
else:
|
||||||
charge = self.__manager.charge(widget.name)
|
charge = self.__manager.charge(widget.name)
|
||||||
if charge == 'Discharging':
|
if charge == "Discharging":
|
||||||
state.append('discharging-{}'.format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity))))
|
state.append(
|
||||||
elif charge == 'Unknown':
|
"discharging-{}".format(
|
||||||
state.append('unknown-{}'.format(min([10, 25, 50, 80, 100], key=lambda i: abs(i-capacity))))
|
min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif charge == "Unknown":
|
||||||
|
state.append(
|
||||||
|
"unknown-{}".format(
|
||||||
|
min([10, 25, 50, 80, 100], key=lambda i: abs(i - capacity))
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if capacity > 95:
|
if capacity > 95:
|
||||||
state.append('charged')
|
state.append("charged")
|
||||||
else:
|
else:
|
||||||
state.append('charging')
|
state.append("charging")
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -17,27 +17,29 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=30)
|
@core.decorators.every(seconds=30)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.brightness))
|
super().__init__(config, theme, core.widget.Widget(self.brightness))
|
||||||
|
|
||||||
self.__brightness = 'n/a'
|
self.__brightness = "n/a"
|
||||||
self.__readcmd = None
|
self.__readcmd = None
|
||||||
step = self.parameter('step', 2)
|
step = self.parameter("step", 2)
|
||||||
|
|
||||||
if shutil.which('light'):
|
if shutil.which("light"):
|
||||||
self.__readcmd = self.__light
|
self.__readcmd = self.__light
|
||||||
self.register_cmd('light -A {}%'.format(step),
|
self.register_cmd("light -A {}%".format(step), "light -U {}%".format(step))
|
||||||
'light -U {}%'.format(step))
|
elif shutil.which("brightnessctl"):
|
||||||
elif shutil.which('brightnessctl'):
|
|
||||||
self.__readcmd = self.__brightnessctl
|
self.__readcmd = self.__brightnessctl
|
||||||
self.register_cmd('brightnessctl s {}%+'.format(step),
|
self.register_cmd(
|
||||||
'brightnessctl s {}%-'.format(step))
|
"brightnessctl s {}%+".format(step), "brightnessctl s {}%-".format(step)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.__readcmd = self.__xbacklight
|
self.__readcmd = self.__xbacklight
|
||||||
self.register_cmd('xbacklight +{}%'.format(step),
|
self.register_cmd(
|
||||||
'xbacklight -{}%'.format(step))
|
"xbacklight +{}%".format(step), "xbacklight -{}%".format(step)
|
||||||
|
)
|
||||||
|
|
||||||
def register_cmd(self, up_cmd, down_cmd):
|
def register_cmd(self, up_cmd, down_cmd):
|
||||||
core.input.register(self, button=core.input.WHEEL_UP, cmd=up_cmd)
|
core.input.register(self, button=core.input.WHEEL_UP, cmd=up_cmd)
|
||||||
|
@ -47,20 +49,21 @@ class Module(core.module.Module):
|
||||||
return self.__brightness
|
return self.__brightness
|
||||||
|
|
||||||
def __light(self):
|
def __light(self):
|
||||||
return util.cli.execute('light').strip()
|
return util.cli.execute("light").strip()
|
||||||
|
|
||||||
def __brightnessctl(self):
|
def __brightnessctl(self):
|
||||||
m = util.cli.execute('brightnessctl m').strip()
|
m = util.cli.execute("brightnessctl m").strip()
|
||||||
g = util.cli.execute('brightnessctl g').strip()
|
g = util.cli.execute("brightnessctl g").strip()
|
||||||
return float(g)/float(m)*100.0
|
return float(g) / float(m) * 100.0
|
||||||
|
|
||||||
def __xbacklight(self):
|
def __xbacklight(self):
|
||||||
return util.cli.execute('xbacklight -get').strip()
|
return util.cli.execute("xbacklight -get").strip()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
try:
|
try:
|
||||||
self.__brightness = '{:3.0f}%'.format(float(self.__readcmd()))
|
self.__brightness = "{:3.0f}%".format(float(self.__readcmd()))
|
||||||
except:
|
except:
|
||||||
self.__brightness = 'n/a'
|
self.__brightness = "n/a"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -32,18 +32,21 @@ import core.decorators
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self._layout = self.parameter('layout', 'cmus.prev cmus.main cmus.next cmus.shuffle cmus.repeat')
|
self._layout = self.parameter(
|
||||||
self._fmt = self.parameter('format', '{artist} - {title} {position}/{duration}')
|
"layout", "cmus.prev cmus.main cmus.next cmus.shuffle cmus.repeat"
|
||||||
self._server = self.parameter('server', None)
|
)
|
||||||
self._passwd = self.parameter('passwd', None)
|
self._fmt = self.parameter("format", "{artist} - {title} {position}/{duration}")
|
||||||
|
self._server = self.parameter("server", None)
|
||||||
|
self._passwd = self.parameter("passwd", None)
|
||||||
self._status = None
|
self._status = None
|
||||||
self._shuffle = False
|
self._shuffle = False
|
||||||
self._repeat = False
|
self._repeat = False
|
||||||
self._tags = defaultdict(lambda: '')
|
self._tags = defaultdict(lambda: "")
|
||||||
|
|
||||||
# Create widgets
|
# Create widgets
|
||||||
widget_list = []
|
widget_list = []
|
||||||
|
@ -51,25 +54,48 @@ class Module(core.module.Module):
|
||||||
for widget_name in self._layout.split():
|
for widget_name in self._layout.split():
|
||||||
widget = core.widget.Widget(name=widget_name, module=self)
|
widget = core.widget.Widget(name=widget_name, module=self)
|
||||||
widget_list.append(widget)
|
widget_list.append(widget)
|
||||||
self._cmd = 'cmus-remote'
|
self._cmd = "cmus-remote"
|
||||||
if self._server is not None:
|
if self._server is not None:
|
||||||
self._cmd = '{cmd} --server {server}'.format(cmd=self._cmd, server=self._server)
|
self._cmd = "{cmd} --server {server}".format(
|
||||||
|
cmd=self._cmd, server=self._server
|
||||||
|
)
|
||||||
if self._passwd is not None:
|
if self._passwd is not None:
|
||||||
self._cmd = '{cmd} --passwd {passwd}'.format(cmd=self._cmd, passwd=self._passwd)
|
self._cmd = "{cmd} --passwd {passwd}".format(
|
||||||
|
cmd=self._cmd, passwd=self._passwd
|
||||||
|
)
|
||||||
|
|
||||||
if widget_name == 'cmus.prev':
|
if widget_name == "cmus.prev":
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': '{cmd} -r'.format(cmd=self._cmd)}
|
widget_map[widget] = {
|
||||||
elif widget_name == 'cmus.main':
|
"button": core.input.LEFT_MOUSE,
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': '{cmd} -u'.format(cmd=self._cmd)}
|
"cmd": "{cmd} -r".format(cmd=self._cmd),
|
||||||
|
}
|
||||||
|
elif widget_name == "cmus.main":
|
||||||
|
widget_map[widget] = {
|
||||||
|
"button": core.input.LEFT_MOUSE,
|
||||||
|
"cmd": "{cmd} -u".format(cmd=self._cmd),
|
||||||
|
}
|
||||||
widget.full_text(self.description)
|
widget.full_text(self.description)
|
||||||
elif widget_name == 'cmus.next':
|
elif widget_name == "cmus.next":
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': '{cmd} -n'.format(cmd=self._cmd)}
|
widget_map[widget] = {
|
||||||
elif widget_name == 'cmus.shuffle':
|
"button": core.input.LEFT_MOUSE,
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': '{cmd} -S'.format(cmd=self._cmd)}
|
"cmd": "{cmd} -n".format(cmd=self._cmd),
|
||||||
elif widget_name == 'cmus.repeat':
|
}
|
||||||
widget_map[widget] = {'button': core.input.LEFT_MOUSE, 'cmd': '{cmd} -R'.format(cmd=self._cmd)}
|
elif widget_name == "cmus.shuffle":
|
||||||
|
widget_map[widget] = {
|
||||||
|
"button": core.input.LEFT_MOUSE,
|
||||||
|
"cmd": "{cmd} -S".format(cmd=self._cmd),
|
||||||
|
}
|
||||||
|
elif widget_name == "cmus.repeat":
|
||||||
|
widget_map[widget] = {
|
||||||
|
"button": core.input.LEFT_MOUSE,
|
||||||
|
"cmd": "{cmd} -R".format(cmd=self._cmd),
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
raise KeyError('The cmus module does not support a {widget_name!r} widget'.format(widget_name=widget_name))
|
raise KeyError(
|
||||||
|
"The cmus module does not support a {widget_name!r} widget".format(
|
||||||
|
widget_name=widget_name
|
||||||
|
)
|
||||||
|
)
|
||||||
self.widgets(widget_list)
|
self.widgets(widget_list)
|
||||||
|
|
||||||
# Register input callbacks
|
# Register input callbacks
|
||||||
|
@ -88,44 +114,45 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
returns = {
|
returns = {
|
||||||
'cmus.shuffle': 'shuffle-on' if self._shuffle else 'shuffle-off',
|
"cmus.shuffle": "shuffle-on" if self._shuffle else "shuffle-off",
|
||||||
'cmus.repeat': 'repeat-on' if self._repeat else 'repeat-off',
|
"cmus.repeat": "repeat-on" if self._repeat else "repeat-off",
|
||||||
'cmus.prev': 'prev',
|
"cmus.prev": "prev",
|
||||||
'cmus.next': 'next',
|
"cmus.next": "next",
|
||||||
}
|
}
|
||||||
return returns.get(widget.name, self._status)
|
return returns.get(widget.name, self._status)
|
||||||
|
|
||||||
def _eval_line(self, line):
|
def _eval_line(self, line):
|
||||||
if line.startswith('file '):
|
if line.startswith("file "):
|
||||||
full_file = line[5:]
|
full_file = line[5:]
|
||||||
file1 = os.path.basename(full_file)
|
file1 = os.path.basename(full_file)
|
||||||
file2 = os.path.splitext(file1)[0]
|
file2 = os.path.splitext(file1)[0]
|
||||||
self._tags.update({'file': full_file})
|
self._tags.update({"file": full_file})
|
||||||
self._tags.update({'file1': file1})
|
self._tags.update({"file1": file1})
|
||||||
self._tags.update({'file2': file2})
|
self._tags.update({"file2": file2})
|
||||||
return
|
return
|
||||||
name, key, value = (line.split(' ', 2) + [None, None])[:3]
|
name, key, value = (line.split(" ", 2) + [None, None])[:3]
|
||||||
|
|
||||||
if name == 'status':
|
if name == "status":
|
||||||
self._status = key
|
self._status = key
|
||||||
if name == 'tag':
|
if name == "tag":
|
||||||
self._tags.update({key: value})
|
self._tags.update({key: value})
|
||||||
if name in ['duration', 'position']:
|
if name in ["duration", "position"]:
|
||||||
self._tags.update({name: util.format.duration(int(key))})
|
self._tags.update({name: util.format.duration(int(key))})
|
||||||
if name == 'set' and key == 'repeat':
|
if name == "set" and key == "repeat":
|
||||||
self._repeat = value == 'true'
|
self._repeat = value == "true"
|
||||||
if name == 'set' and key == 'shuffle':
|
if name == "set" and key == "shuffle":
|
||||||
self._shuffle = value == 'true'
|
self._shuffle = value == "true"
|
||||||
|
|
||||||
def _load_song(self):
|
def _load_song(self):
|
||||||
info = ''
|
info = ""
|
||||||
try:
|
try:
|
||||||
info = util.cli.execute('{cmd} -Q'.format(cmd=self._cmd))
|
info = util.cli.execute("{cmd} -Q".format(cmd=self._cmd))
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
self._status = None
|
self._status = None
|
||||||
|
|
||||||
self._tags = defaultdict(lambda: '')
|
self._tags = defaultdict(lambda: "")
|
||||||
for line in info.split('\n'):
|
for line in info.split("\n"):
|
||||||
self._eval_line(line)
|
self._eval_line(line)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Displays CPU utilization across all CPUs.
|
"""Displays CPU utilization across all CPUs.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
* cpu.warning : Warning threshold in % of CPU usage (defaults to 70%)
|
* cpu.warning : Warning threshold in % of CPU usage (defaults to 70%)
|
||||||
* cpu.critical: Critical threshold in % of CPU usage (defaults to 80%)
|
* cpu.critical: Critical threshold in % of CPU usage (defaults to 80%)
|
||||||
* cpu.format : Format string (defaults to '{:.01f}%')
|
* cpu.format : Format string (defaults to '{:.01f}%')
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
|
@ -14,17 +14,19 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.utilization))
|
super().__init__(config, theme, core.widget.Widget(self.utilization))
|
||||||
self.widget().set('theme.minwidth', self._format.format(100.0-10e-20))
|
self.widget().set("theme.minwidth", self._format.format(100.0 - 10e-20))
|
||||||
self._utilization = psutil.cpu_percent(percpu=False)
|
self._utilization = psutil.cpu_percent(percpu=False)
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd='gnome-system-monitor')
|
self, button=core.input.LEFT_MOUSE, cmd="gnome-system-monitor"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _format(self):
|
def _format(self):
|
||||||
return self.parameter('format', '{:.01f}%')
|
return self.parameter("format", "{:.01f}%")
|
||||||
|
|
||||||
def utilization(self, _):
|
def utilization(self, _):
|
||||||
return self._format.format(self._utilization)
|
return self._format.format(self._utilization)
|
||||||
|
@ -35,4 +37,5 @@ class Module(core.module.Module):
|
||||||
def state(self, _):
|
def state(self, _):
|
||||||
return self.threshold_state(self._utilization, 70, 80)
|
return self.threshold_state(self._utilization, 70, 80)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,12 +10,14 @@ Parameters:
|
||||||
import core.decorators
|
import core.decorators
|
||||||
from .datetime import Module
|
from .datetime import Module
|
||||||
|
|
||||||
|
|
||||||
class Module(Module):
|
class Module(Module):
|
||||||
@core.decorators.every(hours=1)
|
@core.decorators.every(hours=1)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme)
|
super().__init__(config, theme)
|
||||||
|
|
||||||
def default_format(self):
|
def default_format(self):
|
||||||
return '%x'
|
return "%x"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Displays the current date and time.
|
"""Displays the current date and time.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
* datetime.format: strftime()-compatible formatting string
|
* datetime.format: strftime()-compatible formatting string
|
||||||
* datetime.locale: locale to use rather than the system default
|
* datetime.locale: locale to use rather than the system default
|
||||||
'''
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import datetime
|
import datetime
|
||||||
|
@ -15,29 +15,31 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE, cmd='calendar')
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd="calendar")
|
||||||
self._fmt = self.parameter('format', self.default_format())
|
self._fmt = self.parameter("format", self.default_format())
|
||||||
l = locale.getdefaultlocale()
|
l = locale.getdefaultlocale()
|
||||||
if not l or l == (None, None):
|
if not l or l == (None, None):
|
||||||
l = ('en_US', 'UTF-8')
|
l = ("en_US", "UTF-8")
|
||||||
lcl = self.parameter('locale', '.'.join(l))
|
lcl = self.parameter("locale", ".".join(l))
|
||||||
try:
|
try:
|
||||||
locale.setlocale(locale.LC_TIME, lcl.split('.'))
|
locale.setlocale(locale.LC_TIME, lcl.split("."))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
locale.setlocale(locale.LC_TIME, ('en_US', 'UTF-8'))
|
locale.setlocale(locale.LC_TIME, ("en_US", "UTF-8"))
|
||||||
|
|
||||||
def default_format(self):
|
def default_format(self):
|
||||||
return '%x %X'
|
return "%x %X"
|
||||||
|
|
||||||
def full_text(self, widget):
|
def full_text(self, widget):
|
||||||
enc = locale.getpreferredencoding()
|
enc = locale.getpreferredencoding()
|
||||||
retval = datetime.datetime.now().strftime(self._fmt)
|
retval = datetime.datetime.now().strftime(self._fmt)
|
||||||
if hasattr(retval, 'decode'):
|
if hasattr(retval, "decode"):
|
||||||
return retval.decode(enc)
|
return retval.decode(enc)
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -8,15 +8,17 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
||||||
|
|
||||||
def full_text(self, widgets):
|
def full_text(self, widgets):
|
||||||
return 'debug'
|
return "debug"
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return 'warning'
|
return "warning"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Shows free diskspace, total diskspace and the percentage of free disk space.
|
"""Shows free diskspace, total diskspace and the percentage of free disk space.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
* disk.warning: Warning threshold in % of disk space (defaults to 80%)
|
* disk.warning: Warning threshold in % of disk space (defaults to 80%)
|
||||||
|
@ -8,7 +8,7 @@ Parameters:
|
||||||
* disk.path: Path to calculate disk usage from (defaults to /)
|
* disk.path: Path to calculate disk usage from (defaults to /)
|
||||||
* disk.open: Which application / file manager to launch (default xdg-open)
|
* disk.open: Which application / file manager to launch (default xdg-open)
|
||||||
* disk.format: Format string, tags {path}, {used}, {left}, {size} and {percent} (defaults to '{path} {used}/{size} ({percent:05.02f}%)')
|
* disk.format: Format string, tags {path}, {used}, {left}, {size} and {percent} (defaults to '{path} {used}/{size} ({percent:05.02f}%)')
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -18,20 +18,24 @@ import core.input
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.diskspace))
|
super().__init__(config, theme, core.widget.Widget(self.diskspace))
|
||||||
|
|
||||||
self._path = self.parameter('path', '/')
|
self._path = self.parameter("path", "/")
|
||||||
self._format = self.parameter('format', '{used}/{size} ({percent:05.02f}%)')
|
self._format = self.parameter("format", "{used}/{size} ({percent:05.02f}%)")
|
||||||
|
|
||||||
self._used = 0
|
self._used = 0
|
||||||
self._left = 0
|
self._left = 0
|
||||||
self._size = 0
|
self._size = 0
|
||||||
self._percent = 0
|
self._percent = 0
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd='{} {}'.format(self.parameter('open', 'xdg-open'), self._path))
|
self,
|
||||||
|
button=core.input.LEFT_MOUSE,
|
||||||
|
cmd="{} {}".format(self.parameter("open", "xdg-open"), self._path),
|
||||||
|
)
|
||||||
|
|
||||||
def diskspace(self, widget):
|
def diskspace(self, widget):
|
||||||
used_str = util.format.byte(self._used)
|
used_str = util.format.byte(self._used)
|
||||||
|
@ -39,20 +43,23 @@ class Module(core.module.Module):
|
||||||
left_str = util.format.byte(self._left)
|
left_str = util.format.byte(self._left)
|
||||||
percent_str = self._percent
|
percent_str = self._percent
|
||||||
|
|
||||||
return self._format.format(path=self._path,
|
return self._format.format(
|
||||||
used=used_str,
|
path=self._path,
|
||||||
left=left_str,
|
used=used_str,
|
||||||
size=size_str,
|
left=left_str,
|
||||||
percent=percent_str)
|
size=size_str,
|
||||||
|
percent=percent_str,
|
||||||
|
)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
st = os.statvfs(self._path)
|
st = os.statvfs(self._path)
|
||||||
self._size = st.f_blocks * st.f_frsize
|
self._size = st.f_blocks * st.f_frsize
|
||||||
self._used = (st.f_blocks - st.f_bfree) * st.f_frsize
|
self._used = (st.f_blocks - st.f_bfree) * st.f_frsize
|
||||||
self._left = self._size - self._used;
|
self._left = self._size - self._used
|
||||||
self._percent = 100.0 * self._used/self._size
|
self._percent = 100.0 * self._used / self._size
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return self.threshold_state(self._percent, 80, 90)
|
return self.threshold_state(self._percent, 80, 90)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -8,23 +8,26 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.event
|
import core.event
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
super().__init__(config, theme, core.widget.Widget(self.full_text))
|
||||||
self.__error = ''
|
self.__error = ""
|
||||||
self.__state = 'critical'
|
self.__state = "critical"
|
||||||
|
|
||||||
core.event.register('error', self.__set_error)
|
core.event.register("error", self.__set_error)
|
||||||
|
|
||||||
def full_text(self, widgets):
|
def full_text(self, widgets):
|
||||||
return self.__error
|
return self.__error
|
||||||
|
|
||||||
def __set_error(self, error='n/a', state='critical'):
|
def __set_error(self, error="n/a", state="critical"):
|
||||||
self.__error = error
|
self.__error = error
|
||||||
self.__state = state
|
self.__state = state
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self.__error: return [self.__state]
|
if self.__error:
|
||||||
|
return [self.__state]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -16,6 +16,7 @@ import core.widget
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
@ -33,25 +34,33 @@ class Module(core.module.Module):
|
||||||
directory = self.__get_git_root(directory)
|
directory = self.__get_git_root(directory)
|
||||||
repo = pygit2.Repository(directory)
|
repo = pygit2.Repository(directory)
|
||||||
|
|
||||||
new_widgets.append(core.widget.Widget(name='git.main', full_text=repo.head.shorthand))
|
new_widgets.append(
|
||||||
|
core.widget.Widget(name="git.main", full_text=repo.head.shorthand)
|
||||||
|
)
|
||||||
|
|
||||||
for filepath, flags in repo.status().items():
|
for filepath, flags in repo.status().items():
|
||||||
if flags == pygit2.GIT_STATUS_WT_NEW or \
|
if (
|
||||||
flags == pygit2.GIT_STATUS_INDEX_NEW:
|
flags == pygit2.GIT_STATUS_WT_NEW
|
||||||
state['new'] = True
|
or flags == pygit2.GIT_STATUS_INDEX_NEW
|
||||||
if flags == pygit2.GIT_STATUS_WT_DELETED or \
|
):
|
||||||
flags == pygit2.GIT_STATUS_INDEX_DELETED:
|
state["new"] = True
|
||||||
state['deleted'] = True
|
if (
|
||||||
if flags == pygit2.GIT_STATUS_WT_MODIFIED or \
|
flags == pygit2.GIT_STATUS_WT_DELETED
|
||||||
flags == pygit2.GIT_STATUS_INDEX_MODIFIED:
|
or flags == pygit2.GIT_STATUS_INDEX_DELETED
|
||||||
state['modified'] = True
|
):
|
||||||
|
state["deleted"] = True
|
||||||
|
if (
|
||||||
|
flags == pygit2.GIT_STATUS_WT_MODIFIED
|
||||||
|
or flags == pygit2.GIT_STATUS_INDEX_MODIFIED
|
||||||
|
):
|
||||||
|
state["modified"] = True
|
||||||
self.__error = False
|
self.__error = False
|
||||||
if 'new' in state:
|
if "new" in state:
|
||||||
new_widgets.append(core.widget.Widget(name='git.new'))
|
new_widgets.append(core.widget.Widget(name="git.new"))
|
||||||
if 'modified' in state:
|
if "modified" in state:
|
||||||
new_widgets.append(core.widget.Widget(name='git.modified'))
|
new_widgets.append(core.widget.Widget(name="git.modified"))
|
||||||
if 'deleted' in state:
|
if "deleted" in state:
|
||||||
new_widgets.append(core.widget.Widget(name='git.deleted'))
|
new_widgets.append(core.widget.Widget(name="git.deleted"))
|
||||||
|
|
||||||
self.widgets().clear()
|
self.widgets().clear()
|
||||||
self.widget(new_widgets)
|
self.widget(new_widgets)
|
||||||
|
@ -60,7 +69,7 @@ class Module(core.module.Module):
|
||||||
self.__error = True
|
self.__error = True
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return widget.name.split('.')[1]
|
return widget.name.split(".")[1]
|
||||||
|
|
||||||
def __get_git_root(self, directory):
|
def __get_git_root(self, directory):
|
||||||
while len(directory) > 1:
|
while len(directory) > 1:
|
||||||
|
@ -69,4 +78,5 @@ class Module(core.module.Module):
|
||||||
directory = "/".join(directory.split("/")[0:-1])
|
directory = "/".join(directory.split("/")[0:-1])
|
||||||
return "/"
|
return "/"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -8,6 +8,7 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -16,4 +17,5 @@ class Module(core.module.Module):
|
||||||
def full_text(self, widgets):
|
def full_text(self, widgets):
|
||||||
return platform.release()
|
return platform.release()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -15,6 +15,7 @@ Parameters:
|
||||||
from xkbgroup import *
|
from xkbgroup import *
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
import core.module
|
import core.module
|
||||||
|
@ -23,15 +24,14 @@ import core.input
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.current_layout))
|
super().__init__(config, theme, core.widget.Widget(self.current_layout))
|
||||||
|
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.__next_keymap)
|
||||||
cmd=self.__next_keymap)
|
core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.__prev_keymap)
|
||||||
core.input.register(self, button=core.input.RIGHT_MOUSE,
|
self.__show_variant = util.format.asbool(self.parameter("show_variant", True))
|
||||||
cmd=self.__prev_keymap)
|
|
||||||
self.__show_variant = util.format.asbool(self.parameter('show_variant', True))
|
|
||||||
|
|
||||||
def __next_keymap(self, event):
|
def __next_keymap(self, event):
|
||||||
self.__set_keymap(1)
|
self.__set_keymap(1)
|
||||||
|
@ -41,7 +41,8 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def __set_keymap(self, rotation):
|
def __set_keymap(self, rotation):
|
||||||
xkb = XKeyboard()
|
xkb = XKeyboard()
|
||||||
if xkb.groups_count < 2: return # nothing to do
|
if xkb.groups_count < 2:
|
||||||
|
return # nothing to do
|
||||||
layouts = xkb.groups_symbols
|
layouts = xkb.groups_symbols
|
||||||
idx = layouts.index(xkb.group_symbol)
|
idx = layouts.index(xkb.group_symbol)
|
||||||
xkb.group_symbol = str(layouts[(idx + rotation) % len(layouts)])
|
xkb.group_symbol = str(layouts[(idx + rotation) % len(layouts)])
|
||||||
|
@ -49,13 +50,22 @@ class Module(core.module.Module):
|
||||||
def current_layout(self, widget):
|
def current_layout(self, widget):
|
||||||
try:
|
try:
|
||||||
xkb = XKeyboard()
|
xkb = XKeyboard()
|
||||||
log.debug('group num: {}'.format(xkb.group_num))
|
log.debug("group num: {}".format(xkb.group_num))
|
||||||
name = xkb.group_name if util.format.asbool(self.parameter('showname'), False) else xkb.group_symbol
|
name = (
|
||||||
|
xkb.group_name
|
||||||
|
if util.format.asbool(self.parameter("showname"), False)
|
||||||
|
else xkb.group_symbol
|
||||||
|
)
|
||||||
if self.__show_variant:
|
if self.__show_variant:
|
||||||
return '{} ({})'.format(name, xkb.group_variant) if xkb.group_variant else name
|
return (
|
||||||
|
"{} ({})".format(name, xkb.group_variant)
|
||||||
|
if xkb.group_variant
|
||||||
|
else name
|
||||||
|
)
|
||||||
return name
|
return name
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('got exception: {}'.format(e))
|
print("got exception: {}".format(e))
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Displays system load.
|
"""Displays system load.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
* load.warning : Warning threshold for the one-minute load average (defaults to 70% of the number of CPUs)
|
* load.warning : Warning threshold for the one-minute load average (defaults to 70% of the number of CPUs)
|
||||||
* load.critical: Critical threshold for the one-minute load average (defaults to 80% of the number of CPUs)
|
* load.critical: Critical threshold for the one-minute load average (defaults to 80% of the number of CPUs)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
@ -13,6 +13,7 @@ import multiprocessing
|
||||||
import core.module
|
import core.module
|
||||||
import core.input
|
import core.input
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.load))
|
super().__init__(config, theme, core.widget.Widget(self.load))
|
||||||
|
@ -21,11 +22,12 @@ class Module(core.module.Module):
|
||||||
self._cpus = multiprocessing.cpu_count()
|
self._cpus = multiprocessing.cpu_count()
|
||||||
except NotImplementedError as e:
|
except NotImplementedError as e:
|
||||||
self._cpus = 1
|
self._cpus = 1
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd='gnome-system-monitor')
|
self, button=core.input.LEFT_MOUSE, cmd="gnome-system-monitor"
|
||||||
|
)
|
||||||
|
|
||||||
def load(self, widget):
|
def load(self, widget):
|
||||||
return '{:.02f}/{:.02f}/{:.02f}'.format(
|
return "{:.02f}/{:.02f}/{:.02f}".format(
|
||||||
self._load[0], self._load[1], self._load[2]
|
self._load[0], self._load[1], self._load[2]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ class Module(core.module.Module):
|
||||||
self._load = os.getloadavg()
|
self._load = os.getloadavg()
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return self.threshold_state(self._load[0], self._cpus*0.7, self._cpus*0.8)
|
return self.threshold_state(self._load[0], self._cpus * 0.7, self._cpus * 0.8)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Displays available RAM, total amount of RAM and percentage available.
|
"""Displays available RAM, total amount of RAM and percentage available.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
* memory.warning : Warning threshold in % of memory used (defaults to 80%)
|
* memory.warning : Warning threshold in % of memory used (defaults to 80%)
|
||||||
* memory.critical: Critical threshold in % of memory used (defaults to 90%)
|
* memory.critical: Critical threshold in % of memory used (defaults to 90%)
|
||||||
* memory.format: Format string (defaults to '{used}/{total} ({percent:05.02f}%)')
|
* memory.format: Format string (defaults to '{used}/{total} ({percent:05.02f}%)')
|
||||||
* memory.usedonly: Only show the amount of RAM in use (defaults to False). Same as memory.format='{used}'
|
* memory.usedonly: Only show the amount of RAM in use (defaults to False). Same as memory.format='{used}'
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -17,49 +17,61 @@ import core.input
|
||||||
|
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.memory_usage))
|
super().__init__(config, theme, core.widget.Widget(self.memory_usage))
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(
|
||||||
cmd='gnome-system-monitor')
|
self, button=core.input.LEFT_MOUSE, cmd="gnome-system-monitor"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _format(self):
|
def _format(self):
|
||||||
if util.format.asbool(self.parameter('usedonly', False)):
|
if util.format.asbool(self.parameter("usedonly", False)):
|
||||||
return '{used}'
|
return "{used}"
|
||||||
else:
|
else:
|
||||||
return self.parameter('format', '{used}/{total} ({percent:05.02f}%)')
|
return self.parameter("format", "{used}/{total} ({percent:05.02f}%)")
|
||||||
|
|
||||||
def memory_usage(self, widget):
|
def memory_usage(self, widget):
|
||||||
return self._format.format(**self._mem)
|
return self._format.format(**self._mem)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
data = {}
|
data = {}
|
||||||
with open('/proc/meminfo', 'r') as f:
|
with open("/proc/meminfo", "r") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
tmp = re.split(r'[:\s]+', line)
|
tmp = re.split(r"[:\s]+", line)
|
||||||
value = int(tmp[1])
|
value = int(tmp[1])
|
||||||
if tmp[2] == 'kB': value = value*1024
|
if tmp[2] == "kB":
|
||||||
if tmp[2] == 'mB': value = value*1024*1024
|
value = value * 1024
|
||||||
if tmp[2] == 'gB': value = value*1024*1024*1024
|
if tmp[2] == "mB":
|
||||||
|
value = value * 1024 * 1024
|
||||||
|
if tmp[2] == "gB":
|
||||||
|
value = value * 1024 * 1024 * 1024
|
||||||
data[tmp[0]] = value
|
data[tmp[0]] = value
|
||||||
if 'MemAvailable' in data:
|
if "MemAvailable" in data:
|
||||||
used = data['MemTotal'] - data['MemAvailable']
|
used = data["MemTotal"] - data["MemAvailable"]
|
||||||
else:
|
else:
|
||||||
used = data['MemTotal'] - data['MemFree'] - data['Buffers'] - data['Cached'] - data['Slab']
|
used = (
|
||||||
|
data["MemTotal"]
|
||||||
|
- data["MemFree"]
|
||||||
|
- data["Buffers"]
|
||||||
|
- data["Cached"]
|
||||||
|
- data["Slab"]
|
||||||
|
)
|
||||||
self._mem = {
|
self._mem = {
|
||||||
'total': util.format.byte(data['MemTotal']),
|
"total": util.format.byte(data["MemTotal"]),
|
||||||
'available': util.format.byte(data['MemAvailable']),
|
"available": util.format.byte(data["MemAvailable"]),
|
||||||
'free': util.format.byte(data['MemFree']),
|
"free": util.format.byte(data["MemFree"]),
|
||||||
'used': util.format.byte(used),
|
"used": util.format.byte(used),
|
||||||
'percent': float(used)/float(data['MemTotal'])*100.0
|
"percent": float(used) / float(data["MemTotal"]) * 100.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if self._mem['percent'] > float(self.parameter('critical', 90)):
|
if self._mem["percent"] > float(self.parameter("critical", 90)):
|
||||||
return 'critical'
|
return "critical"
|
||||||
if self._mem['percent'] > float(self.parameter('warning', 80)):
|
if self._mem["percent"] > float(self.parameter("warning", 80)):
|
||||||
return 'warning'
|
return "warning"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
"""Displays the name, IP address(es) and status of each available network interface.
|
"""Displays the name, IP address(es) and status of each available network interface.
|
||||||
|
|
||||||
|
@ -22,22 +22,30 @@ import core.decorators
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=10)
|
@core.decorators.every(seconds=10)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
widgets = []
|
widgets = []
|
||||||
super().__init__(config, theme, widgets)
|
super().__init__(config, theme, widgets)
|
||||||
self._exclude = tuple(filter(len, self.parameter('exclude', 'lo,virbr,docker,vboxnet,veth,br').split(',')))
|
self._exclude = tuple(
|
||||||
self._include = self.parameter('include', '').split(',')
|
filter(
|
||||||
|
len,
|
||||||
|
self.parameter("exclude", "lo,virbr,docker,vboxnet,veth,br").split(","),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._include = self.parameter("include", "").split(",")
|
||||||
|
|
||||||
self._states = { 'include': [], 'exclude': [] }
|
self._states = {"include": [], "exclude": []}
|
||||||
for state in tuple(filter(len, util.format.aslist(self.parameter('states', '')))):
|
for state in tuple(
|
||||||
if state[0] == '^':
|
filter(len, util.format.aslist(self.parameter("states", "")))
|
||||||
self._states['exclude'].append(state[1:])
|
):
|
||||||
|
if state[0] == "^":
|
||||||
|
self._states["exclude"].append(state[1:])
|
||||||
else:
|
else:
|
||||||
self._states['include'].append(state)
|
self._states["include"].append(state)
|
||||||
self._format = self.parameter('format','{intf} {state} {ip} {ssid}');
|
self._format = self.parameter("format", "{intf} {state} {ip} {ssid}")
|
||||||
self.iwgetid = shutil.which('iwgetid')
|
self.iwgetid = shutil.which("iwgetid")
|
||||||
self._update_widgets(widgets)
|
self._update_widgets(widgets)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
@ -46,71 +54,91 @@ class Module(core.module.Module):
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
states = []
|
states = []
|
||||||
|
|
||||||
if widget.get('state') == 'down':
|
if widget.get("state") == "down":
|
||||||
states.append('critical')
|
states.append("critical")
|
||||||
elif widget.get('state') != 'up':
|
elif widget.get("state") != "up":
|
||||||
states.append('warning')
|
states.append("warning")
|
||||||
|
|
||||||
intf = widget.get('intf')
|
intf = widget.get("intf")
|
||||||
iftype = 'wireless' if self._iswlan(intf) else 'wired'
|
iftype = "wireless" if self._iswlan(intf) else "wired"
|
||||||
iftype = 'tunnel' if self._istunnel(intf) else iftype
|
iftype = "tunnel" if self._istunnel(intf) else iftype
|
||||||
|
|
||||||
states.append('{}-{}'.format(iftype, widget.get('state')))
|
states.append("{}-{}".format(iftype, widget.get("state")))
|
||||||
|
|
||||||
return states
|
return states
|
||||||
|
|
||||||
def _iswlan(self, intf):
|
def _iswlan(self, intf):
|
||||||
# wifi, wlan, wlp, seems to work for me
|
# wifi, wlan, wlp, seems to work for me
|
||||||
if intf.startswith('w'): return True
|
if intf.startswith("w"):
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _istunnel(self, intf):
|
def _istunnel(self, intf):
|
||||||
return intf.startswith('tun') or intf.startswith('wg')
|
return intf.startswith("tun") or intf.startswith("wg")
|
||||||
|
|
||||||
def get_addresses(self, intf):
|
def get_addresses(self, intf):
|
||||||
retval = []
|
retval = []
|
||||||
try:
|
try:
|
||||||
for ip in netifaces.ifaddresses(intf).get(netifaces.AF_INET, []):
|
for ip in netifaces.ifaddresses(intf).get(netifaces.AF_INET, []):
|
||||||
if ip.get('addr', '') != '':
|
if ip.get("addr", "") != "":
|
||||||
retval.append(ip.get('addr'))
|
retval.append(ip.get("addr"))
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
def _update_widgets(self, widgets):
|
def _update_widgets(self, widgets):
|
||||||
interfaces = [i for i in netifaces.interfaces() if not i.startswith(self._exclude)]
|
interfaces = [
|
||||||
|
i for i in netifaces.interfaces() if not i.startswith(self._exclude)
|
||||||
|
]
|
||||||
interfaces.extend([i for i in netifaces.interfaces() if i in self._include])
|
interfaces.extend([i for i in netifaces.interfaces() if i in self._include])
|
||||||
|
|
||||||
for widget in widgets:
|
for widget in widgets:
|
||||||
widget.set('visited', False)
|
widget.set("visited", False)
|
||||||
|
|
||||||
for intf in interfaces:
|
for intf in interfaces:
|
||||||
addr = []
|
addr = []
|
||||||
state = 'down'
|
state = "down"
|
||||||
for ip in self.get_addresses(intf):
|
for ip in self.get_addresses(intf):
|
||||||
addr.append(ip)
|
addr.append(ip)
|
||||||
state = 'up'
|
state = "up"
|
||||||
|
|
||||||
if len(self._states['exclude']) > 0 and state in self._states['exclude']: continue
|
if len(self._states["exclude"]) > 0 and state in self._states["exclude"]:
|
||||||
if len(self._states['include']) > 0 and state not in self._states['include']: continue
|
continue
|
||||||
|
if (
|
||||||
|
len(self._states["include"]) > 0
|
||||||
|
and state not in self._states["include"]
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
widget = self.widget(intf)
|
widget = self.widget(intf)
|
||||||
if not widget:
|
if not widget:
|
||||||
widget = core.widget.Widget(name=intf, module=self)
|
widget = core.widget.Widget(name=intf, module=self)
|
||||||
widgets.append(widget)
|
widgets.append(widget)
|
||||||
# join/split is used to get rid of multiple whitespaces (in case SSID is not available, for instance
|
# join/split is used to get rid of multiple whitespaces (in case SSID is not available, for instance
|
||||||
widget.full_text(' '.join(self._format.format(ip=', '.join(addr),intf=intf,state=state,ssid=self.get_ssid(intf)).split()))
|
widget.full_text(
|
||||||
widget.set('intf', intf)
|
" ".join(
|
||||||
widget.set('state', state)
|
self._format.format(
|
||||||
widget.set('visited', True)
|
ip=", ".join(addr),
|
||||||
|
intf=intf,
|
||||||
|
state=state,
|
||||||
|
ssid=self.get_ssid(intf),
|
||||||
|
).split()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
widget.set("intf", intf)
|
||||||
|
widget.set("state", state)
|
||||||
|
widget.set("visited", True)
|
||||||
|
|
||||||
for widget in widgets:
|
for widget in widgets:
|
||||||
if widget.get('visited') is False:
|
if widget.get("visited") is False:
|
||||||
widgets.remove(widget)
|
widgets.remove(widget)
|
||||||
|
|
||||||
def get_ssid(self, intf):
|
def get_ssid(self, intf):
|
||||||
if self._iswlan(intf) and self.iwgetid:
|
if self._iswlan(intf) and self.iwgetid:
|
||||||
return util.cli.execute('{} -r {}'.format(self.iwgetid, intf), ignore_errors=True)
|
return util.cli.execute(
|
||||||
return ''
|
"{} -r {}".format(self.iwgetid, intf), ignore_errors=True
|
||||||
|
)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from .__pulseaudio import Module
|
from .__pulseaudio import Module
|
||||||
|
|
||||||
|
|
||||||
class Module(Module):
|
class Module(Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, 'sink')
|
super().__init__(config, theme, "sink")
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from .__pulseaudio import Module
|
from .__pulseaudio import Module
|
||||||
|
|
||||||
|
|
||||||
class Module(Module):
|
class Module(Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, 'source')
|
super().__init__(config, theme, "source")
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -24,30 +24,39 @@ import core.decorators
|
||||||
|
|
||||||
import util.cli
|
import util.cli
|
||||||
|
|
||||||
|
|
||||||
def get_rtt(module, widget):
|
def get_rtt(module, widget):
|
||||||
try:
|
try:
|
||||||
widget.set('rtt-unreachable', False)
|
widget.set("rtt-unreachable", False)
|
||||||
res = util.cli.execute('ping -n -q -c {} -W {} {}'.format(
|
res = util.cli.execute(
|
||||||
widget.get('rtt-probes'), widget.get('rtt-timeout'), widget.get('address')
|
"ping -n -q -c {} -W {} {}".format(
|
||||||
))
|
widget.get("rtt-probes"),
|
||||||
|
widget.get("rtt-timeout"),
|
||||||
|
widget.get("address"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
for line in res.split('\n'):
|
for line in res.split("\n"):
|
||||||
if line.startswith('{} packets transmitted'.format(widget.get('rtt-probes'))):
|
if line.startswith(
|
||||||
m = re.search(r'(\d+)% packet loss', line)
|
"{} packets transmitted".format(widget.get("rtt-probes"))
|
||||||
|
):
|
||||||
|
m = re.search(r"(\d+)% packet loss", line)
|
||||||
|
|
||||||
widget.set('packet-loss', m.group(1))
|
widget.set("packet-loss", m.group(1))
|
||||||
|
|
||||||
if not line.startswith('rtt'): continue
|
if not line.startswith("rtt"):
|
||||||
m = re.search(r'([0-9\.]+)/([0-9\.]+)/([0-9\.]+)/([0-9\.]+)\s+(\S+)', line)
|
continue
|
||||||
|
m = re.search(r"([0-9\.]+)/([0-9\.]+)/([0-9\.]+)/([0-9\.]+)\s+(\S+)", line)
|
||||||
|
|
||||||
widget.set('rtt-min', float(m.group(1)))
|
widget.set("rtt-min", float(m.group(1)))
|
||||||
widget.set('rtt-avg', float(m.group(2)))
|
widget.set("rtt-avg", float(m.group(2)))
|
||||||
widget.set('rtt-max', float(m.group(3)))
|
widget.set("rtt-max", float(m.group(3)))
|
||||||
widget.set('rtt-unit', m.group(5))
|
widget.set("rtt-unit", m.group(5))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
widget.set('rtt-unreachable', True)
|
widget.set("rtt-unreachable", True)
|
||||||
|
|
||||||
|
core.event.trigger("update", [module.id], redraw_only=True)
|
||||||
|
|
||||||
core.event.trigger('update', [ module.id ], redraw_only=True)
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=60)
|
@core.decorators.every(seconds=60)
|
||||||
|
@ -56,29 +65,31 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
widget = self.widget()
|
widget = self.widget()
|
||||||
|
|
||||||
widget.set('address', self.parameter('address', '8.8.8.8'))
|
widget.set("address", self.parameter("address", "8.8.8.8"))
|
||||||
widget.set('rtt-probes', self.parameter('probes', 5))
|
widget.set("rtt-probes", self.parameter("probes", 5))
|
||||||
widget.set('rtt-timeout', self.parameter('timeout', 5.0))
|
widget.set("rtt-timeout", self.parameter("timeout", 5.0))
|
||||||
widget.set('rtt-avg', 0.0)
|
widget.set("rtt-avg", 0.0)
|
||||||
widget.set('rtt-unit', '')
|
widget.set("rtt-unit", "")
|
||||||
widget.set('packet-loss', 0)
|
widget.set("packet-loss", 0)
|
||||||
|
|
||||||
def rtt(self, widget):
|
def rtt(self, widget):
|
||||||
if widget.get('rtt-unreachable'):
|
if widget.get("rtt-unreachable"):
|
||||||
return '{}: unreachable'.format(widget.get('address'))
|
return "{}: unreachable".format(widget.get("address"))
|
||||||
return '{}: {:.1f}{} ({}%)'.format(
|
return "{}: {:.1f}{} ({}%)".format(
|
||||||
widget.get('address'),
|
widget.get("address"),
|
||||||
widget.get('rtt-avg'),
|
widget.get("rtt-avg"),
|
||||||
widget.get('rtt-unit'),
|
widget.get("rtt-unit"),
|
||||||
widget.get('packet-loss')
|
widget.get("packet-loss"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
if widget.get('rtt-unreachable'): return ['critical']
|
if widget.get("rtt-unreachable"):
|
||||||
return self.threshold_state(widget.get('rtt-avg'), 1000.0, 2000.0)
|
return ["critical"]
|
||||||
|
return self.threshold_state(widget.get("rtt-avg"), 1000.0, 2000.0)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
thread = threading.Thread(target=get_rtt, args=(self, self.widget(),))
|
thread = threading.Thread(target=get_rtt, args=(self, self.widget(),))
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -24,45 +24,49 @@ import core.decorators
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.location
|
import util.location
|
||||||
|
|
||||||
|
|
||||||
def get_redshift_value(module):
|
def get_redshift_value(module):
|
||||||
widget = module.widget()
|
widget = module.widget()
|
||||||
location = module.parameter('location', 'auto')
|
location = module.parameter("location", "auto")
|
||||||
lat = module.parameter('lat', None)
|
lat = module.parameter("lat", None)
|
||||||
lon = module.parameter('lon', None)
|
lon = module.parameter("lon", None)
|
||||||
|
|
||||||
# Even if location method is set to manual, if we have no lat or lon,
|
# Even if location method is set to manual, if we have no lat or lon,
|
||||||
# fall back to the geoclue2 method.
|
# fall back to the geoclue2 method.
|
||||||
if location == 'manual' and (lat is None or lon is None):
|
if location == "manual" and (lat is None or lon is None):
|
||||||
location = 'geoclue2'
|
location = "geoclue2"
|
||||||
|
|
||||||
command = ['redshift', '-p']
|
command = ["redshift", "-p"]
|
||||||
if location == 'manual':
|
if location == "manual":
|
||||||
command.extend(['-l', '{}:{}'.format(lat, lon)])
|
command.extend(["-l", "{}:{}".format(lat, lon)])
|
||||||
if location == 'geoclue2':
|
if location == "geoclue2":
|
||||||
command.extend(['-l', 'geoclue2'])
|
command.extend(["-l", "geoclue2"])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
res = util.cli.execute(' '.join(command))
|
res = util.cli.execute(" ".join(command))
|
||||||
except Exception:
|
except Exception:
|
||||||
res = ''
|
res = ""
|
||||||
widget.set('temp', 'n/a')
|
widget.set("temp", "n/a")
|
||||||
widget.set('transition', '')
|
widget.set("transition", "")
|
||||||
widget.set('state', 'day')
|
widget.set("state", "day")
|
||||||
for line in res.split('\n'):
|
for line in res.split("\n"):
|
||||||
line = line.lower()
|
line = line.lower()
|
||||||
if 'temperature' in line:
|
if "temperature" in line:
|
||||||
widget.set('temp', line.split(' ')[2])
|
widget.set("temp", line.split(" ")[2])
|
||||||
if 'period' in line:
|
if "period" in line:
|
||||||
state = line.split(' ')[1]
|
state = line.split(" ")[1]
|
||||||
if 'day' in state:
|
if "day" in state:
|
||||||
widget.set('state', 'day')
|
widget.set("state", "day")
|
||||||
elif 'night' in state:
|
elif "night" in state:
|
||||||
widget.set('state', 'night')
|
widget.set("state", "night")
|
||||||
else:
|
else:
|
||||||
widget.set('state', 'transition')
|
widget.set("state", "transition")
|
||||||
match = re.search(r'(\d+)\.\d+% ([a-z]+)', line)
|
match = re.search(r"(\d+)\.\d+% ([a-z]+)", line)
|
||||||
widget.set('transition', '({}% {})'.format(match.group(1), match.group(2)))
|
widget.set(
|
||||||
core.event.trigger('update', [ widget.module.id ], redraw_only=True)
|
"transition", "({}% {})".format(match.group(1), match.group(2))
|
||||||
|
)
|
||||||
|
core.event.trigger("update", [widget.module.id], redraw_only=True)
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=10)
|
@core.decorators.every(seconds=10)
|
||||||
|
@ -71,24 +75,24 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
self.__thread = None
|
self.__thread = None
|
||||||
|
|
||||||
if self.parameter('location', '') == 'ipinfo':
|
if self.parameter("location", "") == "ipinfo":
|
||||||
# override lon/lat with ipinfo
|
# override lon/lat with ipinfo
|
||||||
try:
|
try:
|
||||||
location = util.location.coordinates()
|
location = util.location.coordinates()
|
||||||
self.set('lat', location[0])
|
self.set("lat", location[0])
|
||||||
self.set('lon', location[1])
|
self.set("lon", location[1])
|
||||||
self.set('location', 'manual')
|
self.set("location", "manual")
|
||||||
except Exception:
|
except Exception:
|
||||||
# Fall back to geoclue2.
|
# Fall back to geoclue2.
|
||||||
self.set('location', 'geoclue2')
|
self.set("location", "geoclue2")
|
||||||
|
|
||||||
self._text = ''
|
self._text = ""
|
||||||
|
|
||||||
def text(self, widget):
|
def text(self, widget):
|
||||||
val = widget.get('temp', 'n/a')
|
val = widget.get("temp", "n/a")
|
||||||
transition = widget.get('transition', '')
|
transition = widget.get("transition", "")
|
||||||
if transition:
|
if transition:
|
||||||
val = '{} {}'.format(val, transition)
|
val = "{} {}".format(val, transition)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
@ -98,6 +102,7 @@ class Module(core.module.Module):
|
||||||
self.__thread.start()
|
self.__thread.start()
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return widget.get('state', None)
|
return widget.get("state", None)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -26,11 +26,12 @@ import core.widget
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.format
|
import util.format
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, [])
|
super().__init__(config, theme, [])
|
||||||
|
|
||||||
self.__chip = self.parameter('chip', '')
|
self.__chip = self.parameter("chip", "")
|
||||||
self.__data = {}
|
self.__data = {}
|
||||||
self.__update()
|
self.__update()
|
||||||
|
|
||||||
|
@ -42,31 +43,45 @@ class Module(core.module.Module):
|
||||||
self.__update_widget(widget)
|
self.__update_widget(widget)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
widget_type = widget.get('type', '')
|
widget_type = widget.get("type", "")
|
||||||
try:
|
try:
|
||||||
data = self.__data[widget.get('adapter')][widget.get('package')][widget.get('field')]
|
data = self.__data[widget.get("adapter")][widget.get("package")][
|
||||||
if 'crit' in data and float(data['input']) > float(data['crit']):
|
widget.get("field")
|
||||||
return ['critical', widget_type]
|
]
|
||||||
if 'max' in data and float(data['input']) > float(data['max']):
|
if "crit" in data and float(data["input"]) > float(data["crit"]):
|
||||||
return ['warning', widget_type]
|
return ["critical", widget_type]
|
||||||
|
if "max" in data and float(data["input"]) > float(data["max"]):
|
||||||
|
return ["warning", widget_type]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return [widget_type]
|
return [widget_type]
|
||||||
|
|
||||||
def __create_widgets(self):
|
def __create_widgets(self):
|
||||||
show_temp = util.format.asbool(self.parameter('showtemp', True))
|
show_temp = util.format.asbool(self.parameter("showtemp", True))
|
||||||
show_fan = util.format.asbool(self.parameter('showfan', True))
|
show_fan = util.format.asbool(self.parameter("showfan", True))
|
||||||
show_other = util.format.asbool(self.parameter('showother', False))
|
show_other = util.format.asbool(self.parameter("showother", False))
|
||||||
include_chip = tuple(filter(len, util.format.aslist(self.parameter('chip_include', ''))))
|
include_chip = tuple(
|
||||||
exclude_chip = tuple(filter(len, util.format.aslist(self.parameter('chip_exclude', ''))))
|
filter(len, util.format.aslist(self.parameter("chip_include", "")))
|
||||||
include_field = tuple(filter(len, util.format.aslist(self.parameter('field_include', ''))))
|
)
|
||||||
exclude_field = tuple(filter(len, util.format.aslist(self.parameter('field_exclude', ''))))
|
exclude_chip = tuple(
|
||||||
include_chip_field = tuple(filter(len, util.format.aslist(self.parameter('chip_field_include', ''))))
|
filter(len, util.format.aslist(self.parameter("chip_exclude", "")))
|
||||||
exclude_chip_field = tuple(filter(len, util.format.aslist(self.parameter('chip_field_exclude', ''))))
|
)
|
||||||
|
include_field = tuple(
|
||||||
|
filter(len, util.format.aslist(self.parameter("field_include", "")))
|
||||||
|
)
|
||||||
|
exclude_field = tuple(
|
||||||
|
filter(len, util.format.aslist(self.parameter("field_exclude", "")))
|
||||||
|
)
|
||||||
|
include_chip_field = tuple(
|
||||||
|
filter(len, util.format.aslist(self.parameter("chip_field_include", "")))
|
||||||
|
)
|
||||||
|
exclude_chip_field = tuple(
|
||||||
|
filter(len, util.format.aslist(self.parameter("chip_field_exclude", "")))
|
||||||
|
)
|
||||||
|
|
||||||
if util.format.asbool(self.parameter('showcpu', True)):
|
if util.format.asbool(self.parameter("showcpu", True)):
|
||||||
widget = self.add_widget(full_text=self.__cpu)
|
widget = self.add_widget(full_text=self.__cpu)
|
||||||
widget.set('type', 'cpu')
|
widget.set("type", "cpu")
|
||||||
|
|
||||||
for adapter in self.__data:
|
for adapter in self.__data:
|
||||||
if include_chip or exclude_chip:
|
if include_chip or exclude_chip:
|
||||||
|
@ -79,23 +94,27 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
if include_chip_field:
|
if include_chip_field:
|
||||||
try:
|
try:
|
||||||
if all([i.split('.')[0] not in adapter for i in include_chip_field]):
|
if all(
|
||||||
|
[i.split(".")[0] not in adapter for i in include_chip_field]
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for package in self.__data[adapter]:
|
for package in self.__data[adapter]:
|
||||||
if util.format.asbool(self.parameter('showname', False)):
|
if util.format.asbool(self.parameter("showname", False)):
|
||||||
widget = self.add_widget(full_text=package)
|
widget = self.add_widget(full_text=package)
|
||||||
widget.set('data', self.__data[adapter][package])
|
widget.set("data", self.__data[adapter][package])
|
||||||
widget.set('package', package)
|
widget.set("package", package)
|
||||||
widget.set('field', '')
|
widget.set("field", "")
|
||||||
widget.set('adapter', adapter)
|
widget.set("adapter", adapter)
|
||||||
for field in self.__data[adapter][package]:
|
for field in self.__data[adapter][package]:
|
||||||
|
|
||||||
if include_field or exclude_field:
|
if include_field or exclude_field:
|
||||||
if include_field:
|
if include_field:
|
||||||
if all([included not in field for included in include_field]):
|
if all(
|
||||||
|
[included not in field for included in include_field]
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if any([excluded in field for excluded in exclude_field]):
|
if any([excluded in field for excluded in exclude_field]):
|
||||||
|
@ -104,62 +123,79 @@ class Module(core.module.Module):
|
||||||
try:
|
try:
|
||||||
if include_chip_field or exclude_chip_field:
|
if include_chip_field or exclude_chip_field:
|
||||||
if include_chip_field:
|
if include_chip_field:
|
||||||
if all([i.split('.')[1] not in field for i in include_chip_field if i.split('.')[0] in adapter]):
|
if all(
|
||||||
|
[
|
||||||
|
i.split(".")[1] not in field
|
||||||
|
for i in include_chip_field
|
||||||
|
if i.split(".")[0] in adapter
|
||||||
|
]
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if any([i.split('.')[1] in field for i in exclude_chip_field if i.split('.')[0] in adapter]):
|
if any(
|
||||||
|
[
|
||||||
|
i.split(".")[1] in field
|
||||||
|
for i in exclude_chip_field
|
||||||
|
if i.split(".")[0] in adapter
|
||||||
|
]
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
widget = None
|
widget = None
|
||||||
if 'temp' in field and show_temp:
|
if "temp" in field and show_temp:
|
||||||
# seems to be a temperature
|
# seems to be a temperature
|
||||||
widget = self.add_widget()
|
widget = self.add_widget()
|
||||||
widget.set('type', 'temp')
|
widget.set("type", "temp")
|
||||||
if 'fan' in field and show_fan:
|
if "fan" in field and show_fan:
|
||||||
# seems to be a fan
|
# seems to be a fan
|
||||||
widget = self.add_widget()
|
widget = self.add_widget()
|
||||||
widget.set('type', 'fan')
|
widget.set("type", "fan")
|
||||||
elif show_other:
|
elif show_other:
|
||||||
# everything else
|
# everything else
|
||||||
widget = self.add_widget()
|
widget = self.add_widget()
|
||||||
widget.set('type', 'other')
|
widget.set("type", "other")
|
||||||
if widget:
|
if widget:
|
||||||
widget.set('package', package)
|
widget.set("package", package)
|
||||||
widget.set('field', field)
|
widget.set("field", field)
|
||||||
widget.set('adapter', adapter)
|
widget.set("adapter", adapter)
|
||||||
|
|
||||||
def __update_widget(self, widget):
|
def __update_widget(self, widget):
|
||||||
if widget.get('field', '') == '':
|
if widget.get("field", "") == "":
|
||||||
return # nothing to do
|
return # nothing to do
|
||||||
data = self.__data[widget.get('adapter')][widget.get('package')][widget.get('field')]
|
data = self.__data[widget.get("adapter")][widget.get("package")][
|
||||||
if 'temp' in widget.get('field'):
|
widget.get("field")
|
||||||
widget.full_text(u'{:0.01f}°C'.format(data['input']))
|
]
|
||||||
elif 'fan' in widget.get('field'):
|
if "temp" in widget.get("field"):
|
||||||
widget.full_text(u'{:0.0f}RPM'.format(data['input']))
|
widget.full_text("{:0.01f}°C".format(data["input"]))
|
||||||
|
elif "fan" in widget.get("field"):
|
||||||
|
widget.full_text("{:0.0f}RPM".format(data["input"]))
|
||||||
else:
|
else:
|
||||||
widget.full_text(u'{:0.0f}'.format(data['input']))
|
widget.full_text("{:0.0f}".format(data["input"]))
|
||||||
|
|
||||||
def __update(self):
|
def __update(self):
|
||||||
output = util.cli.execute('sensors -u {}'.format(self.__chip), ignore_errors=True)
|
output = util.cli.execute(
|
||||||
|
"sensors -u {}".format(self.__chip), ignore_errors=True
|
||||||
|
)
|
||||||
self.__data = self.__parse(output)
|
self.__data = self.__parse(output)
|
||||||
|
|
||||||
def __parse(self, data):
|
def __parse(self, data):
|
||||||
output = {}
|
output = {}
|
||||||
package = ''
|
package = ""
|
||||||
adapter = None
|
adapter = None
|
||||||
chip = None
|
chip = None
|
||||||
for line in data.split('\n'):
|
for line in data.split("\n"):
|
||||||
if 'Adapter' in line:
|
if "Adapter" in line:
|
||||||
# new adapter
|
# new adapter
|
||||||
line = line.replace('Adapter: ', '')
|
line = line.replace("Adapter: ", "")
|
||||||
output[chip + ' ' + line] = {}
|
output[chip + " " + line] = {}
|
||||||
adapter = chip + ' ' + line
|
adapter = chip + " " + line
|
||||||
chip = line #default - line before adapter is always the chip
|
chip = line # default - line before adapter is always the chip
|
||||||
if not adapter: continue
|
if not adapter:
|
||||||
key, value = (line.split(':') + ['', ''])[:2]
|
continue
|
||||||
if not line.startswith(' '):
|
key, value = (line.split(":") + ["", ""])[:2]
|
||||||
|
if not line.startswith(" "):
|
||||||
# assume this starts a new package
|
# assume this starts a new package
|
||||||
if package in output[adapter] and output[adapter][package] == {}:
|
if package in output[adapter] and output[adapter][package] == {}:
|
||||||
del output[adapter][package]
|
del output[adapter][package]
|
||||||
|
@ -168,9 +204,9 @@ class Module(core.module.Module):
|
||||||
else:
|
else:
|
||||||
# feature for this chip
|
# feature for this chip
|
||||||
try:
|
try:
|
||||||
name, variant = (key.strip().split('_', 1) + ['',''])[:2]
|
name, variant = (key.strip().split("_", 1) + ["", ""])[:2]
|
||||||
if not name in output[adapter][package]:
|
if not name in output[adapter][package]:
|
||||||
output[adapter][package][name] = { }
|
output[adapter][package][name] = {}
|
||||||
if variant:
|
if variant:
|
||||||
output[adapter][package][name][variant] = {}
|
output[adapter][package][name][variant] = {}
|
||||||
output[adapter][package][name][variant] = float(value)
|
output[adapter][package][name][variant] = float(value)
|
||||||
|
@ -181,23 +217,26 @@ class Module(core.module.Module):
|
||||||
def __cpu(self, _):
|
def __cpu(self, _):
|
||||||
mhz = None
|
mhz = None
|
||||||
try:
|
try:
|
||||||
output = open('/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq').read()
|
output = open(
|
||||||
mhz = int(float(output)/1000.0)
|
"/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq"
|
||||||
|
).read()
|
||||||
|
mhz = int(float(output) / 1000.0)
|
||||||
except:
|
except:
|
||||||
output = open('/proc/cpuinfo').read()
|
output = open("/proc/cpuinfo").read()
|
||||||
m = re.search(r'cpu MHz\s+:\s+(\d+)', output)
|
m = re.search(r"cpu MHz\s+:\s+(\d+)", output)
|
||||||
if m:
|
if m:
|
||||||
mhz = int(m.group(1))
|
mhz = int(m.group(1))
|
||||||
else:
|
else:
|
||||||
m = re.search(r'BogoMIPS\s+:\s+(\d+)', output)
|
m = re.search(r"BogoMIPS\s+:\s+(\d+)", output)
|
||||||
if m:
|
if m:
|
||||||
return '{} BogoMIPS'.format(int(m.group(1)))
|
return "{} BogoMIPS".format(int(m.group(1)))
|
||||||
if not mhz:
|
if not mhz:
|
||||||
return 'n/a'
|
return "n/a"
|
||||||
|
|
||||||
if mhz < 1000:
|
if mhz < 1000:
|
||||||
return '{} MHz'.format(mhz)
|
return "{} MHz".format(mhz)
|
||||||
else:
|
else:
|
||||||
return '{:0.01f} GHz'.format(float(mhz)/1000.0)
|
return "{:0.01f} GHz".format(float(mhz) / 1000.0)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,6 +10,7 @@ import core.module
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.decorators
|
import core.decorators
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(minutes=60)
|
@core.decorators.every(minutes=60)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
|
@ -19,4 +20,5 @@ class Module(core.module.Module):
|
||||||
def text(self, _):
|
def text(self, _):
|
||||||
return self.__text
|
return self.__text
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
import core.widget
|
import core.widget
|
||||||
import core.module
|
import core.module
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config=config, theme=theme, widgets=core.widget.Widget('test'))
|
super().__init__(config=config, theme=theme, widgets=core.widget.Widget("test"))
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -10,12 +10,14 @@ Parameters:
|
||||||
import core.decorators
|
import core.decorators
|
||||||
from .datetime import Module
|
from .datetime import Module
|
||||||
|
|
||||||
|
|
||||||
class Module(Module):
|
class Module(Module):
|
||||||
@core.decorators.every(seconds=59) # ensures one update per minute
|
@core.decorators.every(seconds=59) # ensures one update per minute
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme)
|
super().__init__(config, theme)
|
||||||
|
|
||||||
def default_format(self):
|
def default_format(self):
|
||||||
return '%X'
|
return "%X"
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -29,30 +29,39 @@ import core.event
|
||||||
import util.cli
|
import util.cli
|
||||||
import util.popup
|
import util.popup
|
||||||
|
|
||||||
|
|
||||||
def build_menu(parent, current_directory, callback):
|
def build_menu(parent, current_directory, callback):
|
||||||
with os.scandir(current_directory) as it:
|
with os.scandir(current_directory) as it:
|
||||||
for entry in it:
|
for entry in it:
|
||||||
if entry.name.startswith('.'): continue
|
if entry.name.startswith("."):
|
||||||
|
continue
|
||||||
if entry.is_file():
|
if entry.is_file():
|
||||||
name = entry.name[:entry.name.rfind('.')]
|
name = entry.name[: entry.name.rfind(".")]
|
||||||
parent.add_menuitem(name, callback=lambda : callback(os.path.join(current_directory, name)))
|
parent.add_menuitem(
|
||||||
|
name,
|
||||||
|
callback=lambda: callback(os.path.join(current_directory, name)),
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
submenu = util.popup.menu(parent, leave=False)
|
submenu = util.popup.menu(parent, leave=False)
|
||||||
build_menu(submenu, os.path.join(current_directory, entry.name), callback)
|
build_menu(
|
||||||
|
submenu, os.path.join(current_directory, entry.name), callback
|
||||||
|
)
|
||||||
parent.add_cascade(entry.name, submenu)
|
parent.add_cascade(entry.name, submenu)
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.text))
|
super().__init__(config, theme, core.widget.Widget(self.text))
|
||||||
|
|
||||||
self.__duration = int(self.parameter('duration', 30))
|
self.__duration = int(self.parameter("duration", 30))
|
||||||
self.__offx = int(self.parameter('offx', 0))
|
self.__offx = int(self.parameter("offx", 0))
|
||||||
self.__offy = int(self.parameter('offy', 0))
|
self.__offy = int(self.parameter("offy", 0))
|
||||||
self.__path = os.path.expanduser(self.parameter('location', '~/.password-store/'))
|
self.__path = os.path.expanduser(
|
||||||
|
self.parameter("location", "~/.password-store/")
|
||||||
|
)
|
||||||
self.__reset()
|
self.__reset()
|
||||||
core.input.register(self, button=core.input.LEFT_MOUSE,
|
core.input.register(self, button=core.input.LEFT_MOUSE, cmd=self.popup)
|
||||||
cmd=self.popup)
|
|
||||||
|
|
||||||
def popup(self, widget):
|
def popup(self, widget):
|
||||||
menu = util.popup.menu(leave=False)
|
menu = util.popup.menu(leave=False)
|
||||||
|
@ -62,14 +71,17 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def __reset(self):
|
def __reset(self):
|
||||||
self.__timer = None
|
self.__timer = None
|
||||||
self.__text = str(self.parameter('text', '<click-for-password>'))
|
self.__text = str(self.parameter("text", "<click-for-password>"))
|
||||||
|
|
||||||
def __callback(self, secret_name):
|
def __callback(self, secret_name):
|
||||||
secret_name = secret_name.replace(self.__path, '') # remove common path
|
secret_name = secret_name.replace(self.__path, "") # remove common path
|
||||||
if self.__timer:
|
if self.__timer:
|
||||||
self.__timer.cancel()
|
self.__timer.cancel()
|
||||||
res = util.cli.execute('pass -c {}'.format(secret_name), wait=False,
|
res = util.cli.execute(
|
||||||
env={ 'PASSWORD_STORE_CLIP_TIME': self.__duration })
|
"pass -c {}".format(secret_name),
|
||||||
|
wait=False,
|
||||||
|
env={"PASSWORD_STORE_CLIP_TIME": self.__duration},
|
||||||
|
)
|
||||||
self.__timer = threading.Timer(self.__duration, self.__reset)
|
self.__timer = threading.Timer(self.__duration, self.__reset)
|
||||||
self.__timer.start()
|
self.__timer.start()
|
||||||
self.__start = int(time.time())
|
self.__start = int(time.time())
|
||||||
|
@ -77,7 +89,10 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
def text(self, widget):
|
def text(self, widget):
|
||||||
if self.__timer:
|
if self.__timer:
|
||||||
return '{} ({}s)'.format(self.__text, self.__duration - (int(time.time()) - self.__start))
|
return "{} ({}s)".format(
|
||||||
|
self.__text, self.__duration - (int(time.time()) - self.__start)
|
||||||
|
)
|
||||||
return self.__text
|
return self.__text
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# pylint: disable=C0111,R0903
|
# pylint: disable=C0111,R0903
|
||||||
|
|
||||||
'''Shows a widget for each connected screen and allows the user to enable/disable screens.
|
"""Shows a widget for each connected screen and allows the user to enable/disable screens.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
* xrandr.overwrite_i3config: If set to 'true', this module assembles a new i3 config
|
* xrandr.overwrite_i3config: If set to 'true', this module assembles a new i3 config
|
||||||
|
@ -14,7 +14,7 @@ Requires the following python module:
|
||||||
|
|
||||||
Requires the following executable:
|
Requires the following executable:
|
||||||
* xrandr
|
* xrandr
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -33,17 +33,18 @@ try:
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=5) # takes up to 5s to detect a new screen
|
@core.decorators.every(seconds=5) # takes up to 5s to detect a new screen
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
widgets = []
|
widgets = []
|
||||||
super().__init__(config, theme, widgets)
|
super().__init__(config, theme, widgets)
|
||||||
|
|
||||||
self._autoupdate = util.format.asbool(self.parameter('autoupdate', True))
|
self._autoupdate = util.format.asbool(self.parameter("autoupdate", True))
|
||||||
self._needs_update = True
|
self._needs_update = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
i3.Subscription(self._output_update, 'output')
|
i3.Subscription(self._output_update, "output")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -58,31 +59,33 @@ class Module(core.module.Module):
|
||||||
|
|
||||||
self._needs_update = False
|
self._needs_update = False
|
||||||
|
|
||||||
for line in util.cli.execute('xrandr -q').split('\n'):
|
for line in util.cli.execute("xrandr -q").split("\n"):
|
||||||
if not ' connected' in line:
|
if not " connected" in line:
|
||||||
continue
|
continue
|
||||||
display = line.split(' ', 2)[0]
|
display = line.split(" ", 2)[0]
|
||||||
m = re.search(r'\d+x\d+\+(\d+)\+\d+', line)
|
m = re.search(r"\d+x\d+\+(\d+)\+\d+", line)
|
||||||
|
|
||||||
widget = self.widget(display)
|
widget = self.widget(display)
|
||||||
if not widget:
|
if not widget:
|
||||||
widget = core.widget.Widget(full_text=display, name=display, module=self)
|
widget = core.widget.Widget(
|
||||||
|
full_text=display, name=display, module=self
|
||||||
|
)
|
||||||
core.input.register(widget, button=1, cmd=self._toggle)
|
core.input.register(widget, button=1, cmd=self._toggle)
|
||||||
core.input.register(widget, button=3, cmd=self._toggle)
|
core.input.register(widget, button=3, cmd=self._toggle)
|
||||||
new_widgets.append(widget)
|
new_widgets.append(widget)
|
||||||
widget.set('state', 'on' if m else 'off')
|
widget.set("state", "on" if m else "off")
|
||||||
widget.set('pos', int(m.group(1)) if m else sys.maxsize)
|
widget.set("pos", int(m.group(1)) if m else sys.maxsize)
|
||||||
|
|
||||||
self.widgets(new_widgets)
|
self.widgets(new_widgets)
|
||||||
|
|
||||||
if self._autoupdate == False:
|
if self._autoupdate == False:
|
||||||
widget = core.widget.Widget(full_text='', module=self)
|
widget = core.widget.Widget(full_text="", module=self)
|
||||||
widget.set('state', 'refresh')
|
widget.set("state", "refresh")
|
||||||
core.input.register(widget, button=1, cmd=self._refresh)
|
core.input.register(widget, button=1, cmd=self._refresh)
|
||||||
self.widgets().append(widget)
|
self.widgets().append(widget)
|
||||||
|
|
||||||
def state(self, widget):
|
def state(self, widget):
|
||||||
return widget.get('state', 'off')
|
return widget.get("state", "off")
|
||||||
|
|
||||||
def _refresh(self, event):
|
def _refresh(self, event):
|
||||||
self._needs_update = True
|
self._needs_update = True
|
||||||
|
@ -91,26 +94,50 @@ class Module(core.module.Module):
|
||||||
self._refresh(self, event)
|
self._refresh(self, event)
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
if util.format.asbool(self.parameter('overwrite_i3config', False)) == True:
|
if util.format.asbool(self.parameter("overwrite_i3config", False)) == True:
|
||||||
toggle_cmd = '{}/../../bin/toggle-display.sh'.format(path)
|
toggle_cmd = "{}/../../bin/toggle-display.sh".format(path)
|
||||||
else:
|
else:
|
||||||
toggle_cmd = 'xrandr'
|
toggle_cmd = "xrandr"
|
||||||
|
|
||||||
widget = self.widget_by_id(event['instance'])
|
widget = self.widget_by_id(event["instance"])
|
||||||
|
|
||||||
if widget.get('state') == 'on':
|
if widget.get("state") == "on":
|
||||||
util.cli.execute('{} --output {} --off'.format(toggle_cmd, widget.name))
|
util.cli.execute("{} --output {} --off".format(toggle_cmd, widget.name))
|
||||||
else:
|
else:
|
||||||
first_neighbor = next((widget for widget in self.widgets() if widget.get('state') == 'on'), None)
|
first_neighbor = next(
|
||||||
last_neighbor = next((widget for widget in reversed(self.widgets()) if widget.get('state') == 'on'), None)
|
(widget for widget in self.widgets() if widget.get("state") == "on"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
last_neighbor = next(
|
||||||
|
(
|
||||||
|
widget
|
||||||
|
for widget in reversed(self.widgets())
|
||||||
|
if widget.get("state") == "on"
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
neighbor = first_neighbor if event['button'] == core.input.LEFT_MOUSE else last_neighbor
|
neighbor = (
|
||||||
|
first_neighbor
|
||||||
|
if event["button"] == core.input.LEFT_MOUSE
|
||||||
|
else last_neighbor
|
||||||
|
)
|
||||||
|
|
||||||
if neighbor is None:
|
if neighbor is None:
|
||||||
util.cli.execute('{} --output {} --auto'.format(toggle_cmd, widget.name))
|
util.cli.execute(
|
||||||
|
"{} --output {} --auto".format(toggle_cmd, widget.name)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
util.cli.execute('{} --output {} --auto --{}-of {}'.format(toggle_cmd, widget.name,
|
util.cli.execute(
|
||||||
'left' if event.get('button') == core.input.LEFT_MOUSE else 'right',
|
"{} --output {} --auto --{}-of {}".format(
|
||||||
neighbor.name))
|
toggle_cmd,
|
||||||
|
widget.name,
|
||||||
|
"left"
|
||||||
|
if event.get("button") == core.input.LEFT_MOUSE
|
||||||
|
else "right",
|
||||||
|
neighbor.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -3,74 +3,83 @@ import unittest
|
||||||
|
|
||||||
import core.config
|
import core.config
|
||||||
|
|
||||||
|
|
||||||
class config(unittest.TestCase):
|
class config(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.someModules = [ 'b', 'x', 'a' ]
|
self.someModules = ["b", "x", "a"]
|
||||||
self.moreModules = [ 'this', 'module', 'here' ]
|
self.moreModules = ["this", "module", "here"]
|
||||||
self.someTheme = 'some-theme'
|
self.someTheme = "some-theme"
|
||||||
self.someIconset = 'some-iconset'
|
self.someIconset = "some-iconset"
|
||||||
self.defaultConfig = core.config.Config([])
|
self.defaultConfig = core.config.Config([])
|
||||||
|
|
||||||
def test_module(self):
|
def test_module(self):
|
||||||
cfg = core.config.Config([ '-m' ] + self.someModules)
|
cfg = core.config.Config(["-m"] + self.someModules)
|
||||||
self.assertEqual(self.someModules, cfg.modules())
|
self.assertEqual(self.someModules, cfg.modules())
|
||||||
|
|
||||||
def test_module_ordering_maintained(self):
|
def test_module_ordering_maintained(self):
|
||||||
cfg = core.config.Config([ '-m' ] + self.someModules + [ '-m' ] + self.moreModules)
|
cfg = core.config.Config(["-m"] + self.someModules + ["-m"] + self.moreModules)
|
||||||
self.assertEqual(self.someModules + self.moreModules, cfg.modules())
|
self.assertEqual(self.someModules + self.moreModules, cfg.modules())
|
||||||
|
|
||||||
def test_default_interval(self):
|
def test_default_interval(self):
|
||||||
self.assertEqual(1, self.defaultConfig.interval())
|
self.assertEqual(1, self.defaultConfig.interval())
|
||||||
|
|
||||||
def test_interval(self):
|
def test_interval(self):
|
||||||
cfg = core.config.Config([ '-p', 'interval=4'])
|
cfg = core.config.Config(["-p", "interval=4"])
|
||||||
self.assertEqual(4, cfg.interval())
|
self.assertEqual(4, cfg.interval())
|
||||||
|
|
||||||
def test_float_interval(self):
|
def test_float_interval(self):
|
||||||
cfg = core.config.Config([ '-p', 'interval=0.5'])
|
cfg = core.config.Config(["-p", "interval=0.5"])
|
||||||
self.assertEqual(0.5, cfg.interval())
|
self.assertEqual(0.5, cfg.interval())
|
||||||
|
|
||||||
def test_default_theme(self):
|
def test_default_theme(self):
|
||||||
self.assertEqual('default', self.defaultConfig.theme())
|
self.assertEqual("default", self.defaultConfig.theme())
|
||||||
|
|
||||||
def test_theme(self):
|
def test_theme(self):
|
||||||
cfg = core.config.Config(['-t', self.someTheme])
|
cfg = core.config.Config(["-t", self.someTheme])
|
||||||
self.assertEqual(self.someTheme, cfg.theme())
|
self.assertEqual(self.someTheme, cfg.theme())
|
||||||
|
|
||||||
def test_default_iconset(self):
|
def test_default_iconset(self):
|
||||||
self.assertEqual('auto', self.defaultConfig.iconset())
|
self.assertEqual("auto", self.defaultConfig.iconset())
|
||||||
|
|
||||||
def test_iconset(self):
|
def test_iconset(self):
|
||||||
cfg = core.config.Config(['-i', self.someIconset])
|
cfg = core.config.Config(["-i", self.someIconset])
|
||||||
self.assertEqual(self.someIconset, cfg.iconset())
|
self.assertEqual(self.someIconset, cfg.iconset())
|
||||||
|
|
||||||
def test_right_to_left(self):
|
def test_right_to_left(self):
|
||||||
cfg = core.config.Config(['-r'])
|
cfg = core.config.Config(["-r"])
|
||||||
self.assertTrue(cfg.reverse())
|
self.assertTrue(cfg.reverse())
|
||||||
self.assertFalse(self.defaultConfig.reverse())
|
self.assertFalse(self.defaultConfig.reverse())
|
||||||
|
|
||||||
def test_logfile(self):
|
def test_logfile(self):
|
||||||
cfg = core.config.Config(['-f', 'my-custom-logfile'])
|
cfg = core.config.Config(["-f", "my-custom-logfile"])
|
||||||
self.assertEquals(None, self.defaultConfig.logfile())
|
self.assertEquals(None, self.defaultConfig.logfile())
|
||||||
self.assertEquals('my-custom-logfile', cfg.logfile())
|
self.assertEquals("my-custom-logfile", cfg.logfile())
|
||||||
|
|
||||||
def test_all_modules(self):
|
def test_all_modules(self):
|
||||||
modules = core.config.all_modules()
|
modules = core.config.all_modules()
|
||||||
self.assertGreater(len(modules), 0)
|
self.assertGreater(len(modules), 0)
|
||||||
for module in modules:
|
for module in modules:
|
||||||
pyname = '{}.py'.format(module)
|
pyname = "{}.py".format(module)
|
||||||
base = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..', 'modules'))
|
base = os.path.abspath(
|
||||||
self.assertTrue(os.path.exists(os.path.join(base, 'contrib', pyname)) or os.path.exists(os.path.join(base, 'core', pyname)))
|
os.path.join(
|
||||||
|
os.path.dirname(os.path.realpath(__file__)), "..", "..", "modules"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
os.path.exists(os.path.join(base, "contrib", pyname))
|
||||||
|
or os.path.exists(os.path.join(base, "core", pyname))
|
||||||
|
)
|
||||||
|
|
||||||
def test_list_output(self):
|
def test_list_output(self):
|
||||||
with unittest.mock.patch('core.config.sys') as sys:
|
with unittest.mock.patch("core.config.sys") as sys:
|
||||||
cfg = core.config.Config([ '-l', 'themes' ])
|
cfg = core.config.Config(["-l", "themes"])
|
||||||
cfg = core.config.Config([ '-l', 'modules' ])
|
cfg = core.config.Config(["-l", "modules"])
|
||||||
cfg = core.config.Config([ '-l', 'modules-markdown' ])
|
cfg = core.config.Config(["-l", "modules-markdown"])
|
||||||
# TODO: think of some plausibility testing here
|
# TODO: think of some plausibility testing here
|
||||||
|
|
||||||
def test_missing_parameter(self):
|
def test_missing_parameter(self):
|
||||||
cfg = core.config.Config([ '-p', 'test.key' ])
|
cfg = core.config.Config(["-p", "test.key"])
|
||||||
self.assertEqual('no-value-set', cfg.get('test.key', 'no-value-set'))
|
self.assertEqual("no-value-set", cfg.get("test.key", "no-value-set"))
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -5,59 +5,62 @@ import core.widget
|
||||||
import core.module
|
import core.module
|
||||||
import core.config
|
import core.config
|
||||||
|
|
||||||
|
|
||||||
class TestModule(core.module.Module):
|
class TestModule(core.module.Module):
|
||||||
def __init__(self, config=None, theme=None):
|
def __init__(self, config=None, theme=None):
|
||||||
config = core.config.Config([])
|
config = core.config.Config([])
|
||||||
super().__init__(config, theme, core.widget.Widget(self.get))
|
super().__init__(config, theme, core.widget.Widget(self.get))
|
||||||
self.text = ''
|
self.text = ""
|
||||||
|
|
||||||
@core.decorators.scrollable
|
@core.decorators.scrollable
|
||||||
def get(self, widget):
|
def get(self, widget):
|
||||||
return self.text
|
return self.text
|
||||||
|
|
||||||
|
|
||||||
class config(unittest.TestCase):
|
class config(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.module = TestModule()
|
self.module = TestModule()
|
||||||
self.widget = self.module.widget()
|
self.widget = self.module.widget()
|
||||||
self.width = 10
|
self.width = 10
|
||||||
self.module.set('width', self.width)
|
self.module.set("width", self.width)
|
||||||
|
|
||||||
def test_no_text(self):
|
def test_no_text(self):
|
||||||
self.assertEqual('', self.module.text)
|
self.assertEqual("", self.module.text)
|
||||||
self.assertEqual('', self.module.get(self.widget))
|
self.assertEqual("", self.module.get(self.widget))
|
||||||
|
|
||||||
def test_smaller(self):
|
def test_smaller(self):
|
||||||
self.module.text = 'test'
|
self.module.text = "test"
|
||||||
self.assertLess(len(self.module.text), self.width)
|
self.assertLess(len(self.module.text), self.width)
|
||||||
self.assertEqual('test', self.module.get(self.widget))
|
self.assertEqual("test", self.module.get(self.widget))
|
||||||
|
|
||||||
def test_bigger(self):
|
def test_bigger(self):
|
||||||
self.module.text = 'abcdefghijklmnopqrst'
|
self.module.text = "abcdefghijklmnopqrst"
|
||||||
self.assertGreater(len(self.module.text), self.width)
|
self.assertGreater(len(self.module.text), self.width)
|
||||||
self.assertEqual(self.module.text[:self.width], self.module.get(self.widget))
|
self.assertEqual(self.module.text[: self.width], self.module.get(self.widget))
|
||||||
|
|
||||||
def test_bounce(self):
|
def test_bounce(self):
|
||||||
self.module.text = 'abcd'
|
self.module.text = "abcd"
|
||||||
self.module.set('width', 2)
|
self.module.set("width", 2)
|
||||||
self.assertEqual('ab', self.module.get(self.widget))
|
self.assertEqual("ab", self.module.get(self.widget))
|
||||||
self.assertEqual('bc', self.module.get(self.widget))
|
self.assertEqual("bc", self.module.get(self.widget))
|
||||||
self.assertEqual('cd', self.module.get(self.widget))
|
self.assertEqual("cd", self.module.get(self.widget))
|
||||||
self.assertEqual('bc', self.module.get(self.widget))
|
self.assertEqual("bc", self.module.get(self.widget))
|
||||||
self.assertEqual('ab', self.module.get(self.widget))
|
self.assertEqual("ab", self.module.get(self.widget))
|
||||||
self.assertEqual('bc', self.module.get(self.widget))
|
self.assertEqual("bc", self.module.get(self.widget))
|
||||||
self.assertEqual('cd', self.module.get(self.widget))
|
self.assertEqual("cd", self.module.get(self.widget))
|
||||||
self.assertEqual('bc', self.module.get(self.widget))
|
self.assertEqual("bc", self.module.get(self.widget))
|
||||||
self.assertEqual('ab', self.module.get(self.widget))
|
self.assertEqual("ab", self.module.get(self.widget))
|
||||||
|
|
||||||
def test_nobounce(self):
|
def test_nobounce(self):
|
||||||
self.module.set('scrolling.bounce', False)
|
self.module.set("scrolling.bounce", False)
|
||||||
self.module.text = 'abcd'
|
self.module.text = "abcd"
|
||||||
self.module.set('width', 2)
|
self.module.set("width", 2)
|
||||||
self.assertEqual('ab', self.module.get(self.widget))
|
self.assertEqual("ab", self.module.get(self.widget))
|
||||||
self.assertEqual('bc', self.module.get(self.widget))
|
self.assertEqual("bc", self.module.get(self.widget))
|
||||||
self.assertEqual('cd', self.module.get(self.widget))
|
self.assertEqual("cd", self.module.get(self.widget))
|
||||||
self.assertEqual('ab', self.module.get(self.widget))
|
self.assertEqual("ab", self.module.get(self.widget))
|
||||||
self.assertEqual('bc', self.module.get(self.widget))
|
self.assertEqual("bc", self.module.get(self.widget))
|
||||||
self.assertEqual('cd', self.module.get(self.widget))
|
self.assertEqual("cd", self.module.get(self.widget))
|
||||||
|
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue