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.