218 lines
4.2 KiB
Lua
Executable File
218 lines
4.2 KiB
Lua
Executable File
local widget_types = {
|
|
bar = require("classes/volume/bar_widget"),
|
|
arc = require("classes/volume/arc_widget")
|
|
}
|
|
|
|
local P = {
|
|
name = "volume"
|
|
}
|
|
P.__index = P
|
|
|
|
---
|
|
-- Internal methods
|
|
---
|
|
function P:_full_args()
|
|
-- Build complete pamixer arguments, combining sink and options.
|
|
-- Must have a leading space.
|
|
if (self.pa_sink == "") then
|
|
return " " .. self.pa_options
|
|
else
|
|
return " --sink" .. self.pa_sink .. " " .. self.pa_options
|
|
end
|
|
end
|
|
|
|
function P:_get_status()
|
|
-- Update mute status and volume.
|
|
-- Values in this table are updated.
|
|
awful.spawn.easy_async(
|
|
"pamixer --get-mute --get-volume" .. self:_full_args(),
|
|
function(stdout, stderr, exitreason, exitcode)
|
|
|
|
-- Get mute state
|
|
local muted = string.match(stdout, "(%w%w%w%w%w?) ")
|
|
self.muted = (muted == "true")
|
|
|
|
local value = string.match(stdout, "(%d?%d?%d)") -- (\d?\d?\d)\%)
|
|
|
|
if (value == nil) then
|
|
self.volume = nil
|
|
self._ready = false
|
|
else
|
|
self.volume = tonumber(string.format("% 3d", value))
|
|
self._ready = true
|
|
end
|
|
|
|
self:_update_widget()
|
|
end
|
|
)
|
|
|
|
-- This is used inside a timer, so return true to keep it running.
|
|
return true
|
|
end
|
|
|
|
|
|
|
|
function P:_update_widget()
|
|
if (not self._ready) then
|
|
self._widget:set_state("error")
|
|
self._widget:set_value(self.max_value);
|
|
self._widget:set_tooltip("Volume error");
|
|
return
|
|
end
|
|
|
|
self._widget:set_value(self.volume);
|
|
self._widget:set_tooltip("Volume " .. self.volume .. "%");
|
|
|
|
if (self.muted) then
|
|
self._widget:set_state("muted")
|
|
else
|
|
self._widget:set_state("unmuted")
|
|
end
|
|
end
|
|
|
|
---
|
|
-- Simple actions
|
|
---
|
|
function P:volume_up()
|
|
if (not self._ready) or (self.volume >= self.max_value) then
|
|
return
|
|
end
|
|
|
|
if self.muted then
|
|
self:unmute()
|
|
end
|
|
|
|
awful.spawn("pamixer --increase 5" .. self:_full_args(), false)
|
|
wrapper.sound.play("volume_up")
|
|
self.volume = self.volume + 5
|
|
if self.volume > self.max_value then
|
|
self.volume = self.max_value
|
|
end
|
|
self:_update_widget()
|
|
end
|
|
|
|
function P:volume_down()
|
|
if (not self._ready) or (self.volume <= 0) then
|
|
return
|
|
end
|
|
|
|
if self.muted then
|
|
self:unmute()
|
|
end
|
|
|
|
awful.spawn("pamixer --decrease 5" .. self:_full_args(), false)
|
|
wrapper.sound.play("volume_down")
|
|
self.volume = self.volume - 5
|
|
if self.volume < 0 then
|
|
self.volume = 0
|
|
end
|
|
self:_update_widget()
|
|
end
|
|
|
|
function P:volume_set(value)
|
|
if (not self._ready) then
|
|
return
|
|
end
|
|
|
|
if self.muted then
|
|
self:unmute()
|
|
end
|
|
|
|
if (value < 0) then
|
|
value = 0
|
|
end
|
|
|
|
if (value > self.max_value) then
|
|
value = self.max_value
|
|
end
|
|
|
|
awful.spawn("pamixer --set_volume " .. tostring(value) .. self:_full_args(), false)
|
|
self.volume = value
|
|
self:_update_widget()
|
|
end
|
|
|
|
function P:mute()
|
|
if (not self._ready) then
|
|
return
|
|
end
|
|
|
|
self.muted = true
|
|
awful.spawn("pamixer --mute" .. self:_full_args(), false)
|
|
self:_update_widget()
|
|
end
|
|
|
|
function P:unmute()
|
|
if (not self._ready) then
|
|
return
|
|
end
|
|
|
|
self.muted = false
|
|
awful.spawn("pamixer --unmute" .. self:_full_args(), false)
|
|
self:_update_widget()
|
|
end
|
|
|
|
function P:toggle_mute()
|
|
if (not self._ready) then
|
|
return
|
|
end
|
|
|
|
if self.muted then
|
|
self:unmute()
|
|
else
|
|
self:mute()
|
|
end
|
|
end
|
|
|
|
|
|
---
|
|
-- Create new volume_interface
|
|
---
|
|
function P:new(args)
|
|
-- Arguments
|
|
local v = {
|
|
pa_options = args.cli_options or "",
|
|
pa_sink = args.pa_sink or "",
|
|
update_interval = args.update_interal or 5,
|
|
max_value = args.max_value or 100,
|
|
widget_type = args.widget_type or "arc",
|
|
|
|
|
|
_ready = false, -- is all the information in this class up-to-date?
|
|
-- if this is false, ui will show an error and most methods will
|
|
-- do nothing. Updated in _get_status()
|
|
}
|
|
|
|
-- Create widget for this volume interface
|
|
v._widget = widget_types[v.widget_type]:new()
|
|
v.widget = v._widget.widget
|
|
|
|
-- Attach button press signals
|
|
v.widget:connect_signal("button::press",
|
|
function(_, _, _, button, mods)
|
|
if (button == 3) then -- Right-click
|
|
v:toggle_mute()
|
|
elseif (button == 4) then -- Scroll up
|
|
v:volume_up()
|
|
elseif (button == 5) then -- Scroll down
|
|
v:volume_down()
|
|
end
|
|
end
|
|
)
|
|
|
|
setmetatable(v, self)
|
|
|
|
-- This timer keeps mute and volume status up-to-date.
|
|
v.timer = gears.timer {
|
|
timeout = v.update_interval,
|
|
call_now = true,
|
|
autostart = true,
|
|
callback = function()
|
|
v:_get_status()
|
|
end
|
|
}
|
|
|
|
return v
|
|
end
|
|
|
|
return P
|