ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.48
Committed: Sun Jun 10 15:01:14 2012 UTC (11 years, 11 months ago) by root
Branch: MAIN
Changes since 1.47: +4 -1 lines
Log Message:
must have been in a hurry

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.35 #TODO: once, rootalign
8    
9 root 1.41 =head1 NAME
10 root 1.33
11 root 1.41 background - manage terminal background
12    
13     =head1 SYNOPSIS
14 root 1.33
15 root 1.36 urxvt --background-expr 'background expression'
16     --background-border
17 root 1.46 --background-interval seconds
18 root 1.33
19 root 1.41 =head1 DESCRIPTION
20 root 1.33
21 root 1.36 This extension manages the terminal background by creating a picture that
22     is behind the text, replacing the normal background colour.
23    
24     It does so by evaluating a Perl expression that I<calculates> the image on
25     the fly, for example, by grabbing the root background or loading a file.
26    
27     While the full power of Perl is available, the operators have been design
28     to be as simple as possible.
29    
30     For example, to load an image and scale it to the window size, you would
31     use:
32    
33     urxvt --background-expr 'scale load "/path/to/mybg.png"'
34    
35     Or specified as a X resource:
36    
37     URxvt.background-expr: scale load "/path/to/mybg.png"
38    
39 root 1.41 =head1 THEORY OF OPERATION
40 root 1.36
41     At startup, just before the window is mapped for the first time, the
42     expression is evaluated and must yield an image. The image is then
43     extended as necessary to cover the whole terminal window, and is set as a
44     background pixmap.
45    
46     If the image contains an alpha channel, then it will be used as-is in
47     visuals that support alpha channels (for example, for a compositing
48     manager). In other visuals, the terminal background colour will be used to
49     replace any transparency.
50    
51     When the expression relies, directly or indirectly, on the window size,
52     position, the root pixmap, or a timer, then it will be remembered. If not,
53     then it will be removed.
54    
55     If any of the parameters that the expression relies on changes (when the
56     window is moved or resized, its position or size changes; when the root
57     pixmap is replaced by another one the root background changes; or when the
58     timer elapses), then the expression will be evaluated again.
59    
60     For example, an expression such as C<scale load "$HOME/mybg.png"> scales the
61     image to the window size, so it relies on the window size and will
62     be reevaluated each time it is changed, but not when it moves for
63     example. That ensures that the picture always fills the terminal, even
64     after it's size changes.
65    
66 root 1.41 =head2 EXPRESSIONS
67 root 1.36
68     Expressions are normal Perl expressions, in fact, they are Perl blocks -
69     which means you could use multiple lines and statements:
70    
71     again 3600;
72     if (localtime now)[6]) {
73     return scale load "$HOME/weekday.png";
74     } else {
75     return scale load "$HOME/sunday.png";
76     }
77    
78     This expression gets evaluated once per hour. It will set F<sunday.png> as
79 root 1.39 background on Sundays, and F<weekday.png> on all other days.
80 root 1.36
81     Fortunately, we expect that most expressions will be much simpler, with
82     little Perl knowledge needed.
83    
84     Basically, you always start with a function that "generates" an image
85     object, such as C<load>, which loads an image from disk, or C<root>, which
86     returns the root window background image:
87    
88     load "$HOME/mypic.png"
89    
90     The path is usually specified as a quoted string (the exact rules can be
91     found in the L<perlop> manpage). The F<$HOME> at the beginning of the
92     string is expanded to the home directory.
93    
94     Then you prepend one or more modifiers or filtering expressions, such as
95     C<scale>:
96    
97     scale load "$HOME/mypic.png"
98    
99     Just like a mathematical expression with functions, you should read these
100     expressions from right to left, as the C<load> is evaluated first, and
101     its result becomes the argument to the C<scale> function.
102    
103     Many operators also allow some parameters preceding the input image
104     that modify its behaviour. For example, C<scale> without any additional
105     arguments scales the image to size of the terminal window. If you specify
106 root 1.43 an additional argument, it uses it as a scale factor (multiply by 100 to
107     get a percentage):
108 root 1.36
109 root 1.43 scale 2, load "$HOME/mypic.png"
110 root 1.36
111     This enlarges the image by a factor of 2 (200%). As you can see, C<scale>
112     has now two arguments, the C<200> and the C<load> expression, while
113     C<load> only has one argument. Arguments are separated from each other by
114     commas.
115    
116     Scale also accepts two arguments, which are then separate factors for both
117     horizontal and vertical dimensions. For example, this halves the image
118     width and doubles the image height:
119    
120 root 1.43 scale 0.5, 2, load "$HOME/mypic.png"
121 root 1.36
122 root 1.39 Other effects than scalign are also readily available, for exmaple, you can
123     tile the image to fill the whole window, instead of resizing it:
124    
125     tile load "$HOME/mypic.png"
126    
127     In fact, images returned by C<load> are in C<tile> mode by default, so the C<tile> operator
128     is kind of superfluous.
129    
130     Another common effect is to mirror the image, so that the same edges touch:
131    
132     mirror load "$HOME/mypic.png"
133    
134     This is also a typical background expression:
135    
136     rootalign root
137    
138     It first takes a snapshot of the screen background image, and then
139     moves it to the upper left corner of the screen - the result is
140     pseudo-transparency, as the image seems to be static while the window is
141     moved around.
142 root 1.36
143 root 1.41 =head2 CYCLES AND CACHING
144 root 1.36
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     memory, or comserve memory by loading images more often.
159    
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.41 =head1 REFERENCE
179 root 1.33
180 root 1.41 =head2 COMMAND LINE SWITCHES
181 root 1.36
182     =over 4
183    
184     =item --background-expr perl-expression
185    
186     Specifies the Perl expression to evaluate.
187    
188     =item --background-border
189    
190     By default, the expression creates an image that fills the full window,
191     overwriting borders and any other areas, such as the scrollbar.
192    
193     Specifying this flag changes the behaviour, so that the image only
194     replaces the background of the character area.
195    
196 root 1.46 =item --background-interval seconds
197    
198     Since some operations in the underlying XRender extension can effetively
199     freeze your X-server for prolonged time, this extension enforces a minimum
200     time between updates, which is normally about 0.1 seconds.
201    
202     If you want to do updates more often, you can decrease this safety
203     interval with this switch.
204    
205 root 1.36 =back
206    
207 root 1.33 =cut
208 root 1.12
209 root 1.36 our $HOME;
210 root 1.33 our ($self, $old, $new);
211 root 1.29 our ($x, $y, $w, $h);
212 root 1.3
213 root 1.16 # enforce at least this interval between updates
214 root 1.46 our $MIN_INTERVAL = 6/59.951;
215 root 1.9
216 root 1.1 {
217     package urxvt::bgdsl; # background language
218    
219 root 1.43 use List::Util qw(min max sum shuffle);
220    
221 root 1.15 =head2 PROVIDERS/GENERATORS
222    
223 root 1.31 These functions provide an image, by loading it from disk, grabbing it
224 sf-exg 1.32 from the root screen or by simply generating it. They are used as starting
225 root 1.31 points to get an image you can play with.
226    
227 root 1.15 =over 4
228    
229     =item load $path
230    
231 root 1.29 Loads the image at the given C<$path>. The image is set to plane tiling
232     mode.
233    
234 root 1.31 Loaded images will be cached for one cycle.
235 root 1.29
236 root 1.15 =cut
237    
238 root 1.2 sub load($) {
239 root 1.1 my ($path) = @_;
240    
241 root 1.33 $new->{load}{$path} = $old->{load}{$path} || $self->new_img_from_file ($path);
242 root 1.1 }
243    
244 root 1.31 =item root
245    
246     Returns the root window pixmap, that is, hopefully, the background image
247     of your screen. The image is set to extend mode.
248    
249     This function makes your expression root sensitive, that means it will be
250     reevaluated when the bg image changes.
251    
252     =cut
253    
254 root 1.2 sub root() {
255 root 1.9 $new->{rootpmap_sensitive} = 1;
256 root 1.1 die "root op not supported, exg, we need you";
257     }
258    
259 root 1.31 =item solid $colour
260    
261     =item solid $width, $height, $colour
262    
263     Creates a new image and completely fills it with the given colour. The
264     image is set to tiling mode.
265    
266 root 1.40 If C<$width> and C<$height> are omitted, it creates a 1x1 image, which is
267 root 1.31 useful for solid backgrounds or for use in filtering effects.
268    
269     =cut
270    
271 root 1.42 sub solid($;$$) {
272 root 1.31 my $colour = pop;
273    
274 root 1.33 my $img = $self->new_img (urxvt::PictStandardARGB32, $_[0] || 1, $_[1] || 1);
275 root 1.31 $img->fill ($colour);
276 root 1.15 $img
277     }
278    
279 root 1.45 =item clone $img
280 root 1.31
281 root 1.45 Returns an exact copy of the image. This is useful if you want to have
282     multiple copies of the same image to apply different effects to.
283 root 1.31
284 root 1.20 =cut
285    
286 root 1.45 sub clone($) {
287     $_[0]->clone
288 root 1.20 }
289    
290     =back
291    
292 root 1.28 =head2 TILING MODES
293    
294     The following operators modify the tiling mode of an image, that is, the
295     way that pixels outside the image area are painted when the image is used.
296 root 1.15
297     =over 4
298    
299 root 1.28 =item tile $img
300    
301     Tiles the whole plane with the image and returns this new image - or in
302     other words, it returns a copy of the image in plane tiling mode.
303    
304 root 1.34 Example: load an image and tile it over the background, without
305     resizing. The C<tile> call is superfluous because C<load> already defaults
306     to tiling mode.
307    
308     tile load "mybg.png"
309    
310 root 1.28 =item mirror $img
311    
312     Similar to tile, but reflects the image each time it uses a new copy, so
313     that top edges always touch top edges, right edges always touch right
314     edges and so on (with normal tiling, left edges always touch right edges
315     and top always touch bottom edges).
316    
317 root 1.36 Example: load an image and mirror it over the background, avoiding sharp
318 root 1.34 edges at the image borders at the expense of mirroring the image itself
319    
320     mirror load "mybg.png"
321    
322 root 1.28 =item pad $img
323    
324     Takes an image and modifies it so that all pixels outside the image area
325     become transparent. This mode is most useful when you want to place an
326     image over another image or the background colour while leaving all
327     background pixels outside the image unchanged.
328    
329 root 1.36 Example: load an image and display it in the upper left corner. The rest
330 root 1.34 of the space is left "empty" (transparent or wahtever your compisotr does
331     in alpha mode, else background colour).
332    
333     pad load "mybg.png"
334    
335 root 1.28 =item extend $img
336    
337     Extends the image over the whole plane, using the closest pixel in the
338     area outside the image. This mode is mostly useful when you more complex
339     filtering operations and want the pixels outside the image to have the
340     same values as the pixels near the edge.
341    
342 root 1.34 Example: just for curiosity, how does this pixel extension stuff work?
343    
344     extend move 50, 50, load "mybg.png"
345    
346 root 1.15 =cut
347    
348 root 1.28 sub pad($) {
349     my $img = $_[0]->clone;
350     $img->repeat_mode (urxvt::RepeatNone);
351     $img
352     }
353    
354     sub tile($) {
355     my $img = $_[0]->clone;
356     $img->repeat_mode (urxvt::RepeatNormal);
357     $img
358     }
359    
360     sub mirror($) {
361     my $img = $_[0]->clone;
362     $img->repeat_mode (urxvt::RepeatReflect);
363     $img
364     }
365 root 1.4
366 root 1.28 sub extend($) {
367 root 1.24 my $img = $_[0]->clone;
368 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
369 root 1.24 $img
370     }
371    
372 root 1.28 =back
373    
374 root 1.45 =head2 VARIABLE VALUES
375 root 1.28
376 root 1.45 The following functions provide variable data such as the terminal window
377     dimensions. They are not (Perl-) variables, they just return stuff that
378     varies. Most of them make your expression sensitive to some events, for
379     example using C<TW> (terminal width) means your expression is evaluated
380     again when the terminal is resized.
381 root 1.28
382     =over 4
383    
384 root 1.45 =item TX
385    
386     =item TY
387    
388     Return the X and Y coordinates of the terminal window (the terminal
389     window is the full window by default, and the character area only when in
390     border-respect mode).
391    
392     Using these functions make your expression sensitive to window moves.
393    
394     These functions are mainly useful to align images to the root window.
395    
396     Example: load an image and align it so it looks as if anchored to the
397     background.
398    
399     move -TX, -TY, load "mybg.png"
400    
401     =item TW
402    
403     Return the width (C<TW>) and height (C<TH>) of the terminal window (the
404     terminal window is the full window by default, and the character area only
405     when in border-respect mode).
406    
407     Using these functions make your expression sensitive to window resizes.
408    
409     These functions are mainly useful to scale images, or to clip images to
410     the window size to conserve memory.
411    
412     Example: take the screen background, clip it to the window size, blur it a
413     bit, align it to the window position and use it as background.
414    
415     clip move -TX, -TY, blur 5, root
416    
417     =cut
418    
419     sub TX() { $new->{position_sensitive} = 1; $x }
420     sub TY() { $new->{position_sensitive} = 1; $y }
421     sub TW() { $new->{size_sensitive} = 1; $w }
422     sub TH() { $new->{size_sensitive} = 1; $h }
423    
424     =item now
425    
426     Returns the current time as (fractional) seconds since the epoch.
427    
428     Using this expression does I<not> make your expression sensitive to time,
429     but the next two functions do.
430    
431     =item again $seconds
432    
433     When this function is used the expression will be reevaluated again in
434     C<$seconds> seconds.
435    
436     Example: load some image and rotate it according to the time of day (as if it were
437     the hour pointer of a clock). Update this image every minute.
438    
439     again 60; rotate TW, TH, 50, 50, (now % 86400) * -720 / 86400, scale load "myclock.png"
440 root 1.28
441 root 1.45 =item counter $seconds
442    
443     Like C<again>, but also returns an increasing counter value, starting at
444     0, which might be useful for some simple animation effects.
445 root 1.28
446     =cut
447    
448 root 1.45 sub now() { urxvt::NOW }
449    
450     sub again($) {
451     $new->{again} = $_[0];
452     }
453    
454     sub counter($) {
455     $new->{again} = $_[0];
456     $self->{counter} + 0
457 root 1.28 }
458    
459 root 1.45 =back
460    
461     =head2 SHAPE CHANGING OPERATORS
462    
463     The following operators modify the shape, size or position of the image.
464    
465     =over 4
466    
467 root 1.28 =item clip $img
468    
469     =item clip $width, $height, $img
470    
471     =item clip $x, $y, $width, $height, $img
472    
473     Clips an image to the given rectangle. If the rectangle is outside the
474     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
475     larger than the image, then the tiling mode defines how the extra pixels
476     will be filled.
477    
478     If C<$x> an C<$y> are missing, then C<0> is assumed for both.
479    
480     If C<$width> and C<$height> are missing, then the window size will be
481     assumed.
482    
483     Example: load an image, blur it, and clip it to the window size to save
484     memory.
485    
486     clip blur 10, load "mybg.png"
487    
488     =cut
489    
490 root 1.20 sub clip($;$$;$$) {
491 root 1.7 my $img = pop;
492 root 1.30 my $h = pop || TH;
493     my $w = pop || TW;
494 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
495 root 1.4 }
496    
497 root 1.28 =item scale $img
498    
499 root 1.43 =item scale $size_factor, $img
500 root 1.28
501 root 1.43 =item scale $width_factor, $height_factor, $img
502 root 1.28
503 root 1.43 Scales the image by the given factors in horizontal
504     (C<$width>) and vertical (C<$height>) direction.
505 root 1.28
506 root 1.43 If only one factor is give, it is used for both directions.
507 root 1.28
508 root 1.43 If no factors are given, scales the image to the window size without
509 root 1.28 keeping aspect.
510    
511     =item resize $width, $height, $img
512    
513     Resizes the image to exactly C<$width> times C<$height> pixels.
514    
515 root 1.43 =item fit $img
516    
517     =item fit $width, $height, $img
518    
519     Fits the image into the given C<$width> and C<$height> without changing
520     aspect, or the terminal size. That means it will be shrunk or grown until
521     the whole image fits into the given area, possibly leaving borders.
522    
523     =item cover $img
524    
525     =item cover $width, $height, $img
526    
527     Similar to C<fit>, but shrinks or grows until all of the area is covered
528     by the image, so instead of potentially leaving borders, it will cut off
529     image data that doesn't fit.
530    
531 root 1.28 =cut
532    
533 root 1.33 sub scale($;$;$) {
534 root 1.28 my $img = pop;
535    
536 root 1.43 @_ == 2 ? $img->scale ($_[0] * $img->w, $_[1] * $img->h)
537     : @_ ? $img->scale ($_[0] * $img->w, $_[0] * $img->h)
538 root 1.30 : $img->scale (TW, TH)
539 root 1.28 }
540    
541 root 1.2 sub resize($$$) {
542 root 1.7 my $img = pop;
543     $img->scale ($_[0], $_[1])
544 root 1.1 }
545    
546 root 1.43 sub fit($;$$) {
547     my $img = pop;
548     my $w = ($_[0] || TW) / $img->w;
549     my $h = ($_[1] || TH) / $img->h;
550     scale +(min $w, $h), $img
551     }
552    
553     sub cover($;$$) {
554     my $img = pop;
555     my $w = ($_[0] || TW) / $img->w;
556     my $h = ($_[1] || TH) / $img->h;
557     scale +(max $w, $h), $img
558     }
559    
560 root 1.36 =item move $dx, $dy, $img
561    
562     Moves the image by C<$dx> pixels in the horizontal, and C<$dy> pixels in
563     the vertical.
564    
565     Example: move the image right by 20 pixels and down by 30.
566    
567     move 20, 30, ...
568    
569 root 1.46 =item align $xalign, $yalign, $img
570    
571     Aligns the image according to a factor - C<0> means the image is moved to
572     the left or top edge (for C<$xalign> or C<$yalign>), C<0.5> means it is
573     exactly centered and C<1> means it touches the right or bottom edge.
574    
575     Example: remove any visible border around an image, center it vertically but move
576     it to the right hand side.
577    
578     align 1, 0.5, pad $img
579    
580 root 1.44 =item center $img
581    
582     =item center $width, $height, $img
583    
584     Centers the image, i.e. the center of the image is moved to the center of
585     the terminal window (or the box specified by C<$width> and C<$height> if
586     given).
587    
588 root 1.46 Example: load an image and center it.
589    
590     center pad load "mybg.png"
591    
592 root 1.36 =item rootalign $img
593    
594     Moves the image so that it appears glued to the screen as opposed to the
595     window. This gives the illusion of a larger area behind the window. It is
596     exactly equivalent to C<move -TX, -TY>, that is, it moves the image to the
597     top left of the screen.
598    
599     Example: load a background image, put it in mirror mode and root align it.
600    
601     rootalign mirror load "mybg.png"
602    
603     Example: take the screen background and align it, giving the illusion of
604     transparency as long as the window isn't in front of other windows.
605    
606 root 1.46 rootalign root
607 root 1.36
608     =cut
609    
610 root 1.7 sub move($$;$) {
611 root 1.20 my $img = pop->clone;
612     $img->move ($_[0], $_[1]);
613     $img
614 root 1.1 }
615    
616 root 1.46 sub align($;$$) {
617     my $img = pop;
618    
619     move $_[0] * (TW - $img->w),
620     $_[1] * (TH - $img->h),
621     $img
622     }
623    
624 root 1.44 sub center($;$$) {
625     my $img = pop;
626     my $w = $_[0] || TW;
627 root 1.46 my $h = $_[1] || TH;
628 root 1.44
629     move 0.5 * ($w - $img->w), 0.5 * ($h - $img->h), $img
630     }
631    
632 root 1.36 sub rootalign($) {
633     move -TX, -TY, $_[0]
634 root 1.1 }
635    
636 root 1.45 =back
637    
638     =head2 COLOUR MODIFICATIONS
639    
640     The following operators change the pixels of the image.
641    
642     =over 4
643    
644 root 1.36 =item contrast $factor, $img
645    
646     =item contrast $r, $g, $b, $img
647    
648     =item contrast $r, $g, $b, $a, $img
649    
650     Adjusts the I<contrast> of an image.
651    
652 root 1.45 The first form applies a single C<$factor> to red, green and blue, the
653     second form applies separate factors to each colour channel, and the last
654     form includes the alpha channel.
655    
656     Values from 0 to 1 lower the contrast, values higher than 1 increase the
657     contrast.
658    
659     Due to limitations in the underlying XRender extension, lowering contrast
660     also reduces brightness, while increasing contrast currently also
661     increases brightness.
662 root 1.38
663 root 1.45 =item brightness $bias, $img
664 root 1.36
665     =item brightness $r, $g, $b, $img
666    
667     =item brightness $r, $g, $b, $a, $img
668    
669 root 1.38 Adjusts the brightness of an image.
670    
671 root 1.45 The first form applies a single C<$bias> to red, green and blue, the
672     second form applies separate biases to each colour channel, and the last
673     form includes the alpha channel.
674    
675     Values less than 0 reduce brightness, while values larger than 0 increase
676     it. Useful range is from -1 to 1 - the former results in a black, the
677     latter in a white picture.
678    
679     Due to idiosynchrasies in the underlying XRender extension, biases less
680     than zero can be I<very> slow.
681    
682 root 1.36 =cut
683 root 1.1
684 root 1.2 sub contrast($$;$$;$) {
685 root 1.7 my $img = pop;
686     my ($r, $g, $b, $a) = @_;
687 root 1.4
688 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
689     $a = 1 if @_ < 5;
690 root 1.4
691 root 1.1 $img = $img->clone;
692 root 1.37 $img->contrast ($r, $g, $b, $a);
693 root 1.1 $img
694     }
695    
696 root 1.2 sub brightness($$;$$;$) {
697 root 1.7 my $img = pop;
698     my ($r, $g, $b, $a) = @_;
699 root 1.4
700 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
701     $a = 1 if @_ < 5;
702 root 1.4
703 root 1.1 $img = $img->clone;
704     $img->brightness ($r, $g, $b, $a);
705     $img
706     }
707    
708 root 1.38 =item blur $radius, $img
709    
710     =item blur $radius_horz, $radius_vert, $img
711    
712     Gaussian-blurs the image with (roughly) C<$radius> pixel radius. The radii
713     can also be specified separately.
714    
715 root 1.39 Blurring is often I<very> slow, at least compared or other
716     operators. Larger blur radii are slower than smaller ones, too, so if you
717     don't want to freeze your screen for long times, start experimenting with
718     low values for radius (<5).
719    
720 root 1.38 =cut
721    
722 root 1.36 sub blur($$;$) {
723     my $img = pop;
724     $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
725     }
726    
727 root 1.38 =item rotate $new_width, $new_height, $center_x, $center_y, $degrees
728    
729     Rotates the image by C<$degrees> degrees, counter-clockwise, around the
730 root 1.43 pointer at C<$center_x> and C<$center_y> (specified as factor of image
731 root 1.38 width/height), generating a new image with width C<$new_width> and height
732     C<$new_height>.
733    
734     #TODO# new width, height, maybe more operators?
735    
736     Example: rotate the image by 90 degrees
737    
738     =cut
739    
740 root 1.36 sub rotate($$$$$$) {
741     my $img = pop;
742     $img->rotate (
743     $_[0],
744     $_[1],
745 root 1.43 $_[2] * $img->w,
746     $_[3] * $img->h,
747 root 1.36 $_[4] * (3.14159265 / 180),
748     )
749     }
750    
751 root 1.15 =back
752    
753     =cut
754    
755 root 1.1 }
756    
757     sub parse_expr {
758     my $expr = eval "sub {\npackage urxvt::bgdsl;\n#line 0 'background expression'\n$_[0]\n}";
759     die if $@;
760     $expr
761     }
762    
763     # compiles a parsed expression
764     sub set_expr {
765     my ($self, $expr) = @_;
766    
767     $self->{expr} = $expr;
768     $self->recalculate;
769     }
770    
771     # evaluate the current bg expression
772     sub recalculate {
773 root 1.33 my ($arg_self) = @_;
774 root 1.1
775 root 1.10 # rate limit evaluation
776    
777 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
778     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
779     $arg_self->recalculate;
780 root 1.9 });
781 root 1.12 return;
782 root 1.9 }
783    
784 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
785 root 1.9
786 root 1.10 # set environment to evaluate user expression
787 root 1.6
788 root 1.33 local $self = $arg_self;
789 root 1.1
790 root 1.36 local $HOME = $ENV{HOME};
791 root 1.3 local $old = $self->{state};
792     local $new = my $state = $self->{state} = {};
793 root 1.1
794 root 1.29 ($x, $y, $w, $h) =
795 root 1.33 $self->background_geometry ($self->{border});
796 root 1.22
797 root 1.10 # evaluate user expression
798    
799 root 1.1 my $img = eval { $self->{expr}->() };
800     warn $@ if $@;#d#
801 root 1.48 die "background-expr did not return an image.\n" if !UNIVERSAL::isa $img, "urxvt::img";
802 root 1.1
803 root 1.34 $state->{size_sensitive} = 1
804     if $img->repeat_mode != urxvt::RepeatNormal;
805    
806 root 1.10 # if the expression is sensitive to external events, prepare reevaluation then
807    
808 root 1.2 my $repeat;
809    
810 root 1.1 if (my $again = $state->{again}) {
811 root 1.2 $repeat = 1;
812 root 1.35 my $self = $self;
813 root 1.6 $state->{timer} = $again == $old->{again}
814     ? $old->{timer}
815 root 1.7 : urxvt::timer->new->after ($again)->interval ($again)->cb (sub {
816     ++$self->{counter};
817     $self->recalculate
818     });
819 root 1.1 }
820    
821 root 1.2 if (delete $state->{position_sensitive}) {
822     $repeat = 1;
823     $self->enable (position_change => sub { $_[0]->recalculate });
824     } else {
825     $self->disable ("position_change");
826     }
827    
828     if (delete $state->{size_sensitive}) {
829     $repeat = 1;
830     $self->enable (size_change => sub { $_[0]->recalculate });
831     } else {
832     $self->disable ("size_change");
833     }
834    
835 root 1.9 if (delete $state->{rootpmap_sensitive}) {
836     $repeat = 1;
837     $self->enable (rootpmap_change => sub { $_[0]->recalculate });
838     } else {
839     $self->disable ("rootpmap_change");
840     }
841    
842 root 1.10 # clear stuff we no longer need
843    
844 root 1.6 %$old = ();
845    
846 root 1.5 unless ($repeat) {
847     delete $self->{state};
848     delete $self->{expr};
849     }
850    
851 root 1.34 # set background pixmap
852 root 1.1
853 root 1.33 $self->set_background ($img, $self->{border});
854 root 1.1 $self->scr_recolour (0);
855     $self->want_refresh;
856     }
857    
858     sub on_start {
859     my ($self) = @_;
860    
861 root 1.47 my $expr = $self->x_resource ("%.expr")
862 root 1.33 or return;
863    
864 root 1.48 $self->has_render
865     or die "background extension needs RENDER extension 0.10 or higher, ignoring background-expr.\n";
866    
867 root 1.33 $self->set_expr (parse_expr $expr);
868 root 1.47 $self->{border} = $self->x_resource_boolean ("%.border");
869 root 1.1
870 root 1.47 $MIN_INTERVAL = $self->x_resource ("%.interval");
871 root 1.46
872 root 1.1 ()
873     }
874