Skip to content

Instantly share code, notes, and snippets.

@alvaro-jmp
Last active May 12, 2025 03:11
Show Gist options
  • Select an option

  • Save alvaro-jmp/3a0b1ae132780a56c6b0838e290471c2 to your computer and use it in GitHub Desktop.

Select an option

Save alvaro-jmp/3a0b1ae132780a56c6b0838e290471c2 to your computer and use it in GitHub Desktop.
Script to list windows and switch to a window, list applications and be able to execute any desired one, which are found in ~/.local/share/applications and /usr/share/applications through dmenu.
#!/bin/bash
# Script to list windows and switch to a window, list applications and be able to execute any desired one, which are found in ~/.local/share/applications and /usr/share/applications through dmenu.
# The first time it is executed or after installing or uninstalling an application, the script takes a moment x to list the applications each time it is executed.
terminal="xterm"
# Information is obtained about the last time the content of folders ~/.local/share/applications and /usr/share/applications were modified.
info_last_modified_local_apps=".local/share/applications $(stat ~/.local/share/applications | grep -Ei ".*^(Modify|Change)" | tr "\n" " ")"
info_last_modified_usr_apps="/usr/share/applications $(stat /usr/share/applications | grep -Ei ".*^(Modify|Change)" | tr "\n" " ")"
function listing_apps() {
IFS=$'\n'
local matches=""
local fix_matches=""
local list_general_apps=""
local list_home_apps=""
local cont=0
for FILE in $(ls /usr/share/applications/*.desktop); do
matches=$(cat $FILE | grep -m 4 -Ei '^Name=|^GenericName=|^Exec=|^Terminal=')
if [[ "$matches" =~ .*^Name= ]] && [[ "$matches" =~ .*^Exec= ]]; then
fix_matches="RUN >>> $(echo $matches | sed -z 's/\n/,/g')$cont"
list_general_apps+="$fix_matches$IFS"
cont=$((cont + 1))
fi
done
for FILE in $(ls ~/.local/share/applications/*.desktop); do
matches=$(cat $FILE | grep -m 4 -Ei '^Name=|^GenericName=|^Exec=|^Terminal=')
if [[ "$matches" =~ .*^Name= ]] && [[ "$matches" =~ .*^Exec= ]]; then
fix_matches="RUN >>> $(echo $matches | sed -z 's/\n/,/g')$cont"
list_home_apps+="$fix_matches$IFS"
cont=$((cont + 1))
fi
done
# The information of the listed applications is stored in a text string in ~/.cache/etc/dmenu-list-apps.txt
printf "%s%s" "$list_general_apps" "$list_home_apps" | tee ~/.cache/etc/dmenu-list-apps.txt
# The information about the last time the content of folders ~/.local/share/applications and /usr/share/applications were modified is stored in a text string in ~/.cache/etc/last-changes-info-share-applications.txt
printf "%s\n%s" "$info_last_modified_local_apps" "$info_last_modified_usr_apps" | tee ~/.cache/etc/last-changes-info-share-applications.txt
}
###############
######## INIT #
###############
# Evaluate if the file ~/.cache/etc/last-changes-info-share-applications.txt exists
if ! [ -f ~/.cache/etc/last-changes-info-share-applications.txt ]; then
if ! [ -d ~/.cache/etc ]; then
mkdir ~/.cache/etc
fi
listing_apps
# Evaluate if the file ~/.cache/etc/dmenu-list-apps.txt exists
elif ! [ -f ~/.cache/etc/dmenu-list-apps.txt ]; then
if ! [ -d ~/.cache/etc ]; then
mkdir ~/.cache/etc
fi
listing_apps
fi
IFS=$'\n'
info_last_modifications=()
# Load the information about the last time the content of folders ~/.local/share/applications and /usr/share/applications were modified
mapfile -t info_last_modifications < ~/.cache/etc/last-changes-info-share-applications.txt
# If the contents of folders ~/.local/share/applications and /usr/share/applications have been modified, a new list of applications is generated.
if ! [[ "${info_last_modifications[0]}" == "$info_last_modified_local_apps" ]]; then
listing_apps
fi
if ! [[ "${info_last_modifications[1]}" == "$info_last_modified_usr_apps" ]]; then
listing_apps
fi
list_windows=$(wmctrl -l | sort -nk2 | awk '{print "WIN ###", $0}')
list_apps=()
# Read the dmenu-list-apps.txt and store the information in a string array
mapfile -t list_apps < ~/.cache/etc/dmenu-list-apps.txt
# Print the list of applications and windows in dmenu
result=$(printf "%s\n%s\n" "${list_windows}" "${list_apps[@]}" | dmenu -i -l 10)
# To switch between windows
if [[ "$result" =~ ^WIN ]]; then
echo $result | awk '{print $3}' | xargs wmctrl -i -a
# To run applications
elif [[ "$result" =~ ^RUN ]]; then
# Get the id that matches the index of the array of the application list
w_id=$(echo $result | grep -oEi ",[0-9]*$")
w_id=${w_id:1}
# To know if the command needs to be executed in a terminal according to the index
use_term=$(echo "${list_apps[$w_id]}" | grep -m 1 -oEi "Terminal=true" | xargs echo)
# Get the command to execute according to the index
run=$(echo "${list_apps[$w_id]}" | grep -m 1 -oEi "Exec=.*(Terminal=|Exec=|Name=|GenericName=|,[0-9]*$)" | sed "s/Exec=//; s/\( Terminal=\| Exec=\| Name=\| GenericName=\|,[0-9]*\).*$//")
# It runs in the terminal
if [[ "$use_term" =~ true ]]; then
"$terminal" -e "$run" &
# It does not run in the terminal
else
eval $run &
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment