-- Standard awesome library require ("awful") require ("awful.autofocus") -- <- XXX: I may not need this... require ("awful.rules") require ("beautiful") -- theme handling require ("naughty") -- notifications require ("vicious") -- widgets require ("keychain") -- custom keychain library require ("shifty") -- dynamic tagging require ("menu") require ("scratch") -- scratchpad (XXX: not the behavior I need actually) --{{{ Variable definitions local amenu = awful.menu local join = awful.util.table.join local spawn = awful.util.spawn local configdir = awful.util.getdir ("config") -- Themes define colours, icons, and wallpapers beautiful.init (configdir .. "/theme/theme.lua") -- Some custom programs are only loaded by awesome: I put 'em in this -- directory: BIN_DIR = configdir .. "/bin/" -- This is used later as the default terminal and editor to run. USER = os.getenv ("USER") HOME = os.getenv ("HOME") HOST = os.getenv ("HOST") LANG = os.getenv ("LANG") or "en_US.UTF-8" XTERM = "urxvt -cr red -bg black -fg white +sb" ETERM_NEW = BIN_DIR .. "emacs-shell" ETERM_DEFAULT = BIN_DIR .. "emacs-shell-default" MAIL_READER = BIN_DIR .. "emacs-gnus" STANDBY_SCREEN = BIN_DIR .. "force-dpms-standby" STANDBY_AND_LOCK_SCREEN = BIN_DIR .. "force-dpms-standby lock" IRC = XTERM .. " -T weechat -e weechat-curses" -- Emms global shortcut commands at the window manager level: I use Emms -- commands instead of the mpc ones so that my emms session stay up to date. EMMS_PLAYLIST = "emacsclient -c -e '(emms-browser)'" EMMS_PAUSE = "emacsclient -e '(emms-pause)'" EMMS_PREVIOUS = "emacsclient -e '(emms-previous)'" EMMS_NEXT = "emacsclient -e '(emms-next)'" EMMS_SEEK_BACKWARD = "emacsclient -e '(emms-seek-backward)'" EMMS_SEEK_FORWARD = "emacsclient -e '(emms-seek-forward)'" EMMS_VOLUME_RAISE = "emacsclient -e '(emms-volume-raise)'" EMMS_VOLUME_LOWER = "emacsclient -e '(emms-volume-lower)'" terminal = XTERM -- editor = os.getenv ("EDITOR") or "nano" -- editor_cmd = terminal.." -e "..editor local setup_advanced_keymap local setup_default_keymap if HOST == "adonis" then TERM_GEOMETRY = "237x67+20+20" SET_TO_DEFAULT_KEYMAP = "" SET_TO_ADVANCED_KEYMAP = "" setup_advanced_keymap = function () end setup_default_keymap = function () end else TERM_GEOMETRY="180x60+20+20" -- Keyboard mapping configuration shortcuts SET_TO_DEFAULT_KEYMAP = "xmodmap "..HOME.."/.xmodmaprc.default" SET_TO_ADVANCED_KEYMAP = "xmodmap "..HOME.."/.xmodmaprc.advanced" setup_advanced_keymap = function () spawn (SET_TO_ADVANCED_KEYMAP) end setup_default_keymap = function () spawn (SET_TO_DEFAULT_KEYMAP) end end -- System monitor SYSTEM_MONITOR = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop" SYSTEM_MONITOR_BIS = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop -u "..USER -- Sound mixer (since I do not use a widget for now...) SOUND_MIXER = XTERM.." -e alsamixer" -- --- -- Default modkey. -- Usually, Mod4 is the key with a logo between Control and Alt. -- If you do not like this or do not have such a key, -- I suggest you to remap Mod4 to another key using xmodmap or other tools. -- However, you can use another modifier like Mod1, but it may interact with others. modkey = "Mod4" altkey = "Mod1" -- alias... local mk, ak, ck, sk, ek = modkey, altkey, "Control", "Shift", "Escape" -- Table of layouts to cover with awful.layout.inc, order matters. -- -- XXX: I really miss a custom tiled layout à la emacs/ion3. But that would -- require a unified management of empty screen regions, thus a somehow deep -- modification of the awesome API to make it neat. layouts = { -- I never use the other layouts yet... 'cause they don't fit my needs. awful.layout.suit.floating, awful.layout.suit.max, } -- define some helpers... local function next_layout () awful.layout.inc (layouts, 1) end local function prev_layout () awful.layout.inc (layouts, -1) end --}}} --{{{ Shifty shifty.config.tags = { ["[www]"] = { position = 1, nopopup = true, persist = true, init = true, }, ["[emacs]"] = { position = 2, nopopup = true, persist = true, init = true, }, ["[irc]"] = { position = 3, nopopup = true, persist = false, init = false, }, ["[sys]"] = { position = 9, nopopup = false, persist = false, init = false, exclusive = true, }, } for i = 4, 8 do -- XXX: do I need them? shifty.config.tags = join (shifty.config.tags, { ["["..i.."]"] = { position = i, persist = true, }}) end shifty.config.apps = { { match = {"Iceweasel.*", "Firefox.*" }, tag = "[www]", }, { match = {"emacs.*" }, tag = "[emacs]", }, { match = {"htop" }, tag = "[sys]", }, { match = {"weechat" }, tag = "[irc]", }, { match = {"MPlayer" }, float = true, }, { match = {"wsim.*", "wsnet" }, float = true, nopopup = true, ontop = true, }, } shifty.config.defaults = { layout = awful.layout.suit.max, persist = true, run = function (tag) naughty.notify ({ text = tag.name }) end, floatBars = false, } shifty.init () --}}} --{{{ Menu -- Create a laucher widget and a main menu. -- -- XXX: Note this menu is not displayed properly, but as I never use it, I did -- not try to fix that problem... myawesomemenu = { { "manual", terminal .. " -e man awesome" }, { "restart", awesome.restart }, { "quit", awesome.quit }, } mymenuitems = { { "awesome", myawesomemenu, beautiful.awesome_icon }, { "debian", menu.debian_menu }, { "open terminal", terminal }, } mymainmenu = amenu ({ items = mymenuitems }) mylauncher_cfg = { image = image (beautiful.awesome_icon), menu = mymainmenu } mylauncher = awful.widget.launcher (mylauncher_cfg) --}}} --{{{ Wibox -- Create a textclock widget mytextclock = awful.widget.textclock () -- Create a systray mysystray = widget ({ type = "systray" }) --{{{ Spacers: separator = widget ({ type = "textbox" }) separator.text = "" separator.width = 1 separator.bg = beautiful.bg_focus --}}} --{{{ CPU usage: cpugraph = awful.widget.graph () cpugraph:set_width (36) cpugraph:set_background_color (beautiful.bg_normal) cpugraph:set_color ("#FF5656") cpugraph:set_gradient_colors ({ "#FF5656", "#88A175", "#AECF96" }) vicious.register (cpugraph, vicious.widgets.cpu, "$1") --}}} --{{{ Memory usage: memprogbar = awful.widget.progressbar () memprogbar:set_width (8) memprogbar:set_vertical (true) memprogbar:set_background_color (beautiful.bg_normal) memprogbar:set_border_color (nil) memprogbar:set_color ("#AECF96") memprogbar:set_gradient_colors ({ "#AECF96", "#88A175", "#FF5656" }) vicious.register (memprogbar, vicious.widgets.mem, "$1", 10) --}}} --{{{ Per-screen wibox -- Create a wibox for each screen and add it mywibox = {} mypromptbox = {} mylayoutbox = {} mytaglist = {} mytaglist.buttons = join ( awful.button ({ }, 1, awful.tag.viewonly), awful.button ({ mk, }, 1, awful.client.movetotag), awful.button ({ }, 3, awful.tag.viewtoggle), awful.button ({ mk, }, 3, awful.client.toggletag), awful.button ({ }, 4, awful.tag.viewprev), awful.button ({ }, 5, awful.tag.viewnext), {}) mytasklist = {} mytasklist.buttons = join ( awful.button ({ }, 1, function (c) if not c:isvisible () then awful.tag.viewonly (c:tags ()[1]) end client.focus = c c:raise () end), awful.button ({ }, 3, function () if instance then instance:hide () instance = nil else instance = amenu.clients ({ width = 250 }) end end), awful.button ({ }, 4, function () awful.client.focus.byidx (1) if client.focus then client.focus:raise () end end), awful.button ({ }, 5, function () awful.client.focus.byidx (-1) if client.focus then client.focus:raise () end end), {}) local layout_buttons = join (awful.button ({ }, 1, next_layout), awful.button ({ }, 3, prev_layout), awful.button ({ }, 4, next_layout), awful.button ({ }, 5, prev_layout), {}) -- TODO: I really don't like the prompt at the top of the screen. Maybe I should -- use a kind of dedicated infoline at the bottom of the root window, as in -- ion3.... for s = 1, screen.count () do -- Create a promptbox for each screen mypromptbox[s] = awful.widget.prompt ({ layout = awful.widget.layout.horizontal.leftright }) -- Create an imagebox widget which will contains an icon indicating which -- layout we're using. We need one layoutbox per screen. mylayoutbox[s] = awful.widget.layoutbox (s) mylayoutbox[s]:buttons (layout_buttons) -- Create a taglist widget mytaglist[s] = awful.widget.taglist (s, awful.widget.taglist.label.all, mytaglist.buttons) -- Create a tasklist widget local function currenttags (c) return awful.widget.tasklist.label.currenttags (c, s) end mytasklist[s] = awful.widget.tasklist (currenttags, mytasklist.buttons) -- Actually create the wibox mywibox[s] = awful.wibox ({ position = "top", screen = s }) -- Add widgets to the wibox --- note order matters here mywibox[s].widgets = { { -- the content of this table is aligned to the left.. mylauncher, mytaglist[s], mypromptbox[s], -- ... and goes left-right: layout = awful.widget.layout.horizontal.leftright }, mylayoutbox[s], -- the remaining is aligned to the right... mytextclock, separator, memprogbar.widget, separator, cpugraph.widget, separator, s == 1 and mysystray or nil, mytasklist[s], -- ... and goes right-left: layout = awful.widget.layout.horizontal.rightleft } end --}}} -- Shifty stuff... shifty.promptbox = mypromptbox --}}} --{{{ Mouse bindings local rootbuttons = join ( awful.button ({ }, 3, function () mymainmenu:toggle () end), awful.button ({ }, 4, awful.tag.viewnext), awful.button ({ }, 5, awful.tag.viewprev), {}) root.buttons (rootbuttons) --}}} --{{{ Keychain initialization keychain.init ({ -- configutation table content should go here: default values -- I chose are here (@see keychain.init documentation for -- further details): escapes = { keychain.keystroke ( { }, "Escape" ), keychain.keystroke ( { modkey }, "g" ), -- <- "emacs-like" }, -- enable infolines, appearing 2 seconds after the typing of -- the first prefix keys. use_bowls = true, use_timers = true, timeout = 2, }) --}}} --{{{ Various helpers --{{{ Prompts: local function run_prompt () mypromptbox[mouse.screen]:run () end local function lua_prompt () awful.prompt.run ({ prompt = "Run Lua code: " }, mypromptbox[mouse.screen].widget, awful.util.eval, nil, awful.util.getdir ("cache") .. "/history_eval") end -- @see http://awesome.naquadah.org/wiki/Anrxcs_Manual_Prompt local function man_prompt () local function man (page) -- Use GNU Emacs for manual page display spawn ("emacsclient --eval '(manual-entry \"'" .. page .. "'\")'", false) -- Use the KDE Help Center for manual page display -- spawn ("khelpcenter man:" .. page, false) -- Use the terminal emulator for manual page display -- spawn ("urxvt -e man " .. page, false) end awful.prompt.run ({ prompt = "Manual: " }, mypromptbox[mouse.screen].widget, man) end --}}} --{{{ Client focus local function switch_focus () awful.client.focus.history.previous () if client.focus then client.focus:raise () end end local function focus_byidx (i) awful.client.focus.byidx (i) if client.focus then client.focus:raise () end end --}}} --{{{ Misc. local function new_tag (nopopup) shifty.add ({ rel_index = 1, nopopup = nopopup }) end local function spn (cmd) return function () spawn (cmd) end end -- Other client-related facilities local function cli_toggle_fs (c) c.fullscreen = not c.fullscreen end local function cli_swpmaster (c) c:swap (awful.client.getmaster ()) end local function cli_redraw (c) c:redraw () end local function cli_kill (c) c:kill () end local function cli_raise (c) client.focus = c; c:raise () end local function cli_toggle_maximized (c) c.maximized_horizontal = not c.maximized_horizontal c.maximized_vertical = not c.maximized_vertical end --}}} --}}} --{{{ Custom part of the configuration goes in another file... require ("links") --}}} --{{{ Key bindings -- helpers: local akey = awful.key local kcha = keychain local kkey = keychain.key local ksub = keychain.subchain globalkeys = join ( -- System monitoring: akey ({ mk, }, ek, spn (SYSTEM_MONITOR) ), akey ({ mk, ak, }, ek, spn (SYSTEM_MONITOR_BIS) ), -- Manuals: akey ({ mk, }, "F1", man_prompt ), -- Standard programs: akey ({ mk, }, "F2", spn (ETERM_DEFAULT) ), akey ({ mk, ak, }, "F2", spn (ETERM_NEW) ), akey ({ mk, ak, sk, }, "F2", spn (XTERM) ), akey ({ mk, }, "F3", run_prompt ), akey ({ mk, ak, }, "F3", lua_prompt ), akey ({ mk, }, "F4", spn (IRC) ), akey ({ mk, }, "F5", spn (MAIL_READER) ), -- Sound mixer: -- akey ({ mk, }, "F7", spn (SOUND_MIXER) ), akey ({ mk, }, "F7", function () scratch.drop (SOUND_MIXER, "bottom", "center", 1, 0.33, false) end ), -- DPMS: akey ({ mk, }, "F10", spn (STANDBY_SCREEN) ), akey ({ mk, ak, }, "F10", spn (STANDBY_AND_LOCK_SCREEN) ), -- Menu: (XXX: That's not what I want... I'd like a prompt with the -- global menu encoded in it...) akey ({ mk, }, "F12", function () mymainmenu:toggle () end), -- Misc. prompts (translations, etc.): kcha ({ mk, }, "e", { kkey ({ }, "f", function () find_translation ("enfr", false) end), kkey ({ mk, }, "f", function () find_translation ("enfr", true) end), kkey ({ }, "s", function () find_synonym ("en", false) end), kkey ({ mk, }, "s", function () find_synonym ("en", true) end), }), kcha ({ mk, }, "f", { kkey ({ }, "e", function () find_translation ("fren", false) end), kkey ({ mk, }, "e", function () find_translation ("fren", true) end), kkey ({ }, "s", function () find_synonym ("fr", false) end), kkey ({ mk, }, "s", function () find_synonym ("fr", true) end), kkey ({ }, "c", function () find_conj ("fr", false) end), kkey ({ mk, }, "c", function () find_conj ("fr", true) end), }), -- Keymaps kcha ({ mk, }, "k", { kkey ({ mk, }, "a", setup_advanced_keymap ), kkey ({ }, "a", setup_advanced_keymap ), kkey ({ mk, }, "d", setup_default_keymap ), kkey ({ }, "d", setup_default_keymap ), }), -- Custom link manipulation... akey ({ mk, }, "o", function () query_open_gate6_link (true) end), akey ({ mk, ak, }, "o", function () query_open_gate6_link (false) end), -- Disabled cause I can never use it this way... and `scratch.pad' -- cannot come to the rescue for what I want (maybe a `scratch' -- tag?)... (that would require empty regions management actually, as -- for custom tiling): -- -- akey ({ mk, }, "space", -- function () scratch.drop (XTERM, "bottom", "center", 1, 0.33, true) end), -- Emms global shortcuts akey ({ mk, ak, }, "p", spn (EMMS_PLAYLIST) ), akey ({ mk, ak, }, "space", spn (EMMS_PAUSE) ), akey ({ mk, ak, }, "Prior", spn (EMMS_PREVIOUS) ), akey ({ mk, ak, }, "Next", spn (EMMS_NEXT) ), akey ({ mk, ak, }, "Left", spn (EMMS_SEEK_BACKWARD) ), akey ({ mk, ak, }, "Right", spn (EMMS_SEEK_FORWARD) ), akey ({ mk, ak, }, "Up", spn (EMMS_VOLUME_RAISE) ), akey ({ mk, ak, }, "Down", spn (EMMS_VOLUME_LOWER) ), -- Tag management...: akey ({ mk, }, "Left", awful.tag.viewprev ), akey ({ mk, }, "Right", awful.tag.viewnext ), akey ({ mk, sk, }, "Left", shifty.shift_prev ), akey ({ mk, sk, }, "Right", shifty.shift_next ), kcha ({ mk, }, "t", { kkey ({ }, "n", function () new_tag (false) end), kkey ({ mk, }, "n", function () new_tag (true) end), kkey ({ }, "k", shifty.del ), kkey ({ }, "r", shifty.rename ), }), -- Layout manipulation: akey ({ mk, sk, }, ",", function () awful.client.swap.byidx (-1) end), akey ({ mk, sk, }, ".", function () awful.client.swap.byidx ( 1) end), akey ({ mk, ck, }, "j", function () awful.screen.focus_relative ( 1) end), akey ({ mk, ck, }, "k", function () awful.screen.focus_relative (-1) end), akey ({ mk, }, "Tab", function () focus_byidx ( 1) end ), akey ({ mk, sk, }, "Tab", function () focus_byidx (-1) end ), akey ({ mk, }, "u", awful.client.urgent.jumpto ), kcha ({ mk, }, "l", { kkey ({ }, "l", prev_layout ), kkey ({ mk, }, "l", next_layout ), kkey ({ }, ",", prev_layout ), kkey ({ }, ".", next_layout ), }), -- Session-mgmt... kcha ({ mk, ak, }, "x", { kkey ({ mk, ak, }, "r", awesome.restart ), kkey ({ mk, ak, }, "c", awesome.quit ), }), {}) -- Client-related bindings: clientkeys = join ( akey ({ mk, sk, }, "f", cli_toggle_fs ), akey ({ mk, sk, }, "Return", cli_swpmaster ), akey ({ mk, sk, }, "space", awful.client.floating.toggle ), akey ({ mk, sk, }, "r", cli_redraw ), kcha ({ mk, }, "x", { kkey ({ mk, }, "r", cli_raise ), kkey ({ mk, }, "c", cli_kill ), kkey ({ }, "o", switch_focus ), -- Bound twice: kkey ({ }, ",", function (c) awful.client.swap.byidx (-1) end), kkey ({ }, ".", function (c) awful.client.swap.byidx ( 1) end), -- I never use them...: -- kkey ({ }, "2", function (c) awful.tag.incmaster ( 1) end), -- kkey ({ }, "3", function (c) awful.tag.incncol ( 1) end), }), -- Ibid. -- akey ({ mk, sk, }, "o", awful.client.movetoscreen ), -- akey ({ mk, }, "n", function (c) c.minimized = not c.minimized end), -- akey ({ mk, sk, }, "m", cli_toggle_maximized ), -- akey ({ mk, ak, }, "Up", function (c) awful.client.focus.bydirection ("up", c) end), -- akey ({ mk, ak, }, "Down", function (c) awful.client.focus.bydirection ("down", c) end), -- akey ({ mk, ak, }, "Left", function (c) awful.client.focus.bydirection ("left", c) end), -- akey ({ mk, ak, }, "Right", function (c) awful.client.focus.bydirection ("right", c) end), {}) -- Compute the maximum number of digit we need, limited to 9 keynumber = 9 -- Bind all key numbers to tags. -- Be careful: we use keycodes to make it work on any keyboard layout. -- This should map on the top row of your keyboard, usually 1 to 9. for i = 1, keynumber do globalkeys = join (globalkeys, akey ({ mk, }, "#" .. i + 9, -- view tag function () awful.tag.viewonly (shifty.getpos (i)) end), akey ({ mk, ck, }, "#" .. i + 9, -- toggle tag function () local t = shifty.getpos (i) t.selected = not t.selected end), akey ({ mk, sk, }, "#" .. i + 9, -- move client to tag and view function () if client.focus then local t = shifty.getpos (i) awful.client.movetotag (t) awful.tag.viewonly (t) end end), akey ({ mk, ck, sk, }, "#" .. i + 9, -- add tag to client function () if client.focus then awful.client.toggletag (shifty.getpos (i)) end end), {}) end -- Setup initial keys root.keys (globalkeys) shifty.config.clientkeys = clientkeys --}}} --{{{ Various client bindings and general rules. clientbuttons = join (awful.button ({ }, 1, cli_raise), -- TODO: use keygrapbber to move and resize... awful.button ({ mk, }, 1, awful.mouse.client.move), awful.button ({ mk, }, 3, awful.mouse.client.resize), {}) awful.rules.rules = { -- All clients will match this rule. { rule = { }, properties = { border_width = beautiful.border_width, border_color = beautiful.border_normal, focus = true, keys = clientkeys, buttons = clientbuttons, }, }, } --}}} --{{{ Signals -- Signal function to execute when a new client appears. local function on_client_startup (c, startup) -- No titlebar... (unless I decide to remove the ): -- awful.titlebar.add (c, { modkey = mk }) -- Enable sloppy focus c:add_signal ("mouse::enter", function (c) if awful.layout.get (c.screen) ~= awful.layout.suit.magnifier and awful.client.focus.filter (c) then client.focus = c end end) if not startup then -- Set the windows at the slave, -- i.e. put it at the end of others instead of setting it master. -- awful.client.setslave (c) -- Put windows in a smart way, only if they does not set an initial -- position. if not c.size_hints.user_position and not c.size_hints.program_position then awful.placement.no_overlap (c) awful.placement.no_offscreen (c) end end end client.add_signal ("manage", on_client_startup) client.add_signal ("focus", function (c) c.border_color = beautiful.border_focus end) client.add_signal ("unfocus", function (c) c.border_color = beautiful.border_normal end) --}}}