Skip to main content

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_opacitynumber0.75Shadow opacity (0.0 = invisible, 1.0 = solid)
shadow_colorstring"#000000"Shadow color as hex string
shadow_clipboolean/stringtrueOnly show shadow on offset side (true, false, or "directional")

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_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
opacitynumberShadow opacity (0.0-1.0)
colorstring or tableColor as "#RRGGBB" string or {r, g, b, a} table (values 0.0-1.0)
clip_directionalbooleanOnly show shadow on the offset side (default: true)

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, clip_directional = true } 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, clip_directional = false } 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, clip_directional = false } 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, clip_directional = true } 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, clip_directional = true } 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

  • Shadows are rendered using a 9-slice technique: 4 corners and 4 edges, allowing efficient resizing
  • Each shadow renders its own gradient textures (4 corners + 2 edges + 1 fill pixel, ~2.5KB 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