#!/usr/bin/env zsh set -euo pipefail readonly LOG_FILE="${HOME}/.screenshots.log" readonly NOTIFY_TIME_LOW_MS=1500 readonly NOTIFY_TIME_NORMAL_MS=3000 readonly NOTIFY_TIME_CRITICAL_MS=5000 readonly CODE_CANCELED=22 readonly NOTIFY_LABEL="Screenshot" readonly SCREENSHOTS_DIR="${SCREENSHOTS_DIR:-${HOME}/Pictures/screenshots}" readonly TIMESTAMP_FORMAT="%H-%M-%S_%Y-%m-%d" readonly NOOPENGL="${NOOPENGL:-}" readonly NONOTIFY="${NONOTIFY:-}" mkdir -p "${SCREENSHOTS_DIR}" _notify() { local -r level="${1}" local -r notify_time_ms="${2}" local -r msg="${3}" if [ -n "${NONOTIFY}" ]; then return 0 fi notify-send --urgency "${level}" \ --expire-time "${notify_time_ms}" \ "${NOTIFY_LABEL}" \ "${msg}" } _notify_low() { _notify low "${NOTIFY_TIME_LOW_MS}" "${1}" } _notify_normal() { _notify normal "${NOTIFY_TIME_NORMAL_MS}" "${1}" } _notify_error() { _notify critical "${NOTIFY_TIME_CRITICAL_MS}" "Error: ${1}" } _capture_select() { local -r pipe="$(mktemp)" grim -g "$(slurp 2>"${pipe}")" - local -r code="$?" if grep -F "selection cancelled" <"${pipe}"; then rm "${pipe}" return "${CODE_CANCELED}" fi cat "${pipe}" 1>&2 rm "${pipe}" return "${code}" } _capture_entire() { grim - } _capture_window() { grim -g "$(swaymsg -t get_tree | jq -r '.. | select(.type? == "con" and .focused == true) | .rect | "\(.x),\(.y) \(.width)x\(.height)"')" - } _copy_to_clipboard() { wl-copy -t image/png } _save_to_file() { cat > "${1}" } _process_screenshot() { local -r capture_func="${1}" local -r output_func="${2}" local -r success_msg="${3}" local -r error_msg="${4}" local -r output_arg="${5:-}" if ! ${capture_func} | ${output_func} "${output_arg}"; then if (( ${pipestatus[1]} == "${CODE_CANCELED}" )); then _notify_low "Selection was cancelled by keystroke." return 0 fi _notify_error "${error_msg}" return 1 fi _notify_normal "${success_msg}" return 0 } _select_save() { local -r filename="${SCREENSHOTS_DIR}/selection_$(date +"${TIMESTAMP_FORMAT}").png" _process_screenshot _capture_select \ _save_to_file \ "Selection saved to ${filename}" \ "Failed to save selection screenshot" \ "${filename}" } _select_copy() { _process_screenshot _capture_select \ _copy_to_clipboard \ "Selection copied to clipboard" \ "Failed to copy selection to clipboard" } _window_save() { local -r filename="${SCREENSHOTS_DIR}/window_$(date +"${TIMESTAMP_FORMAT}").png" _process_screenshot _capture_window \ _save_to_file \ "Current window saved to ${filename}" \ "Failed to save Current window screenshot" \ "${filename}" } _window_copy() { _process_screenshot _capture_window \ _copy_to_clipboard \ "Current window copied to clipboard" \ "Failed to copy current window to clipboard" } _entire_save() { local -r filename="${SCREENSHOTS_DIR}/screen_$(date +"${TIMESTAMP_FORMAT}").png" _process_screenshot _capture_entire \ _save_to_file \ "Entire screen saved to ${filename}" \ "Failed to save entire screen" \ "${filename}" } _entire_copy() { _process_screenshot _capture_entire \ _copy_to_clipboard \ "Entire screen copied to clipboard" \ "Failed to copy entire screen to clipboard" } main() { if [ $# -ne 2 ]; then echo "Usage: ${0} {select|window|entire} {save|copy}" exit 1 fi local -r target="${1}" local -r action="${2}" case "${target}-${action}" in select-save) _select_save &>> "${LOG_FILE}" ;; select-copy) _select_copy &>> "${LOG_FILE}" ;; window-save) _window_save &>> "${LOG_FILE}" ;; window-copy) _window_copy &>> "${LOG_FILE}" ;; entire-save) _entire_save &>> "${LOG_FILE}" ;; entire-copy) _entire_copy &>> "${LOG_FILE}" ;; *) echo "Invalid options: target=${target}, action=${action}" echo "Available targets: select, window, entire" echo "Available actions: save, copy" exit 1 ;; esac } main "$@"