ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.34
Committed: Thu Jun 7 17:04:33 2012 UTC (12 years ago) by root
Branch: MAIN
Changes since 1.33: +25 -4 lines
Log Message:
µcorrectness

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     =head1 background - manage terminal background
7    
8     =head2 SYNOPSIS
9    
10     rxvt -background-expr 'background expression'
11     -background-border
12    
13     =head2 DESCRIPTION
14    
15     =head2 REFERENCE
16    
17     =cut
18 root 1.12
19 root 1.28 our $EXPR;
20     #$EXPR = 'move W * 0.1, -H * 0.1, resize W * 0.5, H * 0.5, repeat_none load "opensource.png"';
21 root 1.30 $EXPR = 'move -TX, -TY, load "argb.png"';
22 root 1.19 #$EXPR = '
23     # rotate W, H, 50, 50, counter 1/59.95, repeat_mirror,
24     # clip X, Y, W, H, repeat_mirror,
25     # load "/root/pix/das_fette_schwein.jpg"
26     #';
27     #$EXPR = 'solid "red"';
28 root 1.1 #$EXPR = 'blur root, 10, 10'
29     #$EXPR = 'blur move (root, -x, -y), 5, 5'
30     #resize load "/root/pix/das_fette_schwein.jpg", w, h
31    
32 root 1.33 our ($self, $old, $new);
33 root 1.29 our ($x, $y, $w, $h);
34 root 1.3
35 root 1.16 # enforce at least this interval between updates
36 root 1.10 our $MIN_INTERVAL = 1/100;
37 root 1.9
38 root 1.1 {
39     package urxvt::bgdsl; # background language
40    
41 root 1.15 =head2 PROVIDERS/GENERATORS
42    
43 root 1.31 These functions provide an image, by loading it from disk, grabbing it
44 sf-exg 1.32 from the root screen or by simply generating it. They are used as starting
45 root 1.31 points to get an image you can play with.
46    
47 root 1.15 =over 4
48    
49     =item load $path
50    
51 root 1.29 Loads the image at the given C<$path>. The image is set to plane tiling
52     mode.
53    
54 root 1.31 Loaded images will be cached for one cycle.
55 root 1.29
56 root 1.15 =cut
57    
58 root 1.2 sub load($) {
59 root 1.1 my ($path) = @_;
60    
61 root 1.33 $new->{load}{$path} = $old->{load}{$path} || $self->new_img_from_file ($path);
62 root 1.1 }
63    
64 root 1.31 =item root
65    
66     Returns the root window pixmap, that is, hopefully, the background image
67     of your screen. The image is set to extend mode.
68    
69     This function makes your expression root sensitive, that means it will be
70     reevaluated when the bg image changes.
71    
72     =cut
73    
74 root 1.2 sub root() {
75 root 1.9 $new->{rootpmap_sensitive} = 1;
76 root 1.1 die "root op not supported, exg, we need you";
77     }
78    
79 root 1.31 =item solid $colour
80    
81     =item solid $width, $height, $colour
82    
83     Creates a new image and completely fills it with the given colour. The
84     image is set to tiling mode.
85    
86     If <$width> and C<$height> are omitted, it creates a 1x1 image, which is
87     useful for solid backgrounds or for use in filtering effects.
88    
89     =cut
90    
91     sub solid($$;$) {
92     my $colour = pop;
93    
94 root 1.33 my $img = $self->new_img (urxvt::PictStandardARGB32, $_[0] || 1, $_[1] || 1);
95 root 1.31 $img->fill ($colour);
96 root 1.15 $img
97     }
98    
99     =back
100    
101 root 1.20 =head2 VARIABLES
102    
103 root 1.31 The following functions provide variable data such as the terminal
104 sf-exg 1.32 window dimensions. Most of them make your expression sensitive to some
105 root 1.31 events, for example using C<TW> (terminal width) means your expression is
106     evaluated again when the terminal is resized.
107    
108 root 1.20 =over 4
109    
110 root 1.31 =item TX
111    
112     =item TY
113    
114     Return the X and Y coordinates of the terminal window (the terminal
115     window is the full window by default, and the character area only when in
116     border-respect mode).
117    
118     Using these functions make your expression sensitive to window moves.
119    
120     These functions are mainly useful to align images to the root window.
121    
122     Example: load an image and align it so it looks as if anchored to the
123     background.
124    
125     move -TX, -TY, load "mybg.png"
126    
127     =item TW
128    
129     Return the width (C<TW>) and height (C<TH>) of the terminal window (the
130     terminal window is the full window by default, and the character area only
131     when in border-respect mode).
132    
133     Using these functions make your expression sensitive to window resizes.
134    
135     These functions are mainly useful to scale images, or to clip images to
136     the window size to conserve memory.
137    
138     Example: take the screen background, clip it to the window size, blur it a
139     bit, align it to the window position and use it as background.
140    
141     clip move -TX, -TY, blur 5, root
142    
143 root 1.20 =cut
144    
145 root 1.30 sub TX() { $new->{position_sensitive} = 1; $x }
146     sub TY() { $new->{position_sensitive} = 1; $y }
147     sub TW() { $new->{size_sensitive} = 1; $w }
148     sub TH() { $new->{size_sensitive} = 1; $h }
149 root 1.20
150 root 1.33 =item now
151    
152     Returns the current time as (fractional) seconds since the epoch.
153    
154     Using this expression does I<not> make your expression sensitive to time,
155     but the next two functions do.
156    
157     =item again $seconds
158    
159     When this function is used the expression will be reevaluated again in
160     C<$seconds> seconds.
161    
162     Example: load some image and rotate it according to the time of day (as if it were
163     the hour pointer of a clock). update this image every minute.
164    
165     again 60; rotate TW, TH, 50, 50, (now % 86400) * -720 / 86400, scale load "myclock.png"
166    
167     =item counter $seconds
168    
169     Like C<again>, but also returns an increasing counter value, starting at
170     0, which might be useful for some simple animation effects.
171    
172     =cut
173    
174 root 1.20 sub now() { urxvt::NOW }
175    
176     sub again($) {
177     $new->{again} = $_[0];
178     }
179    
180     sub counter($) {
181     $new->{again} = $_[0];
182 root 1.33 $self->{counter} + 0
183 root 1.20 }
184    
185     =back
186    
187 root 1.28 =head2 TILING MODES
188    
189     The following operators modify the tiling mode of an image, that is, the
190     way that pixels outside the image area are painted when the image is used.
191 root 1.15
192     =over 4
193    
194 root 1.28 =item tile $img
195    
196     Tiles the whole plane with the image and returns this new image - or in
197     other words, it returns a copy of the image in plane tiling mode.
198    
199 root 1.34 Example: load an image and tile it over the background, without
200     resizing. The C<tile> call is superfluous because C<load> already defaults
201     to tiling mode.
202    
203     tile load "mybg.png"
204    
205 root 1.28 =item mirror $img
206    
207     Similar to tile, but reflects the image each time it uses a new copy, so
208     that top edges always touch top edges, right edges always touch right
209     edges and so on (with normal tiling, left edges always touch right edges
210     and top always touch bottom edges).
211    
212 root 1.34 Exmaple: load an image and mirror it over the background, avoiding sharp
213     edges at the image borders at the expense of mirroring the image itself
214    
215     mirror load "mybg.png"
216    
217 root 1.28 =item pad $img
218    
219     Takes an image and modifies it so that all pixels outside the image area
220     become transparent. This mode is most useful when you want to place an
221     image over another image or the background colour while leaving all
222     background pixels outside the image unchanged.
223    
224 root 1.34 Example: load an image and display it in the upper left corner. The rets
225     of the space is left "empty" (transparent or wahtever your compisotr does
226     in alpha mode, else background colour).
227    
228     pad load "mybg.png"
229    
230 root 1.28 =item extend $img
231    
232     Extends the image over the whole plane, using the closest pixel in the
233     area outside the image. This mode is mostly useful when you more complex
234     filtering operations and want the pixels outside the image to have the
235     same values as the pixels near the edge.
236    
237 root 1.34 Example: just for curiosity, how does this pixel extension stuff work?
238    
239     extend move 50, 50, load "mybg.png"
240    
241 root 1.15 =cut
242    
243 root 1.28 sub pad($) {
244     my $img = $_[0]->clone;
245     $img->repeat_mode (urxvt::RepeatNone);
246     $img
247     }
248    
249     sub tile($) {
250     my $img = $_[0]->clone;
251     $img->repeat_mode (urxvt::RepeatNormal);
252     $img
253     }
254    
255     sub mirror($) {
256     my $img = $_[0]->clone;
257     $img->repeat_mode (urxvt::RepeatReflect);
258     $img
259     }
260 root 1.4
261 root 1.28 sub extend($) {
262 root 1.24 my $img = $_[0]->clone;
263 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
264 root 1.24 $img
265     }
266    
267 root 1.28 =back
268    
269     =head2 PIXEL OPERATORS
270    
271     The following operators modify the image pixels in various ways.
272    
273     =over 4
274    
275     =item clone $img
276    
277     Returns an exact copy of the image.
278    
279     =cut
280    
281     sub clone($) {
282     $_[0]->clone
283     }
284    
285     =item clip $img
286    
287     =item clip $width, $height, $img
288    
289     =item clip $x, $y, $width, $height, $img
290    
291     Clips an image to the given rectangle. If the rectangle is outside the
292     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
293     larger than the image, then the tiling mode defines how the extra pixels
294     will be filled.
295    
296     If C<$x> an C<$y> are missing, then C<0> is assumed for both.
297    
298     If C<$width> and C<$height> are missing, then the window size will be
299     assumed.
300    
301     Example: load an image, blur it, and clip it to the window size to save
302     memory.
303    
304     clip blur 10, load "mybg.png"
305    
306     =cut
307    
308 root 1.20 sub clip($;$$;$$) {
309 root 1.7 my $img = pop;
310 root 1.30 my $h = pop || TH;
311     my $w = pop || TW;
312 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
313 root 1.4 }
314    
315 root 1.28 =item scale $img
316    
317     =item scale $size_percent, $img
318    
319     =item scale $width_percent, $height_percent, $img
320    
321     Scales the image by the given percentages in horizontal
322     (C<$width_percent>) and vertical (C<$height_percent>) direction.
323    
324     If only one percentage is give, it is used for both directions.
325    
326     If no percentages are given, scales the image to the window size without
327     keeping aspect.
328    
329     =item resize $width, $height, $img
330    
331     Resizes the image to exactly C<$width> times C<$height> pixels.
332    
333     =cut
334    
335     #TODO: maximise, maximise_fill?
336    
337 root 1.33 sub scale($;$;$) {
338 root 1.28 my $img = pop;
339    
340     @_ == 2 ? $img->scale ($_[0] * $img->w * 0.01, $_[1] * $img->h * 0.01)
341     : @_ ? $img->scale ($_[0] * $img->w * 0.01, $_[0] * $img->h * 0.01)
342 root 1.30 : $img->scale (TW, TH)
343 root 1.28 }
344    
345 root 1.2 sub resize($$$) {
346 root 1.7 my $img = pop;
347     $img->scale ($_[0], $_[1])
348 root 1.1 }
349    
350 root 1.7 sub move($$;$) {
351 root 1.20 my $img = pop->clone;
352     $img->move ($_[0], $_[1]);
353     $img
354 root 1.1 }
355    
356 root 1.20 sub rotate($$$$$$) {
357 root 1.7 my $img = pop;
358     $img->rotate (
359     $_[0],
360 root 1.4 $_[1],
361 root 1.7 $_[2] * $img->w * .01,
362     $_[3] * $img->h * .01,
363     $_[4] * (3.14159265 / 180),
364 root 1.4 )
365 root 1.1 }
366    
367 root 1.28 sub blur($$;$) {
368     my $img = pop;
369 root 1.30 $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
370 root 1.1 }
371    
372 root 1.2 sub contrast($$;$$;$) {
373 root 1.7 my $img = pop;
374     my ($r, $g, $b, $a) = @_;
375 root 1.4
376 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
377     $a = 1 if @_ < 5;
378 root 1.4
379 root 1.1 $img = $img->clone;
380     $img->contrast ($r, $g, $b, $a);
381     $img
382     }
383    
384 root 1.2 sub brightness($$;$$;$) {
385 root 1.7 my $img = pop;
386     my ($r, $g, $b, $a) = @_;
387 root 1.4
388 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
389     $a = 1 if @_ < 5;
390 root 1.4
391 root 1.1 $img = $img->clone;
392     $img->brightness ($r, $g, $b, $a);
393     $img
394     }
395    
396 root 1.15 =back
397    
398     =cut
399    
400 root 1.1 }
401    
402     sub parse_expr {
403     my $expr = eval "sub {\npackage urxvt::bgdsl;\n#line 0 'background expression'\n$_[0]\n}";
404     die if $@;
405     $expr
406     }
407    
408     # compiles a parsed expression
409     sub set_expr {
410     my ($self, $expr) = @_;
411    
412     $self->{expr} = $expr;
413     $self->recalculate;
414     }
415    
416     # evaluate the current bg expression
417     sub recalculate {
418 root 1.33 my ($arg_self) = @_;
419 root 1.1
420 root 1.10 # rate limit evaluation
421    
422 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
423     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
424     $arg_self->recalculate;
425 root 1.9 });
426 root 1.12 return;
427 root 1.9 }
428    
429 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
430 root 1.9
431 root 1.10 # set environment to evaluate user expression
432 root 1.6
433 root 1.33 local $self = $arg_self;
434 root 1.1
435 root 1.3 local $old = $self->{state};
436     local $new = my $state = $self->{state} = {};
437 root 1.1
438 root 1.29 ($x, $y, $w, $h) =
439 root 1.33 $self->background_geometry ($self->{border});
440 root 1.22
441 root 1.10 # evaluate user expression
442    
443 root 1.1 my $img = eval { $self->{expr}->() };
444     warn $@ if $@;#d#
445 root 1.15 die if !UNIVERSAL::isa $img, "urxvt::img";
446 root 1.1
447 root 1.34 $state->{size_sensitive} = 1
448     if $img->repeat_mode != urxvt::RepeatNormal;
449    
450 root 1.10 # if the expression is sensitive to external events, prepare reevaluation then
451    
452 root 1.2 my $repeat;
453    
454 root 1.1 if (my $again = $state->{again}) {
455 root 1.2 $repeat = 1;
456 root 1.6 $state->{timer} = $again == $old->{again}
457     ? $old->{timer}
458 root 1.7 : urxvt::timer->new->after ($again)->interval ($again)->cb (sub {
459     ++$self->{counter};
460     $self->recalculate
461     });
462 root 1.1 }
463    
464 root 1.2 if (delete $state->{position_sensitive}) {
465     $repeat = 1;
466     $self->enable (position_change => sub { $_[0]->recalculate });
467     } else {
468     $self->disable ("position_change");
469     }
470    
471     if (delete $state->{size_sensitive}) {
472     $repeat = 1;
473     $self->enable (size_change => sub { $_[0]->recalculate });
474     } else {
475     $self->disable ("size_change");
476     }
477    
478 root 1.9 if (delete $state->{rootpmap_sensitive}) {
479     $repeat = 1;
480     $self->enable (rootpmap_change => sub { $_[0]->recalculate });
481     } else {
482     $self->disable ("rootpmap_change");
483     }
484    
485 root 1.10 # clear stuff we no longer need
486    
487 root 1.6 %$old = ();
488    
489 root 1.5 unless ($repeat) {
490     delete $self->{state};
491     delete $self->{expr};
492     }
493    
494 root 1.34 # set background pixmap
495 root 1.1
496 root 1.33 $self->set_background ($img, $self->{border});
497 root 1.1 $self->scr_recolour (0);
498     $self->want_refresh;
499     }
500    
501     sub on_start {
502     my ($self) = @_;
503    
504 root 1.33 my $expr = $self->x_resource ("background.expr")
505     or return;
506    
507     $self->set_expr (parse_expr $expr);
508     $self->{border} = $self->x_resource_boolean ("background.border");
509 root 1.1
510     ()
511     }
512