Claude/gnome wallpaper auto rotation r1ailq #1
+54
-7
@@ -1,11 +1,36 @@
|
||||
import GLib from 'gi://GLib';
|
||||
import Gio from 'gi://Gio';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import St from 'gi://St';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import {SettingsKey} from './settingsKeys.js';
|
||||
import {loadGstreamerModules, GSTREAMER_INSTALL_HINT} from './gstreamerAvailability.js';
|
||||
|
||||
/**
|
||||
* Ways to get a decoded frame onto an actor, tried in order and "pinned"
|
||||
* once one works. `new Clutter.Image()` failed with "is not a constructor"
|
||||
* in real-world testing (Clutter.Image is apparently no longer directly
|
||||
* constructible from GJS in current Mutter); St.ImageContent — the same
|
||||
* mechanism gnome-shell's own code uses for uploading raw pixel buffers —
|
||||
* is tried first, with the legacy Clutter.Image/set_data path kept only as
|
||||
* a fallback for older shells.
|
||||
*/
|
||||
const FRAME_IMAGE_STRATEGIES = [
|
||||
{
|
||||
name: 'St.ImageContent',
|
||||
create: (width, height) => St.ImageContent.new_with_preferred_size(width, height),
|
||||
upload: (image, Cogl, data, width, height) =>
|
||||
image.set_bytes(GLib.Bytes.new(data), Cogl.PixelFormat.RGBA_8888, width, height, width * 4),
|
||||
},
|
||||
{
|
||||
name: 'Clutter.Image',
|
||||
create: () => new Clutter.Image(),
|
||||
upload: (image, Cogl, data, width, height) =>
|
||||
image.set_data(data, Cogl.PixelFormat.RGBA_8888, width, height, width * 4),
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Plays a video or animated GIF file as a looping animated background.
|
||||
* `playbin` typefinds the source by content rather than extension, so GIFs
|
||||
@@ -53,6 +78,8 @@ export class LiveWallpaperManager {
|
||||
this._pollCount = 0;
|
||||
this._pollTimeoutId = 0;
|
||||
this._noFrameWatchdogId = 0;
|
||||
this._imageStrategyIndex = 0;
|
||||
this._frameErrorCount = 0;
|
||||
}
|
||||
|
||||
get isAvailable() {
|
||||
@@ -219,6 +246,8 @@ export class LiveWallpaperManager {
|
||||
|
||||
this._frameCount = 0;
|
||||
this._pollCount = 0;
|
||||
this._imageStrategyIndex = 0;
|
||||
this._frameErrorCount = 0;
|
||||
// ~30fps polling of the appsink from the main thread. See the
|
||||
// comment on appsink's properties above for why this replaces
|
||||
// a 'new-sample' signal handler.
|
||||
@@ -282,7 +311,14 @@ export class LiveWallpaperManager {
|
||||
buffer.unmap(mapInfo);
|
||||
}
|
||||
} catch (e) {
|
||||
this._logger.error(e, 'Failed to poll live wallpaper frame');
|
||||
// Rate-limited: this runs at ~30fps, so logging every failure
|
||||
// would flood the journal (and this loop keeps retrying every
|
||||
// frame, e.g. while cycling through FRAME_IMAGE_STRATEGIES).
|
||||
this._frameErrorCount++;
|
||||
if (this._frameErrorCount === 1 || this._frameErrorCount % 300 === 0) {
|
||||
this._logger.error(
|
||||
e, `Failed to poll live wallpaper frame (${this._frameErrorCount} failures so far)`);
|
||||
}
|
||||
}
|
||||
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
@@ -292,20 +328,31 @@ export class LiveWallpaperManager {
|
||||
if (!this._actor)
|
||||
return;
|
||||
|
||||
if (!this._image || this._videoWidth !== width || this._videoHeight !== height) {
|
||||
this._image = new Clutter.Image();
|
||||
const needsNewImage = !this._image || this._videoWidth !== width || this._videoHeight !== height;
|
||||
|
||||
while (this._imageStrategyIndex < FRAME_IMAGE_STRATEGIES.length) {
|
||||
const strategy = FRAME_IMAGE_STRATEGIES[this._imageStrategyIndex];
|
||||
try {
|
||||
if (needsNewImage) {
|
||||
this._image = strategy.create(width, height);
|
||||
this._videoWidth = width;
|
||||
this._videoHeight = height;
|
||||
}
|
||||
|
||||
try {
|
||||
this._image.set_data(data, this._Cogl.PixelFormat.RGBA_8888, width, height, width * 4);
|
||||
strategy.upload(this._image, this._Cogl, data, width, height);
|
||||
this._actor.set_content(this._image);
|
||||
return;
|
||||
} catch (e) {
|
||||
this._logger.error(e, 'Failed to upload live wallpaper frame');
|
||||
this._logger.warn(
|
||||
`Live wallpaper: frame image strategy "${strategy.name}" failed ` +
|
||||
`(${e.message ?? e}), trying the next one`);
|
||||
this._imageStrategyIndex++;
|
||||
this._image = null;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('All live wallpaper frame image strategies failed');
|
||||
}
|
||||
|
||||
_onBusMessage(message) {
|
||||
const Gst = this._Gst;
|
||||
switch (message.type) {
|
||||
|
||||
Reference in New Issue
Block a user