Preface
Goal: Separate Main Flow, Code, and Data.
So anyone can focus to alter special customization in Main Script, without changing the whole stuff.
Reading
Before you jump off to scripting, you might desire to read this overview.
All The Source Code:
Impatient coder like me, like to open many tab on browser.
Table of Content
-
Preface: Table of Content
-
3: System Calls
-
6: Hash: Config
-
10: Run Baby Run
1: Directory Structure
Directory Structure has been explained in preface.
This figure will explain how it looks
in Ruby script
directory.
2: Modularizing in Ruby
Nothing to say here. Ruby is simple
Declare a module
No need to explicitly define what to export.
Here we export hc
function variable from helper script.
Nothing to write in helper Script
You can wrap the script in module.
module Config
Tag_names = Array (1..9)
Tag_keys = (Array (1..9)) << 0
end
Call a module
require_relative 'helper'
require_relative 'config'
3: System Calls
Here we wrap herbstclient
system call
in a function named hc
.
helper.rb
def hc(arguments)
system("herbstclient #{arguments}")
end
autostart.rb
# Read the manual in $ man herbstluftwm
hc('emit_hook reload')
# gap counter
system("echo 35 > /tmp/herbstluftwm-gap")
4: Array: Tag Names and Keys
config.rb
Tag_names = Array (1..9)
Tag_keys = (Array (1..9)) << 0
5: Hash: Color Schemes
Using key-value pairs, a simple data structure.
gmc.rb
module GMC
COLOR = {
'white' => '#ffffff',
'black' => '#000000',
'grey50' => '#fafafa',
'grey100' => '#f5f5f5',
}
end
autostart.rb
# background before wallpaper
system("xsetroot -solid '#{GMC::COLOR['blue500']}'")
View Source File:
6: Hash: Config
The Hash in Config is very similar with the colors above. Except that it has string interpolation all over the place.
config.rb
module Config
# Modifier variables
s = 'Shift'
c = 'Control'
m = 'Mod4'
a = 'Mod1'
Keybinds = {
# session
"#{m}-#{s}-q" => 'quit',
"#{m}-#{s}-r" => 'reload',
"#{m}-#{s}-c" => 'close'
}
end
This config will be utilized in main script as shown in the following code.
autostart.rb
helper::do_config("keybind", %config::keybinds);
do_config("keybind", Config::Keybinds)
do_config("keybind", Config::Tagskeybinds)
do_config("mousebind", Config::Mousebinds)
do_config("attr", Config::Attributes)
do_config("set", Config::Sets)
do_config("rule", Config::Rules)
View Source File:
7: Processing The Hash Config
This is the heart of this script.
This do-config
function has two arguments,
the herbstclient command i.e “keybind”, and hash from config.
I can see how simple and clean, Ruby is.
helper.rb
def do_config(command, hash)
# loop over hash
hash.each do |key, value|
hc(command+' '+key+' '+value)
# uncomment to debug in terminal
# puts(command+' '+key+' '+value)
end
end
Debug Herbstclient Command
I do not remove line where I do debug when I made this script, so anyone can use it later, avoid examining blindly. Sometimes strange things happen. Just uncomment this line to see what happened.
puts(command+' '+key+' '+value)
You can see the debugging result in figure below.
View Source File:
8: Setting the Tags
Nothing special here,
Ruby read all exported variable from modules.
And I define local tag_names
to avoid long namespace.
helper.rb
def set_tags_with_name()
tag_names = Config::Tag_names
tag_keys = Config::Tag_keys
hc("rename default '#{tag_names[0]}' 2>/dev/null || true")
tag_names.each_with_index do |tag_name, index|
hc("add '#{tag_names[index]}'")
key = tag_keys[index]
unless key.to_s.empty?
hc("keybind Mod4-#{key} use_index '#{index}'");
hc("keybind Mod4-Shift-#{key} move_index '#{index}'");
end
end
end
9: Launch the Panel
Two more functions left, it is do_panel
and startup_run
.
This two also be easy to do in Ruby.
helper.rb
def do_panel()
panel = __dir__ + "/panel-lemonbar.rb"
if not File.exist?(panel) and File.executable?(panel)
panel = "/etc/xdg/herbstluftwm/panel.sh"
end
raw = IO.popen('herbstclient list_monitors | cut -d: -f1').read()
monitors = raw.split("\n")
for monitor in (monitors)
system("#{panel} #{monitor} &");
end
end
10: Run Baby Run
This is the last part. It is intended to be modified. Everyone has their own personal preferences.
startup.rb
def startup_run()
command = 'silent new_attr bool my_not_first_autostart'
system("herbstclient #{command}")
exitcode = $?.exitstatus
if (exitcode == 0)
# 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 &")
end
end
View Source File:
11: Putting It All Together
The last part is going to main script and putting it all back together.
Now the flow is clear
Header Part: autostart.rb
require_relative 'gmc'
require_relative 'helper'
require_relative 'config'
require_relative 'startup'
Procedural Part: autostart.rb
# background before wallpaper
system("xsetroot -solid '#{GMC::COLOR['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
hc('keyunbind --all')
hc("mouseunbind --all")
hc("unrule -F")
set_tags_with_name()
# do hash config
do_config("keybind", Config::Keybinds)
do_config("keybind", Config::Tagskeybinds)
do_config("mousebind", Config::Mousebinds)
do_config("attr", Config::Attributes)
do_config("set", Config::Sets)
do_config("rule", Config::Rules)
# unlock, just to be sure
hc("unlock")
# launch statusbar panel (e.g. dzen2 or lemonbar)
do_panel()
# load on startup
startup_run
View Source File:
Coming up Next
After the Window Manager, comes the Panel.
Happy Configuring.