#!/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="$app ($(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=""\""$(list_apps | grep -i -m1 "^$query")"\"" 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 ${packages} package."
else
#if package-app uses multiple packages, use plural case
abovetext+=$'\n'"- This app installs these packages: $(sed 's/ /, /g' <<<"$packages")"
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: $website"
#show credits link if available - on same line as website link
if [ -f "${DIRECTORY}/apps/${app}/credits" ];then
abovetext+=" | Credits"
fi
else #website unavailable
#show credits link standalone, if available
if [ -f "${DIRECTORY}/apps/${app}/credits" ];then
abovetext+=$'\n'"- Credits"
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'"- $(printf "%'d" "$num_users") 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=Enable!!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/&/&/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