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 directory:
24 BIN_DIR = configdir .. "/bin/"
26 -- This is used later as the default terminal and editor to run.
27 USER = os.getenv ("USER")
28 HOME = os.getenv ("HOME")
29 HOST = os.getenv ("HOST")
30 LANG = os.getenv ("LANG") or "en_US.UTF-8"
31 XTERM = "urxvt -cr red -bg black -fg white +sb"
32 STANDBY_SCREEN = BIN_DIR .. "force-dpms-standby"
33 STANDBY_AND_LOCK_SCREEN = BIN_DIR .. "force-dpms-standby lock"
34 IRC = XTERM .. " -T weechat -e weechat-curses"
36 -- See `http://www-verimag.imag.fr/~berthier/file:.emacs.el' for details about
38 ETERM_NEW = "emacsclient -c -e '(new-shell-buffer)'"
39 ETERM_DEFAULT = "emacsclient -c -e '(goto-shell-buffer)'"
40 MAIL_READER = "emacsclient -c -e '(goto-gnus-buffer)'"
42 -- Emms global shortcut commands at the window manager level: I use Emms
43 -- commands instead of the mpc ones so that my emms session stay up to date.
44 EMMS_PLAYLIST = "emacsclient -c -e '(emms-browser)'"
45 EMMS_PAUSE = "emacsclient -e '(emms-pause)'"
46 EMMS_PREVIOUS = "emacsclient -e '(emms-previous)'"
47 EMMS_NEXT = "emacsclient -e '(emms-next)'"
48 EMMS_SEEK_BACKWARD = "emacsclient -e '(emms-seek-backward)'"
49 EMMS_SEEK_FORWARD = "emacsclient -e '(emms-seek-forward)'"
50 EMMS_VOLUME_RAISE = "emacsclient -e '(emms-volume-raise)'"
51 EMMS_VOLUME_LOWER = "emacsclient -e '(emms-volume-lower)'"
53 TERM_GEOMETRY="180x60+20+20"
55 -- Keyboard mapping configuration shortcuts
56 SET_TO_DEFAULT_KEYMAP = "xmodmap "..HOME.."/.xmodmaprc.default"
57 SET_TO_ADVANCED_KEYMAP = "xmodmap "..HOME.."/.xmodmaprc.advanced"
58 local function setup_advanced_keymap () spawn (SET_TO_ADVANCED_KEYMAP) end
59 local function setup_default_keymap () spawn (SET_TO_DEFAULT_KEYMAP) end
62 SYSTEM_MONITOR = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop"
63 SYSTEM_MONITOR_BIS = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop -u "..USER
65 -- Sound mixer (since I do not use a widget for now...)
66 SOUND_MIXER = XTERM.." -e alsamixer"
70 -- Default modkey. Usually, Mod4 is the key with a logo between Control and
71 -- Alt. If you do not like this or do not have such a key, I suggest you to
72 -- remap Mod4 to another key using xmodmap or other tools. However, you can use
73 -- another modifier like Mod1, but it may interact with others.
77 local mk, ak, ck, sk, ek = modkey, altkey, "Control", "Shift", "Escape"
79 -- Table of layouts to cover with awful.layout.inc, order matters.
81 -- XXX: I really miss a custom tiled layout à la emacs/ion3. But that would
82 -- require a unified management of empty screen regions, thus a somehow deep
83 -- modification of the awesome API to make it neat.
85 -- I never use the other layouts yet... 'cause they don't fit my needs.
86 awful.layout.suit.floating,
87 awful.layout.suit.max,
89 -- define some helpers...
90 local function next_layout () awful.layout.inc (layouts, 1) end
91 local function prev_layout () awful.layout.inc (layouts, -1) end
97 shifty.config.tags = {
98 ["[www]"] = { position = 1, nopopup = true, persist = true, init = true, },
99 ["[emacs]"] = { position = 2, nopopup = true, persist = true, init = true, },
100 ["[irc]"] = { position = 3, nopopup = true, persist = false, init = false, },
101 ["[sys]"] = { position = 9, nopopup = false, persist = false, init = false, exclusive = true, },
103 for i = 4, 8 do -- XXX: do I need them?
104 shifty.config.tags = join (shifty.config.tags,
105 { ["["..i.."]"] = { position = i, persist = true, }})
107 shifty.config.apps = {
108 { match = {"Iceweasel.*", "Firefox.*" }, tag = "[www]", },
109 { match = {"emacs.*" }, tag = "[emacs]", },
110 { match = {"htop" }, tag = "[sys]", },
111 { match = {"weechat" }, tag = "[irc]", },
112 { match = {"MPlayer" }, float = true, },
113 { match = {"wsim.*", "wsnet" }, float = true, nopopup = true, ontop = true, },
115 shifty.config.defaults = {
116 layout = awful.layout.suit.max,
118 run = function (tag) naughty.notify ({ text = tag.name }) end,
127 -- Create a laucher widget and a main menu.
129 -- XXX: Note this menu is not displayed properly, but as I never use it, I did
130 -- not try to fix that problem...
132 { "manual", XTERM .. " -e man awesome" },
133 { "restart", awesome.restart },
134 { "quit", awesome.quit },
138 { "awesome", myawesomemenu, beautiful.awesome_icon },
139 { "debian", menu.debian_menu },
140 { "open terminal", XTERM },
142 mymainmenu = amenu ({ items = mymenuitems })
148 -- Create a textclock widget
149 mytextclock = awful.widget.textclock ()
152 mysystray = widget ({ type = "systray" })
156 separator = widget ({ type = "textbox" })
159 separator.bg = beautiful.bg_focus
165 cpugraph = awful.widget.graph ()
166 cpugraph:set_width (32)
167 cpugraph:set_height (14)
168 cpugraph:set_gradient_angle (0)
169 cpugraph:set_background_color (beautiful.bg_normal)
170 cpugraph:set_color ("#FF5656")
171 cpugraph:set_gradient_colors ({ "#FF5656", "#88A175", "#AECF96" })
172 vicious.register (cpugraph, vicious.widgets.cpu, "$1")
178 memprogbar = awful.widget.progressbar ()
179 memprogbar:set_width (6)
180 memprogbar:set_height (14)
181 memprogbar:set_vertical (true)
182 memprogbar:set_background_color (beautiful.bg_normal)
183 memprogbar:set_border_color (nil)
184 memprogbar:set_color ("#AECF96")
185 memprogbar:set_gradient_colors ({ "#AECF96", "#88A175", "#FF5656" })
186 vicious.register (memprogbar, vicious.widgets.mem, "$1", 10)
190 --{{{ Per-screen wibox
192 -- Create a wibox for each screen and add it
200 awful.button ({ }, 1, awful.tag.viewonly),
201 awful.button ({ mk, }, 1, awful.client.movetotag),
202 awful.button ({ }, 3, awful.tag.viewtoggle),
203 awful.button ({ mk, }, 3, awful.client.toggletag),
204 awful.button ({ }, 4, awful.tag.viewprev),
205 awful.button ({ }, 5, awful.tag.viewnext),
208 local function cli_focus (c)
209 if not c:isvisible () then awful.tag.viewonly (c:tags ()[1]) end
212 -- do not move mouse to client here...
217 join (awful.button ({ }, 1, cli_focus),
220 local layout_buttons =
221 join (awful.button ({ }, 1, next_layout),
222 awful.button ({ }, 3, prev_layout),
223 awful.button ({ }, 4, next_layout),
224 awful.button ({ }, 5, prev_layout),
227 -- TODO: I really don't like the prompt at the top of the screen. Maybe I should
228 -- use a kind of dedicated infoline at the bottom of the root window, as in
231 for s = 1, screen.count () do
232 -- Create a promptbox for each screen
234 awful.widget.prompt ({
235 layout = awful.widget.layout.horizontal.leftright
238 -- Create an imagebox widget which will contains an icon indicating which
239 -- layout we're using. We need one layoutbox per screen.
240 mylayoutbox[s] = awful.widget.layoutbox (s)
241 mylayoutbox[s]:buttons (layout_buttons)
243 -- Create a taglist widget
244 mytaglist[s] = awful.widget.taglist (s,
245 awful.widget.taglist.label.all,
248 -- Create a tasklist widget
249 local function currenttags (c)
250 return awful.widget.tasklist.label.currenttags (c, s)
252 mytasklist[s] = awful.widget.tasklist (currenttags,
255 -- Actually create the wibox
256 mywibox[s] = awful.wibox ({ position = "top", screen = s, height = 14, })
258 -- Add widgets to the wibox --- note order matters here
259 mywibox[s].widgets = {
260 { -- the content of this table is aligned to the left..
262 mypromptbox[s], -- ... and goes left-right:
263 layout = awful.widget.layout.horizontal.leftright
265 mylayoutbox[s], -- the remaining is aligned to the right...
272 s == 1 and mysystray or nil,
273 mytasklist[s], -- ... and goes right-left:
274 layout = awful.widget.layout.horizontal.rightleft
281 shifty.promptbox = mypromptbox
288 join (awful.button ({ }, 4, awful.tag.viewnext),
289 awful.button ({ }, 5, awful.tag.viewprev),
292 root.buttons (rootbuttons)
296 --{{{ Keychain initialization
299 -- configutation table content should go here: default values
300 -- I chose are repeated here (@see keychain.init documentation
301 -- for further details):
303 keychain.keystroke ( { }, "Escape" ),
304 keychain.keystroke ( { mk, }, "g" ), -- <- "emacs-like"
306 -- enable infolines, appearing 2 seconds after the typing of
307 -- the first prefix keys.
315 --{{{ Various helpers
319 local function run_prompt ()
320 mypromptbox[mouse.screen]:run ()
323 local function lua_prompt ()
324 awful.prompt.run ({ prompt = "Run Lua code: " },
325 mypromptbox[mouse.screen].widget,
326 awful.util.eval, nil,
327 awful.util.getdir ("cache") .. "/history_eval")
330 -- @see http://awesome.naquadah.org/wiki/Anrxcs_Manual_Prompt
331 local function man_prompt ()
333 local function man (page)
334 -- Use GNU Emacs for manual page display
335 spawn ("emacsclient --eval '(manual-entry \"'" .. page .. "'\")'", false)
338 awful.prompt.run ({ prompt = "Manual: " },
339 mypromptbox[mouse.screen].widget,
347 local function mouse_to_client (c)
349 local geom = c:geometry ()
350 mouse.coords ({ x = geom.x, y = geom.y })
354 local function switch_focus ()
355 awful.client.focus.history.previous ()
357 client.focus:raise ()
358 mouse_to_client (client.focus)
362 local function focus_byidx (i)
365 awful.client.focus.byidx (i)
367 client.focus:raise ()
368 mouse_to_client (client.focus)
373 local function swap_byidx (i)
374 return function (c) awful.client.swap.byidx (i) end
377 local function focus_relative (i)
378 return function () awful.screen.focus_relative (i) end
385 local function new_tag (nopopup)
386 return function () shifty.add ({ rel_index = 1, nopopup = nopopup }) end
389 local function spn (cmd)
390 return function () spawn (cmd) end
393 -- Helper for toggling boolean field named `f' in table `t'.
394 local function toggle (t, f) t[f] = not t[f] end
396 -- Other client-related facilities
397 local function cli_toggle_fs (c) toggle (c, "fullscreen") end
398 local function cli_toggle_max_v (c) toggle (c, "maximized_vertical") end
399 local function cli_toggle_max_h (c) toggle (c, "maximized_horizontal") end
401 local function cli_swpmaster (c) c:swap (awful.client.getmaster ()) end
402 local function cli_redraw (c) c:redraw () end
403 local function cli_kill (c) c:kill () end
404 local function cli_lower (c) c:lower () end
405 local function cli_raise (c) client.focus = c; c:raise () end
411 --{{{ Part of the configuration that is related to quick link accesses
420 local bind = keychain
421 local ksub = keychain.sub
425 -- System monitoring:
426 bind ({ mk, }, ek, spn (SYSTEM_MONITOR) ),
427 bind ({ mk, ak, }, ek, spn (SYSTEM_MONITOR_BIS) ),
430 bind ({ mk, }, "F1", man_prompt ),
432 -- Standard programs:
433 bind ({ mk, }, "F2", spn (ETERM_DEFAULT) ),
434 bind ({ mk, ak, }, "F2", spn (ETERM_NEW) ),
435 bind ({ mk, ak, sk, }, "F2", spn (XTERM) ),
436 bind ({ mk, }, "F3", run_prompt ),
437 bind ({ mk, ak, }, "F3", lua_prompt ),
438 bind ({ mk, }, "F4", spn (IRC) ),
439 bind ({ mk, }, "F5", spn (MAIL_READER) ),
442 -- bind ({ mk, }, "F7", spn (SOUND_MIXER) ),
445 scratch.drop (SOUND_MIXER, "bottom", "center", 1, 0.33, false)
449 bind ({ mk, }, "F10", spn (STANDBY_SCREEN) ),
450 bind ({ mk, ak, }, "F10", spn (STANDBY_AND_LOCK_SCREEN) ),
452 -- Menu: (XXX: That's not what I want... I'd like a prompt with the
453 -- global menu encoded in it...)
454 bind ({ mk, }, "F12", function () mymainmenu:toggle () end),
456 -- Misc. prompts (translations, etc.):
457 bind ({ mk, }, "e", {
458 ksub ({ }, "f", function () find_translation ("enfr", false) end),
459 ksub ({ mk, }, "f", function () find_translation ("enfr", true) end),
460 ksub ({ }, "s", function () find_synonym ("en", false) end),
461 ksub ({ mk, }, "s", function () find_synonym ("en", true) end),
464 bind ({ mk, }, "f", {
465 ksub ({ }, "e", function () find_translation ("fren", false) end),
466 ksub ({ mk, }, "e", function () find_translation ("fren", true) end),
467 ksub ({ }, "s", function () find_synonym ("fr", false) end),
468 ksub ({ mk, }, "s", function () find_synonym ("fr", true) end),
469 ksub ({ }, "c", function () find_fr_conj (false) end),
470 ksub ({ mk, }, "c", function () find_fr_conj (true) end),
474 bind ({ mk, }, "k", {
475 ksub ({ mk, }, "a", setup_advanced_keymap ),
476 ksub ({ }, "a", setup_advanced_keymap ),
477 ksub ({ mk, }, "d", setup_default_keymap ),
478 ksub ({ }, "d", setup_default_keymap ),
481 -- Custom link manipulation...
482 bind ({ mk, }, "o", function () query_open_gate6_link (true) end),
483 bind ({ mk, ak, }, "o", function () query_open_gate6_link (false) end),
485 -- Disabled cause I can never use it this way... and `scratch.pad'
486 -- cannot come to the rescue for what I want (maybe a `scratch'
487 -- tag?)... (that would require empty regions management actually, as
488 -- for custom tiling):
490 -- bind ({ mk, }, "space",
491 -- function () scratch.drop (XTERM, "bottom", "center", 1, 0.33, true) end),
493 -- Emms global shortcuts
494 bind ({ mk, ak, }, "p", spn (EMMS_PLAYLIST) ),
495 bind ({ mk, ak, }, "space", spn (EMMS_PAUSE) ),
496 bind ({ mk, ak, }, "Prior", spn (EMMS_PREVIOUS) ),
497 bind ({ mk, ak, }, "Next", spn (EMMS_NEXT) ),
498 bind ({ mk, ak, }, "Left", spn (EMMS_SEEK_BACKWARD) ),
499 bind ({ mk, ak, }, "Right", spn (EMMS_SEEK_FORWARD) ),
500 bind ({ mk, ak, }, "Up", spn (EMMS_VOLUME_RAISE) ),
501 bind ({ mk, ak, }, "Down", spn (EMMS_VOLUME_LOWER) ),
503 -- Tag management...:
504 bind ({ mk, }, "Left", awful.tag.viewprev ),
505 bind ({ mk, }, "Right", awful.tag.viewnext ),
506 bind ({ mk, sk, }, "Left", shifty.shift_prev ),
507 bind ({ mk, sk, }, "Right", shifty.shift_next ),
508 bind ({ mk, }, "t", {
509 ksub ({ }, "n", new_tag (false) ),
510 ksub ({ mk, }, "n", new_tag (true) ),
511 ksub ({ }, "k", shifty.del ),
512 ksub ({ }, "r", shifty.rename ),
515 -- Layout manipulation:
516 bind ({ mk, sk, }, ",", swap_byidx (-1) ),
517 bind ({ mk, sk, }, ".", swap_byidx ( 1) ),
518 bind ({ mk, ck, }, "j", focus_relative ( 1) ),
519 bind ({ mk, ck, }, "k", focus_relative (-1) ),
520 bind ({ mk, }, "Tab", focus_byidx ( 1) ),
521 bind ({ mk, sk, }, "Tab", focus_byidx (-1) ),
522 bind ({ mk, }, "u", awful.client.urgent.jumpto ),
523 bind ({ mk, }, "l", {
524 ksub ({ }, "l", prev_layout ),
525 ksub ({ mk, }, "l", next_layout ),
526 ksub ({ }, ",", prev_layout ),
527 ksub ({ }, ".", next_layout ),
531 bind ({ mk, ak, }, "x", {
532 ksub ({ mk, ak, }, "r", awesome.restart ),
533 ksub ({ mk, ak, }, "c", awesome.quit ),
538 -- Client-related bindings:
541 bind ({ mk, sk, }, "f", cli_toggle_fs ),
542 bind ({ mk, ak, }, "v", cli_toggle_max_v ),
543 bind ({ mk, sk, }, "v", cli_toggle_max_v ),
544 bind ({ mk, ak, }, "h", cli_toggle_max_h ),
545 bind ({ mk, sk, }, "h", cli_toggle_max_h ),
546 bind ({ mk, sk, }, "Return", cli_swpmaster ),
547 bind ({ mk, sk, }, "space", awful.client.floating.toggle ),
548 bind ({ mk, sk, }, "r", cli_redraw ),
549 bind ({ mk, }, "x", {
550 ksub ({ }, "r", cli_raise ),
551 ksub ({ mk, }, "r", cli_raise ),
552 ksub ({ }, "l", cli_lower ),
553 -- XXX: Problem with the following one, which is also a the
554 -- beginning of a prefix for global keys. But I still think
555 -- client keys should have priority over global ones...
556 ksub ({ mk, }, "l", cli_lower ),
557 ksub ({ mk, }, "c", cli_kill ),
558 ksub ({ }, "o", switch_focus ),
560 ksub ({ }, ",", swap_byidx (-1) ),
561 ksub ({ }, ".", swap_byidx ( 1) ),
562 -- I never use them...:
563 -- ksub ({ }, "2", function (c) awful.tag.incmaster ( 1) end),
564 -- ksub ({ }, "3", function (c) awful.tag.incncol ( 1) end),
567 -- bind ({ mk, sk, }, "o", awful.client.movetoscreen ),
568 -- bind ({ mk, }, "n", function (c) c.minimized = not c.minimized end),
569 -- bind ({ mk, ak, }, "Up", function (c) awful.client.focus.bydirection ("up", c) end),
570 -- bind ({ mk, ak, }, "Down", function (c) awful.client.focus.bydirection ("down", c) end),
571 -- bind ({ mk, ak, }, "Left", function (c) awful.client.focus.bydirection ("left", c) end),
572 -- bind ({ mk, ak, }, "Right", function (c) awful.client.focus.bydirection ("right", c) end),
575 -- Compute the maximum number of digit we need, limited to 9
578 -- Bind all key numbers to tags.
579 -- Be careful: we use keycodes to make it work on any keyboard layout.
580 -- This should map on the top row of your keyboard, usually 1 to 9.
581 for i = 1, keynumber do
584 bind ({ mk, }, "#" .. i + 9, -- view tag
586 awful.tag.viewonly (shifty.getpos (i))
588 bind ({ mk, ck, }, "#" .. i + 9, -- toggle tag
590 local t = shifty.getpos (i)
591 t.selected = not t.selected
593 bind ({ mk, sk, }, "#" .. i + 9, -- move client to tag and view
596 local t = shifty.getpos (i)
597 awful.client.movetotag (t)
598 awful.tag.viewonly (t)
601 bind ({ mk, ck, sk, }, "#" .. i + 9, -- add tag to client
604 awful.client.toggletag (shifty.getpos (i))
610 -- Setup initial keys
612 root.keys (globalkeys)
613 shifty.config.clientkeys = clientkeys
617 --{{{ Various client bindings and general rules.
620 join (awful.button ({ }, 1, cli_raise),
621 -- TODO: use keygrapbber to move and resize...
622 awful.button ({ mk, }, 1, awful.mouse.client.move),
623 awful.button ({ mk, }, 3, awful.mouse.client.resize),
626 awful.rules.rules = {
627 -- All clients will match this rule.
631 border_width = beautiful.border_width,
632 border_color = beautiful.border_normal,
635 buttons = clientbuttons,
644 -- Signal function to execute when a new client appears.
645 local function on_client_startup (c, startup)
646 -- No titlebar... (unless I decide to remove the ):
647 -- awful.titlebar.add (c, { modkey = mk })
649 -- Enable sloppy focus
650 c:add_signal ("mouse::enter",
652 if awful.layout.get (c.screen) ~= awful.layout.suit.magnifier and
653 awful.client.focus.filter (c)
660 -- Set the windows at the slave,
661 -- i.e. put it at the end of others instead of setting it master.
662 -- awful.client.setslave (c)
664 -- Put windows in a smart way, only if they does not set an initial
666 if not c.size_hints.user_position and
667 not c.size_hints.program_position
669 awful.placement.no_overlap (c)
670 awful.placement.no_offscreen (c)
675 client.add_signal ("manage", on_client_startup)
676 client.add_signal ("focus", function (c) c.border_color = beautiful.border_focus end)
677 client.add_signal ("unfocus", function (c) c.border_color = beautiful.border_normal end)