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 math = require("math")
19 -- Check if awesome encountered an error during startup and fell back to
20 -- another config (This code will only ever execute for the fallback config)
21 if awesome.startup_errors then
22 naughty.notify({ preset = naughty.config.presets.critical,
23 title = "Oops, there were errors during startup!",
24 text = awesome.startup_errors })
27 -- Handle runtime errors after startup
29 local in_error = false
30 awesome.connect_signal("debug::error", function (err)
31 -- Make sure we don't go into an endless error loop
32 if in_error then return end
35 naughty.notify({ preset = naughty.config.presets.critical,
36 title = "Oops, an error happened!",
37 text = tostring(err) })
43 -- {{{ Variable definitions
44 -- Themes define colours, icons, and wallpapers
45 beautiful.init(awful.util.get_themes_dir() .. "default/theme.lua")
47 -- This is used later as the default terminal and editor to run.
48 terminal = "x-terminal-emulator"
49 editor = "sensible-editor"
50 editor_cmd = terminal .. " -e " .. editor
53 -- Usually, Mod4 is the key with a logo between Control and Alt.
54 -- If you do not like this or do not have such a key,
55 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
56 -- However, you can use another modifier like Mod1, but it may interact with others.
60 -- Table of layouts to cover with awful.layout.inc, order matters.
61 awful.layout.layouts = {
62 awful.layout.suit.fair,
63 awful.layout.suit.tile,
64 -- awful.layout.suit.tile.left,
65 -- awful.layout.suit.tile.bottom,
66 awful.layout.suit.tile.top,
67 -- awful.layout.suit.spiral,
68 -- awful.layout.suit.spiral.dwindle,
69 awful.layout.suit.max,
70 -- awful.layout.suit.max.fullscreen,
71 -- awful.layout.suit.magnifier,
72 -- awful.layout.suit.corner.nw,
73 -- awful.layout.suit.corner.ne,
74 -- awful.layout.suit.corner.sw,
75 -- awful.layout.suit.corner.se,
76 awful.layout.suit.floating,
79 layout_default = awful.layout.layouts[1]
80 layout_tiled = awful.layout.layouts[2]
81 layout_maximised = awful.layout.layouts[4]
82 layout_floating = awful.layout.layouts[5]
85 -- {{{ Helper functions
86 local function client_menu_toggle_fn()
90 if instance and instance.wibox.visible then
94 instance = awful.menu.clients({ theme = { width = 250 } })
99 local function sorted_pairs(t, f)
101 for n in pairs(t) do table.insert(a, n) end
103 local i = 0 -- iterator variable
104 local iter = function () -- iterator function
106 if a[i] == nil then return nil
107 else return a[i], t[a[i]]
113 local function print_table(tbl, indent)
114 if not indent then indent = 0 end
115 for k, v in pairs(tbl) do
116 formatting = string.rep(" ", indent) .. k .. ": "
117 if type(v) == "table" then
119 print_table(v, indent+1)
121 print(formatting .. tostring(v))
126 local lain_bat = lain.widgets.bat({
127 batteries = {"BAT0", "BAT1"},
128 settings = function()
130 if bat_now.status == "1" then delim = "↑" end
131 widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
135 local function poloniex_price(output, pair, prec)
136 local xc, pos, err = require("lain.util").dkjson.decode(output, 1, nil)
137 if not prec then prec = 4 end
138 val = (xc and xc[pair]["last"]) or 0
139 val = math.floor(val*10^prec+0.5)/10^prec
140 return (not err and val) or "n/a"
143 local xc_widget = lain.widgets.abase({
144 cmd = "curl -m5 -s 'https://poloniex.com/public?command=returnTicker'",
146 settings = function()
147 widget:set_text(poloniex_price(output, 'BTC_ETH') .. " Ƀ/Ξ")
154 -- Create a launcher widget and a main menu
156 { "hotkeys", function() return false, hotkeys_popup.show_help end},
157 { "manual", terminal .. " -e man awesome" },
158 { "edit config", editor_cmd .. " " .. awesome.conffile },
159 { "restart", awesome.restart },
160 { "quit", awesome.quit }
163 mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon },
164 { "open terminal", terminal }
168 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
172 -- {{{ Menubar configuration
173 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
177 local spacer = wibox.widget.textbox()
178 spacer:set_text(' | ')
179 -- Create a textclock widget
180 mytextclock = wibox.widget.textclock("%a %d %b %H:%M:%S", 1)
182 -- Create a wibox for each screen and add it
187 mytaglist.buttons = awful.util.table.join(
188 awful.button({ }, 1, function(t) t:view_only() end),
189 awful.button({ modkey }, 1, function(t)
191 client.focus:move_to_tag(t)
194 awful.button({ }, 3, awful.tag.viewtoggle),
195 awful.button({ modkey }, 3, function(t)
197 client.focus:toggle_tag(t)
200 awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
201 awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
205 mytasklist.buttons = awful.util.table.join(
206 awful.button({ }, 1, function (c)
207 if c == client.focus then
208 -- I don't like click-minimising
209 -- c.minimized = true
211 -- Without this, the following
212 -- :isvisible() makes no sense
214 if not c:isvisible() and c.first_tag then
215 c.first_tag:view_only()
217 -- This will also un-minimize
218 -- the client, if needed
223 awful.button({ }, 3, client_menu_toggle_fn()),
224 awful.button({ }, 4, function ()
225 awful.client.focus.byidx(1)
227 awful.button({ }, 5, function ()
228 awful.client.focus.byidx(-1)
235 tags.config["main"] = {
236 t1 = { layout = layout_default, selected = true },
237 t2 = { layout = layout_default },
238 t3 = { layout = layout_tiled },
239 t4 = { layout = layout_tiled },
240 t5 = { layout = layout_tiled },
241 t6 = { layout = layout_floating },
242 t7 = { layout = layout_maximised },
243 t8 = { layout = layout_maximised },
244 t9 = { layout = layout_maximised },
246 tags.config["aux"] = {
247 t1 = { layout = layout_default, selected = true },
248 t2 = { layout = layout_default },
249 t3 = { layout = layout_tiled },
250 t4 = { layout = layout_floating },
251 t5 = { layout = layout_floating },
252 t6 = { layout = layout_floating },
253 t7 = { layout = layout_floating },
254 t8 = { layout = layout_floating },
255 t9 = { layout = layout_maximised },
259 screentags[1] = tags.config["main"]
260 if screen.count() == 2 then -- aux screen is on the right
261 screentags[2] = tags.config["aux"]
262 elseif screen.count() == 3 then -- main screen is still #1 in the middle
263 screentags[2] = tags.config["aux"]
264 screentags[3] = tags.config["aux"]
267 awful.screen.connect_for_each_screen(function(s)
269 --DISABLED--if beautiful.wallpaper then
270 --DISABLED-- local wallpaper = beautiful.wallpaper
271 --DISABLED-- -- If wallpaper is a function, call it with the screen
272 --DISABLED-- if type(wallpaper) == "function" then
273 --DISABLED-- wallpaper = wallpaper(s)
275 --DISABLED-- gears.wallpaper.maximized(wallpaper, s, true)
278 if not tags[s.index] then
281 for n,p in sorted_pairs(screentags[s.index]) do
283 n = string.sub(n, 2) -- remove leading 't' needed for syntax in table
284 table.insert(tags[s.index], awful.tag.add(n, p))
287 -- Create a promptbox for each screen
288 mypromptbox[s] = awful.widget.prompt()
289 -- Create an imagebox widget which will contains an icon indicating which layout we're using.
290 -- We need one layoutbox per screen.
291 mylayoutbox[s] = awful.widget.layoutbox(s)
292 mylayoutbox[s]:buttons(awful.util.table.join(
293 awful.button({ }, 1, function () awful.layout.inc( 1) end),
294 awful.button({ }, 3, function () awful.layout.inc(-1) end),
295 awful.button({ }, 4, function () awful.layout.inc( 1) end),
296 awful.button({ }, 5, function () awful.layout.inc(-1) end)))
297 -- Create a taglist widget
298 mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.filter.all, mytaglist.buttons)
300 -- Create a tasklist widget
301 mytasklist[s] = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons)
304 mywibox[s] = awful.wibar({ position = "top", screen = s })
306 -- Add widgets to the wibox
308 layout = wibox.layout.align.horizontal,
310 layout = wibox.layout.fixed.horizontal,
315 mytasklist[s], -- Middle widget
317 layout = wibox.layout.fixed.horizontal,
319 wibox.widget.systray(),
331 -- {{{ Mouse bindings
332 root.buttons(awful.util.table.join(
333 awful.button({ }, 3, function () mymainmenu:toggle() end),
334 awful.button({ }, 4, awful.tag.viewnext),
335 awful.button({ }, 5, awful.tag.viewprev)
340 globalkeys = awful.util.table.join(
341 awful.key({ modkey, }, "s", hotkeys_popup.show_help,
342 {description="show help", group="awesome"}),
343 awful.key({ modkey, }, "Left", awful.tag.viewprev,
344 {description = "view previous", group = "tag"}),
345 awful.key({ modkey, }, "Right", awful.tag.viewnext,
346 {description = "view next", group = "tag"}),
347 awful.key({ modkey, }, "Escape", awful.tag.history.restore,
348 {description = "go back", group = "tag"}),
350 awful.key({ modkey, }, "k",
352 awful.client.focus.byidx( 1)
354 {description = "focus next by index", group = "client"}
356 awful.key({ modkey, }, "j",
358 awful.client.focus.byidx(-1)
360 {description = "focus previous by index", group = "client"}
362 awful.key({ modkey, }, "w", function () mymainmenu:show() end,
363 {description = "show main menu", group = "awesome"}),
365 -- Layout manipulation
366 awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( 1) end,
367 {description = "swap with next client by index", group = "client"}),
368 awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( -1) end,
369 {description = "swap with previous client by index", group = "client"}),
370 awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
371 {description = "focus the next screen", group = "screen"}),
372 awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
373 {description = "focus the previous screen", group = "screen"}),
374 awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
375 {description = "jump to urgent client", group = "client"}),
376 awful.key({ modkey, }, "Tab",
378 awful.client.focus.history.previous()
383 {description = "go back", group = "client"}),
386 awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
387 {description = "open a terminal", group = "launcher"}),
388 awful.key({ modkey, "Control" }, "r", awesome.restart,
389 {description = "reload awesome", group = "awesome"}),
390 awful.key({ modkey, "Shift" }, "q", awesome.quit,
391 {description = "quit awesome", group = "awesome"}),
393 awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
394 {description = "increase master width factor", group = "layout"}),
395 awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
396 {description = "decrease master width factor", group = "layout"}),
397 awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
398 {description = "increase the number of master clients", group = "layout"}),
399 awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
400 {description = "decrease the number of master clients", group = "layout"}),
401 awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
402 {description = "increase the number of columns", group = "layout"}),
403 awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
404 {description = "decrease the number of columns", group = "layout"}),
405 awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
406 {description = "select next", group = "layout"}),
407 awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
408 {description = "select previous", group = "layout"}),
410 awful.key({ modkey, "Control" }, "n",
412 local c = awful.client.restore()
413 -- Focus restored client
419 {description = "restore minimized", group = "client"}),
422 awful.key({ modkey }, "r", function () mypromptbox[awful.screen.focused()]:run() end,
423 {description = "run prompt", group = "launcher"}),
425 awful.key({ modkey }, "x",
427 awful.prompt.run({ prompt = "Run Lua code: " },
428 mypromptbox[awful.screen.focused()].widget,
429 awful.util.eval, nil,
430 awful.util.get_cache_dir() .. "/history_eval")
432 {description = "lua execute prompt", group = "awesome"}),
434 awful.key({ modkey }, "p", function() menubar.show() end,
435 {description = "show the menubar", group = "launcher"})
438 clientkeys = awful.util.table.join(
439 awful.key({ modkey, }, "f",
441 c.fullscreen = not c.fullscreen
444 {description = "toggle fullscreen", group = "client"}),
445 awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
446 {description = "close", group = "client"}),
447 awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
448 {description = "toggle floating", group = "client"}),
449 awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
450 {description = "move to master", group = "client"}),
451 awful.key({ modkey, }, "o", function (c) c:move_to_screen() end,
452 {description = "move to screen", group = "client"}),
453 awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
454 {description = "toggle keep on top", group = "client"}),
455 awful.key({ modkey, }, "n",
457 -- The client currently has the input focus, so it cannot be
458 -- minimized, since minimized clients can't have the focus.
461 {description = "minimize", group = "client"}),
462 awful.key({ modkey, }, "m",
464 c.maximized = not c.maximized
467 {description = "maximize", group = "client"})
470 -- Bind all key numbers to tags.
471 -- Be careful: we use keycodes to make it works on any keyboard layout.
472 -- This should map on the top row of your keyboard, usually 1 to 9.
474 globalkeys = awful.util.table.join(globalkeys,
476 awful.key({ modkey }, "#" .. i + 9,
478 local screen = awful.screen.focused()
479 local tag = screen.tags[i]
484 {description = "view tag #"..i, group = "tag"}),
486 awful.key({ modkey, "Control" }, "#" .. i + 9,
488 local screen = awful.screen.focused()
489 local tag = screen.tags[i]
491 awful.tag.viewtoggle(tag)
494 {description = "toggle tag #" .. i, group = "tag"}),
495 -- Move client to tag.
496 awful.key({ modkey, "Shift" }, "#" .. i + 9,
499 local tag = client.focus.screen.tags[i]
501 client.focus:move_to_tag(tag)
505 {description = "move focused client to tag #"..i, group = "tag"}),
506 -- Toggle tag on focused client.
507 awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
510 local tag = client.focus.screen.tags[i]
512 client.focus:toggle_tag(tag)
516 {description = "toggle focused client on tag #" .. i, group = "tag"})
520 clientbuttons = awful.util.table.join(
521 awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
522 awful.button({ modkey }, 1, awful.mouse.client.move),
523 awful.button({ modkey }, 3, awful.mouse.client.resize))
526 globalkeys = awful.util.table.join(globalkeys,
527 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
528 awful.key({ cmdkey }, "m", function () awful.spawn("chromium") end),
529 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e python") end),
530 awful.key({ cmdkey }, "c", function () awful.spawn("icedove") end),
531 awful.key({ cmdkey }, "r", function () mypromptbox[mouse.screen]:run() end),
532 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
533 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
534 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
535 awful.key({ cmdkey }, "f", function () awful.spawn("thunar") end),
536 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),
537 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),
538 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
541 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
542 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
543 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute 0 toggle") end),
544 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
545 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume 0 -2%") end),
546 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
547 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume 0 +2%") end),
548 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute 1 toggle") end),
549 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute 1 toggle") end),
550 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
551 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
552 awful.key(nil, "XF86Display", function () awful.spawn("") end),
553 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
554 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
555 awful.key(nil, "XF86Search", function () awful.spawn("") end),
556 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
557 awful.key(nil, "XF86Explorer", function () awful.spawn("") end)
561 root.keys(globalkeys)
565 -- Rules to apply to new clients (through the "manage" signal).
567 local function move_to_tag(s, t)
569 c:move_to_tag(tags[s][t])
573 awful.rules.rules = {
574 -- All clients will match this rule.
576 properties = { border_width = beautiful.border_width,
577 border_color = beautiful.border_normal,
578 focus = awful.client.focus.filter,
581 buttons = clientbuttons,
582 screen = awful.screen.preferred,
583 placement = awful.placement.no_overlap+awful.placement.no_offscreen,
588 -- Add titlebars to normal clients and dialogs
589 --DISABLED-- { rule_any = {type = { "normal", "dialog" }
590 --DISABLED-- }, properties = { titlebars_enabled = true }
593 { rule = { type = "dialog" },
594 properties = { placement = awful.placement.centered }},
596 { rule = { class = "URxvt" },
599 size_hints_honor = false
601 { rule = { class = "URxvt", instance = "irc" },
605 callback = move_to_tag(screen.count(), screen.count() == 1 and 2 or 1)
607 { rule = { class = "Firefox", instance = "Navigator" },
611 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
613 { rule = { class = "Icedove", instance = "Mail" },
617 callback = move_to_tag(screen.count() == 1 and 1 or 2, 8)
619 { rule = { class = "Chromium", instance = "chromium" },
623 callback = move_to_tag(screen.count() == 1 and 1 or 2, 9)
625 { rule = { class = "Gscan2pdf" },
629 callback = move_to_tag(1, 5)
631 { rule = { name = "gscan2pdf .*" },
636 { rule = { class = "Thunar", type = "normal" },
645 -- Signal function to execute when a new client appears.
646 client.connect_signal("manage", function (c)
647 -- Set the windows at the slave,
648 -- i.e. put it at the end of others instead of setting it master.
649 -- if not awesome.startup then awful.client.setslave(c) end
651 if awesome.startup and
652 not c.size_hints.user_position
653 and not c.size_hints.program_position then
654 -- Prevent clients from being unreachable after screen count changes.
655 awful.placement.no_offscreen(c)
659 -- Add a titlebar if titlebars_enabled is set to true in the rules.
660 client.connect_signal("request::titlebars", function(c)
661 -- buttons for the titlebar
662 local buttons = awful.util.table.join(
663 awful.button({ }, 1, function()
666 awful.mouse.client.move(c)
668 awful.button({ }, 3, function()
671 awful.mouse.client.resize(c)
675 awful.titlebar(c) : setup {
677 awful.titlebar.widget.iconwidget(c),
679 layout = wibox.layout.fixed.horizontal
684 widget = awful.titlebar.widget.titlewidget(c)
687 layout = wibox.layout.flex.horizontal
690 awful.titlebar.widget.floatingbutton (c),
691 awful.titlebar.widget.maximizedbutton(c),
692 awful.titlebar.widget.stickybutton (c),
693 awful.titlebar.widget.ontopbutton (c),
694 awful.titlebar.widget.closebutton (c),
695 layout = wibox.layout.fixed.horizontal()
697 layout = wibox.layout.align.horizontal
701 -- Enable sloppy focus
702 client.connect_signal("mouse::enter", function(c)
703 if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
704 and awful.client.focus.filter(c) then
709 client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
710 client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
712 awful.ewmh.add_activate_filter(function(c, context, hints)
713 if context == "ewmh" and c.class == "Firefox" then return false end
716 -- vim:ft=lua:sw=4:sts=4:ts=4:et