Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions lua/awful/wallpaper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,16 @@ end
local function paint()
if not next(pending_repaint) then return end

local root_width, root_height = capi.root.size()
-- On X11 the root window is always at (0, 0) so AwesomeWM only needs
-- root.size(); on Wayland (somewm) wlr_output_layout can place outputs
-- at negative coordinates (portrait monitor left of the primary), so
-- the surface would otherwise be allocated in layout-absolute space and
-- all draws into negative-x screens would land off-surface. Fetch the
-- layout origin and pre-translate the cairo context so every subsequent
-- s.geometry.x / geo.x (still layout-absolute) maps onto surface pixels.
local root_geom = capi.root.geometry()
local root_x, root_y = root_geom.x, root_geom.y
local root_width, root_height = root_geom.width, root_geom.height

-- Get the current wallpaper content.
local source = surface(root.wallpaper())
Expand All @@ -265,11 +274,14 @@ local function paint()
if source then
target = source:create_similar(cairo.Content.COLOR, root_width, root_height)
cr = cairo.Context(target)
cr:translate(-root_x, -root_y)

-- Copy the old wallpaper to the new one
cr:save()
cr.operator = cairo.Operator.SOURCE
cr:set_source_surface(source, 0, 0)
-- source is already in surface-pixel space (matches target size),
-- compensate the outer translate so source(0,0) lands on target(0,0).
cr:set_source_surface(source, root_x, root_y)

for s in screen do
cr:rectangle(
Expand All @@ -287,6 +299,7 @@ local function paint()
else
target = cairo.ImageSurface(cairo.Format.RGB32, root_width, root_height)
cr = cairo.Context(target)
cr:translate(-root_x, -root_y)
end

local walls = {}
Expand Down
62 changes: 54 additions & 8 deletions root.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,32 @@ luaA_root_size(lua_State *L)
return 2;
}

/** Get root window geometry including origin
* On X11 the root window is always at (0, 0) so AwesomeWM gets away with
* root.size() alone; on Wayland wlr_output_layout can place outputs at
* negative coordinates (e.g. a portrait monitor left of the primary), so
* callers that draw into a single root-sized surface must also know the
* layout origin. Returns a table {x, y, width, height}.
* Lua: root.geometry() -> { x = ..., y = ..., width = ..., height = ... }
*/
static int
luaA_root_geometry(lua_State *L)
{
struct wlr_box box;

wlr_output_layout_get_box(output_layout, NULL, &box);
lua_createtable(L, 0, 4);
lua_pushinteger(L, box.x);
lua_setfield(L, -2, "x");
lua_pushinteger(L, box.y);
lua_setfield(L, -2, "y");
lua_pushinteger(L, box.width);
lua_setfield(L, -2, "width");
lua_pushinteger(L, box.height);
lua_setfield(L, -2, "height");
return 1;
}

/** Get root window physical size in mm (stub for AwesomeWM compatibility)
* Returns approximate physical dimensions based on monitor DPI
* Lua: root.size_mm() -> width_mm, height_mm
Expand Down Expand Up @@ -954,10 +980,19 @@ clear_wallpaper_info_in_lua(lua_State *L)

/** Create a cache entry for one screen
* Returns true on success, false on failure
*
* layout_x/layout_y are the origin of the output_layout bounding box, which
* matches the upper-left of the cairo pattern supplied by awful.wallpaper's
* paint(). On X11 this is always (0, 0); on Wayland it can be negative when
* an output (e.g. a portrait monitor) sits left-of/above the primary. The
* pattern's pixel (u, v) therefore corresponds to layout (u + layout_x,
* v + layout_y), so extracting a screen at absolute layout (x, y) needs the
* translate offset shifted by (layout_x, layout_y).
*/
static bool
create_wallpaper_cache_entry(const char *path, cairo_pattern_t *pattern,
wallpaper_screen_info_t *info)
wallpaper_screen_info_t *info,
int layout_x, int layout_y)
{
cairo_surface_t *surface = NULL;
cairo_t *cr = NULL;
Expand All @@ -976,7 +1011,7 @@ create_wallpaper_cache_entry(const char *path, cairo_pattern_t *pattern,

/* Paint pattern to surface, offsetting to extract the screen region */
cr = cairo_create(surface);
cairo_translate(cr, -x, -y);
cairo_translate(cr, layout_x - x, layout_y - y);
cairo_set_source(cr, pattern);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
Expand Down Expand Up @@ -1046,6 +1081,12 @@ root_set_wallpaper_cached(lua_State *L, cairo_pattern_t *pattern)
screen_infos, MAX_PENDING_SCREENS);
}

/* Layout origin matches the cairo pattern's upper-left (see awful.wallpaper
* paint() which allocates target at layout bbox size, pixel (0,0) = layout
* (layout_box.x, layout_box.y)). */
struct wlr_box layout_box;
wlr_output_layout_get_box(output_layout, NULL, &layout_box);

/* Create cache entries for all pending screens */
if (screen_count > 0) {
for (int i = 0; i < screen_count; i++) {
Expand All @@ -1062,7 +1103,8 @@ root_set_wallpaper_cached(lua_State *L, cairo_pattern_t *pattern)
}

/* Create new cache entry */
if (create_wallpaper_cache_entry(info->path, pattern, info))
if (create_wallpaper_cache_entry(info->path, pattern, info,
layout_box.x, layout_box.y))
result = true;
}

Expand All @@ -1072,10 +1114,12 @@ root_set_wallpaper_cached(lua_State *L, cairo_pattern_t *pattern)
}

/* Fallback: no caching (cache not ready, no path, or no screens) */
/* Use full layout geometry */
struct wlr_box layout_box;
wlr_output_layout_get_box(output_layout, NULL, &layout_box);
int x = 0, y = 0;
/* Use full layout geometry including its origin — awful.wallpaper paints
* each screen at its layout (x, y), which can be negative when an output
* sits left-of / above the primary (e.g. a portrait HP at x = -2160).
* Using (0, 0) here clips that content off the cairo surface and places
* the scene buffer node where it doesn't intersect the off-origin output. */
int x = layout_box.x, y = layout_box.y;
int width = layout_box.width;
int height = layout_box.height;

Expand All @@ -1095,7 +1139,8 @@ root_set_wallpaper_cached(lua_State *L, cairo_pattern_t *pattern)
goto cleanup;

cr = cairo_create(surface);
cairo_translate(cr, -x, -y);
/* Fallback surface and awful.wallpaper pattern are both bbox-sized with
* matching pixel origin (layout upper-left); copy 1:1, no translate. */
cairo_set_source(cr, pattern);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
Expand Down Expand Up @@ -1858,6 +1903,7 @@ const luaL_Reg root_methods[] = {
{ "drawins", luaA_root_drawins },
{ "size", luaA_root_size },
{ "size_mm", luaA_root_size_mm },
{ "geometry", luaA_root_geometry },
{ "tags", luaA_root_tags },
{ "content", luaA_root_get_content },
/* __index and __newindex MUST be in methods, not meta!
Expand Down
Loading