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 = "↑" end
132 widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
136 local function poloniex_price(output, pair, prec)
137 local xc, pos, err = dkjson.decode(output, 1, nil)
138 if not prec then prec = 4 end
139 val = (xc and xc[pair]["last"]) or 0
140 val = math.floor(val*10^prec+0.5)/10^prec
141 return (not err and val) or "n/a"
144 local eth_widget = lain.widgets.abase({
145 cmd = "curl -m5 -s 'https://poloniex.com/public?command=returnTicker'",
147 settings = function()
148 widget:set_text(poloniex_price(output, 'BTC_ETH') .. " Ƀ/Ξ")
152 local function coindesk_price(output, base, prec)
154 local xc, pos, err = dkjson.decode(output, 1, nil)
155 if not prec then prec = 4 end
156 val = (xc and xc["bpi"][base]["rate_float"]) or 0
157 val = math.floor(val*10^prec+0.5)/10^prec
158 return (not err and val) or "n/a"
161 local btc_widget = lain.widgets.abase({
162 cmd = "curl -m5 -Ls 'https://api.coindesk.com/v1/bpi/currentprice/EUR.json'",
164 settings = function()
165 widget:set_text(coindesk_price(output, "EUR", 2) .. " €/Ƀ")
172 -- Create a launcher widget and a main menu
174 { "hotkeys", function() return false, hotkeys_popup.show_help end},
175 { "manual", terminal .. " -e man awesome" },
176 { "edit config", editor_cmd .. " " .. awesome.conffile },
177 { "restart", awesome.restart },
178 { "quit", awesome.quit }
181 mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
182 { "open terminal", terminal }
186 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
190 -- {{{ Menubar configuration
191 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
195 local spacer = wibox.widget.textbox()
196 spacer:set_text(' | ')
197 -- Create a textclock widget
198 mytextclock = wibox.widget.textclock("%a %d %b %H:%M:%S", 1)
200 -- Create a wibox for each screen and add it
205 mytaglist.buttons = awful.util.table.join(
206 awful.button({ }, 1, function(t) t:view_only() end),
207 awful.button({ modkey }, 1, function(t)
209 client.focus:move_to_tag(t)
212 awful.button({ }, 3, awful.tag.viewtoggle),
213 awful.button({ modkey }, 3, function(t)
215 client.focus:toggle_tag(t)
218 awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
219 awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
223 mytasklist.buttons = awful.util.table.join(
224 awful.button({ }, 1, function (c)
225 if c == client.focus then
226 -- I don't like click-minimising
227 -- c.minimized = true
229 -- Without this, the following
230 -- :isvisible() makes no sense
232 if not c:isvisible() and c.first_tag then
233 c.first_tag:view_only()
235 -- This will also un-minimize
236 -- the client, if needed
241 awful.button({ }, 3, client_menu_toggle_fn()),
242 awful.button({ }, 4, function ()
243 awful.client.focus.byidx(1)
245 awful.button({ }, 5, function ()
246 awful.client.focus.byidx(-1)
253 tags.config["main"] = {
254 t1 = { layout = layout_default, selected = true },
255 t2 = { layout = layout_default },
256 t3 = { layout = layout_tiled },
257 t4 = { layout = layout_tiled },
258 t5 = { layout = layout_tiled },
259 t6 = { layout = layout_floating },
260 t7 = { layout = layout_maximised },
261 t8 = { layout = layout_maximised },
262 t9 = { layout = layout_maximised },
264 tags.config["aux"] = {
265 t1 = { layout = layout_default, selected = true },
266 t2 = { layout = layout_default },
267 t3 = { layout = layout_tiled },
268 t4 = { layout = layout_floating },
269 t5 = { layout = layout_floating },
270 t6 = { layout = layout_floating },
271 t7 = { layout = layout_floating },
272 t8 = { layout = layout_floating },
273 t9 = { layout = layout_maximised },
277 screentags[1] = tags.config["main"]
278 if screen.count() == 2 then -- aux screen is on the right
279 screentags[2] = tags.config["aux"]
280 elseif screen.count() == 3 then -- main screen is still #1 in the middle
281 screentags[2] = tags.config["aux"]
282 screentags[3] = tags.config["aux"]
285 awful.screen.connect_for_each_screen(function(s)
287 --DISABLED--if beautiful.wallpaper then
288 --DISABLED-- local wallpaper = beautiful.wallpaper
289 --DISABLED-- -- If wallpaper is a function, call it with the screen
290 --DISABLED-- if type(wallpaper) == "function" then
291 --DISABLED-- wallpaper = wallpaper(s)
293 --DISABLED-- gears.wallpaper.maximized(wallpaper, s, true)
296 if not tags[s.index] then
299 for n,p in sorted_pairs(screentags[s.index]) do
301 n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
302 table.insert(tags[s.index], awful.tag.add(n, p))
305 -- Create a promptbox for each screen
306 mypromptbox[s] = awful.widget.prompt()
307 -- Create an imagebox widget which will contains an icon indicating which layout we're using.
308 -- We need one layoutbox per screen.
309 mylayoutbox[s] = awful.widget.layoutbox(s)
310 mylayoutbox[s]:buttons(awful.util.table.join(
311 awful.button({ }, 1, function () awful.layout.inc( 1) end),
312 awful.button({ }, 3, function () awful.layout.inc(-1) end),
313 awful.button({ }, 4, function () awful.layout.inc( 1) end),
314 awful.button({ }, 5, function () awful.layout.inc(-1) end)))
315 -- Create a taglist widget
316 mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
318 -- Create a tasklist widget
319 mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
322 mywibox[s] = awful.wibar({ position = "top", screen = s })
324 -- Add widgets to the wibox
326 layout = wibox.layout.align.horizontal,
328 layout = wibox.layout.fixed.horizontal,
333 mytasklist[s], -- Middle widget
335 layout = wibox.layout.fixed.horizontal,
337 wibox.widget.systray(),
351 -- {{{ Mouse bindings
352 root.buttons(awful.util.table.join(
353 awful.button({ }, 3, function () mymainmenu:toggle() end),
354 awful.button({ }, 4, awful.tag.viewnext),
355 awful.button({ }, 5, awful.tag.viewprev)
360 globalkeys = awful.util.table.join(
361 awful.key({ modkey, }, "s", hotkeys_popup.show_help,
362 {description="show help", group="awesome"}),
363 awful.key({ modkey, }, "Left", awful.tag.viewprev,
364 {description = "view previous", group = "tag"}),
365 awful.key({ modkey, }, "Right", awful.tag.viewnext,
366 {description = "view next", group = "tag"}),
367 awful.key({ modkey, }, "Escape", awful.tag.history.restore,
368 {description = "go back", group = "tag"}),
370 awful.key({ modkey, }, "k",
372 awful.client.focus.byidx( 1)
374 {description = "focus next by index", group = "client"}
376 awful.key({ modkey, }, "j",
378 awful.client.focus.byidx(-1)
380 {description = "focus previous by index", group = "client"}
382 awful.key({ modkey, }, "w", function () mymainmenu:show() end,
383 {description = "show main menu", group = "awesome"}),
385 -- Layout manipulation
386 awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( 1) end,
387 {description = "swap with next client by index", group = "client"}),
388 awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( -1) end,
389 {description = "swap with previous client by index", group = "client"}),
390 awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
391 {description = "focus the next screen", group = "screen"}),
392 awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
393 {description = "focus the previous screen", group = "screen"}),
394 awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
395 {description = "jump to urgent client", group = "client"}),
396 awful.key({ modkey, }, "Tab",
398 awful.client.focus.history.previous()
403 {description = "go back", group = "client"}),
406 awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
407 {description = "open a terminal", group = "launcher"}),
408 awful.key({ modkey, "Control" }, "r", awesome.restart,
409 {description = "reload awesome", group = "awesome"}),
410 awful.key({ modkey, "Shift" }, "q", awesome.quit,
411 {description = "quit awesome", group = "awesome"}),
413 awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
414 {description = "increase master width factor", group = "layout"}),
415 awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
416 {description = "decrease master width factor", group = "layout"}),
417 awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
418 {description = "increase the number of master clients", group = "layout"}),
419 awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
420 {description = "decrease the number of master clients", group = "layout"}),
421 awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
422 {description = "increase the number of columns", group = "layout"}),
423 awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
424 {description = "decrease the number of columns", group = "layout"}),
425 awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
426 {description = "select next", group = "layout"}),
427 awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
428 {description = "select previous", group = "layout"}),
430 awful.key({ modkey, "Control" }, "n",
432 local c = awful.client.restore()
433 -- Focus restored client
439 {description = "restore minimized", group = "client"}),
442 awful.key({ modkey }, "r", function () mypromptbox[awful.screen.focused()]:run() end,
443 {description = "run prompt", group = "launcher"}),
445 awful.key({ modkey }, "x",
447 awful.prompt.run({ prompt = "Run Lua code: " },
448 mypromptbox[awful.screen.focused()].widget,
449 awful.util.eval, nil,
450 awful.util.get_cache_dir() .. "/history_eval")
452 {description = "lua execute prompt", group = "awesome"}),
454 awful.key({ modkey }, "p", function() menubar.show() end,
455 {description = "show the menubar", group = "launcher"})
458 clientkeys = awful.util.table.join(
459 awful.key({ modkey, }, "f",
461 c.fullscreen = not c.fullscreen
464 {description = "toggle fullscreen", group = "client"}),
465 awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
466 {description = "close", group = "client"}),
467 awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
468 {description = "toggle floating", group = "client"}),
469 awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
470 {description = "move to master", group = "client"}),
471 awful.key({ modkey, }, "o", function (c) c:move_to_screen() end,
472 {description = "move to screen", group = "client"}),
473 awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
474 {description = "toggle keep on top", group = "client"}),
475 awful.key({ modkey, }, "n",
477 -- The client currently has the input focus, so it cannot be
478 -- minimized, since minimized clients can't have the focus.
481 {description = "minimize", group = "client"}),
482 awful.key({ modkey, }, "m",
484 c.maximized = not c.maximized
487 {description = "maximize", group = "client"})
490 -- Bind all key numbers to tags.
491 -- Be careful: we use keycodes to make it works on any keyboard layout.
492 -- This should map on the top row of your keyboard, usually 1 to 9.
494 globalkeys = awful.util.table.join(globalkeys,
496 awful.key({ modkey }, "#" .. i + 9,
498 local screen = awful.screen.focused()
499 local tag = screen.tags[i]
504 {description = "view tag #"..i, group = "tag"}),
506 awful.key({ modkey, "Control" }, "#" .. i + 9,
508 local screen = awful.screen.focused()
509 local tag = screen.tags[i]
511 awful.tag.viewtoggle(tag)
514 {description = "toggle tag #" .. i, group = "tag"}),
515 -- Move client to tag.
516 awful.key({ modkey, "Shift" }, "#" .. i + 9,
519 local tag = client.focus.screen.tags[i]
521 client.focus:move_to_tag(tag)
525 {description = "move focused client to tag #"..i, group = "tag"}),
526 -- Toggle tag on focused client.
527 awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
530 local tag = client.focus.screen.tags[i]
532 client.focus:toggle_tag(tag)
536 {description = "toggle focused client on tag #" .. i, group = "tag"})
540 clientbuttons = awful.util.table.join(
541 awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
542 awful.button({ modkey }, 1, awful.mouse.client.move),
543 awful.button({ modkey }, 3, awful.mouse.client.resize))
546 globalkeys = awful.util.table.join(globalkeys,
547 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
548 awful.key({ cmdkey }, "m", function () awful.spawn("chromium") end),
549 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
550 awful.key({ cmdkey }, "c", function () awful.spawn("icedove") end),
551 awful.key({ cmdkey }, "r", function () mypromptbox[mouse.screen]:run() end),
552 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
553 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
554 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
555 awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
556 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),
557 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),
558 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
561 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
562 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
563 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
564 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
565 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
566 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
567 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
568 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute 1 toggle") end),
569 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute 1 toggle") end),
570 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
571 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
572 awful.key(nil, "XF86Display", function () awful.spawn("") end),
573 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
574 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
575 awful.key(nil, "XF86Search", function () awful.spawn("") end),
576 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
577 awful.key(nil, "XF86Explorer", function () awful.spawn("") end)
581 root.keys(globalkeys)
585 -- Rules to apply to new clients (through the "manage" signal).
587 local function move_to_tag(s, t)
589 c:move_to_tag(tags[s][t])
593 awful.rules.rules = {
594 -- All clients will match this rule.
596 properties = { border_width = beautiful.border_width,
597 border_color = beautiful.border_normal,
598 focus = awful.client.focus.filter,
601 buttons = clientbuttons,
602 screen = awful.screen.preferred,
603 placement = awful.placement.no_overlap+awful.placement.no_offscreen,
608 -- Add titlebars to normal clients and dialogs
609 --DISABLED-- { rule_any = {type = { "normal", "dialog" }
610 --DISABLED-- }, properties = { titlebars_enabled = true }
613 { rule = { type = "dialog" },
614 properties = { placement = awful.placement.centered }},
616 { rule = { class = "URxvt" },
619 size_hints_honor = false
621 { rule = { class = "URxvt", instance = "irc" },
625 callback = move_to_tag(screen.count(), screen.count() == 1 and 2 or 1)
627 { rule = { class = "Firefox", instance = "Navigator" },
631 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
633 { rule = { class = "Icedove", instance = "Mail" },
637 callback = move_to_tag(screen.count() == 1 and 1 or 2, 8)
639 { rule = { class = "Chromium", instance = "chromium" },
643 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
645 { rule = { class = "Gscan2pdf" },
649 callback = move_to_tag(1, 5)
651 { rule = { name = "gscan2pdf .*" },
656 { rule = { class = "Thunar", type = "normal" },
665 -- Signal function to execute when a new client appears.
666 client.connect_signal("manage", function (c)
667 -- Set the windows at the slave,
668 -- i.e. put it at the end of others instead of setting it master.
669 -- if not awesome.startup then awful.client.setslave(c) end
671 if awesome.startup and
672 not c.size_hints.user_position
673 and not c.size_hints.program_position then
674 -- Prevent clients from being unreachable after screen count changes.
675 awful.placement.no_offscreen(c)
679 -- Add a titlebar if titlebars_enabled is set to true in the rules.
680 client.connect_signal("request::titlebars", function(c)
681 -- buttons for the titlebar
682 local buttons = awful.util.table.join(
683 awful.button({ }, 1, function()
686 awful.mouse.client.move(c)
688 awful.button({ }, 3, function()
691 awful.mouse.client.resize(c)
695 awful.titlebar(c) : setup {
697 awful.titlebar.widget.iconwidget(c),
699 layout = wibox.layout.fixed.horizontal
704 widget = awful.titlebar.widget.titlewidget(c)
707 layout = wibox.layout.flex.horizontal
710 awful.titlebar.widget.floatingbutton (c),
711 awful.titlebar.widget.maximizedbutton(c),
712 awful.titlebar.widget.stickybutton (c),
713 awful.titlebar.widget.ontopbutton (c),
714 awful.titlebar.widget.closebutton (c),
715 layout = wibox.layout.fixed.horizontal()
717 layout = wibox.layout.align.horizontal
721 -- Enable sloppy focus
722 client.connect_signal("mouse::enter", function(c)
723 if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
724 and awful.client.focus.filter(c) then
729 client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
730 client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
732 awful.ewmh.add_activate_filter(function(c, context, hints)
733 if context == "ewmh" and c.class == "Firefox" then return false end
736 -- vim:ft=lua:sw=4:sts=4:ts=4:et