summaryrefslogtreecommitdiff
path: root/.local/bin/get-dpi
blob: 3fba92030f8a668c534b003cc07f3a2f07a76363 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env bash
# Copyright 2019  Luke Shumaker

sanitize() {
	[[ $? == 0 ]] || return $?
	printf '%g\n' "$@"
}

calc() {
	[[ $? == 0 ]] || return $?
	sanitize "$(bc <<<"scale=6; $1")"
}

errusage() {
	if (( $# > 0 )); then
		printf '%s: %s\n' "${0##*/}" "$(printf "$@")" >&2
	fi
	printf "Try '%s --help' for more information.\n" "${0##*/}" >&2
	exit 2
}

usage() {
	printf 'Usage: %s [OPTIONS]\n' "${0##*/}"
	printf "Report DPI settings\n"
	echo
	printf 'OPTIONS:\n':
	printf '  -h, --help      Show this message\n'
	printf '  --device-geometry=OUTPUT=<X>x<Y>[x<Z>]\n'
	printf '                  Override the hardware-reported physical\n'
	printf '                  dimensions for the X11 output OUTPUT; X, Y,\n'
	printf '                  and Z must either have a suffix of "in" or\n'
	printf '                  "mm", or be "auto"; providing Z causes the\n'
	printf '                  the dimensions to be scaled to a reference\n'
	printf '                  viewing distance of 28in (as described in\n'
	printf '                  [CSS3-values])\n'
	echo
	printf '[CSS3-values]: https://www.w3.org/TR/css3-values/#reference-pixel\n'
}

set -euE -o pipefail
args=$(getopt -n "${0##*/}" -o 'hn' -l 'help,device-geometry:' -- "$@") || errusage
eval "set -- $args"

declare -A arg_device_geometry
while (( $# > 0 )); do
	case "$1" in
		-h|--help)
			usage
			exit 0
			;;
		--device-geometry)
			if [[ "$2" != *=* ]]; then
				errusage 'Invalid --device-geometry=%q' "$2"
			fi
			device=${2%=*}
			geometry=${2##*=}
			re_dim='([0-9]+(.[0-9]+)?(in|mm)|auto)'
			re_geo="^${re_dim}x${re_dim}(x${re_dim})?\$"
			if ! [[ "$geometry" =~ $re_geo ]]; then
				errusage 'Invalid --device-geometry=%q' "$2"
			fi
			arg_device_geometry["$device"]=$geometry
			shift 2
			;;
		--)
			shift
			break
			;;
	esac
done
if (( $# > 0 )); then
	errusage
fi

# Xft
dpi=$(xrdb -query|sed -n 's/^Xft\.dpi:\s*//p')
[[ -n "$dpi" ]] || dpi=96x96
xft_xdpi=$(sanitize "${dpi%%x*}")
xft_ydpi=$(sanitize "${dpi#*x}")
echo X11-resources Xft ${xft_xdpi}x${xft_ydpi}

# GDK
gdk_scale=$(sanitize "${GDK_SCALE:-1}")
dpi=$(calc "${gdk_scale} * 96")
echo environment GDK-widget ${dpi}x${dpi}

gdk_dpi_scale=$(sanitize "${GDK_DPI_SCALE:-1}")
dpi=$(calc "${gdk_scale} * ${gdk_dpi_scale} * ${xft_xdpi}")
echo environment+X11-resources GDK-text ${dpi}x${dpi}

# RandR
(
	export LC_ALL=C
	xrandr | sed -rn -e 's@(.*) connected( .*)? ([0-9]+)x([0-9]+)\+([0-9]+)\+([0-9]+)( .*)? ([0-9]+)mm x ([0-9]+)mm( .*)?@\1 \3 \4 \8 \9@p' -e 's@^   ([0-9]+)x([0-9]+)i? .*\*.*@ \1 \2@p' | sed '/^\S/{ N; s/\n//; }'
	#                      1             2      3        4         5         6       7      8            9         10                                 1        2
	#                      `-outputName  |      `-fb_xpx `-fb_ypx  `-fb_xoff `-fb_yoff      `- hw_xmm    `- hw_ymm |                                  `-hw_xpx `-hw_ypx
	#                                    `-discard                                  `- discard                     `- discard
) | while read -r output fb_xpx fb_ypx hw_xmm hw_ymm hw_xpx hw_ypx; do
	if [[ -n "${arg_device_geometry["$output"]:-}" ]]; then
		IFS=x read override_x override_y override_z <<<"${arg_device_geometry["$output"]}"
		case "$override_x" in
			*mm) override_xmm="$(sanitize "${override_x%mm}")";;
			*in) override_xmm="$(calc "$(sanitize "${override_x%in}")*25.4")";;
			auto) override_xmm="$hw_xmm";;
		esac
		case "$override_y" in
			*mm) override_ymm="$(sanitize "${override_y%mm}")";;
			*in) override_ymm="$(calc "$(sanitize "${override_y%in}")*25.4")";;
			auto) override_ymm="$hw_ymm";;
		esac
		if [[ "$override_z" == '' ||  "$override_z" == 'auto' ]]; then
			hw_xmm=$override_xmm
			hw_ymm=$override_ymm
		else
			# algorithm from https://www.w3.org/TR/css3-values/#reference-pixel
			ref_zmm=711.2 # 28in
			case "$override_z" in
				*mm) override_zmm="$(sanitize "${override_z%mm}")";;
				*in) override_zmm="$(calc "$(sanitize "${override_z%in}")*25.4")";;
			esac
			hw_xmm=$(calc "(${override_xmm}*${ref_zmm})/${override_zmm}")
			hw_ymm=$(calc "(${override_ymm}*${ref_zmm})/${override_zmm}")
		fi
	fi

	hw_xdpi=$(calc "($hw_xpx*25.4)/$hw_xmm")
	hw_ydpi=$(calc "($hw_ypx*25.4)/$hw_ymm")

	fb_xdpi=$(calc "($fb_xpx*25.4)/$hw_xmm")
	fb_ydpi=$(calc "($fb_ypx*25.4)/$hw_ymm")

	echo X11-RandR-hw $output ${hw_xdpi}x${hw_ydpi}
	echo X11-RandR-fb $output ${fb_xdpi}x${fb_ydpi}
done