nixos/home-modules/explicit-configs/awesome/deficient/brightness/brightness.lua

231 lines
6.1 KiB
Lua
Raw Normal View History

2025-05-03 23:42:03 -07:00
--[[
Brightness control
==================
based on `xbacklight`!
alternative ways to control brightness:
sudo setpci -s 00:02.0 F4.B=80
xgamma -gamma .75
xrandr --output LVDS1 --brightness 0.9
echo X > /sys/class/backlight/intel_backlight/brightness
xbacklight
--]]
local awful = require("awful")
local wibox = require("wibox")
local gears = require("gears")
local gtable = require("gears.table")
local naughty = require("naughty")
local timer = gears.timer or timer
local exec = awful.spawn.easy_async
------------------------------------------
-- Private utility functions
------------------------------------------
local function warning(text)
if not naughty then return end
local args = {
title = "Brightness Control",
preset = naughty.config.presets.normal,
}
if naughty.notification then
args.message = text
naughty.notification(args)
else
args.text = text
naughty.notify(args)
end
end
local function readcommand(command)
-- I know, you should *never* use `io.popen`, but it's called at most once
-- per backend through the whole awesome session… I promise!
local file = io.popen(command)
local text = file:read('*all')
file:close()
return text
end
------------------------------------------
-- Backend: brightnessctl
------------------------------------------
local backends = {}
backends.brightnessctl = {
cmd = "brightnessctl",
_max = nil,
supported = function(self)
return tonumber(readcommand("brightnessctl --class=backlight max")) ~= nil
end,
parse_output = function(self, output)
-- dev,class,curr,percent,max
local _, _, _, percent, _ = output:match("(.*),(.*),(%d*),(%d*)%%,(%d*)")
return tonumber(percent)
end,
get = function(self, callback)
exec({ self.cmd, "--class=backlight", "-m", "info" }, function(output)
callback(self:parse_output(output))
end)
end,
set = function(self, percent, callback)
exec({ self.cmd, "--class=backlight", "-m", "set", percent .. "%" }, function(output)
callback(self:parse_output(output))
end)
end,
up = function(self, step, callback)
exec({ self.cmd, "--class=backlight", "-m", "set", step .. "%+" }, function(output)
callback(self:parse_output(output))
end)
end,
down = function(self, step, callback)
exec({ self.cmd, "--class=backlight", "-m", "set", step .. "%-" }, function(output)
callback(self:parse_output(output))
end)
end,
}
------------------------------------------
-- Backend: xbacklight
------------------------------------------
backends.xbacklight = {
cmd = "xbacklight",
supported = function(self)
return tonumber(readcommand("xbacklight -get")) ~= nil
end,
get = function(self, callback)
exec({self.cmd, "-get"}, function(output)
callback(tonumber(output))
end)
end,
set = function(self, value, callback)
exec({self.cmd, "-set", tostring(value)}, callback)
end,
up = function(self, step, callback)
exec({self.cmd, "-inc", tostring(step)}, callback)
end,
down = function(self, step, callback)
exec({self.cmd, "-dec", tostring(step)}, callback)
end,
}
------------------------------------------
-- Brightness control interface
------------------------------------------
local bcontrol = { backends = backends }
function bcontrol:new(args)
return setmetatable({}, {__index = self}):init(args)
end
function bcontrol:init(args)
-- determine backend
local backend = args.backend
if type(backend) == "string" then
backend = backends[backend]
if backend == nil then
warning("Unknown backend: " .. args.backend)
end
end
if backend == nil then
if backends.brightnessctl:supported() then
backend = backends.brightnessctl
elseif backends.xbacklight:supported() then
backend = backends.xbacklight
else
backend = nil
warning("Neither brightnessctl nor xbacklight seems to work")
end
end
self.is_valid = backend ~= nil
self.backend = backend
self.step = tonumber(args.step or '5')
self.levels = args.levels or {1, 25, 50, 75, 100}
self.widget = wibox.widget.textbox()
if self.is_valid then
self.widget:buttons(gtable.join(
awful.button({ }, 1, function() self:up() end),
awful.button({ }, 3, function() self:down() end),
awful.button({ }, 2, function() self:toggle() end),
awful.button({ }, 4, function() self:up(1) end),
awful.button({ }, 5, function() self:down(1) end)
))
self.timer = timer({
timeout = args.timeout or 3,
callback = function() self:update() end,
autostart = true,
call_now = true
})
end
return self
end
function bcontrol:set_text(value)
local brightness = math.floor(0.5 + value)
self.widget:set_text(string.format(" [%3d] ", brightness))
end
function bcontrol:update(opt_value)
if opt_value and string.match(opt_value, "%S+") then
self:set_text(opt_value)
else
self.backend:get(function(...) self:set_text(...) end)
end
end
function bcontrol:set(brightness, callback)
self.backend:set(brightness, callback or function(...) self:update(...) end)
end
function bcontrol:up(step, callback)
self.backend:up(step or self.step, callback or function(...) self:update(...) end)
end
function bcontrol:down(step, callback)
self.backend:down(step or self.step, callback or function(...) self:update(...) end)
end
function bcontrol:toggle()
self.backend:get(function(value)
local ilevel = 1
for i, lv in ipairs(self.levels) do
if math.abs(lv - value) < math.abs(self.levels[ilevel] - value) then
ilevel = i
end
end
self:set(self.levels[ilevel % #(self.levels) + 1])
end)
end
return setmetatable(bcontrol, {
__call = bcontrol.new,
})
-- vim: set ts=4 sw=4 et: