add (unnecessary) watchdog to wallpaper-daemon
This commit is contained in:
@@ -67,10 +67,9 @@ spicetify-maketplace # spotify themes
|
|||||||
nwg-look # theme of GTK apps
|
nwg-look # theme of GTK apps
|
||||||
catppuccin-gtk-theme-mocha # theme of GTK apps
|
catppuccin-gtk-theme-mocha # theme of GTK apps
|
||||||
kvantum
|
kvantum
|
||||||
qt5ct
|
|
||||||
qt6ct
|
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
bc
|
bc
|
||||||
jq
|
jq
|
||||||
python-colorthief
|
python-colorthief
|
||||||
|
python-watchdog
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Select image file if none is provided
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
image=$(zenity --file-selection --title="Open File" --file-filter="*.jpg *.jpeg *.png *.webp *.bmp *.jfif *.tiff *.avif *.heic *.heif")
|
image=$(zenity --file-selection --title="Open File" --file-filter="*.jpg *.jpeg *.png *.webp *.bmp *.jfif *.tiff *.avif *.heic *.heif")
|
||||||
else
|
else
|
||||||
@@ -9,6 +10,9 @@ fi
|
|||||||
[ -z "$image" ] && exit 1
|
[ -z "$image" ] && exit 1
|
||||||
[ ! -f "$image" ] && exit 1
|
[ ! -f "$image" ] && exit 1
|
||||||
|
|
||||||
|
|
||||||
|
# Copy image to local wallpaper directory
|
||||||
|
|
||||||
ext=${image##*.}
|
ext=${image##*.}
|
||||||
random_name=$(tr -dc 'a-zA-Z0-9' </dev/urandom | head -c 16)
|
random_name=$(tr -dc 'a-zA-Z0-9' </dev/urandom | head -c 16)
|
||||||
current_dir="$HOME/.local/share/wallpaper/current"
|
current_dir="$HOME/.local/share/wallpaper/current"
|
||||||
@@ -28,26 +32,18 @@ cp -f "$temp_img" "$image_copied" || (
|
|||||||
exit 1
|
exit 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if [ "$XDG_CURRENT_DESKTOP" = "Hyprland" ]; then
|
# Generate blurred wallpaper
|
||||||
hyprctl hyprpaper reload ,"$image_copied" || exit 1
|
|
||||||
echo "preload = $image_copied" >"$HOME/.config/hypr/hyprpaper.conf"
|
|
||||||
echo "wallpaper = , $image_copied" >>"$HOME/.config/hypr/hyprpaper.conf"
|
|
||||||
|
|
||||||
notify-send "Wallpaper Changed" "$image"
|
blur_dir="$HOME/.local/share/wallpaper/blurred"
|
||||||
elif [ "$XDG_CURRENT_DESKTOP" = "niri" ]; then
|
mkdir -p "$blur_dir" || (
|
||||||
killall swaybg
|
|
||||||
killall swww
|
|
||||||
|
|
||||||
blur_dir="$HOME/.local/share/wallpaper/blurred"
|
|
||||||
mkdir -p "$blur_dir" || (
|
|
||||||
echo "Could not create cache directory"
|
echo "Could not create cache directory"
|
||||||
exit 1
|
exit 1
|
||||||
)
|
)
|
||||||
rm -f "${blur_dir:?}"/blurred-*
|
rm -f "${blur_dir:?}"/blurred-*
|
||||||
blurred_image="$blur_dir/blurred-${random_name}.$ext"
|
blurred_image="$blur_dir/blurred-${random_name}.$ext"
|
||||||
|
|
||||||
# blur
|
## Time consuming task (magick -blur) in background
|
||||||
(
|
(
|
||||||
# notify-send "Generating Blurred Wallpaper" "This may take a few seconds..."
|
# notify-send "Generating Blurred Wallpaper" "This may take a few seconds..."
|
||||||
|
|
||||||
sigma=$(magick identify -format "%w %h" "$image_copied" | awk -v f=0.01 '{
|
sigma=$(magick identify -format "%w %h" "$image_copied" | awk -v f=0.01 '{
|
||||||
@@ -58,6 +54,7 @@ elif [ "$XDG_CURRENT_DESKTOP" = "niri" ]; then
|
|||||||
printf "%.2f", s
|
printf "%.2f", s
|
||||||
}')
|
}')
|
||||||
|
|
||||||
|
### use a temporary file to avoid incomplete file being used
|
||||||
temp_blurred=$(mktemp --suffix=."$ext") || exit 1
|
temp_blurred=$(mktemp --suffix=."$ext") || exit 1
|
||||||
trap 'rm -f "${temp_blurred}"' EXIT
|
trap 'rm -f "${temp_blurred}"' EXIT
|
||||||
magick "$image_copied" -blur 0x"$sigma" "$temp_blurred" || (
|
magick "$image_copied" -blur 0x"$sigma" "$temp_blurred" || (
|
||||||
@@ -69,19 +66,28 @@ elif [ "$XDG_CURRENT_DESKTOP" = "niri" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
)
|
)
|
||||||
|
|
||||||
# nohup swaybg -i "$blurred_image" -m fill > /dev/null 2> /dev/null &
|
if [ "$XDG_CURRENT_DESKTOP" = "niri" ]; then
|
||||||
swww img -n backdrop "$blurred_image" --transition-type fade --transition-duration 2 > /dev/null 2> /dev/null
|
swww img -n backdrop "$blurred_image" --transition-type fade --transition-duration 2 > /dev/null 2> /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
notify-send "Blurred Wallpaper Generated" "$blurred_image"
|
notify-send "Blurred Wallpaper Generated" "$blurred_image"
|
||||||
) &
|
) &
|
||||||
|
|
||||||
|
# Apply wallpaper
|
||||||
|
|
||||||
|
if [ "$XDG_CURRENT_DESKTOP" = "Hyprland" ]; then
|
||||||
swww img -n background "$image_copied" --transition-type fade --transition-duration 2 > /dev/null 2> /dev/null
|
swww img -n background "$image_copied" --transition-type fade --transition-duration 2 > /dev/null 2> /dev/null
|
||||||
|
|
||||||
notify-send "Wallpaper Changed" "$image"
|
notify-send "Wallpaper Changed" "$image"
|
||||||
|
|
||||||
|
change-colortheme -i "$image_copied" || exit 1
|
||||||
|
elif [ "$XDG_CURRENT_DESKTOP" = "niri" ]; then
|
||||||
|
swww img -n background "$image_copied" --transition-type fade --transition-duration 2 > /dev/null 2> /dev/null
|
||||||
|
|
||||||
|
notify-send "Wallpaper Changed" "$image"
|
||||||
|
|
||||||
|
change-colortheme -i "$image_copied" || exit 1
|
||||||
else
|
else
|
||||||
echo "Unsupported desktop environment: $XDG_CURRENT_DESKTOP"
|
echo "Unsupported desktop environment: $XDG_CURRENT_DESKTOP"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# notify-send "Extracting Colors from Wallpaper" "This may take a few seconds..."
|
|
||||||
change-colortheme -i "$image_copied" || exit 1
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
swayidle -w timeout 300 'hyprlock &' timeout 600 'niri msg action power-off-monitors' before-sleep 'hyprlock &'
|
|
||||||
@@ -8,21 +8,24 @@ from sys import exit
|
|||||||
from time import sleep
|
from time import sleep
|
||||||
from os import environ
|
from os import environ
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
|
||||||
NORMAL_WALLPAPER_DIR = Path("/home/kolkas/.local/share/wallpaper/current")
|
NORMAL_WALLPAPER_DIR = Path("~/.local/share/wallpaper/current").expanduser()
|
||||||
BLURRED_WALLPAPER_DIR = Path("/home/kolkas/.local/share/wallpaper/blurred")
|
BLURRED_WALLPAPER_DIR = Path("~/.local/share/wallpaper/blurred").expanduser()
|
||||||
|
|
||||||
|
|
||||||
def _get_first_file(dir: Path, pattern: str = "*") -> Path | None:
|
def getFirstFile(dir: Path, pattern: str = "*") -> Path | None:
|
||||||
|
'''`find $dir -type f | head -n 1`'''
|
||||||
return next(dir.glob(pattern), None)
|
return next(dir.glob(pattern), None)
|
||||||
|
|
||||||
|
|
||||||
def get_niri_socket():
|
def getNiriSocket():
|
||||||
return environ['NIRI_SOCKET']
|
return environ['NIRI_SOCKET']
|
||||||
|
|
||||||
|
|
||||||
def _log(msg: str):
|
def _log(msg: str):
|
||||||
# print(msg)
|
print(msg)
|
||||||
|
|
||||||
# logFIle = Path("/tmp/niri-autoblur.log")
|
# logFIle = Path("/tmp/niri-autoblur.log")
|
||||||
# try:
|
# try:
|
||||||
@@ -46,7 +49,7 @@ def swwwLoadImg(namespace: str, wallpaper: Path):
|
|||||||
"--transition-duration",
|
"--transition-duration",
|
||||||
"0.5",
|
"0.5",
|
||||||
]
|
]
|
||||||
_log(" ".join(cmd))
|
_log(f"[SWWW] {" ".join(cmd)}")
|
||||||
ret = 0
|
ret = 0
|
||||||
try:
|
try:
|
||||||
ret = subprocess.run(cmd, check=True).returncode
|
ret = subprocess.run(cmd, check=True).returncode
|
||||||
@@ -104,6 +107,49 @@ class AutoBlur:
|
|||||||
# init state
|
# init state
|
||||||
# self.setBlurred(AutoBlur.initIsBlurred())
|
# self.setBlurred(AutoBlur.initIsBlurred())
|
||||||
|
|
||||||
|
# Start watching dirs
|
||||||
|
self.addWatchDir()
|
||||||
|
|
||||||
|
class WatchdogHandler(FileSystemEventHandler):
|
||||||
|
_callback = None
|
||||||
|
|
||||||
|
def __init__(self, callback):
|
||||||
|
if callback is None:
|
||||||
|
raise ValueError("callback cannot be None")
|
||||||
|
super().__init__()
|
||||||
|
self._callback = callback
|
||||||
|
|
||||||
|
def on_created(self, event):
|
||||||
|
if not event.is_directory:
|
||||||
|
src_path = str(event.src_path)
|
||||||
|
path = Path(src_path)
|
||||||
|
_log(f"[Watchdog] file created: {path}")
|
||||||
|
self._callback(path) # type: ignore
|
||||||
|
|
||||||
|
def on_moved(self, event):
|
||||||
|
if not event.is_directory:
|
||||||
|
dest_path = str(event.dest_path)
|
||||||
|
path = Path(dest_path)
|
||||||
|
_log(f"[Watchdog] file moved to: {path}")
|
||||||
|
self._callback(path) # type: ignore
|
||||||
|
|
||||||
|
def addWatchDir(self):
|
||||||
|
normalHandler = self.WatchdogHandler(self._onNormalDirEvent)
|
||||||
|
blurredHandler = self.WatchdogHandler(self._onBlurredDirEvent)
|
||||||
|
observer = Observer()
|
||||||
|
observer.schedule(normalHandler, str(self._normalDir), recursive=False)
|
||||||
|
observer.schedule(blurredHandler, str(self._blurredDir), recursive=False)
|
||||||
|
observer.start()
|
||||||
|
_log(f"[Watchdog] watching dirs: {self._normalDir}, {self._blurredDir}")
|
||||||
|
|
||||||
|
def _onNormalDirEvent(self, path: Path):
|
||||||
|
if not self._isBlurred.is_set():
|
||||||
|
self._apply(path)
|
||||||
|
|
||||||
|
def _onBlurredDirEvent(self, path: Path):
|
||||||
|
if self._isBlurred.is_set():
|
||||||
|
self._apply(path)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def initIsBlurred() -> bool:
|
def initIsBlurred() -> bool:
|
||||||
'''[ $(niri msg focused-window | wc -l) -gt 1 ]'''
|
'''[ $(niri msg focused-window | wc -l) -gt 1 ]'''
|
||||||
@@ -118,9 +164,9 @@ class AutoBlur:
|
|||||||
|
|
||||||
def setBlurred(self, isBlurred: bool) -> None:
|
def setBlurred(self, isBlurred: bool) -> None:
|
||||||
# Cache state, avoid starting thread unnecessarily
|
# Cache state, avoid starting thread unnecessarily
|
||||||
# if not self._isFirst and self._isBlurred.is_set() == isBlurred:
|
if not self._isFirst and self._isBlurred.is_set() == isBlurred:
|
||||||
# _log("[AutoBlur] state unchanged")
|
_log("[AutoBlur] state unchanged")
|
||||||
# return
|
return
|
||||||
self._isFirst = False
|
self._isFirst = False
|
||||||
|
|
||||||
if isBlurred:
|
if isBlurred:
|
||||||
@@ -138,9 +184,9 @@ class AutoBlur:
|
|||||||
'''Wait until wallpapers are ready & apply the correct one according to the current state'''
|
'''Wait until wallpapers are ready & apply the correct one according to the current state'''
|
||||||
while True:
|
while True:
|
||||||
if self._isBlurred.is_set():
|
if self._isBlurred.is_set():
|
||||||
wallpaper = _get_first_file(self._blurredDir)
|
wallpaper = getFirstFile(self._blurredDir)
|
||||||
else:
|
else:
|
||||||
wallpaper = _get_first_file(self._normalDir)
|
wallpaper = getFirstFile(self._normalDir)
|
||||||
|
|
||||||
if wallpaper is not None and wallpaper.exists():
|
if wallpaper is not None and wallpaper.exists():
|
||||||
if self._apply(wallpaper):
|
if self._apply(wallpaper):
|
||||||
@@ -195,11 +241,11 @@ def handleEvent(event_name, payload):
|
|||||||
_log(f"[EventHandler] unhandled event: {event_name}")
|
_log(f"[EventHandler] unhandled event: {event_name}")
|
||||||
|
|
||||||
|
|
||||||
def print_event(eventName, payload):
|
def printEvent(eventName, payload):
|
||||||
_log(f"[EventHandler] event: {eventName}, payload:\n{json.dumps(payload, indent=2, ensure_ascii=False)}")
|
_log(f"[EventHandler] event: {eventName}, payload:\n{json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
|
||||||
|
|
||||||
def connect_niri(niriSocket: str, handler) -> bool:
|
def connectNiri(niriSocket: str, handler) -> bool:
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
try:
|
try:
|
||||||
sock.connect(niriSocket)
|
sock.connect(niriSocket)
|
||||||
@@ -260,6 +306,9 @@ def connect_niri(niriSocket: str, handler) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# connectNiri(getNiriSocket(), printEvent)
|
||||||
|
# exit(0)
|
||||||
|
|
||||||
desktop = environ.get("XDG_CURRENT_DESKTOP", "")
|
desktop = environ.get("XDG_CURRENT_DESKTOP", "")
|
||||||
if desktop == "niri":
|
if desktop == "niri":
|
||||||
_log("[Main] running in Niri")
|
_log("[Main] running in Niri")
|
||||||
@@ -272,22 +321,22 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
_log("[Main] loading initial wallpapers")
|
_log("[Main] loading initial wallpapers")
|
||||||
# Init wallpaper for backdrop
|
# Init wallpaper for backdrop
|
||||||
blurred = _get_first_file(BLURRED_WALLPAPER_DIR)
|
blurred = getFirstFile(BLURRED_WALLPAPER_DIR)
|
||||||
if blurred:
|
if blurred:
|
||||||
swwwLoadImg("backdrop", blurred)
|
swwwLoadImg("backdrop", blurred)
|
||||||
# Init wallpaper for background
|
# Init wallpaper for background
|
||||||
normal = _get_first_file(NORMAL_WALLPAPER_DIR)
|
normal = getFirstFile(NORMAL_WALLPAPER_DIR)
|
||||||
if normal:
|
if normal:
|
||||||
swwwLoadImg("background", normal)
|
swwwLoadImg("background", normal)
|
||||||
|
|
||||||
# Connect to Niri socket
|
# Connect to Niri socket
|
||||||
_log(f"[Main] connecting to Niri socket")
|
_log(f"[Main] connecting to Niri socket")
|
||||||
niri_socket = get_niri_socket()
|
niri_socket = getNiriSocket()
|
||||||
if not niri_socket:
|
if not niri_socket:
|
||||||
_log("[Main] NIRI_SOCKET environment variable is not set.")
|
_log("[Main] NIRI_SOCKET environment variable is not set.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if not connect_niri(niri_socket, handleEvent):
|
if not connectNiri(niri_socket, handleEvent):
|
||||||
exit(1)
|
exit(1)
|
||||||
elif desktop == "Hyprland":
|
elif desktop == "Hyprland":
|
||||||
_log("[Main] running in Hyprland")
|
_log("[Main] running in Hyprland")
|
||||||
@@ -297,10 +346,13 @@ if __name__ == "__main__":
|
|||||||
sleep(1) # similarly
|
sleep(1) # similarly
|
||||||
|
|
||||||
_log("[Main] loading initial wallpaper")
|
_log("[Main] loading initial wallpaper")
|
||||||
normal = _get_first_file(NORMAL_WALLPAPER_DIR)
|
normal = getFirstFile(NORMAL_WALLPAPER_DIR)
|
||||||
if normal:
|
if normal:
|
||||||
swwwLoadImg("background", normal)
|
swwwLoadImg("background", normal)
|
||||||
|
|
||||||
# Wait indefinitely
|
# Wait indefinitely
|
||||||
while True:
|
while True:
|
||||||
sleep(3600)
|
sleep(3600)
|
||||||
|
else:
|
||||||
|
_log(f"[Main] unsupported desktop environment: {desktop}")
|
||||||
|
exit(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user