Skip to main content

Wayland vs X11

This page explains why some AwesomeWM features work differently (or don't work) on Wayland.

Fundamental Differences

AspectX11Wayland
Window managementClient-side hints, WM interpretsCompositor controls everything
DrawingServer-side or client-sideClient-side only (EGL/Vulkan)
InputGlobal accessPer-surface, security-focused
ScreenshotsAny app can captureRequires compositor support
Tray iconsX11 embed (_NET_SYSTEMTRAY)D-Bus (StatusNotifierItem)

What This Means for SomeWM

No WM Restart

X11: AwesomeWM can restart itself, re-reading config and reconnecting to windows.

Wayland: The compositor is the display server. Restarting it would disconnect all clients.

Workaround: Use Mod4 + Ctrl + r to reload your Lua configuration without restarting.

Different Systray

X11: Tray icons are embedded X11 windows inside the wibox.

Wayland: Tray icons use the StatusNotifierItem (SNI) D-Bus protocol.

Impact: Most modern apps (NetworkManager, Discord, Bluetooth) support SNI. Legacy XEmbed-only apps won't show tray icons.

No Global Input Injection

X11: xdotool and similar tools can inject input anywhere.

Wayland: Security model prevents apps from injecting input into other apps.

Impact: root.fake_input() is a stub. Automation tools need compositor support.

No X Properties

X11: Windows can store arbitrary properties that persist across sessions.

Wayland: No equivalent mechanism exists.

Impact: awesome.register_xproperty() and related APIs are stubs.

Titlebar Border Positioning

X11: Borders drawn OUTSIDE the window frame by X server.

Wayland: Borders are scene graph elements at geometry edges.

Impact: Titlebars start INSIDE the border area (inset by border_width).

Partially Working Features

Strut Aggregation

Single panel struts work correctly. Multiple panels on the same screen edge may not reserve space properly.

XKB Layout Toggle

XKB toggle options like grp:alt_shift_toggle don't automatically change layouts. Use explicit keybindings instead:

awful.key({ "Mod1", "Shift" }, "space", function()
local current = awesome.xkb_get_layout_group()
awesome.xkb_set_layout_group((current + 1) % 2)
end)

See Also