]> git.madduck.net Git - etc/awesome.git/blob - .config/awesome/rc.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:

more intuitive key mappings
[etc/awesome.git] / .config / awesome / rc.lua
1 -- Standard awesome library
2 require("awful")
3 require("beautiful")
4 require("naughty")
5
6 -- Load Debian menu entries
7 require("debian.menu")
8
9 -- {{{ Variable definitions
10 -- Themes define colours, icons, and wallpapers
11 -- The default is a dark theme
12 theme_path = "/usr/share/awesome/themes/default/theme.lua"
13 -- Uncommment this for a lighter theme
14 -- theme_path = "/usr/share/awesome/themes/sky/theme.lua"
15
16 -- Actually load theme
17 beautiful.init(theme_path)
18
19 -- This is used later as the default terminal and editor to run.
20 terminal = "x-terminal-emulator"
21 editor = os.getenv("EDITOR") or "editor"
22 editor_cmd = terminal .. " -e " .. editor
23
24 -- Default modkey.
25 -- Usually, Mod4 is the key with a logo between Control and Alt.
26 -- If you do not like this or do not have such a key,
27 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
28 -- However, you can use another modifier like Mod1, but it may interact with others.
29 modkey = "Mod4"
30
31 -- Table of layouts to cover with awful.layout.inc, order matters.
32 layouts =
33 {
34     awful.layout.suit.tile,
35     awful.layout.suit.tile.left,
36     awful.layout.suit.tile.bottom,
37     awful.layout.suit.tile.top,
38     awful.layout.suit.fair,
39     awful.layout.suit.fair.horizontal,
40     awful.layout.suit.max,
41     awful.layout.suit.max.fullscreen,
42     awful.layout.suit.magnifier,
43     awful.layout.suit.floating
44 }
45
46 -- Table of clients that should be set floating. The index may be either
47 -- the application class or instance. The instance is useful when running
48 -- a console app in a terminal like (Music on Console)
49 --    xterm -name mocp -e mocp
50 -- OVERRULED BY TILEDAPPS BELOW
51 floatapps =
52 {
53     -- by class
54     ["MPlayer"] = true,
55     ["pinentry"] = true,
56     ["GIMP"] = true,
57     ["twinkle"] = true,
58     ["Add-ons"] = true,
59     ["Play stream"] = true,
60     ["gscan2pdf"] = true,
61 }
62
63 -- Applications that should never float, assuming everything else floats
64 -- (by instance)
65 tiledapps =
66 {
67     ["urxvt"] = true,
68 }
69
70 -- Applications that should be maximised
71 -- (by instance)
72 maxapps =
73 {
74     ["Navigator"] = true,
75     -- jpilot is -v
76     ["-v"] = true,
77     ["Xpdf"] = true,
78     ["gscan2pdf"] = true
79 }
80
81 -- Applications to be moved to a pre-defined tag by class or instance.
82 -- Use the screen and tags indices.
83 apptags =
84 {
85     ["Navigator"] = { screen = 1, tag = 9 },
86     -- jpilot is -v
87     ["-v"] = { screen = 1, tag = 8 },
88 }
89
90 -- Define if we want to use titlebar on all applications.
91 use_titlebar = false
92 -- }}}
93
94 -- {{{ Tags
95 -- Define tags table.
96 tags = {}
97 for s = 1, screen.count() do
98     -- Each screen has its own tag table.
99     tags[s] = {}
100     -- Create 9 tags per screen.
101     for tagnumber = 1, 9 do
102         tags[s][tagnumber] = tag(tagnumber)
103         -- split at 0.5/50% exactly
104         tags[s][tagnumber].mwfact = 0.5
105         -- Add tags to screen one by one
106         tags[s][tagnumber].screen = s
107         awful.layout.set(layouts[5], tags[s][tagnumber])
108     end
109     -- I'm sure you want to see at least one tag.
110     tags[s][1].selected = true
111 end
112 -- }}}
113
114 -- {{{ Wibox
115 -- Create a textbox widget
116 mytextbox = widget({ type = "textbox", align = "right" })
117 -- Set the default text in textbox
118 mytextbox.text = "<b><small> " .. awesome.release .. " </small></b>"
119
120 -- Create a laucher widget and a main menu
121 myawesomemenu = {
122    { "manual", terminal .. " -e man awesome" },
123    { "edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" },
124    { "restart", awesome.restart },
125    { "quit", awesome.quit }
126 }
127
128 mymainmenu = awful.menu.new({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
129                                         { "open terminal", terminal },
130                                         { "Debian", debian.menu.Debian_menu.Debian }
131                                       }
132                             })
133
134 mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon),
135                                      menu = mymainmenu })
136
137 -- Create a systray
138 mysystray = widget({ type = "systray", align = "right" })
139
140 -- Create textbox widgets
141 mytimebox = widget({ type = "textbox", name = "mytimebox", align = "right" })
142 mybatterybox = widget({ type = "textbox", name = "mybatterybox", align = "right" })
143
144 -- Create a wibox for each screen and add it
145 mywibox = {}
146 mypromptbox = {}
147 mylayoutbox = {}
148 mytaglist = {}
149 mytaglist.buttons = awful.util.table.join(
150                     awful.button({ }, 1, awful.tag.viewonly),
151                     awful.button({ modkey }, 1, awful.client.movetotag),
152                     awful.button({ }, 3, function (tag) tag.selected = not tag.selected end),
153                     awful.button({ modkey }, 3, awful.client.toggletag),
154                     awful.button({ }, 4, awful.tag.viewnext),
155                     awful.button({ }, 5, awful.tag.viewprev)
156                     )
157 mytasklist = {}
158 mytasklist.buttons = awful.util.table.join(
159                      awful.button({ }, 1, function (c)
160                                               if not c:isvisible() then
161                                                   awful.tag.viewonly(c:tags()[1])
162                                               end
163                                               client.focus = c
164                                               c:raise()
165                                           end),
166                      awful.button({ }, 3, function ()
167                                               if instance then
168                                                   instance:hide()
169                                                   instance = nil
170                                               else
171                                                   instance = awful.menu.clients({ width=250 })
172                                               end
173                                           end),
174                      awful.button({ }, 4, function ()
175                                               awful.client.focus.byidx(1)
176                                               if client.focus then client.focus:raise() end
177                                           end),
178                      awful.button({ }, 5, function ()
179                                               awful.client.focus.byidx(-1)
180                                               if client.focus then client.focus:raise() end
181                                           end))
182
183 for s = 1, screen.count() do
184     -- Create a promptbox for each screen
185     mypromptbox[s] = awful.widget.prompt({ align = "left" })
186     -- Create an imagebox widget which will contains an icon indicating which layout we're using.
187     -- We need one layoutbox per screen.
188     mylayoutbox[s] = widget({ type = "imagebox", align = "right" })
189     mylayoutbox[s]:buttons(awful.util.table.join(
190                            awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end),
191                            awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end),
192                            awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end),
193                            awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end)))
194     -- Create a taglist widget
195     mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons)
196
197     -- Create a tasklist widget
198     mytasklist[s] = awful.widget.tasklist(function(c)
199                                               return awful.widget.tasklist.label.currenttags(c, s)
200                                           end, mytasklist.buttons)
201
202     -- Create the wibox
203     mywibox[s] = wibox({ position = "top", fg = beautiful.fg_normal, bg = beautiful.bg_normal })
204     -- Add widgets to the wibox - order matters
205     mywibox[s].widgets = { mytaglist[s],
206                            mytasklist[s],
207                            mypromptbox[s],
208                            mybatterybox,
209                            mytimebox,
210                            mylayoutbox[s],
211                            s == screen.count() and mysystray or nil }
212     mywibox[s].screen = s
213 end
214 -- }}}
215
216 --Battery widget
217 batterywidget = widget({ type = 'progressbar', name = 'batterywidget' })
218 batterywidget.width = 100
219 batterywidget.height = 0.8
220 batterywidget.gap = 1
221 batterywidget.border_padding = 1
222 batterywidget.border_width = 1
223 batterywidget.ticks_count = 10
224 batterywidget.ticks_gap = 1
225 batterywidget.vertical = false
226 batterywidget:bar_properties_set('bat', {
227   bg = 'black',
228   fg = 'blue4',
229   fg_off = 'red',
230   reverse = false,
231   min_value = 0,
232   max_value = 100
233 })
234 -- }}}
235
236
237 -- {{{ Mouse bindings
238 root.buttons(awful.util.table.join(
239     awful.button({ }, 3, function () mymainmenu:toggle() end),
240     awful.button({ }, 4, awful.tag.viewnext),
241     awful.button({ }, 5, awful.tag.viewprev)
242 ))
243 -- }}}
244
245 -- {{{ Key bindings
246 globalkeys = awful.util.table.join(
247     awful.key({ modkey,           }, "Left",   awful.tag.viewprev       ),
248     awful.key({ modkey,           }, "Right",  awful.tag.viewnext       ),
249     awful.key({ modkey,           }, "Escape", awful.tag.history.restore),
250     awful.key({ modkey, "Shift"   }, "Right", function () awful.screen.focus( 1)       end),
251     awful.key({ modkey, "Shift"   }, "Left", function () awful.screen.focus(-1)       end),
252     awful.key({ modkey, "Shift"   }, "h",   awful.tag.viewprev       ),
253     awful.key({ modkey, "Shift"   }, "l",  awful.tag.viewnext       ),
254
255     awful.key({ modkey,           }, "k",
256         function ()
257             awful.client.focus.byidx( 1)
258             if client.focus then client.focus:raise() end
259         end),
260     awful.key({ modkey,           }, "j",
261         function ()
262             awful.client.focus.byidx(-1)
263             if client.focus then client.focus:raise() end
264         end),
265     awful.key({ modkey,           }, "w", function () mymainmenu:show(true)        end),
266
267     -- Layout manipulation
268     awful.key({ modkey, "Shift"   }, "k", function () awful.client.swap.byidx(  1) end),
269     awful.key({ modkey, "Shift"   }, "j", function () awful.client.swap.byidx( -1) end),
270     awful.key({ modkey, "Control" }, "k", function () awful.screen.focus( 1)       end),
271     awful.key({ modkey, "Control" }, "j", function () awful.screen.focus(-1)       end),
272     awful.key({ modkey,           }, "u", awful.client.urgent.jumpto),
273     awful.key({ modkey,           }, "Tab",
274         function ()
275             awful.client.focus.history.previous()
276             if client.focus then
277                 client.focus:raise()
278             end
279         end),
280
281     -- Standard program
282     awful.key({ modkey,           }, "Return", function () awful.util.spawn(terminal) end),
283     awful.key({ modkey, "Control" }, "r", awesome.restart),
284     awful.key({ modkey, "Shift"   }, "q", awesome.quit),
285
286     awful.key({ modkey,           }, "l",     function () awful.tag.incmwfact( 0.05)    end),
287     awful.key({ modkey,           }, "h",     function () awful.tag.incmwfact(-0.05)    end),
288     awful.key({ modkey, "Shift"   }, "h",     function () awful.tag.incnmaster( 1)      end),
289     awful.key({ modkey, "Shift"   }, "l",     function () awful.tag.incnmaster(-1)      end),
290     awful.key({ modkey, "Control" }, "h",     function () awful.tag.incncol( 1)         end),
291     awful.key({ modkey, "Control" }, "l",     function () awful.tag.incncol(-1)         end),
292     awful.key({ modkey,           }, "space", function () awful.layout.inc(layouts,  1) end),
293     awful.key({ modkey, "Shift"   }, "space", function () awful.layout.inc(layouts, -1) end),
294
295     -- Prompt
296     awful.key({ modkey },            "r",     function () mypromptbox[mouse.screen]:run() end),
297
298     awful.key({ modkey }, "x",
299               function ()
300                   awful.prompt.run({ prompt = "Run Lua code: " },
301                   mypromptbox[mouse.screen].widget,
302                   awful.util.eval, nil,
303                   awful.util.getdir("cache") .. "/history_eval")
304               end)
305 )
306
307 -- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them
308 clientkeys = awful.util.table.join(
309     awful.key({ modkey,           }, "f",      function (c) c.fullscreen = not c.fullscreen  end),
310     awful.key({ modkey, "Shift"   }, "c",      function (c) c:kill()                         end),
311     awful.key({ modkey, "Control" }, "space",  awful.client.floating.toggle                     ),
312     awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end),
313     awful.key({ modkey,           }, "o",      awful.client.movetoscreen                        ),
314     awful.key({ modkey, "Shift"   }, "r",      function (c) c:redraw()                       end),
315     awful.key({ modkey }, "t", awful.client.togglemarked),
316     awful.key({ modkey,}, "m",
317         function (c)
318 --            if not awful.client.floating then
319 --                awful.client.floating.toggle()
320 --            end
321             c.maximized_horizontal = not c.maximized_horizontal
322             c.maximized_vertical   = not c.maximized_vertical
323         end)
324 )
325
326 -- Compute the maximum number of digit we need, limited to 9
327 keynumber = 0
328 for s = 1, screen.count() do
329    keynumber = math.min(9, math.max(#tags[s], keynumber));
330 end
331
332 for i = 1, keynumber do
333     globalkeys = awful.util.table.join(globalkeys,
334         awful.key({ modkey }, i,
335                   function ()
336                         local screen = mouse.screen
337                         if tags[screen][i] then
338                             awful.tag.viewonly(tags[screen][i])
339                         end
340                   end),
341         awful.key({ modkey, "Control" }, i,
342                   function ()
343                       local screen = mouse.screen
344                       if tags[screen][i] then
345                           tags[screen][i].selected = not tags[screen][i].selected
346                       end
347                   end),
348         awful.key({ modkey, "Shift" }, i,
349                   function ()
350                       if client.focus and tags[client.focus.screen][i] then
351                           awful.client.movetotag(tags[client.focus.screen][i])
352                       end
353                   end),
354         awful.key({ modkey, "Control", "Shift" }, i,
355                   function ()
356                       if client.focus and tags[client.focus.screen][i] then
357                           awful.client.toggletag(tags[client.focus.screen][i])
358                       end
359                   end),
360         awful.key({ modkey, "Shift" }, "F" .. i,
361                   function ()
362                       local screen = mouse.screen
363                       if tags[screen][i] then
364                           for k, c in pairs(awful.client.getmarked()) do
365                               awful.client.movetotag(tags[screen][i], c)
366                           end
367                       end
368                    end))
369 end
370
371 cmdmodkey = "Mod3"
372
373 -- xmms2 & sound
374 globalkeys = awful.util.table.join(globalkeys,
375   awful.key({ cmdmodkey }, "Prior", function () awful.util.spawn("amixer set Master 2+") end),
376   awful.key({ cmdmodkey }, "Next", function () awful.util.spawn("amixer set Master 2-") end),
377   awful.key({ cmdmodkey }, "Up", function () awful.util.spawn("amixer set PCM 2+") end),
378   awful.key({ cmdmodkey }, "Down", function () awful.util.spawn("amixer set PCM 2-") end),
379   awful.key({ cmdmodkey }, "Home", function () awful.util.spawn("amixer set Mic toggle") end),
380   awful.key({ cmdmodkey }, "End", function () awful.util.spawn("amixer set Master toggle") end),
381   awful.key({ cmdmodkey }, "Left", function () awful.util.spawn("xmms2 prev") end),
382   awful.key({ cmdmodkey }, "Right", function () awful.util.spawn("xmms2 next") end),
383   awful.key({ cmdmodkey }, "space", function () awful.util.spawn("xmms2 toggleplay") end),
384   awful.key({ cmdmodkey }, "backslash", function () awful.util.spawn_with_shell("xmms2 current | head -1 | xmessage -nearmouse -timeout 5 -file -") end),
385   awful.key({ cmdmodkey, "Shift" }, "backslash", function () awful.util.spawn_with_shell("xmms2 list | xmessage -nearmouse -timeout 5 -file -") end)
386 )
387
388 -- misc apps
389 globalkeys = awful.util.table.join(globalkeys,
390   awful.key({ cmdmodkey }, "n", function () awful.util.spawn("sensible-browser") end),
391   awful.key({ cmdmodkey }, "m", function () awful.util.spawn(terminal .. " -e mutt -f =store") end),
392   awful.key({ cmdmodkey }, "t", function () awful.util.spawn(terminal) end),
393   awful.key({ cmdmodkey }, "c", function () awful.util.spawn(terminal .. " -e python") end),
394   awful.key({ cmdmodkey }, "r", function () awful.util.spawn("gmrun") end),
395   awful.key({ cmdmodkey }, "j", function () awful.util.spawn("jpilot") end),
396   awful.key({ cmdmodkey }, "x", function () awful.util.spawn_with_shell("/sbin/start-stop-daemon --start --background --exec /usr/bin/xscreensaver; xscreensaver-command -lock") end),
397   awful.key({ cmdmodkey, "Shift" }, "x", function () awful.util.spawn("xscreensaver-command -exit") end),
398   awful.key(nil, "XF86ScreenSaver", function () awful.util.spawn("xset dpms force off") end)
399 )
400
401 -- Set keys
402 root.keys(globalkeys)
403 -- }}}
404
405 -- {{{ Hooks
406 -- Hook function to execute when focusing a client.
407 awful.hooks.focus.register(function (c)
408     if not awful.client.ismarked(c) then
409         c.border_color = beautiful.border_focus
410     end
411 end)
412
413 -- Hook function to execute when unfocusing a client.
414 awful.hooks.unfocus.register(function (c)
415     if not awful.client.ismarked(c) then
416         c.border_color = beautiful.border_normal
417     end
418 end)
419
420 -- Hook function to execute when marking a client
421 awful.hooks.marked.register(function (c)
422     c.border_color = beautiful.border_marked
423 end)
424
425 -- Hook function to execute when unmarking a client.
426 awful.hooks.unmarked.register(function (c)
427     c.border_color = beautiful.border_focus
428 end)
429
430 -- Hook function to execute when the mouse enters a client.
431 awful.hooks.mouse_enter.register(function (c)
432     -- Sloppy focus, but disabled for magnifier layout
433     if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
434         and awful.client.focus.filter(c) then
435         client.focus = c
436     end
437 end)
438
439 -- Hook function to execute when a new client appears.
440 awful.hooks.manage.register(function (c, startup)
441     -- If we are not managing this application at startup,
442     -- move it to the screen where the mouse is.
443     -- We only do it for filtered windows (i.e. no dock, etc).
444     if not startup and awful.client.focus.filter(c) then
445         c.screen = mouse.screen
446     end
447
448     if use_titlebar then
449         -- Add a titlebar
450         awful.titlebar.add(c, { modkey = modkey })
451     end
452     -- Add mouse bindings
453     c:buttons(awful.util.table.join(
454         awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
455         awful.button({ modkey }, 1, awful.mouse.client.move),
456         awful.button({ modkey }, 3, awful.mouse.client.resize)
457     ))
458     -- New client may not receive focus
459     -- if they're not focusable, so set border anyway.
460     c.border_width = beautiful.border_width
461     c.border_color = beautiful.border_normal
462
463     -- Check if the application should be floating.
464     -- OVERRIDDEN, SEE tiledapps BELOW
465     local cls = c.class
466     local inst = c.instance
467     if floatapps[cls] then
468         awful.client.floating.set(c, floatapps[cls])
469     elseif floatapps[inst] then
470         awful.client.floating.set(c, floatapps[inst])
471     end
472
473     -- Override with tiledapps
474     awful.client.floating.set(c, not (tiledapps[inst] or tiledapps[cls]))
475
476     -- Check application->screen/tag mappings.
477     local target
478     if apptags[cls] then
479         target = apptags[cls]
480     elseif apptags[inst] then
481         target = apptags[inst]
482     end
483     if target then
484         c.screen = target.screen
485         awful.client.movetotag(tags[target.screen][target.tag], c)
486     end
487
488     -- Do this after tag mapping, so you don't see it on the wrong tag for a split second.
489     client.focus = c
490
491     -- Set key bindings
492     c:keys(clientkeys)
493
494     -- Set the windows at the slave,
495     -- i.e. put it at the end of others instead of setting it master.
496     -- awful.client.setslave(c)
497
498     -- Honor size hints: if you want to drop the gaps between windows, set this to false.
499     c.size_hints_honor = true
500
501     -- Maximise some
502     if maxapps[inst] or maxapps[cls] then
503         c.maximized_horizontal = not c.maximized_horizontal
504         c.maximized_vertical   = not c.maximized_vertical
505     end
506 end)
507
508 -- Hook function to execute when arranging the screen.
509 -- (tag switch, new client, etc)
510 awful.hooks.arrange.register(function (screen)
511     local layout = awful.layout.getname(awful.layout.get(screen))
512     if layout and beautiful["layout_" ..layout] then
513         mylayoutbox[screen].image = image(beautiful["layout_" .. layout])
514     else
515         mylayoutbox[screen].image = nil
516     end
517
518     -- Give focus to the latest client in history if no window has focus
519     -- or if the current window is a desktop or a dock one.
520     if not client.focus then
521         local c = awful.client.focus.history.get(screen, 0)
522         if c then client.focus = c end
523     end
524 end)
525
526 -- Hook called every second
527 awful.hooks.timer.register(1, function ()
528     mytimebox.text = os.date(" %a %d %b %H:%M:%S ")
529 end)
530
531 -- Hook called every sixty seconds
532 function hook_battery()
533     mybatterybox.text = " " .. get_acpibatt() .. " "
534 end
535
536 -- {{{ Statusbar battery
537 --
538 function get_acpibatt()
539
540     local f = io.popen('acpi -b', 'r')
541     if not f then
542       return "acpi -b failed"
543     end
544
545     local s = f:read('*l')
546     f:close()
547     if not s then
548       return '-';
549     end
550
551     -- Battery 0: Discharging, 89%, 00:02:14 remaining
552     -- Battery 0: Charging, 58%, 00:02:14 until charged
553     -- Battery 0: Full, 100%
554     -- so find the first bit first and then go look for the time
555     local st, en, status, percent = string.find(s, '%a+%s%d:%s(%a+),%s(%d+%%)');
556     local st, en, time = string.find(s, ',%s(%d+:%d+):%d+%s%a+', en);
557
558     if not status or not percent then -- time can be empty if we're full
559       return "couldn't parse line " .. s
560     end
561
562     if not time then
563       return percent
564     end
565
566     if status == 'Charging' then
567       return '↑ ' .. percent;
568     elseif status == 'Discharging' then
569       return '↓ '.. time;
570     else
571       return '';
572     end
573 end
574 -- }}}
575
576 --{{{ batt hook
577 local function get_bat()
578   local a = io.open("/sys/class/power_supply/BAT1/charge_full")
579   for line in a:lines() do
580     full = line
581   end
582   a:close()
583   local b = io.open("/sys/class/power_supply/BAT1/charge_now")
584   for line in b:lines() do
585     now = line
586   end
587   b:close()
588   batt=math.floor(now*100/full)
589   batterywidget:bar_data_add("bat",batt )
590 end
591 --}}}
592
593 -- Set up some hooks
594 awful.hooks.timer.register(20, hook_battery)
595 -- awful.hooks.timer.register(5, get_bat)
596 -- }}}
597
598 -- Highlight statusbars on the screen that has focus,
599 -- set this to false if you only have one screen or
600 -- you don't like it :P
601 if screen.count() > 1 then
602   statusbar_highlight_focus = true
603 else
604   statusbar_highlight_focus = false
605 end
606
607 hook_battery()
608
609 function displayMonth(month,year,weekStart)
610     local t,wkSt=os.time{year=year, month=month+1, day=0},weekStart or 1
611     local d=os.date("*t",t)
612     local mthDays,stDay=d.day,(d.wday-d.day-wkSt+1)%7
613
614     local lines = {}
615
616     for x=0,6 do
617         lines[x+1] = os.date("%a ",os.time{year=2006,month=1,day=x+wkSt})
618     end
619     lines[8] = "    "
620
621     local writeLine = 1
622     while writeLine < (stDay + 1) do
623         lines[writeLine] = lines[writeLine] .. "   "
624         writeLine = writeLine + 1
625     end
626
627     for x=1,mthDays do
628         if writeLine == 8 then
629             writeLine = 1
630         end
631         if writeLine == 1 or x == 1 then
632             lines[8] = lines[8] .. os.date(" %V",os.time{year=year,month=month,day=x})
633         end
634         if (#(tostring(x)) == 1) then
635             x = " " .. x
636         end
637         lines[writeLine] = lines[writeLine] .. " " .. x
638         writeLine = writeLine + 1
639     end
640     local header = os.date("%B %Y\n",os.time{year=year,month=month,day=1})
641     header = string.rep(" ", math.floor((#(lines[1]) - #header) / 2 )) .. header
642
643     return header .. table.concat(lines, '\n')
644 end
645
646 local calendar = {}
647 function switchNaughtyMonth(switchMonths)
648     if (#calendar < 3) then return end
649     local swMonths = switchMonths or 1
650     calendar[1] = calendar[1] + swMonths
651     calendar[3].box.widgets[2].text = displayMonth(calendar[1], calendar[2], 2)
652 end
653
654 mytimebox.mouse_enter = function ()
655     local month, year = os.date('%m'), os.date('%Y')
656     calendar = { month, year,
657                 naughty.notify({
658                     text = displayMonth(month, year, 2),
659                     timeout = 0, hover_timeout = 0.5,
660                     width = 200, screen = mouse.screen
661                 })
662                }
663 end
664 mytimebox.mouse_leave = function () naughty.destroy(calendar[3]) end
665
666 mytimebox.buttons = awful.util.table.join(
667     awful.button({ }, 1, function() switchNaughtyMonth(-1) end),
668     awful.button({ }, 3, function() switchNaughtyMonth(1) end),
669     awful.button({ }, 4, function() switchNaughtyMonth(-1) end),
670     awful.button({ }, 5, function() switchNaughtyMonth(1) end),
671     awful.button({ 'Shift' }, 1, function() switchNaughtyMonth(-12) end),
672     awful.button({ 'Shift' }, 3, function() switchNaughtyMonth(12) end),
673     awful.button({ 'Shift' }, 4, function() switchNaughtyMonth(-12) end),
674     awful.button({ 'Shift' }, 5, function() switchNaughtyMonth(12) end)
675 )