├── 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://github.com/rstacruz)
98 | [](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 |
--------------------------------------------------------------------------------