local volume_widget = require("volume/widget") local 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.icon.image = beautiful.icons.volume.error self.widget.arc.value = 100; --self.widget.bar.value = 100; self.widget.tooltip.text = "Volume error" return end self.widget.arc.value = self.volume / 100; self.widget.tooltip.text = "Volume " .. self.volume .. "%" --self.widget.bar.value = self.volume; if (self.muted) then -- Set muted icon self.widget.icon.image = beautiful.icons.volume.mute else -- Set icon by value if self.volume > 70 then self.widget.icon.image = beautiful.icons.volume.high elseif self.volume > 40 then self.widget.icon.image = beautiful.icons.volume.medium elseif self.volume > 0 then self.widget.icon.image = beautiful.icons.volume.low elseif self.volume == 0 then self.widget.icon.image = beautiful.icons.volume.off end end end --- -- Simple actions --- function P:volume_up() if (not self.ready) or (self.volume >= 100) 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 > 100 then self.volume = 100 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 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) v:_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 v = { pa_options = args.cli_options or "", pa_sink = args.pa_sink or "", update_interval = args.update_interal or 1, 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 = volume_widget.new() -- Attach button press signals v.widget.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 ) v.widget.tooltip = awful.tooltip { objects = { v.widget.widget }, text = "System volume" } setmetatable(v, self) self.__index = 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