ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.101
Committed: Sat Jul 24 11:58:27 2021 UTC (2 years, 9 months ago) by root
Branch: MAIN
Changes since 1.100: +3 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #! perl
2    
3 root 1.88 #:META:RESOURCE:%.expr:string:background expression
4     #:META:RESOURCE:%.border:boolean:respect the terminal border
5     #:META:RESOURCE:%.interval:seconds:minimum time between updates
6 sf-exg 1.92 #:META:RESOURCE:pixmap:file[;geom]:set image as background
7     #:META:RESOURCE:backgroundPixmap:file[;geom]:set image as background
8     #:META:RESOURCE:tr:boolean:set root pixmap as background
9     #:META:RESOURCE:transparent:boolean:set root pixmap as background
10     #:META:RESOURCE:tint:color:tint background with color
11     #:META:RESOURCE:tintColor:color:tint background with color
12     #:META:RESOURCE:sh:number:shade background by number %
13     #:META:RESOURCE:shading:number:shade background by number %
14     #:META:RESOURCE:blr:HxV:gaussian-blur background with radii
15     #:META:RESOURCE:blurRadius:HxV:gaussian-blur background with radii
16 root 1.101 #:META:OSC:20:change/query background image
17     #:META:OSC:705:change transparent background tint colour
18 root 1.33
19 root 1.41 =head1 NAME
20 root 1.33
21 root 1.79 background - manage terminal background
22 root 1.41
23     =head1 SYNOPSIS
24 root 1.33
25 root 1.36 urxvt --background-expr 'background expression'
26     --background-border
27 root 1.46 --background-interval seconds
28 root 1.33
29 root 1.75 =head1 QUICK AND DIRTY CHEAT SHEET
30    
31 root 1.98 Load a random jpeg image and tile the background with it without scaling
32     or anything else:
33 root 1.75
34     load "/path/to/img.jpg"
35    
36     The same, but use mirroring/reflection instead of tiling:
37    
38     mirror load "/path/to/img.jpg"
39    
40     Load an image and scale it to exactly fill the terminal window:
41    
42     scale keep { load "/path/to/img.jpg" }
43    
44     Implement pseudo-transparency by using a suitably-aligned root pixmap
45     as window background:
46    
47     rootalign root
48    
49     Likewise, but keep a blurred copy:
50    
51     rootalign keep { blur 10, root }
52    
53 root 1.41 =head1 DESCRIPTION
54 root 1.33
55 root 1.36 This extension manages the terminal background by creating a picture that
56     is behind the text, replacing the normal background colour.
57    
58     It does so by evaluating a Perl expression that I<calculates> the image on
59     the fly, for example, by grabbing the root background or loading a file.
60    
61     While the full power of Perl is available, the operators have been design
62     to be as simple as possible.
63    
64     For example, to load an image and scale it to the window size, you would
65     use:
66    
67 root 1.64 urxvt --background-expr 'scale keep { load "/path/to/mybg.png" }'
68 root 1.36
69     Or specified as a X resource:
70    
71 sf-exg 1.90 URxvt.background.expr: scale keep { load "/path/to/mybg.png" }
72 root 1.36
73 root 1.41 =head1 THEORY OF OPERATION
74 root 1.36
75     At startup, just before the window is mapped for the first time, the
76     expression is evaluated and must yield an image. The image is then
77     extended as necessary to cover the whole terminal window, and is set as a
78     background pixmap.
79    
80     If the image contains an alpha channel, then it will be used as-is in
81     visuals that support alpha channels (for example, for a compositing
82     manager). In other visuals, the terminal background colour will be used to
83     replace any transparency.
84    
85     When the expression relies, directly or indirectly, on the window size,
86     position, the root pixmap, or a timer, then it will be remembered. If not,
87     then it will be removed.
88    
89     If any of the parameters that the expression relies on changes (when the
90     window is moved or resized, its position or size changes; when the root
91     pixmap is replaced by another one the root background changes; or when the
92     timer elapses), then the expression will be evaluated again.
93    
94 root 1.64 For example, an expression such as C<scale keep { load "$HOME/mybg.png"
95     }> scales the image to the window size, so it relies on the window size
96     and will be reevaluated each time it is changed, but not when it moves for
97 root 1.36 example. That ensures that the picture always fills the terminal, even
98 sf-exg 1.51 after its size changes.
99 root 1.36
100 root 1.41 =head2 EXPRESSIONS
101 root 1.36
102     Expressions are normal Perl expressions, in fact, they are Perl blocks -
103     which means you could use multiple lines and statements:
104    
105 root 1.64 scale keep {
106     again 3600;
107     if (localtime now)[6]) {
108     return load "$HOME/weekday.png";
109     } else {
110     return load "$HOME/sunday.png";
111     }
112 root 1.36 }
113    
114 root 1.68 This inner expression is evaluated once per hour (and whenever the
115 sf-exg 1.73 terminal window is resized). It sets F<sunday.png> as background on
116 root 1.68 Sundays, and F<weekday.png> on all other days.
117 root 1.36
118     Fortunately, we expect that most expressions will be much simpler, with
119     little Perl knowledge needed.
120    
121     Basically, you always start with a function that "generates" an image
122     object, such as C<load>, which loads an image from disk, or C<root>, which
123     returns the root window background image:
124    
125     load "$HOME/mypic.png"
126    
127     The path is usually specified as a quoted string (the exact rules can be
128     found in the L<perlop> manpage). The F<$HOME> at the beginning of the
129     string is expanded to the home directory.
130    
131     Then you prepend one or more modifiers or filtering expressions, such as
132     C<scale>:
133    
134     scale load "$HOME/mypic.png"
135    
136     Just like a mathematical expression with functions, you should read these
137     expressions from right to left, as the C<load> is evaluated first, and
138     its result becomes the argument to the C<scale> function.
139    
140     Many operators also allow some parameters preceding the input image
141     that modify its behaviour. For example, C<scale> without any additional
142     arguments scales the image to size of the terminal window. If you specify
143 root 1.43 an additional argument, it uses it as a scale factor (multiply by 100 to
144     get a percentage):
145 root 1.36
146 root 1.43 scale 2, load "$HOME/mypic.png"
147 root 1.36
148     This enlarges the image by a factor of 2 (200%). As you can see, C<scale>
149 sf-exg 1.91 has now two arguments, the C<2> and the C<load> expression, while
150 root 1.36 C<load> only has one argument. Arguments are separated from each other by
151     commas.
152    
153     Scale also accepts two arguments, which are then separate factors for both
154     horizontal and vertical dimensions. For example, this halves the image
155     width and doubles the image height:
156    
157 root 1.43 scale 0.5, 2, load "$HOME/mypic.png"
158 root 1.36
159 root 1.68 IF you try out these expressions, you might suffer from some sluggishness,
160 sf-exg 1.73 because each time the terminal is resized, it loads the PNG image again
161 root 1.68 and scales it. Scaling is usually fast (and unavoidable), but loading the
162     image can be quite time consuming. This is where C<keep> comes in handy:
163 root 1.39
164 root 1.64 scale 0.5, 2, keep { load "$HOME/mypic.png" }
165 root 1.39
166 root 1.64 The C<keep> operator executes all the statements inside the braces only
167     once, or when it thinks the outcome might change. In other cases it
168     returns the last value computed by the brace block.
169 root 1.39
170 root 1.64 This means that the C<load> is only executed once, which makes it much
171 sf-exg 1.65 faster, but also means that more memory is being used, because the loaded
172 root 1.64 image must be kept in memory at all times. In this expression, the
173     trade-off is likely worth it.
174 root 1.39
175 root 1.64 But back to effects: Other effects than scaling are also readily
176     available, for example, you can tile the image to fill the whole window,
177     instead of resizing it:
178 root 1.39
179 root 1.64 tile keep { load "$HOME/mypic.png" }
180 root 1.39
181 root 1.64 In fact, images returned by C<load> are in C<tile> mode by default, so the
182     C<tile> operator is kind of superfluous.
183 root 1.39
184 root 1.64 Another common effect is to mirror the image, so that the same edges
185     touch:
186 root 1.36
187 root 1.64 mirror keep { load "$HOME/mypic.png" }
188 root 1.36
189 root 1.64 Another common background expression is:
190 root 1.63
191 root 1.64 rootalign root
192 root 1.39
193 root 1.64 This one first takes a snapshot of the screen background image, and then
194 sf-exg 1.65 moves it to the upper left corner of the screen (as opposed to the upper
195 root 1.64 left corner of the terminal window)- the result is pseudo-transparency:
196     the image seems to be static while the window is moved around.
197    
198 root 1.71 =head2 COLOUR SPECIFICATIONS
199    
200 sf-exg 1.73 Whenever an operator expects a "colour", then this can be specified in one
201 root 1.71 of two ways: Either as string with an X11 colour specification, such as:
202    
203     "red" # named colour
204     "#f00" # simple rgb
205     "[50]red" # red with 50% alpha
206     "TekHVC:300/50/50" # anything goes
207    
208     OR as an array reference with one, three or four components:
209    
210     [0.5] # 50% gray, 100% alpha
211     [0.5, 0, 0] # dark red, no green or blur, 100% alpha
212     [0.5, 0, 0, 0.7] # same with explicit 70% alpha
213    
214 root 1.64 =head2 CACHING AND SENSITIVITY
215    
216     Since some operations (such as C<load> and C<blur>) can take a long time,
217     caching results can be very important for a smooth operation. Caching can
218     also be useful to reduce memory usage, though, for example, when an image
219     is cached by C<load>, it could be shared by multiple terminal windows
220     running inside urxvtd.
221    
222     =head3 C<keep { ... }> caching
223    
224     The most important way to cache expensive operations is to use C<keep {
225     ... }>. The C<keep> operator takes a block of multiple statements enclosed
226     by C<{}> and keeps the return value in memory.
227    
228     An expression can be "sensitive" to various external events, such as
229 sf-exg 1.65 scaling or moving the window, root background changes and timers. Simply
230 sf-exg 1.67 using an expression (such as C<scale> without parameters) that depends on
231 root 1.64 certain changing values (called "variables"), or using those variables
232     directly, will make an expression sensitive to these events - for example,
233     using C<scale> or C<TW> will make the expression sensitive to the terminal
234     size, and thus to resizing events.
235 root 1.39
236 root 1.64 When such an event happens, C<keep> will automatically trigger a
237     reevaluation of the whole expression with the new value of the expression.
238 root 1.39
239 root 1.64 C<keep> is most useful for expensive operations, such as C<blur>:
240 root 1.39
241 root 1.68 rootalign keep { blur 20, root }
242 root 1.39
243 root 1.64 This makes a blurred copy of the root background once, and on subsequent
244     calls, just root-aligns it. Since C<blur> is usually quite slow and
245     C<rootalign> is quite fast, this trades extra memory (for the cached
246     blurred pixmap) with speed (blur only needs to be redone when root
247     changes).
248 root 1.39
249 root 1.64 =head3 C<load> caching
250 root 1.36
251 root 1.64 The C<load> operator itself does not keep images in memory, but as long as
252     the image is still in memory, C<load> will use the in-memory image instead
253     of loading it freshly from disk.
254 root 1.63
255 root 1.64 That means that this expression:
256 root 1.63
257 root 1.64 keep { load "$HOME/path..." }
258 root 1.63
259 root 1.64 Not only caches the image in memory, other terminal instances that try to
260     C<load> it can reuse that in-memory copy.
261 root 1.63
262 root 1.41 =head1 REFERENCE
263 root 1.33
264 root 1.41 =head2 COMMAND LINE SWITCHES
265 root 1.36
266 root 1.100 =over
267 root 1.36
268     =item --background-expr perl-expression
269    
270     Specifies the Perl expression to evaluate.
271    
272     =item --background-border
273    
274     By default, the expression creates an image that fills the full window,
275     overwriting borders and any other areas, such as the scrollbar.
276    
277     Specifying this flag changes the behaviour, so that the image only
278     replaces the background of the character area.
279    
280 root 1.46 =item --background-interval seconds
281    
282 sf-exg 1.51 Since some operations in the underlying XRender extension can effectively
283 root 1.46 freeze your X-server for prolonged time, this extension enforces a minimum
284     time between updates, which is normally about 0.1 seconds.
285    
286     If you want to do updates more often, you can decrease this safety
287     interval with this switch.
288    
289 root 1.36 =back
290    
291 root 1.33 =cut
292 root 1.12
293 root 1.52 our %_IMG_CACHE;
294 root 1.36 our $HOME;
295 root 1.63 our ($self, $frame);
296 root 1.84 our ($x, $y, $w, $h, $focus);
297 root 1.3
298 root 1.16 # enforce at least this interval between updates
299 root 1.46 our $MIN_INTERVAL = 6/59.951;
300 root 1.9
301 root 1.1 {
302     package urxvt::bgdsl; # background language
303    
304 root 1.63 sub FR_PARENT() { 0 } # parent frame, if any - must be #0
305     sub FR_CACHE () { 1 } # cached values
306     sub FR_AGAIN () { 2 } # what this expr is sensitive to
307     sub FR_STATE () { 3 } # watchers etc.
308    
309 root 1.43 use List::Util qw(min max sum shuffle);
310    
311 root 1.15 =head2 PROVIDERS/GENERATORS
312    
313 root 1.31 These functions provide an image, by loading it from disk, grabbing it
314 sf-exg 1.32 from the root screen or by simply generating it. They are used as starting
315 root 1.31 points to get an image you can play with.
316    
317 root 1.100 =over
318 root 1.15
319     =item load $path
320    
321 root 1.29 Loads the image at the given C<$path>. The image is set to plane tiling
322     mode.
323    
324 sf-exg 1.65 If the image is already in memory (e.g. because another terminal instance
325 sf-exg 1.83 uses it), then the in-memory copy is returned instead.
326 root 1.54
327 root 1.64 =item load_uc $path
328    
329     Load uncached - same as load, but does not cache the image, which means it
330 root 1.72 is I<always> loaded from the filesystem again, even if another copy of it
331     is in memory at the time.
332 root 1.29
333 root 1.15 =cut
334    
335 root 1.72 sub load_uc($) {
336     $self->new_img_from_file ($_[0])
337     }
338    
339 root 1.63 sub load($) {
340 root 1.54 my ($path) = @_;
341    
342     $_IMG_CACHE{$path} || do {
343 root 1.72 my $img = load_uc $path;
344 root 1.54 Scalar::Util::weaken ($_IMG_CACHE{$path} = $img);
345     $img
346     }
347     }
348    
349 root 1.31 =item root
350    
351     Returns the root window pixmap, that is, hopefully, the background image
352 root 1.62 of your screen.
353 root 1.31
354     This function makes your expression root sensitive, that means it will be
355     reevaluated when the bg image changes.
356    
357     =cut
358    
359 root 1.2 sub root() {
360 root 1.63 $frame->[FR_AGAIN]{rootpmap} = 1;
361 root 1.52 $self->new_img_from_root
362 root 1.1 }
363    
364 root 1.31 =item solid $colour
365    
366     =item solid $width, $height, $colour
367    
368     Creates a new image and completely fills it with the given colour. The
369     image is set to tiling mode.
370    
371 root 1.40 If C<$width> and C<$height> are omitted, it creates a 1x1 image, which is
372 root 1.31 useful for solid backgrounds or for use in filtering effects.
373    
374     =cut
375    
376 root 1.42 sub solid($;$$) {
377 root 1.31 my $colour = pop;
378    
379 root 1.59 my $img = $self->new_img (urxvt::PictStandardARGB32, 0, 0, $_[0] || 1, $_[1] || 1);
380 root 1.31 $img->fill ($colour);
381 root 1.15 $img
382     }
383    
384 root 1.45 =item clone $img
385 root 1.31
386 root 1.45 Returns an exact copy of the image. This is useful if you want to have
387     multiple copies of the same image to apply different effects to.
388 root 1.31
389 root 1.20 =cut
390    
391 root 1.45 sub clone($) {
392     $_[0]->clone
393 root 1.20 }
394    
395 root 1.56 =item merge $img ...
396    
397 root 1.57 Takes any number of images and merges them together, creating a single
398 root 1.62 image containing them all. The tiling mode of the first image is used as
399 sf-exg 1.65 the tiling mode of the resulting image.
400 root 1.56
401 root 1.61 This function is called automatically when an expression returns multiple
402     images.
403    
404 root 1.56 =cut
405    
406     sub merge(@) {
407 root 1.61 return $_[0] unless $#_;
408    
409 root 1.58 # rather annoyingly clumsy, but optimisation is for another time
410    
411 root 1.59 my $x0 = +1e9;
412     my $y0 = +1e9;
413 root 1.58 my $x1 = -1e9;
414     my $y1 = -1e9;
415    
416     for (@_) {
417     my ($x, $y, $w, $h) = $_->geometry;
418    
419     $x0 = $x if $x0 > $x;
420     $y0 = $y if $y0 > $y;
421    
422     $x += $w;
423     $y += $h;
424    
425 root 1.59 $x1 = $x if $x1 < $x;
426     $y1 = $y if $y1 < $y;
427 root 1.58 }
428    
429 root 1.59 my $base = $self->new_img (urxvt::PictStandardARGB32, $x0, $y0, $x1 - $x0, $y1 - $y0);
430 root 1.62 $base->repeat_mode ($_[0]->repeat_mode);
431 root 1.58 $base->fill ([0, 0, 0, 0]);
432    
433 root 1.59 $base->draw ($_)
434 root 1.58 for @_;
435    
436     $base
437 root 1.56 }
438    
439 root 1.76 =back
440    
441 root 1.28 =head2 TILING MODES
442    
443     The following operators modify the tiling mode of an image, that is, the
444     way that pixels outside the image area are painted when the image is used.
445 root 1.15
446 root 1.100 =over
447 root 1.15
448 root 1.28 =item tile $img
449    
450     Tiles the whole plane with the image and returns this new image - or in
451     other words, it returns a copy of the image in plane tiling mode.
452    
453 root 1.34 Example: load an image and tile it over the background, without
454     resizing. The C<tile> call is superfluous because C<load> already defaults
455     to tiling mode.
456    
457     tile load "mybg.png"
458    
459 root 1.28 =item mirror $img
460    
461     Similar to tile, but reflects the image each time it uses a new copy, so
462     that top edges always touch top edges, right edges always touch right
463     edges and so on (with normal tiling, left edges always touch right edges
464     and top always touch bottom edges).
465    
466 root 1.36 Example: load an image and mirror it over the background, avoiding sharp
467 root 1.34 edges at the image borders at the expense of mirroring the image itself
468    
469     mirror load "mybg.png"
470    
471 root 1.28 =item pad $img
472    
473     Takes an image and modifies it so that all pixels outside the image area
474     become transparent. This mode is most useful when you want to place an
475     image over another image or the background colour while leaving all
476     background pixels outside the image unchanged.
477    
478 root 1.36 Example: load an image and display it in the upper left corner. The rest
479 sf-exg 1.51 of the space is left "empty" (transparent or whatever your compositor does
480 root 1.34 in alpha mode, else background colour).
481    
482     pad load "mybg.png"
483    
484 root 1.28 =item extend $img
485    
486     Extends the image over the whole plane, using the closest pixel in the
487 sf-exg 1.51 area outside the image. This mode is mostly useful when you use more complex
488 root 1.28 filtering operations and want the pixels outside the image to have the
489     same values as the pixels near the edge.
490    
491 root 1.34 Example: just for curiosity, how does this pixel extension stuff work?
492    
493     extend move 50, 50, load "mybg.png"
494    
495 root 1.15 =cut
496    
497 root 1.28 sub pad($) {
498     my $img = $_[0]->clone;
499     $img->repeat_mode (urxvt::RepeatNone);
500     $img
501     }
502    
503     sub tile($) {
504     my $img = $_[0]->clone;
505     $img->repeat_mode (urxvt::RepeatNormal);
506     $img
507     }
508    
509     sub mirror($) {
510     my $img = $_[0]->clone;
511     $img->repeat_mode (urxvt::RepeatReflect);
512     $img
513     }
514 root 1.4
515 root 1.28 sub extend($) {
516 root 1.24 my $img = $_[0]->clone;
517 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
518 root 1.24 $img
519     }
520    
521 root 1.28 =back
522    
523 root 1.45 =head2 VARIABLE VALUES
524 root 1.28
525 root 1.45 The following functions provide variable data such as the terminal window
526     dimensions. They are not (Perl-) variables, they just return stuff that
527     varies. Most of them make your expression sensitive to some events, for
528     example using C<TW> (terminal width) means your expression is evaluated
529     again when the terminal is resized.
530 root 1.28
531 root 1.100 =over
532 root 1.28
533 root 1.45 =item TX
534    
535     =item TY
536    
537     Return the X and Y coordinates of the terminal window (the terminal
538     window is the full window by default, and the character area only when in
539     border-respect mode).
540    
541 root 1.84 Using these functions makes your expression sensitive to window moves.
542 root 1.45
543     These functions are mainly useful to align images to the root window.
544    
545     Example: load an image and align it so it looks as if anchored to the
546 root 1.64 background (that's exactly what C<rootalign> does btw.):
547 root 1.45
548 root 1.64 move -TX, -TY, keep { load "mybg.png" }
549 root 1.45
550     =item TW
551    
552 root 1.77 =item TH
553    
554 root 1.45 Return the width (C<TW>) and height (C<TH>) of the terminal window (the
555     terminal window is the full window by default, and the character area only
556     when in border-respect mode).
557    
558 root 1.84 Using these functions makes your expression sensitive to window resizes.
559 root 1.45
560     These functions are mainly useful to scale images, or to clip images to
561     the window size to conserve memory.
562    
563     Example: take the screen background, clip it to the window size, blur it a
564     bit, align it to the window position and use it as background.
565    
566 root 1.64 clip move -TX, -TY, keep { blur 5, root }
567 root 1.45
568 root 1.84 =item FOCUS
569    
570     Returns a boolean indicating whether the terminal window has keyboard
571     focus, in which case it returns true.
572    
573     Using this function makes your expression sensitive to focus changes.
574    
575     A common use case is to fade the background image when the terminal loses
576     focus, often together with the C<-fade> command line option. In fact,
577     there is a special function for just that use case: C<focus_fade>.
578    
579 sf-exg 1.86 Example: use two entirely different background images, depending on
580 root 1.84 whether the window has focus.
581    
582     FOCUS ? keep { load "has_focus.jpg" } : keep { load "no_focus.jpg" }
583    
584 root 1.45 =cut
585    
586 root 1.84 sub TX () { $frame->[FR_AGAIN]{position} = 1; $x }
587     sub TY () { $frame->[FR_AGAIN]{position} = 1; $y }
588     sub TW () { $frame->[FR_AGAIN]{size} = 1; $w }
589     sub TH () { $frame->[FR_AGAIN]{size} = 1; $h }
590     sub FOCUS() { $frame->[FR_AGAIN]{focus} = 1; $focus }
591 root 1.45
592     =item now
593    
594     Returns the current time as (fractional) seconds since the epoch.
595    
596     Using this expression does I<not> make your expression sensitive to time,
597     but the next two functions do.
598    
599     =item again $seconds
600    
601     When this function is used the expression will be reevaluated again in
602     C<$seconds> seconds.
603    
604     Example: load some image and rotate it according to the time of day (as if it were
605     the hour pointer of a clock). Update this image every minute.
606    
607 root 1.64 again 60;
608     rotate 50, 50, (now % 86400) * -72 / 8640, scale keep { load "myclock.png" }
609 root 1.28
610 root 1.45 =item counter $seconds
611    
612     Like C<again>, but also returns an increasing counter value, starting at
613     0, which might be useful for some simple animation effects.
614 root 1.28
615     =cut
616    
617 root 1.45 sub now() { urxvt::NOW }
618    
619     sub again($) {
620 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
621 root 1.45 }
622    
623     sub counter($) {
624 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
625     $frame->[FR_STATE]{counter} + 0
626 root 1.28 }
627    
628 root 1.45 =back
629    
630     =head2 SHAPE CHANGING OPERATORS
631    
632     The following operators modify the shape, size or position of the image.
633    
634 root 1.100 =over
635 root 1.45
636 root 1.28 =item clip $img
637    
638     =item clip $width, $height, $img
639    
640     =item clip $x, $y, $width, $height, $img
641    
642     Clips an image to the given rectangle. If the rectangle is outside the
643     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
644     larger than the image, then the tiling mode defines how the extra pixels
645     will be filled.
646    
647 root 1.78 If C<$x> and C<$y> are missing, then C<0> is assumed for both.
648 root 1.28
649     If C<$width> and C<$height> are missing, then the window size will be
650     assumed.
651    
652     Example: load an image, blur it, and clip it to the window size to save
653     memory.
654    
655 root 1.64 clip keep { blur 10, load "mybg.png" }
656 root 1.28
657     =cut
658    
659 root 1.20 sub clip($;$$;$$) {
660 root 1.7 my $img = pop;
661 root 1.30 my $h = pop || TH;
662     my $w = pop || TW;
663 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
664 root 1.4 }
665    
666 root 1.28 =item scale $img
667    
668 root 1.43 =item scale $size_factor, $img
669 root 1.28
670 root 1.43 =item scale $width_factor, $height_factor, $img
671 root 1.28
672 root 1.43 Scales the image by the given factors in horizontal
673     (C<$width>) and vertical (C<$height>) direction.
674 root 1.28
675 sf-exg 1.81 If only one factor is given, it is used for both directions.
676 root 1.28
677 root 1.43 If no factors are given, scales the image to the window size without
678 root 1.28 keeping aspect.
679    
680     =item resize $width, $height, $img
681    
682     Resizes the image to exactly C<$width> times C<$height> pixels.
683    
684 root 1.43 =item fit $img
685    
686     =item fit $width, $height, $img
687    
688     Fits the image into the given C<$width> and C<$height> without changing
689     aspect, or the terminal size. That means it will be shrunk or grown until
690     the whole image fits into the given area, possibly leaving borders.
691    
692     =item cover $img
693    
694     =item cover $width, $height, $img
695    
696     Similar to C<fit>, but shrinks or grows until all of the area is covered
697     by the image, so instead of potentially leaving borders, it will cut off
698     image data that doesn't fit.
699    
700 root 1.28 =cut
701    
702 root 1.33 sub scale($;$;$) {
703 root 1.28 my $img = pop;
704    
705 root 1.43 @_ == 2 ? $img->scale ($_[0] * $img->w, $_[1] * $img->h)
706     : @_ ? $img->scale ($_[0] * $img->w, $_[0] * $img->h)
707 root 1.30 : $img->scale (TW, TH)
708 root 1.28 }
709    
710 root 1.2 sub resize($$$) {
711 root 1.7 my $img = pop;
712     $img->scale ($_[0], $_[1])
713 root 1.1 }
714    
715 root 1.43 sub fit($;$$) {
716     my $img = pop;
717     my $w = ($_[0] || TW) / $img->w;
718     my $h = ($_[1] || TH) / $img->h;
719     scale +(min $w, $h), $img
720     }
721    
722     sub cover($;$$) {
723     my $img = pop;
724     my $w = ($_[0] || TW) / $img->w;
725     my $h = ($_[1] || TH) / $img->h;
726     scale +(max $w, $h), $img
727     }
728    
729 root 1.36 =item move $dx, $dy, $img
730    
731     Moves the image by C<$dx> pixels in the horizontal, and C<$dy> pixels in
732     the vertical.
733    
734     Example: move the image right by 20 pixels and down by 30.
735    
736     move 20, 30, ...
737    
738 root 1.46 =item align $xalign, $yalign, $img
739    
740     Aligns the image according to a factor - C<0> means the image is moved to
741     the left or top edge (for C<$xalign> or C<$yalign>), C<0.5> means it is
742     exactly centered and C<1> means it touches the right or bottom edge.
743    
744     Example: remove any visible border around an image, center it vertically but move
745     it to the right hand side.
746    
747     align 1, 0.5, pad $img
748    
749 root 1.44 =item center $img
750    
751     =item center $width, $height, $img
752    
753     Centers the image, i.e. the center of the image is moved to the center of
754     the terminal window (or the box specified by C<$width> and C<$height> if
755     given).
756    
757 root 1.46 Example: load an image and center it.
758    
759 root 1.64 center keep { pad load "mybg.png" }
760 root 1.46
761 root 1.36 =item rootalign $img
762    
763     Moves the image so that it appears glued to the screen as opposed to the
764     window. This gives the illusion of a larger area behind the window. It is
765     exactly equivalent to C<move -TX, -TY>, that is, it moves the image to the
766     top left of the screen.
767    
768     Example: load a background image, put it in mirror mode and root align it.
769    
770 root 1.64 rootalign keep { mirror load "mybg.png" }
771 root 1.36
772     Example: take the screen background and align it, giving the illusion of
773     transparency as long as the window isn't in front of other windows.
774    
775 root 1.46 rootalign root
776 root 1.36
777     =cut
778    
779 root 1.7 sub move($$;$) {
780 root 1.20 my $img = pop->clone;
781     $img->move ($_[0], $_[1]);
782     $img
783 root 1.1 }
784    
785 root 1.46 sub align($;$$) {
786     my $img = pop;
787    
788     move $_[0] * (TW - $img->w),
789     $_[1] * (TH - $img->h),
790     $img
791     }
792    
793 root 1.44 sub center($;$$) {
794     my $img = pop;
795     my $w = $_[0] || TW;
796 root 1.46 my $h = $_[1] || TH;
797 root 1.44
798     move 0.5 * ($w - $img->w), 0.5 * ($h - $img->h), $img
799     }
800    
801 root 1.36 sub rootalign($) {
802     move -TX, -TY, $_[0]
803 root 1.1 }
804    
805 root 1.64 =item rotate $center_x, $center_y, $degrees, $img
806 root 1.52
807 root 1.64 Rotates the image clockwise by C<$degrees> degrees, around the point at
808     C<$center_x> and C<$center_y> (specified as factor of image width/height).
809 root 1.52
810 sf-exg 1.81 Example: rotate the image by 90 degrees around its center.
811 root 1.52
812 root 1.64 rotate 0.5, 0.5, 90, keep { load "$HOME/mybg.png" }
813 root 1.52
814     =cut
815    
816 root 1.53 sub rotate($$$$) {
817 root 1.52 my $img = pop;
818     $img->rotate (
819 root 1.60 $_[0] * ($img->w + $img->x),
820     $_[1] * ($img->h + $img->y),
821 root 1.52 $_[2] * (3.14159265 / 180),
822     )
823     }
824    
825 root 1.45 =back
826    
827     =head2 COLOUR MODIFICATIONS
828    
829     The following operators change the pixels of the image.
830    
831 root 1.100 =over
832 root 1.45
833 root 1.70 =item tint $color, $img
834    
835     Tints the image in the given colour.
836    
837     Example: tint the image red.
838    
839     tint "red", load "rgb.png"
840    
841     Example: the same, but specify the colour by component.
842    
843     tint [1, 0, 0], load "rgb.png"
844    
845     =cut
846    
847     sub tint($$) {
848     $_[1]->tint ($_[0])
849     }
850    
851 sf-exg 1.82 =item shade $factor, $img
852    
853     Shade the image by the given factor.
854    
855     =cut
856    
857     sub shade($$) {
858     $_[1]->shade ($_[0])
859     }
860    
861 root 1.36 =item contrast $factor, $img
862    
863     =item contrast $r, $g, $b, $img
864    
865     =item contrast $r, $g, $b, $a, $img
866    
867     Adjusts the I<contrast> of an image.
868    
869 root 1.45 The first form applies a single C<$factor> to red, green and blue, the
870     second form applies separate factors to each colour channel, and the last
871     form includes the alpha channel.
872    
873     Values from 0 to 1 lower the contrast, values higher than 1 increase the
874     contrast.
875    
876     Due to limitations in the underlying XRender extension, lowering contrast
877     also reduces brightness, while increasing contrast currently also
878     increases brightness.
879 root 1.38
880 root 1.45 =item brightness $bias, $img
881 root 1.36
882     =item brightness $r, $g, $b, $img
883    
884     =item brightness $r, $g, $b, $a, $img
885    
886 root 1.38 Adjusts the brightness of an image.
887    
888 root 1.45 The first form applies a single C<$bias> to red, green and blue, the
889     second form applies separate biases to each colour channel, and the last
890     form includes the alpha channel.
891    
892     Values less than 0 reduce brightness, while values larger than 0 increase
893     it. Useful range is from -1 to 1 - the former results in a black, the
894     latter in a white picture.
895    
896 sf-exg 1.51 Due to idiosyncrasies in the underlying XRender extension, biases less
897 root 1.45 than zero can be I<very> slow.
898    
899 root 1.75 You can also try the experimental(!) C<muladd> operator.
900    
901 root 1.36 =cut
902 root 1.1
903 root 1.2 sub contrast($$;$$;$) {
904 root 1.7 my $img = pop;
905     my ($r, $g, $b, $a) = @_;
906 root 1.4
907 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
908     $a = 1 if @_ < 4;
909 root 1.4
910 root 1.1 $img = $img->clone;
911 root 1.37 $img->contrast ($r, $g, $b, $a);
912 root 1.1 $img
913     }
914    
915 root 1.2 sub brightness($$;$$;$) {
916 root 1.7 my $img = pop;
917     my ($r, $g, $b, $a) = @_;
918 root 1.4
919 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
920     $a = 1 if @_ < 4;
921 root 1.4
922 root 1.1 $img = $img->clone;
923     $img->brightness ($r, $g, $b, $a);
924     $img
925     }
926    
927 root 1.75 =item muladd $mul, $add, $img # EXPERIMENTAL
928    
929 sf-exg 1.80 First multiplies the pixels by C<$mul>, then adds C<$add>. This can be used
930 root 1.75 to implement brightness and contrast at the same time, with a wider value
931     range than contrast and brightness operators.
932    
933     Due to numerous bugs in XRender implementations, it can also introduce a
934     number of visual artifacts.
935    
936     Example: increase contrast by a factor of C<$c> without changing image
937     brightness too much.
938    
939     muladd $c, (1 - $c) * 0.5, $img
940    
941     =cut
942    
943     sub muladd($$$) {
944     $_[2]->muladd ($_[0], $_[1])
945     }
946    
947 root 1.38 =item blur $radius, $img
948    
949     =item blur $radius_horz, $radius_vert, $img
950    
951     Gaussian-blurs the image with (roughly) C<$radius> pixel radius. The radii
952     can also be specified separately.
953    
954 root 1.39 Blurring is often I<very> slow, at least compared or other
955     operators. Larger blur radii are slower than smaller ones, too, so if you
956     don't want to freeze your screen for long times, start experimenting with
957     low values for radius (<5).
958    
959 root 1.38 =cut
960    
961 root 1.36 sub blur($$;$) {
962     my $img = pop;
963     $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
964     }
965    
966 root 1.84 =item focus_fade $img
967    
968     =item focus_fade $factor, $img
969    
970     =item focus_fade $factor, $color, $img
971    
972     Fades the image by the given factor (and colour) when focus is lost (the
973 root 1.85 same as the C<-fade>/C<-fadecolor> command line options, which also supply
974 root 1.84 the default values for C<factor> and C<$color>. Unlike with C<-fade>, the
975 sf-exg 1.87 C<$factor> is a real value, not a percentage value (that is, 0..1, not
976 root 1.84 0..100).
977    
978     Example: do the right thing when focus fading is requested.
979    
980     focus_fade load "mybg.jpg";
981    
982     =cut
983    
984     sub focus_fade($;$$) {
985     my $img = pop;
986    
987     return $img
988     if FOCUS;
989    
990     my $fade = @_ >= 1 ? $_[0] : defined $self->resource ("fade") ? $self->resource ("fade") * 0.01 : 0;
991     my $color = @_ >= 2 ? $_[1] : $self->resource ("color+" . urxvt::Color_fade);
992    
993     $img = $img->tint ($color) if $color ne "rgb:00/00/00";
994     $img = $img->muladd (1 - $fade, 0) if $fade;
995    
996     $img
997     }
998    
999 root 1.52 =back
1000    
1001     =head2 OTHER STUFF
1002 root 1.38
1003 root 1.56 Anything that didn't fit any of the other categories, even after applying
1004 root 1.52 force and closing our eyes.
1005    
1006 root 1.100 =over
1007 root 1.52
1008 root 1.66 =item keep { ... }
1009 root 1.52
1010 root 1.66 This operator takes a code block as argument, that is, one or more
1011 root 1.52 statements enclosed by braces.
1012    
1013 root 1.68 The trick is that this code block is only evaluated when the outcome
1014     changes - on other calls the C<keep> simply returns the image it computed
1015     previously (yes, it should only be used with images). Or in other words,
1016     C<keep> I<caches> the result of the code block so it doesn't need to be
1017     computed again.
1018    
1019     This can be extremely useful to avoid redoing slow operations - for
1020     example, if your background expression takes the root background, blurs it
1021     and then root-aligns it it would have to blur the root background on every
1022     window move or resize.
1023    
1024     Another example is C<load>, which can be quite slow.
1025 root 1.52
1026 root 1.63 In fact, urxvt itself encloses the whole expression in some kind of
1027 root 1.68 C<keep> block so it only is reevaluated as required.
1028 root 1.63
1029 root 1.68 Putting the blur into a C<keep> block will make sure the blur is only done
1030     once, while the C<rootalign> is still done each time the window moves.
1031 root 1.52
1032 sf-exg 1.73 rootalign keep { blur 10, root }
1033 root 1.52
1034 root 1.63 This leaves the question of how to force reevaluation of the block,
1035     in case the root background changes: If expression inside the block
1036     is sensitive to some event (root background changes, window geometry
1037     changes), then it will be reevaluated automatically as needed.
1038 root 1.38
1039 sf-exg 1.92 =back
1040    
1041     =head1 OLD BACKGROUND IMAGE SETTINGS
1042    
1043     This extension also provides support for the old options/resources and
1044     OSC sequences for setting a background image. These settings are
1045     B<deprecated> and will be removed in future versions.
1046    
1047     =head2 OPTIONS AND RESOURCES
1048    
1049 root 1.100 =over
1050 sf-exg 1.92
1051     =item B<-pixmap> I<file[;oplist]>
1052    
1053     =item B<backgroundPixmap:> I<file[;oplist]>
1054    
1055     Use the specified image file as the window's background and also
1056     optionally specify a colon separated list of operations to modify it.
1057     Note that you may need to quote the C<;> character when using the
1058     command line option, as C<;> is usually a metacharacter in shells.
1059     Supported operations are:
1060    
1061 root 1.100 =over
1062 sf-exg 1.92
1063     =item B<WxH+X+Y>
1064    
1065     sets scale and position. B<"W" / "H"> specify the horizontal/vertical
1066     scale (percent), and B<"X" / "Y"> locate the image centre (percent). A
1067     scale of 0 disables scaling.
1068    
1069     =item B<op=tile>
1070    
1071     enables tiling
1072    
1073     =item B<op=keep-aspect>
1074    
1075     maintain the image aspect ratio when scaling
1076    
1077     =item B<op=root-align>
1078    
1079     use the position of the terminal window relative to the root window as
1080     the image offset, simulating a root window background
1081    
1082     =back
1083    
1084     The default scale and position setting is C<100x100+50+50>.
1085     Alternatively, a predefined set of templates can be used to achieve
1086     the most common setups:
1087    
1088 root 1.100 =over
1089 sf-exg 1.92
1090     =item B<style=tiled>
1091    
1092     the image is tiled with no scaling. Equivalent to 0x0+0+0:op=tile
1093    
1094     =item B<style=aspect-stretched>
1095    
1096     the image is scaled to fill the whole window maintaining the aspect
1097     ratio and centered. Equivalent to 100x100+50+50:op=keep-aspect
1098    
1099     =item B<style=stretched>
1100    
1101     the image is scaled to fill the whole window. Equivalent to 100x100
1102    
1103     =item B<style=centered>
1104    
1105     the image is centered with no scaling. Equivalent to 0x0+50+50
1106    
1107     =item B<style=root-tiled>
1108    
1109     the image is tiled with no scaling and using 'root' positioning.
1110     Equivalent to 0x0:op=tile:op=root-align
1111    
1112     =back
1113    
1114     If multiple templates are specified the last one wins. Note that a
1115     template overrides all the scale, position and operations settings.
1116    
1117     If used in conjunction with pseudo-transparency, the specified image
1118     will be blended over the transparent background using alpha-blending.
1119    
1120     =item B<-tr>|B<+tr>
1121    
1122     =item B<transparent:> I<boolean>
1123    
1124     Turn on/off pseudo-transparency by using the root pixmap as background.
1125    
1126     =item B<-tint> I<colour>
1127    
1128     =item B<tintColor:> I<colour>
1129    
1130     Tint the transparent background with the given colour. Note that a
1131     black tint yields a completely black image while a white tint yields
1132     the image unchanged.
1133    
1134     =item B<-sh> I<number>
1135    
1136     =item B<shading:> I<number>
1137    
1138     Darken (0 .. 99) or lighten (101 .. 200) the transparent background.
1139     A value of 100 means no shading.
1140    
1141     =item B<-blr> I<HxV>
1142    
1143     =item B<blurRadius:> I<HxV>
1144    
1145     Apply gaussian blur with the specified radius to the transparent
1146     background. If a single number is specified, the vertical and
1147     horizontal radii are considered to be the same. Setting one of the
1148     radii to 1 and the other to a large number creates interesting effects
1149     on some backgrounds. The maximum radius value is 128. An horizontal or
1150     vertical radius of 0 disables blurring.
1151    
1152     =back
1153    
1154     =head2 OSC sequences
1155    
1156 root 1.98 This extension will react to the following OSC sequences. Note that
1157 sf-exg 1.99 this extension will not be autoloaded when these are used currently,
1158 root 1.98 so to make urxvt recognize them, you have to enable the C<background>
1159     extension. One way to achieve that is to use the C<--background-expr ''>
1160     command line argument or by specifying an empty C<URxvt.background.expr:>>
1161     resource.
1162    
1163 root 1.100 =over
1164 sf-exg 1.92
1165     =item B<< C<ESC ] 705 ; Pt ST> >> Change transparent background tint colour to B<< C<Pt> >>.
1166    
1167     =item B<< C<ESC ] 20 ; Pt ST> >> Change/Query background image
1168     parameters: the value of B<< C<Pt> >> can be one of the following
1169     commands:
1170    
1171 root 1.100 =over
1172 sf-exg 1.92
1173     =item B<< C<?> >>
1174    
1175     display scale and position in the title
1176    
1177     =item B<< C<;WxH+X+Y> >>
1178    
1179     change scale and/or position
1180    
1181     =item B<< C<FILE;WxH+X+Y> >>
1182    
1183     change background image
1184    
1185     =back
1186    
1187 root 1.38 =cut
1188    
1189 root 1.68 sub keep(&) {
1190 root 1.63 my $id = $_[0]+0;
1191    
1192     local $frame = $self->{frame_cache}{$id} ||= [$frame];
1193    
1194     unless ($frame->[FR_CACHE]) {
1195     $frame->[FR_CACHE] = [ $_[0]() ];
1196    
1197     my $self = $self;
1198     my $frame = $frame;
1199     Scalar::Util::weaken $frame;
1200     $self->compile_frame ($frame, sub {
1201     # clear this frame cache, also for all parents
1202     for (my $frame = $frame; $frame; $frame = $frame->[0]) {
1203     undef $frame->[FR_CACHE];
1204     }
1205    
1206     $self->recalculate;
1207     });
1208 root 1.55 };
1209    
1210     # in scalar context we always return the first original result, which
1211     # is not quite how perl works.
1212     wantarray
1213 root 1.63 ? @{ $frame->[FR_CACHE] }
1214     : $frame->[FR_CACHE][0]
1215 root 1.52 }
1216    
1217 root 1.68 # sub keep_clear() {
1218     # delete $self->{frame_cache};
1219     # }
1220 root 1.36
1221 root 1.15 =back
1222    
1223     =cut
1224    
1225 root 1.1 }
1226    
1227     sub parse_expr {
1228 root 1.98 my ($expr) = @_;
1229    
1230     # an empty expression is valid and represents the default background
1231     if ($expr !~ /\S/) {
1232     $expr = sub {
1233     undef
1234     };
1235     } else {
1236     $expr = eval
1237     "sub {\n"
1238     . "package urxvt::bgdsl;\n"
1239     . "#line 0 'background expression'\n"
1240     . "$expr\n"
1241     . "}";
1242     die if $@;
1243     }
1244    
1245 root 1.1 $expr
1246     }
1247    
1248     # compiles a parsed expression
1249     sub set_expr {
1250     my ($self, $expr) = @_;
1251    
1252 root 1.74 $self->{root} = []; # the outermost frame
1253 root 1.1 $self->{expr} = $expr;
1254     $self->recalculate;
1255     }
1256    
1257 root 1.63 # takes a hash of sensitivity indicators and installs watchers
1258     sub compile_frame {
1259     my ($self, $frame, $cb) = @_;
1260    
1261     my $state = $frame->[urxvt::bgdsl::FR_STATE] ||= {};
1262     my $again = $frame->[urxvt::bgdsl::FR_AGAIN];
1263    
1264     # don't keep stuff alive
1265     Scalar::Util::weaken $state;
1266    
1267     if ($again->{nested}) {
1268     $state->{nested} = 1;
1269     } else {
1270     delete $state->{nested};
1271     }
1272    
1273     if (my $interval = $again->{time}) {
1274     $state->{time} = [$interval, urxvt::timer->new->after ($interval)->interval ($interval)]
1275     if $state->{time}[0] != $interval;
1276    
1277     # callback *might* have changed, although we could just rule that out
1278     $state->{time}[1]->cb (sub {
1279     ++$state->{counter};
1280     $cb->();
1281     });
1282     } else {
1283     delete $state->{time};
1284     }
1285    
1286     if ($again->{position}) {
1287     $state->{position} = $self->on (position_change => $cb);
1288     } else {
1289     delete $state->{position};
1290     }
1291    
1292     if ($again->{size}) {
1293     $state->{size} = $self->on (size_change => $cb);
1294     } else {
1295     delete $state->{size};
1296     }
1297    
1298     if ($again->{rootpmap}) {
1299     $state->{rootpmap} = $self->on (rootpmap_change => $cb);
1300     } else {
1301     delete $state->{rootpmap};
1302     }
1303 root 1.84
1304     if ($again->{focus}) {
1305     $state->{focus} = $self->on (focus_in => $cb, focus_out => $cb);
1306     } else {
1307     delete $state->{focus};
1308     }
1309 root 1.63 }
1310    
1311 root 1.1 # evaluate the current bg expression
1312     sub recalculate {
1313 root 1.33 my ($arg_self) = @_;
1314 root 1.1
1315 root 1.10 # rate limit evaluation
1316    
1317 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
1318     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
1319     $arg_self->recalculate;
1320 root 1.9 });
1321 root 1.12 return;
1322 root 1.9 }
1323    
1324 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
1325 root 1.9
1326 root 1.96 unless ($arg_self->has_render) {
1327     warn "background extension needs RENDER extension 0.10 or higher, ignoring background-expr.\n";
1328     return;
1329     }
1330    
1331 root 1.10 # set environment to evaluate user expression
1332 root 1.6
1333 root 1.63 local $self = $arg_self;
1334     local $HOME = $ENV{HOME};
1335 root 1.74 local $frame = $self->{root};
1336 root 1.1
1337 root 1.63 ($x, $y, $w, $h) = $self->background_geometry ($self->{border});
1338 root 1.84 $focus = $self->focus;
1339 root 1.22
1340 root 1.10 # evaluate user expression
1341    
1342 root 1.63 my @img = eval { $self->{expr}->() };
1343 root 1.61 die $@ if $@;
1344 root 1.63 die "background-expr did not return anything.\n" unless @img;
1345 root 1.1
1346 root 1.98 if ($img[0]) {
1347     die "background-expr: expected image(s), got something else.\n"
1348     if grep { !UNIVERSAL::isa $_, "urxvt::img" } @img;
1349 root 1.10
1350 root 1.98 my $img = urxvt::bgdsl::merge @img;
1351 root 1.55
1352 root 1.101 $frame->[urxvt::bgdsl::FR_AGAIN]{size} = 1
1353 root 1.98 if $img->repeat_mode != urxvt::RepeatNormal;
1354 root 1.9
1355 root 1.98 # if the expression is sensitive to external events, prepare reevaluation then
1356     $self->compile_frame ($frame, sub { $arg_self->recalculate });
1357    
1358     # clear stuff we no longer need
1359 root 1.10
1360 root 1.63 # unless (%{ $frame->[FR_STATE] }) {
1361     # delete $self->{state};
1362     # delete $self->{expr};
1363     # }
1364 root 1.5
1365 root 1.98 # set background pixmap
1366    
1367     $self->set_background ($img, $self->{border});
1368     } else {
1369     $self->clr_background;
1370     }
1371 root 1.1
1372 root 1.89 $self->scr_recolor (0);
1373 root 1.1 $self->want_refresh;
1374     }
1375    
1376 sf-exg 1.92 sub old_bg_opts {
1377     my ($self, $arg) = @_;
1378    
1379     $arg or return;
1380    
1381     my @str = split /;/, $arg;
1382    
1383     return unless $str[0] or $self->{bg_opts}->{path};
1384    
1385     my $bg_opts = $self->{bg_opts};
1386    
1387     if ($str[0]) {
1388 root 1.97 $bg_opts->{tile} = 0;
1389 sf-exg 1.92 $bg_opts->{keep_aspect} = 0;
1390 root 1.97 $bg_opts->{root_align} = 0;
1391     $bg_opts->{h_scale} = $bg_opts->{v_scale} = 100;
1392     $bg_opts->{h_align} = $bg_opts->{v_align} = 50;
1393     $bg_opts->{path} = $str[0];
1394 sf-exg 1.92 }
1395    
1396     my @oplist = split /:/, $str[1];
1397    
1398     for (@oplist) {
1399     if (/style=tiled/i) {
1400     $bg_opts->{tile} = 1;
1401     $bg_opts->{keep_aspect} = 0;
1402     $bg_opts->{root_align} = 0;
1403     $bg_opts->{h_scale} = $bg_opts->{v_scale} = 0;
1404     $bg_opts->{h_align} = $bg_opts->{v_align} = 0;
1405     } elsif (/style=aspect-stretched/i) {
1406     $bg_opts->{tile} = 0;
1407     $bg_opts->{keep_aspect} = 1;
1408     $bg_opts->{root_align} = 0;
1409     $bg_opts->{h_scale} = $bg_opts->{v_scale} = 100;
1410     $bg_opts->{h_align} = $bg_opts->{v_align} = 50;
1411     } elsif (/style=stretched/i) {
1412     $bg_opts->{tile} = 0;
1413     $bg_opts->{keep_aspect} = 0;
1414     $bg_opts->{root_align} = 0;
1415     $bg_opts->{h_scale} = $bg_opts->{v_scale} = 100;
1416     $bg_opts->{h_align} = $bg_opts->{v_align} = 50;
1417     } elsif (/style=centered/i) {
1418     $bg_opts->{tile} = 0;
1419     $bg_opts->{keep_aspect} = 0;
1420     $bg_opts->{root_align} = 0;
1421     $bg_opts->{h_scale} = $bg_opts->{v_scale} = 0;
1422     $bg_opts->{h_align} = $bg_opts->{v_align} = 50;
1423     } elsif (/style=root-tiled/i) {
1424     $bg_opts->{tile} = 1;
1425     $bg_opts->{keep_aspect} = 0;
1426     $bg_opts->{root_align} = 1;
1427     $bg_opts->{h_scale} = $bg_opts->{v_scale} = 0;
1428     $bg_opts->{h_align} = $bg_opts->{v_align} = 0;
1429     } elsif (/op=tile/i) {
1430     $bg_opts->{tile} = 1;
1431 root 1.94 } elsif (/op=keep-aspect/i) {
1432 sf-exg 1.92 $bg_opts->{keep_aspect} = 1;
1433 root 1.94 } elsif (/op=root-align/i) {
1434 sf-exg 1.92 $bg_opts->{root_align} = 1;
1435     } elsif (/^ =? ([0-9]+)? (?:[xX] ([0-9]+))? ([+-][0-9]+)? ([+-][0-9]+)? $/x) {
1436     my ($w, $h, $x, $y) = ($1, $2, $3, $4);
1437    
1438     if ($str[0]) {
1439     $w = $h unless defined $w;
1440     $h = $w unless defined $h;
1441     $y = $x unless defined $y;
1442     }
1443    
1444     $bg_opts->{h_scale} = $w if defined $w;
1445     $bg_opts->{v_scale} = $h if defined $h;
1446     $bg_opts->{h_align} = $x if defined $x;
1447     $bg_opts->{v_align} = $y if defined $y;
1448     }
1449     }
1450     }
1451    
1452 root 1.97 # helper function, quote string as perl without allowing
1453     # any code execution or other shenanigans. does not
1454     # support binary NULs in string.
1455     sub q0 {
1456     (my $str = shift) =~ s/\x00//g; # make sure there really aren't any embedded NULs
1457     "q\x00$str\x00"
1458     }
1459    
1460 sf-exg 1.92 sub old_bg_expr {
1461     my ($self) = @_;
1462    
1463     my $expr;
1464    
1465     my $bg_opts = $self->{bg_opts};
1466    
1467 sf-exg 1.93 if ($bg_opts->{root} =~ /^\s*(?:true|yes|on|1)\s*$/i) {
1468 sf-exg 1.92 $expr .= "tile (";
1469    
1470     my $shade = $bg_opts->{shade};
1471    
1472     if ($shade) {
1473     $shade = List::Util::min $shade, 200;
1474     $shade = List::Util::max $shade, -100;
1475     $shade = 200 - (100 + $shade) if $shade < 0;
1476    
1477     $shade = $shade * 0.01 - 1;
1478     $expr .= "shade $shade, ";
1479     }
1480    
1481     my $tint = $bg_opts->{tint};
1482    
1483     if ($tint) {
1484 root 1.97 $tint = q0 $tint;
1485     $expr .= "tint $tint,";
1486 sf-exg 1.92 }
1487    
1488     my $blur = $bg_opts->{blur};
1489    
1490     if ($blur and $blur =~ /^ =? ([0-9]+)? (?:[xX] ([0-9]+))? $/x) {
1491     my $hr = defined $1 ? $1 : 1;
1492     my $vr = defined $2 ? $2 : $hr;
1493    
1494     if ($hr != 0 and $vr != 0) {
1495     $expr .= "blur $hr, $vr, ";
1496     }
1497     }
1498    
1499     $expr .= "rootalign root)";
1500     }
1501    
1502     if ($bg_opts->{path}) {
1503     my $file_expr;
1504     my $h_scale = $bg_opts->{h_scale} * 0.01;
1505     my $v_scale = $bg_opts->{v_scale} * 0.01;
1506     my $h_align = $bg_opts->{h_align} * 0.01;
1507     my $v_align = $bg_opts->{v_align} * 0.01;
1508    
1509     if (!$bg_opts->{tile}) {
1510     $file_expr .= "pad (";
1511     } else {
1512     $file_expr .= "tile (";
1513     }
1514    
1515     if ($bg_opts->{root_align}) {
1516     $file_expr .= "rootalign ";
1517     } else {
1518     $file_expr .= "align $h_align, $v_align, ";
1519     }
1520    
1521     if ($h_scale != 0 and $v_scale != 0) {
1522     my $op = $bg_opts->{keep_aspect} ? "fit" : "resize";
1523     $file_expr .= "$op TW * $h_scale, TH * $v_scale, ";
1524     }
1525    
1526 root 1.97 my $path = q0 $bg_opts->{path};
1527    
1528     $file_expr .= "keep { load $path })";
1529 sf-exg 1.92
1530     if ($expr) {
1531     $expr .= ", tint (\"[50]white\", $file_expr)";
1532     } else {
1533     $expr = $file_expr;
1534     }
1535     }
1536    
1537     $expr
1538     }
1539    
1540     sub on_osc_seq {
1541     my ($self, $op, $arg) = @_;
1542    
1543     $self->{bg_opts} or return;
1544    
1545 root 1.95 $op =~ /^(?:20|705)$/ or return;
1546 sf-exg 1.92
1547     if ($op eq "20") {
1548     if ($arg eq "?") {
1549     my $h_scale = $self->{bg_opts}->{h_scale};
1550     my $v_scale = $self->{bg_opts}->{v_scale};
1551     my $h_align = $self->{bg_opts}->{h_align};
1552     my $v_align = $self->{bg_opts}->{v_align};
1553     $self->cmd_parse ("\033]2;[${h_scale}x${v_scale}+${h_align}+${v_align}]\007");
1554     } else {
1555     $self->old_bg_opts ($arg);
1556     my $expr = $self->old_bg_expr;
1557     $self->set_expr (parse_expr $expr) if $expr;
1558     }
1559     } elsif ($op eq "705") {
1560     $self->{bg_opts}->{tint} = $arg;
1561     my $expr = $self->old_bg_expr;
1562     $self->set_expr (parse_expr $expr) if $expr;
1563     }
1564    
1565     1
1566     }
1567    
1568     sub find_resource {
1569 sf-exg 1.93 my ($self, $res, $opt) = @_;
1570 sf-exg 1.92
1571 sf-exg 1.93 my $v = $self->x_resource ($opt);
1572     $v = $self->x_resource ($res) unless defined $v;
1573 sf-exg 1.92
1574     $v
1575     }
1576    
1577 root 1.1 sub on_start {
1578     my ($self) = @_;
1579    
1580 sf-exg 1.92 my $expr = $self->x_resource ("%.expr");
1581    
1582     if (!$expr) {
1583     $self->{bg_opts} = { h_scale => 100, v_scale => 100,
1584     h_align => 50, v_align => 50 };
1585    
1586 root 1.97 $self->{bg_opts}{shade} = $self->find_resource ("shading", "sh");
1587     $self->{bg_opts}{tint} = $self->find_resource ("tintColor", "tint");
1588     $self->{bg_opts}{blur} = $self->find_resource ("blurRadius", "blr");
1589     $self->{bg_opts}{root} = $self->find_resource ("transparent", "tr");
1590 sf-exg 1.92
1591     $self->old_bg_opts ($self->find_resource ("backgroundPixmap", "pixmap"));
1592     $expr = $self->old_bg_expr;
1593     }
1594    
1595 root 1.33 $self->set_expr (parse_expr $expr);
1596 root 1.47 $self->{border} = $self->x_resource_boolean ("%.border");
1597 root 1.1
1598 root 1.47 $MIN_INTERVAL = $self->x_resource ("%.interval");
1599 root 1.46
1600 root 1.1 ()
1601     }
1602