-- 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 . -- 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) -- Get an icon from a cumulative total of battery percentages and current charging state 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) 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)) local battery_widget do -- create battery widget local style = awmtk2.create_style("battery", awmtk2.generic.status_widget,args.style) 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 -- "Virtual" here means a battery that displays the state of a cumulative total of all attached batteries (as if there are any devices that even have more than 1 battery) 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] check2.checked = true end default_backlight_device = data 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