First commit. Add .i3 directory

This commit is contained in:
kuben
2019-07-02 21:47:58 +02:00
commit 554573c69b
23 changed files with 1604 additions and 0 deletions

1
.i3/lemonbar/cache/credentials.json vendored Normal file
View File

@@ -0,0 +1 @@
{"username":"kuben-","auth_type":1,"auth_data":"QVFDYzhMY0tnZ2g2M2N1czFhcXI4c0xRMkQzc3pRdXlFZVVVeEVzN0xRRE1VSnItVmw3Z05XWWhRVUNCX2pqS25mSXhGcVRyV0RFcGtTWVFMR3pzSG1jZVdTY0JnNnJFT0hDdFptdzM="}

1
.i3/lemonbar/cache/volume vendored Normal file
View File

@@ -0,0 +1 @@
49151

27
.i3/lemonbar/conky_fast Normal file
View File

@@ -0,0 +1,27 @@
-- Conky for external bar
-- out simple text to console
conky.config = {
background=false,
update_interval=0.2,
total_run_times=0,
override_utf8_locale=true,
short_units=true,
uppercase=false,
out_to_console=true,
out_to_x=false,
if_up_strictness='address',
format_human_readable=true,
}
conky.text = [[
CNK_FAST \
${time %a %d %b %H:%M:%S} \
${exec ~/.i3/lemonbar/get_vol.sh} \
${if_up wlp3s0}${downspeedf wlp3s0} ${upspeedf wlp3s0}\
${else}down down${endif}\
\
${if_up enp2s0}${downspeedf enp2s0} ${upspeedf enp2s0}\
${else}down down${endif}\
\
]]

26
.i3/lemonbar/conky_slow Normal file
View File

@@ -0,0 +1,26 @@
-- Conky for external bar
-- out simple text to console
conky.config = {
background=false,
update_interval=5,
total_run_times=0,
override_utf8_locale=true,
short_units=true,
uppercase=false,
out_to_console=true,
out_to_x=false,
if_up_strictness='address',
format_human_readable=true,
}
conky.text = [[
CNK_SLOW \
${cpu} \
${mem} \
${fs_used_perc /} \
${fs_used_perc /home} \
${exec ~/.i3/lemonbar/get_bat.sh} \
${exec brillo} \
${exec /home/kuba/.i3/scripts/lang.sh show}
]]

5
.i3/lemonbar/get_bat.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
acpi | head -n 1 | awk '{pct = substr($4, 1, length($4)-2);\
if($3 ~ "Dis") print "D"pct;\
else if($3 ~ "Cha") printf "C"pct;\
else print "F"substr($5, 1, length($5)-1);}'

8
.i3/lemonbar/get_vol.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
RTN=$(amixer get Master | grep "Front Left: Playback" | \
awk -F'[]%[]' '{if ($5 == "off") {print "MUTE"} else {printf "%d", $2}}')
if [[ -z $RTN ]]; then
echo "NONE"
else
echo "$RTN"
fi

View File

@@ -0,0 +1,95 @@
import subprocess
from enum import Enum
import i3_lemonbar_config as config
p_bluetooth = None
kill_on_unfocus = []
class bar_mode(Enum):
power, normal, control = range(-1,2) # Don't cycle through power
def cycle(self):
try:
return bar_mode(self.value + 1)
except ValueError:
return bar_mode(0)
mode = bar_mode.normal
floatterm_args = lambda prog : ['terminator', '-r', 'FLOAT_TERM', '-p'
, 'dark', '-e', 'echo kill_unfocus $$ > {}; exec {}'.format(
config.fifo_file_executor, prog)]
def date_comm(args):
subprocess.Popen(['yad', '--no-buttons', '--calendar', '--sticky'
, '--on-top' , '--class' , '"YADWIN"', '--posx=1650', '--posy=24'
, '--close-on-unfocus'])
def pavu_comm(args):
global kill_on_unfocus
p = subprocess.Popen(['pavucontrol', '--class=FLOAT_PAVU'])
kill_on_unfocus.append(p.pid)
def htop_comm(args):
subprocess.Popen(floatterm_args('htop'))
def nmtui_comm(args):
subprocess.Popen(floatterm_args('nmtui'))
def lang_comm(args):
subprocess.Popen(['sh', '/home/kuba/.i3/scripts/lang.sh', 'next'])
def dpms_comm(args):
subprocess.Popen(['sh', '/home/kuba/.i3/scripts/dpmsctl.sh'])
def adj_br(args):
subprocess.Popen(['/home/kuba/.i3/scripts/adjbr.sh', '-b', config.fifo_file_executor])
def i3msg_comm(args):
subprocess.Popen(args.split())
def add_tokill(args):
global kill_on_unfocus
kill_on_unfocus.append(int(args.split()[1]))
def set_mode(args):
global mode
new_mode = args.split()[1]
if new_mode == "cycle":
mode = mode.cycle()
for m in bar_mode:
if new_mode == m.name:
mode = m
break
def bluetooth(args):
btcargs = args.split()[1:]
btcargs = [a.replace('pxc550', '00:16:94:22:29:0E') for a in btcargs]
btcargs.append('\n')
inp = ' '.join(btcargs)
p_bluetooth.stdin.write(inp)
p_bluetooth.stdin.flush()
show_secs = False
def toggle_secs(args):
global show_secs
show_secs = not show_secs
# Keymaps
def_keymap = 'pl'
keymaps = {'Firefox': 'se'}
cur_class = ''
def set_lang(args):
global keymaps
lang = args.split()[1]
keymaps[cur_class] = lang
commands_dict = {'toggle_secs': toggle_secs
,'date': date_comm
,'pavu': pavu_comm
,'load': htop_comm
,'wlan': nmtui_comm
,'dpms': dpms_comm
,'i3-msg': i3msg_comm
,'switch_lang': lang_comm
,'kill_unfocus': add_tokill
,'mode': set_mode
,'adj_br': adj_br
,'setlang': set_lang
,'bluetooth': bluetooth
}

View File

@@ -0,0 +1,86 @@
import subprocess
import getpass
pid_file = '/tmp/i3_lemonbar_launcher.pid'
fifo_file_status = '/tmp/i3_lemonbar1_{}'.format(getpass.getuser())
fifo_file_executor= '/tmp/i3_lemonbar2_{}'.format(getpass.getuser())
health_file = '/tmp/i3_lemonbar_health.info'
path="/home/kuba/.i3/lemonbar/"
logpath="/home/kuba/lemonbar.log" # Write here on exceptions
geometry="x24"
#font="xos4 Terminess Powerline:pixelsize=12:style=Bold"
#iconfont="-misc-font awesome 5 free-medium-r-normal--0-0-0-0-p-0-iso10646-1"
fonts = ["Hack:pixelsize=12" #":style=Bold"
,"Font Awesome 5 Free Solid:pixelsize=16"
,"Font Awesome 5 Brands:pixelsize=16"]
cpu_alert = 75
net_alert = 5
# color definitions
color_back="#FF1D1F21" # Default background
color_fore="#FFC5C8C6" # Default foreground
color_poweropts = "#FF620A00"
color_head="#FFB5BD68" # Background for first element
color_sec_b1="#FF282A2E" # Background for section 1
color_sec_b2="#FF454A4F" # Background for section 2
color_sec_b3="#FF60676E" # Background for section 3
color_vga="#FF3F8C0F"
color_hdmi="#FFDD5435"
color_icon="#FF979997" # For icons
color_cpu="#FF5F819D" # Background color for cpu alert
color_net="#FF5E8D87" # Background color for net alert
color_disable="#FF1D1F21" # Foreground for disable elements
color_wsp="#FF8C9440" # Background for selected workspace
lemonbar_args = ['lemonbar', '-p', '-g', geometry, '-B', color_back
, '-F', color_fore, '-a' '20']
for font in fonts:
lemonbar_args.append('-f')
lemonbar_args.append(font)
#default space between sections
#if [ ${res_w} -gt 1024 ]; then
# stab=' '
#else
# stab=' '
#fi
# Char glyps for powerline fonts
sep_left="" # Powerline separator left alt. 
sep_right="" # Powerline separator right
sep_l_left="" # Powerline light separator left
sep_l_right="" # Powerline light sepatator right
# Icon glyphs from Terminusicons2
icon_clock="" # Clock icon
icon_cpu=""# " # CPU icon alt. 
icon_mem="" # MEM icon
icon_dl="" # Download icon
icon_ul="" # Upload icon
icon_vol="" # Volume icon
icon_vol_low="" # Volume icon
icon_vol_mute="" # Volume icon
icon_hd=" [/]" # HD / icon
icon_home=" [/home]" # HD /home icon
icon_mail="" # Mail icon
icon_chat="Ò" # IRC/Chat icon
icon_music="Î" # Music icon
icon_prog="" # Window icon alt. 
icon_contact="Á" # Contact icon
icon_wsp="" # Workspace icon
icon_wlan=""
icon_eth=""
icon_lang=""
icon_keyset=""
icon_bright=""
icon_brightness=''
icon_charged="" #alt. 
icon_charging="" #alt. 
icon_batt_0=""
icon_batt_1=""
icon_batt_2=""
icon_batt_3=""
icon_batt_4=""
icon_bluetooth=""

View File

@@ -0,0 +1,262 @@
import fcntl, sys, os, time, logging
import signal, atexit
import subprocess
import contextlib
from threading import Thread
import argparse
import re # regexp
import i3_lemonbar_config as config
import i3_lemonbar_common as common
import i3_lemonbar_parser as lemonparser
import i3_workspaces as wspaces
p_conky_slow = None
p_conky_fast = None
p_lemonbar = None
i3_ws_obj = None
def assert_only_instance():
"""
If PID file exists:
Look for process with given PID
If found:
Exit program
If not found:
Delete PID file and continue
Look for fifo file
If exists:
Delete it
"""
try:
pid = None
with open(config.pid_file, 'r') as fp:
pid = int(fp.read())
except IOError:
logger.debug('Could not open PID file. Assuming non existent')
except ValueError:
logger.debug('''PID file contents broken''')
try:
os.remove(config.pid_file)
logger.debug('''Deleted old PID file, continuing as usual''')
except OSError:
logger.debug('''Failed deleting old PID file.''')
os._exit(1)
if pid is not None:
try:
logger.debug('''Found old PID file. Looking for owner''')
os.kill(pid, 0)
logger.debug('''Owner exists''')
logger.debug('''Failed, another instance of the launcher is running
(PID {})'''.format(pid))
os._exit(1)
except ProcessLookupError:
logger.debug('''Owner does not exist''')
try:
os.remove(config.pid_file)
logger.debug('''Deleted old PID file, continuing as usual''')
except OSError:
logger.debug('''Failed deleting old PID file.''')
os._exit(1)
with open(config.pid_file, 'w+') as fp:
fp.write('{:d}'.format(os.getpid()))
logger.debug('''Created and wrote to PID file''')
create_new_fifo(config.fifo_file_status)
create_new_fifo(config.fifo_file_executor)
def create_new_fifo(fifo_file):
"""
Create new fifo file, removing old one if it exists
"""
try:
os.remove(fifo_file)
logger.debug('''Removed old fifo file''')
except OSError:
logger.debug('''No old fifo file, good''')
try:
os.mkfifo(fifo_file)
except OSError:
logger.error('''Failed, couldn't create fifo file''')
os.remove(config.pid_file) # Clean up own PID file
sys.exit(0)
def handle_exit(signum, frame):
logger.info('Signal handler called with signal {}'.format(signum))
logger.info('Calling os._exit(0)')
os._exit(0)
# Terminates process p nicely
def nice_term(p):
if p is not None:
p.terminate()
def nice_delete(f):
with contextlib.suppress(FileNotFoundError):
os.remove(f)
def clean_up():
logger.debug('Cleaning up')
nice_delete(config.pid_file)
nice_delete(config.fifo_file_status)
nice_delete(config.fifo_file_executor)
nice_term(p_conky_slow)
nice_term(p_conky_fast)
nice_term(common.p_bluetooth)
if i3_ws_obj is not None:
i3_ws_obj.quit()
sys.exit(0)
def write_sys_status():
global p_conky_slow, p_conky_fast, i3_ws_obj
with open(config.fifo_file_status, 'w') as fifo:
p_conky_slow = subprocess.Popen(['conky', '-c', config.path+'conky_slow'], # Use communicate
stdout=fifo, stderr=fifo)
logger.debug('Started conky slow')
p_conky_fast = subprocess.Popen(['conky', '-c', config.path+'conky_fast'],
stdout=fifo, stderr=fifo)
logger.debug('Started conky fast')
i3_ws_obj = wspaces.i3ws(fifo_file=config.fifo_file_status)
def parse_status():
global p_lemonbar
with open(config.fifo_file_executor, 'w') as fifo_write:
p_lemonbar = subprocess.Popen(config.lemonbar_args
,stdin=subprocess.PIPE, stdout=fifo_write, text=True)
with open(config.fifo_file_status, 'r', buffering=1) as fifo_read:
# Let parser read from fifo
logger.debug("FIFO {} opened for reading".format(config.fifo_file_status))
lemonparser.parse_line('WSPINA1___main INA2___web FOC5___terms INA6___stats ')
while True:
try:
data = fifo_read.readline() # Blocking read
if len(data) == 0:
logger.debug("Writer closed")
break
psd = lemonparser.parse_line(data)
p_lemonbar.stdin.write(lemonparser.parse_line(data) + '\n')
p_lemonbar.stdin.flush()
#logger.debug('Read: "{0}"'.format(data))
#logger.debug('Parsed "{0}"'.format(psd))
except BrokenPipeError:
logger.debug('Broken pipe in parse status thread, exiting')
clean_up()
except:
logger.debug('Unknown exception in parse status thread, exiting')
clean_up()
def exec_commands():
with open(config.fifo_file_executor, 'r', buffering=1) as fifo_read:
logger.debug("FIFO {} opened for reading".format(config.fifo_file_executor))
while True:
try:
data = fifo_read.readline()
logger.debug('Trying reading: "{0}"'.format(data.strip('\n')))
try:
for key,func in common.commands_dict.items():
l = len(key)
if data[:l] == key:
func(data)
break
except:
logger.debug('Exception occured executing command\n Line in: {}\n Data: {}'.format(line_in, line_in[l:].split()))
if len(data) == 0:
logger.debug("Lemonbar output closed")
break
logger.debug('Read: "{0}"'.format(data.strip('\n')))
except BrokenPipeError:
logger.debug('Broken pipe in exec commands thread, exiting')
clean_up()
except:
logger.debug('Unknown exception in exec commands thread, exiting')
raise
clean_up()
def strip_ansi_unicode(s):
# ANSI escape sequences are for colors in terminal and similar
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]')
strip_ansi = ansi_escape.sub('', s)
strip_unicode = (strip_ansi.encode('ascii', 'ignore')).decode('utf-8')
return strip_unicode
def handle_bluetooth():
common.p_bluetooth = subprocess.Popen('bluetoothctl'
,stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
for line in common.p_bluetooth.stdout:
#try:
logger.debug('Bluetooth read line {}'.format(line.strip('\n')))
with open(config.fifo_file_status, 'w') as fifo:
clean_line = strip_ansi_unicode(line)
if (not clean_line.startswith('[bluetooth]')
and not clean_line.startswith('[CHG]')
and not clean_line.isspace()):
fifo.write('RESP [bluetoothctl] ' + clean_line)
#except:
# raise
class i3_thread:
""" Helper class to start and stop threads"""
all_threads = [] # Static, contains all started threads
def __init__(self, target, desc):
self.thread = Thread(target = target)
self.desc = desc
self.all_threads.append(self)
self.thread.start()
def join_threads():
for i3_th in i3_thread.all_threads:
i3_th.thread.join()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Blah blah blah.')
parser.add_argument('--debug', action='store_true')
args = parser.parse_args()
if(args.debug):
debuglvl = logging.DEBUG
else:
debuglvl = logging.INFO
# Setup logger to stdout
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
logger = logging.getLogger('Normal logger')
logger.setLevel(debuglvl)
logger.addHandler(handler)
# Setup health logger to file in tmp
formatter = logging.Formatter('%(asctime)s %(message)s')
handler = logging.FileHandler(config.health_file)
handler.setFormatter(formatter)
health_logger = logging.getLogger('Health logger')
health_logger.addHandler(handler)
# logger.basicConfig(stream=sys.stdout, level=debuglvl)
assert_only_instance() # Creates pid file and fifo file
atexit.register(clean_up)
signal.signal(signal.SIGTERM, handle_exit)
signal.signal(signal.SIGINT, handle_exit)
# Start writing and reading threads
# Create readers before writers
i3_thread(target = exec_commands, desc='Exec commands thread')
i3_thread(target = parse_status, desc='Parse status thread')
i3_thread(target = write_sys_status, desc='Write sys status thread')
i3_thread(target = handle_bluetooth, desc='Bluetooth thread')
logger.debug('Threads started')
i3_thread.join_threads()
logger.debug('Reached end')

View File

@@ -0,0 +1,290 @@
import sys
from enum import Enum
import i3_lemonbar_config as conf
import i3_lemonbar_common as common
displays = ''
workspaces = ''
win_title = ''
sys_load = ''
net_load = ''
volume = ''
brightness = ''
battery = ''
date = ''
language = ''
time = ''
response = '%{r}'
blank = ' '
sr = conf.sep_right
slr = conf.sep_l_right
sl = conf.sep_left
sll = conf.sep_l_left
def block(fg = None, bg = None, font = None, click = None, append=''):
# Remeber that clickable blocks need to be closed
rtn = []
if click is not None:
if click == '':
rtn.append('A')
else:
rtn.append('A:'+click+':')
if fg is not None:
rtn.append('F'+fg)
if bg is not None:
rtn.append('B'+bg)
if font is not None:
rtn.append('T'+font)
return ''.join(['%{', ' '.join(rtn), '}', append])
reset = block(fg='-', bg='-')
reset_power = block(fg='-', bg=conf.color_poweropts)
class COLOR_SCHEME(Enum):
A1 = (conf.color_sec_b1, conf.color_fore, conf.color_icon)
A2 = (conf.color_sec_b2, conf.color_fore, conf.color_icon)
A1_INA = (conf.color_sec_b1, conf.color_disable, conf.color_disable)
A2_INA = (conf.color_sec_b2, conf.color_disable, conf.color_disable)
CPU_ALERT= (conf.color_cpu, conf.color_back, conf.color_back)
NET_ALERT= (conf.color_net, conf.color_back, conf.color_back)
SPECIAL = (conf.color_head, conf.color_back, conf.color_back)
def __init__(self, back_color, text_color, icon_color):
self.back_color = back_color
self.text_color = text_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 %{r}'])
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)
response= ''.join(['%{r}', 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_conky_slow(data):
global sys_load, battery
# System load
if int(data[0]) > int(conf.cpu_alert):
cpu_alt = COLOR_SCHEME.CPU_ALERT
else:
cpu_alt = COLOR_SCHEME.A2
sys_load = ''.join(['%{r}'
, double_sect(text1 = (data[0] + '%'), text2 = data[1], icon1 = conf.icon_cpu
, icon2 = conf.icon_mem, alt=cpu_alt , click = 'load')
, double_sect(text1 = (data[2] + '%'), text2 = (data[3] + '%')
, icon1 = conf.icon_hd, icon2 = conf.icon_home, alt=COLOR_SCHEME.A1)
]) # cpu mem disk_r disk_home
#sec_color = conf.color_sec_b1 if (b == 1) else conf.color_sec_b2
(batt_stat, batt) = (data[4][0], int(data[4][1:]))
icon_batt = conf.icon_charging if batt_stat == 'C' else \
conf.icon_charged if batt_stat == 'F' else \
conf.icon_batt_0 if batt < 20 else \
conf.icon_batt_1 if batt < 40 else \
conf.icon_batt_2 if batt < 60 else \
conf.icon_batt_3 if batt < 80 else \
conf.icon_batt_4
battery = single_sect(icon=icon_batt, click='dpms', text=(str(batt)+'%')
, alt=COLOR_SCHEME.A2)
update_bright([data[5]])
update_lang([data[6]])
def update_lang(data):
global language
language = single_sect(icon=conf.icon_lang, click='lang', text=data[0]
, alt=COLOR_SCHEME.A2)
def update_bright(data):
global brightness
brtxt = str(int(float(data[0])))
brightness = single_sect(icon=conf.icon_bright, click='adj_br'
, text=(brtxt+'%'), alt=COLOR_SCHEME.A1)
def update_conky_fast(data):
global date, time, volume
mute = data[4] == 'MUTE' or data[4] == 'NONE'
(vol,vols) = (-1,'×') if mute else (int(data[4]), data[4]+'%')
icon_v = conf.icon_vol_mute if vol == 0 else \
conf.icon_vol_low if vol < 50 else conf.icon_vol
volume = single_sect(icon=icon_v, click='pavu', text=vols
, alt=COLOR_SCHEME.A2)
tme = data[3] if common.show_secs else data[3][:-3]
date = single_sect(icon=conf.icon_clock, click='date'
, text=' '.join(data[0:3]), alt=COLOR_SCHEME.A1)
time = single_sect(click='toggle_secs', text=tme, alt=COLOR_SCHEME.SPECIAL)
update_net(data[5:9])
def update_net(data):
global net_load
if data[0] == 'down': # wlan
(wland_v, wlanu_v) = ('x', 'x')
wlan_alt = COLOR_SCHEME.A2_INA
else:
(wland_v, wlanu_v) = (data[0],data[1])
if max(float(wland_v), float(wlanu_v)) > float(conf.net_alert):
wlan_alt = COLOR_SCHEME.NET_ALERT
else:
wlan_alt = COLOR_SCHEME.A2
if data[2] == 'down': # eth
(ethd_v, ethu_v) = ('x', 'x')
eth_alt = COLOR_SCHEME.A1_INA
else:
(ethd_v, ethu_v) = (data[2],data[3])
if max(float(ethd_v), float(ethu_v)) > float(conf.net_alert):
eth_alt = COLOR_SCHEME.NET_ALERT
else:
eth_alt = COLOR_SCHEME.A1
net_load = ''.join([
double_sect(click = 'wlan', alt=wlan_alt, text1 = wland_v, text2 = wlanu_v,
icon1 = (conf.icon_wlan + conf.icon_dl), icon2 = conf.icon_ul)
, double_sect(click = 'eth', alt=eth_alt, text1 = ethd_v, text2 = ethu_v,
icon1 = (conf.icon_eth + conf.icon_dl), icon2 = conf.icon_ul)
]) # wlan_d wlan_u eth_d eth_u
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():
# Need to end with a reset block, otherwise the color fills the %{r} spacer
if common.mode == common.bar_mode.normal:
return ''.join(['%{l}', reset, displays, workspaces, win_title, sys_load, net_load
, volume, brightness, battery, date, language, time, reset])
elif common.mode == common.bar_mode.power:
return ''.join(['%{l}', reset, power_opts, sys_load, net_load
, volume, brightness, battery, date, language, time, reset_power])
elif common.mode == common.bar_mode.control:
return ''.join(['%{l}', reset, displays, workspaces, controls, response, time, reset])
else:
return ''.join(['%{l}', reset, displays, workspaces, 'Not normal' , time, reset])
parsers_dict = { 'CNK_FAST':update_conky_fast
,'CNK_SLOW':update_conky_slow
,'WSP':update_workspaces
,'LANG':update_lang
,'BRIGHT':update_bright
,'WIN':update_title
,'DISP':update_displays
,'RESP':update_response
}
def parse_line(line_in):
''' Lines are
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
'''
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
#return '%s\n' + format_line() # Done this way in .sh
return format_line()
if __name__ == "__main__":
for line in sys.stdin:
print(parse_line(line))

View File

@@ -0,0 +1,186 @@
#!/usr/bin/env python
#
# Print i3 workspaces on every change.
#
# Format:
# For every workspace (x = workspace name)
# - "FOCx" -> Focused workspace
# - "INAx" -> Inactive workspace
# - "ACTx" -> Ative workspace
# - "URGx" -> Urgent workspace
#
# Based in wsbar.py en examples dir
#
# 16 feb 2015 - Electro7
import sys, os, signal
import logging
import time
from subprocess import call
import i3ipc
import i3_lemonbar_config as config
import i3_lemonbar_common as common
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')
class State(object):
# workspace states
focused = 'FOC'
active = 'ACT'
inactive = 'INA'
urgent = 'URG'
def get_state(self, workspace, output):
if workspace['focused']:
if output['current_workspace'] == workspace['name']:
return self.focused
else:
return self.active
if workspace['urgent']:
return self.urgent
else:
return self.inactive
class i3ws(object):
ws_format = '%s%s '
end_format = 'WSP%s'
state = State()
backgrounds = {}
fifo = None
def __init__(self, state=None, fifo_file=None):
if state:
self.state = state
if fifo_file:
self.fifo = open(fifo_file, 'w')
# conn
self.conn = i3ipc.Connection()
# Run call backs once
self.change(self.conn, None)
self.win_focused(self.conn, None)
self.conn.on('workspace::focus', self.change)
self.conn.on('workspace::init', self.change)
self.conn.on('workspace::empty', self.change)
self.conn.on('window::focus', self.win_focused)
logging.debug('Started i3 workspaces manager')
try:
self.conn.main()
except BrokenPipeError:
logging.debug('Broken pipe in i3 workspaces thread, exiting')
except:
logging.debug('Unknown exception in i3 workspaces thread, exiting')
def change(self, i3, e):
# Receives event and workspace data
outputs = i3.get_outputs()
active = ['DISP']
for output in outputs:
if output.name != 'xroot-0':
active.append(output.name)
self.backgrounds[output.name] = img_path(1)
self.display(':'.join(active))
workspaces = i3.get_workspaces()
text = self.format(workspaces, outputs)
self.display(text)
self.set_bg()
def win_focused(self, i3, e):
win = i3.get_tree().find_focused()
name = win.name
role = win.window_role
wclass = win.window_class
text = 'WIN{}'.format(name)
self.display(text)
common.cur_class = wclass
# Kill floating windows
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:
logging.debug('Tried killing process {} but it doesn\'t exist'.format(pid))
common.kill_on_unfocus = []
# Set correct keymap
if wclass in common.keymaps:
new_km = common.keymaps[wclass]
logging.debug('Setting {} as keymap for {}'.format(new_km, wclass))
else:
new_km = common.def_keymap
logging.debug('Setting default keymap {} for {}'.format(common.def_keymap, wclass))
call(['/home/kuba/.i3/scripts/lang.sh', 'qset', new_km])
def format(self, workspaces, outputs):
# Formats the text according to the workspace data given.
out = ''
for workspace in workspaces:
output = None
for output_ in outputs:
if output_['name'] == workspace['output']:
output = output_
break
if not output:
continue
st = self.state.get_state(workspace, output)
if st == 'FOC':
self.backgrounds[output['name']] = img_path(workspace['name'].partition(' ')[0])
name = workspace['name'].replace(" ","___")
item= self.ws_format % (st, name)
out += item
return self.end_format % out
def display(self, text):
if self.fifo is not None:
self.fifo.write(text + '\n')
self.fifo.flush()
else:
# Displays the text in stout
print(text)
sys.stdout.flush()
def set_bg(self):
args = ''
for key in self.backgrounds.keys():
args += ' ' + key + ' ' + self.backgrounds[key]
call(['sh', '/home/kuba/.i3/lemonbar/set_bg.sh', args])
def quit(self):
if self.fifo is not None:
try:
self.fifo.close()
except BrokenPipeError:
pass
if __name__ == '__main__':
ws = i3ws()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print('') # force new line
# finally:
# ws.quit()

24
.i3/lemonbar/set_bg.sh Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
function get_index(){
for i in "${!xra_out[@]}"; do
if [[ "${xra_out[$i]}" = "$value" ]]; then
echo "${i}";
break
fi
done
}
xra_out=($(xrandr | grep ' connected' | awk '{print $1}'))
in=($@)
for i in `seq 0 2 ${#in[@]}`; do
value="${in[$i]}"
idx=$(get_index)
if [ ! -z "$idx" ]; then
screen_idx="$idx"
#"${xra_out[$idx-1]}"
paths[${screen_idx%:}]="--bg-scale ${in[$i+1]}"
fi
done
#echo "${paths[@]}"
str=`printf -v var "%s\n" "${System[@]}"`
sh -c "feh ${paths[@]}"

5
.i3/lemonbar/set_mode.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
if [[ -p /tmp/i3_lemonbar2_$USER ]]; then
echo "$@" > /tmp/i3_lemonbar2_$USER
fi