An image sharing menu for swaywm with imv

Recreating the share menu from iOS in Sway

📅 7 Aug 2023 | ~3 min read
Tags: #linux

Recently, I have been wanting to include more images within the notes that I take in Emacs org-mode. Previously I had been using this script to take screenshots, but it was something that I never really used it to its full potential. I bound the script in my sway config as below:

bindsym print exec ~/bin/screenshot.sh

I had the idea to implement a photo sharing menu similar to what you get on an iPhone. I wanted to be able to see the image and take actions on it with a single key-press. I knew that my current image viewer imv could be configured with custom key-bindings, so I decided that this would be the best way to approach the problem.

A quick reference to the imv manpage revealed that running the program with the -w flag allows for a custom window title which made it trivial to run custom window rules and enable a centred floating window.

for_window [title="imv floating"] {
  floating enable}

For my use case, I realised that it was better for me to save all files to disk and remove the option of copying images directly to the clipboard, so I removed all the necessary options from the file that Robbie wrote above.

shotdir=$HOME/screenshots
filename="${shotdir}/screenshot-$(date +'%Y-%m-%d-%H%M%S.png')"

screenshot_area_to_file="Screenshot area to file"
screenshot_window_to_file="Screenshot focused window to file"
screenshot_monitor_to_file="Screenshot focused monitor to file"

# Store each option in a single string seperated by newlines.
options="$screenshot_window_to_file\n"
options+="$screenshot_area_to_file\n"
options+="$screenshot_monitor_to_file"

# Prompt the user with tofi.
choice="$(echo -e "$options" | tofi)"

case $choice in
    $screenshot_area_to_file)
        grim -g "$(slurp)" "$filename"
        imv -w "imv floating" "$filename"
        ;;
    $screenshot_window_to_file)
        grim -g "$(swaymsg -t get_tree | jq -j '.. | select(.type?) | select(.focused).rect | "\(.x),\(.y) \(.width)x\(.height)"')" "$filename"
        imv -w "imv floating" "$filename"
        ;;
    $screenshot_monitor_to_file)
        grim -o $(swaymsg -t get_outputs | jq -r '.[] | select(.focused) | .name') "$filename"
        imv -w "imv floating" "$filename"
        ;;
esac

With this done, I could now start defining the commands that I want to use from my menu.

The commands

At the moment, I only have three commands, and I have been using the first two on a daily basis.

[binds]

# Rotate the currently open image by 90 degrees by pressing 'R'
<Shift+R> = exec mogrify -rotate 90 "$imv_current_file"
# Delete and then close an open image by pressing 'X'
<Shift+X> = exec rm "$imv_current_file"; quit

f = fullscreen

y = exec wl-copy "[[""$imv_current_file""]]"
e = exec sh ~/bin/imv-dired-jump.sh

t = exec tesseract "$imv_current_file" - | wl-copy
#!/bin/sh
#
# Proxy the `swaymsg` command to the focused window.
imv "$@" &
imv_pid = $!

file="$imv_current_file"

emacsclient -e -c "(dired-jump nil \"""$file""\")" &
killall imv-wayland

Future ideas

✉️ Respond by Email.