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")
18 -- Check if awesome encountered an error during startup and fell back to
19 -- another config (This code will only ever execute for the fallback config)
20 if awesome.startup_errors then
21 naughty.notify({ preset = naughty.config.presets.critical,
22 title = "Oops, there were errors during startup!",
23 text = awesome.startup_errors })
26 -- Handle runtime errors after startup
28 local in_error = false
29 awesome.connect_signal("debug::error", function (err)
30 -- Make sure we don't go into an endless error loop
31 if in_error then return end
34 naughty.notify({ preset = naughty.config.presets.critical,
35 title = "Oops, an error happened!",
36 text = tostring(err) })
42 -- {{{ Variable definitions
43 -- Themes define colours, icons, and wallpapers
44 beautiful.init(awful.util.get_themes_dir() .. "default/theme.lua")
46 -- This is used later as the default terminal and editor to run.
47 terminal = "x-terminal-emulator"
48 editor = "sensible-editor"
49 editor_cmd = terminal .. " -e " .. editor
52 -- Usually, Mod4 is the key with a logo between Control and Alt.
53 -- If you do not like this or do not have such a key,
54 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
55 -- However, you can use another modifier like Mod1, but it may interact with others.
59 -- Table of layouts to cover with awful.layout.inc, order matters.
60 awful.layout.layouts = {
61 awful.layout.suit.fair,
62 awful.layout.suit.tile,
63 -- awful.layout.suit.tile.left,
64 -- awful.layout.suit.tile.bottom,
65 awful.layout.suit.tile.top,
66 -- awful.layout.suit.spiral,
67 -- awful.layout.suit.spiral.dwindle,
68 awful.layout.suit.max,
69 -- awful.layout.suit.max.fullscreen,
70 -- awful.layout.suit.magnifier,
71 -- awful.layout.suit.corner.nw,
72 -- awful.layout.suit.corner.ne,
73 -- awful.layout.suit.corner.sw,
74 -- awful.layout.suit.corner.se,
75 awful.layout.suit.floating,
78 layout_default = awful.layout.layouts[1]
79 layout_tiled = awful.layout.layouts[2]
80 layout_maximised = awful.layout.layouts[4]
81 layout_floating = awful.layout.layouts[5]
84 -- {{{ Helper functions
85 local function client_menu_toggle_fn()
89 if instance and instance.wibox.visible then
93 instance = awful.menu.clients({ theme = { width = 250 } })
98 local function sorted_pairs(t, f)
100 for n in pairs(t) do table.insert(a, n) end
102 local i = 0 -- iterator variable
103 local iter = function () -- iterator function
105 if a[i] == nil then return nil
106 else return a[i], t[a[i]]
112 local function print_table(tbl, indent)
113 if not indent then indent = 0 end
114 for k, v in pairs(tbl) do
115 formatting = string.rep(" ", indent) .. k .. ": "
116 if type(v) == "table" then
118 print_table(v, indent+1)
120 print(formatting .. tostring(v))
125 local lain_bat = lain.widgets.bat({
126 batteries = {"BAT0", "BAT1"},
127 settings = function()
129 if bat_now.status == "1" then delim = "↑" end
130 widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
134 local function poloniex_price(output, pair, accuracy)
135 local xc, pos, err = require("lain.util").dkjson.decode(output, 1, nil)
136 if not accuracy then accuracy = 4 end
137 val = (xc and xc[pair]["last"]) or 0
138 val = val - val % (1/(10^accuracy))
139 return (not err and val) or "n/a"
142 local xc_widget = lain.widgets.abase({
143 cmd = "curl -m5 -s 'https://poloniex.com/public?command=returnTicker'",
145 settings = function()
146 widget:set_text(poloniex_price(output, 'BTC_ETH') .. " Ƀ/Ξ")
153 -- Create a launcher widget and a main menu
155 { "hotkeys", function() return false, hotkeys_popup.show_help end},
156 { "manual", terminal .. " -e man awesome" },
157 { "edit config", editor_cmd .. " " .. awesome.conffile },
158 { "restart", awesome.restart },
159 { "quit", awesome.quit }
162 mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
163 { "open terminal", terminal }
167 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
171 -- {{{ Menubar configuration
172 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
176 local spacer = wibox.widget.textbox()
177 spacer:set_text(' | ')
178 -- Create a textclock widget
179 mytextclock = wibox.widget.textclock("%a %d %b %H:%M:%S", 1)
181 -- Create a wibox for each screen and add it
186 mytaglist.buttons = awful.util.table.join(
187 awful.button({ }, 1, function(t) t:view_only() end),
188 awful.button({ modkey }, 1, function(t)
190 client.focus:move_to_tag(t)
193 awful.button({ }, 3, awful.tag.viewtoggle),
194 awful.button({ modkey }, 3, function(t)
196 client.focus:toggle_tag(t)
199 awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
200 awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
204 mytasklist.buttons = awful.util.table.join(
205 awful.button({ }, 1, function (c)
206 if c == client.focus then
207 -- I don't like click-minimising
208 -- c.minimized = true
210 -- Without this, the following
211 -- :isvisible() makes no sense
213 if not c:isvisible() and c.first_tag then
214 c.first_tag:view_only()
216 -- This will also un-minimize
217 -- the client, if needed
222 awful.button({ }, 3, client_menu_toggle_fn()),
223 awful.button({ }, 4, function ()
224 awful.client.focus.byidx(1)
226 awful.button({ }, 5, function ()
227 awful.client.focus.byidx(-1)
234 tags.config["main"] = {
235 t1 = { layout = layout_default, selected = true },
236 t2 = { layout = layout_default },
237 t3 = { layout = layout_tiled },
238 t4 = { layout = layout_tiled },
239 t5 = { layout = layout_tiled },
240 t6 = { layout = layout_floating },
241 t7 = { layout = layout_maximised },
242 t8 = { layout = layout_maximised },
243 t9 = { layout = layout_maximised },
245 tags.config["aux"] = {
246 t1 = { layout = layout_default, selected = true },
247 t2 = { layout = layout_default },
248 t3 = { layout = layout_tiled },
249 t4 = { layout = layout_floating },
250 t5 = { layout = layout_floating },
251 t6 = { layout = layout_floating },
252 t7 = { layout = layout_floating },
253 t8 = { layout = layout_floating },
254 t9 = { layout = layout_maximised },
258 screentags[1] = tags.config["main"]
259 if screen.count() == 2 then -- aux screen is on the right
260 screentags[2] = tags.config["aux"]
261 elseif screen.count() == 3 then -- main screen is still #1 in the middle
262 screentags[2] = tags.config["aux"]
263 screentags[3] = tags.config["aux"]
266 awful.screen.connect_for_each_screen(function(s)
268 --DISABLED--if beautiful.wallpaper then
269 --DISABLED-- local wallpaper = beautiful.wallpaper
270 --DISABLED-- -- If wallpaper is a function, call it with the screen
271 --DISABLED-- if type(wallpaper) == "function" then
272 --DISABLED-- wallpaper = wallpaper(s)
274 --DISABLED-- gears.wallpaper.maximized(wallpaper, s, true)
277 if not tags[s.index] then
280 for n,p in sorted_pairs(screentags[s.index]) do
282 n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
283 table.insert(tags[s.index], awful.tag.add(n, p))
286 -- Create a promptbox for each screen
287 mypromptbox[s] = awful.widget.prompt()
288 -- Create an imagebox widget which will contains an icon indicating which layout we're using.
289 -- We need one layoutbox per screen.
290 mylayoutbox[s] = awful.widget.layoutbox(s)
291 mylayoutbox[s]:buttons(awful.util.table.join(
292 awful.button({ }, 1, function () awful.layout.inc( 1) end),
293 awful.button({ }, 3, function () awful.layout.inc(-1) end),
294 awful.button({ }, 4, function () awful.layout.inc( 1) end),
295 awful.button({ }, 5, function () awful.layout.inc(-1) end)))
296 -- Create a taglist widget
297 mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
299 -- Create a tasklist widget
300 mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
303 mywibox[s] = awful.wibar({ position = "top", screen = s })
305 -- Add widgets to the wibox
307 layout = wibox.layout.align.horizontal,
309 layout = wibox.layout.fixed.horizontal,
314 mytasklist[s], -- Middle widget
316 layout = wibox.layout.fixed.horizontal,
318 wibox.widget.systray(),
330 -- {{{ Mouse bindings
331 root.buttons(awful.util.table.join(
332 awful.button({ }, 3, function () mymainmenu:toggle() end),
333 awful.button({ }, 4, awful.tag.viewnext),
334 awful.button({ }, 5, awful.tag.viewprev)
339 globalkeys = awful.util.table.join(
340 awful.key({ modkey, }, "s", hotkeys_popup.show_help,
341 {description="show help", group="awesome"}),
342 awful.key({ modkey, }, "Left", awful.tag.viewprev,
343 {description = "view previous", group = "tag"}),
344 awful.key({ modkey, }, "Right", awful.tag.viewnext,
345 {description = "view next", group = "tag"}),
346 awful.key({ modkey, }, "Escape", awful.tag.history.restore,
347 {description = "go back", group = "tag"}),
349 awful.key({ modkey, }, "k",
351 awful.client.focus.byidx( 1)
353 {description = "focus next by index", group = "client"}
355 awful.key({ modkey, }, "j",
357 awful.client.focus.byidx(-1)
359 {description = "focus previous by index", group = "client"}
361 awful.key({ modkey, }, "w", function () mymainmenu:show() end,
362 {description = "show main menu", group = "awesome"}),
364 -- Layout manipulation
365 awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( 1) end,
366 {description = "swap with next client by index", group = "client"}),
367 awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( -1) end,
368 {description = "swap with previous client by index", group = "client"}),
369 awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
370 {description = "focus the next screen", group = "screen"}),
371 awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
372 {description = "focus the previous screen", group = "screen"}),
373 awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
374 {description = "jump to urgent client", group = "client"}),
375 awful.key({ modkey, }, "Tab",
377 awful.client.focus.history.previous()
382 {description = "go back", group = "client"}),
385 awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
386 {description = "open a terminal", group = "launcher"}),
387 awful.key({ modkey, "Control" }, "r", awesome.restart,
388 {description = "reload awesome", group = "awesome"}),
389 awful.key({ modkey, "Shift" }, "q", awesome.quit,
390 {description = "quit awesome", group = "awesome"}),
392 awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
393 {description = "increase master width factor", group = "layout"}),
394 awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
395 {description = "decrease master width factor", group = "layout"}),
396 awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
397 {description = "increase the number of master clients", group = "layout"}),
398 awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
399 {description = "decrease the number of master clients", group = "layout"}),
400 awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
401 {description = "increase the number of columns", group = "layout"}),
402 awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
403 {description = "decrease the number of columns", group = "layout"}),
404 awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
405 {description = "select next", group = "layout"}),
406 awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
407 {description = "select previous", group = "layout"}),
409 awful.key({ modkey, "Control" }, "n",
411 local c = awful.client.restore()
412 -- Focus restored client
418 {description = "restore minimized", group = "client"}),
421 awful.key({ modkey }, "r", function () mypromptbox[awful.screen.focused()]:run() end,
422 {description = "run prompt", group = "launcher"}),
424 awful.key({ modkey }, "x",
426 awful.prompt.run({ prompt = "Run Lua code: " },
427 mypromptbox[awful.screen.focused()].widget,
428 awful.util.eval, nil,
429 awful.util.get_cache_dir() .. "/history_eval")
431 {description = "lua execute prompt", group = "awesome"}),
433 awful.key({ modkey }, "p", function() menubar.show() end,
434 {description = "show the menubar", group = "launcher"})
437 clientkeys = awful.util.table.join(
438 awful.key({ modkey, }, "f",
440 c.fullscreen = not c.fullscreen
443 {description = "toggle fullscreen", group = "client"}),
444 awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
445 {description = "close", group = "client"}),
446 awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
447 {description = "toggle floating", group = "client"}),
448 awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
449 {description = "move to master", group = "client"}),
450 awful.key({ modkey, }, "o", function (c) c:move_to_screen() end,
451 {description = "move to screen", group = "client"}),
452 awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
453 {description = "toggle keep on top", group = "client"}),
454 awful.key({ modkey, }, "n",
456 -- The client currently has the input focus, so it cannot be
457 -- minimized, since minimized clients can't have the focus.
460 {description = "minimize", group = "client"}),
461 awful.key({ modkey, }, "m",
463 c.maximized = not c.maximized
466 {description = "maximize", group = "client"})
469 -- Bind all key numbers to tags.
470 -- Be careful: we use keycodes to make it works on any keyboard layout.
471 -- This should map on the top row of your keyboard, usually 1 to 9.
473 globalkeys = awful.util.table.join(globalkeys,
475 awful.key({ modkey }, "#" .. i + 9,
477 local screen = awful.screen.focused()
478 local tag = screen.tags[i]
483 {description = "view tag #"..i, group = "tag"}),
485 awful.key({ modkey, "Control" }, "#" .. i + 9,
487 local screen = awful.screen.focused()
488 local tag = screen.tags[i]
490 awful.tag.viewtoggle(tag)
493 {description = "toggle tag #" .. i, group = "tag"}),
494 -- Move client to tag.
495 awful.key({ modkey, "Shift" }, "#" .. i + 9,
498 local tag = client.focus.screen.tags[i]
500 client.focus:move_to_tag(tag)
504 {description = "move focused client to tag #"..i, group = "tag"}),
505 -- Toggle tag on focused client.
506 awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
509 local tag = client.focus.screen.tags[i]
511 client.focus:toggle_tag(tag)
515 {description = "toggle focused client on tag #" .. i, group = "tag"})
519 clientbuttons = awful.util.table.join(
520 awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
521 awful.button({ modkey }, 1, awful.mouse.client.move),
522 awful.button({ modkey }, 3, awful.mouse.client.resize))
525 globalkeys = awful.util.table.join(globalkeys,
526 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
527 awful.key({ cmdkey }, "m", function () awful.spawn("chromium") end),
528 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
529 awful.key({ cmdkey }, "c", function () awful.spawn("icedove") end),
530 awful.key({ cmdkey }, "r", function () mypromptbox[mouse.screen]:run() end),
531 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
532 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
533 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
534 awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
535 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),
536 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),
537 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
540 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
541 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
542 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
543 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
544 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
545 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
546 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
547 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute 1 toggle") end),
548 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute 1 toggle") end),
549 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
550 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
551 awful.key(nil, "XF86Display", function () awful.spawn("") end),
552 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
553 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
554 awful.key(nil, "XF86Search", function () awful.spawn("") end),
555 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
556 awful.key(nil, "XF86Explorer", function () awful.spawn("") end)
560 root.keys(globalkeys)
564 -- Rules to apply to new clients (through the "manage" signal).
566 local function move_to_tag(s, t)
568 c:move_to_tag(tags[s][t])
572 awful.rules.rules = {
573 -- All clients will match this rule.
575 properties = { border_width = beautiful.border_width,
576 border_color = beautiful.border_normal,
577 focus = awful.client.focus.filter,
580 buttons = clientbuttons,
581 screen = awful.screen.preferred,
582 placement = awful.placement.no_overlap+awful.placement.no_offscreen,
587 -- Add titlebars to normal clients and dialogs
588 --DISABLED-- { rule_any = {type = { "normal", "dialog" }
589 --DISABLED-- }, properties = { titlebars_enabled = true }
592 { rule = { type = "dialog" },
593 properties = { placement = awful.placement.centered }},
595 { rule = { class = "URxvt" },
598 size_hints_honor = false
600 { rule = { class = "URxvt", instance = "irc" },
604 callback = move_to_tag(screen.count(), screen.count() == 1 and 2 or 1)
606 { rule = { class = "Firefox", instance = "Navigator" },
610 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
612 { rule = { class = "Icedove", instance = "Mail" },
616 callback = move_to_tag(screen.count() == 1 and 1 or 2, 8)
618 { rule = { class = "Chromium", instance = "chromium" },
622 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
624 { rule = { class = "Gscan2pdf" },
628 callback = move_to_tag(1, 5)
630 { rule = { name = "gscan2pdf .*" },
635 { rule = { class = "Thunar", type = "normal" },
644 -- Signal function to execute when a new client appears.
645 client.connect_signal("manage", function (c)
646 -- Set the windows at the slave,
647 -- i.e. put it at the end of others instead of setting it master.
648 -- if not awesome.startup then awful.client.setslave(c) end
650 if awesome.startup and
651 not c.size_hints.user_position
652 and not c.size_hints.program_position then
653 -- Prevent clients from being unreachable after screen count changes.
654 awful.placement.no_offscreen(c)
658 -- Add a titlebar if titlebars_enabled is set to true in the rules.
659 client.connect_signal("request::titlebars", function(c)
660 -- buttons for the titlebar
661 local buttons = awful.util.table.join(
662 awful.button({ }, 1, function()
665 awful.mouse.client.move(c)
667 awful.button({ }, 3, function()
670 awful.mouse.client.resize(c)
674 awful.titlebar(c) : setup {
676 awful.titlebar.widget.iconwidget(c),
678 layout = wibox.layout.fixed.horizontal
683 widget = awful.titlebar.widget.titlewidget(c)
686 layout = wibox.layout.flex.horizontal
689 awful.titlebar.widget.floatingbutton (c),
690 awful.titlebar.widget.maximizedbutton(c),
691 awful.titlebar.widget.stickybutton (c),
692 awful.titlebar.widget.ontopbutton (c),
693 awful.titlebar.widget.closebutton (c),
694 layout = wibox.layout.fixed.horizontal()
696 layout = wibox.layout.align.horizontal
700 -- Enable sloppy focus
701 client.connect_signal("mouse::enter", function(c)
702 if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
703 and awful.client.focus.filter(c) then
708 client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
709 client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
711 awful.ewmh.add_activate_filter(function(c, context, hints)
712 if context == "ewmh" and c.class == "Firefox" then return false end
715 -- vim:ft=lua:sw=4:sts=4:ts=4:et