Created
April 14, 2019 14:37
-
-
Save gservat/09c34d46de353c36c2316e2df79391e7 to your computer and use it in GitHub Desktop.
Display profile switcher using nvidia-settings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
exec > >(tee -a "/tmp/display-switcher.log") 2>&1 | |
# NOTE: This requires GNU getopt. On Mac OS X and FreeBSD, you have to install this | |
# separately; see below. | |
usage() { | |
cat << HELP >&2 | |
Usage: $0 [option ...] {profile} | |
OPTIONS: | |
-h, --help This help message | |
-v, --verbose Enable verbose mode | |
-w N, --wait N Seconds to wait before changing profile | |
-m TEXT, --message TEXT Text to display as a notification | |
-t SECS, --message-timeout SECS How long (seconds) to display the notification for | |
-u NAME, --user NAME User to use for X11 notifications | |
HELP | |
} | |
msg() { | |
if $VERBOSE; then | |
echo "[$(date)] $1" | |
fi | |
} | |
if ! TEMP=$(getopt -o hvt:u:m:w: --long verbose,help,user:,message:,message-timeout:,wait: -n 'display-switcher' -- "$@"); then | |
usage | |
exit 1 | |
fi | |
# Note the quotes around `$TEMP': they are essential! | |
eval set -- "$TEMP" | |
VERBOSE=false | |
WAIT=0 | |
MESSAGE="Switching display profile to %s soon..." | |
NOTIFY_USER= | |
NOTIFY_UID= | |
NOTIFY_ARGS= | |
ICON="/usr/share/icons/Pop/48x48/devices/gnome-dev-computer.svg" | |
while true; do | |
case "$1" in | |
-v | --verbose ) VERBOSE=true; shift ;; | |
-w | --wait ) WAIT="$2"; shift 2 ;; | |
-m | --message ) MESSAGE="$2"; shift 2 ;; | |
-t | --message-timeout ) NOTIFY_ARGS="${NOTIFY_ARGS} -t ${2}000"; shift 2 ;; | |
-u | --user ) | |
NOTIFY_USER="$2" | |
shift 2 | |
if ! NOTIFY_UID="$(id -u ${NOTIFY_USER} 2>/dev/null)"; then | |
echo "ERROR: Unable to get UID for ${NOTIFY_USER}." | |
exit 1 | |
fi | |
;; | |
-h | --help ) usage; exit 0 ;; | |
-- ) shift; break ;; | |
* ) break ;; | |
esac | |
done | |
if [[ -z ${NOTIFY_USER} ]]; then | |
echo "ERROR: You need to specify the username for the authorized X user to use for notifications." | |
usage | |
exit 1 | |
fi | |
NOTIFY_CMD="sudo -u ${NOTIFY_USER} DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${NOTIFY_UID}/bus dunstify -I ${ICON}" | |
# nvidia-settings -q dpys | |
BENQ_4K_EDID="DPY-EDID-ead0ac88-15bf-e410-e2a5-8538dcd8450d" | |
LG_5K_EDID="DPY-EDID-79885171-ff0f-23e3-0566-988d08123861" | |
NOTEBOOK_EDID="DPY-EDID-703b6c15-6e68-abf3-2744-8a1b0abf4d39" | |
# nvidia-settings -q CurrentMetaMode | tr '\n' ' ' | |
PROFILE=${1} | |
case "${PROFILE}" in | |
laptop-only) | |
MODE="${NOTEBOOK_EDID}: 3840x2160 @3840x2160 +0+0 {ViewPortIn=3840x2160, ViewPortOut=3840x2160+0+0}" | |
;; | |
5k-4k-vertical-laptop) | |
MODE="${BENQ_4K_EDID}: 3840x2160 @2160x3840 +4096+0 {ViewPortIn=2160x3840, ViewPortOut=3840x2160+0+0, Rotation=90}, ${LG_5K_EDID}: 4096x2304 @4096x2304 +0+0 {ViewPortIn=4096x2304, ViewPortOut=4096x2304+0+0}, ${NOTEBOOK_EDID}: 3840x2160 @3840x2160 +6256+0 {ViewPortIn=3840x2160, ViewPortOut=3840x2160+0+0}" | |
;; | |
5k-4k-vertical-no-laptop) | |
MODE="${BENQ_4K_EDID}: 3840x2160 @2160x3840 +4096+0 {ViewPortIn=2160x3840, ViewPortOut=3840x2160+0+0, Rotation=90}, ${LG_5K_EDID}: 4096x2304 @4096x2304 +0+0 {ViewPortIn=4096x2304, ViewPortOut=4096x2304+0+0}" | |
;; | |
*) | |
usage | |
echo -e "\\nERROR: You need to specify a valid profile to switch to." | |
exit 1 | |
;; | |
esac | |
msg Starting... | |
msg "Notify command: ${NOTIFY_CMD}" | |
FINAL_MSG=$(printf "${MESSAGE}" ${PROFILE}) | |
msg "Sending notification: ${NOTIFY_CMD} ${NOTIFY_ARGS} \"${FINAL_MSG}\"" | |
${NOTIFY_CMD} ${NOTIFY_ARGS} "${FINAL_MSG}" | |
if [[ ${WAIT} -gt 0 ]]; then | |
msg "Sleeping for ${WAIT} seconds" | |
sleep "${WAIT}" | |
fi | |
# Finally, run nvidia-settings. | |
msg "Running: nvidia-settings --assign \"CurrentMetaMode=${MODE}\"" | |
nvidia-settings --assign "CurrentMetaMode=${MODE}" | |
${NOTIFY_CMD} -t 3000 "Display profile has been switched" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Background
I've got the following hardware:
The issue that I had was that tools like
xrandr
(and companions likeautorandr
/arandr
) simply did not work reliably. Sometimes they would configure my screens the way I wanted, but most of the time they spat out errors (e.g.BadValue
) and left monitors off, or they did weird stuff like enable panning so the virtual size was much bigger than the monitor size. This meant that if I docked off, there was a pretty good chance that when I docked on again, I'd have to spend a bunch of frustrating minutes playing withxrandr
to get my screens set-up correctly again. You can imagine how this can get old and frustrating pretty quickly!Solution
I found that
nvidia-settings
was actually reliable in setting up my screens the way I wanted, and you can actually drivenvidia-settings
via the CLI. Interestingly enough, it seemed that often enough the displays did not always come up under the same names (e.g.DPY-0
was not alwaysDPY-0
... it sometimes came up asDPY-1
for instance), so I switched to using the EDID values, which are guaranteed to be the same.To use this script, you'll have to remove/add EDID values for your monitors and configure the various display profiles that you want to be able to switch between. In my case, the profiles I've set-up are:
laptop-only
for when I'm undocked (i.e. no monitors - notebook only)5k-4k-vertical-laptop
for when I want my 5K (landscape) + 4K (portrait) + my notebook display (rarely used)5k-4k-vertical-no-laptop
for when I want my 5K (landscape) + 4K (portrait) but the notebook monitor switched off (used when docked)To come up with the values for these profiles, you'll want to use
nvidia-settings
to set-up your screens and once it looks the way you want it to look, simply exit and runnvidia-settings -q CurrentMetaMode
. You'll need the text after the::
, which will go into theMODE=X
part of the case statement. In thisMODE
line, you'll need to replace names likeDPY-X
with theirEDID
equivalent, which you can find by usingnvidia-settings -q dpys
(underHas the following names
).The end result is that after docking/undocking a bunch of times, the displays came up reliably how I want them to be set-up.
To automate the switching of display profiles when I dock on/off, I've created
/etc/udev/rules.d/70-thunderbolt-dock.rules
with the following 2 rules:Hope this saves you some frustration!