lemonbar: Move all lemonbar parsing to units.
Remove i3 workspaces dependency on lemonbar. Implement sorting and alignment of modules
This commit is contained in:
@@ -106,61 +106,6 @@ def strip_ansi_unicode(s):
|
|||||||
strip_unicode = (strip_ansi.encode('ascii', 'ignore')).decode('utf-8')
|
strip_unicode = (strip_ansi.encode('ascii', 'ignore')).decode('utf-8')
|
||||||
return strip_unicode
|
return strip_unicode
|
||||||
|
|
||||||
# Callbacks for workspaces
|
|
||||||
def add_callbacks(i3ws): #TODO this should be done by module
|
|
||||||
i3ws.change_callbacks.append(set_bg)
|
|
||||||
i3ws.focus_callbacks.append(set_keymap)
|
|
||||||
i3ws.focus_callbacks.append(kill_floating_windows)
|
|
||||||
|
|
||||||
def img_path(num):
|
|
||||||
dir = '/home/kuba/Obrazy/Wallpapers/'
|
|
||||||
return dir + {
|
|
||||||
1: '1_main',
|
|
||||||
2: '2_web',
|
|
||||||
3: '3_music',
|
|
||||||
4: '4_work',
|
|
||||||
5: '5_terms',
|
|
||||||
6: '6_stats',
|
|
||||||
7: '7',
|
|
||||||
8: '8',
|
|
||||||
9: '9',
|
|
||||||
}.get(int(num), 'default')
|
|
||||||
|
|
||||||
def set_bg(i3ws):
|
|
||||||
cmd_args = ['sh', '/home/kuba/scripts/set_bg.sh']
|
|
||||||
for output in i3ws.outputs:
|
|
||||||
if output.active:
|
|
||||||
bg = img_path(output.current_workspace.partition(' ')[0])
|
|
||||||
cmd_args.append(bg)
|
|
||||||
subprocess.call(cmd_args)
|
|
||||||
|
|
||||||
def kill_floating_windows(i3ws):
|
|
||||||
global kill_on_unfocus, logger
|
|
||||||
role = i3ws.focused_window.window_role
|
|
||||||
wclass = i3ws.focused_window.window_class
|
|
||||||
|
|
||||||
if role != 'FLOAT_TERM' and wclass != 'FLOAT_PAVU' and wclass != 'YADWINBR':
|
|
||||||
# Is there a window that the bar has opened?
|
|
||||||
for pid in kill_on_unfocus:
|
|
||||||
try:
|
|
||||||
os.kill(pid, signal.SIGTERM)
|
|
||||||
except ProcessLookupError:
|
|
||||||
logger.debug('Tried killing process {} but it doesn\'t exist'.format(pid))
|
|
||||||
kill_on_unfocus = []
|
|
||||||
|
|
||||||
def set_keymap(i3ws):
|
|
||||||
global cur_class, keymaps, logger
|
|
||||||
wclass = i3ws.focused_window.window_class
|
|
||||||
cur_class = wclass
|
|
||||||
|
|
||||||
if wclass in keymaps:
|
|
||||||
new_km = keymaps[wclass]
|
|
||||||
logger.debug('Setting {} as keymap for {}'.format(new_km, wclass))
|
|
||||||
else:
|
|
||||||
new_km = def_keymap
|
|
||||||
logger.debug('Setting default keymap {} for {}'.format(def_keymap, wclass))
|
|
||||||
subprocess.call(['/home/kuba/.i3/scripts/lang.sh', 'qset', new_km])
|
|
||||||
|
|
||||||
def create_new_fifo(fifo_file):
|
def create_new_fifo(fifo_file):
|
||||||
"""
|
"""
|
||||||
Create new fifo file, removing old one if it exists
|
Create new fifo file, removing old one if it exists
|
||||||
|
|||||||
@@ -10,11 +10,9 @@ import i3_lemonbar_config as config
|
|||||||
import i3_lemonbar_common as common
|
import i3_lemonbar_common as common
|
||||||
import i3_lemonbar_modules as modules
|
import i3_lemonbar_modules as modules
|
||||||
import i3_lemonbar_parser as lemonparser
|
import i3_lemonbar_parser as lemonparser
|
||||||
import i3_workspaces as wspaces
|
|
||||||
|
|
||||||
p_conky_slow = None
|
p_conky_slow = None
|
||||||
p_lemonbar = None
|
p_lemonbar = None
|
||||||
i3_ws_obj = None
|
|
||||||
|
|
||||||
def assert_only_instance():
|
def assert_only_instance():
|
||||||
"""
|
"""
|
||||||
@@ -90,19 +88,16 @@ def clean_up():
|
|||||||
nice_delete(config.fifo_file_status)
|
nice_delete(config.fifo_file_status)
|
||||||
nice_term(p_conky_slow)
|
nice_term(p_conky_slow)
|
||||||
modules.stop_all()
|
modules.stop_all()
|
||||||
if i3_ws_obj is not None:
|
|
||||||
i3_ws_obj.quit()
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def write_sys_status():
|
|
||||||
global i3_ws_obj
|
|
||||||
|
|
||||||
i3_ws_obj = wspaces.i3ws(logger=common.logger, fifo_file=config.fifo_file_status)
|
|
||||||
i3_ws_obj.work()
|
|
||||||
|
|
||||||
def queue_parse_job(job):
|
def queue_parse_job(job):
|
||||||
common.parsing_queue.put(job)
|
common.parsing_queue.put(job)
|
||||||
|
|
||||||
|
def keep_fifo_open():
|
||||||
|
with open(config.fifo_file_status, 'w', buffering=1) as fifo_write:
|
||||||
|
while True:
|
||||||
|
fifo_write.write('HEARTBEAT\n')
|
||||||
|
time.sleep(30)
|
||||||
def put_fifo_in_queue():
|
def put_fifo_in_queue():
|
||||||
with open(config.fifo_file_status, 'r', buffering=1) as fifo_read:
|
with open(config.fifo_file_status, 'r', buffering=1) as fifo_read:
|
||||||
# Let parser read from fifo
|
# Let parser read from fifo
|
||||||
@@ -263,8 +258,8 @@ if __name__ == "__main__":
|
|||||||
# Create readers before writers
|
# Create readers before writers
|
||||||
i3_thread(target = exec_commands, desc='Exec commands thread')
|
i3_thread(target = exec_commands, desc='Exec commands thread')
|
||||||
i3_thread(target = parse_status, desc='Parse status thread')
|
i3_thread(target = parse_status, desc='Parse status thread')
|
||||||
|
i3_thread(target = keep_fifo_open, desc='')
|
||||||
i3_thread(target = put_fifo_in_queue, desc='')
|
i3_thread(target = put_fifo_in_queue, desc='')
|
||||||
i3_thread(target = write_sys_status, desc='Write sys status thread')
|
|
||||||
i3_thread(target = user_screen, desc='Screen thread for user commands')
|
i3_thread(target = user_screen, desc='Screen thread for user commands')
|
||||||
modules.start_all()
|
modules.start_all()
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import subprocess
|
|||||||
import i3_lemonbar_config as config
|
import i3_lemonbar_config as config
|
||||||
import i3_lemonbar_common as common
|
import i3_lemonbar_common as common
|
||||||
import i3_lemonbar_parser as parser
|
import i3_lemonbar_parser as parser
|
||||||
|
import i3_workspaces as wspaces
|
||||||
|
|
||||||
class LemonModule(threading.Thread):
|
class LemonModule(threading.Thread):
|
||||||
# Module generates some status message, parses it, and handles on click actions
|
# Module generates some status message, parses it, and handles on click actions
|
||||||
@@ -13,20 +14,17 @@ class LemonModule(threading.Thread):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self._start_module()
|
self._start_module()
|
||||||
|
|
||||||
if self.dummy is not None:
|
|
||||||
# Begin by parsing dummy data to create all lemonbar elements
|
|
||||||
parsed = self.parse(self.dummy)
|
|
||||||
common.parsing_queue.put([parsed])
|
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
common.logger.info('Started module {}'.format(self.name))
|
if self.status_handle is None:
|
||||||
common.health_logger.info('Module {} up'.format(self.name))
|
return
|
||||||
|
|
||||||
|
common.logger.info('Started module {}'.format(self.__class__.__name__))
|
||||||
|
common.health_logger.info('Module {} up'.format(self.__class__.__name__))
|
||||||
while True:
|
while True:
|
||||||
line = self.status_handle.readline()
|
line = self.status_handle.readline()
|
||||||
if not line:
|
if not line:
|
||||||
common.logger.info('Reached end of module {}'.format(self.name))
|
common.logger.info('Reached end of module {}'.format(self.__class__.__name__))
|
||||||
common.health_logger.info('Module {} down'.format(self.name))
|
common.health_logger.info('Module {} down'.format(self.__class__.__name__))
|
||||||
break
|
break
|
||||||
|
|
||||||
parsed = self.parse(line)
|
parsed = self.parse(line)
|
||||||
@@ -64,7 +62,6 @@ class ConkyFastModule(LemonModule):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.prefix = 'CNK_FAST'
|
self.prefix = 'CNK_FAST'
|
||||||
self.dummy = 'CNK_FAST Fri 23 Aug 00:00:00 MUTE down down down down'
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def _start_module(self):
|
def _start_module(self):
|
||||||
@@ -72,12 +69,13 @@ class ConkyFastModule(LemonModule):
|
|||||||
stdout=subprocess.PIPE, text=True)
|
stdout=subprocess.PIPE, text=True)
|
||||||
self.status_handle = self.p_handle.stdout
|
self.status_handle = self.p_handle.stdout
|
||||||
|
|
||||||
self.wlan_load = parser.LemonUnit('wlan_load', action='wlan')
|
self.wlan_load = parser.IconTextUnit('wlan_load', action='wlan', order=13)
|
||||||
self.eth_load = parser.LemonUnit('eth_load', action='eth')
|
self.eth_load = parser.IconTextUnit('eth_load', action='eth', order=14)
|
||||||
self.volume = parser.LemonUnit('volume', action='pavu')
|
self.volume = parser.IconTextUnit('volume', action='pavu', order=20)
|
||||||
self.date = parser.LemonUnit('date', action='date')
|
self.date = parser.IconTextUnit('date', action='date', order=40)
|
||||||
self.time = parser.LemonUnit('time', action='toggle_secs'
|
self.time = parser.IconTextUnit('time', action='toggle_secs', order=41
|
||||||
, alt_scheme=parser.COLOR_SCHEME.SPECIAL)
|
, alt_scheme=parser.COLOR_SCHEME.SPECIAL)
|
||||||
|
self.time.modes = [mode for mode in common.bar_mode]
|
||||||
|
|
||||||
parser.g_parser.register_unit(self.wlan_load)
|
parser.g_parser.register_unit(self.wlan_load)
|
||||||
parser.g_parser.register_unit(self.eth_load)
|
parser.g_parser.register_unit(self.eth_load)
|
||||||
@@ -120,7 +118,6 @@ class ConkySlowModule(LemonModule):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.prefix = 'CNK_SLOW'
|
self.prefix = 'CNK_SLOW'
|
||||||
self.dummy = 'CNK_SLOW 11 2.24G 91 74 F100 100.00 pl'
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def _start_module(self):
|
def _start_module(self):
|
||||||
@@ -128,12 +125,12 @@ class ConkySlowModule(LemonModule):
|
|||||||
stdout=subprocess.PIPE, text=True)
|
stdout=subprocess.PIPE, text=True)
|
||||||
self.status_handle = self.p_handle.stdout
|
self.status_handle = self.p_handle.stdout
|
||||||
|
|
||||||
self.sys_load = parser.LemonUnit('sys_load', action='load')
|
self.sys_load = parser.IconTextUnit('sys_load', action='load', order=10)
|
||||||
self.disk = parser.LemonUnit('disk')
|
self.disk = parser.IconTextUnit('disk', order=11)
|
||||||
self.brightness = parser.LemonUnit('brightness', action='adj_br'
|
self.brightness = parser.IconTextUnit('brightness', action='adj_br', order=21
|
||||||
, external={'BRIGHT': self.parse_brightness, 'BAJS': self.parse_brightness})
|
, external={'BRIGHT': self.parse_brightness})
|
||||||
self.battery = parser.LemonUnit('battery', action='dpms')
|
self.battery = parser.IconTextUnit('battery', action='dpms', order=22)
|
||||||
self.language = parser.LemonUnit('language', action='lang'
|
self.language = parser.IconTextUnit('language', action='lang', order=32
|
||||||
, external={'LANG': self.parse_language})
|
, external={'LANG': self.parse_language})
|
||||||
|
|
||||||
parser.g_parser.register_unit(self.sys_load)
|
parser.g_parser.register_unit(self.sys_load)
|
||||||
@@ -190,17 +187,257 @@ class ConkySlowModule(LemonModule):
|
|||||||
def parse_language(self, data):
|
def parse_language(self, data):
|
||||||
self.language.items = [(config.icon_lang, data[0])]
|
self.language.items = [(config.icon_lang, data[0])]
|
||||||
|
|
||||||
def start_all():
|
class i3Module(LemonModule):
|
||||||
global m_conky_fast, m_conky_slow
|
# Handles outputs (displays), workspaces and active window
|
||||||
|
# TODO trigger formatting
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.displays = ''
|
||||||
|
self.win_title = ''
|
||||||
|
self.workspaces = ''
|
||||||
|
|
||||||
|
def _start_module(self):
|
||||||
|
self.i3_ws_obj = wspaces.i3ws(logger=common.logger)
|
||||||
|
|
||||||
|
self.displays = parser.CustomUnit('displays', format_function = self.format_displays, order=-30)
|
||||||
|
self.workspaces = parser.CustomUnit('workspaces', format_function = self.format_workspaces, order=-20)
|
||||||
|
self.title = parser.CustomUnit('title', format_function = self.format_title, order=-10)
|
||||||
|
self.displays.modes.append(common.bar_mode.control)
|
||||||
|
self.workspaces.modes.append(common.bar_mode.control)
|
||||||
|
|
||||||
|
parser.g_parser.register_unit(self.displays)
|
||||||
|
parser.g_parser.register_unit(self.workspaces)
|
||||||
|
parser.g_parser.register_unit(self.title)
|
||||||
|
|
||||||
|
# Add callbacks for parsing
|
||||||
|
self.i3_ws_obj.change_callbacks.append(self.parse_displays)
|
||||||
|
self.i3_ws_obj.change_callbacks.append(self.parse_workspaces)
|
||||||
|
self.i3_ws_obj.focus_callbacks.append(self.parse_title)
|
||||||
|
|
||||||
|
# Add callbacks for special actions
|
||||||
|
self.i3_ws_obj.change_callbacks.append(i3Module.set_bg)
|
||||||
|
self.i3_ws_obj.focus_callbacks.append(i3Module.set_keymap)
|
||||||
|
self.i3_ws_obj.focus_callbacks.append(i3Module.kill_floating_windows)
|
||||||
|
|
||||||
|
def _stop_module(self):
|
||||||
|
parser.g_parser.remove_unit(self.displays)
|
||||||
|
parser.g_parser.remove_unit(self.workspaces)
|
||||||
|
parser.g_parser.remove_unit(self.title)
|
||||||
|
|
||||||
|
if self.i3_ws_obj is not None:
|
||||||
|
self.i3_ws_obj.quit()
|
||||||
|
|
||||||
|
# Overload run as i3_ws_obj.work() is a blocking command
|
||||||
|
# Parsing is instead done through callbacks
|
||||||
|
def run(self):
|
||||||
|
common.logger.info('Started module {}'.format(self.__class__.__name__))
|
||||||
|
common.health_logger.info('Module {} up'.format(self.__class__.__name__))
|
||||||
|
|
||||||
|
self.i3_ws_obj.work() # This is a blocking command
|
||||||
|
|
||||||
|
common.logger.info('Reached end of module {}'.format(self.__class__.__name__))
|
||||||
|
common.health_logger.info('Module {} down'.format(self.__class__.__name__))
|
||||||
|
|
||||||
|
def parse_displays(self, i3ws):
|
||||||
|
parsed_list = [parser.block(click='displays', font='2')]
|
||||||
|
for output in i3ws.outputs:
|
||||||
|
output_name = output.name
|
||||||
|
if output.active:
|
||||||
|
if output_name == 'eDP1':
|
||||||
|
col_head = config.color_head
|
||||||
|
elif output_name == 'DP1':
|
||||||
|
col_head = config.color_vga
|
||||||
|
elif output_name == 'HDMI2':
|
||||||
|
col_head = config.color_hdmi
|
||||||
|
else:
|
||||||
|
col_head = '#00000000' # Undefined
|
||||||
|
parsed_list.append(parser.block(fg=config.color_back, bg=col_head))
|
||||||
|
parsed_list.append(config.icon_wsp)
|
||||||
|
parsed_list.append(parser.block(click=''))
|
||||||
|
|
||||||
|
self.displays = ' '.join(parsed_list)
|
||||||
|
|
||||||
|
def parse_workspaces(self, i3ws):
|
||||||
|
prefix = parser.block(font='1', fg=config.color_back, bg=config.color_head)
|
||||||
|
prefix_foc = ''.join([parser.block(fg = config.color_head, bg=config.color_wsp)
|
||||||
|
, ' ', config.sep_right, ' '
|
||||||
|
, parser.block(fg=config.color_back, bg=config.color_wsp, font='1')])
|
||||||
|
prefix_ina = parser.block(fg=config.color_back, bg=config.color_head, font='1', append=' ')
|
||||||
|
wspces = []
|
||||||
|
|
||||||
|
for workspace in i3ws.workspaces:
|
||||||
|
# Find out which output the workspace is on
|
||||||
|
output = None # TODO actually use this information
|
||||||
|
for output_ in i3ws.outputs:
|
||||||
|
if output_['name'] == workspace['output']:
|
||||||
|
output = output_
|
||||||
|
break
|
||||||
|
if not output:
|
||||||
|
continue
|
||||||
|
status = i3ws.state.get_state(workspace, output) # FOC or INA
|
||||||
|
name = workspace['name'] # e.g. 5 terms
|
||||||
|
current = ''.join([parser.block(click=('i3-msg workspace' + name))
|
||||||
|
, name, parser.block(click='')])
|
||||||
|
if status == "FOC":
|
||||||
|
wspces.append(''.join([prefix_foc, current]))
|
||||||
|
else:
|
||||||
|
wspces.append(''.join([prefix_ina, current]))
|
||||||
|
|
||||||
|
self.workspaces = ''.join([prefix, ' '.join(wspces)])
|
||||||
|
|
||||||
|
def parse_title(self, i3ws):
|
||||||
|
if i3ws.focused_window is None:
|
||||||
|
return
|
||||||
|
self.win_title = ' '.join([parser.block(fg=config.color_head, bg=config.color_sec_b2)
|
||||||
|
, config.sep_right, parser.block(fg=config.color_head, bg=config.color_sec_b2, click='mode cycle')
|
||||||
|
, config.icon_prog
|
||||||
|
, parser.block(fg=config.color_sec_b2, bg='-')
|
||||||
|
, i3ws.focused_window.name])
|
||||||
|
|
||||||
|
def format_displays(self):
|
||||||
|
return self.displays
|
||||||
|
|
||||||
|
def format_workspaces(self):
|
||||||
|
return self.workspaces
|
||||||
|
|
||||||
|
def format_title(self):
|
||||||
|
return self.win_title
|
||||||
|
|
||||||
|
def img_path(num):
|
||||||
|
dir = '/home/kuba/Obrazy/Wallpapers/'
|
||||||
|
return dir + {
|
||||||
|
1: '1_main',
|
||||||
|
2: '2_web',
|
||||||
|
3: '3_music',
|
||||||
|
4: '4_work',
|
||||||
|
5: '5_terms',
|
||||||
|
6: '6_stats',
|
||||||
|
7: '7',
|
||||||
|
8: '8',
|
||||||
|
9: '9',
|
||||||
|
}.get(int(num), 'default')
|
||||||
|
|
||||||
|
def set_bg(i3ws):
|
||||||
|
cmd_args = ['sh', '/home/kuba/scripts/set_bg.sh']
|
||||||
|
for output in i3ws.outputs:
|
||||||
|
if output.active:
|
||||||
|
bg = i3Module.img_path(output.current_workspace.partition(' ')[0])
|
||||||
|
cmd_args.append(bg)
|
||||||
|
subprocess.call(cmd_args)
|
||||||
|
|
||||||
|
def kill_floating_windows(i3ws):
|
||||||
|
if i3ws.focused_window is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
role = i3ws.focused_window.window_role
|
||||||
|
wclass = i3ws.focused_window.window_class
|
||||||
|
|
||||||
|
if role != 'FLOAT_TERM' and wclass != 'FLOAT_PAVU' and wclass != 'YADWINBR':
|
||||||
|
# Is there a window that the bar has opened?
|
||||||
|
for pid in common.kill_on_unfocus:
|
||||||
|
try:
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
except ProcessLookupError:
|
||||||
|
common.logger.debug('Tried killing process {} but it doesn\'t exist'.format(pid))
|
||||||
|
common.kill_on_unfocus = []
|
||||||
|
|
||||||
|
def set_keymap(i3ws):
|
||||||
|
if i3ws.focused_window is None:
|
||||||
|
return
|
||||||
|
wclass = i3ws.focused_window.window_class
|
||||||
|
common.cur_class = wclass
|
||||||
|
|
||||||
|
if wclass in common.keymaps:
|
||||||
|
new_km = common.keymaps[wclass]
|
||||||
|
common.logger.debug('Setting {} as keymap for {}'.format(new_km, wclass))
|
||||||
|
else:
|
||||||
|
new_km = common.def_keymap
|
||||||
|
common.logger.debug('Setting default keymap {} for {}'.format(new_km, wclass))
|
||||||
|
subprocess.call(['/home/kuba/.i3/scripts/lang.sh', 'qset', new_km])
|
||||||
|
|
||||||
|
class ScreenModule(LemonModule):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.prefix = 'RESP'
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def _start_module(self):
|
||||||
|
# No external commands needed
|
||||||
|
self.status_handle = None
|
||||||
|
|
||||||
|
self.controls = parser.ButtonsUnit('controls', order=-10)
|
||||||
|
self.response = parser.IconTextUnit('response', order=10)
|
||||||
|
|
||||||
|
self.controls.items = [('', config.icon_prog, 'mode cycle')
|
||||||
|
,('', '', None)
|
||||||
|
,('', 'on', 'bluetooth power on')
|
||||||
|
,('', 'off', 'bluetooth power off')
|
||||||
|
,('PXC 550', '', None)
|
||||||
|
,('', 'conn.', 'bluetooth connect pxc550')
|
||||||
|
,('', 'disc.', 'bluetooth disconnect pxc550')
|
||||||
|
]
|
||||||
|
|
||||||
|
self.response.modes = [common.bar_mode.control]
|
||||||
|
self.controls.modes = [common.bar_mode.control]
|
||||||
|
|
||||||
|
parser.g_parser.register_unit(self.response)
|
||||||
|
parser.g_parser.register_unit(self.controls)
|
||||||
|
|
||||||
|
def _stop_module(self):
|
||||||
|
parser.g_parser.remove_unit(self.response)
|
||||||
|
parser.g_parser.remove_unit(self.controls)
|
||||||
|
|
||||||
|
def _parse_data(self, data):
|
||||||
|
self.response.items = [('', ' '.join(data))]
|
||||||
|
|
||||||
|
class PowerOptionsModule(LemonModule):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.prefix = ''
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def _start_module(self):
|
||||||
|
# No external commands needed
|
||||||
|
self.status_handle = None
|
||||||
|
|
||||||
|
self.power_opts = parser.CustomUnit('power', format_function=self.format_power_opts, order=-1)
|
||||||
|
|
||||||
|
self.power_opts.modes = [common.bar_mode.power]
|
||||||
|
|
||||||
|
parser.g_parser.register_unit(self.power_opts)
|
||||||
|
|
||||||
|
def _stop_module(self):
|
||||||
|
parser.g_parser.remove_unit(self.power_opts)
|
||||||
|
|
||||||
|
def _parse_data(self, data):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def format_power_opts(self):
|
||||||
|
return ''.join([parser.block(fg=config.color_fore, bg=config.color_poweropts)
|
||||||
|
, ' Abort (Esc) | System (l) lock, (e) logout, (s) suspend, (h) hibernate'
|
||||||
|
, ', (r) reboot, (Shift+s) shutdown'])
|
||||||
|
|
||||||
|
def start_all():
|
||||||
|
global m_conky_fast, m_conky_slow, m_i3ws
|
||||||
|
|
||||||
|
m_i3ws = i3Module()
|
||||||
m_conky_slow = ConkySlowModule()
|
m_conky_slow = ConkySlowModule()
|
||||||
m_conky_fast = ConkyFastModule()
|
m_conky_fast = ConkyFastModule()
|
||||||
|
m_screen = ScreenModule()
|
||||||
|
m_power = PowerOptionsModule()
|
||||||
|
|
||||||
|
m_i3ws.start()
|
||||||
m_conky_slow.start()
|
m_conky_slow.start()
|
||||||
m_conky_fast.start()
|
m_conky_fast.start()
|
||||||
|
m_screen.start()
|
||||||
|
m_power.start()
|
||||||
|
|
||||||
def stop_all():
|
def stop_all():
|
||||||
global m_conky_fast, m_conky_slow
|
global m_conky_fast, m_conky_slow, m_i3ws
|
||||||
|
|
||||||
|
m_i3ws.stop()
|
||||||
m_conky_slow.stop()
|
m_conky_slow.stop()
|
||||||
m_conky_fast.stop()
|
m_conky_fast.stop()
|
||||||
|
m_screen.stop()
|
||||||
|
m_power.stop()
|
||||||
|
|||||||
@@ -1,28 +1,107 @@
|
|||||||
import sys
|
import sys
|
||||||
|
import bisect # Sorting of list
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import i3_lemonbar_config as conf
|
import i3_lemonbar_config as config
|
||||||
import i3_lemonbar_common as common
|
import i3_lemonbar_common as common
|
||||||
|
|
||||||
displays = ''
|
sr = config.sep_right
|
||||||
workspaces = ''
|
slr = config.sep_l_right
|
||||||
win_title = ''
|
sl = config.sep_left
|
||||||
time = ''
|
sll = config.sep_l_left
|
||||||
response = ''
|
|
||||||
|
|
||||||
blank = ' '
|
class IconTextUnit:
|
||||||
|
def __init__(self, name, order, action = None, alt_scheme=None, external=None):
|
||||||
sr = conf.sep_right
|
|
||||||
slr = conf.sep_l_right
|
|
||||||
sl = conf.sep_left
|
|
||||||
sll = conf.sep_l_left
|
|
||||||
|
|
||||||
class LemonUnit:
|
|
||||||
def __init__(self, name, action = None, alt_scheme=None, external=None):
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.action = action
|
self.action = action
|
||||||
|
self.order = order
|
||||||
self.alt_scheme = alt_scheme # None means default
|
self.alt_scheme = alt_scheme # None means default
|
||||||
self.external = external
|
self.external = external
|
||||||
self.items = [] # List of tuples (icon, text)
|
self.items = [] # List of tuples (icon, text)
|
||||||
|
self.modes = [common.bar_mode.normal]
|
||||||
|
|
||||||
|
def format(self):
|
||||||
|
close = block(click='') if self.action is not None else ''
|
||||||
|
|
||||||
|
b_color = self.alt_scheme.back_color
|
||||||
|
i_color = self.alt_scheme.icon_color
|
||||||
|
t_color = self.alt_scheme.text_color
|
||||||
|
|
||||||
|
# Start with a major separator. Keep previous background color, set foreground color
|
||||||
|
# of separator to background color of this unit
|
||||||
|
blocks = []
|
||||||
|
blocks.append(block(fg=b_color, append=sl))
|
||||||
|
blocks.append(' ') # TODO perhaps more nice solution than manual spacing
|
||||||
|
if len(self.items) >= 1:
|
||||||
|
(icon, text) = self.items[0]
|
||||||
|
blocks.append(block(click=self.action, fg=i_color, bg=b_color, font='2'
|
||||||
|
, append=' ' + icon))
|
||||||
|
blocks.append(' ')
|
||||||
|
blocks.append(block(fg=t_color, font='1', append=text))
|
||||||
|
if len(self.items) >= 2:
|
||||||
|
for item in self.items[1:]:
|
||||||
|
(icon, text) = item
|
||||||
|
# Append minor separator
|
||||||
|
blocks.append(' ')
|
||||||
|
blocks.append(sll)
|
||||||
|
|
||||||
|
blocks.append(block(fg=i_color, bg=b_color, font='2', append=' ' + icon))
|
||||||
|
blocks.append(' ')
|
||||||
|
blocks.append(block(fg=t_color, font='1', append=text))
|
||||||
|
|
||||||
|
if len(self.items) >= 1:
|
||||||
|
blocks.append(close)
|
||||||
|
return ''.join(blocks)
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.order < other.order
|
||||||
|
|
||||||
|
class ButtonsUnit:
|
||||||
|
def __init__(self, name, order, alt_scheme=None, external=None):
|
||||||
|
self.name = name
|
||||||
|
self.order = order
|
||||||
|
self.alt_scheme = alt_scheme # None means default
|
||||||
|
self.external = external
|
||||||
|
self.items = [] # List of tuples (icon, text, action)
|
||||||
|
self.modes = [common.bar_mode.normal]
|
||||||
|
|
||||||
|
def format(self):
|
||||||
|
b_color = self.alt_scheme.back_color
|
||||||
|
i_color = self.alt_scheme.icon_color
|
||||||
|
t_color = self.alt_scheme.text_color
|
||||||
|
|
||||||
|
# Start with a major separator. Keep previous background color, set foreground color
|
||||||
|
# of separator to background color of this unit
|
||||||
|
blocks = []
|
||||||
|
blocks.append(block(fg=b_color, append=sl))
|
||||||
|
blocks.append(' ')
|
||||||
|
for item in self.items:
|
||||||
|
(icon, text, action) = item
|
||||||
|
close = block(click='') if action is not None else ''
|
||||||
|
|
||||||
|
blocks.append(block(click=action, fg=i_color, bg=b_color, font='2'
|
||||||
|
, append=' ' + icon))
|
||||||
|
blocks.append(' ')
|
||||||
|
blocks.append(block(fg=t_color, font='1', append=text))
|
||||||
|
blocks.append(close)
|
||||||
|
|
||||||
|
return ''.join(blocks)
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.order < other.order
|
||||||
|
|
||||||
|
class CustomUnit:
|
||||||
|
def __init__(self, name, format_function, order, action = None, alt_scheme=None, external=None):
|
||||||
|
self.name = name
|
||||||
|
self.action = action
|
||||||
|
self.order = order
|
||||||
|
self.alt_scheme = alt_scheme # None means default
|
||||||
|
self.external = external
|
||||||
|
self.format = format_function
|
||||||
|
self.items = [] # List of tuples (icon, text)
|
||||||
|
self.modes = [common.bar_mode.normal]
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.order < other.order
|
||||||
|
|
||||||
class LemonParser:
|
class LemonParser:
|
||||||
# Handle parsing of units
|
# Handle parsing of units
|
||||||
@@ -33,58 +112,42 @@ class LemonParser:
|
|||||||
self.units = []
|
self.units = []
|
||||||
|
|
||||||
def register_unit(self, unit):
|
def register_unit(self, unit):
|
||||||
self.units.append(unit)
|
# Keep the list sorted
|
||||||
|
bisect.insort_left(self.units, unit)
|
||||||
|
|
||||||
def remove_unit(self, unit):
|
def remove_unit(self, unit):
|
||||||
self.remove(unit)
|
self.units.remove(unit)
|
||||||
|
|
||||||
def format(self):
|
def format(self):
|
||||||
formatted = []
|
formatted = ['%{l}'] # Start left-justified
|
||||||
|
previously_left_justified = True
|
||||||
|
# Iterate over all units. Apply alternating color schemes
|
||||||
|
alt = 1
|
||||||
|
for unit in self.units:
|
||||||
|
# Show only units appropriate for the current mode
|
||||||
|
if common.mode not in unit.modes:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Negative order means left justified, positive means right justified
|
||||||
|
if previously_left_justified and unit.order > 0:
|
||||||
|
# Switch to right justified
|
||||||
|
formatted.append(block(fg='-', bg='-')) # Reset so the color doesn't fill
|
||||||
|
formatted.append('%{r}')
|
||||||
|
previously_left_justified = False
|
||||||
|
|
||||||
# Iterate over all units. Keep count to apply alternating color schemes
|
|
||||||
for count, unit in enumerate(self.units):
|
|
||||||
if unit.alt_scheme is None:
|
if unit.alt_scheme is None:
|
||||||
# Apply default color scheme, which is alternating
|
# Apply default color scheme, which is alternating
|
||||||
color_scheme = COLOR_SCHEME.A1 if count % 2 else COLOR_SCHEME.A2
|
unit.alt_scheme = COLOR_SCHEME.A1 if alt == 1 else COLOR_SCHEME.A2
|
||||||
else:
|
else:
|
||||||
# Apply alternate color scheme
|
# Keep alternate color scheme
|
||||||
color_scheme = unit.alt_scheme
|
|
||||||
# INA is a special case
|
# INA is a special case
|
||||||
if color_scheme == COLOR_SCHEME.INA:
|
if unit.alt_scheme == COLOR_SCHEME.INA:
|
||||||
color_scheme = COLOR_SCHEME.A1_INA if count % 2 else COLOR_SCHEME.A2_INA
|
unit.alt_scheme = COLOR_SCHEME.A1_INA if alt == 1 else COLOR_SCHEME.A2_INA
|
||||||
|
|
||||||
close = block(click='') if unit.action is not None else ''
|
formatted.append(unit.format())
|
||||||
|
alt = alt + 1 if alt + 1 <= 2 else 1
|
||||||
b_color = color_scheme.back_color
|
|
||||||
i_color = color_scheme.icon_color
|
|
||||||
t_color = color_scheme.text_color
|
|
||||||
|
|
||||||
# Start with a major separator. Keep previous background color, set foreground color
|
|
||||||
# of separator to background color of this unit
|
|
||||||
blocks = []
|
|
||||||
blocks.append(block(fg=b_color, append=sl))
|
|
||||||
blocks.append(' ') # TODO perhaps more nice soluting than manual spacing
|
|
||||||
if len(unit.items) >= 1:
|
|
||||||
(icon, text) = unit.items[0]
|
|
||||||
blocks.append(block(click=unit.action, fg=i_color, bg=b_color, font='2'
|
|
||||||
, append=' ' + icon))
|
|
||||||
blocks.append(' ')
|
|
||||||
blocks.append(block(fg=t_color, font='1', append=text))
|
|
||||||
if len(unit.items) >= 2:
|
|
||||||
for item in unit.items[1:]:
|
|
||||||
(icon, text) = item
|
|
||||||
# Append minor separator
|
|
||||||
blocks.append(' ')
|
|
||||||
blocks.append(sll)
|
|
||||||
|
|
||||||
blocks.append(block(fg=i_color, bg=b_color, font='2', append=' ' + icon))
|
|
||||||
blocks.append(' ')
|
|
||||||
blocks.append(block(fg=t_color, font='1', append=text))
|
|
||||||
|
|
||||||
if len(unit.items) >= 1:
|
|
||||||
blocks.append(close)
|
|
||||||
formatted.append(''.join(blocks))
|
|
||||||
|
|
||||||
|
formatted.append(block(fg='-', bg='-')) # Not sure if needed
|
||||||
return ' '.join(formatted)
|
return ' '.join(formatted)
|
||||||
|
|
||||||
g_parser = LemonParser()
|
g_parser = LemonParser()
|
||||||
@@ -105,150 +168,25 @@ def block(fg = None, bg = None, font = None, click = None, append=''):
|
|||||||
rtn.append('T'+font)
|
rtn.append('T'+font)
|
||||||
return ''.join(['%{', ' '.join(rtn), '}', append])
|
return ''.join(['%{', ' '.join(rtn), '}', append])
|
||||||
|
|
||||||
reset = block(fg='-', bg='-')
|
|
||||||
reset_power = block(fg='-', bg=conf.color_poweropts)
|
|
||||||
|
|
||||||
class COLOR_SCHEME(Enum):
|
class COLOR_SCHEME(Enum):
|
||||||
A1 = (conf.color_sec_b1, conf.color_fore, conf.color_icon)
|
A1 = (config.color_sec_b1, config.color_fore, config.color_icon)
|
||||||
A2 = (conf.color_sec_b2, conf.color_fore, conf.color_icon)
|
A2 = (config.color_sec_b2, config.color_fore, config.color_icon)
|
||||||
INA = (None, None, None) # This one is special, dynamically changed to A1_INA or A2_INA
|
INA = (None, None, None) # This one is special, dynamically changed to A1_INA or A2_INA
|
||||||
A1_INA = (conf.color_sec_b1, conf.color_disable, conf.color_disable)
|
A1_INA = (config.color_sec_b1, config.color_disable, config.color_disable)
|
||||||
A2_INA = (conf.color_sec_b2, conf.color_disable, conf.color_disable)
|
A2_INA = (config.color_sec_b2, config.color_disable, config.color_disable)
|
||||||
CPU_ALERT= (conf.color_cpu, conf.color_back, conf.color_back)
|
CPU_ALERT= (config.color_cpu, config.color_back, config.color_back)
|
||||||
NET_ALERT= (conf.color_net, conf.color_back, conf.color_back)
|
NET_ALERT= (config.color_net, config.color_back, config.color_back)
|
||||||
SPECIAL = (conf.color_head, conf.color_back, conf.color_back)
|
SPECIAL = (config.color_head, config.color_back, config.color_back)
|
||||||
def __init__(self, back_color, text_color, icon_color):
|
def __init__(self, back_color, text_color, icon_color):
|
||||||
self.back_color = back_color
|
self.back_color = back_color
|
||||||
self.text_color = text_color
|
self.text_color = text_color
|
||||||
self.icon_color = icon_color
|
self.icon_color = icon_color
|
||||||
|
|
||||||
def single_sect(icon='', text='', click=None, alt=COLOR_SCHEME.A1):
|
|
||||||
# If there is an action we need to close the block
|
|
||||||
close = block(click='') if click is not None else ''
|
|
||||||
if icon != '':
|
|
||||||
icon = ' ' + icon
|
|
||||||
return ' '.join([block(fg=alt.back_color, append=sl)
|
|
||||||
, block(click=click, fg=alt.icon_color, bg=alt.back_color
|
|
||||||
, font='2', append=icon)
|
|
||||||
, block(fg=alt.text_color, font='1', append=text)
|
|
||||||
, close])
|
|
||||||
|
|
||||||
def double_sect(text1 = '', text2 = '', icon1 = '', icon2 = '', click = None
|
|
||||||
, alt=COLOR_SCHEME.A1):
|
|
||||||
# If text_color None then icon_color will apply
|
|
||||||
close = block(click='') if click is not None else ''
|
|
||||||
return ''.join([block(fg=alt.back_color, append=sl), ' '
|
|
||||||
, block(click=click, fg=alt.icon_color, bg=alt.back_color, font='2')
|
|
||||||
, ' ', icon1, block(fg=alt.text_color, font='1'), ' ', text1
|
|
||||||
, block(fg=alt.icon_color), sll, block(font='2')
|
|
||||||
, icon2, block(fg=alt.text_color, font='1'), ' ', text2, ' ', close])
|
|
||||||
|
|
||||||
def control_sect(sec_color=None, head='', buttons=[], actions=[]):
|
|
||||||
rtn = head
|
|
||||||
for button, action in zip(buttons, actions):
|
|
||||||
# If there is an action we need to close the block
|
|
||||||
close = block(click='') if action is not None else ''
|
|
||||||
rtn += ' '.join([block(click=action), button, close])
|
|
||||||
return rtn
|
|
||||||
|
|
||||||
# Constants
|
|
||||||
power_opts = ''.join([block(fg=conf.color_fore, bg=conf.color_poweropts)
|
|
||||||
, ' Abort (Esc) | System (l) lock, (e) logout, (s) suspend, (h) hibernate'
|
|
||||||
, ', (r) reboot, (Shift+s) shutdown'])
|
|
||||||
controls = ' '.join([block(fg=conf.color_head, bg=conf.color_sec_b2)
|
|
||||||
, conf.sep_right, block(fg=conf.color_head, bg=conf.color_sec_b2, click='mode cycle')
|
|
||||||
, conf.icon_prog
|
|
||||||
, block(fg=conf.color_sec_b2, bg='-', click='')
|
|
||||||
, control_sect(head='', buttons=['on', 'off']
|
|
||||||
, actions=['bluetooth power on', 'bluetooth power off'])
|
|
||||||
, control_sect(head='PXC 550', buttons=['conn.', 'disc.']
|
|
||||||
, actions=['bluetooth connect pxc550', 'bluetooth disconnect pxc550'])
|
|
||||||
])
|
|
||||||
def update_response(data):
|
|
||||||
global response
|
|
||||||
|
|
||||||
resp = ' '.join(data)
|
|
||||||
#common.logger.debug('Got response {}'.format(resp))
|
|
||||||
response= single_sect(text=resp)
|
|
||||||
|
|
||||||
def update_displays(data):
|
|
||||||
global displays
|
|
||||||
|
|
||||||
dsp_array = data[0].split(':')
|
|
||||||
parsed_list = [block(click='displays', font='2')]
|
|
||||||
for dsp in dsp_array[1:]:
|
|
||||||
if dsp == 'eDP1':
|
|
||||||
col_head = conf.color_head
|
|
||||||
elif dsp == 'DP1':
|
|
||||||
col_head = conf.color_vga
|
|
||||||
elif dsp == 'HDMI2':
|
|
||||||
col_head = conf.color_hdmi
|
|
||||||
else:
|
|
||||||
col_head = '#00000000' # Undefined
|
|
||||||
parsed_list.append(block(fg=conf.color_back, bg=col_head))
|
|
||||||
parsed_list.append(conf.icon_wsp)
|
|
||||||
parsed_list.append(block(click=''))
|
|
||||||
|
|
||||||
displays = ' '.join(parsed_list)
|
|
||||||
|
|
||||||
def update_workspaces(data):
|
|
||||||
global workspaces
|
|
||||||
prefix = block(font='1', fg=conf.color_back, bg=conf.color_head)
|
|
||||||
prefix_foc = ''.join([block(fg = conf.color_head, bg=conf.color_wsp)
|
|
||||||
, conf.sep_right
|
|
||||||
, block(fg=conf.color_back, bg=conf.color_wsp, font='1')])
|
|
||||||
prefix_ina = block(fg=conf.color_back, bg=conf.color_head, font='1')
|
|
||||||
wspces = []
|
|
||||||
for entry in data: # entry for example FOC5___terms
|
|
||||||
status = entry[0:3] # FOC or INA
|
|
||||||
num = entry[3]
|
|
||||||
name = entry[7:]
|
|
||||||
full_name = ' '.join(['', num, name])
|
|
||||||
current = ''.join([block(click=('i3-msg workspace' + full_name))
|
|
||||||
, full_name, block(click='')])
|
|
||||||
if status == "FOC":
|
|
||||||
wspces.append(''.join([prefix_foc, current]))
|
|
||||||
else:
|
|
||||||
wspces.append(''.join([prefix_ina, current]))
|
|
||||||
|
|
||||||
workspaces = ''.join([prefix, ' '.join(wspces)])
|
|
||||||
|
|
||||||
def update_title(data):
|
|
||||||
global win_title
|
|
||||||
win_title = ' '.join([block(fg=conf.color_head, bg=conf.color_sec_b2)
|
|
||||||
, conf.sep_right, block(fg=conf.color_head, bg=conf.color_sec_b2, click='mode cycle')
|
|
||||||
, conf.icon_prog
|
|
||||||
, block(fg=conf.color_sec_b2, bg='-')
|
|
||||||
, ' '.join(data)])
|
|
||||||
|
|
||||||
def format_line():
|
def format_line():
|
||||||
# Need to end with a reset block, otherwise the color fills the %{r} spacer
|
return g_parser.format()
|
||||||
if common.mode == common.bar_mode.normal:
|
|
||||||
return ''.join(['%{l}', reset, displays, workspaces, win_title
|
|
||||||
, '%{r}', g_parser.format(), reset])
|
|
||||||
elif common.mode == common.bar_mode.power:
|
|
||||||
return ''.join(['%{l}', reset, power_opts
|
|
||||||
, '%{r}', g_parser.format(), reset_power])
|
|
||||||
elif common.mode == common.bar_mode.control:
|
|
||||||
return ''.join(['%{l}', reset, displays, workspaces, controls
|
|
||||||
, '%{r}', response, time, reset])
|
|
||||||
else:
|
|
||||||
return ''.join(['%{l}', reset, displays, workspaces, 'Not normal'
|
|
||||||
, '%{r}', time, reset])
|
|
||||||
|
|
||||||
parsers_dict = { 'WSP':update_workspaces
|
|
||||||
,'WIN':update_title
|
|
||||||
,'DISP':update_displays
|
|
||||||
,'RESP':update_response
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse_line(line_in):
|
def parse_line(line_in):
|
||||||
''' Lines are
|
# Parse lines that external programs have written to fifo
|
||||||
|
|
||||||
CNK_FAST Fri 21 Sep 19:45:18 VolXXX wlan_d wlan_u eth_d eth_u
|
|
||||||
CNK_SLOW cpu mem disk_root disk_home batt bri lang disp
|
|
||||||
WSPINA1___main INA2___web FOC5___terms INA6___stats
|
|
||||||
'''
|
|
||||||
|
|
||||||
for unit in g_parser.units:
|
for unit in g_parser.units:
|
||||||
if unit.external is not None:
|
if unit.external is not None:
|
||||||
@@ -258,17 +196,6 @@ def parse_line(line_in):
|
|||||||
func(line_in[l:].split())
|
func(line_in[l:].split())
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
|
||||||
for key,func in parsers_dict.items():
|
|
||||||
l = len(key)
|
|
||||||
if line_in[:l] == key:
|
|
||||||
func(line_in[l:].split())
|
|
||||||
break
|
|
||||||
|
|
||||||
except:
|
|
||||||
print('Exception occured\n Line in: {}\n Data: {}'.format(line_in, line_in[l:].split()))
|
|
||||||
raise
|
|
||||||
|
|
||||||
formatted_line = format_line()
|
formatted_line = format_line()
|
||||||
return formatted_line
|
return formatted_line
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#
|
|
||||||
# Print i3 workspaces on every change.
|
# Print i3 workspaces on every change.
|
||||||
#
|
#
|
||||||
# Format:
|
# Format:
|
||||||
@@ -20,7 +19,7 @@ import time
|
|||||||
from subprocess import call
|
from subprocess import call
|
||||||
import i3ipc
|
import i3ipc
|
||||||
|
|
||||||
import i3_lemonbar_common as common
|
print_stdout = False
|
||||||
|
|
||||||
class State(object):
|
class State(object):
|
||||||
# workspace states
|
# workspace states
|
||||||
@@ -47,24 +46,20 @@ class State(object):
|
|||||||
class i3ws(object):
|
class i3ws(object):
|
||||||
ws_format = '%s%s '
|
ws_format = '%s%s '
|
||||||
end_format = 'WSP%s'
|
end_format = 'WSP%s'
|
||||||
state = State()
|
|
||||||
outputs = []
|
|
||||||
focused_window = None
|
|
||||||
running = True
|
|
||||||
fifo = None
|
|
||||||
|
|
||||||
# Callback functions have argument i3ws
|
def __init__(self, logger, state=None):
|
||||||
change_callbacks = []
|
self.state = State()
|
||||||
focus_callbacks = []
|
self.outputs = []
|
||||||
|
self.workspaces = []
|
||||||
|
self.focused_window = None
|
||||||
def __init__(self, logger, state=None, fifo_file=None):
|
self.running = True
|
||||||
if state:
|
if state:
|
||||||
self.state = state
|
self.state = state
|
||||||
if fifo_file:
|
|
||||||
self.fifo = open(fifo_file, 'w')
|
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
common.add_callbacks(self)
|
|
||||||
|
# Callback functions have argument i3ws
|
||||||
|
self.change_callbacks = []
|
||||||
|
self.focus_callbacks = []
|
||||||
|
|
||||||
def work(self):
|
def work(self):
|
||||||
# While loop to restart connection as long as there is an i3 ipc socket
|
# While loop to restart connection as long as there is an i3 ipc socket
|
||||||
@@ -79,8 +74,11 @@ class i3ws(object):
|
|||||||
self.conn = i3ipc.Connection()
|
self.conn = i3ipc.Connection()
|
||||||
|
|
||||||
# Run call backs once
|
# Run call backs once
|
||||||
#self.change(self.conn, None)
|
for cb in self.change_callbacks:
|
||||||
#self.win_focused(self.conn, None)
|
cb(self)
|
||||||
|
|
||||||
|
for cb in self.focus_callbacks:
|
||||||
|
cb(self)
|
||||||
|
|
||||||
self.conn.on('workspace::focus' , self.change)
|
self.conn.on('workspace::focus' , self.change)
|
||||||
self.conn.on('workspace::init' , self.change)
|
self.conn.on('workspace::init' , self.change)
|
||||||
@@ -109,8 +107,8 @@ class i3ws(object):
|
|||||||
fmt_outputs.append(output.name)
|
fmt_outputs.append(output.name)
|
||||||
self.display(':'.join(fmt_outputs))
|
self.display(':'.join(fmt_outputs))
|
||||||
|
|
||||||
workspaces = i3.get_workspaces()
|
self.workspaces = i3.get_workspaces()
|
||||||
text = self.format(workspaces, self.outputs)
|
text = self.format(self.workspaces, self.outputs)
|
||||||
self.display(text)
|
self.display(text)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
@@ -129,6 +127,7 @@ class i3ws(object):
|
|||||||
|
|
||||||
def format(self, workspaces, outputs):
|
def format(self, workspaces, outputs):
|
||||||
# Formats the text according to the workspace data given.
|
# Formats the text according to the workspace data given.
|
||||||
|
# Only important when running in free standing mode
|
||||||
out = ''
|
out = ''
|
||||||
for workspace in workspaces:
|
for workspace in workspaces:
|
||||||
output = None
|
output = None
|
||||||
@@ -145,10 +144,8 @@ class i3ws(object):
|
|||||||
return self.end_format % out
|
return self.end_format % out
|
||||||
|
|
||||||
def display(self, text):
|
def display(self, text):
|
||||||
if self.fifo is not None:
|
global print_stdout
|
||||||
self.fifo.write(text + '\n')
|
if print_stdout:
|
||||||
self.fifo.flush()
|
|
||||||
else:
|
|
||||||
# Displays the text in stout
|
# Displays the text in stout
|
||||||
print(text)
|
print(text)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@@ -157,11 +154,6 @@ class i3ws(object):
|
|||||||
self.logger.debug('Quitting i3 workspace script')
|
self.logger.debug('Quitting i3 workspace script')
|
||||||
self.running = False
|
self.running = False
|
||||||
self.conn.main_quit()
|
self.conn.main_quit()
|
||||||
if self.fifo is not None:
|
|
||||||
try:
|
|
||||||
self.fifo.close()
|
|
||||||
except BrokenPipeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def handle_exit(signal, frame):
|
def handle_exit(signal, frame):
|
||||||
global ws
|
global ws
|
||||||
@@ -171,6 +163,7 @@ def handle_exit(signal, frame):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Run as stand-alone
|
# Run as stand-alone
|
||||||
|
print_stdout = True
|
||||||
|
|
||||||
# Setup logger to stdout with debug log level
|
# Setup logger to stdout with debug log level
|
||||||
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
||||||
|
|||||||
Reference in New Issue
Block a user