Brightness Control on i3wm

Photo of author

i3 being very barebone, you need to configure brightness control yourself. This is a recurring theme when dealing with i3wm.

It’s a hassle the first time when you are configuring these things, but once you get used to it, it’s not that difficult. But that’s applicable to everything in life. Nothing is difficult once you get used to it.

Bind script to brightness keys on i3wm

In the simplest term, you just need to bind your brightness-up key on your laptop to a script that actually brightens it up. Just add something like following to your ~/.config/i3/config:

set $brightness_script $HOME/.config/scripts/brightness.py
bindsym XF86MonBrightnessDown exec --no-startup-id $brightness_script -
bindsym XF86MonBrightnessUp exec --no-startup-id $brightness_script +

This binds brightness_script with the keys. The script obviously doesn’t exist and you would have to write it yourself.

Brightness Script

While it can be a bash script, I have recently decided to start using Python for all my scripting needs. I want a scripting language where string comparison is intuitive and I don’t have to worry about things not working just because I didn’t put a space between operators and etc.

The bash script needs to handle two sub-commands: “+” and “-“. One increases the brightness and the other decreases it. I use the following script:

#!/usr/bin/python3

import ShellCommand
import subprocess
import sys
import os

MIN=0   #%
MAX=100 #%
STEP=5
STATUS_PATH=os.path.expanduser("/tmp/mysession/brightness")

def getScreens():
    # xrandr -q | grep ' connected' | cut -d ' ' -f1
    output = ShellCommand.runShellCommand("xrandr -q")
    return [ line.split()[0] for line in output.split("\n") if " connected" in line ]

def getCurrentBrightness():
    #curBr=$(xrandr --verbose | grep Brightness: | head -n 1 | awk '{print $2}')
    output = ShellCommand.runShellCommand("xrandr --verbose")
    brightness = [ line.split()[1] for line in output.split("\n") if "Brightness:" in line ][0]
    if brightness == "1.0":
        return 100
    return int(float(brightness) * 100)


def setCurrentBrightness(brightness: int):
    brightness_float = float(brightness) / 100
    for screen in getScreens():
        subprocess.run(["xrandr", "--output", screen, "--brightness", str(brightness_float)])

def writeToFile(val):
    # Output the value in a file so that status.conf picks it up for display
    f = open(STATUS_PATH, "w")
    f.write(str(val))
    f.close()

def sendNotification(val):
    ShellCommand.runShellCommand(f"notify-send 'Brightness {val}' -h string:x-canonical-private-synchronous:brightness_percentage --app-name System")

if __name__ == '__main__':
    arg = sys.argv[1]
    match arg:
        case "+":
            val = getCurrentBrightness() + STEP
            if (val > 100):
                val = 100
        case "-":
            val = getCurrentBrightness() - STEP
            if (val < 0):
                val = 0
        case "w":
            val = getCurrentBrightness()
        case _:
            exit

    setCurrentBrightness(val)
    writeToFile(val)
    sendNotification(val)

Here is what the script does:

  • It supports three sub-commands:
    • “+” to increase brightness.
    • “-” to decrease it.
    • “w” to just write the brightness level to a file.
      • This is useful to execute when device boots for the first time to ensure the brightness level file exists for i3status. See below for more details.
  • For all sub-commands it writes the brightness level to a file. This will be later used to update our i3status to show what is the current brightness level.
  • It gets and sets the brightness level using xrandr command.
  • ShellCommand is just a helper library I wrote to run the shell commands. It’s not a actual library.
  • The script also sends a notification to indicate the brightness has changed.

Updating i3status bar

As for updating the i3status bar, just add this to your config:

read_file brightness {
    format = "B: %content"
    path = "/tmp/mysession/brightness"
}

i3status can read value from a file and just display its content. This is pretty useful. With this technique you can show anything you want on your status bar.

In case you notice that your status bar is not updating when you increase or decrease brightness, you may need to forcefully refresh your i3status bar. You can do that by simply updating your bind commands to:

set $i3refresh killall -SIGUSR1 i3status
bindsym XF86MonBrightnessDown exec --no-startup-id $brightness_script + && $i3refresh

Conclusion

With this, you should have a proper brightness control on i3wm. Hopefully this also gives you idea on how to bind any script with any keys on i3wm.

Now that I think of it, my previous post on Configuring screenshots on i3wm follows similar pattern as this. Write a script and just bind it to a key. Check it out if you need more inspiration.

Oh hi there 👋
It’s nice to meet you.

Sign up to receive updates in your inbox once a month.

I don’t spam! You can always unsubscribe if you don't like it.

🗞️ Don’t miss the latest posts!

Subscribe to the Monthly Newsletter

I won't spam. Promise!

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments