Monday, December 15, 2008

Awesome Window Manager

I have recently discovered the awesome window manager. It is a tiling window manager which is very light and easy to use. Theres is some documentation at their website http://awesome.naquadah.org/ and they also have a excellent wiki. The one problem I had was finding rc.lua files which worked for the newer versions so I decided to post mine so maybe it will be helpful to others. Its still a work in progress as I learn more but heres what it is as of now.

--Include awesome libraries, with lots of useful function!
require("awful")
require("beautiful")
require("wicked")

-- {{{ Variable definitions
theme_path = "/home/purehate/.config/awesome/themes/my_theme"

-- Actually load theme
beautiful.init(theme_path)

-- defaults.
terminal = "Eterm -O --tint grey 50 --cmod 100 -x --scrollbar-popup --buttonbar no --font-fx none -f white -c white --font '-Adobe-Courier-Medium-R-Normal--14-100-100-100-M-90-ISO8859-1' "
editor = os.getenv("EDITOR") or "nano"
editor_cmd = terminal .. " -e " .. editor

--set function
function setFg(color, text)
return "" .. text .. ""
end

-- Default modkey.
modkey = "Mod4"

-- Table of layouts to cover with awful.layout.inc, order matters.
layouts =
{
"tile",
"tileleft",
"tilebottom",
"tiletop",
"fairh",
"fairv",
"magnifier",
"max",
"spiral",
"dwindle",
"floating"
}

-- Table of clients that should be set floating.
floatapps =
{
-- by class
["MPlayer"] = true,
["gimp"] = true,
["aterm"] = true,

-- by instance

}

-- Applications to be moved to a pre-defined tag by class or instance.
-- Use the screen and tags indices.
apptags =
{
["Firefox"] = { screen = 1, tag = 1 },
}

-- Define if we want to use titlebar on all applications.
use_titlebar = false
-- }}}

-- {{{ Tags
-- Define tags table.
tags = {}
for s = 1, screen.count() do
-- Each screen has its own tag table.
tags[s] = {}
-- Create 9 tags per screen.
for tagnumber = 1, 9 do
tags[s][tagnumber] = tag({ name = tagnumber, layout = layouts[1] })
-- Add tags to screen one by one
tags[s][tagnumber].screen = s
end
-- I'm sure you want to see at least one tag.
tags[s][1].selected = true
end
-- }}}

-- {{{ Wibox
-- Create a textbox widget
mytextbox = widget({ type = "textbox", align = "right" })
-- Set the default text in textbox
mytextbox.text = " " .. os.date() .. " "
-- Create a laucher widget and a main menu
mymainmenu = awful.menu.new({ items =
{
{"firefox", "firefox" },
{"Alpine", terminal .. "-e alpine" },
{"vmware", "vmware" },
{"K3B", "k3b" },
{"mc", terminal .. "-e mc" },
{"rss feeds", terminal .. " -e newsbeuter" },
{"konqueror", "konqueror" },
{"mrxvt", "mrxvt -tr -shade 75 +trt -fg white -cr white" },
{"openoffice", "ooffice" },
{"kate", "kate" },
{"aterm", " aterm -sl 3000 -tr +sb -si -sk -fade 70 -sh 60 -fn -misc-fixed-medium-r-normal-*-*-120-*-*-c-*-iso8859-2 -g 130x50+20-0 -fg white" },
{"rootXterm", "sudo xterm" },
{"Mplayer", "kmplayer" },
{"vlc", "vlc" },
{"amarok", "amarok" },
{"lynx", terminal .. " -e lynx" },
{"gimp", "gimp" },
{"pidgin", "pidgin" },
{"Transmission", "transmission" },
{"Hack_songs", terminal .. "-e mpg123 -z --list /media/Hack_songs/List.lst" },
{"backtrack", terminal .. "-e ssh root@192.168.1.223" },
{"wireshark", "wireshark" },
{"edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" },
{"restart", "sudo reboot" },
{"shutdown", "sudo poweroff" },
{"close menu", function () awful.menu.close("mymainmenu") end }
}})

mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
menu = mymainmenu })

-- Create a systray
mysystray = widget({ type = "systray", align = "right" })

--- Create a cpu widget
cpuwidget = widget({
type = 'textbox',
name = 'cpuwidget'
})

wicked.register(cpuwidget, wicked.widgets.cpu,
' CPU: $1%')

--and then create a cpu graph
cpugraphwidget = widget({
type = 'graph',
name = 'cpugraphwidget',

})

cpugraphwidget.height = 0.85
cpugraphwidget.width = 80
cpugraphwidget.bg = '#333333'
cpugraphwidget.border_color = '#0a0a0a'
cpugraphwidget.grow = 'left'

cpugraphwidget:plot_properties_set('cpu', {
fg = '#AEC6D8',
fg_center = '#285577',
fg_end = '#285577',
vertical_gradient = false
})

wicked.register(cpugraphwidget, wicked.widgets.cpu, '$1', 1, 'cpu')

--mem widget
memwidget = widget({
type = 'textbox',
name = 'memwidget'
})

wicked.register(memwidget, wicked.widgets.mem,
' Memory: $1 ($2Mb/$3Mb)',
nil, nil, {2, 4, 4})

--Add mem widgit
membarwidget = widget({
type = 'progressbar',
name = 'membarwidget'
})

membarwidget.height = 0.85
membarwidget.width = 80
membarwidget.bg = '#333333'
membarwidget.border_color = '#0a0a0a'
membarwidget.grow = 'left'

membarwidget:bar_properties_set('mem', {
bg = '#222222',
fg = '#285577',
fg_center = '#285577',
fg_end = '#285577',
fg_off = '#222222',
reverse = false,
min_value = 0,
max_value = 100
})

wicked.register(membarwidget, wicked.widgets.mem, '$1', 1, 'mem')

--start emerge widgets
--last sync
lastsync = widget({
type = 'textbox',
name = 'lastsync'
})

function run_script()
local filedescriptor = io.popen('sudo /home/purehate/scripts/lastsync.pl')
local value = filedescriptor:read()
filedescriptor:close()

return {value}
end
wicked.register(lastsync, run_script,
' Last-Sync: $1', 10)

---emerge current
current = widget({
type = 'textbox',
name = 'current'
})

function run_script()
local filedescriptor = io.popen('sudo /home/purehate/scripts/emerge-current.sh')
local value = filedescriptor:read()
filedescriptor:close()

return {value}
end
wicked.register(current, run_script,
' Current Package: $1', 10)

--emerge progress
progress = widget({
type = 'textbox',
name = 'progress'
})

function run_script()
local filedescriptor = io.popen('sudo /home/purehate/scripts/emerge-progress.sh')
local value = filedescriptor:read()
filedescriptor:close()

return {value}
end
wicked.register(progress, run_script,
' Progress: $1', 10)

--emerge status
status = widget({
type = 'textbox',
name = 'status'
})

function run_script()
local filedescriptor = io.popen('sudo /home/purehate/scripts/emerge-status.sh')
local value = filedescriptor:read()
filedescriptor:close()

return {value}
end
wicked.register(status, run_script,
' Status: $1', 10)

--net widget
netwidget = widget({
type = 'textbox',
name = 'netwidget'
})

wicked.register(netwidget, wicked.widgets.net,
' Net: ${eth0 down} / ${eth0 up} [ ${eth0 rx} // ${eth0 tx} ]',
nil, nil, 3)

-----file system widget
fswidget = widget({
type = 'textbox',
name = 'fswidget'
})

wicked.register(fswidget, wicked.widgets.fs,
' FS: ${/ used}/${/ size} (${/ usep} used)', 120)

--Emerge text widget
emerge = widget({
type = "textbox",
name = "emerge"
})
emerge.text = "Emerge Status: "

--Show our IP
ip = widget({
type = 'textbox',
name = 'ip'
})

function run_script()
local filedescriptor = io.popen('sudo /home/purehate/scripts/ip.sh')
local value = filedescriptor:read()
filedescriptor:close()

return {value}
end
wicked.register(ip, run_script,
' Current IP: $1', 10)

-- Create a wibox for each screen and add it
mywibox = {}
mypromptbox = {}
mylayoutbox = {}
mytaglist = {}
mytaglist.buttons = { button({ }, 1, awful.tag.viewonly),
button({ modkey }, 1, awful.client.movetotag),
button({ }, 3, function (tag) tag.selected = not tag.selected end),
button({ modkey }, 3, awful.client.toggletag),
button({ }, 4, awful.tag.viewnext),
button({ }, 5, awful.tag.viewprev) }
mytasklist = {}
mytasklist.buttons = { button({ }, 1, function (c) client.focus = c; c:raise() end),
button({ }, 3, function () awful.menu.clients({ width=250 }) end),
button({ }, 4, function () awful.client.focus.byidx(1) end),
button({ }, 5, function () awful.client.focus.byidx(-1) end) }

for s = 1, screen.count() do
-- Create a promptbox for each screen
mypromptbox[s] = widget({ type = "textbox", align = "left" })
-- Create an imagebox widget which will contains an icon indicating which layout we're using.
-- We need one layoutbox per screen.
mylayoutbox[s] = widget({ type = "imagebox", align = "right" })
mylayoutbox[s]:buttons({ button({ }, 1, function () awful.layout.inc(layouts, 1) end),
button({ }, 3, function () awful.layout.inc(layouts, -1) end),
button({ }, 4, function () awful.layout.inc(layouts, 1) end),
button({ }, 5, function () awful.layout.inc(layouts, -1) end) })
-- Create a taglist widget
mytaglist[s] = awful.widget.taglist.new(s, awful.widget.taglist.label.all, mytaglist.buttons)

-- Create a tasklist widget
mytasklist[s] = awful.widget.tasklist.new(function(c)
return awful.widget.tasklist.label.currenttags(c, s)
end, mytasklist.buttons)

-- Create the wibox
mywibox[s] = {}
mywibox[s][1] = wibox({ position = "top", fg = beautiful.fg_normal, bg = beautiful.bg_normal })

-- Add widgets to the wibox - order matters
mywibox[s][1].widgets = { mylauncher,
mytaglist[s],
memwidget,
membarwidget,
netwidget,
cpuwidget,
cpugraphwidget,
fswidget,
ip,
mytextbox,
mylayoutbox[s],
s == 1 and mysystray or nil }
mywibox[s][1].screen = s
-- Create the second wibox
mywibox[s][2] = wibox({ position = "bottom", fg = beautiful.fg_normal, bg = beautiful.bg_normal })

-- Add widgets to the wibox - order matters
mywibox[s][2].widgets = { emerge,
current,
progress,
status,
lastsync,
mytasklist[s]
}
mywibox[s][2].screen = s
end
-- }}}

-- {{{ Mouse bindings
awesome.buttons({
button({ }, 3, function () mymainmenu:toggle() end),
button({ }, 4, function() awful.spawn(settings.apps.terminal) end),
button({ }, 5, awful.tag.viewprev)
})
-- }}}

-- {{{ Key bindings

-- Bind keyboard digits
-- Compute the maximum number of digit we need, limited to 9
keynumber = 0
for s = 1, screen.count() do
keynumber = math.min(9, math.max(#tags[s], keynumber));
end

for i = 1, keynumber do
keybinding({ modkey }, i,
function ()
local screen = mouse.screen
if tags[screen][i] then
awful.tag.viewonly(tags[screen][i])
end
end):add()
keybinding({ modkey, "Control" }, i,
function ()
local screen = mouse.screen
if tags[screen][i] then
tags[screen][i].selected = not tags[screen][i].selected
end
end):add()
keybinding({ modkey, "Shift" }, i,
function ()
if client.focus then
if tags[client.focus.screen][i] then
awful.client.movetotag(tags[client.focus.screen][i])
end
end
end):add()
keybinding({ modkey, "Control", "Shift" }, i,
function ()
if client.focus then
if tags[client.focus.screen][i] then
awful.client.toggletag(tags[client.focus.screen][i])
end
end
end):add()
end

keybinding({ modkey }, "Left", awful.tag.viewprev):add()
keybinding({ modkey }, "Right", awful.tag.viewnext):add()
keybinding({ modkey }, "Escape", awful.tag.history.restore):add()

-- Standard program
keybinding({ modkey }, "Return", function () awful.util.spawn(terminal) end):add()

keybinding({ modkey, "Control" }, "r", function ()
mypromptbox[mouse.screen].text =
awful.util.escape(awful.util.restart())
end):add()
keybinding({ modkey, "Shift" }, "q", awesome.quit):add()

-- Client manipulation
keybinding({ modkey }, "m", awful.client.maximize):add()
keybinding({ modkey }, "f", function () client.focus.fullscreen = not client.focus.fullscreen end):add()
keybinding({ modkey, "Shift" }, "c", function () client.focus:kill() end):add()
keybinding({ modkey }, "j", function () awful.client.focus.byidx(1); client.focus:raise() end):add()
keybinding({ modkey }, "k", function () awful.client.focus.byidx(-1); client.focus:raise() end):add()
keybinding({ modkey, "Shift" }, "j", function () awful.client.swap.byidx(1) end):add()
keybinding({ modkey, "Shift" }, "k", function () awful.client.swap(-1) end):add()
keybinding({ modkey, "Control" }, "j", function () awful.screen.focus(1) end):add()
keybinding({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end):add()
keybinding({ modkey, "Control" }, "space", awful.client.togglefloating):add()
keybinding({ modkey, "Control" }, "Return", function () client.focus:swap(awful.client.getmaster()) end):add()
keybinding({ modkey }, "o", awful.client.movetoscreen):add()
keybinding({ modkey }, "Tab", awful.client.focus.history.previous):add()
keybinding({ modkey }, "u", awful.client.urgent.jumpto):add()
keybinding({ modkey, "Shift" }, "r", function () client.focus:redraw() end):add()
-- Layout manipulation
keybinding({ modkey }, "l", function () awful.tag.incmwfact(0.05) end):add()
keybinding({ modkey }, "h", function () awful.tag.incmwfact(-0.05) end):add()
keybinding({ modkey, "Shift" }, "h", function () awful.tag.incnmaster(1) end):add()
keybinding({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end):add()
keybinding({ modkey, "Control" }, "h", function () awful.tag.incncol(1) end):add()
keybinding({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end):add()
keybinding({ modkey }, "space", function () awful.layout.inc(layouts, 1) end):add()
keybinding({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end):add()

-- Prompt
keybinding({ modkey }, "F1", function ()
awful.prompt.run({ prompt = "Run: " }, mypromptbox[mouse.screen], awful.util.spawn, awful.completion.bash,
awful.util.getdir("cache") .. "/history")
end):add()
keybinding({ modkey }, "F4", function ()
awful.prompt.run({ prompt = "Run Lua code: " }, mypromptbox[mouse.screen], awful.util.eval, awful.prompt.bash,
awful.util.getdir("cache") .. "/history_eval")
end):add()

keybinding({ modkey, "Ctrl" }, "i", function ()
local s = mouse.screen
if mypromptbox[s].text then
mypromptbox[s].text = nil
else
mypromptbox[s].text = nil
if client.focus.class then
mypromptbox[s].text = "Class: " .. client.focus.class .. " "
end
if client.focus.instance then
mypromptbox[s].text = mypromptbox[s].text .. "Instance: ".. client.focus.instance .. " "
end
if client.focus.role then
mypromptbox[s].text = mypromptbox[s].text .. "Role: ".. client.focus.role
end
end
end):add()

-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them
keybinding({ modkey }, "t", awful.client.togglemarked):add()

for i = 1, keynumber do
keybinding({ modkey, "Shift" }, "F" .. i,
function ()
local screen = mouse.screen
if tags[screen][i] then
for k, c in pairs(awful.client.getmarked()) do
awful.client.movetotag(tags[screen][i], c)
end
end
end):add()
end
-- }}}

-- {{{ Hooks
-- Hook function to execute when focusing a client.
awful.hooks.focus.register(function (c)
if not awful.client.ismarked(c) then
c.border_color = beautiful.border_focus
end
end)

-- Hook function to execute when unfocusing a client.
awful.hooks.unfocus.register(function (c)
if not awful.client.ismarked(c) then
c.border_color = beautiful.border_normal
end
end)

-- Hook function to execute when marking a client
awful.hooks.marked.register(function (c)
c.border_color = beautiful.border_marked
end)

-- Hook function to execute when unmarking a client.
awful.hooks.unmarked.register(function (c)
c.border_color = beautiful.border_focus
end)

-- Hook function to execute when the mouse enters a client.
awful.hooks.mouse_enter.register(function (c)
-- Sloppy focus, but disabled for magnifier layout
if awful.layout.get(c.screen) ~= "magnifier"
and awful.client.focus.filter(c) then
client.focus = c
end
end)

-- Hook function to execute when a new client appears.
awful.hooks.manage.register(function (c)
if use_titlebar then
-- Add a titlebar
awful.titlebar.add(c, { modkey = modkey })
end
-- Add mouse bindings
c:buttons({
button({ }, 1, function (c) client.focus = c; c:raise() end),
button({ modkey }, 1, function (c) c:mouse_move() end),
button({ modkey }, 3, function (c) c:mouse_resize() end)
})
-- New client may not receive focus
-- if they're not focusable, so set border anyway.
c.border_width = beautiful.border_width
c.border_color = beautiful.border_normal
client.focus = c

-- Check if the application should be floating.
local cls = c.class
local inst = c.instance
if floatapps[cls] then
c.floating = floatapps[cls]
elseif floatapps[inst] then
c.floating = floatapps[inst]
end

-- Check application->screen/tag mappings.
local target
if apptags[cls] then
target = apptags[cls]
elseif apptags[inst] then
target = apptags[inst]
end
if target then
c.screen = target.screen
awful.client.movetotag(tags[target.screen][target.tag], c)
end

-- Set the windows at the slave,
-- i.e. put it at the end of others instead of setting it master.
-- awful.client.setslave(c)

-- Honor size hints: if you want to drop the gaps between windows, set this to false.
-- c.honorsizehints = false
end)

-- Hook function to execute when arranging the screen.
-- (tag switch, new client, etc)
awful.hooks.arrange.register(function (screen)
local layout = awful.layout.get(screen)
if layout then
mylayoutbox[screen].image = image(beautiful["layout_" .. layout])
else
mylayoutbox[screen].image = nil
end

-- Give focus to the latest client in history if no window has focus
-- or if the current window is a desktop or a dock one.
if not client.focus then
local c = awful.client.focus.history.get(screen, 0)
if c then client.focus = c end
end

-- Uncomment if you want mouse warping
--[[
if client.focus then
local c_c = client.focus:fullgeometry()
local m_c = mouse.coords()

if m_c.x <>= c_c.x + c_c.width or
m_c.y <>= c_c.y + c_c.height then
if table.maxn(m_c.buttons) == 0 then
mouse.coords({ x = c_c.x + 5, y = c_c.y + 5})
end
end
end
]]
end)

-- }}}

5 comments:

Mark said...

I can always use good samples of lua files, I just started the rather steep learning curve so any help is welcome.
Thanks for sharing..

chuksjonia said...

I have been tring to make it work in slackware 12. Have you tried it?

skrite dot net said...

I just started using awesome wm myself. Your setup is very elegant. And thanks for posting the config, too.

Gerrit Garbereder said...

I've tried to integrate the shutdown button to my rc.lua but it does not work. I think it's cause of the missing root password which is needed for sudo... How does it work here?

Best regards,
Gerrit

v.chungath said...

thanks for sharing
@Gerrit: I think you can use gksudo instead of sudo to show the password prompt.