Speed up changes
This commit is contained in:
+46
-18
@@ -13,6 +13,7 @@ CURRENT_THEME_PATH="$HOME/.config/omarchy/current/theme"
|
||||
NEXT_THEME_PATH="$HOME/.config/omarchy/current/next-theme"
|
||||
CURRENT_BACKGROUND_LINK="$HOME/.config/omarchy/current/background"
|
||||
BACKGROUND_TRANSITION_CACHE="$HOME/.cache/omarchy/background-transitions"
|
||||
THEME_SET_LOCK="${XDG_RUNTIME_DIR:-/tmp}/omarchy-theme-set.lock"
|
||||
USER_THEMES_PATH="$HOME/.config/omarchy/themes"
|
||||
OMARCHY_THEMES_PATH="$OMARCHY_PATH/themes"
|
||||
|
||||
@@ -30,22 +31,34 @@ run_parallel() {
|
||||
done
|
||||
}
|
||||
|
||||
snapshot_current_background() {
|
||||
local current_background snapshot extension
|
||||
shell_ipc() {
|
||||
timeout 2 omarchy-shell-ipc --if-running "$@" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
current_background=$(readlink -f "$CURRENT_BACKGROUND_LINK" 2>/dev/null || true)
|
||||
[[ -f $current_background ]] || return
|
||||
snapshot_background_path() {
|
||||
local background="$1"
|
||||
local name="$2"
|
||||
local snapshot extension
|
||||
|
||||
[[ -f $background ]] || return
|
||||
|
||||
mkdir -p "$BACKGROUND_TRANSITION_CACHE"
|
||||
extension=${current_background##*.}
|
||||
snapshot="$BACKGROUND_TRANSITION_CACHE/previous-$$.$extension"
|
||||
ln "$current_background" "$snapshot" 2>/dev/null || cp "$current_background" "$snapshot"
|
||||
extension=${background##*.}
|
||||
snapshot="$BACKGROUND_TRANSITION_CACHE/$name-$$.$extension"
|
||||
ln "$background" "$snapshot" 2>/dev/null || cp "$background" "$snapshot"
|
||||
echo "$snapshot"
|
||||
}
|
||||
|
||||
snapshot_current_background() {
|
||||
local current_background
|
||||
|
||||
current_background=$(readlink -f "$CURRENT_BACKGROUND_LINK" 2>/dev/null || true)
|
||||
snapshot_background_path "$current_background" "previous"
|
||||
}
|
||||
|
||||
set_theme_background() {
|
||||
local backgrounds=()
|
||||
local current_background index new_background next_index
|
||||
local current_background index new_background next_index new_background_snapshot
|
||||
|
||||
mapfile -d '' -t backgrounds < <(
|
||||
find -L "$HOME/.config/omarchy/backgrounds/$THEME_NAME/" "$CURRENT_THEME_PATH/backgrounds/" -maxdepth 1 -type f \
|
||||
@@ -55,7 +68,7 @@ set_theme_background() {
|
||||
|
||||
if (( ${#backgrounds[@]} == 0 )); then
|
||||
omarchy-notification-send "No background was found for theme" -t 2000
|
||||
omarchy-shell-ipc-fast shell applyTheme "$colors_payload" "$shell_payload" >/dev/null 2>&1 || true
|
||||
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -75,16 +88,25 @@ set_theme_background() {
|
||||
new_background="${backgrounds[$next_index]}"
|
||||
fi
|
||||
|
||||
ln -nsf "$new_background" "$CURRENT_BACKGROUND_LINK"
|
||||
new_background_snapshot=$(snapshot_background_path "$new_background" "next")
|
||||
|
||||
if [[ -f $OLD_BACKGROUND_SNAPSHOT ]]; then
|
||||
omarchy-shell-ipc-fast background themeTransition "$OLD_BACKGROUND_SNAPSHOT" "$new_background" "$colors_payload" "$shell_payload" >/dev/null 2>&1 || \
|
||||
omarchy-shell-ipc-fast shell applyTheme "$colors_payload" "$shell_payload" >/dev/null 2>&1 || true
|
||||
(sleep 3; rm -f "$OLD_BACKGROUND_SNAPSHOT") &
|
||||
if [[ -f $OLD_BACKGROUND_SNAPSHOT && -f $new_background_snapshot ]]; then
|
||||
shell_ipc background themeTransition "$OLD_BACKGROUND_SNAPSHOT" "$new_background_snapshot" "$new_background" "$colors_payload" "$shell_payload" || \
|
||||
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
||||
(sleep 3; rm -f "$OLD_BACKGROUND_SNAPSHOT" "$new_background_snapshot") &
|
||||
elif [[ -f $new_background_snapshot ]]; then
|
||||
shell_ipc background themeTransition "" "$new_background_snapshot" "$new_background" "$colors_payload" "$shell_payload" || \
|
||||
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
||||
(sleep 3; rm -f "$new_background_snapshot") &
|
||||
else
|
||||
omarchy-shell-ipc-fast background themeTransition "" "$new_background" "$colors_payload" "$shell_payload" >/dev/null 2>&1 || \
|
||||
omarchy-shell-ipc-fast shell applyTheme "$colors_payload" "$shell_payload" >/dev/null 2>&1 || true
|
||||
shell_ipc background themeTransition "$OLD_BACKGROUND_SNAPSHOT" "$new_background" "$new_background" "$colors_payload" "$shell_payload" || \
|
||||
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
||||
if [[ -f $OLD_BACKGROUND_SNAPSHOT ]]; then
|
||||
(sleep 3; rm -f "$OLD_BACKGROUND_SNAPSHOT") &
|
||||
fi
|
||||
fi
|
||||
|
||||
ln -nsf "$new_background" "$CURRENT_BACKGROUND_LINK"
|
||||
}
|
||||
|
||||
THEME_NAME=$(echo "$1" | sed -E 's/<[^>]+>//g' | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
|
||||
@@ -94,9 +116,15 @@ if [[ ! -d $OMARCHY_THEMES_PATH/$THEME_NAME ]] && [[ ! -d $USER_THEMES_PATH/$THE
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Serialize theme changes. Theme switching rebuilds a shared next-theme staging
|
||||
# directory and updates current theme/background symlinks; concurrent calls can
|
||||
# otherwise race and make one selection appear to be ignored.
|
||||
exec 9>"$THEME_SET_LOCK"
|
||||
flock 9
|
||||
|
||||
# Prevent file-watch reloads from changing shell colors before the background
|
||||
# reveal is ready. The theme IPC below resumes reloads as it applies colors.
|
||||
omarchy-shell-ipc --if-running shell suspendThemeReloads >/dev/null 2>&1 || true
|
||||
shell_ipc shell suspendThemeReloads || true
|
||||
|
||||
# Setup clean next theme directory (for atomic theme config swapping)
|
||||
rm -rf "$NEXT_THEME_PATH"
|
||||
@@ -131,7 +159,7 @@ echo "$THEME_NAME" >"$HOME/.config/omarchy/current/theme.name"
|
||||
colors_payload=$([[ -f $CURRENT_THEME_PATH/colors.toml ]] && base64 -w 0 "$CURRENT_THEME_PATH/colors.toml")
|
||||
shell_payload=$([[ -f $CURRENT_THEME_PATH/shell.toml ]] && base64 -w 0 "$CURRENT_THEME_PATH/shell.toml")
|
||||
if [[ $OMARCHY_THEME_SKIP_BACKGROUND == "1" ]]; then
|
||||
omarchy-shell-ipc-fast shell applyTheme "$colors_payload" "$shell_payload" >/dev/null 2>&1 || true
|
||||
shell_ipc shell applyTheme "$colors_payload" "$shell_payload" || true
|
||||
else
|
||||
set_theme_background
|
||||
fi
|
||||
|
||||
@@ -2,6 +2,8 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Shapes
|
||||
import qs.Commons as NoctaliaCommons
|
||||
|
||||
Item {
|
||||
@@ -36,14 +38,15 @@ Item {
|
||||
}
|
||||
|
||||
function setBackground(path, instant) {
|
||||
transitionBackground("", path, instant)
|
||||
transitionBackground("", path, path, instant, false)
|
||||
}
|
||||
|
||||
function transitionBackground(fromPath, path, instant) {
|
||||
function transitionBackground(fromPath, path, finalPath, instant, force) {
|
||||
path = String(path || "").trim()
|
||||
finalPath = String(finalPath || path).trim()
|
||||
fromPath = String(fromPath || "").trim()
|
||||
if (!path || path === currentBackground) return
|
||||
currentBackground = path
|
||||
if (!path || (!force && finalPath === currentBackground)) return
|
||||
currentBackground = finalPath
|
||||
backgroundVersion += 1
|
||||
revealStartedVersion = -1
|
||||
|
||||
@@ -83,8 +86,8 @@ Item {
|
||||
pendingShellRaw = ""
|
||||
}
|
||||
|
||||
function transitionBackgroundWithTheme(fromPath, path, colorsB64, shellB64) {
|
||||
transitionBackground(fromPath, path, false)
|
||||
function transitionBackgroundWithTheme(fromPath, path, finalPath, colorsB64, shellB64) {
|
||||
transitionBackground(fromPath, path, finalPath, false, true)
|
||||
setPendingTheme(colorsB64, shellB64)
|
||||
if (!incomingBackground || revealProgress >= 1) applyPendingTheme()
|
||||
}
|
||||
@@ -142,11 +145,11 @@ Item {
|
||||
}
|
||||
|
||||
function transition(fromPath: string, path: string): void {
|
||||
root.transitionBackground(fromPath, path, false)
|
||||
root.transitionBackground(fromPath, path, path, false, false)
|
||||
}
|
||||
|
||||
function themeTransition(fromPath: string, path: string, colorsB64: string, shellB64: string): void {
|
||||
root.transitionBackgroundWithTheme(fromPath, path, colorsB64, shellB64)
|
||||
function themeTransition(fromPath: string, path: string, finalPath: string, colorsB64: string, shellB64: string): void {
|
||||
root.transitionBackgroundWithTheme(fromPath, path, finalPath, colorsB64, shellB64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +170,7 @@ Item {
|
||||
easing.type: Easing.InOutCubic
|
||||
onFinished: {
|
||||
if (root.incomingBackground) {
|
||||
root.displayedBackground = root.incomingBackground
|
||||
root.displayedBackground = root.currentBackground || root.incomingBackground
|
||||
root.finishingTransition = true
|
||||
}
|
||||
root.revealProgress = 1
|
||||
@@ -188,6 +191,19 @@ Item {
|
||||
anchors { top: true; bottom: true; left: true; right: true }
|
||||
color: "transparent"
|
||||
property bool maskReady: false
|
||||
|
||||
function maybeStartReveal() {
|
||||
if (!root.incomingBackground || root.revealProgress !== 0 || maskReady) return
|
||||
if (incomingFrame.status !== Image.Ready) return
|
||||
if (root.oldBackground && oldFrame.status !== Image.Ready) return
|
||||
Qt.callLater(function() {
|
||||
if (!root.incomingBackground || root.revealProgress !== 0 || maskReady) return
|
||||
if (incomingFrame.status !== Image.Ready) return
|
||||
if (root.oldBackground && oldFrame.status !== Image.Ready) return
|
||||
root.startReveal(panel)
|
||||
})
|
||||
}
|
||||
|
||||
WlrLayershell.namespace: "omarchy-background"
|
||||
WlrLayershell.layer: WlrLayer.Background
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
@@ -199,7 +215,7 @@ Item {
|
||||
source: root.imageUrl(root.displayedBackground)
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: false
|
||||
cache: true
|
||||
onStatusChanged: {
|
||||
if (status === Image.Ready && root.finishingTransition) {
|
||||
root.incomingBackground = ""
|
||||
@@ -209,18 +225,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: incomingFrame
|
||||
anchors.fill: parent
|
||||
source: root.imageUrl(root.incomingBackground)
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: false
|
||||
visible: root.incomingBackground !== "" && status === Image.Ready
|
||||
opacity: root.revealProgress >= 1 ? 1 : 0.001
|
||||
onStatusChanged: if (status === Image.Ready && root.incomingBackground) revealCanvas.prepareImage()
|
||||
}
|
||||
|
||||
Image {
|
||||
id: oldFrame
|
||||
anchors.fill: parent
|
||||
@@ -228,94 +232,71 @@ Item {
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: false
|
||||
smooth: true
|
||||
mipmap: true
|
||||
visible: root.oldBackground !== "" && root.revealProgress < 1
|
||||
onStatusChanged: if (status === Image.Ready && root.incomingBackground) revealCanvas.requestPaint()
|
||||
onStatusChanged: panel.maybeStartReveal()
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: revealCanvas
|
||||
Item {
|
||||
id: incomingLayer
|
||||
anchors.fill: parent
|
||||
visible: root.incomingBackground !== "" && root.revealProgress < 1 && incomingFrame.status === Image.Ready && oldFrame.status === Image.Ready
|
||||
opacity: panel.maskReady ? 1 : 0
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Immediate
|
||||
visible: root.incomingBackground !== "" && incomingFrame.status === Image.Ready && (root.revealProgress >= 1 || panel.maskReady)
|
||||
layer.enabled: root.incomingBackground !== "" && root.revealProgress < 1
|
||||
layer.smooth: true
|
||||
layer.effect: MultiEffect {
|
||||
maskEnabled: true
|
||||
maskSource: revealMask
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 0.02
|
||||
}
|
||||
|
||||
Image {
|
||||
id: incomingFrame
|
||||
anchors.fill: parent
|
||||
source: root.imageUrl(root.incomingBackground)
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: false
|
||||
smooth: true
|
||||
mipmap: true
|
||||
onStatusChanged: panel.maybeStartReveal()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: revealMask
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
layer.enabled: true
|
||||
|
||||
readonly property real slant: -0.18
|
||||
readonly property real centerTop: width / 2 - slant * height / 2
|
||||
readonly property real centerBottom: width / 2 + slant * height / 2
|
||||
readonly property real reach: width / 2 + Math.abs(slant) * height / 2 + 4
|
||||
readonly property real spread: reach * root.revealProgress
|
||||
|
||||
function prepareImage() {
|
||||
var src = root.imageUrl(root.incomingBackground)
|
||||
if (!src) return
|
||||
if (isImageLoaded(src)) {
|
||||
requestPaint()
|
||||
} else if (!isImageLoading(src)) {
|
||||
loadImage(src)
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: "white"
|
||||
strokeColor: "transparent"
|
||||
startX: revealMask.centerTop - revealMask.spread; startY: 0
|
||||
PathLine { x: revealMask.centerTop + revealMask.spread; y: 0 }
|
||||
PathLine { x: revealMask.centerBottom + revealMask.spread; y: revealMask.height }
|
||||
PathLine { x: revealMask.centerBottom - revealMask.spread; y: revealMask.height }
|
||||
PathLine { x: revealMask.centerTop - revealMask.spread; y: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onImageLoaded: function(url) {
|
||||
if (url === root.imageUrl(root.incomingBackground)) requestPaint()
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
ctx.reset()
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
|
||||
var src = root.imageUrl(root.incomingBackground)
|
||||
if (!src || incomingFrame.status !== Image.Ready || root.revealProgress >= 1) return
|
||||
if (!isImageLoaded(src)) {
|
||||
prepareImage()
|
||||
return
|
||||
}
|
||||
|
||||
var iw = incomingFrame.sourceSize.width
|
||||
var ih = incomingFrame.sourceSize.height
|
||||
if (iw <= 0 || ih <= 0 || width <= 0 || height <= 0) return
|
||||
|
||||
var sx = 0
|
||||
var sy = 0
|
||||
var sw = iw
|
||||
var sh = ih
|
||||
if (iw / ih > width / height) {
|
||||
sw = ih * width / height
|
||||
sx = (iw - sw) / 2
|
||||
} else {
|
||||
sh = iw * height / width
|
||||
sy = (ih - sh) / 2
|
||||
}
|
||||
|
||||
var centerTop = width / 2 - slant * height / 2
|
||||
var centerBottom = width / 2 + slant * height / 2
|
||||
var reach = width / 2 + Math.abs(slant) * height / 2 + 4
|
||||
var spread = reach * root.revealProgress
|
||||
var leftTop = centerTop - spread
|
||||
var leftBottom = centerBottom - spread
|
||||
var rightTop = centerTop + spread
|
||||
var rightBottom = centerBottom + spread
|
||||
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(leftTop, 0)
|
||||
ctx.lineTo(rightTop, 0)
|
||||
ctx.lineTo(rightBottom, height)
|
||||
ctx.lineTo(leftBottom, height)
|
||||
ctx.closePath()
|
||||
ctx.clip()
|
||||
ctx.drawImage(src, sx, sy, sw, sh, 0, 0, width, height)
|
||||
ctx.restore()
|
||||
|
||||
if (!panel.maskReady && root.incomingBackground && root.revealProgress === 0) {
|
||||
Qt.callLater(function() { root.startReveal(panel) })
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onRevealProgressChanged() { revealCanvas.requestPaint() }
|
||||
function onIncomingBackgroundChanged() {
|
||||
panel.maskReady = false
|
||||
revealCanvas.prepareImage()
|
||||
}
|
||||
Connections {
|
||||
target: root
|
||||
function onIncomingBackgroundChanged() {
|
||||
panel.maskReady = false
|
||||
panel.maybeStartReveal()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user