--- rxvt-unicode/src/perl/background 2012/06/10 19:01:03 1.51 +++ rxvt-unicode/src/perl/background 2012/06/14 17:06:57 1.56 @@ -73,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 @@ -204,7 +204,7 @@ =cut -our %_IMGCACHE; +our %_IMG_CACHE; our $HOME; our ($self, $old, $new); our ($x, $y, $w, $h); @@ -230,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 @@ -251,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 @@ -286,7 +303,15 @@ $_[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 @@ -411,14 +436,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 @@ -435,7 +460,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 @@ -447,11 +472,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 } @@ -632,6 +657,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 @@ -723,28 +769,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 @@ -799,15 +884,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} @@ -817,23 +901,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"); } @@ -842,7 +926,7 @@ %$old = (); - unless ($repeat) { + unless (%$again) { delete $self->{state}; delete $self->{expr}; }