Lemonbar new!

This commit is contained in:
Geoffrey Frogeye 2018-08-21 21:50:44 +02:00
parent ca47c8a8a2
commit 8857158edb
2 changed files with 327 additions and 28 deletions

262
config/lemonbar/new.py Executable file
View file

@ -0,0 +1,262 @@
#!/usr/bin/env python3
import enum
import logging
import threading
import time
# TODO Update strategies (periodic, inotify file)
# TODO Section order (priority system maybe ?)
# TODO Allow deletion of Bar, BarGroup and Section for screen changes
# TODO Optimize to use write() calls instead of string concatenation (writing
# BarGroup strings should be a good compromise)
class BarGroupType(enum.Enum):
LEFT = 0
RIGHT = 1
# MID_LEFT = 2
# MID_RIGHT = 3
class Bar:
"""
One bar for each screen
"""
everyone = set()
string = ""
@staticmethod
def init():
Section.init()
# Debug
Bar()
def __init__(self):
self.screen = 0 # TODO
self.groups = dict()
for groupType in BarGroupType:
group = BarGroup(groupType, self)
self.groups[groupType] = group
self.childsChanged = False
self.everyone.add(self)
@staticmethod
def addSectionAll(section, group, screens=None):
"""
.. note::
Add the section before updating it for the first time.
"""
assert isinstance(section, Section)
assert isinstance(group, BarGroupType)
# TODO screens selection
for bar in Bar.everyone:
bar.addSection(section, group=group)
def addSection(self, section, group):
assert isinstance(section, Section)
assert isinstance(group, BarGroupType)
self.groups[group].addSection(section)
def update(self):
if self.childsChanged:
self.string = ""
self.childsChanged = False
@staticmethod
def updateAll():
for bar in Bar.everyone:
bar.update()
Bar.string = ""
class BarGroup:
"""
One for each group of each bar
"""
everyone = set()
def __init__(self, groupType, parent):
assert isinstance(groupType, BarGroupType)
assert isinstance(parent, Bar)
self.groupType = groupType
self.parent = parent
self.sections = list()
self.string = ''
self.form = ''
#: One of the sections that had their theme or visibility changed
self.childsThemeChanged = False
#: One of the sections that had their text (maybe their size) changed
self.childsTextChanged = False
BarGroup.everyone.add(self)
def addSection(self, section):
self.sections.append(section)
section.parents.add(self)
def update(self):
if self.childsThemeChanged:
# TODO
self.form = ">".join([sec.curText for sec in self.sections
if sec.visible])
if self.childsTextChanged or self.childsThemeChanged:
print("118")
self.string = ">".join([sec.curText for sec in self.sections
if sec.visible])
print("|{0}|".format(self.string))
self.parent.childsChanged = True
self.childsThemeChanged = False
self.childsTextChanged = False
@staticmethod
def updateAll():
print("130")
for group in BarGroup.everyone:
group.update()
Bar.updateAll()
class SectionThread(threading.Thread):
def run(self):
while Section.somethingChanged.wait():
Section.updateAll()
while len(Section.sizeChanging) > 0:
time.sleep(0.1)
Section.updateAll()
class Section:
#: Sections that do not have their destination size
sizeChanging = set()
somethingChanged = threading.Event()
updateThread = None
@staticmethod
def init():
Section.updateThread = SectionThread(daemon=True)
Section.updateThread.start()
def __init__(self):
#: Displayed section
#: Note: A section can be empty and displayed!
self.visible = False
#: Displayed text
self.curText = ''
#: Displayed text size
self.curSize = 0
#: Destination text
self.dstText = ''
#: Destination size
self.dstSize = 0
#: Groups that have this section
self.parents = set()
def informParentsThemeChanged(self):
for parent in self.parents:
parent.childsThemeChanged = True
def informParentsTextChanged(self):
for parent in self.parents:
parent.childsTextChanged = True
def updateText(self, text):
if len(text):
self.dstText = ' {} '.format(text)
self.dstSize = len(self.dstText)
else:
self.dstSize = 0
if self.curSize == self.dstSize:
self.curText = self.dstText
self.informParentsTextChanged()
else:
Section.sizeChanging.add(self)
Section.somethingChanged.set()
def updateVisibility(self, visibility):
assert isinstance(visibility, bool)
self.visible = visibility
self.informParentsThemeChanged()
Section.somethingChanged.set()
@staticmethod
def fit(text, size):
t = len(text)
return text[:size] if t >= size else text + " " * (size - t)
def update(self):
# TODO Might profit of a better logic
if not self.visible:
self.updateVisibility(True)
return
if self.dstSize > self.curSize:
self.curSize += 1
elif self.dstSize < self.curSize:
self.curSize -= 1
else:
# Visibility toggling must be done one step after curSize = 0
if self.dstSize == 0:
self.updateVisibility(False)
Section.sizeChanging.remove(self)
return
self.curText = Section.fit(self.dstText, self.curSize)
self.informParentsTextChanged()
@staticmethod
def updateAll():
"""
Process all sections for text size changes
"""
for sizeChanging in Section.sizeChanging.copy():
sizeChanging.update()
# print("{1:3d} |{0}|".format(sizeChanging.curText, sizeChanging.curSize))
BarGroup.updateAll()
Section.somethingChanged.clear()
if __name__ == '__main__':
Bar.init()
sec = Section()
sec1 = Section()
Bar.addSectionAll(sec, BarGroupType.LEFT)
Bar.addSectionAll(sec1, BarGroupType.LEFT)
sec.updateText("Hello")
# sec1.updateText("world!")
time.sleep(2)
sec.updateText("Salut")
# sec1.updateText("le monde !")
time.sleep(2)
sec.updateText("")
# sec1.updateText("")
time.sleep(2)

View file

@ -15,44 +15,53 @@ import difflib
# Constants # Constants
FONT = "DejaVu Sans Mono for Powerline" FONT = "DejaVu Sans Mono for Powerline"
thm = ['#002b36','#dc322f','#859900','#b58900','#268bd2','#6c71c4','#2aa198','#93a1a1','#657b83','#dc322f','#859900','#b58900','#268bd2','#6c71c4','#2aa198','#fdf6e3'] # 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' fg = '#93a1a1'
bg = '#002b36' bg = '#002b36'
THEMES = { THEMES = {
'CENTER': (fg, bg), 'CENTER': (fg, bg),
'DEFAULT': (thm[0], thm[8]), 'DEFAULT': (thm[0], thm[8]),
'1': (thm[0], thm[9]), '1': (thm[0], thm[9]),
'2': (thm[0], thm[10]), '2': (thm[0], thm[10]),
'3': (thm[0], thm[11]), '3': (thm[0], thm[11]),
'4': (thm[0], thm[12]), '4': (thm[0], thm[12]),
'5': (thm[0], thm[13]), '5': (thm[0], thm[13]),
'6': (thm[0], thm[14]), '6': (thm[0], thm[14]),
'7': (thm[0], thm[15]), '7': (thm[0], thm[15]),
} }
# Utils # Utils
def fitText(text, size): def fitText(text, size):
""" """
Add spaces or cut a string to be `size` characters long Add spaces or cut a string to be `size` characters long
""" """
if size > 0: if size > 0:
if len(text) >= size: t = len(text)
if t >= size:
return text[:size] return text[:size]
else: else:
return ('%' + str(size) + 's') % text diff = size - t
return text + " " * diff
else: else:
return '' return ''
def fgColor(theme): def fgColor(theme):
global THEMES global THEMES
return THEMES[theme][0] return THEMES[theme][0]
def bgColor(theme): def bgColor(theme):
global THEMES global THEMES
return THEMES[theme][1] return THEMES[theme][1]
class Section: class Section:
def __init__(self, theme='DEFAULT'): def __init__(self, theme='DEFAULT'):
self.text = '' self.text = ''
@ -108,12 +117,15 @@ class Section:
s += '' s += ''
return s return s
# Section definition # Section definition
sTime = Section('3') sTime = Section('3')
hostname = os.environ['HOSTNAME'].split('.')[0] hostname = os.environ['HOSTNAME'].split('.')[0]
sHost = Section('2') sHost = Section('2')
sHost.update(os.environ['USER'] + '@' + hostname.split('-')[-1] if '-' in hostname else hostname) sHost.update(
os.environ['USER'] + '@' + hostname.split('-')[-1]
if '-' in hostname else hostname)
# Groups definition # Groups definition
@ -123,6 +135,7 @@ gRight = [sTime, sHost]
# Bar handling # Bar handling
bar = subprocess.Popen(['lemonbar', '-f', FONT, '-b'], stdin=subprocess.PIPE) bar = subprocess.Popen(['lemonbar', '-f', FONT, '-b'], stdin=subprocess.PIPE)
def updateBar(): def updateBar():
global timeLastUpdate, timeUpdate global timeLastUpdate, timeUpdate
global gLeft, gRight global gLeft, gRight
@ -131,37 +144,55 @@ def updateBar():
text = '' text = ''
for oi in range(len(outputs)): for oi in range(len(outputs)):
output = outputs[oi] output = outputs[oi]
gLeftFiltered = list(filter(lambda s: s.visible and (not s.output or s.output == output.name), gLeft)) gLeftFiltered = list(
filter(
lambda s: s.visible and (
not s.output or s.output == output.name),
gLeft))
tLeft = '' tLeft = ''
l = len(gLeftFiltered) l = len(gLeftFiltered)
for gi in range(l): for gi in range(l):
g = gLeftFiltered[gi] g = gLeftFiltered[gi]
nextTheme = gLeftFiltered[gi + 1].theme if gi + 1 < l else 'CENTER' # Next visible section for transition # Next visible section for transition
nextTheme = gLeftFiltered[gi + 1].theme if gi + 1 < l else 'CENTER'
tLeft = tLeft + g.draw(True, nextTheme) tLeft = tLeft + g.draw(True, nextTheme)
tRight = '' tRight = ''
for gi in range(len(gRight)): for gi in range(len(gRight)):
g = gRight[gi] g = gRight[gi]
nextTheme = 'CENTER' nextTheme = 'CENTER'
for gn in gRight[gi+1:]: for gn in gRight[gi + 1:]:
if gn.visible: if gn.visible:
nextTheme = gn.theme nextTheme = gn.theme
break break
tRight = g.draw(False, nextTheme) + tRight 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() bar.stdin.flush()
# Values # Values
i3 = i3ipc.Connection() i3 = i3ipc.Connection()
outputs = [] outputs = []
def on_output(): def on_output():
global outputs 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) outputs = sorted(
sorted(
list(
filter(
lambda o: o.active,
i3.get_outputs())),
key=lambda o: o.rect.y),
key=lambda o: o.rect.x)
on_output() on_output()
def on_workspace_focus(): def on_workspace_focus():
global i3 global i3
global gLeft global gLeft
@ -170,6 +201,7 @@ def on_workspace_focus():
sNames = [s.name for s in gLeft] sNames = [s.name for s in gLeft]
newGLeft = [] newGLeft = []
def actuate(section, workspace): def actuate(section, workspace):
if workspace: if workspace:
section.name = workspace.name section.name = workspace.name
@ -189,21 +221,22 @@ def on_workspace_focus():
section.update('') section.update('')
section.theme = '6' section.theme = '6'
for tag, i, j, k, l in difflib.SequenceMatcher(None, sNames, wNames).get_opcodes(): for tag, i, j, k, l in difflib.SequenceMatcher(
if tag == 'equal': # If the workspaces didn't changed None, sNames, wNames).get_opcodes():
for a in range(j-i): if tag == 'equal': # If the workspaces didn't changed
workspace = workspaces[k+a] for a in range(j - i):
section = gLeft[i+a] workspace = workspaces[k + a]
section = gLeft[i + a]
actuate(section, workspace) actuate(section, workspace)
newGLeft.append(section) 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]: for section in gLeft[i:j]:
if section.visible: if section.visible:
actuate(section, None) actuate(section, None)
newGLeft.append(section) newGLeft.append(section)
else: else:
del section 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]: for workspace in workspaces[k:l]:
section = Section() section = Section()
actuate(section, workspace) actuate(section, workspace)
@ -211,6 +244,8 @@ def on_workspace_focus():
gLeft = newGLeft gLeft = newGLeft
updateBar() updateBar()
on_workspace_focus() on_workspace_focus()
@ -230,20 +265,24 @@ def i3events(i3childPipe):
i3.main() i3.main()
i3parentPipe, i3childPipe = multiprocessing.Pipe() i3parentPipe, i3childPipe = multiprocessing.Pipe()
i3process = multiprocessing.Process(target=i3events, args=(i3childPipe,)) i3process = multiprocessing.Process(target=i3events, args=(i3childPipe,))
i3process.start() i3process.start()
def updateValues(): def updateValues():
# Time # Time
now = datetime.datetime.now() now = datetime.datetime.now()
sTime.update(now.strftime('%x %X')) sTime.update(now.strftime('%x %X'))
def updateAnimation(): def updateAnimation():
for s in set(gLeft + gRight): for s in set(gLeft + gRight):
s.updateSize() s.updateSize()
updateBar() updateBar()
lastUpdate = 0 lastUpdate = 0
while True: while True:
now = time.time() now = time.time()
@ -262,5 +301,3 @@ while True:
lastUpdate = now lastUpdate = now
time.sleep(0.05) time.sleep(0.05)