2023-10-10 19:51:07 +02:00
|
|
|
#!/usr/bin/env bash
|
2023-09-02 18:58:22 +02:00
|
|
|
|
2023-10-13 12:40:12 +02:00
|
|
|
function printHelp() {
|
2023-10-20 12:42:23 +02:00
|
|
|
cat <<EOF
|
2023-10-20 18:27:42 +02:00
|
|
|
Usage: hyprfreeze (-a | -p <pid> | -n <name> | -r) [options]
|
2023-10-13 12:40:12 +02:00
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
Utility to suspend a game process (and other programs) in Hyprland.
|
2023-10-13 12:40:12 +02:00
|
|
|
|
|
|
|
Options:
|
2024-02-10 22:39:37 +01:00
|
|
|
-h, --help show help message
|
|
|
|
|
|
|
|
-a, --active toggle suspend by active window
|
|
|
|
-p, --pid toggle suspend by process id
|
|
|
|
-n, --name toggle suspend by process name/command
|
2024-02-11 18:11:48 +01:00
|
|
|
-r, --prop toggle suspend by clicking on window (hyprprop must be installed)
|
2024-02-10 22:39:37 +01:00
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
-s, --silent don't send notification
|
2023-12-06 14:35:47 +01:00
|
|
|
-t, --notif-timeout notification timeout in milliseconds (default 5000)
|
2024-02-10 22:39:37 +01:00
|
|
|
--info show information about the process
|
|
|
|
--dry-run doesn't actually suspend/resume a process, useful with --info
|
|
|
|
--debug enable debug mode
|
2023-10-13 12:40:12 +02:00
|
|
|
EOF
|
|
|
|
}
|
|
|
|
|
2024-02-10 22:39:37 +01:00
|
|
|
function debugPrint() {
|
|
|
|
if [ "$DEBUG" -eq 1 ]; then
|
|
|
|
echo "[DEBUG] $1"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2023-10-20 12:42:23 +02:00
|
|
|
function toggleFreeze() {
|
2024-02-10 22:39:37 +01:00
|
|
|
# Skip this function if --dry-run flag was provided
|
|
|
|
if [[ $DRYRUN == "1" ]]; then return 0; fi
|
|
|
|
|
|
|
|
# Get pids of process tree
|
2024-02-11 18:01:24 +01:00
|
|
|
PIDS=$(pstree -p "$PID" | grep -oP '\(\K[^\)]+')
|
2024-02-10 22:39:37 +01:00
|
|
|
|
|
|
|
debugPrint "PIDs: $PIDS"
|
|
|
|
|
|
|
|
# Prevent suspending itself
|
|
|
|
local pid_of_script=$$
|
2024-02-11 18:01:24 +01:00
|
|
|
if echo "$PIDS" | grep -q "$pid_of_script"; then
|
2024-02-10 22:39:37 +01:00
|
|
|
echo "You are trying to suspend the hyprfreeze process."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Suspend or resume processes
|
2024-02-11 18:01:24 +01:00
|
|
|
if [[ "$(ps -o state= "$PID")" == T ]]; then
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Resuming processes..."
|
2024-02-13 11:46:40 +01:00
|
|
|
kill -CONT $PIDS 2>/dev/null && echo "Resumed $(ps -p "$PID" -o comm= 2>/dev/null) (PID $PID)" || exit 1
|
2024-02-10 22:39:37 +01:00
|
|
|
else
|
|
|
|
debugPrint "Suspending processes..."
|
2024-02-13 11:46:40 +01:00
|
|
|
kill -STOP $PIDS 2>/dev/null && echo "Suspended $(ps -p "$PID" -o comm= 2>/dev/null) (PID $PID)" || exit 1
|
2024-02-10 22:39:37 +01:00
|
|
|
fi
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
function getPidByActive() {
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Getting PID by active window..."
|
|
|
|
PID=$(hyprctl activewindow -j | jq '.pid')
|
|
|
|
debugPrint "PID by active window: $PID"
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
function getPidByPid() {
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Getting PID by PID: $1"
|
|
|
|
# Check if process pid exists
|
2024-02-11 18:01:24 +01:00
|
|
|
if ! ps -p "$1" &>/dev/null; then
|
2024-02-10 22:39:37 +01:00
|
|
|
echo "Process ID $1 not found"
|
|
|
|
exit 1
|
|
|
|
fi
|
2023-10-13 12:40:12 +02:00
|
|
|
|
2024-02-10 22:39:37 +01:00
|
|
|
PID=$1
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
function getPidByName() {
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Getting PID by name: $1"
|
|
|
|
# Check if process name exists
|
|
|
|
if ! pidof -x "$1" >/dev/null; then
|
|
|
|
echo "Process name $1 not found"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Get last process if there are multiple
|
2024-02-11 18:01:24 +01:00
|
|
|
PID=$(pidof "$1" | awk '{print $NF}')
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "PID by name: $PID"
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
function getPidByProp() {
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Getting PID by prop..."
|
|
|
|
if ! command -v hyprprop; then
|
2024-02-10 19:23:05 +01:00
|
|
|
echo "You need to install 'hyprprop' to use this feature. (https://github.com/vilari-mickopf/hyprprop)"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2024-02-10 22:39:37 +01:00
|
|
|
PID=$(hyprprop | jq '.pid')
|
|
|
|
debugPrint "PID by prop: $PID"
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 12:42:23 +02:00
|
|
|
function printInfo() {
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Printing process info...\n"
|
|
|
|
echo -e "$(tput bold)Process tree:$(tput sgr0)"
|
2024-02-11 18:01:24 +01:00
|
|
|
ps -p "$PID" 2>/dev/null && pstree -p "$PID"
|
2023-10-13 12:40:12 +02:00
|
|
|
|
2024-02-10 22:39:37 +01:00
|
|
|
echo -e "\n$(tput bold)Process threads:$(tput sgr0)"
|
2024-02-11 18:01:24 +01:00
|
|
|
ps -eLo pid,tid,comm | grep "$PID" 2>/dev/null
|
2023-10-13 12:40:12 +02:00
|
|
|
|
2024-02-10 22:39:37 +01:00
|
|
|
echo -e "\n$(tput bold)Process ID$(tput sgr0) = $PID \
|
2024-02-11 18:01:24 +01:00
|
|
|
\n$(tput bold)Process name$(tput sgr0) = $(ps -p "$PID" -o comm= 2>/dev/null) \
|
|
|
|
\n$(tput bold)Process state$(tput sgr0) = $(ps -o state= -p "$PID" 2>/dev/null)\n"
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
function sendNotification() {
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Sending notification..."
|
2024-02-11 18:01:24 +01:00
|
|
|
local title
|
|
|
|
title=$( [[ "$(ps -p "$PID" -o state=)" == T ]] &&
|
|
|
|
echo "Suspended $(ps -p "$PID" -o comm= 2>/dev/null)" ||
|
|
|
|
echo "Resumed $(ps -p "$PID" -o comm= 2>/dev/null)")
|
2023-10-20 18:27:42 +02:00
|
|
|
|
2024-02-11 18:01:24 +01:00
|
|
|
local message="PID $PID"
|
2023-10-20 18:27:42 +02:00
|
|
|
|
2024-02-10 22:39:37 +01:00
|
|
|
notify-send "${title}" "${message}" -t "$NOTIF_TIMEOUT" -a Hyprfreeze
|
2023-10-20 18:27:42 +02:00
|
|
|
}
|
2023-10-13 12:40:12 +02:00
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
function args() {
|
2024-02-10 22:39:37 +01:00
|
|
|
# Track required flags
|
|
|
|
local required_flag_count=0
|
|
|
|
|
|
|
|
# Parse options
|
|
|
|
local options="hap:n:rst:"
|
|
|
|
local long_options="help,active,pid:,name:,prop,silent,notif-timeout:,info,dry-run,debug"
|
2024-02-11 18:01:24 +01:00
|
|
|
local parsed_args
|
|
|
|
parsed_args=$(getopt -o "$options" --long "$long_options" -n "$(basename "$0")" -- "$@")
|
|
|
|
|
2024-02-10 22:39:37 +01:00
|
|
|
eval set -- "$parsed_args"
|
|
|
|
while true; do
|
|
|
|
case $1 in
|
|
|
|
-h | --help)
|
|
|
|
printHelp
|
|
|
|
exit 0
|
|
|
|
;;
|
|
|
|
-a | --active)
|
|
|
|
((required_flag_count++))
|
|
|
|
FLAG_ACTIVE=true
|
|
|
|
;;
|
|
|
|
-p | --pid)
|
|
|
|
((required_flag_count++))
|
|
|
|
shift
|
|
|
|
FLAG_PID="$1"
|
|
|
|
;;
|
|
|
|
-n | --name)
|
|
|
|
((required_flag_count++))
|
|
|
|
shift
|
|
|
|
NAME_FLAG="$1"
|
|
|
|
;;
|
|
|
|
-r | --prop)
|
|
|
|
((required_flag_count++))
|
|
|
|
FLAG_PROP=true
|
|
|
|
;;
|
|
|
|
-s | --silent)
|
|
|
|
SILENT=1
|
|
|
|
;;
|
|
|
|
-t | --notif-timeout)
|
|
|
|
shift
|
|
|
|
NOTIF_TIMEOUT="$1"
|
|
|
|
;;
|
|
|
|
--info)
|
|
|
|
INFO=1
|
|
|
|
;;
|
|
|
|
--dry-run)
|
|
|
|
DRYRUN=1
|
|
|
|
;;
|
|
|
|
--debug)
|
|
|
|
DEBUG=1
|
|
|
|
;;
|
|
|
|
--)
|
|
|
|
shift # Skip -- argument
|
|
|
|
break
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
# Check if more than one required flag is provided, or if none was provided
|
|
|
|
if [ $required_flag_count -ne 1 ]; then
|
|
|
|
printHelp
|
|
|
|
exit 1
|
|
|
|
fi
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function main() {
|
2024-02-10 22:39:37 +01:00
|
|
|
debugPrint "Starting main function..."
|
|
|
|
# Get pid by a required flag
|
|
|
|
if [ "$FLAG_ACTIVE" = true ]; then
|
|
|
|
getPidByActive
|
|
|
|
elif [ -n "$FLAG_PID" ]; then
|
|
|
|
getPidByPid "$FLAG_PID"
|
|
|
|
elif [ -n "$NAME_FLAG" ]; then
|
|
|
|
getPidByName "$NAME_FLAG"
|
|
|
|
elif [ "$FLAG_PROP" = true ]; then
|
|
|
|
getPidByProp
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Suspend or resume process
|
|
|
|
toggleFreeze
|
|
|
|
|
|
|
|
# Run these functions after PID is obtained
|
|
|
|
if [ $INFO -eq 1 ]; then printInfo; fi
|
|
|
|
if [ $SILENT -ne 1 ]; then sendNotification; fi
|
|
|
|
|
|
|
|
debugPrint "End of main function."
|
2023-10-13 12:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 18:27:42 +02:00
|
|
|
SILENT=0
|
2023-12-06 14:35:47 +01:00
|
|
|
NOTIF_TIMEOUT=5000
|
2023-10-13 12:40:12 +02:00
|
|
|
INFO=0
|
|
|
|
DRYRUN=0
|
2024-02-10 22:39:37 +01:00
|
|
|
DEBUG=0
|
2023-10-13 12:40:12 +02:00
|
|
|
|
|
|
|
args "$@"
|
|
|
|
|
|
|
|
main
|