ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.38
Committed: Fri Jun 8 21:48:07 2012 UTC (11 years, 11 months ago) by root
Branch: MAIN
Changes since 1.37: +26 -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.33 #:META:X_RESOURCE:%.border.:boolean:respect the terminal border
5    
6 root 1.35 #TODO: once, rootalign
7    
8 root 1.33 =head1 background - manage terminal background
9    
10     =head2 SYNOPSIS
11    
12 root 1.36 urxvt --background-expr 'background expression'
13     --background-border
14 root 1.33
15     =head2 DESCRIPTION
16    
17 root 1.36 This extension manages the terminal background by creating a picture that
18     is behind the text, replacing the normal background colour.
19    
20     It does so by evaluating a Perl expression that I<calculates> the image on
21     the fly, for example, by grabbing the root background or loading a file.
22    
23     While the full power of Perl is available, the operators have been design
24     to be as simple as possible.
25    
26     For example, to load an image and scale it to the window size, you would
27     use:
28    
29     urxvt --background-expr 'scale load "/path/to/mybg.png"'
30    
31     Or specified as a X resource:
32    
33     URxvt.background-expr: scale load "/path/to/mybg.png"
34    
35     =head2 THEORY OF OPERATION
36    
37     At startup, just before the window is mapped for the first time, the
38     expression is evaluated and must yield an image. The image is then
39     extended as necessary to cover the whole terminal window, and is set as a
40     background pixmap.
41    
42     If the image contains an alpha channel, then it will be used as-is in
43     visuals that support alpha channels (for example, for a compositing
44     manager). In other visuals, the terminal background colour will be used to
45     replace any transparency.
46    
47     When the expression relies, directly or indirectly, on the window size,
48     position, the root pixmap, or a timer, then it will be remembered. If not,
49     then it will be removed.
50    
51     If any of the parameters that the expression relies on changes (when the
52     window is moved or resized, its position or size changes; when the root
53     pixmap is replaced by another one the root background changes; or when the
54     timer elapses), then the expression will be evaluated again.
55    
56     For example, an expression such as C<scale load "$HOME/mybg.png"> scales the
57     image to the window size, so it relies on the window size and will
58     be reevaluated each time it is changed, but not when it moves for
59     example. That ensures that the picture always fills the terminal, even
60     after it's size changes.
61    
62     =head3 EXPRESSIONS
63    
64     Expressions are normal Perl expressions, in fact, they are Perl blocks -
65     which means you could use multiple lines and statements:
66    
67     again 3600;
68     if (localtime now)[6]) {
69     return scale load "$HOME/weekday.png";
70     } else {
71     return scale load "$HOME/sunday.png";
72     }
73    
74     This expression gets evaluated once per hour. It will set F<sunday.png> as
75     background on sundays, and F<weekday.png> on all other days.
76    
77     Fortunately, we expect that most expressions will be much simpler, with
78     little Perl knowledge needed.
79    
80     Basically, you always start with a function that "generates" an image
81     object, such as C<load>, which loads an image from disk, or C<root>, which
82     returns the root window background image:
83    
84     load "$HOME/mypic.png"
85    
86     The path is usually specified as a quoted string (the exact rules can be
87     found in the L<perlop> manpage). The F<$HOME> at the beginning of the
88     string is expanded to the home directory.
89    
90     Then you prepend one or more modifiers or filtering expressions, such as
91     C<scale>:
92    
93     scale load "$HOME/mypic.png"
94    
95     Just like a mathematical expression with functions, you should read these
96     expressions from right to left, as the C<load> is evaluated first, and
97     its result becomes the argument to the C<scale> function.
98    
99     Many operators also allow some parameters preceding the input image
100     that modify its behaviour. For example, C<scale> without any additional
101     arguments scales the image to size of the terminal window. If you specify
102     an additional argument, it uses it as a percentage:
103    
104     scale 200, load "$HOME/mypic.png"
105    
106     This enlarges the image by a factor of 2 (200%). As you can see, C<scale>
107     has now two arguments, the C<200> and the C<load> expression, while
108     C<load> only has one argument. Arguments are separated from each other by
109     commas.
110    
111     Scale also accepts two arguments, which are then separate factors for both
112     horizontal and vertical dimensions. For example, this halves the image
113     width and doubles the image height:
114    
115     scale 50, 200, load "$HOME/mypic.png"
116    
117     TODO
118    
119     =head3 CYCLES AND CACHING
120    
121     TODO
122    
123     Each time the expression is reevaluated, a new cycle is said to have begun. Many operators
124     cache their results till the next cycle. For example
125    
126 root 1.33 =head2 REFERENCE
127    
128 root 1.36 =head3 COMMAND LINE SWITCHES
129    
130     =over 4
131    
132     =item --background-expr perl-expression
133    
134     Specifies the Perl expression to evaluate.
135    
136     =item --background-border
137    
138     By default, the expression creates an image that fills the full window,
139     overwriting borders and any other areas, such as the scrollbar.
140    
141     Specifying this flag changes the behaviour, so that the image only
142     replaces the background of the character area.
143    
144     =back
145    
146 root 1.33 =cut
147 root 1.12
148 root 1.36 our $EXPR;#d#
149 root 1.28 #$EXPR = 'move W * 0.1, -H * 0.1, resize W * 0.5, H * 0.5, repeat_none load "opensource.png"';
150 root 1.30 $EXPR = 'move -TX, -TY, load "argb.png"';
151 root 1.19 #$EXPR = '
152     # rotate W, H, 50, 50, counter 1/59.95, repeat_mirror,
153     # clip X, Y, W, H, repeat_mirror,
154     # load "/root/pix/das_fette_schwein.jpg"
155     #';
156     #$EXPR = 'solid "red"';
157 root 1.1 #$EXPR = 'blur root, 10, 10'
158     #$EXPR = 'blur move (root, -x, -y), 5, 5'
159     #resize load "/root/pix/das_fette_schwein.jpg", w, h
160    
161 root 1.36 our $HOME;
162 root 1.33 our ($self, $old, $new);
163 root 1.29 our ($x, $y, $w, $h);
164 root 1.3
165 root 1.16 # enforce at least this interval between updates
166 root 1.10 our $MIN_INTERVAL = 1/100;
167 root 1.9
168 root 1.1 {
169     package urxvt::bgdsl; # background language
170    
171 root 1.15 =head2 PROVIDERS/GENERATORS
172    
173 root 1.31 These functions provide an image, by loading it from disk, grabbing it
174 sf-exg 1.32 from the root screen or by simply generating it. They are used as starting
175 root 1.31 points to get an image you can play with.
176    
177 root 1.15 =over 4
178    
179     =item load $path
180    
181 root 1.29 Loads the image at the given C<$path>. The image is set to plane tiling
182     mode.
183    
184 root 1.31 Loaded images will be cached for one cycle.
185 root 1.29
186 root 1.15 =cut
187    
188 root 1.2 sub load($) {
189 root 1.1 my ($path) = @_;
190    
191 root 1.33 $new->{load}{$path} = $old->{load}{$path} || $self->new_img_from_file ($path);
192 root 1.1 }
193    
194 root 1.31 =item root
195    
196     Returns the root window pixmap, that is, hopefully, the background image
197     of your screen. The image is set to extend mode.
198    
199     This function makes your expression root sensitive, that means it will be
200     reevaluated when the bg image changes.
201    
202     =cut
203    
204 root 1.2 sub root() {
205 root 1.9 $new->{rootpmap_sensitive} = 1;
206 root 1.1 die "root op not supported, exg, we need you";
207     }
208    
209 root 1.31 =item solid $colour
210    
211     =item solid $width, $height, $colour
212    
213     Creates a new image and completely fills it with the given colour. The
214     image is set to tiling mode.
215    
216     If <$width> and C<$height> are omitted, it creates a 1x1 image, which is
217     useful for solid backgrounds or for use in filtering effects.
218    
219     =cut
220    
221     sub solid($$;$) {
222     my $colour = pop;
223    
224 root 1.33 my $img = $self->new_img (urxvt::PictStandardARGB32, $_[0] || 1, $_[1] || 1);
225 root 1.31 $img->fill ($colour);
226 root 1.15 $img
227     }
228    
229     =back
230    
231 root 1.20 =head2 VARIABLES
232    
233 root 1.31 The following functions provide variable data such as the terminal
234 sf-exg 1.32 window dimensions. Most of them make your expression sensitive to some
235 root 1.31 events, for example using C<TW> (terminal width) means your expression is
236     evaluated again when the terminal is resized.
237    
238 root 1.20 =over 4
239    
240 root 1.31 =item TX
241    
242     =item TY
243    
244     Return the X and Y coordinates of the terminal window (the terminal
245     window is the full window by default, and the character area only when in
246     border-respect mode).
247    
248     Using these functions make your expression sensitive to window moves.
249    
250     These functions are mainly useful to align images to the root window.
251    
252     Example: load an image and align it so it looks as if anchored to the
253     background.
254    
255     move -TX, -TY, load "mybg.png"
256    
257     =item TW
258    
259     Return the width (C<TW>) and height (C<TH>) of the terminal window (the
260     terminal window is the full window by default, and the character area only
261     when in border-respect mode).
262    
263     Using these functions make your expression sensitive to window resizes.
264    
265     These functions are mainly useful to scale images, or to clip images to
266     the window size to conserve memory.
267    
268     Example: take the screen background, clip it to the window size, blur it a
269     bit, align it to the window position and use it as background.
270    
271     clip move -TX, -TY, blur 5, root
272    
273 root 1.20 =cut
274    
275 root 1.30 sub TX() { $new->{position_sensitive} = 1; $x }
276     sub TY() { $new->{position_sensitive} = 1; $y }
277     sub TW() { $new->{size_sensitive} = 1; $w }
278     sub TH() { $new->{size_sensitive} = 1; $h }
279 root 1.20
280 root 1.33 =item now
281    
282     Returns the current time as (fractional) seconds since the epoch.
283    
284     Using this expression does I<not> make your expression sensitive to time,
285     but the next two functions do.
286    
287     =item again $seconds
288    
289     When this function is used the expression will be reevaluated again in
290     C<$seconds> seconds.
291    
292     Example: load some image and rotate it according to the time of day (as if it were
293 root 1.36 the hour pointer of a clock). Update this image every minute.
294 root 1.33
295     again 60; rotate TW, TH, 50, 50, (now % 86400) * -720 / 86400, scale load "myclock.png"
296    
297     =item counter $seconds
298    
299     Like C<again>, but also returns an increasing counter value, starting at
300     0, which might be useful for some simple animation effects.
301    
302     =cut
303    
304 root 1.20 sub now() { urxvt::NOW }
305    
306     sub again($) {
307     $new->{again} = $_[0];
308     }
309    
310     sub counter($) {
311     $new->{again} = $_[0];
312 root 1.33 $self->{counter} + 0
313 root 1.20 }
314    
315     =back
316    
317 root 1.28 =head2 TILING MODES
318    
319     The following operators modify the tiling mode of an image, that is, the
320     way that pixels outside the image area are painted when the image is used.
321 root 1.15
322     =over 4
323    
324 root 1.28 =item tile $img
325    
326     Tiles the whole plane with the image and returns this new image - or in
327     other words, it returns a copy of the image in plane tiling mode.
328    
329 root 1.34 Example: load an image and tile it over the background, without
330     resizing. The C<tile> call is superfluous because C<load> already defaults
331     to tiling mode.
332    
333     tile load "mybg.png"
334    
335 root 1.28 =item mirror $img
336    
337     Similar to tile, but reflects the image each time it uses a new copy, so
338     that top edges always touch top edges, right edges always touch right
339     edges and so on (with normal tiling, left edges always touch right edges
340     and top always touch bottom edges).
341    
342 root 1.36 Example: load an image and mirror it over the background, avoiding sharp
343 root 1.34 edges at the image borders at the expense of mirroring the image itself
344    
345     mirror load "mybg.png"
346    
347 root 1.28 =item pad $img
348    
349     Takes an image and modifies it so that all pixels outside the image area
350     become transparent. This mode is most useful when you want to place an
351     image over another image or the background colour while leaving all
352     background pixels outside the image unchanged.
353    
354 root 1.36 Example: load an image and display it in the upper left corner. The rest
355 root 1.34 of the space is left "empty" (transparent or wahtever your compisotr does
356     in alpha mode, else background colour).
357    
358     pad load "mybg.png"
359    
360 root 1.28 =item extend $img
361    
362     Extends the image over the whole plane, using the closest pixel in the
363     area outside the image. This mode is mostly useful when you more complex
364     filtering operations and want the pixels outside the image to have the
365     same values as the pixels near the edge.
366    
367 root 1.34 Example: just for curiosity, how does this pixel extension stuff work?
368    
369     extend move 50, 50, load "mybg.png"
370    
371 root 1.15 =cut
372    
373 root 1.28 sub pad($) {
374     my $img = $_[0]->clone;
375     $img->repeat_mode (urxvt::RepeatNone);
376     $img
377     }
378    
379     sub tile($) {
380     my $img = $_[0]->clone;
381     $img->repeat_mode (urxvt::RepeatNormal);
382     $img
383     }
384    
385     sub mirror($) {
386     my $img = $_[0]->clone;
387     $img->repeat_mode (urxvt::RepeatReflect);
388     $img
389     }
390 root 1.4
391 root 1.28 sub extend($) {
392 root 1.24 my $img = $_[0]->clone;
393 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
394 root 1.24 $img
395     }
396    
397 root 1.28 =back
398    
399     =head2 PIXEL OPERATORS
400    
401     The following operators modify the image pixels in various ways.
402    
403     =over 4
404    
405     =item clone $img
406    
407     Returns an exact copy of the image.
408    
409     =cut
410    
411     sub clone($) {
412     $_[0]->clone
413     }
414    
415     =item clip $img
416    
417     =item clip $width, $height, $img
418    
419     =item clip $x, $y, $width, $height, $img
420    
421     Clips an image to the given rectangle. If the rectangle is outside the
422     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
423     larger than the image, then the tiling mode defines how the extra pixels
424     will be filled.
425    
426     If C<$x> an C<$y> are missing, then C<0> is assumed for both.
427    
428     If C<$width> and C<$height> are missing, then the window size will be
429     assumed.
430    
431     Example: load an image, blur it, and clip it to the window size to save
432     memory.
433    
434     clip blur 10, load "mybg.png"
435    
436     =cut
437    
438 root 1.20 sub clip($;$$;$$) {
439 root 1.7 my $img = pop;
440 root 1.30 my $h = pop || TH;
441     my $w = pop || TW;
442 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
443 root 1.4 }
444    
445 root 1.28 =item scale $img
446    
447     =item scale $size_percent, $img
448    
449     =item scale $width_percent, $height_percent, $img
450    
451     Scales the image by the given percentages in horizontal
452     (C<$width_percent>) and vertical (C<$height_percent>) direction.
453    
454     If only one percentage is give, it is used for both directions.
455    
456     If no percentages are given, scales the image to the window size without
457     keeping aspect.
458    
459     =item resize $width, $height, $img
460    
461     Resizes the image to exactly C<$width> times C<$height> pixels.
462    
463     =cut
464    
465     #TODO: maximise, maximise_fill?
466    
467 root 1.33 sub scale($;$;$) {
468 root 1.28 my $img = pop;
469    
470     @_ == 2 ? $img->scale ($_[0] * $img->w * 0.01, $_[1] * $img->h * 0.01)
471     : @_ ? $img->scale ($_[0] * $img->w * 0.01, $_[0] * $img->h * 0.01)
472 root 1.30 : $img->scale (TW, TH)
473 root 1.28 }
474    
475 root 1.2 sub resize($$$) {
476 root 1.7 my $img = pop;
477     $img->scale ($_[0], $_[1])
478 root 1.1 }
479    
480 root 1.36 =item move $dx, $dy, $img
481    
482     Moves the image by C<$dx> pixels in the horizontal, and C<$dy> pixels in
483     the vertical.
484    
485     Example: move the image right by 20 pixels and down by 30.
486    
487     move 20, 30, ...
488    
489     =item rootalign $img
490    
491     Moves the image so that it appears glued to the screen as opposed to the
492     window. This gives the illusion of a larger area behind the window. It is
493     exactly equivalent to C<move -TX, -TY>, that is, it moves the image to the
494     top left of the screen.
495    
496     Example: load a background image, put it in mirror mode and root align it.
497    
498     rootalign mirror load "mybg.png"
499    
500     Example: take the screen background and align it, giving the illusion of
501     transparency as long as the window isn't in front of other windows.
502    
503     rootalign root
504    
505     =cut
506    
507 root 1.7 sub move($$;$) {
508 root 1.20 my $img = pop->clone;
509     $img->move ($_[0], $_[1]);
510     $img
511 root 1.1 }
512    
513 root 1.36 sub rootalign($) {
514     move -TX, -TY, $_[0]
515 root 1.1 }
516    
517 root 1.36 =item contrast $factor, $img
518    
519     =item contrast $r, $g, $b, $img
520    
521     =item contrast $r, $g, $b, $a, $img
522    
523     Adjusts the I<contrast> of an image.
524    
525 root 1.38 #TODO#
526    
527 root 1.36 =item brightness $factor, $img
528    
529     =item brightness $r, $g, $b, $img
530    
531     =item brightness $r, $g, $b, $a, $img
532    
533 root 1.38 Adjusts the brightness of an image.
534    
535 root 1.36 =cut
536 root 1.1
537 root 1.2 sub contrast($$;$$;$) {
538 root 1.7 my $img = pop;
539     my ($r, $g, $b, $a) = @_;
540 root 1.4
541 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
542     $a = 1 if @_ < 5;
543 root 1.4
544 root 1.1 $img = $img->clone;
545 root 1.37 $img->contrast ($r, $g, $b, $a);
546 root 1.1 $img
547     }
548    
549 root 1.2 sub brightness($$;$$;$) {
550 root 1.7 my $img = pop;
551     my ($r, $g, $b, $a) = @_;
552 root 1.4
553 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
554     $a = 1 if @_ < 5;
555 root 1.4
556 root 1.1 $img = $img->clone;
557     $img->brightness ($r, $g, $b, $a);
558     $img
559     }
560    
561 root 1.38 =item blur $radius, $img
562    
563     =item blur $radius_horz, $radius_vert, $img
564    
565     Gaussian-blurs the image with (roughly) C<$radius> pixel radius. The radii
566     can also be specified separately.
567    
568     =cut
569    
570 root 1.36 sub blur($$;$) {
571     my $img = pop;
572     $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
573     }
574    
575 root 1.38 =item rotate $new_width, $new_height, $center_x, $center_y, $degrees
576    
577     Rotates the image by C<$degrees> degrees, counter-clockwise, around the
578     pointer at C<$center_x> and C<$center_y> (specified as percentage of image
579     width/height), generating a new image with width C<$new_width> and height
580     C<$new_height>.
581    
582     #TODO# new width, height, maybe more operators?
583    
584     Example: rotate the image by 90 degrees
585    
586     =cut
587    
588 root 1.36 sub rotate($$$$$$) {
589     my $img = pop;
590     $img->rotate (
591     $_[0],
592     $_[1],
593     $_[2] * $img->w * .01,
594     $_[3] * $img->h * .01,
595     $_[4] * (3.14159265 / 180),
596     )
597     }
598    
599 root 1.15 =back
600    
601     =cut
602    
603 root 1.1 }
604    
605     sub parse_expr {
606     my $expr = eval "sub {\npackage urxvt::bgdsl;\n#line 0 'background expression'\n$_[0]\n}";
607     die if $@;
608     $expr
609     }
610    
611     # compiles a parsed expression
612     sub set_expr {
613     my ($self, $expr) = @_;
614    
615     $self->{expr} = $expr;
616     $self->recalculate;
617     }
618    
619     # evaluate the current bg expression
620     sub recalculate {
621 root 1.33 my ($arg_self) = @_;
622 root 1.1
623 root 1.10 # rate limit evaluation
624    
625 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
626     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
627     $arg_self->recalculate;
628 root 1.9 });
629 root 1.12 return;
630 root 1.9 }
631    
632 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
633 root 1.9
634 root 1.10 # set environment to evaluate user expression
635 root 1.6
636 root 1.33 local $self = $arg_self;
637 root 1.1
638 root 1.36 local $HOME = $ENV{HOME};
639 root 1.3 local $old = $self->{state};
640     local $new = my $state = $self->{state} = {};
641 root 1.1
642 root 1.29 ($x, $y, $w, $h) =
643 root 1.33 $self->background_geometry ($self->{border});
644 root 1.22
645 root 1.10 # evaluate user expression
646    
647 root 1.1 my $img = eval { $self->{expr}->() };
648     warn $@ if $@;#d#
649 root 1.15 die if !UNIVERSAL::isa $img, "urxvt::img";
650 root 1.1
651 root 1.34 $state->{size_sensitive} = 1
652     if $img->repeat_mode != urxvt::RepeatNormal;
653    
654 root 1.10 # if the expression is sensitive to external events, prepare reevaluation then
655    
656 root 1.2 my $repeat;
657    
658 root 1.1 if (my $again = $state->{again}) {
659 root 1.2 $repeat = 1;
660 root 1.35 my $self = $self;
661 root 1.6 $state->{timer} = $again == $old->{again}
662     ? $old->{timer}
663 root 1.7 : urxvt::timer->new->after ($again)->interval ($again)->cb (sub {
664     ++$self->{counter};
665     $self->recalculate
666     });
667 root 1.1 }
668    
669 root 1.2 if (delete $state->{position_sensitive}) {
670     $repeat = 1;
671     $self->enable (position_change => sub { $_[0]->recalculate });
672     } else {
673     $self->disable ("position_change");
674     }
675    
676     if (delete $state->{size_sensitive}) {
677     $repeat = 1;
678     $self->enable (size_change => sub { $_[0]->recalculate });
679     } else {
680     $self->disable ("size_change");
681     }
682    
683 root 1.9 if (delete $state->{rootpmap_sensitive}) {
684     $repeat = 1;
685     $self->enable (rootpmap_change => sub { $_[0]->recalculate });
686     } else {
687     $self->disable ("rootpmap_change");
688     }
689    
690 root 1.10 # clear stuff we no longer need
691    
692 root 1.6 %$old = ();
693    
694 root 1.5 unless ($repeat) {
695     delete $self->{state};
696     delete $self->{expr};
697     }
698    
699 root 1.34 # set background pixmap
700 root 1.1
701 root 1.33 $self->set_background ($img, $self->{border});
702 root 1.1 $self->scr_recolour (0);
703     $self->want_refresh;
704     }
705    
706     sub on_start {
707     my ($self) = @_;
708    
709 root 1.33 my $expr = $self->x_resource ("background.expr")
710     or return;
711    
712     $self->set_expr (parse_expr $expr);
713     $self->{border} = $self->x_resource_boolean ("background.border");
714 root 1.1
715     ()
716     }
717