2020-02-01 21:37:38 +01:00
|
|
|
import sys
|
2020-01-19 13:29:34 +01:00
|
|
|
import json
|
2020-01-26 13:31:20 +01:00
|
|
|
import time
|
2020-01-19 13:29:34 +01:00
|
|
|
|
2020-02-09 13:46:56 +01:00
|
|
|
import core.theme
|
2020-02-16 14:30:45 +01:00
|
|
|
import core.event
|
2020-02-09 13:46:56 +01:00
|
|
|
|
2020-04-30 20:18:42 +02:00
|
|
|
import util.format
|
|
|
|
|
2020-04-05 10:53:17 +02:00
|
|
|
def dump_json(obj):
|
2020-04-05 13:58:59 +02:00
|
|
|
return obj.dict()
|
|
|
|
|
|
|
|
def assign(src, dst, key, src_key=None, default=None):
|
|
|
|
if not src_key:
|
|
|
|
src_key = key.replace('_', '-') # automagically replace - with _
|
|
|
|
|
|
|
|
for k in src_key if isinstance(src_key, list) else [src_key]:
|
|
|
|
if k in src:
|
|
|
|
dst[key] = src[k]
|
|
|
|
return
|
|
|
|
if default is not None:
|
|
|
|
dst[key] = default
|
2020-04-05 10:53:17 +02:00
|
|
|
|
|
|
|
class block(object):
|
|
|
|
__COMMON_THEME_FIELDS = [
|
2020-04-05 13:58:59 +02:00
|
|
|
'separator', 'separator-block-width', 'default-separators',
|
|
|
|
'border-top', 'border-left', 'border-right', 'border-bottom',
|
2020-04-05 14:27:09 +02:00
|
|
|
'fg', 'bg', 'padding', 'prefix', 'suffix'
|
2020-04-05 10:53:17 +02:00
|
|
|
]
|
|
|
|
def __init__(self, theme, module, widget):
|
|
|
|
self.__attributes = {}
|
|
|
|
for key in self.__COMMON_THEME_FIELDS:
|
|
|
|
tmp = theme.get(key, widget)
|
2020-04-05 13:58:59 +02:00
|
|
|
if tmp is not None:
|
2020-04-05 10:53:17 +02:00
|
|
|
self.__attributes[key] = tmp
|
|
|
|
|
|
|
|
self.__attributes['name'] = module.id
|
|
|
|
self.__attributes['instance'] = widget.id
|
2020-04-08 14:13:18 +02:00
|
|
|
self.__attributes['prev-bg'] = theme.get('bg', 'previous')
|
2020-04-05 10:53:17 +02:00
|
|
|
|
|
|
|
def set(self, key, value):
|
|
|
|
self.__attributes[key] = value
|
|
|
|
|
2020-04-05 14:27:09 +02:00
|
|
|
def is_pango(self, attr):
|
|
|
|
if isinstance(attr, dict) and 'pango' in attr:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def pangoize(self, text):
|
|
|
|
if not self.is_pango(text):
|
|
|
|
return text
|
|
|
|
self.__attributes['markup'] = 'pango'
|
|
|
|
attr = dict(text['pango'])
|
|
|
|
text = attr.get('full_text', '')
|
|
|
|
if 'full_text' in attr:
|
|
|
|
del attr['full_text']
|
2020-04-07 20:59:26 +02:00
|
|
|
result = '<span'
|
2020-04-05 14:27:09 +02:00
|
|
|
for key, value in attr.items():
|
|
|
|
result = '{} {}="{}"'.format(result, key, value)
|
|
|
|
result = '{}>{}</span>'.format(result, text)
|
|
|
|
return result
|
|
|
|
|
2020-04-05 13:58:59 +02:00
|
|
|
def dict(self):
|
|
|
|
result = {}
|
|
|
|
|
|
|
|
assign(self.__attributes, result, 'full_text', ['full_text', 'separator'])
|
|
|
|
assign(self.__attributes, result, 'separator', 'default-separators')
|
|
|
|
|
|
|
|
if '_decorator' in self.__attributes:
|
|
|
|
assign(self.__attributes, result, 'color', 'bg')
|
|
|
|
assign(self.__attributes, result, 'background', 'prev-bg')
|
|
|
|
result['_decorator'] = True
|
|
|
|
else:
|
|
|
|
assign(self.__attributes, result, 'color', 'fg')
|
|
|
|
assign(self.__attributes, result, 'background', 'bg')
|
|
|
|
|
|
|
|
if 'full_text' in self.__attributes:
|
2020-04-05 14:27:09 +02:00
|
|
|
result['full_text'] = self.pangoize(result['full_text'])
|
2020-04-05 13:58:59 +02:00
|
|
|
result['full_text'] = self.__format(self.__attributes['full_text'])
|
|
|
|
|
|
|
|
for k in [
|
|
|
|
'name', 'instance', 'separator_block_width', 'border', 'border_top',
|
2020-04-05 14:27:09 +02:00
|
|
|
'border_bottom', 'border_left', 'border_right', 'markup'
|
2020-04-05 13:58:59 +02:00
|
|
|
]:
|
|
|
|
assign(self.__attributes, result, k)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
def __pad(self, text):
|
|
|
|
padding = self.__attributes.get('padding', '')
|
|
|
|
if not text: return padding
|
|
|
|
return '{}{}{}'.format(padding, text, padding)
|
|
|
|
|
|
|
|
def __format(self, text):
|
|
|
|
if text is None: return None
|
2020-04-05 14:27:09 +02:00
|
|
|
prefix = self.pangoize(self.__attributes.get('prefix'))
|
|
|
|
suffix = self.pangoize(self.__attributes.get('suffix'))
|
2020-04-05 13:58:59 +02:00
|
|
|
return '{}{}{}'.format(
|
2020-04-05 14:27:09 +02:00
|
|
|
self.__pad(prefix),
|
2020-04-05 13:58:59 +02:00
|
|
|
text,
|
2020-04-05 14:27:09 +02:00
|
|
|
self.__pad(suffix)
|
2020-04-05 13:58:59 +02:00
|
|
|
)
|
2020-04-05 10:53:17 +02:00
|
|
|
|
2020-01-19 13:29:34 +01:00
|
|
|
class i3(object):
|
2020-03-15 14:02:48 +01:00
|
|
|
def __init__(self, theme=core.theme.Theme(), config=core.config.Config([])):
|
2020-04-04 13:57:42 +02:00
|
|
|
self.__modules = []
|
2020-04-05 10:53:17 +02:00
|
|
|
self.__content = {}
|
2020-04-04 13:57:42 +02:00
|
|
|
self.__theme = theme
|
|
|
|
self.__config = config
|
2020-04-12 20:11:02 +02:00
|
|
|
core.event.register('update', self.update)
|
2020-02-16 14:30:45 +01:00
|
|
|
core.event.register('start', self.draw, 'start')
|
2020-04-12 20:11:02 +02:00
|
|
|
core.event.register('draw', self.draw, 'statusline')
|
2020-02-16 14:30:45 +01:00
|
|
|
core.event.register('stop', self.draw, 'stop')
|
2020-02-01 21:37:38 +01:00
|
|
|
|
2020-03-01 14:08:16 +01:00
|
|
|
def theme(self, new_theme=None):
|
|
|
|
if new_theme:
|
2020-04-04 13:57:42 +02:00
|
|
|
self.__theme = new_theme
|
|
|
|
return self.__theme
|
2020-03-01 14:08:16 +01:00
|
|
|
|
2020-02-02 14:18:13 +01:00
|
|
|
def modules(self, modules=None):
|
|
|
|
if not modules:
|
2020-04-04 13:57:42 +02:00
|
|
|
return self.__modules
|
|
|
|
self.__modules = modules if isinstance(modules, list) else [ modules ]
|
2020-02-02 14:18:13 +01:00
|
|
|
|
2020-02-08 14:22:43 +01:00
|
|
|
def draw(self, what, args=None):
|
|
|
|
cb = getattr(self, what)
|
|
|
|
data = cb(args) if args else cb()
|
2020-04-05 10:53:17 +02:00
|
|
|
if 'blocks' in data:
|
|
|
|
sys.stdout.write(json.dumps(data['blocks'], default=dump_json))
|
2020-02-01 21:37:38 +01:00
|
|
|
if 'suffix' in data:
|
|
|
|
sys.stdout.write(data['suffix'])
|
|
|
|
sys.stdout.write('\n')
|
2020-02-02 21:21:24 +01:00
|
|
|
sys.stdout.flush()
|
2020-02-01 21:37:38 +01:00
|
|
|
|
2020-01-19 13:29:34 +01:00
|
|
|
def start(self):
|
2020-02-01 21:37:38 +01:00
|
|
|
return {
|
2020-04-05 10:53:17 +02:00
|
|
|
'blocks': { 'version': 1, 'click_events': True },
|
2020-02-01 21:37:38 +01:00
|
|
|
'suffix': '\n[',
|
|
|
|
}
|
2020-01-19 13:29:34 +01:00
|
|
|
|
|
|
|
def stop(self):
|
2020-02-01 21:37:38 +01:00
|
|
|
return { 'suffix': '\n]' }
|
|
|
|
|
2020-04-05 10:53:17 +02:00
|
|
|
def __separator_block(self, module, widget):
|
2020-04-05 13:58:59 +02:00
|
|
|
if not self.__theme.get('separator'):
|
|
|
|
return []
|
2020-04-05 10:53:17 +02:00
|
|
|
blk = block(self.__theme, module, widget)
|
|
|
|
blk.set('_decorator', True)
|
2020-04-05 13:58:59 +02:00
|
|
|
return [blk]
|
2020-04-05 10:53:17 +02:00
|
|
|
|
|
|
|
def __content_block(self, module, widget):
|
|
|
|
blk = block(self.__theme, module, widget)
|
2020-04-05 13:58:59 +02:00
|
|
|
blk.set('min_width', widget.get('theme.minwidth'))
|
|
|
|
blk.set('full_text', self.__content[widget])
|
2020-04-26 10:33:41 +02:00
|
|
|
if widget.get('pango', False):
|
|
|
|
blk.set('markup', 'pango')
|
2020-04-05 10:53:17 +02:00
|
|
|
if self.__config.debug():
|
2020-04-28 20:25:28 +02:00
|
|
|
state = module.state(widget)
|
|
|
|
if isinstance(state, list):
|
|
|
|
state = ', '.join(state)
|
|
|
|
blk.set('__state', state)
|
2020-04-05 10:53:17 +02:00
|
|
|
return blk
|
|
|
|
|
|
|
|
def blocks(self, module):
|
|
|
|
blocks = []
|
2020-02-09 13:30:40 +01:00
|
|
|
for widget in module.widgets():
|
2020-04-30 12:50:24 +02:00
|
|
|
if widget.module and self.__config.autohide(widget.module.name):
|
2020-03-15 14:01:09 +01:00
|
|
|
if not any(state in widget.state() for state in [ 'warning', 'critical']):
|
|
|
|
continue
|
2020-04-29 14:39:12 +02:00
|
|
|
if module.hidden():
|
|
|
|
continue
|
2020-04-05 13:58:59 +02:00
|
|
|
blocks.extend(self.__separator_block(module, widget))
|
2020-04-05 10:53:17 +02:00
|
|
|
blocks.append(self.__content_block(module, widget))
|
2020-02-16 14:39:10 +01:00
|
|
|
core.event.trigger('next-widget')
|
2020-04-05 10:53:17 +02:00
|
|
|
return blocks
|
2020-02-09 13:30:40 +01:00
|
|
|
|
2020-04-05 13:58:59 +02:00
|
|
|
# TODO: only updates full text, not the state!?
|
2020-04-12 14:44:02 +02:00
|
|
|
def update(self, affected_modules=None, redraw_only=False):
|
2020-03-23 15:32:06 +01:00
|
|
|
now = time.time()
|
2020-04-04 13:57:42 +02:00
|
|
|
for module in self.__modules:
|
2020-03-29 14:43:04 +02:00
|
|
|
if affected_modules and not module.id in affected_modules:
|
2020-02-23 21:13:49 +01:00
|
|
|
continue
|
2020-03-23 15:32:06 +01:00
|
|
|
if not affected_modules and module.next_update:
|
2020-04-13 09:27:03 +02:00
|
|
|
if module.parameter('interval', '') == 'never':
|
|
|
|
continue
|
2020-03-23 15:32:06 +01:00
|
|
|
if now < module.next_update:
|
|
|
|
continue
|
2020-04-12 14:44:02 +02:00
|
|
|
if not redraw_only:
|
|
|
|
module.update_wrapper()
|
2020-04-13 09:27:03 +02:00
|
|
|
if module.parameter('interval', '') != 'never':
|
2020-04-30 20:18:42 +02:00
|
|
|
module.next_update = now + util.format.seconds(module.parameter('interval', self.__config.interval()))
|
2020-02-24 15:05:58 +01:00
|
|
|
for widget in module.widgets():
|
2020-04-05 10:53:17 +02:00
|
|
|
self.__content[widget] = widget.full_text()
|
2020-02-09 13:25:34 +01:00
|
|
|
|
|
|
|
def statusline(self):
|
2020-04-05 10:53:17 +02:00
|
|
|
blocks = []
|
2020-04-04 13:57:42 +02:00
|
|
|
for module in self.__modules:
|
2020-04-05 10:53:17 +02:00
|
|
|
blocks.extend(self.blocks(module))
|
2020-02-01 21:37:38 +01:00
|
|
|
return {
|
2020-04-05 10:53:17 +02:00
|
|
|
'blocks': blocks,
|
2020-02-01 21:37:38 +01:00
|
|
|
'suffix': ','
|
|
|
|
}
|
2020-01-19 13:29:34 +01:00
|
|
|
|
2020-01-26 13:31:20 +01:00
|
|
|
def wait(self, interval):
|
|
|
|
time.sleep(interval)
|
|
|
|
|
2020-01-19 13:29:34 +01:00
|
|
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|