├── README.md └── feh-blur /README.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | 4 | 5 | 6 |
7 | 8 |

9 | 10 |

11 | feh-blur-wallpaper 12 |

13 | 14 |

15 | Blur your desktop wallpaper when windows are open (Linux) 16 |

17 | 18 |

19 | 20 |

21 | 22 |
23 | 24 | Blurs your desktop wallpaper when windows are open. 25 | Runs as a service, blurring any wallpaper set by [feh]. 26 | Works great with [i3wm], but should work with any Linux window manager! 🎉 27 | 28 | ## Usage 29 | 30 | Run `feh-blur`. (Tip: optionally, you can pass `-d` to it to run it in the background.) 31 | 32 | ```sh 33 | # Step 1: run the feh-blur service 34 | $ feh-blur 35 | 36 | >> Monitoring changes 37 | feh-blur will now blur any wallpapers set using 'feh'. 38 | 39 | >> Found wallpaper 40 | /home/rsc/wallpapers/unsplash.jpg 41 | Generating blurred images... done. 42 | ``` 43 | 44 | Set a wallpaper using [feh]. You can do this before starting feh-blur, or while feh-blur is running. 45 | 46 | ``` 47 | feh --bg-fill "/path/to/yourwallpaper.jpg" 48 | ``` 49 | 50 | See `feh-blur --help` for full usage options. 51 | 52 | ``` 53 | Usage: feh-blur [-v|--verbose] 54 | 55 | Options: 56 | -b, --blur N set blur strength to N (4...128, default 32) 57 | --darken N darken image by N (4...100, default 32) 58 | --lighten N lengthen image by N (4...100, default 0) 59 | -c, --uncontrast reduce contrast 60 | --save-image PATH save blurred image to PATH 61 | --no-animate skip fading animation 62 | 63 | Daemon options: 64 | -d, --daemon run in background 65 | -s, --stop stop previously-ran daemon 66 | 67 | Other options: 68 | -v, --verbose show more messages 69 | -q, --quiet supress messages 70 | ``` 71 | 72 | ## Installation 73 | 74 | Install [feh-blur](./feh-blur) somewhere. You may also need some dependencies, install them using your Linux distro's appropriate package manager. 75 | 76 | ```sh 77 | # Arch Linux 78 | sudo pacman -S wmctrl graphicsmagick feh 79 | 80 | # Ubuntu and alike 81 | sudo apt install wmctrl graphicsmagick feh 82 | ``` 83 | 84 | ## Prior art 85 | 86 | Based on [ganifladi/blurme](https://github.com/ganifladi/blurme). feh-blur-wallpaper has been written from the ground up, using some parts of blurme as reference. 87 | 88 | ## Thanks 89 | 90 | **feh-wallpaper-blur** © 2019, Rico Sta. Cruz. Released under the [MIT] License.
91 | Authored and maintained by Rico Sta. Cruz with help from contributors ([list][contributors]). 92 | 93 | > [ricostacruz.com](http://ricostacruz.com)  ·  94 | > GitHub [@rstacruz](https://github.com/rstacruz)  ·  95 | > Twitter [@rstacruz](https://twitter.com/rstacruz) 96 | 97 | [![](https://img.shields.io/github/followers/rstacruz.svg?style=social&label=@rstacruz)](https://github.com/rstacruz)   98 | [![](https://img.shields.io/twitter/follow/rstacruz.svg?style=social&label=@rstacruz)](https://twitter.com/rstacruz) 99 | 100 | [mit]: http://mit-license.org/ 101 | [contributors]: http://github.com/rstacruz/feh-wallpaper-blur/contributors 102 | [feh]: https://wiki.archlinux.org/index.php/feh 103 | [i3wm]: https://i3wm.org/ 104 | -------------------------------------------------------------------------------- /feh-blur: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # https://github.com/rstacruz/feh-blur 3 | 4 | if [[ "$1" != "--worker" ]]; then 5 | # Where to write stuff 6 | export CACHE_DIR="/tmp/feh-blur.$$" 7 | 8 | # How much to blur (--blur N) 9 | export BLUR_STRENGTH="32" 10 | 11 | # Contrast (--uncontrast) 12 | export REDUCE_CONTRAST="0" 13 | 14 | # How much to dim (--dim N) 15 | export DIM_STRENGTH="32" 16 | 17 | # Dimmer 18 | export DIM_COLOR="#000" 19 | 20 | # Where to write the final blurred image (--save-image PATH) 21 | export BLUR_IMAGE_SAVE_LOCATION="" 22 | 23 | # Interval between frames in an animation 24 | export ANIMATION_INTERVAL=0.005 25 | 26 | # Fade in and out? 27 | export ANIMATE_FADE=1 28 | 29 | # Interval to check with wmctrl 30 | export POLL_INTERVAL=0.3 31 | 32 | # The verbosity. --verbose sets this to 2, and --quiet sets it to 0. 33 | export VERBOSE=1 34 | fi 35 | 36 | # The name of this program 37 | export BIN="$(basename "$0")" 38 | 39 | # Expression for proc grepping 40 | PROC_EXPR="bash.*$(basename "$0")" 41 | 42 | # Run mode. -d sets this to background (daemon) mode. 43 | # Values: background | foreground | noop 44 | MODE=foreground 45 | 46 | # Guard so that do_cleanup will only be invoked once. 47 | CLEANING_UP=0 48 | 49 | # Image extension to use. 'ppm' is used because it's faster to read/write to, I 50 | # think. 51 | EXT="ppm" 52 | 53 | # The original source. 54 | wall_original="$CACHE_DIR/original.$EXT" 55 | 56 | # Echo some info. Only if verbose=1 57 | info () { 58 | if [[ "$VERBOSE" -gt 0 ]]; then 59 | echo " $1" 60 | fi 61 | } 62 | 63 | head () { 64 | if [[ "$VERBOSE" -gt 0 ]]; then 65 | echo "" 66 | echo -e " \033[31m>>\033[32m $1\033[0m" 67 | fi 68 | } 69 | 70 | # Log some debug info 71 | debug () { 72 | if [[ "$VERBOSE" -gt 1 ]]; then 73 | echo " - $1" 74 | fi 75 | } 76 | 77 | # Generate a bunch of images 78 | generate_blurred_images () { 79 | mkdir -p "$CACHE_DIR" 80 | local source="$1" 81 | local original="$CACHE_DIR/original.$EXT" 82 | 83 | gm convert "$source" -resize 1920x "$original" 84 | 85 | head "Found wallpaper" 86 | info "$source" 87 | info "Generating blurred images..." 88 | 89 | local fx1="" 90 | local fx2="" 91 | local fx3="" 92 | 93 | if [[ "$BLUR_STRENGTH" != "0" ]]; then 94 | fx1="$fx1 -scale 25% -blur 0x$(( "$BLUR_STRENGTH" / 4 )) -scale 400%" 95 | fx2="$fx2 -scale 25% -blur 0x$(( "$BLUR_STRENGTH" / 2 )) -scale 400%" 96 | fx3="$fx3 -scale 25% -blur 0x$(( "$BLUR_STRENGTH" / 1 )) -scale 400%" 97 | fi 98 | 99 | if [[ "$REDUCE_CONTRAST" = "1" ]]; then 100 | fx1="+contrast $fx1" 101 | fx2="+contrast +contrast $fx2" 102 | fx3="+contrast +contrast +contrast $fx3" 103 | fi 104 | 105 | if [[ "$DIM_STRENGTH" != "0" ]]; then 106 | fx1="$fx1 -fill $DIM_COLOR -colorize $(( "$DIM_STRENGTH" / 4 ))%" 107 | fx2="$fx2 -fill $DIM_COLOR -colorize $(( "$DIM_STRENGTH" / 2 ))%" 108 | fx3="$fx3 -fill $DIM_COLOR -colorize $(( "$DIM_STRENGTH" / 1 ))%" 109 | fi 110 | 111 | gm convert "$original" \ 112 | $fx1 \ 113 | "$CACHE_DIR/blur-0.$EXT" 114 | gm convert "$CACHE_DIR/blur-0.$EXT" \ 115 | $fx2 \ 116 | "$CACHE_DIR/blur-1.$EXT" 117 | gm convert "$CACHE_DIR/blur-0.$EXT" \ 118 | $fx3 \ 119 | "$CACHE_DIR/blur-final.$EXT" 120 | 121 | if [[ -n "$BLUR_IMAGE_SAVE_LOCATION" ]]; then 122 | gm convert \ 123 | "$CACHE_DIR/blur-final.$EXT" \ 124 | "$BLUR_IMAGE_SAVE_LOCATION" 125 | fi 126 | 127 | info "Done." 128 | } 129 | 130 | # Get current feh wallpaper 131 | get_feh_wallpaper() { 132 | tail -n1 "$HOME/.fehbg" | sed 's/--no-fehbg //g' | cut -d"'" -f2 133 | } 134 | 135 | # Get wallpaper mode like --bg-tile 136 | get_feh_wallpaper_mode() { 137 | tail -n1 "$HOME/.fehbg" | sed 's/--no-fehbg //g' | cut -d' ' -f2 138 | } 139 | 140 | # get_current_workspace => "2" 141 | get_current_workspace() { 142 | # 2 * DG: N/A VP: 0,0 WA: N/A Name 143 | wmctrl -d | grep '\*' | cut -d' ' -f1 144 | } 145 | 146 | # get_open_windows_count() => "2" 147 | get_open_windows_count() { 148 | workspace="$(get_current_workspace)" 149 | wmctrl -l | cut -d' ' -f3 | grep -c "$workspace" 150 | } 151 | 152 | is_blank() { 153 | count=$(get_open_windows_count) 154 | [[ "$count" -eq 0 ]] 155 | } 156 | 157 | set_blurred_wallpaper() { 158 | debug "Setting blurred wallpaper" 159 | local mode="$1" # --bg-tile 160 | 161 | if [[ "$ANIMATE_FADE" == 1 ]]; then 162 | # We're going to redirect output to /dev/null to supress feh warnings 163 | feh --no-fehbg "$mode" "$CACHE_DIR/blur-0.$EXT" &> /dev/null 164 | sleep $ANIMATION_INTERVAL 165 | feh --no-fehbg "$mode" "$CACHE_DIR/blur-1.$EXT" &> /dev/null 166 | sleep $ANIMATION_INTERVAL 167 | fi 168 | 169 | feh --no-fehbg "$mode" "$CACHE_DIR/blur-final.$EXT" &> /dev/null 170 | } 171 | 172 | set_original_wallpaper() { 173 | debug "Setting original wallpaper" 174 | local mode="$1" # --bg-tile 175 | 176 | if [[ "$ANIMATE_FADE" == 1 ]]; then 177 | feh --no-fehbg "$mode" "$CACHE_DIR/blur-1.$EXT" &> /dev/null 178 | sleep $ANIMATION_INTERVAL 179 | feh --no-fehbg "$mode" "$CACHE_DIR/blur-0.$EXT" &> /dev/null 180 | sleep $ANIMATION_INTERVAL 181 | fi 182 | 183 | feh --no-fehbg "$mode" "$wall_original" &> /dev/null 184 | } 185 | 186 | kill_other_instances() { 187 | if [[ "$(pgrep -fcl "$PROC_EXPR")" -gt 1 ]]; then 188 | head "Stopping other instances of $BIN..." 189 | 190 | local count=1 191 | while [[ "$(pgrep -fcl "$PROC_EXPR")" -gt 1 ]]; do 192 | count=$(( count + 1 )) 193 | old_pid="$(pgrep -fo "$PROC_EXPR")" 194 | 195 | # Kill it; if it refuses after some time, force-stop it 196 | if [[ "$count" -gt 10 ]]; then 197 | kill -9 "$old_pid" 198 | else 199 | kill "$old_pid" 200 | fi 201 | sleep 0.1 202 | done 203 | fi 204 | } 205 | 206 | run_loop () { 207 | prev_blank="-" 208 | prev_wallpaper="-" 209 | first_run="1" 210 | 211 | while true; do 212 | wallpaper="$(get_feh_wallpaper)" 213 | 214 | # Check if wallpaper has changed. 215 | if [[ "$prev_wallpaper" != "$wallpaper" ]]; then 216 | wallpaper_mode="$(get_feh_wallpaper_mode)" 217 | 218 | # If there's no wallpaper, try again later. 219 | if [[ -z "$wallpaper" ]]; then 220 | sleep "$POLL_INTERVAL" 221 | continue 222 | else 223 | generate_blurred_images "$wallpaper" 224 | prev_wallpaper="$wallpaper" 225 | prev_blank="" 226 | fi 227 | fi 228 | 229 | blank="$(is_blank && echo 1 || echo 0)" 230 | if [[ "$prev_blank" != "$blank" ]]; then 231 | if [[ "$blank" == 0 ]]; then 232 | set_blurred_wallpaper "$wallpaper_mode" 233 | elif [[ "$first_run" == "0" ]]; then 234 | # Skip set_original_wallpaper if we were started without 235 | # an active window so that the animation is skipped 236 | set_original_wallpaper "$wallpaper_mode" 237 | fi 238 | prev_blank="$blank" 239 | fi 240 | 241 | first_run=0 242 | sleep "$POLL_INTERVAL" 243 | done 244 | } 245 | 246 | show_help() { 247 | echo "Usage: $BIN [-v|--verbose]" 248 | echo '' 249 | echo 'Options:' 250 | echo ' -b, --blur N set blur strength to N (4...128, default 32)' 251 | echo ' --darken N darken image by N (4...100, default 32)' 252 | echo ' --lighten N lengthen image by N (4...100, default 0)' 253 | echo ' -c, --uncontrast reduce contrast' 254 | echo ' --save-image PATH save blurred image to PATH' 255 | echo ' --no-animate skip fading animation' 256 | echo '' 257 | echo 'Daemon options:' 258 | echo ' -d, --daemon run in background' 259 | echo ' -s, --stop stop previously-ran daemon' 260 | echo '' 261 | echo 'Other options:' 262 | echo ' -v, --verbose show more messages' 263 | echo ' -q, --quiet supress messages' 264 | echo '' 265 | } 266 | 267 | parse_opts() { 268 | while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in 269 | -h | --help) 270 | MODE=noop 271 | show_help 272 | ;; 273 | -V | --version ) 274 | MODE=noop 275 | echo version 276 | ;; 277 | -b | --blur ) 278 | shift 279 | BLUR_STRENGTH="$1" 280 | ;; 281 | -c | --uncontrast ) 282 | REDUCE_CONTRAST=1 283 | ;; 284 | --save-image ) 285 | shift 286 | BLUR_IMAGE_SAVE_LOCATION="$1" 287 | ;; 288 | --no-animate ) 289 | ANIMATE_FADE=0 290 | ;; 291 | -D | --dim | --darken ) 292 | shift 293 | DIM_COLOR="#000" 294 | DIM_STRENGTH="$1" 295 | ;; 296 | --lighten ) 297 | shift 298 | DIM_COLOR="#fff" 299 | DIM_STRENGTH="$1" 300 | ;; 301 | --tint-color ) 302 | shift 303 | DIM_COLOR="$1" 304 | ;; 305 | --tint-strength ) 306 | shift 307 | DIM_STRENGTH="$1" 308 | ;; 309 | -d | --daemon ) 310 | MODE=background 311 | ;; 312 | -s | --stop ) 313 | MODE=stop 314 | ;; 315 | -q | --quiet ) 316 | VERBOSE=0 317 | ;; 318 | -v | --verbose ) 319 | VERBOSE=2 320 | ;; 321 | esac; shift; done 322 | if [[ "$1" == '--' ]]; then shift; fi 323 | } 324 | 325 | ensure_feh() { 326 | if ! command -v feh >/dev/null; then 327 | echo "$BIN requires Feh to set wallpapers." 328 | exit 329 | fi 330 | } 331 | 332 | # Ensure that 'graphicsmagick' is available. 333 | ensure_gm() { 334 | if ! command -v gm >/dev/null; then 335 | echo "$BIN requires GraphicsMagick to set wallpapers." 336 | exit 337 | fi 338 | } 339 | 340 | ensure_wmctrl() { 341 | if ! command -v wmctrl >/dev/null; then 342 | echo "$BIN requires wmctrl to detect events." 343 | exit 344 | fi 345 | } 346 | 347 | print_usage() { 348 | head "Monitoring changes" 349 | info "$BIN will now blur any wallpapers set using 'feh'." 350 | info "To change your wallpaper, try:" 351 | info "" 352 | info " feh --bg-tile your-image.jpg" 353 | } 354 | 355 | main() { 356 | ensure_feh 357 | ensure_gm 358 | ensure_wmctrl 359 | parse_opts "$@" 360 | 361 | case "$MODE" in 362 | background) 363 | kill_other_instances 364 | print_usage 365 | "$0" --worker --quiet & disown 366 | 367 | head "Background mode" 368 | info "$BIN started in background mode!" 369 | info "To stop, use '$BIN --stop'." 370 | ;; 371 | 372 | stop) 373 | kill_other_instances 374 | ;; 375 | 376 | noop) 377 | exit 378 | ;; 379 | 380 | *) 381 | kill_other_instances 382 | print_usage 383 | run_loop 384 | ;; 385 | esac 386 | } 387 | 388 | # Perform cleanup operations before stopping. 389 | do_cleanup () { 390 | # Guard clause so that it's only ran once 391 | if [[ "$CLEANING_UP" == "1" ]]; then return; fi 392 | CLEANING_UP=1 393 | 394 | rm -rf "$CACHE_DIR" 395 | 396 | # Restore original wallpaper before exiting 397 | if [[ "$MODE" == "foreground" ]] && [[ -e "$HOME/.fehbg" ]]; then 398 | head "Restoring original wallpaper" 399 | source "$HOME/.fehbg" 400 | fi 401 | } 402 | 403 | finish () { 404 | do_cleanup 405 | exit 1 406 | } 407 | 408 | trap finish EXIT 409 | trap finish SIGHUP 410 | trap finish SIGINT 411 | trap finish SIGTERM 412 | main "$@" 413 | --------------------------------------------------------------------------------