summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2019-05-06 10:20:21 -0400
committerLuke Shumaker <lukeshu@datawire.io>2019-05-06 10:20:21 -0400
commitf28657d882d340158ef0af3974ff0d04d712a344 (patch)
tree32d0ce7303047112c3ddc51f499c7e153518e166
parentaf56e80a3c60e17859ae3b3daa5fc4b44754b667 (diff)
fix-dpi: Better GTK+ support
-rw-r--r--.config/bash/rc.d/95_gtk3.sh9
-rwxr-xr-x.local/bin/fix-dpi187
-rwxr-xr-x.local/bin/get-dpi42
3 files changed, 183 insertions, 55 deletions
diff --git a/.config/bash/rc.d/95_gtk3.sh b/.config/bash/rc.d/95_gtk3.sh
new file mode 100644
index 0000000..99ed337
--- /dev/null
+++ b/.config/bash/rc.d/95_gtk3.sh
@@ -0,0 +1,9 @@
+#!/hint/bash
+
+_gtk_set_shell_DPI() {
+ if [[ -n $DISPLAY ]]; then
+ eval "$(systemctl --user show-environment | grep -e ^GDK_SCALE= -e ^GDK_DPI_SCALE=)"
+ export GDK_SCALE GDK_DPI_SCALE
+ fi
+}
+PROMPT_COMMAND+='_gtk_set_shell_DPI;'
diff --git a/.local/bin/fix-dpi b/.local/bin/fix-dpi
index ee0412d..b700ea9 100755
--- a/.local/bin/fix-dpi
+++ b/.local/bin/fix-dpi
@@ -1,69 +1,146 @@
#!/usr/bin/env bash
# Copyright 2019 Luke Shumaker
-#
-# Adjusts the xrandr 1.2, xrandr 1.3, and xrdb DPI settings according
-# to each output's current mode (pixel resolution) and self-reported
-# physical dimensions (mm).
-
-# env-var: MAX_DPI: integer
-# env-var: DRY_RUN: empty=false / non-empty=true
-
-( # Phase 1: Probe outputs
- 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
-) | ( # Phase 2: Translate that to a set of actions to perform
- max_xdpi=${MAX_DPI:-96}
- max_ydpi=${MAX_DPI:-96}
-
- dpi=$(xrdb -query|sed -n 's/^Xft\.dpi:\s*//p')
- xdpi=${dpi%%x*}
- ydpi=${dpi#*x}
- if (( xdpi > max_xdpi )); then
- max_xdpi=$xdpi
- fi
- if (( ydpi > max_ydpi )); then
- max_ydpi=$ydpi
+
+sanitize() {
+ [[ $? == 0 ]] || return $?
+ printf '%g\n' "$@"
+}
+
+calc() {
+ [[ $? == 0 ]] || return $?
+ sanitize "$(bc <<<"scale=6; $1")"
+}
+
+round() {
+ [[ $? == 0 ]] || return $?
+ printf '%.f\n' "$@"
+}
+
+roundup_by() {
+ [[ $? == 0 ]] || return $?
+ awk -v by="$2" 'function ceil(x) { return (x == int(x)) ? x : int(x)+1 } { print ceil($1/96)*96 }' <<<"$1"
+}
+
+max() {
+ [[ $? == 0 ]] || return $?
+ awk -v a="$1" -v b="$2" '{ print (a > b) ? a : b }' <<<''
+}
+
+errusage() {
+ if (( $# > 0 )); then
+ printf '%s: %s\n' "${0##*/}" "$(printf "$@")" >&2
fi
+ printf "Try '%s --help' for more information.\n" "${0##*/}" >&2
+ exit 2
+}
- declare -A outputs
- while read -r output fb_xpx fb_ypx hw_xmm hw_ymm hw_xpx hw_ypx; do
- hw_xdpi=$(bc <<<"($hw_xpx*25.4)/$hw_xmm")
- hw_ydpi=$(bc <<<"($hw_ypx*25.4)/$hw_ymm")
+usage() {
+ printf 'Usage: %s [OPTIONS]\n' "${0##*/}"
+ printf "Adjust DPI settings to reflect each output's current mode\n"
+ printf "(pixel resolution) and self-reported physical dimensions (mm).\n"
+ echo
+ printf 'OPTIONS:\n'
+ printf ' -h, --help Show this message\n'
+ printf ' -n, --dry-run Print what would be done, without doing it\n'
+ printf ' --render-dpi=<auto|auto-hwonly|DPI|XDPIxYDPI>\n'
+ printf ' Specify what DPI applications should render\n'
+ printf ' at (default: auto)\n'
+}
- fb_xdpi=$(bc <<<"($fb_xpx*25.4)/$hw_xmm")
- fb_ydpi=$(bc <<<"($fb_ypx*25.4)/$hw_ymm")
+set -euE -o pipefail
+args=$(getopt -n "${0##*/}" -o 'hn' -l 'help,dry-run,render-dpi:' -- "$@") || errusage
+eval "set -- $args"
- if (( hw_xdpi > max_xdpi )); then
- max_xdpi=$hw_xdpi
- fi
- if (( hw_ydpi > max_ydpi )); then
- max_ydpi=$hw_ydpi
- fi
+arg_dry_run=false
+arg_render_dpi=auto
+while (( $# > 0 )); do
+ case "$1" in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -n|--dry-run)
+ arg_dry_run=true
+ shift
+ ;;
+ --render-dpi)
+ arg_render_dpi=$2
+ case "$2" in
+ auto|auto-hwonly)
+ arg_render_dpi=$2
+ ;;
+ *)
+ if ! arg_render_dpi="$(sanitize "${2%%x*}" 2>/dev/null)x$(sanitize "${2#*x}" 2>/dev/null)"; then
+ errusage 'Invalid --render-dpi=%q' "$2"
+ fi
+ ;;
+ esac
+ shift 2
+ ;;
+ --)
+ shift
+ break
+ ;;
+ esac
+done
+if (( $# > 0 )); then
+ errusage
+fi
- if (( fb_xdpi > max_xdpi )); then
- max_xdpi=$fb_xdpi
- fi
- if (( fb_ydpi > max_ydpi )); then
- max_ydpi=$fb_ydpi
+dpis="$(get-dpi)"
+
+if [[ $arg_render_dpi == auto ]] || [[ $arg_render_dpi == auto-hwonly ]]; then
+ arg_render_xdpi=96
+ arg_render_ydpi=96
+ while read -r source item dpi; do
+ if [[ $arg_render_dpi == auto-hwonly ]] && [[ $source != X11-RandR-hw ]]; then
+ continue
fi
+ arg_render_xdpi=$(max "$(round "${dpi%%x*}")" "$arg_render_xdpi")
+ arg_render_ydpi=$(max "$(round "${dpi#*x}")" "$arg_render_ydpi")
+ done <<<"$dpis"
- outputs["$output"]="$hw_xdpi $hw_ydpi"
- done
+ # GDK 3 only supports integer up-scale factors, because
+ # they're morons. Round arg_render_dpi up to a multiple of '96'.
+ arg_render_xdpi=$(roundup_by "$arg_render_xdpi" 96)
+ arg_render_ydpi=$(roundup_by "$arg_render_ydpi" 96)
+else
+ arg_render_xdpi=${arg_render_dpi%%x*}
+ arg_render_ydpi=${arg_render_dpi#*x}
+fi
+
+(
echo 'xrandr \'
- printf ' --dpi %q \\\n' "${max_xdpi}x${max_ydpi}"
- for output in "${!outputs[@]}"; do
- read -r xdpi ydpi <<<"${outputs[$output]}"
- printf ' --output %q --scale %q \\\n' "$output" "$(bc <<<"scale=5; $max_xdpi/$xdpi")x$(bc <<<"scale=5; $max_ydpi/$ydpi")"
- done
+ printf ' --dpi %q \\\n' "${arg_render_xdpi}x${arg_render_ydpi}"
+ while read -r source item dpi; do
+ if [[ $source != X11-RandR-hw ]]; then
+ continue
+ fi
+ hw_xdpi="$(sanitize "${dpi%%x*}")"
+ hw_ydpi="$(sanitize "${dpi#*x}")"
+
+ fb_xdpi="$(calc "$arg_render_xdpi/$hw_xdpi")"
+ fb_ydpi="$(calc "$arg_render_ydpi/$hw_ydpi")"
+ printf ' --output %q --scale %q \\\n' "$item" "${fb_xdpi}x${fb_ydpi}"
+ done <<<"$dpis"
+
echo
- printf "xrdb -merge <<<'Xft.dpi: %s'\n" "${max_xdpi}x${max_ydpi}"
-) | ( # Phase 3: Apply those actions
- if [[ -z "$DRY_RUN" ]]; then
- bash -v
- else
+
+ printf "xrdb -merge <<<'Xft.dpi: %s'\n" "${arg_render_xdpi}x${arg_render_ydpi}"
+
+ echo
+
+ GDK_SCALE="$(calc "(${arg_render_xdpi}+${arg_render_ydpi})/2 /96")"
+ printf 'export GDK_SCALE=%q\n' "$GDK_SCALE"
+ # You're not "supposed" to set XRDB Xft.dpi if GDK_SCALE is
+ # set. Undo Xft.dpi for GDK applications.
+ GDK_DPI_SCALE="$(calc "1/$GDK_SCALE")"
+ printf 'export GDK_DPI_SCALE=%q\n' "$GDK_DPI_SCALE"
+ echo systemctl --user import-environment GDK_SCALE GDK_DPI_SCALE
+) | (
+ if $arg_dry_run; then
cat
+ else
+ bash -v
fi
)
diff --git a/.local/bin/get-dpi b/.local/bin/get-dpi
new file mode 100755
index 0000000..b9979bd
--- /dev/null
+++ b/.local/bin/get-dpi
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# Copyright 2019 Luke Shumaker
+
+sanitize() {
+ printf '%g\n' "$@"
+}
+
+calc() {
+ sanitize "$(bc <<<"scale=6; $1")"
+}
+
+# GDK
+dpi=$(calc "$(sanitize "${GDK_SCALE:-1}") * 96")
+echo environment GDK-widget ${dpi}x${dpi}
+
+dpi=$(calc "$(sanitize "${GDK_DPI_SCALE:-1}") * 96")
+echo environment GDK-text ${dpi}x${dpi}
+
+# Xft
+dpi=$(xrdb -query|sed -n 's/^Xft\.dpi:\s*//p')
+[[ -n "$dpi" ]] || dpi=96x96
+xdpi=$(sanitize "${dpi%%x*}")
+ydpi=$(sanitize "${dpi#*x}")
+echo X11-resources Xft ${xdpi}x${ydpi}
+
+# 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
+ 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