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.

148 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
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,args.vertical)
  40. local widget = wibox.widget(t.container({
  41. t.icon({
  42. id = "client_volume_icon",
  43. resize = true,
  44. }),
  45. t.textbox({
  46. id = "error"
  47. }),
  48. t.slider({
  49. minimum = 0,
  50. maximum = 100,
  51. id = "client_volume",
  52. value = -1
  53. }),
  54. layout = wibox.layout.fixed.horizontal
  55. }))
  56. local errorbox = widget:get_children_by_id("error")[1]
  57. local icon = widget:get_children_by_id("client_volume_icon")[1]
  58. local slider = widget:get_children_by_id("client_volume")[1]
  59. -- Local tracking value to prevent zero volume on start
  60. local touched = false
  61. -- Attach to focus change
  62. client.connect_signal("update_volume",function(c)
  63. awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
  64. local pactl_data = fastyaml(stdout)
  65. local cl
  66. for _,v in pairs(pactl_data) do
  67. if not c then return end
  68. if v:match("application.process.id = \""..tostring(c.pid).."\"") then
  69. cl = v
  70. end
  71. end
  72. if not cl then
  73. slider.visible = false
  74. errorbox.visible = true
  75. errorbox:set_markup("No sound/Not available")
  76. icon:set_image(beautiful["volume-muted-symbolic"])
  77. return
  78. end
  79. local volume = tonumber(cl:match("Volume:[^\n]-(%d*)%%"))
  80. slider.visible = true
  81. errorbox.visible = false
  82. icon:set_image(get_icon(volume))
  83. slider.value = volume
  84. touched = true
  85. end)
  86. end)
  87. client.connect_signal("focus",function(c)
  88. touched = false
  89. c:emit_signal("update_volume")
  90. end)
  91. local update_timer = gears.timer({
  92. timeout = 0.5,
  93. autostart = true,
  94. callback = function()
  95. if client.focus then
  96. client.focus:emit_signal("update_volume")
  97. end
  98. end
  99. })
  100. -- Async lock to prevent callback interference
  101. local volume_lock = false
  102. -- Function to set client volume
  103. local function volume(value)
  104. if volume_lock then return end
  105. volume_lock = true
  106. awful.spawn.easy_async("pactl list sink-inputs",function(stdout)
  107. local pactl_data = fastyaml(stdout)
  108. if not (client.focus and client.focus.pid) then
  109. volume_lock = false
  110. return
  111. end
  112. for _,v in pairs(pactl_data) do
  113. if v:match("application.process.id = \""..tostring(client.focus.pid).."\"") then
  114. local sink_id = v:match("^%s*Sink Input #(%d+)")
  115. if sink_id then
  116. print(sink_id, value)
  117. awful.spawn("pactl set-sink-input-volume "..tostring(sink_id).." "..tostring(value).."%")
  118. end
  119. end
  120. end
  121. volume_lock = false
  122. end)
  123. end
  124. -- Attach change to slider
  125. slider:connect_signal("widget::redraw_needed",function()
  126. if touched then
  127. volume(slider.value)
  128. update_timer:again()
  129. end
  130. end)
  131. root.keys(gears.table.join(
  132. root.keys(),
  133. ask.k(":client.volume_up", function()
  134. volume("+5")
  135. end,{description = "increase client volume", group = "client"}),
  136. ask.k(":client.volume_down", function()
  137. volume("-5")
  138. end,{description = "decrease client volume", group = "client"}),
  139. ask.k(":client.volume_mute", function()
  140. volume(0)
  141. end,{description = "mute client", group = "client"})
  142. ))
  143. return widget
  144. end