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