]> 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:

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