Commit 76cd042d authored by epsi sayidina's avatar epsi sayidina

herbstluftwm: modularized

parent 492f8498
#!/usr/bin/env bash
#~/.config/herbstluftwm/bash/autostart.sh
~/.config/herbstluftwm/bash/autostart.sh
#~/.config/herbstluftwm/perl/autostart.pl
#~/.config/herbstluftwm/python/autostart.py
#~/.config/herbstluftwm/ruby/autostart.rb
#~/.config/herbstluftwm/php/autostart.php
~/.config/herbstluftwm/lua/autostart.lua
#~/.config/herbstluftwm/lua/autostart.lua
#~/.config/herbstluftwm/haskell/autostart
#!/usr/bin/env bash
# this is a modularized config for herbstluftwm
# This is a modularized config for herbstluftwm
. ~/.config/herbstluftwm/bash/assets/gmc.sh
. ~/.config/herbstluftwm/bash/config.sh
......
module Assets.MyGMC (myColor, colorSchemes) where
-- colorschemes
import Data.Map as M
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- google material colors
-- https://material.io/guidelines/style/color.html
-- Color names are easier to remember:
-- Signature/ Declaration of Associative Array/ Hash/ Dictionary/ Map
colorSchemes :: [(String, String)]
colorSchemes =
[("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")
]
myColor :: String -> String
myColor key = M.findWithDefault "#ffffff" key (fromList colorSchemes)
module MyConfig
( tag_names, tag_keys -- array
, keybinds, tagskeybinds, mousebinds -- dictionary
, attributes, sets, rules -- dictionary
) where
import Assets.MyGMC
type Pair = (String, String)
tag_names :: [Int]
tag_names = [1..9]
tag_keys :: [Int]
tag_keys = [1..9] ++ [0]
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- keybindings
-- if you have a super key you will be much happier with Mod set to Mod4
-- Mod=Mod1 -- Use alt as the main modifier
-- Alt=Mod1
-- Mod=Mod4 -- Use the super key as the main modifier
-- Modifier variables
s = "Shift"
c = "Control"
m = "Mod4"
a = "Mod1"
-- resizing frames
resizestep = "0.05"
keybinds :: [Pair]
keybinds =
-- session
[(m ++ "-" ++ s ++ "-q", "quit")
,(m ++ "-" ++ s ++ "-r", "reload")
,(m ++ "-" ++ s ++ "-c", "close")
-- use your $TERMINAL with xterm as fallback
,(m ++ "-Return", "spawn ${TERMINAL:-xfce4-terminal}")
-- epsi
,(m ++ "-d", "spawn dmenu_run_hlwm")
,(m ++ "-" ++ s ++ "-d", "spawn rofi -show run -opacity 90")
,(m ++ "-" ++ s ++ "-x", "spawn oblogout")
-- basic movement
-- focusing clients
,(m ++ "-Left", "focus left")
,(m ++ "-Down", "focus down")
,(m ++ "-Up", "focus up")
,(m ++ "-Right", "focus right")
,(m ++ "-h", "focus left")
,(m ++ "-j", "focus down")
,(m ++ "-k", "focus up")
,(m ++ "-l", "focus right")
-- moving clients
,(m ++ "-" ++ s ++ "-Left", "shift left")
,(m ++ "-" ++ s ++ "-Down", "shift down")
,(m ++ "-" ++ s ++ "-Up", "shift up")
,(m ++ "-" ++ s ++ "-Right", "shift right")
,(m ++ "-" ++ s ++ "-h", "shift left")
,(m ++ "-" ++ s ++ "-j", "shift down")
,(m ++ "-" ++ s ++ "-k", "shift up")
,(m ++ "-" ++ s ++ "-l", "shift right")
-- splitting frames
-- create an empty frame at the specified direction
,(m ++ "-u", "split bottom 0.5")
,(m ++ "-o", "split right 0.5")
-- let the current frame explode into subframes
,(m ++ "-" ++ c ++ "-space", "split explode")
-- resizing frames
,(m ++ "-" ++ c ++ "-h", "resize left +"++ resizestep)
,(m ++ "-" ++ c ++ "-j", "resize down +"++ resizestep)
,(m ++ "-" ++ c ++ "-k", "resize up +"++ resizestep)
,(m ++ "-" ++ c ++ "-l", "resize right +"++ resizestep)
,(m ++ "-" ++ c ++ "-Left", "resize left +"++ resizestep)
,(m ++ "-" ++ c ++ "-Down", "resize down +"++ resizestep)
,(m ++ "-" ++ c ++ "-Up", "resize up +"++ resizestep)
,(m ++ "-" ++ c ++ "-Right", "resize right +"++ resizestep)
-- MPC
,(m ++ "-" ++ a ++ "-h", "spawn mpc toggle")
,(m ++ "-" ++ a ++ "-t", "spawn mpc prev")
,(m ++ "-" ++ a ++ "-n", "spawn mpc next")
]
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
-- tags
tagskeybinds :: [Pair]
tagskeybinds =
-- cycle through tags
[(m ++ "-period", "use_index +1 --skip-visible")
,(m ++ "-comma", "use_index -1 --skip-visible")
-- layouting
,(m ++ "-r", "remove")
,(m ++ "-s", "floating toggle")
,(m ++ "-f", "fullscreen toggle")
,(m ++ "-p", "pseudotile toggle")
-- focus
,(m ++ "-BackSpace", "cycle_monitor")
,(m ++ "-Tab", "cycle_all +1")
,(m ++ "-" ++ s ++ "-Tab", "cycle_all -1")
,(m ++ "-c", "cycle")
,(m ++ "-i", "jumpto urgent")
]
mousebinds :: [Pair]
mousebinds =
-- mouse
[(m ++ "-Button1", "move")
,(m ++ "-Button2", "zoom")
,(m ++ "-Button3", "resize")
]
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
-- theme
attributes :: [Pair]
attributes =
[("theme.tiling.reset", "1")
,("theme.floating.reset", "1")
,("theme.active.color", "'" ++ myColor "red500" ++ "'")
,("theme.normal.color", "'" ++ myColor "grey200" ++ "'")
,("theme.urgent.color", "'" ++ myColor "pink500" ++ "'")
,("theme.inner_width", "0")
,("theme.inner_color", "black")
,("theme.border_width", "2")
,("theme.floating.border_width", "4")
,("theme.floating.outer_width", "1")
,("theme.floating.outer_color", "'black'")
,("theme.active.inner_color", "'#3E4A00'")
,("theme.active.outer_color", "'#3E4A00'")
,("theme.background_color", "'#141414'")
]
sets :: [Pair]
sets =
[("frame_border_active_color", "'" ++ myColor "grey200" ++ "'")
,("frame_bg_active_color", "'" ++ myColor "yellow900" ++ "'")
,("frame_border_normal_color", "'" ++ myColor "grey50" ++ "'")
,("frame_bg_normal_color", "'" ++ myColor "red500" ++ "'")
,("frame_border_width", "0")
,("always_show_frame", "0")
,("frame_bg_transparent", "1")
,("frame_transparent_width", "2")
,("frame_gap", "20")
,("window_gap", "0")
,("frame_padding", "0")
,("smart_window_surroundings", "0")
,("smart_frame_surroundings", "1")
,("mouse_recenter_gap", "0")
]
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
-- rules
rules :: [Pair]
rules =
-- normally focus new clients
[("focus=on", "")
-- zero based array
,("class=Firefox", "tag=" ++ show (tag_names !! 1) )
,("class=Chromium", "tag=" ++ show (tag_names !! 1) )
,("class=Geany", "tag=" ++ show (tag_names !! 2) )
,("class=Thunar", "tag=" ++ show (tag_names !! 3) )
,("class=gimp", "tag=" ++ show (tag_names !! 4) ++" pseudotile=on")
,("class=Oblogout", "fullscreen=on")
,("class~'(.*[Rr]xvt.*|.*[Tt]erm|Konsole)'", "focus=on")
,("windowtype~'_NET_WM_WINDOW_TYPE_(DIALOG|UTILITY|SPLASH)'", "pseudotile=on")
--,"windowtype='_NET_WM_WINDOW_TYPE_DIALOG'", "focus=on")
,("windowtype='_NET_WM_WINDOW_TYPE_DIALOG'", "fullscreen=on")
,("windowtype~'_NET_WM_WINDOW_TYPE_(NOTIFICATION|DOCK|DESKTOP)'", "manage=off")
]
module MyHelper
( hc
, do_config
, set_tags_with_name
, bind_cycle_layout
, do_panel
) where
import System.Process
import System.Exit
import System.Directory
import System.IO
import MyConfig
type Pair = (String, String)
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- helpers
hc :: String -> IO ExitCode
hc arguments = system $ "herbstclient " ++ arguments
-- IO action procedure
do_config :: String -> [Pair] -> IO ()
do_config command pairs = do
-- loop over a hash dictionary of tuples
mapM_ (\(key, value) -> do
hc(command ++ " " ++ key ++ " " ++ value)
-- uncomment to debug in terminal
-- putStrLn(command ++ " " ++ key ++ " " ++ value)
) pairs
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- tags related
get_indices :: [Int] -> [Int]
get_indices l = [0 .. (length l) - 1]
-- Pattern Matching
keybind_keytag :: Int -> Maybe Int -> IO ()
keybind_keytag index Nothing = do return ()
keybind_keytag index (Just key) = do
hc("keybind Mod4-" ++ show(key)
++ " use_index '" ++ show(index) ++ "'")
hc("keybind Mod4-Shift-" ++ show(key)
++ " move_index '" ++ show(index) ++ "'")
return ()
set_tag :: Int -> IO ()
set_tag index = do
hc("add '" ++ show(tag_names !! index) ++ "'")
-- uncomment to debug in terminal
-- putStrLn $ show index
let key = tag_keys !! index
keybind_keytag index (Just key)
return ()
set_tags_with_name :: IO ()
set_tags_with_name = do
hc("rename default '"
++ show (tag_names !! 0) ++ "' 2>/dev/null || true")
mapM_ set_tag (get_indices tag_names)
return ()
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- miscellanous
bind_cycle_layout :: IO ExitCode
bind_cycle_layout = do
-- The following cycles through the available layouts
-- within a frame, but skips layouts, if the layout change
-- wouldn't affect the actual window positions.
-- I.e. if there are two windows within a frame,
-- the grid layout is skipped.
hc( "keybind Mod4-space "
++ "or , and . compare tags.focus.curframe_wcount = 2 "
++ ". cycle_layout +1 vertical horizontal max vertical grid "
++ ", cycle_layout +1 " )
-- do multi monitor setup here, e.g.:
-- hc("set_monitors 1280x1024+0+0 1280x1024+1280+0");
-- or simply:
-- hc("detect_monitors");
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- find the panel
-- poorly designed, need more refactoring
-- and migrate imperative thinking to functional
do_panel :: IO ()
do_panel = do
-- Source directory is irrelevant in Haskell
-- So hardcoded, for the sake of learning
let path = "/.config/herbstluftwm/bash/dzen2/panel.sh"
home <- getHomeDirectory
let file = home ++ path
isExist <- doesFileExist file
permission <- getPermissions file
let exec_ok = executable permission
-- need to check for executable permission also
let panel = if(isExist && exec_ok)
then file
else "/etc/xdg/herbstluftwm/panel.sh"
-- uncomment to debug in terminal
-- putStrLn panel
(_, Just pipeout, _, _) <-
createProcess (proc "herbstclient" ["list_monitors"])
{ std_out = CreatePipe }
(_, Just cutout, _, ph) <-
createProcess (proc "cut" ["-d:", "-f1"])
{ std_in = UseHandle pipeout, std_out = CreatePipe }
raw <- hGetContents cutout
_ <- waitForProcess ph
-- uncomment to debug in terminal
-- putStrLn raw
let monitors = lines raw
mapM_ (\monitor -> do
system(panel ++ " " ++ show(monitor) ++ " &")
) monitors
return ()
module MyStartup(startup_run) where
import System.Process
import System.IO
import System.Exit
import Control.Monad
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- startup
startup_run :: IO ()
startup_run = do
-- no need to use silent, as the std_err redirected
let args = ["new_attr", "bool", "my_not_first_autostart"]
(_, _, Just pipeerr, ph) <-
createProcess (proc "herbstclient" args)
{ std_err = CreatePipe }
capture_err <- hGetContents pipeerr
exitcode <- waitForProcess ph
-- The test may use against, either exitcode or capture_err
when (exitcode == ExitSuccess) $ do
-- non windowed app
system $ "compton &"
system $ "dunst &"
system $ "parcellite &"
system $ "nitrogen --restore &"
system $ "mpd &"
-- windowed app
system $ "xfce4-terminal &"
system $ "sleep 1 && firefox &"
system $ "sleep 2 && geany &"
system $ "sleep 2 && thunar &"
return ()
-- This is a modularized config for herbstluftwm
import System.Process
import Assets.MyGMC
import MyConfig
import MyHelper
import MyStartup
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- main
main = do
-- background before wallpaper
system $ "xsetroot -solid '" ++ myColor "blue500" ++ "'"
--putStrLn $ "xsetroot -solid '" ++ myColor "blue500" ++ "'"
-- Read the manual in $ man herbstluftwm
hc "emit_hook reload"
-- gap counter
system $ "echo 35 > /tmp/herbstluftwm-gap"
-- do not repaint until unlock
hc "lock"
-- standard
-- remove all existing keybindings
hc "keyunbind --all"
hc "mouseunbind --all"
hc "unrule -F"
set_tags_with_name
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- do hash config
do_config "keybind" keybinds
do_config "keybind" tagskeybinds
do_config "mousebind" mousebinds
do_config "attr" attributes
do_config "set" sets
do_config "rule" rules
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
-- finishing, some extra miles
-- I'm not sure what in this is
bind_cycle_layout
-- example of custom layout
let layout = "(split horizontal:0.5:0 "
++ "(clients vertical:0) (clients vertical:0))"
hc("load " ++ show(tag_names !! 0) ++ " '" ++ layout ++ "'")
-- tag number 5
hc "floating 5 on"
-- hc "set tree_style '╾│ ├└╼─┐'"
hc "set tree_style '⊙│ ├╰»─╮'"
-- unlock, just to be sure
hc "unlock"
-- launch statusbar panel (e.g. dzen2 or lemonbar)
do_panel
-- load on startup
startup_run
#!/usr/bin/lua
-- this is a modularized config for herbstluftwm
-- This is a modularized config for herbstluftwm
local dirname = debug.getinfo(1).source:match("@?(.*/)")
package.path = package.path .. ';' .. dirname .. '?.lua;'
......@@ -12,13 +12,13 @@ local startup = require(".startup")
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
-- main
---- background before wallpaper
-- background before wallpaper
os.execute("xsetroot -solid '" .. gmc.color["blue500"] .. "'")
---- Read the manual in $ man herbstluftwm
-- Read the manual in $ man herbstluftwm
helper.hc('emit_hook reload')
---- gap counter
-- gap counter
os.execute("echo 35 > /tmp/herbstluftwm-gap")
-- do not repaint until unlock
......@@ -27,26 +27,26 @@ helper.hc("lock")
-- standard
-- remove all existing keybindings
helper.hc('keyunbind --all')
helper.hc("mouseunbind --all")
helper.hc("unrule -F")
helper.hc('mouseunbind --all')
helper.hc('unrule -F')
helper.set_tags_with_name()
-- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----
-- do hash config
helper.do_config("keybind", config.keybinds)
helper.do_config("keybind", config.tagskeybinds)
helper.do_config("mousebind", config.mousebinds)
helper.do_config("attr", config.attributes)
helper.do_config("set", config.sets)