Skip to content

xapp_get_tmp_dir: honour TMPDIR and XDG_RUNTIME_DIR (fixes blank tray icons) - #216

Open
thexmeta wants to merge 1 commit into
linuxmint:masterfrom
thexmeta:tmpdir-honour-environment
Open

thexmeta wants to merge 1 commit into
linuxmint:masterfrom
thexmeta:tmpdir-honour-environment

Conversation

@thexmeta

Copy link
Copy Markdown

Summary

xapp_get_tmp_dir() never consults the environment: it probes /dev/shm first and only falls back to g_get_tmp_dir(). That makes the location of XApp's temporary files unredirectable on any system with a writable /dev/shm — which is essentially all of them.

This patch gives the environment priority, using the first writable location:

  1. $TMPDIR
  2. $XDG_RUNTIME_DIR
  3. /dev/shm (previous behaviour, retained as a fallback)
  4. g_get_tmp_dir()

Why it matters — it causes blank tray icons

xapp-sn-watcher materialises a StatusNotifierItem's IconPixmap to a file and hands the path to panel applets (xapp-sn-watcher/sn-item.c:244):

full_path = g_build_filename (xapp_get_tmp_dir (), filename, NULL);

where filename is xapp-tmp-%p-%d.png. Two properties of that scheme combine badly:

  • %p is the icon item's live heap pointer, so the name changes on every watcher restart and the previous file is orphaned.
  • The watcher g_unlinks the pixmap on item finalisation and sweeps rm -f <dir>/xapp-tmp-*.png on startup (xapp-sn-watcher/xapp-sn-watcher.c:542).

A panel applet that caches the path — as Cinnamon's xapp-status does; it reads proxy.icon_name once and only re-reads on a property change — is then left holding a dead path. load_image_from_file_async fails and the tray slot renders blank.

Reproduced on Cinnamon 6.4.10 / Debian 13 with Chromium/Electron apps that export IconPixmap only and no IconName property at all (Bitwarden: Id=Bitwarden_status_icon_1, IconPixmap 512×512 ARGB, IconName absent). Two unrelated apps showed blank slots from the same cause. Log evidence:

St-WARNING **: Could not load image from file: Failed to open file
    "/dev/shm/xapp-tmp-0x7f0454001880-0.png": No such file or directory
GdkPixbuf-CRITICAL **: gdk_pixbuf_get_width: assertion 'GDK_IS_PIXBUF (pixbuf)' failed

An app whose temp file still existed rendered correctly at the same moment, isolating the cause to the missing file rather than the applet.

Using $XDG_RUNTIME_DIR when it is available fixes this class of failure, because it is per-boot and user-owned and is not purged mid-session, so the file outlives a watcher restart within a session.

The change

const gchar *
xapp_get_tmp_dir (void)
{
    static const gchar *tmp_dir = NULL;

    if (tmp_dir == NULL)
    {
        const gchar *env_dir = g_getenv ("TMPDIR");

        if (env_dir == NULL || env_dir[0] == '\0')
            env_dir = g_getenv ("XDG_RUNTIME_DIR");

        if (env_dir != NULL && env_dir[0] != '\0' && access (env_dir, W_OK) == 0)
            tmp_dir = g_strdup (env_dir);
        else if (access ("/dev/shm", W_OK) == 0)
            tmp_dir = g_strdup ("/dev/shm");
        else
            tmp_dir = g_get_tmp_dir ();
    }

    return tmp_dir;
}

g_strdup() is required because the returned pointer is cached in a static for the process lifetime, so it must not point into getenv()'s storage. The access(W_OK) probe is preserved for every candidate, so an unwritable directory still falls through. The ABI is unchanged.

Notes

  • Previously the result was always /dev/shm when writable. After this patch it is $XDG_RUNTIME_DIR in a normal systemd session. That is the intended behavioural change.
  • The doc comment is updated: it currently claims to be "identical to g_get_tmp_dir, but includes the /dev/shm ramdisk as the first choice", which describes the old behaviour.
  • /dev/shm is retained as a fallback so behaviour is unchanged on systems without TMPDIR or XDG_RUNTIME_DIR.

Testing

Built against the Debian xapp 2.8.8-1 source and verified in the compiled library:

  • strings libxapp.so.1 — TMPDIR and XDG_RUNTIME_DIR now present (neither existed before).
  • Disassembly of xapp_get_tmp_dir shows the expected sequence: g_getenv("TMPDIR") → null/empty check → g_getenv("XDG_RUNTIME_DIR") → access(W_OK) → /dev/shm → g_get_tmp_dir().
  • Confirmed with a writable $TMPDIR/$XDG_RUNTIME_DIR that the function returns the environment value, and that an unwritable value falls through.

Happy to rework the precedence or add a configure option if you would prefer this to be opt-in rather than default.

xapp_get_tmp_dir() never consulted the environment: it probed /dev/shm
first and fell back to g_get_tmp_dir(), so the location of XApp's
temporary files could not be redirected on any system with a writable
/dev/shm.

Give the environment priority, using the first writable location:

  1. $TMPDIR
  2. $XDG_RUNTIME_DIR
  3. /dev/shm (previous behaviour, kept as a fallback)
  4. g_get_tmp_dir()

This fixes blank tray icons. xapp-sn-watcher materialises a
StatusNotifierItem's IconPixmap to <tmpdir>/xapp-tmp-<heap-ptr>-<idx>.png
and hands the path to panel applets. The name embeds the icon item's live
heap pointer, so it changes on every watcher restart, and the watcher
g_unlinks the file on item finalisation. An applet that cached the path
fails to load it and renders an empty slot. Observed with Chromium/
Electron apps that export IconPixmap only and have no IconName property
(e.g. Bitwarden).

XDG_RUNTIME_DIR is per-boot and user-owned and is not purged mid-session,
so the temp file outlives a watcher restart within a session.

The returned pointer is cached in a static for the process lifetime, so
the chosen value is g_strdup()ed rather than pointing into getenv()
storage. The access(W_OK) probe is preserved for every candidate.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant