Screenshots
SomeWM provides built-in screenshot support through awful.screenshot (interactive region selection), somewm-client (CLI), and external Wayland-native tools like grim and slurp.
Method 1: awful.screenshot (Interactive)
awful.screenshot provides a built-in interactive snipping tool. It captures the desktop, shows an overlay, and lets you draw a selection rectangle.
Basic Usage
awful.key({ modkey }, "Print", function()
local s = awful.screenshot({ interactive = true })
s:refresh()
end, { description = "interactive screenshot", group = "screenshot" }),
This captures the screen, shows it as a fullscreen overlay, and lets you drag a rectangle. The screenshot saves to $HOME by default.
Customizing Save Location
awful.key({ modkey }, "Print", function()
local s = awful.screenshot({
interactive = true,
directory = os.getenv("HOME") .. "/Pictures/screenshots/",
prefix = "shot",
})
s:refresh()
end, { description = "interactive screenshot", group = "screenshot" }),
Smooth Interactive Mode on HiDPI
On HiDPI displays, the default overlay repaints the full captured image on every mouse move, which can be slow. A faster approach: hide the screenshot background and show only a dimmed overlay over the live desktop. The final crop still uses the pre-captured surface, so image quality is unaffected.
awful.key({ modkey }, "Print", function()
local s = awful.screenshot({ interactive = true })
s:connect_signal("snipping::start", function(self)
if self._private.frame then
-- Hide the screenshot background, show selection over live desktop
self._private.imagebox.visible = false
self._private.frame.bg = "#00000040"
self._private.frame.surface_scale = 1.0
end
end)
s:refresh()
end, { description = "interactive screenshot", group = "screenshot" }),
Why this works:
imagebox.visible = falseprevents expensive image repaints on every mouse movebg = "#00000040"adds a semi-transparent dim so the selection rectangle is visible against the live desktopsurface_scale = 1.0keeps even the dim overlay redraws cheap (no HiDPI upscaling)accept()still crops from the pre-captured surface, so the saved screenshot is full quality
Notifications on Save
awful.key({ modkey }, "Print", function()
local s = awful.screenshot({
interactive = true,
directory = os.getenv("HOME") .. "/Pictures/screenshots/",
})
s:connect_signal("snipping::start", function(self)
if self._private.frame then
self._private.imagebox.visible = false
self._private.frame.bg = "#00000040"
self._private.frame.surface_scale = 1.0
end
end)
s:connect_signal("file::saved", function(self, path)
naughty.notify {
title = "Screenshot saved",
text = path,
timeout = 3,
}
end)
s:refresh()
end, { description = "interactive screenshot", group = "screenshot" }),
Delayed Capture
Use auto_save_delay to wait before entering interactive mode (useful for capturing menus):
local s = awful.screenshot({
interactive = true,
auto_save_delay = 3,
})
s:connect_signal("timer::tick", function(self, remaining)
naughty.notify { title = "Screenshot in " .. remaining .. "s", timeout = 1 }
end)
Method 2: somewm-client somewm-only
The simplest method - use somewm-client screenshot:
# Full screen screenshot
somewm-client screenshot
# Save to specific path
somewm-client screenshot ~/Pictures/screenshot.png
This captures the focused screen and saves to the specified path (or a default location).
From Lua
-- Take screenshot via IPC
awful.spawn("somewm-client screenshot ~/Pictures/screenshot.png")
Method 3: grim + slurp
For more flexibility, use the external Wayland-native tools:
# Install on Arch
pacman -S grim slurp wl-clipboard
# Install on Debian/Ubuntu
apt install grim slurp wl-clipboard
Full Screen
grim ~/Pictures/screenshot.png
Select Region
grim -g "$(slurp)" ~/Pictures/screenshot.png
slurp lets you draw a rectangle to capture.
Specific Output (Monitor)
# List outputs
grim -l
# Capture specific output
grim -o DP-1 ~/Pictures/screenshot.png
To Clipboard
# Full screen to clipboard
grim - | wl-copy
# Region to clipboard
grim -g "$(slurp)" - | wl-copy
Keybinding Setup
Add these keybindings to your rc.lua:
awful.keyboard.append_global_keybindings({
-- Print: Full screen screenshot
awful.key({}, "Print", function()
local filename = os.date("~/Pictures/screenshot_%Y%m%d_%H%M%S.png")
awful.spawn.with_shell("grim " .. filename)
naughty.notify { title = "Screenshot", text = "Saved to " .. filename }
end, { description = "screenshot full screen", group = "screenshot" }),
-- Shift+Print: Select region
awful.key({ "Shift" }, "Print", function()
local filename = os.date("~/Pictures/screenshot_%Y%m%d_%H%M%S.png")
awful.spawn.with_shell('grim -g "$(slurp)" ' .. filename)
end, { description = "screenshot region", group = "screenshot" }),
-- Ctrl+Print: Full screen to clipboard
awful.key({ "Control" }, "Print", function()
awful.spawn.with_shell("grim - | wl-copy")
naughty.notify { title = "Screenshot", text = "Copied to clipboard" }
end, { description = "screenshot to clipboard", group = "screenshot" }),
-- Ctrl+Shift+Print: Region to clipboard
awful.key({ "Control", "Shift" }, "Print", function()
awful.spawn.with_shell('grim -g "$(slurp)" - | wl-copy')
end, { description = "screenshot region to clipboard", group = "screenshot" }),
})
Screenshot Module
For a reusable screenshot module, create ~/.config/somewm/screenshot.lua:
-- screenshot.lua
local awful = require("awful")
local naughty = require("naughty")
local screenshot = {}
-- Default save directory
screenshot.directory = os.getenv("HOME") .. "/Pictures"
-- Generate timestamped filename
local function filename()
return screenshot.directory .. "/" .. os.date("screenshot_%Y%m%d_%H%M%S.png")
end
-- Full screen
function screenshot.full()
local f = filename()
awful.spawn.easy_async_with_shell("grim " .. f, function()
naughty.notify {
title = "Screenshot",
text = "Saved: " .. f,
timeout = 3,
}
end)
end
-- Region selection
function screenshot.region()
local f = filename()
awful.spawn.with_shell('grim -g "$(slurp)" ' .. f)
end
-- Full screen to clipboard
function screenshot.full_clipboard()
awful.spawn.easy_async_with_shell("grim - | wl-copy", function()
naughty.notify {
title = "Screenshot",
text = "Copied to clipboard",
timeout = 3,
}
end)
end
-- Region to clipboard
function screenshot.region_clipboard()
awful.spawn.with_shell('grim -g "$(slurp)" - | wl-copy')
end
-- Focused window
function screenshot.window()
local c = client.focus
if not c then return end
local g = c:geometry()
local f = filename()
local region = string.format("%d,%d %dx%d", g.x, g.y, g.width, g.height)
awful.spawn.with_shell('grim -g "' .. region .. '" ' .. f)
end
return screenshot
Use in rc.lua:
local screenshot = require("screenshot")
awful.keyboard.append_global_keybindings({
awful.key({}, "Print", screenshot.full),
awful.key({ "Shift" }, "Print", screenshot.region),
awful.key({ "Control" }, "Print", screenshot.full_clipboard),
awful.key({ "Control", "Shift" }, "Print", screenshot.region_clipboard),
awful.key({ modkey }, "Print", screenshot.window),
})
Screenshot with Delay
For menus or dropdowns that dismiss on focus loss:
# 3 second delay
sleep 3 && grim ~/Pictures/screenshot.png
# Or in Lua
awful.spawn.with_shell("sleep 3 && grim ~/Pictures/screenshot.png")
Screenshot Specific Window
Using window geometry from Lua:
awful.key({ modkey }, "Print", function()
local c = client.focus
if not c then return end
local g = c:geometry()
local filename = os.date("~/Pictures/window_%Y%m%d_%H%M%S.png")
awful.spawn.with_shell(string.format(
'grim -g "%d,%d %dx%d" %s',
g.x, g.y, g.width, g.height, filename
))
end)
Annotating Screenshots
After capturing, open in an annotation tool:
-- Take screenshot and open in swappy for annotation
awful.key({}, "Print", function()
awful.spawn.with_shell('grim -g "$(slurp)" - | swappy -f -')
end)
Install swappy:
pacman -S swappy # Arch
apt install swappy # Debian/Ubuntu
Troubleshooting
grim: failed to create screenshot
Ensure grim is installed and you're running under Wayland:
echo $WAYLAND_DISPLAY # Should show something like "wayland-0"
slurp not working
Make sure your compositor supports the wlr-layer-shell protocol. SomeWM supports this by default.
Clipboard not working
Install wl-clipboard:
pacman -S wl-clipboard
# or
apt install wl-clipboard
Test it:
echo "test" | wl-copy
wl-paste # Should print "test"
See Also
- Screenshots Concepts - How the capture pipeline works
- awful.screenshot Reference - Full API documentation
- CLI Control - More somewm-client commands
- Keybindings - Setting up keybindings