Run black on all Python scripts!
This commit is contained in:
parent
fb6cfce656
commit
cd9cbcaa28
30 changed files with 1027 additions and 704 deletions
|
@ -11,14 +11,23 @@ if __name__ == "__main__":
|
|||
WORKSPACE_THEME = 0
|
||||
FOCUS_THEME = 3
|
||||
URGENT_THEME = 1
|
||||
CUSTOM_SUFFIXES = '▲■'
|
||||
CUSTOM_SUFFIXES = "▲■"
|
||||
|
||||
customNames = dict()
|
||||
for i in range(len(CUSTOM_SUFFIXES)):
|
||||
short = str(i+1)
|
||||
full = short + ' ' + CUSTOM_SUFFIXES[i]
|
||||
short = str(i + 1)
|
||||
full = short + " " + CUSTOM_SUFFIXES[i]
|
||||
customNames[short] = full
|
||||
Bar.addSectionAll(I3WorkspacesProvider(theme=WORKSPACE_THEME, themeFocus=FOCUS_THEME, themeUrgent=URGENT_THEME, themeMode=URGENT_THEME, customNames=customNames), BarGroupType.LEFT)
|
||||
Bar.addSectionAll(
|
||||
I3WorkspacesProvider(
|
||||
theme=WORKSPACE_THEME,
|
||||
themeFocus=FOCUS_THEME,
|
||||
themeUrgent=URGENT_THEME,
|
||||
themeMode=URGENT_THEME,
|
||||
customNames=customNames,
|
||||
),
|
||||
BarGroupType.LEFT,
|
||||
)
|
||||
|
||||
# TODO Middle
|
||||
Bar.addSectionAll(MpdProvider(theme=7), BarGroupType.LEFT)
|
||||
|
|
|
@ -11,7 +11,7 @@ import logging
|
|||
import coloredlogs
|
||||
import updaters
|
||||
|
||||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||
coloredlogs.install(level="DEBUG", fmt="%(levelname)s %(message)s")
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
|
@ -62,12 +62,13 @@ class Bar:
|
|||
Bar.running = True
|
||||
Section.init()
|
||||
|
||||
cmd = ['lemonbar', '-b', '-a', '64']
|
||||
cmd = ["lemonbar", "-b", "-a", "64"]
|
||||
for font in Bar.FONTS:
|
||||
cmd += ["-f", "{}:size={}".format(font, Bar.FONTSIZE)]
|
||||
Bar.process = subprocess.Popen(cmd, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE)
|
||||
Bar.stdoutThread = BarStdoutThread()
|
||||
Bar.process = subprocess.Popen(
|
||||
cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE
|
||||
)
|
||||
Bar.stdoutThread = BarStdoutThread()
|
||||
Bar.stdoutThread.start()
|
||||
|
||||
# Debug
|
||||
|
@ -92,7 +93,7 @@ class Bar:
|
|||
print(88)
|
||||
|
||||
try:
|
||||
i3.on('ipc_shutdown', doStop)
|
||||
i3.on("ipc_shutdown", doStop)
|
||||
i3.main()
|
||||
except BaseException:
|
||||
print(93)
|
||||
|
@ -114,7 +115,7 @@ class Bar:
|
|||
if function in Bar.actionsF2H.keys():
|
||||
return Bar.actionsF2H[function]
|
||||
|
||||
handle = '{:x}'.format(Bar.nextHandle).encode()
|
||||
handle = "{:x}".format(Bar.nextHandle).encode()
|
||||
Bar.nextHandle += 1
|
||||
|
||||
Bar.actionsF2H[function] = handle
|
||||
|
@ -177,7 +178,7 @@ class Bar:
|
|||
Bar.string += BarGroup.color(*Section.EMPTY)
|
||||
|
||||
# print(Bar.string)
|
||||
Bar.process.stdin.write(bytes(Bar.string + '\n', 'utf-8'))
|
||||
Bar.process.stdin.write(bytes(Bar.string + "\n", "utf-8"))
|
||||
Bar.process.stdin.flush()
|
||||
|
||||
|
||||
|
@ -196,7 +197,7 @@ class BarGroup:
|
|||
self.parent = parent
|
||||
|
||||
self.sections = list()
|
||||
self.string = ''
|
||||
self.string = ""
|
||||
self.parts = []
|
||||
|
||||
#: One of the sections that had their theme or visibility changed
|
||||
|
@ -220,11 +221,11 @@ class BarGroup:
|
|||
|
||||
@staticmethod
|
||||
def fgColor(color):
|
||||
return "%{F" + (color or '-') + "}"
|
||||
return "%{F" + (color or "-") + "}"
|
||||
|
||||
@staticmethod
|
||||
def bgColor(color):
|
||||
return "%{B" + (color or '-') + "}"
|
||||
return "%{B" + (color or "-") + "}"
|
||||
|
||||
@staticmethod
|
||||
def color(fg, bg):
|
||||
|
@ -243,8 +244,9 @@ class BarGroup:
|
|||
oSec = secs[s + 1] if s < lenS - 1 else None
|
||||
else:
|
||||
oSec = secs[s - 1] if s > 0 else None
|
||||
oTheme = Section.THEMES[oSec.theme] \
|
||||
if oSec is not None else Section.EMPTY
|
||||
oTheme = (
|
||||
Section.THEMES[oSec.theme] if oSec is not None else Section.EMPTY
|
||||
)
|
||||
|
||||
if self.groupType == BarGroupType.LEFT:
|
||||
if s == 0:
|
||||
|
@ -263,7 +265,6 @@ class BarGroup:
|
|||
parts.append(BarGroup.color(*theme))
|
||||
parts.append(sec)
|
||||
|
||||
|
||||
# TODO OPTI Concatenate successive strings
|
||||
self.parts = parts
|
||||
|
||||
|
@ -315,11 +316,26 @@ class Section:
|
|||
# COLORS = ['#272822', '#383830', '#49483e', '#75715e', '#a59f85', '#f8f8f2',
|
||||
# '#f5f4f1', '#f9f8f5', '#f92672', '#fd971f', '#f4bf75', '#a6e22e',
|
||||
# '#a1efe4', '#66d9ef', '#ae81ff', '#cc6633']
|
||||
COLORS = ['#181818', '#AB4642', '#A1B56C', '#F7CA88', '#7CAFC2', '#BA8BAF',
|
||||
'#86C1B9', '#D8D8D8', '#585858', '#AB4642', '#A1B56C', '#F7CA88',
|
||||
'#7CAFC2', '#BA8BAF', '#86C1B9', '#F8F8F8']
|
||||
FGCOLOR = '#F8F8F2'
|
||||
BGCOLOR = '#272822'
|
||||
COLORS = [
|
||||
"#181818",
|
||||
"#AB4642",
|
||||
"#A1B56C",
|
||||
"#F7CA88",
|
||||
"#7CAFC2",
|
||||
"#BA8BAF",
|
||||
"#86C1B9",
|
||||
"#D8D8D8",
|
||||
"#585858",
|
||||
"#AB4642",
|
||||
"#A1B56C",
|
||||
"#F7CA88",
|
||||
"#7CAFC2",
|
||||
"#BA8BAF",
|
||||
"#86C1B9",
|
||||
"#F8F8F8",
|
||||
]
|
||||
FGCOLOR = "#F8F8F2"
|
||||
BGCOLOR = "#272822"
|
||||
|
||||
THEMES = list()
|
||||
EMPTY = (FGCOLOR, BGCOLOR)
|
||||
|
@ -347,17 +363,18 @@ class Section:
|
|||
|
||||
if theme is None:
|
||||
theme = Section.lastChosenTheme
|
||||
Section.lastChosenTheme = (Section.lastChosenTheme + 1) \
|
||||
% len(Section.THEMES)
|
||||
Section.lastChosenTheme = (Section.lastChosenTheme + 1) % len(
|
||||
Section.THEMES
|
||||
)
|
||||
self.theme = theme
|
||||
|
||||
#: Displayed text
|
||||
self.curText = ''
|
||||
self.curText = ""
|
||||
#: Displayed text size
|
||||
self.curSize = 0
|
||||
|
||||
#: Destination text
|
||||
self.dstText = Text(' ', Text(), ' ')
|
||||
self.dstText = Text(" ", Text(), " ")
|
||||
#: Destination size
|
||||
self.dstSize = 0
|
||||
|
||||
|
@ -367,13 +384,16 @@ class Section:
|
|||
self.icon = self.ICON
|
||||
self.persistent = self.PERSISTENT
|
||||
|
||||
|
||||
def __str__(self):
|
||||
try:
|
||||
return "<{}><{}>{:01d}{}{:02d}/{:02d}" \
|
||||
.format(self.curText, self.dstText,
|
||||
self.theme, "+" if self.visible else "-",
|
||||
self.curSize, self.dstSize)
|
||||
return "<{}><{}>{:01d}{}{:02d}/{:02d}".format(
|
||||
self.curText,
|
||||
self.dstText,
|
||||
self.theme,
|
||||
"+" if self.visible else "-",
|
||||
self.curSize,
|
||||
self.dstSize,
|
||||
)
|
||||
except:
|
||||
return super().__str__()
|
||||
|
||||
|
@ -399,9 +419,15 @@ class Section:
|
|||
elif isinstance(text, Text) and not len(text.elements):
|
||||
text = None
|
||||
|
||||
self.dstText[0] = None if (text is None and not self.persistent) else ((' ' + self.icon + ' ') if self.icon else ' ')
|
||||
self.dstText[0] = (
|
||||
None
|
||||
if (text is None and not self.persistent)
|
||||
else ((" " + self.icon + " ") if self.icon else " ")
|
||||
)
|
||||
self.dstText[1] = text
|
||||
self.dstText[2] = ' ' if self.dstText[1] is not None and len(self.dstText[1]) else None
|
||||
self.dstText[2] = (
|
||||
" " if self.dstText[1] is not None and len(self.dstText[1]) else None
|
||||
)
|
||||
|
||||
self.dstSize = len(self.dstText)
|
||||
self.dstText.setSection(self)
|
||||
|
@ -481,7 +507,7 @@ class Section:
|
|||
elif p < 0:
|
||||
return ramp[0]
|
||||
else:
|
||||
return ramp[round(p * (len(ramp)-1))]
|
||||
return ramp[round(p * (len(ramp) - 1))]
|
||||
|
||||
|
||||
class StatefulSection(Section):
|
||||
|
@ -492,10 +518,11 @@ class StatefulSection(Section):
|
|||
def __init__(self, *args, **kwargs):
|
||||
Section.__init__(self, *args, **kwargs)
|
||||
self.state = self.DEFAULT_STATE
|
||||
if hasattr(self, 'onChangeState'):
|
||||
if hasattr(self, "onChangeState"):
|
||||
self.onChangeState(self.state)
|
||||
self.setDecorators(clickLeft=self.incrementState,
|
||||
clickRight=self.decrementState)
|
||||
self.setDecorators(
|
||||
clickLeft=self.incrementState, clickRight=self.decrementState
|
||||
)
|
||||
|
||||
def incrementState(self):
|
||||
newState = min(self.state + 1, self.NUMBER_STATES - 1)
|
||||
|
@ -509,16 +536,17 @@ class StatefulSection(Section):
|
|||
assert isinstance(state, int)
|
||||
assert state < self.NUMBER_STATES
|
||||
self.state = state
|
||||
if hasattr(self, 'onChangeState'):
|
||||
if hasattr(self, "onChangeState"):
|
||||
self.onChangeState(state)
|
||||
self.refreshData()
|
||||
|
||||
|
||||
class ColorCountsSection(StatefulSection):
|
||||
# TODO FEAT Blend colors when not expanded
|
||||
# TODO FEAT Blend colors with importance of count
|
||||
# TODO FEAT Allow icons instead of counts
|
||||
NUMBER_STATES = 3
|
||||
COLORABLE_ICON = '?'
|
||||
COLORABLE_ICON = "?"
|
||||
|
||||
def __init__(self, theme=None):
|
||||
StatefulSection.__init__(self, theme=theme)
|
||||
|
@ -538,12 +566,12 @@ class ColorCountsSection(StatefulSection):
|
|||
# Icon + Total
|
||||
elif self.state == 1 and len(counts) > 1:
|
||||
total = sum([count for count, color in counts])
|
||||
return Text(self.COLORABLE_ICON, ' ', total)
|
||||
return Text(self.COLORABLE_ICON, " ", total)
|
||||
# Icon + Counts
|
||||
else:
|
||||
text = Text(self.COLORABLE_ICON)
|
||||
for count, color in counts:
|
||||
text.append(' ', Text(count, fg=color))
|
||||
text.append(" ", Text(count, fg=color))
|
||||
return text
|
||||
|
||||
|
||||
|
@ -586,12 +614,12 @@ class Text:
|
|||
if self.prefix is not None and self.suffix is not None:
|
||||
return
|
||||
|
||||
self.prefix = ''
|
||||
self.suffix = ''
|
||||
self.prefix = ""
|
||||
self.suffix = ""
|
||||
|
||||
def nest(prefix, suffix):
|
||||
self.prefix = self.prefix + '%{' + prefix + '}'
|
||||
self.suffix = '%{' + suffix + '}' + self.suffix
|
||||
self.prefix = self.prefix + "%{" + prefix + "}"
|
||||
self.suffix = "%{" + suffix + "}" + self.suffix
|
||||
|
||||
def getColor(val):
|
||||
# TODO Allow themes
|
||||
|
@ -600,27 +628,27 @@ class Text:
|
|||
|
||||
def button(number, function):
|
||||
handle = Bar.getFunctionHandle(function)
|
||||
nest('A' + number + ':' + handle.decode() + ':', 'A' + number)
|
||||
nest("A" + number + ":" + handle.decode() + ":", "A" + number)
|
||||
|
||||
for key, val in self.decorators.items():
|
||||
if val is None:
|
||||
continue
|
||||
if key == 'fg':
|
||||
if key == "fg":
|
||||
reset = self.section.THEMES[self.section.theme][0]
|
||||
nest('F' + getColor(val), 'F' + reset)
|
||||
elif key == 'bg':
|
||||
nest("F" + getColor(val), "F" + reset)
|
||||
elif key == "bg":
|
||||
reset = self.section.THEMES[self.section.theme][1]
|
||||
nest('B' + getColor(val), 'B' + reset)
|
||||
nest("B" + getColor(val), "B" + reset)
|
||||
elif key == "clickLeft":
|
||||
button('1', val)
|
||||
button("1", val)
|
||||
elif key == "clickMiddle":
|
||||
button('2', val)
|
||||
button("2", val)
|
||||
elif key == "clickRight":
|
||||
button('3', val)
|
||||
button("3", val)
|
||||
elif key == "scrollUp":
|
||||
button('4', val)
|
||||
button("4", val)
|
||||
elif key == "scrollDown":
|
||||
button('5', val)
|
||||
button("5", val)
|
||||
else:
|
||||
log.warn("Unkown decorator: {}".format(key))
|
||||
|
||||
|
@ -652,7 +680,7 @@ class Text:
|
|||
curString += self.suffix
|
||||
|
||||
if pad and remSize > 0:
|
||||
curString += ' ' * remSize
|
||||
curString += " " * remSize
|
||||
curSize += remSize
|
||||
|
||||
if size is not None:
|
||||
|
@ -688,7 +716,6 @@ class Text:
|
|||
curSize += len(str(element))
|
||||
return curSize
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.elements[index]
|
||||
|
||||
|
|
|
@ -7,150 +7,188 @@ Debugging script
|
|||
import i3ipc
|
||||
import os
|
||||
import psutil
|
||||
|
||||
# import alsaaudio
|
||||
from time import time
|
||||
import subprocess
|
||||
|
||||
i3 = i3ipc.Connection()
|
||||
lemonbar = subprocess.Popen(['lemonbar', '-b'], stdin=subprocess.PIPE)
|
||||
lemonbar = subprocess.Popen(["lemonbar", "-b"], stdin=subprocess.PIPE)
|
||||
|
||||
# Utils
|
||||
def upChart(p):
|
||||
block = ' ▁▂▃▄▅▆▇█'
|
||||
return block[round(p * (len(block)-1))]
|
||||
block = " ▁▂▃▄▅▆▇█"
|
||||
return block[round(p * (len(block) - 1))]
|
||||
|
||||
def humanSizeOf(num, suffix='B'): # TODO Credit
|
||||
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
|
||||
|
||||
def humanSizeOf(num, suffix="B"): # TODO Credit
|
||||
for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
|
||||
if abs(num) < 1024.0:
|
||||
return "%3.0f%2s%s" % (num, unit, suffix)
|
||||
num /= 1024.0
|
||||
return "%.0f%2s%s" % (num, 'Yi', suffix)
|
||||
return "%.0f%2s%s" % (num, "Yi", suffix)
|
||||
|
||||
|
||||
# Values
|
||||
mode = ''
|
||||
mode = ""
|
||||
container = i3.get_tree().find_focused()
|
||||
workspaces = i3.get_workspaces()
|
||||
outputs = i3.get_outputs()
|
||||
|
||||
username = os.environ['USER']
|
||||
hostname = os.environ['HOSTNAME']
|
||||
if '-' in hostname:
|
||||
hostname = hostname.split('-')[-1]
|
||||
username = os.environ["USER"]
|
||||
hostname = os.environ["HOSTNAME"]
|
||||
if "-" in hostname:
|
||||
hostname = hostname.split("-")[-1]
|
||||
|
||||
oldNetIO = dict()
|
||||
oldTime = time()
|
||||
|
||||
|
||||
def update():
|
||||
activeOutputs = sorted(sorted(list(filter(lambda o: o.active, outputs)), key=lambda o: o.rect.y), key=lambda o: o.rect.x)
|
||||
z = ''
|
||||
activeOutputs = sorted(
|
||||
sorted(list(filter(lambda o: o.active, outputs)), key=lambda o: o.rect.y),
|
||||
key=lambda o: o.rect.x,
|
||||
)
|
||||
z = ""
|
||||
for aOutput in range(len(activeOutputs)):
|
||||
output = activeOutputs[aOutput]
|
||||
# Mode || Workspaces
|
||||
t = []
|
||||
if (mode != ''):
|
||||
if mode != "":
|
||||
t.append(mode)
|
||||
else:
|
||||
t.append(' '.join([(w.name.upper() if w.focused else w.name) for w in workspaces if w.output == output.name]))
|
||||
t.append(
|
||||
" ".join(
|
||||
[
|
||||
(w.name.upper() if w.focused else w.name)
|
||||
for w in workspaces
|
||||
if w.output == output.name
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
# Windows Title
|
||||
#if container:
|
||||
# if container:
|
||||
# t.append(container.name)
|
||||
|
||||
# CPU
|
||||
t.append('C' + ''.join([upChart(p/100) for p in psutil.cpu_percent(percpu=True)]))
|
||||
t.append(
|
||||
"C" + "".join([upChart(p / 100) for p in psutil.cpu_percent(percpu=True)])
|
||||
)
|
||||
|
||||
# Memory
|
||||
t.append('M' + str(round(psutil.virtual_memory().percent)) + '% ' +
|
||||
'S' + str(round(psutil.swap_memory().percent)) + '%')
|
||||
t.append(
|
||||
"M"
|
||||
+ str(round(psutil.virtual_memory().percent))
|
||||
+ "% "
|
||||
+ "S"
|
||||
+ str(round(psutil.swap_memory().percent))
|
||||
+ "%"
|
||||
)
|
||||
|
||||
# Disks
|
||||
d = []
|
||||
for disk in psutil.disk_partitions():
|
||||
e = ''
|
||||
if disk.device.startswith('/dev/sd'):
|
||||
e += 'S' + disk.device[-2:].upper()
|
||||
elif disk.device.startswith('/dev/mmcblk'):
|
||||
e += 'M' + disk.device[-3] + disk.device[-1]
|
||||
e = ""
|
||||
if disk.device.startswith("/dev/sd"):
|
||||
e += "S" + disk.device[-2:].upper()
|
||||
elif disk.device.startswith("/dev/mmcblk"):
|
||||
e += "M" + disk.device[-3] + disk.device[-1]
|
||||
else:
|
||||
e += '?'
|
||||
e += ' '
|
||||
e += str(round(psutil.disk_usage(disk.mountpoint).percent)) + '%'
|
||||
e += "?"
|
||||
e += " "
|
||||
e += str(round(psutil.disk_usage(disk.mountpoint).percent)) + "%"
|
||||
d.append(e)
|
||||
t.append(' '.join(d))
|
||||
t.append(" ".join(d))
|
||||
|
||||
# Network
|
||||
netStats = psutil.net_if_stats()
|
||||
netIO = psutil.net_io_counters(pernic=True)
|
||||
net = []
|
||||
for iface in filter(lambda i: i != 'lo' and netStats[i].isup, netStats.keys()):
|
||||
s = ''
|
||||
if iface.startswith('eth'):
|
||||
s += 'E'
|
||||
elif iface.startswith('wlan'):
|
||||
s += 'W'
|
||||
for iface in filter(lambda i: i != "lo" and netStats[i].isup, netStats.keys()):
|
||||
s = ""
|
||||
if iface.startswith("eth"):
|
||||
s += "E"
|
||||
elif iface.startswith("wlan"):
|
||||
s += "W"
|
||||
else:
|
||||
s += '?'
|
||||
s += "?"
|
||||
|
||||
s += ' '
|
||||
s += " "
|
||||
now = time()
|
||||
global oldNetIO, oldTime
|
||||
|
||||
sent = ((oldNetIO[iface].bytes_sent if iface in oldNetIO else 0) - (netIO[iface].bytes_sent if iface in netIO else 0)) / (oldTime - now)
|
||||
recv = ((oldNetIO[iface].bytes_recv if iface in oldNetIO else 0) - (netIO[iface].bytes_recv if iface in netIO else 0)) / (oldTime - now)
|
||||
s += '↓' + humanSizeOf(abs(recv), 'B/s') + ' ↑' + humanSizeOf(abs(sent), 'B/s')
|
||||
sent = (
|
||||
(oldNetIO[iface].bytes_sent if iface in oldNetIO else 0)
|
||||
- (netIO[iface].bytes_sent if iface in netIO else 0)
|
||||
) / (oldTime - now)
|
||||
recv = (
|
||||
(oldNetIO[iface].bytes_recv if iface in oldNetIO else 0)
|
||||
- (netIO[iface].bytes_recv if iface in netIO else 0)
|
||||
) / (oldTime - now)
|
||||
s += (
|
||||
"↓"
|
||||
+ humanSizeOf(abs(recv), "B/s")
|
||||
+ " ↑"
|
||||
+ humanSizeOf(abs(sent), "B/s")
|
||||
)
|
||||
|
||||
oldNetIO = netIO
|
||||
oldTime = now
|
||||
|
||||
net.append(s)
|
||||
t.append(' '.join(net))
|
||||
t.append(" ".join(net))
|
||||
|
||||
# Battery
|
||||
if os.path.isdir('/sys/class/power_supply/BAT0'):
|
||||
with open('/sys/class/power_supply/BAT0/charge_now') as f:
|
||||
if os.path.isdir("/sys/class/power_supply/BAT0"):
|
||||
with open("/sys/class/power_supply/BAT0/charge_now") as f:
|
||||
charge_now = int(f.read())
|
||||
with open('/sys/class/power_supply/BAT0/charge_full_design') as f:
|
||||
with open("/sys/class/power_supply/BAT0/charge_full_design") as f:
|
||||
charge_full = int(f.read())
|
||||
t.append('B' + str(round(100*charge_now/charge_full)) + '%')
|
||||
t.append("B" + str(round(100 * charge_now / charge_full)) + "%")
|
||||
|
||||
# Volume
|
||||
# t.append('V ' + str(alsaaudio.Mixer('Master').getvolume()[0]) + '%')
|
||||
|
||||
t.append(username + '@' + hostname)
|
||||
t.append(username + "@" + hostname)
|
||||
|
||||
# print(' - '.join(t))
|
||||
# t = [output.name]
|
||||
|
||||
z += ' - '.join(t) + '%{S' + str(aOutput + 1) + '}'
|
||||
#lemonbar.stdin.write(bytes(' - '.join(t), 'utf-8'))
|
||||
#lemonbar.stdin.write(bytes('%{S' + str(aOutput + 1) + '}', 'utf-8'))
|
||||
z += " - ".join(t) + "%{S" + str(aOutput + 1) + "}"
|
||||
# lemonbar.stdin.write(bytes(' - '.join(t), 'utf-8'))
|
||||
# lemonbar.stdin.write(bytes('%{S' + str(aOutput + 1) + '}', 'utf-8'))
|
||||
|
||||
lemonbar.stdin.write(bytes(z+'\n', 'utf-8'))
|
||||
lemonbar.stdin.write(bytes(z + "\n", "utf-8"))
|
||||
lemonbar.stdin.flush()
|
||||
|
||||
|
||||
# Event listeners
|
||||
def on_mode(i3, e):
|
||||
global mode
|
||||
if (e.change == 'default'):
|
||||
mode = ''
|
||||
else :
|
||||
if e.change == "default":
|
||||
mode = ""
|
||||
else:
|
||||
mode = e.change
|
||||
update()
|
||||
|
||||
|
||||
i3.on("mode", on_mode)
|
||||
|
||||
#def on_window_focus(i3, e):
|
||||
# def on_window_focus(i3, e):
|
||||
# global container
|
||||
# container = e.container
|
||||
# update()
|
||||
#
|
||||
#i3.on("window::focus", on_window_focus)
|
||||
# i3.on("window::focus", on_window_focus)
|
||||
|
||||
|
||||
def on_workspace_focus(i3, e):
|
||||
global workspaces
|
||||
workspaces = i3.get_workspaces()
|
||||
update()
|
||||
|
||||
|
||||
i3.on("workspace::focus", on_workspace_focus)
|
||||
|
||||
# Starting
|
||||
|
|
|
@ -16,22 +16,37 @@ import difflib
|
|||
FONT = "DejaVu Sans Mono for Powerline"
|
||||
|
||||
# TODO Update to be in sync with base16
|
||||
thm = ['#002b36', '#dc322f', '#859900', '#b58900', '#268bd2', '#6c71c4',
|
||||
'#2aa198', '#93a1a1', '#657b83', '#dc322f', '#859900', '#b58900',
|
||||
'#268bd2', '#6c71c4', '#2aa198', '#fdf6e3']
|
||||
fg = '#93a1a1'
|
||||
bg = '#002b36'
|
||||
thm = [
|
||||
"#002b36",
|
||||
"#dc322f",
|
||||
"#859900",
|
||||
"#b58900",
|
||||
"#268bd2",
|
||||
"#6c71c4",
|
||||
"#2aa198",
|
||||
"#93a1a1",
|
||||
"#657b83",
|
||||
"#dc322f",
|
||||
"#859900",
|
||||
"#b58900",
|
||||
"#268bd2",
|
||||
"#6c71c4",
|
||||
"#2aa198",
|
||||
"#fdf6e3",
|
||||
]
|
||||
fg = "#93a1a1"
|
||||
bg = "#002b36"
|
||||
|
||||
THEMES = {
|
||||
'CENTER': (fg, bg),
|
||||
'DEFAULT': (thm[0], thm[8]),
|
||||
'1': (thm[0], thm[9]),
|
||||
'2': (thm[0], thm[10]),
|
||||
'3': (thm[0], thm[11]),
|
||||
'4': (thm[0], thm[12]),
|
||||
'5': (thm[0], thm[13]),
|
||||
'6': (thm[0], thm[14]),
|
||||
'7': (thm[0], thm[15]),
|
||||
"CENTER": (fg, bg),
|
||||
"DEFAULT": (thm[0], thm[8]),
|
||||
"1": (thm[0], thm[9]),
|
||||
"2": (thm[0], thm[10]),
|
||||
"3": (thm[0], thm[11]),
|
||||
"4": (thm[0], thm[12]),
|
||||
"5": (thm[0], thm[13]),
|
||||
"6": (thm[0], thm[14]),
|
||||
"7": (thm[0], thm[15]),
|
||||
}
|
||||
|
||||
# Utils
|
||||
|
@ -49,7 +64,7 @@ def fitText(text, size):
|
|||
diff = size - t
|
||||
return text + " " * diff
|
||||
else:
|
||||
return ''
|
||||
return ""
|
||||
|
||||
|
||||
def fgColor(theme):
|
||||
|
@ -63,20 +78,20 @@ def bgColor(theme):
|
|||
|
||||
|
||||
class Section:
|
||||
def __init__(self, theme='DEFAULT'):
|
||||
self.text = ''
|
||||
def __init__(self, theme="DEFAULT"):
|
||||
self.text = ""
|
||||
self.size = 0
|
||||
self.toSize = 0
|
||||
self.theme = theme
|
||||
self.visible = False
|
||||
self.name = ''
|
||||
self.name = ""
|
||||
|
||||
def update(self, text):
|
||||
if text == '':
|
||||
if text == "":
|
||||
self.toSize = 0
|
||||
else:
|
||||
if len(text) < len(self.text):
|
||||
self.text = text + self.text[len(text):]
|
||||
self.text = text + self.text[len(text) :]
|
||||
else:
|
||||
self.text = text
|
||||
self.toSize = len(text) + 3
|
||||
|
@ -93,39 +108,39 @@ class Section:
|
|||
self.visible = self.size
|
||||
return self.toSize == self.size
|
||||
|
||||
def draw(self, left=True, nextTheme='DEFAULT'):
|
||||
s = ''
|
||||
def draw(self, left=True, nextTheme="DEFAULT"):
|
||||
s = ""
|
||||
if self.visible:
|
||||
if not left:
|
||||
if self.theme == nextTheme:
|
||||
s += ''
|
||||
s += ""
|
||||
else:
|
||||
s += '%{F' + bgColor(self.theme) + '}'
|
||||
s += '%{B' + bgColor(nextTheme) + '}'
|
||||
s += ''
|
||||
s += '%{F' + fgColor(self.theme) + '}'
|
||||
s += '%{B' + bgColor(self.theme) + '}'
|
||||
s += ' ' if self.size > 1 else ''
|
||||
s += "%{F" + bgColor(self.theme) + "}"
|
||||
s += "%{B" + bgColor(nextTheme) + "}"
|
||||
s += ""
|
||||
s += "%{F" + fgColor(self.theme) + "}"
|
||||
s += "%{B" + bgColor(self.theme) + "}"
|
||||
s += " " if self.size > 1 else ""
|
||||
s += fitText(self.text, self.size - 3)
|
||||
s += ' ' if self.size > 2 else ''
|
||||
s += " " if self.size > 2 else ""
|
||||
if left:
|
||||
if self.theme == nextTheme:
|
||||
s += ''
|
||||
s += ""
|
||||
else:
|
||||
s += '%{F' + bgColor(self.theme) + '}'
|
||||
s += '%{B' + bgColor(nextTheme) + '}'
|
||||
s += ''
|
||||
s += "%{F" + bgColor(self.theme) + "}"
|
||||
s += "%{B" + bgColor(nextTheme) + "}"
|
||||
s += ""
|
||||
return s
|
||||
|
||||
|
||||
# Section definition
|
||||
sTime = Section('3')
|
||||
sTime = Section("3")
|
||||
|
||||
hostname = os.environ['HOSTNAME'].split('.')[0]
|
||||
sHost = Section('2')
|
||||
hostname = os.environ["HOSTNAME"].split(".")[0]
|
||||
sHost = Section("2")
|
||||
sHost.update(
|
||||
os.environ['USER'] + '@' + hostname.split('-')[-1]
|
||||
if '-' in hostname else hostname)
|
||||
os.environ["USER"] + "@" + hostname.split("-")[-1] if "-" in hostname else hostname
|
||||
)
|
||||
|
||||
|
||||
# Groups definition
|
||||
|
@ -133,7 +148,7 @@ gLeft = []
|
|||
gRight = [sTime, sHost]
|
||||
|
||||
# Bar handling
|
||||
bar = subprocess.Popen(['lemonbar', '-f', FONT, '-b'], stdin=subprocess.PIPE)
|
||||
bar = subprocess.Popen(["lemonbar", "-f", FONT, "-b"], stdin=subprocess.PIPE)
|
||||
|
||||
|
||||
def updateBar():
|
||||
|
@ -141,35 +156,45 @@ def updateBar():
|
|||
global gLeft, gRight
|
||||
global outputs
|
||||
|
||||
text = ''
|
||||
text = ""
|
||||
for oi in range(len(outputs)):
|
||||
output = outputs[oi]
|
||||
gLeftFiltered = list(
|
||||
filter(
|
||||
lambda s: s.visible and (
|
||||
not s.output or s.output == output.name),
|
||||
gLeft))
|
||||
tLeft = ''
|
||||
lambda s: s.visible and (not s.output or s.output == output.name), gLeft
|
||||
)
|
||||
)
|
||||
tLeft = ""
|
||||
l = len(gLeftFiltered)
|
||||
for gi in range(l):
|
||||
g = gLeftFiltered[gi]
|
||||
# Next visible section for transition
|
||||
nextTheme = gLeftFiltered[gi + 1].theme if gi + 1 < l else 'CENTER'
|
||||
nextTheme = gLeftFiltered[gi + 1].theme if gi + 1 < l else "CENTER"
|
||||
tLeft = tLeft + g.draw(True, nextTheme)
|
||||
|
||||
tRight = ''
|
||||
tRight = ""
|
||||
for gi in range(len(gRight)):
|
||||
g = gRight[gi]
|
||||
nextTheme = 'CENTER'
|
||||
for gn in gRight[gi + 1:]:
|
||||
nextTheme = "CENTER"
|
||||
for gn in gRight[gi + 1 :]:
|
||||
if gn.visible:
|
||||
nextTheme = gn.theme
|
||||
break
|
||||
tRight = g.draw(False, nextTheme) + tRight
|
||||
text += '%{l}' + tLeft + '%{r}' + tRight + \
|
||||
'%{B' + bgColor('CENTER') + '}' + '%{S' + str(oi + 1) + '}'
|
||||
text += (
|
||||
"%{l}"
|
||||
+ tLeft
|
||||
+ "%{r}"
|
||||
+ tRight
|
||||
+ "%{B"
|
||||
+ bgColor("CENTER")
|
||||
+ "}"
|
||||
+ "%{S"
|
||||
+ str(oi + 1)
|
||||
+ "}"
|
||||
)
|
||||
|
||||
bar.stdin.write(bytes(text + '\n', 'utf-8'))
|
||||
bar.stdin.write(bytes(text + "\n", "utf-8"))
|
||||
bar.stdin.flush()
|
||||
|
||||
|
||||
|
@ -182,12 +207,10 @@ def on_output():
|
|||
global outputs
|
||||
outputs = sorted(
|
||||
sorted(
|
||||
list(
|
||||
filter(
|
||||
lambda o: o.active,
|
||||
i3.get_outputs())),
|
||||
key=lambda o: o.rect.y),
|
||||
key=lambda o: o.rect.x)
|
||||
list(filter(lambda o: o.active, i3.get_outputs())), key=lambda o: o.rect.y
|
||||
),
|
||||
key=lambda o: o.rect.x,
|
||||
)
|
||||
|
||||
|
||||
on_output()
|
||||
|
@ -209,34 +232,33 @@ def on_workspace_focus():
|
|||
if workspace.visible:
|
||||
section.update(workspace.name)
|
||||
else:
|
||||
section.update(workspace.name.split(' ')[0])
|
||||
section.update(workspace.name.split(" ")[0])
|
||||
|
||||
if workspace.focused:
|
||||
section.theme = '4'
|
||||
section.theme = "4"
|
||||
elif workspace.urgent:
|
||||
section.theme = '1'
|
||||
section.theme = "1"
|
||||
else:
|
||||
section.theme = '6'
|
||||
section.theme = "6"
|
||||
else:
|
||||
section.update('')
|
||||
section.theme = '6'
|
||||
section.update("")
|
||||
section.theme = "6"
|
||||
|
||||
for tag, i, j, k, l in difflib.SequenceMatcher(
|
||||
None, sNames, wNames).get_opcodes():
|
||||
if tag == 'equal': # If the workspaces didn't changed
|
||||
for tag, i, j, k, l in difflib.SequenceMatcher(None, sNames, wNames).get_opcodes():
|
||||
if tag == "equal": # If the workspaces didn't changed
|
||||
for a in range(j - i):
|
||||
workspace = workspaces[k + a]
|
||||
section = gLeft[i + a]
|
||||
actuate(section, workspace)
|
||||
newGLeft.append(section)
|
||||
if tag in ('delete', 'replace'): # If the workspaces were removed
|
||||
if tag in ("delete", "replace"): # If the workspaces were removed
|
||||
for section in gLeft[i:j]:
|
||||
if section.visible:
|
||||
actuate(section, None)
|
||||
newGLeft.append(section)
|
||||
else:
|
||||
del section
|
||||
if tag in ('insert', 'replace'): # If the workspaces were removed
|
||||
if tag in ("insert", "replace"): # If the workspaces were removed
|
||||
for workspace in workspaces[k:l]:
|
||||
section = Section()
|
||||
actuate(section, workspace)
|
||||
|
@ -255,12 +277,14 @@ def i3events(i3childPipe):
|
|||
# Proxy functions
|
||||
def on_workspace_focus(i3, e):
|
||||
global i3childPipe
|
||||
i3childPipe.send('on_workspace_focus')
|
||||
i3childPipe.send("on_workspace_focus")
|
||||
|
||||
i3.on("workspace::focus", on_workspace_focus)
|
||||
|
||||
def on_output(i3, e):
|
||||
global i3childPipe
|
||||
i3childPipe.send('on_output')
|
||||
i3childPipe.send("on_output")
|
||||
|
||||
i3.on("output", on_output)
|
||||
|
||||
i3.main()
|
||||
|
@ -274,7 +298,7 @@ i3process.start()
|
|||
def updateValues():
|
||||
# Time
|
||||
now = datetime.datetime.now()
|
||||
sTime.update(now.strftime('%x %X'))
|
||||
sTime.update(now.strftime("%x %X"))
|
||||
|
||||
|
||||
def updateAnimation():
|
||||
|
@ -288,9 +312,9 @@ while True:
|
|||
now = time.time()
|
||||
if i3parentPipe.poll():
|
||||
msg = i3parentPipe.recv()
|
||||
if msg == 'on_workspace_focus':
|
||||
if msg == "on_workspace_focus":
|
||||
on_workspace_focus()
|
||||
elif msg == 'on_output':
|
||||
elif msg == "on_output":
|
||||
on_output()
|
||||
# TODO Restart lemonbar
|
||||
else:
|
||||
|
|
|
@ -16,17 +16,18 @@ import mpd
|
|||
import random
|
||||
import math
|
||||
|
||||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||
coloredlogs.install(level="DEBUG", fmt="%(levelname)s %(message)s")
|
||||
log = logging.getLogger()
|
||||
|
||||
# TODO Generator class (for I3WorkspacesProvider, NetworkProvider and later
|
||||
# PulseaudioProvider and MpdProvider)
|
||||
|
||||
|
||||
def humanSize(num):
|
||||
"""
|
||||
Returns a string of width 3+3
|
||||
"""
|
||||
for unit in ('B ','KiB','MiB','GiB','TiB','PiB','EiB','ZiB'):
|
||||
for unit in ("B ", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"):
|
||||
if abs(num) < 1000:
|
||||
if num >= 10:
|
||||
return "{:3d}{}".format(int(num), unit)
|
||||
|
@ -35,16 +36,15 @@ def humanSize(num):
|
|||
num /= 1024.0
|
||||
return "{:d}YiB".format(num)
|
||||
|
||||
|
||||
def randomColor(seed=0):
|
||||
random.seed(seed)
|
||||
return '#{:02x}{:02x}{:02x}'.format(*[random.randint(0, 255) for _ in range(3)])
|
||||
return "#{:02x}{:02x}{:02x}".format(*[random.randint(0, 255) for _ in range(3)])
|
||||
|
||||
|
||||
class TimeProvider(StatefulSection, PeriodicUpdater):
|
||||
|
||||
FORMATS = ["%H:%M",
|
||||
"%m-%d %H:%M:%S",
|
||||
"%a %y-%m-%d %H:%M:%S"]
|
||||
FORMATS = ["%H:%M", "%m-%d %H:%M:%S", "%a %y-%m-%d %H:%M:%S"]
|
||||
NUMBER_STATES = len(FORMATS)
|
||||
DEFAULT_STATE = 1
|
||||
|
||||
|
@ -55,18 +55,18 @@ class TimeProvider(StatefulSection, PeriodicUpdater):
|
|||
def __init__(self, theme=None):
|
||||
PeriodicUpdater.__init__(self)
|
||||
StatefulSection.__init__(self, theme)
|
||||
self.changeInterval(1) # TODO OPTI When state < 1
|
||||
self.changeInterval(1) # TODO OPTI When state < 1
|
||||
|
||||
|
||||
class AlertLevel(enum.Enum):
|
||||
NORMAL = 0
|
||||
WARNING = 1
|
||||
DANGER = 2
|
||||
|
||||
|
||||
class AlertingSection(StatefulSection):
|
||||
# TODO EASE Correct settings for themes
|
||||
THEMES = {AlertLevel.NORMAL: 2,
|
||||
AlertLevel.WARNING: 3,
|
||||
AlertLevel.DANGER: 1}
|
||||
THEMES = {AlertLevel.NORMAL: 2, AlertLevel.WARNING: 3, AlertLevel.DANGER: 1}
|
||||
PERSISTENT = True
|
||||
|
||||
def getLevel(self, quantity):
|
||||
|
@ -92,16 +92,16 @@ class AlertingSection(StatefulSection):
|
|||
|
||||
class CpuProvider(AlertingSection, PeriodicUpdater):
|
||||
NUMBER_STATES = 3
|
||||
ICON = ''
|
||||
ICON = ""
|
||||
|
||||
def fetcher(self):
|
||||
percent = psutil.cpu_percent(percpu=False)
|
||||
self.updateLevel(percent/100)
|
||||
self.updateLevel(percent / 100)
|
||||
if self.state >= 2:
|
||||
percents = psutil.cpu_percent(percpu=True)
|
||||
return ''.join([Section.ramp(p/100) for p in percents])
|
||||
return "".join([Section.ramp(p / 100) for p in percents])
|
||||
elif self.state >= 1:
|
||||
return Section.ramp(percent/100)
|
||||
return Section.ramp(percent / 100)
|
||||
|
||||
def __init__(self, theme=None):
|
||||
AlertingSection.__init__(self, theme)
|
||||
|
@ -113,12 +113,13 @@ class RamProvider(AlertingSection, PeriodicUpdater):
|
|||
"""
|
||||
Shows free RAM
|
||||
"""
|
||||
|
||||
NUMBER_STATES = 4
|
||||
ICON = ''
|
||||
ICON = ""
|
||||
|
||||
def fetcher(self):
|
||||
mem = psutil.virtual_memory()
|
||||
freePerc = mem.percent/100
|
||||
freePerc = mem.percent / 100
|
||||
self.updateLevel(freePerc)
|
||||
|
||||
if self.state < 1:
|
||||
|
@ -130,7 +131,7 @@ class RamProvider(AlertingSection, PeriodicUpdater):
|
|||
text.append(freeStr)
|
||||
if self.state >= 3:
|
||||
totalStr = humanSize(mem.total)
|
||||
text.append('/', totalStr)
|
||||
text.append("/", totalStr)
|
||||
|
||||
return text
|
||||
|
||||
|
@ -146,18 +147,18 @@ class TemperatureProvider(AlertingSection, PeriodicUpdater):
|
|||
|
||||
def fetcher(self):
|
||||
allTemp = psutil.sensors_temperatures()
|
||||
if 'coretemp' not in allTemp:
|
||||
if "coretemp" not in allTemp:
|
||||
# TODO Opti Remove interval
|
||||
return ''
|
||||
temp = allTemp['coretemp'][0]
|
||||
return ""
|
||||
temp = allTemp["coretemp"][0]
|
||||
|
||||
self.warningThresold = temp.high
|
||||
self.dangerThresold = temp.critical
|
||||
self.updateLevel(temp.current)
|
||||
|
||||
self.icon = Section.ramp(temp.current/temp.high, self.RAMP)
|
||||
self.icon = Section.ramp(temp.current / temp.high, self.RAMP)
|
||||
if self.state >= 1:
|
||||
return '{:.0f}°C'.format(temp.current)
|
||||
return "{:.0f}°C".format(temp.current)
|
||||
|
||||
def __init__(self, theme=None):
|
||||
AlertingSection.__init__(self, theme)
|
||||
|
@ -176,15 +177,16 @@ class BatteryProvider(AlertingSection, PeriodicUpdater):
|
|||
self.icon = None
|
||||
return None
|
||||
|
||||
self.icon = ("" if bat.power_plugged else "") + \
|
||||
Section.ramp(bat.percent/100, self.RAMP)
|
||||
self.icon = ("" if bat.power_plugged else "") + Section.ramp(
|
||||
bat.percent / 100, self.RAMP
|
||||
)
|
||||
|
||||
self.updateLevel(1-bat.percent/100)
|
||||
self.updateLevel(1 - bat.percent / 100)
|
||||
|
||||
if self.state < 1:
|
||||
return
|
||||
|
||||
t = Text('{:.0f}%'.format(bat.percent))
|
||||
t = Text("{:.0f}%".format(bat.percent))
|
||||
|
||||
if self.state < 2:
|
||||
return t
|
||||
|
@ -200,7 +202,6 @@ class BatteryProvider(AlertingSection, PeriodicUpdater):
|
|||
self.changeInterval(5)
|
||||
|
||||
|
||||
|
||||
class PulseaudioProvider(StatefulSection, ThreadedUpdater):
|
||||
NUMBER_STATES = 3
|
||||
DEFAULT_STATE = 1
|
||||
|
@ -208,28 +209,27 @@ class PulseaudioProvider(StatefulSection, ThreadedUpdater):
|
|||
def __init__(self, theme=None):
|
||||
ThreadedUpdater.__init__(self)
|
||||
StatefulSection.__init__(self, theme)
|
||||
self.pulseEvents = pulsectl.Pulse('event-handler')
|
||||
self.pulseEvents = pulsectl.Pulse("event-handler")
|
||||
|
||||
self.pulseEvents.event_mask_set(pulsectl.PulseEventMaskEnum.sink)
|
||||
self.pulseEvents.event_callback_set(self.handleEvent)
|
||||
self.start()
|
||||
self.refreshData()
|
||||
|
||||
|
||||
def fetcher(self):
|
||||
sinks = []
|
||||
with pulsectl.Pulse('list-sinks') as pulse:
|
||||
with pulsectl.Pulse("list-sinks") as pulse:
|
||||
for sink in pulse.sink_list():
|
||||
if sink.port_active.name == "analog-output-headphones":
|
||||
icon = ""
|
||||
elif sink.port_active.name == "analog-output-speaker":
|
||||
icon = "" if sink.mute else ""
|
||||
elif sink.port_active.name == "headset-output":
|
||||
icon = ''
|
||||
icon = ""
|
||||
else:
|
||||
icon = "?"
|
||||
vol = pulse.volume_get_all_chans(sink)
|
||||
fg = (sink.mute and '#333333') or (vol > 1 and '#FF0000') or None
|
||||
fg = (sink.mute and "#333333") or (vol > 1 and "#FF0000") or None
|
||||
|
||||
t = Text(icon, fg=fg)
|
||||
sinks.append(t)
|
||||
|
@ -245,7 +245,7 @@ class PulseaudioProvider(StatefulSection, ThreadedUpdater):
|
|||
vol -= 1
|
||||
t.append(ramp)
|
||||
else:
|
||||
t.append(" {:2.0f}%".format(vol*100))
|
||||
t.append(" {:2.0f}%".format(vol * 100))
|
||||
|
||||
return Text(*sinks)
|
||||
|
||||
|
@ -263,27 +263,27 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
|
||||
def actType(self):
|
||||
self.ssid = None
|
||||
if self.iface.startswith('eth') or self.iface.startswith('enp'):
|
||||
if 'u' in self.iface:
|
||||
self.icon = ''
|
||||
if self.iface.startswith("eth") or self.iface.startswith("enp"):
|
||||
if "u" in self.iface:
|
||||
self.icon = ""
|
||||
else:
|
||||
self.icon = ''
|
||||
elif self.iface.startswith('wlan') or self.iface.startswith('wl'):
|
||||
self.icon = ''
|
||||
self.icon = ""
|
||||
elif self.iface.startswith("wlan") or self.iface.startswith("wl"):
|
||||
self.icon = ""
|
||||
if self.showSsid:
|
||||
cmd = ["iwgetid", self.iface, "--raw"]
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE)
|
||||
self.ssid = p.stdout.strip().decode()
|
||||
elif self.iface.startswith('tun') or self.iface.startswith('tap'):
|
||||
self.icon = ''
|
||||
elif self.iface.startswith('docker'):
|
||||
self.icon = ''
|
||||
elif self.iface.startswith('veth'):
|
||||
self.icon = ''
|
||||
elif self.iface.startswith('vboxnet'):
|
||||
self.icon = ''
|
||||
elif self.iface.startswith("tun") or self.iface.startswith("tap"):
|
||||
self.icon = ""
|
||||
elif self.iface.startswith("docker"):
|
||||
self.icon = ""
|
||||
elif self.iface.startswith("veth"):
|
||||
self.icon = ""
|
||||
elif self.iface.startswith("vboxnet"):
|
||||
self.icon = ""
|
||||
else:
|
||||
self.icon = '?'
|
||||
self.icon = "?"
|
||||
|
||||
def getAddresses(self):
|
||||
ipv4 = None
|
||||
|
@ -298,9 +298,11 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
def fetcher(self):
|
||||
self.icon = None
|
||||
self.persistent = False
|
||||
if self.iface not in self.parent.stats or \
|
||||
not self.parent.stats[self.iface].isup or \
|
||||
self.iface.startswith('lo'):
|
||||
if (
|
||||
self.iface not in self.parent.stats
|
||||
or not self.parent.stats[self.iface].isup
|
||||
or self.iface.startswith("lo")
|
||||
):
|
||||
return None
|
||||
|
||||
# Get addresses
|
||||
|
@ -317,30 +319,36 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
|
||||
if self.showAddress:
|
||||
if ipv4:
|
||||
netStrFull = '{}/{}'.format(ipv4.address, ipv4.netmask)
|
||||
netStrFull = "{}/{}".format(ipv4.address, ipv4.netmask)
|
||||
addr = ipaddress.IPv4Network(netStrFull, strict=False)
|
||||
addrStr = '{}/{}'.format(ipv4.address, addr.prefixlen)
|
||||
addrStr = "{}/{}".format(ipv4.address, addr.prefixlen)
|
||||
text.append(addrStr)
|
||||
# TODO IPV6
|
||||
# if ipv6:
|
||||
# text += ' ' + ipv6.address
|
||||
|
||||
if self.showSpeed:
|
||||
recvDiff = self.parent.IO[self.iface].bytes_recv \
|
||||
recvDiff = (
|
||||
self.parent.IO[self.iface].bytes_recv
|
||||
- self.parent.prevIO[self.iface].bytes_recv
|
||||
sentDiff = self.parent.IO[self.iface].bytes_sent \
|
||||
)
|
||||
sentDiff = (
|
||||
self.parent.IO[self.iface].bytes_sent
|
||||
- self.parent.prevIO[self.iface].bytes_sent
|
||||
)
|
||||
recvDiff /= self.parent.dt
|
||||
sentDiff /= self.parent.dt
|
||||
text.append('↓{}↑{}'.format(humanSize(recvDiff),
|
||||
humanSize(sentDiff)))
|
||||
text.append("↓{}↑{}".format(humanSize(recvDiff), humanSize(sentDiff)))
|
||||
|
||||
if self.showTransfer:
|
||||
text.append('⇓{}⇑{}'.format(
|
||||
humanSize(self.parent.IO[self.iface].bytes_recv),
|
||||
humanSize(self.parent.IO[self.iface].bytes_sent)))
|
||||
text.append(
|
||||
"⇓{}⇑{}".format(
|
||||
humanSize(self.parent.IO[self.iface].bytes_recv),
|
||||
humanSize(self.parent.IO[self.iface].bytes_sent),
|
||||
)
|
||||
)
|
||||
|
||||
return ' '.join(text)
|
||||
return " ".join(text)
|
||||
|
||||
def onChangeState(self, state):
|
||||
self.showSsid = state >= 1
|
||||
|
@ -402,32 +410,33 @@ class NetworkProvider(Section, PeriodicUpdater):
|
|||
self.fetchData()
|
||||
self.changeInterval(5)
|
||||
|
||||
|
||||
class RfkillProvider(Section, PeriodicUpdater):
|
||||
# TODO FEAT rfkill doesn't seem to indicate that the hardware switch is
|
||||
# toggled
|
||||
PATH = '/sys/class/rfkill'
|
||||
PATH = "/sys/class/rfkill"
|
||||
|
||||
def fetcher(self):
|
||||
t = Text()
|
||||
for device in os.listdir(self.PATH):
|
||||
with open(os.path.join(self.PATH, device, 'soft'), 'rb') as f:
|
||||
softBlocked = f.read().strip() != b'0'
|
||||
with open(os.path.join(self.PATH, device, 'hard'), 'rb') as f:
|
||||
hardBlocked = f.read().strip() != b'0'
|
||||
with open(os.path.join(self.PATH, device, "soft"), "rb") as f:
|
||||
softBlocked = f.read().strip() != b"0"
|
||||
with open(os.path.join(self.PATH, device, "hard"), "rb") as f:
|
||||
hardBlocked = f.read().strip() != b"0"
|
||||
|
||||
if not hardBlocked and not softBlocked:
|
||||
continue
|
||||
|
||||
with open(os.path.join(self.PATH, device, 'type'), 'rb') as f:
|
||||
with open(os.path.join(self.PATH, device, "type"), "rb") as f:
|
||||
typ = f.read().strip()
|
||||
|
||||
fg = (hardBlocked and '#CCCCCC') or (softBlocked and '#FF0000')
|
||||
if typ == b'wlan':
|
||||
icon = ''
|
||||
elif typ == b'bluetooth':
|
||||
icon = ''
|
||||
fg = (hardBlocked and "#CCCCCC") or (softBlocked and "#FF0000")
|
||||
if typ == b"wlan":
|
||||
icon = ""
|
||||
elif typ == b"bluetooth":
|
||||
icon = ""
|
||||
else:
|
||||
icon = '?'
|
||||
icon = "?"
|
||||
|
||||
t.append(Text(icon, fg=fg))
|
||||
return t
|
||||
|
@ -437,6 +446,7 @@ class RfkillProvider(Section, PeriodicUpdater):
|
|||
Section.__init__(self, theme)
|
||||
self.changeInterval(5)
|
||||
|
||||
|
||||
class SshAgentProvider(PeriodicUpdater):
|
||||
def fetcher(self):
|
||||
cmd = ["ssh-add", "-l"]
|
||||
|
@ -444,17 +454,18 @@ class SshAgentProvider(PeriodicUpdater):
|
|||
if proc.returncode != 0:
|
||||
return None
|
||||
text = Text()
|
||||
for line in proc.stdout.split(b'\n'):
|
||||
for line in proc.stdout.split(b"\n"):
|
||||
if not len(line):
|
||||
continue
|
||||
fingerprint = line.split()[1]
|
||||
text.append(Text('', fg=randomColor(seed=fingerprint)))
|
||||
text.append(Text("", fg=randomColor(seed=fingerprint)))
|
||||
return text
|
||||
|
||||
def __init__(self):
|
||||
PeriodicUpdater.__init__(self)
|
||||
self.changeInterval(5)
|
||||
|
||||
|
||||
class GpgAgentProvider(PeriodicUpdater):
|
||||
def fetcher(self):
|
||||
cmd = ["gpg-connect-agent", "keyinfo --list", "/bye"]
|
||||
|
@ -463,39 +474,41 @@ class GpgAgentProvider(PeriodicUpdater):
|
|||
if proc.returncode != 0:
|
||||
return None
|
||||
text = Text()
|
||||
for line in proc.stdout.split(b'\n'):
|
||||
if not len(line) or line == b'OK':
|
||||
for line in proc.stdout.split(b"\n"):
|
||||
if not len(line) or line == b"OK":
|
||||
continue
|
||||
spli = line.split()
|
||||
if spli[6] != b'1':
|
||||
if spli[6] != b"1":
|
||||
continue
|
||||
keygrip = spli[2]
|
||||
text.append(Text('', fg=randomColor(seed=keygrip)))
|
||||
text.append(Text("", fg=randomColor(seed=keygrip)))
|
||||
return text
|
||||
|
||||
def __init__(self):
|
||||
PeriodicUpdater.__init__(self)
|
||||
self.changeInterval(5)
|
||||
|
||||
|
||||
class KeystoreProvider(Section, MergedUpdater):
|
||||
# TODO OPTI+FEAT Use ColorCountsSection and not MergedUpdater, this is useless
|
||||
ICON = ''
|
||||
ICON = ""
|
||||
|
||||
def __init__(self, theme=None):
|
||||
MergedUpdater.__init__(self, SshAgentProvider(), GpgAgentProvider())
|
||||
Section.__init__(self, theme)
|
||||
|
||||
|
||||
class NotmuchUnreadProvider(ColorCountsSection, InotifyUpdater):
|
||||
COLORABLE_ICON = ''
|
||||
COLORABLE_ICON = ""
|
||||
|
||||
def subfetcher(self):
|
||||
db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY, path=self.dir)
|
||||
counts = []
|
||||
for account in self.accounts:
|
||||
queryStr = 'folder:/{}/ and tag:unread'.format(account)
|
||||
queryStr = "folder:/{}/ and tag:unread".format(account)
|
||||
query = notmuch.Query(db, queryStr)
|
||||
nbMsgs = query.count_messages()
|
||||
if account == 'frogeye':
|
||||
if account == "frogeye":
|
||||
global q
|
||||
q = query
|
||||
if nbMsgs < 1:
|
||||
|
@ -504,7 +517,7 @@ class NotmuchUnreadProvider(ColorCountsSection, InotifyUpdater):
|
|||
# db.close()
|
||||
return counts
|
||||
|
||||
def __init__(self, dir='~/.mail/', theme=None):
|
||||
def __init__(self, dir="~/.mail/", theme=None):
|
||||
PeriodicUpdater.__init__(self)
|
||||
ColorCountsSection.__init__(self, theme)
|
||||
|
||||
|
@ -512,23 +525,24 @@ class NotmuchUnreadProvider(ColorCountsSection, InotifyUpdater):
|
|||
assert os.path.isdir(self.dir)
|
||||
|
||||
# Fetching account list
|
||||
self.accounts = sorted([a for a in os.listdir(self.dir)
|
||||
if not a.startswith('.')])
|
||||
self.accounts = sorted(
|
||||
[a for a in os.listdir(self.dir) if not a.startswith(".")]
|
||||
)
|
||||
# Fetching colors
|
||||
self.colors = dict()
|
||||
for account in self.accounts:
|
||||
filename = os.path.join(self.dir, account, 'color')
|
||||
with open(filename, 'r') as f:
|
||||
filename = os.path.join(self.dir, account, "color")
|
||||
with open(filename, "r") as f:
|
||||
color = f.read().strip()
|
||||
self.colors[account] = color
|
||||
|
||||
self.addPath(os.path.join(self.dir, '.notmuch', 'xapian'))
|
||||
self.addPath(os.path.join(self.dir, ".notmuch", "xapian"))
|
||||
|
||||
|
||||
class TodoProvider(ColorCountsSection, InotifyUpdater):
|
||||
# TODO OPT/UX Maybe we could get more data from the todoman python module
|
||||
# TODO OPT Specific callback for specific directory
|
||||
COLORABLE_ICON = ''
|
||||
COLORABLE_ICON = ""
|
||||
|
||||
def updateCalendarList(self):
|
||||
calendars = sorted(os.listdir(self.dir))
|
||||
|
@ -538,13 +552,13 @@ class TodoProvider(ColorCountsSection, InotifyUpdater):
|
|||
self.addPath(os.path.join(self.dir, calendar), refresh=False)
|
||||
|
||||
# Fetching name
|
||||
path = os.path.join(self.dir, calendar, 'displayname')
|
||||
with open(path, 'r') as f:
|
||||
path = os.path.join(self.dir, calendar, "displayname")
|
||||
with open(path, "r") as f:
|
||||
self.names[calendar] = f.read().strip()
|
||||
|
||||
# Fetching color
|
||||
path = os.path.join(self.dir, calendar, 'color')
|
||||
with open(path, 'r') as f:
|
||||
path = os.path.join(self.dir, calendar, "color")
|
||||
with open(path, "r") as f:
|
||||
self.colors[calendar] = f.read().strip()
|
||||
self.calendars = calendars
|
||||
|
||||
|
@ -579,8 +593,8 @@ class TodoProvider(ColorCountsSection, InotifyUpdater):
|
|||
if self.state < 2:
|
||||
c = self.countUndone(None)
|
||||
if c > 0:
|
||||
counts.append((c, '#00000'))
|
||||
counts.append((0, '#FFFFF'))
|
||||
counts.append((c, "#00000"))
|
||||
counts.append((0, "#FFFFF"))
|
||||
return counts
|
||||
# Optimisation ends here
|
||||
|
||||
|
@ -591,6 +605,7 @@ class TodoProvider(ColorCountsSection, InotifyUpdater):
|
|||
counts.append((c, self.colors[calendar]))
|
||||
return counts
|
||||
|
||||
|
||||
class I3WindowTitleProvider(Section, I3Updater):
|
||||
# TODO FEAT To make this available from start, we need to find the
|
||||
# `focused=True` element following the `focus` array
|
||||
|
@ -603,6 +618,7 @@ class I3WindowTitleProvider(Section, I3Updater):
|
|||
Section.__init__(self, theme=theme)
|
||||
self.on("window", self.on_window)
|
||||
|
||||
|
||||
class I3WorkspacesProviderSection(Section):
|
||||
def selectTheme(self):
|
||||
if self.urgent:
|
||||
|
@ -626,12 +642,12 @@ class I3WorkspacesProviderSection(Section):
|
|||
|
||||
def setName(self, name):
|
||||
self.shortName = name
|
||||
self.fullName = self.parent.customNames[name] \
|
||||
if name in self.parent.customNames else name
|
||||
self.fullName = (
|
||||
self.parent.customNames[name] if name in self.parent.customNames else name
|
||||
)
|
||||
|
||||
def switchTo(self):
|
||||
self.parent.i3.command('workspace {}'.format(self.shortName))
|
||||
|
||||
self.parent.i3.command("workspace {}".format(self.shortName))
|
||||
|
||||
def __init__(self, name, parent):
|
||||
Section.__init__(self)
|
||||
|
@ -652,7 +668,6 @@ class I3WorkspacesProviderSection(Section):
|
|||
self.updateText(None)
|
||||
|
||||
|
||||
|
||||
class I3WorkspacesProvider(Section, I3Updater):
|
||||
# TODO FEAT Multi-screen
|
||||
|
||||
|
@ -713,7 +728,7 @@ class I3WorkspacesProvider(Section, I3Updater):
|
|||
self.sections[e.current.num].show()
|
||||
|
||||
def on_mode(self, i3, e):
|
||||
if e.change == 'default':
|
||||
if e.change == "default":
|
||||
self.modeSection.updateText(None)
|
||||
for section in self.sections.values():
|
||||
section.tempShow()
|
||||
|
@ -722,7 +737,9 @@ class I3WorkspacesProvider(Section, I3Updater):
|
|||
for section in self.sections.values():
|
||||
section.tempEmpty()
|
||||
|
||||
def __init__(self, theme=0, themeFocus=3, themeUrgent=1, themeMode=2, customNames=dict()):
|
||||
def __init__(
|
||||
self, theme=0, themeFocus=3, themeUrgent=1, themeMode=2, customNames=dict()
|
||||
):
|
||||
I3Updater.__init__(self)
|
||||
Section.__init__(self)
|
||||
self.themeNormal = theme
|
||||
|
@ -746,13 +763,14 @@ class I3WorkspacesProvider(Section, I3Updater):
|
|||
parent.addSection(self.modeSection)
|
||||
self.initialPopulation(parent)
|
||||
|
||||
|
||||
class MpdProvider(Section, ThreadedUpdater):
|
||||
# TODO FEAT More informations and controls
|
||||
|
||||
MAX_LENGTH = 50
|
||||
|
||||
def connect(self):
|
||||
self.mpd.connect('localhost', 6600)
|
||||
self.mpd.connect("localhost", 6600)
|
||||
|
||||
def __init__(self, theme=None):
|
||||
ThreadedUpdater.__init__(self)
|
||||
|
@ -784,18 +802,16 @@ class MpdProvider(Section, ThreadedUpdater):
|
|||
|
||||
infosStr = " - ".join(infos)
|
||||
if len(infosStr) > MpdProvider.MAX_LENGTH:
|
||||
infosStr = infosStr[:MpdProvider.MAX_LENGTH-1] + '…'
|
||||
infosStr = infosStr[: MpdProvider.MAX_LENGTH - 1] + "…"
|
||||
|
||||
return " {}".format(infosStr)
|
||||
|
||||
def loop(self):
|
||||
try:
|
||||
self.mpd.idle('player')
|
||||
self.mpd.idle("player")
|
||||
self.refreshData()
|
||||
except mpd.base.ConnectionError as e:
|
||||
log.warn(e, exc_info=True)
|
||||
self.connect()
|
||||
except BaseException as e:
|
||||
log.error(e, exc_info=True)
|
||||
|
||||
|
||||
|
|
|
@ -11,13 +11,14 @@ import coloredlogs
|
|||
import i3ipc
|
||||
from display import Text
|
||||
|
||||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||
coloredlogs.install(level="DEBUG", fmt="%(levelname)s %(message)s")
|
||||
log = logging.getLogger()
|
||||
|
||||
# TODO Sync bar update with PeriodicUpdater updates
|
||||
|
||||
notBusy = threading.Event()
|
||||
|
||||
|
||||
class Updater:
|
||||
@staticmethod
|
||||
def init():
|
||||
|
@ -52,8 +53,9 @@ class PeriodicUpdaterThread(threading.Thread):
|
|||
counter = 0
|
||||
while True:
|
||||
notBusy.set()
|
||||
if PeriodicUpdater.intervalsChanged \
|
||||
.wait(timeout=PeriodicUpdater.intervalStep):
|
||||
if PeriodicUpdater.intervalsChanged.wait(
|
||||
timeout=PeriodicUpdater.intervalStep
|
||||
):
|
||||
# ↑ sleeps here
|
||||
notBusy.clear()
|
||||
PeriodicUpdater.intervalsChanged.clear()
|
||||
|
@ -127,7 +129,6 @@ class PeriodicUpdater(Updater):
|
|||
|
||||
|
||||
class InotifyUpdaterEventHandler(pyinotify.ProcessEvent):
|
||||
|
||||
def process_default(self, event):
|
||||
# DEBUG
|
||||
# from pprint import pprint
|
||||
|
@ -155,8 +156,9 @@ class InotifyUpdater(Updater):
|
|||
|
||||
@staticmethod
|
||||
def init():
|
||||
notifier = pyinotify.ThreadedNotifier(InotifyUpdater.wm,
|
||||
InotifyUpdaterEventHandler())
|
||||
notifier = pyinotify.ThreadedNotifier(
|
||||
InotifyUpdater.wm, InotifyUpdaterEventHandler()
|
||||
)
|
||||
notifier.start()
|
||||
|
||||
# TODO Mask for folders
|
||||
|
@ -174,8 +176,7 @@ class InotifyUpdater(Updater):
|
|||
self.dirpath = os.path.dirname(path)
|
||||
self.filename = os.path.basename(path)
|
||||
else:
|
||||
raise FileNotFoundError("No such file or directory: '{}'"
|
||||
.format(path))
|
||||
raise FileNotFoundError("No such file or directory: '{}'".format(path))
|
||||
|
||||
# Register watch action
|
||||
if self.dirpath not in InotifyUpdater.paths:
|
||||
|
@ -266,4 +267,4 @@ class MergedUpdater(Updater):
|
|||
updater.updateText = newUpdateText.__get__(updater, Updater)
|
||||
|
||||
self.updaters.append(updater)
|
||||
self.texts[updater] = ''
|
||||
self.texts[updater] = ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue