hyprpaper
hyprpaper copied to clipboard
Segfault if ipc requests sent too rapidly
If I send ipc requests too rapidly, hyprpaper segfaults in a variety of places (curiously, often in vnsprint
), or gets a bus error.
I have a script to load a random wallpaper:
#!/usr/bin/python
from pathlib import Path
from random import choices
from subprocess import run
cmdbase = ["hyprctl", "hyprpaper"]
def load_backgrounds(mapping: dict[str, Path]):
mapping: dict[str, str] = {k: str(v) for k, v in mapping.items()}
for bg in mapping.values():
run(cmdbase + ["preload", bg])
for monitor, bg in mapping.items():
run(cmdbase + ["wallpaper", f"{monitor},{bg}"])
run(cmdbase + ["unload", "all"])
if __name__ == "__main__":
imgs = Path("~/google-drive/Desktop Backgrounds").expanduser().resolve()
monitors = {"DP-1", "DP-2"}
extns = {".jpg", ".jpeg", ".png"}
available = [x for x in imgs.glob("*") if x.suffix.lower() in extns]
backgrounds = dict(zip(monitors, choices(available, k=len(monitors))))
load_backgrounds(backgrounds)
If I run this in a loop at the terminal it will segfault after ~3 iterations. If I add a sleep, i.e.
while true; do
random_wallpaper.py
sleep 0.5
I can control the behaviour somewhat. With 0.5 it dies only occasionally, and usually with sigbus. With 0.1 it segfaults pretty quickly. Obviously looping over wallpapers isn't very useful, but I can't guarantee that a user won't hit the 'reload' button in quick succession.
For the time being I can work around it with a file lock. Should the socket code block until the load operation is finished?
version
Latest master with my case-insensitive patch, i.e. 0a85097519be78d4529a9a526fb8f6a52474ef5a
Is there a temporary workaround to this problem? I switch wallpapers pretty frequently since I have a different one for each workspace, and hyprpaper
would crash a couple times a day.
try with 3596630a207a02a0035a0a178a1fdbf2a5f40a30
Now we die normally:
zwlr_layer_surface_v1@24: error 0: wrong configure serial: 425141
[Thread 0x7ffff6a706c0 (LWP 2092053) exited]
[Inferior 1 (process 2092049) exited normally]
The particular serial changes so it could be memory corruption. If you tell me what to set a breakpoint on I'll see if I can get a proper backtrace.
This was a segfault before and I couldn't reproduce this time, so I think the segfault is cured, even if the problem has just moved.
Is there a temporary workaround to this problem? I switch wallpapers pretty frequently since I have a different one for each workspace, and
hyprpaper
would crash a couple times a day.
You can set it up to restart e.g. with systemd. I think there's an example in the linked issue. OTOH I don't have any noticeable crashes with the script above ticking every 5 minutes after adding a delay and a lock:
from time import sleep
from filelock import FileLock
lock = FileLock("/tmp/hyprpaper.lock")
def load_backgrounds(mapping: dict[str, Path]):
with lock:
# as above
sleep(0.5)
No need to use python if you don't want to, this is trivial in e.g. bash. Using a file lock might be the trick if you're flipping between workspaces fast enough to get there before hyprpaper has settled down from the last switch.
Now we die normally:
zwlr_layer_surface_v1@24: error 0: wrong configure serial: 425141 [Thread 0x7ffff6a706c0 (LWP 2092053) exited] [Inferior 1 (process 2092049) exited normally]
The particular serial changes so it could be memory corruption. If you tell me what to set a breakpoint on I'll see if I can get a proper backtrace.
This was a segfault before and I couldn't reproduce this time, so I think the segfault is cured, even if the problem has just moved.
I think there's a race condition here:
[Event] Configuring with serial 659167
[Event] Configuring with serial 659167 done
[LOG] configure for DP-1
Configuring with serial 659167
Configuring with serial 659167 finished
[LOG] Image data for DP-1: /home/aniva/.config/hypr/wallpapers/7.jpg at [-0.00, 0.00], scale: 1.00 (original image size: [3840, 2160])
[LOG] Submitting viewport dest size 3840x2160 for 60000d20
[Event] Configuring with serial 659171
[Event] Configuring with serial 659171 done
[LOG] configure for DP-1
[LOG] handlePreferredScale: 1.00 for 7f3e60000d20
[LOG] handlePreferredScale: 1.00 for 7f3e60000d20
Configuring with serial 659171
Configuring with serial 659171 finished
[LOG] Image data for DP-1: /home/aniva/.config/hypr/wallpapers/7.jpg at [-0.00, 0.00], scale: 1.00 (original image size: [3840, 2160])
[LOG] Submitting viewport dest size 3840x2160 for 60000d20
zwlr_layer_surface_v1@41: error 0: wrong configure serial: 659167
The [Event]
messages are sent from the event handler and the Configure with serial ...
messages are sent from CHyprpaper::recheckMonitor
. It seems like the ack_configure
event for 167
has not reached the client when the event for 171
is received by hyprpaper
.
I'm not sure how can we solve this. Even setting the configuration serial as atomic doesn't mitigate this problem.
Arrived here via search for the issue after i experienced it by accidentally hitting the [1] key when switching to workspace 2 by pressing [Super]+[2].
So by following the Hyprland wiki to set up different wallpapers for each workspace and then cycle them too fast: crash.
The claim "Hyprpaper is a blazing fast wallpaper utility" seems a bit weird given that this issue happens when you "switch too fast" ... 😅
Right now i use a script to subscribe to the Hyprland socket and only switch the wallpapers after a timeout during which no workspace change happens. It works but doesn't feel "blazing fast" tbf.
//edit: After reducing the DelaySec to 0.1 it feels relatively fast (enough)... so taking the chance to be laughed at, here's my script...
#!/bin/bash
# Script vars (no touch)
ScriptDir=$(dirname "$0")
TimerPid=0
# Config vars (do touch)
DelaySec=0.1
JsonFile="$ScriptDir/wallpapers.json"
CurFile="/tmp/wallpaperd"
# Save current terminal settings
SttyBackup=$(stty -g)
# Disable echoing of control characters (^C)
stty -echoctl
hyprctl hyprpaper unload all
# Load Wallpapers associative array from the JSON file
declare -A Wallpapers
FirstPaper=""
while IFS="=" read -r key value; do
if [[ $FirstPaper == "" ]]; then
FirstPaper=$value
fi
Wallpapers["$key"]="$value"
echo "preloading $value"
hyprctl hyprpaper preload "$value"
done < <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" $JsonFile)
WorkspaceName=$(hyprctl -j activeworkspace | jq -r '.name')
echo "Current workspace '$WorkspaceName'"
WallpaperValue="${Wallpapers[$WorkspaceName]}"
if [[ -z $WallpaperValue ]]; then
WallpaperValue="$FirstPaper"
fi
hyprctl hyprpaper wallpaper "DP-2,$WallpaperValue"
echo "$WallpaperValue" > "$CurFile"
# Handle termination / ctrl+c
CleanUp () {
echo "Cleaning up..."
if [ -f "$CurFile" ]; then
rm $CurFile
fi
stty "$SttyBackup"
exit 0
}
# Use trap to call CleanUp when a SIGINT is received
trap CleanUp SIGINT SIGTERM
# Function to change wallpaper
WallpaperSet () {
local CurrentPaper=""
local WorkspaceName="$1"
local WallpaperValue="${Wallpapers[$WorkspaceName]}"
if [ -f "$CurFile" ]; then
CurrentPaper=$(< "$CurFile")
echo "CurrentPaper is $CurrentPaper"
fi
if [[ -n "$WallpaperValue" && $WallpaperValue != $CurrentPaper ]]; then
echo "Set wallpaper '$WallpaperValue'"
echo "$WallpaperValue" > "$CurFile"
# Use hyprctl to change the wallpaper
hyprctl hyprpaper wallpaper "DP-2,$WallpaperValue"
else
echo "Same wallpaper, skipping..."
fi
}
WallpaperCue () {
local WorkspaceName="$1"
[[ 0 < $TimerPid ]] && kill -0 $TimerPid > /dev/null 2>&1 && kill "$TimerPid"
(sleep $DelaySec; WallpaperSet "$WorkspaceName") &
TimerPid=$!
}
# Subscribe to Hyprland socket and process the stream
socat -u UNIX-CONNECT:/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | while read -r line; do
#echo $line
if [[ "$line" == "activespecial>>special:"* ]]; then
SpecialWorkspace="${line#activespecial>>}" # Removes everything up to and including ">>"
SpecialWorkspace="${SpecialWorkspace%%,*}" # Removes everything after and including ","
echo "Special workspace name '$SpecialWorkspace'"
WallpaperCue "$SpecialWorkspace"
fi
if [[ "$line" == "activespecial>>,"* ]]; then
echo "Reset special workspace to '$WorkspaceName'"
WallpaperCue "$WorkspaceName"
fi
if [[ "$line" == "workspace>>"* ]]; then
WorkspaceName="${line#workspace>>}"
echo "Workspace name '$WorkspaceName'"
# Check if the workspace name exists in the Wallpapers array
if [[ -n "${Wallpapers[$WorkspaceName]}" ]]; then
WallpaperCue "$WorkspaceName"
fi
fi
done
For configuration it expects a wallpapers.json in the same directory (see config vars) in this format:
{
"1": "~/Pictures/Wallpaper/something.png",
"2": "~/Pictures/Wallpaper/somethingelse.webp",
"special:magic": "~/Pictures/Wallpaper/whatever.jpg"
}
Replace the array keys with your workspace names.. special workplaces work too..
//edit2:
I also tried to use hyprctl hyprpaper listactive
for initialisation but it only says "invalid command". Not sure if i'm stupid or if it's bugged or if my version (hyprpaper 0.6.0-3) just doesn't feature it yet.
The problem is still here on 0.7.0:
[LOG] configure for DP-1
[LOG] handlePreferredScale: 1.00 for 7c4c00003660
[LOG] handlePreferredScale: 1.00 for 7c4c00003660
[LOG] Image data for DP-1: /home/aniva/.config/hypr/wallpapers/5.jpg at [-0.00, 0.00], scale: 1.00 (original image size: [3840, 2160])
[LOG] Submitting viewport dest size 3840x2160 for 3660
zwlr_layer_surface_v1@814: error 0: wrong configure serial: 467542
fish: Job 1, 'hyprpaper &' has ended
This happens if I switch wallpapers twice within a fraction of a second