Commit 051bfd0a authored by epsi sayidina's avatar epsi sayidina

herbstluftwm tags with dzen2

parent 4e6d6429
local _M = {}
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- common functions
function _M.sleep (n)
local t = os.clock()
while os.clock() - t <= n do
-- nothing
end
end
-- https://stackoverflow.com/questions/1426954/split-string-in-lua?rq=1
function _M.split(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={} ; i=0 -- zero based
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
i = i + 1
end
return t
end
-- http://lua-users.org/wiki/StringTrim
function _M.trim1(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
-- https://stackoverflow.com/questions/33510736/check-if-array-contains-specific-value
function _M.has_value (tab, val)
for index, value in ipairs(tab) do
if value == val then
return true
end
end
return false
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- return
return _M
local _M = {}
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- google material colors
-- https://material.io/guidelines/style/color.html
-- Associative Array (Hash)
_M.color = {
['white'] = '#ffffff',
['black'] = '#000000',
['grey50'] = '#fafafa',
['grey100'] = '#f5f5f5',
['grey200'] = '#eeeeee',
['grey300'] = '#e0e0e0',
['grey400'] = '#bdbdbd',
['grey500'] = '#9e9e9e',
['grey600'] = '#757575',
['grey700'] = '#616161',
['grey800'] = '#424242',
['grey900'] = '#212121',
['red50'] = '#ffebee',
['red100'] = '#ffcdd2',
['red200'] = '#ef9a9a',
['red300'] = '#e57373',
['red400'] = '#ef5350',
['red500'] = '#f44336',
['red600'] = '#e53935',
['red700'] = '#d32f2f',
['red800'] = '#c62828',
['red900'] = '#b71c1c',
['redA100'] = '#ff8a80',
['redA200'] = '#ff5252',
['redA400'] = '#ff1744',
['redA700'] = '#d50000',
['pink50'] = '#fce4ec',
['pink100'] = '#f8bbd0',
['pink200'] = '#f48fb1',
['pink300'] = '#f06292',
['pink400'] = '#ec407a',
['pink500'] = '#e91e63',
['pink600'] = '#d81b60',
['pink700'] = '#c2185b',
['pink800'] = '#ad1457',
['pink900'] = '#880e4f',
['pinkA100'] = '#ff80ab',
['pinkA200'] = '#ff4081',
['pinkA400'] = '#f50057',
['pinkA700'] = '#c51162',
['blue50'] = '#e3f2fd',
['blue100'] = '#bbdefb',
['blue200'] = '#90caf9',
['blue300'] = '#64b5f6',
['blue400'] = '#42a5f5',
['blue500'] = '#2196f3',
['blue600'] = '#1e88e5',
['blue700'] = '#1976d2',
['blue800'] = '#1565c0',
['blue900'] = '#0d47a1',
['blueA100'] = '#82b1ff',
['blueA200'] = '#448aff',
['blueA400'] = '#2979ff',
['blueA700'] = '#2962ff',
['yellow50'] = '#fffde7',
['yellow100'] = '#fff9c4',
['yellow200'] = '#fff59d',
['yellow300'] = '#fff176',
['yellow400'] = '#ffee58',
['yellow500'] = '#ffeb3b',
['yellow600'] = '#fdd835',
['yellow700'] = '#fbc02d',
['yellow800'] = '#f9a825',
['yellow900'] = '#f57f17',
['yellowA100'] = '#ffff8d',
['yellowA200'] = '#ffff00',
['yellowA400'] = '#ffea00',
['yellowA700'] = '#ffd600',
['teal50'] = '#e0f2f1',
['teal100'] = '#b2dfdb',
['teal200'] = '#80cbc4',
['teal300'] = '#4db6ac',
['teal400'] = '#26a69a',
['teal500'] = '#009688',
['teal600'] = '#00897b',
['teal700'] = '#00796b',
['teal800'] = '#00695c',
['teal900'] = '#004d40',
['tealA100'] = '#a7ffeb',
['tealA200'] = '#64ffda',
['tealA400'] = '#1de9b6',
['tealA700'] = '#00bfa5',
['green50'] = '#e8f5e9',
['green100'] = '#c8e6c9',
['green200'] = '#a5d6a7',
['green300'] = '#81c784',
['green400'] = '#66bb6a',
['green500'] = '#4caf50',
['green600'] = '#43a047',
['green700'] = '#388e3c',
['green800'] = '#2e7d32',
['green900'] = '#1b5e20',
['greenA100'] = '#b9f6ca',
['greenA200'] = '#69f0ae',
['greenA400'] = '#00e676',
['greenA700'] = '#00c853',
['orange50'] = '#fff3e0',
['orange100'] = '#ffe0b2',
['orange200'] = '#ffcc80',
['orange300'] = '#ffb74d',
['orange400'] = '#ffa726',
['orange500'] = '#ff9800',
['orange600'] = '#fb8c00',
['orange700'] = '#f57c00',
['orange800'] = '#ef6c00',
['orange900'] = '#e65100',
['orangeA100'] = '#ffd180',
['orangeA200'] = '#ffab40',
['orangeA400'] = '#ff9100',
['orangeA700'] = '#ff6d00',
['deepOrange50'] = '#fbe9e7',
['deepOrange100'] = '#ffccbc',
['deepOrange200'] = '#ffab91',
['deepOrange300'] = '#ff8a65',
['deepOrange400'] = '#ff7043',
['deepOrange500'] = '#ff5722',
['deepOrange600'] = '#f4511e',
['deepOrange700'] = '#e64a19',
['deepOrange800'] = '#d84315',
['deepOrange900'] = '#bf360c',
['deepOrangeA100'] = '#ff9e80',
['deepOrangeA200'] = '#ff6e40',
['deepOrangeA400'] = '#ff3d00',
['deepOrangeA700'] = '#dd2c00'
}
return _M
local _M = {}
local common = require('.common')
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- helpers
-- script arguments
function _M.get_monitor(arguments)
-- no ternary operator, using expression
return (#arguments > 0) and tonumber(arguments[1]) or 0
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- geometry calculation
function _M.get_geometry(monitor)
local command = 'herbstclient monitor_rect ' .. monitor
local handle = io.popen(command)
local result = handle:read("*a")
handle:close()
if (result == nil or result == '') then
print('Invalid monitor ' .. monitors)
os.exit()
end
local raw = common.trim1(result)
local geometry = common.split(raw, ' ')
return geometry
end
function _M.get_top_panel_geometry(height, geometry)
-- geometry has the format X Y W H
return geometry[0], geometry[1], geometry[2], height
end
function _M.get_bottom_panel_geometry(height, geometry)
-- geometry has the format X Y W H
return geometry[0], (geometry[3]-height), geometry[2], height
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- dzen Parameters
function _M.get_dzen2_parameters(monitor, panel_height)
local geometry = _M.get_geometry(monitor)
local xpos, ypos, width, height = _M.get_top_panel_geometry(
panel_height, geometry)
local bgcolor = '#000000'
local fgcolor = '#ffffff'
local font = '-*-takaopgothic-medium-*-*-*-12-*-*-*-*-*-*-*'
local parameters = ""
.. " -x "..xpos.." -y "..ypos
.. " -w "..width.." -h "..height
.. " -fn '"..font.."'"
.. " -ta l -bg '"..bgcolor.."' -fg '"..fgcolor.."'"
.. " -title-name dzentop"
return parameters
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- return
return _M
local gmc = require('.gmc')
local common = require('.common')
local helper = require('.helper')
local _M = {}
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- initialize
-- custom tag names
_M.tag_shows = {'一 ichi', '二 ni', '三 san', '四 shi',
'五 go', '六 roku', '七 shichi', '八 hachi', '九 kyū', '十 jū'}
-- initialize variable segment
_M.segment_windowtitle = ''
_M.tags_status = {}
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- decoration
_M.separator = '^bg()^fg(' .. gmc.color['black'] .. ')|^bg()^fg()'
-- http://fontawesome.io/
_M.font_awesome = '^fn(FontAwesome-9)'
-- Powerline Symbol
_M.right_hard_arrow = '^fn(powerlinesymbols-14)^fn()'
_M.right_soft_arrow = '^fn(powerlinesymbols-14)^fn()'
_M.left_hard_arrow = '^fn(powerlinesymbols-14)^fn()'
_M.left_soft_arrow = '^fn(powerlinesymbols-14)^fn()'
-- theme
_M.pre_icon = '^fg(' .. gmc.color['yellow500'] .. ')'
.. _M.font_awesome
_M.post_icon = '^fn()^fg()'
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- main
function _M.get_statusbar_text(monitor)
local text = ''
-- draw tags, zero based
for index = 0, #(_M.tags_status)-1 do
text = text .. _M.output_by_tag(monitor, _M.tags_status[index])
end
-- draw window title
text = text .. _M.output_leftside_top()
return text
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- each segments
function _M.output_by_tag(monitor, tag_status)
local text = ''
local tag_index = string.sub(tag_status, 2, 2)
local tag_mark = string.sub(tag_status, 1, 1)
local index = tonumber(tag_index)-- not a zero based array
local tag_name = _M.tag_shows[index]
-- ----- pre tag
if tag_mark == '#' then
text = text .. '^bg(' .. gmc.color['blue500'] .. ')'
.. '^fg(' .. gmc.color['black'] .. ')'
.. _M.right_hard_arrow
text = text .. '^bg(' .. gmc.color['blue500'] .. ')'
.. '^fg(' .. gmc.color['white'] .. ')'
elseif tag_mark == '+' then
text = text .. '^bg(' .. gmc.color['yellow500'] .. ')'
.. '^fg(' .. gmc.color['grey400'] .. ')'
elseif tag_mark == ':' then
text = text .. '^bg()'
.. '^fg(' .. gmc.color['white'] .. ')'
elseif tag_mark == '!' then
text = text .. '^bg(' .. gmc.color['red500'] .. ')'
.. '^fg(' .. gmc.color['white'] .. ')'
else
text = text .. '^bg()'
.. '^fg(' .. gmc.color['grey600'] .. ')'
end
-- ----- tag by number
-- assuming using dzen2_svn
-- clickable tags if using SVN dzen
text = text .. '^ca(1,herbstclient focus_monitor '
.. '"' .. monitor .. '" && '
.. 'herbstclient use "' .. tag_index .. '")'
.. ' ' .. tag_name ..' ^ca()'
-- ----- post tag
if (tag_mark == '#') then
text = text .. '^bg(' .. gmc.color['black'] .. ')'
.. '^fg(' .. gmc.color['blue500'] .. ')'
.. _M.right_hard_arrow
end
return text
end
function _M.output_leftside_top()
local text = ' ^r(5x0) ' .. _M.separator .. ' ^r(5x0) '
.. _M.segment_windowtitle
return text
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- setting variables, response to event handler
function _M.set_tag_value(monitor)
local command = 'herbstclient tag_status ' .. monitor
local handle = io.popen(command)
local result = handle:read("*a")
handle:close()
local raw = common.trim1(result)
_M.tags_status = common.split(raw, "\t")
end
function _M.set_windowtitle(windowtitle)
local icon = _M.pre_icon .. '' .. _M.post_icon
if (windowtitle == nil) then windowtitle = '' end
_M.segment_windowtitle = ' ' .. icon ..
' ^bg()^fg(' .. gmc.color['grey700'] .. ') ' .. windowtitle
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- return
return _M
#!/usr/bin/lua
-- This is a modularized config for herbstluftwm tags in dzen2 statusbar
local dirname = debug.getinfo(1).source:match("@?(.*/)")
package.path = package.path .. ';' .. dirname .. '?.lua;'
local helper = require('.helper')
local pipehandler = require('.pipehandler')
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- initialize
panel_height = 24
monitor = helper.get_monitor(arg)
-- do `man herbsluftclient`, and type \pad to search what it means
os.execute('herbstclient pad ' .. monitor .. ' '
.. panel_height .. ' 0 ' .. panel_height .. ' 0')
dzen2_parameters = helper.get_dzen2_parameters(monitor, panel_height)
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- main
-- remove all dzen2 instance
os.execute('pkill dzen2')
-- run process in the background
pipehandler.detach_dzen2(monitor, dzen2_parameters)
-- optional transparency
pipehandler.detach_transset()
-- luaposix available in AUR
local posix = require "posix"
local common = require('.common')
local helper = require('.helper')
local output = require('.output')
local _M = {}
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- pipe
function _M.handle_command_event(monitor, event)
-- find out event origin
column = common.split(event, "\t")
origin = column[0]
tag_cmds = {'tag_changed', 'tag_flags', 'tag_added', 'tag_removed'}
title_cmds = {'window_title_changed', 'focus_changed'}
if origin == 'reload' then
os.execute('pkill dzen2')
elseif origin == 'quit_panel' then
os.exit()
elseif common.has_value(tag_cmds, origin) then
output.set_tag_value(monitor)
elseif common.has_value(title_cmds, origin) then
output.set_windowtitle(column[2])
end
end
function _M.init_content(monitor, process)
-- initialize statusbar before loop
output.set_tag_value(monitor)
output.set_windowtitle('')
local text = output.get_statusbar_text(monitor)
process:write(text .. "\n")
process:flush()
end
function _M.walk_content(monitor, process)
-- start a pipe
command_in = 'herbstclient --idle'
local pipe_in = assert(io.popen(command_in, 'r'))
local text = ''
-- wait for each event
for event in pipe_in:lines() do
_M.handle_command_event(monitor, event)
text = output.get_statusbar_text(monitor)
process:write(text .. "\n")
process:flush()
end -- for loop
pipein:close()
end
function _M.run_dzen2(monitor, parameters)
local command_out = 'dzen2 ' .. parameters
local pipe_out = assert(io.popen(command_out, 'w'))
_M.init_content(monitor, pipe_out)
_M.walk_content(monitor, pipe_out) -- loop for each event
pipe_out:close()
end
function _M.detach_dzen2(monitor, parameters)
local pid = posix.fork()
if pid == 0 then -- this is the child process
_M.run_dzen2(monitor, parameters)
else -- this is the parent process
-- nothing
end
end
function _M.detach_transset()
local pid = posix.fork()
if pid == 0 then -- this is the child process
common.sleep(1)
-- you may use either xorg-transset or transset-df instead
-- https://github.com/wilfunctionyr/transset-df
os.execute('transset .8 -n dzentop >/dev/null')
else -- this is the parent process
-- nothing
end
end
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- return
return _M
......@@ -39,22 +39,31 @@ sub handle_command_event {
}
}
sub do_content {
sub init_content {
my $monitor = shift;
my $pipe_out = shift;
my $pipe_out = shift;
# initialize statusbar before loop
output::set_tag_value($monitor);
output::set_windowtitle('');
my $text = output::get_statusbar_text($monitor);
print $pipe_out $text."\n";
flush $pipe_out;
}
sub walk_content {
my $monitor = shift;
my $pipe_out = shift;
# start a pipe
my $pipe_in = IO::Pipe->new();
my $command = 'herbstclient --idle';
my $handle = $pipe_in->reader($command);
my $event = '';
my $text = '';
my $event = '';
while(<$pipe_in>) {
# wait for next event
$event = $_;
......@@ -76,7 +85,8 @@ sub run_dzen2 {
my $command = "dzen2 $parameters";
my $handle = $pipe_out->writer($command);
do_content($monitor, $pipe_out);
init_content($monitor, $pipe_out);
walk_content($monitor, $pipe_out); # loop for each event
$pipe_out->close();
}
......@@ -97,7 +107,7 @@ sub detach_transset {
sleep 1;
# you may use either xorg-transset instead or transset-df
# you may use either xorg-transset or transset-df instead
# https://github.com/wildefyr/transset-df
system('transset .8 -n dzentop >/dev/null');
......
......@@ -3,10 +3,10 @@
# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
# helpers
# script arguments
// script arguments
function get_monitor($arguments)
{
# ternary operator
// ternary operator
return count($arguments) > 0 ? (int)$arguments[0] : 0;
}
......@@ -27,14 +27,14 @@ function get_geometry($monitor)
function get_top_panel_geometry($height, $geometry)
{
# geometry has the format X Y W H
// geometry has the format X Y W H
return array(
$geometry[0], $geometry[1], $geometry[2], $height);
}
function get_bottom_panel_geometry($height, $geometry)
{
# geometry has the format X Y W H
// geometry has the format X Y W H
return array(
$geometry[0], ($geometry[3]-$height), $geometry[2], $height);
}
......
......@@ -4,11 +4,11 @@ require_once(__DIR__.'/gmc.php');
# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
# initialize
# custom tag names
// custom tag names
$tag_shows = ['一 ichi', '二 ni', '三 san', '四 shi',
'五 go', '六 roku', '七 shichi', '八 hachi', '九 kyū', '十 jū'];
# initialize variable segment
// initialize variable segment
$segment_windowtitle = '';
$tags_status = [];
......@@ -17,16 +17,16 @@ $tags_status = [];
$separator = "^bg()^fg(${color['black']})|^bg()^fg()";
# http://fontawesome.io/
// http://fontawesome.io/
$font_awesome = '^fn(FontAwesome-9)';
# Powerline Symbol
// Powerline Symbol
$right_hard_arrow = '^fn(powerlinesymbols-14)^fn()';
$right_soft_arrow = '^fn(powerlinesymbols-14)^fn()';
$left_hard_arrow = '^fn(powerlinesymbols-14)^fn()';
$left_soft_arrow = '^fn(powerlinesymbols-14)^fn()';
# theme
// theme
$pre_icon = "^fg(${color['yellow500']})${font_awesome}";
$post_icon = "^fn()^fg()";
......@@ -38,12 +38,12 @@ function get_statusbar_text($monitor)
global $tags_status;
$text = '';
# draw tags
// draw tags
foreach ($tags_status as $tag_status) {
$text .= output_by_tag($monitor, $tag_status);
}
# draw window title
// draw window title