ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.68
Committed: Sun Jul 1 21:47:07 2012 UTC (11 years, 10 months ago) by root
Branch: MAIN
Changes since 1.67: +27 -29 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #! perl
2    
3 root 1.16 #:META:X_RESOURCE:%.expr:string:background expression
4 root 1.46 #:META:X_RESOURCE:%.border:boolean:respect the terminal border
5     #:META:X_RESOURCE:%.interval:seconds:minimum time between updates
6 root 1.33
7 root 1.41 =head1 NAME
8 root 1.33
9 root 1.41 background - manage terminal background
10    
11     =head1 SYNOPSIS
12 root 1.33
13 root 1.36 urxvt --background-expr 'background expression'
14     --background-border
15 root 1.46 --background-interval seconds
16 root 1.33
17 root 1.41 =head1 DESCRIPTION
18 root 1.33
19 root 1.36 This extension manages the terminal background by creating a picture that
20     is behind the text, replacing the normal background colour.
21    
22     It does so by evaluating a Perl expression that I<calculates> the image on
23     the fly, for example, by grabbing the root background or loading a file.
24    
25     While the full power of Perl is available, the operators have been design
26     to be as simple as possible.
27    
28     For example, to load an image and scale it to the window size, you would
29     use:
30    
31 root 1.64 urxvt --background-expr 'scale keep { load "/path/to/mybg.png" }'
32 root 1.36
33     Or specified as a X resource:
34    
35 root 1.64 URxvt.background-expr: scale keep { load "/path/to/mybg.png" }
36 root 1.36
37 root 1.41 =head1 THEORY OF OPERATION
38 root 1.36
39     At startup, just before the window is mapped for the first time, the
40     expression is evaluated and must yield an image. The image is then
41     extended as necessary to cover the whole terminal window, and is set as a
42     background pixmap.
43    
44     If the image contains an alpha channel, then it will be used as-is in
45     visuals that support alpha channels (for example, for a compositing
46     manager). In other visuals, the terminal background colour will be used to
47     replace any transparency.
48    
49     When the expression relies, directly or indirectly, on the window size,
50     position, the root pixmap, or a timer, then it will be remembered. If not,
51     then it will be removed.
52    
53     If any of the parameters that the expression relies on changes (when the
54     window is moved or resized, its position or size changes; when the root
55     pixmap is replaced by another one the root background changes; or when the
56     timer elapses), then the expression will be evaluated again.
57    
58 root 1.64 For example, an expression such as C<scale keep { load "$HOME/mybg.png"
59     }> scales the image to the window size, so it relies on the window size
60     and will be reevaluated each time it is changed, but not when it moves for
61 root 1.36 example. That ensures that the picture always fills the terminal, even
62 sf-exg 1.51 after its size changes.
63 root 1.36
64 root 1.41 =head2 EXPRESSIONS
65 root 1.36
66     Expressions are normal Perl expressions, in fact, they are Perl blocks -
67     which means you could use multiple lines and statements:
68    
69 root 1.64 scale keep {
70     again 3600;
71     if (localtime now)[6]) {
72     return load "$HOME/weekday.png";
73     } else {
74     return load "$HOME/sunday.png";
75     }
76 root 1.36 }
77    
78 root 1.68 This inner expression is evaluated once per hour (and whenever the
79     temrinal window is resized). It sets F<sunday.png> as background on
80     Sundays, and F<weekday.png> on all other days.
81 root 1.36
82     Fortunately, we expect that most expressions will be much simpler, with
83     little Perl knowledge needed.
84    
85     Basically, you always start with a function that "generates" an image
86     object, such as C<load>, which loads an image from disk, or C<root>, which
87     returns the root window background image:
88    
89     load "$HOME/mypic.png"
90    
91     The path is usually specified as a quoted string (the exact rules can be
92     found in the L<perlop> manpage). The F<$HOME> at the beginning of the
93     string is expanded to the home directory.
94    
95     Then you prepend one or more modifiers or filtering expressions, such as
96     C<scale>:
97    
98     scale load "$HOME/mypic.png"
99    
100     Just like a mathematical expression with functions, you should read these
101     expressions from right to left, as the C<load> is evaluated first, and
102     its result becomes the argument to the C<scale> function.
103    
104     Many operators also allow some parameters preceding the input image
105     that modify its behaviour. For example, C<scale> without any additional
106     arguments scales the image to size of the terminal window. If you specify
107 root 1.43 an additional argument, it uses it as a scale factor (multiply by 100 to
108     get a percentage):
109 root 1.36
110 root 1.43 scale 2, load "$HOME/mypic.png"
111 root 1.36
112     This enlarges the image by a factor of 2 (200%). As you can see, C<scale>
113     has now two arguments, the C<200> and the C<load> expression, while
114     C<load> only has one argument. Arguments are separated from each other by
115     commas.
116    
117     Scale also accepts two arguments, which are then separate factors for both
118     horizontal and vertical dimensions. For example, this halves the image
119     width and doubles the image height:
120    
121 root 1.43 scale 0.5, 2, load "$HOME/mypic.png"
122 root 1.36
123 root 1.68 IF you try out these expressions, you might suffer from some sluggishness,
124     because each time the terminal is resized, it loads the PNG image agin
125     and scales it. Scaling is usually fast (and unavoidable), but loading the
126     image can be quite time consuming. This is where C<keep> comes in handy:
127 root 1.39
128 root 1.64 scale 0.5, 2, keep { load "$HOME/mypic.png" }
129 root 1.39
130 root 1.64 The C<keep> operator executes all the statements inside the braces only
131     once, or when it thinks the outcome might change. In other cases it
132     returns the last value computed by the brace block.
133 root 1.39
134 root 1.64 This means that the C<load> is only executed once, which makes it much
135 sf-exg 1.65 faster, but also means that more memory is being used, because the loaded
136 root 1.64 image must be kept in memory at all times. In this expression, the
137     trade-off is likely worth it.
138 root 1.39
139 root 1.64 But back to effects: Other effects than scaling are also readily
140     available, for example, you can tile the image to fill the whole window,
141     instead of resizing it:
142 root 1.39
143 root 1.64 tile keep { load "$HOME/mypic.png" }
144 root 1.39
145 root 1.64 In fact, images returned by C<load> are in C<tile> mode by default, so the
146     C<tile> operator is kind of superfluous.
147 root 1.39
148 root 1.64 Another common effect is to mirror the image, so that the same edges
149     touch:
150 root 1.36
151 root 1.64 mirror keep { load "$HOME/mypic.png" }
152 root 1.36
153 root 1.64 Another common background expression is:
154 root 1.63
155 root 1.64 rootalign root
156 root 1.39
157 root 1.64 This one first takes a snapshot of the screen background image, and then
158 sf-exg 1.65 moves it to the upper left corner of the screen (as opposed to the upper
159 root 1.64 left corner of the terminal window)- the result is pseudo-transparency:
160     the image seems to be static while the window is moved around.
161    
162     =head2 CACHING AND SENSITIVITY
163    
164     Since some operations (such as C<load> and C<blur>) can take a long time,
165     caching results can be very important for a smooth operation. Caching can
166     also be useful to reduce memory usage, though, for example, when an image
167     is cached by C<load>, it could be shared by multiple terminal windows
168     running inside urxvtd.
169    
170     =head3 C<keep { ... }> caching
171    
172     The most important way to cache expensive operations is to use C<keep {
173     ... }>. The C<keep> operator takes a block of multiple statements enclosed
174     by C<{}> and keeps the return value in memory.
175    
176     An expression can be "sensitive" to various external events, such as
177 sf-exg 1.65 scaling or moving the window, root background changes and timers. Simply
178 sf-exg 1.67 using an expression (such as C<scale> without parameters) that depends on
179 root 1.64 certain changing values (called "variables"), or using those variables
180     directly, will make an expression sensitive to these events - for example,
181     using C<scale> or C<TW> will make the expression sensitive to the terminal
182     size, and thus to resizing events.
183 root 1.39
184 root 1.64 When such an event happens, C<keep> will automatically trigger a
185     reevaluation of the whole expression with the new value of the expression.
186 root 1.39
187 root 1.64 C<keep> is most useful for expensive operations, such as C<blur>:
188 root 1.39
189 root 1.68 rootalign keep { blur 20, root }
190 root 1.39
191 root 1.64 This makes a blurred copy of the root background once, and on subsequent
192     calls, just root-aligns it. Since C<blur> is usually quite slow and
193     C<rootalign> is quite fast, this trades extra memory (for the cached
194     blurred pixmap) with speed (blur only needs to be redone when root
195     changes).
196 root 1.39
197 root 1.64 =head3 C<load> caching
198 root 1.36
199 root 1.64 The C<load> operator itself does not keep images in memory, but as long as
200     the image is still in memory, C<load> will use the in-memory image instead
201     of loading it freshly from disk.
202 root 1.63
203 root 1.64 That means that this expression:
204 root 1.63
205 root 1.64 keep { load "$HOME/path..." }
206 root 1.63
207 root 1.64 Not only caches the image in memory, other terminal instances that try to
208     C<load> it can reuse that in-memory copy.
209 root 1.63
210 root 1.41 =head1 REFERENCE
211 root 1.33
212 root 1.41 =head2 COMMAND LINE SWITCHES
213 root 1.36
214     =over 4
215    
216     =item --background-expr perl-expression
217    
218     Specifies the Perl expression to evaluate.
219    
220     =item --background-border
221    
222     By default, the expression creates an image that fills the full window,
223     overwriting borders and any other areas, such as the scrollbar.
224    
225     Specifying this flag changes the behaviour, so that the image only
226     replaces the background of the character area.
227    
228 root 1.46 =item --background-interval seconds
229    
230 sf-exg 1.51 Since some operations in the underlying XRender extension can effectively
231 root 1.46 freeze your X-server for prolonged time, this extension enforces a minimum
232     time between updates, which is normally about 0.1 seconds.
233    
234     If you want to do updates more often, you can decrease this safety
235     interval with this switch.
236    
237 root 1.36 =back
238    
239 root 1.33 =cut
240 root 1.12
241 root 1.52 our %_IMG_CACHE;
242 root 1.36 our $HOME;
243 root 1.63 our ($self, $frame);
244 root 1.29 our ($x, $y, $w, $h);
245 root 1.3
246 root 1.16 # enforce at least this interval between updates
247 root 1.46 our $MIN_INTERVAL = 6/59.951;
248 root 1.9
249 root 1.1 {
250     package urxvt::bgdsl; # background language
251    
252 root 1.63 sub FR_PARENT() { 0 } # parent frame, if any - must be #0
253     sub FR_CACHE () { 1 } # cached values
254     sub FR_AGAIN () { 2 } # what this expr is sensitive to
255     sub FR_STATE () { 3 } # watchers etc.
256    
257 root 1.43 use List::Util qw(min max sum shuffle);
258    
259 root 1.15 =head2 PROVIDERS/GENERATORS
260    
261 root 1.31 These functions provide an image, by loading it from disk, grabbing it
262 sf-exg 1.32 from the root screen or by simply generating it. They are used as starting
263 root 1.31 points to get an image you can play with.
264    
265 root 1.15 =over 4
266    
267     =item load $path
268    
269 root 1.29 Loads the image at the given C<$path>. The image is set to plane tiling
270     mode.
271    
272 sf-exg 1.65 If the image is already in memory (e.g. because another terminal instance
273 root 1.64 uses it), then the in-memory copy us returned instead.
274 root 1.54
275 root 1.64 =item load_uc $path
276    
277     Load uncached - same as load, but does not cache the image, which means it
278     is I<always> loaded from the filesystem again.
279 root 1.29
280 root 1.15 =cut
281    
282 root 1.64 sub load_uc($) {
283     $self->new_img_from_file ($path)
284     }
285    
286 root 1.63 sub load($) {
287 root 1.54 my ($path) = @_;
288    
289     $_IMG_CACHE{$path} || do {
290 root 1.64 my $img = load_uc $path;
291 root 1.54 Scalar::Util::weaken ($_IMG_CACHE{$path} = $img);
292     $img
293     }
294     }
295    
296 root 1.31 =item root
297    
298     Returns the root window pixmap, that is, hopefully, the background image
299 root 1.62 of your screen.
300 root 1.31
301     This function makes your expression root sensitive, that means it will be
302     reevaluated when the bg image changes.
303    
304     =cut
305    
306 root 1.2 sub root() {
307 root 1.63 $frame->[FR_AGAIN]{rootpmap} = 1;
308 root 1.52 $self->new_img_from_root
309 root 1.1 }
310    
311 root 1.31 =item solid $colour
312    
313     =item solid $width, $height, $colour
314    
315     Creates a new image and completely fills it with the given colour. The
316     image is set to tiling mode.
317    
318 root 1.40 If C<$width> and C<$height> are omitted, it creates a 1x1 image, which is
319 root 1.31 useful for solid backgrounds or for use in filtering effects.
320    
321     =cut
322    
323 root 1.42 sub solid($;$$) {
324 root 1.31 my $colour = pop;
325    
326 root 1.59 my $img = $self->new_img (urxvt::PictStandardARGB32, 0, 0, $_[0] || 1, $_[1] || 1);
327 root 1.31 $img->fill ($colour);
328 root 1.15 $img
329     }
330    
331 root 1.45 =item clone $img
332 root 1.31
333 root 1.45 Returns an exact copy of the image. This is useful if you want to have
334     multiple copies of the same image to apply different effects to.
335 root 1.31
336 root 1.20 =cut
337    
338 root 1.45 sub clone($) {
339     $_[0]->clone
340 root 1.20 }
341    
342 root 1.56 =item merge $img ...
343    
344 root 1.57 Takes any number of images and merges them together, creating a single
345 root 1.62 image containing them all. The tiling mode of the first image is used as
346 sf-exg 1.65 the tiling mode of the resulting image.
347 root 1.56
348 root 1.61 This function is called automatically when an expression returns multiple
349     images.
350    
351 root 1.56 =cut
352    
353     sub merge(@) {
354 root 1.61 return $_[0] unless $#_;
355    
356 root 1.58 # rather annoyingly clumsy, but optimisation is for another time
357    
358 root 1.59 my $x0 = +1e9;
359     my $y0 = +1e9;
360 root 1.58 my $x1 = -1e9;
361     my $y1 = -1e9;
362    
363     for (@_) {
364     my ($x, $y, $w, $h) = $_->geometry;
365    
366     $x0 = $x if $x0 > $x;
367     $y0 = $y if $y0 > $y;
368    
369     $x += $w;
370     $y += $h;
371    
372 root 1.59 $x1 = $x if $x1 < $x;
373     $y1 = $y if $y1 < $y;
374 root 1.58 }
375    
376 root 1.59 my $base = $self->new_img (urxvt::PictStandardARGB32, $x0, $y0, $x1 - $x0, $y1 - $y0);
377 root 1.62 $base->repeat_mode ($_[0]->repeat_mode);
378 root 1.58 $base->fill ([0, 0, 0, 0]);
379    
380 root 1.59 $base->draw ($_)
381 root 1.58 for @_;
382    
383     $base
384 root 1.56 }
385    
386 root 1.28 =head2 TILING MODES
387    
388     The following operators modify the tiling mode of an image, that is, the
389     way that pixels outside the image area are painted when the image is used.
390 root 1.15
391     =over 4
392    
393 root 1.28 =item tile $img
394    
395     Tiles the whole plane with the image and returns this new image - or in
396     other words, it returns a copy of the image in plane tiling mode.
397    
398 root 1.34 Example: load an image and tile it over the background, without
399     resizing. The C<tile> call is superfluous because C<load> already defaults
400     to tiling mode.
401    
402     tile load "mybg.png"
403    
404 root 1.28 =item mirror $img
405    
406     Similar to tile, but reflects the image each time it uses a new copy, so
407     that top edges always touch top edges, right edges always touch right
408     edges and so on (with normal tiling, left edges always touch right edges
409     and top always touch bottom edges).
410    
411 root 1.36 Example: load an image and mirror it over the background, avoiding sharp
412 root 1.34 edges at the image borders at the expense of mirroring the image itself
413    
414     mirror load "mybg.png"
415    
416 root 1.28 =item pad $img
417    
418     Takes an image and modifies it so that all pixels outside the image area
419     become transparent. This mode is most useful when you want to place an
420     image over another image or the background colour while leaving all
421     background pixels outside the image unchanged.
422    
423 root 1.36 Example: load an image and display it in the upper left corner. The rest
424 sf-exg 1.51 of the space is left "empty" (transparent or whatever your compositor does
425 root 1.34 in alpha mode, else background colour).
426    
427     pad load "mybg.png"
428    
429 root 1.28 =item extend $img
430    
431     Extends the image over the whole plane, using the closest pixel in the
432 sf-exg 1.51 area outside the image. This mode is mostly useful when you use more complex
433 root 1.28 filtering operations and want the pixels outside the image to have the
434     same values as the pixels near the edge.
435    
436 root 1.34 Example: just for curiosity, how does this pixel extension stuff work?
437    
438     extend move 50, 50, load "mybg.png"
439    
440 root 1.15 =cut
441    
442 root 1.28 sub pad($) {
443     my $img = $_[0]->clone;
444     $img->repeat_mode (urxvt::RepeatNone);
445     $img
446     }
447    
448     sub tile($) {
449     my $img = $_[0]->clone;
450     $img->repeat_mode (urxvt::RepeatNormal);
451     $img
452     }
453    
454     sub mirror($) {
455     my $img = $_[0]->clone;
456     $img->repeat_mode (urxvt::RepeatReflect);
457     $img
458     }
459 root 1.4
460 root 1.28 sub extend($) {
461 root 1.24 my $img = $_[0]->clone;
462 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
463 root 1.24 $img
464     }
465    
466 root 1.28 =back
467    
468 root 1.45 =head2 VARIABLE VALUES
469 root 1.28
470 root 1.45 The following functions provide variable data such as the terminal window
471     dimensions. They are not (Perl-) variables, they just return stuff that
472     varies. Most of them make your expression sensitive to some events, for
473     example using C<TW> (terminal width) means your expression is evaluated
474     again when the terminal is resized.
475 root 1.28
476     =over 4
477    
478 root 1.45 =item TX
479    
480     =item TY
481    
482     Return the X and Y coordinates of the terminal window (the terminal
483     window is the full window by default, and the character area only when in
484     border-respect mode).
485    
486     Using these functions make your expression sensitive to window moves.
487    
488     These functions are mainly useful to align images to the root window.
489    
490     Example: load an image and align it so it looks as if anchored to the
491 root 1.64 background (that's exactly what C<rootalign> does btw.):
492 root 1.45
493 root 1.64 move -TX, -TY, keep { load "mybg.png" }
494 root 1.45
495     =item TW
496    
497     Return the width (C<TW>) and height (C<TH>) of the terminal window (the
498     terminal window is the full window by default, and the character area only
499     when in border-respect mode).
500    
501     Using these functions make your expression sensitive to window resizes.
502    
503     These functions are mainly useful to scale images, or to clip images to
504     the window size to conserve memory.
505    
506     Example: take the screen background, clip it to the window size, blur it a
507     bit, align it to the window position and use it as background.
508    
509 root 1.64 clip move -TX, -TY, keep { blur 5, root }
510 root 1.45
511     =cut
512    
513 root 1.63 sub TX() { $frame->[FR_AGAIN]{position} = 1; $x }
514     sub TY() { $frame->[FR_AGAIN]{position} = 1; $y }
515     sub TW() { $frame->[FR_AGAIN]{size} = 1; $w }
516     sub TH() { $frame->[FR_AGAIN]{size} = 1; $h }
517 root 1.45
518     =item now
519    
520     Returns the current time as (fractional) seconds since the epoch.
521    
522     Using this expression does I<not> make your expression sensitive to time,
523     but the next two functions do.
524    
525     =item again $seconds
526    
527     When this function is used the expression will be reevaluated again in
528     C<$seconds> seconds.
529    
530     Example: load some image and rotate it according to the time of day (as if it were
531     the hour pointer of a clock). Update this image every minute.
532    
533 root 1.64 again 60;
534     rotate 50, 50, (now % 86400) * -72 / 8640, scale keep { load "myclock.png" }
535 root 1.28
536 root 1.45 =item counter $seconds
537    
538     Like C<again>, but also returns an increasing counter value, starting at
539     0, which might be useful for some simple animation effects.
540 root 1.28
541     =cut
542    
543 root 1.45 sub now() { urxvt::NOW }
544    
545     sub again($) {
546 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
547 root 1.45 }
548    
549     sub counter($) {
550 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
551     $frame->[FR_STATE]{counter} + 0
552 root 1.28 }
553    
554 root 1.45 =back
555    
556     =head2 SHAPE CHANGING OPERATORS
557    
558     The following operators modify the shape, size or position of the image.
559    
560     =over 4
561    
562 root 1.28 =item clip $img
563    
564     =item clip $width, $height, $img
565    
566     =item clip $x, $y, $width, $height, $img
567    
568     Clips an image to the given rectangle. If the rectangle is outside the
569     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
570     larger than the image, then the tiling mode defines how the extra pixels
571     will be filled.
572    
573     If C<$x> an C<$y> are missing, then C<0> is assumed for both.
574    
575     If C<$width> and C<$height> are missing, then the window size will be
576     assumed.
577    
578     Example: load an image, blur it, and clip it to the window size to save
579     memory.
580    
581 root 1.64 clip keep { blur 10, load "mybg.png" }
582 root 1.28
583     =cut
584    
585 root 1.20 sub clip($;$$;$$) {
586 root 1.7 my $img = pop;
587 root 1.30 my $h = pop || TH;
588     my $w = pop || TW;
589 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
590 root 1.4 }
591    
592 root 1.28 =item scale $img
593    
594 root 1.43 =item scale $size_factor, $img
595 root 1.28
596 root 1.43 =item scale $width_factor, $height_factor, $img
597 root 1.28
598 root 1.43 Scales the image by the given factors in horizontal
599     (C<$width>) and vertical (C<$height>) direction.
600 root 1.28
601 root 1.43 If only one factor is give, it is used for both directions.
602 root 1.28
603 root 1.43 If no factors are given, scales the image to the window size without
604 root 1.28 keeping aspect.
605    
606     =item resize $width, $height, $img
607    
608     Resizes the image to exactly C<$width> times C<$height> pixels.
609    
610 root 1.43 =item fit $img
611    
612     =item fit $width, $height, $img
613    
614     Fits the image into the given C<$width> and C<$height> without changing
615     aspect, or the terminal size. That means it will be shrunk or grown until
616     the whole image fits into the given area, possibly leaving borders.
617    
618     =item cover $img
619    
620     =item cover $width, $height, $img
621    
622     Similar to C<fit>, but shrinks or grows until all of the area is covered
623     by the image, so instead of potentially leaving borders, it will cut off
624     image data that doesn't fit.
625    
626 root 1.28 =cut
627    
628 root 1.33 sub scale($;$;$) {
629 root 1.28 my $img = pop;
630    
631 root 1.43 @_ == 2 ? $img->scale ($_[0] * $img->w, $_[1] * $img->h)
632     : @_ ? $img->scale ($_[0] * $img->w, $_[0] * $img->h)
633 root 1.30 : $img->scale (TW, TH)
634 root 1.28 }
635    
636 root 1.2 sub resize($$$) {
637 root 1.7 my $img = pop;
638     $img->scale ($_[0], $_[1])
639 root 1.1 }
640    
641 root 1.43 sub fit($;$$) {
642     my $img = pop;
643     my $w = ($_[0] || TW) / $img->w;
644     my $h = ($_[1] || TH) / $img->h;
645     scale +(min $w, $h), $img
646     }
647    
648     sub cover($;$$) {
649     my $img = pop;
650     my $w = ($_[0] || TW) / $img->w;
651     my $h = ($_[1] || TH) / $img->h;
652     scale +(max $w, $h), $img
653     }
654    
655 root 1.36 =item move $dx, $dy, $img
656    
657     Moves the image by C<$dx> pixels in the horizontal, and C<$dy> pixels in
658     the vertical.
659    
660     Example: move the image right by 20 pixels and down by 30.
661    
662     move 20, 30, ...
663    
664 root 1.46 =item align $xalign, $yalign, $img
665    
666     Aligns the image according to a factor - C<0> means the image is moved to
667     the left or top edge (for C<$xalign> or C<$yalign>), C<0.5> means it is
668     exactly centered and C<1> means it touches the right or bottom edge.
669    
670     Example: remove any visible border around an image, center it vertically but move
671     it to the right hand side.
672    
673     align 1, 0.5, pad $img
674    
675 root 1.44 =item center $img
676    
677     =item center $width, $height, $img
678    
679     Centers the image, i.e. the center of the image is moved to the center of
680     the terminal window (or the box specified by C<$width> and C<$height> if
681     given).
682    
683 root 1.46 Example: load an image and center it.
684    
685 root 1.64 center keep { pad load "mybg.png" }
686 root 1.46
687 root 1.36 =item rootalign $img
688    
689     Moves the image so that it appears glued to the screen as opposed to the
690     window. This gives the illusion of a larger area behind the window. It is
691     exactly equivalent to C<move -TX, -TY>, that is, it moves the image to the
692     top left of the screen.
693    
694     Example: load a background image, put it in mirror mode and root align it.
695    
696 root 1.64 rootalign keep { mirror load "mybg.png" }
697 root 1.36
698     Example: take the screen background and align it, giving the illusion of
699     transparency as long as the window isn't in front of other windows.
700    
701 root 1.46 rootalign root
702 root 1.36
703     =cut
704    
705 root 1.7 sub move($$;$) {
706 root 1.20 my $img = pop->clone;
707     $img->move ($_[0], $_[1]);
708     $img
709 root 1.1 }
710    
711 root 1.46 sub align($;$$) {
712     my $img = pop;
713    
714     move $_[0] * (TW - $img->w),
715     $_[1] * (TH - $img->h),
716     $img
717     }
718    
719 root 1.44 sub center($;$$) {
720     my $img = pop;
721     my $w = $_[0] || TW;
722 root 1.46 my $h = $_[1] || TH;
723 root 1.44
724     move 0.5 * ($w - $img->w), 0.5 * ($h - $img->h), $img
725     }
726    
727 root 1.36 sub rootalign($) {
728     move -TX, -TY, $_[0]
729 root 1.1 }
730    
731 root 1.64 =item rotate $center_x, $center_y, $degrees, $img
732 root 1.52
733 root 1.64 Rotates the image clockwise by C<$degrees> degrees, around the point at
734     C<$center_x> and C<$center_y> (specified as factor of image width/height).
735 root 1.52
736 root 1.64 Example: rotate the image by 90 degrees around it's center.
737 root 1.52
738 root 1.64 rotate 0.5, 0.5, 90, keep { load "$HOME/mybg.png" }
739 root 1.52
740     =cut
741    
742 root 1.53 sub rotate($$$$) {
743 root 1.52 my $img = pop;
744     $img->rotate (
745 root 1.60 $_[0] * ($img->w + $img->x),
746     $_[1] * ($img->h + $img->y),
747 root 1.52 $_[2] * (3.14159265 / 180),
748     )
749     }
750    
751 root 1.45 =back
752    
753     =head2 COLOUR MODIFICATIONS
754    
755     The following operators change the pixels of the image.
756    
757     =over 4
758    
759 root 1.36 =item contrast $factor, $img
760    
761     =item contrast $r, $g, $b, $img
762    
763     =item contrast $r, $g, $b, $a, $img
764    
765     Adjusts the I<contrast> of an image.
766    
767 root 1.45 The first form applies a single C<$factor> to red, green and blue, the
768     second form applies separate factors to each colour channel, and the last
769     form includes the alpha channel.
770    
771     Values from 0 to 1 lower the contrast, values higher than 1 increase the
772     contrast.
773    
774     Due to limitations in the underlying XRender extension, lowering contrast
775     also reduces brightness, while increasing contrast currently also
776     increases brightness.
777 root 1.38
778 root 1.45 =item brightness $bias, $img
779 root 1.36
780     =item brightness $r, $g, $b, $img
781    
782     =item brightness $r, $g, $b, $a, $img
783    
784 root 1.38 Adjusts the brightness of an image.
785    
786 root 1.45 The first form applies a single C<$bias> to red, green and blue, the
787     second form applies separate biases to each colour channel, and the last
788     form includes the alpha channel.
789    
790     Values less than 0 reduce brightness, while values larger than 0 increase
791     it. Useful range is from -1 to 1 - the former results in a black, the
792     latter in a white picture.
793    
794 sf-exg 1.51 Due to idiosyncrasies in the underlying XRender extension, biases less
795 root 1.45 than zero can be I<very> slow.
796    
797 root 1.36 =cut
798 root 1.1
799 root 1.2 sub contrast($$;$$;$) {
800 root 1.7 my $img = pop;
801     my ($r, $g, $b, $a) = @_;
802 root 1.4
803 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
804     $a = 1 if @_ < 4;
805 root 1.4
806 root 1.1 $img = $img->clone;
807 root 1.37 $img->contrast ($r, $g, $b, $a);
808 root 1.1 $img
809     }
810    
811 root 1.2 sub brightness($$;$$;$) {
812 root 1.7 my $img = pop;
813     my ($r, $g, $b, $a) = @_;
814 root 1.4
815 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
816     $a = 1 if @_ < 4;
817 root 1.4
818 root 1.1 $img = $img->clone;
819     $img->brightness ($r, $g, $b, $a);
820     $img
821     }
822    
823 root 1.38 =item blur $radius, $img
824    
825     =item blur $radius_horz, $radius_vert, $img
826    
827     Gaussian-blurs the image with (roughly) C<$radius> pixel radius. The radii
828     can also be specified separately.
829    
830 root 1.39 Blurring is often I<very> slow, at least compared or other
831     operators. Larger blur radii are slower than smaller ones, too, so if you
832     don't want to freeze your screen for long times, start experimenting with
833     low values for radius (<5).
834    
835 root 1.38 =cut
836    
837 root 1.36 sub blur($$;$) {
838     my $img = pop;
839     $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
840     }
841    
842 root 1.52 =back
843    
844     =head2 OTHER STUFF
845 root 1.38
846 root 1.56 Anything that didn't fit any of the other categories, even after applying
847 root 1.52 force and closing our eyes.
848    
849     =over 4
850    
851 root 1.66 =item keep { ... }
852 root 1.52
853 root 1.66 This operator takes a code block as argument, that is, one or more
854 root 1.52 statements enclosed by braces.
855    
856 root 1.68 The trick is that this code block is only evaluated when the outcome
857     changes - on other calls the C<keep> simply returns the image it computed
858     previously (yes, it should only be used with images). Or in other words,
859     C<keep> I<caches> the result of the code block so it doesn't need to be
860     computed again.
861    
862     This can be extremely useful to avoid redoing slow operations - for
863     example, if your background expression takes the root background, blurs it
864     and then root-aligns it it would have to blur the root background on every
865     window move or resize.
866    
867     Another example is C<load>, which can be quite slow.
868 root 1.52
869 root 1.63 In fact, urxvt itself encloses the whole expression in some kind of
870 root 1.68 C<keep> block so it only is reevaluated as required.
871 root 1.63
872 root 1.68 Putting the blur into a C<keep> block will make sure the blur is only done
873     once, while the C<rootalign> is still done each time the window moves.
874 root 1.52
875 root 1.66 rootlign keep { blur 10, root }
876 root 1.52
877 root 1.63 This leaves the question of how to force reevaluation of the block,
878     in case the root background changes: If expression inside the block
879     is sensitive to some event (root background changes, window geometry
880     changes), then it will be reevaluated automatically as needed.
881 root 1.38
882     =cut
883    
884 root 1.68 sub keep(&) {
885 root 1.63 my $id = $_[0]+0;
886    
887     local $frame = $self->{frame_cache}{$id} ||= [$frame];
888    
889     unless ($frame->[FR_CACHE]) {
890     $frame->[FR_CACHE] = [ $_[0]() ];
891    
892     my $self = $self;
893     my $frame = $frame;
894     Scalar::Util::weaken $frame;
895     $self->compile_frame ($frame, sub {
896     # clear this frame cache, also for all parents
897     for (my $frame = $frame; $frame; $frame = $frame->[0]) {
898     undef $frame->[FR_CACHE];
899     }
900    
901     $self->recalculate;
902     });
903 root 1.55 };
904    
905     # in scalar context we always return the first original result, which
906     # is not quite how perl works.
907     wantarray
908 root 1.63 ? @{ $frame->[FR_CACHE] }
909     : $frame->[FR_CACHE][0]
910 root 1.52 }
911    
912 root 1.68 # sub keep_clear() {
913     # delete $self->{frame_cache};
914     # }
915 root 1.36
916 root 1.15 =back
917    
918     =cut
919    
920 root 1.1 }
921    
922     sub parse_expr {
923 root 1.63 my $expr = eval
924     "sub {\n"
925     . "package urxvt::bgdsl;\n"
926     . "#line 0 'background expression'\n"
927     . "$_[0]\n"
928     . "}";
929 root 1.1 die if $@;
930     $expr
931     }
932    
933     # compiles a parsed expression
934     sub set_expr {
935     my ($self, $expr) = @_;
936    
937 root 1.63 $self->{root} = [];
938 root 1.1 $self->{expr} = $expr;
939     $self->recalculate;
940     }
941    
942 root 1.63 # takes a hash of sensitivity indicators and installs watchers
943     sub compile_frame {
944     my ($self, $frame, $cb) = @_;
945    
946     my $state = $frame->[urxvt::bgdsl::FR_STATE] ||= {};
947     my $again = $frame->[urxvt::bgdsl::FR_AGAIN];
948    
949     # don't keep stuff alive
950     Scalar::Util::weaken $state;
951    
952     if ($again->{nested}) {
953     $state->{nested} = 1;
954     } else {
955     delete $state->{nested};
956     }
957    
958     if (my $interval = $again->{time}) {
959     $state->{time} = [$interval, urxvt::timer->new->after ($interval)->interval ($interval)]
960     if $state->{time}[0] != $interval;
961    
962     # callback *might* have changed, although we could just rule that out
963     $state->{time}[1]->cb (sub {
964     ++$state->{counter};
965     $cb->();
966     });
967     } else {
968     delete $state->{time};
969     }
970    
971     if ($again->{position}) {
972     $state->{position} = $self->on (position_change => $cb);
973     } else {
974     delete $state->{position};
975     }
976    
977     if ($again->{size}) {
978     $state->{size} = $self->on (size_change => $cb);
979     } else {
980     delete $state->{size};
981     }
982    
983     if ($again->{rootpmap}) {
984     $state->{rootpmap} = $self->on (rootpmap_change => $cb);
985     } else {
986     delete $state->{rootpmap};
987     }
988     }
989    
990 root 1.1 # evaluate the current bg expression
991     sub recalculate {
992 root 1.33 my ($arg_self) = @_;
993 root 1.1
994 root 1.10 # rate limit evaluation
995    
996 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
997     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
998     $arg_self->recalculate;
999 root 1.9 });
1000 root 1.12 return;
1001 root 1.9 }
1002    
1003 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
1004 root 1.9
1005 root 1.10 # set environment to evaluate user expression
1006 root 1.6
1007 root 1.63 local $self = $arg_self;
1008     local $HOME = $ENV{HOME};
1009     local $frame = [];
1010 root 1.1
1011 root 1.63 ($x, $y, $w, $h) = $self->background_geometry ($self->{border});
1012 root 1.22
1013 root 1.10 # evaluate user expression
1014    
1015 root 1.63 my @img = eval { $self->{expr}->() };
1016 root 1.61 die $@ if $@;
1017 root 1.63 die "background-expr did not return anything.\n" unless @img;
1018     die "background-expr: expected image(s), got something else.\n"
1019     if grep { !UNIVERSAL::isa $_, "urxvt::img" } @img;
1020 root 1.1
1021 root 1.63 my $img = urxvt::bgdsl::merge @img;
1022 root 1.10
1023 root 1.63 $frame->[FR_AGAIN]{size} = 1
1024 root 1.55 if $img->repeat_mode != urxvt::RepeatNormal;
1025    
1026 root 1.63 # if the expression is sensitive to external events, prepare reevaluation then
1027     $self->compile_frame ($frame, sub { $arg_self->recalculate });
1028 root 1.9
1029 root 1.10 # clear stuff we no longer need
1030    
1031 root 1.63 # unless (%{ $frame->[FR_STATE] }) {
1032     # delete $self->{state};
1033     # delete $self->{expr};
1034     # }
1035 root 1.5
1036 root 1.34 # set background pixmap
1037 root 1.1
1038 root 1.33 $self->set_background ($img, $self->{border});
1039 root 1.1 $self->scr_recolour (0);
1040     $self->want_refresh;
1041     }
1042    
1043     sub on_start {
1044     my ($self) = @_;
1045    
1046 root 1.47 my $expr = $self->x_resource ("%.expr")
1047 root 1.33 or return;
1048    
1049 root 1.48 $self->has_render
1050     or die "background extension needs RENDER extension 0.10 or higher, ignoring background-expr.\n";
1051    
1052 root 1.33 $self->set_expr (parse_expr $expr);
1053 root 1.47 $self->{border} = $self->x_resource_boolean ("%.border");
1054 root 1.1
1055 root 1.47 $MIN_INTERVAL = $self->x_resource ("%.interval");
1056 root 1.46
1057 root 1.1 ()
1058     }
1059