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