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 (11 years, 11 months ago) by root
Branch: MAIN
Changes since 1.32: +56 -20 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #! perl
2
3 #:META:X_RESOURCE:%.expr:string:background expression
4 #: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
19 our $EXPR;
20 #$EXPR = 'move W * 0.1, -H * 0.1, resize W * 0.5, H * 0.5, repeat_none load "opensource.png"';
21 $EXPR = 'move -TX, -TY, load "argb.png"';
22 #$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 #$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 our ($self, $old, $new);
33 our ($x, $y, $w, $h);
34
35 # enforce at least this interval between updates
36 our $MIN_INTERVAL = 1/100;
37
38 {
39 package urxvt::bgdsl; # background language
40
41 =head2 PROVIDERS/GENERATORS
42
43 These functions provide an image, by loading it from disk, grabbing it
44 from the root screen or by simply generating it. They are used as starting
45 points to get an image you can play with.
46
47 =over 4
48
49 =item load $path
50
51 Loads the image at the given C<$path>. The image is set to plane tiling
52 mode.
53
54 Loaded images will be cached for one cycle.
55
56 =cut
57
58 sub load($) {
59 my ($path) = @_;
60
61 $new->{load}{$path} = $old->{load}{$path} || $self->new_img_from_file ($path);
62 }
63
64 =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 sub root() {
75 $new->{rootpmap_sensitive} = 1;
76 die "root op not supported, exg, we need you";
77 }
78
79 =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 my $img = $self->new_img (urxvt::PictStandardARGB32, $_[0] || 1, $_[1] || 1);
95 $img->fill ($colour);
96 $img
97 }
98
99 =back
100
101 =head2 VARIABLES
102
103 The following functions provide variable data such as the terminal
104 window dimensions. Most of them make your expression sensitive to some
105 events, for example using C<TW> (terminal width) means your expression is
106 evaluated again when the terminal is resized.
107
108 =over 4
109
110 =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 =cut
144
145 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
150 =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 sub now() { urxvt::NOW }
175
176 sub again($) {
177 $new->{again} = $_[0];
178 }
179
180 sub counter($) {
181 $new->{again} = $_[0];
182 $self->{counter} + 0
183 }
184
185 =back
186
187 =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
192 =over 4
193
194 =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 =cut
221
222 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
240 sub extend($) {
241 my $img = $_[0]->clone;
242 $img->repeat_mode (urxvt::RepeatPad);
243 $img
244 }
245
246 =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 sub clip($;$$;$$) {
288 my $img = pop;
289 my $h = pop || TH;
290 my $w = pop || TW;
291 $img->sub_rect ($_[0], $_[1], $w, $h)
292 }
293
294 =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 sub scale($;$;$) {
317 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 : $img->scale (TW, TH)
322 }
323
324 sub resize($$$) {
325 my $img = pop;
326 $img->scale ($_[0], $_[1])
327 }
328
329 sub move($$;$) {
330 my $img = pop->clone;
331 $img->move ($_[0], $_[1]);
332 $img
333 }
334
335 sub rotate($$$$$$) {
336 my $img = pop;
337 $img->rotate (
338 $_[0],
339 $_[1],
340 $_[2] * $img->w * .01,
341 $_[3] * $img->h * .01,
342 $_[4] * (3.14159265 / 180),
343 )
344 }
345
346 sub blur($$;$) {
347 my $img = pop;
348 $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0])
349 }
350
351 sub contrast($$;$$;$) {
352 my $img = pop;
353 my ($r, $g, $b, $a) = @_;
354
355 ($g, $b) = ($r, $r) if @_ < 4;
356 $a = 1 if @_ < 5;
357
358 $img = $img->clone;
359 $img->contrast ($r, $g, $b, $a);
360 $img
361 }
362
363 sub brightness($$;$$;$) {
364 my $img = pop;
365 my ($r, $g, $b, $a) = @_;
366
367 ($g, $b) = ($r, $r) if @_ < 4;
368 $a = 1 if @_ < 5;
369
370 $img = $img->clone;
371 $img->brightness ($r, $g, $b, $a);
372 $img
373 }
374
375 =back
376
377 =cut
378
379 }
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 my ($arg_self) = @_;
398
399 # rate limit evaluation
400
401 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 });
405 return;
406 }
407
408 $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL;
409
410 # set environment to evaluate user expression
411
412 local $self = $arg_self;
413
414 local $old = $self->{state};
415 local $new = my $state = $self->{state} = {};
416
417 ($x, $y, $w, $h) =
418 $self->background_geometry ($self->{border});
419
420 # evaluate user expression
421
422 my $img = eval { $self->{expr}->() };
423 warn $@ if $@;#d#
424 die if !UNIVERSAL::isa $img, "urxvt::img";
425
426 # if the expression is sensitive to external events, prepare reevaluation then
427
428 my $repeat;
429
430 if (my $again = $state->{again}) {
431 $repeat = 1;
432 $state->{timer} = $again == $old->{again}
433 ? $old->{timer}
434 : urxvt::timer->new->after ($again)->interval ($again)->cb (sub {
435 ++$self->{counter};
436 $self->recalculate
437 });
438 }
439
440 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 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 # clear stuff we no longer need
462
463 %$old = ();
464
465 unless ($repeat) {
466 delete $self->{state};
467 delete $self->{expr};
468 }
469
470 # prepare and set background pixmap
471
472 $img = $img->sub_rect (0, 0, $w, $h)
473 if $img->w != $w || $img->h != $h;
474
475 $self->set_background ($img, $self->{border});
476 $self->scr_recolour (0);
477 $self->want_refresh;
478 }
479
480 sub on_start {
481 my ($self) = @_;
482
483 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
489 ()
490 }
491