Skip to main content

Fractional Scaling somewm-only

SomeWM supports fractional output scaling for HiDPI displays through the screen.scale property.

What is Fractional Scaling?

Display scaling makes UI elements larger on high-resolution displays:

ScaleEffectUse Case
1.0Native resolutionStandard 1080p/1440p
1.2525% larger1440p HiDPI
1.550% larger4K laptop displays
2.0Double size4K desktop / Retina

Without scaling, a 4K display makes everything tiny. Fractional scaling (1.25, 1.5, 1.75) offers more options than just integer scaling (1x, 2x).

Setting Scale from Lua

At Startup

In your rc.lua:

-- Set scale for all screens
awful.screen.connect_for_each_screen(function(s)
s.scale = 1.5
end)

-- Or just the primary screen
screen.primary.scale = 1.5

Per-Screen Configuration

awful.screen.connect_for_each_screen(function(s)
-- Different scale based on screen size
if s.geometry.width > 3000 then
s.scale = 1.5 -- 4K display
elseif s.geometry.width > 2000 then
s.scale = 1.25 -- 1440p display
else
s.scale = 1.0 -- 1080p or smaller
end
end)

Dynamic Adjustment

-- Keybinding to adjust scale
awful.keyboard.append_global_keybindings({
awful.key({ modkey }, "equal", function()
local s = awful.screen.focused()
s.scale = s.scale + 0.25
end, { description = "increase scale", group = "screen" }),

awful.key({ modkey }, "minus", function()
local s = awful.screen.focused()
s.scale = math.max(0.5, s.scale - 0.25)
end, { description = "decrease scale", group = "screen" }),
})

Setting Scale from CLI

Use somewm-client to adjust scale at runtime:

# Get current scale of focused screen
somewm-client screen scale

# Set focused screen to 1.5
somewm-client screen scale 1.5

# Set specific screen (by index)
somewm-client screen scale 1 1.5
somewm-client screen scale 2 1.0

Making Themes DPI-Aware

Use beautiful.xresources.apply_dpi() to scale theme values:

-- theme.lua
local xresources = require("beautiful.xresources")
local dpi = xresources.apply_dpi

local theme = {}

-- These values scale with DPI
theme.font = "sans " .. dpi(10)
theme.useless_gap = dpi(4)
theme.border_width = dpi(2)
theme.notification_width = dpi(300)

-- Icon sizes
theme.menu_height = dpi(20)
theme.menu_width = dpi(150)

-- Widget sizes
theme.wibar_height = dpi(24)
theme.systray_icon_spacing = dpi(4)

return theme

The dpi() function reads the system DPI and scales values accordingly.

Manual DPI Calculation

If you need more control:

local function scale_value(value)
local s = awful.screen.focused()
return math.floor(value * (s.scale or 1.0))
end

-- Usage
local margin = scale_value(8) -- 8 at 1x, 12 at 1.5x, etc.

Workarea and Geometry

When you change scale, screen geometry updates:

local s = screen.primary
print("Before:", s.geometry.width, s.geometry.height)

s.scale = 2.0

print("After:", s.geometry.width, s.geometry.height)
-- Width/height are now halved (logical pixels)

The workarea also recalculates to account for wibars at the new scale.

App Compatibility

Wayland-Native Apps

Apps supporting wp_fractional_scale_v1 render at native resolution and scale properly. Most modern GTK4 and Qt6 apps support this.

XWayland Apps

X11 apps through XWayland may appear blurry at fractional scales. Options:

  1. Use integer scaling (1.0, 2.0) for crisp XWayland apps
  2. Force per-app scaling via environment variables:
-- Force 2x for specific app, let Wayland downscale
awful.spawn.with_shell("GDK_SCALE=2 my-gtk-app")

GTK Apps

# Force GTK3 to use Wayland
export GDK_BACKEND=wayland

# Or set in rc.lua autostart
awful.spawn.with_shell("export GDK_BACKEND=wayland")

Qt Apps

# Enable Qt Wayland
export QT_QPA_PLATFORM=wayland
export QT_SCALE_FACTOR=1.5

Electron Apps

# Enable Wayland for Electron
export ELECTRON_OZONE_PLATFORM_HINT=wayland

Mixed-DPI Multi-Monitor

For setups with different DPI monitors:

awful.screen.connect_for_each_screen(function(s)
-- Identify screen by geometry or output name
if s.geometry.width == 3840 then
s.scale = 1.5 -- 4K monitor
else
s.scale = 1.0 -- 1080p monitor
end
end)

Handling Hotplug

screen.connect_signal("added", function(s)
-- New monitor connected, set appropriate scale
if s.geometry.width > 3000 then
s.scale = 1.5
else
s.scale = 1.0
end
end)

Common Scale Values

ResolutionDiagonalRecommended Scale
1920x108024"+1.0
2560x144027"1.0 - 1.25
3840x216027"1.5 - 2.0
3840x216032"1.25 - 1.5
2880x180015" (laptop)1.5 - 2.0

Troubleshooting

Blurry Text

  • Try integer scaling (1.0, 2.0) instead of fractional
  • Ensure app supports Wayland native rendering
  • Check font hinting settings

Widgets Wrong Size

Make sure you're using dpi() for all size values in theme.lua:

-- Wrong: fixed pixel values
theme.useless_gap = 4

-- Right: DPI-aware values
theme.useless_gap = dpi(4)

Scale Not Applying

Check that you're setting scale on the correct screen:

-- Debug: print all screens and their scales
for s in screen do
print("Screen " .. s.index .. ": scale = " .. (s.scale or "nil"))
end

See Also