Skip to content

"Browse Files" button does nothing on Wayland compositors (missing WAYLAND_DISPLAY and XDG_RUNTIME_DIR in exec_user_async) #538

Description

@nisidabay

Bug Description

The "Browse Files" button (and "View Timeshift Logs") does nothing on Wayland compositors. The file manager (Thunar, Nautilus, etc.) silently fails and never appears.

This is a different root cause from the issues previously closed (#517, #520). While PR #518 fixed those by switching from exec_script_async() to exec_user_async() to drop root privileges, exec_user_async() itself does not pass the Wayland-specific environment variables needed for GTK apps to connect to the compositor.

Root Cause

1. TeeJee.Process.valaexec_user_async() missing Wayland env vars

In src/Utility/TeeJee.Process.vala, the exec_user_async() function constructs this pkexec command:

cmd = "pkexec --user %s env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS ".printf(user) + cmd;

It passes X11 variables (DISPLAY, XAUTHORITY) and DBUS_SESSION_BUS_ADDRESS, but does NOT pass:

  • WAYLAND_DISPLAY (e.g., wayland-1)
  • XDG_RUNTIME_DIR (e.g., /run/user/1000)

Without these, GTK apps launched via pkexec cannot connect to the Wayland compositor socket. The file manager silently fails because it has no display to connect to.

2. Main.valasetup_env() breaks Wayland variable resolution

In src/Core/Main.vala, the setup_env() function has an additional problem:

if (wayland_display != null && xdg_runtime_dir != null) {
    string path = "%s/%s".printf(xdg_runtime_dir, wayland_display);
    GLib.Environment.set_variable("WAYLAND_DISPLAY", path, true);
    GLib.Environment.set_variable("XDG_RUNTIME_DIR", "/run/user/0", true);
}

This code:

  • Changes WAYLAND_DISPLAY from the normal value wayland-1 to the full path /run/user/1000/wayland-1
  • Overwrites XDG_RUNTIME_DIR to /run/user/0 (root's runtime dir)

This breaks the standard Wayland resolution where GTK apps combine XDG_RUNTIME_DIR/WAYLAND_DISPLAY to find the compositor socket. After this transformation, the Wayland socket can't be found because the path construction becomes nonsensical (/run/user/0/wayland-1 doesn't exist, and /run/user/1000/wayland-1 is now unreachable via normal variable resolution).

Steps to Reproduce

  1. Use a Wayland compositor (e.g., Niri, Hyprland, Sway, GNOME on Wayland)
  2. Start Timeshift
  3. Select a snapshot
  4. Click "Browse Files"
  5. Nothing happens — no file manager window appears, no error dialog

Environment

  • OS: Arch Linux
  • Compositor: Niri (Wayland)
  • Timeshift Version: 24.06.5
  • File Manager: Thunar (also confirmed on Nautilus)

Suggested Fix

Fix 1: Add Wayland env vars to exec_user_async() in TeeJee.Process.vala

cmd = "pkexec --user %s env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS WAYLAND_DISPLAY=$WAYLAND_DISPLAY XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR ".printf(user) + cmd;

Fix 2: Correct setup_env() in Main.vala

The setup_env() function should not mangle the WAYLAND_DISPLAY value or override XDG_RUNTIME_DIR for the root process in a way that breaks child process resolution. The Wayland socket needs to remain accessible. Possible approaches:

  • Keep WAYLAND_DISPLAY as the socket name (e.g., wayland-1) and preserve the original XDG_RUNTIME_DIR so child processes can resolve the socket path correctly
  • Or, if the full path must be set for the root process's own use, ensure the original variables are restored/passed correctly when launching user processes via exec_user_async()

Workaround

Create a wrapper script for your file manager at /usr/local/bin/thunar (or equivalent for your file manager) that forces X11 fallback when Wayland is unavailable:

#!/bin/bash
if [ -z "$WAYLAND_DISPLAY" ] && [ -n "$DISPLAY" ]; then
    export GDK_BACKEND=x11
fi
exec /usr/bin/thunar "$@"

This works because DISPLAY is still passed through by exec_user_async(), so the file manager can fall back to XWayland.

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions