All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
   3 # On-the-fly adjusting of the font size in urxvt
 
   5 # Copyright (c) 2008 David O'Neill
 
   6 #               2012 Noah K. Tilton <noahktilton@gmail.com>
 
   7 #               2009-2012 Simon Lundström <simmel@soy.se>
 
   8 #               2012-2016 Jan Larres <jan@majutsushi.net>
 
  10 # Permission is hereby granted, free of charge, to any person obtaining a copy
 
  11 # of this software and associated documentation files (the "Software"), to
 
  12 # deal in the Software without restriction, including without limitation the
 
  13 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 
  14 # sell copies of the Software, and to permit persons to whom the Software is
 
  15 # furnished to do so, subject to the following conditions:
 
  17 # The above copyright notice and this permission notice shall be included in
 
  18 # all copies or substantial portions of the Software.
 
  20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
  21 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
  22 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
  23 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
  24 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
  25 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
  28 # URL: https://github.com/majutsushi/urxvt-font-size
 
  31 # https://github.com/dave0/urxvt-font-size
 
  32 # https://github.com/noah/urxvt-font
 
  33 # https://github.com/simmel/urxvt-resize-font
 
  36 #:META:X_RESOURCE:%.step:interger:font size increase/decrease step
 
  40 font-size - interactive font size setter
 
  44 Put the font-size script into $HOME/.urxvt/ext/ and add it to the list
 
  45 of enabled perl-extensions in ~/.Xresources:
 
  47   URxvt.perl-ext-common: ...,font-size
 
  51   URxvt.keysym.C-Up:     font-size:increase
 
  52   URxvt.keysym.C-Down:   font-size:decrease
 
  53   URxvt.keysym.C-S-Up:   font-size:incglobal
 
  54   URxvt.keysym.C-S-Down: font-size:decglobal
 
  55   URxvt.keysym.C-equal:  font-size:reset
 
  56   URxvt.keysym.C-slash:  font-size:show
 
  58 Note that for urxvt versions older than 9.21 the resources have to look like this:
 
  60   URxvt.keysym.C-Up:     perl:font-size:increase
 
  61   URxvt.keysym.C-Down:   perl:font-size:decrease
 
  62   URxvt.keysym.C-S-Up:   perl:font-size:incglobal
 
  63   URxvt.keysym.C-S-Down: perl:font-size:decglobal
 
  64   URxvt.keysym.C-equal   perl:font-size:reset
 
  65   URxvt.keysym.C-slash   perl:font-size:show
 
  71 =item * increase/decrease:
 
  73       increase or decrease the font size of the current terminal.
 
  75 =item * incglobal/decglobal:
 
  77       same as above and also adjust the X server values so all newly
 
  78       started terminals will use the same fontsize.
 
  80 =item * incsave/decsave:
 
  82       same as incglobal/decglobal and also modify the ~/.Xresources
 
  83       file so the changed font sizes will persist over a restart of
 
  84       the X server or a reboot.
 
  88       reset the font size to the value of the resource when starting
 
  93       show the current value of the 'font' resource in a popup.
 
  97 You can also change the step size that the script will use to increase
 
 100   URxvt.font-size.step: 4
 
 102 The default step size is 1. This means that with this setting a
 
 103 size change sequence would be for example 8->12->16->20 instead of
 
 104 8->9->10->11->12 etc. Please note that many X11 fonts are only
 
 105 available in specific sizes, though, and odd sizes are often not
 
 106 available, resulting in an effective step size of 2 instead of 1
 
 117     "boldItalicFont" => 713
 
 124     $self->{step} = $self->x_resource("%.step") || 1;
 
 126     foreach my $type (qw(font boldFont italicFont boldItalicFont)) {
 
 127         $self->{$type} = $self->x_resource($type) || "undef";
 
 131 # Needed for backwards compatibility with < 9.21
 
 134     my ($self, $cmd) = @_;
 
 136     my $step = $self->{step};
 
 138     if ($cmd eq "font-size:increase") {
 
 139         fonts_change_size($self,  $step, 0);
 
 140     } elsif ($cmd eq "font-size:decrease") {
 
 141         fonts_change_size($self, -$step, 0);
 
 142     } elsif ($cmd eq "font-size:incglobal") {
 
 143         fonts_change_size($self,  $step, 1);
 
 144     } elsif ($cmd eq "font-size:decglobal") {
 
 145         fonts_change_size($self, -$step, 1);
 
 146     } elsif ($cmd eq "font-size:incsave") {
 
 147         fonts_change_size($self,  $step, 2);
 
 148     } elsif ($cmd eq "font-size:decsave") {
 
 149         fonts_change_size($self, -$step, 2);
 
 150     } elsif ($cmd eq "font-size:reset") {
 
 152     } elsif ($cmd eq "font-size:show") {
 
 159     my ($self, $action) = @_;
 
 161     my $step = $self->{step};
 
 163     if ($action eq "increase") {
 
 164         fonts_change_size($self,  $step, 0);
 
 165     } elsif ($action eq "decrease") {
 
 166         fonts_change_size($self, -$step, 0);
 
 167     } elsif ($action eq "incglobal") {
 
 168         fonts_change_size($self,  $step, 1);
 
 169     } elsif ($action eq "decglobal") {
 
 170         fonts_change_size($self, -$step, 1);
 
 171     } elsif ($action eq "incsave") {
 
 172         fonts_change_size($self,  $step, 2);
 
 173     } elsif ($action eq "decsave") {
 
 174         fonts_change_size($self, -$step, 2);
 
 175     } elsif ($action eq "reset") {
 
 177     } elsif ($action eq "show") {
 
 182 sub fonts_change_size
 
 184     my ($term, $delta, $save) = @_;
 
 188     my $curres = $term->resource('font');
 
 190         $term->scr_add_lines("\r\nWarning: No font configured, trying a default.\r\nPlease set a font with the 'URxvt.font' resource.");
 
 193     my @curfonts = split(/\s*,\s*/, $curres);
 
 195     my $basefont = shift(@curfonts);
 
 196     my ($newbasefont, $newbasedelta, $newbasesize) = handle_font($term, $basefont, $delta, 0, 0);
 
 197     push @newfonts, $newbasefont;
 
 199     # Only adjust other fonts if base font changed
 
 200     if ($newbasefont ne $basefont) {
 
 201         foreach my $font (@curfonts) {
 
 202             my ($newfont, $newdelta, $newsize) = handle_font($term, $font, $delta, $newbasedelta, $newbasesize);
 
 203             push @newfonts, $newfont;
 
 205         my $newres = join(",", @newfonts);
 
 206         font_apply_new($term, $newres, "font", $save);
 
 208         handle_type($term, "boldFont",       $delta, $newbasedelta, $newbasesize, $save);
 
 209         handle_type($term, "italicFont",     $delta, $newbasedelta, $newbasesize, $save);
 
 210         handle_type($term, "boldItalicFont", $delta, $newbasedelta, $newbasesize, $save);
 
 214         # write the new values back to the file
 
 215         my $xresources = readlink $ENV{"HOME"} . "/.Xresources";
 
 216         system("xrdb -edit " . $xresources);
 
 224     foreach my $type (qw(font boldFont italicFont boldItalicFont)) {
 
 225         my $initial = $term->{$type};
 
 226         if ($initial ne "undef") {
 
 227             font_apply_new($term, $initial, $type, 0);
 
 236     my $out = $term->resource('font');
 
 237     $out =~ s/\s*,\s*/\n/g;
 
 239     $term->{'font-size'}{'overlay'} = {
 
 240         overlay => $term->overlay_simple(0, -1, $out),
 
 241         timer => urxvt::timer->new->start(urxvt::NOW + 5)->cb(
 
 243                 delete $term->{'font-size'}{'overlay'};
 
 251     my ($term, $type, $delta, $basedelta, $basesize, $save) = @_;
 
 253     my $curres = $term->resource($type);
 
 257     my @curfonts = split(/\s*,\s*/, $curres);
 
 260     foreach my $font (@curfonts) {
 
 261         my ($newfont, $newdelta, $newsize) = handle_font($term, $font, $delta, $basedelta, $basesize);
 
 262         push @newfonts, $newfont;
 
 265     my $newres = join(",", @newfonts);
 
 266     font_apply_new($term, $newres, $type, $save);
 
 271     my ($term, $font, $delta, $basedelta, $basesize) = @_;
 
 278     if ($font =~ /^\s*x:/) {
 
 282     if ($font =~ /^\s*(\[.*\])?xft:/) {
 
 283         ($newfont, $newdelta, $newsize) = font_change_size_xft($term, $font, $delta, $basedelta, $basesize);
 
 284     } elsif ($font =~ /^\s*-/) {
 
 285         ($newfont, $newdelta, $newsize) = font_change_size_xlfd($term, $font, $delta, $basedelta, $basesize);
 
 287         # check whether the font is a valid alias and if yes resolve it to the
 
 289         my $lsfinfo = `xlsfonts -l $font 2>/dev/null`;
 
 291         if ($lsfinfo eq "") {
 
 292             # not a valid alias, ring the bell if it is the base font and just
 
 293             # return the current font
 
 294             if ($basesize == 0) {
 
 297             return ($font, $basedelta, $basesize);
 
 300         my $fontinfo = (split(/\n/, $lsfinfo))[-1];
 
 301         my ($fontfull) = ($fontinfo =~ /\s+([-a-z0-9]+$)/);
 
 302         ($newfont, $newdelta, $newsize) = font_change_size_xlfd($term, $fontfull, $delta, $basedelta, $basesize);
 
 305     # $term->scr_add_lines("\r\nNew font is $newfont\n");
 
 307         $newfont = "x:$newfont";
 
 309     return ($newfont, $newdelta, $newsize);
 
 312 sub font_change_size_xft
 
 314     my ($term, $fontstring, $delta, $basedelta, $basesize) = @_;
 
 316     my @pieces   = split(/:/, $fontstring);
 
 321     foreach my $piece (@pieces) {
 
 322         if ($piece =~ /^(?:(?:pixel)?size=|[^=-]+-)(\d+(\.\d*)?)$/) {
 
 325             if ($basedelta != 0) {
 
 326                 $new_size = $size + $basedelta;
 
 328                 $new_size = $size + $delta;
 
 331             $piece =~ s/(=|-)$size/$1$new_size/;
 
 333         push @resized, $piece;
 
 336     my $resized_str = join(":", @resized);
 
 338     # don't make fonts too small
 
 339     if ($new_size >= 6) {
 
 340         return ($resized_str, $new_size - $size, $new_size);
 
 342         if ($basesize == 0) {
 
 345         return ($fontstring, 0, $size);
 
 349 sub font_change_size_xlfd
 
 351     my ($term, $fontstring, $delta, $basedelta, $basesize) = @_;
 
 353     #-xos4-terminus-medium-r-normal-*-12-*-*-*-*-*-*-1
 
 355     my @fields = qw(foundry family weight slant setwidth style pixelSize pointSize Xresolution Yresolution spacing averageWidth registry encoding);
 
 358     $fontstring =~ s/^-//;  # Strip leading - before split
 
 359     @font{@fields} = split(/-/, $fontstring);
 
 361     if ($font{pixelSize} eq '*') {
 
 362         $term->scr_add_lines("\r\nWarning: Font size undefined, assuming 12.\r\nPlease set the 'URxvt.font' resource to a font with a concrete size.");
 
 363         $font{pixelSize} = '12'
 
 365     if ($font{registry} eq '*') {
 
 366         $font{registry} ='iso8859';
 
 369     # Blank out the size for the pattern
 
 371     $pattern{foundry} = '*';
 
 372     $pattern{setwidth} = '*';
 
 373     $pattern{pixelSize} = '*';
 
 374     $pattern{pointSize} = '*';
 
 375     # if ($basesize != 0) {
 
 376     #     $pattern{Xresolution} = '*';
 
 377     #     $pattern{Yresolution} = '*';
 
 379     $pattern{averageWidth} = '*';
 
 380     # make sure there are no empty fields
 
 381     foreach my $field (@fields) {
 
 382         $pattern{$field} = '*' unless defined($pattern{$field});
 
 384     my $new_fontstring = '-' . join('-', @pattern{@fields});
 
 387     # $term->scr_add_lines("\r\nPattern is $new_fontstring\n");
 
 388     open(FOO, "xlsfonts -fn '$new_fontstring' | sort -u |") or die $!;
 
 391         s/^-//;  # Strip leading '-' before split
 
 392         my @fontdata = split(/-/, $_);
 
 394         push @candidates, [$fontdata[6], "-$_"];
 
 395         # $term->scr_add_lines("\r\npossibly $fontdata[6] $_\n");
 
 400         die "No possible fonts!";
 
 403     if ($basesize != 0) {
 
 404         # sort by font size, descending
 
 405         @candidates = sort {$b->[0] <=> $a->[0]} @candidates;
 
 407         # font is not the base font, so find the largest font that is at most
 
 408         # as large as the base font. If the largest possible font is smaller
 
 409         # than the base font bail and hope that a 0-size font can be found at
 
 410         # the end of the function
 
 411         if ($candidates[0]->[0] > $basesize) {
 
 412             foreach my $candidate (@candidates) {
 
 413                 if ($candidate->[0] <= $basesize) {
 
 414                     return ($candidate->[1], $candidate->[0] - $font{pixelSize}, $candidate->[0]);
 
 418     } elsif ($delta > 0) {
 
 419         # sort by font size, ascending
 
 420         @candidates = sort {$a->[0] <=> $b->[0]} @candidates;
 
 422         foreach my $candidate (@candidates) {
 
 423             if ($candidate->[0] >= $font{pixelSize} + $delta) {
 
 424                 return ($candidate->[1], $candidate->[0] - $font{pixelSize}, $candidate->[0]);
 
 427     } elsif ($delta < 0) {
 
 428         # sort by font size, descending
 
 429         @candidates = sort {$b->[0] <=> $a->[0]} @candidates;
 
 431         foreach my $candidate (@candidates) {
 
 432             if ($candidate->[0] <= $font{pixelSize} + $delta && $candidate->[0] != 0) {
 
 433                 return ($candidate->[1], $candidate->[0] - $font{pixelSize}, $candidate->[0]);
 
 438     # no fitting font available, check whether a 0-size font can be used to
 
 439     # fit the size of the base font
 
 440     @candidates = sort {$a->[0] <=> $b->[0]} @candidates;
 
 441     if ($basesize != 0 && $candidates[0]->[0] == 0) {
 
 442         return ($candidates[0]->[1], $basedelta, $basesize);
 
 444         # if there is absolutely no smaller/larger font that can be used
 
 445         # return the current one, and beep if this is the base font
 
 446         if ($basesize == 0) {
 
 449         return ("-$fontstring", 0, $font{pixelSize});
 
 455     my ($term, $newfont, $type, $save) = @_;
 
 457     # $term->scr_add_lines("\r\nnew font is $newfont\n");
 
 459     $term->cmd_parse("\033]" . $escapecodes{$type} . ";" . $newfont . "\033\\");
 
 462     # system("xrdb -load " . X_RESOURCES);
 
 465         # merge the new values
 
 466         open(XRDB_MERGE, "| xrdb -merge") || die "can't fork: $!";
 
 467         local $SIG{PIPE} = sub { die "xrdb pipe broken" };
 
 468         print XRDB_MERGE "URxvt." . $type . ": " . $newfont;
 
 469         close(XRDB_MERGE) || die "bad xrdb: $! $?";