[updated] Scratchpad (hide) any window, any X11 based wm

I looked for a solution on the forum to send in the scratchpad any window and why not several of them regardless of the window manager even dk, but without success.
So I got to work.

Dependencies: xdo, xorg-xset, xorg-xprop, wmctrl, libnotify, polybar & rofi (optionals)

We need xset to switch on/off a led (number 3) on the keyboard, feel free to change it in the script and enabling ipc feature in your polybar config: enanle-ipc = true

Options to launch the script scratchpad -h (hide), scratchpad -u (unhide the first and so on) and for a rofi menu scratchpad -r

#!/bin/bash

BARPID=$(pgrep --full <your_bar_name_here>)

_empty() {
    xset -led 3
    polybar-msg -p "$BARPID" \
    action "#scratchpad-ipc.hook.0" >/dev/null 2>&1
    notify-send 'nothing else in scratchpad'
}

_indicator() {
    xset led 3
    polybar-msg -p "$BARPID" \
    action "#scratchpad-ipc.hook.1" >/dev/null 2>&1
}

TARGET=$(xdo id ${1})
ID_LIST="$XDG_RUNTIME_DIR/scratchpad_hidden.list"
ID_LIST_ALL="$XDG_RUNTIME_DIR/scratchpad_all.list"

case "$1" in
    -h) # sending all existing windows ids/instances/classes in a file to keep track
        wmctrl -lx | awk '{print $1" "$3}' >> "$ID_LIST_ALL"
        # using lowercases will match ids in $ID_LIST_ALL
        echo "$TARGET" | tr [:upper:] [:lower:] >> "$ID_LIST"
        xdo hide "$TARGET"
        sed -i -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d;
        s/\n//; h; P' "$ID_LIST_ALL"
        _indicator
    ;;
    -u) if [[ $(xprop -id $(sed -n '1p' "$ID_LIST") \
            | awk '/window state: / {print $3}') = Withdrawn ]]; then
            # show the first entry
            xdo show $(sed -n '1p' "$ID_LIST")
            # remove it from the list
            sed -i '1d' "$ID_LIST"
            if (( $(grep "" -c "$ID_LIST") > 0 )); then
                _indicator
            else
                _empty
            fi
        else
            _empty
        fi
    ;;
    -r) if (( $(grep "" -c $ID_LIST) > 0 )); then
            
            HIDDEN=$(cat $ID_LIST)

            N=$(for w in $HIDDEN; do
                NAME=$(xprop -id "$w" WM_CLASS 2>/dev/null | sed -r 's/.+ "(.+)"$/\1/')
                TITLE=$(xprop -id "$w" _NET_WM_NAME 2>/dev/null | sed -r 's/.+ "(.+)"$/\1/')
                [[ "$NAME" = "WM_CLASS" ]] && echo "$w" || echo "$NAME  \"$TITLE\""
            done | rofi -dmenu -no-custom -format  i -p 'Unhide a window: ')
                     
            [[ -n "$N" ]] && {
                
                ID=$(echo "$HIDDEN" | sed -n "$((N+1))p")
                xdo show "$ID"
                
                mapfile -t < <(wmctrl -lx | awk '{print $1}')
                for line in "${MAPFILE[@]}"; do
                    if [[ $(grep $line "$ID_LIST") ]]; then
                        # removing the right line
                        sed -i "/${line}/d" "$ID_LIST"
                        # removing blank lines
                        sed -i '/^\s*$/d' "$ID_LIST"
                        break
                    else
                        continue
                    fi
                done
                
                if (( $(grep "" -c $ID_LIST) > 0 )); then
                    _indicator
                else
                    _empty
                fi
            }
        else
            _empty
        fi
    ;;
esac

Polybar module:

[module/scratchpad-ipc]
type = custom/ipc
format = <output>
format-padding = 1
hook-0 = echo ""
hook-1 = echo "  $(grep "" -c "$XDG_RUNTIME_DIR"/scratchpad_hidden.list)"
initial = 1

I prefer custom/ipc modules over studip intervals to execute a command.
Of course add it in your bar section eg: modules-left = scratchpad-ipc
Hope you like it :smile:

5 Likes
1 Like

Thanks for contributing these scripts.

2 Likes

You’re welcome

scratchpad in the i3 sense of the term, I believe.

Like a hidden desktop.

But this script is window manager agnostic, so it will also work as (for example) as a tint2 executor in openbox.

1 Like

Thank you for taking the time to clarify and make me understand.
Very kind of you.

2 Likes

Top work again @archus

1 Like