hyprwm / hyprpaper

Hyprpaper is a blazing fast wayland wallpaper utility with IPC controls.
https://wiki.hyprland.org/Hypr-Ecosystem/hyprpaper/
BSD 3-Clause "New" or "Revised" License
724 stars 53 forks source link

[Feature Request] Auto-Preload #164

Open Rabcor opened 3 months ago

Rabcor commented 3 months ago

For ease of use, hyprpaper should automatically preload any wallpaper you try to use if it is not already preloaded.

Additionally, whenever this automatic preload gets triggered, it should unload all previously auto-preloaded files that are not currently active (to prevent memory usage getting out of hand).

This would make preloading optional, thus making hyprpaper a lot more user-friendly.

vaxerski commented 3 months ago

>give users control

>users complain about too much control

dedguy21 commented 3 months ago

I don't know about auto-preload, but it we could somehow point and start the "default" wallpaper we set in hyprpaper.conf, that would go a long way in making the desktop startup time at least 'feel' faster.

vaxerski commented 3 months ago

? The image still needs to be preloaded. How would that speed anything up?

dedguy21 commented 3 months ago

In the same way 'Azote' or even 'swww' do it. I'm not sure what the exact mechanics are for it. But they somehow cache (maybe even .cache) the image they know they will start with and it doesn't have to go through the same initializations.

Who knows maybe they're leveraging swaybg or something 🤷

Rabcor commented 3 months ago

give users control

users complain about too much control

Well it's the neverending issue for application designers ain't it?

You give users a lot of control, they complain that it's complicated, you simplify it, and users complain about not having enough control. :laughing:

So the best solution is usually to make it 'complicated' with a lot of control, but 'smart', e.g. smart enough to deduce what you actually want when you're not 100% explicit about it.

Aka: Auto-preload.

I'm a little curious though, is there any actual use for manual preloading? I mean sure, if you preload all your walls before loading them, then you can switch between them really fast... But when are you ever going to need those milliseconds (if not microseconds)? enough to waste your RAM on it?

The only possible scenario I can think of where this would actually be useful is if you want to make a complicated script that does frame-by-frame animation using hyprpaper :rofl:

Which is probably why you get people complaining about it, it's an incredibly niche feature (although now that I say that, I wonder which would perform better, a normal animated GIF renderer, or hyprpaper doing what I just described, now I'm quite curious...)

Edit: I tried it. Hyprpaper uses 2x the cpu qimgv dies, which in turn uses 2x the cpu mpv does.

So mpvpaper does this super well.

Actually if you're ever gonna implement this, might as well just rely on mpv or libmpv to do it.

gitduk commented 3 months ago

my script hyprpaper.sh :

#!/usr//bin/env zsh

WALLPAPER_DIR="$HOME/Pictures/wallpaper"
HYPRPAPER_CONF="$HOME/.config/hypr/hyprpaper.conf"
MONITOR="$(hyprctl monitors|grep 'ID 0'|awk '{print $2}')"

init_config() {
  local monitor=$MONITOR

  # preload wallpaper
  ls $WALLPAPER_DIR | while read -r file; do
    echo "preload = $WALLPAPER_DIR/$file"
  done | tee $HYPRPAPER_CONF

  # set wallpaper
  echo "wallpaper = $monitor,$(shuf -n 1 -e $WALLPAPER_DIR/*)" | tee -a $HYPRPAPER_CONF

  # ipc options
  echo "ipc = on" | tee -a $HYPRPAPER_CONF
}

random_wallpaper() {
  local monitor=$MONITOR
  local wallpaper="$(shuf -n 1 -e $WALLPAPER_DIR/*)"
  notify-send "${wallpaper##*/}"
  hyprctl hyprpaper wallpaper "$monitor,$wallpaper"
}

switch_wallpaper() {
  local monitor=$MONITOR
  local action=$1
  local wallpaper
  local prev_wallpaper
  local next_wallpaper

  current_wallpaper="$(hyprctl hyprpaper listactive | sed 's|.*/||')"
  echo "Currnet: $current_wallpaper"

  ls -1v $WALLPAPER_DIR | while read -r file; do
    [[ -n "$next_wallpaper" ]] && next_wallpaper="$file" && break
    if [[ "$file" == "$current_wallpaper" ]]; then
      next_wallpaper="$file"
    else
      prev_wallpaper="$file"
    fi
  done

  echo "Next: $next_wallpaper"
  echo "Prev: $prev_wallpaper"

  if [[ $action == "next" ]]; then
    [[ -n "$next_wallpaper" ]] && wallpaper=$next_wallpaper
  elif [[ $action == "prev" ]]; then
    [[ -n "$prev_wallpaper" ]] && wallpaper=$prev_wallpaper
  else
    echo "Invalid action" && exit 1
  fi

  if [[ -n "$wallpaper" ]]; then
    notify-send "$wallpaper"
    hyprctl hyprpaper wallpaper "$monitor,$WALLPAPER_DIR/$wallpaper"
  else
    notify-send "No wallpaper found"
  fi
}

# ###  Main  ##################################################################

SHORT="i,r,s:"
LONG="init,random,switch:"
ARGS=`getopt -a -o $SHORT -l $LONG -n "${0##*/}" -- "$@"`

if [[ $? -ne 0 || $# -eq 0 ]]; then
  cat <<- EOF

$0 -[`echo $SHORT|sed 's/,/|/g'`] --[`echo $LONG|sed 's/,/|/g'`]
EOF
fi

eval set -- "${ARGS}"

while true
do
  case "$1" in
  -i|--init) init_config ;;
  -r|--random) random_wallpaper ;;
  -s|--switch) switch_wallpaper $2; shift ;;
  --) shift ; break ;;
  esac
shift
done

hyprland.conf:

...

# auto load wallpaper
exec-once = ~/.config/hypr/scripts/hyprpaper.sh --init && hyprpaper &

# wallpaper submap
submap = wallpaper
bind = ,r, exec, ~/.config/hypr/scripts/hyprpaper.sh --random
bind = ,n, exec, ~/.config/hypr/scripts/hyprpaper.sh --switch next
bind = ,p, exec, ~/.config/hypr/scripts/hyprpaper.sh --switch prev
bind = ,q, submap, reset 
submap = reset

...
Rabcor commented 3 months ago

my script hyprpaper.sh :

That seems massively overcomplicated if our goal is just to auto-preloud, it could be very easily achieved like this:

#!/bin/bash
pgrep hyprpaper || hyprctl dispatch exec hyprpaper && sleep 1
hyprctl hyprpaper preload "$@"
hyprctl hyprpaper wallpaper ",$@"
hyprctl hyprpaper unload unused

The only problem being that the unload command would unload everything that's unused instead of only the things that were autoloaded, but for me i wouldn't really care about that so this is what I'd do.

And if we want something more complicated, like say automatically loading random walls at set intervals, it can also be achieved in a much more simple manner like this

#!/bin/bash

INTERVAL=1800
subdirectories=true

if [[ $# -lt 1 ]] || [[ ! -d "$@"   ]]; then
    echo "Usage:
    $0 <dir containing images>"
    exit 1
fi

$subdirectories || DEPTH="-maxdepth 1"

while true; do
    pgrep hyprpaper || hyprctl dispatch exec hyprpaper && sleep 1
    find "$@" $DEPTH \
        | while read -r img; do
            echo "$((RANDOM % 1000)):$img"
        done \
        | sort -n | cut -d':' -f2- \
        | while read -r img; do
            hyprctl hyprpaper preload "$img"
            hyprctl hyprpaper wallpaper ",$img"
            hyprctl hyprpaper unload unused
            pgrep hyprpaper && sleep $INTERVAL
        done
done

Granted your scripts ability to switch manually to the next and previous image is cool, i can technically do that anyways with mine by just doing pkill sleep, even if that is a bit yikes to do.