--- rxvt-unicode/src/perl/background 2012/06/10 15:01:14 1.48 +++ rxvt-unicode/src/perl/background 2012/06/14 18:06:15 1.57 @@ -4,8 +4,6 @@ #:META:X_RESOURCE:%.border:boolean:respect the terminal border #:META:X_RESOURCE:%.interval:seconds:minimum time between updates -#TODO: once, rootalign - =head1 NAME background - manage terminal background @@ -61,7 +59,7 @@ image to the window size, so it relies on the window size and will be reevaluated each time it is changed, but not when it moves for example. That ensures that the picture always fills the terminal, even -after it's size changes. +after its size changes. =head2 EXPRESSIONS @@ -75,7 +73,7 @@ return scale load "$HOME/sunday.png"; } -This expression gets evaluated once per hour. It will set F as +This expression is evaluated once per hour. It will set F as background on Sundays, and F on all other days. Fortunately, we expect that most expressions will be much simpler, with @@ -119,7 +117,7 @@ scale 0.5, 2, load "$HOME/mypic.png" -Other effects than scalign are also readily available, for exmaple, you can +Other effects than scaling are also readily available, for example, you can tile the image to fill the whole window, instead of resizing it: tile load "$HOME/mypic.png" @@ -155,7 +153,7 @@ image, it will forget about the first one. This allows you to either speed things up by keeping multiple images in -memory, or comserve memory by loading images more often. +memory, or conserve memory by loading images more often. For example, you can keep two images in memory and use a random one like this: @@ -195,7 +193,7 @@ =item --background-interval seconds -Since some operations in the underlying XRender extension can effetively +Since some operations in the underlying XRender extension can effectively freeze your X-server for prolonged time, this extension enforces a minimum time between updates, which is normally about 0.1 seconds. @@ -206,6 +204,7 @@ =cut +our %_IMG_CACHE; our $HOME; our ($self, $old, $new); our ($x, $y, $w, $h); @@ -231,14 +230,31 @@ Loads the image at the given C<$path>. The image is set to plane tiling mode. -Loaded images will be cached for one cycle. +Loaded images will be cached for one cycle, and shared between temrinals +running in the same process (e.g. in C). + +=item load_uc $path + +Load uncached - same as load, but does not cache the image. This function +is most useufl if you want to optimise a background expression in some +way. =cut + sub load_uc($) { + my ($path) = @_; + + $_IMG_CACHE{$path} || do { + my $img = $self->new_img_from_file ($path); + Scalar::Util::weaken ($_IMG_CACHE{$path} = $img); + $img + } + } + sub load($) { my ($path) = @_; - $new->{load}{$path} = $old->{load}{$path} || $self->new_img_from_file ($path); + $new->{load}{$path} = $old->{load}{$path} || load_uc $path; } =item root @@ -252,8 +268,8 @@ =cut sub root() { - $new->{rootpmap_sensitive} = 1; - die "root op not supported, exg, we need you"; + $new->{again}{rootpmap} = 1; + $self->new_img_from_root } =item solid $colour @@ -287,7 +303,16 @@ $_[0]->clone } -=back +=item merge $img ... + +Takes any number of images and merges them together, creating a single +image containing them all. + +=cut + + sub merge(@) { + #TODO + } =head2 TILING MODES @@ -327,7 +352,7 @@ background pixels outside the image unchanged. Example: load an image and display it in the upper left corner. The rest -of the space is left "empty" (transparent or wahtever your compisotr does +of the space is left "empty" (transparent or whatever your compositor does in alpha mode, else background colour). pad load "mybg.png" @@ -335,7 +360,7 @@ =item extend $img Extends the image over the whole plane, using the closest pixel in the -area outside the image. This mode is mostly useful when you more complex +area outside the image. This mode is mostly useful when you use more complex filtering operations and want the pixels outside the image to have the same values as the pixels near the edge. @@ -412,14 +437,14 @@ Example: take the screen background, clip it to the window size, blur it a bit, align it to the window position and use it as background. - clip move -TX, -TY, blur 5, root + clip move -TX, -TY, once { blur 5, root } =cut - sub TX() { $new->{position_sensitive} = 1; $x } - sub TY() { $new->{position_sensitive} = 1; $y } - sub TW() { $new->{size_sensitive} = 1; $w } - sub TH() { $new->{size_sensitive} = 1; $h } + sub TX() { $new->{again}{position} = 1; $x } + sub TY() { $new->{again}{position} = 1; $y } + sub TW() { $new->{again}{size} = 1; $w } + sub TH() { $new->{again}{size} = 1; $h } =item now @@ -436,7 +461,7 @@ Example: load some image and rotate it according to the time of day (as if it were the hour pointer of a clock). Update this image every minute. - again 60; rotate TW, TH, 50, 50, (now % 86400) * -720 / 86400, scale load "myclock.png" + again 60; rotate 50, 50, (now % 86400) * -720 / 86400, scale load "myclock.png" =item counter $seconds @@ -448,11 +473,11 @@ sub now() { urxvt::NOW } sub again($) { - $new->{again} = $_[0]; + $new->{again}{time} = $_[0]; } sub counter($) { - $new->{again} = $_[0]; + $new->{again}{time} = $_[0]; $self->{counter} + 0 } @@ -633,6 +658,27 @@ move -TX, -TY, $_[0] } +=item rotate $center_x, $center_y, $degrees + +Rotates the image by C<$degrees> degrees, counter-clockwise, around the +pointer at C<$center_x> and C<$center_y> (specified as factor of image +width/height). + +#TODO# new width, height, maybe more operators? + +Example: rotate the image by 90 degrees + +=cut + + sub rotate($$$$) { + my $img = pop; + $img->rotate ( + $_[0] * $img->w, + $_[1] * $img->h, + $_[2] * (3.14159265 / 180), + ) + } + =back =head2 COLOUR MODIFICATIONS @@ -676,7 +722,7 @@ it. Useful range is from -1 to 1 - the former results in a black, the latter in a white picture. -Due to idiosynchrasies in the underlying XRender extension, biases less +Due to idiosyncrasies in the underlying XRender extension, biases less than zero can be I slow. =cut @@ -685,8 +731,8 @@ my $img = pop; my ($r, $g, $b, $a) = @_; - ($g, $b) = ($r, $r) if @_ < 4; - $a = 1 if @_ < 5; + ($g, $b) = ($r, $r) if @_ < 3; + $a = 1 if @_ < 4; $img = $img->clone; $img->contrast ($r, $g, $b, $a); @@ -697,8 +743,8 @@ my $img = pop; my ($r, $g, $b, $a) = @_; - ($g, $b) = ($r, $r) if @_ < 4; - $a = 1 if @_ < 5; + ($g, $b) = ($r, $r) if @_ < 3; + $a = 1 if @_ < 4; $img = $img->clone; $img->brightness ($r, $g, $b, $a); @@ -724,28 +770,67 @@ $img->blur ($_[0], @_ >= 2 ? $_[1] : $_[0]) } -=item rotate $new_width, $new_height, $center_x, $center_y, $degrees +=back -Rotates the image by C<$degrees> degrees, counter-clockwise, around the -pointer at C<$center_x> and C<$center_y> (specified as factor of image -width/height), generating a new image with width C<$new_width> and height -C<$new_height>. +=head2 OTHER STUFF -#TODO# new width, height, maybe more operators? +Anything that didn't fit any of the other categories, even after applying +force and closing our eyes. -Example: rotate the image by 90 degrees +=over 4 + +=item once { ... } + +This function takes a code block as argument, that is, one or more +statements enclosed by braces. + +The trick is that this code block is only evaluated once - future calls +will simply return the original image (yes, it should only be used with +images). + +This can be extremely useful to avoid redoign the same slow operations +again and again- for example, if your background expression takes the root +background, blurs it and then root-aligns it it would have to blur the +root background on every window move or resize. + +Putting the blur into a C block will make sure the blur is only done +once: + + rootlign once { blur 10, root } + +This leaves the question of how to force reevaluation of the block, in +case the root background changes: Right now, all once blocks forget that +they ahve been executed before each time the root background changes (if +the expression is sensitive to that) or when C is called. + +=item once_again + +Resets all C block as if they had never been called, i.e. on the +next call they will be reevaluated again. =cut - sub rotate($$$$$$) { - my $img = pop; - $img->rotate ( - $_[0], - $_[1], - $_[2] * $img->w, - $_[3] * $img->h, - $_[4] * (3.14159265 / 180), - ) + sub once(&) { + my $once = $self->{once_cache}{$_[0]+0} ||= do { + local $new->{again}; + my @res = $_[0](); + [$new->{again}, \@res] + }; + + $new->{again} = { + %{ $new->{again} }, + %{ $once->[0] } + }; + + # in scalar context we always return the first original result, which + # is not quite how perl works. + wantarray + ? @{ $once->[1] } + : $once->[1][0] + } + + sub once_again() { + delete $self->{once_cache}; } =back @@ -800,15 +885,14 @@ warn $@ if $@;#d# die "background-expr did not return an image.\n" if !UNIVERSAL::isa $img, "urxvt::img"; - $state->{size_sensitive} = 1 - if $img->repeat_mode != urxvt::RepeatNormal; - # if the expression is sensitive to external events, prepare reevaluation then - my $repeat; + my $again = delete $state->{again}; - if (my $again = $state->{again}) { - $repeat = 1; + $again->{size} = 1 + if $img->repeat_mode != urxvt::RepeatNormal; + + if (my $again = $again->{time}) { my $self = $self; $state->{timer} = $again == $old->{again} ? $old->{timer} @@ -818,23 +902,23 @@ }); } - if (delete $state->{position_sensitive}) { - $repeat = 1; + if ($again->{position}) { $self->enable (position_change => sub { $_[0]->recalculate }); } else { $self->disable ("position_change"); } - if (delete $state->{size_sensitive}) { - $repeat = 1; + if ($again->{size}) { $self->enable (size_change => sub { $_[0]->recalculate }); } else { $self->disable ("size_change"); } - if (delete $state->{rootpmap_sensitive}) { - $repeat = 1; - $self->enable (rootpmap_change => sub { $_[0]->recalculate }); + if ($again->{rootpmap}) { + $self->enable (rootpmap_change => sub { + delete $_[0]{once_cache}; # this will override once-block values from + $_[0]->recalculate; + }); } else { $self->disable ("rootpmap_change"); } @@ -843,7 +927,7 @@ %$old = (); - unless ($repeat) { + unless (%$again) { delete $self->{state}; delete $self->{expr}; }