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

53bfc3ba328a7794181878122cfd12ddf7226404
[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
47     pulsebar.colors              = args.colors or pulsebar.colors
48     pulsebar.followtag           = args.followtag or false
49     pulsebar.notification_preset = args.notification_preset
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             font = "Monospace 10"
56         }
57     end
58
59     pulsebar.bar = wibox.widget {
60         color            = pulsebar.colors.unmute,
61         background_color = pulsebar.colors.background,
62         forced_height    = height,
63         forced_width     = width,
64         margins          = margins,
65         paddings         = paddings,
66         ticks            = ticks,
67         ticks_size       = ticks_size,
68         widget           = wibox.widget.progressbar,
69     }
70
71     pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
72
73     function pulsebar.update(callback)
74         helpers.async({ awful.util.shell, "-c", type(pulsebar.cmd) == "string" and pulsebar.cmd or pulsebar.cmd() },
75         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                 muted  = string.match(s, "muted: (%S+)") or "N/A"
80             }
81
82             pulsebar.device = volume_now.index
83
84             local ch = 1
85             volume_now.channel = {}
86             for v in string.gmatch(s, ":.-(%d+)%%") do
87               volume_now.channel[ch] = v
88               ch = ch + 1
89             end
90
91             volume_now.left  = volume_now.channel[1] or "N/A"
92             volume_now.right = volume_now.channel[2] or "N/A"
93
94             local volu = volume_now.left
95             local mute = volume_now.muted
96
97             if volu:match("N/A") or mute:match("N/A") then return end
98
99             if volu ~= pulsebar._current_level or mute ~= pulsebar._mute then
100                 pulsebar._current_level = tonumber(volu)
101                 pulsebar.bar:set_value(pulsebar._current_level / 100)
102                 if pulsebar._current_level == 0 or mute == "yes" then
103                     pulsebar._mute = mute
104                     pulsebar.tooltip:set_text ("[muted]")
105                     pulsebar.bar.color = pulsebar.colors.mute
106                 else
107                     pulsebar._mute = "no"
108                     pulsebar.tooltip:set_text(string.format("%s %s: %s", pulsebar.devicetype, pulsebar.device, volu))
109                     pulsebar.bar.color = pulsebar.colors.unmute
110                 end
111
112                 settings()
113
114                 if type(callback) == "function" then callback() end
115             end
116         end)
117     end
118
119     function pulsebar.notify()
120         pulsebar.update(function()
121             local preset = pulsebar.notification_preset
122
123             preset.title = string.format("%s %s - %s%%", pulsebar.devicetype, pulsebar.device, pulsebar._current_level)
124
125             if pulsebar._mute == "yes" then
126                 preset.title = preset.title .. " muted"
127             end
128
129             -- tot is the maximum number of ticks to display in the notification
130             -- fallback: default horizontal wibox height
131             local wib, tot = awful.screen.focused().mywibox, 20
132
133             -- if we can grab mywibox, tot is defined as its height if
134             -- horizontal, or width otherwise
135             if wib then
136                 if wib.position == "left" or wib.position == "right" then
137                     tot = wib.width
138                 else
139                     tot = wib.height
140                 end
141             end
142
143             int = math.modf((pulsebar._current_level / 100) * tot)
144             preset.text = string.format(
145                 "%s%s%s%s",
146                 tick_pre,
147                 string.rep(tick, int),
148                 string.rep(" ", tot - int),
149                 tick_post
150             )
151
152             if pulsebar.followtag then preset.screen = awful.screen.focused() end
153
154             if not pulsebar.notification then
155                 pulsebar.notification = naughty.notify {
156                     preset  = preset,
157                     destroy = function() pulsebar.notification = nil end
158                 }
159             else
160                 naughty.replace_text(pulsebar.notification, preset.title, preset.text)
161             end
162         end)
163     end
164
165     helpers.newtimer(string.format("pulsebar-%s-%s", pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update)
166
167     return pulsebar
168 end
169
170 return factory