Allow selecting animated GIFs as live wallpapers
The playback pipeline already typefinds by content and decodes GIFs via GStreamer's decodebin like any other video, but the preferences file picker filtered to video/* MIME types only, hiding .gif files. Widen the filter to include image/gif and *.gif, add an "All files" fallback, and update the related copy/docs to mention GIF support. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RDqbdjsiisSU7CbQke4g8
This commit is contained in:
@@ -10,11 +10,11 @@ protection against OLED burn-in.
|
|||||||
through the images inside them on a timer, in sequential or shuffled
|
through the images inside them on a timer, in sequential or shuffled
|
||||||
order, with an optional crossfade between changes. The chosen wallpaper
|
order, with an optional crossfade between changes. The chosen wallpaper
|
||||||
can also be applied to the lock screen.
|
can also be applied to the lock screen.
|
||||||
- **Live wallpapers** — play a looping video file as your desktop
|
- **Live wallpapers** — play a looping video *or animated GIF* as your
|
||||||
background. Frames are decoded with GStreamer and rendered directly by
|
desktop background. Frames are decoded with GStreamer and rendered
|
||||||
GNOME Shell's own Clutter stage (no external, incompatible Clutter
|
directly by GNOME Shell's own Clutter stage (no external, incompatible
|
||||||
build involved). Playback can automatically pause on battery power or
|
Clutter build involved). Playback can automatically pause on battery
|
||||||
while a window is fullscreen.
|
power or while a window is fullscreen.
|
||||||
- **OLED burn-in protection** — three independent, individually toggled
|
- **OLED burn-in protection** — three independent, individually toggled
|
||||||
techniques:
|
techniques:
|
||||||
- *Pixel shifting*: nudges the background a few pixels on a slow drift
|
- *Pixel shifting*: nudges the background a few pixels on a slow drift
|
||||||
@@ -34,9 +34,9 @@ protection against OLED burn-in.
|
|||||||
- GNOME Shell 50.
|
- GNOME Shell 50.
|
||||||
- For live wallpapers: GStreamer with its `good` and `base` plugin sets
|
- For live wallpapers: GStreamer with its `good` and `base` plugin sets
|
||||||
(e.g. `gstreamer1.0-plugins-good` and `gstreamer1.0-plugins-base`, or
|
(e.g. `gstreamer1.0-plugins-good` and `gstreamer1.0-plugins-base`, or
|
||||||
your distribution's equivalent). If these aren't installed, the live
|
your distribution's equivalent) — the `good` set is also what provides
|
||||||
wallpaper toggle stays disabled and BenthicBloom's other features work
|
animated GIF decoding. If these aren't installed, the live wallpaper
|
||||||
normally.
|
toggle stays disabled and BenthicBloom's other features work normally.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
|||||||
import {SettingsKey} from './settingsKeys.js';
|
import {SettingsKey} from './settingsKeys.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays a video file as a looping animated background.
|
* Plays a video or animated GIF file as a looping animated background.
|
||||||
|
* `playbin` typefinds the source by content rather than extension, so GIFs
|
||||||
|
* are decoded through GStreamer's own GIF element (from the "good" plugin
|
||||||
|
* set) and handled exactly like any other video stream below this point.
|
||||||
*
|
*
|
||||||
* Mutter embeds its own private copy of Clutter, so GStreamer video sinks
|
* Mutter embeds its own private copy of Clutter, so GStreamer video sinks
|
||||||
* that hand back a Clutter actor from a *different* Clutter instance (e.g.
|
* that hand back a Clutter actor from a *different* Clutter instance (e.g.
|
||||||
|
|||||||
@@ -176,8 +176,9 @@ export default class BenthicBloomPreferences extends ExtensionPreferences {
|
|||||||
const group = new Adw.PreferencesGroup({
|
const group = new Adw.PreferencesGroup({
|
||||||
title: _('Video Wallpaper'),
|
title: _('Video Wallpaper'),
|
||||||
description: _(
|
description: _(
|
||||||
'Play a looping video as your desktop background instead of a static image. ' +
|
'Play a looping video or animated GIF as your desktop background instead of a static image. ' +
|
||||||
'Requires GStreamer (with its "good" and "base" plugin sets) to be installed on your system.'),
|
'Requires GStreamer (with its "good" and "base" plugin sets, which provide GIF decoding) ' +
|
||||||
|
'to be installed on your system.'),
|
||||||
});
|
});
|
||||||
page.add(group);
|
page.add(group);
|
||||||
group.add(this._switchRow(
|
group.add(this._switchRow(
|
||||||
@@ -185,17 +186,26 @@ export default class BenthicBloomPreferences extends ExtensionPreferences {
|
|||||||
_('Enable Live Wallpaper'), _('Overrides the static wallpaper while active')));
|
_('Enable Live Wallpaper'), _('Overrides the static wallpaper while active')));
|
||||||
|
|
||||||
const fileRow = new Adw.ActionRow({
|
const fileRow = new Adw.ActionRow({
|
||||||
title: _('Video File'),
|
title: _('Video / GIF File'),
|
||||||
subtitle: settings.get_string(SettingsKey.LIVE_WALLPAPER_PATH) || _('None selected'),
|
subtitle: settings.get_string(SettingsKey.LIVE_WALLPAPER_PATH) || _('None selected'),
|
||||||
});
|
});
|
||||||
const chooseButton = new Gtk.Button({label: _('Choose…'), valign: Gtk.Align.CENTER, css_classes: ['flat']});
|
const chooseButton = new Gtk.Button({label: _('Choose…'), valign: Gtk.Align.CENTER, css_classes: ['flat']});
|
||||||
chooseButton.connect('clicked', () => {
|
chooseButton.connect('clicked', () => {
|
||||||
const dialog = new Gtk.FileDialog({title: _('Select Wallpaper Video')});
|
const dialog = new Gtk.FileDialog({title: _('Select Wallpaper Video or GIF')});
|
||||||
const filter = new Gtk.FileFilter();
|
|
||||||
filter.add_mime_type('video/*');
|
const mediaFilter = new Gtk.FileFilter({name: _('Videos and animated GIFs')});
|
||||||
|
mediaFilter.add_mime_type('video/*');
|
||||||
|
mediaFilter.add_mime_type('image/gif');
|
||||||
|
mediaFilter.add_pattern('*.gif');
|
||||||
|
|
||||||
|
const allFilter = new Gtk.FileFilter({name: _('All files')});
|
||||||
|
allFilter.add_pattern('*');
|
||||||
|
|
||||||
const filterList = new Gio.ListStore({item_type: Gtk.FileFilter});
|
const filterList = new Gio.ListStore({item_type: Gtk.FileFilter});
|
||||||
filterList.append(filter);
|
filterList.append(mediaFilter);
|
||||||
|
filterList.append(allFilter);
|
||||||
dialog.filters = filterList;
|
dialog.filters = filterList;
|
||||||
|
dialog.default_filter = mediaFilter;
|
||||||
|
|
||||||
dialog.open(fileRow.get_root(), null, (source, result) => {
|
dialog.open(fileRow.get_root(), null, (source, result) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -70,13 +70,13 @@
|
|||||||
<key name="live-wallpaper-enabled" type="b">
|
<key name="live-wallpaper-enabled" type="b">
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
<summary>Enable live wallpaper</summary>
|
<summary>Enable live wallpaper</summary>
|
||||||
<description>Whether a video is played as an animated desktop background instead of a static image.</description>
|
<description>Whether a video or animated GIF is played as an animated desktop background instead of a static image.</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="live-wallpaper-path" type="s">
|
<key name="live-wallpaper-path" type="s">
|
||||||
<default>""</default>
|
<default>""</default>
|
||||||
<summary>Live wallpaper video file</summary>
|
<summary>Live wallpaper media file</summary>
|
||||||
<description>Path to the video file used as the live wallpaper.</description>
|
<description>Path to the video or animated GIF file used as the live wallpaper.</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="live-wallpaper-muted" type="b">
|
<key name="live-wallpaper-muted" type="b">
|
||||||
|
|||||||
Reference in New Issue
Block a user