Rundown

This guide is for all Qubers who enjoy customization including using animated / interactive wallpapers while still operating within a reasonably secure operating system. Qubes OS normally discourages desktop-level visual modifications that interact with dom0, but using the method below, you can safely run a live wallpaper inside an AppVM while maintaining strong isolation.

If you’ve ever wanted your desktop to feel more alive without compromising Qubes security principles, this guide is for you.


Requirements:

To follow this guide, you'll need:

✔ An AppVM (any name you prefer)

This VM will run your wallpaper player. Recommended templates for this guide: Fedora or Debian.

✔ A TemplateVM

Used for installing packages (mpv, firejail) needed by your AppVM.

✔ A video file to use as your wallpaper

Place it in the AppVM as ~/wallpaper.[Video extension].

✔ dom0 packages

Use the preinstalled window-management utility in dom0 (wmctrl) or update it if needed.


Disclaimer:

This is a community made guide, please check for mistakes in commands (I'm not good at typing). Information was up to date as of making. 12/11/25

I'm new to qubes, not to linux, so for debuging i might not be the best to ask questions to.

Dom0 Security disclaimer:

This method requires running a script in dom0. The script is intentionally minimal and restricted to safe operations (setting window geometry and adjusting _NET_WM_WINDOW_TYPE). It does not import or execute untrusted content, modify dom0 configuration, or alter system-level behavior. However, dom0 is the most security-sensitive domain in Qubes OS. Always inspect scripts line-by-line before running them and never copy unknown or unsanitized files into dom0.


Installation:

1. Prepare a template & AppVM.

Use/Make a template containing Debian/Fedora, Depending on the video and hardware adjust memory, VCPU's, and storage capacity. DO NOT give this AppVM Internet.

2. Install Essential Packages.

Dom0 Package:

sudo qubes-dom0-update wmctrl
Template Package:
#Debian
sudo apt install mpv firejail
#Fedora
sudo dnf install mpv firejail

3. Place Video File in AppVM.

Transfer your video from qube of choice.

4. Create Live Video Wallpaper script in Dom0.

You can write this script manually if you're paranoid (Not really recommended)

OR

Import it after sanitation Using: ``` qvm-run --pass-io [VM with file] 'cat /home/user/Desktop/script.txt' > /home/[dom0 usr]/Desktop/wallpaper.txt

Script **(DO NOT RUN WITH SUDO)**:

!/usr/bin/env bash

set -euo pipefail

echo "===== QUBES WALLPAPER V1.2 By Pro42good =====" echo "Run 'wmctrl -l' in dom0 and copy the WINID of the video window." echo

read -rp "Enter WINID: " WINID read -rp "Width (default 1920): " WIDTH read -rp "Height (default 1080): " HEIGHT

WIDTH=${WIDTH:-1920} HEIGHT=${HEIGHT:-1080}

echo echo "[*] Ensuring the window is visible (un-minimizing)..." wmctrl -i -r "$WINID" -b remove,hidden,shaded wmctrl -i -r "$WINID" -b remove,maximized_vert,maximized_horz

echo "[*] Applying geometry..." wmctrl -i -r "$WINID" -e "0,0,0,${WIDTH},${HEIGHT}"

echo "[*] Removing decorations using SPLASH window type..." xprop -id "$WINID" -f _NET_WM_WINDOW_TYPE 32a \ -set _NET_WM_WINDOW_TYPE "_NET_WM_WINDOW_TYPE_SPLASH" \ >/dev/null 2>&1 || true

echo "[*] Fixing leftover top gap by reapplying geometry..." wmctrl -i -r "$WINID" -e "0,0,0,${WIDTH},${HEIGHT}"

echo "[*] Making sticky, skipping taskbar/pager..." wmctrl -i -r "$WINID" -b add,sticky,skip_taskbar,skip_pager

echo "[*] Refreshing compositor..." wmctrl -i -r "$WINID" -b add,fullscreen sleep 0.2 wmctrl -i -r "$WINID" -b remove,fullscreen

echo echo "===== COMPLETE =====" echo "Your Wallpaper is now set!" echo "If your having any issues, say something in Qubes forums for this wallpaper guide." echo "Mouse Input is supported, Keyboard input is NOT supported." echo "To close the wallpaper, shut the AppVM off."

#### 5. You're Done!
Yep, that's it. You have the script, no more packages or scripts required.

---

# Usage:

1. Inside dom0 run `wmctrl -l` and take note of the output.

2. Open Terminal inside of wallpaper AppVM.

3. Take note of `wmctrl -l` result in dom0 again.

4. Inside your AppVM for wallpapers load your video/app using firejail for extra security.

For videos

firejail mpv --loop --no-border -no-input-cursor --no-input-default-bindings -ontop=no --ontop=no --geometry=100%x100% --fullscreen /Directory

5. Run `wmctrl -l` again and look for the newest addition to the list compared to the last 2 times.

6. Run the script from dom0.
cd [Where stored] bash wallpaper.txt `` 7. Insert the wallpaper window ID The wallpaper Window ID looks something like this0x052001dc`.

  1. Enter Screen Resolution, and Your Done!

Extra technical documentation:

This method works because it relies on window properties that XFWM will reliably apply to Qubes-proxied windows, while avoiding the behaviors that cause those windows to be dropped or mispositioned. Since AppVM windows are not native X11 clients but are instead rendered inside the VM and forwarded to dom0 via qubes-guid, dom0 window managers do not receive complete frame-control metadata. As a result, many standard X11 decoration hints—particularly _MOTIF_WM_HINTS—are ignored, and attempts to adjust stacking (e.g., using _NET_WM_STATE_BELOW, lower, or above) can cause the compositor to treat the window as non-visible. When that happens, qubes-guid simply stops drawing the window, which appears to “vanish.”

To work around this, the guide uses _NET_WM_WINDOW_TYPE_SPLASH. Unlike other types (e.g., DOCK or NORMAL), SPLASH is one of the few window categories that XFWM consistently applies to proxied Qubes windows without forcing them into a reserved-strut configuration or onto an always-on-top layer. SPLASH removes decorations and border frames but keeps the window at a standard stacking level. This allows the wallpaper window to behave like any other application: when other windows receive focus, they naturally appear above it without the need for forced stacking rules that would otherwise break Qubes’ compositor assumptions.

After switching the window type to SPLASH, dom0 must reapply the window geometry. This is because XFWM initially calculates frame extents based on the original decorated window, and simply removing decorations does not recalculate those extents. Reapplying geometry forces XFWM to interpret the window as borderless from the start, eliminating the leftover top gap. The result is a stable, decoration-free, correctly placed fullscreen window that remains behind other windows in normal use—effectively functioning as a wallpaper—while remaining fully compliant with Qubes’ security model and avoiding unsupported manipulations of proxied window layers.

This approach works because it aligns with how Qubes OS expects proxied windows to behave, rather than trying to force them into roles (like true desktop backgrounds or lowered system layers) that the GUI virtualization layer does not support.


Issues

  1. On version 1.1 if you had the video maximized it would still have the top border, fixed on 1.2.

For the skeptics:

Live Demonstration + Nano showing code:

https://youtu.be/Xu1Yjwkrhnk?si=v788_Aj7wTWV-0gp

Please forgive me for the bad quality, im not good at using qubes and I don't know how to record

@Pro42good Was here