ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.62
Committed: Sun Jun 17 21:58:18 2012 UTC (11 years, 11 months ago) by root
Branch: MAIN
Changes since 1.61: +4 -2 lines
Log Message:
*** empty log message ***

File Contents

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