Reno is the second iteration of the AWMTK-powered AwesomeWM config.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
13 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. -- This file is part of Reno desktop.
  2. --
  3. -- 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.
  4. --
  5. -- 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.
  6. --
  7. -- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
  8. -- Generic battery widget with support for multiple power sources, backlights and backlight control
  9. local awful = require("awful")
  10. local beautiful = require("beautiful")
  11. local gears = require("gears")
  12. local wibox = require("wibox")
  13. local awmtk2 = require("awmtk2")
  14. local syscontrol = require("syscontrol")
  15. local ask = require("asckey")
  16. local function get_virtual_icon(data)
  17. -- Get an icon from a cumulative total of battery percentages and current charging state
  18. local count = 0
  19. local cumulative = 0
  20. local name = "battery-"
  21. for k,v in pairs(data) do
  22. if type(v) == "number" then
  23. cumulative = cumulative + v
  24. count = count + 1
  25. end
  26. end
  27. local percentage = math.floor((cumulative/(count*100))*100)
  28. if percentage < 15 then
  29. name = name.."caution-"
  30. elseif percentage < 30 then
  31. name = name.."low-"
  32. elseif percentage < 60 then
  33. name = name.."good-"
  34. else
  35. name = name.."full-"
  36. end
  37. if data["charge"] then
  38. name = name.."charging-"
  39. end
  40. return beautiful[name.."symbolic"],percentage
  41. end
  42. return function(args)
  43. local style = awmtk2.create_style("battery",
  44. awmtk2.generic.popup,args.style)
  45. local templates = awmtk2.create_template_lib("battery",awmtk2.templates,args.templates)
  46. local t = awmtk2.build_templates(templates,style)
  47. -- set up popup layout
  48. local layout = wibox.widget({
  49. layout = wibox.layout.fixed.vertical,
  50. spacing = style.base.spacing
  51. })
  52. -- create popup
  53. local popup = awful.popup(t.popup(layout))
  54. local battery_widget
  55. do -- create battery widget
  56. local style = awmtk2.create_style("battery",
  57. awmtk2.generic.status_widget,args.style)
  58. local templates = awmtk2.create_template_lib("battery",awmtk2.templates,args.templates)
  59. local t = awmtk2.build_templates(templates,style)
  60. battery_widget = wibox.widget(t.button({
  61. {
  62. image = beautiful["battery-missing-symbolic"],
  63. resize = true,
  64. widget = wibox.widget.imagebox,
  65. id = "virtual_id"
  66. },
  67. (args.percentage and {
  68. markup = "0%",
  69. id = "percentage_id",
  70. widget = wibox.widget.textbox
  71. }),
  72. layout = wibox.layout.fixed.horizontal,
  73. spacing = style.base.spacing
  74. }))
  75. -- make it possible to press the button and make it toggle the popup
  76. battery_widget:connect_signal("button::press",style.button.onpress)
  77. battery_widget:connect_signal("button::release",style.button.onrelease)
  78. battery_widget:connect_signal("button::press",function(self,x,y,button)
  79. if button == 1 then
  80. popup.visible = (not popup.visible)
  81. if popup.visible then
  82. popup:move_next_to(mouse.current_widget_geometry)
  83. end
  84. end
  85. end)
  86. end
  87. -- map widgets to their names to make it easier to update separate components
  88. local widget_map = {}
  89. -- also map current charge state of every device to get the icon for the tray
  90. local percentage_map = {}
  91. -- {{{ Power supply devices
  92. local power_devices = syscontrol.power_supply.enumerate()
  93. for _,device in pairs(power_devices) do
  94. local data = syscontrol.power_supply.read_attribs(device)
  95. if data.type == "Battery" then
  96. widget_map[data.name] = wibox.widget(t.container({
  97. t.article({
  98. icon = get_virtual_icon({
  99. data.capacity,
  100. charge = data.charging
  101. }),
  102. icon_id = "battery_icon",
  103. title = "Battery ("..data.model..")",
  104. }),
  105. t.textbox({
  106. markup = ("Capacity: %d%%"):format(data.capacity),
  107. id = "capacity_id"
  108. }),
  109. t.textbox({
  110. markup = ("Quality: %.4f%%"):format(data.quality),
  111. id = "quality_id",
  112. }),
  113. layout = wibox.layout.fixed.vertical
  114. },{
  115. bg = style.container.bg_highlight,
  116. bgimage = style.container.bgimage_highlight
  117. }))
  118. layout:add(widget_map[data.name])
  119. percentage_map[data.name] = data.capacity
  120. elseif data.type == "Mains" then
  121. widget_map[data.name] = wibox.widget(t.container({
  122. t.article({
  123. icon = beautiful["ac-adapter-symbolic"],
  124. title = "Power supply",
  125. }),
  126. t.textbox({
  127. markup = "Powered: "..tostring(data.online),
  128. id = "online_id",
  129. }),
  130. layout = wibox.layout.fixed.vertical
  131. },{
  132. bg = style.container.bg_highlight,
  133. bgimage = style.container.bgimage_highlight
  134. }))
  135. layout:add(widget_map[data.name])
  136. percentage_map["charge"] = data.online
  137. end
  138. end
  139. -- "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)
  140. local function update_virtual_battery()
  141. local icon = battery_widget:get_children_by_id("virtual_id")[1]
  142. local percentage = battery_widget:get_children_by_id("percentage_id")[1]
  143. local capacity
  144. icon.image,capacity = get_virtual_icon(percentage_map)
  145. if percentage then
  146. percentage:set_markup(tostring(capacity).."%")
  147. end
  148. end
  149. update_virtual_battery()
  150. -- Update loop
  151. local power_update = gears.timer({
  152. timeout = args.power_polling or 2,
  153. autostart = true,
  154. callback = function()
  155. for k,v in pairs(power_devices) do
  156. local data,err = syscontrol.power_supply.read_attribs(v)
  157. if data and data.type == "Mains" then
  158. local w = widget_map[data.name]
  159. local online = w:get_children_by_id("online_id")[1]
  160. online:set_markup("Powered: "..tostring(data.online))
  161. percentage_map["charge"] = data.online
  162. elseif data and data.type == "Battery" then
  163. local w = widget_map[data.name]
  164. local icon = w:get_children_by_id("battery_icon")[1]
  165. local capacity = w:get_children_by_id("capacity_id")[1]
  166. local quality = w:get_children_by_id("quality_id")[1]
  167. icon.image = get_virtual_icon({
  168. data.capacity,
  169. charge = data.charging
  170. })
  171. capacity:set_markup(("Capacity: %d%%"):format(data.capacity))
  172. quality:set_markup(("Quality: %.4f%%"):format(data.quality))
  173. percentage_map[data.name] = data.capacity
  174. else
  175. print(err)
  176. end
  177. update_virtual_battery()
  178. end
  179. end
  180. })
  181. -- }}}
  182. -- {{{ Backlight
  183. local backlight_devices = syscontrol.backlight.enumerate()
  184. local default_backlight_device
  185. for k,v in pairs(backlight_devices) do
  186. local data = syscontrol.backlight.read_attribs(v)
  187. if data then
  188. widget_map[data.name] = wibox.widget(t.container({
  189. {
  190. t.article({
  191. icon = beautiful["backlight-symbolic"],
  192. title = "Backlight",
  193. }),
  194. (data.writable and t.checkbox({
  195. checked = true,
  196. id = "checkbox",
  197. forced_height = style.article.icon_size,
  198. forced_width = style.article.icon_size
  199. })),
  200. layout = wibox.layout.fixed.horizontal,
  201. spacing = style.base.spacing
  202. },
  203. t.textbox({
  204. markup = "Brightness: "..tostring(data.brightness),
  205. id = "brightness_id"
  206. }),
  207. t.textbox({
  208. markup = "Max brightness: "..tostring(data.max_brightness),
  209. id = "max_brightness"
  210. }),
  211. (data.writable and t.slider({
  212. minimum = data.max_brightness*0.05,
  213. maximum = data.max_brightness,
  214. value = tonumber(data.brightness),
  215. id = "slider"
  216. })),
  217. layout = wibox.layout.fixed.vertical
  218. },{
  219. bg = style.container.bg_highlight,
  220. bgimage = style.container.bgimage_highlight
  221. }))
  222. if data.writable then
  223. local w = widget_map[data.name]
  224. local slider = w:get_children_by_id("slider")[1]
  225. slider:connect_signal("widget::redraw_needed",function(self)
  226. local value = self.value
  227. syscontrol.backlight.set_brightness(data,math.floor(value))
  228. end)
  229. slider.value = tonumber(data.brightness)
  230. local checkbox = w:get_children_by_id("checkbox")[1]
  231. checkbox:connect_signal("button::press",function()
  232. if default_backlight_device then
  233. local check2 = widget_map[default_backlight_device.name]
  234. :get_children_by_id("checkbox")[1]
  235. check2.checked = false
  236. end
  237. default_backlight_device = data
  238. end)
  239. end
  240. layout:add(widget_map[data.name])
  241. end
  242. end
  243. -- Update loop
  244. local backlight_update = gears.timer({
  245. timeout = args.backlight_polling or 2,
  246. autostart = true,
  247. callback = function()
  248. for k,v in pairs(backlight_devices) do
  249. local data,err = syscontrol.backlight.read_attribs(v)
  250. if data then
  251. local w = widget_map[data.name]
  252. local online = w:get_children_by_id("brightness_id")[1]
  253. online:set_markup("Brightness: "..tostring(data.brightness))
  254. else
  255. print(err)
  256. end
  257. end
  258. end
  259. })
  260. -- Keybindings
  261. root.keys(gears.table.join(
  262. root.keys(),
  263. ask.k(":battery.brightness_up",function()
  264. if default_backlight_device then
  265. local data = default_backlight_device
  266. local s = widget_map[data.name]:get_children_by_id("slider")[1]
  267. local value = s.value+(data.max_brightness*0.05)
  268. if value > data.max_brightness then
  269. value = data.max_brightness
  270. end
  271. syscontrol.backlight.set_brightness(data,math.floor(value))
  272. s.value = math.floor(value)
  273. end
  274. end,{description="increase brightness", group = "widgets"}),
  275. ask.k(":battery.brightness_down",function()
  276. if default_backlight_device then
  277. local data = default_backlight_device
  278. local s = widget_map[data.name]:get_children_by_id("slider")[1]
  279. local value = s.value-(data.max_brightness*0.05)
  280. if value < data.max_brightness*0.05 then
  281. value = data.max_brightness*0.05
  282. end
  283. syscontrol.backlight.set_brightness(data,math.floor(value))
  284. s.value = math.floor(value)
  285. end
  286. end,{description="decrease brightness", group = "widgets"})
  287. ))
  288. -- }}}
  289. -- We don't need this widget if we don't have anything to show
  290. local function count(t)
  291. local count = 0
  292. for k,v in pairs(t) do
  293. count = count + 1
  294. end
  295. return count
  296. end
  297. if count(widget_map) == 0 then
  298. backlight_update:stop()
  299. power_update:stop()
  300. return
  301. end
  302. return battery_widget
  303. end