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