HOWTO Switch Displays by Just One Keypress

MagicMint
  8 years ago
  4

Some motivation

Personally, one of the reasons why I like Linux Mint is that almost everything works out of the box. However, there is one area where things can cause headache: graphics cards and their configuration, most notably when you have to make a presentation, and you must adapt your notebook to an unknown projector, TV set or monitor.

Even if you don’t need to go through the usual Nvidia & al. hassles (because you have an Intel-only controller wink), you surely wished once or twice to be able to switch both the monitors and the speakers, let alone preventing it from going asleep while you’re watching your video — all that if not automagically, at least by pressing a single button angle, for instance the one dedicated to monitor switching (in my case the Fn+F8 key).

To cut a long story short, let’s see if we can make your wish come true…

Installation

First of all, dig up the Software Manager, and install the package named disper. Its documentation says it’s aimed at Nvidia cards primarily, but it does work with other graphics cards too. You can bind the tool with a command

disper --cycle

straightway to that Fn+Fx display switch key if it’s recognized by your notebook, or to Super(=Windows)+Fx if not (you know where: Menu› Administration› System Settings› (Hardware›) Keyboard› Keyboard Shortcuts› Custom Shortcuts).

 

Your newly acquired magic wand won’t do much yet, though. It needs some preliminary configuration, in order — among others — to set up its working directories in a terminal (there is a bug in the current version 0.3.1-1 of the tool, so you better proceed like this indecision):

…$ mkdir --parents ~/.config/disper/hooks
…$ mkdir ~/.disper
…$ cd ~/.disper
…$ ln --symbolic ~/.config/disper/hooks

Configuration

You must still tell disper what you want from it. So start the text editor from a terminal with:

…$ gedit ~/.config/disper/config

Fill the file with the following contents, and save it:

# ~/.config/disper/config (MagicMint) O00310
# disper command line options
# (ɔ) GPL-2, see /usr/share/common-licenses/GPL-2

# Detect displays
--displays=auto

# Define display layout
# Valid options are:
# right, left, top, or bottom
--direction=bottom

# Define the cycling stages
# Valid options are:
# -s (primary), -S (secondary), -c (clone), or -e (extend)
--cycle-stages=-S:-e:-s

# Enable notifications & other plugins
--plugins=all

# End of configuration

Some explanations

At each push of the display button, disper is supposed to cycle between the secondary display, a dual mode in which the display extends onto both monitors, and the primary display (which it starts from). Instead of extending the primary display in the second stage, you could just clone it — but I don’t see the point of that in presentation mode.

The secondary display is arranged under the primary one, in order to avoid any interference with …› Preferences› Window Tiling and Edge Flip› …› Enable Edge Flip. By the way, you can test the hardware (with the external display attached) with the following command:

…$ disper --list

Switching Speakers

If you’re playing a video on an external TV set, e.g., connected through an HDMI cable, you should also switch the audio output to that external device — if possible automatically. Fortunately, it’s just the matter of another small script which you must make up with the following commands:

…$ touch ~/.config/disper/hooks/audio-switch.sh
…$ chmod +x ~/.config/disper/hooks/audio-switch.sh
…$ gedit ~/.config/disper/hooks/audio-switch.sh

Fill in again the following contents, and save the file:

#!/bin/bash
# ~/.config/disper/hooks/audio-switch.sh (MagicMint) O0310
# Switch audio output between PC & TV set
# (ɔ) GPL-2, see /usr/share/common-licenses/GPL-2

DISPRIMARY=`grep -m1 name ~/.config/monitors.xml | awk -F '"' '{print $2}'`

[[ "$DISPER_STAGE" == switch ]] || exit 0

case "$DISPER_DISPLAYS" in
 # When only the built-in display is connected
 "$DISPRIMARY" ) 
  # Switch to internal speakers
  pactl set-card-profile 0 output:analog-stereo
 ;;

 # Otherwise there is some external device connected
 *)
  # Switch to external speakers
  pactl set-card-profile 0 output:hdmi-stereo
 ;;
esac

#End of script

Sound card parameters

Notebooks will have only a single sound card built in, hence this card will have an index of 0. The two profiles for output will also be named like in the script above, but for any eventuality you should check this in the output of the following “magic” command:

…$ LANG=C pacmd info | sed '1,/card(s) available/d' | sed '/active profile:/,$d'

Detecting HDMI at plugin

I’ve found that that the HDMI sound output is only detected automatically, when the sound system is forced to load a specific module after the HDMI plug has been plugged in. For this purpose, make a backup of its configuration file first:

…$ sudo cp --interactive /etc/pulse/default.pa /etc/pulse/default.pa.bak

The module we add doesn’t do what its name suggests, i.e. to switch to HDMI sound automatically, but it lets the new sound output get detected at least, so that disper can switch to it by itself:

…$ sudo echo load-module module-switch-on-connect >> /etc/pulse/default.pa

You must log out from your graphic session and re-login in order for the above setting to become effective. If you have problems with switching the sound, it’s advisable to install pavucontrol, the Pulsaudio Volume Control which you can check the process with.

Power management

If you have some half-decent power savings settings, they will inevitably come into your way when you forget to disable them before starting the presentation: the external screen will be turned off sooner or later, or the computer will go to sleep for lack of user interaction angry

You can prevent this by setting up just another script. As usual, start by:

…$ touch ~/.config/disper/hooks/cinnamon-sleep-display.sh
…$ chmod +x ~/.config/disper/hooks/cinnamon-sleep-display.sh
…$ gedit ~/.config/disper/hooks/cinnamon-sleep-display.sh

This file should have the following content, so paste it in, and save the file:

#!/bin/bash
# ~/.config/disper/hooks/cinnamon-sleep-display.sh (MagicMint) O0310
# Set or reset screen sleep delays
# (ɔ) GPL-2, see /usr/share/common-licenses/GPL-2

DISPRIMARY=`grep -m1 name ~/.config/monitors.xml | awk -F '"' '{print $2}'`

ERROR1="This is not a Cinnamon session. Power settings cannot be altered."
ERROR2="(disper) Cinnamon key not found: "

# The key strings (v2.4.6+rebecca)
POWER="org.cinnamon.settings-daemon.plugins.power"
SDA="sleep-display-ac"
SDB="sleep-display-battery"
SIAT="sleep-inactive-ac-timeout"
SIBT="sleep-inactive-battery-timeout"

PREFIX="/var/tmp/`whoami`/"
mkdir --parents "$PREFIX"

# Sensible delays to sleep
TURN_OFF=300
declare -i SLEEP=2*$TURN_OFF
declare -i TURN_OFF_AC=2*$TURN_OFF
declare -i SLEEP_AC=6*$TURN_OFF

[[ "$DISPER_STAGE" == switch ]] || exit 0

set_delay() { #key #default
 value=$2
 test -s $PREFIX$1 && read value < $PREFIX$1
 gsettings set "$POWER" $1 $value 2>/dev/null
}

reset_delay() { #key
 value=`gsettings get "$POWER" $1`
 if [[ "$value" != "0" ]]; then
  echo $value > $PREFIX$1
  test -s $PREFIX$1 || notify-send -i "dialog-warning" "$ERROR2"$1
 fi
 gsettings set "$POWER" $1 "0" 2>/dev/null
}

# This script works for cinnamon only
if env | grep -q XDG_CURRENT_DESKTOP=X-Cinnamon; then
 case "$DISPER_DISPLAYS" in
  # When only the built-in display is connected
  "$DISPRIMARY" ) 
   # Use screen sleep delays
   set_delay $SDA $TURN_OFF_AC
   set_delay $SDB $TURN_OFF
   set_delay $SIAT $SLEEP_AC
   set_delay $SIBT $SLEEP
  ;;

  # Otherwise there is some external device connected
  *)  
   # Don’t use screen sleep delays
   reset_delay $SDA
   reset_delay $SDB 
   reset_delay $SIAT 
   reset_delay $SIBT 
  ;;
 esac
else
 notify-send -i "dialog-error" "$ERROR1"
fi

#End of script

Power options

With the script above, the screen and suspend on inactivity delays will look like in the picture below, but only if you use the built-in display alone (that means that switching back to those values works only if HDMI is unplugged). Otherwise, these timeouts will be deactivated, and no display, neither internal nor external, will ever be switched off inadvertently yes

Power Options

Comments
MagicMint 8 years ago

If pulsaudio fails to recognize the HDMI sound output in spite of everything, try the following command(s):

pacmd unload-module module-udev-detect \
&& pacmd load-module module-udev-detect


Sascha_1 8 years ago

I'm able to switch displays by "disper --cycle".
How do I switch audio output? My primary audio is "Headphones" and secondary would be the second display, which has built in speakers.


Hammer459 9 years ago

Pretty good. I would say, a little more explanation and it'd be darn near perfect