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

widget.temp: reset path to /sys/devices; closes #441
[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 local math     = math
14 local string   = string
15 local type     = type
16 local tonumber = tonumber
17
18 -- PulseAudio volume bar
19 -- lain.widget.pulsebar
20
21 local function factory(args)
22     local pulsebar = {
23         colors = {
24             background = "#000000",
25             mute       = "#EB8F8F",
26             unmute     = "#A4CE8A"
27         },
28
29         _current_level = 0,
30         _mute          = "no",
31         device         = "N/A"
32     }
33
34     local args       = args or {}
35     local timeout    = args.timeout or 5
36     local settings   = args.settings or function() end
37     local width      = args.width or 63
38     local height     = args.height or 1
39     local margins    = args.margins or 1
40     local paddings   = args.paddings or 1
41     local ticks      = args.ticks or false
42     local ticks_size = args.ticks_size or 7
43     local tick       = args.tick or "|"
44     local tick_pre   = args.tick_pre or "["
45     local tick_post  = args.tick_post or "]"
46     local tick_none  = args.tick_none or " "
47
48     pulsebar.colors              = args.colors or pulsebar.colors
49     pulsebar.followtag           = args.followtag or false
50     pulsebar.notification_preset = args.notification_preset
51     pulsebar.devicetype          = args.devicetype or "sink"
52     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'"
53
54     if not pulsebar.notification_preset then
55         pulsebar.notification_preset = {
56             font = "Monospace 10"
57         }
58     end
59
60     pulsebar.bar = wibox.widget {
61         color            = pulsebar.colors.unmute,
62         background_color = pulsebar.colors.background,
63         forced_height    = height,
64         forced_width     = width,
65         margins          = margins,
66         paddings         = paddings,
67         ticks            = ticks,
68         ticks_size       = ticks_size,
69         widget           = wibox.widget.progressbar,
70     }
71
72     pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
73
74     function pulsebar.update(callback)
75         helpers.async({ awful.util.shell, "-c", type(pulsebar.cmd) == "string" and pulsebar.cmd or pulsebar.cmd() },
76         function(s)
77             volume_now = {
78                 index  = string.match(s, "index: (%S+)") or "N/A",
79                 device = string.match(s, "device.string = \"(%S+)\"") or "N/A",
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: %s", pulsebar.devicetype, 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("%s %s - %s%%", pulsebar.devicetype, pulsebar.device, pulsebar._current_level)
125
126             if pulsebar._mute == "yes" then
127                 preset.title = preset.title .. " muted"
128             end
129
130             -- tot is the maximum number of ticks to display in the notification
131             -- fallback: default horizontal wibox height
132             local wib, tot = awful.screen.focused().mywibox, 20
133
134             -- if we can grab mywibox, tot is defined as its height if
135             -- horizontal, or width otherwise
136             if wib then
137                 if wib.position == "left" or wib.position == "right" then
138                     tot = wib.width
139                 else
140                     tot = wib.height
141                 end
142             end
143
144             int = math.modf((pulsebar._current_level / 100) * tot)
145             preset.text = string.format(
146                 "%s%s%s%s",
147                 tick_pre,
148                 string.rep(tick, int),
149                 string.rep(tick_none, tot - int),
150                 tick_post
151             )
152
153             if pulsebar.followtag then preset.screen = awful.screen.focused() end
154
155             if not pulsebar.notification then
156                 pulsebar.notification = naughty.notify {
157                     preset  = preset,
158                     destroy = function() pulsebar.notification = nil end
159                 }
160             else
161                 naughty.replace_text(pulsebar.notification, preset.title, preset.text)
162             end
163         end)
164     end
165
166     helpers.newtimer(string.format("pulsebar-%s-%s", pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update)
167
168     return pulsebar
169 end
170
171 return factory