Skip to main content
Version: 1.4

Shadows somewm-only

SomeWM provides built-in compositor-level shadows for windows and wiboxes. This replaces the need for external compositors like picom, which only work on X11.

Shadows are rendered using a smoothstep gradient falloff, displayed via the wlroots scene graph. They support full customization including color, blur radius, offset, and opacity.

What gets shadows?

This feature applies to clients (application windows) and drawins/wiboxes (containers like panels and popups). Individual widgets inside a wibox do not get separate shadows. For widget-level shadow effects, use Lua/Cairo drawing techniques.

Theme Variables

Configure global shadow defaults in your theme.lua. Shadows are disabled by default and must be explicitly enabled.

Client Shadow Variables

These control shadows for application windows (clients):

VariableTypeDefaultDescription
shadow_enabledbooleanfalseEnable shadows globally for clients
shadow_radiusinteger12Blur radius in pixels
shadow_offset_xinteger-15Horizontal offset (negative = left/behind window)
shadow_offset_yinteger-15Vertical offset (negative = up/behind window)
shadow_spreadinteger0Grow the shadow by this many pixels on every side before the blur
shadow_corner_radiusinteger0Round the shadow's corners by this many pixels
shadow_opacitynumber0.75Shadow opacity (0.0 = invisible, 1.0 = solid)
shadow_colorstring"#000000"Shadow color as "#RRGGBB" or "#RRGGBBAA" (alpha multiplies opacity)
note

shadow_clip from earlier 1.4 releases is still accepted but has no effect since 1.4.3. The shadow is drawn at its offset and fades out on every side; sides fully covered by the window are simply not visible.

Drawin/Wibox Shadow Variables

These control shadows for drawins and wiboxes (panels, popups, notifications). If not specified, they inherit from the client shadow settings.

VariableTypeDefaultDescription
shadow_drawin_enabledboolean(inherits from shadow_enabled)Enable shadows for drawins/wiboxes
shadow_drawin_radiusinteger(inherits from shadow_radius)Blur radius for drawins
shadow_drawin_offset_xinteger(inherits from shadow_offset_x)Horizontal offset for drawins
shadow_drawin_offset_yinteger(inherits from shadow_offset_y)Vertical offset for drawins
shadow_drawin_spreadinteger(inherits from shadow_spread)Spread for drawins
shadow_drawin_corner_radiusinteger(inherits from shadow_corner_radius)Corner radius for drawins
shadow_drawin_opacitynumber(inherits from shadow_opacity)Opacity for drawins
shadow_drawin_colorstring(inherits from shadow_color)Color for drawins

Theme Example

-- In your theme.lua

-- Enable shadows for all windows
theme.shadow_enabled = true
theme.shadow_radius = 12
theme.shadow_offset_x = -15
theme.shadow_offset_y = -15
theme.shadow_opacity = 0.75
theme.shadow_color = "#000000"

-- Disable shadows for panels/wiboxes (optional)
theme.shadow_drawin_enabled = false

Client Properties

client.shadow

The shadow property controls shadows on individual clients.

Type: boolean or table

Access: Read/Write

When set to a boolean:

  • true - Enable shadow using theme defaults
  • false - Disable shadow for this client

When set to a table, you can override individual shadow parameters:

OptionTypeDescription
enabledbooleanEnable/disable shadow (default: true when table is provided)
radiusintegerBlur radius in pixels
offset_xintegerHorizontal offset
offset_yintegerVertical offset
spreadintegerGrow the shadow by this many pixels on every side before the blur
corner_radiusintegerRound the shadow's corners by this many pixels
opacitynumberShadow opacity (0.0-1.0)
colorstring or tableColor as "#RRGGBB"/"#RRGGBBAA" string or {r, g, b, a} table (values 0.0-1.0); alpha multiplies opacity

Examples:

-- Enable shadow with theme defaults
c.shadow = true

-- Disable shadow
c.shadow = false

-- Custom shadow configuration
c.shadow = {
radius = 8,
opacity = 0.5,
color = "#FF0000" -- Red shadow
}

-- Partial override (other values use theme defaults)
c.shadow = {
offset_x = -25,
offset_y = -25
}

-- Color as RGBA table
c.shadow = {
color = {0.5, 0.0, 0.5, 1.0} -- Purple
}

Reading Shadow Configuration

When reading client.shadow, you receive:

  • false if shadows are disabled
  • A table with all current shadow settings if enabled
local s = c.shadow
if s then
print("Shadow enabled with radius:", s.radius)
print("Shadow color:", s.color)
else
print("Shadow disabled")
end

Drawin/Wibox Properties

drawin.shadow

The shadow property on drawins and wiboxes works identically to the client shadow property.

Type: boolean or table

Access: Read/Write

Examples:

-- Wibox with shadow
local mywibox = wibox {
width = 300,
height = 50,
visible = true,
shadow = true
}

-- Popup with custom shadow
local popup = awful.popup {
widget = mytextbox,
shadow = {
radius = 16,
opacity = 0.8
}
}

-- Notification-style glow effect
local notification_box = wibox {
width = 400,
height = 100,
shadow = {
color = "#3399FF",
radius = 20,
opacity = 0.6
}
}

Signals

property::shadow

Emitted when the shadow property changes on a client or drawin.

client.connect_signal("property::shadow", function(c)
if c.shadow then
print(c.name .. " now has shadows enabled")
end
end)

Using Rules

Apply shadow settings automatically based on window properties:

ruled.client.append_rule {
rule = { class = "mpv" },
properties = { shadow = false } -- No shadows on video players
}

ruled.client.append_rule {
rule = { type = "dialog" },
properties = {
shadow = {
radius = 8,
opacity = 0.9
}
}
}

ruled.client.append_rule {
rule = { class = "Rofi" },
properties = {
shadow = {
color = "#5588FF",
radius = 24,
opacity = 0.5
}
}
}

Dynamic Control

Use somewm-client to control shadows at runtime:

# Enable shadows on all clients (uses theme defaults)
somewm-client eval 'for _, c in ipairs(client.get()) do c.shadow = true end'

# Classic drop shadow (bottom-right)
somewm-client eval 'for _, c in ipairs(client.get()) do c.shadow = { offset_x = 8, offset_y = 8, radius = 12, opacity = 0.6 } end'

# Soft halo (all sides)
somewm-client eval 'for _, c in ipairs(client.get()) do c.shadow = { offset_x = 0, offset_y = 0, radius = 24, opacity = 0.5 } end'

# Blue glow
somewm-client eval 'for _, c in ipairs(client.get()) do c.shadow = { color = "#3399FF", radius = 20, opacity = 0.6, offset_x = 0, offset_y = 0 } end'

# Tight, sharp shadow
somewm-client eval 'for _, c in ipairs(client.get()) do c.shadow = { radius = 4, offset_x = 3, offset_y = 3, opacity = 0.9 } end'

# Wibar panel shadow (downward)
somewm-client eval 'for s in screen do if s.mywibox then s.mywibox.shadow = { radius = 12, offset_x = 0, offset_y = 4, opacity = 0.7 } end end'

# Disable shadows
somewm-client eval 'for _, c in ipairs(client.get()) do c.shadow = false end'

Complete Example

A full theme.lua shadow configuration:

local theme = {}

-- ... other theme settings ...

-- Shadow configuration
theme.shadow_enabled = true
theme.shadow_radius = 14
theme.shadow_offset_x = -18
theme.shadow_offset_y = -18
theme.shadow_opacity = 0.7
theme.shadow_color = "#000000"

-- Wiboxes/panels: subtle shadows or none
theme.shadow_drawin_enabled = true
theme.shadow_drawin_radius = 8
theme.shadow_drawin_opacity = 0.4

return theme

Combined with rules in rc.lua:

-- Fullscreen windows don't need shadows
ruled.client.append_rule {
rule_any = { fullscreen = true },
properties = { shadow = false }
}

-- Floating windows get enhanced shadows
ruled.client.append_rule {
rule_any = { floating = true },
properties = {
shadow = {
radius = 20,
offset_x = -20,
offset_y = -20,
opacity = 0.85
}
}
}

Technical Notes

  • The shadow is the window's frame grown by spread, moved by the offset, rounded by corner_radius, fading out over radius pixels on every side
  • It is rendered as a nine-patch (4 corner patches, 4 stretched edge strips, solid interior), so resizing never re-renders textures
  • Each shadow renders its own tiny gradient textures (a few KB total)
  • The falloff uses a smoothstep function that visually approximates Gaussian blur
  • Shadow nodes are placed below content in the wlroots scene graph

See Also