| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  | #!/bin/bash | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Global readonly variables can't be shadowed by local variables so wrap | 
					
						
							|  |  |  | # our code in a function so we can declare all variables local | 
					
						
							|  |  |  | main() { | 
					
						
							|  |  |  |   # Customizable configuration constants | 
					
						
							|  |  |  |   local -r DEFAULT_MOD_LIST='cpu mem bl vol-amixer bat dt' | 
					
						
							|  |  |  |   local -r DEFAULT_PRE=' ' | 
					
						
							|  |  |  |   local -r DEFAULT_SEP_L='| ' | 
					
						
							|  |  |  |   local -r DEFAULT_SEP_R=' ' | 
					
						
							|  |  |  |   local -r DEFAULT_SUF=' ' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 21:58:52 -05:00
										 |  |  |   local -r mod_list="${1-${DEFAULT_MOD_LIST}}" | 
					
						
							| 
									
										
										
										
											2020-12-29 15:56:54 -05:00
										 |  |  |   local -r pre="${2-${DEFAULT_PRE}}" | 
					
						
							|  |  |  |   local -r sep_l="${3-${DEFAULT_SEP_L}}" | 
					
						
							|  |  |  |   local -r sep_r="${4-${DEFAULT_SEP_R}}" | 
					
						
							|  |  |  |   local -r suf="${5-${DEFAULT_SUF}}" | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   local -r MOD_DIR="$(dirname "$0")"/module | 
					
						
							|  |  |  |   local -r ACTION_DIR=/tmp/xrsb-action | 
					
						
							|  |  |  |   local -i ACTION_DIR_LEN=${#ACTION_DIR} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Cache module values so we can reuse them without recomputing them | 
					
						
							|  |  |  |   local -A stat_cache | 
					
						
							| 
									
										
										
										
											2020-12-28 22:04:18 -05:00
										 |  |  |   # Since stat_cache is hash ordered, maintain the display order (as defined | 
					
						
							|  |  |  |   # by mod_list) of the keys so we can loop over the cache in display order | 
					
						
							|  |  |  |   # when generating the full status | 
					
						
							| 
									
										
										
										
											2020-12-29 14:19:54 -05:00
										 |  |  |   local -a stat_cache_ordered_mods mods | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |   local mod mod_file | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |   # Map the module file name to the module function | 
					
						
							|  |  |  |   mod_to_fn() { | 
					
						
							|  |  |  |     printf 'mod_%s' "${1//-/_}" | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # For each module in the list, if the module file exists then source it, add | 
					
						
							|  |  |  |   # its name to the ordered array, and call its function and cache the value | 
					
						
							| 
									
										
										
										
											2020-12-29 14:19:54 -05:00
										 |  |  |   IFS=', ' read -r -a mods <<< "${mod_list}" | 
					
						
							|  |  |  |   for mod in ${mods[@]}; do | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |     mod_file="${MOD_DIR}/${mod}" | 
					
						
							|  |  |  |     if [[ -r "${mod_file}" ]]; then | 
					
						
							| 
									
										
										
										
											2020-12-28 20:17:51 -05:00
										 |  |  |       # shellcheck source=/dev/null | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |       source "${mod_file}" | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |       stat_cache_ordered_mods+=("${mod}") | 
					
						
							|  |  |  |       stat_cache["${mod}"]="$("$(mod_to_fn "${mod}")")" | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |     fi | 
					
						
							|  |  |  |   done | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |   # Construct and display the status by looping over the cached values in  order | 
					
						
							|  |  |  |   draw_status() { | 
					
						
							|  |  |  |     local mod stat | 
					
						
							|  |  |  |     for mod in "${stat_cache_ordered_mods[@]}"; do | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |       printf -v stat '%b%b%b%b' \ | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |         "${stat}" "${sep_l}" "${stat_cache[${mod}]}" "${sep_r}" | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |     done | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Trim the leading left separator and trailing right separator, and | 
					
						
							|  |  |  |     # display the status | 
					
						
							|  |  |  |     local -ri offset=${#sep_l} | 
					
						
							|  |  |  |     local -ri len=$((${#stat} - offset - ${#sep_r})) | 
					
						
							|  |  |  |     xsetroot -name "${pre}${stat:${offset}:${len}}${suf}" | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Draw the initial status | 
					
						
							|  |  |  |   draw_status | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |   # For each file in the action directory, remove the file, and if a module for | 
					
						
							|  |  |  |   # the action is cached, call the module function and update the cache. If | 
					
						
							|  |  |  |   # any cache entries were updated, redraw the status. | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |   process_signal () { | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |     local -a action_paths | 
					
						
							|  |  |  |     local action_path mod is_changed | 
					
						
							|  |  |  |     readarray -d '' action_paths< \ | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |       <(find "${ACTION_DIR}" -maxdepth 1 -type f -exec rm -f {} + -print0) | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |     for action_path in "${action_paths[@]}"; do | 
					
						
							|  |  |  |       mod="${action_path:$((ACTION_DIR_LEN + 1))}" | 
					
						
							|  |  |  |       if [[ -v stat_cache[${mod}] ]]; then | 
					
						
							|  |  |  |         stat_cache["${mod}"]="$("$(mod_to_fn "${mod}")")" | 
					
						
							|  |  |  |         is_changed=1 | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |       fi | 
					
						
							|  |  |  |     done | 
					
						
							| 
									
										
										
										
											2020-12-29 11:13:34 -05:00
										 |  |  |     if [[ -v is_changed ]]; then draw_status; fi | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-29 15:56:54 -05:00
										 |  |  |   # Begin trapping signals | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |   mkdir -p "${ACTION_DIR}" | 
					
						
							|  |  |  |   trap process_signal SIGUSR1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-29 15:56:54 -05:00
										 |  |  |   # Wait for signals efficiently. In a loop begin a long-running sleep command | 
					
						
							|  |  |  |   # in the background, then wait on it. If we trap a signal before the wait | 
					
						
							|  |  |  |   # is over and sleep is still running, trap will call process_signal, then | 
					
						
							|  |  |  |   # code execution will resume at the line after the wait statement. So on | 
					
						
							|  |  |  |   # that line we kill the (probably) still running sleep command so they | 
					
						
							|  |  |  |   # don't pile up, and loop to sleep and wait for the next signal. If we | 
					
						
							|  |  |  |   # don't trap a signal during the long running sleep, then the wait ends, | 
					
						
							|  |  |  |   # we try to kill the sleep command that has already exited, so it doesn't | 
					
						
							|  |  |  |   # matter, and loop to sleep and wait again. Note that we don't make the | 
					
						
							|  |  |  |   # sleep too long because if the daemon is killed, the sleep will become | 
					
						
							|  |  |  |   # an orphaned process until the sleep period elapses. | 
					
						
							|  |  |  |   local -i sleep_pid | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |   while :; do | 
					
						
							| 
									
										
										
										
											2020-12-29 15:56:54 -05:00
										 |  |  |     sleep 30m & | 
					
						
							|  |  |  |     sleep_pid="$!" | 
					
						
							|  |  |  |     wait "${sleep_pid}" | 
					
						
							|  |  |  |     kill "${sleep_pid}" 2>/dev/null | 
					
						
							| 
									
										
										
										
											2020-12-28 20:02:32 -05:00
										 |  |  |   done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | main "$@" | 
					
						
							|  |  |  | 
 |