-- 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 . -- Pulseaudio per-client volume setting local awful = require("awful") local gears = require("gears") local wibox = require("wibox") local awmtk2 = require("awmtk2") local fastyaml = require("parsers").fast_split_yaml local beautiful = require("beautiful") local ask = require("asckey") local pactl_data = {} local test_pactl = os.execute("pactl --version") local result = test_pactl if _VERSION:match("5.1") then result = (test_pactl == 0) end if not result then return end local function get_icon(percent) if percent >= 66 then return beautiful["volume-high-symbolic"] elseif percent >= 33 then return beautiful["volume-medium-symbolic"] elseif percent > 0 then return beautiful["volume-low-symbolic"] else return beautiful["volume-muted-symbolic"] end end return function(args) local style = awmtk2.create_style("client_volume", awmtk2.generic.oneline_widget, args.style) local templates = awmtk2.create_template_lib("client_volume",awmtk2.templates,args.templates) local t = awmtk2.build_templates(templates,style) local widget = wibox.widget(t.container({ t.center({ id = "client_volume_icon", widget = wibox.widget.imagebox }), t.textbox({ id = "error" }), t.slider({ minimum = 0, maximum = 100, id = "client_volume", value = -1 }), layout = wibox.layout.fixed.horizontal })) local errorbox = widget:get_children_by_id("error")[1] local icon = widget:get_children_by_id("client_volume_icon")[1] local slider = widget:get_children_by_id("client_volume")[1] -- Local tracking value to prevent zero volume on start local slider_touched = false -- Get initial pactl data awful.spawn.easy_async("pactl list sink-inputs",function(stdout) local pactl_data = fastyaml(stdout) end) -- Attach to focus change client.connect_signal("update_volume",function(c) awful.spawn.easy_async("pactl list sink-inputs",function(stdout) local pactl_data = fastyaml(stdout) local cl for k,v in pairs(pactl_data) do if not c then return end if v:match("application.process.id = \""..tostring(c.pid).."\"") then cl = v end end if not cl then slider.visible = false errorbox.visible = true errorbox:set_markup("No sound/Not available") icon:set_image(beautiful["volume-muted-symbolic"]) return end local volume = tonumber(cl:match("Volume:[^\n]-(%d*)%%")) slider.visible = true errorbox.visible = false icon:set_image(get_icon(volume)) slider.value = volume touched = true end) end) client.connect_signal("focus",function(c) touched = false c:emit_signal("update_volume") end) local update_timer = gears.timer({ timeout = 0.5, autostart = true, callback = function() if client.focus then client.focus:emit_signal("update_volume") end end }) -- Async lock to prevent callback interference local volume_lock = false -- Function to set client volume local function volume(volume) if volume_lock then return end volume_lock = true awful.spawn.easy_async("pactl list sink-inputs",function(stdout) local pactl_data = fastyaml(stdout) local cl = {} if not (client.focus and client.focus.pid) then volume_lock = false return end for k,v in pairs(pactl_data) do if v:match("application.process.id = \""..tostring(client.focus.pid).."\"") then local sink_id = v:match("^%s*Sink Input #(%d+)") if sink_id then print(sink_id, volume) awful.spawn("pactl set-sink-input-volume "..tostring(sink_id).." "..tostring(volume).."%") end end end volume_lock = false end) end -- Attach change to slider slider:connect_signal("widget::redraw_needed",function(widget) if touched then volume(slider.value) update_timer:again() end end) root.keys(gears.table.join( root.keys(), ask.k(":client.volume_up", function() volume("+5") end,{description = "increase client volume", group = "client"}), ask.k(":client.volume_down", function() volume("-5") end,{description = "decrease client volume", group = "client"}), ask.k(":client.volume_mute", function() volume(0) end,{description = "mute client", group = "client"}) )) return widget end