mirror of
				https://github.com/ItsDrike/dotfiles.git
				synced 2025-11-04 01:16:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			226 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
#!/bin/bash
 | 
						|
 | 
						|
# Inspired by grimblast (https://github.com/hyprwm/contrib/blob/main/grimblast/grimblast)
 | 
						|
 | 
						|
# Requirements:
 | 
						|
# - `grim`: screenshot utility for wayland
 | 
						|
# - `slurp`: to select an area
 | 
						|
# - `hyprctl`: to read properties of current window
 | 
						|
# - `wl-copy`: clipboard utility
 | 
						|
# - `jq`: json utility to parse hyprctl output
 | 
						|
# - `notify-send`: to show notifications
 | 
						|
# - `swappy`: for editing the screenshots (only required for --edit)
 | 
						|
 | 
						|
# Helper functions
 | 
						|
 | 
						|
die() {
 | 
						|
    MSG="${1}"
 | 
						|
    ERR_CODE="${2:-1}"
 | 
						|
    URGENCY="${3:-critical}"
 | 
						|
 | 
						|
    >&2 echo "$MSG"
 | 
						|
    if [ "$NOTIFY" = "yes" ]; then
 | 
						|
        notify-send -a screenshot -u "$URGENCY" "Error ($ERR_CODE)" "$MSG"
 | 
						|
    fi
 | 
						|
    exit "$ERR_CODE"
 | 
						|
}
 | 
						|
 | 
						|
# Argument parsing
 | 
						|
 | 
						|
SAVE_METHOD=
 | 
						|
SAVE_FILE=
 | 
						|
TARGET=
 | 
						|
NOTIFY=no
 | 
						|
CURSOR=no
 | 
						|
EDIT=no
 | 
						|
DELAY=0
 | 
						|
 | 
						|
while [ "$1" ]; do
 | 
						|
    case "$1" in
 | 
						|
        -h | --help)
 | 
						|
            >&2 cat << EOF
 | 
						|
screenshot taking utility script, allowing for easy all-in-one solution for
 | 
						|
controlling how a screenshot should be taken.
 | 
						|
 | 
						|
Methods (one is required):
 | 
						|
    --copy: Copy the screenshot data into the clipboard
 | 
						|
    --save [FILE]: Save the screenshot data into a file
 | 
						|
    --copysave [FILE]: Both save to clipboard and to file
 | 
						|
General options:
 | 
						|
    --notify: Send a notification that the screenshot was saved
 | 
						|
    --cursor: Capture cursor in the screenshot
 | 
						|
    --edit: Once the screenshot is taken, edit it first with swappy
 | 
						|
    --delay [MILISECONDS]: Wait for given time until the screenshot is taken
 | 
						|
    --target [TARGET]: (REQUIRED) What should be captured
 | 
						|
Variables:
 | 
						|
    FILE: A path to a .png image file for output, or '-' to pipe to STDOUT
 | 
						|
    MILISECONDS: Number of miliseconds; Must be a whole, non-negative number!
 | 
						|
    TARGET: Area on screen; can be one of:
 | 
						|
        - activewin: Currently active window
 | 
						|
        - window: Manually select a window
 | 
						|
        - activemon: Currently active monitor (output)
 | 
						|
        - monitor: Manually select a monitor
 | 
						|
        - all: Everything (all visible monitors/outputs)
 | 
						|
        - area: Manually select a region
 | 
						|
EOF
 | 
						|
            exit 0
 | 
						|
            ;;
 | 
						|
        --notify)
 | 
						|
            NOTIFY=yes
 | 
						|
            shift
 | 
						|
            ;;
 | 
						|
        --cursor)
 | 
						|
            CURSOR=yes
 | 
						|
            shift
 | 
						|
            ;;
 | 
						|
        --edit)
 | 
						|
            EDIT=yes
 | 
						|
            shift
 | 
						|
            ;;
 | 
						|
        --target)
 | 
						|
            if [ -z "$TARGET" ]; then
 | 
						|
                case "$2" in
 | 
						|
                    activewin|window|activemon|monitor|all|area)
 | 
						|
                        TARGET="$2"
 | 
						|
                        shift 2
 | 
						|
                        ;;
 | 
						|
                    *)
 | 
						|
                        die "Invalid target (see TARGET variable in --help)"
 | 
						|
                        ;;
 | 
						|
                esac
 | 
						|
            else
 | 
						|
                die "Only one target can be passed."
 | 
						|
            fi
 | 
						|
            ;;
 | 
						|
        --delay)
 | 
						|
            case "$2" in
 | 
						|
                ''|*[!0-9]*)
 | 
						|
                    die "Argument after --delay must be an amount of MILISECONDS"
 | 
						|
                    ;;
 | 
						|
                *)
 | 
						|
                    DELAY="$2"
 | 
						|
                    shift 2
 | 
						|
                    ;;
 | 
						|
            esac
 | 
						|
            ;;
 | 
						|
 | 
						|
        --copy)
 | 
						|
            if [ -z "$SAVE_METHOD" ]; then
 | 
						|
                SAVE_METHOD="copy"
 | 
						|
                shift
 | 
						|
            else
 | 
						|
                die "Only one method can be passed."
 | 
						|
            fi
 | 
						|
            ;;
 | 
						|
        --save)
 | 
						|
            if [ -z "$SAVE_METHOD" ]; then
 | 
						|
                SAVE_METHOD="save"
 | 
						|
                SAVE_FILE="$2"
 | 
						|
                shift 2
 | 
						|
            else
 | 
						|
                die "Only one method can be passed."
 | 
						|
            fi
 | 
						|
            ;;
 | 
						|
        --copysave)
 | 
						|
            if [ -z "$SAVE_METHOD" ]; then
 | 
						|
                SAVE_METHOD="copysave"
 | 
						|
                SAVE_FILE="$2"
 | 
						|
                shift 2
 | 
						|
            else
 | 
						|
                die "Only one method can be passed."
 | 
						|
            fi
 | 
						|
            ;;
 | 
						|
        *)
 | 
						|
            die "Unrecognized argument: $1"
 | 
						|
            ;;
 | 
						|
    esac
 | 
						|
done
 | 
						|
 | 
						|
# Screenshot functions
 | 
						|
 | 
						|
takeScreenshot() {
 | 
						|
    FILE="$1"
 | 
						|
    GEOM="$2"
 | 
						|
 | 
						|
    ARGS=()
 | 
						|
    [ "$CURSOR" = "yes" ] && ARGS+=("-c")
 | 
						|
    [ -n "$GEOM" ] && ARGS+=("-g" "$GEOM")
 | 
						|
    ARGS+=("$FILE")
 | 
						|
 | 
						|
    sleep "$DELAY"e-3
 | 
						|
    grim "${ARGS[@]}" || die "Unable to invoke grim"
 | 
						|
}
 | 
						|
 | 
						|
takeEditedScreenshot() {
 | 
						|
    FILE="$1"
 | 
						|
    GEOM="$2"
 | 
						|
 | 
						|
    if [ "$EDIT" = "yes" ]; then
 | 
						|
        takeScreenshot - "$GEOM" | swappy -f - -o "$FILE" || die "Unable to invoke swappy"
 | 
						|
    else
 | 
						|
        takeScreenshot "$FILE" "$GEOM"
 | 
						|
    fi
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
# Obtain the geometry for screenshot to be taken at
 | 
						|
 | 
						|
if [ "$TARGET" = "area" ]; then
 | 
						|
    GEOM="$(slurp -d)"
 | 
						|
    if [ -z "$GEOM" ]; then
 | 
						|
        die "No area selected" 2 normal
 | 
						|
    fi
 | 
						|
    WHAT="Area"
 | 
						|
elif [ "$TARGET" = "all" ]; then
 | 
						|
    GEOM=""
 | 
						|
    WHAT="Screen"
 | 
						|
elif [ "$TARGET" = "activewin" ]; then
 | 
						|
    FOCUSED="$(hyprctl activewindow -j)"
 | 
						|
    GEOM="$(echo "$FOCUSED" | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')"
 | 
						|
    APP_ID="$(echo "$FOCUSED" | jq -r '.class')"
 | 
						|
    WHAT="$APP_ID window"
 | 
						|
elif [ "$TARGET" = "window" ]; then
 | 
						|
    WORKSPACES="$(hyprctl monitors -j | jq -r 'map(.activeWorkspace.id)')"
 | 
						|
    WINDOWS="$(hyprctl clients -j | jq -r --argjson workspaces "$WORKSPACES" 'map(select([.workspace.id] | inside($workspaces)))' )"
 | 
						|
    GEOM=$(echo "$WINDOWS" | jq -r '.[] | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' | slurp -r)
 | 
						|
    if [ -z "$GEOM" ]; then
 | 
						|
        die "No window selected" 2 normal
 | 
						|
    fi
 | 
						|
    WHAT="Window"
 | 
						|
elif [ "$TARGET" = "activemon" ]; then
 | 
						|
    ACTIVEMON="$(hyprctl monitors -j | jq -r '.[] | select(.focused == true)')"
 | 
						|
    GEOM="$(echo "$ACTIVEMON" | jq -r '"\(.x),\(.y) \(.width)x\(.height)"')"
 | 
						|
    WHAT="$(echo "$ACTIVEMON" | jq -r '.name')"
 | 
						|
elif [ "$TARGET" = "monitor" ]; then
 | 
						|
    GEOM="$(slurp -o)"
 | 
						|
    if [ -z "$GEOM" ]; then
 | 
						|
        die "No monitor selected" 2 normal
 | 
						|
    fi
 | 
						|
    WHAT="Monitor"
 | 
						|
else
 | 
						|
    if [ -z "$TARGET" ]; then
 | 
						|
        die "No target specified!"
 | 
						|
    else
 | 
						|
        die "Unknown target: $SAVE_METHOD"
 | 
						|
    fi
 | 
						|
fi
 | 
						|
 | 
						|
# Invoke grim and capture the screenshot
 | 
						|
 | 
						|
if [ "$SAVE_METHOD" = "save" ]; then
 | 
						|
    takeEditedScreenshot "$SAVE_FILE" "$GEOM"
 | 
						|
    notify-send -a screenshot "Success" "$WHAT screenshot saved" -i "$(realpath "$SAVE_FILE")"
 | 
						|
elif [ "$SAVE_METHOD" = "copy" ]; then
 | 
						|
    TEMP_FILE="$(mktemp --suffix=.png)"
 | 
						|
    takeEditedScreenshot "-" "$GEOM" | tee "$TEMP_FILE" | wl-copy --type image/png || die "Clipboard error"
 | 
						|
    notify-send -a screenshot "Success" "$WHAT screenshot copied" -i "$(realpath "$TEMP_FILE")" && rm "$TEMP_FILE"
 | 
						|
elif [ "$SAVE_METHOD" = "copysave" ]; then
 | 
						|
    takeEditedScreenshot "-" "$GEOM" | tee "$SAVE_FILE" | wl-copy --type image/png || die "Clipboard error"
 | 
						|
    notify-send -a screenshot "Success" "$WHAT screenshot copied and saved" -i "$(realpath "$SAVE_FILE")"
 | 
						|
else
 | 
						|
    if [ -z "$SAVE_METHOD" ]; then
 | 
						|
        die "No save method specified!"
 | 
						|
    else
 | 
						|
        die "Unknown save method: $SAVE_METHOD"
 | 
						|
    fi
 | 
						|
fi
 |