Skip to main content
Version: 2.1 (dev)

CLI Control somewm-only

somewm-client is SomeWM's IPC tool for controlling the compositor from scripts and the command line. It communicates with SomeWM via a Unix socket.

note

AwesomeWM has its own CLI tool (awesome-client), but it uses a different protocol. This guide covers somewm-client, which is specific to SomeWM.

tip

To try commands without affecting your real session, run them against a nested instance via Testing with a nested compositor.

Basic Usage​

Check If Running​

# Prints PONG if SomeWM is running
somewm-client ping

Help​

# Usage and the flag list
somewm-client --help

# Every command registered in this build
somewm-client commands

There is no per-group help verb. somewm-client commands prints the authoritative list, and the reference documents the arguments.

Everyday Control​

The somewm-client reference documents the full command surface (clients, tags, screens, input, screenshots, session). A taste of what one-liners cover:

somewm-client client list                   # windows with IDs
somewm-client client info focused # everything about the focused window
somewm-client client focus 3 # focus by ID
somewm-client tag view 2 # switch workspace by index
somewm-client screen scale 1.5 # set focused screen scale
somewm-client screenshot save ~/shot.png # capture to file
somewm-client lock # lock the session

tag view takes an index, not a tag name.

lock requires a lock surface to be registered (i.e., require("lockscreen").init() in rc.lua).

Tune Input Devices at Runtime somewm-only​

Try input settings live, then persist the keepers in rc.lua:

somewm-client input tap_to_click 1     # set
somewm-client input accel_speed # query (no argument)

All 21 IPC-reachable properties are listed in the input commands reference. Run somewm-client input with no arguments to dump them with their current values.

Lua Evaluation​

eval runs arbitrary Lua in SomeWM's context. Reach for it only when no dedicated command covers the job, since command output is parseable and survives API changes:

# Version, focused window, client count: use the commands
somewm-client version
somewm-client client info focused
somewm-client client list | grep -c '^id='

# Move the focused window to tag 2
somewm-client client movetotag 2

# Float the focused window (get-or-set, not a toggle)
somewm-client client floating focused true

What eval is actually for:

# Simple expression
somewm-client eval "return 1 + 1"
# Output: 2

# Toggle rather than set, which no command does
somewm-client eval "local c = client.focus; if c then c.floating = not c.floating end"

# Reach state no command exposes
somewm-client eval "return awesome.startup_errors"

Eval for Scripting​

Two constraints decide how these get written, and neither announces itself:

  • One line only. The protocol is one command per line. In a multi-line string only the first line runs and the rest is silently dropped; a string starting with a newline fails with Missing Lua code to evaluate. Use semicolons.
  • Only capi globals are in scope. client, screen, tag, mouse, awesome, root, and require. awful, gears, beautiful, naughty, wibox, and ruled are nil until you require them.
# Windows that are floating right now, one per line
somewm-client eval "local r = {}; for _, c in ipairs(client.get()) do if c.floating then table.insert(r, c.id .. ' ' .. (c.name or '')) end end; return table.concat(r, '\n')"

# Anything from the Lua libraries needs a require first
somewm-client eval "local awful = require('awful'); return awful.screen.focused().index"

Two more things that bite in scripts:

  • Use c.id, not c.window. c.window is an X11 window ID, so it is 0 for native Wayland clients and only meaningful for XWayland ones. c.id is what client list prints and what every somewm-client client ... command accepts.
  • Replies begin with an OK line and end with a blank line. Filter on the payload (grep '^id=') rather than capturing the reply whole.

Exit Codes in Scripts​

Exit codes distinguish "not running" from "bad command" (full table):

if somewm-client ping > /dev/null 2>&1; then
echo "SomeWM is running"
else
echo "SomeWM is not running"
fi

Scripting Examples​

Rofi Window Switcher​

#!/bin/bash
# window-switcher.sh

# Get window list, dropping the OK line and the trailing blank
windows=$(somewm-client client list | grep '^id=')

# Show in rofi (display full line, return selected)
selected=$(echo "$windows" | rofi -dmenu -p "Window")

if [ -n "$selected" ]; then
# Extract numeric ID from "id=N ..."
id=$(echo "$selected" | sed 's/id=\([0-9]*\).*/\1/')
somewm-client client focus "$id"
fi

Toggle Layout Script​

#!/bin/bash
# toggle-layout.sh

current=$(somewm-client input xkb_layout)

if [ "$current" = "us" ]; then
somewm-client input xkb_layout "de"
else
somewm-client input xkb_layout "us"
fi

Polybar Integration​

# In polybar config
[module/layout]
type = custom/script
exec = somewm-client input xkb_layout
interval = 1
click-left = somewm-client input xkb_layout "$([ $(somewm-client input xkb_layout) = 'us' ] && echo 'de' || echo 'us')"

Focus or Launch​

#!/bin/bash
# focus-or-launch.sh <class> <command>

class="$1"
command="$2"

# Check if a window with this class exists, return its ID
window_id=$(somewm-client client list \
| grep "class=\"$class\"" \
| head -1 \
| sed 's/^id=\([0-9]*\).*/\1/')

if [ -n "$window_id" ]; then
somewm-client client focus "$window_id"
else
$command &
fi

Usage:

./focus-or-launch.sh Firefox firefox
./focus-or-launch.sh Alacritty alacritty

Workspace Indicator for Status Bars​

#!/bin/bash
# Get current tag info for status bar

somewm-client eval "local awful = require('awful'); local s = awful.screen.focused(); local t = {}; for _, tag in ipairs(s.tags) do table.insert(t, (tag.selected and '*' or '') .. tag.name .. (#tag:clients() > 0 and '+' or '')) end; return table.concat(t, ' ')" | tail -n +2

Troubleshooting​

Connection Failed​

somewm-client ping
# Error: Failed to connect to /run/user/1000/somewm-socket
# Is somewm running?
# connect: No such file or directory

Exit code 2. Check that:

  1. SomeWM is actually running
  2. The socket exists: ls /run/user/$(id -u)/somewm-*
  3. You're running as the same user as SomeWM
  4. SOMEWM_SOCKET is unset, or points at the instance you meant

Command Not Found​

somewm-client foobar
# ERROR Unknown command: foobar

Exit code 1. The compositor validates command names, not the binary, so a typo reaches the socket before it is rejected. Check the list:

somewm-client commands

Two-word commands map to one name, so client foo is reported as client.foo.

Eval Syntax Errors​

somewm-client eval "return client.focus.name"
# ERROR ./lua/awful/ipc.lua:1845: [string "return client.focus.name"]:1: attempt to index a nil value

Nothing was focused, so client.focus was nil. Guard it:

somewm-client eval "return client.focus and client.focus.name or 'none'"

Or skip the guard entirely and let the command report it: client info focused errors with No focused client.

See Also​