ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.69
Committed: Mon Jul 2 01:32:26 2012 UTC (11 years, 10 months ago) by root
Branch: MAIN
Changes since 1.68: +1 -5 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.63 sub load($) {
283 root 1.54 my ($path) = @_;
284    
285     $_IMG_CACHE{$path} || do {
286 root 1.69 my $img = $self->new_img_from_file ($path);
287 root 1.54 Scalar::Util::weaken ($_IMG_CACHE{$path} = $img);
288     $img
289     }
290     }
291    
292 root 1.31 =item root
293    
294     Returns the root window pixmap, that is, hopefully, the background image
295 root 1.62 of your screen.
296 root 1.31
297     This function makes your expression root sensitive, that means it will be
298     reevaluated when the bg image changes.
299    
300     =cut
301    
302 root 1.2 sub root() {
303 root 1.63 $frame->[FR_AGAIN]{rootpmap} = 1;
304 root 1.52 $self->new_img_from_root
305 root 1.1 }
306    
307 root 1.31 =item solid $colour
308    
309     =item solid $width, $height, $colour
310    
311     Creates a new image and completely fills it with the given colour. The
312     image is set to tiling mode.
313    
314 root 1.40 If C<$width> and C<$height> are omitted, it creates a 1x1 image, which is
315 root 1.31 useful for solid backgrounds or for use in filtering effects.
316    
317     =cut
318    
319 root 1.42 sub solid($;$$) {
320 root 1.31 my $colour = pop;
321    
322 root 1.59 my $img = $self->new_img (urxvt::PictStandardARGB32, 0, 0, $_[0] || 1, $_[1] || 1);
323 root 1.31 $img->fill ($colour);
324 root 1.15 $img
325     }
326    
327 root 1.45 =item clone $img
328 root 1.31
329 root 1.45 Returns an exact copy of the image. This is useful if you want to have
330     multiple copies of the same image to apply different effects to.
331 root 1.31
332 root 1.20 =cut
333    
334 root 1.45 sub clone($) {
335     $_[0]->clone
336 root 1.20 }
337    
338 root 1.56 =item merge $img ...
339    
340 root 1.57 Takes any number of images and merges them together, creating a single
341 root 1.62 image containing them all. The tiling mode of the first image is used as
342 sf-exg 1.65 the tiling mode of the resulting image.
343 root 1.56
344 root 1.61 This function is called automatically when an expression returns multiple
345     images.
346    
347 root 1.56 =cut
348    
349     sub merge(@) {
350 root 1.61 return $_[0] unless $#_;
351    
352 root 1.58 # rather annoyingly clumsy, but optimisation is for another time
353    
354 root 1.59 my $x0 = +1e9;
355     my $y0 = +1e9;
356 root 1.58 my $x1 = -1e9;
357     my $y1 = -1e9;
358    
359     for (@_) {
360     my ($x, $y, $w, $h) = $_->geometry;
361    
362     $x0 = $x if $x0 > $x;
363     $y0 = $y if $y0 > $y;
364    
365     $x += $w;
366     $y += $h;
367    
368 root 1.59 $x1 = $x if $x1 < $x;
369     $y1 = $y if $y1 < $y;
370 root 1.58 }
371    
372 root 1.59 my $base = $self->new_img (urxvt::PictStandardARGB32, $x0, $y0, $x1 - $x0, $y1 - $y0);
373 root 1.62 $base->repeat_mode ($_[0]->repeat_mode);
374 root 1.58 $base->fill ([0, 0, 0, 0]);
375    
376 root 1.59 $base->draw ($_)
377 root 1.58 for @_;
378    
379     $base
380 root 1.56 }
381    
382 root 1.28 =head2 TILING MODES
383    
384     The following operators modify the tiling mode of an image, that is, the
385     way that pixels outside the image area are painted when the image is used.
386 root 1.15
387     =over 4
388    
389 root 1.28 =item tile $img
390    
391     Tiles the whole plane with the image and returns this new image - or in
392     other words, it returns a copy of the image in plane tiling mode.
393    
394 root 1.34 Example: load an image and tile it over the background, without
395     resizing. The C<tile> call is superfluous because C<load> already defaults
396     to tiling mode.
397    
398     tile load "mybg.png"
399    
400 root 1.28 =item mirror $img
401    
402     Similar to tile, but reflects the image each time it uses a new copy, so
403     that top edges always touch top edges, right edges always touch right
404     edges and so on (with normal tiling, left edges always touch right edges
405     and top always touch bottom edges).
406    
407 root 1.36 Example: load an image and mirror it over the background, avoiding sharp
408 root 1.34 edges at the image borders at the expense of mirroring the image itself
409    
410     mirror load "mybg.png"
411    
412 root 1.28 =item pad $img
413    
414     Takes an image and modifies it so that all pixels outside the image area
415     become transparent. This mode is most useful when you want to place an
416     image over another image or the background colour while leaving all
417     background pixels outside the image unchanged.
418    
419 root 1.36 Example: load an image and display it in the upper left corner. The rest
420 sf-exg 1.51 of the space is left "empty" (transparent or whatever your compositor does
421 root 1.34 in alpha mode, else background colour).
422    
423     pad load "mybg.png"
424    
425 root 1.28 =item extend $img
426    
427     Extends the image over the whole plane, using the closest pixel in the
428 sf-exg 1.51 area outside the image. This mode is mostly useful when you use more complex
429 root 1.28 filtering operations and want the pixels outside the image to have the
430     same values as the pixels near the edge.
431    
432 root 1.34 Example: just for curiosity, how does this pixel extension stuff work?
433    
434     extend move 50, 50, load "mybg.png"
435    
436 root 1.15 =cut
437    
438 root 1.28 sub pad($) {
439     my $img = $_[0]->clone;
440     $img->repeat_mode (urxvt::RepeatNone);
441     $img
442     }
443    
444     sub tile($) {
445     my $img = $_[0]->clone;
446     $img->repeat_mode (urxvt::RepeatNormal);
447     $img
448     }
449    
450     sub mirror($) {
451     my $img = $_[0]->clone;
452     $img->repeat_mode (urxvt::RepeatReflect);
453     $img
454     }
455 root 1.4
456 root 1.28 sub extend($) {
457 root 1.24 my $img = $_[0]->clone;
458 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
459 root 1.24 $img
460     }
461    
462 root 1.28 =back
463    
464 root 1.45 =head2 VARIABLE VALUES
465 root 1.28
466 root 1.45 The following functions provide variable data such as the terminal window
467     dimensions. They are not (Perl-) variables, they just return stuff that
468     varies. Most of them make your expression sensitive to some events, for
469     example using C<TW> (terminal width) means your expression is evaluated
470     again when the terminal is resized.
471 root 1.28
472     =over 4
473    
474 root 1.45 =item TX
475    
476     =item TY
477    
478     Return the X and Y coordinates of the terminal window (the terminal
479     window is the full window by default, and the character area only when in
480     border-respect mode).
481    
482     Using these functions make your expression sensitive to window moves.
483    
484     These functions are mainly useful to align images to the root window.
485    
486     Example: load an image and align it so it looks as if anchored to the
487 root 1.64 background (that's exactly what C<rootalign> does btw.):
488 root 1.45
489 root 1.64 move -TX, -TY, keep { load "mybg.png" }
490 root 1.45
491     =item TW
492    
493     Return the width (C<TW>) and height (C<TH>) of the terminal window (the
494     terminal window is the full window by default, and the character area only
495     when in border-respect mode).
496    
497     Using these functions make your expression sensitive to window resizes.
498    
499     These functions are mainly useful to scale images, or to clip images to
500     the window size to conserve memory.
501    
502     Example: take the screen background, clip it to the window size, blur it a
503     bit, align it to the window position and use it as background.
504    
505 root 1.64 clip move -TX, -TY, keep { blur 5, root }
506 root 1.45
507     =cut
508    
509 root 1.63 sub TX() { $frame->[FR_AGAIN]{position} = 1; $x }
510     sub TY() { $frame->[FR_AGAIN]{position} = 1; $y }
511     sub TW() { $frame->[FR_AGAIN]{size} = 1; $w }
512     sub TH() { $frame->[FR_AGAIN]{size} = 1; $h }
513 root 1.45
514     =item now
515    
516     Returns the current time as (fractional) seconds since the epoch.
517    
518     Using this expression does I<not> make your expression sensitive to time,
519     but the next two functions do.
520    
521     =item again $seconds
522    
523     When this function is used the expression will be reevaluated again in
524     C<$seconds> seconds.
525    
526     Example: load some image and rotate it according to the time of day (as if it were
527     the hour pointer of a clock). Update this image every minute.
528    
529 root 1.64 again 60;
530     rotate 50, 50, (now % 86400) * -72 / 8640, scale keep { load "myclock.png" }
531 root 1.28
532 root 1.45 =item counter $seconds
533    
534     Like C<again>, but also returns an increasing counter value, starting at
535     0, which might be useful for some simple animation effects.
536 root 1.28
537     =cut
538    
539 root 1.45 sub now() { urxvt::NOW }
540    
541     sub again($) {
542 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
543 root 1.45 }
544    
545     sub counter($) {
546 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
547     $frame->[FR_STATE]{counter} + 0
548 root 1.28 }
549    
550 root 1.45 =back
551    
552     =head2 SHAPE CHANGING OPERATORS
553    
554     The following operators modify the shape, size or position of the image.
555    
556     =over 4
557    
558 root 1.28 =item clip $img
559    
560     =item clip $width, $height, $img
561    
562     =item clip $x, $y, $width, $height, $img
563    
564     Clips an image to the given rectangle. If the rectangle is outside the
565     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
566     larger than the image, then the tiling mode defines how the extra pixels
567     will be filled.
568    
569     If C<$x> an C<$y> are missing, then C<0> is assumed for both.
570    
571     If C<$width> and C<$height> are missing, then the window size will be
572     assumed.
573    
574     Example: load an image, blur it, and clip it to the window size to save
575     memory.
576    
577 root 1.64 clip keep { blur 10, load "mybg.png" }
578 root 1.28
579     =cut
580    
581 root 1.20 sub clip($;$$;$$) {
582 root 1.7 my $img = pop;
583 root 1.30 my $h = pop || TH;
584     my $w = pop || TW;
585 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
586 root 1.4 }
587    
588 root 1.28 =item scale $img
589    
590 root 1.43 =item scale $size_factor, $img
591 root 1.28
592 root 1.43 =item scale $width_factor, $height_factor, $img
593 root 1.28
594 root 1.43 Scales the image by the given factors in horizontal
595     (C<$width>) and vertical (C<$height>) direction.
596 root 1.28
597 root 1.43 If only one factor is give, it is used for both directions.
598 root 1.28
599 root 1.43 If no factors are given, scales the image to the window size without
600 root 1.28 keeping aspect.
601    
602     =item resize $width, $height, $img
603    
604     Resizes the image to exactly C<$width> times C<$height> pixels.
605    
606 root 1.43 =item fit $img
607    
608     =item fit $width, $height, $img
609    
610     Fits the image into the given C<$width> and C<$height> without changing
611     aspect, or the terminal size. That means it will be shrunk or grown until
612     the whole image fits into the given area, possibly leaving borders.
613    
614     =item cover $img
615    
616     =item cover $width, $height, $img
617    
618     Similar to C<fit>, but shrinks or grows until all of the area is covered
619     by the image, so instead of potentially leaving borders, it will cut off
620     image data that doesn't fit.
621    
622 root 1.28 =cut
623    
624 root 1.33 sub scale($;$;$) {
625 root 1.28 my $img = pop;
626    
627 root 1.43 @_ == 2 ? $img->scale ($_[0] * $img->w, $_[1] * $img->h)
628     : @_ ? $img->scale ($_[0] * $img->w, $_[0] * $img->h)
629 root 1.30 : $img->scale (TW, TH)
630 root 1.28 }
631    
632 root 1.2 sub resize($$$) {
633 root 1.7 my $img = pop;
634     $img->scale ($_[0], $_[1])
635 root 1.1 }
636    
637 root 1.43 sub fit($;$$) {
638     my $img = pop;
639     my $w = ($_[0] || TW) / $img->w;
640     my $h = ($_[1] || TH) / $img->h;
641     scale +(min $w, $h), $img
642     }
643    
644     sub cover($;$$) {
645     my $img = pop;
646     my $w = ($_[0] || TW) / $img->w;
647     my $h = ($_[1] || TH) / $img->h;
648     scale +(max $w, $h), $img
649     }
650    
651 root 1.36 =item move $dx, $dy, $img
652    
653     Moves the image by C<$dx> pixels in the horizontal, and C<$dy> pixels in
654     the vertical.
655    
656     Example: move the image right by 20 pixels and down by 30.
657    
658     move 20, 30, ...
659    
660 root 1.46 =item align $xalign, $yalign, $img
661    
662     Aligns the image according to a factor - C<0> means the image is moved to
663     the left or top edge (for C<$xalign> or C<$yalign>), C<0.5> means it is
664     exactly centered and C<1> means it touches the right or bottom edge.
665    
666     Example: remove any visible border around an image, center it vertically but move
667     it to the right hand side.
668    
669     align 1, 0.5, pad $img
670    
671 root 1.44 =item center $img
672    
673     =item center $width, $height, $img
674    
675     Centers the image, i.e. the center of the image is moved to the center of
676     the terminal window (or the box specified by C<$width> and C<$height> if
677     given).
678    
679 root 1.46 Example: load an image and center it.
680    
681 root 1.64 center keep { pad load "mybg.png" }
682 root 1.46
683 root 1.36 =item rootalign $img
684    
685     Moves the image so that it appears glued to the screen as opposed to the
686     window. This gives the illusion of a larger area behind the window. It is
687     exactly equivalent to C<move -TX, -TY>, that is, it moves the image to the
688     top left of the screen.
689    
690     Example: load a background image, put it in mirror mode and root align it.
691    
692 root 1.64 rootalign keep { mirror load "mybg.png" }
693 root 1.36
694     Example: take the screen background and align it, giving the illusion of
695     transparency as long as the window isn't in front of other windows.
696    
697 root 1.46 rootalign root
698 root 1.36
699     =cut
700    
701 root 1.7 sub move($$;$) {
702 root 1.20 my $img = pop->clone;
703     $img->move ($_[0], $_[1]);
704     $img
705 root 1.1 }
706    
707 root 1.46 sub align($;$$) {
708     my $img = pop;
709    
710     move $_[0] * (TW - $img->w),
711     $_[1] * (TH - $img->h),
712     $img
713     }
714    
715 root 1.44 sub center($;$$) {
716     my $img = pop;
717     my $w = $_[0] || TW;
718 root 1.46 my $h = $_[1] || TH;
719 root 1.44
720     move 0.5 * ($w - $img->w), 0.5 * ($h - $img->h), $img
721     }
722    
723 root 1.36 sub rootalign($) {
724     move -TX, -TY, $_[0]
725 root 1.1 }
726    
727 root 1.64 =item rotate $center_x, $center_y, $degrees, $img
728 root 1.52
729 root 1.64 Rotates the image clockwise by C<$degrees> degrees, around the point at
730     C<$center_x> and C<$center_y> (specified as factor of image width/height).
731 root 1.52
732 root 1.64 Example: rotate the image by 90 degrees around it's center.
733 root 1.52
734 root 1.64 rotate 0.5, 0.5, 90, keep { load "$HOME/mybg.png" }
735 root 1.52
736     =cut
737    
738 root 1.53 sub rotate($$$$) {
739 root 1.52 my $img = pop;
740     $img->rotate (
741 root 1.60 $_[0] * ($img->w + $img->x),
742     $_[1] * ($img->h + $img->y),
743 root 1.52 $_[2] * (3.14159265 / 180),
744     )
745     }
746    
747 root 1.45 =back
748    
749     =head2 COLOUR MODIFICATIONS
750    
751     The following operators change the pixels of the image.
752    
753     =over 4
754    
755 root 1.36 =item contrast $factor, $img
756    
757     =item contrast $r, $g, $b, $img
758    
759     =item contrast $r, $g, $b, $a, $img
760    
761     Adjusts the I<contrast> of an image.
762    
763 root 1.45 The first form applies a single C<$factor> to red, green and blue, the
764     second form applies separate factors to each colour channel, and the last
765     form includes the alpha channel.
766    
767     Values from 0 to 1 lower the contrast, values higher than 1 increase the
768     contrast.
769    
770     Due to limitations in the underlying XRender extension, lowering contrast
771     also reduces brightness, while increasing contrast currently also
772     increases brightness.
773 root 1.38
774 root 1.45 =item brightness $bias, $img
775 root 1.36
776     =item brightness $r, $g, $b, $img
777    
778     =item brightness $r, $g, $b, $a, $img
779    
780 root 1.38 Adjusts the brightness of an image.
781    
782 root 1.45 The first form applies a single C<$bias> to red, green and blue, the
783     second form applies separate biases to each colour channel, and the last
784     form includes the alpha channel.
785    
786     Values less than 0 reduce brightness, while values larger than 0 increase
787     it. Useful range is from -1 to 1 - the former results in a black, the
788     latter in a white picture.
789    
790 sf-exg 1.51 Due to idiosyncrasies in the underlying XRender extension, biases less
791 root 1.45 than zero can be I<very> slow.
792    
793 root 1.36 =cut
794 root 1.1
795 root 1.2 sub contrast($$;$$;$) {
796 root 1.7 my $img = pop;
797     my ($r, $g, $b, $a) = @_;
798 root 1.4
799 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
800     $a = 1 if @_ < 4;
801 root 1.4
802 root 1.1 $img = $img->clone;
803 root 1.37 $img->contrast ($r, $g, $b, $a);
804 root 1.1 $img
805     }
806    
807 root 1.2 sub brightness($$;$$;$) {
808 root 1.7 my $img = pop;
809     my ($r, $g, $b, $a) = @_;
810 root 1.4
811 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
812     $a = 1 if @_ < 4;
813 root 1.4
814 root 1.1 $img = $img->clone;
815     $img->brightness ($r, $g, $b, $a);
816     $img
817     }
818    
819 root 1.38 =item blur $radius, $img
820    
821     =item blur $radius_horz, $radius_vert, $img
822    
823     Gaussian-blurs the image with (roughly) C<$radius> pixel radius. The radii
824     can also be specified separately.
825    
826 root 1.39 Blurring is often I<very> slow, at least compared or other
827     operators. Larger blur radii are slower than smaller ones, too, so if you
828     don't want to freeze your screen for long times, start experimenting with
829     low values for radius (<5).
830    
831 root 1.38 =cut
832    
833 root 1.36 sub blur($$;$) {
834     my $img = pop;
835     $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
836     }
837    
838 root 1.52 =back
839    
840     =head2 OTHER STUFF
841 root 1.38
842 root 1.56 Anything that didn't fit any of the other categories, even after applying
843 root 1.52 force and closing our eyes.
844    
845     =over 4
846    
847 root 1.66 =item keep { ... }
848 root 1.52
849 root 1.66 This operator takes a code block as argument, that is, one or more
850 root 1.52 statements enclosed by braces.
851    
852 root 1.68 The trick is that this code block is only evaluated when the outcome
853     changes - on other calls the C<keep> simply returns the image it computed
854     previously (yes, it should only be used with images). Or in other words,
855     C<keep> I<caches> the result of the code block so it doesn't need to be
856     computed again.
857    
858     This can be extremely useful to avoid redoing slow operations - for
859     example, if your background expression takes the root background, blurs it
860     and then root-aligns it it would have to blur the root background on every
861     window move or resize.
862    
863     Another example is C<load>, which can be quite slow.
864 root 1.52
865 root 1.63 In fact, urxvt itself encloses the whole expression in some kind of
866 root 1.68 C<keep> block so it only is reevaluated as required.
867 root 1.63
868 root 1.68 Putting the blur into a C<keep> block will make sure the blur is only done
869     once, while the C<rootalign> is still done each time the window moves.
870 root 1.52
871 root 1.66 rootlign keep { blur 10, root }
872 root 1.52
873 root 1.63 This leaves the question of how to force reevaluation of the block,
874     in case the root background changes: If expression inside the block
875     is sensitive to some event (root background changes, window geometry
876     changes), then it will be reevaluated automatically as needed.
877 root 1.38
878     =cut
879    
880 root 1.68 sub keep(&) {
881 root 1.63 my $id = $_[0]+0;
882    
883     local $frame = $self->{frame_cache}{$id} ||= [$frame];
884    
885     unless ($frame->[FR_CACHE]) {
886     $frame->[FR_CACHE] = [ $_[0]() ];
887    
888     my $self = $self;
889     my $frame = $frame;
890     Scalar::Util::weaken $frame;
891     $self->compile_frame ($frame, sub {
892     # clear this frame cache, also for all parents
893     for (my $frame = $frame; $frame; $frame = $frame->[0]) {
894     undef $frame->[FR_CACHE];
895     }
896    
897     $self->recalculate;
898     });
899 root 1.55 };
900    
901     # in scalar context we always return the first original result, which
902     # is not quite how perl works.
903     wantarray
904 root 1.63 ? @{ $frame->[FR_CACHE] }
905     : $frame->[FR_CACHE][0]
906 root 1.52 }
907    
908 root 1.68 # sub keep_clear() {
909     # delete $self->{frame_cache};
910     # }
911 root 1.36
912 root 1.15 =back
913    
914     =cut
915    
916 root 1.1 }
917    
918     sub parse_expr {
919 root 1.63 my $expr = eval
920     "sub {\n"
921     . "package urxvt::bgdsl;\n"
922     . "#line 0 'background expression'\n"
923     . "$_[0]\n"
924     . "}";
925 root 1.1 die if $@;
926     $expr
927     }
928    
929     # compiles a parsed expression
930     sub set_expr {
931     my ($self, $expr) = @_;
932    
933 root 1.63 $self->{root} = [];
934 root 1.1 $self->{expr} = $expr;
935     $self->recalculate;
936     }
937    
938 root 1.63 # takes a hash of sensitivity indicators and installs watchers
939     sub compile_frame {
940     my ($self, $frame, $cb) = @_;
941    
942     my $state = $frame->[urxvt::bgdsl::FR_STATE] ||= {};
943     my $again = $frame->[urxvt::bgdsl::FR_AGAIN];
944    
945     # don't keep stuff alive
946     Scalar::Util::weaken $state;
947    
948     if ($again->{nested}) {
949     $state->{nested} = 1;
950     } else {
951     delete $state->{nested};
952     }
953    
954     if (my $interval = $again->{time}) {
955     $state->{time} = [$interval, urxvt::timer->new->after ($interval)->interval ($interval)]
956     if $state->{time}[0] != $interval;
957    
958     # callback *might* have changed, although we could just rule that out
959     $state->{time}[1]->cb (sub {
960     ++$state->{counter};
961     $cb->();
962     });
963     } else {
964     delete $state->{time};
965     }
966    
967     if ($again->{position}) {
968     $state->{position} = $self->on (position_change => $cb);
969     } else {
970     delete $state->{position};
971     }
972    
973     if ($again->{size}) {
974     $state->{size} = $self->on (size_change => $cb);
975     } else {
976     delete $state->{size};
977     }
978    
979     if ($again->{rootpmap}) {
980     $state->{rootpmap} = $self->on (rootpmap_change => $cb);
981     } else {
982     delete $state->{rootpmap};
983     }
984     }
985    
986 root 1.1 # evaluate the current bg expression
987     sub recalculate {
988 root 1.33 my ($arg_self) = @_;
989 root 1.1
990 root 1.10 # rate limit evaluation
991    
992 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
993     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
994     $arg_self->recalculate;
995 root 1.9 });
996 root 1.12 return;
997 root 1.9 }
998    
999 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
1000 root 1.9
1001 root 1.10 # set environment to evaluate user expression
1002 root 1.6
1003 root 1.63 local $self = $arg_self;
1004     local $HOME = $ENV{HOME};
1005     local $frame = [];
1006 root 1.1
1007 root 1.63 ($x, $y, $w, $h) = $self->background_geometry ($self->{border});
1008 root 1.22
1009 root 1.10 # evaluate user expression
1010    
1011 root 1.63 my @img = eval { $self->{expr}->() };
1012 root 1.61 die $@ if $@;
1013 root 1.63 die "background-expr did not return anything.\n" unless @img;
1014     die "background-expr: expected image(s), got something else.\n"
1015     if grep { !UNIVERSAL::isa $_, "urxvt::img" } @img;
1016 root 1.1
1017 root 1.63 my $img = urxvt::bgdsl::merge @img;
1018 root 1.10
1019 root 1.63 $frame->[FR_AGAIN]{size} = 1
1020 root 1.55 if $img->repeat_mode != urxvt::RepeatNormal;
1021    
1022 root 1.63 # if the expression is sensitive to external events, prepare reevaluation then
1023     $self->compile_frame ($frame, sub { $arg_self->recalculate });
1024 root 1.9
1025 root 1.10 # clear stuff we no longer need
1026    
1027 root 1.63 # unless (%{ $frame->[FR_STATE] }) {
1028     # delete $self->{state};
1029     # delete $self->{expr};
1030     # }
1031 root 1.5
1032 root 1.34 # set background pixmap
1033 root 1.1
1034 root 1.33 $self->set_background ($img, $self->{border});
1035 root 1.1 $self->scr_recolour (0);
1036     $self->want_refresh;
1037     }
1038    
1039     sub on_start {
1040     my ($self) = @_;
1041    
1042 root 1.47 my $expr = $self->x_resource ("%.expr")
1043 root 1.33 or return;
1044    
1045 root 1.48 $self->has_render
1046     or die "background extension needs RENDER extension 0.10 or higher, ignoring background-expr.\n";
1047    
1048 root 1.33 $self->set_expr (parse_expr $expr);
1049 root 1.47 $self->{border} = $self->x_resource_boolean ("%.border");
1050 root 1.1
1051 root 1.47 $MIN_INTERVAL = $self->x_resource ("%.interval");
1052 root 1.46
1053 root 1.1 ()
1054     }
1055