Faster and smoother theme changes
This commit is contained in:
+36
-4
@@ -12,6 +12,7 @@ fi
|
||||
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"
|
||||
USER_THEMES_PATH="$HOME/.config/omarchy/themes"
|
||||
OMARCHY_THEMES_PATH="$OMARCHY_PATH/themes"
|
||||
|
||||
@@ -29,6 +30,19 @@ run_parallel() {
|
||||
done
|
||||
}
|
||||
|
||||
snapshot_current_background() {
|
||||
local current_background snapshot extension
|
||||
|
||||
current_background=$(readlink -f "$CURRENT_BACKGROUND_LINK" 2>/dev/null || true)
|
||||
[[ -f $current_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"
|
||||
echo "$snapshot"
|
||||
}
|
||||
|
||||
set_theme_background() {
|
||||
local backgrounds=()
|
||||
local current_background index new_background next_index
|
||||
@@ -41,6 +55,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
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -61,7 +76,15 @@ set_theme_background() {
|
||||
fi
|
||||
|
||||
ln -nsf "$new_background" "$CURRENT_BACKGROUND_LINK"
|
||||
omarchy-shell-ipc-fast background setInstant "$new_background" >/dev/null 2>&1 || true
|
||||
|
||||
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") &
|
||||
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
|
||||
fi
|
||||
}
|
||||
|
||||
THEME_NAME=$(echo "$1" | sed -E 's/<[^>]+>//g' | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
|
||||
@@ -71,6 +94,10 @@ if [[ ! -d $OMARCHY_THEMES_PATH/$THEME_NAME ]] && [[ ! -d $USER_THEMES_PATH/$THE
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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
|
||||
|
||||
# Setup clean next theme directory (for atomic theme config swapping)
|
||||
rm -rf "$NEXT_THEME_PATH"
|
||||
mkdir -p "$NEXT_THEME_PATH"
|
||||
@@ -87,6 +114,11 @@ fi
|
||||
# Generate dynamic configs
|
||||
omarchy-theme-set-templates
|
||||
|
||||
OLD_BACKGROUND_SNAPSHOT=""
|
||||
if [[ $OMARCHY_THEME_SKIP_BACKGROUND != "1" ]]; then
|
||||
OLD_BACKGROUND_SNAPSHOT=$(snapshot_current_background)
|
||||
fi
|
||||
|
||||
# Swap next theme in as current
|
||||
rm -rf "$CURRENT_THEME_PATH"
|
||||
mv "$NEXT_THEME_PATH" "$CURRENT_THEME_PATH"
|
||||
@@ -98,9 +130,9 @@ echo "$THEME_NAME" >"$HOME/.config/omarchy/current/theme.name"
|
||||
# for file-watch debounce while the rest of the theme hooks run.
|
||||
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")
|
||||
omarchy-shell-ipc-fast shell applyTheme "$colors_payload" "$shell_payload" >/dev/null 2>&1 || true
|
||||
|
||||
if [[ $OMARCHY_THEME_SKIP_BACKGROUND != "1" ]]; then
|
||||
if [[ $OMARCHY_THEME_SKIP_BACKGROUND == "1" ]]; then
|
||||
omarchy-shell-ipc-fast shell applyTheme "$colors_payload" "$shell_payload" >/dev/null 2>&1 || true
|
||||
else
|
||||
set_theme_background
|
||||
fi
|
||||
|
||||
|
||||
@@ -170,7 +170,18 @@ QtObject {
|
||||
shellValues = parsed
|
||||
}
|
||||
|
||||
property bool themeReloadSuspended: false
|
||||
|
||||
function suspendThemeReloads() {
|
||||
themeReloadSuspended = true
|
||||
}
|
||||
|
||||
function resumeThemeReloads() {
|
||||
themeReloadSuspended = false
|
||||
}
|
||||
|
||||
function reloadTheme() {
|
||||
if (themeReloadSuspended) return
|
||||
colorsFile.reload()
|
||||
shellFile.reload()
|
||||
}
|
||||
@@ -184,7 +195,7 @@ QtObject {
|
||||
watchChanges: true
|
||||
printErrors: false
|
||||
onLoaded: root.loadColors(text())
|
||||
onFileChanged: reload()
|
||||
onFileChanged: root.reloadTheme()
|
||||
}
|
||||
property FileView shellFile: FileView {
|
||||
id: shellFile
|
||||
@@ -193,7 +204,7 @@ QtObject {
|
||||
printErrors: false
|
||||
onLoaded: root.loadShell(text())
|
||||
onLoadFailed: root.loadShell("")
|
||||
onFileChanged: reload()
|
||||
onFileChanged: root.reloadTheme()
|
||||
}
|
||||
property FileView themeNameFile: FileView {
|
||||
path: Quickshell.env("HOME") + "/.config/omarchy/current/theme.name"
|
||||
|
||||
@@ -2,6 +2,7 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import qs.Commons as NoctaliaCommons
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -19,6 +20,10 @@ Item {
|
||||
property string oldBackground: ""
|
||||
property bool finishingTransition: false
|
||||
property int backgroundVersion: 0
|
||||
property int revealStartedVersion: -1
|
||||
property int pendingThemeVersion: -1
|
||||
property string pendingColorsRaw: ""
|
||||
property string pendingShellRaw: ""
|
||||
property real revealProgress: 1
|
||||
|
||||
function imageUrl(path) {
|
||||
@@ -31,10 +36,16 @@ Item {
|
||||
}
|
||||
|
||||
function setBackground(path, instant) {
|
||||
transitionBackground("", path, instant)
|
||||
}
|
||||
|
||||
function transitionBackground(fromPath, path, instant) {
|
||||
path = String(path || "").trim()
|
||||
fromPath = String(fromPath || "").trim()
|
||||
if (!path || path === currentBackground) return
|
||||
currentBackground = path
|
||||
backgroundVersion += 1
|
||||
revealStartedVersion = -1
|
||||
|
||||
revealAnimation.stop()
|
||||
finishingTransition = false
|
||||
@@ -47,11 +58,46 @@ Item {
|
||||
return
|
||||
}
|
||||
|
||||
oldBackground = displayedBackground
|
||||
oldBackground = fromPath || displayedBackground
|
||||
incomingBackground = path
|
||||
revealProgress = 0
|
||||
}
|
||||
|
||||
function decodePayload(payload) {
|
||||
try { return Qt.atob(String(payload || "")) } catch (e) { return "" }
|
||||
}
|
||||
|
||||
function setPendingTheme(colorsB64, shellB64) {
|
||||
pendingColorsRaw = decodePayload(colorsB64)
|
||||
pendingShellRaw = decodePayload(shellB64)
|
||||
pendingThemeVersion = backgroundVersion
|
||||
}
|
||||
|
||||
function applyPendingTheme() {
|
||||
if (pendingThemeVersion !== backgroundVersion) return
|
||||
NoctaliaCommons.Color.resumeThemeReloads()
|
||||
NoctaliaCommons.Color.loadColors(pendingColorsRaw)
|
||||
NoctaliaCommons.Color.loadShell(pendingShellRaw)
|
||||
pendingThemeVersion = -1
|
||||
pendingColorsRaw = ""
|
||||
pendingShellRaw = ""
|
||||
}
|
||||
|
||||
function transitionBackgroundWithTheme(fromPath, path, colorsB64, shellB64) {
|
||||
transitionBackground(fromPath, path, false)
|
||||
setPendingTheme(colorsB64, shellB64)
|
||||
if (!incomingBackground || revealProgress >= 1) applyPendingTheme()
|
||||
}
|
||||
|
||||
function startReveal(panel) {
|
||||
if (!incomingBackground) return
|
||||
panel.maskReady = true
|
||||
if (revealStartedVersion === backgroundVersion) return
|
||||
revealStartedVersion = backgroundVersion
|
||||
applyPendingTheme()
|
||||
revealAnimation.restart()
|
||||
}
|
||||
|
||||
function openSelector() {
|
||||
if (!bgSwitchProc.running) bgSwitchProc.running = true
|
||||
}
|
||||
@@ -94,6 +140,14 @@ Item {
|
||||
function setInstant(path: string): void {
|
||||
root.setBackground(path, true)
|
||||
}
|
||||
|
||||
function transition(fromPath: string, path: string): void {
|
||||
root.transitionBackground(fromPath, path, false)
|
||||
}
|
||||
|
||||
function themeTransition(fromPath: string, path: string, colorsB64: string, shellB64: string): void {
|
||||
root.transitionBackgroundWithTheme(fromPath, path, colorsB64, shellB64)
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -230,41 +284,28 @@ Item {
|
||||
sy = (ih - sh) / 2
|
||||
}
|
||||
|
||||
var center = width / 2
|
||||
var reach = width / 2 + Math.abs(slant) * height + 4
|
||||
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 = center - spread
|
||||
var leftBottom = center - spread + slant * height
|
||||
var rightTop = center + spread
|
||||
var rightBottom = center + spread + slant * height
|
||||
var leftTop = centerTop - spread
|
||||
var leftBottom = centerBottom - spread
|
||||
var rightTop = centerTop + spread
|
||||
var rightBottom = centerBottom + spread
|
||||
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(center, 0)
|
||||
ctx.lineTo(leftTop, 0)
|
||||
ctx.lineTo(leftBottom, height)
|
||||
ctx.lineTo(center, height)
|
||||
ctx.closePath()
|
||||
ctx.clip()
|
||||
ctx.drawImage(src, sx, sy, sw, sh, 0, 0, width, height)
|
||||
ctx.restore()
|
||||
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(center, 0)
|
||||
ctx.moveTo(leftTop, 0)
|
||||
ctx.lineTo(rightTop, 0)
|
||||
ctx.lineTo(rightBottom, height)
|
||||
ctx.lineTo(center, 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() {
|
||||
panel.maskReady = true
|
||||
revealAnimation.restart()
|
||||
})
|
||||
Qt.callLater(function() { root.startReveal(panel) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -792,11 +792,17 @@ ShellRoot {
|
||||
var shellRaw = ""
|
||||
try { colorsRaw = Qt.atob(String(colorsB64 || "")) } catch (e) { colorsRaw = "" }
|
||||
try { shellRaw = Qt.atob(String(shellB64 || "")) } catch (e2) { shellRaw = "" }
|
||||
NoctaliaCommons.Color.resumeThemeReloads()
|
||||
NoctaliaCommons.Color.loadColors(colorsRaw)
|
||||
NoctaliaCommons.Color.loadShell(shellRaw)
|
||||
return "ok"
|
||||
}
|
||||
|
||||
function suspendThemeReloads(): string {
|
||||
NoctaliaCommons.Color.suspendThemeReloads()
|
||||
return "ok"
|
||||
}
|
||||
|
||||
function reloadTheme(): string {
|
||||
NoctaliaCommons.Color.reloadTheme()
|
||||
return "ok"
|
||||
|
||||
Reference in New Issue
Block a user