ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.76
Committed: Tue Aug 14 23:57:07 2012 UTC (11 years, 9 months ago) by root
Branch: MAIN
Changes since 1.75: +2 -0 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.75 =head1 QUICK AND DIRTY CHEAT SHEET
18    
19     Just load a random jpeg image and tile the background with it without
20     scaling or anything else:
21    
22     load "/path/to/img.jpg"
23    
24     The same, but use mirroring/reflection instead of tiling:
25    
26     mirror load "/path/to/img.jpg"
27    
28     Load an image and scale it to exactly fill the terminal window:
29    
30     scale keep { load "/path/to/img.jpg" }
31    
32     Implement pseudo-transparency by using a suitably-aligned root pixmap
33     as window background:
34    
35     rootalign root
36    
37     Likewise, but keep a blurred copy:
38    
39     rootalign keep { blur 10, root }
40    
41 root 1.41 =head1 DESCRIPTION
42 root 1.33
43 root 1.36 This extension manages the terminal background by creating a picture that
44     is behind the text, replacing the normal background colour.
45    
46     It does so by evaluating a Perl expression that I<calculates> the image on
47     the fly, for example, by grabbing the root background or loading a file.
48    
49     While the full power of Perl is available, the operators have been design
50     to be as simple as possible.
51    
52     For example, to load an image and scale it to the window size, you would
53     use:
54    
55 root 1.64 urxvt --background-expr 'scale keep { load "/path/to/mybg.png" }'
56 root 1.36
57     Or specified as a X resource:
58    
59 root 1.64 URxvt.background-expr: scale keep { load "/path/to/mybg.png" }
60 root 1.36
61 root 1.41 =head1 THEORY OF OPERATION
62 root 1.36
63     At startup, just before the window is mapped for the first time, the
64     expression is evaluated and must yield an image. The image is then
65     extended as necessary to cover the whole terminal window, and is set as a
66     background pixmap.
67    
68     If the image contains an alpha channel, then it will be used as-is in
69     visuals that support alpha channels (for example, for a compositing
70     manager). In other visuals, the terminal background colour will be used to
71     replace any transparency.
72    
73     When the expression relies, directly or indirectly, on the window size,
74     position, the root pixmap, or a timer, then it will be remembered. If not,
75     then it will be removed.
76    
77     If any of the parameters that the expression relies on changes (when the
78     window is moved or resized, its position or size changes; when the root
79     pixmap is replaced by another one the root background changes; or when the
80     timer elapses), then the expression will be evaluated again.
81    
82 root 1.64 For example, an expression such as C<scale keep { load "$HOME/mybg.png"
83     }> scales the image to the window size, so it relies on the window size
84     and will be reevaluated each time it is changed, but not when it moves for
85 root 1.36 example. That ensures that the picture always fills the terminal, even
86 sf-exg 1.51 after its size changes.
87 root 1.36
88 root 1.41 =head2 EXPRESSIONS
89 root 1.36
90     Expressions are normal Perl expressions, in fact, they are Perl blocks -
91     which means you could use multiple lines and statements:
92    
93 root 1.64 scale keep {
94     again 3600;
95     if (localtime now)[6]) {
96     return load "$HOME/weekday.png";
97     } else {
98     return load "$HOME/sunday.png";
99     }
100 root 1.36 }
101    
102 root 1.68 This inner expression is evaluated once per hour (and whenever the
103 sf-exg 1.73 terminal window is resized). It sets F<sunday.png> as background on
104 root 1.68 Sundays, and F<weekday.png> on all other days.
105 root 1.36
106     Fortunately, we expect that most expressions will be much simpler, with
107     little Perl knowledge needed.
108    
109     Basically, you always start with a function that "generates" an image
110     object, such as C<load>, which loads an image from disk, or C<root>, which
111     returns the root window background image:
112    
113     load "$HOME/mypic.png"
114    
115     The path is usually specified as a quoted string (the exact rules can be
116     found in the L<perlop> manpage). The F<$HOME> at the beginning of the
117     string is expanded to the home directory.
118    
119     Then you prepend one or more modifiers or filtering expressions, such as
120     C<scale>:
121    
122     scale load "$HOME/mypic.png"
123    
124     Just like a mathematical expression with functions, you should read these
125     expressions from right to left, as the C<load> is evaluated first, and
126     its result becomes the argument to the C<scale> function.
127    
128     Many operators also allow some parameters preceding the input image
129     that modify its behaviour. For example, C<scale> without any additional
130     arguments scales the image to size of the terminal window. If you specify
131 root 1.43 an additional argument, it uses it as a scale factor (multiply by 100 to
132     get a percentage):
133 root 1.36
134 root 1.43 scale 2, load "$HOME/mypic.png"
135 root 1.36
136     This enlarges the image by a factor of 2 (200%). As you can see, C<scale>
137     has now two arguments, the C<200> and the C<load> expression, while
138     C<load> only has one argument. Arguments are separated from each other by
139     commas.
140    
141     Scale also accepts two arguments, which are then separate factors for both
142     horizontal and vertical dimensions. For example, this halves the image
143     width and doubles the image height:
144    
145 root 1.43 scale 0.5, 2, load "$HOME/mypic.png"
146 root 1.36
147 root 1.68 IF you try out these expressions, you might suffer from some sluggishness,
148 sf-exg 1.73 because each time the terminal is resized, it loads the PNG image again
149 root 1.68 and scales it. Scaling is usually fast (and unavoidable), but loading the
150     image can be quite time consuming. This is where C<keep> comes in handy:
151 root 1.39
152 root 1.64 scale 0.5, 2, keep { load "$HOME/mypic.png" }
153 root 1.39
154 root 1.64 The C<keep> operator executes all the statements inside the braces only
155     once, or when it thinks the outcome might change. In other cases it
156     returns the last value computed by the brace block.
157 root 1.39
158 root 1.64 This means that the C<load> is only executed once, which makes it much
159 sf-exg 1.65 faster, but also means that more memory is being used, because the loaded
160 root 1.64 image must be kept in memory at all times. In this expression, the
161     trade-off is likely worth it.
162 root 1.39
163 root 1.64 But back to effects: Other effects than scaling are also readily
164     available, for example, you can tile the image to fill the whole window,
165     instead of resizing it:
166 root 1.39
167 root 1.64 tile keep { load "$HOME/mypic.png" }
168 root 1.39
169 root 1.64 In fact, images returned by C<load> are in C<tile> mode by default, so the
170     C<tile> operator is kind of superfluous.
171 root 1.39
172 root 1.64 Another common effect is to mirror the image, so that the same edges
173     touch:
174 root 1.36
175 root 1.64 mirror keep { load "$HOME/mypic.png" }
176 root 1.36
177 root 1.64 Another common background expression is:
178 root 1.63
179 root 1.64 rootalign root
180 root 1.39
181 root 1.64 This one first takes a snapshot of the screen background image, and then
182 sf-exg 1.65 moves it to the upper left corner of the screen (as opposed to the upper
183 root 1.64 left corner of the terminal window)- the result is pseudo-transparency:
184     the image seems to be static while the window is moved around.
185    
186 root 1.71 =head2 COLOUR SPECIFICATIONS
187    
188 sf-exg 1.73 Whenever an operator expects a "colour", then this can be specified in one
189 root 1.71 of two ways: Either as string with an X11 colour specification, such as:
190    
191     "red" # named colour
192     "#f00" # simple rgb
193     "[50]red" # red with 50% alpha
194     "TekHVC:300/50/50" # anything goes
195    
196     OR as an array reference with one, three or four components:
197    
198     [0.5] # 50% gray, 100% alpha
199     [0.5, 0, 0] # dark red, no green or blur, 100% alpha
200     [0.5, 0, 0, 0.7] # same with explicit 70% alpha
201    
202 root 1.64 =head2 CACHING AND SENSITIVITY
203    
204     Since some operations (such as C<load> and C<blur>) can take a long time,
205     caching results can be very important for a smooth operation. Caching can
206     also be useful to reduce memory usage, though, for example, when an image
207     is cached by C<load>, it could be shared by multiple terminal windows
208     running inside urxvtd.
209    
210     =head3 C<keep { ... }> caching
211    
212     The most important way to cache expensive operations is to use C<keep {
213     ... }>. The C<keep> operator takes a block of multiple statements enclosed
214     by C<{}> and keeps the return value in memory.
215    
216     An expression can be "sensitive" to various external events, such as
217 sf-exg 1.65 scaling or moving the window, root background changes and timers. Simply
218 sf-exg 1.67 using an expression (such as C<scale> without parameters) that depends on
219 root 1.64 certain changing values (called "variables"), or using those variables
220     directly, will make an expression sensitive to these events - for example,
221     using C<scale> or C<TW> will make the expression sensitive to the terminal
222     size, and thus to resizing events.
223 root 1.39
224 root 1.64 When such an event happens, C<keep> will automatically trigger a
225     reevaluation of the whole expression with the new value of the expression.
226 root 1.39
227 root 1.64 C<keep> is most useful for expensive operations, such as C<blur>:
228 root 1.39
229 root 1.68 rootalign keep { blur 20, root }
230 root 1.39
231 root 1.64 This makes a blurred copy of the root background once, and on subsequent
232     calls, just root-aligns it. Since C<blur> is usually quite slow and
233     C<rootalign> is quite fast, this trades extra memory (for the cached
234     blurred pixmap) with speed (blur only needs to be redone when root
235     changes).
236 root 1.39
237 root 1.64 =head3 C<load> caching
238 root 1.36
239 root 1.64 The C<load> operator itself does not keep images in memory, but as long as
240     the image is still in memory, C<load> will use the in-memory image instead
241     of loading it freshly from disk.
242 root 1.63
243 root 1.64 That means that this expression:
244 root 1.63
245 root 1.64 keep { load "$HOME/path..." }
246 root 1.63
247 root 1.64 Not only caches the image in memory, other terminal instances that try to
248     C<load> it can reuse that in-memory copy.
249 root 1.63
250 root 1.41 =head1 REFERENCE
251 root 1.33
252 root 1.41 =head2 COMMAND LINE SWITCHES
253 root 1.36
254     =over 4
255    
256     =item --background-expr perl-expression
257    
258     Specifies the Perl expression to evaluate.
259    
260     =item --background-border
261    
262     By default, the expression creates an image that fills the full window,
263     overwriting borders and any other areas, such as the scrollbar.
264    
265     Specifying this flag changes the behaviour, so that the image only
266     replaces the background of the character area.
267    
268 root 1.46 =item --background-interval seconds
269    
270 sf-exg 1.51 Since some operations in the underlying XRender extension can effectively
271 root 1.46 freeze your X-server for prolonged time, this extension enforces a minimum
272     time between updates, which is normally about 0.1 seconds.
273    
274     If you want to do updates more often, you can decrease this safety
275     interval with this switch.
276    
277 root 1.36 =back
278    
279 root 1.33 =cut
280 root 1.12
281 root 1.52 our %_IMG_CACHE;
282 root 1.36 our $HOME;
283 root 1.63 our ($self, $frame);
284 root 1.29 our ($x, $y, $w, $h);
285 root 1.3
286 root 1.16 # enforce at least this interval between updates
287 root 1.46 our $MIN_INTERVAL = 6/59.951;
288 root 1.9
289 root 1.1 {
290     package urxvt::bgdsl; # background language
291    
292 root 1.63 sub FR_PARENT() { 0 } # parent frame, if any - must be #0
293     sub FR_CACHE () { 1 } # cached values
294     sub FR_AGAIN () { 2 } # what this expr is sensitive to
295     sub FR_STATE () { 3 } # watchers etc.
296    
297 root 1.43 use List::Util qw(min max sum shuffle);
298    
299 root 1.15 =head2 PROVIDERS/GENERATORS
300    
301 root 1.31 These functions provide an image, by loading it from disk, grabbing it
302 sf-exg 1.32 from the root screen or by simply generating it. They are used as starting
303 root 1.31 points to get an image you can play with.
304    
305 root 1.15 =over 4
306    
307     =item load $path
308    
309 root 1.29 Loads the image at the given C<$path>. The image is set to plane tiling
310     mode.
311    
312 sf-exg 1.65 If the image is already in memory (e.g. because another terminal instance
313 root 1.64 uses it), then the in-memory copy us returned instead.
314 root 1.54
315 root 1.64 =item load_uc $path
316    
317     Load uncached - same as load, but does not cache the image, which means it
318 root 1.72 is I<always> loaded from the filesystem again, even if another copy of it
319     is in memory at the time.
320 root 1.29
321 root 1.15 =cut
322    
323 root 1.72 sub load_uc($) {
324     $self->new_img_from_file ($_[0])
325     }
326    
327 root 1.63 sub load($) {
328 root 1.54 my ($path) = @_;
329    
330     $_IMG_CACHE{$path} || do {
331 root 1.72 my $img = load_uc $path;
332 root 1.54 Scalar::Util::weaken ($_IMG_CACHE{$path} = $img);
333     $img
334     }
335     }
336    
337 root 1.31 =item root
338    
339     Returns the root window pixmap, that is, hopefully, the background image
340 root 1.62 of your screen.
341 root 1.31
342     This function makes your expression root sensitive, that means it will be
343     reevaluated when the bg image changes.
344    
345     =cut
346    
347 root 1.2 sub root() {
348 root 1.63 $frame->[FR_AGAIN]{rootpmap} = 1;
349 root 1.52 $self->new_img_from_root
350 root 1.1 }
351    
352 root 1.31 =item solid $colour
353    
354     =item solid $width, $height, $colour
355    
356     Creates a new image and completely fills it with the given colour. The
357     image is set to tiling mode.
358    
359 root 1.40 If C<$width> and C<$height> are omitted, it creates a 1x1 image, which is
360 root 1.31 useful for solid backgrounds or for use in filtering effects.
361    
362     =cut
363    
364 root 1.42 sub solid($;$$) {
365 root 1.31 my $colour = pop;
366    
367 root 1.59 my $img = $self->new_img (urxvt::PictStandardARGB32, 0, 0, $_[0] || 1, $_[1] || 1);
368 root 1.31 $img->fill ($colour);
369 root 1.15 $img
370     }
371    
372 root 1.45 =item clone $img
373 root 1.31
374 root 1.45 Returns an exact copy of the image. This is useful if you want to have
375     multiple copies of the same image to apply different effects to.
376 root 1.31
377 root 1.20 =cut
378    
379 root 1.45 sub clone($) {
380     $_[0]->clone
381 root 1.20 }
382    
383 root 1.56 =item merge $img ...
384    
385 root 1.57 Takes any number of images and merges them together, creating a single
386 root 1.62 image containing them all. The tiling mode of the first image is used as
387 sf-exg 1.65 the tiling mode of the resulting image.
388 root 1.56
389 root 1.61 This function is called automatically when an expression returns multiple
390     images.
391    
392 root 1.56 =cut
393    
394     sub merge(@) {
395 root 1.61 return $_[0] unless $#_;
396    
397 root 1.58 # rather annoyingly clumsy, but optimisation is for another time
398    
399 root 1.59 my $x0 = +1e9;
400     my $y0 = +1e9;
401 root 1.58 my $x1 = -1e9;
402     my $y1 = -1e9;
403    
404     for (@_) {
405     my ($x, $y, $w, $h) = $_->geometry;
406    
407     $x0 = $x if $x0 > $x;
408     $y0 = $y if $y0 > $y;
409    
410     $x += $w;
411     $y += $h;
412    
413 root 1.59 $x1 = $x if $x1 < $x;
414     $y1 = $y if $y1 < $y;
415 root 1.58 }
416    
417 root 1.59 my $base = $self->new_img (urxvt::PictStandardARGB32, $x0, $y0, $x1 - $x0, $y1 - $y0);
418 root 1.62 $base->repeat_mode ($_[0]->repeat_mode);
419 root 1.58 $base->fill ([0, 0, 0, 0]);
420    
421 root 1.59 $base->draw ($_)
422 root 1.58 for @_;
423    
424     $base
425 root 1.56 }
426    
427 root 1.76 =back
428    
429 root 1.28 =head2 TILING MODES
430    
431     The following operators modify the tiling mode of an image, that is, the
432     way that pixels outside the image area are painted when the image is used.
433 root 1.15
434     =over 4
435    
436 root 1.28 =item tile $img
437    
438     Tiles the whole plane with the image and returns this new image - or in
439     other words, it returns a copy of the image in plane tiling mode.
440    
441 root 1.34 Example: load an image and tile it over the background, without
442     resizing. The C<tile> call is superfluous because C<load> already defaults
443     to tiling mode.
444    
445     tile load "mybg.png"
446    
447 root 1.28 =item mirror $img
448    
449     Similar to tile, but reflects the image each time it uses a new copy, so
450     that top edges always touch top edges, right edges always touch right
451     edges and so on (with normal tiling, left edges always touch right edges
452     and top always touch bottom edges).
453    
454 root 1.36 Example: load an image and mirror it over the background, avoiding sharp
455 root 1.34 edges at the image borders at the expense of mirroring the image itself
456    
457     mirror load "mybg.png"
458    
459 root 1.28 =item pad $img
460    
461     Takes an image and modifies it so that all pixels outside the image area
462     become transparent. This mode is most useful when you want to place an
463     image over another image or the background colour while leaving all
464     background pixels outside the image unchanged.
465    
466 root 1.36 Example: load an image and display it in the upper left corner. The rest
467 sf-exg 1.51 of the space is left "empty" (transparent or whatever your compositor does
468 root 1.34 in alpha mode, else background colour).
469    
470     pad load "mybg.png"
471    
472 root 1.28 =item extend $img
473    
474     Extends the image over the whole plane, using the closest pixel in the
475 sf-exg 1.51 area outside the image. This mode is mostly useful when you use more complex
476 root 1.28 filtering operations and want the pixels outside the image to have the
477     same values as the pixels near the edge.
478    
479 root 1.34 Example: just for curiosity, how does this pixel extension stuff work?
480    
481     extend move 50, 50, load "mybg.png"
482    
483 root 1.15 =cut
484    
485 root 1.28 sub pad($) {
486     my $img = $_[0]->clone;
487     $img->repeat_mode (urxvt::RepeatNone);
488     $img
489     }
490    
491     sub tile($) {
492     my $img = $_[0]->clone;
493     $img->repeat_mode (urxvt::RepeatNormal);
494     $img
495     }
496    
497     sub mirror($) {
498     my $img = $_[0]->clone;
499     $img->repeat_mode (urxvt::RepeatReflect);
500     $img
501     }
502 root 1.4
503 root 1.28 sub extend($) {
504 root 1.24 my $img = $_[0]->clone;
505 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
506 root 1.24 $img
507     }
508    
509 root 1.28 =back
510    
511 root 1.45 =head2 VARIABLE VALUES
512 root 1.28
513 root 1.45 The following functions provide variable data such as the terminal window
514     dimensions. They are not (Perl-) variables, they just return stuff that
515     varies. Most of them make your expression sensitive to some events, for
516     example using C<TW> (terminal width) means your expression is evaluated
517     again when the terminal is resized.
518 root 1.28
519     =over 4
520    
521 root 1.45 =item TX
522    
523     =item TY
524    
525     Return the X and Y coordinates of the terminal window (the terminal
526     window is the full window by default, and the character area only when in
527     border-respect mode).
528    
529     Using these functions make your expression sensitive to window moves.
530    
531     These functions are mainly useful to align images to the root window.
532    
533     Example: load an image and align it so it looks as if anchored to the
534 root 1.64 background (that's exactly what C<rootalign> does btw.):
535 root 1.45
536 root 1.64 move -TX, -TY, keep { load "mybg.png" }
537 root 1.45
538     =item TW
539    
540     Return the width (C<TW>) and height (C<TH>) of the terminal window (the
541     terminal window is the full window by default, and the character area only
542     when in border-respect mode).
543    
544     Using these functions make your expression sensitive to window resizes.
545    
546     These functions are mainly useful to scale images, or to clip images to
547     the window size to conserve memory.
548    
549     Example: take the screen background, clip it to the window size, blur it a
550     bit, align it to the window position and use it as background.
551    
552 root 1.64 clip move -TX, -TY, keep { blur 5, root }
553 root 1.45
554     =cut
555    
556 root 1.63 sub TX() { $frame->[FR_AGAIN]{position} = 1; $x }
557     sub TY() { $frame->[FR_AGAIN]{position} = 1; $y }
558     sub TW() { $frame->[FR_AGAIN]{size} = 1; $w }
559     sub TH() { $frame->[FR_AGAIN]{size} = 1; $h }
560 root 1.45
561     =item now
562    
563     Returns the current time as (fractional) seconds since the epoch.
564    
565     Using this expression does I<not> make your expression sensitive to time,
566     but the next two functions do.
567    
568     =item again $seconds
569    
570     When this function is used the expression will be reevaluated again in
571     C<$seconds> seconds.
572    
573     Example: load some image and rotate it according to the time of day (as if it were
574     the hour pointer of a clock). Update this image every minute.
575    
576 root 1.64 again 60;
577     rotate 50, 50, (now % 86400) * -72 / 8640, scale keep { load "myclock.png" }
578 root 1.28
579 root 1.45 =item counter $seconds
580    
581     Like C<again>, but also returns an increasing counter value, starting at
582     0, which might be useful for some simple animation effects.
583 root 1.28
584     =cut
585    
586 root 1.45 sub now() { urxvt::NOW }
587    
588     sub again($) {
589 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
590 root 1.45 }
591    
592     sub counter($) {
593 root 1.63 $frame->[FR_AGAIN]{time} = $_[0];
594     $frame->[FR_STATE]{counter} + 0
595 root 1.28 }
596    
597 root 1.45 =back
598    
599     =head2 SHAPE CHANGING OPERATORS
600    
601     The following operators modify the shape, size or position of the image.
602    
603     =over 4
604    
605 root 1.28 =item clip $img
606    
607     =item clip $width, $height, $img
608    
609     =item clip $x, $y, $width, $height, $img
610    
611     Clips an image to the given rectangle. If the rectangle is outside the
612     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
613     larger than the image, then the tiling mode defines how the extra pixels
614     will be filled.
615    
616     If C<$x> an C<$y> are missing, then C<0> is assumed for both.
617    
618     If C<$width> and C<$height> are missing, then the window size will be
619     assumed.
620    
621     Example: load an image, blur it, and clip it to the window size to save
622     memory.
623    
624 root 1.64 clip keep { blur 10, load "mybg.png" }
625 root 1.28
626     =cut
627    
628 root 1.20 sub clip($;$$;$$) {
629 root 1.7 my $img = pop;
630 root 1.30 my $h = pop || TH;
631     my $w = pop || TW;
632 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
633 root 1.4 }
634    
635 root 1.28 =item scale $img
636    
637 root 1.43 =item scale $size_factor, $img
638 root 1.28
639 root 1.43 =item scale $width_factor, $height_factor, $img
640 root 1.28
641 root 1.43 Scales the image by the given factors in horizontal
642     (C<$width>) and vertical (C<$height>) direction.
643 root 1.28
644 root 1.43 If only one factor is give, it is used for both directions.
645 root 1.28
646 root 1.43 If no factors are given, scales the image to the window size without
647 root 1.28 keeping aspect.
648    
649     =item resize $width, $height, $img
650    
651     Resizes the image to exactly C<$width> times C<$height> pixels.
652    
653 root 1.43 =item fit $img
654    
655     =item fit $width, $height, $img
656    
657     Fits the image into the given C<$width> and C<$height> without changing
658     aspect, or the terminal size. That means it will be shrunk or grown until
659     the whole image fits into the given area, possibly leaving borders.
660    
661     =item cover $img
662    
663     =item cover $width, $height, $img
664    
665     Similar to C<fit>, but shrinks or grows until all of the area is covered
666     by the image, so instead of potentially leaving borders, it will cut off
667     image data that doesn't fit.
668    
669 root 1.28 =cut
670    
671 root 1.33 sub scale($;$;$) {
672 root 1.28 my $img = pop;
673    
674 root 1.43 @_ == 2 ? $img->scale ($_[0] * $img->w, $_[1] * $img->h)
675     : @_ ? $img->scale ($_[0] * $img->w, $_[0] * $img->h)
676 root 1.30 : $img->scale (TW, TH)
677 root 1.28 }
678    
679 root 1.2 sub resize($$$) {
680 root 1.7 my $img = pop;
681     $img->scale ($_[0], $_[1])
682 root 1.1 }
683    
684 root 1.43 sub fit($;$$) {
685     my $img = pop;
686     my $w = ($_[0] || TW) / $img->w;
687     my $h = ($_[1] || TH) / $img->h;
688     scale +(min $w, $h), $img
689     }
690    
691     sub cover($;$$) {
692     my $img = pop;
693     my $w = ($_[0] || TW) / $img->w;
694     my $h = ($_[1] || TH) / $img->h;
695     scale +(max $w, $h), $img
696     }
697    
698 root 1.36 =item move $dx, $dy, $img
699    
700     Moves the image by C<$dx> pixels in the horizontal, and C<$dy> pixels in
701     the vertical.
702    
703     Example: move the image right by 20 pixels and down by 30.
704    
705     move 20, 30, ...
706    
707 root 1.46 =item align $xalign, $yalign, $img
708    
709     Aligns the image according to a factor - C<0> means the image is moved to
710     the left or top edge (for C<$xalign> or C<$yalign>), C<0.5> means it is
711     exactly centered and C<1> means it touches the right or bottom edge.
712    
713     Example: remove any visible border around an image, center it vertically but move
714     it to the right hand side.
715    
716     align 1, 0.5, pad $img
717    
718 root 1.44 =item center $img
719    
720     =item center $width, $height, $img
721    
722     Centers the image, i.e. the center of the image is moved to the center of
723     the terminal window (or the box specified by C<$width> and C<$height> if
724     given).
725    
726 root 1.46 Example: load an image and center it.
727    
728 root 1.64 center keep { pad load "mybg.png" }
729 root 1.46
730 root 1.36 =item rootalign $img
731    
732     Moves the image so that it appears glued to the screen as opposed to the
733     window. This gives the illusion of a larger area behind the window. It is
734     exactly equivalent to C<move -TX, -TY>, that is, it moves the image to the
735     top left of the screen.
736    
737     Example: load a background image, put it in mirror mode and root align it.
738    
739 root 1.64 rootalign keep { mirror load "mybg.png" }
740 root 1.36
741     Example: take the screen background and align it, giving the illusion of
742     transparency as long as the window isn't in front of other windows.
743    
744 root 1.46 rootalign root
745 root 1.36
746     =cut
747    
748 root 1.7 sub move($$;$) {
749 root 1.20 my $img = pop->clone;
750     $img->move ($_[0], $_[1]);
751     $img
752 root 1.1 }
753    
754 root 1.46 sub align($;$$) {
755     my $img = pop;
756    
757     move $_[0] * (TW - $img->w),
758     $_[1] * (TH - $img->h),
759     $img
760     }
761    
762 root 1.44 sub center($;$$) {
763     my $img = pop;
764     my $w = $_[0] || TW;
765 root 1.46 my $h = $_[1] || TH;
766 root 1.44
767     move 0.5 * ($w - $img->w), 0.5 * ($h - $img->h), $img
768     }
769    
770 root 1.36 sub rootalign($) {
771     move -TX, -TY, $_[0]
772 root 1.1 }
773    
774 root 1.64 =item rotate $center_x, $center_y, $degrees, $img
775 root 1.52
776 root 1.64 Rotates the image clockwise by C<$degrees> degrees, around the point at
777     C<$center_x> and C<$center_y> (specified as factor of image width/height).
778 root 1.52
779 root 1.64 Example: rotate the image by 90 degrees around it's center.
780 root 1.52
781 root 1.64 rotate 0.5, 0.5, 90, keep { load "$HOME/mybg.png" }
782 root 1.52
783     =cut
784    
785 root 1.53 sub rotate($$$$) {
786 root 1.52 my $img = pop;
787     $img->rotate (
788 root 1.60 $_[0] * ($img->w + $img->x),
789     $_[1] * ($img->h + $img->y),
790 root 1.52 $_[2] * (3.14159265 / 180),
791     )
792     }
793    
794 root 1.45 =back
795    
796     =head2 COLOUR MODIFICATIONS
797    
798     The following operators change the pixels of the image.
799    
800     =over 4
801    
802 root 1.70 =item tint $color, $img
803    
804     Tints the image in the given colour.
805    
806     Example: tint the image red.
807    
808     tint "red", load "rgb.png"
809    
810     Example: the same, but specify the colour by component.
811    
812     tint [1, 0, 0], load "rgb.png"
813    
814     =cut
815    
816     sub tint($$) {
817     $_[1]->tint ($_[0])
818     }
819    
820 root 1.36 =item contrast $factor, $img
821    
822     =item contrast $r, $g, $b, $img
823    
824     =item contrast $r, $g, $b, $a, $img
825    
826     Adjusts the I<contrast> of an image.
827    
828 root 1.45 The first form applies a single C<$factor> to red, green and blue, the
829     second form applies separate factors to each colour channel, and the last
830     form includes the alpha channel.
831    
832     Values from 0 to 1 lower the contrast, values higher than 1 increase the
833     contrast.
834    
835     Due to limitations in the underlying XRender extension, lowering contrast
836     also reduces brightness, while increasing contrast currently also
837     increases brightness.
838 root 1.38
839 root 1.45 =item brightness $bias, $img
840 root 1.36
841     =item brightness $r, $g, $b, $img
842    
843     =item brightness $r, $g, $b, $a, $img
844    
845 root 1.38 Adjusts the brightness of an image.
846    
847 root 1.45 The first form applies a single C<$bias> to red, green and blue, the
848     second form applies separate biases to each colour channel, and the last
849     form includes the alpha channel.
850    
851     Values less than 0 reduce brightness, while values larger than 0 increase
852     it. Useful range is from -1 to 1 - the former results in a black, the
853     latter in a white picture.
854    
855 sf-exg 1.51 Due to idiosyncrasies in the underlying XRender extension, biases less
856 root 1.45 than zero can be I<very> slow.
857    
858 root 1.75 You can also try the experimental(!) C<muladd> operator.
859    
860 root 1.36 =cut
861 root 1.1
862 root 1.2 sub contrast($$;$$;$) {
863 root 1.7 my $img = pop;
864     my ($r, $g, $b, $a) = @_;
865 root 1.4
866 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
867     $a = 1 if @_ < 4;
868 root 1.4
869 root 1.1 $img = $img->clone;
870 root 1.37 $img->contrast ($r, $g, $b, $a);
871 root 1.1 $img
872     }
873    
874 root 1.2 sub brightness($$;$$;$) {
875 root 1.7 my $img = pop;
876     my ($r, $g, $b, $a) = @_;
877 root 1.4
878 root 1.49 ($g, $b) = ($r, $r) if @_ < 3;
879     $a = 1 if @_ < 4;
880 root 1.4
881 root 1.1 $img = $img->clone;
882     $img->brightness ($r, $g, $b, $a);
883     $img
884     }
885    
886 root 1.75 =item muladd $mul, $add, $img # EXPERIMENTAL
887    
888     First multipliesthe pixels by C<$mul>, then adds C<$add>. This cna be used
889     to implement brightness and contrast at the same time, with a wider value
890     range than contrast and brightness operators.
891    
892     Due to numerous bugs in XRender implementations, it can also introduce a
893     number of visual artifacts.
894    
895     Example: increase contrast by a factor of C<$c> without changing image
896     brightness too much.
897    
898     muladd $c, (1 - $c) * 0.5, $img
899    
900     =cut
901    
902     sub muladd($$$) {
903     $_[2]->muladd ($_[0], $_[1])
904     }
905    
906 root 1.38 =item blur $radius, $img
907    
908     =item blur $radius_horz, $radius_vert, $img
909    
910     Gaussian-blurs the image with (roughly) C<$radius> pixel radius. The radii
911     can also be specified separately.
912    
913 root 1.39 Blurring is often I<very> slow, at least compared or other
914     operators. Larger blur radii are slower than smaller ones, too, so if you
915     don't want to freeze your screen for long times, start experimenting with
916     low values for radius (<5).
917    
918 root 1.38 =cut
919    
920 root 1.36 sub blur($$;$) {
921     my $img = pop;
922     $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
923     }
924    
925 root 1.52 =back
926    
927     =head2 OTHER STUFF
928 root 1.38
929 root 1.56 Anything that didn't fit any of the other categories, even after applying
930 root 1.52 force and closing our eyes.
931    
932     =over 4
933    
934 root 1.66 =item keep { ... }
935 root 1.52
936 root 1.66 This operator takes a code block as argument, that is, one or more
937 root 1.52 statements enclosed by braces.
938    
939 root 1.68 The trick is that this code block is only evaluated when the outcome
940     changes - on other calls the C<keep> simply returns the image it computed
941     previously (yes, it should only be used with images). Or in other words,
942     C<keep> I<caches> the result of the code block so it doesn't need to be
943     computed again.
944    
945     This can be extremely useful to avoid redoing slow operations - for
946     example, if your background expression takes the root background, blurs it
947     and then root-aligns it it would have to blur the root background on every
948     window move or resize.
949    
950     Another example is C<load>, which can be quite slow.
951 root 1.52
952 root 1.63 In fact, urxvt itself encloses the whole expression in some kind of
953 root 1.68 C<keep> block so it only is reevaluated as required.
954 root 1.63
955 root 1.68 Putting the blur into a C<keep> block will make sure the blur is only done
956     once, while the C<rootalign> is still done each time the window moves.
957 root 1.52
958 sf-exg 1.73 rootalign keep { blur 10, root }
959 root 1.52
960 root 1.63 This leaves the question of how to force reevaluation of the block,
961     in case the root background changes: If expression inside the block
962     is sensitive to some event (root background changes, window geometry
963     changes), then it will be reevaluated automatically as needed.
964 root 1.38
965     =cut
966    
967 root 1.68 sub keep(&) {
968 root 1.63 my $id = $_[0]+0;
969    
970     local $frame = $self->{frame_cache}{$id} ||= [$frame];
971    
972     unless ($frame->[FR_CACHE]) {
973     $frame->[FR_CACHE] = [ $_[0]() ];
974    
975     my $self = $self;
976     my $frame = $frame;
977     Scalar::Util::weaken $frame;
978     $self->compile_frame ($frame, sub {
979     # clear this frame cache, also for all parents
980     for (my $frame = $frame; $frame; $frame = $frame->[0]) {
981     undef $frame->[FR_CACHE];
982     }
983    
984     $self->recalculate;
985     });
986 root 1.55 };
987    
988     # in scalar context we always return the first original result, which
989     # is not quite how perl works.
990     wantarray
991 root 1.63 ? @{ $frame->[FR_CACHE] }
992     : $frame->[FR_CACHE][0]
993 root 1.52 }
994    
995 root 1.68 # sub keep_clear() {
996     # delete $self->{frame_cache};
997     # }
998 root 1.36
999 root 1.15 =back
1000    
1001     =cut
1002    
1003 root 1.1 }
1004    
1005     sub parse_expr {
1006 root 1.63 my $expr = eval
1007     "sub {\n"
1008     . "package urxvt::bgdsl;\n"
1009     . "#line 0 'background expression'\n"
1010     . "$_[0]\n"
1011     . "}";
1012 root 1.1 die if $@;
1013     $expr
1014     }
1015    
1016     # compiles a parsed expression
1017     sub set_expr {
1018     my ($self, $expr) = @_;
1019    
1020 root 1.74 $self->{root} = []; # the outermost frame
1021 root 1.1 $self->{expr} = $expr;
1022     $self->recalculate;
1023     }
1024    
1025 root 1.63 # takes a hash of sensitivity indicators and installs watchers
1026     sub compile_frame {
1027     my ($self, $frame, $cb) = @_;
1028    
1029     my $state = $frame->[urxvt::bgdsl::FR_STATE] ||= {};
1030     my $again = $frame->[urxvt::bgdsl::FR_AGAIN];
1031    
1032     # don't keep stuff alive
1033     Scalar::Util::weaken $state;
1034    
1035     if ($again->{nested}) {
1036     $state->{nested} = 1;
1037     } else {
1038     delete $state->{nested};
1039     }
1040    
1041     if (my $interval = $again->{time}) {
1042     $state->{time} = [$interval, urxvt::timer->new->after ($interval)->interval ($interval)]
1043     if $state->{time}[0] != $interval;
1044    
1045     # callback *might* have changed, although we could just rule that out
1046     $state->{time}[1]->cb (sub {
1047     ++$state->{counter};
1048     $cb->();
1049     });
1050     } else {
1051     delete $state->{time};
1052     }
1053    
1054     if ($again->{position}) {
1055     $state->{position} = $self->on (position_change => $cb);
1056     } else {
1057     delete $state->{position};
1058     }
1059    
1060     if ($again->{size}) {
1061     $state->{size} = $self->on (size_change => $cb);
1062     } else {
1063     delete $state->{size};
1064     }
1065    
1066     if ($again->{rootpmap}) {
1067     $state->{rootpmap} = $self->on (rootpmap_change => $cb);
1068     } else {
1069     delete $state->{rootpmap};
1070     }
1071     }
1072    
1073 root 1.1 # evaluate the current bg expression
1074     sub recalculate {
1075 root 1.33 my ($arg_self) = @_;
1076 root 1.1
1077 root 1.10 # rate limit evaluation
1078    
1079 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
1080     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
1081     $arg_self->recalculate;
1082 root 1.9 });
1083 root 1.12 return;
1084 root 1.9 }
1085    
1086 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
1087 root 1.9
1088 root 1.10 # set environment to evaluate user expression
1089 root 1.6
1090 root 1.63 local $self = $arg_self;
1091     local $HOME = $ENV{HOME};
1092 root 1.74 local $frame = $self->{root};
1093 root 1.1
1094 root 1.63 ($x, $y, $w, $h) = $self->background_geometry ($self->{border});
1095 root 1.22
1096 root 1.10 # evaluate user expression
1097    
1098 root 1.63 my @img = eval { $self->{expr}->() };
1099 root 1.61 die $@ if $@;
1100 root 1.63 die "background-expr did not return anything.\n" unless @img;
1101     die "background-expr: expected image(s), got something else.\n"
1102     if grep { !UNIVERSAL::isa $_, "urxvt::img" } @img;
1103 root 1.1
1104 root 1.63 my $img = urxvt::bgdsl::merge @img;
1105 root 1.10
1106 root 1.63 $frame->[FR_AGAIN]{size} = 1
1107 root 1.55 if $img->repeat_mode != urxvt::RepeatNormal;
1108    
1109 root 1.63 # if the expression is sensitive to external events, prepare reevaluation then
1110     $self->compile_frame ($frame, sub { $arg_self->recalculate });
1111 root 1.9
1112 root 1.10 # clear stuff we no longer need
1113    
1114 root 1.63 # unless (%{ $frame->[FR_STATE] }) {
1115     # delete $self->{state};
1116     # delete $self->{expr};
1117     # }
1118 root 1.5
1119 root 1.34 # set background pixmap
1120 root 1.1
1121 root 1.33 $self->set_background ($img, $self->{border});
1122 root 1.1 $self->scr_recolour (0);
1123     $self->want_refresh;
1124     }
1125    
1126     sub on_start {
1127     my ($self) = @_;
1128    
1129 root 1.47 my $expr = $self->x_resource ("%.expr")
1130 root 1.33 or return;
1131    
1132 root 1.48 $self->has_render
1133     or die "background extension needs RENDER extension 0.10 or higher, ignoring background-expr.\n";
1134    
1135 root 1.33 $self->set_expr (parse_expr $expr);
1136 root 1.47 $self->{border} = $self->x_resource_boolean ("%.border");
1137 root 1.1
1138 root 1.47 $MIN_INTERVAL = $self->x_resource ("%.interval");
1139 root 1.46
1140 root 1.1 ()
1141     }
1142