‹ back home

Shotman 0.2 development update

2022-08-28

These last couple of week I’ve been putting a lot of time into shotman. Shotman is a small GUI tool I wrote a few months ago. It shows a small preview window when a screenshot is saved, and has controls to copy the screenshot into clipboard or delete it right away.

The previous version was 0.1. This newly written version is to be 0.2.

About version 0.1

The initial implementation was more of a prototype than anything else. It worked, but was slow. It can take a couple of seconds to even render the window. That aside, it had a lot of quirks regarding window sizing and positioning, and its clipboard support is flaky (this was delegated to Qt, so not much control under the hood here).

A screenshot shotman v0.1.
On the upper left: shotman v0.1, showing a screenshot preview.

The slowness

The slowness is mostly due to the design; taking the screenshot was delegated to grimshot, a bash script which in turn uses grim to actually take the screenshot. The screenshot was taken, then encoded as png, saved to disk, then loaded from disk and decoded by shotman, and finally rendered on screen by shotman. This is a lot of back and forth to get pixels from the compositor back into the same compositor.

The most obvious design change I’ve made is how screenshots are taken; the new version will request that the wayland compositor make a copy of the screen into memory. Shotman will then create its window, and just tell the compositor to render that same in-memory screenshot onto the new window. Shotman doesn’t copy the screenshot around at all – it doesn’t even need to read it for rendering!

The result of this is that it’s a lot faster. It takes well under 80ms from startup to the point a window is rendered on screen on the same machine where shotman would take between 1.6 seconds (at 2560x1600px). That’s a 95% speed-up.

The thumbnail window

On shotman 0.1, the rendered window was just a regular window, and required configuring sway to make the window float and render properly. This was a very hacky approach, and wouldn’t even work on other compositors.

The 0.2 shotman now renders itself using the wlr-layer-shell wayland protocol. This lets it render as a floating widget without any custom compositor configuration, and allows it to work on any compositor exposing this protocol (for now, mostly wlroots-based compositors).

Keyboard control

Keyboard controls remain mostly the same (see the relevant section of README). Usually, after taking a screenshot one would either dismiss the window right away (Esc), or copy it to clipboard and then dismiss. It’s not meant to linger around.

It is not also possible to edit the image by pressing e. Currently, gimp is hardcoded, though I expect to make this configurable in future.

A new “nice to have” is that the h, j, k, l, keys can now be used to re-anchor the window onto different corners of the screen quickly and easily.

A pending annoyance is that, once the window is unfocused, it cannot be refocused with just the keyboard. This is because sway does not offer any mechanism for a user to re-focus a layer-shell window (with good reason too; this almost never makes sense for layer shell surface). I’m considering attaching a pop-up to an invisible layer-shell instead. Using the invisible layer-shell surface allows me to continue anchoring the window in a specific corner, but the floating pop-up can be re-focus via the usual “focus floating” mapping.

Clipboard

Regarding clipboard support, the new version handles it directly, which has resulted in far more reliable results.

Normally, pressing ctrl+c copies the image into clipboard (no need to “select anything here, this window can only copy one thing). I’m also working on copying the filepath into clipboard, so that applications can paste the file themselves too.

Copying the filepath should also provide an interesting mechanic with ctrl+x, which should allow moving the original screenshot file by just pasting it elsewhere.

Mouse and touch controls

The original version also had buttons that could be clicked. I realised I’d last used these the day I wrote the tool and never again. However, I will be implementing those in the new version as well, since I want shotman to be usable either keyboard-only, pointer-only or touch-only. The touch-only usability aspect is important since I want to be able to use this same tool to take screenshots on Linux-based phones. A fast, reliable tool for this is much needed, so I hope to be able to fill this gap early on.

Currently shotman runs on a Linux phone, but there’s no convenient way to interact with it due to being purely keyboard driven.

My intent is to include buttons for copying, deleting and closing, and also allow swiping the window towards the border of the screen to dismiss it. Fortunately, one of laptop has a touch display which should make testing this a lot simpler.

Current state and near-future plans

A screenshot shotman v0.1.
On the upper right: shotman v0.2, showing a screenshot preview. Still missing buttons (though honestly, the main focus is keyboard controls)

The newly written version work works well, fast and reliably. There are, however, several pending items that still need to be addressed. The biggest one is the ability to take a screenshot of a single window or a selected region.

There’s also a lot of edge cases and smaller details that need to be addressed all over the codebase, though this are more about cleaning up than about actual usability issues.

Filenames format is now a bit less problematic:

Screenshot.from.2022-08-28.at.10_49_36.465683503.png

This keeps files sorted in natural order (thanks to using ISO-like formats), makes them very easy for humans to recognise, and avoids issues with tools and websites that are picky about filename characters. Keeping the ms looks weird, but avoid issues when multiple screenshots are taken within a second. This last part might still change a bit in future.

I do want to look into animating the motion when the window is re-anchored from one corner onto another – but only if this keeps complexity low, which is yet to be seen.

Scaling support is still WIP, but should be ready soon.

Unfixable bugs

There’s two low-impact bugs that cannot be easily fixed:

Why not existing any tools?

Tools for taking screenshots already exist on Linux, but none of them fit the bill quite right for this use case.

The most obvious contender is grim. It is a general-purpose tool for taking screenshots, and also very easy to use in scripts. However, it was not quite right for this use case; it will save the image to disk, which then needs to be read again to render it on-screen. It’s a great tool, but not right for this particular use-case.

Shotman does one thing and one thing only, but does it well. It renders a GUI when taking a screenshot, allowing copying, deleting or keeping it. A pending feature is to press e to open the image in an editor (e.g.: GIMP), but that’s the end of its scope.

Upcoming timeline

If time permits, I hope to have a release with all these new improvements in the next week or two. I’m not entirely sure about a timeline for the touch-aspect, but after implementing that I hope to transition this project into a stable phase.

In the meantime, have a look at shotman in its new home over at sourcehut:

https://git.sr.ht/~whynothugo/shotman

Want to sponsor my work? See this page for details.

— § —