--- rxvt-unicode/src/perl/background 2019/09/17 17:15:29 1.94 +++ rxvt-unicode/src/perl/background 2019/09/17 20:38:14 1.98 @@ -26,8 +26,8 @@ =head1 QUICK AND DIRTY CHEAT SHEET -Just load a random jpeg image and tile the background with it without -scaling or anything else: +Load a random jpeg image and tile the background with it without scaling +or anything else: load "/path/to/img.jpg" @@ -1151,6 +1151,13 @@ =head2 OSC sequences +This extension will react to the following OSC sequences. Note that +this extension will not be autoloaded when these are used currenmtly, +so to make urxvt recognize them, you have to enable the C +extension. One way to achieve that is to use the C<--background-expr ''> +command line argument or by specifying an empty C> +resource. + =over 4 =item B<< C >> Change transparent background tint colour to B<< C >>. @@ -1216,13 +1223,23 @@ } sub parse_expr { - my $expr = eval - "sub {\n" - . "package urxvt::bgdsl;\n" - . "#line 0 'background expression'\n" - . "$_[0]\n" - . "}"; - die if $@; + my ($expr) = @_; + + # an empty expression is valid and represents the default background + if ($expr !~ /\S/) { + $expr = sub { + undef + }; + } else { + $expr = eval + "sub {\n" + . "package urxvt::bgdsl;\n" + . "#line 0 'background expression'\n" + . "$expr\n" + . "}"; + die if $@; + } + $expr } @@ -1304,6 +1321,11 @@ $arg_self->{next_refresh} = urxvt::NOW + $MIN_INTERVAL; + unless ($arg_self->has_render) { + warn "background extension needs RENDER extension 0.10 or higher, ignoring background-expr.\n"; + return; + } + # set environment to evaluate user expression local $self = $arg_self; @@ -1318,27 +1340,33 @@ my @img = eval { $self->{expr}->() }; die $@ if $@; die "background-expr did not return anything.\n" unless @img; - die "background-expr: expected image(s), got something else.\n" - if grep { !UNIVERSAL::isa $_, "urxvt::img" } @img; - my $img = urxvt::bgdsl::merge @img; + if ($img[0]) { + die "background-expr: expected image(s), got something else.\n" + if grep { !UNIVERSAL::isa $_, "urxvt::img" } @img; - $frame->[FR_AGAIN]{size} = 1 - if $img->repeat_mode != urxvt::RepeatNormal; + my $img = urxvt::bgdsl::merge @img; - # if the expression is sensitive to external events, prepare reevaluation then - $self->compile_frame ($frame, sub { $arg_self->recalculate }); + $frame->[FR_AGAIN]{size} = 1 + if $img->repeat_mode != urxvt::RepeatNormal; - # clear stuff we no longer need + # if the expression is sensitive to external events, prepare reevaluation then + $self->compile_frame ($frame, sub { $arg_self->recalculate }); + + # clear stuff we no longer need # unless (%{ $frame->[FR_STATE] }) { # delete $self->{state}; # delete $self->{expr}; # } - # set background pixmap + # set background pixmap + + $self->set_background ($img, $self->{border}); + } else { + $self->clr_background; + } - $self->set_background ($img, $self->{border}); $self->scr_recolor (0); $self->want_refresh; } @@ -1355,12 +1383,12 @@ my $bg_opts = $self->{bg_opts}; if ($str[0]) { - $bg_opts->{tile} = 0; + $bg_opts->{tile} = 0; $bg_opts->{keep_aspect} = 0; - $bg_opts->{root_align} = 0; - $bg_opts->{h_scale} = $bg_opts->{v_scale} = 100; - $bg_opts->{h_align} = $bg_opts->{v_align} = 50; - $bg_opts->{path} = unpack "H*", $str[0]; + $bg_opts->{root_align} = 0; + $bg_opts->{h_scale} = $bg_opts->{v_scale} = 100; + $bg_opts->{h_align} = $bg_opts->{v_align} = 50; + $bg_opts->{path} = $str[0]; } my @oplist = split /:/, $str[1]; @@ -1419,6 +1447,14 @@ } } +# helper function, quote string as perl without allowing +# any code execution or other shenanigans. does not +# support binary NULs in string. +sub q0 { + (my $str = shift) =~ s/\x00//g; # make sure there really aren't any embedded NULs + "q\x00$str\x00" +} + sub old_bg_expr { my ($self) = @_; @@ -1443,7 +1479,8 @@ my $tint = $bg_opts->{tint}; if ($tint) { - $expr .= "tint $tint, "; + $tint = q0 $tint; + $expr .= "tint $tint,"; } my $blur = $bg_opts->{blur}; @@ -1484,7 +1521,9 @@ $file_expr .= "$op TW * $h_scale, TH * $v_scale, "; } - $file_expr .= "keep { load pack \"H*\", \"$bg_opts->{path}\" })"; + my $path = q0 $bg_opts->{path}; + + $file_expr .= "keep { load $path })"; if ($expr) { $expr .= ", tint (\"[50]white\", $file_expr)"; @@ -1501,7 +1540,7 @@ $self->{bg_opts} or return; - $op =~ /^(20|705)$/ or return; + $op =~ /^(?:20|705)$/ or return; if ($op eq "20") { if ($arg eq "?") { @@ -1542,20 +1581,15 @@ $self->{bg_opts} = { h_scale => 100, v_scale => 100, h_align => 50, v_align => 50 }; - $self->{bg_opts}->{shade} = $self->find_resource ("shading", "sh"); - $self->{bg_opts}->{tint} = $self->find_resource ("tintColor", "tint"); - $self->{bg_opts}->{blur} = $self->find_resource ("blurRadius", "blr"); - $self->{bg_opts}->{root} = $self->find_resource ("transparent", "tr"); + $self->{bg_opts}{shade} = $self->find_resource ("shading", "sh"); + $self->{bg_opts}{tint} = $self->find_resource ("tintColor", "tint"); + $self->{bg_opts}{blur} = $self->find_resource ("blurRadius", "blr"); + $self->{bg_opts}{root} = $self->find_resource ("transparent", "tr"); $self->old_bg_opts ($self->find_resource ("backgroundPixmap", "pixmap")); $expr = $self->old_bg_expr; } - $expr or return; - - $self->has_render - or die "background extension needs RENDER extension 0.10 or higher, ignoring background-expr.\n"; - $self->set_expr (parse_expr $expr); $self->{border} = $self->x_resource_boolean ("%.border");