guest@dotshare [~/groups/wms/i3] $ ls deterenkelts-i3-config/ | cat

deterenkelt’s i3 config (scrot) (+1 likes)

deterenkelt Jul 17, 2015 (wms/i3)

i3_config(raw, dl)

SCROT

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# i3 config file (v4)
#
# Please see http://i3wm.org/docs/userguide.html for a complete reference!
#
# To get a config file with the same key positions, but for your current
# layout, use the i3-config-wizard

# font for window titles. ISO 10646 = Unicode
# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
font xft:Terminus 12

## Keybindings
set $mod Mod4
## Focus: ijkl   ↑←↓→
bindcode $mod+31 focus up
bindcode $mod+44 focus left
bindcode $mod+45 focus down
bindcode $mod+46 focus right

## Move focused window
bindcode $mod+Shift+31 move up
bindcode $mod+Shift+44 move left
bindcode $mod+Shift+45 move down
bindcode $mod+Shift+46 move right
## Change container layout (q=stacked, w=default, e=tabbed)
bindcode $mod+24 layout stacking
bindcode $mod+25 layout default
bindcode $mod+26 layout tabbed
## In stacked/tabbed windows cursor may wrap in cycle
force_focus_wrapping no
## u     Focus the parent container
bindcode $mod+30 focus parent
## m     Focus the child container
bindcode $mod+58 focus child
## h     Split in horizontal orientation
bindcode $mod+43 split h
## v     Split in vertical orientation
bindcode $mod+55 split v

## SPC	Toggle tiling / floating
bindsym $mod+space floating toggle
## Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod
## S-SPC  Focus last floating/tiled container
bindsym $mod+Shift+space focus mode_toggle

## C-u   Focus to next output to the left
bindcode $mod+Control+30 focus output left
## C-o   Focus to next output to the right [o]
bindcode $mod+Control+32 focus output right

## f    Enter fullscreen mode for the focused container
bindcode $mod+41 fullscreen
## c    Kill focused window
bindcode $mod+54 kill
## Resize window (you can also use the mouse for that)
mode "resize" {
	bindcode 31   resize grow height 10 px or 10 ppt
	bindcode 44   resize shrink width 10 px or 10 ppt
	bindcode 45   resize shrink height 10 px or 10 ppt
	bindcode 46   resize grow width 10 px or 10 ppt
	## Back to normal: Enter or Escape
	bindsym Return mode "default"
	bindsym Escape mode "default"
}
## x	Resize
bindcode $mod+53 mode "resize"

## S-r  Reload configuration file (not used)
#bindcode $mod+Shift+27 reload
## C-r  Restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
## Since this config is a template, it’s necessary to replace output names
bindcode $mod+Control+27 exec "~/.i3/update_config.sh"

## C-q  Quit
bindcode $mod+Control+24 exec "~/.i3/on_quit.sh"
# bindcode $mod+Control+Shift+24 exec "sudo /usr/bin/killall iftop; ~/scripts/xorg.conf_chooser.sh"
## C-t  To choose other xorg.conf when X will start again.
bindcode $mod+Control+28 exec "~/.i3/autostart.sh stop_after_main_workspace"

## How to make it work?
#bindcode $mod+Control_L+29 exec "Xdialog --msgbox 'CONTROL_L+y' 0x0"
#bindcode $mod+Control_R+29 exec "Xdialog --msgbox 'CONTROL_R+y' 0x0"

## RET
bindsym $mod+Return exec urxvtc
## r
## One-command urxvtc instance, it is replacement for dmenu (also see ~/.bashrc and ~/.Xresources)
bindcode $mod+27 exec --no-startup-id /bin/bash -c 'export ONE_COMMAND_SHELL=t && urxvtc -name one_command_shell'

### screenshot.sh block
##
## It is useful to take screenshots in the way to get rid of further processing in GIMP,
##   i.e. take them in PNG or JPEG by desire, with or without delay, if it be PNG, shall
##   it be full RGB or indexed colours? Taking all that into account I’ve written out
##   the functions which will actually be in use, and that got me 6:
##
##   Fullscreen (PNG)
##   Fullscreen (JPEG)
##   Window (PNG only)  +delay
##   Area (PNG only)    +indexed
##
## Thankfully, that fits the number of available keybindings for the left hand based on
##   Super, Alt, Shift, Control and S (the letter) keycodes, that is 7, but… it’s still
##   would be a pain to remember which modifier alternates what in conjunction with what.
##   So I’ve decided to use three keys for screen, window and area and use one modifier
##   key to alternate one thing: delay, indexed format and JPEG.
##
## s (screen)
bindcode --release $mod+39 exec --no-startup-id ". ~/scripts/screenshot.sh"
#bindcode --release $mod+Control+39 exec --no-startup-id ". ~/scripts/screenshot.sh -delay"
#bindcode --release $mod+Shift+39 exec --no-startup-id ". ~/scripts/screenshot.sh -indexed"
bindcode --release $mod+Mod1+39 exec --no-startup-id ". ~/scripts/screenshot.sh -jpeg"

## a (window)
bindcode --release $mod+38 exec --no-startup-id ". ~/scripts/screenshot.sh -window"
bindcode --release $mod+Control+38 exec --no-startup-id ". ~/scripts/screenshot.sh -window -delay"
#bindcode --release $mod+Shift+38 exec --no-startup-id ". ~/scripts/screenshot.sh -window -indexed"
#bindcode --release $mod+Mod1+38 exec --no-startup-id ". ~/scripts/screenshot.sh -window -jpeg"

## z (area)
bindcode --release $mod+52 exec --no-startup-id ". ~/scripts/screenshot.sh -area"
#bindcode --release $mod+Control+52 exec --no-startup-id ". ~/scripts/screenshot.sh -area -delay"
bindcode --release $mod+Shift+52 exec --no-startup-id ". ~/scripts/screenshot.sh -area -indexed"
#bindcode --release $mod+Mod1+52 exec --no-startup-id ". ~/scripts/screenshot.sh -area -jpeg"

## C-l → i3lock
bindcode $mod+Control+46 exec --no-startup-id i3lock
##
## F1
bindcode $mod+67 exec --no-startup-id mpc toggle
## F2
bindcode $mod+68 exec --no-startup-id "~/scripts/add2playlist.sh"
                                                             # create new
bindcode $mod+Shift+68 exec --no-startup-id "~/scripts/add2playlist.sh -c"
## F3
bindcode $mod+69 exec --no-startup-id amixer set Master toggle
## F4
## See ‘amixer scontrols | $PAGER’ for a complete list of controls
bindcode $mod+70 exec --no-startup-id "amixer sset 'Capture',0 toggle"
## F5
bindcode $mod+71 exec --no-startup-id amixer set Master 2%-
bindcode $mod+Control+71 exec --no-startup-id xbacklight -dec 5
## F6
bindcode $mod+72 exec --no-startup-id eval mpc volume -2
## F7
bindcode $mod+73 exec --no-startup-id eval mpc volume +2
## F8
bindcode $mod+74 exec --no-startup-id amixer set Master 2%+
bindcode $mod+Control+74 exec --no-startup-id xbacklight -inc 5
## F9
bindcode $mod+75 exec --no-startup-id eval mpc prev
## F10
bindcode $mod+76 exec --no-startup-id eval mpc next
## F11
bindcode $mod+95 exec --no-startup-id eject
bindcode $mod+Shift+95 exec --no-startup-id eject -t
## F12
#bindcode $mod+96 exec --no-startup-id /bin/bash -c ""

## g     Restrict wallpapers to subdirectory
bindcode $mod+42 exec --no-startup-id "~/scripts/wallpaper_setter.sh -r"
## b     Decrease brightness
bindcode $mod+56 exec --no-startup-id "~/scripts/wallpaper_setter.sh -b -0.1"
## S-b   Increase brightness
bindcode $mod+Shift+56 exec --no-startup-id "~/scripts/wallpaper_setter.sh -b +0.1"
## n     Change mode
bindcode $mod+57 exec --no-startup-id "~/scripts/wallpaper_setter.sh -m"
## ,     Set previous (<)
bindcode $mod+59 exec --no-startup-id "~/scripts/wallpaper_setter.sh -p"
## .     Set new (>)
bindcode $mod+60  exec --no-startup-id "~/scripts/wallpaper_setter.sh -n"
## S-.   Force new (--|>)
bindcode $mod+Shift+60  exec --no-startup-id "~/scripts/wallpaper_setter.sh -fn"
## /     Keep
bindcode $mod+61 exec --no-startup-id "~/scripts/wallpaper_setter.sh -k"

## Switch to workspace and launch related application.
## `
bindcode $mod+49 workspace 0:Main
## 1
bindcode $mod+10 exec --no-startup-id "i3-msg workspace 1:Firefox && { pgrep -u $UID firefox &>/dev/null || { firefox --profile ~/.ff & } }"
## 2
## This is to distinguish emacsclient window running in X and those in
##   terminals, i.e. to forbid creation of more than one X window while there
##   can be other emacsclients in terminals. See also ‘ec‘ alias in ~/.bashrc.
bindcode $mod+11 exec --no-startup-id "i3-msg workspace 2:Emacs && { pgrep -u $UID -f '^emacsclient --al' || { emacsclient --alternate-editor= -c -display $DISPLAY & } }"
## 3
bindcode $mod+12 exec --no-startup-id "i3-msg workspace 3:Thunar && { pgrep -u $UID thunar &>/dev/null || { thunar & } }"
## 4
bindcode $mod+13 exec --no-startup-id "i3-msg workspace 4:Geeqie && { pgrep -u $UID geeqie &>/dev/null || { geeqie & } }"
## 5
bindcode $mod+14 workspace 5:Misc
## 6
bindcode $mod+15 workspace 6:IM
## 7
bindcode $mod+16 workspace 7:Games
## 8
bindcode $mod+17 exec --no-startup-id "i3-msg workspace 8:GIMP && { pgrep -u $UID gimp &>/dev/null || { gimp & } }"
## 9
bindcode $mod+18 exec --no-startup-id "i3-msg workspace 9:MPD && { pgrep -u $UID ncmpcpp &>/dev/null || { urxvtc -name ncmpcpp -e ncmpcpp & } }"
## 0
bindcode $mod+19 workspace 10:Outer_space
## -
# bindcode $mod+20 workspace 11:Mail
## TAB   Back and forth
bindsym $mod+Tab workspace back_and_forth

workspace 0:Main         output DVI-I-0
workspace 1:Firefox      output DVI-I-0
workspace 2:Emacs        output DVI-I-0
workspace 3:Thunar       output DVI-I-0
workspace 4:Geeqie       output DVI-I-0
workspace 5:Misc         output DVI-I-0
workspace 6:IM           output DVI-I-0
workspace 7:Games        output DVI-I-0
workspace 8:GIMP         output DVI-I-0
workspace 9:MPD          output DVI-I-0
workspace 10:Outer_space  output SLAVE_OUTPUT_1

## Move focused container to workspace
bindcode $mod+Shift+49 move container to workspace 0:Main
bindcode $mod+Shift+10 move container to workspace 1:Firefox
bindcode $mod+Shift+11 move container to workspace 2:Emacs
bindcode $mod+Shift+12 move container to workspace 3:Thunar
bindcode $mod+Shift+13 move container to workspace 4:Geeqie
bindcode $mod+Shift+14 move container to workspace 5:Misc
bindcode $mod+Shift+15 move container to workspace 6:IM
bindcode $mod+Shift+16 move container to workspace 7:Games
bindcode $mod+Shift+17 move container to workspace 8:GIMP
bindcode $mod+Shift+18 move container to workspace 9:MPD
bindcode $mod+Shift+19 move container to workspace 10:Outer_space
# bindcode $mod+Shift+20 move container to workspace 11:Mail
bindsym $mod+Shift+Tab move container to workspace back_and_forth

## Assigning windows to workspaces
assign [class="Firefox"]"1:Firefox"
assign [class="Emacs"]"2:Emacs"
assign [class="Thunar"]"3:Thunar"
assign [class="Geeqie"]"4:Geeqie"
assign [class="(?i)libreoffice*"]"5:Misc"
assign [class="Soffice"]"5:Misc"
assign [class="^qemu*"]"5:Misc"
assign [class="spicec"]"5:Misc"
assign [class="screenshot_preview"]"5:Misc"
assign [class="Pidgin"]"6:IM"
assign [class="Skype"]"6:IM"
assign [class="Ts3client"]"6:IM"
assign [class="Wine"]"7:Games"
assign [class="Steam"]"7:Games"
assign [class="hl2_linux"]"7:Games"
assign [class="[tT]rine*"] → "7:Games"
assign [class="StarConflict"] → "7:Games"
assign [class="Gimp"] → "8:GIMP"
assign [class="URxvt" instance="ncmpcpp"] → "9:MPD"
assign [class="mpv" instance="big_screen"] → "10:Outer_space"

## Arbitrary commands for specific windows
for_window [class="URxvt" instance="one_command_shell"] floating enable
for_window [class="spicec"] floating disable
for_window [class="Xdialog"] floating enable
for_window [class="Yad"] floating enable
for_window [class="Convert Script"] floating enable


## This executes every reload
exec_always --no-startup-id "~/.i3/set_keyboard.sh"
## And this once at the start
exec --no-startup-id "~/.i3/autostart.sh"

## Window border style
new_window 1pixel
new_float 1pixel

hide_edge_borders both
focus_follows_mouse no

## Default
## class                    border  backgr. text    indicator
# client.focused            #4c7899 #285577 #ffffff #2e9ef4
# client.focused_inactive   #333333 #5f676a #ffffff #484e50
# client.unfocused          #333333 #222222 #888888 #292d2e
# client.urgent             #2f343a #900000 #ffffff #900000

## class                    border  backgr. text    indicator
client.focused              #ad7fa8 #75507b #ffffff #ad7fa8
client.focused_inactive     #555753 #3c3c3c #ffffff #ad7fa8
client.unfocused            #555753 #3c3c3c #888888 #ad7fa8
client.urgent               #ad7fa8 #ad7fa8 #ffffff #ff0000

bar {
	# verbose yes
	# separator_symbol ":|:"
	output DVI-I-0
	position top
	tray_output none
	workspace_buttons yes
	strip_workspace_numbers yes
	status_command ". ~/.i3/generate_json_for_i3bar.sh"
	wheel_up_cmd nop # disable mouse wheel on workspace buttons
	wheel_down_cmd nop
	colors {
		background #3c3c3c
		statusline #cccccc
		focused_workspace    #ad7fa8 #75507b #ffffff
		active_workspace     #75507b #ad7fa8 #ffffff
		inactive_workspace   #3c3c3c #3c3c3c #bbbbbb
		urgent_workspace     #df5757 #c22f2f #ffffff
	}
}

# bar {
# 	output SLAVE_OUTPUT_1
# 	position top
# 	workspace_buttons yes
# }

CLICK TO VIEW

x

i3_autostart.sh(raw, dl)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/bin/bash

# autostart.sh
# This script is called from ~/.i3/config with ‘exec ~/.i3/autstart.sh’

#[ "${ENV_DEBUG/*a*/}" ] || {
true && {
	exec &>/tmp/envlogs/autostart
	date
	set -x
}

# Temporarily disable pointer while setting layout
# $1 == <enable|disable>
pointer_control() {
	[ -v pointer_devices ] || pointer_devices=$(xinput --list \
		| sed -nr '/Virtual\score.*pointer/ !s/.*id=([0-9]+)\s+\[slave\s+pointer.*/\1/p')
	for dev in $pointer_devices; do xinput --$1 $dev; done
}

# Wait for the last command sent to background to create a window
wait_for_program () {
	local c=0; until [ $((++c)) -eq 15 ]; do
		xdotool search --onlyvisible --pid $! 2>/dev/null && break
		sleep 1
    done
	[ $c -eq 15 ] && i3-nagbar -m "Error on executing $0 script"
}

# Cleaning before new session.
# This is a well-known bug, emacsclient cannot connect to the daemon after X
#   have been restarted.
# Though, it works in a gentoo-way: via init scripts,
#   like ‘/etc/init.d/emacs.username’.
# This gives us the last solution: to run it from tmux session, if we want
#   to keep our configuration away from messing with system configuration,
#   be it init scripts or whatever.
#   pkill -9 emacsclient
pkill -9 emacsclient

# Because we can close terminals holding root’s iftops, but not them.
sudo /usr/bin/killall iftop

# Applications that need to be started before layout setting:
#   urxvtd, tmux and emacs daemon in tmux.
# Substitute line:
	# neww -n wa-a "{ (nohup emacs --daemon &>/dev/null) & } && /bin/bash " \; \
#   is useless since emacsclient running from here still fails to connect to
#   Emacs because it tries to do that while applications are messing around
#   with gpg keys, which causes a delay before i3 windows actually appear.
#   This was checked on the other machine with the same configuration except
#     the key management: all works fine there.
#   I fucking hate that goddamn piece of crap, but too lazy to set up vim.
# Yes, it seems that the only way to have that shit working between X restarts
#   and independently of X is to run daemon via init scripts >_>
pgrep urxvtd || urxvtd -q -o -f
tmux="tmux -u -f $HOME/.tmux/config -S $HOME/.tmux/socket"
if pgrep -u $UID -f '^tmux.*$' &>/dev/null; then
	[ "$1" = stop_after_main_workspace ] && {
		for pane in `$tmux list-windows -t0 | sed -r 's/^([0-9]+):.*/\1/g'`; do
			$tmux send -t 0:$pane C-c
			$tmux send -t 0:$pane export\ DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" ENTER
			$tmux send -t 0:$pane export\ DISPLAY="$DISPLAY" ENTER
		done
	}
else
	$tmux \
	new -d su \; \
	set remain-on-exit on \; \
	neww su \; \
	set remain-on-exit on \; \
	select-window -t 0:1
# Another user termianl in tmux
#	neww -n wa-a \; \
#	set remain-on-exit on \; \
fi

pointer_control disable

# WIDTH and HEIGHT were set in the ~/.preload.sh
case $HOSTNAME in
	fanetbook)
		hsetroot -fill ~/.env/wallpaper.png
		urxvtc -hold -name 'htop' -title "htop" -e htop
		xte "mousemove $(( WIDTH/2 ))  $(( HEIGHT/2 ))"
		xte 'mouseclick 1'
		i3-msg layout tabbed

		for iface_config in `ls ~/.iftop/$HOSTNAME.*`; do
			urxvtc -hold -title ${iface_config##*.} \
				-e sudo /usr/sbin/iftop -c "$iface_config"
		done
		urxvtc
		urxvtc
		urxvtc -hold -title tmux -e $tmux attach \; find-window -N root

		startup_apps=()
		;;
	*)
		pgrep -u $UID -f "^bash $HOME/scripts/wallpaper_setter.sh -B" \
			|| { ~/scripts/wallpaper_setter.sh -B -0.3 \
			   -e "i3-nagbar -m \"%m\" -b Restart \"%a\"" \
			   -d /home/picts/screens & }
		# Urxvtc windows must appear after wallpaper is set, due to their
		#   fake transparency.
		~/scripts/wallpaper_setter.sh -w

		urxvtc --title 'Todo list' -e watch -t -n15 cat -n ~/todo
# ┌────┐
# │    │
# │    │
# └────┘
		i3-msg split v
		urxvtc -hold -title 'htop' -e htop
# ╔════╗
# ║    ║
# ╟────╢
# ║    ║
# ╚════╝
		# Move cursor near the center of the lower urxvtc with htop
		xte "mousemove $(( WIDTH/2 ))  $(( 3*HEIGHT/4 ))"
		xte 'mouseclick 1'  # …and focus it.
		i3-msg split h
# ╔═════╗ # ╔═══════╗
# ║     ║ # ║       ║
# ╟─────╢ # ╠━━━┯━━━╣
# ║  ⋅  ║ # ║   │   ║
# ╚═════╝ # ╚═══╧═══╝
		iface_configs=(`ls ~/.iftop/$HOSTNAME.*`)
		[ ${#iface_configs} -gt 1 ] && iftops_need_their_own_container=t
		for ((i=0; i<${#iface_configs[@]}; i++)); do
			urxvtc -hold -title ${iface_configs[$i]##*.} \
				-e sudo /usr/sbin/iftop -c "${iface_configs[$i]}"
			[ $i -eq 0 ] && [ -v iftops_need_their_own_container ] && \
				i3-msg split h
		done
# ╔═════════════════╗
# ║                 ║
# ╠━━━━━━━━┳━━┯━━┯━━╣
# ║        ┃  │  │  ║  (Possible variation if there are 3 htop configs)
# ╚════════╩══╧══╧══╝
		[ -v iftops_need_their_own_container ] && {
			xte "mousemove $(( 9*WIDTH/16 )) $(( 3*HEIGHT/4 ))"
			xte 'mouseclick 1'
			i3-msg layout tabbed
		}
# ╔═════════════════╗ # ╔═════════════════╗
# ║                 ║ # ║                 ║
# ║                 ║ # ║                 ║
# ╠━━━━━━━━┳━━┯━━┯━━╣ # ╠━━━━━━━━┳━━━━━━━━╣
# ║        ┃⋅ │  │  ║ # ║        ┃––+––+––║  ← tabs
# ║        ┃  │  │  ║ # ║        ┃        ║
# ╚════════╩══╧══╧══╝ # ╚════════╩════════╝
		xte "mousemove $(( WIDTH/2 ))  $(( HEIGHT/4 ))"
		xte 'mouseclick 1'
		# raise upper empty urxvtc up to ≈5/6 of the height
		i3-msg resize grow height 30 px or 30 ppt
		i3-msg split h
		urxvtc
# ╔═════════════════╗ # ╔════════╤════════╗
# ║        ⋅        ║ # ║        │        ║
# ║                 ║ # ║        │        ║
# ╠━━━━━━━━┳━━━━━━━━╣ # ║        │        ║
# ║        ┃––+––+––║ # ║        │        ║
# ║        ┃        ║ # ╠━━━━━━━━╈━━━━━━━━╣
# ╚════════╩════════╝ # ║        ┃––+––+––║
                      # ║        ┃        ║
                      # ╚════════╩════════╝
		xte "mousemove $(( WIDTH/4 )) $(( HEIGHT/2 ))"
		xte 'mouseclick 1'
		i3-msg split h
		i3-msg layout tabbed
		urxvtc
		urxvtc
# ╔════════╤════════╗ # ╔════════╦════════╗
# ║        │        ║ # ║––+––+––┃        ║
# ║        │        ║ # ║        ┃        ║
# ║   ⋅    │        ║ # ║        ┃        ║
# ║        │        ║ # ║        ┃        ║
# ╠━━━━━━━━╈━━━━━━━━╣ # ╠━━━━━━━━╋━━━━━━━━╣
# ║        ┃––+––+––║ # ║        ┃––+––+––║
# ║        ┃        ║ # ║        ┃        ║
# ╚════════╩════════╝ # ╚════════╩════════╝
		xte "mousemove $(( 3*WIDTH/4 )) $(( HEIGHT/2 ))"
		xte 'mouseclick 1'
		i3-msg split h
		i3-msg layout tabbed
		urxvtc
		urxvtc -hold -title tmux -e $tmux attach
		xte "mousemove $(( 11*WIDTH/12 )) $(( HEIGHT/2 ))"
		xte 'mouseclick 1'
# ╔════════╦════════╗ # ╔════════╦════════╗
# ║––+––+––┃        ║ # ║––+––+––┃––+––+––║
# ║        ┃        ║ # ║        ┃        ║
# ║        ┃   ⋅    ║ # ║        ┃        ║
# ║        ┃        ║ # ║        ┃--+--+  ║ ← tmux panes
# ╠━━━━━━━━╋━━━━━━━━╣ # ╠━━━━━━━━╋━━━━━━━━╣
# ║        ┃––+––+––║ # ║        ┃––+––+––║
# ║        ┃        ║ # ║        ┃        ║
# ╚════════╩════════╝ # ╚════════╩════════╝
		# This is for calling via hotkey in ~/.i3/config to test without
		#   restarting WM.
		[ "$1" = stop_after_main_workspace ] && {
			pointer_control enable
			exit 0
		}

		# Oh, fine, we can just run emacsclient with no argument to -a option
		#   and it will start emacs daemon and will connect to it.
		# But if daemon runs from here, it will fail after X restart ;_;
		# Crapissimo: neither -a, nor -a '', -a "", -a $'\000' do not work.
		#  "emacsclient --alternate-editor= -c -display $DISPLAY")
		startup_apps=(firefox pidgin)
		# ↖ These apps are to be killed gracefully by ~/.i3/on_quit.sh
		;;
esac
pointer_control enable


# Some configs decrypted at ~/bin/run_app.sh
for app in "${startup_apps[@]}" mpd thunar geeqie gimp redshift; do

	# Switch to its workspace to take off urgency hint
#	workspace="`sed -nr "s/^bindcode.*exec.*i3-msg\s+workspace\s+([0-9]*:?\S+)\s+.*pgrep\s+-u\s+\\\\\\$UID\s+$app.*\\\$/\1/p" ~/.i3/config`"

	# { … & } becasue otherwise ‘&’ will fork to background the whole string
	#   including subshell created by the left part of ‘||’ statement.
	# (nohup $app) actuallyy needed only for emacs as daemon
	# Preventing apps that persist between sessions to be runned again
	pgrep -u $UID -f "^$app\>" >/dev/null || { (nohup $app) & }
done

until mpc &>/dev/null; do  sleep 1;  done
pgrep -xu $UID mpdscribble || mpdscribble
pgrep -xu $UID ncmpcpp >/dev/null || urxvtc -name ncmpcpp -e ncmpcpp

crontab -l | grep -qF 'wallpaper_setter.sh' || {
	echo '*/10 * * * * ~/scripts/wallpaper_setter.sh -qn' \
		>/var/spool/cron/crontabs/$ME \
		|| notify-send -t 4000 "${0##*/}" "Couldn’t set crontab file."
}
 

x

.i3_gen_json_for_i3bar.sh(raw, dl)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#!/usr/bin/env bash

# generate-text-for-i3bar.sh
# A replacement for i3status written in bash.

# Shebang here is just for you to check the JSON output for syntax errors,
#   not for running as executable in your i3 config,
#   where it must be _sourced_ from.

[ "${ENV_DEBUG/*g*/}" ] || exec 2>/tmp/envlogs/gentext4i3bar

# Colors for output
red='#ee1010'
yellow='#edd400'
green='#8ae234'
white='#ffffff'
orange='#e07a1f'
brown='#b16161'
blue='#729fcf'
timeout_step=0 # counts seconds till timeout_max
timeout_max=30 # the actual timeout is one second; timeout_max introduces
               # a period functions may rely on; functions have their own
               # local timeouts, “wait_time” variable.
separator_char='·'  # U+00B7 https://en.wikipedia.org/wiki/Interpunct

# module settings
active_window_name_max_length=50

# Decrypt Gmail authentication data
eval `gpg -qd ~/.env/private_data.sh.gpg 2>/dev/null \
      | grep -E '^GMAIL_(USERNAME|PASSWORD)'`

# Tabulation and spaces in output of the script are just to have a nice view
#   while testing this script in a terminal and are not neccesary.

# 1. Let’s call each element of the status bar ‘a block’.
# 2. Then each block is consisted of a variable which will contain related JSON
#    stuff and a function generating that JSON. Functions are named after
#    the variables, but have ‘get_’ prefix.
# 3. The ‘blocks’ array defines the list of blocks which will be used to compile
#    the bar string; index number defines the priority of each block, i.e. will
#    it appear first and on the left (lower index) or last and on the right
#    (highest index).
# 4. What is actually shown on the bar is defined by the $bar variable, which
#    contains a string of _variable names_, in other words, block names. This
#    string evaluates at runtime each time after all functions in func_list
#    are done.
blocks=(
	# [0]=test [1]=separator
	[10]=active_window_name

	# indicators block
	[20]=mpd_state
	[30]=speakers_state
	[31]=mic_state
	[40]=internet_status
	[50]=gmail

	[59]=cond_separator_1 # conditional separator
	[60]=nice_date
)

case $HOSTNAME in
	fanetbook)
		blocks[54]=xkb_layout
		blocks[59]=battery_status
		;;
	home)
		blocks[15]=free_space
		blocks[16]=separator
		blocks[55]=schedule
		;;
esac

unset func_list
# $bar is to be eval’ed to output
bar='${comma:-}\n\t[' # Since comma isn’t set for the first time, its line will be empty
for block in ${blocks[@]}; do
	func_list+=" get_$block"
	bar+='\n\t${'$block':-}'
done
bar+="\n\t]"


# Some functions may generate empty line if no indicator needed.

# DESCRIPTION:
#     Block for testing purposes.
get_test() {
	# https://developer.gnome.org/pango/stable/PangoMarkupFormat.html
	test='{ "full_text": "<span foreground=\"blue\" bgcolor=\"#efefef\" size=\"x-large\">Blue text</span> is <i>cool</i>!",
\t  "align": "right",
\t  "markup": "pango",
\t  "separator": false },'
}

# DESCRIPTION:
#     The problem with i3bar separator is, if a separator symbol is set
#       in the bar section of i3 config, it WILL take space on the bar,
#       even if "separator":"false" is passed through json.
get_separator() {
	separator='{ "full_text": "'$separator_char'",
\t  "separator": false },'
}

# DESCRIPTION:
#     This separator is conditional and appears only when there is at least
#       one indicator shown (no indicators may be present and that’s a taihen)
#     The logic is each block of the same group sets variable like
#       set_cond_separator_N, where N is common for all blocks within a group.
#       Function as this checks that variable and prints conditional separator
get_cond_separator_1() {
	unset cond_separator_1
	[ -v set_cond_separator_1 ] \
		&& cond_separator_1='{ "full_text": "'$separator_char'",
\t  "separator": false },'
}

# NOTE:
#     Despite the fact it may seem useless to have, because all the important
#       info you should be able to output in the window itself (also window
#       titles while stacked/tabbed), and on small screens there may be
#       not enough space for the title, but it’s here
#         - just for it to be if it accidentally become needed;
#         - if window lags and its output is grey screen or copy of what was
#           on the previous workspace, this window title is the only way you
#           can tell what actually this window is and where is belongs to.
get_active_window_name() {
	id=`xprop -root | sed -nr 's/^_NET_ACTIVE_WINDOW.*# (.*)$/\1/p'`
	local title=`xprop -id "$id" | sed -nr 's/\\\//g;s/^WM_NAME[^"]+"([^"]+)".*/\1/p'` \
		u_open u_close
	[ ${#title} -gt $active_window_name_max_length ] && {
		## sed is expensive
		title=`echo "$title" | sed -r "s/^(.{1,$active_window_name_max_length})\b.*/\1…/"`
		## bash is not, but treats words with less care
		# title=${title:0:$max_length}
	}
	# to underline window titles that have spaces
	# [ "${title//* */}" ] || { u_open='<u>'; u_close='</u>'; }
	active_window_name='{ "full_text": "'"$u_open$title$u_close${title:+ $separator_char}"'",
\t  "align": "right",
\t  "markup": "pango",
\t  "separator": false },'
}

get_xkb_layout() {
	# When compiling my own xkb map via xkbcomp, I used the layout I made
	#   with setxkbmap where Scroll Lock indicator was used to indicate
	#   the current layout. But there’s no indicator on the tiny keyboard
	#   I’ve bought recently, so this function is to substitute this lack.
	#   Oh there was also a specific tool to print the current layout,
	#   https://github.com/ierton/xkb-switch I dunno how reliable it is,
	#   and since it’s not in repositories, I rather use xset.
	local scroll_lock=`xset -q | sed -nr 's/.*Scroll Lock:\s+(\S+)\s*$/\1/p'`
	[ "$scroll_lock" = on ] \
		&& local scroll_lock=RUS \
		|| local scroll_lock=ENG
#\t  "color": "#00ff00",
	xkb_layout='{ "full_text": "'"$scroll_lock"'",
\t  "align": "right",
\t  "separator": false },'
	set_cond_separaor_1=t
}

get_free_space() {
	local wait_time=10 color_tag inner_separator
	[ $timeout_step -eq 0 -o $((timeout_step % wait_time)) -eq 0 ] && {
		mountpoints='/home / /usr'
		yellow_point='5'
		red_point='1'
		unset free_space
		for mountpoint in $mountpoints; do
		# We look for an existed mount point which is in use and not bound.
			sed -nr "s~^\S+\s+$mountpoint\s+\S+\s+(\S+)\s.*~\1~p" \
				/proc/mounts | grep -qv bind \
			&& local present_mpoints[${#present_mpoints[@]}]="$mountpoint"
		done
		[ -v present_mpoints ] && for ((i=0; i<${#present_mpoints[@]}; i++)); do
			[ $i -lt $((${#present_mpoints[@]}-1)) ] \
				&& local inner_separator=" $_not_used_until_they_fix_the_bug_separator_char " \
				|| unset inner_separator # This comma appears between blocks
			                              #   showing mountpoints.
			read total free <<< `df -BG -P "${present_mpoints[$i]}" |\
			  sed -rn '$ s/^\S+\s+([0-9]+)G\s+\S+\s+([0-9]+)G.*$/\1\n\2/p'`
			unset color_tag
			if [ $free -le $red_point ]; then
				color_tag='<span fgcolor=\"'$red'\">'
			elif [ $free -le $yellow_point ]; then
				color_tag='<span fgcolor=\"'$yellow'\">'
			fi
			# extra space for the last iteration
			# $separator_char isn’t used here in favour of {separator} block
			#   because of the middle line shifted by the subscript tag.
			[ $((i+1)) -eq ${#present_mpoints[@]} ] && inner_separator+=' '
			free_space="${free_space:-}${inner_comma:-}
\t{ \"full_text\": \"${color_tag:-}${present_mpoints[$i]}:$free${color_tag:+</span>}/<sub>$total</sub>$inner_separator\",
\t  \"separator\":false,
\t  \"separator_block_width\":0,
\t  \"markup\": \"pango\" }"

			local inner_comma=',' # This comma is a part of json and divides
			                      #   {blocks} of code.
		done
		[ "$free_space" ] && free_space="$free_space," # buuug >_< $inner_comma isn’t appended to the last block
	}
}


get_mpd_state() {
	unset mpd_caught_playing mpd_state
	mpc |& sed '2s/playing//;T;Q1' &>/dev/null || {
		mpd_caught_playing=t # this uses in get_gmail
		mpd_state='{ "full_text": "♬",\n\t  "separator": false },'
		set_cond_separator_1=t
	}
}

get_speakers_state() {
	unset speakers_state
	amixer get 'Master',0 |& sed '$s/on]$/&/;T;Q1' &>/dev/null && {
		speakers_state="{ \"full_text\": \"⊀\",
\t  \"color\": \"$red\",
\t  \"separator\": false },"
		set_cond_separaor_1=t
	}
}

get_mic_state() {
	unset mic_state
	amixer get 'Capture',0 |& sed '$s/on]$/&/;T;Q1' &>/dev/null && {
		mic_state="{ \"full_text\": \"⍉\",
\t  \"color\": \"$red\",
\t  \"separator\": false },"
		set_cond_separaor_1=t
	}
}

get_battery_status() {
	local wait_time=30
	[ $timeout_step -eq 0 -o $((timeout_step % wait_time)) -eq 0 ] && {
		unset battery_status journal debug blocks offset next_block \
		      bat_time_left bat_ejected
		[ -e /sys/class/power_supply/ADP1/online ] && {
			# We have adapter, and probably, battery.
			if [ -e /sys/class/power_supply/BAT1/status ]; then
				# Yes, battery is present too.
				pushd /sys/class/power_supply &>/dev/null
				[ -v battery_initial_data_prepared ] || {
					# Maximum charge available after the last calibration
					charge_full=$(< BAT1/charge_full)
					# Maximum charge as it was designed
					charge_full_design=$(< BAT1/charge_full_design)
					# When charging, this shows how much
					charge_now=$(< BAT1/charge_now)
					# Strange values, used only for journal
					## current_now=$(< BAT1/current_now)

					steps_per_block=' ░▒▓█'
					blocks_count=5
					levels_count=$(( ${#steps_per_block} * $blocks_count ))
					total_hours_by_design="6"
					battery_initial_data_prepared=t
				}
				# When charging, this shows how much
				charge_now=$(< BAT1/charge_now)
				# Battery status by kernel
				bat_status=$(< BAT1/status)
				# Is external power supply plugged?
				adp_online=$(< ADP1/online)
				popd &>/dev/null

				battery_lifetime=`echo "scale=2;
                                  $total_hours_by_design*$charge_now\
				                  /$charge_full_design" | bc`
				bat_lt_hours=${battery_lifetime%.*}
				[ ${#bat_lt_hours} -ne 0 ] && \
					bat_lt_hours="${bat_lt_hours}h " || unset bat_lt_hours
				bat_lt_minutes=`echo "scale=0; ${battery_lifetime#*.}*3/5" | bc`
				[ ${#bat_lt_minutes} -ne 0 ] && \
					bat_lt_minutes="${bat_lt_minutes}m"
				bat_time_left=" ${bat_lt_hours:-}${bat_lt_minutes:-}"
# W!
# Write a journal of battery charge level till it’s completely discharged.
# Be sure _the filesystem_ you save journal on _is protected_ from power loss,
#   e.g. has "data=journal,barrier=1" among mount opts for ext3/4, otherwise
#   all discharging will be in vain.
				# journal=/battery_journal.csv
				level=$(( $charge_now * $levels_count / $charge_full ))
				full_blocks=$(( $level / $blocks_count ))
				[ $full_blocks -lt $blocks_count ] && {
					if [ $level -eq 0 ]; then
						offset=$level
					else
						offset=$(( $level - $full_blocks * $blocks_count - 1 ))
					fi
					next_block=${steps_per_block:$offset:1}
				}

				for ((i=0; i<$full_blocks; i++)); do
					blocks="$blocks${steps_per_block:4:1}"
				done
				[ -v next_block ] && blocks="$blocks$next_block"
				while [ ${#blocks} -lt $blocks_count ]; do
					blocks="$blocks${steps_per_block:0:1}"
				done

				if [ $adp_online -eq 1 ]; then
					color=$green
				elif [ $level -ge 5 ]; then
					color=$white
				elif [ $level -gt 1 ]; then
					color=$orange
				else
					# Battery is about to be discharged completely → 0
					# (but still can work for 30 min in idle for me)
					color=$red
					# Throw a message about shutdown and try to perform it.
					$(Xdialog --timeout 5 \
						--ok-label Shutdown --cancel-label 'NO, WAIT!' \
						--yesno 'Battery level is low.\nIt’s time to shutdown soon.' 370x100)
					[ $charge_now -eq 0 -a $? -eq 0 ] && {
						shutdown &>/dev/null || { # ~/bin/shutdown
							Xdialog --msgbox 'Shutdown returned with an error.\nYou have to do it manually!' 330x100
							# If the script cannot call shutdown itself,
							#   it must at least try to save the energy
							#   going to sleep for 20 minutes (by that time
							#   the battery will be probably exhausted).
							sleep 1200
						}
					}
				fi
				# [ -v journal ] && \
				# echo "`date +%s`;$charge_now;$current_now;$level" >> $journal
			else
				blocks='EJECTED'
				color=$red
			fi
		} || {
			blocks='NO POWER_SUPPLY CLASS FOUND'
			color=$red
		}
		battery_status="{ \"full_text\": \"┫$blocks┣${bat_time_left:-}\",
\t  \"color\":\"$color\",
\t  \"separator\":false },"
	}
	set_cond_separaor_1=t
}

get_internet_status() {
	local wait_time=5
	[ $timeout_step -eq 0 -o $((timeout_step % wait_time)) -eq 0 ] && {
		unset has_internets
		[ -p /dev/fd/$pingout ] && {
			grep -q ' 0% packet loss' </dev/fd/$pingout \
				&& has_internets=t && {
				internet_status='{ "full_text": "",
\t  "separator":false },'
				# set_cond_separaor_1=t
			}||{
				internet_status='{ "full_text": "∿",
\t  "color": "'$red'",
\t  "separator":false },'
				set_cond_separaor_1=t
			}
			exec {pingout}<&-
		}
		[ -v COPROC ] || {
			# wait_time can be here 2×, 3× timeouts or more.
			coproc ping -W $wait_time -q -n -c1 8.8.4.4
			# <& duplicates input file descriptors,
			# >& duplicates output file descriptors, They both work here.
			# {braces} are important.
			exec {pingout}<&${COPROC[0]}
		}
	}
}

get_gmail() {
	local wait_time=5
	[ $timeout_step -eq 0 -o $((timeout_step % wait_time)) -eq 0 ] && {
		unset gmail
		if [ -v has_internets ]; then
			gmail_server_reply=`curl --connect-timeout $wait_time \
			-su $GMAIL_USERNAME:$GMAIL_PASSWORD \
		    https://mail.google.com/mail/feed/atom 2>/dev/null`
			[ "$gmail_server_reply" ] || {
				# Unable to connect to mail.google.com
				gmail='{ "full_text": "U✉",
\t  "color": "'$orange'",
\t  "separator":false },'
				set_cond_separaor_1=t
				return 1
			}
			sed -r 's~^<H2>Error [0-9]{3}</H2>$~&~;T;Q1' \
				&>/dev/null <<<"$gmail_server_reply" || {
				# Server reported invalid user data or other fault.
				gmail='{ "full_text": "E✉",
\t  "color": "'$red'",
\t  "separator":false },'
				set_cond_separaor_1=t
				return 1
			}
			letters_unread=`sed -nr 's/.*<fullcount>([0-9]+)<.*/\1/p' \
			                <<<"$gmail_server_reply"`
			[ "$letters_unread" -gt 0 ] && {
				# Yay, a new letter!
				gmail='{ "full_text": "'$letters_unread'",
\t  "color": "'$green'",
\t  "separator":false,
\t  "separator_block_width":0 },
\t{ "full_text": "✉",
\t  "color": "'$green'",
\t  "separator":false },'
				set_cond_separaor_1=t
			}
			[ "$letters_unread" -gt ${old_letters_unread:-0} ] && {
				[ -v mpd_caught_playing ] && mpc pause >/dev/null
				aplay ~/.env/Tutturuu_v2.wav           >/dev/null
				[ -v mpd_caught_playing ] && mpc play  >/dev/null
			}
			old_letters_unread=$letters_unread
		fi
	}
}

get_schedule() {
	local wait_time=30
	[ $timeout_step -eq 0 -o $((timeout_step % wait_time)) -eq 0 ] && {
		unset schedule
		# Error: Received EOF from statusline process
		# read dayofweek dayofmonth hour < <(date "+%A %d %H")
		local date_t=`date "+%A %-d %-H"`
		local dayofweek=${date_t%% *}
		local dayofmonth_t=${date_t#* }
		local dayofmonth=${dayofmonth_t% *}
		local hour=${date_t##* }
		case "$dayofweek" in
			# If ~/watered hasn’t been `touch`ed within 1/2/3 days…
			Понедельник|Четверг)
				[ "`find $HOME/ -maxdepth 1 -name watered -mtime -1 2>/dev/null`" ] \
					|| schedule='{ "full_text": "✼",
\t  "color": "'$green'",
\t  "separator": false },'
				;;
			Вторник|Пятница)
				[ "`find ~/ -maxdepth 1 -name watered -mtime -2 2>/dev/null`" ] \
					|| schedule='{ "full_text": "✼",
\t  "color": "'$yellow'",
\t  "separator": false },'
				;;
			Среда|Суббота)
				[ "`find ~/ -maxdepth 1 -name watered -mtime -3 2>/dev/null`" ] \
					|| schedule='{ "full_text": "✼",
\t  "color": "'$brown'",
\t  "separator": false },'
				;;
		esac
		[[ "$dayofmonth" =~ ^[0-9]+$ ]] && [ $dayofmonth -ge 15 ] \
			&& [ -z "`find ~/ -maxdepth 1 -name sent -mtime -$((dayofmonth-14)) 2>/dev/null`" ] \
			&& schedule="${schedule:+${schedule}\n}"'{ "full_text": "♒",
\t  "color": "'$blue'",
\t  "separator": false },'
	}
	[ "$schedule" ] && set_cond_separaor_1=t
}

get_nice_date() {
	# This is to fix declensional endings of months’ names in russian locale.
	local wait_time=10
	[ $timeout_step -eq 0 -o $((timeout_step % wait_time)) -eq 0 ] && {
		# Why %b is “июня”, but “июл”? >_>
		# nice_date=`date +'%A, %-d %b %-H:%M'`
		nice_date=`date +'%A, %-d =%-m= %-H:%M' \
	         | sed 's/=1=/января/;   s/=2=/февраля/;
	                s/=3=/марта/;    s/=4=/апреля/;
	                s/=5=/мая/;      s/=6=/июня/;
	                s/=7=/июля/;     s/=8=/августа/;
	                s/=9=/сентября/; s/=10=/октября/;
	                s/=11=/ноября/;  s/=12=/декабря/'`
		nice_date='{ "full_text": "'$nice_date'",
\t "markup": "pango",
\t "urgent": "true" }'
	}
}

# http://i3wm.org/docs/i3bar-protocol.html
echo '{"version":1}[' && while true; do
	for func in $func_list; do
		$func
	done
	eval echo -e \"${bar//\\/\\\\}\" || exit 3
	comma=','
	unset ${!set_cond_separator_*}
	sleep 1;
	[ $((++timeout_step)) -gt $timeout_max ] && timeout_step=1
done
 

x

Notes

All terminals opened automatically at login time.
Custom bar is generated with https://github.com/deterenkelt/dotfiles/blob/master/.i3/generate_json_for_i3bar.sh and includes indicators for
- mpd (if playing)
- Gmail icon with number of unread letters. Icon appears with a sound stop pauses mpd.
- disabled ALSA master output.
- disabled ALSA mic input (it’s handy to switch the mic via ALSA and not think about whether I pressed correct hotkey in pidgin/mumble/skype/teamviewer — one thing to do it, dammit!)
- laptop battery status with 25 states of charge and separate states when it’s not plugged and fully charged.
- active window name.
- space left on the drives.
- and of course, time.

Visit https://github.com/deterenkelt/dotfiles/tree/master/.i3 for more info.

  • * - * - * -

The app in the left terminal is watch.sh https://github.com/deterenkelt/watchsh