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