#!/bin/bash
#appropriated from https://gitlab.com/wef/dotfiles/-/blob/master/bin/sway-select-window for use with eww

declare -A icons=(
)

jq_get_windows='
     # descend to workspace or scratchpad
     .nodes[0].nodes[0]
     # save workspace name as .w
     | {"w": .name} + (
       if (.nodes|length) > 0 then # workspace
         [recurse(.nodes[])]
       else # scratchpad
         []
       end
       + .floating_nodes
       | .[]
       # select nodes with no children (windows)
       | select(.nodes==[])
     )'

jq_windows_to_tsv='
    [
      (.id | tostring),
      # remove markup and index from workspace name, replace scratch with "[S]"
      (.w | gsub("<[^>]*>|:$"; "") | sub("__i3_scratch"; "[S]")),
      # get app name (or window class if xwayland)
      (.app_id // .window_properties.class),
      (.name),
      (.pid)
    ]
    | @tsv'

get_hardcoded_icon() {
    icon="${icons[$1]}"
    echo "$icon"
}

get_desktop() {
    app="$1"
    p="/usr/share/applications"

    # fast and easy cases first:
    for prefix in "" org.kde. org.gnome. org.freedesktop.; do
        d="$p/$prefix$app.desktop"
        [[ -r "$d" ]] && {
            echo "$d"
            [[ "$verbose" ]] && echo "found '$d'" >&2
            return
        }
    done

    # maybe lowercase
    for prefix in "" org.kde. org.gnome. org.freedesktop.; do
        d="$p/$prefix${app,,}.desktop"
        [[ -r "$d" ]] && {
            echo "$d"
            [[ "$verbose" ]] && echo "found '$d'" >&2
            return
        }
    done

    # this is fairly reliable but slow:
    # look for a .desktop file with Exec=$app eg
    # gnome-disks (but exclude gnome-disk-image-writer.desktop)
    # gnome-font-viewer
    GREP='egrep -r'
    type rg &>/dev/null && GREP=rg
    d=$( $GREP -il "^exec=$app( %u)*[[:space:]]*$" $p | head -n 1)
    [[ -r "$d" ]] && {
        echo "$d"
        [[ "$verbose" ]] && echo "found '$d'" >&2
        return
    }

    # desperation - weird apps like com.github.wwmm.pulseeffects.desktop!!
    # shellcheck disable=SC2012
    d=$( ls "$p/"*".$app.desktop" 2>/dev/null | head -n 1 )
    [[ -r "$d" ]] && {
        echo "$d"
        [[ "$verbose" ]] && echo "found '$d'" >&2
        return
    }
}

get_icon() {
    app="$1"

    icon=$( get_hardcoded_icon "$app_name" )
    [[ "$icon" && -r "$icon" ]] && {
        echo "$icon"
        [[ "$verbose" ]] && echo "using hardcoded icon '$icon'" >&2
        return
    }
    # let's go poke in the .desktop files:
    icon_name=""
    dt=$( get_desktop "$app" )
    # sometimes we get the 'class' rather than the exe - so try this:
    [[ "$dt" ]] || {
        app=$( tr '\0' '\n' < "/proc/$pid/cmdline" | head -n 1 )
        dt=$( get_desktop "$( basename "$app" )" )
    }
    [[ "$dt" ]] && {
        icon_name=$( awk -v IGNORECASE="set" -F"=" '/^icon/ {print $2}' "$dt" )
        [[ -r "$icon_name" ]] && {
            icon="$icon_name"
            echo "$icon"
            [[ "$verbose" ]] && echo "using .desktop icon '$icon'" >&2
            return
        }
        [[ "$icon_name" ]] && {
            icon_locations=(
                icons/hicolor/scalable/apps
                icons/hicolor/48x48/apps
                icons/gnome/48x48/apps
                icons/gnome/48x48/devices
                pixmaps
            )
            for d in "${icon_locations[@]}"; do
                for s in .svg .png .xpm ""; do
                    icon=/usr/share/$d/$icon_name$s
                    [[ -r $icon ]] && {
                        echo "$icon"
                        [[ "$verbose" ]] && echo "using .desktop icon '$icon'" >&2
                        return
                    }
                done
            done
            icon=$(find /usr/share/icons | grep "/${icon_name}-symbolic.svg" | head -n 1)
            [[ -r $icon ]] && {
                echo "$icon"
                [[ "$verbose" ]] && echo "using .desktop icon '$icon'" >&2
                return
            }
        }
    }
    icon=$( find /usr/share/icons /usr/share/pixmaps | grep -E -i "/$app.(png|svg)" | head -n 1 )
    [[ "$icon" && -r "$icon" ]] && {
        echo "$icon"
        [[ "$verbose" ]] && echo "using found icon '$icon'" >&2
        return
    }
    # failed:
    icon="/usr/share/icons/breeze-dark/mimetypes/32/unknown.svg"
    [[ "$verbose" ]] && echo "using missing icon '$icon'" >&2
    echo "$icon"
}

function get_scratchpad() {
  applist_array=()
  applist=""
  shopt -s lastpipe
  swaymsg -t get_tree |
  jq -r "$jq_get_windows | $jq_windows_to_tsv" |
  column -s $'\t' -o $'\t' -t | while IFS=$'\t' read -r win_id ws_name app_name win_title pid; do
    shopt -s extglob
    app_name="${app_name%%*( )}"
    icon=$( get_icon "$app_name" "$pid" )
    [[ "$verbose" ]] && printf "[%s]=%s\n" "$app_name" "$icon" >&2
    applist_array_item=$(jq -n --arg icon "${icon}" --arg name "${app_name##*.}" --arg title "${win_title}" --arg win_id "${win_id}" '{icon: $icon,name: $name,title: $title,win_id: $win_id}')
    applist_array+=("${applist_array_item}")
  done
  applist=$(printf '%s\n' "${applist_array[@]}" | jq -s .)
  echo ${applist}
}

get_scratchpad
swaymsg -t subscribe '["window"]' --monitor | {
  while read -r event; do
    get_scratchpad
  done
}
