Files
dotfiles/config/awesome/config/widgets.lua
T
2026-07-03 10:45:31 +02:00

119 lines
4.5 KiB
Lua

local awful = require("awful")
local gears = require("gears")
local wibox = require("wibox")
local colors = require("config.colors")
local M = {}
-- "ICON value" with ICON tinted accent, like polybar's *-prefix-foreground.
function M.label(icon, val)
return string.format("<span foreground='%s'>%s</span> %s", colors.white, icon, val or "")
end
-- A slim separator in the disabled color, like polybar's separator.
function M.sep()
local w = wibox.widget.textbox()
w.markup = string.format("<span foreground='%s00'> </span>", colors.disabled)
return w
end
-- Wrap a widget in a small margin so bar modules aren't crammed together.
function M.padded(w, left, right)
return wibox.container.margin(w, left or 8, right or 8)
end
-- Focused window title (polybar xwindow / %title%)
function M.make_title()
local t = wibox.widget.textbox()
local function update()
local c = client.focus
t.markup = c and string.format("<span foreground='%s'>%s</span>", colors.white, gears.string.xml_escape(c.name or "")) or ""
end
client.connect_signal("focus", update)
client.connect_signal("unfocus", update)
client.connect_signal("property::name", update)
return t
end
-- CPU usage % (two top samples so the reading is accurate)
function M.make_cpu()
return awful.widget.watch(
{ "bash", "-c", [[LANG=C top -bn2 -d0.3 | grep -m2 '^%Cpu' | tail -1 | awk '{printf "%.0f", 100 - $8}']] },
3, function(w, out) w.markup = M.label("<span font_size='large'> </span>", out:gsub("%s+$", "") .. "%") end)
end
-- Volume: click to mute, scroll to adjust, right-click for the mixer.
-- Keeps its own refresh() so button presses update instantly instead of
-- waiting on the polling timer.
function M.make_vol()
local w = wibox.widget.textbox()
local vol_script = [[
sink=$(LANG=C pactl get-default-sink 2>/dev/null)
m=$(LANG=C pactl get-sink-mute "$sink" 2>/dev/null | grep -oE 'yes|no')
v=$(LANG=C pactl get-sink-volume "$sink" 2>/dev/null | grep -oE '[0-9]+%' | head -n1)
echo "$m $v"
]]
local function shell_quote(s) return "'" .. s:gsub("'", "'\\''") .. "'" end
local vol_cmd = "sh -c " .. shell_quote(vol_script)
local function refresh()
awful.spawn.easy_async_with_shell(vol_cmd, function(out)
local muted, pct = out:match("(%a+)%s+(%d+)%%")
if muted == nil and pct == nil then
w.markup = string.format("<span foreground='%s'><span font_size='large'>󱄠</span> n/a</span>", colors.disabled)
return
end
muted = muted == "yes"
pct = pct or "0"
w.markup = muted and string.format("<span foreground='%s'>MUTE</span>", colors.yellow) or M.label("<span font_size='large'>󱄠</span>", pct .. "%")
end)
end
w:buttons(gears.table.join(
awful.button({ }, 1, function() awful.spawn("/home/jason/.local/bin/audioswitch") end),
awful.button({ }, 3, function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-mute "$(pactl get-default-sink)" toggle']], function() refresh() end) end),
awful.button({ }, 4, function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" +2%']], function() refresh() end) end),
awful.button({ }, 5, function() awful.spawn.easy_async_with_shell([[sh -c 'pactl set-sink-volume "$(pactl get-default-sink)" -2%']], function() refresh() end) end)
))
gears.timer { timeout = 2, call_now = true, autostart = true, callback = refresh }
return w
end
-- Brightness: click to toggle between night (default gamma) and day (boosted).
function M.make_brightness()
local OUTPUT = "HDMI-A-0"
local DAY_CMD = "xrandr --output " .. OUTPUT .. " --set CTM \"1.1,0,0,0,1.1,0,0,0,1.1\" --gamma 1.08:1.08:1.08"
local NIGHT_CMD = "xrandr --output " .. OUTPUT .. " --set CTM \"1,0,0,0,1,0,0,0,1\" --gamma 1.0:1.0:1.0"
local w = wibox.widget.textbox()
local is_day = true
local function render()
local icon = is_day and " 󱁞 " or " 󱠩 "
w.markup = string.format(
"<span font_family='JetBrainsMono Nerd Font' foreground='%s' font_size='large'>%s</span>",
colors.white, icon
)
end
local function apply(day)
local cmd = day and DAY_CMD or NIGHT_CMD
awful.spawn.easy_async_with_shell(cmd, function()
is_day = day
render()
end)
end
w:buttons(gears.table.join(
awful.button({ }, 1, function() apply(not is_day) end)
))
apply(true)
return w
end
return M