Files
benthicbloom/lib/gstreamerAvailability.js
T
QuintaandClaude Sonnet 5 40af1dad26 Fix potential login freeze: skip blocking GStreamer registry rescan
Gst.init() has no async variant. If the plugin registry cache is stale
(e.g. right after a system update), it synchronously rescans every
plugin, spawning gst-plugin-scanner per plugin and probing hardware
for codecs. Since gnome-shell is single-threaded and is the
compositor, that can freeze the whole screen for several seconds,
same as the blocking UPower proxy lookup fixed earlier.

Set GST_REGISTRY_UPDATE=no when a cache already exists so Gst.init()
trusts it and returns immediately, then refresh the cache in a
throwaway subprocess afterward so it doesn't go stale forever.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 12:11:11 +02:00

125 lines
4.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
/**
* True if a GStreamer plugin registry cache already exists for this user.
* A plain local directory listing — fast, unlike the scan below.
*/
function hasGstRegistryCache() {
const cacheDir = Gio.File.new_for_path(
GLib.build_filenamev([GLib.get_user_cache_dir(), 'gstreamer-1.0']));
try {
const enumerator = cacheDir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
const hasEntry = enumerator.next_file(null) !== null;
enumerator.close(null);
return hasEntry;
} catch (e) {
return false;
}
}
/**
* Gst.init() has no async variant. If its plugin registry cache is stale
* (e.g. right after a system update touched GStreamer packages), it
* synchronously rescans every plugin — spawning gst-plugin-scanner per
* plugin, and probing hardware for codec plugins — which can block
* gnome-shell's single main thread (it *is* the compositor) for many
* seconds, exactly the conditions right after login. That froze the entire
* screen the same way the blocking UPower proxy lookup did.
*
* GST_REGISTRY_UPDATE=no makes Gst.init() trust the existing cache
* unconditionally instead of validating it, so it returns immediately. Only
* set when a cache already exists — an extension-lifetime-first-ever
* GStreamer run on this machine still needs one real scan to have anything
* to trust.
*/
function keepGstInitFast() {
if (hasGstRegistryCache())
GLib.setenv('GST_REGISTRY_UPDATE', 'no', true);
}
/**
* Refreshes the on-disk registry cache in a throwaway subprocess, so a
* stale cache (skipped above) doesn't stay stale forever and newly
* installed plugins eventually become visible. Runs fully out-of-process:
* even if a hardware probe inside it hangs, gnome-shell is unaffected.
*/
function refreshGstRegistryInBackground() {
try {
const launcher = new Gio.SubprocessLauncher(
Gio.SubprocessFlags.STDOUT_SILENCE | Gio.SubprocessFlags.STDERR_SILENCE);
launcher.setenv('GST_REGISTRY_UPDATE', 'yes', true);
const proc = launcher.spawnv(['gst-inspect-1.0', '--exists', 'playbin']);
proc.wait_check_async(null, (source, result) => {
try {
source.wait_check_finish(result);
} catch (e) {
// Best-effort refresh; a missing binary or nonzero exit just leaves the cache as-is.
}
});
} catch (e) {
// Best-effort refresh; a missing gst-inspect-1.0 just leaves the cache as-is.
}
}
/**
* Loads the GObject-Introspection bindings the live wallpaper feature needs
* (Gst, GstApp for the appsink signals, Cogl for uploading decoded frames)
* and initializes GStreamer. Used by liveWallpaper.js, which only ever runs
* inside the gnome-shell process itself.
*
* Cogl is Mutter's *private* library: its typelib is only reachable from
* gnome-shell's own process (which gets a private search path), never from
* an ordinary GTK application. Do NOT reuse this for a diagnostic check in
* prefs.js — that runs in a separate, plain GTK4 process where importing
* Cogl will *always* fail regardless of whether live wallpapers actually
* work, producing a false "not found" report. Use
* checkGstreamerBaseAvailable() there instead.
*/
export async function loadGstreamerModules() {
keepGstInitFast();
const [{default: Gst}, , {default: Cogl}] = await Promise.all([
import('gi://Gst?version=1.0'),
import('gi://GstApp?version=1.0'),
import('gi://Cogl'),
]);
if (!Gst.is_initialized())
Gst.init(null);
refreshGstRegistryInBackground();
return {Gst, Cogl};
}
/**
* Lighter check for prefs.js: confirms the system-wide GStreamer packages
* (Gst core + the "app" plugin providing GstApp) are installed, without
* touching Cogl. This can't fully confirm live wallpapers will work (that
* also needs Cogl, only checkable from inside gnome-shell itself), but a
* failure here is a genuine, actionable problem, unlike a Cogl probe.
*/
export async function checkGstreamerBaseAvailable() {
keepGstInitFast();
const [{default: Gst}] = await Promise.all([
import('gi://Gst?version=1.0'),
import('gi://GstApp?version=1.0'),
]);
if (!Gst.is_initialized())
Gst.init(null);
refreshGstRegistryInBackground();
}
export const GSTREAMER_INSTALL_HINT =
'Install GStreamer’s "base" and "good" plugin sets (with their GObject-Introspection data), ' +
'which provide playback and GIF decoding:\n' +
'• Arch: sudo pacman -S gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav\n' +
'• Debian/Ubuntu: sudo apt install gstreamer1.0-plugins-base gstreamer1.0-plugins-good ' +
'gir1.2-gst-plugins-base-1.0\n' +
'• Fedora: sudo dnf install gstreamer1-plugins-base gstreamer1-plugins-good gobject-introspection\n' +
'Then restart GNOME Shell (log out and back in on Wayland).';