xfdesktop 4.20: wallpaper rename migration misses `xfce-teal.jpg`, leaving a white desktop after upgrading from 4.18

AI disclosure: Analyzed and drafted with claude-opus-5

Upgrading from Xfce 4.18 to 4.20 (xfdesktop 4.20.2), the wallpaper is not found and a white background is shown.

https://gitlab.xfce.org/xfce/xfdesktop/-/blob/master/common/xfdesktop-common.c?ref_type=ebc54f5452a3d2838ef26d68fe94ec0bf927a940#L527-535

Commit 79328611 (SVG wallpapers with licenses, 2024-08-27) replaced three shipped wallpapers with SVG versions. Commit ebc54f54 (Migrate old .png background filenames to .svg, 2024-09-30) added fixup_image_filename() to rewrite stale last-image values in the xfce4-desktop channel so that users upgrading from 4.18 keep their background. That migration table lists xfce-teal.png, but the file removed in commit 79328611 was xfce-teal.jpg — it has been a JPEG since at least 4.16.1 and was never a PNG in any released version. Consequently xfce-stripes.png and xfce-verticals.png are migrated correctly while xfce-teal.jpg is not: it survives the upgrade as a last-image pointing at a file that no longer exists, and the affected monitors render a plain white desktop.

Teal was the Xfce 4.18 default wallpaper, so this affects every user who never changed their background — which, at our site, is most of them.

Excerpt from a real xfce4-desktop.xml after the upgrade, showing the migration having succeeded for stripes and failed for teal within the same channel, on monitors treated identically in every other respect:

<property name="monitorDP-4" type="empty">
  <property name="workspace0" type="empty">
    <property name="image-style" type="int" value="5"/>
    <property name="last-image" type="string" value="/usr/share/backgrounds/xfce/xfce-stripes.svg"/>   <!-- migrated -->
  </property>
</property>
<property name="monitorDP-2" type="empty">
  <property name="workspace0" type="empty">
    <property name="image-style" type="int" value="5"/>
    <property name="last-image" type="string" value="/usr/share/backgrounds/xfce/xfce-teal.jpg"/>      <!-- not migrated: white desktop -->
  </property>
</property>

Release tarball contents confirm the extension has always been .jpg:

Release teal stripes verticals
4.16.1 xfce-teal.jpg xfce-stripes.png xfce-verticals.png
4.18.1 xfce-teal.jpg xfce-stripes.png xfce-verticals.png
4.19.0 – 4.19.3 xfce-teal.jpg xfce-stripes.png xfce-verticals.png
4.20.0 – 4.20.2 xfce-teal.svg xfce-stripes.svg xfce-verticals.svg

Suggested fix

The rewrite itself is extension-agnostic — memcpy(&new_filename[len - 3], "svg", 3) handles .jpg just as well as .png — so the table only needs the correct entry:

    static const gchar *to_svg[] = {
        BACKGROUNDS_DIR "/xfce-stripes.png",
        BACKGROUNDS_DIR "/xfce-teal.jpg",
        BACKGROUNDS_DIR "/xfce-verticals.png",
    };

Keeping xfce-teal.png alongside it costs nothing and covers anyone who typed the path by hand.

That alone will not help users who have already upgraded, however. The whole block is gated on

    if (migration_version < 1) {

with CUR_SETTINGS_MIGRATION_VERSION defined as 1 at common/xfdesktop-common.c:502, and the version is written unconditionally at the end of xfdesktop_migrate_backdrop_settings(). Everyone who has logged into 4.20 once already carries last-settings-migration-version=1, so a corrected table would never run for them — precisely the population that is looking at a white desktop today.

Bumping CUR_SETTINGS_MIGRATION_VERSION to 2 is therefore needed as well. Re-running the entire version-1 block would be wasteful and possibly surprising, since it also performs the numeric-monitor-to-monitor-name migration; splitting fixup_image_filename() out behind its own if (migration_version < 2) gate seems cleaner:

#define CUR_SETTINGS_MIGRATION_VERSION 2

    if (migration_version < 2) {
        GHashTable *backdrop_properties = xfconf_channel_get_properties(channel, "/backdrop");
        GHashTableIter iter;
        g_hash_table_iter_init(&iter, backdrop_properties);
        gchar *name;
        GValue *value;
        while (g_hash_table_iter_next(&iter, (gpointer)&name, (gpointer)&value)) {
            fixup_image_filename(channel, name, value);
        }
        g_hash_table_destroy(backdrop_properties);
    }

Secondary observation

The comment at common/xfdesktop-common.c:629 notes that the version-1 migration can only succeed for monitors that are currently plugged in. fixup_image_filename() does not share that limitation — it iterates over all /backdrop properties and only matches on the property name suffix — but because it is nested inside the same one-shot gate, it gets exactly one chance to run. A configuration accumulated over years across docking stations and remote displays (the one that prompted this report has 26 monitor entries) will keep stale filenames for every output that happened not to be attached at that single moment. Giving the filename fixup its own gate, as above, does not fix this on its own, but running it on a later version bump would clean up the outputs that were missed the first time.

Workaround for affected users

xfconf-query -c xfce4-desktop -lv \
| awk '$2 == "/usr/share/backgrounds/xfce/xfce-teal.jpg" {print $1}' \
| while read -r p; do
    xfconf-query -c xfce4-desktop -p "$p" -s /usr/share/backgrounds/xfce/xfce-teal.svg
  done

xfdesktop watches the channel, so the background reappears without a restart.