69

Ubuntu 20.04 has decided we need 4 clicks to shut down:

  1. Click top right of screen arrow-down
  2. Expand "power off/logout" panel
  3. Click "Power off"
  4. Confirm you want to power off by choosing power off vs reboot etc

Let's cut out at least 2 clicks here... how?

UPDATE: This is a "Lounge PC" - operated by mouse (no power button within reach as the laptop is closed). We watch a film, we want to click to shutdown and not type commands.

Marc
  • 823

10 Answers10

39

You can easily make it 2 clicks:

  1. Open Settings
  2. Go to "Power"
  3. Change the "Power button action" dropdown to "Power off"

Now click the physical power button on your device and then select power off from the prompt - that is 2 clicks (1 if you don't count pressing the power button as a click).

Daniel M.
  • 2,046
27

Reduce by two clicks

Option 1) Install the Poweroff Button on Topbar extension by Darknico. It adds a separate Power button on the right of the top bar.

Option 2) Create a "regular" launcher for "Power Off" (with thanks to pomsky). Either:

You may reduce with one more click by substituting the command in the launcher with "poweroff". Then, a single click on the launcher will immediately shut down the machine without confirmation dialog.

Reduce by one click

Option 3) Use the extension Bring Out Submenu Of Power Off/Logout Button by Pratap, or Simpler Off Menu by K3rcus. These extensions bring the items in the "Power Off/Log Out" submenu directly into the system menu, allowing to access them with one less click.

vanadium
  • 97,564
16

Getting it down to 1 "click" (technically a button press):

By default, ubuntu shuts down the machine when you press the power button.

Then just wait 60 seconds for the machine to power off instead of clicking again.

7

Keyboard shortkey screenshot

I have the habit of creating my own keyboard shortcut to shutdown the PC because this is lot easier and less painful.

I have used too many buttons to avoid any accidental shutdown.

You can decrease it and make it like Super+P or something like that if you are careful enough.

pomsky
  • 70,557
Pranav
  • 1,250
6

The answer is 0.

Install KShutdown, specify how long are you going to be online. As long as you stick to the plan and not mess with the time and save whatever you're doing 2 minutes prior. The machine will turn itself off, without you even touching it.

If you want to write your own command, start the terminal and type:

sudo shutdown -h +30

+30 (minutes) is an example. Change it to however long you want to stay online. And if you want the machine to turn itself off at a specific time, try:

sudo shutdown -h 20:30

(time is hypothetical, change it to whatever you want).

Note: Without the -h or -r switch it isn't a valid command.

Gryu
  • 8,002
  • 9
  • 37
  • 53
3

0 clicks, a few clacks.

An alternative solution that doesn't require a mouse (just keyboard):

  1. Press and hold Ctrl+ALT+t

This brings up a terminal window.

  1. Type "poweroff" then hit the Enter key.
Joshua
  • 151
2

HomA (Home Automation)

As of February 10, 2025, HomA was released to replace tvpowered bash script below. HomA is written in python and automatically discovers the same devices that you must hard code into tvpowered below. Additionally HomA supports Bluetooth Low Energy (BLE) LED Light Strips and automatically shuts them off when system is suspended.

Sony TV remote suspends laptop

This answer is based on IoT (Inernet of Things).

tvpowered (TV controls power to the computer) is a bash script. When you press the power button on your Sony TV remote:

  • The Sony TV will be shut off
  • The Google Android TV will be shut off
  • The light behind the Sony TV will be shut off
  • The light behind the Google TV will be shut off
  • The laptop will be put to sleep

Additionally the tvpowered script will:

  • Turn off picture of TV to save power when you are not watching movies on TV.
  • Display pop-up bubble when you change volume of TV used for listening to music.

volume change.gif

Please note this only works with Sony Bravia TVs.


Overview

When TV is turned off tvpowered automatically suspends, hibernates or powers off the laptop. Change the setting of SCTL global variable to control which action is taken.

tvpowered should be run as a normal user and called in Startup Applications.

Program design is straight forward:

  1. Wait for TV to be powered on.
  2. Begin fully active operation.
  3. Check if TV is powered off. If off go to step 5.
  4. Sleep for 3 seconds and repeat step 3.
  5. Suspend or Poweroff system when TV is powered off.
  6. If resuming from suspend go back to step 1.

In between these steps pop-up bubble messages appear on Desktop and are also logged to journalctl:

$ journalctl -xe | grep tvpower

Jun 11 18:11:20 tvpowered[27398]: TV is powered on. 'tvpowered' is now waiting for TV to power off.
Jun 11 18:11:47 tvpowered[28229]: TV Powered off. 'systemctl suspend' being called.
Jun 11 18:11:47 tvpowered[28238]: System powered back up. Checking if TV powered on. './tvpowered'.
Jun 11 18:12:26 tvpowered[31672]: TV is powered on. 'tvpowered' is now waiting for TV to power off.

tvpowered script

Copy and paste the script into a file on your computer and mark it executable with:

chmod a+x /path/to/tvpowered

Where /path/to/ is the directory name you created the file in.

You can also user your file manager (like Nautilus) to make the file executable.

In the script below there are a few constants you will need to set:

SCTL=suspend        # systemctl paramater: suspend or poweroff
IP=192.168.0.19     # IP address for Sony TV on LAN
ADB_IP=192.168.0.21 # IP address for Google TV on LAN for Android Debug Bridge
PWRD=123            # Password for Sony TV IP Connect

tvpowered complete bash script

#!/bin/bash

NAME: tvpowered

PATH: /usr/bin/ OR ~/bin (/home/USERNAME/bin) OR /mnt/e/bin/

DESC: When TV is powered off automatically suspend the laptop.

DATE: June 9, 2020. Modified March 30, 2023.

NOTE: Written for Ask Ubuntu question:

https://askubuntu.com/questions/1247484/

4-clicks-to-shut-down-ubuntu-can-we-reduce-this

UPDT: Jun 10 2020: Make name politically correct for Microsoft guidelines.

Change name from 'slave2tv' to 'tvpowered'. Abandon approach of polling

i2c, drm, i915, nvidia, xrandr, etc to see if monitor turned off. Setup

WiFi on TV instead and use Sony REST API to communicate TV status.

Jun 11 2020: Add pop-up bubble status messages. Add dependencies.

Add TenMinuteSpam. Add WaitUserSignOn. Add $SCTL constant. Convert

in-line code to mainline format.

Oct 03 2020: If ethernet disconnected we don't want to suspend.

Add TenMinuteSpam. Add WaitUserSignOn. Add $SCTL constant. Convert

in-line code to mainline format.

Oct 18 2020: If WiFi disconnected we don't want to suspend.

Dec 23 2020: After resume turn off picture with power savings.

Dec 31 2020: Fast popping bubble messages when volume changes.

Jan 09 2021: Improve performance and reduce system resources.

Jan 31 2021: Switch from /tmp to /run/user/1000 (RAM).

Mar 13 2023: New IP address 19 after power outage.

Mar 26 2023: Change volume partial UTF-8 ticks from 4 to 8.

Mar 28 2023: Change call to pictureoff

Mar 30 2023: Google TV to sleep (TV Remote Power Off).

Sources:

https://gist.github.com/kalleth/e10e8f3b8b7cb1bac21463b0073a65fb#cec-sonycec

https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/audio/v1_0/setAudioVolume/index.html

https://developer.sony.com/develop/audio-control-api/get-started/http-example#tutorial-step-2

https://en.wikipedia.org/wiki/CURL

https://stackoverflow.com/questions/7172784/how-do-i-post-json-data-with-curl

https://stackoverflow.com/questions/2829613/how-do-you-tell-if-a-string-contains-another-string-in-posix-sh

SCTL=suspend # systemctl parameter: 'suspend' or 'poweroff' IP=192.168.0.19 # IP address for Sony TV on LAN ADB_IP=192.168.0.21 # IP address for Google TV on LAN for Android Debug Bridge PWRD=123 # Password for Sony TV IP Connect (Pre-Shared key)

Must have curl package.

command -v curl >/dev/null 2>&1 || { echo >&2
"'curl' package required but it is not installed. Aborting.";
exit 2; }

Must have notify-send from libnotify-bin package

command -v notify-send >/dev/null 2>&1 || { echo >&2
"'libnotify-bin' package required but it is not installed. Aborting.";
exit 3; }

Must have adb (Android Debug Bridge) package

command -v adb >/dev/null 2>&1 || { echo >&2
"'adb' package required but it is not installed. Aborting.";
exit 4; }

cURLit () {

# $1 = JSON String in pretty format converted to file for cURL --data.
# $2 = Sony subsystem to talk to, eg accessControl, audio, system, etc.
# 3  = variable name to receive reply from TV

local TEMP Result ReturnState

# Declare mathres as reference to argument 3 provided (Bash 4.3 or greater)
declare -n Result=$3  # ERROR: declare: `': not a valid identifier

# Create temporary file in RAM for curl command
TEMP=$(mktemp --tmpdir=/run/user/1000 tvpowered.XXXXXXXX)
echo "$1" > "$TEMP"

# -s = silent
Result=$(curl -s -H "Content-Type: application/json; charset=UTF-8" \
         -H "X-Auth-PSK: $PWRD" \
         --data @"$TEMP" \
         http://$IP/sony/"$2")
# echo "Result: $Result"    # Remove leading # for debugging
ReturnState="$?"
# TO-DO: check $? and if non-zero pop up dialog with $TEMP contents
rm "$TEMP"

# Test string

#curl -s -H "Content-Type: application/json; charset=UTF-8" -H "X-Auth-PSK: 123" --data "{ "method": "getPowerStatus", "id": 50, "params": [], "version": "1.0" }" http://192.168.0.16sony/system } # cURLit

GetPowerStatus () {

local Reply ReturnState

# Copy and paste JSON strings from Sony website: 
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/getPowerStatus/index.html
JSONstr='{
            "method": "getPowerStatus",
            "id": 50,
            "params": [],
            "version": "1.0"
         }'

cURLit "$JSONstr" "system" Reply    # No $ for Reply variable! pass pointer
ReturnState="$?"                    # Usually '6', not checked.

#echo "ReturnState: $ReturnState Reply: $Reply"    # Remove # for debugging
# Reply: {"result":[{"status":"active"}],"id":50}
#    or: {"result":[{"status":"standby"}],"id":50}

# Does 'active' substring exist in TV's reply?
[[ "${Reply#*active}" != "$Reply" ]] && return 0

# TV is turned off (standby) or no network (blank)
return 1

} # GetPowerStatus

GetVolume () {

# Copy and paste JSON strings from Sony website: 
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/audio/v1_0/getVolumeInformation/index.html
JSONstr='{
            "method": "getVolumeInformation",
            "id": 33,
            "params": [],
            "version": "1.0"
         }'

# Then pass string to cURL for execution
cURLit "$JSONstr" "audio" Reply

# Sample output:
#   Volume:, {"result":[[{"target":"speaker","volume":44,"mute":false,
#   "maxVolume":100,"minVolume":0},{"target":"headphone","volume":15,
#   "mute":false,"maxVolume":100,"minVolume":0}]],"id":33}

Start="${Reply:41:4}"
Volume=${Start%,*}

return $Volume

} # GetVolume

Bar="" # Global Volume Level bar

VolumeBar () {

Bar=""                      # Progress Bar / Volume level
Len=25                      # Length of Progress Bar / Volume level
Div=4                       # Divisor into Volume for # of full blocks
Fill="▒"                    # Fill background up to $Len
Parts=8                     # Divisor into  Volume for # of part blocks
# UTF-8 left blocks: 1, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8
Arr=("█" "▏" "▎" "▍" "▌" "▋" "▊" "█")

FullBlock=$((${1} / Div))   # Number of full blocks
PartBlock=$((${1} % Parts)) # Size of partial block (array index)

while [[ $FullBlock -gt 0 ]]; do
    Bar="$Bar${Arr[0]}"     # Add 1 full block into Progress Bar
    (( FullBlock-- ))       # Decrement full blocks counter
done

# If remainder zero no partial block, else append character from array
if [[ $PartBlock -gt 0 ]]; then
    Bar="$Bar${Arr[$PartBlock]}"
fi

while [[ "${#Bar}" -lt "$Len" ]]; do
    Bar="$Bar$Fill"         # Pad Progress Bar with fill character
done

} # VolumeBar

log () { logger --id=$$ -t "tvpowered" "$1" } # log

WaitForSignOn () {

# tvpowered might be loaded during boot. The user name is required
# for sending popup bubble messages and dialogs to screen. We must
# wait until user signs on to get .Xauthority file settings.

# code lifted from eyesome.sh
SpamOn=10       # Causes 10 iterations of 2 second sleep
SpamContext="Login"
TotalWait=0

# Wait for user to sign on then get Xserver access for xrandr calls
UserName=""
while [[ $UserName == "" ]]; do

    # Find UserName currently logged in.
    UserName="$(who -u | grep -F '(:0)' | head -n 1 | awk '{print $1}')"
    [[ $UserName != "" ]] && break

    sleep "$SpamLength"
    TotalWait=$(( TotalWait + SpamLength ))
done

if [[ $TotalWait != "0" ]] ; then
    log "Waited $TotalWait seconds for $UserName to login."
    xhost local:root
    export XAUTHORITY="/home/$UserName/.Xauthority"
fi

} # WaitForSignOn

LastVolume=0 CurrVolume=0

TenMinuteSpam () {

# If TV not powered up Spam user for 10 minutes that 'tvpowered' is running
# and will shut down / suspend system

WaitForSignOn   # Might be called by root during boot before user signed on.

Cnt=0
while : ; do

    if GetPowerStatus ; then
        log "TV is powered on. 'tvpowered' is now waiting for TV to power off."
        break
    else
        # Spam user every 60 seconds
        (( $(( Cnt % 20 )) == 0 )) && \
            notify-send --urgency=critical "tvpowered" \
                -h string:x-canonical-private-synchronous:startup \
                --icon=/usr/share/icons/gnome/48x48/devices/display.png \
                "TV not communicating.\n Checking TV again..."
    fi
    sleep 3
    (( Cnt++ ))
done

GetVolume
LastVolume="$?"
VolumeBar $LastVolume
notify-send --urgency=critical "tvpowered" \
    --icon=/usr/share/icons/gnome/48x48/devices/display.png \
    "Fully activated.\n System will $SCTL when TV powered off.  Volume: $LastVolume $Bar"

adb connect "$ABD_IP"  # Connect to Google TV.
return 0

} # TenMinuteSpam

###################################

MAINLINE

###################################

Main () {

echo "$0: Initialization. Ensuring TV is powered on before starting."
TenMinuteSpam
echo "$0: Fully activated. Waiting for TV to powered off and then $SCTL."
echo "$0: LastVolume: $LastVolume"

Cnt=0
FirstTime=true
VolumeCnt=0             # TV Remote changed volume, so shorter sleep

while : ; do

    if ! GetPowerStatus; then

        # START FROM ABOVE: 
        # This was causing 2% CPU drain with Network Manager and
        # debus-daemon. So move from above GetPowerStatus to below.

        # If network down then wait for it to come up. 
        #etherup=$(cat /sys/class/net/e*/carrier) # Returns 1 even disconnected
        #wifi_up=$(cat /sys/class/net/w*/carrier)
        #if [[ $etherup <> "1" && $wifi_up <> "1" ]] ; then
        state=$(nmcli -f STATE -t g)            # Network manager takes .5 CPU
        if [[ $state == disconnected ]] ; then
            # Spam user every 60 * Cot seconds
            notify-send --urgency=critical "tvpowered" \
                -h string:x-canonical-private-synchronous:startup \
                --icon=/usr/share/icons/gnome/48x48/devices/display.png \
                "Internet not up.\nChecking Ethernet and/or  WiFi state again..."
            sleep $((Cnt * 60))
            (( Cnt++ ))
            continue
        else
            Cnt=0                               # Reset timer for next loop
        fi

        # END FROM ABOVE: If network down then wait for it to come up


        state=$(nmcli -f STATE -t g)        # Network manager takes .5 CPU
        if [[ $state == disconnected ]] ; then
            echo "Unexpected disconnect, aborting suspend."
        else
            log "TV Powered off. 'systemctl $SCTL' being called."
            adb connect "$ABD_IP"  # Connect to Google TV.
            adb shell input keyevent 26  # Google TV to sleep (remote off)
            systemctl "$SCTL"
            # systemctl will suspend. When resuming we hit next line
            log "System powered back up. Checking if TV powered on. '$0'."
            sleep 10                        # Time to wake from suspend
            TenMinuteSpam                   # Wait for network connection
            pictureoff                      # Picture off energy saving
        fi
    fi

    GetVolume
    CurrVolume="$?"
    # echo CurrVolume: $CurrVolume LastVolume: $LastVolume

    if [[ "$CurrVolume" != "$LastVolume" ]] ; then
        # Make volume bar using progress bar methods
        VolumeBar $CurrVolume
        # Ask Ubuntu: https://askubuntu.com/a/871207/307523
        notify-send --urgency=critical "tvpowered" \
            -h string:x-canonical-private-synchronous:volume \
            --icon=/usr/share/icons/gnome/48x48/devices/audio-speakers.png \
            "Volume: $CurrVolume $Bar"
        LastVolume=$CurrVolume
        VolumeCnt=100  # For 1 second, faster checks for volume change
        # TODO: Process VolumeCnt internally in loop instead of larger loop
    fi

    if [[ $VolumeCnt > 0 ]]; then
        (( VolumeCnt-- ))
        SleepTime=.01
    else
        SleepTime=.75
    fi

    sleep $SleepTime

    # Next iteration
    FirstTime=false
done

exit 0

} # Main

Main "$@"


Summary

I was inspired by OP's question and never realized how cumbersome and time-consuming my end of day suspend process used to be:

  1. Find where the cursor is on on one of three monitors
  2. Navigate to top right of whichever monitor and left click Cog menu
  3. Pull mouse down to suspend option
  4. Click suspend (being careful not to click shutdown next to it!)
  5. Power off Sony TV
  6. Power off Toshiba TV

tvpowered has eliminated time consuming steps 1. through 4.

EDIT: A website was made to document tvpowered


Bonus - Turn off Light Behind TV

For nighttime viewing, there is a light behind the TV. Whenever the laptop goes to sleep, it first shuts off the light.

Create the script /etc/NetworkManager/dispatcher.d/pre-down.d/smartplug_off and place into it:

#!/bin/bash

NAME: smartplug_off

PATH: /etc/NetworkManager/dispatcher.d/pre-down.d

DESC: Turn off smartplug light power for TV light

DATE: March 7, 2020.

CALL: Called by Network Manager before going down. Network manager in turn

is called by systemd during suspend/hibernate/shutdown

NOTE: myisp.sh and hs100.sh must be installed for hs100 tp-link power plug.

https://developer.gnome.org/NetworkManager/stable/NetworkManager.html

PlugName="192.168.0.15"

status=$(hs100.sh -i "$PlugName" check | cut -f2) if [ $status == "OFF" ] ; then : # Nothing to do already off elif [ $status == "ON" ] ; then hs100.sh -i "$PlugName" off else echo Error hs100.sh not responding check connection and IP "$PlugName". fi

0

I have a laptop by my television that I access with a wireless keyboard/touchpad device. I also keep the lid closed as well.

What I did is add a simple gnome extension called Gnome-Shutdown-Button. You can find a ton of these extensions at https://extensions.gnome.org/

It opens a dialogue that says "shutting down in 30 seconds" (it might be less) and offers a second option to shut down now.

0

This is still the case in Ubuntu 22, plus the time getting the mouse pointer to mouse find the tiny button at the top. :-(

I discovered the quickest way was:

  • press the Windows key
  • type of (shorter than off)

Unless you have something else installed "Power Off" should be the first option and you can press Return.

SharpC
  • 115
-1

in terminal shutdown now do the trick for me

sda11
  • 1