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

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