mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-28 14:07:47 -04:00
142 lines
5.7 KiB
QML
142 lines
5.7 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import qs.Common
|
|
import qs.Services
|
|
import "../../Common/WidgetPlacement.js" as Placement
|
|
import "../../Common/LockScrollAtlas.js" as Atlas
|
|
|
|
Item {
|
|
id: root
|
|
|
|
required property var screen
|
|
|
|
readonly property string screenName: screen.name
|
|
readonly property string source: {
|
|
const path = SessionData.getMonitorWallpaper(screenName);
|
|
return path && !path.startsWith("#") ? "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/') : "";
|
|
}
|
|
readonly property string backgroundKey: LockPlacementService.backgroundKey(screenName, screen.width, screen.height)
|
|
readonly property bool needed: !IdleService.isShellLocked && LockPlacementService.usesScrollAtlas(screenName) && LockPlacementService.neededFor(screen) && !LockPlacementService.hasSample(screenName, backgroundKey)
|
|
readonly property real sampleScale: LockPlacementService.sampleSize / Math.max(1, screen.width, screen.height)
|
|
readonly property int sampleWidth: Math.max(1, Math.round(screen.width * sampleScale))
|
|
readonly property int sampleHeight: Math.max(1, Math.round(screen.height * sampleScale))
|
|
readonly property string atlasKey: JSON.stringify([source, screen.width, screen.height, Theme.lockScreenScrimAlpha, Theme.screenOffColor.toString(), SettingsData.effectiveWallpaperBackgroundColor.toString()])
|
|
property var atlas: null
|
|
readonly property bool busy: builder.active
|
|
|
|
onNeededChanged: sample()
|
|
onBackgroundKeyChanged: sample()
|
|
Component.onCompleted: LockPlacementService.setScrollSampler(screenName, true)
|
|
Component.onDestruction: LockPlacementService.setScrollSampler(screenName, false)
|
|
|
|
function sample() {
|
|
if (!needed || busy)
|
|
return;
|
|
if (atlas?.key !== atlasKey) {
|
|
builder.active = true;
|
|
return;
|
|
}
|
|
if (atlas.failed)
|
|
return;
|
|
const scroll = SessionData.getMonitorScrollPosition(screenName);
|
|
const view = Atlas.scrollWindow(atlas.imageWidth, atlas.imageHeight, screen.width, screen.height, scroll.scrollX, scroll.scrollY);
|
|
LockPlacementService.storeSample(screenName, backgroundKey, Atlas.crop(atlas.luminances, atlas.width, atlas.height, view, sampleWidth, sampleHeight), sampleWidth, sampleHeight);
|
|
}
|
|
|
|
function finish(result) {
|
|
atlas = result;
|
|
Qt.callLater(() => {
|
|
builder.active = false;
|
|
sample();
|
|
});
|
|
}
|
|
|
|
Loader {
|
|
id: builder
|
|
active: false
|
|
|
|
sourceComponent: Item {
|
|
property string key
|
|
property string url
|
|
|
|
Component.onCompleted: {
|
|
key = root.atlasKey;
|
|
url = root.source;
|
|
}
|
|
|
|
Image {
|
|
id: probe
|
|
visible: false
|
|
asynchronous: true
|
|
cache: false
|
|
source: parent.url
|
|
sourceSize: Qt.size(LockPlacementService.sampleSize * 8, LockPlacementService.sampleSize * 8)
|
|
|
|
onStatusChanged: {
|
|
if (status === Image.Error) {
|
|
root.finish({
|
|
key: parent.key,
|
|
failed: true
|
|
});
|
|
return;
|
|
}
|
|
if (status !== Image.Ready)
|
|
return;
|
|
const size = Atlas.atlasSize(implicitWidth, implicitHeight, root.screen.width, root.screen.height, root.sampleWidth, root.sampleHeight);
|
|
canvas.width = size.width;
|
|
canvas.height = size.height;
|
|
canvas.load();
|
|
}
|
|
}
|
|
|
|
Canvas {
|
|
id: canvas
|
|
readonly property string key: parent.key
|
|
readonly property string imageUrl: parent.url
|
|
|
|
opacity: 0
|
|
|
|
function load() {
|
|
if (available && width > 0)
|
|
loadImage(imageUrl, Qt.size(width, height));
|
|
}
|
|
|
|
onAvailableChanged: load()
|
|
onImageLoaded: requestPaint()
|
|
onPaint: {
|
|
if (isImageError(imageUrl)) {
|
|
root.finish({
|
|
key,
|
|
failed: true
|
|
});
|
|
return;
|
|
}
|
|
if (!isImageLoaded(imageUrl))
|
|
return;
|
|
const context = getContext("2d");
|
|
context.fillStyle = SettingsData.effectiveWallpaperBackgroundColor;
|
|
context.fillRect(0, 0, width, height);
|
|
context.drawImage(imageUrl, 0, 0, width, height);
|
|
const pixels = context.getImageData(0, 0, width, height).data;
|
|
unloadImage(imageUrl);
|
|
const scrim = Theme.screenOffColor;
|
|
const alpha = Theme.lockScreenScrimAlpha;
|
|
const blend = (value, over) => value / 255 * (1 - alpha) + over * alpha;
|
|
const luminances = new Array(width * height);
|
|
for (let i = 0; i < luminances.length; i++)
|
|
luminances[i] = Placement.luminance(blend(pixels[i * 4], scrim.r), blend(pixels[i * 4 + 1], scrim.g), blend(pixels[i * 4 + 2], scrim.b));
|
|
root.finish({
|
|
key,
|
|
imageWidth: probe.implicitWidth,
|
|
imageHeight: probe.implicitHeight,
|
|
width,
|
|
height,
|
|
luminances
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|