2023-01-19 13:42:20 +00:00
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- Generic battery widget with support for multiple power sources, backlights and backlight control
local awful = require ( " awful " )
local beautiful = require ( " beautiful " )
local gears = require ( " gears " )
local wibox = require ( " wibox " )
local awmtk2 = require ( " awmtk2 " )
local syscontrol = require ( " syscontrol " )
local ask = require ( " asckey " )
local function get_virtual_icon ( data )
2023-08-16 19:40:39 +00:00
-- Get an icon from average of total battery percentage and current charging state
2023-01-19 13:42:20 +00:00
local count = 0
local cumulative = 0
local name = " battery- "
for _ , v in pairs ( data ) do
if type ( v ) == " number " then
cumulative = cumulative + v
count = count + 1
end
end
local percentage = math.floor ( ( cumulative / ( count * 100 ) ) * 100 )
if percentage < 15 then
name = name .. " caution- "
elseif percentage < 30 then
name = name .. " low- "
elseif percentage < 60 then
name = name .. " good- "
else
name = name .. " full- "
end
if data [ " charge " ] then
name = name .. " charging- "
end
return beautiful [ name .. " symbolic " ] , percentage
end
return function ( args )
local style = awmtk2.create_style ( " battery " ,
awmtk2.generic . popup , args.style , args.vertical )
local templates = awmtk2.create_template_lib ( " battery " , awmtk2.templates , args.templates )
local t = awmtk2.build_templates ( templates , style , args.vertical )
-- set up popup layout
local layout = wibox.widget ( {
layout = wibox.layout . fixed.vertical ,
spacing = style.base . spacing
} )
-- create popup
local popup = awful.popup ( t.popup ( layout ) )
2023-03-05 12:53:37 +00:00
popup : connect_signal ( " button::press " , function ( _ , _ , _ , b )
if b == 3 then
popup.visible = false
end
end )
2023-01-19 13:42:20 +00:00
local battery_widget
do -- create battery widget
local style = awmtk2.create_style ( " battery " ,
awmtk2.generic . status_widget , args.style , args.vertical )
local templates = awmtk2.create_template_lib ( " battery " , awmtk2.templates , args.templates )
local t = awmtk2.build_templates ( templates , style , args.vertical )
battery_widget = wibox.widget ( t.button ( {
t.icon ( {
image = beautiful [ " battery-missing-symbolic " ] ,
resize = true ,
id = " virtual_id "
} ) ,
( args.percentage and {
markup = " 0% " ,
id = " percentage_id " ,
widget = wibox.widget . textbox
} ) ,
layout = wibox.layout . fixed.horizontal ,
spacing = style.base . spacing
} ) )
-- make it possible to press the button and make it toggle the popup
battery_widget : connect_signal ( " button::press " , style.button . onpress )
battery_widget : connect_signal ( " button::release " , style.button . onrelease )
battery_widget : connect_signal ( " button::press " , function ( _ , _ , _ , button )
if button == 1 then
popup.visible = ( not popup.visible )
if popup.visible then
popup : move_next_to ( mouse.current_widget_geometry )
end
end
end )
end
-- map widgets to their names to make it easier to update separate components
local widget_map = { }
-- also map current charge state of every device to get the icon for the tray
local percentage_map = { }
-- {{{ Power supply devices
local power_devices = syscontrol.power_supply . enumerate ( )
for _ , device in pairs ( power_devices ) do
local data = syscontrol.power_supply . read_attribs ( device )
if data.type == " Battery " then
widget_map [ data.name ] = wibox.widget ( t.container ( {
t.article ( {
icon = get_virtual_icon ( {
data.capacity ,
charge = data.charging
} ) ,
icon_id = " battery_icon " ,
title = " Battery ( " .. data.model .. " ) " ,
} ) ,
t.textbox ( {
markup = ( " Capacity: %d%% " ) : format ( data.capacity ) ,
id = " capacity_id "
} ) ,
t.textbox ( {
markup = ( " Quality: %.4f%% " ) : format ( data.quality ) ,
id = " quality_id " ,
} ) ,
layout = wibox.layout . fixed.vertical
} , {
bg = style.container . bg_highlight ,
bgimage = style.container . bgimage_highlight
} ) )
layout : add ( widget_map [ data.name ] )
percentage_map [ data.name ] = data.capacity
elseif data.type == " Mains " then
widget_map [ data.name ] = wibox.widget ( t.container ( {
t.article ( {
icon = beautiful [ " ac-adapter-symbolic " ] ,
title = " Power supply " ,
} ) ,
t.textbox ( {
markup = " Powered: " .. tostring ( data.online ) ,
id = " online_id " ,
} ) ,
layout = wibox.layout . fixed.vertical
} , {
bg = style.container . bg_highlight ,
bgimage = style.container . bgimage_highlight
} ) )
layout : add ( widget_map [ data.name ] )
percentage_map [ " charge " ] = data.online
end
end
2023-08-16 19:40:39 +00:00
-- "Virtual" here means an abstract icon that represents the average state of all batteries.
2023-01-19 13:42:20 +00:00
local function update_virtual_battery ( )
local icon = battery_widget : get_children_by_id ( " virtual_id " ) [ 1 ]
local percentage = battery_widget : get_children_by_id ( " percentage_id " ) [ 1 ]
local capacity
icon.image , capacity = get_virtual_icon ( percentage_map )
if percentage then
percentage : set_markup ( tostring ( capacity ) .. " % " )
end
end
update_virtual_battery ( )
-- Update loop
local power_update = gears.timer ( {
timeout = args.power_polling or 2 ,
autostart = true ,
callback = function ( )
for _ , v in pairs ( power_devices ) do
local data , err = syscontrol.power_supply . read_attribs ( v )
if data and data.type == " Mains " then
local w = widget_map [ data.name ]
local online = w : get_children_by_id ( " online_id " ) [ 1 ]
online : set_markup ( " Powered: " .. tostring ( data.online ) )
percentage_map [ " charge " ] = data.online
elseif data and data.type == " Battery " then
local w = widget_map [ data.name ]
local icon = w : get_children_by_id ( " battery_icon " ) [ 1 ]
local capacity = w : get_children_by_id ( " capacity_id " ) [ 1 ]
local quality = w : get_children_by_id ( " quality_id " ) [ 1 ]
icon.image = get_virtual_icon ( {
data.capacity ,
charge = data.charging
} )
capacity : set_markup ( ( " Capacity: %d%% " ) : format ( data.capacity ) )
quality : set_markup ( ( " Quality: %.4f%% " ) : format ( data.quality ) )
percentage_map [ data.name ] = data.capacity
else
print ( err )
end
update_virtual_battery ( )
end
end
} )
-- }}}
-- {{{ Backlight
local backlight_devices = syscontrol.backlight . enumerate ( )
local default_backlight_device
for _ , v in pairs ( backlight_devices ) do
local data = syscontrol.backlight . read_attribs ( v )
if data then
widget_map [ data.name ] = wibox.widget ( t.container ( {
{
t.article ( {
icon = beautiful [ " backlight-symbolic " ] ,
title = " Backlight " ,
} ) ,
( data.writable and t.center (
t.checkbox ( {
checked = false ,
id = " checkbox " ,
forced_height = style.article . icon_size ,
forced_width = style.article . icon_size
} ) ,
{
width = style.checkbox . width ,
height = style.checkbox . height
} )
) ,
layout = wibox.layout . fixed.horizontal ,
spacing = style.base . spacing
} ,
t.textbox ( {
markup = " Brightness: " .. tostring ( data.brightness ) ,
id = " brightness_id "
} ) ,
t.textbox ( {
markup = " Max brightness: " .. tostring ( data.max_brightness ) ,
id = " max_brightness "
} ) ,
( data.writable and t.slider ( {
minimum = data.max_brightness * 0.05 ,
maximum = data.max_brightness ,
value = tonumber ( data.brightness ) ,
id = " slider "
} ) ) ,
layout = wibox.layout . fixed.vertical
} , {
bg = style.container . bg_highlight ,
bgimage = style.container . bgimage_highlight
} ) )
if data.writable then
local w = widget_map [ data.name ]
local slider = w : get_children_by_id ( " slider " ) [ 1 ]
slider : connect_signal ( " widget::redraw_needed " , function ( self )
local value = self.value
syscontrol.backlight . set_brightness ( data , math.floor ( value ) )
end )
slider.value = tonumber ( data.brightness )
local checkbox = w : get_children_by_id ( " checkbox " ) [ 1 ]
checkbox : connect_signal ( " button::press " , function ( )
if default_backlight_device then
local check2 = widget_map [ default_backlight_device.name ]
: get_children_by_id ( " checkbox " ) [ 1 ]
2023-05-20 15:54:06 +00:00
check2.checked = false
2023-01-19 13:42:20 +00:00
end
default_backlight_device = data
2023-05-20 15:54:06 +00:00
checkbox.checked = true
2023-01-19 13:42:20 +00:00
end )
end
layout : add ( widget_map [ data.name ] )
end
end
-- Update loop
local backlight_update = gears.timer ( {
timeout = args.backlight_polling or 2 ,
autostart = true ,
callback = function ( )
for _ , v in pairs ( backlight_devices ) do
local data , err = syscontrol.backlight . read_attribs ( v )
if data then
local w = widget_map [ data.name ]
local online = w : get_children_by_id ( " brightness_id " ) [ 1 ]
online : set_markup ( " Brightness: " .. tostring ( data.brightness ) )
else
print ( err )
end
end
end
} )
-- Keybindings
root.keys ( gears.table . join (
root.keys ( ) ,
ask.k ( " :battery.brightness_up " , function ( )
if default_backlight_device then
local data = default_backlight_device
local s = widget_map [ data.name ] : get_children_by_id ( " slider " ) [ 1 ]
local value = s.value + ( data.max_brightness * 0.05 )
if value > data.max_brightness then
value = data.max_brightness
end
syscontrol.backlight . set_brightness ( data , math.floor ( value ) )
s.value = math.floor ( value )
end
end , { description = " increase brightness " , group = " widgets " } ) ,
ask.k ( " :battery.brightness_down " , function ( )
if default_backlight_device then
local data = default_backlight_device
local s = widget_map [ data.name ] : get_children_by_id ( " slider " ) [ 1 ]
local value = s.value - ( data.max_brightness * 0.05 )
if value < data.max_brightness * 0.05 then
value = data.max_brightness * 0.05
end
syscontrol.backlight . set_brightness ( data , math.floor ( value ) )
s.value = math.floor ( value )
end
end , { description = " decrease brightness " , group = " widgets " } )
) )
-- }}}
-- We don't need this widget if we don't have anything to show
local function count ( t )
local count = 0
for k , v in pairs ( t ) do
count = count + 1
end
return count
end
if count ( widget_map ) == 0 then
backlight_update : stop ( )
power_update : stop ( )
return
end
return battery_widget
end