madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

enable font size extension
authormartin f. krafft <madduck@madduck.net>
Mon, 28 Nov 2016 09:48:17 +0000 (10:48 +0100)
committermartin f. krafft <madduck@madduck.net>
Mon, 28 Nov 2016 09:53:31 +0000 (10:53 +0100)
.Xresources
.urxvt/ext/font-size [new file with mode: 0755]

index 154b540..b5e6cf6 100644 (file)
@@ -13,6 +13,13 @@ Rxvt.font:                     \
                                -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1
 #endif
 
+URxvt.keysym.C-equal:          font-size:increase
+URxvt.keysym.C-minus:          font-size:decrease
+URxvt.keysym.C-plus:           font-size:incglobal
+URxvt.keysym.C-underscore:     font-size:decglobal
+URxvt.keysym.C-0:              font-size:reset
+URxvt.keysym.C-backslash:      font-size:show
+
 Rxvt.background:               white
 Rxvt.foreground:               black
 
@@ -46,7 +53,7 @@ URxvt.cutchars:                "\`\"'&()*,;<=>?@[]^{|}⇝·/:"
 
 Rxvt.loginShell:               true
 
-URxvt.perl-ext-common:         default,matcher,confirm-paste,-readline
+URxvt.perl-ext-common:         default,matcher,confirm-paste,-readline,font-size
 
 URxvt.keysym.C-Return:         matcher:select
 URxvt.keysym.MC-Return:        matcher:last
diff --git a/.urxvt/ext/font-size b/.urxvt/ext/font-size
new file mode 100755 (executable)
index 0000000..3efaa76
--- /dev/null
@@ -0,0 +1,471 @@
+#!/usr/bin/env perl
+#
+# On-the-fly adjusting of the font size in urxvt
+#
+# Copyright (c) 2008 David O'Neill
+#               2012 Noah K. Tilton <noahktilton@gmail.com>
+#               2009-2012 Simon Lundström <simmel@soy.se>
+#               2012-2016 Jan Larres <jan@majutsushi.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# URL: https://github.com/majutsushi/urxvt-font-size
+#
+# Based on:
+# https://github.com/dave0/urxvt-font-size
+# https://github.com/noah/urxvt-font
+# https://github.com/simmel/urxvt-resize-font
+#
+
+#:META:X_RESOURCE:%.step:interger:font size increase/decrease step
+
+=head1 NAME
+
+font-size - interactive font size setter
+
+=head1 USAGE
+
+Put the font-size script into $HOME/.urxvt/ext/ and add it to the list
+of enabled perl-extensions in ~/.Xresources:
+
+  URxvt.perl-ext-common: ...,font-size
+
+Add some keybindings:
+
+  URxvt.keysym.C-Up:     font-size:increase
+  URxvt.keysym.C-Down:   font-size:decrease
+  URxvt.keysym.C-S-Up:   font-size:incglobal
+  URxvt.keysym.C-S-Down: font-size:decglobal
+  URxvt.keysym.C-equal:  font-size:reset
+  URxvt.keysym.C-slash:  font-size:show
+
+Note that for urxvt versions older than 9.21 the resources have to look like this:
+
+  URxvt.keysym.C-Up:     perl:font-size:increase
+  URxvt.keysym.C-Down:   perl:font-size:decrease
+  URxvt.keysym.C-S-Up:   perl:font-size:incglobal
+  URxvt.keysym.C-S-Down: perl:font-size:decglobal
+  URxvt.keysym.C-equal   perl:font-size:reset
+  URxvt.keysym.C-slash   perl:font-size:show
+
+Supported functions:
+
+=over 2
+
+=item * increase/decrease:
+
+      increase or decrease the font size of the current terminal.
+
+=item * incglobal/decglobal:
+
+      same as above and also adjust the X server values so all newly
+      started terminals will use the same fontsize.
+
+=item * incsave/decsave:
+
+      same as incglobal/decglobal and also modify the ~/.Xresources
+      file so the changed font sizes will persist over a restart of
+      the X server or a reboot.
+
+=item * reset:
+
+      reset the font size to the value of the resource when starting
+      the terminal.
+
+=item * show
+
+      show the current value of the 'font' resource in a popup.
+
+=back
+
+You can also change the step size that the script will use to increase
+the font size:
+
+  URxvt.font-size.step: 4
+
+The default step size is 1. This means that with this setting a
+size change sequence would be for example 8->12->16->20 instead of
+8->9->10->11->12 etc. Please note that many X11 fonts are only
+available in specific sizes, though, and odd sizes are often not
+available, resulting in an effective step size of 2 instead of 1
+in that case.
+=cut
+
+use strict;
+use warnings;
+
+my %escapecodes = (
+    "font"           => 710,
+    "boldFont"       => 711,
+    "italicFont"     => 712,
+    "boldItalicFont" => 713
+);
+
+sub on_start
+{
+    my ($self) = @_;
+
+    $self->{step} = $self->x_resource("%.step") || 1;
+
+    foreach my $type (qw(font boldFont italicFont boldItalicFont)) {
+        $self->{$type} = $self->x_resource($type) || "undef";
+    }
+}
+
+# Needed for backwards compatibility with < 9.21
+sub on_user_command
+{
+    my ($self, $cmd) = @_;
+
+    my $step = $self->{step};
+
+    if ($cmd eq "font-size:increase") {
+        fonts_change_size($self,  $step, 0);
+    } elsif ($cmd eq "font-size:decrease") {
+        fonts_change_size($self, -$step, 0);
+    } elsif ($cmd eq "font-size:incglobal") {
+        fonts_change_size($self,  $step, 1);
+    } elsif ($cmd eq "font-size:decglobal") {
+        fonts_change_size($self, -$step, 1);
+    } elsif ($cmd eq "font-size:incsave") {
+        fonts_change_size($self,  $step, 2);
+    } elsif ($cmd eq "font-size:decsave") {
+        fonts_change_size($self, -$step, 2);
+    } elsif ($cmd eq "font-size:reset") {
+        fonts_reset($self);
+    } elsif ($cmd eq "font-size:show") {
+        fonts_show($self);
+    }
+}
+
+sub on_action
+{
+    my ($self, $action) = @_;
+
+    my $step = $self->{step};
+
+    if ($action eq "increase") {
+        fonts_change_size($self,  $step, 0);
+    } elsif ($action eq "decrease") {
+        fonts_change_size($self, -$step, 0);
+    } elsif ($action eq "incglobal") {
+        fonts_change_size($self,  $step, 1);
+    } elsif ($action eq "decglobal") {
+        fonts_change_size($self, -$step, 1);
+    } elsif ($action eq "incsave") {
+        fonts_change_size($self,  $step, 2);
+    } elsif ($action eq "decsave") {
+        fonts_change_size($self, -$step, 2);
+    } elsif ($action eq "reset") {
+        fonts_reset($self);
+    } elsif ($action eq "show") {
+        fonts_show($self);
+    }
+}
+
+sub fonts_change_size
+{
+    my ($term, $delta, $save) = @_;
+
+    my @newfonts = ();
+
+    my $curres = $term->resource('font');
+    if (!$curres) {
+        $term->scr_add_lines("\r\nWarning: No font configured, trying a default.\r\nPlease set a font with the 'URxvt.font' resource.");
+        $curres = "fixed";
+    }
+    my @curfonts = split(/\s*,\s*/, $curres);
+
+    my $basefont = shift(@curfonts);
+    my ($newbasefont, $newbasedelta, $newbasesize) = handle_font($term, $basefont, $delta, 0, 0);
+    push @newfonts, $newbasefont;
+
+    # Only adjust other fonts if base font changed
+    if ($newbasefont ne $basefont) {
+        foreach my $font (@curfonts) {
+            my ($newfont, $newdelta, $newsize) = handle_font($term, $font, $delta, $newbasedelta, $newbasesize);
+            push @newfonts, $newfont;
+        }
+        my $newres = join(",", @newfonts);
+        font_apply_new($term, $newres, "font", $save);
+
+        handle_type($term, "boldFont",       $delta, $newbasedelta, $newbasesize, $save);
+        handle_type($term, "italicFont",     $delta, $newbasedelta, $newbasesize, $save);
+        handle_type($term, "boldItalicFont", $delta, $newbasedelta, $newbasesize, $save);
+    }
+
+    if ($save > 1) {
+        # write the new values back to the file
+        my $xresources = readlink $ENV{"HOME"} . "/.Xresources";
+        system("xrdb -edit " . $xresources);
+    }
+}
+
+sub fonts_reset
+{
+    my ($term) = @_;
+
+    foreach my $type (qw(font boldFont italicFont boldItalicFont)) {
+        my $initial = $term->{$type};
+        if ($initial ne "undef") {
+            font_apply_new($term, $initial, $type, 0);
+        }
+    }
+}
+
+sub fonts_show
+{
+    my ($term) = @_;
+
+    my $out = $term->resource('font');
+    $out =~ s/\s*,\s*/\n/g;
+
+    $term->{'font-size'}{'overlay'} = {
+        overlay => $term->overlay_simple(0, -1, $out),
+        timer => urxvt::timer->new->start(urxvt::NOW + 5)->cb(
+            sub {
+                delete $term->{'font-size'}{'overlay'};
+            }
+        ),
+    };
+}
+
+sub handle_type
+{
+    my ($term, $type, $delta, $basedelta, $basesize, $save) = @_;
+
+    my $curres = $term->resource($type);
+    if (!$curres) {
+        return;
+    }
+    my @curfonts = split(/\s*,\s*/, $curres);
+    my @newfonts = ();
+
+    foreach my $font (@curfonts) {
+        my ($newfont, $newdelta, $newsize) = handle_font($term, $font, $delta, $basedelta, $basesize);
+        push @newfonts, $newfont;
+    }
+
+    my $newres = join(",", @newfonts);
+    font_apply_new($term, $newres, $type, $save);
+}
+
+sub handle_font
+{
+    my ($term, $font, $delta, $basedelta, $basesize) = @_;
+
+    my $newfont;
+    my $newdelta;
+    my $newsize;
+    my $prefix = 0;
+
+    if ($font =~ /^\s*x:/) {
+        $font =~ s/^\s*x://;
+        $prefix = 1;
+    }
+    if ($font =~ /^\s*(\[.*\])?xft:/) {
+        ($newfont, $newdelta, $newsize) = font_change_size_xft($term, $font, $delta, $basedelta, $basesize);
+    } elsif ($font =~ /^\s*-/) {
+        ($newfont, $newdelta, $newsize) = font_change_size_xlfd($term, $font, $delta, $basedelta, $basesize);
+    } else {
+        # check whether the font is a valid alias and if yes resolve it to the
+        # actual font
+        my $lsfinfo = `xlsfonts -l $font 2>/dev/null`;
+
+        if ($lsfinfo eq "") {
+            # not a valid alias, ring the bell if it is the base font and just
+            # return the current font
+            if ($basesize == 0) {
+                $term->scr_bell;
+            }
+            return ($font, $basedelta, $basesize);
+        }
+
+        my $fontinfo = (split(/\n/, $lsfinfo))[-1];
+        my ($fontfull) = ($fontinfo =~ /\s+([-a-z0-9]+$)/);
+        ($newfont, $newdelta, $newsize) = font_change_size_xlfd($term, $fontfull, $delta, $basedelta, $basesize);
+    }
+
+    # $term->scr_add_lines("\r\nNew font is $newfont\n");
+    if ($prefix) {
+        $newfont = "x:$newfont";
+    }
+    return ($newfont, $newdelta, $newsize);
+}
+
+sub font_change_size_xft
+{
+    my ($term, $fontstring, $delta, $basedelta, $basesize) = @_;
+
+    my @pieces   = split(/:/, $fontstring);
+    my @resized  = ();
+    my $size     = 0;
+    my $new_size = 0;
+
+    foreach my $piece (@pieces) {
+        if ($piece =~ /^(?:(?:pixel)?size=|[^=-]+-)(\d+(\.\d*)?)$/) {
+            $size = $1;
+
+            if ($basedelta != 0) {
+                $new_size = $size + $basedelta;
+            } else {
+                $new_size = $size + $delta;
+            }
+
+            $piece =~ s/(=|-)$size/$1$new_size/;
+        }
+        push @resized, $piece;
+    }
+
+    my $resized_str = join(":", @resized);
+
+    # don't make fonts too small
+    if ($new_size >= 6) {
+        return ($resized_str, $new_size - $size, $new_size);
+    } else {
+        if ($basesize == 0) {
+            $term->scr_bell;
+        }
+        return ($fontstring, 0, $size);
+    }
+}
+
+sub font_change_size_xlfd
+{
+    my ($term, $fontstring, $delta, $basedelta, $basesize) = @_;
+
+    #-xos4-terminus-medium-r-normal-*-12-*-*-*-*-*-*-1
+
+    my @fields = qw(foundry family weight slant setwidth style pixelSize pointSize Xresolution Yresolution spacing averageWidth registry encoding);
+
+    my %font;
+    $fontstring =~ s/^-//;  # Strip leading - before split
+    @font{@fields} = split(/-/, $fontstring);
+
+    if ($font{pixelSize} eq '*') {
+        $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.");
+        $font{pixelSize} = '12'
+    }
+    if ($font{registry} eq '*') {
+        $font{registry} ='iso8859';
+    }
+
+    # Blank out the size for the pattern
+    my %pattern = %font;
+    $pattern{foundry} = '*';
+    $pattern{setwidth} = '*';
+    $pattern{pixelSize} = '*';
+    $pattern{pointSize} = '*';
+    # if ($basesize != 0) {
+    #     $pattern{Xresolution} = '*';
+    #     $pattern{Yresolution} = '*';
+    # }
+    $pattern{averageWidth} = '*';
+    # make sure there are no empty fields
+    foreach my $field (@fields) {
+        $pattern{$field} = '*' unless defined($pattern{$field});
+    }
+    my $new_fontstring = '-' . join('-', @pattern{@fields});
+
+    my @candidates;
+    # $term->scr_add_lines("\r\nPattern is $new_fontstring\n");
+    open(FOO, "xlsfonts -fn '$new_fontstring' | sort -u |") or die $!;
+    while (<FOO>) {
+        chomp;
+        s/^-//;  # Strip leading '-' before split
+        my @fontdata = split(/-/, $_);
+
+        push @candidates, [$fontdata[6], "-$_"];
+        # $term->scr_add_lines("\r\npossibly $fontdata[6] $_\n");
+    }
+    close(FOO);
+
+    if (!@candidates) {
+        die "No possible fonts!";
+    }
+
+    if ($basesize != 0) {
+        # sort by font size, descending
+        @candidates = sort {$b->[0] <=> $a->[0]} @candidates;
+
+        # font is not the base font, so find the largest font that is at most
+        # as large as the base font. If the largest possible font is smaller
+        # than the base font bail and hope that a 0-size font can be found at
+        # the end of the function
+        if ($candidates[0]->[0] > $basesize) {
+            foreach my $candidate (@candidates) {
+                if ($candidate->[0] <= $basesize) {
+                    return ($candidate->[1], $candidate->[0] - $font{pixelSize}, $candidate->[0]);
+                }
+            }
+        }
+    } elsif ($delta > 0) {
+        # sort by font size, ascending
+        @candidates = sort {$a->[0] <=> $b->[0]} @candidates;
+
+        foreach my $candidate (@candidates) {
+            if ($candidate->[0] >= $font{pixelSize} + $delta) {
+                return ($candidate->[1], $candidate->[0] - $font{pixelSize}, $candidate->[0]);
+            }
+        }
+    } elsif ($delta < 0) {
+        # sort by font size, descending
+        @candidates = sort {$b->[0] <=> $a->[0]} @candidates;
+
+        foreach my $candidate (@candidates) {
+            if ($candidate->[0] <= $font{pixelSize} + $delta && $candidate->[0] != 0) {
+                return ($candidate->[1], $candidate->[0] - $font{pixelSize}, $candidate->[0]);
+            }
+        }
+    }
+
+    # no fitting font available, check whether a 0-size font can be used to
+    # fit the size of the base font
+    @candidates = sort {$a->[0] <=> $b->[0]} @candidates;
+    if ($basesize != 0 && $candidates[0]->[0] == 0) {
+        return ($candidates[0]->[1], $basedelta, $basesize);
+    } else {
+        # if there is absolutely no smaller/larger font that can be used
+        # return the current one, and beep if this is the base font
+        if ($basesize == 0) {
+            $term->scr_bell;
+        }
+        return ("-$fontstring", 0, $font{pixelSize});
+    }
+}
+
+sub font_apply_new
+{
+    my ($term, $newfont, $type, $save) = @_;
+
+    # $term->scr_add_lines("\r\nnew font is $newfont\n");
+
+    $term->cmd_parse("\033]" . $escapecodes{$type} . ";" . $newfont . "\033\\");
+
+    # load the xrdb db
+    # system("xrdb -load " . X_RESOURCES);
+
+    if ($save > 0) {
+        # merge the new values
+        open(XRDB_MERGE, "| xrdb -merge") || die "can't fork: $!";
+        local $SIG{PIPE} = sub { die "xrdb pipe broken" };
+        print XRDB_MERGE "URxvt." . $type . ": " . $newfont;
+        close(XRDB_MERGE) || die "bad xrdb: $! $?";
+    }
+}