#!/bin/bash

error() { #red text and exit 1
  echo -e "\e[91m$1\e[0m" 1>&2
  exit 1
}

if ! command -v yad &>/dev/null; then
  error "YAD needs to be installed to run Pi-Apps. Most likely you did not install Pi-Apps correctly. Please run the install script."
fi

if [[ $(id -u) == 0 ]]; then
  echo "Pi-Apps is not designed to be run as root! Please try again as a regular user." | yad --center --window-icon="${DIRECTORY}/icons/logo.png" \
  --width=700 --height=300 --text-info --title="Error" \
  --image="${DIRECTORY}/icons/error.png" --image-on-top --fontname=12 \
  --button='OK'
  error "Pi-Apps is not designed to be run as root! Please try again as a regular user."
fi

# set GUI format versioning
export GUI_FORMAT_VERSION=2

#Transition from the GUI that calls itself to the self-contained GUI: when called by the old GUI, kill that yad window and treat this subprocess as the new main thread
if [ -z "$1" ] && [ ! -z "$2" ] && [ ! -z "$3" ] ;then
  kill $(ps -fC yad | grep "yad --class Pi-Apps --name Pi-Apps --center --title=Pi-Apps --image" | awk '{print $2}')
  unset YAD_XID #new gui, don't try to get dimensions of the now closed app list
fi

DIRECTORY="$(readlink -f "$(dirname "$0")")"

#check mission-critical scripts and re-download them if they contain a syntax error
(
  sleep 10
  command -v shellcheck >/dev/null || exit 0
  
  if shellcheck "${DIRECTORY}/updater" --color=always | grep '\[31m' --before 1 ;then
    echo "Downloading updater script to repair syntax error"
    errors="$(wget -O "${DIRECTORY}/updater" 'https://raw.githubusercontent.com/Botspot/pi-apps/master/updater' 2>&1)" || echo "$errors"
  fi | sed 's/]31m//g'
  
  if shellcheck "${DIRECTORY}/api" --color=always | grep '\[31m' --before 1 ;then
    echo "Downloading api script to repair syntax error"
    errors="$(wget -O "${DIRECTORY}/api" 'https://raw.githubusercontent.com/Botspot/pi-apps/master/api' 2>&1)" || echo "$errors"
  fi | sed 's/]31m//g'
) &

set -a #make all functions in the api available to subprocesses
source "${DIRECTORY}/api" || error "failed to source ${DIRECTORY}/api"

#For systems with older versions of yad, the text color column cannot be left blank. This python script determines the default text color from GTK bindings.
if [ -z "${text_color+x}" ];then
  #0400 is the latest version
  yad_version="$(zcat /usr/share/doc/yad/NEWS.gz | head -n 1 | tr -cd '0123456789\n')"
  if [ $yad_version -lt 0400 ]; then
    if command -v python3 &>/dev/null; then
      python_version="python3"
    else
      python_version="python2"
    fi
    export text_color=$(echo "import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
tv = Gtk.TextView()
style = tv.get_style_context()
textcolor = style.get_color(Gtk.StateType.NORMAL)
print(Gdk.RGBA.to_string(textcolor))
" | $python_version -)
  else
    export text_color=""
  fi
fi

#display the pi-apps logo in the terminal
generate_logo &

#install dependencies
runonce <<"EOF"
  dependencies='yad curl wget aria2 lsb-release software-properties-common apt-utils apt-transport-https gnupg imagemagick bc librsvg2-bin locales shellcheck git wmctrl xdotool x11-utils rsync unzip debsums libgtk3-perl'
  # Install dependencies if necessary
  if ! dpkg -s $dependencies >/dev/null 2>&1; then
    sudo_popup apt install $dependencies -y -f --no-install-recommends
  fi
EOF

#run is_supported_system once mostly to check for unsupported ubuntu/debian distros and warn the user with a blocking GUI popup
runonce <<"EOF"
  if ! is_supported_system >/dev/null;then
    text="YOUR SYSTEM IS UNSUPPORTED:
$(is_supported_system)

Pi-Apps will disable the sending of any error reports until you have resolved the issue above.
Your mileage may vary with using Pi-Apps in this state. Expect the majority of apps to be broken."

    yadflags=(--class Pi-Apps --name "Pi-Apps" --window-icon="${DIRECTORY}/icons/logo.png" --title="Pi-Apps")
    userinput_func "$text" "Ok"
  fi
  true
EOF

#Various stuff to run in background (enclosed in brackets so Geany IDE can collapse the code)
{
mkdir -p "${DIRECTORY}/data/status" "${DIRECTORY}/data/update-status" \
  "${DIRECTORY}/data/preload" "${DIRECTORY}/data/settings" \
  "${DIRECTORY}/data/status" "${DIRECTORY}/data/update-status" \
  "${DIRECTORY}/data/categories"

#check for updates
"${DIRECTORY}/updater" set-status &
trap "kill $! &>/dev/null" EXIT #kill the above subprocess on exit

#Click pi-apps usage link every time the GUI is run
shlink_link usage active
}

#Determine the app list mode. Allowed values: 'yad-*', 'xlunch-*'
guimode="$(cat "${DIRECTORY}/data/settings/App List Style")"
[ -z "$guimode" ] && guimode=yad-default

#In YAD mode, two windows are handled in a side-by-side configuration. As a group, they must be centered on the the screen.
#In Xlunch mode, the window must be centered, but xlunch only handles absolute offsets.
get_positions() {
  #determine screen_width and screen_height
  if [ -z "$screen_width" ] || [ -z "$screen_height" ];then
    screen_dimensions="$(xrandr --nograb --current | awk -F 'connected |\\+|\\('  '/ connected.*[0-9]+x[0-9]+\+/ && $2 {printf $2 ", "}' | sed -n -e 's/^.*primary //p' | tr 'x+' ' ' | tr ',+' ' ')"
    if [ -z "$screen_dimensions" ];then
      # if screen_dimensions is empty, this could be a single monitor wayland display which does not have the word "primary" in the output
      # workaround is to get the first output returned for the connected display
      screen_dimensions="$(xrandr --nograb --current | awk -F 'connected |\\+|\\('  '/ connected.*[0-9]+x[0-9]+\+/ && $2 {printf $2 ", "}' | tr 'x+' ' ' | tr ',+' ' ')"
    fi
    screen_width="$(awk '{print $1}' <<<"$screen_dimensions")"
    screen_height="$(awk '{print $2}' <<<"$screen_dimensions")"
  fi
  
  if [[ "$guimode" == yad* ]];then
    
    # if this is being run by yad, there should be a yad window id
    # store in arrary of x and y
    # this allows for windows to be moved by the user and the second window to still show up where expected
    main_yad_window=$YAD_XID
    if [ -n "${main_yad_window}" ]; then
      window_info=$(xwininfo -id $main_yad_window)
      
      #skip calculating offsets if yad window is in the same place as last time
      if [ -z "$last_window_info" ] || [ -z "$geometry1" ] || [ -z "$geometry2" ] || [ "$last_window_info" != "$window_info" ];then
        # for speed of execution, we are assuming the order of matches from xwininfo
        # this is safe as the output order has been standardized for over a decade
        # this is the location of where the window content starts inside the title bar and window borders (pos x then pos y)
        main_yad_window_pos=($(echo "$window_info" | sed -n 's/Absolute upper-left.*://p'))
        # these are the dimensions of where the window content starts inside the title bar and window borders (dim x then dim y)
        main_yad_window_dim=($(echo "$window_info" | sed -n 's/Width://p;s/Height://p'))
        # again, for speed, all border widths are saved to one array
        # left, right, title, bottom [0, 1, 2, 3]
        # this is the size of the window borders (including title bar)
        border_widths=($(xprop _NET_FRAME_EXTENTS -id "$main_yad_window" | sed -n  's/_NET_FRAME_EXTENTS.*=//p' | tr ',' '\n'))
        #total dimensions for both yad windows side by side
        if [ $screen_width -le 1000 ] || [ $screen_height -le 600 ];then
          #gui size for small screens
          height=${main_yad_window_dim[1]}
          width=600
          
          #width of first window
          width1=${main_yad_window_dim[0]}
          #width of second window
          width2=350
        else
          #gui size for large screens
          height=${main_yad_window_dim[1]}
          width=800
          
          #width of first window
          width1=${main_yad_window_dim[0]}
          #width of second window
          width2=480
        fi
        #how far down the top of the title bar of yad window is from the top of the screen
        yoffset=$((main_yad_window_pos[1]-border_widths[2]))
        
        #screen offsets for window 1
        #use current position of the left side of the main window border
        xoffset1=$((main_yad_window_pos[0]-border_widths[0]))
        #screen offsets for window 2
        #use current position of the right side of the main window border
        xoffset2=$((xoffset1+border_widths[0]+width1+border_widths[1]))
        
        #set completed location arguments for both yad windows
        geometry1="--geometry=${width1}x${height}+${xoffset1}+${yoffset}"
        geometry2="--geometry=${width2}x${height}+${xoffset2}+${yoffset}"
      fi
    else
      # default positions when the main window does not exist yet
      #total dimensions for both yad windows side by side
      if [ $screen_width -le 1000 ] || [ $screen_height -le 600 ];then
        #gui size for small screens
        height=400
        width=600
        
        #width of first window
        width1=250
        #width of second window
        width2=$((width - width1))
      else
        #gui size for large screens
        height=600
        width=800
        
        #width of first window
        width1=320
        #width of second window
        width2=$((width - width1))
      fi
      #how far down the top of the title bar of yad window is from the top of the screen
      yoffset=$(((screen_height/2)-(height/2)))
      
      #screen offsets for window 1
      xoffset1=$(((screen_width/2)-(width/2)))
      #screen offsets for window 2
      xoffset2=$(((screen_width/2)-(width/2)+width1))
      
      #set completed location arguments for both yad windows
      geometry1="--geometry=${width1}x${height}+${xoffset1}+${yoffset}"
      geometry2="--geometry=${width2}x${height}+${xoffset2}+${yoffset}"
    fi
    
  elif [[ "$guimode" == xlunch* ]];then
    #desired dimensions for xlunch window
    height=700
    width=800
    #determine 
    xoffset=$(((screen_width/2)-(width/2)))
    yoffset=$(((screen_height/2)-(height/2)))
  else
    error "Unrecognized app list style '$guimode'!"
  fi
}
# run get_positions once incase sometime requires the position value immediatly
get_positions

#Compile xlunch if required
if [[ "$guimode" == xlunch* ]] && ([ ! -d "${DIRECTORY}/xlunch" ] || [ ! -f /usr/bin/xlunch ]);then
  #signal files
  rm -f /tmp/xlunchfailed /tmp/xlunchfinished /tmp/terminalexit
  echo '' > /tmp/terminalexit
  "${DIRECTORY}/etc/terminal-run" "
    function error {
      echo -e "\""\e[91m$1\e[39m"\""
      echo 'Close this terminal to exit.'
      echo '' > /tmp/xlunchfailed
      sleep infinity
    }
    trap 'echo "\"""\"" > /tmp/terminalexit' EXIT
    
    #uninstall xlunch first
    sudo rm -rf /etc/xlunch /usr/share/xlunch /usr/bin/xlunch /usr/bin/genentries /usr/bin/updateentries /usr/bin/genentries.desktop.sh /usr/share/icons/hicolor/48x48/apps/xlunch_ghost.png /usr/share/icons/hicolor/48x48/apps/xlunch.png /usr/share/applications/genentries.desktop
    
    rm -f /tmp/terminalexit
    sudo rm -rf /usr/bin/xlunch "\""$DIRECTORY/xlunch"\"" 2>/dev/null
    sudo apt install -y libimlib2-dev libx11-dev || error 'APT failed to install libimlib2-dev and libx11-dev packages!'
    cd "\""$DIRECTORY"\""
    git clone https://github.com/Tomas-M/xlunch || error 'Failed to clone xlunch repository!'
    cd "\""$DIRECTORY/xlunch"\""
    echo 'Running make...'
    echo "\"""\$"(cat '${DIRECTORY}/xlunch/Makefile' | grep -v 'genentries \|cp -r svgicons/')"\"" > '${DIRECTORY}/xlunch/Makefile'
    make -j8 || error 'make command failed!'
    echo 'Running sudo make install...'
    sudo make install || error 'sudo make install failed!'
    sudo rm -f /usr/share/applications/genentries.desktop
    cd $HOME
    if [ ! -f /usr/bin/xlunch ];then
      error 'xlunch should be installed now, but /usr/bin/xlunch does not exist!'
    fi
    echo '' > /tmp/xlunchfinished
  " 'Compiling xlunch...'
  
  #if terminal doesn't start in 3 seconds, then /tmp/terminalexit will exist.
  sleep 3
  
  #check for an exit status code from the running terminal
  while true; do
    if [ -f /tmp/xlunchfinished ];then
      echo "xlunch finished installing."
      break
    elif [ -f /tmp/xlunchfailed ];then
      #revert back to yad
      echo 'yad-default' > "{DIRECTORY}/data/settings/App List Style"
      error "xlunch failed to compile!"
    elif [ -f /tmp/terminalexit ];then #if terminal doesn't start in 3 seconds, then /tmp/terminalexit will exist.
      #revert back to yad
      echo 'yad-default' > "{DIRECTORY}/data/settings/App List Style"
      error "The xlunch compilation terminal exited prematurely."
    else
      sleep 1
    fi
  done
fi

#Determine message of the day. If announcements file missing or over a day old, download it.
if [ ! -f "${DIRECTORY}/data/announcements" ] || [ ! -z "$(find "${DIRECTORY}/data/announcements" -mtime +1 -print)" ]; then
  announcements="$(wget -qO- https://raw.githubusercontent.com/Botspot/pi-apps-announcements/main/message)"
  echo "$announcements" > "${DIRECTORY}/data/announcements"
fi & #use $announcements and & here to avoid delaying launch or emptying the file before download completes

details_window() { #input: prefix/app
  local input="$1"

  [ -z "$input" ] && return
  
  # make sure terminal_manage function is available
  # the old updater did not source the new api script
  typeset -f terminal_manage &>/dev/null || { set -a; source "${DIRECTORY}/api"; }
  
  #app is in format $prefix/$app, so split them out
  local app="$(basename "$input")"
  local prefix="$(dirname "$input")"
  
  #add status heading
  local app_status="$(app_status "${app}")"
  
  #text to the right of the app icon
  local abovetext="<b>$app</b> ($(sed 's/corrupted/corrupted - installation failed/g' <<<"$app_status" | sed 's/disabled/disabled - installation is prevented on your system/g'))"
  
  #If package-app, show what packages it installs
  if [ -f "${DIRECTORY}/apps/${app}/packages" ];then
    local packages="$(pkgapp_packages_required "$app")"
    if [ -z "$packages" ]; then
      #returned required package list is empty. application cannot be installed
      #this case cannot be hit if the application is already hidden which it should be
      yad "${yadflags[@]}" --title=Results --width=310 \
        --text=""\""<b>$(list_apps | grep -i -m1 "^$query")</b>"\"" is not compatible with your ${__os_desc} ${arch}-bit OS." \
        --button=OK:0
      return
    fi
    if [ "$(wc -w <<<"$packages")" == 1 ];then
      #if package-app uses only 1 package, use singular case
      abovetext+=$'\n'"- This app installs the <b>${packages}</b> package."
    else
      #if package-app uses multiple packages, use plural case
      abovetext+=$'\n'"- This app installs these packages: <b>$(sed 's/ /, /g' <<<"$packages")</b>"
    fi
  fi
  
  #show app's website if available
  if [ -f "${DIRECTORY}/apps/${app}/website" ];then
    local website="$(head -n1 "${DIRECTORY}/apps/${app}/website")"
    abovetext+=$'\n'"- Website: <a href="\""$website"\"">$website</a>"
    
    #show credits link if available - on same line as website link
    if [ -f "${DIRECTORY}/apps/${app}/credits" ];then
      abovetext+=" | <a href="\""file://${DIRECTORY}/apps/${app}/credits"\"">Credits</a>"
    fi
    
  else #website unavailable
    #show credits link standalone, if available
    if [ -f "${DIRECTORY}/apps/${app}/credits" ];then
      abovetext+=$'\n'"- <a href="\""file://${DIRECTORY}/apps/${app}/credits"\"">Credits</a>"
    fi
  fi
  
  local num_users="$(usercount "$app")"
  if [ ! -z "$num_users" ] && [ "$num_users" -gt 20 ];then
    #list the number of users, using this printf command to add commas (,) for every thousand number
    abovetext+=$'\n'"- <b>$(printf "%'d" "$num_users")</b> users"
    
    if [ "$num_users" -ge 10000 ];then
      #if this app has over 10,000 users, add two exclamation points!!
      abovetext+="!!"
    elif [ "$num_users" -ge 1500 ];then
      #if this app has over 1500 users, add an exclamation point!
      abovetext+="!"
    fi
  fi
  
  #array holding various buttons that may be passed to yad
  local whichbutton=()
  
  if [ -f "${DIRECTORY}/apps/$app/uninstall" ] || [ -f "${DIRECTORY}/apps/$app/install" ] || [ -f "${DIRECTORY}/apps/$app/install-$arch" ];then
    whichbutton+=("--button=Scripts!${DIRECTORY}/icons/shellscript.png!Feel free to see how an app is installed!"$'\n'"Perfect for learning or troubleshooting.:6")
  fi
  if [ "$(cat "${DIRECTORY}/data/settings/Show Edit button")" == 'Yes' ];then
    #if edit button enabled, show it
    whichbutton+=("--button=Edit!${DIRECTORY}/icons/edit.png!Make changes to the app:8")
  fi
  
  #display buttons based on app's installation status
  if [ "$app_status" == 'installed' ];then
    #if installed, display uninstall button
    whichbutton+=("--button=Uninstall!${DIRECTORY}/icons/uninstall.png:2")
  elif [ "$app_status" == 'uninstalled' ];then
    #if uninstalled, display install button
    whichbutton+=("--button=Install!${DIRECTORY}/icons/install.png:4")
  elif [ "$app_status" == 'disabled' ];then
    #if disabled, display only an 'enable' button
    whichbutton+=("--button=<b>Enable</b>!!Force this app to install on your system."$'\n'"This app was disabled for a reason so if you enable it..."$'\n'"YOU HAVE BEEN WARNED.:12")
  else
    #if app status is 'corrupted', and a log file exists for this app, then display a button to view the log file
    if [ "$app_status" == 'corrupted' ];then
      local logfile="$(ls "$DIRECTORY/logs"/* -t | grep "fail-${app}" | head -n1)"
      if [ ! -z "$logfile" ];then
        whichbutton+=("--button=Errors!${DIRECTORY}/icons/log-file.png!$app failed to $(echo "$(basename "$logfile")" | awk -F'-' '{print $1}'). Click this button to view the error output saved in the log file.:14")
      fi
    fi
    #if status is corrupted or unknown, then show both buttons
    whichbutton+=("--button=Uninstall!${DIRECTORY}/icons/uninstall.png:2" "--button=Install!${DIRECTORY}/icons/install.png:4")
  fi
  
  #only display app icon if it exists
  if [ -f "${DIRECTORY}/apps/${app}/icon-64.png" ];then
    local imageline=(--image="${DIRECTORY}/apps/${app}/icon-64.png" --image-on-top)
  fi
  
  #Make sure app details window is focused (necessary for openbox window manager)
  (i=0
    while [ "$(xdotool getactivewindow getwindowname)" != "Details of ${app}" ] && [ $i -lt 20 ]; do
      wmctrl -a "Details of ${app}" #Raise the window named "Details of ${app}"
      sleep 0.2
      i=$((i+1))
    done) &
  
  #display app details window
  get_positions
  
    (cat "${DIRECTORY}/apps/$app/description" || echo "Description unavailable") | yad "${yadflags[@]}" --text-info --fontname=12 --wrap --show-uri \
    --text="$(sed 's/&/&amp;/g' <<<"$abovetext")" \
    "${imageline[@]}" \
    --title="Details of ${app}" --window-icon="${DIRECTORY}/icons/logo.png" \
    $geometry2 --skip-taskbar \
    "${whichbutton[@]}"
  button=$?
  
  case $button in
  4) #install
    terminal_manage install "$app" &
    ;;
    
  2) #uninstall
    terminal_manage uninstall "$app" &
    ;;
    
  6) #scripts
    install_script="${DIRECTORY}/apps/${app}/$(script_name_cpu "$app")"
    uninstall_script="${DIRECTORY}/apps/${app}/uninstall"
    
    text_editor "$uninstall_script" &
    sleep 0.1
    text_editor "$install_script" &
    
    details_window "$@" #open details window again
    ;;
    
  8) #edit
    "${DIRECTORY}/createapp" "$app"
    refresh_list
    ;;
    
  12) #enable
    
    #remove status file containing 'disabled'
    rm -f "${DIRECTORY}/data/status/${app}"
    refresh_list &
    details_window "$@" #open details window again
    ;;
    
  14) #viewlog
    echo "Viewing error log of $app..."
    echo "Log filepath: $logfile"
    "${DIRECTORY}/etc/viewlog" "$logfile"
    
    details_window "$@" #open details window again
    ;;
  esac
}

if [[ "$guimode" == yad* ]];then
  
  #create a named pipe to send app list through to yad
  pipe="$(mktemp -u)" #get a random filename to work with
  mkfifo $pipe #make the named pipe
  #create a named pipe to store detailspid
  detailspid="$(mktemp -u)" #get a random filename to work with
  mkfifo $detailspid #make the named pipe
  trap "rm -f $pipe; rm -f $detailspid" EXIT #remove the named pipes on exit
  echo pipe is $pipe
  echo detailspid is $detailspid
  
  #in background process, send initial app list to yad; first echo line waits until yad is accepting input, then use small delay to prevent items from being missed
  (echo -e '\f' > $pipe
  sleep 0.5
  "${DIRECTORY}/preload" yad '' >> $pipe) &
  
  #retrieve a random line from the announcements file for this session
  motd="$(shuf -n 1 "${DIRECTORY}/data/announcements")"
  
  refresh_list() { #Refresh the current list of apps in the event of a change
    if [ ! -z "$pipe" ];then
      echo -e "\f" > "$pipe"
      "${DIRECTORY}/preload" yad "$prefix" > "$pipe" 2>/dev/null
    fi
  }
  
  kill_details() { #close the details window in 1 second for better UX. Uses the $detailspid variable. To close it immediately add an argument of 0
    echo "" >> $detailspid &
    detailspidlist="$(cat $detailspid)"
    (
    if [ "$1" != 0 ];then
      sleep 1.5
    fi
    
    echo "$detailspidlist" | while read line ; do
      [ ! -z "$line" ] && pkill -P "$line" 2>/dev/null
      [ ! -z "$line" ] && kill "$line" 2>/dev/null
    done
    ) &
  }
  
  run_user_selection() { #Function that is run in yad gui to execute user selection
    yadflags=(--class Pi-Apps --name "Pi-Apps" --window-icon="${DIRECTORY}/icons/logo.png" --title="Pi-Apps" --separator='\n')
    echo "YAD_XID is $YAD_XID"
    input="$3"
    if [[ "$input" == *'Updates/' ]];then
      #updater window
      kill_details
      
      get_positions
      "${DIRECTORY}/updater" gui fast $geometry2 --skip-taskbar --close-on-unfocus
      exitcode=$? #0 if update successful, 1 if list of updates was closed
      
      #figure out which prefix we are on and refresh the app list
      prefix="$(echo "$input" | sed 's+Updates/$++g')"
      
      if [ $exitcode == 0 ];then
        refresh_list
      fi
    elif [ "$input" == 'Search/' ];then
      #search window
      kill_details
      
      details_window_check(){
        local input
        read input
        [ -z "$input" ] && return
        details_window "/$input"
      }
      get_positions
      #show app details window for this selected app
      yadflags+=("$geometry2" --close-on-unfocus)
      app_search_gui | details_window_check &
      echo "$!" >> $detailspid &
      
    elif [[ "$input" == */ ]];then
      #app folder selected
      echo -e '\f' > $pipe #clear the yad list
      "${DIRECTORY}/preload" yad "${input::-1}" >> $pipe #send yad the app-list - derived from folder name but dropping the final slash character
      
    elif [[ "$input" == 'YAD_XID is'* ]];then
      YAD_XID="$(echo "$input" | awk '{print $3}')"
    elif [ ! -z "$input" ];then #app details window
      
      get_positions
      
      #show app details window, and close the previous one
      kill_details
      details_window "$input" &
      echo "$!" >> $detailspid &
    fi
  }
  { yad "${yadflags[@]}" \
    --image="${DIRECTORY}/icons/logo-64.png" --image-on-top --text "$motd" \
    --list --no-headers --column=:IMG  --column=Name --column=Sysname:HD --column=tip:HD --column=@fore@:HD \
    --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \
    --tooltip-column=4 \
    --dclick-action "bash -c "\""run_user_selection %s"\""" --select-action="bash -c "\""run_user_selection %s"\""" \
    --button="!${DIRECTORY}/icons/search.png"!'Search':"bash -c "\""run_user_selection '' '' Search/"\""" \
    --button="!${DIRECTORY}/icons/options.png"!'Settings':2 \
    "$geometry1"; button=$?; kill "$!"; } < <(exec tail -f --retry $pipe)
  
  kill_details 0 #immediately close details window without delay
  unset YAD_XID #avoid trying to get dimensions of a now closed yad window (fixes badWindow error in get_positions after returning from settings)
  
  if [ "$button" == 2 ];then
  
    # remove pipe early so that nothing attempts to write to it
    rm -f "$pipe"
    rm -f "$detailspid"
    
    "${DIRECTORY}/settings"
    "${DIRECTORY}/gui" "$@" #run new instance of this script
  fi

  #END of yad main window
  
elif [[ "$guimode" == xlunch* ]];then
  
  #create a named pipe to send app list through to yad
  pipe="$(mktemp -u)" #get a random filename to work with
  mkfifo $pipe #make the named pipe
  trap "rm $pipe" EXIT #remove this named pipe on exit
  echo pipe is $pipe
  
  #disabled, but too cool to remove: this can make the transparent background of xlunch blurry - like Windows 7
  if false;then
    scrot -a "$((xoffset+1)),$((yoffset+33)),${width},${height}" blur.png #blur_init.png
    convert -blur 10x5 ~/blur.png ~/blur.png
  fi
  
  #Depending on the xlunch theme, different arguments will be used.
  if [ "$guimode" == xlunch-light-3d ];then
    #light mode
    xlunchflags=(--multiple --dontquit -WoCS -s 64 --bc e0e0e000 --tc 000000 --pc 6060ffff --hc ffffff50 \
      -p "Search: " -a -c $([ $width -lt 550 ] && echo 1 || echo 2) --title "Pi-Apps: Raspberry Pi app store" \
      --icon "${DIRECTORY}/icons/logo.png" --scrollbarcolor ffffff40 --scrollindicatorcolor 0000ff80 \
      --width $width --height $height --xposition $xoffset --yposition $yoffset \
      --button "${DIRECTORY}/icons/logo-3d.png;;$((($width/2)-(300/2))),0;:exec echo pi-apps-homepage" \
      --button "${DIRECTORY}/icons/settings-dark.png;;$(($width-140)),30;:exec echo pi-apps-settings" \
      -g "${DIRECTORY}/icons/background-3d.png")
  elif [ "$guimode" == xlunch-dark-3d ];then
    #dark mode, 3d opaque version
    xlunchflags=(--multiple --dontquit -WoCS -s 64 --bc ffffff00 --tc DCDDDE --pc ffffffa0 --hc ffffff30 \
      -p "Search: " -a -c $([ $width -lt 550 ] && echo 1 || echo 2) --title "Pi-Apps: Raspberry Pi app store" \
      --icon "${DIRECTORY}/icons/logo.png" --scrollbarcolor ffffff20 --scrollindicatorcolor ffffff40 \
      --width $width --height $height --xposition $xoffset --yposition $yoffset \
      --button "${DIRECTORY}/icons/logo-3d-dark.png;;$((($width/2)-(300/2))),0;:exec echo pi-apps-homepage" \
      --button "${DIRECTORY}/icons/settings-light.png;;$(($width-140)),30;:exec echo pi-apps-settings" \
      -g "${DIRECTORY}/icons/background-3d-dark.png")
  else
    #dark mode, transparent version
    xlunchflags=(--multiple --dontquit -WoCS -s 64 --bc 000000A0 --tc ffffffff --pc 6060ffff --hc ffffff30 \
      -p "Search: " -a -c $([ $width -lt 550 ] && echo 1 || echo 2) --title "Pi-Apps: Raspberry Pi app store" \
      --icon "${DIRECTORY}/icons/logo.png" --scrollbarcolor ffffff40 --scrollindicatorcolor 0000ff80 \
      --width $width --height $height --xposition $xoffset --yposition $yoffset \
      --button "${DIRECTORY}/icons/logo-128.png;;$((($width/2)-(128/2))),0;:exec echo pi-apps-homepage" \
      --button "${DIRECTORY}/icons/logo-text.png;;$([ -z "$prefix" ] && echo '45' || echo '65'),$([ -z "$prefix" ] && echo '10' || echo '0');:exec echo pi-apps-homepage" \
      --button "${DIRECTORY}/icons/settings-light.png;;$(($width-140)),30;:exec echo pi-apps-settings")
  fi
  
  
  #in background process, send initial app list to xlunch; first echo line waits until xlunch is accepting input
  (
    #set initial value to make xlunch keep listening
    echo 'botspot is cool' > $pipe
    echo "$("${DIRECTORY}/preload" xlunch '')" > $pipe) &
  
  #read pipe      pipe to xlunch               read output of xlunch
  tail -f --retry $pipe | xlunch "${xlunchflags[@]}" | while read -r input; do
    echo "Received '$input'"
    
    if [ "$input" == 'Updates/' ];then
      echo > $pipe #clear list
      
      "${DIRECTORY}/updater" gui fast --skip-taskbar --close-on-unfocus
      exitcode=$? #0 if update successful, 1 if list of updates was closed
      
      #refresh main level
      "${DIRECTORY}/preload" xlunch '' > $pipe
      
    #category selected
    elif [[ "$input" == */ ]];then
      echo > $pipe #clear list
      "${DIRECTORY}/preload" xlunch "$(echo "$input" | sed 's+/$++g')" > $pipe
      
    #pi-apps logo button clicked - go to homepage in web browser
    elif [ "$input" == 'pi-apps-homepage' ];then
      x-www-browser "$(cat "${DIRECTORY}/etc/git_url")" &
      
    #Settings button clicked
    elif [ "$input" == 'pi-apps-settings' ];then
      #close xlunch
      echo ':quit' > $pipe
      
      #run settings, then run pi-apps gui
      "${DIRECTORY}/settings"
      "${DIRECTORY}/gui" "$@"
      
      #exit this script
      exit 0
      
    #app selected
    else
      echo > $pipe #clear list
      
      #in subprocess, open details window for app
      geometry2="--center --height=$((height/2)) --width=$width" details_window "$input"
      
      #show app list again
      "${DIRECTORY}/preload" xlunch "$(dirname "$input" | sed 's/^.$//g')" > $pipe
    fi
  done
  
fi
