1 -- Standard awesome library
3 require ("awful.autofocus") -- <- XXX: I may not need this...
4 require ("awful.rules")
5 require ("beautiful") -- theme handling
6 require ("naughty") -- notifications
7 require ("vicious") -- widgets
8 require ("keychain") -- custom keychain library
9 require ("shifty") -- dynamic tagging
11 require ("scratch") -- scratchpad (XXX: not the behavior I need actually)
13 --{{{ Variable definitions
15 local amenu = awful.menu
16 local join = awful.util.table.join
17 local spawn = awful.util.spawn
18 local configdir = awful.util.getdir ("config")
20 -- Themes define colours, icons, and wallpapers
21 beautiful.init (configdir .. "/theme/theme.lua")
23 -- Some custom programs are only loaded by awesome: I put 'em in this
25 BIN_DIR = configdir .. "/bin/"
27 -- This is used later as the default terminal and editor to run.
28 USER = os.getenv ("USER")
29 HOME = os.getenv ("HOME")
30 HOST = os.getenv ("HOST")
31 LANG = os.getenv ("LANG") or "en_US.UTF-8"
32 XTERM = "urxvt -cr red -bg black -fg white +sb"
33 ETERM_NEW = BIN_DIR .. "emacs-shell"
34 ETERM_DEFAULT = BIN_DIR .. "emacs-shell-default"
35 MAIL_READER = BIN_DIR .. "emacs-gnus"
36 STANDBY_SCREEN = BIN_DIR .. "force-dpms-standby"
37 STANDBY_AND_LOCK_SCREEN = BIN_DIR .. "force-dpms-standby lock"
38 IRC = XTERM .. " -T weechat -e weechat-curses"
40 -- Emms global shortcut commands at the window manager level: I use Emms
41 -- commands instead of the mpc ones so that my emms session stay up to date.
42 EMMS_PLAYLIST = "emacsclient -c -e '(emms-browser)'"
43 EMMS_PAUSE = "emacsclient -e '(emms-pause)'"
44 EMMS_PREVIOUS = "emacsclient -e '(emms-previous)'"
45 EMMS_NEXT = "emacsclient -e '(emms-next)'"
46 EMMS_SEEK_BACKWARD = "emacsclient -e '(emms-seek-backward)'"
47 EMMS_SEEK_FORWARD = "emacsclient -e '(emms-seek-forward)'"
48 EMMS_VOLUME_RAISE = "emacsclient -e '(emms-volume-raise)'"
49 EMMS_VOLUME_LOWER = "emacsclient -e '(emms-volume-lower)'"
52 -- editor = os.getenv ("EDITOR") or "nano"
53 -- editor_cmd = terminal.." -e "..editor
55 local setup_advanced_keymap
56 local setup_default_keymap
57 if HOST == "adonis" then
58 TERM_GEOMETRY = "237x67+20+20"
60 SET_TO_DEFAULT_KEYMAP = ""
61 SET_TO_ADVANCED_KEYMAP = ""
62 setup_advanced_keymap = function () end
63 setup_default_keymap = function () end
65 TERM_GEOMETRY="180x60+20+20"
67 -- Keyboard mapping configuration shortcuts
68 SET_TO_DEFAULT_KEYMAP = "xmodmap "..HOME.."/.xmodmaprc.default"
69 SET_TO_ADVANCED_KEYMAP = "xmodmap "..HOME.."/.xmodmaprc.advanced"
70 setup_advanced_keymap = function () spawn (SET_TO_ADVANCED_KEYMAP) end
71 setup_default_keymap = function () spawn (SET_TO_DEFAULT_KEYMAP) end
75 SYSTEM_MONITOR = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop"
76 SYSTEM_MONITOR_BIS = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop -u "..USER
78 -- Sound mixer (since I do not use a widget for now...)
79 SOUND_MIXER = XTERM.." -e alsamixer"
84 -- Usually, Mod4 is the key with a logo between Control and Alt.
85 -- If you do not like this or do not have such a key,
86 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
87 -- However, you can use another modifier like Mod1, but it may interact with others.
91 local mk, ak, ck, sk, ek = modkey, altkey, "Control", "Shift", "Escape"
93 -- Table of layouts to cover with awful.layout.inc, order matters.
95 -- XXX: I really miss a custom tiled layout à la emacs/ion3. But that would
96 -- require a unified management of empty screen regions, thus a somehow deep
97 -- modification of the awesome API to make it neat.
99 -- I never use the other layouts yet... 'cause they don't fit my needs.
100 awful.layout.suit.floating,
101 awful.layout.suit.max,
103 -- define some helpers...
104 local function next_layout () awful.layout.inc (layouts, 1) end
105 local function prev_layout () awful.layout.inc (layouts, -1) end
111 shifty.config.tags = {
112 ["[www]"] = { position = 1, nopopup = true, persist = true, init = true, },
113 ["[emacs]"] = { position = 2, nopopup = true, persist = true, init = true, },
114 ["[irc]"] = { position = 3, nopopup = true, persist = false, init = false, },
115 ["[sys]"] = { position = 9, nopopup = false, persist = false, init = false, exclusive = true, },
117 for i = 4, 8 do -- XXX: do I need them?
118 shifty.config.tags = join (shifty.config.tags,
119 { ["["..i.."]"] = { position = i, persist = true, }})
121 shifty.config.apps = {
122 { match = {"Iceweasel.*", "Firefox.*" }, tag = "[www]", },
123 { match = {"emacs.*" }, tag = "[emacs]", },
124 { match = {"htop" }, tag = "[sys]", },
125 { match = {"weechat" }, tag = "[irc]", },
126 { match = {"MPlayer" }, float = true, },
127 { match = {"wsim.*", "wsnet" }, float = true, nopopup = true, ontop = true, },
129 shifty.config.defaults = {
130 layout = awful.layout.suit.max,
132 run = function (tag) naughty.notify ({ text = tag.name }) end,
141 -- Create a laucher widget and a main menu.
143 -- XXX: Note this menu is not displayed properly, but as I never use it, I did
144 -- not try to fix that problem...
146 { "manual", terminal .. " -e man awesome" },
147 { "restart", awesome.restart },
148 { "quit", awesome.quit },
152 { "awesome", myawesomemenu, beautiful.awesome_icon },
153 { "debian", menu.debian_menu },
154 { "open terminal", terminal },
156 mymainmenu = amenu ({ items = mymenuitems })
159 image = image (beautiful.awesome_icon),
163 mylauncher = awful.widget.launcher (mylauncher_cfg)
169 -- Create a textclock widget
170 mytextclock = awful.widget.textclock ()
173 mysystray = widget ({ type = "systray" })
177 separator = widget ({ type = "textbox" })
180 separator.bg = beautiful.bg_focus
186 cpugraph = awful.widget.graph ()
187 cpugraph:set_width (36)
188 cpugraph:set_background_color (beautiful.bg_normal)
189 cpugraph:set_color ("#FF5656")
190 cpugraph:set_gradient_colors ({ "#FF5656", "#88A175", "#AECF96" })
191 vicious.register (cpugraph, vicious.widgets.cpu, "$1")
197 memprogbar = awful.widget.progressbar ()
198 memprogbar:set_width (8)
199 memprogbar:set_vertical (true)
200 memprogbar:set_background_color (beautiful.bg_normal)
201 memprogbar:set_border_color (nil)
202 memprogbar:set_color ("#AECF96")
203 memprogbar:set_gradient_colors ({ "#AECF96", "#88A175", "#FF5656" })
204 vicious.register (memprogbar, vicious.widgets.mem, "$1", 10)
208 --{{{ Per-screen wibox
210 -- Create a wibox for each screen and add it
218 awful.button ({ }, 1, awful.tag.viewonly),
219 awful.button ({ mk, }, 1, awful.client.movetotag),
220 awful.button ({ }, 3, awful.tag.viewtoggle),
221 awful.button ({ mk, }, 3, awful.client.toggletag),
222 awful.button ({ }, 4, awful.tag.viewprev),
223 awful.button ({ }, 5, awful.tag.viewnext),
229 awful.button ({ }, 1,
231 if not c:isvisible () then awful.tag.viewonly (c:tags ()[1]) end
235 awful.button ({ }, 3,
241 instance = amenu.clients ({ width = 250 })
244 awful.button ({ }, 4,
246 awful.client.focus.byidx (1)
247 if client.focus then client.focus:raise () end
249 awful.button ({ }, 5,
251 awful.client.focus.byidx (-1)
252 if client.focus then client.focus:raise () end
256 local layout_buttons =
257 join (awful.button ({ }, 1, next_layout),
258 awful.button ({ }, 3, prev_layout),
259 awful.button ({ }, 4, next_layout),
260 awful.button ({ }, 5, prev_layout),
263 -- TODO: I really don't like the prompt at the top of the screen. Maybe I should
264 -- use a kind of dedicated infoline at the bottom of the root window, as in
267 for s = 1, screen.count () do
268 -- Create a promptbox for each screen
270 awful.widget.prompt ({
271 layout = awful.widget.layout.horizontal.leftright
274 -- Create an imagebox widget which will contains an icon indicating which
275 -- layout we're using. We need one layoutbox per screen.
276 mylayoutbox[s] = awful.widget.layoutbox (s)
277 mylayoutbox[s]:buttons (layout_buttons)
279 -- Create a taglist widget
280 mytaglist[s] = awful.widget.taglist (s,
281 awful.widget.taglist.label.all,
284 -- Create a tasklist widget
285 local function currenttags (c)
286 return awful.widget.tasklist.label.currenttags (c, s)
288 mytasklist[s] = awful.widget.tasklist (currenttags,
291 -- Actually create the wibox
292 mywibox[s] = awful.wibox ({
297 -- Add widgets to the wibox --- note order matters here
298 mywibox[s].widgets = {
299 { -- the content of this table is aligned to the left..
302 mypromptbox[s], -- ... and goes left-right:
303 layout = awful.widget.layout.horizontal.leftright
305 mylayoutbox[s], -- the remaining is aligned to the right...
312 s == 1 and mysystray or nil,
313 mytasklist[s], -- ... and goes right-left:
314 layout = awful.widget.layout.horizontal.rightleft
321 shifty.promptbox = mypromptbox
329 awful.button ({ }, 3, function () mymainmenu:toggle () end),
330 awful.button ({ }, 4, awful.tag.viewnext),
331 awful.button ({ }, 5, awful.tag.viewprev),
334 root.buttons (rootbuttons)
338 --{{{ Keychain initialization
341 -- configutation table content should go here: default values
342 -- I chose are here (@see keychain.init documentation for
345 keychain.keystroke ( { }, "Escape" ),
346 keychain.keystroke ( { modkey }, "g" ), -- <- "emacs-like"
348 -- enable infolines, appearing 2 seconds after the typing of
349 -- the first prefix keys.
357 --{{{ Various helpers
361 local function run_prompt ()
362 mypromptbox[mouse.screen]:run ()
365 local function lua_prompt ()
366 awful.prompt.run ({ prompt = "Run Lua code: " },
367 mypromptbox[mouse.screen].widget,
368 awful.util.eval, nil,
369 awful.util.getdir ("cache") .. "/history_eval")
371 -- @see http://awesome.naquadah.org/wiki/Anrxcs_Manual_Prompt
372 local function man_prompt ()
374 local function man (page)
375 -- Use GNU Emacs for manual page display
376 spawn ("emacsclient --eval '(manual-entry \"'" .. page .. "'\")'", false)
377 -- Use the KDE Help Center for manual page display
378 -- spawn ("khelpcenter man:" .. page, false)
379 -- Use the terminal emulator for manual page display
380 -- spawn ("urxvt -e man " .. page, false)
383 awful.prompt.run ({ prompt = "Manual: " }, mypromptbox[mouse.screen].widget,
391 local function switch_focus ()
392 awful.client.focus.history.previous ()
394 client.focus:raise ()
398 local function focus_byidx (i)
399 awful.client.focus.byidx (i)
400 if client.focus then client.focus:raise () end
407 local function new_tag (nopopup)
408 shifty.add ({ rel_index = 1, nopopup = nopopup })
411 local function spn (cmd)
412 return function () spawn (cmd) end
415 -- Other client-related facilities
416 local function cli_toggle_fs (c) c.fullscreen = not c.fullscreen end
417 local function cli_swpmaster (c) c:swap (awful.client.getmaster ()) end
418 local function cli_redraw (c) c:redraw () end
419 local function cli_kill (c) c:kill () end
420 local function cli_raise (c) client.focus = c; c:raise () end
421 local function cli_toggle_maximized (c)
422 c.maximized_horizontal = not c.maximized_horizontal
423 c.maximized_vertical = not c.maximized_vertical
430 --{{{ Custom part of the configuration goes in another file...
439 local akey = awful.key
440 local kcha = keychain
441 local kkey = keychain.key
442 local ksub = keychain.subchain
446 -- System monitoring:
447 akey ({ mk, }, ek, spn (SYSTEM_MONITOR) ),
448 akey ({ mk, ak, }, ek, spn (SYSTEM_MONITOR_BIS) ),
451 akey ({ mk, }, "F1", man_prompt ),
453 -- Standard programs:
454 akey ({ mk, }, "F2", spn (ETERM_DEFAULT) ),
455 akey ({ mk, ak, }, "F2", spn (ETERM_NEW) ),
456 akey ({ mk, ak, sk, }, "F2", spn (XTERM) ),
457 akey ({ mk, }, "F3", run_prompt ),
458 akey ({ mk, ak, }, "F3", lua_prompt ),
459 akey ({ mk, }, "F4", spn (IRC) ),
460 akey ({ mk, }, "F5", spn (MAIL_READER) ),
463 -- akey ({ mk, }, "F7", spn (SOUND_MIXER) ),
466 scratch.drop (SOUND_MIXER, "bottom", "center", 1, 0.33, false)
470 akey ({ mk, }, "F10", spn (STANDBY_SCREEN) ),
471 akey ({ mk, ak, }, "F10", spn (STANDBY_AND_LOCK_SCREEN) ),
473 -- Menu: (XXX: That's not what I want... I'd like a prompt with the
474 -- global menu encoded in it...)
475 akey ({ mk, }, "F12", function () mymainmenu:toggle () end),
477 -- Misc. prompts (translations, etc.):
478 kcha ({ mk, }, "e", {
479 kkey ({ }, "f", function () find_translation ("enfr", false) end),
480 kkey ({ mk, }, "f", function () find_translation ("enfr", true) end),
481 kkey ({ }, "s", function () find_synonym ("en", false) end),
482 kkey ({ mk, }, "s", function () find_synonym ("en", true) end),
485 kcha ({ mk, }, "f", {
486 kkey ({ }, "e", function () find_translation ("fren", false) end),
487 kkey ({ mk, }, "e", function () find_translation ("fren", true) end),
488 kkey ({ }, "s", function () find_synonym ("fr", false) end),
489 kkey ({ mk, }, "s", function () find_synonym ("fr", true) end),
490 kkey ({ }, "c", function () find_conj ("fr", false) end),
491 kkey ({ mk, }, "c", function () find_conj ("fr", true) end),
495 kcha ({ mk, }, "k", {
496 kkey ({ mk, }, "a", setup_advanced_keymap ),
497 kkey ({ }, "a", setup_advanced_keymap ),
498 kkey ({ mk, }, "d", setup_default_keymap ),
499 kkey ({ }, "d", setup_default_keymap ),
502 -- Custom link manipulation...
503 akey ({ mk, }, "o", function () query_open_gate6_link (true) end),
504 akey ({ mk, ak, }, "o", function () query_open_gate6_link (false) end),
506 -- Disabled cause I can never use it this way... and `scratch.pad'
507 -- cannot come to the rescue for what I want (maybe a `scratch'
508 -- tag?)... (that would require empty regions management actually, as
509 -- for custom tiling):
511 -- akey ({ mk, }, "space",
512 -- function () scratch.drop (XTERM, "bottom", "center", 1, 0.33, true) end),
514 -- Emms global shortcuts
515 akey ({ mk, ak, }, "p", spn (EMMS_PLAYLIST) ),
516 akey ({ mk, ak, }, "space", spn (EMMS_PAUSE) ),
517 akey ({ mk, ak, }, "Prior", spn (EMMS_PREVIOUS) ),
518 akey ({ mk, ak, }, "Next", spn (EMMS_NEXT) ),
519 akey ({ mk, ak, }, "Left", spn (EMMS_SEEK_BACKWARD) ),
520 akey ({ mk, ak, }, "Right", spn (EMMS_SEEK_FORWARD) ),
521 akey ({ mk, ak, }, "Up", spn (EMMS_VOLUME_RAISE) ),
522 akey ({ mk, ak, }, "Down", spn (EMMS_VOLUME_LOWER) ),
524 -- Tag management...:
525 akey ({ mk, }, "Left", awful.tag.viewprev ),
526 akey ({ mk, }, "Right", awful.tag.viewnext ),
527 akey ({ mk, sk, }, "Left", shifty.shift_prev ),
528 akey ({ mk, sk, }, "Right", shifty.shift_next ),
529 kcha ({ mk, }, "t", {
530 kkey ({ }, "n", function () new_tag (false) end),
531 kkey ({ mk, }, "n", function () new_tag (true) end),
532 kkey ({ }, "k", shifty.del ),
533 kkey ({ }, "r", shifty.rename ),
536 -- Layout manipulation:
537 akey ({ mk, sk, }, ",", function () awful.client.swap.byidx (-1) end),
538 akey ({ mk, sk, }, ".", function () awful.client.swap.byidx ( 1) end),
539 akey ({ mk, ck, }, "j", function () awful.screen.focus_relative ( 1) end),
540 akey ({ mk, ck, }, "k", function () awful.screen.focus_relative (-1) end),
541 akey ({ mk, }, "Tab", function () focus_byidx ( 1) end ),
542 akey ({ mk, sk, }, "Tab", function () focus_byidx (-1) end ),
543 akey ({ mk, }, "u", awful.client.urgent.jumpto ),
544 kcha ({ mk, }, "l", {
545 kkey ({ }, "l", prev_layout ),
546 kkey ({ mk, }, "l", next_layout ),
547 kkey ({ }, ",", prev_layout ),
548 kkey ({ }, ".", next_layout ),
552 kcha ({ mk, ak, }, "x", {
553 kkey ({ mk, ak, }, "r", awesome.restart ),
554 kkey ({ mk, ak, }, "c", awesome.quit ),
559 -- Client-related bindings:
562 akey ({ mk, sk, }, "f", cli_toggle_fs ),
563 akey ({ mk, sk, }, "Return", cli_swpmaster ),
564 akey ({ mk, sk, }, "space", awful.client.floating.toggle ),
565 akey ({ mk, sk, }, "r", cli_redraw ),
566 kcha ({ mk, }, "x", {
567 kkey ({ mk, }, "r", cli_raise ),
568 kkey ({ mk, }, "c", cli_kill ),
569 kkey ({ }, "o", switch_focus ),
571 kkey ({ }, ",", function (c) awful.client.swap.byidx (-1) end),
572 kkey ({ }, ".", function (c) awful.client.swap.byidx ( 1) end),
573 -- I never use them...:
574 -- kkey ({ }, "2", function (c) awful.tag.incmaster ( 1) end),
575 -- kkey ({ }, "3", function (c) awful.tag.incncol ( 1) end),
578 -- akey ({ mk, sk, }, "o", awful.client.movetoscreen ),
579 -- akey ({ mk, }, "n", function (c) c.minimized = not c.minimized end),
580 -- akey ({ mk, sk, }, "m", cli_toggle_maximized ),
581 -- akey ({ mk, ak, }, "Up", function (c) awful.client.focus.bydirection ("up", c) end),
582 -- akey ({ mk, ak, }, "Down", function (c) awful.client.focus.bydirection ("down", c) end),
583 -- akey ({ mk, ak, }, "Left", function (c) awful.client.focus.bydirection ("left", c) end),
584 -- akey ({ mk, ak, }, "Right", function (c) awful.client.focus.bydirection ("right", c) end),
587 -- Compute the maximum number of digit we need, limited to 9
590 -- Bind all key numbers to tags.
591 -- Be careful: we use keycodes to make it work on any keyboard layout.
592 -- This should map on the top row of your keyboard, usually 1 to 9.
593 for i = 1, keynumber do
596 akey ({ mk, }, "#" .. i + 9, -- view tag
598 awful.tag.viewonly (shifty.getpos (i))
600 akey ({ mk, ck, }, "#" .. i + 9, -- toggle tag
602 local t = shifty.getpos (i)
603 t.selected = not t.selected
605 akey ({ mk, sk, }, "#" .. i + 9, -- move client to tag and view
608 local t = shifty.getpos (i)
609 awful.client.movetotag (t)
610 awful.tag.viewonly (t)
613 akey ({ mk, ck, sk, }, "#" .. i + 9, -- add tag to client
616 awful.client.toggletag (shifty.getpos (i))
622 -- Setup initial keys
624 root.keys (globalkeys)
625 shifty.config.clientkeys = clientkeys
629 --{{{ Various client bindings and general rules.
632 join (awful.button ({ }, 1, cli_raise),
633 -- TODO: use keygrapbber to move and resize...
634 awful.button ({ mk, }, 1, awful.mouse.client.move),
635 awful.button ({ mk, }, 3, awful.mouse.client.resize),
638 awful.rules.rules = {
639 -- All clients will match this rule.
643 border_width = beautiful.border_width,
644 border_color = beautiful.border_normal,
647 buttons = clientbuttons,
656 -- Signal function to execute when a new client appears.
657 local function on_client_startup (c, startup)
658 -- No titlebar... (unless I decide to remove the ):
659 -- awful.titlebar.add (c, { modkey = mk })
661 -- Enable sloppy focus
662 c:add_signal ("mouse::enter",
664 if awful.layout.get (c.screen) ~= awful.layout.suit.magnifier and
665 awful.client.focus.filter (c)
672 -- Set the windows at the slave,
673 -- i.e. put it at the end of others instead of setting it master.
674 -- awful.client.setslave (c)
676 -- Put windows in a smart way, only if they does not set an initial
678 if not c.size_hints.user_position and
679 not c.size_hints.program_position
681 awful.placement.no_overlap (c)
682 awful.placement.no_offscreen (c)
687 client.add_signal ("manage", on_client_startup)
688 client.add_signal ("focus", function (c) c.border_color = beautiful.border_focus end)
689 client.add_signal ("unfocus", function (c) c.border_color = beautiful.border_normal end)