Merge pull request #1 from tobi-wan-kenobi/master

updating everything
This commit is contained in:
Martin Morlot 2019-10-04 15:56:00 +02:00 committed by GitHub
commit b453c41230
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 739 additions and 192 deletions

7
Dockerfile Normal file
View file

@ -0,0 +1,7 @@
#start with a Python 3.x container
FROM python:3
#grab repository from github
RUN git clone --recursive https://github.com/tobi-wan-kenobi/bumblebee-status.git /var/bumblebee-status
#run the statusline with no modules or themes specified
CMD python3 /var/bumblebee-status/bumblebee-status

View file

@ -5,7 +5,7 @@
[![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage)
[![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status)
**Many, many thanks to all contributors! As of now, 47 of the modules are from various contributors (!), and only 19 from myself.**
**Many, many thanks to all contributors! As of now, 48 of the modules are from various contributors (!), and only 19 from myself.**
![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png)

View file

@ -25,7 +25,7 @@ def all_modules():
"name": mod
})
return result
class Module(object):
"""Module instance base class
@ -142,7 +142,7 @@ class Engine(object):
self._running = True
self._modules = []
self.input = inp
self._aliases = self._read_aliases()
self._aliases = self._aliases()
self.load_modules(config.modules())
self._current_module = None
self._theme = theme
@ -230,16 +230,16 @@ class Engine(object):
self.input.register_callback(obj=module,
button=button["id"], cmd=module.parameter(button["name"]))
def _read_aliases(self):
result = {}
for module in all_modules():
try:
mod = importlib.import_module("bumblebee.modules.{}".format(module["name"]))
for alias in getattr(mod, "ALIASES", []):
result[alias] = module["name"]
except Exception as error:
log.warning("failed to import {}: {}".format(module["name"], str(error)))
return result
def _aliases(self):
return {
'date': 'datetime',
'time': 'datetime',
'datetz': 'datetimetz',
'timetz': 'datetimetz',
'pasink': 'pulseaudio',
'pasource': 'pulseaudio',
'test-alias': 'test',
}
def _load_module(self, module_name, config_name=None):
"""Load specified module and return it as object"""

View file

@ -1,12 +1,17 @@
# pylint: disable=C0111,R0903
#pylint: disable=C0111,R0903,W0212
"""Enable/disable automatic screen locking.
Requires the following executables:
* xset
* xdg-screensaver
* xdotool
* xprop (as dependency for xdotool)
* notify-send
"""
import logging
import os
import psutil
import bumblebee.input
import bumblebee.output
import bumblebee.engine
@ -14,35 +19,84 @@ import bumblebee.engine
class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
super(Module, self).__init__(engine, config,
bumblebee.output.Widget(full_text=self.caffeine)
bumblebee.output.Widget(full_text="")
)
self._active = False
self._xid = None
engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE,
cmd=self._toggle
)
def caffeine(self, widget):
return ""
def _check_requirements(self):
requirements = ['xdotool', 'xprop', 'xdg-screensaver']
missing = []
for tool in requirements:
if not bumblebee.util.which(tool):
missing.append(tool)
return missing
def state(self, widget):
if self._active():
def _get_i3bar_xid(self):
xid = bumblebee.util.execute("xdotool search --class \"i3bar\"").partition('\n')[0].strip()
if xid.isdigit():
return xid
logging.warning("Module caffeine: xdotool couldn't get X window ID of \"i3bar\".")
return None
def _notify(self):
if not bumblebee.util.which('notify-send'):
return
if self._active:
bumblebee.util.execute("notify-send \"Consuming caffeine\"")
else:
bumblebee.util.execute("notify-send \"Out of coffee\"")
def _suspend_screensaver(self):
self._xid = self._get_i3bar_xid()
if self._xid is None:
return False
pid = os.fork()
if pid == 0:
os.setsid()
bumblebee.util.execute("xdg-screensaver suspend {}".format(self._xid))
os._exit(0)
else:
os.waitpid(pid, 0)
return True
def _resume_screensaver(self):
success = True
xprop_path = bumblebee.util.which('xprop')
pids = [ p.pid for p in psutil.process_iter() if p.cmdline() == [xprop_path, '-id', str(self._xid), '-spy'] ]
for pid in pids:
try:
os.kill(pid, 9)
except OSError:
success = False
return success
def state(self, _):
if self._active:
return "activated"
return "deactivated"
def _active(self):
for line in bumblebee.util.execute("xset q").split("\n"):
if "timeout" in line:
timeout = int(line.split(" ")[4])
if timeout == 0:
return True
return False
return False
def _toggle(self, _):
missing = self._check_requirements()
if missing:
logging.warning('Could not run caffeine - missing %s!', ", ".join(missing))
return
def _toggle(self, widget):
if self._active():
bumblebee.util.execute("xset s default")
bumblebee.util.execute("notify-send \"Out of coffee\"")
self._active = not self._active
if self._active:
success = self._suspend_screensaver()
else:
bumblebee.util.execute("xset s off")
bumblebee.util.execute("notify-send \"Consuming caffeine\"")
success = self._resume_screensaver()
if success:
self._notify()
else:
self._active = not self._active
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -16,8 +16,6 @@ import datetime
import locale
import bumblebee.engine
ALIASES = ["date", "time"]
def default_format(module):
default = "%x %X"
if module == "date":

View file

@ -26,8 +26,6 @@ import bumblebee.input
import bumblebee.output
import bumblebee.engine
ALIASES = ["datetz", "timetz"]
def default_format(module):
default = "%x %X %Z"
if module == "datetz":

View file

@ -1,22 +1,38 @@
# pylint: disable=C0111,R0903
"""Displays the current song being played in DeaDBeeF and
provides some media control bindings.
Left click toggles pause, scroll up skips the current song,
scroll down returns to the previous song.
"""Displays the current song being played in DeaDBeeF and provides
some media control bindings.
Left click toggles pause, scroll up skips the current song, scroll
down returns to the previous song.
Requires the following library:
* subprocess
Parameters:
* deadbeef.format: Format string (defaults to "{artist} - {title}")
Available values are: {artist}, {title}, {album}, {length},
{trackno}, {year}, {comment},
{copyright}, {time}
* deadbeef.previous: Change binding for previous song (default is left click)
* deadbeef.next: Change binding for next song (default is right click)
* deadbeef.pause: Change binding for toggling pause (default is middle click)
* deadbeef.format: Format string (defaults to "{artist} - {title}")
Available values are: {artist}, {title}, {album}, {length},
{trackno}, {year}, {comment},
{copyright}, {time}
This is deprecated, but much simpler.
* deadbeef.tf_format: A foobar2000 title formatting-style format string.
These can be much more sophisticated than the standard
format strings. This is off by default, but specifying
any tf_format will enable it. If both deadbeef.format
and deadbeef.tf_format are specified, deadbeef.tf_format
takes priority.
* deadbeef.tf_format_if_stopped: Controls whether or not the tf_format format
string should be displayed even if no song is paused or
playing. This could be useful if you want to implement
your own stop strings with the built in logic. Any non-
null value will enable this (by default the module will
hide itself when the player is stopped).
* deadbeef.previous: Change binding for previous song (default is left click)
* deadbeef.next: Change binding for next song (default is right click)
* deadbeef.pause: Change binding for toggling pause (default is middle click)
Available options for deadbeef.previous, deadbeef.next and deadbeef.pause are:
LEFT_CLICK, RIGHT_CLICK, MIDDLE_CLICK, SCROLL_UP, SCROLL_DOWN
"""
import sys
import bumblebee.input
import bumblebee.output
@ -34,54 +50,94 @@ class Module(bumblebee.engine.Module):
super(Module, self).__init__(engine, config,
bumblebee.output.Widget(full_text=self.deadbeef)
)
buttons = {"LEFT_CLICK":bumblebee.input.LEFT_MOUSE,
"RIGHT_CLICK":bumblebee.input.RIGHT_MOUSE,
"MIDDLE_CLICK":bumblebee.input.MIDDLE_MOUSE,
"SCROLL_UP":bumblebee.input.WHEEL_UP,
"SCROLL_DOWN":bumblebee.input.WHEEL_DOWN,
buttons = {"LEFT_CLICK": bumblebee.input.LEFT_MOUSE,
"RIGHT_CLICK": bumblebee.input.RIGHT_MOUSE,
"MIDDLE_CLICK": bumblebee.input.MIDDLE_MOUSE,
"SCROLL_UP": bumblebee.input.WHEEL_UP,
"SCROLL_DOWN": bumblebee.input.WHEEL_DOWN,
}
self._song = ""
self._format = self.parameter("format", "{artist} - {title}")
self._tf_format = self.parameter("tf_format", "")
self._show_tf_when_stopped = bool(self.parameter("tf_format_if_stopped", ""))
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", ""]
cmd = "deadbeef "
engine.input.register_callback(self, button=buttons[prev_button],
cmd=cmd + "--prev")
cmd=cmd + "--prev")
engine.input.register_callback(self, button=buttons[next_button],
cmd=cmd + "--next")
cmd=cmd + "--next")
engine.input.register_callback(self, button=buttons[pause_button],
cmd=cmd + "--play-pause")
cmd=cmd + "--play-pause")
# modify the tf_format if we don't want it to show on stop
# this adds conditions to the query itself, rather than
# polling to see if deadbeef is running
# doing this reduces the number of calls we have to make
if self._tf_format and not self._show_tf_when_stopped:
self._tf_format = "$if($or(%isplaying%,%ispaused%),{query})".format(query=self._tf_format)
@scrollable
def deadbeef(self, widget):
return str(self._song)
return self.string_song
def hidden(self):
return str(self._song) == ""
return self.string_song == ""
def update(self, widgets):
try:
deadbeef = subprocess.Popen(self.now_playing,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
data = deadbeef.communicate()[0]
if data == "nothing":
self._song = ""
else:
data = data.split(";")
self._song = self._format.format(artist=data[0],
title=data[1],
album=data[2],
length=data[3],
trackno=data[4],
year=data[5],
comment=data[6],
copyright=data[7],
time=data[8])
if self._tf_format == "": # no tf format set, use the old style
return self.update_standard(widgets)
return self.update_tf(widgets)
except Exception:
self._song = "error"
def update_tf(self, widgets):
## ensure that deadbeef is actually running
## easiest way to do this is to check --nowplaying for
## the string "nothing"
if read_process(self.now_playing) == "nothing":
self._song = ""
return
## perform the actual query -- these can be much more sophisticated
self.now_playing_tf[-1] = self._tf_format
data = read_process(self.now_playing_tf)
self._song = data
def update_standard(self, widgets):
data = read_process(self.now_playing)
if data == "nothing":
self._song = ""
else:
data = data.split(";")
self._song = self._format.format(artist=data[0],
title=data[1],
album=data[2],
length=data[3],
trackno=data[4],
year=data[5],
comment=data[6],
copyright=data[7],
time=data[8])
@property
def string_song(self):
"""\
Returns the current song as a string, either as a unicode() (Python <
3) or a regular str() (Python >= 3)
"""
if sys.version_info.major < 3:
return unicode(self._song)
return str(self._song)
def read_process(command):
proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return proc.stdout.read()
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -0,0 +1,119 @@
# pylint: disable=C0111,R0903
"""Display and run a Pomodoro timer.
Left click to start timer, left click again to pause.
Right click will cancel the timer.
Parameters:
* pomodoro.work: The work duration of timer in minutes (defaults to 25)
* pomodoro.break: The break duration of timer in minutes (defaults to 5)
* pomodoro.format: Timer display format with "%m" and "%s" for minutes and seconds (defaults to "%m:%s")
Examples: "%m min %s sec", "%mm", "", "timer"
* pomodoro.notify: Notification command to run when timer ends/starts (defaults to nothing)
Example: 'notify-send "Time up!"'
"""
from __future__ import absolute_import
import datetime
from math import ceil
import bumblebee.input
import bumblebee.output
import bumblebee.engine
class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
widgets = bumblebee.output.Widget(full_text=self.text)
super(Module, self).__init__(engine, config, widgets)
# Parameters
self._work_period = int(self.parameter("work", 25))
self._break_period = int(self.parameter("break", 5))
self._time_format = self.parameter("format", "%m:%s")
self._notify_cmd = self.parameter("notify", "")
# TODO: Handle time formats more gracefully. This is kludge.
self.display_seconds_p = False
self.display_minutes_p = False
if "%s" in self._time_format:
self.display_seconds_p = True
if "%m" in self._time_format:
self.display_minutes_p = True
self.remaining_time = datetime.timedelta(minutes=self._work_period)
self.time = None
self.pomodoro = { "state":"OFF", "type": ""}
self._text = self.remaining_time_str() + self.pomodoro["type"]
engine.input.register_callback(self, button=bumblebee.input.LEFT_MOUSE,
cmd=self.timer_play_pause)
engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE,
cmd=self.timer_reset)
def remaining_time_str(self):
if self.display_seconds_p and self.display_minutes_p:
minutes, seconds = divmod(self.remaining_time.seconds, 60)
if not self.display_seconds_p:
minutes = ceil(self.remaining_time.seconds / 60)
seconds = 0
if not self.display_minutes_p:
minutes = 0
seconds = self.remaining_time.seconds
minutes = "{:2d}".format(minutes)
seconds = "{:02d}".format(seconds)
return self._time_format.replace("%m",minutes).replace("%s",seconds)+" "
def text(self, widget):
return "{}".format(self._text)
def update(self, widget):
if self.pomodoro["state"] == "ON":
timediff = (datetime.datetime.now() - self.time)
if timediff.seconds >= 0:
self.remaining_time -= timediff
self.time = datetime.datetime.now()
if self.remaining_time.seconds <= 0:
self.notify()
if self.pomodoro["type"] == "Work":
self.pomodoro["type"] = "Break"
self.remaining_time = datetime.timedelta(minutes=self._break_period)
elif self.pomodoro["type"] == "Break":
self.pomodoro["type"] = "Work"
self.remaining_time = datetime.timedelta(minutes=self._work_period)
self._text = self.remaining_time_str() + self.pomodoro["type"]
def notify(self):
if self._notify_cmd:
bumblebee.util.execute(self._notify_cmd)
def timer_play_pause(self, widget):
if self.pomodoro["state"] == "OFF":
self.pomodoro = {"state": "ON", "type": "Work"}
self.remaining_time = datetime.timedelta(minutes=self._work_period)
self.time = datetime.datetime.now()
elif self.pomodoro["state"] == "ON":
self.pomodoro["state"] = "PAUSED"
self.remaining_time -= (datetime.datetime.now() - self.time)
self.time = datetime.datetime.now()
elif self.pomodoro["state"] == "PAUSED":
self.pomodoro["state"] = "ON"
self.time = datetime.datetime.now()
def timer_reset(self, widget):
if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "PAUSED":
self.pomodoro = {"state":"OFF", "type": "" }
self.remaining_time = datetime.timedelta(minutes=self._work_period)
def state(self, widget):
state = [];
state.append(self.pomodoro["state"].lower())
if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "OFF":
state.append(self.pomodoro["type"].lower())
return state

View file

@ -24,8 +24,6 @@ import bumblebee.input
import bumblebee.output
import bumblebee.engine
ALIASES = ["pasink", "pasource"]
class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
super(Module, self).__init__(engine, config,

View file

@ -45,6 +45,7 @@ class Module(bumblebee.engine.Module):
# Use BBC newsfeed as demo:
self._feeds = self.parameter('feeds', 'https://www.espn.com/espn/rss/news').split(" ")
self._feeds_to_update = []
self._response = ""
self._max_title_length = int(self.parameter("length", 60))

View file

@ -13,6 +13,8 @@ Parameters:
LEFT_CLICK, RIGHT_CLICK, MIDDLE_CLICK, SCROLL_UP, SCROLL_DOWN
"""
import sys
import bumblebee.input
import bumblebee.output
import bumblebee.engine
@ -52,12 +54,12 @@ class Module(bumblebee.engine.Module):
engine.input.register_callback(self, button=buttons[pause_button],
cmd=cmd + "PlayPause")
## @scrollable
@scrollable
def spotify(self, widget):
return str(self._song)
return self.string_song
def hidden(self):
return str(self._song) == ""
return self.string_song == ""
def update(self, widgets):
try:
@ -71,7 +73,15 @@ class Module(bumblebee.engine.Module):
artist=','.join(props.get('xesam:artist')),
trackNumber=str(props.get('xesam:trackNumber')),
playbackStatus=u"\u25B6" if playback_status=="Playing" else u"\u258D\u258D" if playback_status=="Paused" else "",)
except Exception:
self._song = ""
@property
def string_song(self):
if sys.version_info.major < 3:
return unicode(self._song)
return str(self._song)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -5,8 +5,6 @@
import bumblebee.engine
ALIASES = ["test-alias"]
class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
super(Module, self).__init__(engine, config,

View file

@ -60,7 +60,7 @@ class Module(bumblebee.engine.Module):
def _reset(self):
self._timer = None
self._text = "<click-for-password>"
self._text = str(self.parameter("text", "<click-for-password>"))
def _callback(self, secret_name):
secret_name = secret_name.replace(self._path, "") # remove common path

View file

@ -25,9 +25,12 @@ Be aware of security implications of doing this!
"""
import time
import logging
from pkg_resources import parse_version
import bumblebee.engine
from bumblebee.util import execute, bytefmt, asbool
log = logging.getLogger(__name__)
class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
@ -63,7 +66,16 @@ class Module(bumblebee.engine.Module):
return state
def _update_widgets(self, widgets):
zfs_version_path = "/sys/module/zfs/version"
# zpool list -H: List all zpools, use script mode (no headers and tabs as separators).
try:
with open(zfs_version_path, 'r') as zfs_mod_version:
zfs_version = zfs_mod_version.readline().rstrip().split('-')[0]
except IOError:
# ZFS isn't installed or the module isn't loaded, stub the version
zfs_version = "0.0.0"
logging.error("ZFS version information not found at {}, check the module is loaded.".format(zfs_version_path))
raw_zpools = execute(('sudo ' if self._usesudo else '') + 'zpool list -H').split('\n')
for widget in widgets:
@ -71,8 +83,11 @@ class Module(bumblebee.engine.Module):
for raw_zpool in raw_zpools:
try:
# Ignored fields (assigned to _) are "expandsz" and "altroot"
name, size, alloc, free, _, frag, cap, dedup, health, _ = raw_zpool.split('\t')
# 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"):
name, size, alloc, free, _, frag, cap, dedup, health, _ = raw_zpool.split('\t')
else:
name, size, alloc, free, _, _, frag, cap, dedup, health, _ = raw_zpool.split('\t')
cap = cap.rstrip('%')
percentuse=int(cap)
percentfree=100-percentuse

View file

@ -8,12 +8,15 @@ import uuid
import bumblebee.store
_TrueValues = ["true", "t", "yes", "y", "1"]
def scrollable(func):
def wrapper(module, widget):
text = func(module, widget)
if not text: return text
width = widget.get("theme.width", module.parameter("width", 30))
widget.set("theme.minwidth", "A"*width)
if module.parameter("scrolling.makewide", "true").lower() in _TrueValues:
widget.set("theme.minwidth", "A"*width)
if len(text) <= width:
return text
# we need to shorten

View file

@ -31,7 +31,7 @@ def execute(cmd, wait=True):
raise RuntimeError("{} exited with {}".format(cmd, proc.returncode))
if hasattr(out, "decode"):
rv = out.decode("utf-8")
rv = out.decode("utf-8", "ignore")
else:
rv = out

View file

@ -1,17 +1,9 @@
# pylint: disable=C0103,C0111
import json
import unittest
import mock
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
from mock import patch
import tests.mocks as mocks
from bumblebee.config import Config
from bumblebee.input import LEFT_MOUSE
from bumblebee.modules.caffeine import Module
@ -19,35 +11,40 @@ class TestCaffeineModule(unittest.TestCase):
def setUp(self):
mocks.setup_test(self, Module)
self.xset_active = " timeout: 0 cycle: 123"
self.xset_inactive = " timeout: 600 cycle: 123"
def tearDown(self):
mocks.teardown_test(self)
def test_text(self):
self.assertEquals(self.module.caffeine(self.anyWidget), "")
def test_check_requirements(self):
with patch('bumblebee.util.which', side_effect=['', 'xprop', 'xdg-screensaver']):
self.assertTrue(['xdotool'] == self.module._check_requirements())
def test_active(self):
self.popen.mock.communicate.return_value = (self.xset_active, None)
self.assertTrue(not "deactivated" in self.module.state(self.anyWidget))
self.assertTrue("activated" in self.module.state(self.anyWidget))
def test_get_i3bar_xid_returns_digit(self):
self.popen.mock.communicate.return_value = ("8388614", None)
self.assertTrue(self.module._get_i3bar_xid().isdigit())
def test_inactive(self):
self.popen.mock.communicate.return_value = (self.xset_inactive, None)
self.assertTrue("deactivated" in self.module.state(self.anyWidget))
self.popen.mock.communicate.return_value = ("no text", None)
self.assertTrue("deactivated" in self.module.state(self.anyWidget))
def test_get_i3bar_xid_returns_error_string(self):
self.popen.mock.communicate.return_value = ("Some error message", None)
self.assertTrue(self.module._get_i3bar_xid() is None)
def test_toggle(self):
self.popen.mock.communicate.return_value = (self.xset_active, None)
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("xset s default")
self.popen.assert_call("notify-send \"Out of coffee\"")
self.popen.mock.communicate.return_value = (self.xset_inactive, None)
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.popen.assert_call("xset s off")
self.popen.assert_call("notify-send \"Consuming caffeine\"")
def test_get_i3bar_xid_returns_empty_string(self):
self.popen.mock.communicate.return_value = ("", None)
self.assertTrue(self.module._get_i3bar_xid() is None)
def test_suspend_screensaver_success(self):
with patch.object(self.module, '_get_i3bar_xid', return_value=8388614):
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.assertTrue(self.module._suspend_screensaver() is True)
def test_suspend_screensaver_fail(self):
with patch.object(self.module, '_get_i3bar_xid', return_value=None):
self.module._active = False
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.assertTrue(self.module._suspend_screensaver() is False)
def test_resume_screensaver(self):
with patch.object(self.module, '_check_requirements', return_value=[]):
self.module._active = True
mocks.mouseEvent(stdin=self.stdin, button=LEFT_MOUSE, inp=self.input, module=self.module)
self.assertTrue(self.module._resume_screensaver() is True)
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View file

@ -0,0 +1,42 @@
{
"icons": [ "awesome-fonts" ],
"defaults": {
"separator-block-width": 0,
"warning": {
"fg": "#002b36",
"bg": "#b58900"
},
"critical": {
"fg": "#002b36",
"bg": "#dc322f"
}
},
"cycle": [
{ "fg": "#B1B1B3", "bg": "#474749" },
{ "fg": "#BEBEBE", "bg": "#323234" }
],
"dnf": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"pacman": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"pomodoro": {
"paused": {
"fg": "#002b36",
"bg": "#b58900"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -42,5 +42,20 @@
"fg": "#002b36",
"bg": "#859900"
}
}
},
"pomodoro": {
"paused": {
"fg": "#002b36",
"bg": "#b58900"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -54,5 +54,20 @@
"modified": { "bg": "#458588" },
"deleted": { "bg": "#9d0006" },
"new": { "bg": "#b16286" }
}
},
"pomodoro": {
"paused": {
"fg": "#1d2021",
"bg": "#d79921"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -21,38 +21,52 @@
"fg": "#282828",
"bg": "#fbf1c7"
}
],
"dnf": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"apt": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"battery": {
"charged": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"AC": {
"fg": "#1d2021",
"bg": "#b8bb26"
}
},
"bluetooth": {
"ON": {
"fg": "#1d2021",
"bg": "#b8bb26"
}
},
"git": {
"modified": { "bg": "#458588" },
"deleted": { "bg": "#9d0006" },
"new": { "bg": "#b16286" }
}
],
"dnf": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"apt": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"battery": {
"charged": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"AC": {
"fg": "#1d2021",
"bg": "#b8bb26"
}
},
"bluetooth": {
"ON": {
"fg": "#1d2021",
"bg": "#b8bb26"
}
},
"git": {
"modified": { "bg": "#458588" },
"deleted": { "bg": "#9d0006" },
"new": { "bg": "#b16286" }
},
"pomodoro": {
"paused": {
"fg": "#1d2021",
"bg": "#d79921"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -54,5 +54,19 @@
"modified": { "bg": "#458588" },
"deleted": { "bg": "#9d0006" },
"new": { "bg": "#b16286" }
}
},
"pomodoro": {
"paused": {
"fg": "#1d2021",
"bg": "#d79921"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -54,5 +54,20 @@
"modified": { "bg": "#458588" },
"deleted": { "bg": "#9d0006" },
"new": { "bg": "#b16286" }
}
},
"pomodoro": {
"paused": {
"fg": "#1d2021",
"bg": "#d79921"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -47,5 +47,20 @@
"fg": "#0f1117",
"bg": "#84a0c6"
}
},
"pomodoro": {
"paused": {
"fg": "#0f1117",
"bg": "#e2a478"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#b4be82",
"bg": "#161821"
}
}
}

View file

@ -46,5 +46,19 @@
"fg": "#0f1117",
"bg": "#84a0c6"
}
},
"pomodoro": {
"paused": {
"fg": "#0f1117",
"bg": "#e2a478"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#89b8c2",
"bg": "#161821"
}
}
}

View file

@ -46,5 +46,20 @@
"fg": "#89b8c2",
"bg": "#161821"
}
},
"pomodoro": {
"paused": {
"fg": "#e2a478",
"bg": "#c6c8d1"
},
"work": {
"fg": "#89b8c2",
"bg": "#161821"
},
"break": {
"fg": "#b4be82",
"bg": "#161821"
}
}
}

View file

@ -40,5 +40,20 @@
"fg": "#89b8c2",
"bg": "#161821"
}
},
"pomodoro": {
"paused": {
"fg": "#0f1117",
"bg": "#e2a478"
},
"work": {
"fg": "#1d2021",
"bg": "#b8bb26"
},
"break": {
"fg": "#89b8c2",
"bg": "#161821"
}
}
}

View file

@ -302,6 +302,10 @@
},
"system": {
"prefix": "system"
}
},
"pomodoro": {
"off": { "prefix": "pom" },
"paused": { "prefix": "||" },
"on": { "prefix": " >" }
}
}

View file

@ -222,5 +222,11 @@
},
"rss": {
"prefix": ""
},
"pomodoro": {
"off": { "prefix": "" },
"paused": { "prefix": "" },
"work": { "prefix": "" },
"break": { "prefix": "" }
}
}

View file

@ -185,5 +185,11 @@
},
"rss": {
"prefix": "\uf1ea"
},
"pomodoro": {
"off": { "prefix": "\uf24f" },
"paused": { "prefix": "\uf210" },
"on": { "prefix": "\uf488" }
}
}

View file

@ -36,5 +36,20 @@
"fg": "#282C34",
"bg": "#98C379"
}
}
},
"pomodoro": {
"paused": {
"fg": "#282C34",
"bg": "#E5C07B"
},
"work": {
"fg": "#98C379",
"bg": "#282C34"
},
"break": {
"fg": "#282C34",
"bg": "#98C379"
}
}
}

View file

@ -43,5 +43,20 @@
"fg": "#494949",
"bg": "#41db00"
}
}
},
"pomodoro": {
"paused": {
"fg": "#d75f00",
"bg": "#ffd700"
},
"work": {
"fg": "#ffd700",
"bg": "#d75f00"
},
"break": {
"fg": "#494949",
"bg": "#41db00"
}
}
}

View file

@ -40,5 +40,20 @@
},
"cmus": {
"bg": "#C42021"
}
},
"pomodoro": {
"paused": {
"fg": "#FDFFFC",
"bg": "#B91372"
},
"work": {
"fg": "#FDFFFC",
"bg": "#41EAD4"
},
"break": {
"fg": "#FDFFFC",
"bg": "#011627"
}
}
}

View file

@ -21,29 +21,43 @@
},
"apt": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"pacman": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"battery": {
"charged": {
"fg": "#002b36",
"bg": "#859900"
},
"AC": {
"fg": "#002b36",
"bg": "#859900"
}
},
"git": {
"modified": { "bg": "#2aa198" },
"deleted": { "bg": "#d33682" },
"new": { "bg": "#859900" }
}
"fg": "#002b36",
"bg": "#859900"
}
},
"pacman": {
"good": {
"fg": "#002b36",
"bg": "#859900"
}
},
"battery": {
"charged": {
"fg": "#002b36",
"bg": "#859900"
},
"AC": {
"fg": "#002b36",
"bg": "#859900"
}
},
"git": {
"modified": { "bg": "#2aa198" },
"deleted": { "bg": "#d33682" },
"new": { "bg": "#859900" }
},
"pomodoro": {
"paused": {
"fg": "#002b36",
"bg": "#b58900"
},
"work": {
"fg": "#eee8d5",
"bg": "#586e75"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -47,5 +47,19 @@
"modified": { "bg": "#2aa198" },
"deleted": { "bg": "#d33682" },
"new": { "bg": "#859900" }
}
},
"pomodoro": {
"paused": {
"fg": "#002b36",
"bg": "#b58900"
},
"work": {
"fg": "#eee8d5",
"bg": "#586e75"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -49,5 +49,20 @@
"modified": { "bg": "#2aa198" },
"deleted": { "bg": "#d33682" },
"new": { "bg": "#859900" }
}
},
"pomodoro": {
"paused": {
"fg": "#002b36",
"bg": "#b58900"
},
"work": {
"fg": "#eee8d5",
"bg": "#586e75"
},
"break": {
"fg": "#002b36",
"bg": "#859900"
}
}
}

View file

@ -44,5 +44,20 @@
"fg": "background",
"bg": "color3"
}
}
},
"pomodoro": {
"paused": {
"fg": "cursor",
"bg": "color6"
},
"work": {
"fg": "background",
"bg": "foreground"
},
"break": {
"fg": "background",
"bg": "color3"
}
}
}