All posts

Dynamic tmux popup sizing across different displays

1 min read

tmux's display-popup is hard to size when you switch between displays. Fixed character sizes are either too small on 4K or too large on a laptop. Percentages don't help either - 60% of a 4K monitor is massive.

With some help, came up with a wrapper script that uses a fancy algorithm.

popup = base × (screen / reference) ^ 0.5

You set your reference screen (the one you tune on) and base sizes for each preset. On other screens, sizes scale sub-linearly - a screen twice as large gets a popup ~1.4x bigger, not 2x.

tmux-popup
#!/usr/bin/env bash
set -e

# Reference screen (MacBook) - presets are tuned for this size
REF_W=186
REF_H=43

# Scaling factor (0.0-1.0): lower = more "sticky", higher = more linear
SCALE=0.5

# Size presets: base_w, max_w, base_h, max_h
declare -A PRESETS=(
	[small]="70 130 18 35"
	[medium]="110 200 30 50"
	[large]="150 260 40 65"
)

size="medium"

while [[ $# -gt 0 ]]; do
	case "$1" in
	--size)
		size="$2"
		shift 2
		;;
	--)
		shift
		break
		;;
	*)
		break
		;;
	esac
done

if [[ -z "${PRESETS[$size]}" ]]; then
	echo "Unknown size: $size (use small, medium, large)" >&2
	exit 1
fi

read -r base_w max_w base_h max_h <<<"${PRESETS[$size]}"
read -r w h <<<"$(tmux display -p '#{window_width} #{window_height}')"

read -r pw ph <<<"$(awk \
	-v w="$w" -v h="$h" \
	-v bw="$base_w" -v bh="$base_h" \
	-v mw="$max_w" -v mh="$max_h" \
	-v rw="$REF_W" -v rh="$REF_H" \
	-v s="$SCALE" \
	'BEGIN {
		pw = int(bw * ((w / rw) ^ s) + 0.5)
		if (pw > mw) pw = mw
		if (pw > w - 2) pw = w - 2

		ph = int(bh * ((h / rh) ^ s) + 0.5)
		if (ph > mh) ph = mh
		if (ph > h - 2) ph = h - 2

		print pw, ph
	}')"

exec tmux display-popup -w "$pw" -h "$ph" -E "$@"

Usage in .tmux.conf:

bind C-j run-shell 'tmux-popup --size medium workmux'
bind C-f run-shell 'tmux-popup workmux'

To tune, first get your terminal size with tmux display -p '#{window_width} #{window_height}', set REF_W/REF_H to match, then adjust the base values until they look right. The SCALE factor controls how much sizes grow on larger screens.

Will keep experimenting with this but for now it feels good.


Thanks for reading! You can check out my projects on GitHub or follow me on Twitter.