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