From f4439fb9bb24edbb75437a31600dc5080207a1c3 Mon Sep 17 00:00:00 2001 From: Patrick Spek Date: Mon, 8 Mar 2021 13:00:29 +0100 Subject: Update hlwm config --- .config/herbstluftwm/autostart | 61 ++++++------ .config/herbstluftwm/panel-bot.sh | 84 +++++++++++++++++ .config/herbstluftwm/panel-top.sh | 188 +++++++++++++++++++++++++++++++++++++ .config/herbstluftwm/panel.sh | 189 -------------------------------------- 4 files changed, 300 insertions(+), 222 deletions(-) create mode 100755 .config/herbstluftwm/panel-bot.sh create mode 100755 .config/herbstluftwm/panel-top.sh delete mode 100755 .config/herbstluftwm/panel.sh (limited to '.config') diff --git a/.config/herbstluftwm/autostart b/.config/herbstluftwm/autostart index d59b4a3..69c6d40 100755 --- a/.config/herbstluftwm/autostart +++ b/.config/herbstluftwm/autostart @@ -8,37 +8,26 @@ hc() { hc emit_hook reload -xsetroot -solid '#5A8E3A' +xsetroot -solid '#cccccc' # remove all existing keybindings hc keyunbind --all # 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 Mod=Mod4 # Use the super key as the main modifier hc keybind $Mod-Shift-x quit -hc keybind $Mod-r reload -hc keybind $Mod-x close -#hc keybind $Mod-Return spawn "${TERMINAL:-xterm}" # use your $TERMINAL with xterm as fallback +hc keybind $Mod-r reload +hc keybind $Mod-x close # basic movement in tiling and floating mode # focusing clients -hc keybind $Mod-Left focus left -hc keybind $Mod-Down focus down -hc keybind $Mod-Up focus up -hc keybind $Mod-Right focus right hc keybind $Mod-h focus left hc keybind $Mod-j focus down hc keybind $Mod-k focus up hc keybind $Mod-l focus right # moving clients in tiling and floating mode -hc keybind $Mod-Shift-Left shift left -hc keybind $Mod-Shift-Down shift down -hc keybind $Mod-Shift-Up shift up -hc keybind $Mod-Shift-Right shift right hc keybind $Mod-Shift-h shift left hc keybind $Mod-Shift-j shift down hc keybind $Mod-Shift-k shift up @@ -46,8 +35,8 @@ hc keybind $Mod-Shift-l shift right # splitting frames # create an empty frame at the specified direction -hc keybind $Mod-\\ split bottom 0.5 -hc keybind $Mod-\| split right 0.5 +hc keybind $Mod-backslash split bottom 0.5 +hc keybind $Mod-Shift-backslash split right 0.5 # let the current frame explode into subframes hc keybind $Mod-Control-space split explode @@ -57,10 +46,6 @@ hc keybind $Mod-Control-h resize left +$resizestep hc keybind $Mod-Control-j resize down +$resizestep hc keybind $Mod-Control-k resize up +$resizestep hc keybind $Mod-Control-l resize right +$resizestep -hc keybind $Mod-Control-Left resize left +$resizestep -hc keybind $Mod-Control-Down resize down +$resizestep -hc keybind $Mod-Control-Up resize up +$resizestep -hc keybind $Mod-Control-Right resize right +$resizestep # tags tag_names=( work social web mail fun media vms 8 9 ) @@ -101,7 +86,8 @@ hc mousebind $Mod-Button2 zoom hc mousebind $Mod-Button3 resize # focus -hc keybind $Mod-BackSpace cycle_monitor +hc keybind $Mod-Control+j cycle_monitor -1 +hc keybind $Mod-Control+k cycle_monitor +1 hc keybind $Mod-Tab cycle_all +1 hc keybind $Mod-Shift-Tab cycle_all -1 hc keybind $Mod-c cycle @@ -113,18 +99,20 @@ hc attr theme.floating.reset 1 hc set frame_border_active_color '#3381DA' hc set frame_border_normal_color '#222222' hc set frame_bg_normal_color '#777777' -hc set frame_bg_active_color '#3381DA' +hc set frame_bg_active_color '#000000' hc set frame_border_width 1 hc set always_show_frame on -hc set frame_bg_transparent on -hc set frame_transparent_width 5 +hc set frame_bg_transparent 1 +hc set frame_normal_opacity 0 +hc set frame_focus_opacity 1 +#hc set frame_transparent_width 5 hc set frame_gap 4 -hc attr theme.active.color '#9fbc00' +hc attr theme.active.color '#3381DA' hc attr theme.normal.color '#454545' hc attr theme.urgent.color orange hc attr theme.inner_width 1 -hc attr theme.inner_color black +#hc attr theme.inner_color black hc attr theme.border_width 3 hc attr theme.floating.border_width 4 hc attr theme.floating.outer_width 1 @@ -133,7 +121,7 @@ hc attr theme.active.inner_color '#3E4A00' hc attr theme.active.outer_color '#3E4A00' hc attr theme.background_color '#141414' -hc set window_gap 0 +hc set window_gap 4 hc set frame_padding 0 hc set smart_window_surroundings off hc set smart_frame_surroundings on @@ -159,12 +147,19 @@ hc unlock # do multi monitor setup here, e.g.: # hc set_monitors 1280x1024+0+0 1280x1024+1280+0 # or simply: -# hc detect_monitors +hc detect_monitors + +# find the top panel +panel_top=~/.config/herbstluftwm/panel-top.sh +[ -x "$panel_top" ] || panel_top=/etc/xdg/herbstluftwm/panel.sh + +panel_bot=~/.config/herbstluftwm/panel-bot.sh -# find the panel -panel=~/.config/herbstluftwm/panel.sh -[ -x "$panel" ] || panel=/etc/xdg/herbstluftwm/panel.sh for monitor in $(hc list_monitors | cut -d: -f1) ; do - # start it on each monitor - "$panel" "$monitor" & + # Create space for the panels to exist + hc pad "$monitor" 21 0 21 0 + + # Start panels + "$panel_top" "$monitor" & + "$panel_bot" "$monitor" & done diff --git a/.config/herbstluftwm/panel-bot.sh b/.config/herbstluftwm/panel-bot.sh new file mode 100755 index 0000000..4a3bc18 --- /dev/null +++ b/.config/herbstluftwm/panel-bot.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ; } +quote() { local q="$(printf '%q ' "$@")"; printf '%s' "${q% }" ; } +uniq_linebuffered() { awk '$0 != l { print ; l=$0 ; fflush(); }' "$@"; } + +monitor=${1:-0} + +hc attr "monitors.$monitor" > /dev/null || { printf "Invalid monitor $monitor" && exit 1 ; } + +monitor_tag="$(herbstclient attr "monitors.$monitor.tag")" +monitor_offset_x=$(hc monitor_rect "$monitor" | awk '{print $1 }') +monitor_offset_y=$(hc monitor_rect "$monitor" | awk '{print $2 }') +monitor_width=$(hc monitor_rect "$monitor" | awk '{ print $3 }') +monitor_height=$(hc monitor_rect "$monitor" | awk '{ print $4 }') +panel_height=21 +panel_color_bg="$(hc get frame_border_normal_color)" +panel_color_fg="#efefef" +panel_color_focus="$(hc get frame_border_active_color)" +panel_font="Liberation Mono:size=9" +panel_offset_x=$(( monitor_offset_x )) +panel_offset_y=$(( monitor_offset_y + monitor_height - panel_height )) + +{ + hc --idle +} 2> /dev/null | { + while : + do + # Wait for an event + IFS=$'\t' read -ra event || break + + # Declare clients as an array + declare -a clients + + # Collect all clients on the monitor + for client in $(hc attr clients | grep '0x') + do + [[ "$(hc attr "clients.$client.tag")" != $monitor_tag ]] && continue + + clients+=("$client") + done + + name_offset_interval=$(( monitor_width / ${#clients[@]} )) + + # Look up current focus window + focus="$(hc attr clients.focus.winid)" + + # Loop through the clients to create a representation + index=0 + + for client in "${clients[@]}" + do + + if [[ "$client" == "$focus." ]] + then + color_fg="$panel_color_focus" + else + color_fg="$panel_color_fg" + fi + + name=" $(hc attr "clients.$client.title") " + name_width=$(xftwidth "$panel_font" "$name") + name_offset=$(( name_offset_interval * index )) + + printf "^pa(%s)^bg(%s)^fg(%s)^ca(1,%s)%s^ca()" \ + "$name_offset" \ + "$panel_color_bg" \ + "$color_fg" \ + "herbstclient jumpto '$client'" \ + "$name" + + index=$(( index + 1 )) + done + + # Add a newline + printf "\n" + + # Clean up some variables + unset clients + unset index + done +} | dzen2 -w "$monitor_width" -x "$panel_offset_x" -y "$panel_offset_y" -fn "$panel_font" -h "$panel_height" \ + -e "button3=;button4=exec:$hc_quoted use_index -1;button5=exec:$hc_quoted use_index +1" \ + -ta l -bg "$panel_color_bg" -fg "$panel_color_fg" diff --git a/.config/herbstluftwm/panel-top.sh b/.config/herbstluftwm/panel-top.sh new file mode 100755 index 0000000..536f674 --- /dev/null +++ b/.config/herbstluftwm/panel-top.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash + +quote() { + local q="$(printf '%q ' "$@")" + printf '%s' "${q% }" +} + +hc_quoted="$(quote "${herbstclient_command[@]:-herbstclient}")" +hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;} +monitor=${1:-0} +geometry=( $(hc monitor_rect "$monitor") ) +if [ -z "$geometry" ] ;then + echo "Invalid monitor $monitor" + exit 1 +fi +# geometry has the format W H X Y +x=${geometry[0]} +y=${geometry[1]} +panel_width=${geometry[2]} +panel_height=21 +font="Liberation Mono:size=9" +bgcolor=$(hc get frame_border_normal_color) +selbg=$(hc get window_border_active_color) +selfg='#101010' + +#### +# Try to find textwidth binary. +# In e.g. Ubuntu, this is named dzen2-textwidth. +if which xftwidth > /dev/null +then + textwidth=xftwidth +elif which textwidth > /dev/null +then + textwidth="textwidth"; +else + echo "This script requires the textwidth tool of the dzen2 project." + exit 1 +fi + +#### +# true if we are using the svn version of dzen2 +# depending on version/distribution, this seems to have version strings like +# "dzen-" or "dzen-x.x.x-svn" +if dzen2 -v 2>&1 | head -n 1 | grep -q '^dzen-\([^,]*-svn\|\),'; then + dzen2_svn="true" +else + dzen2_svn="" +fi + +if awk -Wv 2>/dev/null | head -1 | grep -q '^mawk'; then + # mawk needs "-W interactive" to line-buffer stdout correctly + # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593504 + uniq_linebuffered() { + awk -W interactive '$0 != l { print ; l=$0 ; fflush(); }' "$@" + } +else + # other awk versions (e.g. gawk) issue a warning with "-W interactive", so + # we don't want to use it there. + uniq_linebuffered() { + awk '$0 != l { print ; l=$0 ; fflush(); }' "$@" + } +fi + +{ + ### Event generator ### + # based on different input data (mpc, date, hlwm hooks, ...) this generates events, formed like this: + # \t [...] + # e.g. + # date ^fg(#efefef)18:33^fg(#909090), 2013-10-^fg(#efefef)29 + + #mpc idleloop player & + while true ; do + # "date" output is checked once a second, but an event is only + # generated if the output changed compared to the previous run. + date +$'date\t^fg(#efefef)%H:%M^fg(#909090), %Y-%m-^fg(#efefef)%d' + sleep 1 || break + done > >(uniq_linebuffered) & + childpid=$! + hc --idle + kill $childpid +} 2> /dev/null | { + IFS=$'\t' read -ra tags <<< "$(hc tag_status $monitor)" + visible=true + date="" + windowtitle="" + while true ; do + + ### Output ### + # This part prints dzen data based on the _previous_ data handling run, + # and then waits for the next event to happen. + + separator="^bg()^fg($selbg)|" + # draw tags + for i in "${tags[@]}" ; do + case ${i:0:1} in + '#') + echo -n "^bg($selbg)^fg($selfg)" + ;; + '+') + echo -n "^bg(#9CA668)^fg(#141414)" + ;; + ':') + echo -n "^bg()^fg(#ffffff)" + ;; + '!') + echo -n "^bg(#FF0675)^fg(#141414)" + ;; + *) + echo -n "^bg()^fg(#ababab)" + ;; + esac + if [ ! -z "$dzen2_svn" ] ; then + # clickable tags if using SVN dzen + echo -n "^ca(1,$hc_quoted focus_monitor \"$monitor\" && " + echo -n "$hc_quoted use \"${i:1}\") ${i:1} ^ca()" + else + # non-clickable tags if using older dzen + echo -n " ${i:1} " + fi + done + echo -n "$separator" + echo -n "^bg()^fg() ${windowtitle//^/^^}" + # small adjustments + right="$separator^bg() $date $separator" + right_text_only=$(echo -n "$right" | sed 's.\^[^(]*([^)]*)..g') + # get width of right aligned text.. and add some space.. + width=$($textwidth "$font" "$right_text_only ") + echo -n "^pa($(($panel_width - $width)))$right" + echo + + ### Data handling ### + # This part handles the events generated in the event loop, and sets + # internal variables based on them. The event and its arguments are + # read into the array cmd, then action is taken depending on the event + # name. + # "Special" events (quit_panel/togglehidepanel/reload) are also handled + # here. + + # wait for next event + IFS=$'\t' read -ra cmd || break + # find out event origin + case "${cmd[0]}" in + tag*) + #echo "resetting tags" >&2 + IFS=$'\t' read -ra tags <<< "$(hc tag_status $monitor)" + ;; + date) + #echo "resetting date" >&2 + date="${cmd[@]:1}" + ;; + quit_panel) + exit + ;; + togglehidepanel) + currentmonidx=$(hc list_monitors | sed -n '/\[FOCUS\]$/s/:.*//p') + if [ "${cmd[1]}" -ne "$monitor" ] ; then + continue + fi + if [ "${cmd[1]}" = "current" ] && [ "$currentmonidx" -ne "$monitor" ] ; then + continue + fi + echo "^togglehide()" + if $visible ; then + visible=false + hc pad $monitor 0 + else + visible=true + hc pad $monitor $panel_height + fi + ;; + reload) + exit + ;; + focus_changed|window_title_changed) + windowtitle="${cmd[@]:2}" + ;; + #player) + # ;; + esac + done + + ### dzen2 ### + # After the data is gathered and processed, the output of the previous block + # gets piped to dzen2. + +} | dzen2 -w $panel_width -x $x -y $y -fn "$font" -h $panel_height \ + -e "button3=;button4=exec:$hc_quoted use_index -1;button5=exec:$hc_quoted use_index +1" \ + -ta l -bg "$bgcolor" -fg '#efefef' diff --git a/.config/herbstluftwm/panel.sh b/.config/herbstluftwm/panel.sh deleted file mode 100755 index 5b1deb0..0000000 --- a/.config/herbstluftwm/panel.sh +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env bash - -quote() { - local q="$(printf '%q ' "$@")" - printf '%s' "${q% }" -} - -hc_quoted="$(quote "${herbstclient_command[@]:-herbstclient}")" -hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;} -monitor=${1:-0} -geometry=( $(hc monitor_rect "$monitor") ) -if [ -z "$geometry" ] ;then - echo "Invalid monitor $monitor" - exit 1 -fi -# geometry has the format W H X Y -x=${geometry[0]} -y=${geometry[1]} -panel_width=${geometry[2]} -panel_height=16 -font="-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*" -bgcolor=$(hc get frame_border_normal_color) -selbg=$(hc get window_border_active_color) -selfg='#101010' - -#### -# Try to find textwidth binary. -# In e.g. Ubuntu, this is named dzen2-textwidth. -if which textwidth &> /dev/null ; then - textwidth="textwidth"; -elif which dzen2-textwidth &> /dev/null ; then - textwidth="dzen2-textwidth"; -elif which xftwidth &> /dev/null ; then # For guix - textwidth="xtfwidth"; -else - echo "This script requires the textwidth tool of the dzen2 project." - exit 1 -fi -#### -# true if we are using the svn version of dzen2 -# depending on version/distribution, this seems to have version strings like -# "dzen-" or "dzen-x.x.x-svn" -if dzen2 -v 2>&1 | head -n 1 | grep -q '^dzen-\([^,]*-svn\|\),'; then - dzen2_svn="true" -else - dzen2_svn="" -fi - -if awk -Wv 2>/dev/null | head -1 | grep -q '^mawk'; then - # mawk needs "-W interactive" to line-buffer stdout correctly - # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593504 - uniq_linebuffered() { - awk -W interactive '$0 != l { print ; l=$0 ; fflush(); }' "$@" - } -else - # other awk versions (e.g. gawk) issue a warning with "-W interactive", so - # we don't want to use it there. - uniq_linebuffered() { - awk '$0 != l { print ; l=$0 ; fflush(); }' "$@" - } -fi - -hc pad $monitor $panel_height - -{ - ### Event generator ### - # based on different input data (mpc, date, hlwm hooks, ...) this generates events, formed like this: - # \t [...] - # e.g. - # date ^fg(#efefef)18:33^fg(#909090), 2013-10-^fg(#efefef)29 - - #mpc idleloop player & - while true ; do - # "date" output is checked once a second, but an event is only - # generated if the output changed compared to the previous run. - date +$'date\t^fg(#efefef)%H:%M^fg(#909090), %Y-%m-^fg(#efefef)%d' - sleep 1 || break - done > >(uniq_linebuffered) & - childpid=$! - hc --idle - kill $childpid -} 2> /dev/null | { - IFS=$'\t' read -ra tags <<< "$(hc tag_status $monitor)" - visible=true - date="" - windowtitle="" - while true ; do - - ### Output ### - # This part prints dzen data based on the _previous_ data handling run, - # and then waits for the next event to happen. - - separator="^bg()^fg($selbg)|" - # draw tags - for i in "${tags[@]}" ; do - case ${i:0:1} in - '#') - echo -n "^bg($selbg)^fg($selfg)" - ;; - '+') - echo -n "^bg(#9CA668)^fg(#141414)" - ;; - ':') - echo -n "^bg()^fg(#ffffff)" - ;; - '!') - echo -n "^bg(#FF0675)^fg(#141414)" - ;; - *) - echo -n "^bg()^fg(#ababab)" - ;; - esac - if [ ! -z "$dzen2_svn" ] ; then - # clickable tags if using SVN dzen - echo -n "^ca(1,$hc_quoted focus_monitor \"$monitor\" && " - echo -n "$hc_quoted use \"${i:1}\") ${i:1} ^ca()" - else - # non-clickable tags if using older dzen - echo -n " ${i:1} " - fi - done - echo -n "$separator" - echo -n "^bg()^fg() ${windowtitle//^/^^}" - # small adjustments - right="$separator^bg() $date $separator" - right_text_only=$(echo -n "$right" | sed 's.\^[^(]*([^)]*)..g') - # get width of right aligned text.. and add some space.. - width=$($textwidth "$font" "$right_text_only ") - echo -n "^pa($(($panel_width - $width)))$right" - echo - - ### Data handling ### - # This part handles the events generated in the event loop, and sets - # internal variables based on them. The event and its arguments are - # read into the array cmd, then action is taken depending on the event - # name. - # "Special" events (quit_panel/togglehidepanel/reload) are also handled - # here. - - # wait for next event - IFS=$'\t' read -ra cmd || break - # find out event origin - case "${cmd[0]}" in - tag*) - #echo "resetting tags" >&2 - IFS=$'\t' read -ra tags <<< "$(hc tag_status $monitor)" - ;; - date) - #echo "resetting date" >&2 - date="${cmd[@]:1}" - ;; - quit_panel) - exit - ;; - togglehidepanel) - currentmonidx=$(hc list_monitors | sed -n '/\[FOCUS\]$/s/:.*//p') - if [ "${cmd[1]}" -ne "$monitor" ] ; then - continue - fi - if [ "${cmd[1]}" = "current" ] && [ "$currentmonidx" -ne "$monitor" ] ; then - continue - fi - echo "^togglehide()" - if $visible ; then - visible=false - hc pad $monitor 0 - else - visible=true - hc pad $monitor $panel_height - fi - ;; - reload) - exit - ;; - focus_changed|window_title_changed) - windowtitle="${cmd[@]:2}" - ;; - #player) - # ;; - esac - done - - ### dzen2 ### - # After the data is gathered and processed, the output of the previous block - # gets piped to dzen2. - -} 2> /dev/null | dzen2 -w $panel_width -x $x -y $y -fn "$font" -h $panel_height \ - -e "button3=;button4=exec:$hc_quoted use_index -1;button5=exec:$hc_quoted use_index +1" \ - -ta l -bg "$bgcolor" -fg '#efefef' -- cgit v1.1