#!/bin/bash # Desc: create a message window with xterm # Usage: xterm-notification-widow [OPTS] MESSAGE # Opts: -c|-columns NUM Number of columns in window # -l|-lines NUM Number of lines in window # -x|-xpos NUM X position at which to place window # -y|-ypos NUM Y position at which to place window # -t|timeout NUM Set timeout length for window expiration # -fg|-foreground #HEX Foreground color # -bg|-background #HEX Background color # -s|-style OPT Window style, use '-s help' for list # -so|-styleopts OPT Window style opts, use '-so help' for list # Example: xterm-notification-window -c 30 -l 7 -x 120 -y 180 -t 2 -s 2 BEEP! # Uses alternate character set for box drawing. # For more info see: # https://www.in-ulm.de/~mascheck/various/alternate_charset/ # https://invisible-island.net/xterm/ctlseqs/ctlseqs.html # Alternate Character Set (ACS) info: # ◆ ≠ £ π ; : , . ▒ ␉ ␌ ␍ ␊ ° ± ␤ ┘ ┐ ┌ └ ┼ ⎺ ⎻ ─ ⎼ ⎽ ├ ┤ ┴ ┬ │ ≤ ≥ # ` | } { ; : , . a b c d e f g h j k l m n o p q r s t u v w x y z # DIAMOND:◆:` NEQUAL:≠:| STERLING:£} PI:π:{ # LARROW:,:, DARROW:.:. CHECKER:a:▒ # HORZTAB:␉:b FORMFEED:␌ CARRET:␍:d LINEFEED:␊:e # DEGREE:°:f PLMINUS:±:g NEWLINE:␤:h # LRCORNER:┘:j URCONER:┐:k ULCORNER:┌:l LLCORNER:└:m PLUS:n:┼ # S1:⎺:o S2:⎻:p S3:─:q S4⎼:-:r S5:⎽:s # LTREE:├:t RTREE:┤:u BTREE:┴:v TTREE:┬:w VLINE:│:x # LEQUAL:≤:y GEQUAL:≥:z ### BEGIN ### # /* FUNC DEF*/ -------------------------------------------------------------- msg(){ printf -- "%s\n" "$@"; } emsg(){ printf -- "%s\n" "$@" >&2 ; } usage(){ awk -F '# ' 'NR>2{print $2};$0==""{exit}' <"$0"; } bail(){ emsg "$@"; usage; exit 1; } slide(){ eval "set -- \$$# $*"; printf -- "%s" "$@"; } columnate(){ # desc: print string $3 at $2 col center padded to $1 # usage: columnate padsz width data declare pad padsz width data [[ ! -z "$3" ]] && padsz="$1" width="$2" && shift 2 || exit 1 pad="$(for ((i=0;i~/xtr.tst horz(){ eval printf $'\x1b\(0%c' "$h{1..${col}"\}; } vert(){ eval printf $'\x1b\(0\x1b[D%c\x1b[B' "$v{1..${lin}"\}; } unionvert(){ [[ "${FUNCNAME[-1]}" == "lvert" ]] \ && eval printf -- $'\x1b\(0\x1b[D\x1b[1K%c\x1b[B' "$1{1..$2"\} \ || eval printf -- $'\x1b\(0\x1b[D%c\x1b[B' "$1{1..$2"\} } lvert(){ unionvert "$v" "$lin"; } rvert(){ unionvert "$v" "$lin" "$col"; } ## ab -> idx = a*4 + b ## 0: up, 1: right, 2: down, 3: left ## 00 means going up , then going up -> ┃ ## 12 means going right, then going down -> ┓ #sets=( # "┃┏ ┓┛━┓ ┗┃┛┗ ┏━" # "│╭ ╮╯─╮ ╰│╯╰ ╭─" # "│┌ ┐┘─┐ └│┘└ ┌─" # "║╔ ╗╝═╗ ╚║╝╚ ╔═" # "|+ ++-+ +|++ +-" # "|/ \/-\ \|/\ /-" # ".. .... .... .." # ".o oo.o o.oo o." # "-\ /\|/ /-\/ \|" # railway # "╿┍ ┑┚╼┒ ┕╽┙┖ ┎╾" # knobby pipe # "|p qd-q b|db p-" # #echo -n "${sets[v[i]]:l[i]*4+n[i]:1}" # Set style. example "j${tl}" "${tr}m" in: #printf "\x1b[0;0H%s\r%s\x1b[${COLUMNS}C\b%s" "$(horz)" "j${tl}" "${tr}m" # top case "$opt" in 0) s=(' ' ' ' ' ' ' ') ;; 1) s=('*' '*' '*' '*') ;; 2) s=('j' 'm' 'l' 'k') ;; 3) s=('a' 'a' 'a' 'a') ;; # Use val? #*) s=("$style" "$style" "$style" "$style") ;; # Or as param? #opt=*) s=("${opt#*=}" "${opt#*=}" "${opt#*=}" "${opt#*=}") ;; # TODO: fill edges with ▒ instead of space #fuzz) eval printf $'\x1b\(0\x1b[D%1.1s\x1b[B' "$v{1..${lin}"\} ;; *) s=(' ' ' ' ' ' ' ') ;; esac # Do it the other way! print message, then walk the edge of the screen to draw box. printf -- "\x1b[?25l\x1b[2;3H%s" "$msg" # Set cursor to invis in addition to printing # Ordered as: top, right, left, bottom printf -- "\x1b[0;0H%s\r%s\x1b[${col}C\b%s" "$(horz)" "${s[0]}${tl}" "${tr}${s[1]}" printf -- "\x1b[2;${col}H%s%s\r%s" "$(rvert)" "$tr" "$br" printf -- "\x1b[2;3H%s%s\r%s" "$(lvert)" "$bl" "$tl" printf -- "\x1b[${lin};0H%s\b%s\r%s" "$(horz)" "${br}${s[2]}" "${s[3]}${bl}" } # /* ENV */ ------------------------------------------------------------------ declare -i columns lines xpos ypos declare message foreground background style declare -a styleopts # /* INIT */ ----------------------------------------------------------------- while (($#)); do case "$1" in --help) usage; exit 0 ;; -c|-columns) columns="$2" && shift 2;; -l|lines) lines="$2" && shift 2;; -x|-xpos) xpos="$2" && shift 2;; -y|-ypos) ypos="$2" && shift 2;; -t|-timeout) timeout="$2" && shift 2;; -bg|-background) background="$2" && shift 2;; -fg|-foreground) foreground="$2" && shift 2;; -s|-style) style="$2" && shift 2;; -so|-styleopt) styleopts+=("$2") && shift 2;; -*) bail "E!: invalid flag '$1'";; *) message="$*" && shift $# ;; esac done # Catch empty opts with sane defaults let columns="${columns:-80}" let lines="${lines:-24}" let xpos="${xpos:-16}" let ypos="${ypos:-16}" let timeout="${timeout:-3}" read -r message <<<"${message:-0}" read -r foreground <<<"${foreground:-#cb4b16}" read -r background <<<"${background:-#1a2229}" read -r style <<<"${style:-boxframe}" mapfile -t styleopts <<<"${styleopts[@]:-0}" # Bail if message is to long (( "${#message}" < (columns*lines) )) || bail "E!: message to long" # Hook to catch 'help' opt for style for opt in "${styleopts[@]}"; do [[ "$opt" == "help" ]] && eval "$style" --help && exit 0 done # Validate style choice and creat window function case "$style" in help) printf -- "styles: none boxframe\n"; exit 0;; nostyle) window(){ nostyle "${styleopts[@]}" "$columns" "$lines" "$message"; } ;; boxframe) window(){ boxframe "${styleopts[@]}" "$columns" "$lines" "$message"; } ;; *) bail "E!: invalid style" ;; esac # /* MAIN */ ----------------------------------------------------------------- /usr/bin/xterm \ -class "xterm-notification-window" \ -geometry "${columns}x${lines}+${xpos}+${ypos}" \ -xrm 'XTerm*.faceName: xft:Courier:style=bold' \ -xrm 'XTerm*.faceSize: 20' \ -xrm 'XTerm*.boldMode: true' \ -bg "$background" -fg "$foreground" -fn 10x20 -fs 2000 -cu -ah +sb -T ' ' \ -e "sleep 0.02s; printf -- \"%s\" \"$(window)\" ; sleep ${timeout}s; exit" #-bg "$background" -fg "$foreground" -fn 10x20 -fs 2000 -cu -ah +sb -T ' ' \ ### END ### #declare msg #msg="$@" # ## '-xrm "XTerm*.decTerminalID: vt340"' -- sixel support #/usr/bin/xterm -geometry 32x7+760+480 -bg black -fg red -ah +sb \ # -xrm "xterm*.faceName: xft:Courier:style=bold:size=20" \ # -xrm "xterm*.boldMode: true" \ # -xrm "xterm*.decTerminalID: VT340" \ # -e "printf -- \"%s\" \"$msg\"; read >/dev/null" # # #wait #exit #