ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/background
Revision: 1.33
Committed: Thu Jun 7 16:30:58 2012 UTC (12 years ago) by root
Branch: MAIN
Changes since 1.32: +56 -20 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     =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     =item mirror $img
200    
201     Similar to tile, but reflects the image each time it uses a new copy, so
202     that top edges always touch top edges, right edges always touch right
203     edges and so on (with normal tiling, left edges always touch right edges
204     and top always touch bottom edges).
205    
206     =item pad $img
207    
208     Takes an image and modifies it so that all pixels outside the image area
209     become transparent. This mode is most useful when you want to place an
210     image over another image or the background colour while leaving all
211     background pixels outside the image unchanged.
212    
213     =item extend $img
214    
215     Extends the image over the whole plane, using the closest pixel in the
216     area outside the image. This mode is mostly useful when you more complex
217     filtering operations and want the pixels outside the image to have the
218     same values as the pixels near the edge.
219    
220 root 1.15 =cut
221    
222 root 1.28 sub pad($) {
223     my $img = $_[0]->clone;
224     $img->repeat_mode (urxvt::RepeatNone);
225     $img
226     }
227    
228     sub tile($) {
229     my $img = $_[0]->clone;
230     $img->repeat_mode (urxvt::RepeatNormal);
231     $img
232     }
233    
234     sub mirror($) {
235     my $img = $_[0]->clone;
236     $img->repeat_mode (urxvt::RepeatReflect);
237     $img
238     }
239 root 1.4
240 root 1.28 sub extend($) {
241 root 1.24 my $img = $_[0]->clone;
242 root 1.28 $img->repeat_mode (urxvt::RepeatPad);
243 root 1.24 $img
244     }
245    
246 root 1.28 =back
247    
248     =head2 PIXEL OPERATORS
249    
250     The following operators modify the image pixels in various ways.
251    
252     =over 4
253    
254     =item clone $img
255    
256     Returns an exact copy of the image.
257    
258     =cut
259    
260     sub clone($) {
261     $_[0]->clone
262     }
263    
264     =item clip $img
265    
266     =item clip $width, $height, $img
267    
268     =item clip $x, $y, $width, $height, $img
269    
270     Clips an image to the given rectangle. If the rectangle is outside the
271     image area (e.g. when C<$x> or C<$y> are negative) or the rectangle is
272     larger than the image, then the tiling mode defines how the extra pixels
273     will be filled.
274    
275     If C<$x> an C<$y> are missing, then C<0> is assumed for both.
276    
277     If C<$width> and C<$height> are missing, then the window size will be
278     assumed.
279    
280     Example: load an image, blur it, and clip it to the window size to save
281     memory.
282    
283     clip blur 10, load "mybg.png"
284    
285     =cut
286    
287 root 1.20 sub clip($;$$;$$) {
288 root 1.7 my $img = pop;
289 root 1.30 my $h = pop || TH;
290     my $w = pop || TW;
291 root 1.21 $img->sub_rect ($_[0], $_[1], $w, $h)
292 root 1.4 }
293    
294 root 1.28 =item scale $img
295    
296     =item scale $size_percent, $img
297    
298     =item scale $width_percent, $height_percent, $img
299    
300     Scales the image by the given percentages in horizontal
301     (C<$width_percent>) and vertical (C<$height_percent>) direction.
302    
303     If only one percentage is give, it is used for both directions.
304    
305     If no percentages are given, scales the image to the window size without
306     keeping aspect.
307    
308     =item resize $width, $height, $img
309    
310     Resizes the image to exactly C<$width> times C<$height> pixels.
311    
312     =cut
313    
314     #TODO: maximise, maximise_fill?
315    
316 root 1.33 sub scale($;$;$) {
317 root 1.28 my $img = pop;
318    
319     @_ == 2 ? $img->scale ($_[0] * $img->w * 0.01, $_[1] * $img->h * 0.01)
320     : @_ ? $img->scale ($_[0] * $img->w * 0.01, $_[0] * $img->h * 0.01)
321 root 1.30 : $img->scale (TW, TH)
322 root 1.28 }
323    
324 root 1.2 sub resize($$$) {
325 root 1.7 my $img = pop;
326     $img->scale ($_[0], $_[1])
327 root 1.1 }
328    
329 root 1.7 sub move($$;$) {
330 root 1.20 my $img = pop->clone;
331     $img->move ($_[0], $_[1]);
332     $img
333 root 1.1 }
334    
335 root 1.20 sub rotate($$$$$$) {
336 root 1.7 my $img = pop;
337     $img->rotate (
338     $_[0],
339 root 1.4 $_[1],
340 root 1.7 $_[2] * $img->w * .01,
341     $_[3] * $img->h * .01,
342     $_[4] * (3.14159265 / 180),
343 root 1.4 )
344 root 1.1 }
345    
346 root 1.28 sub blur($$;$) {
347     my $img = pop;
348 root 1.30 $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
349 root 1.1 }
350    
351 root 1.2 sub contrast($$;$$;$) {
352 root 1.7 my $img = pop;
353     my ($r, $g, $b, $a) = @_;
354 root 1.4
355 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
356     $a = 1 if @_ < 5;
357 root 1.4
358 root 1.1 $img = $img->clone;
359     $img->contrast ($r, $g, $b, $a);
360     $img
361     }
362    
363 root 1.2 sub brightness($$;$$;$) {
364 root 1.7 my $img = pop;
365     my ($r, $g, $b, $a) = @_;
366 root 1.4
367 root 1.1 ($g, $b) = ($r, $r) if @_ < 4;
368     $a = 1 if @_ < 5;
369 root 1.4
370 root 1.1 $img = $img->clone;
371     $img->brightness ($r, $g, $b, $a);
372     $img
373     }
374    
375 root 1.15 =back
376    
377     =cut
378    
379 root 1.1 }
380    
381     sub parse_expr {
382     my $expr = eval "sub {\npackage urxvt::bgdsl;\n#line 0 'background expression'\n$_[0]\n}";
383     die if $@;
384     $expr
385     }
386    
387     # compiles a parsed expression
388     sub set_expr {
389     my ($self, $expr) = @_;
390    
391     $self->{expr} = $expr;
392     $self->recalculate;
393     }
394    
395     # evaluate the current bg expression
396     sub recalculate {
397 root 1.33 my ($arg_self) = @_;
398 root 1.1
399 root 1.10 # rate limit evaluation
400    
401 root 1.33 if ($arg_self->{next_refresh} > urxvt::NOW) {
402     $arg_self->{next_refresh_timer} = urxvt::timer->new->after ($arg_self->{next_refresh} - urxvt::NOW)->cb (sub {
403     $arg_self->recalculate;
404 root 1.9 });
405 root 1.12 return;
406 root 1.9 }
407    
408 root 1.33 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
409 root 1.9
410 root 1.10 # set environment to evaluate user expression
411 root 1.6
412 root 1.33 local $self = $arg_self;
413 root 1.1
414 root 1.3 local $old = $self->{state};
415     local $new = my $state = $self->{state} = {};
416 root 1.1
417 root 1.29 ($x, $y, $w, $h) =
418 root 1.33 $self->background_geometry ($self->{border});
419 root 1.22
420 root 1.10 # evaluate user expression
421    
422 root 1.1 my $img = eval { $self->{expr}->() };
423     warn $@ if $@;#d#
424 root 1.15 die if !UNIVERSAL::isa $img, "urxvt::img";
425 root 1.1
426 root 1.10 # if the expression is sensitive to external events, prepare reevaluation then
427    
428 root 1.2 my $repeat;
429    
430 root 1.1 if (my $again = $state->{again}) {
431 root 1.2 $repeat = 1;
432 root 1.6 $state->{timer} = $again == $old->{again}
433     ? $old->{timer}
434 root 1.7 : urxvt::timer->new->after ($again)->interval ($again)->cb (sub {
435     ++$self->{counter};
436     $self->recalculate
437     });
438 root 1.1 }
439    
440 root 1.2 if (delete $state->{position_sensitive}) {
441     $repeat = 1;
442     $self->enable (position_change => sub { $_[0]->recalculate });
443     } else {
444     $self->disable ("position_change");
445     }
446    
447     if (delete $state->{size_sensitive}) {
448     $repeat = 1;
449     $self->enable (size_change => sub { $_[0]->recalculate });
450     } else {
451     $self->disable ("size_change");
452     }
453    
454 root 1.9 if (delete $state->{rootpmap_sensitive}) {
455     $repeat = 1;
456     $self->enable (rootpmap_change => sub { $_[0]->recalculate });
457     } else {
458     $self->disable ("rootpmap_change");
459     }
460    
461 root 1.10 # clear stuff we no longer need
462    
463 root 1.6 %$old = ();
464    
465 root 1.5 unless ($repeat) {
466     delete $self->{state};
467     delete $self->{expr};
468     }
469    
470 root 1.10 # prepare and set background pixmap
471    
472 root 1.4 $img = $img->sub_rect (0, 0, $w, $h)
473     if $img->w != $w || $img->h != $h;
474 root 1.1
475 root 1.33 $self->set_background ($img, $self->{border});
476 root 1.1 $self->scr_recolour (0);
477     $self->want_refresh;
478     }
479    
480     sub on_start {
481     my ($self) = @_;
482    
483 root 1.33 my $expr = $self->x_resource ("background.expr")
484     or return;
485    
486     $self->set_expr (parse_expr $expr);
487     $self->{border} = $self->x_resource_boolean ("background.border");
488 root 1.1
489     ()
490     }
491