Repository navigation
gnome-bg: don't serve a smaller cached pixbuf to a larger request - #277
Merged
mtwebster merged 1 commit intoSep 18, 2026
Merged
Conversation
file_cache_lookup() in get_as_pixbuf_for_size() is keyed only by filename, and get_pixbuf_for_size()'s bg->pixbuf_cache short-circuit matches by aspect ratio alone. Neither checks that the cached pixbuf is actually big enough for what is being requested. On a multi-monitor setup this causes a real, visible bug: if the smaller monitor is rendered first in a fresh GnomeBG (e.g. right after login, before the on-disk per-monitor wallpaper cache for the larger monitor is consulted), its downscaled pixbuf gets cached under the bare filename. The next monitor then reuses that undersized pixbuf -- exact match in get_as_pixbuf_for_size, or aspect-ratio match in get_pixbuf_for_size when the monitors share a similar aspect ratio (e.g. two 16:9 displays) -- and it gets upscaled to fill the larger monitor, producing a visibly blurry wallpaper even though the source file has plenty of resolution. Both call sites now require the cached pixbuf to be at least as big as the request, clamped to the source image's native resolution so wallpapers smaller than the monitor (which can never be upscaled from more detail than they have) don't lose their cache on every draw. Reproduced and fixed on a Linux Mint 22.3 (Cinnamon 6.6.9) laptop with an eDP-1 1366x768 internal panel and an HDMI-1 2560x1440 external monitor: after a cold boot the external monitor's wallpaper rendered visibly soft (edge-detection energy ~5.7 vs. ~7.7-8.1 for the original file, matching a simulated 1366x768-then-upscale reference), while re-setting org.cinnamon.desktop.background picture-uri (the known user workaround) forced a fresh render and fixed it for the rest of the session. The on-disk per-monitor cache (~/.cache/wallpaper/<monitor>_<placement>_<w>_<h>_<md5>) is not a reliable signal when investigating this class of report: it stays untouched and correctly sized because refresh_cache_file() skips rewriting a file that is already valid by mtime, even while the *displayed* image is the stale, upscaled one. This is likely the same defect reported in linuxmint#238 (blurry wallpaper after an HDMI TV, at a different aspect ratio, is unplugged and the internal panel's geometry is restored) -- a case the aspect-ratio check alone would miss, but the filename-only file_cache_lookup() explains. Verified the fix on the affected machine: built this patch against the currently shipping 6.6.2, installed it in place of the packaged libcinnamon-desktop4, and confirmed a cold boot (with the user-level workaround disabled) renders the external monitor sharp from login (edge-detection energy ~8.08, matching the original file's ~8.06).
Member
|
Thanks One thing to note, Cinnamon will no longer be using this library in 6.8 - all background handling has been moved Cinnamon, and it has a new internal CinnamonBg library for dealing with this (and supports individual wallpapers/slideshows on each monitor). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
On a dual-monitor setup where both displays share a similar aspect ratio (here: an eDP-1 1366x768 internal panel and an HDMI-1 2560x1440 external monitor, both 16:9), the wallpaper on the external monitor renders visibly soft/blurry right after a cold boot, even though the wallpaper file's pixel dimensions exactly match the external monitor's native resolution and
picture-optionsiszoom. Re-settingorg.cinnamon.desktop.background picture-urito itself (a known user-level workaround, e.g. toggling it to''and back) forces a fresh render and fixes the sharpness for the rest of the session — until the next full reboot.Mechanism
Both the per-file pixbuf cache in
get_as_pixbuf_for_size()and the single-slotbg->pixbuf_cacheinget_pixbuf_for_size()can serve a pixbuf that is smaller than what is currently being requested, and the caller then has to upscale it to fill the target monitor:file_cache_lookup(bg, PIXBUF, filename)at gnome-bg.c:2121 is keyed only by filename — not by monitor or requested size.load_from_cache_file()at gnome-bg.c:2133 can return a pixbuf already scaled down for a smaller monitor, read from the on-disk per-monitor cache.file_cache_add_pixbuf), with no record of the size/monitor it was scaled for.get_pixbuf_for_size()'s own cache check at gnome-bg.c:2549 then matches by aspect ratio alone (0.2 > fabs(...)), so a pixbuf cached for the smaller monitor is also handed straight back for the larger one whenever the two aspect ratios are close — as they are for a 1366x768 and a 2560x1440 display (|1.7786 − 1.7778| ≈ 0.0008, far under the0.2tolerance).In a fresh
csd-backgroundprocess (right after login, before the on-disk cache for the larger monitor has even been consulted), the smaller monitor gets rendered first indraw_each_monitor()'s per-monitor loop, its already-downscaled 1366x768 pixbuf is cached under the wallpaper's filename, and the very next call for the 2560x1440 monitor reuses it — upscaled — instead of loading the correctly-sized pixbuf.Why the on-disk cache looks fine when you go investigate this
This is the part most likely to mislead anyone chasing a report like this: the on-disk per-monitor cache (
~/.cache/wallpaper/<monitor>_<placement>_<width>_<height>_<md5(path)>) for the external monitor stays untouched and correctly sized even while the bug is actively rendering blurry.refresh_cache_file()at gnome-bg.c:1085 only (re)writes the cache file whencache_file_is_valid()at gnome-bg.c:832 says the existing one is stale — and mtime-based validity has nothing to do with whether the content that's currently on screen is correct. So the file you'd naturally go check is sharp; the pixels actually on the display are not.Evidence
Measured with an edge-detection energy metric (
PIL.ImageFilter.FIND_EDGESmean, summed over channels — higher = sharper) on the same region of the external monitor, comparing against the original wallpaper file:1_5_2560_1440_*cache file (misleadingly sharp, per above)The patched cold-boot number matches the original file; the simulated-bug number is what an affected boot's on-screen content would measure like (confirmed visually on the affected machine — see Testing).
Reproduction conditions
csd-backgroundprocess within an already-running session (tested) — the trigger appears to be specific to how monitor geometry becomes available during actual session startup, not just "fresh process." I have not tracked down the exact RandR/GDK timing involved, and this PR's fix does not depend on it: regardless of when a too-small pixbuf ends up cached, serving it for a larger request is wrong.Related
Likely the same defect class as #238 ("After plugging my laptop to my TV via HDMI and unplugging it, the wallpaper becomes blurry"), auto-closed as stale without investigation. That report involves very different aspect ratios (1024x768 TV vs. 1366x768 laptop panel), which the aspect-ratio check in
get_pixbuf_for_size()would correctly not match — but the filename-onlyfile_cache_lookup()inget_as_pixbuf_for_size()has no such guard and would still serve the wrong-sized cached pixbuf. Both call sites are fixed here.The fix
Both cache checks now require the cached pixbuf to be at least as large as what's being requested, before falling back to the aspect-ratio check (in
get_pixbuf_for_size()) or returning it outright (inget_as_pixbuf_for_size()). To avoid punishing the common case of a wallpaper file smaller than the monitor — where the cached pixbuf being "too small" is simply the most the source image can offer, and forcing a reload would just re-fetch the same pixels — the required size is clamped to the source image's native resolution viagdk_pixbuf_get_file_info().Testing
cinnamon-settings-daemon6.6.4+zena,libcinnamon-desktop46.6.2+zena) and confirmed it applies and compiles cleanly againstmasteras well (only the affected functions changed since 6.6.2).🤖 Generated with Claude Code