aboutsummaryrefslogtreecommitdiff
path: root/xbrightness
blob: 6b5f83fbe50334b16b08e157bcd5eeb16542082d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/bin/env bash
# Change the screen brightness.
# See the output of "$0 -h" for details.
#
# Script obtained at https://unix.stackexchange.com/questions/61256/how-to-change-lcd-intensivity-brightness
# Minor fixes by rhatto

# Exit immediately on each error and unset variable;
# see: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
#set -Eeuo pipefail
set -Eeu

# This script is locale-dependent
export LC_ALL=C

APP_NAME="Screen Brightness Changer"
cmd=${1:-get}
bl_dir=/sys/class/backlight/intel_backlight

function print_help() {
    script_name="$(basename "$0")"
    echo "${APP_NAME} - Allows to change the screen brightness."
    echo "It may do so using the hardware backlight or through software manipulation of pixel values sent to the screen."
    echo
    echo "Usage:"
    echo "  $script_name [OPTIONS] COMMAND"
    echo "Commands:"
    echo "  [on|off]         set the brightness to either 100% or 0%"
    echo "  [0.0, 1.0]       set the brightness to the given fraction"
    echo "  [+-][0.0, 1.0]   increase/decrease the brightness by the given fraction"
    echo "  [0, 100]%        set the brightness to the given percentage"
    echo "  [+-][0, 100]%    increase/decrease the brightness by the given percentage"
    echo "Options:"
    echo "  -h, --help              Print this usage help and exit"
    echo "Examples:"
    echo "  $script_name            # Returns the current brightness"
    echo "  $script_name 1.0        # Set to full brightness"
    echo "  $script_name 100%       # Set to full brightness"
    echo "  $script_name +0.1       # Increase brightness by 10%"
    echo "  $script_name -10%       # Reduce brightness by 10%"
    echo "  $script_name --help     # Print this usage help and exit"
}

# read command-line args
POSITIONAL=()
while [[ $# -gt 0 ]]
do
    arg="${1}"
    shift # $2 -> $1, $3 -> $2, ...

    case "${arg}" in
        -h|--help)
            print_help
            exit 0
            ;;
        *) # non-/unknown option
            POSITIONAL+=("${arg}") # save it in an array for later
            ;;
    esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters

# Check if first number is larger then the second.
# This can do floating-point comparison.
function _isLarger() {
    return "$(awk -v n1="$1" -v n2="$2" \
        'BEGIN { if (n1 >= n2) { print("0") } else { print("1") } }')"
}

# Convert potentially relative (+|-X) into new absolute value.
# If relative=false, return the value.
# Else, return current +|- the value.
function _makeAbs() {
    local _cur="$1"
    local _rel="$2"
    local _rel_sign="$3"
    local _val="$4"
    local _new=""
    if $_rel
    then
        _new=$(printf "%.3f" "$(awk "BEGIN { print($_cur + ($_rel_sign * $_val)) }")")
    else
        _new="$_val"
    fi
    echo -n "$_new"
}

# Limits the input value (float) to the range [0.0, 1.0] (inclusive).
function _limit01() {
    local _val="$1"
    local _new=""
    if _isLarger "$_val" 1
    then
        _new="1.0"
    elif _isLarger 0 "$_val"
    then
        _new="0.0"
    else
        _new="$_val"
    fi
    echo -n "$_new"
}

# Post-process/parse the input command/value.
val_rel=$(echo "$cmd" | grep -q '^[+-]' && echo -n "true" || echo -n "false")
val_rel_sign=$(echo "$cmd" | grep -q '^+' && echo -n "1" || echo -n "-1")
cmd=$(echo "$cmd" | sed -e 's|^[+-]||')

# Calculate the (float) fractional value -
# absolute or relative -
# indicated by the given command.
if   [ "$cmd" == "on" ]; then
    # turn fully bright
    val_new=1.0
elif [ "$cmd" == "off" ]; then
    # turn the screen backlight off
    val_new=0.0
elif echo "$cmd" | grep -q '%$'; then
    val_new=${cmd/\%/}
    val_new=$(printf "%.3f" "$(awk "BEGIN { print($val_new / 100) }")")
elif _isLarger "$cmd" 0 && _isLarger 1 "$cmd"; then
    val_new=$cmd
elif [ "$cmd" == "get" ]; then
    val_new="0"
    val_rel="true"
    val_rel_sign="1"
else
    >&2 echo "Invalid command '$cmd'!"
    exit 1
fi

# Evaluate which backlight/brightness changeing method to use

mth_xbacklight=false
mth_bare=false
mth_xrandr=false
if which xbacklight > /dev/null 2>&1 && xbacklight -get > /dev/null 2>&1
then
    echo "Using 'xbacklight' (hardware) ..."
    # This requires the `xbacklight` utility installed
    # and the systems backlight to be suported by it.
    # This method actually changes the backlight brightness (hardware).
    mth_xbacklight=true
elif [ -d "$bl_dir" ] && [ "$EUID" -eq 0 ]
then
    echo "Using '$bl_dir' (hardware) ..."
    # This requires the $bl_dir directory to be present
    # and this script to be run with root priviledges
    # in order to be able to write ot that dir.
    # This method actually changes the backlight brightness (hardware).
    mth_bare=true
elif which xrandr > /dev/null 2>&1
then
    #echo "Using xrandr (software) ..."
    # This has no prerequisite; it should always work.
    # This method only manipulates the pixel values sent to the screen, imitating more/less brightness (software).
    mth_xrandr=true
else
    >&2 echo "No low-level-method chosen!"
    exit 1
fi

# Fetch the current brightness value as fraction in [0.0, 1.0]
if $mth_xbacklight
then
    val_cur_perc=$(xbacklight -get)
    val_cur=$(printf "%.3f" "$(awk "BEGIN { print($val_cur_perc / 100) }")")
elif $mth_bare
then
    val_max=$(cat "$bl_dir/max_brightness")
    val_cur_abs=$(cat "$bl_dir/brightness")
    val_cur=$(printf "%.3f" "$(awk "BEGIN { print(1.0 * $val_cur_abs / $val_max) }")")
elif $mth_xrandr
then
    val_cur=$(xrandr --verbose | grep -i "brightness" | sed -e 's|.*: ||' | head -1)
else
    >&2 echo "No low-level-method chosen!"
    exit 1
fi

# Calculate the new brightness value as fraction in [0.0, 1.0]
val_new=$(_limit01 "$(_makeAbs "$val_cur" "$val_rel" "$val_rel_sign" "$val_new")")
val_new_perc=$(printf "%.0f" "$(awk "BEGIN { print($val_new * 100) }")")

# Just print the (new == old) current brightness percentage and exit
if [ "$cmd" == "get" ]
then
    echo "${val_new_perc}%"
    exit 0
fi

# Set the new brightness value
if $mth_xbacklight
then
    xbacklight -set "$val_new_perc"
elif $mth_bare
then
    val_max=$(cat "$bl_dir/max_brightness")
    val_new_abs=$(printf "%.0f" "$(awk "BEGIN { print($val_new * $val_max) }")")
    echo -n "$val_new_abs" | tee "$bl_dir/brightness"> /dev/null
elif $mth_xrandr
then
    displays=$(xrandr -q | grep " connected" | sed -e 's| .*||')

    # Apply brightness configuration for each available display
    for display in $displays; do
      echo "Setting brightness to $val_new at $display..."
      # Use "|| true" to not exit on any errors at this stage
      xrandr --output "$display" --brightness "$val_new" || true
    done
else
    >&2 echo "No low-level-method chosen!"
    exit 1
fi