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:

util.markup: fixed typos
[etc/awesome.git] / widget / alsabar.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                          rep    = string.rep }
17 local type, tonumber = type, tonumber
18
19 -- ALSA volume bar
20 -- lain.widget.alsabar
21
22 local function factory(args)
23     local alsabar = {
24         colors = {
25             background = "#000000",
26             mute       = "#EB8F8F",
27             unmute     = "#A4CE8A"
28         },
29
30         _current_level = 0,
31         _playback      = "off"
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 step       = args.step or '5%'
44
45     alsabar.cmd                 = args.cmd or "amixer"
46     alsabar.channel             = args.channel or "Master"
47     alsabar.togglechannel       = args.togglechannel
48     alsabar.colors              = args.colors or alsabar.colors
49     alsabar.followtag           = args.followtag or false
50     alsabar.notification_preset = args.notification_preset
51
52     if not alsabar.notification_preset then
53         alsabar.notification_preset      = {}
54         alsabar.notification_preset.font = "Monospace 10"
55     end
56
57     local format_get_cmd = string.format("%s get %s", alsabar.cmd, alsabar.channel)
58     local format_inc_cmd = string.format("%s sset %s %s+", alsabar.cmd, alsabar.channel, step)
59     local format_dec_cmd = string.format("%s sset %s %s-" , alsabar.cmd, alsabar.channel, step)
60     local format_tog_cmd = string.format("%s sset %s toggle", alsabar.cmd, alsabar.channel)
61
62     if alsabar.togglechannel then
63         format_get_cmd = { awful.util.shell, "-c", string.format("%s get %s; %s get %s",
64         alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel) }
65     end
66
67     alsabar.bar = wibox.widget {
68         forced_height    = height,
69         forced_width     = width,
70         color            = alsabar.colors.unmute,
71         background_color = alsabar.colors.background,
72         margins          = margins,
73         paddings         = paddings,
74         ticks            = ticks,
75         ticks_size       = ticks_size,
76         widget           = wibox.widget.progressbar
77     }
78
79     alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
80
81     function alsabar.update(callback)
82         helpers.async(format_get_cmd, function(mixer)
83             local vol, playback = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
84
85             if not vol or not playback then return end
86
87             if vol ~= alsabar._current_level or playback ~= alsabar._playback then
88                 alsabar._current_level = tonumber(vol)
89                 alsabar.bar:set_value(alsabar._current_level / 100)
90                 if alsabar._current_level == 0 or playback == "off" then
91                     alsabar._playback = playback
92                     alsabar.tooltip:set_text("[Muted]")
93                     alsabar.bar.color = alsabar.colors.mute
94                 else
95                     alsabar._playback = "on"
96                     alsabar.tooltip:set_text(string.format("%s: %s", alsabar.channel, vol))
97                     alsabar.bar.color = alsabar.colors.unmute
98                 end
99
100                 volume_now = {
101                     level  = alsabar._current_level,
102                     status = alsabar._playback
103                 }
104
105                 settings()
106
107                 if type(callback) == "function" then callback() end
108             end
109         end)
110     end
111
112     function alsabar.notify()
113         alsabar.update(function()
114             local preset = alsabar.notification_preset
115
116             preset.title = string.format("%s - %s%%", alsabar.channel, alsabar._current_level)
117
118             if alsabar._playback == "off" then
119                 preset.title = preset.title .. " Muted"
120             end
121
122             -- tot is the maximum number of ticks to display in the notification
123             -- fallback: default horizontal wibox height
124             local wib, tot = awful.screen.focused().mywibox, 20
125
126             -- if we can grab mywibox, tot is defined as its height if
127             -- horizontal, or width otherwise
128             if wib then
129                 if wib.position == "left" or wib.position == "right" then
130                     tot = wib.width
131                 else
132                     tot = wib.height
133                 end
134             end
135
136             int = math.modf((alsabar._current_level / 100) * tot)
137             preset.text = string.format("[%s%s]", string.rep("|", int),
138                           string.rep(" ", tot - int))
139
140             if alsabar.followtag then preset.screen = awful.screen.focused() end
141
142             if not alsabar.notification then
143                 alsabar.notification = naughty.notify {
144                     preset  = preset,
145                     destroy = function() alsabar.notification = nil end
146                 }
147             else
148                 naughty.replace_text(alsabar.notification, preset.title, preset.text)
149             end
150         end)
151     end
152
153     helpers.newtimer(string.format("alsabar-%s-%s", alsabar.cmd, alsabar.channel), timeout, alsabar.update)
154
155     alsabar.bar:connect_signal("button::press", function(_,_,_,button)
156     if (button == 4)     then awful.spawn(format_inc_cmd)
157     elseif (button == 5) then awful.spawn(format_dec_cmd)
158     elseif (button == 1) then awful.spawn(format_tog_cmd)
159     end
160     alsabar.update()
161 end)
162
163     return alsabar
164 end
165
166 return factory