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