From 0fc804a42d3f39821f41144edad066954d3a4814 Mon Sep 17 00:00:00 2001 From: Yorick Barbanneau Date: Mon, 1 Sep 2025 00:58:03 +0200 Subject: [PATCH] refactor(sway): rework the whole screen capture part --- modules/home-manager/desktop/sway/default.nix | 3 + .../desktop/sway/includes/files/screencapt.sh | 160 ++++++++++++++++++ .../desktop/sway/includes/sway.nix | 91 +++------- 3 files changed, 184 insertions(+), 70 deletions(-) create mode 100755 modules/home-manager/desktop/sway/includes/files/screencapt.sh diff --git a/modules/home-manager/desktop/sway/default.nix b/modules/home-manager/desktop/sway/default.nix index 2b2dc67..024cb23 100644 --- a/modules/home-manager/desktop/sway/default.nix +++ b/modules/home-manager/desktop/sway/default.nix @@ -107,6 +107,8 @@ in # emojione font-awesome grim + hicolor-icon-theme + jq lato liberation_ttf libertine @@ -117,6 +119,7 @@ in noto-fonts-cjk-sans slurp wl-clipboard + wl-screenrec xdg-utils ]; diff --git a/modules/home-manager/desktop/sway/includes/files/screencapt.sh b/modules/home-manager/desktop/sway/includes/files/screencapt.sh new file mode 100755 index 0000000..16b8375 --- /dev/null +++ b/modules/home-manager/desktop/sway/includes/files/screencapt.sh @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +set -eu -o pipefail + +APP_NAME="ScreenCapt" + +declare -A COMMAND +COMMAND=( + [screenshot]="grim" + [video]="wl-screenrec" +) +declare -A ICONS +ICONS=( + ["screenshot"]="accessories-screenshot" + ["video"]="record-desktop" +) + +declare -A OUTPUT_DIR +OUTPUT_DIR=( + ["screenshot"]="${XDG_PICTURES_DIR:-"~/pictures"}/screenshots" + ["video"]="${XDG_VIDEOS_DIR:="~/videos"}/screenrecords" +) + +declare -A OUTPUT_FILE_EXT +OUTPUT_FILE_EXT=( + ["screenshot"]="png" + ["video"]="mp4" +) + +TO_FILE=0 +RECORD_AUDIO=0 +ACTION="screenshot" +REGION_TYPE="window" + +notify() { + local summary message command + filename="${1:-""}" + summary="New ${ACTION}!" + if [[ $TO_FILE -eq 1 ]]; then + message+="Available in ${filename##*/}" + else + message+="Available in the clipboard" + fi + command=(notify-send "${summary}" --app-name="$APP_NAME") + if [[ -n "$filename" && "$ACTION" == "screenshots" ]]; then + command+=(--icon="${filename}") + else + command+=("--icon=${ICONS[$ACTION]}") + fi + command+=("$message") + "${command[@]}" +} + +process_args() { + while :; do + case ''${1:-""} in + screenshot) + ACTION="$1" + ;; + + video) + # If a video record is in progress Stop it + if pgrep "wl-screenrec"; then + kill -s SIGINT $(pgrep "wl-screenrec") + exit 0 + fi + TO_FILE=1 + ACTION="$1" + ;; + -r | --region) + if [[ "${2:-""}" =~ ^(r|region|s|screen|w|window)$ ]]; then + REGION_TYPE="$2" + else + exit 1 + fi + ;; + -f | --file) + TO_FILE=1 + ;; + -a | --with-audio) + RECORD_AUDIO=1 + ;; + *) + break + ;; + esac + shift + done +} + +get_app_name() { + local appname + case "$REGION_TYPE" in + r | region) + appname="region" + ;; + s | screen) + appname="screen" + ;; + w | window) + appname=$(swaymsg -t get_tree | jq -r '.. | ((.nodes? // empty) + (.floating_nodes? // empty))[] | select(.visible and .pid and .focused) | "\(.app_id)"') + ;; + esac + printf "%s" "${appname:-}" +} + +get_region() { + local region switch + case "$REGION_TYPE" in + r | region) + region=$(slurp) + switch="-g" + ;; + s | screen) + region=$(swaymsg -t get_outputs | jq -r '.[] | select(.focused) | "\(.name)"') + switch="-o" + ;; + w | window) + region=$(swaymsg -t get_tree | jq -r '.. | ((.nodes? // empty) + (.floating_nodes? // empty))[] | select(.visible and .pid and .focused) | .rect | "\(.x),\(.y) \(.width)x\(.height)"') + switch="-g" + ;; + esac + printf "%s%s" "${switch:-}" "${region:-}" +} + +get_output_filename() { + local date + printf -v date '%(%F_%H.%M.%S)T' + printf "%s/%s-%s.%s" "${OUTPUT_DIR[$ACTION]}" "$date" "$(get_app_name)" "${OUTPUT_FILE_EXT[$ACTION]}" +} + +ensure_directories_exist() { + for dir in "${!OUTPUT_DIR[@]}"; do + mkdir -p "${OUTPUT_DIR[$dir]}" + done +} + +main() { + process_args "$@" + ensure_directories_exist + local command + command=("${COMMAND[$ACTION]}" "$(get_region)") + if [[ "$TO_FILE" -eq 1 ]]; then + local filename + filename=$(get_output_filename) + if [[ "$ACTION" = "video" ]]; then + if [[ "$RECORD_AUDIO" -eq 1 ]]; then + command+=(--audio) + fi + command+=(-f) + fi + command+=("$filename") + "${command[@]}" + else + "${command[@]}" - | wl-copy + fi + notify "${filename:-""}" + exit 0 +} + +main "$@" diff --git a/modules/home-manager/desktop/sway/includes/sway.nix b/modules/home-manager/desktop/sway/includes/sway.nix index ef2ebbc..4f0874c 100644 --- a/modules/home-manager/desktop/sway/includes/sway.nix +++ b/modules/home-manager/desktop/sway/includes/sway.nix @@ -89,9 +89,10 @@ in "${mod}+a" = "focus parent"; "${mod}+Shift+minus" = "move scratchpad"; "${mod}+minus" = "scratchpad show"; - "${mod}+p" = "exec screenshot window"; - "${mod}+Shift+p" = "exec screenshot screen"; + "${mod}+p" = "exec screencapt --region window"; + "${mod}+Shift+p" = "exec screencapt --region screen"; "${mod}+Alt+p" = "mode screenshot"; + "${mod}+Alt+r" = "mode screenrecord"; # Media stuff "${mod}+F1" = "exec ${pkgs.brightnessctl}/bin/brightnessctl s 1%-"; "${mod}+F2" = "exec ${pkgs.brightnessctl}/bin/brightnessctl s +1%"; @@ -122,12 +123,22 @@ in "Escape" = "mode default"; }; "screenshot" = { - "s" = "exec screenshot screen; mode default"; - "Shift+s" = "exec screenshot screen -f; mode default"; - "r" = "exec screenshot region; mode default"; - "Shift+r" = "exec screenshot region -f; mode default"; - "w" = "exec screenshot window; mode default"; - "Shift+w" = "exec screenshot window -f; mode default"; + "s" = "exec screencapt --region screen; mode default"; + "Shift+s" = "exec screencapt --region screen -f; mode default"; + "r" = "exec screencapt --region region; mode default"; + "Shift+r" = "exec screencapt --region region -f; mode default"; + "w" = "exec screencapt --region window; mode default"; + "Shift+w" = "exec screencapt --region window -f; mode default"; + "Return" = "mode default"; + "Escape" = "mode default"; + }; + "screenrecord" = { + "s" = "exec screencapt video --region screen; mode default"; + "Shift+s" = "exec screencapt --region video screen -a; mde default"; + "r" = "exec screencapt video --region region; mode default"; + "Shift+r" = "exec screencapt video --region region -a; mode default"; + "w" = "exec screencapt video --region window -f ; mode default"; + "Shift+w" = "exec screencapt --region video window -a; mode default"; "Return" = "mode default"; "Escape" = "mode default"; }; @@ -228,69 +239,9 @@ in title_align right ''; }; - home.file.".local/bin/screenshot" = { + home.file.".local/bin/screencapt" = { executable = true; - text = '' - #!/usr/bin/env bash - set -eu -o pipefail - - SWAYMSG="${pkgs.sway}/bin/swaymsg" - JQ="${pkgs.jq}/bin/jq" - WLCOPY="${pkgs.wl-clipboard}/bin/wl-copy" - GRIM="${pkgs.grim}/bin/grim" - SLURP="${pkgs.slurp}/bin/slurp" - - # What we want to screenshot - case ''${1:-} in - region) - RECT=$(''$SLURP) - APPNAME="-region" - OUTPUT=$(''${SWAYMSG} -t get_outputs | ''${JQ} -r '.[] | select(.focused) | "\(.name)"') - COMMAND=( - "''${GRIM}" - -g - "''$RECT" - ) - ;; - screen) - OUTPUT=$(''${SWAYMSG} -t get_outputs | ''${JQ} -r '.[] | select(.focused) | "\(.name)"') - COMMAND=( - "''${GRIM}" - -o - "''${OUTPUT}" - ) - ;; - window) - RECT=$(''${SWAYMSG} -t get_tree | ''${JQ} -r '.. | ((.nodes? // empty) + (.floating_nodes? // empty))[] | select(.visible and .pid and .focused) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' ) - APPNAME=$(''${SWAYMSG} -t get_tree | ''${JQ} -r '.. | ((.nodes? // empty) + (.floating_nodes? // empty))[] | select(.visible and .pid and .focused) | "\(.app_id)"') - COMMAND=( - "''${GRIM}" - -g - "''${RECT}" - ) - ;; - *) - >&2 printf "Can't understand what you need\n" - exit 1 - esac - - # Where we want to put it - case ''${2:-"-c"} in - -c|--clipboard) - COMMAND+=(-) - "''${COMMAND[@]}" | ''${WLCOPY} - ;; - -f|--file) - PICTURES_DIR="''${XDG_PICTURES_DIR}/screenshots" - mkdir -p "''${PICTURES_DIR}" - printf -v DATE '%(%F_%H.%M.%S)T' - printf -v FILE "%s/%s-%s%s.png" "''${PICTURES_DIR}" "''${DATE}" "''${OUTPUT:-""}" "''${APPNAME:-""}" - "''${COMMAND[@]}" "''${FILE//\"/}" - ;; - esac - exit 0 - ''; + source = ./files/screencapt.sh; }; - }; }