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.

149 lines
5.4 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
  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. -- Pulseaudio per-client volume setting
  9. local awful = require("awful")
  10. local gears = require("gears")
  11. local wibox = require("wibox")
  12. local awmtk2 = require("awmtk2")
  13. local fastyaml = require("parsers").fast_split_yaml
  14. local beautiful = require("beautiful")
  15. local ask = require("asckey")
  16. local test_pactl = os.execute("pactl --version")
  17. local result = test_pactl
  18. if _VERSION:match("5.1") then
  19. result = (test_pactl == 0)
  20. end
  21. if not result then
  22. return
  23. end
  24. local function get_icon(percent)
  25. if percent >= 66 then
  26. return beautiful["volume-high-symbolic"]
  27. elseif percent >= 33 then
  28. return beautiful["volume-medium-symbolic"]
  29. elseif percent > 0 then
  30. return beautiful["volume-low-symbolic"]
  31. else
  32. return beautiful["volume-muted-symbolic"]
  33. end
  34. end
  35. return function(args)
  36. local style = awmtk2.create_style("client_volume",
  37. awmtk2.generic.oneline_widget, args.style)
  38. local templates = awmtk2.create_template_lib("client_volume",awmtk2.templates,args.templates)
  39. local t = awmtk2.build_templates(templates,style)
  40. local widget = wibox.widget(t.container({
  41. t.center({
  42. id = "client_volume_icon",
  43. resize = true,
  44. widget = wibox.widget.imagebox
  45. }),
  46. t.textbox({
  47. id = "error"
  48. }),
  49. t.slider({
  50. minimum = 0,
  51. maximum = 100,
  52. id = "client_volume",
  53. value = -1
  54. }),
  55. layout = wibox.layout.fixed.horizontal
  56. }))
  57. local errorbox = widget:get_children_by_id("error")[1]
  58. local icon = widget:get_children_by_id("client_volume_icon")[1]
  59. local slider = widget:get_children_by_id("client_volume")[1]
  60. -- Local tracking value to prevent zero volume on start
  61. local touched = false
  62. -- Attach to focus change
  63. client.connect_signal("update_volume",function(c)
  64. awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
  65. local pactl_data = fastyaml(stdout)
  66. local cl
  67. for k,v in pairs(pactl_data) do
  68. if not c then return end
  69. if v:match("application.process.id = \""..tostring(c.pid).."\"") then
  70. cl = v
  71. end
  72. end
  73. if not cl then
  74. slider.visible = false
  75. errorbox.visible = true
  76. errorbox:set_markup("No sound/Not available")
  77. icon:set_image(beautiful["volume-muted-symbolic"])
  78. return
  79. end
  80. local volume = tonumber(cl:match("Volume:[^\n]-(%d*)%%"))
  81. slider.visible = true
  82. errorbox.visible = false
  83. icon:set_image(get_icon(volume))
  84. slider.value = volume
  85. touched = true
  86. end)
  87. end)
  88. client.connect_signal("focus",function(c)
  89. touched = false
  90. c:emit_signal("update_volume")
  91. end)
  92. local update_timer = gears.timer({
  93. timeout = 0.5,
  94. autostart = true,
  95. callback = function()
  96. if client.focus then
  97. client.focus:emit_signal("update_volume")
  98. end
  99. end
  100. })
  101. -- Async lock to prevent callback interference
  102. local volume_lock = false
  103. -- Function to set client volume
  104. local function volume(value)
  105. if volume_lock then return end
  106. volume_lock = true
  107. awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
  108. local pactl_data = fastyaml(stdout)
  109. if not (client.focus and client.focus.pid) then
  110. volume_lock = false
  111. return
  112. end
  113. for _,v in pairs(pactl_data) do
  114. if v:match("application.process.id = \""..tostring(client.focus.pid).."\"") then
  115. local sink_id = v:match("^%s*Sink Input #(%d+)")
  116. if sink_id then
  117. print(sink_id, value)
  118. awful.spawn("pactl set-sink-input-volume "..tostring(sink_id).." "..tostring(value).."%")
  119. end
  120. end
  121. end
  122. volume_lock = false
  123. end)
  124. end
  125. -- Attach change to slider
  126. slider:connect_signal("widget::redraw_needed",function()
  127. if touched then
  128. volume(slider.value)
  129. update_timer:again()
  130. end
  131. end)
  132. root.keys(gears.table.join(
  133. root.keys(),
  134. ask.k(":client.volume_up", function()
  135. volume("+5")
  136. end,{description = "increase client volume", group = "client"}),
  137. ask.k(":client.volume_down", function()
  138. volume("-5")
  139. end,{description = "decrease client volume", group = "client"}),
  140. ask.k(":client.volume_mute", function()
  141. volume(0)
  142. end,{description = "mute client", group = "client"})
  143. ))
  144. return widget
  145. end