]> git.madduck.net Git - etc/awesome.git/blob - widget/pulsebar.lua

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

f97b2d170c9c82f4a877e9162e8104f315d3da24
[etc/awesome.git] / widget / pulsebar.lua
1 --[[
2
3      Licensed under GNU General Public License v2
4       * (c) 2013, Luke Bonham
5       * (c) 2013, Rman
6
7 --]]
8
9 local helpers        = require("lain.helpers")
10 local awful          = require("awful")
11 local naughty        = require("naughty")
12 local wibox          = require("wibox")
13 local math           = { modf   = math.modf }
14 local string         = { format = string.format,
15                          match  = string.match,
16                          gmatch = string.gmatch,
17                          rep    = string.rep }
18 local type, tonumber = type, tonumber
19
20 -- Pulseaudio volume bar
21 -- lain.widget.pulsebar
22
23 local function factory(args)
24     local pulsebar = {
25         colors = {
26             background = "#000000",
27             mute       = "#EB8F8F",
28             unmute     = "#A4CE8A"
29         },
30
31         _current_level = 0,
32         _mute          = "no",
33     }
34
35     local args       = args or {}
36     local timeout    = args.timeout or 5
37     local settings   = args.settings or function() end
38     local width      = args.width or 63
39     local height     = args.heigth or 1
40     local ticks      = args.ticks or false
41     local ticks_size = args.ticks_size or 7
42     local scallback  = args.scallback
43
44     pulsebar.cmd                 = args.cmd or "pacmd list-sinks | sed -n -e '0,/*/d' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
45     pulsebar.sink                = args.sink or 0 -- Legacy, does nothing
46     pulsebar.colors              = args.colors or pulsebar.colors
47     pulsebar.followtag           = args.followtag or false
48     pulsebar.notification_preset = args.notification_preset
49     pulsebar.device              = "N/A"
50     pulsebar.devicetype          = args.devicetype or "sink"
51     pulsebar.cmd                 = args.cmd or "pacmd list-" .. pulsebar.devicetype .. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
52
53     if not pulsebar.notification_preset then
54         pulsebar.notification_preset      = {}
55         pulsebar.notification_preset.font = "Monospace 10"
56     end
57
58     pulsebar.bar = wibox.widget {
59         forced_height    = height,
60         forced_width     = width,
61         color            = pulsebar.colors.unmute,
62         background_color = pulsebar.colors.background,
63         margins          = 1,
64         paddings         = 1,
65         ticks            = ticks,
66         ticks_size       = ticks_size,
67         widget           = wibox.widget.progressbar,
68     }
69
70     pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
71
72     function pulsebar.update(callback)
73         if scallback then pulsebar.cmd = scallback() end
74
75         helpers.async({ awful.util.shell, "-c", pulsebar.cmd }, function(s)
76             volume_now = {
77                 index = string.match(s, "index: (%S+)") or "N/A",
78                 device = string.match(s, "device.string = \"(%S+)\"") or "N/A",
79                 sink   = device, -- legacy API
80                 muted = string.match(s, "muted: (%S+)") or "N/A"
81             }
82
83             pulsebar.device = volume_now.index
84
85             local ch = 1
86             volume_now.channel = {}
87             for v in string.gmatch(s, ":.-(%d+)%%") do
88               volume_now.channel[ch] = v
89               ch = ch + 1
90             end
91
92             volume_now.left  = volume_now.channel[1] or "N/A"
93             volume_now.right = volume_now.channel[2] or "N/A"
94
95             local volu = volume_now.left
96             local mute = volume_now.muted
97
98             if volu:match("N/A") or mute:match("N/A") then return end
99
100             if volu ~= pulsebar._current_level or mute ~= pulsebar._mute then
101                 pulsebar._current_level = tonumber(volu)
102                 pulsebar.bar:set_value(pulsebar._current_level / 100)
103                 if pulsebar._current_level == 0 or mute == "yes" then
104                     pulsebar._mute = mute
105                     pulsebar.tooltip:set_text ("[Muted]")
106                     pulsebar.bar.color = pulsebar.colors.mute
107                 else
108                     pulsebar._mute = "no"
109                     pulsebar.tooltip:set_text(string.format("%s: %s", pulsebar.device, volu))
110                     pulsebar.bar.color = pulsebar.colors.unmute
111                 end
112
113                 settings()
114
115                 if type(callback) == "function" then callback() end
116             end
117         end)
118     end
119
120     function pulsebar.notify()
121         pulsebar.update(function()
122             local preset = pulsebar.notification_preset
123
124             preset.title = string.format("Sink %s - %s%%", pulsebar.device, pulsebar._current_level)
125
126             if pulsebar._mute == "yes" then
127                 preset.title = preset.title .. " Muted"
128             end
129
130             int = math.modf((pulsebar._current_level / 100) * awful.screen.focused().mywibox.height)
131             preset.text = string.format("[%s%s]", string.rep("|", int),
132                           string.rep(" ", awful.screen.focused().mywibox.height - int))
133
134             if pulsebar.followtag then preset.screen = awful.screen.focused() end
135
136             if not pulsebar.notification then
137                 pulsebar.notification = naughty.notify {
138                     preset  = preset,
139                     destroy = function() pulsebar.notification = nil end
140                 }
141             else
142                 naughty.replace_text(pulsebar.notification, preset.title, preset.text)
143             end
144         end)
145     end
146
147     helpers.newtimer(string.format("pulsebar-%s", pulsebar.sink), timeout, pulsebar.update)
148
149     return pulsebar
150 end
151
152 return factory