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.
2 -- Standard awesome library
3 local gears = require("gears")
4 local awful = require("awful")
5 require("awful.autofocus")
6 -- Widget and layout library
7 local wibox = require("wibox")
8 -- Theme handling library
9 local beautiful = require("beautiful")
10 -- Notification library
11 local naughty = require("naughty")
12 local menubar = require("menubar")
13 local hotkeys_popup = require("awful.hotkeys_popup").widget
14 local lain = require("lain")
15 local dkjson = require("lain.util").dkjson
16 local math = require("math")
20 -- Check if awesome encountered an error during startup and fell back to
21 -- another config (This code will only ever execute for the fallback config)
22 if awesome.startup_errors then
23 naughty.notify({ preset = naughty.config.presets.critical,
24 title = "Oops, there were errors during startup!",
25 text = awesome.startup_errors })
28 -- Handle runtime errors after startup
30 local in_error = false
31 awesome.connect_signal("debug::error", function (err)
32 -- Make sure we don't go into an endless error loop
33 if in_error then return end
36 naughty.notify({ preset = naughty.config.presets.critical,
37 title = "Oops, an error happened!",
38 text = tostring(err) })
44 -- {{{ Variable definitions
45 -- Themes define colours, icons, and wallpapers
46 beautiful.init(awful.util.get_themes_dir() .. "default/theme.lua")
48 -- This is used later as the default terminal and editor to run.
49 terminal = "x-terminal-emulator"
50 editor = "sensible-editor"
51 editor_cmd = terminal .. " -e " .. editor
54 -- Usually, Mod4 is the key with a logo between Control and Alt.
55 -- If you do not like this or do not have such a key,
56 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
57 -- However, you can use another modifier like Mod1, but it may interact with others.
61 -- Table of layouts to cover with awful.layout.inc, order matters.
62 awful.layout.layouts = {
63 awful.layout.suit.fair,
64 awful.layout.suit.tile,
65 -- awful.layout.suit.tile.left,
66 -- awful.layout.suit.tile.bottom,
67 awful.layout.suit.tile.top,
68 -- awful.layout.suit.spiral,
69 -- awful.layout.suit.spiral.dwindle,
70 awful.layout.suit.max,
71 -- awful.layout.suit.max.fullscreen,
72 -- awful.layout.suit.magnifier,
73 -- awful.layout.suit.corner.nw,
74 -- awful.layout.suit.corner.ne,
75 -- awful.layout.suit.corner.sw,
76 -- awful.layout.suit.corner.se,
77 awful.layout.suit.floating,
80 layout_default = awful.layout.layouts[1]
81 layout_tiled = awful.layout.layouts[2]
82 layout_maximised = awful.layout.layouts[4]
83 layout_floating = awful.layout.layouts[5]
86 -- {{{ Helper functions
87 local function client_menu_toggle_fn()
91 if instance and instance.wibox.visible then
95 instance = awful.menu.clients({ theme = { width = 250 } })
100 local function sorted_pairs(t, f)
102 for n in pairs(t) do table.insert(a, n) end
104 local i = 0 -- iterator variable
105 local iter = function () -- iterator function
107 if a[i] == nil then return nil
108 else return a[i], t[a[i]]
114 local function print_table(tbl, indent)
115 if not indent then indent = 0 end
116 for k, v in pairs(tbl) do
117 formatting = string.rep(" ", indent) .. k .. ": "
118 if type(v) == "table" then
120 print_table(v, indent+1)
122 print(formatting .. tostring(v))
127 local lain_bat = lain.widgets.bat({
128 batteries = {"BAT0", "BAT1"},
129 settings = function()
131 if bat_now.status == "Charging" then delim = "↑"
132 elseif bat_now.status == "Unknown" then delim = "٭" end
133 widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
137 local function poloniex_price(output, pair, prec)
138 local xc, pos, err = dkjson.decode(output, 1, nil)
139 if not prec then prec = 4 end
140 val = (xc and xc[pair]["last"]) or 0
141 val = math.floor(val*10^prec+0.5)/10^prec
142 return (not err and val) or "n/a"
145 local eth_widget = lain.widgets.abase({
146 cmd = "curl -m5 -s 'https://poloniex.com/public?command=returnTicker'",
148 settings = function()
149 widget:set_text(poloniex_price(output, 'BTC_ETH') .. " Ƀ/Ξ")
153 local function coindesk_price(output, base, prec)
155 local xc, pos, err = dkjson.decode(output, 1, nil)
156 if not prec then prec = 4 end
157 val = (xc and xc["bpi"][base]["rate_float"]) or 0
158 val = math.floor(val*10^prec+0.5)/10^prec
159 return (not err and val) or "n/a"
162 local btc_widget = lain.widgets.abase({
163 cmd = "curl -m5 -Ls 'https://api.coindesk.com/v1/bpi/currentprice/EUR.json'",
165 settings = function()
166 widget:set_text(coindesk_price(output, "EUR", 2) .. " €/Ƀ")
173 -- Create a launcher widget and a main menu
175 { "hotkeys", function() return false, hotkeys_popup.show_help end},
176 { "manual", terminal .. " -e man awesome" },
177 { "edit config", editor_cmd .. " " .. awesome.conffile },
178 { "restart", awesome.restart },
179 { "quit", awesome.quit }
182 mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
183 { "open terminal", terminal }
187 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
191 -- {{{ Menubar configuration
192 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
196 local spacer = wibox.widget.textbox()
197 spacer:set_text(' | ')
198 -- Create a textclock widget
199 mytextclock = wibox.widget.textclock("%a %d %b %H:%M:%S", 1)
201 -- Create a wibox for each screen and add it
206 mytaglist.buttons = awful.util.table.join(
207 awful.button({ }, 1, function(t) t:view_only() end),
208 awful.button({ modkey }, 1, function(t)
210 client.focus:move_to_tag(t)
213 awful.button({ }, 3, awful.tag.viewtoggle),
214 awful.button({ modkey }, 3, function(t)
216 client.focus:toggle_tag(t)
219 awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
220 awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
224 mytasklist.buttons = awful.util.table.join(
225 awful.button({ }, 1, function (c)
226 if c == client.focus then
227 -- I don't like click-minimising
228 -- c.minimized = true
230 -- Without this, the following
231 -- :isvisible() makes no sense
233 if not c:isvisible() and c.first_tag then
234 c.first_tag:view_only()
236 -- This will also un-minimize
237 -- the client, if needed
242 awful.button({ }, 3, client_menu_toggle_fn()),
243 awful.button({ }, 4, function ()
244 awful.client.focus.byidx(1)
246 awful.button({ }, 5, function ()
247 awful.client.focus.byidx(-1)
254 tags.config["main"] = {
255 t1 = { layout = layout_default, selected = true },
256 t2 = { layout = layout_default },
257 t3 = { layout = layout_tiled },
258 t4 = { layout = layout_tiled },
259 t5 = { layout = layout_tiled },
260 t6 = { layout = layout_floating },
261 t7 = { layout = layout_maximised },
262 t8 = { layout = layout_maximised },
263 t9 = { layout = layout_maximised },
265 tags.config["aux"] = {
266 t1 = { layout = layout_default, selected = true },
267 t2 = { layout = layout_default },
268 t3 = { layout = layout_tiled },
269 t4 = { layout = layout_floating },
270 t5 = { layout = layout_floating },
271 t6 = { layout = layout_floating },
272 t7 = { layout = layout_floating },
273 t8 = { layout = layout_floating },
274 t9 = { layout = layout_maximised },
278 screentags[1] = tags.config["main"]
279 if screen.count() == 2 then -- aux screen is on the right
280 screentags[2] = tags.config["aux"]
281 elseif screen.count() == 3 then -- main screen is still #1 in the middle
282 screentags[2] = tags.config["aux"]
283 screentags[3] = tags.config["aux"]
286 awful.screen.connect_for_each_screen(function(s)
288 --DISABLED--if beautiful.wallpaper then
289 --DISABLED-- local wallpaper = beautiful.wallpaper
290 --DISABLED-- -- If wallpaper is a function, call it with the screen
291 --DISABLED-- if type(wallpaper) == "function" then
292 --DISABLED-- wallpaper = wallpaper(s)
294 --DISABLED-- gears.wallpaper.maximized(wallpaper, s, true)
297 if not tags[s.index] then
300 for n,p in sorted_pairs(screentags[s.index]) do
302 n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
303 table.insert(tags[s.index], awful.tag.add(n, p))
306 -- Create a promptbox for each screen
307 mypromptbox[s] = awful.widget.prompt()
308 -- Create an imagebox widget which will contains an icon indicating which layout we're using.
309 -- We need one layoutbox per screen.
310 mylayoutbox[s] = awful.widget.layoutbox(s)
311 mylayoutbox[s]:buttons(awful.util.table.join(
312 awful.button({ }, 1, function () awful.layout.inc( 1) end),
313 awful.button({ }, 3, function () awful.layout.inc(-1) end),
314 awful.button({ }, 4, function () awful.layout.inc( 1) end),
315 awful.button({ }, 5, function () awful.layout.inc(-1) end)))
316 -- Create a taglist widget
317 mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
319 -- Create a tasklist widget
320 mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
323 mywibox[s] = awful.wibar({ position = "top", screen = s })
325 -- Add widgets to the wibox
327 layout = wibox.layout.align.horizontal,
329 layout = wibox.layout.fixed.horizontal,
334 mytasklist[s], -- Middle widget
336 layout = wibox.layout.fixed.horizontal,
338 wibox.widget.systray(),
352 -- {{{ Mouse bindings
353 root.buttons(awful.util.table.join(
354 awful.button({ }, 3, function () mymainmenu:toggle() end),
355 awful.button({ }, 4, awful.tag.viewnext),
356 awful.button({ }, 5, awful.tag.viewprev)
361 globalkeys = awful.util.table.join(
362 awful.key({ modkey, }, "s", hotkeys_popup.show_help,
363 {description="show help", group="awesome"}),
364 awful.key({ modkey, }, "Left", awful.tag.viewprev,
365 {description = "view previous", group = "tag"}),
366 awful.key({ modkey, }, "Right", awful.tag.viewnext,
367 {description = "view next", group = "tag"}),
368 awful.key({ modkey, }, "Escape", awful.tag.history.restore,
369 {description = "go back", group = "tag"}),
371 awful.key({ modkey, }, "k",
373 awful.client.focus.byidx( 1)
375 {description = "focus next by index", group = "client"}
377 awful.key({ modkey, }, "j",
379 awful.client.focus.byidx(-1)
381 {description = "focus previous by index", group = "client"}
383 awful.key({ modkey, }, "w", function () mymainmenu:show() end,
384 {description = "show main menu", group = "awesome"}),
386 -- Layout manipulation
387 awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( 1) end,
388 {description = "swap with next client by index", group = "client"}),
389 awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( -1) end,
390 {description = "swap with previous client by index", group = "client"}),
391 awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
392 {description = "focus the next screen", group = "screen"}),
393 awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
394 {description = "focus the previous screen", group = "screen"}),
395 awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
396 {description = "jump to urgent client", group = "client"}),
397 awful.key({ modkey, }, "Tab",
399 awful.client.focus.history.previous()
404 {description = "go back", group = "client"}),
407 awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
408 {description = "open a terminal", group = "launcher"}),
409 awful.key({ modkey, "Control" }, "r", awesome.restart,
410 {description = "reload awesome", group = "awesome"}),
411 awful.key({ modkey, "Shift" }, "q", awesome.quit,
412 {description = "quit awesome", group = "awesome"}),
414 awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
415 {description = "increase master width factor", group = "layout"}),
416 awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
417 {description = "decrease master width factor", group = "layout"}),
418 awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
419 {description = "increase the number of master clients", group = "layout"}),
420 awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
421 {description = "decrease the number of master clients", group = "layout"}),
422 awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
423 {description = "increase the number of columns", group = "layout"}),
424 awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
425 {description = "decrease the number of columns", group = "layout"}),
426 awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
427 {description = "select next", group = "layout"}),
428 awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
429 {description = "select previous", group = "layout"}),
431 awful.key({ modkey, "Control" }, "n",
433 local c = awful.client.restore()
434 -- Focus restored client
440 {description = "restore minimized", group = "client"}),
443 awful.key({ modkey }, "r", function () mypromptbox[awful.screen.focused()]:run() end,
444 {description = "run prompt", group = "launcher"}),
446 awful.key({ modkey }, "x",
448 awful.prompt.run({ prompt = "Run Lua code: " },
449 mypromptbox[awful.screen.focused()].widget,
450 awful.util.eval, nil,
451 awful.util.get_cache_dir() .. "/history_eval")
453 {description = "lua execute prompt", group = "awesome"}),
455 awful.key({ modkey }, "p", function() menubar.show() end,
456 {description = "show the menubar", group = "launcher"})
459 clientkeys = awful.util.table.join(
460 awful.key({ modkey, }, "f",
462 c.fullscreen = not c.fullscreen
465 {description = "toggle fullscreen", group = "client"}),
466 awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
467 {description = "close", group = "client"}),
468 awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
469 {description = "toggle floating", group = "client"}),
470 awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
471 {description = "move to master", group = "client"}),
472 awful.key({ modkey, }, "o", function (c) c:move_to_screen() end,
473 {description = "move to screen", group = "client"}),
474 awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
475 {description = "toggle keep on top", group = "client"}),
476 awful.key({ modkey, }, "n",
478 -- The client currently has the input focus, so it cannot be
479 -- minimized, since minimized clients can't have the focus.
482 {description = "minimize", group = "client"}),
483 awful.key({ modkey, }, "m",
485 c.maximized = not c.maximized
488 {description = "maximize", group = "client"})
491 -- Bind all key numbers to tags.
492 -- Be careful: we use keycodes to make it works on any keyboard layout.
493 -- This should map on the top row of your keyboard, usually 1 to 9.
495 globalkeys = awful.util.table.join(globalkeys,
497 awful.key({ modkey }, "#" .. i + 9,
499 local screen = awful.screen.focused()
500 local tag = screen.tags[i]
505 {description = "view tag #"..i, group = "tag"}),
507 awful.key({ modkey, "Control" }, "#" .. i + 9,
509 local screen = awful.screen.focused()
510 local tag = screen.tags[i]
512 awful.tag.viewtoggle(tag)
515 {description = "toggle tag #" .. i, group = "tag"}),
516 -- Move client to tag.
517 awful.key({ modkey, "Shift" }, "#" .. i + 9,
520 local tag = client.focus.screen.tags[i]
522 client.focus:move_to_tag(tag)
526 {description = "move focused client to tag #"..i, group = "tag"}),
527 -- Toggle tag on focused client.
528 awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
531 local tag = client.focus.screen.tags[i]
533 client.focus:toggle_tag(tag)
537 {description = "toggle focused client on tag #" .. i, group = "tag"})
541 clientbuttons = awful.util.table.join(
542 awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
543 awful.button({ modkey }, 1, awful.mouse.client.move),
544 awful.button({ modkey }, 3, awful.mouse.client.resize))
547 globalkeys = awful.util.table.join(globalkeys,
548 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
549 awful.key({ cmdkey }, "m", function () awful.spawn("chromium") end),
550 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
551 awful.key({ cmdkey }, "c", function () awful.spawn("icedove") end),
552 awful.key({ cmdkey }, "r", function () mypromptbox[mouse.screen]:run() end),
553 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
554 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
555 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
556 awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
557 awful.key({ cmdkey }, "i", function () awful.spawn(terminal .. " -title irc -name irc -e env MOSH_TITLE_NOPREFIX=true mosh -4 -- irc-host screen -dr irc") end),
558 awful.key({ cmdkey }, "x", function () awful.spawn.with_shell("/sbin/start-stop-daemon --start --background --exec /usr/bin/xscreensaver -- -no-capture-stderr; sleep 2; xscreensaver-command -lock") end),
559 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
562 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
563 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
564 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
565 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
566 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
567 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
568 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
569 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute 1 toggle") end),
570 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute 1 toggle") end),
571 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
572 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
573 awful.key(nil, "XF86Display", function () awful.spawn("") end),
574 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
575 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
576 awful.key(nil, "XF86Search", function () awful.spawn("") end),
577 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
578 awful.key(nil, "XF86Explorer", function () awful.spawn("") end)
582 root.keys(globalkeys)
586 -- Rules to apply to new clients (through the "manage" signal).
588 local function move_to_tag(s, t)
590 c:move_to_tag(tags[s][t])
594 awful.rules.rules = {
595 -- All clients will match this rule.
597 properties = { border_width = beautiful.border_width,
598 border_color = beautiful.border_normal,
599 focus = awful.client.focus.filter,
602 buttons = clientbuttons,
603 screen = awful.screen.preferred,
604 placement = awful.placement.no_overlap+awful.placement.no_offscreen,
609 -- Add titlebars to normal clients and dialogs
610 --DISABLED-- { rule_any = {type = { "normal", "dialog" }
611 --DISABLED-- }, properties = { titlebars_enabled = true }
614 { rule = { type = "dialog" },
615 properties = { placement = awful.placement.centered }},
617 { rule = { class = "URxvt" },
620 size_hints_honor = false
622 { rule = { class = "URxvt", instance = "irc" },
626 callback = move_to_tag(screen.count(), screen.count() == 1 and 2 or 1)
628 { rule = { class = "Firefox", instance = "Navigator" },
632 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
634 { rule = { class = "Icedove", instance = "Mail" },
638 callback = move_to_tag(screen.count() == 1 and 1 or 2, 8)
640 { rule = { class = "Chromium", instance = "chromium" },
644 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
646 { rule = { class = "Gscan2pdf" },
650 callback = move_to_tag(1, 5)
652 { rule = { name = "gscan2pdf .*" },
657 { rule = { class = "Thunar", type = "normal" },
666 -- Signal function to execute when a new client appears.
667 client.connect_signal("manage", function (c)
668 -- Set the windows at the slave,
669 -- i.e. put it at the end of others instead of setting it master.
670 -- if not awesome.startup then awful.client.setslave(c) end
672 if awesome.startup and
673 not c.size_hints.user_position
674 and not c.size_hints.program_position then
675 -- Prevent clients from being unreachable after screen count changes.
676 awful.placement.no_offscreen(c)
680 -- Add a titlebar if titlebars_enabled is set to true in the rules.
681 client.connect_signal("request::titlebars", function(c)
682 -- buttons for the titlebar
683 local buttons = awful.util.table.join(
684 awful.button({ }, 1, function()
687 awful.mouse.client.move(c)
689 awful.button({ }, 3, function()
692 awful.mouse.client.resize(c)
696 awful.titlebar(c) : setup {
698 awful.titlebar.widget.iconwidget(c),
700 layout = wibox.layout.fixed.horizontal
705 widget = awful.titlebar.widget.titlewidget(c)
708 layout = wibox.layout.flex.horizontal
711 awful.titlebar.widget.floatingbutton (c),
712 awful.titlebar.widget.maximizedbutton(c),
713 awful.titlebar.widget.stickybutton (c),
714 awful.titlebar.widget.ontopbutton (c),
715 awful.titlebar.widget.closebutton (c),
716 layout = wibox.layout.fixed.horizontal()
718 layout = wibox.layout.align.horizontal
722 -- Enable sloppy focus
723 client.connect_signal("mouse::enter", function(c)
724 if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
725 and awful.client.focus.filter(c) then
730 client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
731 client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
733 awful.ewmh.add_activate_filter(function(c, context, hints)
734 if context == "ewmh" and c.class == "Firefox" then return false end
737 -- vim:ft=lua:sw=4:sts=4:ts=4:et