textsize.el (6224B)
1 ;;; textsize.el --- Configure frame text size automatically -*- lexical-binding: t; -*- 2 ;; 3 ;; Copyright (C) James Ferguson 4 ;; 5 ;; Author: James Ferguson <james@faff.org> 6 ;; Version: 3.0 7 ;; Package-Requires: ((emacs "26.1")) 8 ;; Keywords: convenience 9 ;; URL: https://github.com/WJCFerguson/textsize 10 ;; 11 ;; This file is not part of GNU Emacs. 12 ;; 13 ;;; License: 14 ;; 15 ;; SPDX-License-Identifier: GPL-3.0-or-later 16 ;; 17 ;;; Commentary: 18 ;; 19 ;; This package automatically calculates and adjusts the default text size for 20 ;; the size and pixel pitch of the display. 21 ;; 22 ;; Hooks to perform the adjustment automatically are set up by enabling 23 ;; `textsize-mode' on initialization. e.g.: 24 ;; 25 ;; (use-package textsize 26 ;; :init (textsize-mode)) 27 ;; 28 ;; Alternatively, the adjustment may be manually triggered by calling 29 ;; `textsize-fix-frame'. 30 ;; 31 ;; You will first want to adjust `textsize-default-points' if the default size 32 ;; does not match your preferences. 33 ;; 34 ;; The calculation is very simplistic but should be adaptable to many scenarios 35 ;; and may be modified using the `-thresholds' customizations below. 36 ;; 37 ;; You may wish to bind keys for transient manual adjustment of the current 38 ;; frame with `textsize-increment', `textsize-decrement', and `textsize-reset' 39 ;; 40 ;;; Code: 41 42 43 ;; ============================================================================= 44 (defgroup textsize nil 45 "Automatically adjusting frame text sizes to suit the current display." 46 :group 'convenience) 47 48 (defcustom textsize-default-points 15 49 "The baseline font point size, to then be adjusted with -thresholds values. 50 51 Some fonts at least appear to render better at point sizes that 52 are multiples of 3." 53 :type 'integer) 54 55 (defcustom textsize-monitor-size-thresholds '((0 . -3) (350 . 0) (500 . 3)) 56 "Point size offsets from the maximum monitor dimension in mm. 57 58 List of pairs of (monitor-size-in-mm . font-point-offset). 59 60 The 2nd value (cdr) of the final cell encountered where the 1st 61 value (car) is <= the monitor size from 62 `textsize--monitor-size-mm', will be used as a font point offset. 63 Thresholds should therefore be sorted in rising order. 64 65 The default of ((0 . -3) (350 . 0) (500 . 3)) will shrink the 66 text for anything smaller than 350mm, and enlarge it for >500mm" 67 :type '(list (cons integer integer))) 68 69 (defcustom textsize-pixel-pitch-thresholds '((0 . 3) (0.12 . 0) (0.18 . -3) (0.25 . -6)) 70 "List of (px-pitch-threshold . font-point-offset). 71 72 As with `textsize-monitor-size-thresholds', an offset will be 73 selected from the monitor's pixel pitch in mm, from `textsize--pixel-pitch'." 74 :type '(list (cons integer integer))) 75 76 ;; ============================================================================= 77 (defun textsize--monitor-size-mm (frame) 78 "Return the max dimension of FRAME's monitor in mm." 79 (apply #'max (frame-monitor-attribute 'mm-size frame))) 80 81 82 (defun textsize--monitor-size-px (frame) 83 "Return the max dimension of FRAME's monitor in pixels." 84 (apply #'max (cddr (frame-monitor-attribute 'geometry frame)))) 85 86 87 (defun textsize--pixel-pitch (frame) 88 "Calculate the pixel pitch for FRAME in mm." 89 ;; On a rotated monitor, px geom is rotated but size is not, so use 90 ;; max dimension of each. 91 (/ (float (textsize--monitor-size-mm frame)) 92 (textsize--monitor-size-px frame))) 93 94 95 (defun textsize--threshold-offset (threshold-list val) 96 "Find the offset for VAL in THRESHOLD-LIST." 97 (let ((result 0)) 98 (dolist (threshold threshold-list) 99 (when (>= val (car threshold)) 100 (setq result (cdr threshold)))) 101 result)) 102 103 (defun textsize--point-size (frame) 104 "Return the point size to use for this FRAME." 105 (+ textsize-default-points 106 ;; manual adjustment: 107 (or (frame-parameter frame 'textsize-manual-adjustment) 0) 108 ;; pixel pitch adjustment: 109 (textsize--threshold-offset textsize-pixel-pitch-thresholds 110 (textsize--pixel-pitch frame)) 111 ;; monitor size in mm adjustment: 112 (textsize--threshold-offset textsize-monitor-size-thresholds 113 (textsize--monitor-size-mm frame)))) 114 115 (defun textsize--window-size-change (window-or-frame) 116 "Defun for `window-size-change-functions' to fix WINDOW-OR-FRAME text size." 117 (when (and (framep window-or-frame) (frame-size-changed-p window-or-frame)) 118 (textsize-fix-frame window-or-frame))) 119 120 ;;;###autoload 121 (defun textsize-modify-manual-adjust (frame offset) 122 "Adjust FRAME's font-point adjustment by OFFSET persistently. 123 124 Add a custom fixed offset to the textsize point size calculation. 125 126 If OFFSET is nil, reset adjustment to zero." 127 (set-frame-parameter 128 frame 129 'textsize-manual-adjustment 130 (if offset 131 (+ offset (or (frame-parameter frame 'textsize-manual-adjustment) 0)) 132 0)) 133 (message "Setting default font to %s points" (textsize--point-size frame)) 134 (textsize-fix-frame frame)) 135 136 ;;;###autoload 137 (defun textsize-increment () 138 "Increment the current frame's automatic text size." 139 (interactive) 140 (textsize-modify-manual-adjust (selected-frame) 1)) 141 142 ;;;###autoload 143 (defun textsize-decrement () 144 "Decrement the current frame's automatic text size." 145 (interactive) 146 (textsize-modify-manual-adjust (selected-frame) -1)) 147 148 ;;;###autoload 149 (defun textsize-reset () 150 "Reset the adjustment on the current frame's automatic text size." 151 (interactive) 152 (textsize-modify-manual-adjust (selected-frame) nil)) 153 154 ;;;###autoload 155 (defun textsize-fix-frame (&optional frame) 156 "Set the default text size appropriately for FRAME display." 157 (interactive) 158 (when (display-graphic-p) 159 (let* ((frame (or frame (selected-frame)))) 160 (set-frame-parameter frame 161 'font 162 (format "%s-%d" 163 (face-attribute 'default :family) 164 (textsize--point-size frame)))))) 165 166 ;;;###autoload 167 (define-minor-mode 168 textsize-mode 169 "Adjusts the default text size for the size and pixel pitch of the display." 170 :global t 171 :group 'textsize 172 (if textsize-mode 173 (add-to-list 'window-size-change-functions #'textsize--window-size-change) 174 (delete #'textsize--window-size-change window-size-change-functions))) 175 176 (provide 'textsize) 177 ;;; textsize.el ends here