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:

use obvious battery widget
[etc/awesome.git] / .config / awesome / rc.lua
1 -- Standard awesome library
2 require("awful")
3 require("awful.autofocus")
4 require("awful.rules")
5 -- Theme handling library
6 require("beautiful")
7 -- Notification library
8 require("naughty")
9
10 --require("vicious")
11
12 require("obvious.battery")
13
14 -- Load Debian menu entries
15 require("debian.menu")
16
17 -- {{{ Variable definitions
18 -- Themes define colours, icons, and wallpapers
19 -- The default is a dark theme
20 theme_path = "/usr/share/awesome/themes/default/theme.lua"
21 -- Uncommment this for a lighter theme
22 -- theme_path = "/usr/share/awesome/themes/sky/theme.lua"
23
24 wallpaper_cmd = { "awsetbg -t .config/awesome/bgstripes.png" } 
25
26 -- Actually load theme
27 beautiful.init(theme_path)
28
29 -- This is used later as the default terminal and editor to run.
30 terminal = "x-terminal-emulator"
31 editor = os.getenv("EDITOR") or "editor"
32 editor_cmd = terminal .. " -e " .. editor
33
34 -- Default modkey.
35 -- Usually, Mod4 is the key with a logo between Control and Alt.
36 -- If you do not like this or do not have such a key,
37 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
38 -- However, you can use another modifier like Mod1, but it may interact with others.
39 modkey = "Mod4"
40
41 -- Table of layouts to cover with awful.layout.inc, order matters.
42 layouts =
43 {
44 --    awful.layout.suit.tile,
45 --    awful.layout.suit.tile.left,
46 --    awful.layout.suit.tile.bottom,
47 --    awful.layout.suit.tile.top,
48     awful.layout.suit.fair,
49     awful.layout.suit.fair.horizontal,
50 --    awful.layout.suit.spiral,
51 --    awful.layout.suit.spiral.dwindle,
52     awful.layout.suit.max,
53 --    awful.layout.suit.max.fullscreen,
54     awful.layout.suit.magnifier,
55     awful.layout.suit.floating
56 }
57
58 ---- Table of clients that should be set floating. The index may be either
59 ---- the application class or instance. The instance is useful when running
60 ---- a console app in a terminal like (Music on Console)
61 ----    xterm -name mocp -e mocp
62 ---- OVERRULED BY TILEDAPPS BELOW
63 --floatapps =
64 --{
65 --    -- by class
66 --    ["MPlayer"] = true,
67 --    ["pinentry"] = true,
68 --    ["GIMP"] = true,
69 --    ["twinkle"] = true,
70 --    ["Add-ons"] = true,
71 --    ["Play stream"] = true,
72 --    ["gscan2pdf"] = true,
73 --}
74 --
75 ---- Applications that should never float, assuming everything else floats
76 ---- (by instance)
77 --tiledapps =
78 --{
79 --    ["urxvt"] = true,
80 --}
81 --
82 ---- Applications that should be maximised
83 ---- (by instance)
84 --maxapps =
85 --{
86 --    ["Navigator"] = true,
87 --    -- jpilot is -v
88 --    ["-v"] = true,
89 --    ["Xpdf"] = true,
90 --    ["gscan2pdf"] = true
91 --}
92 --
93 ---- Applications to be moved to a pre-defined tag by class or instance.
94 ---- Use the screen and tags indices.
95 --apptags =
96 --{
97 --    ["Navigator"] = { screen = 1, tag = 9 },
98 --    -- jpilot is -v
99 --    ["-v"] = { screen = 1, tag = 8 },
100 --}
101
102 -- Define if we want to use titlebar on all applications.
103 use_titlebar = false
104 -- }}}
105
106 -- {{{ Tags
107 tags = {}
108 tags.settings = {
109     { name = "1", layout = layouts[1] },
110     { name = "2", layout = layouts[1] },
111     { name = "3", layout = layouts[1] },
112     { name = "4", layout = layouts[1] },
113     { name = "5", layout = layouts[5] },
114     { name = "6", layout = layouts[3] },
115     { name = "7", layout = layouts[3] },
116     { name = "8", layout = layouts[3] },
117     { name = "9", layout = layouts[3] },
118 }
119
120 -- Define a tag table which hold all screen tags.
121 for s = 1, screen.count() do
122     tags[s] = {}
123     for i, v in ipairs(tags.settings) do
124         tags[s][i] = tag({ name = v.name })
125         tags[s][i].screen = s
126         awful.tag.setproperty(tags[s][i], "layout", v.layout)
127         awful.tag.setproperty(tags[s][i], "mwfact", v.mwfact)
128         awful.tag.setproperty(tags[s][i], "hide",   v.hide)
129     end
130     tags[s][1].selected = true
131 end
132
133 if screen.count() == 3 then
134   tags[1][1].selected = false
135   tags[1][9].selected = true
136 end
137 -- }}}
138
139 -- {{{ Menu
140 -- Create a laucher widget and a main menu
141 myawesomemenu = {
142    { "manual", terminal .. " -e man awesome" },
143    { "edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" },
144    { "restart", awesome.restart },
145    { "quit", awesome.quit }
146 }
147
148 mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
149                                     { "Debian", debian.menu.Debian_menu.Debian },
150                                     { "open terminal", terminal }
151                                   }
152                         })
153
154 mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon),
155                                      menu = mymainmenu })
156 -- }}}
157
158 -- {{{ Wibox
159
160 -- {{{ Reusable separators
161 spacer         = widget({ type = "textbox", name = "spacer" })
162 separator      = widget({ type = "textbox", name = "separator" })
163 spacer.text    = " "
164 separator.text = "٭"
165 -- }}}
166
167 ---- {{{ CPU usage and temperature
168 ---- Widget icon
169 --cpuicon        = widget({ type = "imagebox", name = "cpuicon" })
170 --cpuicon.image  = image(beautiful.widget_cpu)
171 ---- Initialize widgets
172 --thermalwidget  = widget({ type = "textbox", name = "thermalwidget" })
173 --cpuwidget      = awful.widget.graph({ layout = awful.widget.layout.horizontal.rightleft })
174 ---- Graph properties
175 --cpuwidget:set_width(50)
176 ----cpuwidget:set_scale(false)
177 --cpuwidget:set_max_value(100)
178 --cpuwidget:set_background_color(beautiful.fg_off_widget)
179 --cpuwidget:set_border_color(beautiful.border_widget)
180 --cpuwidget:set_color(beautiful.fg_end_widget)
181 --cpuwidget:set_gradient_angle(0)
182 --cpuwidget:set_gradient_colors({
183 --    beautiful.fg_end_widget,
184 --    beautiful.fg_center_widget,
185 --    beautiful.fg_widget })
186 ---- Register widgets
187 --vicious.register(cpuwidget, vicious.widgets.cpu, "$1")
188 --vicious.register(thermalwidget, vicious.widgets.thermal, "CPU: $1°C", 19, "hwmon0")
189 ---- }}}
190
191 -- Battery widget
192 --batterywidget = widget({ type = 'progressbar', name = 'batterywidget' })
193 --batterywidget.width = 100
194 --batterywidget.height = 0.8
195 --batterywidget.gap = 1
196 --batterywidget.border_padding = 1
197 --batterywidget.border_width = 1
198 --batterywidget.ticks_count = 10
199 --batterywidget.ticks_gap = 1
200 --batterywidget.vertical = false
201 --batterywidget:bar_properties_set('bat', {
202 --  bg = 'black',
203 --  fg = 'blue4',
204 --  fg_off = 'red',
205 --  reverse = false,
206 --  min_value = 0,
207 --  max_value = 100
208 --})
209
210 -- Create a textclock widget
211 mytextclock = awful.widget.textclock({ align = "right" }, "%a %d %b %H:%M:%S", 1)
212
213 -- Create a systray
214 mysystray = widget({ type = "systray", align = "right" })
215
216 mybatterybox = widget({ type = "textbox", name = "mybatterybox", align = "right" })
217
218 -- Create a wibox for each screen and add it
219 mywibox = {}
220 mypromptbox = {}
221 mylayoutbox = {}
222 mytaglist = {}
223 mytaglist.buttons = awful.util.table.join(
224                     awful.button({ }, 1, awful.tag.viewonly),
225                     awful.button({ modkey }, 1, awful.client.movetotag),
226                     awful.button({ }, 3, awful.tag.viewtoggle),
227                     awful.button({ modkey }, 3, awful.client.toggletag),
228                     awful.button({ }, 4, awful.tag.viewnext),
229                     awful.button({ }, 5, awful.tag.viewprev)
230                     )
231 mytasklist = {}
232 mytasklist.buttons = awful.util.table.join(
233                      awful.button({ }, 1, function (c)
234                                               if not c:isvisible() then
235                                                   awful.tag.viewonly(c:tags()[1])
236                                               end
237                                               client.focus = c
238                                               c:raise()
239                                           end),
240                      awful.button({ }, 3, function ()
241                                               if instance then
242                                                   instance:hide()
243                                                   instance = nil
244                                               else
245                                                   instance = awful.menu.clients({ width=250 })
246                                               end
247                                           end),
248                      awful.button({ }, 4, function ()
249                                               awful.client.focus.byidx(1)
250                                               if client.focus then client.focus:raise() end
251                                           end),
252                      awful.button({ }, 5, function ()
253                                               awful.client.focus.byidx(-1)
254                                               if client.focus then client.focus:raise() end
255                                           end))
256
257 for s = 1, screen.count() do
258     -- Create a promptbox for each screen
259     mypromptbox[s] = awful.widget.prompt({ layout = awful.widget.layout.horizontal.leftright })
260     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
261     -- We need one layoutbox per screen.
262     mylayoutbox[s] = awful.widget.layoutbox(s)
263     mylayoutbox[s]:buttons(awful.util.table.join(
264                            awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end),
265                            awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end),
266                            awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end),
267                            awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end)))
268     -- Create a taglist widget
269     mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons)
270
271     -- Create a tasklist widget
272     mytasklist[s] = awful.widget.tasklist(function(c)
273                                               return awful.widget.tasklist.label.currenttags(c, s)
274                                           end, mytasklist.buttons)
275
276     -- Create the wibox
277     mywibox[s] = awful.wibox({ position = "top", screen = s })
278     -- Add widgets to the wibox - order matters
279     mywibox[s].widgets = {
280         {
281 --            mylauncher,
282             mytaglist[s],
283             mypromptbox[s],
284             layout = awful.widget.layout.horizontal.leftright
285         },
286         mylayoutbox[s],
287         spacer,
288         mytextclock,
289         spacer, separator, spacer,
290         obvious.battery.widget,
291 --        mybatterybox,
292 --        batterywidget,
293 --        spacer, separator, spacer,
294 --        cpuwidget.widget,
295 --        spacer, separator, spacer,
296 --        thermalwidget.widget,
297         spacer,
298         s == screen.count() and mysystray or nil,
299         mytasklist[s],
300         layout = awful.widget.layout.horizontal.rightleft
301     }
302 end
303
304 -- }}}
305
306 -- {{{ Mouse bindings
307 root.buttons(awful.util.table.join(
308     awful.button({ }, 3, function () mymainmenu:toggle() end),
309     awful.button({ }, 4, awful.tag.viewnext),
310     awful.button({ }, 5, awful.tag.viewprev)
311 ))
312 -- }}}
313
314 -- {{{ Key bindings
315 globalkeys = awful.util.table.join(
316     awful.key({ modkey,           }, "Left",   awful.tag.viewprev       ),
317     awful.key({ modkey,           }, "Right",  awful.tag.viewnext       ),
318     awful.key({ modkey,           }, "Escape", awful.tag.history.restore),
319     awful.key({ modkey, "Shift"   }, "Right", function () awful.screen.focus( 1)       end),
320     awful.key({ modkey, "Shift"   }, "Left", function () awful.screen.focus(-1)       end),
321     awful.key({ modkey, "Shift"   }, "h",   awful.tag.viewprev       ),
322     awful.key({ modkey, "Shift"   }, "l",  awful.tag.viewnext       ),
323
324     awful.key({ modkey,           }, "k",
325         function ()
326             awful.client.focus.byidx( 1)
327             if client.focus then client.focus:raise() end
328         end),
329     awful.key({ modkey,           }, "j",
330         function ()
331             awful.client.focus.byidx(-1)
332             if client.focus then client.focus:raise() end
333         end),
334     awful.key({ modkey,           }, "w", function () mymainmenu:show(true)        end),
335
336     -- Layout manipulation
337     awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx(  1) end),
338     awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx( -1) end),
339     awful.key({ modkey, "Control" }, "k", function () awful.screen.focus( 1)       end),
340     awful.key({ modkey, "Control" }, "j", function () awful.screen.focus(-1)       end),
341     awful.key({ modkey,           }, "u", awful.client.urgent.jumpto),
342     awful.key({ modkey,           }, "Tab",
343         function ()
344             awful.client.focus.history.previous()
345             if client.focus then
346                 client.focus:raise()
347             end
348         end),
349
350     -- Standard program
351     awful.key({ modkey,           }, "Return", function () awful.util.spawn(terminal) end),
352     awful.key({ modkey, "Control" }, "r", awesome.restart),
353     awful.key({ modkey, "Shift"   }, "q", awesome.quit),
354
355     awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)    end),
356     awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)    end),
357     awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1)      end),
358     awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1)      end),
359     awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1)         end),
360     awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1)         end),
361     awful.key({ modkey,           }, "space", function () awful.layout.inc(layouts,  1) end),
362     awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(layouts, -1) end),
363
364     -- Prompt
365     awful.key({ modkey },            "r",     function () mypromptbox[mouse.screen]:run() end),
366
367     awful.key({ modkey }, "x",
368               function ()
369                   awful.prompt.run({ prompt = "Run Lua code: " },
370                   mypromptbox[mouse.screen].widget,
371                   awful.util.eval, nil,
372                   awful.util.getdir("cache") .. "/history_eval")
373               end)
374 )
375
376 clientkeys = awful.util.table.join(
377     awful.key({ modkey,           }, "f",      function (c) c.fullscreen = not c.fullscreen  end),
378     awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end),
379     awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ),
380     awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end),
381     awful.key({ modkey,           }, "o",      awful.client.movetoscreen                        ),
382     awful.key({ modkey, "Shift"   }, "r",      function (c) c:redraw()                       end),
383     awful.key({ modkey            }, "t",      awful.client.togglemarked                        ),
384     awful.key({ modkey,           }, "n",      function (c) c.minimized = not c.minimized    end),
385     awful.key({ modkey,           }, "m",
386         function (c)
387             c.maximized_horizontal = not c.maximized_horizontal
388             c.maximized_vertical   = not c.maximized_vertical
389         end)
390 )
391
392 -- Compute the maximum number of digit we need, limited to 9
393 keynumber = 0
394 for s = 1, screen.count() do
395    keynumber = math.min(9, math.max(#tags[s], keynumber));
396 end
397
398 -- Bind all key numbers to tags.
399 -- Be careful: we use keycodes to make it works on any keyboard layout.
400 -- This should map on the top row of your keyboard, usually 1 to 9.
401 for i = 1, keynumber do
402     globalkeys = awful.util.table.join(globalkeys,
403         awful.key({ modkey }, "#" .. i + 9,
404                   function ()
405                         local screen = mouse.screen
406                         if tags[screen][i] then
407                             awful.tag.viewonly(tags[screen][i])
408                         end
409                   end),
410         awful.key({ modkey, "Control" }, "#" .. i + 9,
411                   function ()
412                       local screen = mouse.screen
413                       if tags[screen][i] then
414                           awful.tag.viewtoggle(tags[screen][i])
415                       end
416                   end),
417         awful.key({ modkey, "Shift" }, "#" .. i + 9,
418                   function ()
419                       if client.focus and tags[client.focus.screen][i] then
420                           awful.client.movetotag(tags[client.focus.screen][i])
421                       end
422                   end),
423         awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
424                   function ()
425                       if client.focus and tags[client.focus.screen][i] then
426                           awful.client.toggletag(tags[client.focus.screen][i])
427                       end
428                   end))
429 end
430
431 clientbuttons = awful.util.table.join(
432     awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
433     awful.button({ modkey }, 1, awful.mouse.client.move),
434     awful.button({ modkey }, 3, awful.mouse.client.resize))
435
436 cmdmodkey = "Mod3"
437
438 -- xmms2 & sound
439 globalkeys = awful.util.table.join(globalkeys,
440   awful.key({ cmdmodkey }, "Prior", function () awful.util.spawn("amixer set Master 2+") end),
441   awful.key({ cmdmodkey }, "Next", function () awful.util.spawn("amixer set Master 2-") end),
442   awful.key({ cmdmodkey }, "Up", function () awful.util.spawn("amixer set PCM 2+") end),
443   awful.key({ cmdmodkey }, "Down", function () awful.util.spawn("amixer set PCM 2-") end),
444   awful.key({ cmdmodkey }, "Home", function () awful.util.spawn("amixer set Mic toggle") end),
445   awful.key({ cmdmodkey }, "End", function () awful.util.spawn("amixer set Master toggle") end),
446   awful.key({ cmdmodkey }, "Left", function () awful.util.spawn("nyxmms2 prev") end),
447   awful.key({ cmdmodkey }, "Right", function () awful.util.spawn("nyxmms2 next") end),
448   awful.key({ cmdmodkey }, "space", function () awful.util.spawn("nyxmms2 toggle") end),
449   awful.key({ cmdmodkey }, "backslash", function ()
450     local f = io.popen('nyxmms2 status', 'r')
451     naughty.notify({ title = "Now playing", text = f:read(), timeout = 5 })
452     f:close()
453   end),
454   awful.key({ cmdmodkey, "Shift" }, "backslash", function ()
455     local f = io.popen('nyxmms2 list', 'r')
456     naughty.notify({ title = "Playlist", text = f:read("*a"), timeout = 15 })
457     f:close()
458   end)
459 )
460
461 -- misc apps
462 globalkeys = awful.util.table.join(globalkeys,
463   awful.key({ cmdmodkey }, "n", function () awful.util.spawn("sensible-browser") end),
464   awful.key({ cmdmodkey }, "m", function () awful.util.spawn(terminal .. " -e mutt -f =store") end),
465   awful.key({ cmdmodkey }, "t", function () awful.util.spawn(terminal) end),
466   awful.key({ cmdmodkey }, "c", function () awful.util.spawn(terminal .. " -e python") end),
467   awful.key({ cmdmodkey }, "r", function () mypromptbox[mouse.screen]:run() end),
468   awful.key({ cmdmodkey }, "j", function () awful.util.spawn("jpilot") end),
469   awful.key({ cmdmodkey }, "i", function () awful.util.spawn(terminal .. " -title irc -name irc -e ssh -Snone -t irc screen -dr irc") end),
470   awful.key({ cmdmodkey }, "x", function () awful.util.spawn_with_shell("/sbin/start-stop-daemon --start --background --exec /usr/bin/xscreensaver; xscreensaver-command -lock") end),
471   awful.key({ cmdmodkey, "Shift" }, "x", function () awful.util.spawn("xscreensaver-command -exit") end),
472   awful.key(nil, "XF86ScreenSaver", function () awful.util.spawn("xset dpms force off") end)
473 )
474
475 -- Set keys
476 root.keys(globalkeys)
477 -- }}}
478
479 -- {{{ Rules
480 awful.rules.rules = {
481     -- All clients will match this rule.
482     { rule = { },
483       properties = { border_width = beautiful.border_width,
484                      border_color = beautiful.border_normal,
485                      focus = true,
486                      floating = true,
487                      keys = clientkeys,
488                      buttons = clientbuttons },
489       callback = awful.placement.centered },
490     { rule = { class = "URxvt" },
491       properties = { floating = false } },
492     { rule = { class = "URxvt", instance = "irc" },
493       properties = { floating = false, tag = tags[screen.count()][screen.count() == 1 and 2 or 1], switchtotag = true } },
494     { rule = { class = "Iceweasel", instance = "Navigator" },
495       properties = { tag = tags[screen.count() == 3 and 1 or screen.count()][9], switchtotag = false, floating = false } },
496 --    { rule = { class = "Iceweasel", instance = "Dialog" },
497 --      properties = { floating = true } },
498     { rule = { class = "Jpilot", instance = "jpilot" },
499       properties = { tag = tags[screen.count() == 3 and 1 or screen.count()][8], switchtotag = true, floating = false } },
500 --    { rule = { name = "OpenOffice.org" },
501 --      properties = { switchtotag = true, floating = true, maximized_vertical = true, maximized_horizontal = true, callback = awful.placement.no_offscreen } },
502 --    { rule = { name = "Okular" },
503 --      properties = { switchtotag = true, floating = true, maximized_vertical = true, maximized_horizontal = true, callback = awful.placement.no_offscreen } },
504 }
505 -- }}}
506
507 -- {{{ Signals
508 -- Signal function to execute when a new client appears.
509 client.add_signal("manage", function (c, startup)
510     -- Add a titlebar
511     -- awful.titlebar.add(c, { modkey = modkey })
512
513     -- Enable sloppy focus
514     c:add_signal("mouse::enter", function(c)
515         if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
516             and awful.client.focus.filter(c) then
517             client.focus = c
518         end
519     end)
520
521     if not startup then
522         -- Set the windows at the slave,
523         -- i.e. put it at the end of others instead of setting it master.
524         -- awful.client.setslave(c)
525
526         -- Put windows in a smart way, only if they does not set an initial position.
527         if not c.size_hints.user_position and not c.size_hints.program_position then
528             --awful.placement.center_vertical(c)
529             --awful.placement.center_horizontal(c)
530             awful.placement.no_overlap(c)
531             awful.placement.no_offscreen(c)
532         end
533     end
534     c.size_hints_honor = false
535 end)
536
537 client.add_signal("focus", function(c) c.border_color = beautiful.border_focus end)
538 client.add_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
539
540 function clear_urgency_flag(c)
541     print("property::urgent received for client: ", c)
542     io.flush ()
543 --    if c.urgent then
544 --        c.urgent = false
545 --    end
546 end
547
548 client.add_signal("new", function (c)
549   c:add_signal("property::urgent", clear_urgency_flag)
550 end)
551
552 -- Hook called every sixty seconds
553 function hook_battery()
554     mybatterybox.text = " " .. get_acpibatt() .. " "
555 end
556 -- }}}
557
558 -- {{{ Statusbar battery
559 --
560 function get_acpibatt()
561     local f = io.popen('acpi -b', 'r')
562     if not f then
563       return "acpi -b failed"
564     end
565
566     local s = f:read('*l')
567     f:close()
568     if not s then
569       return '-';
570     end
571
572     -- Battery 0: Discharging, 89%, 00:02:14 remaining
573     -- Battery 0: Charging, 58%, 00:02:14 until charged
574     -- Battery 0: Full, 100%
575     -- so find the first bit first and then go look for the time
576     local st, en, status, percent = string.find(s, '%a+%s%d:%s(%a+),%s(%d+%%)');
577     local st, en, time = string.find(s, ',%s(%d+:%d+):%d+%s%a+', en);
578
579     if not status or not percent then -- time can be empty if we're full
580       return "couldn't parse line " .. s
581     end
582
583     if not time then
584       return percent
585     end
586
587     if status == 'Charging' then
588       return '↑ ' .. percent;
589     elseif status == 'Discharging' then
590       return '↓ '.. time;
591     else
592       return '';
593     end
594 end
595 --t = timer({ timeout = 20 })
596 --t:add_signal('timeout', hook_battery)
597 --t:start()
598 --hook_battery()
599 --bashets.register_lua(mybatterybox, get_acpibatt, '%1', 30)
600 --bashets.start()
601 -- }}}