commit 344d6d533ab9415b2d225fc8d257c80cf5aae484 Author: crater2150 Date: Sat Oct 24 16:50:19 2009 +0000 Initial commit diff --git a/back.rc.lua b/back.rc.lua new file mode 100644 index 0000000..04074d2 --- /dev/null +++ b/back.rc.lua @@ -0,0 +1,469 @@ +-- Standard awesome library +require("awful") +-- Theme handling library +require("beautiful") +-- Notification library +require("naughty") + +-- Load Debian menu entries +require("debian.menu") + +-- {{{ Variable definitions +-- Themes define colours, icons, and wallpapers +-- The default is a dark theme +theme_path = "/home/jack/.config/awesome/theme.lua" +-- Uncommment this for a lighter theme +-- theme_path = "/usr/share/awesome/themes/sky/theme.lua" + +-- Actually load theme +beautiful.init(theme_path) + +-- This is used later as the default terminal and editor to run. +terminal = "x-terminal-emulator" +editor = os.getenv("EDITOR") or "editor" +editor_cmd = terminal .. " -e " .. editor + +-- 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 = "Mod1" + +-- Table of layouts to cover with awful.layout.inc, order matters. +layouts = +{ + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.magnifier, + awful.layout.suit.floating +} + +-- Table of clients that should be set floating. The index may be either +-- the application class or instance. The instance is useful when running +-- a console app in a terminal like (Music on Console) +-- x-terminal-emulator -name mocp -e mocp +floatapps = +{ + -- by class + ["MPlayer"] = true, + ["pinentry"] = true, + ["gimp"] = true, + -- by instance + ["mocp"] = true +} + +-- Applications to be moved to a pre-defined tag by class or instance. +-- Use the screen and tags indices. +apptags = +{ + -- ["Firefox"] = { screen = 1, tag = 2 }, + -- ["mocp"] = { screen = 2, tag = 4 }, +} + +-- Define if we want to use titlebar on all applications. +use_titlebar = false +-- }}} + +-- {{{ Tags +-- Define tags table. +tags = {} +tags.setup = { + { name = "terms" }, + { name = "web" }, + { name = "music" }, + { name = "dls" }, + { name = "files" }, + { name = "images" }, + { name = "videos" }, + { name = "exps" }, + { name = "other" }, + { name = "nil" } +} +for s = 1, screen.count() do + tags[s] = {} + for i, t in ipairs(tags.setup) do + tags[s][i] = tag({ name = t.name }) + tags[s][i].screen = s + awful.layout.set(layouts[1], tags[s][i]) + end + tags[s][1].selected = true +end +--local tags = {} +-- tags.setup = { +-- { name = "term", layout = layouts[3] }, + -- { name = "emacs", layout = layouts[1] }, + -- { name = "web", layout = layouts[1] }, + --{ name = "mail", layout = layouts[5] }, + --{ name = "im", layout = layouts[1], mwfact = 0.13 }, + -- { name = "6", layout = layouts[7], hide = true }, + -- { name = "7", layout = layouts[7], hide = true }, + -- { name = "rss", layout = layouts[6] }, + -- { name = "media", layout = layouts[7] } +-- } + +-- for s = 1, screen.count() do +-- tags[s] = {} + -- for i, t in ipairs(tags.setup) do + -- tags[s][i] = tag({ name = t.name }) +-- tags[s][i].screen = s +-- awful.tag.setproperty(tags[s][i], "layout", t.layout) + -- awful.tag.setproperty(tags[s][i], "mwfact", t.mwfact) + -- awful.tag.setproperty(tags[s][i], "hide", t.hide) + -- end + -- 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 = " loading... " + +-- Create a laucher widget and a main menu +myawesomemenu = { + { "manual", terminal .. " -e man awesome" }, + { "edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" }, + { "restart", awesome.restart }, + { "quit", awesome.quit } +} + +mymainmenu = awful.menu.new({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon }, + { "open terminal", terminal }, + { "Debian", debian.menu.Debian_menu.Debian } + } + }) + +mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon), + menu = mymainmenu }) + +-- Create a systray +mysystray = widget({ type = "systray", align = "right" }) + +-- Create a wibox for each screen and add it +mywibox = {} +mypromptbox = {} +mylayoutbox = {} +mytaglist = {} +mytaglist.buttons = awful.util.table.join( + awful.button({ }, 1, awful.tag.viewonly), + awful.button({ modkey }, 1, awful.client.movetotag), + awful.button({ }, 3, function (tag) tag.selected = not tag.selected end), + awful.button({ modkey }, 3, awful.client.toggletag), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) + ) +mytasklist = {} +mytasklist.buttons = awful.util.table.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 = awful.menu.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)) + +for s = 1, screen.count() do + -- Create a promptbox for each screen + mypromptbox[s] = awful.widget.prompt({ 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(awful.util.table.join( + awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end), + awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end))) + -- Create a taglist widget + mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons) + + -- Create a tasklist widget + mytasklist[s] = awful.widget.tasklist(function(c) + return awful.widget.tasklist.label.currenttags(c, s) + end, mytasklist.buttons) + + -- Create the wibox + mywibox[s] = wibox({ position = "top", fg = beautiful.fg_normal, bg = beautiful.bg_normal }) + -- Add widgets to the wibox - order matters + mywibox[s].widgets = { mylauncher, + mytaglist[s], + --mylayoutbox[s], + --mytasklist[s], + mypromptbox[s], + mytextbox, + s == 1 and mysystray or nil } + mywibox[s].screen = s +end +-- }}} + +-- {{{ Mouse bindings +root.buttons(awful.util.table.join( + awful.button({ }, 3, function () mymainmenu:toggle() end), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = awful.util.table.join( + awful.key({ modkey, }, "comma", awful.tag.viewprev ), + awful.key({ modkey, }, "period", awful.tag.viewnext ), + awful.key({ modkey, }, "Escape", awful.tag.history.restore), + + awful.key({ modkey, }, "t", + function () + awful.client.focus.byidx( 1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, }, "n", + function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, }, "w", function () mymainmenu:show(true) end), + + -- Layout manipulation + awful.key({ modkey, "Shift" }, "t", function () awful.client.swap.byidx( 1) end), + awful.key({ modkey, "Shift" }, "n", function () awful.client.swap.byidx( -1) end), + awful.key({ modkey, "Control" }, "t", function () awful.screen.focus( 1) end), + awful.key({ modkey, "Control" }, "n", function () awful.screen.focus(-1) end), + awful.key({ modkey, }, "u", awful.client.urgent.jumpto), + awful.key({ modkey, }, "Tab", + function () + awful.client.focus.history.previous() + if client.focus then + client.focus:raise() + end + end), + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), + awful.key({ modkey, "Control" }, "r", awesome.restart), + awful.key({ modkey, "Shift" }, "q", awesome.quit), + + awful.key({ modkey, }, "s", function () awful.tag.incmwfact( 0.05) end), + awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end), + awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1) end), + awful.key({ modkey, "Shift" }, "s", function () awful.tag.incnmaster(-1) end), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), + awful.key({ modkey, "Control" }, "s", function () awful.tag.incncol(-1) end), + awful.key({ modkey, }, "space", function () awful.layout.inc(layouts, 1) end), + awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end), + + -- Prompt + awful.key({ modkey }, "apostrophe", function () mypromptbox[mouse.screen]:run() end), + + awful.key({ modkey }, "x", + function () + awful.prompt.run({ prompt = "Run Lua code: " }, + mypromptbox[mouse.screen].widget, + awful.util.eval, nil, + awful.util.getdir("cache") .. "/history_eval") + end) +) + +-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them +clientkeys = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, }, "semicolon", function (c) c:kill() end), + awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ), + awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end), + awful.key({ modkey, }, "o", awful.client.movetoscreen ), + awful.key({ modkey, "Shift" }, "r", function (c) c:redraw() end), + awful.key({ modkey }, "w", awful.client.togglemarked), + awful.key({ modkey,}, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end) +) + +-- 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 + globalkeys = awful.util.table.join(globalkeys, + awful.key({ modkey }, i, + function () + local screen = mouse.screen + if tags[screen][i] then + awful.tag.viewonly(tags[screen][i]) + end + end), + awful.key({ modkey, "Control" }, i, + function () + local screen = mouse.screen + if tags[screen][i] then + tags[screen][i].selected = not tags[screen][i].selected + end + end), + awful.key({ modkey, "Shift" }, i, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.movetotag(tags[client.focus.screen][i]) + end + end), + awful.key({ modkey, "Control", "Shift" }, i, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.toggletag(tags[client.focus.screen][i]) + end + end), + awful.key({ 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)) +end + +-- Set keys +root.keys(globalkeys) +-- }}} + +-- {{{ 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) ~= awful.layout.suit.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, startup) + -- If we are not managing this application at startup, + -- move it to the screen where the mouse is. + -- We only do it for filtered windows (i.e. no dock, etc). + if not startup and awful.client.focus.filter(c) then + c.screen = mouse.screen + end + + if use_titlebar then + -- Add a titlebar + awful.titlebar.add(c, { modkey = modkey }) + end + -- Add mouse bindings + c:buttons(awful.util.table.join( + awful.button({ }, 1, function (c) client.focus = c; c:raise() end), + awful.button({ modkey }, 1, awful.mouse.client.move), + awful.button({ modkey }, 3, awful.mouse.client.resize) + )) + -- 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 + + -- Check if the application should be floating. + local cls = c.class + local inst = c.instance + if floatapps[cls] ~= nil then + awful.client.floating.set(c, floatapps[cls]) + elseif floatapps[inst] ~= nil then + awful.client.floating.set(c, 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 + c.size_hints_honor = false + -- Do this after tag mapping, so you don't see it on the wrong tag for a split second. + client.focus = c + + -- Set key bindings + c:keys(clientkeys) + + -- 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.size_hints_honor = 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.getname(awful.layout.get(screen)) + if layout and beautiful["layout_" ..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 +end) + +-- Hook called every minute +awful.hooks.timer.register(10, function () + awful.util.spawn("awst") +end) +-- }}} diff --git a/gitrc.lua b/gitrc.lua new file mode 100644 index 0000000..a699196 --- /dev/null +++ b/gitrc.lua @@ -0,0 +1,437 @@ +--### +-- Standard awesome library +require("awful") +-- Theme handling library +require("beautiful") +-- Notification library +require("naughty") +-- Dynamic tagging with shifty +require("lib/shifty") + +-- Wicked +require("wicked") + +-- {{{ Variable definitions +-- Themes define colours, icons, and wallpapers +-- Just link your theme to ~/.awesome_theme +theme_path = os.getenv("HOME") .. "/.config/awesome/theme.lua" + +-- Actually load theme +beautiful.init(theme_path) + +-- Default applications +terminal = "terminal" +-- Editor to use +editor = "terminal -e vim" +-- this is the default level when adding a todo note +todo_level = "high" +-- Default modkey. l +-- 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 = "Mod1" +-- Table of layouts to cover with awful.layout.inc, order matters. +layouts = +{ + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.floating +} + +-- Table of clients that should be set floating. The index may be either +-- the application class or instance. The instance is useful when running +-- a console app in a terminal like (Music on Console) +-- xterm -name mocp -e mocp +floatapps = +{ + -- by class + ["MPlayer"] = true, + ["Xmessage"] = true, + ["Wireshark"] = true, + ["XBoard"] = true, + ["feh"] = true, + ["nitrogen"] = true, + ["Wicd-client.py"] = true, + ["gimp"] = true, + ["XCalc"] = true, + ["display"] = true, + ["Preferences"] = true, + ["XClipboard"] = true, + ["Imagemagick"] = true, + ["Snes9X"] = true, + ["Add-ons"] = true, + ["Wine desktop"] = true +} + +-- Define if we want to use titlebar on all applications. +use_titlebar = false +-- }}} + +--{{{ Shifty + +shifty.config.defaults = { + layout = "tilebottom", +} +shifty.config.tags = { + ["1:terms"] = { init = true, }, + ["2:web"] = { init = true, nopopup = true }, + ["3:music"] = { init =false, nopopup = true, position = 3, spawn = "ario" }, + ["4:dls"] = { init =false, nopopup =false, position = 4, spawn = "dtella && linuxdcpp" }, + ["5:files"] = { init =false, nopopup =false, position = 5 }, + ["6:images"] = { init =false, nopopup =false, position = 6, layout = "float" }, + ["7:videos"] = { init =false, nopopup =false, position = 7, layout = "float" }, + ["8:exps"] = { init =false, nopopup =false, position = 8, layout = "float" }, + ["9:work"] = { init =false, nopopup =false, position = 9 }, +} + +shifty.config.apps = { + { match = { "VLC.*" }, float = true }, + { match = { "" }, honorsizehints= false, + buttons = { + button({ }, 1, function (c) client.focus = c; c:raise() end), + button({ modkey }, 1, function (c) awful.mouse.client.move() end), + button({ modkey }, 3, awful.mouse.client.resize ), }, }, + } + +-- tag defaults +shifty.config.defaults = { + layout = "tilebottom", + ncol = 1, + floatBars = true, +} +shifty.config.layouts = layouts +shifty.config.guess_position = true +shifty.config.remember_index = true +shifty.init() +-- }}} + +-- {{{ Widgets +-- Create a systray +mysystray = widget({ type = "systray", align = "right" }) + +-- 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) } + shifty.taglist = mytaglist +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" }) + +-- Create a datebox widget +datebox = widget({ type = "textbox", align = "right" }) + -- 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" }) + 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) +--}}} + +--{{{ Wibox + mywibox[s] = wibox({ position = "top", fg = beautiful.fg_normal, bg = beautiful.bg_normal }) + -- Add widgets to the wibox - order matters + mywibox[s].widgets = { + mylayoutbox[s], + mytaglist[s], + mypromptbox[s], + mysystray, + datebox, + } + mywibox[s].screen = s +end +--}}} + +--{{{ Functions + +--{{{ Add a todo note + + function addtodo (todo) + infobox.text = "| todo: " .. "" .. awful.util.spawn("todo --add --priority high " .. "'" .. todo .. "'") .. "" + end +--}}} + +--{{{ Show todos + function show_todo() + local todo = awful.util.pread("todo --mono") + todo = naughty.notify({ + text = string.format(os.date("%a, %d %B %Y") .. "\n" .. todo), + timeout = 6, + width = 300, + }) + end +--}}} + + + +--}}} + +--{{{ Keybindings +-- {{{ Mouse bindings +root.buttons(awful.util.table.join( + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = awful.util.table.join( + -- Bindings for shifty + awful.key({ modkey, }, "comma", awful.tag.viewprev ), + awful.key({ modkey, "Shift" }, "comma", shifty.shift_prev ), + awful.key({ modkey, "Shift" }, "period", shifty.shift_next ), + awful.key({ modkey, }, "period", awful.tag.viewnext ), + awful.key({ modkey, }, "Escape", awful.tag.history.restore), + awful.key({ modkey }, "t", function() shifty.add({ rel_index = 1 }) end), + awful.key({ modkey, "Control" }, "t", function() shifty.add({ rel_index = 1, nopopup = true }) end), + awful.key({ modkey }, "r", shifty.rename), + awful.key({ modkey }, "w", shifty.delete), + awful.key({ modkey, "Shift" }, "o", function() shifty.set(awful.tag.selected(mouse.screen), { screen = awful.util.cycle(screen.count() , mouse.screen + 1) }) end), + awful.key({ modkey, }, "y", function() list = naughty.notify({ + text = get_albumart(), + width = 400 }) end), + awful.key({ modkey, }, "j", + function () + awful.client.focus.byidx( 1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, }, "k", + function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end), + + -- Layout manipulation + awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end), + awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end), + awful.key({ modkey, "Control" }, "j", function () awful.screen.focus( 1) end), + awful.key({ modkey, "Control" }, "k", function () awful.screen.focus(-1) end), + awful.key({ modkey, "Shift" }, "u", awful.client.urgent.jumpto), + awful.key({ modkey, }, "Tab", + function () + awful.client.focus.byidx( 1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, "Shift" }, "Tab", + function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end), + + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), + awful.key({ modkey, "Shift" }, "Return", function () awful.util.spawn(editor) end), + awful.key({ modkey, "Control" }, "r", awesome.restart), + awful.key({ modkey, "Shift" }, "q", awesome.quit), + + -- display playlist + awful.key({ modkey, }, "p", function() list = naughty.notify({ + text = get_playlist(), + width = 400 }) end), + + -- Display the todo list + awful.key({ modkey, }, "d", function () show_todo() end), + + -- Paste content of the xbuffer + awful.key({ modkey, "Control" }, "p", function () + awful.prompt.run({ prompt = "Paste to: "}, + mypromptbox[mouse.screen], + function (s) paste(s) end, + awful.completion.shell) end), + -- Lock the screen + + awful.key({ modkey }, "t", function() shifty.add({ rel_index = 1 }) end), + awful.key({ modkey, "Control" }, "t", function() shifty.add({ rel_index = 1, nopopup = true }) end), + awful.key({ modkey }, "r", shifty.rename), + awful.key({ modkey }, "w", shifty.del), + awful.key({ modkey, "Control" }, "o", function () shifty.set(awful.tag.selected(mouse.screen), { screen = awful.util.cycle(mouse.screen + 1, screen.count()) }) end), + awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end), + awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end), + awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1) end), + awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), + awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end), + awful.key({ modkey, }, "space", function () awful.layout.inc(layouts, 1) end), + awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end), + + -- Prompt + -- add a todo + awful.key({ modkey, "Shift" }, "d", + function () + awful.prompt.run({ prompt = " Add Todo Note: " }, + mypromptbox[mouse.screen], + addtodo(t), t, + awful.util.getdir("cache") .. "/todos") + end), + awful.key({ modkey }, "F2", + function () + awful.prompt.run({ fg_cursor = 'orange', bg_cursor = beautiful.bg_normal, + ul_cursor = "single", prompt = " Run: " }, + mypromptbox[mouse.screen], + awful.util.spawn, awful.completion.shell, + awful.util.getdir("cache") .. "/history") + end), + awful.key({ modkey }, "F4", + function () + awful.prompt.run({ prompt = " Run Lua code: " }, + mypromptbox[mouse.screen], + awful.util.eval, nil, + awful.util.getdir("cache") .. "/history_eval") + end) +) + +-- Client awful tagging: this is useful to tag some clients and then do stuff like move to tag on them +clientkeys = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end), + awful.key({ modkey, }, "semicolon", function (c) c:kill() end), + awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ), + awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end), + awful.key({ modkey, }, "o", awful.client.movetoscreen ), + awful.key({ modkey, "Shift" }, "r", function (c) c:redraw() end), + awful.key({ modkey }, "t", awful.client.togglemarked), + awful.key({ modkey,}, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end) +) + +for i=1,9 do + + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey }, i, + function () + local t = awful.tag.viewonly(shifty.getpos(i)) + end)) + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey, "Control" }, i, + function () + local t = shifty.getpos(i) + t.selected = not t.selected + end)) + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey, "Control", "Shift" }, i, + function () + if client.focus then + awful.client.toggletag(shifty.getpos(i)) + end + end)) + -- move clients to other tags + globalkeys = awful.util.table.join(globalkeys, awful.key({ modkey, "Shift" }, i, + function () + if client.focus then + local t = shifty.getpos(i) + awful.client.movetotag(t) + awful.tag.viewonly(t) + end + end)) +end +-- Set keys +root.keys(globalkeys) +shifty.config.globalkeys = globalkeys +shifty.config.clientkeys = clientkeys +--}}} +--}}} + +-- {{{ 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) ~= awful.layout.suit.magnifier + and awful.client.focus.filter(c) then + client.focus = c + end +end) + +-- Hook function to execute when arranging the screen. +-- (tag switch, new client, etc) +awful.hooks.arrange.register(function (screen) + local layout = awful.layout.getname(awful.layout.get(screen)) + if layout and beautiful["layout_" ..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 +end) + +-- Hook called every 15 seconds, displays info +function hook_date () + -- writes status to .status + os.execute("echo $(mpc | grep -) $(gmail.py) $(acpi -b | sed -e 's/%.*/%/;s/.*, //') $(date +'%a %d %b') $(date +'%I:%M') > ~/.status") + -- read .status + io.input("/home/jack/.status") + datebox.text = io.read("*line") +end + +-- Set timers for the hooks +awful.hooks.timer.register(15, hook_date) + +-- run the hook so we don't have to wait +hook_date() + +--}}} + +-- startup commands +os.execute("xmodmap ~/.xmodmap &") +os.execute("xbindkeys &") +os.execute("nitrogen --restore &") +os.execute("xsetroot -cursor_name left_ptr &") + +-- vim: foldmethod=marker:filetype=lua:expandtab:shiftwidth=2:tabstop=2:softtabstop=2:encoding=utf-8:textwidth=80 diff --git a/icons/LICENSE b/icons/LICENSE new file mode 100644 index 0000000..ce5da9d --- /dev/null +++ b/icons/LICENSE @@ -0,0 +1,12 @@ +All 'awesome' icons in this package were created by Adrian C. (anrxc). +They are licensed under the same terms as the awesome distribution itself +- GNU General Public License version 2. To view a human-readable summary +of this license, visit: http://creativecommons.org/licenses/GPL/2.0/ + +The widget icons with the exception of: 'chat', 'crypt', 'power' and +'rss' icons (which were made by me) were originally made by 'sm4tik' +for purposes of 'dzen', I could not find any licensing information +attached to those original bitmaps. Assuming they are in the public +domain I am licensing the widget icons under the terms of the +Creative Commons Attribution-Share Alike license. To view a copy of +this license, visit: http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/icons/awesome.png b/icons/awesome.png new file mode 100644 index 0000000..44697e6 Binary files /dev/null and b/icons/awesome.png differ diff --git a/icons/background.png b/icons/background.png new file mode 100644 index 0000000..0d882b7 Binary files /dev/null and b/icons/background.png differ diff --git a/icons/bat.png b/icons/bat.png new file mode 100644 index 0000000..8ca804a Binary files /dev/null and b/icons/bat.png differ diff --git a/icons/cal.png b/icons/cal.png new file mode 100644 index 0000000..a93384c Binary files /dev/null and b/icons/cal.png differ diff --git a/icons/chat.png b/icons/chat.png new file mode 100644 index 0000000..5dd010e Binary files /dev/null and b/icons/chat.png differ diff --git a/icons/cpu.png b/icons/cpu.png new file mode 100644 index 0000000..38bf844 Binary files /dev/null and b/icons/cpu.png differ diff --git a/icons/crypto.png b/icons/crypto.png new file mode 100644 index 0000000..20f0313 Binary files /dev/null and b/icons/crypto.png differ diff --git a/icons/disk.png b/icons/disk.png new file mode 100644 index 0000000..fea47b9 Binary files /dev/null and b/icons/disk.png differ diff --git a/icons/down.png b/icons/down.png new file mode 100644 index 0000000..22d5855 Binary files /dev/null and b/icons/down.png differ diff --git a/icons/info.png b/icons/info.png new file mode 100644 index 0000000..fd54609 Binary files /dev/null and b/icons/info.png differ diff --git a/icons/layouts/dwindle.png b/icons/layouts/dwindle.png new file mode 100644 index 0000000..1e0aa0a Binary files /dev/null and b/icons/layouts/dwindle.png differ diff --git a/icons/layouts/fairh.png b/icons/layouts/fairh.png new file mode 100644 index 0000000..b4e289d Binary files /dev/null and b/icons/layouts/fairh.png differ diff --git a/icons/layouts/fairhw.png b/icons/layouts/fairhw.png new file mode 100644 index 0000000..65b4555 Binary files /dev/null and b/icons/layouts/fairhw.png differ diff --git a/icons/layouts/fairv.png b/icons/layouts/fairv.png new file mode 100644 index 0000000..e5aad70 Binary files /dev/null and b/icons/layouts/fairv.png differ diff --git a/icons/layouts/fairvw.png b/icons/layouts/fairvw.png new file mode 100644 index 0000000..583b4d5 Binary files /dev/null and b/icons/layouts/fairvw.png differ diff --git a/icons/layouts/floating.png b/icons/layouts/floating.png new file mode 100644 index 0000000..cbc7804 Binary files /dev/null and b/icons/layouts/floating.png differ diff --git a/icons/layouts/floatingw.png b/icons/layouts/floatingw.png new file mode 100644 index 0000000..6e261a4 Binary files /dev/null and b/icons/layouts/floatingw.png differ diff --git a/icons/layouts/fullscreen.png b/icons/layouts/fullscreen.png new file mode 100644 index 0000000..46716f5 Binary files /dev/null and b/icons/layouts/fullscreen.png differ diff --git a/icons/layouts/fullscreenw.png b/icons/layouts/fullscreenw.png new file mode 100644 index 0000000..bc09ae8 Binary files /dev/null and b/icons/layouts/fullscreenw.png differ diff --git a/icons/layouts/magnifier.png b/icons/layouts/magnifier.png new file mode 100644 index 0000000..1476555 Binary files /dev/null and b/icons/layouts/magnifier.png differ diff --git a/icons/layouts/magnifierw.png b/icons/layouts/magnifierw.png new file mode 100644 index 0000000..3dcc2f8 Binary files /dev/null and b/icons/layouts/magnifierw.png differ diff --git a/icons/layouts/max.png b/icons/layouts/max.png new file mode 100644 index 0000000..4246d56 Binary files /dev/null and b/icons/layouts/max.png differ diff --git a/icons/layouts/maxw.png b/icons/layouts/maxw.png new file mode 100644 index 0000000..0c769ee Binary files /dev/null and b/icons/layouts/maxw.png differ diff --git a/icons/layouts/spiral.png b/icons/layouts/spiral.png new file mode 100644 index 0000000..20db5b1 Binary files /dev/null and b/icons/layouts/spiral.png differ diff --git a/icons/layouts/tile.png b/icons/layouts/tile.png new file mode 100644 index 0000000..071a385 Binary files /dev/null and b/icons/layouts/tile.png differ diff --git a/icons/layouts/tilebottom.png b/icons/layouts/tilebottom.png new file mode 100644 index 0000000..aeedbe2 Binary files /dev/null and b/icons/layouts/tilebottom.png differ diff --git a/icons/layouts/tilebottomw.png b/icons/layouts/tilebottomw.png new file mode 100644 index 0000000..125809f Binary files /dev/null and b/icons/layouts/tilebottomw.png differ diff --git a/icons/layouts/tileleft.png b/icons/layouts/tileleft.png new file mode 100644 index 0000000..ab55e08 Binary files /dev/null and b/icons/layouts/tileleft.png differ diff --git a/icons/layouts/tileleftw.png b/icons/layouts/tileleftw.png new file mode 100644 index 0000000..f8e10c7 Binary files /dev/null and b/icons/layouts/tileleftw.png differ diff --git a/icons/layouts/tiletop.png b/icons/layouts/tiletop.png new file mode 100644 index 0000000..3febc35 Binary files /dev/null and b/icons/layouts/tiletop.png differ diff --git a/icons/layouts/tiletopw.png b/icons/layouts/tiletopw.png new file mode 100644 index 0000000..3edfeba Binary files /dev/null and b/icons/layouts/tiletopw.png differ diff --git a/icons/layouts/tilew.png b/icons/layouts/tilew.png new file mode 100644 index 0000000..3c602d1 Binary files /dev/null and b/icons/layouts/tilew.png differ diff --git a/icons/mail.png b/icons/mail.png new file mode 100644 index 0000000..f489e88 Binary files /dev/null and b/icons/mail.png differ diff --git a/icons/mem.png b/icons/mem.png new file mode 100644 index 0000000..b088d4a Binary files /dev/null and b/icons/mem.png differ diff --git a/icons/music.png b/icons/music.png new file mode 100644 index 0000000..4c2764d Binary files /dev/null and b/icons/music.png differ diff --git a/icons/pacman.png b/icons/pacman.png new file mode 100644 index 0000000..466c34f Binary files /dev/null and b/icons/pacman.png differ diff --git a/icons/phones.png b/icons/phones.png new file mode 100644 index 0000000..8b6c26a Binary files /dev/null and b/icons/phones.png differ diff --git a/icons/power.png b/icons/power.png new file mode 100644 index 0000000..b8add29 Binary files /dev/null and b/icons/power.png differ diff --git a/icons/rss.png b/icons/rss.png new file mode 100644 index 0000000..62d361e Binary files /dev/null and b/icons/rss.png differ diff --git a/icons/sat.png b/icons/sat.png new file mode 100644 index 0000000..485f36e Binary files /dev/null and b/icons/sat.png differ diff --git a/icons/submenu.png b/icons/submenu.png new file mode 100644 index 0000000..b2778e2 Binary files /dev/null and b/icons/submenu.png differ diff --git a/icons/sun.png b/icons/sun.png new file mode 100644 index 0000000..2f22c8e Binary files /dev/null and b/icons/sun.png differ diff --git a/icons/taglist/squarefw.png b/icons/taglist/squarefw.png new file mode 100644 index 0000000..2a86430 Binary files /dev/null and b/icons/taglist/squarefw.png differ diff --git a/icons/taglist/squarefz.png b/icons/taglist/squarefz.png new file mode 100644 index 0000000..6291037 Binary files /dev/null and b/icons/taglist/squarefz.png differ diff --git a/icons/taglist/squarefza.png b/icons/taglist/squarefza.png new file mode 100644 index 0000000..5475446 Binary files /dev/null and b/icons/taglist/squarefza.png differ diff --git a/icons/taglist/squarew.png b/icons/taglist/squarew.png new file mode 100644 index 0000000..c750e54 Binary files /dev/null and b/icons/taglist/squarew.png differ diff --git a/icons/taglist/squarez.png b/icons/taglist/squarez.png new file mode 100644 index 0000000..df65248 Binary files /dev/null and b/icons/taglist/squarez.png differ diff --git a/icons/taglist/squareza.png b/icons/taglist/squareza.png new file mode 100644 index 0000000..c3838b4 Binary files /dev/null and b/icons/taglist/squareza.png differ diff --git a/icons/tasklist/floating.png b/icons/tasklist/floating.png new file mode 100644 index 0000000..f29e7f5 Binary files /dev/null and b/icons/tasklist/floating.png differ diff --git a/icons/tasklist/floatingw.png b/icons/tasklist/floatingw.png new file mode 100644 index 0000000..eb802ae Binary files /dev/null and b/icons/tasklist/floatingw.png differ diff --git a/icons/temp.png b/icons/temp.png new file mode 100644 index 0000000..2e712e9 Binary files /dev/null and b/icons/temp.png differ diff --git a/icons/theme.lua b/icons/theme.lua new file mode 100644 index 0000000..d4b103e --- /dev/null +++ b/icons/theme.lua @@ -0,0 +1,92 @@ +--------------------------- +-- Default awesome theme -- +--------------------------- + +theme = {} + +theme.font = "fixed 6" + +theme.bg_normal = "#222222" +theme.bg_focus = "#535d6c" +theme.bg_urgent = "#ff0000" +theme.bg_minimize = "#444444" + +theme.fg_normal = "#aaaaaa" +theme.fg_focus = "#ffffff" +theme.fg_urgent = "#ffffff" +theme.fg_minimize = "#ffffff" + +theme.border_width = "0" +theme.border_normal = "#00000000" +theme.border_focus = "#535d6c55" +theme.border_marked = "#91231c55" + +-- There are another variables sets +-- overriding the default one when +-- defined, the sets are: +-- [taglist|tasklist]_[bg|fg]_[focus|urgent] +-- titlebar_[bg|fg]_[normal|focus] +-- Example: +--taglist_bg_focus = #ff0000 + +-- Display the taglist squares +theme.taglist_squares_sel = "/usr/share/awesome/themes/default/taglist/squarefw.png" +theme.taglist_squares_unsel = "/usr/share/awesome/themes/default/taglist/squarefw.png" + +theme.tasklist_floating_icon = "/usr/share/awesome/themes/default/tasklist/floatingw.png" + +-- Variables set for theming menu +-- menu_[bg|fg]_[normal|focus] +-- menu_[border_color|border_width] +theme.menu_submenu_icon = "/usr/share/awesome/themes/default/submenu.png" +theme.menu_height = "12" +theme.menu_width = "100" + +-- You can add as many variables as +-- you wish and access them by using +-- beautiful.variable in your rc.lua +--bg_widget = #cc0000 + +-- Define the image to load +theme.titlebar_close_button_normal = "/usr/share/awesome/themes/default/titlebar/close_normal.png" +theme.titlebar_close_button_focus = "/usr/share/awesome/themes/default/titlebar/close_focus.png" + +theme.titlebar_ontop_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/ontop_normal_inactive.png" +theme.titlebar_ontop_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/ontop_focus_inactive.png" +theme.titlebar_ontop_button_normal_active = "/usr/share/awesome/themes/default/titlebar/ontop_normal_active.png" +theme.titlebar_ontop_button_focus_active = "/usr/share/awesome/themes/default/titlebar/ontop_focus_active.png" + +theme.titlebar_sticky_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/sticky_normal_inactive.png" +theme.titlebar_sticky_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/sticky_focus_inactive.png" +theme.titlebar_sticky_button_normal_active = "/usr/share/awesome/themes/default/titlebar/sticky_normal_active.png" +theme.titlebar_sticky_button_focus_active = "/usr/share/awesome/themes/default/titlebar/sticky_focus_active.png" + +theme.titlebar_floating_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/floating_normal_inactive.png" +theme.titlebar_floating_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/floating_focus_inactive.png" +theme.titlebar_floating_button_normal_active = "/usr/share/awesome/themes/default/titlebar/floating_normal_active.png" +theme.titlebar_floating_button_focus_active = "/usr/share/awesome/themes/default/titlebar/floating_focus_active.png" + +theme.titlebar_maximized_button_normal_inactive = "/usr/share/awesome/themes/default/titlebar/maximized_normal_inactive.png" +theme.titlebar_maximized_button_focus_inactive = "/usr/share/awesome/themes/default/titlebar/maximized_focus_inactive.png" +theme.titlebar_maximized_button_normal_active = "/usr/share/awesome/themes/default/titlebar/maximized_normal_active.png" +theme.titlebar_maximized_button_focus_active = "/usr/share/awesome/themes/default/titlebar/maximized_focus_active.png" + +-- You can use your own command to set your wallpaper +-- theme.wallpaper_cmd = { "awsetbg /usr/share/awesome/themes/default/background.png" } + +-- You can use your own layout icons like this: +theme.layout_fairh = "/usr/share/awesome/themes/default/layouts/fairhw.png" +theme.layout_fairv = "/usr/share/awesome/themes/default/layouts/fairvw.png" +theme.layout_floating = "/usr/share/awesome/themes/default/layouts/floatingw.png" +theme.layout_magnifier = "/usr/share/awesome/themes/default/layouts/magnifierw.png" +theme.layout_max = "/usr/share/awesome/themes/default/layouts/maxw.png" +theme.layout_fullscreen = "/usr/share/awesome/themes/default/layouts/fullscreenw.png" +theme.layout_tilebottom = "/usr/share/awesome/themes/default/layouts/tilebottomw.png" +theme.layout_tileleft = "/usr/share/awesome/themes/default/layouts/tileleftw.png" +theme.layout_tile = "/usr/share/awesome/themes/default/layouts/tilew.png" +theme.layout_tiletop = "/usr/share/awesome/themes/default/layouts/tiletopw.png" + +theme.awesome_icon = "/usr/share/awesome/themes/default/layouts/taglist/squarew.png" + +return theme +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/icons/time.png b/icons/time.png new file mode 100644 index 0000000..929327e Binary files /dev/null and b/icons/time.png differ diff --git a/icons/titlebar/close_focus.png b/icons/titlebar/close_focus.png new file mode 100644 index 0000000..a5b7958 Binary files /dev/null and b/icons/titlebar/close_focus.png differ diff --git a/icons/titlebar/close_normal.png b/icons/titlebar/close_normal.png new file mode 100644 index 0000000..867cc4b Binary files /dev/null and b/icons/titlebar/close_normal.png differ diff --git a/icons/titlebar/floating_focus_active.png b/icons/titlebar/floating_focus_active.png new file mode 100644 index 0000000..3447bb2 Binary files /dev/null and b/icons/titlebar/floating_focus_active.png differ diff --git a/icons/titlebar/floating_focus_inactive.png b/icons/titlebar/floating_focus_inactive.png new file mode 100644 index 0000000..fd8e622 Binary files /dev/null and b/icons/titlebar/floating_focus_inactive.png differ diff --git a/icons/titlebar/floating_normal_active.png b/icons/titlebar/floating_normal_active.png new file mode 100644 index 0000000..a741315 Binary files /dev/null and b/icons/titlebar/floating_normal_active.png differ diff --git a/icons/titlebar/floating_normal_inactive.png b/icons/titlebar/floating_normal_inactive.png new file mode 100644 index 0000000..3f8f456 Binary files /dev/null and b/icons/titlebar/floating_normal_inactive.png differ diff --git a/icons/titlebar/maximized_focus_active.png b/icons/titlebar/maximized_focus_active.png new file mode 100644 index 0000000..78a2914 Binary files /dev/null and b/icons/titlebar/maximized_focus_active.png differ diff --git a/icons/titlebar/maximized_focus_inactive.png b/icons/titlebar/maximized_focus_inactive.png new file mode 100644 index 0000000..3f2c891 Binary files /dev/null and b/icons/titlebar/maximized_focus_inactive.png differ diff --git a/icons/titlebar/maximized_normal_active.png b/icons/titlebar/maximized_normal_active.png new file mode 100644 index 0000000..e907412 Binary files /dev/null and b/icons/titlebar/maximized_normal_active.png differ diff --git a/icons/titlebar/maximized_normal_inactive.png b/icons/titlebar/maximized_normal_inactive.png new file mode 100644 index 0000000..2bec71c Binary files /dev/null and b/icons/titlebar/maximized_normal_inactive.png differ diff --git a/icons/titlebar/ontop_focus_active.png b/icons/titlebar/ontop_focus_active.png new file mode 100644 index 0000000..f954bed Binary files /dev/null and b/icons/titlebar/ontop_focus_active.png differ diff --git a/icons/titlebar/ontop_focus_inactive.png b/icons/titlebar/ontop_focus_inactive.png new file mode 100644 index 0000000..98001e3 Binary files /dev/null and b/icons/titlebar/ontop_focus_inactive.png differ diff --git a/icons/titlebar/ontop_normal_active.png b/icons/titlebar/ontop_normal_active.png new file mode 100644 index 0000000..dfccec3 Binary files /dev/null and b/icons/titlebar/ontop_normal_active.png differ diff --git a/icons/titlebar/ontop_normal_inactive.png b/icons/titlebar/ontop_normal_inactive.png new file mode 100644 index 0000000..ee37d84 Binary files /dev/null and b/icons/titlebar/ontop_normal_inactive.png differ diff --git a/icons/titlebar/sticky_focus_active.png b/icons/titlebar/sticky_focus_active.png new file mode 100644 index 0000000..1106399 Binary files /dev/null and b/icons/titlebar/sticky_focus_active.png differ diff --git a/icons/titlebar/sticky_focus_inactive.png b/icons/titlebar/sticky_focus_inactive.png new file mode 100644 index 0000000..d7487b9 Binary files /dev/null and b/icons/titlebar/sticky_focus_inactive.png differ diff --git a/icons/titlebar/sticky_normal_active.png b/icons/titlebar/sticky_normal_active.png new file mode 100644 index 0000000..33136a2 Binary files /dev/null and b/icons/titlebar/sticky_normal_active.png differ diff --git a/icons/titlebar/sticky_normal_inactive.png b/icons/titlebar/sticky_normal_inactive.png new file mode 100644 index 0000000..b0cf399 Binary files /dev/null and b/icons/titlebar/sticky_normal_inactive.png differ diff --git a/icons/up.png b/icons/up.png new file mode 100644 index 0000000..94d4898 Binary files /dev/null and b/icons/up.png differ diff --git a/icons/vol.png b/icons/vol.png new file mode 100644 index 0000000..09714c8 Binary files /dev/null and b/icons/vol.png differ diff --git a/icons/wifi.png b/icons/wifi.png new file mode 100644 index 0000000..d9eaef5 Binary files /dev/null and b/icons/wifi.png differ diff --git a/json.lua b/json.lua new file mode 100644 index 0000000..841b0cb --- /dev/null +++ b/json.lua @@ -0,0 +1,515 @@ +--[[ + + JSON Encoder and Parser for Lua 5.1 + + Copyright © 2007 Shaun Brown (http://www.chipmunkav.com). + All Rights Reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + If you find this software useful please give www.chipmunkav.com a mention. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Usage: + + -- Lua script: + local t = { + ["name1"] = "value1", + ["name2"] = {1, false, true, 23.54, "a \021 string"}, + name3 = Json.Null() + } + + local json = Json.Encode (t) + print (json) + --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]} + + local t = Json.Decode(json) + print(t.name2[4]) + --> 23.54 + + Notes: + 1) Encodable Lua types: string, number, boolean, table, nil + 2) Use Json.Null() to insert a null value into a Json object + 3) All control chars are encoded to \uXXXX format eg "\021" encodes to "\u0015" + 4) All Json \uXXXX chars are decoded to chars (0-255 byte range only) + 5) Json single line // and /* */ block comments are discarded during decoding + 6) Numerically indexed Lua arrays are encoded to Json Lists eg [1,2,3] + 7) Lua dictionary tables are converted to Json objects eg {"one":1,"two":2} + 8) Json nulls are decoded to Lua nil and treated by Lua in the normal way + +--]] + +local string = string +local math = math +local table = table +local error = error +local tonumber = tonumber +local tostring = tostring +local type = type +local setmetatable = setmetatable +local pairs = pairs +local ipairs = ipairs +local assert = assert +local Chipmunk = Chipmunk + +module("Json") + +local StringBuilder = { + buffer = {} +} + +function StringBuilder:New() + local o = {} + setmetatable(o, self) + self.__index = self + o.buffer = {} + return o +end + +function StringBuilder:Append(s) + self.buffer[#self.buffer+1] = s +end + +function StringBuilder:ToString() + return table.concat(self.buffer) +end + +local JsonWriter = { + backslashes = { + ['\b'] = "\\b", + ['\t'] = "\\t", + ['\n'] = "\\n", + ['\f'] = "\\f", + ['\r'] = "\\r", + ['"'] = "\\\"", + ['\\'] = "\\\\", + ['/'] = "\\/" + } +} + +function JsonWriter:New() + local o = {} + o.writer = StringBuilder:New() + setmetatable(o, self) + self.__index = self + return o +end + +function JsonWriter:Append(s) + self.writer:Append(s) +end + +function JsonWriter:ToString() + return self.writer:ToString() +end + +function JsonWriter:Write(o) + local t = type(o) + if t == "nil" then + self:WriteNil() + elseif t == "boolean" then + self:WriteString(o) + elseif t == "number" then + self:WriteString(o) + elseif t == "string" then + self:ParseString(o) + elseif t == "table" then + self:WriteTable(o) + elseif t == "function" then + self:WriteFunction(o) + elseif t == "thread" then + self:WriteError(o) + elseif t == "userdata" then + self:WriteError(o) + end +end + +function JsonWriter:WriteNil() + self:Append("null") +end + +function JsonWriter:WriteString(o) + self:Append(tostring(o)) +end + +function JsonWriter:ParseString(s) + self:Append('"') + self:Append(string.gsub(s, "[%z%c\\\"/]", function(n) + local c = self.backslashes[n] + if c then return c end + return string.format("\\u%.4X", string.byte(n)) + end)) + self:Append('"') +end + +function JsonWriter:IsArray(t) + local count = 0 + local isindex = function(k) + if type(k) == "number" and k > 0 then + if math.floor(k) == k then + return true + end + end + return false + end + for k,v in pairs(t) do + if not isindex(k) then + return false, '{', '}' + else + count = math.max(count, k) + end + end + return true, '[', ']', count +end + +function JsonWriter:WriteTable(t) + local ba, st, et, n = self:IsArray(t) + self:Append(st) + if ba then + for i = 1, n do + self:Write(t[i]) + if i < n then + self:Append(',') + end + end + else + local first = true; + for k, v in pairs(t) do + if not first then + self:Append(',') + end + first = false; + self:ParseString(k) + self:Append(':') + self:Write(v) + end + end + self:Append(et) +end + +function JsonWriter:WriteError(o) + error(string.format( + "Encoding of %s unsupported", + tostring(o))) +end + +function JsonWriter:WriteFunction(o) + if o == Null then + self:WriteNil() + else + self:WriteError(o) + end +end + +local StringReader = { + s = "", + i = 0 +} + +function StringReader:New(s) + local o = {} + setmetatable(o, self) + self.__index = self + o.s = s or o.s + return o +end + +function StringReader:Peek() + local i = self.i + 1 + if i <= #self.s then + return string.sub(self.s, i, i) + end + return nil +end + +function StringReader:Next() + self.i = self.i+1 + if self.i <= #self.s then + return string.sub(self.s, self.i, self.i) + end + return nil +end + +function StringReader:All() + return self.s +end + +local JsonReader = { + escapes = { + ['t'] = '\t', + ['n'] = '\n', + ['f'] = '\f', + ['r'] = '\r', + ['b'] = '\b', + } +} + +function JsonReader:New(s) + local o = {} + o.reader = StringReader:New(s) + setmetatable(o, self) + self.__index = self + return o; +end + +function JsonReader:Read() + self:SkipWhiteSpace() + local peek = self:Peek() + if peek == nil then + error(string.format( + "Nil string: '%s'", + self:All())) + elseif peek == '{' then + return self:ReadObject() + elseif peek == '[' then + return self:ReadArray() + elseif peek == '"' then + return self:ReadString() + elseif string.find(peek, "[%+%-%d]") then + return self:ReadNumber() + elseif peek == 't' then + return self:ReadTrue() + elseif peek == 'f' then + return self:ReadFalse() + elseif peek == 'n' then + return self:ReadNull() + elseif peek == '/' then + self:ReadComment() + return self:Read() + else + error(string.format( + "Invalid input: '%s'", + self:All())) + end +end + +function JsonReader:ReadTrue() + self:TestReservedWord{'t','r','u','e'} + return true +end + +function JsonReader:ReadFalse() + self:TestReservedWord{'f','a','l','s','e'} + return false +end + +function JsonReader:ReadNull() + self:TestReservedWord{'n','u','l','l'} + return nil +end + +function JsonReader:TestReservedWord(t) + for i, v in ipairs(t) do + if self:Next() ~= v then + error(string.format( + "Error reading '%s': %s", + table.concat(t), + self:All())) + end + end +end + +function JsonReader:ReadNumber() + local result = self:Next() + local peek = self:Peek() + while peek ~= nil and string.find( + peek, + "[%+%-%d%.eE]") do + result = result .. self:Next() + peek = self:Peek() + end + result = tonumber(result) + if result == nil then + error(string.format( + "Invalid number: '%s'", + result)) + else + return result + end +end + +function JsonReader:ReadString() + local result = "" + assert(self:Next() == '"') + while self:Peek() ~= '"' do + local ch = self:Next() + if ch == '\\' then + ch = self:Next() + if self.escapes[ch] then + ch = self.escapes[ch] + end + end + result = result .. ch + end + assert(self:Next() == '"') + local fromunicode = function(m) + return string.char(tonumber(m, 16)) + end + return string.gsub( + result, + "u%x%x(%x%x)", + fromunicode) +end + +function JsonReader:ReadComment() + assert(self:Next() == '/') + local second = self:Next() + if second == '/' then + self:ReadSingleLineComment() + elseif second == '*' then + self:ReadBlockComment() + else + error(string.format( + "Invalid comment: %s", + self:All())) + end +end + +function JsonReader:ReadBlockComment() + local done = false + while not done do + local ch = self:Next() + if ch == '*' and self:Peek() == '/' then + done = true + end + if not done and + ch == '/' and + self:Peek() == "*" then + error(string.format( + "Invalid comment: %s, '/*' illegal.", + self:All())) + end + end + self:Next() +end + +function JsonReader:ReadSingleLineComment() + local ch = self:Next() + while ch ~= '\r' and ch ~= '\n' do + ch = self:Next() + end +end + +function JsonReader:ReadArray() + local result = {} + assert(self:Next() == '[') + local done = false + if self:Peek() == ']' then + done = true; + end + while not done do + local item = self:Read() + result[#result+1] = item + self:SkipWhiteSpace() + if self:Peek() == ']' then + done = true + end + if not done then + local ch = self:Next() + if ch ~= ',' then + error(string.format( + "Invalid array: '%s' due to: '%s'", + self:All(), ch)) + end + end + end + assert(']' == self:Next()) + return result +end + +function JsonReader:ReadObject() + local result = {} + assert(self:Next() == '{') + local done = false + if self:Peek() == '}' then + done = true + end + while not done do + local key = self:Read() + if type(key) ~= "string" then + error(string.format( + "Invalid non-string object key: %s", + key)) + end + self:SkipWhiteSpace() + local ch = self:Next() + if ch ~= ':' then + error(string.format( + "Invalid object: '%s' due to: '%s'", + self:All(), + ch)) + end + self:SkipWhiteSpace() + local val = self:Read() + result[key] = val + self:SkipWhiteSpace() + if self:Peek() == '}' then + done = true + end + if not done then + ch = self:Next() + if ch ~= ',' then + error(string.format( + "Invalid array: '%s' near: '%s'", + self:All(), + ch)) + end + end + end + assert(self:Next() == "}") + return result +end + +function JsonReader:SkipWhiteSpace() + local p = self:Peek() + while p ~= nil and string.find(p, "[%s/]") do + if p == '/' then + self:ReadComment() + else + self:Next() + end + p = self:Peek() + end +end + +function JsonReader:Peek() + return self.reader:Peek() +end + +function JsonReader:Next() + return self.reader:Next() +end + +function JsonReader:All() + return self.reader:All() +end + +function Encode(o) + local writer = JsonWriter:New() + writer:Write(o) + return writer:ToString() +end + +function Decode(s) + local reader = JsonReader:New(s) + return reader:Read() +end + +function Null() + return Null +end + diff --git a/lib/mpd.lua b/lib/mpd.lua new file mode 100644 index 0000000..df52ec5 --- /dev/null +++ b/lib/mpd.lua @@ -0,0 +1,150 @@ +-- Small interface to MusicPD +-- use luasocket, with a persistant connection to the MPD server. +-- +-- Author: Alexandre "kAworu" Perrin +-- +-- based on a netcat version from Steve Jothen +-- (see http://github.com/otkrove/ion3-config/tree/master/mpd.lua) +require("socket") + +-- Grab env +local socket = socket +local string = string +local tonumber = tonumber +local setmetatable = setmetatable +local os = os + +-- Music Player Daemon Lua library. +module("mpd") + +MPD = { +} MPD_mt = { __index = MPD } + +-- create and return a new mpd client. +-- the settings argument is a table with theses keys: +-- hostname: the MPD's host (default localhost) +-- port: MPD's port to connect to (default 6600) +-- desc: server's description (default hostname) +-- password: the server's password (default nil, no password) +-- timeout: time in sec to wait for connect() and receive() (default 1) +-- retry: time in sec to wait before reconnect if error (default 60) +function new(settings) + local client = {} + if settings == nil then settings = {} end + + client.hostname = settings.hostname or "localhost" + client.port = settings.port or 6600 + client.desc = settings.desc or client.hostname + client.password = settings.password + client.timeout = settings.timeout or 1 + client.retry = settings.retry or 60 + + setmetatable(client, MPD_mt) + + return client +end + + +-- calls the action and returns the server's response. +-- Example: if the server's response to "status" action is: +-- volume: 20 +-- repeat: 0 +-- random: 0 +-- playlist: 599 +-- ... +-- then the returned table is: +-- { volume = 20, repeat = 0, random = 0, playlist = 599, ... } +function MPD:send(action) + local command = string.format("%s\n", action) + local values = {} + + -- connect to MPD server if not already done. + if not self.connected then + if not self.last_try or (os.time() - self.last_try) > self.retry then + self.socket = socket.tcp() + self.socket:settimeout(self.timeout, 't') + self.last_try = os.time() + self.connected = self.socket:connect(self.hostname, self.port) + if self.connected and self.password then + self:send(string.format("password %s", self.password)) + end + end + end + + if not self.connected then + return {} + end + + self.socket:send(command) + + local line = "" + while not line:match("^OK$") do + line = self.socket:receive("*l") + if not line then -- closed,timeout (mpd killed?) + self.connected = false + return self:send(action) + end + + if line:match(string.format("^ACK", action)) then + return { errormsg = line } + end + + local _, _, key, value = string.find(line, "([^:]+):%s(.+)") + if key then + values[string.lower(key)] = value + end + end + + return values +end + +function MPD:next() + self:send("next") +end + +function MPD:previous() + self:send("previous") +end + +function MPD:stop() + self:send("stop") +end + +-- no need to check the new value, mpd will set the volume in [0,100] +function MPD:volume_up(delta) + local stats = self:send("status") + local new_volume = tonumber(stats.volume) + delta + self:send(string.format("setvol %d", new_volume)) +end + +function MPD:volume_down(delta) + self:volume_up(-delta) +end + +function MPD:toggle_random() + local stats = self:send("status") + if tonumber(stats.random) == 0 then + self:send("random 1") + else + self:send("random 0") + end +end + +function MPD:toggle_repeat() + local stats = self:send("status") + if tonumber(stats["repeat"]) == 0 then + self:send("repeat 1") + else + self:send("repeat 0") + end +end + +function MPD:toggle_play() + if self:send("status").state == "stop" then + self:send("play") + else + self:send("pause") + end +end + +-- vim:filetype=lua:tabstop=8:shiftwidth=2:fdm=marker: diff --git a/lib/shifty.lua b/lib/shifty.lua new file mode 100644 index 0000000..75a9f76 --- /dev/null +++ b/lib/shifty.lua @@ -0,0 +1,779 @@ +--- Shifty: Dynamic tagging library for awesome3-git +-- @author koniu <gkusnierz@gmail.com> +-- @author bioe007 <perry.hargrave@gmail.com> +-- +-- http://awesome.naquadah.org/wiki/index.php?title=Shifty + +-- package env +local type = type +local tag = tag +local ipairs = ipairs +local table = table +local client = client +local image = image +local string = string +local screen = screen +local button = button +local mouse = mouse +local beautiful = require("beautiful") +local awful = require("awful") +local pairs = pairs +local io = io +local tonumber = tonumber +local wibox = wibox +local root = root +local dbg= dbg +module("shifty") + +config = {} +config.tags = {} +config.apps = {} +config.defaults = {} +config.guess_name = true +config.guess_position = true +config.remember_index = true +config.default_name = "new" +config.clientkeys = {} +config.globalkeys = nil +config.layouts = {} +config.prompt_sources = { "config_tags", "config_apps", "existing", "history" } +config.prompt_matchers = { "^", ":", "" } + +local matchp = "" +local index_cache = {} +for i = 1, screen.count() do index_cache[i] = {} end + +--{{{ name2tags: matches string 'name' to tag objects +-- @param name : tag name to find +-- @param scr : screen to look for tags on +-- @return table of tag objects or nil +function name2tags(name, scr) + local ret = {} + local a, b = scr or 1, scr or screen.count() + for s = a, b do + for i, t in ipairs(screen[s]:tags()) do + if name == t.name then + table.insert(ret, t) + end + end + end + if #ret > 0 then return ret end +end + +function name2tag(name, scr, idx) + local ts = name2tags(name, scr) + if ts then return ts[idx or 1] end +end +--}}} + +--{{{ tag2index: finds index of a tag object +-- @param scr : screen number to look for tag on +-- @param tag : the tag object to find +-- @return the index [or zero] or end of the list +function tag2index(scr, tag) + for i,t in ipairs(screen[scr]:tags()) do + if t == tag then return i end + end +end +--}}} + +--{{{ rename +--@param tag: tag object to be renamed +--@param prefix: if any prefix is to be added +--@param no_selectall: +function rename(tag, prefix, no_selectall) + local theme = beautiful.get() + local t = tag or awful.tag.selected(mouse.screen) + local scr = t.screen + local bg = nil + local fg = nil + local text = prefix or t.name + local before = t.name + + if t == awful.tag.selected(scr) then + bg = theme.bg_focus or '#535d6c' + fg = theme.fg_urgent or '#ffffff' + else + bg = theme.bg_normal or '#222222' + fg = theme.fg_urgent or '#ffffff' + end + + awful.prompt.run( { + fg_cursor = fg, bg_cursor = bg, ul_cursor = "single", + text = text, selectall = not no_selectall, prompt = " " }, + taglist[scr][tag2index(scr,t)*2], + function (name) if name:len() > 0 then t.name = name; end end, + completion, + awful.util.getdir("cache") .. "/history_tags", nil, + function () + if t.name == before then + if awful.tag.getproperty(t, "initial") then del(t) end + else + awful.tag.setproperty(t, "initial", true) + set(t) + end + awful.hooks.user.call("tags", scr) + end + ) +end +--}}} + +--{{{ send: moves client to tag[idx] +-- maybe this isn't needed here in shifty? +-- @param idx the tag number to send a client to +function send(idx) + local scr = client.focus.screen or mouse.screen + local sel = awful.tag.selected(scr) + local sel_idx = tag2index(scr,sel) + local target = awful.util.cycle(#screen[scr]:tags(), sel_idx + idx) + awful.tag.viewonly(screen[scr]:tags()[target]) + awful.client.movetotag(screen[scr]:tags()[target], client.focus) +end + +function send_next() send(1) end +function send_prev() send(-1) end +--}}} + +function shift_next() set(awful.tag.selected(), { rel_index = 1 }) end +function shift_prev() set(awful.tag.selected(), { rel_index = -1 }) end + +--{{{ pos2idx: translate shifty position to tag index +--@param pos: position (an integer) +--@param scr: screen number +function pos2idx(pos, scr) + local v = 1 + if pos and scr then + for i = #screen[scr]:tags() , 1, -1 do + local t = screen[scr]:tags()[i] + if awful.tag.getproperty(t,"position") and awful.tag.getproperty(t,"position") <= pos then + v = i + 1 + break + end + end + end + return v +end +--}}} + +--{{{ select : helper function chooses the first non-nil argument +--@param args - table of arguments +function select(args) + for i, a in pairs(args) do + if a ~= nil then + return a + end + end +end +--}}} + +--{{{ tagtoscr : move an entire tag to another screen +-- +--@param scr : the screen to move tag to +--@param t : the tag to be moved [awful.tag.selected()] +--@return the tag +function tagtoscr(scr, t) + -- break if called with an invalid screen number + if not scr or scr < 1 or scr > screen.count() then return end + -- tag to move + local otag = t or awful.tag.selected() + + -- set screen and then reset tag to order properly + if #otag:clients() > 0 then + for _ , c in ipairs(otag:clients()) do + if not c.sticky then + c.screen = scr + c:tags( { otag } ) + else + awful.client.toggletag(otag,c) + end + end + end + return otag +end +---}}} + +--{{{ set : set a tags properties +--@param t: the tag +--@param args : a table of optional (?) tag properties +--@return t - the tag object +function set(t, args) + if not t then return end + if not args then args = {} end + + -- set the name + t.name = args.name or t.name + + -- attempt to load preset on initial run + local preset = (awful.tag.getproperty(t, "initial") and config.tags[t.name]) or {} + + -- pick screen and get its tag table + local scr = args.screen or (not t.screen and preset.screen) or t.screen or mouse.screen + if scr > screen.count() then scr = screen.count() end + if t.screen and scr ~= t.screen then + tagtoscr(scr, t) + t.screen = nil + end + local tags = screen[scr]:tags() + + -- try to guess position from the name + local guessed_position = nil + if not (args.position or preset.position) and config.guess_position then + local num = t.name:find('^[1-9]') + if num then guessed_position = tonumber(t.name:sub(1,1)) end + end + + -- select from args, preset, getproperty, config.defaults.configs or defaults + local props = { + layout = select{ args.layout, preset.layout, awful.tag.getproperty(t,"layout"), config.defaults.layout, awful.layout.suit.tile }, + mwfact = select{ args.mwfact, preset.mwfact, awful.tag.getproperty(t,"mwfact"), config.defaults.mwfact, 0.55 }, + nmaster = select{ args.nmaster, preset.nmaster, awful.tag.getproperty(t,"nmaster"), config.defaults.nmaster, 1 }, + ncol = select{ args.ncol, preset.ncol, awful.tag.getproperty(t,"ncol"), config.defaults.ncol, 1 }, + matched = select{ args.matched, awful.tag.getproperty(t,"matched") }, + exclusive = select{ args.exclusive, preset.exclusive, awful.tag.getproperty(t,"exclusive"), config.defaults.exclusive }, + persist = select{ args.persist, preset.persist, awful.tag.getproperty(t,"persist"), config.defaults.persist }, + nopopup = select{ args.nopopup, preset.nopopup, awful.tag.getproperty(t,"nopopup"), config.defaults.nopopup }, + leave_kills = select{ args.leave_kills, preset.leave_kills, awful.tag.getproperty(t,"leave_kills"), config.defaults.leave_kills }, + max_clients = select{ args.max_clients, preset.max_clients, awful.tag.getproperty(t,"max_clients"), config.defaults.max_clients }, + position = select{ args.position, preset.position, guessed_position, awful.tag.getproperty(t,"position" ) }, + icon = select{ args.icon and image(args.icon), preset.icon and image(preset.icon), awful.tag.getproperty(t,"icon"), config.defaults.icon and image(config.defaults.icon) }, + icon_only = select{ args.icon_only, preset.icon_only, awful.tag.getproperty(t,"icon_only"), config.defaults.icon_only }, + sweep_delay = select{ args.sweep_delay, preset.sweep_delay, awful.tag.getproperty(t,"sweep_delay"), config.defaults.sweep_delay }, + overload_keys = select{ args.overload_keys, preset.overload_keys, awful.tag.getproperty(t,"overload_keys"), config.defaults.overload_keys }, + } + + -- get layout by name if given as string + if type(props.layout) == "string" then + props.layout = getlayout(props.layout) + end + + -- set keys + if args.keys or preset.keys then + local keys = awful.util.table.join(config.globalkeys, args.keys or preset.keys) + if props.overload_keys then + props.keys = keys + else + props.keys = squash_keys(keys) + end + end + + -- calculate desired taglist index + local index = args.index or preset.index or config.defaults.index + local rel_index = args.rel_index or preset.rel_index or config.defaults.rel_index + local sel = awful.tag.selected(scr) + local sel_idx = (sel and tag2index(scr,sel)) or 0 --TODO: what happens with rel_idx if no tags selected + local t_idx = tag2index(scr,t) + local limit = (not t_idx and #tags + 1) or #tags + local idx = nil + + if rel_index then + idx = awful.util.cycle(limit, (t_idx or sel_idx) + rel_index) + elseif index then + idx = awful.util.cycle(limit, index) + elseif props.position then + idx = pos2idx(props.position, scr) + if t_idx and t_idx < idx then idx = idx - 1 end + elseif config.remember_index and index_cache[scr][t.name] then + idx = index_cache[scr][t.name] + elseif not t_idx then + idx = #tags + 1 + end + + -- if we have a new index, remove from old index and insert + if idx then + if t_idx then table.remove(tags, t_idx) end + table.insert(tags, idx, t) + index_cache[scr][t.name] = idx + end + + -- set tag properties and push the new tag table + for prop, val in pairs(props) do awful.tag.setproperty(t, prop, val) end + screen[scr]:tags(tags) + + -- execute run/spawn + if awful.tag.getproperty(t, "initial") then + local spawn = args.spawn or preset.spawn or config.defaults.spawn + local run = args.run or preset.run or config.defaults.run + if spawn and args.matched ~= true then awful.util.spawn_with_shell(spawn, scr) end + if run then run(t) end + awful.tag.setproperty(t, "initial", nil) + end + + return t +end +--}}} + +--{{{ add : adds a tag +--@param args: table of optional arguments +-- +function add(args) + if not args then args = {} end + local name = args.name or " " + + -- initialize a new tag object and its data structure + local t = tag( name ) + + -- tell set() that this is the first time + awful.tag.setproperty(t, "initial", true) + + -- apply tag settings + set(t, args) + + -- unless forbidden or if first tag on the screen, show the tag + if not (awful.tag.getproperty(t,"nopopup") or args.noswitch) or #screen[t.screen]:tags() == 1 then awful.tag.viewonly(t) end + + -- get the name or rename + if args.name then + t.name = args.name + else + -- FIXME: hack to delay rename for un-named tags for tackling taglist refresh + -- which disabled prompt from being rendered until input + awful.tag.setproperty(t, "initial", true) + if args.position then + f = function() rename(t, args.rename, true); awful.hooks.timer.unregister(f) end + else + f = function() rename(t); awful.hooks.timer.unregister(f) end + end + awful.hooks.timer.register(0.01, f) + end + + return t +end +--}}} + +--{{{ del : delete a tag +--@param tag : the tag to be deleted [current tag] +function del(tag) + local scr = (tag and tag.screen) or mouse.screen or 1 + local tags = screen[scr]:tags() + local sel = awful.tag.selected(scr) + local t = tag or sel + local idx = tag2index(scr,t) + + -- return if tag not empty (except sticky) + local clients = t:clients() + local sticky = 0 + for i, c in ipairs(clients) do + if c.sticky then sticky = sticky + 1 end + end + if #clients > sticky then return end + + -- store index for later + index_cache[scr][t.name] = idx + + -- remove tag + t.screen = nil + + -- if the current tag is being deleted, restore from history + if t == sel and #tags > 1 then + awful.tag.history.restore(scr) + -- this is supposed to cycle if history is invalid? + -- e.g. if many tags are deleted in a row + if not awful.tag.selected(scr) then + awful.tag.viewonly(tags[awful.util.cycle(#tags, idx - 1)]) + end + end + + -- FIXME: what is this for?? + if client.focus then client.focus:raise() end +end +--}}} + +--{{{ match : handles app->tag matching, a replacement for the manage hook in +-- rc.lua +--@param c : client to be matched +function match(c, startup) + local nopopup, intrusive, nofocus, run, slave, wfact, struts, geom + local target_tag_names, target_tags = {}, {} + local typ = c.type + local cls = c.class + local inst = c.instance + local role = c.role + local name = c.name + local keys = config.clientkeys or c:keys() or {} + local target_screen = mouse.screen + + c.border_color = beautiful.border_normal + c.border_width = beautiful.border_width + + -- try matching client to config.apps + for i, a in ipairs(config.apps) do + if a.match then + for k, w in ipairs(a.match) do + if + (cls and cls:find(w)) or + (inst and inst:find(w)) or + (name and name:find(w)) or + (role and role:find(w)) or + (typ and typ:find(w)) + then + if a.screen then target_screen = a.screen end + if a.tag then + if type(a.tag) == "string" then + target_tag_names = { a.tag } + else + target_tag_names = a.tag + end + end + if a.float ~= nil then awful.client.floating.set(c, a.float) end + if a.geometry ~=nil then geom = { x = a.geometry[1], y = a.geometry[2], width = a.geometry[3], height = a.geometry[4] } end + if a.slave ~=nil then slave = a.slave end + if a.nopopup ~=nil then nopopup = a.nopopup end + if a.intrusive ~=nil then intrusive = a.intrusive end + if a.fullscreen ~=nil then c.fullscreen = a.fullscreen end + if a.honorsizehints ~=nil then c.size_hints_honor = a.honorsizehints end + if a.kill ~=nil then c:kill(); return end + if a.ontop ~= nil then c.ontop = a.ontop end + if a.above ~= nil then c.above = a.above end + if a.below ~= nil then c.below = a.below end + if a.buttons ~= nil then c:buttons(a.buttons) end + if a.nofocus ~= nil then nofocus = a.nofocus end + if a.keys ~= nil then keys = awful.util.table.join(keys, a.keys) end + if a.hide ~= nil then c.hide = a.hide end + if a.minimized ~= nil then c.minimized = a.minimized end + if a.dockable ~= nil then awful.client.dockable.set(c, a.dockable) end + if a.urgent ~= nil then c.urgent = a.urgent end + if a.opacity ~= nil then c.opacity = a.opacity end + if a.titlebar ~= nil then awful.titlebar.add(c, { modkey = modkey }) end + if a.run ~= nil then run = a.run end + if a.sticky ~= nil then c.sticky = a.sticky end + if a.wfact ~= nil then wfact = a.wfact end + if a.struts then struts = a.struts end + end + end + end + end + + -- set key bindings + c:keys(keys) + + -- set properties of floating clients + if awful.client.floating.get(c) then + if config.defaults.floatBars then -- add a titlebar if requested in config.defaults + awful.titlebar.add( c, { modkey = modkey } ) + end + awful.placement.centered(c, c.transient_for) + awful.placement.no_offscreen(c) -- this always seems to stick the client at 0,0 (incl titlebar) + end + + -- if not matched to some names try putting client in c.transient_for or current tags + local sel = awful.tag.selectedlist(target_screen) + if not target_tag_names or #target_tag_names == 0 then + if c.transient_for then + target_tags = c.transient_for:tags() + elseif #sel > 0 then + for i, t in ipairs(sel) do + local mc = awful.tag.getproperty(t,"max_clients") + if not (awful.tag.getproperty(t,"exclusive") or (mc and mc >= #t:clients())) or intrusive then + table.insert(target_tags, t) + end + end + end + end + + -- if we still don't know any target names/tags guess name from class or use default + if (not target_tag_names or #target_tag_names == 0) and (not target_tags or #target_tags == 0) then + if config.guess_name and cls then + target_tag_names = { cls:lower() } + else + target_tag_names = { config.default_name } + end + end + + -- translate target names to tag objects, creating missing ones + if #target_tag_names > 0 and #target_tags == 0 then + for i, tn in ipairs(target_tag_names) do + local res = {} + for j, t in ipairs(name2tags(tn, target_screen) or name2tags(tn) or {}) do + local mc = awful.tag.getproperty(t,"max_clients") + if not (mc and (#t:clients() >= mc)) or intrusive then + table.insert(res, t) + end + end + if #res == 0 then + table.insert(target_tags, add({ name = tn, noswitch = true, matched = true })) + else + target_tags = awful.util.table.join(target_tags, res) + end + end + end + + -- set client's screen/tag if needed + target_screen = target_tags[1].screen or target_screen + if c.screen ~= target_screen then c.screen = target_screen end + c:tags( target_tags ) + if slave then awful.client.setslave(c) end + if wfact then awful.client.setwfact(wfact, c) end + if geom then c:geometry(geom) end + if struts then c:struts(struts) end + + -- switch or highlight + local showtags = {} + local u = nil + if #target_tags > 0 then + for i,t in ipairs(target_tags) do + if not(awful.tag.getproperty(t,"nopopup") or nopopup) then + table.insert(showtags, t) + elseif not startup then + c.urgent = true + end + end + if #showtags > 0 then + awful.tag.viewmore(showtags, c.screen) + end + end + + -- focus and raise accordingly or lower if supressed + if not (nofocus or c.hide or c.minimized) then + if (awful.tag.getproperty(target,"nopopup") or nopopup) and (target and target ~= sel) then + awful.client.focus.history.add(c) + else + client.focus = c + end + c:raise() + else + c:lower() + end + + -- execute run function if specified + if run then run(c, target) end +end +--}}} + +--{{{ sweep : hook function that marks tags as used, visited, deserted +-- also handles deleting used and empty tags +function sweep() + for s = 1, screen.count() do + for i, t in ipairs(screen[s]:tags()) do + local clients = t:clients() + local sticky = 0 + for i, c in ipairs(clients) do + if c.sticky then sticky = sticky + 1 end + end + if #clients == sticky then + if not awful.tag.getproperty(t,"persist") and awful.tag.getproperty(t,"used") then + if awful.tag.getproperty(t,"deserted") or not awful.tag.getproperty(t,"leave_kills") then + local delay = awful.tag.getproperty(t,"sweep_delay") + if delay then + --FIXME: global f, what if more than one at a time is being swept + f = function() del(t); awful.hooks.timer.unregister(f) end + awful.hooks.timer.register(delay, f) + else + del(t) + end + else + if not t.selected and awful.tag.getproperty(t,"visited") then awful.tag.setproperty(t,"deserted", true) end + end + end + else + awful.tag.setproperty(t,"used",true) + end + if t.selected then awful.tag.setproperty(t,"visited",true) end + end + end +end +--}}} + +--{{{ getpos : returns a tag to match position +-- * originally this function did a lot of client stuff, i think its +-- * better to leave what can be done by awful to be done by awful +-- * -perry +-- @param pos : the index to find +-- @return v : the tag (found or created) at position == 'pos' +function getpos(pos) + local v = nil + local existing = {} + local selected = nil + local scr = mouse.screen or 1 + -- search for existing tag assigned to pos + for i = 1, screen.count() do + local s = awful.util.cycle(screen.count(), scr + i - 1) + for j, t in ipairs(screen[s]:tags()) do + if awful.tag.getproperty(t,"position") == pos then + table.insert(existing, t) + if t.selected and s == scr then selected = #existing end + end + end + end + if #existing > 0 then + -- if makeing another of an existing tag, return the end of the list + if selected then v = existing[awful.util.cycle(#existing, selected + 1)] else v = existing[1] end + end + if not v then + -- search for preconf with 'pos' and create it + for i, j in pairs(config.tags) do + if j.position == pos then v = add({ name = i, position = pos, noswitch = not switch }) end + end + end + if not v then + -- not existing, not preconfigured + v = add({ position = pos, rename = pos .. ':', no_selectall = true, noswitch = not switch }) + end + return v +end +--}}} + +--{{{ init : search shifty.config.tags for initial set of tags to open +function init() + local numscr = screen.count() + + for i, j in pairs(config.tags) do + local scr = j.screen or 1 + if j.init and ( scr <= numscr ) then + add({ name = i, persist = true, screen = scr, layout = j.layout, mwfact = j.mwfact }) + end + end +end +--}}} + +--{{{ count : utility function returns the index of a table element +--FIXME: this is currently used only in remove_dup, so is it really necessary? +function count(table, element) + local v = 0 + for i, e in pairs(table) do + if element == e then v = v + 1 end + end + return v +end +--}}} + +--{{{ remove_dup : used by shifty.completion when more than one +--tag at a position exists +function remove_dup(table) + local v = {} + for i, entry in ipairs(table) do + if count(v, entry) == 0 then v[#v+ 1] = entry end + end + return v +end +--}}} + +--{{{ completion : prompt completion +-- +function completion(cmd, cur_pos, ncomp, sources, matchers) + + -- get sources and matches tables + sources = sources or config.prompt_sources + matchers = matchers or config.prompt_matchers + + local get_source = { + -- gather names from config.tags + config_tags = function() + local ret = {} + for n, p in pairs(config.tags) do table.insert(ret, n) end + return ret + end, + -- gather names from config.apps + config_apps = function() + local ret = {} + for i, p in pairs(config.apps) do + if p.tag then + if type(p.tag) == "string" then + table.insert(ret, p.tag) + else + ret = awful.util.table.join(ret, p.tag) + end + end + end + return ret + end, + -- gather names from existing tags, starting with the current screen + existing = function() + local ret = {} + for i = 1, screen.count() do + local s = awful.util.cycle(screen.count(), mouse.screen + i - 1) + local tags = screen[s]:tags() + for j, t in pairs(tags) do table.insert(ret, t.name) end + end + return ret + end, + -- gather names from history + history = function() + local ret = {} + local f = io.open(awful.util.getdir("cache") .. "/history_tags") + for name in f:lines() do table.insert(ret, name) end + f:close() + return ret + end, + } + + -- if empty, match all + if #cmd == 0 or cmd == " " then cmd = "" end + + -- match all up to the cursor if moved or no matchphrase + if matchp == "" or cmd:sub(cur_pos, cur_pos+#matchp) ~= matchp then + matchp = cmd:sub(1, cur_pos) + end + + -- find matching commands + local matches = {} + for i, src in ipairs(sources) do + local source = get_source[src]() + for j, matcher in ipairs(matchers) do + for k, name in ipairs(source) do + if name:find(matcher .. matchp) then + table.insert(matches, name) + end + end + end + end + + -- no matches + if #matches == 0 then return cmd, cur_pos end + + -- remove duplicates + matches = remove_dup(matches) + + -- cycle + while ncomp > #matches do ncomp = ncomp - #matches end + + -- put cursor at the end of the matched phrase + if #matches == 1 then + cur_pos = #matches[ncomp] + 1 + else + cur_pos = matches[ncomp]:find(matchp) + #matchp + end + + -- return match and position + return matches[ncomp], cur_pos +end +--}}} + +-- {{{ tagkeys : hook function that sets keybindings per tag +function tagkeys(s) + local sel = awful.tag.selected(s) + local keys = awful.tag.getproperty(sel, "keys") or config.globalkeys + if keys then root.keys(keys) end +end +-- }}} + +-- {{{ squash_keys: helper function which removes duplicate keybindings +-- by picking only the last one to be listed in keys table arg +function squash_keys(keys) + local squashed = {} + local ret = {} + for i, k in ipairs(keys) do + squashed[table.concat(k.modifiers) .. k.keysym] = k + end + for i, k in pairs(squashed) do + table.insert(ret, k) + end + return ret +end +-- }}} + +-- {{{ getlayout: returns a layout by name +function getlayout(name) + for _, layout in ipairs(config.layouts) do + if awful.layout.getname(layout) == name then return layout end + end +end +-- }}} + +awful.hooks.manage.unregister(awful.tag.withcurrent) +awful.hooks.tags.register(sweep) +awful.hooks.arrange.register(sweep) +awful.hooks.arrange.register(tagkeys) +awful.hooks.clients.register(sweep) +awful.hooks.manage.register(match) + +-- vim: foldmethod=marker:filetype=lua:expandtab:shiftwidth=2:tabstop=2:softtabstop=2:encoding=utf-8:textwidth=80 diff --git a/rc.lua b/rc.lua new file mode 100644 index 0000000..9518105 --- /dev/null +++ b/rc.lua @@ -0,0 +1,335 @@ +-- Standard awesome library +require("awful") +require("awful.autofocus") +require("awful.rules") +-- Theme handling library +require("beautiful") +-- Notification library +require("naughty") +require("teardrop") + +-- {{{ Variable definitions +-- Themes define colours, icons, and wallpapers +beautiful.init("/usr/share/awesome/themes/default/theme.lua") + +-- This is used later as the default terminal and editor to run. +terminal = "terminal" +editor = os.getenv("EDITOR") or "vim" +editor_cmd = terminal .. " -e " .. editor + +-- 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" + +-- Table of layouts to cover with awful.layout.inc, order matters. +layouts = +{ + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.spiral, + awful.layout.suit.spiral.dwindle, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.magnifier, + awful.layout.suit.floating +} +-- }}} + +-- {{{ Tags +-- Define a tag table which hold all screen tags. +tags = {} +for s = 1, screen.count() do + -- Each screen has its own tag table. + tags[s] = awful.tag({ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, s) +end +-- }}} + +-- {{{ Menu +-- Create a laucher widget and a main menu +myawesomemenu = { + { "manual", terminal .. " -e man awesome" }, + { "edit config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" }, + { "restart", awesome.restart }, + { "quit", awesome.quit } +} + +mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon }, + { "open terminal", terminal } + } + }) + +mylauncher = awful.widget.launcher({ image = image(beautiful.awesome_icon), + menu = mymainmenu }) +-- }}} + +-- {{{ Wibox +-- Create a textclock widget +mytextclock = awful.widget.textclock({ align = "right" }) + +-- Create a systray +mysystray = widget({ type = "systray" }) + +-- Create a wibox for each screen and add it +mywibox = {} +mypromptbox = {} +mylayoutbox = {} +mytaglist = {} +mytaglist.buttons = awful.util.table.join( + awful.button({ }, 1, awful.tag.viewonly), + awful.button({ modkey }, 1, awful.client.movetotag), + awful.button({ }, 3, awful.tag.viewtoggle), + awful.button({ modkey }, 3, awful.client.toggletag), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) + ) +mytasklist = {} +mytasklist.buttons = awful.util.table.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 = awful.menu.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)) + +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(awful.util.table.join( + awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end), + awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end), + awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end))) + -- Create a taglist widget + mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons) + + -- Create a tasklist widget + mytasklist[s] = awful.widget.tasklist(function(c) + return awful.widget.tasklist.label.currenttags(c, s) + end, mytasklist.buttons) + + -- Create the wibox + mywibox[s] = awful.wibox({ position = "top", screen = s }) + -- Add widgets to the wibox - order matters + mywibox[s].widgets = { + { + mylauncher, + mytaglist[s], + mypromptbox[s], + layout = awful.widget.layout.horizontal.leftright + }, + mylayoutbox[s], + mytextclock, + s == 1 and mysystray or nil, + mytasklist[s], + layout = awful.widget.layout.horizontal.rightleft + } +end +-- }}} + +-- {{{ Mouse bindings +root.buttons(awful.util.table.join( + awful.button({ }, 3, function () mymainmenu:toggle() end), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = awful.util.table.join( + awful.key({ modkey, }, "Left", awful.tag.viewprev ), + awful.key({ modkey, }, "Right", awful.tag.viewnext ), + awful.key({ modkey, }, "Escape", awful.tag.history.restore), + + awful.key({ modkey, }, "j", + function () + awful.client.focus.byidx( 1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, }, "k", + function () + awful.client.focus.byidx(-1) + if client.focus then client.focus:raise() end + end), + awful.key({ modkey, }, "w", function () mymainmenu:show(true) end), + + -- Layout manipulation + awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end), + awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end), + awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end), + awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end), + awful.key({ modkey, }, "u", awful.client.urgent.jumpto), + awful.key({ modkey, }, "Tab", + function () + awful.client.focus.history.previous() + if client.focus then + client.focus:raise() + end + end), + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end), + awful.key({ modkey, "Control" }, "r", awesome.restart), + awful.key({ modkey, "Shift" }, "q", awesome.quit), + + awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end), + awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end), + awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1) end), + awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end), + awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end), + awful.key({ modkey, }, "space", function () awful.layout.inc(layouts, 1) end), + awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end), + + -- Prompt + awful.key({ modkey }, "r", function () mypromptbox[mouse.screen]:run() end), + + awful.key({ modkey }, "x", + function () + awful.prompt.run({ prompt = "Run Lua code: " }, + mypromptbox[mouse.screen].widget, + awful.util.eval, nil, + awful.util.getdir("cache") .. "/history_eval") + end) +) + +clientkeys = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end), + awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ), + awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end), + awful.key({ modkey, }, "o", awful.client.movetoscreen ), + awful.key({ modkey, "Shift" }, "r", function (c) c:redraw() end), + awful.key({ modkey, }, "n", function (c) c.minimized = not c.minimized end), + awful.key({ modkey, }, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end) +) + +-- 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 + +-- Bind all key numbers to tags. +-- Be careful: we use keycodes to make it works on any keyboard layout. +-- This should map on the top row of your keyboard, usually 1 to 9. +for i = 1, keynumber do + globalkeys = awful.util.table.join(globalkeys, + awful.key({ modkey }, "#" .. i + 9, + function () + local screen = mouse.screen + if tags[screen][i] then + awful.tag.viewonly(tags[screen][i]) + end + end), + awful.key({ modkey, "Control" }, "#" .. i + 9, + function () + local screen = mouse.screen + if tags[screen][i] then + awful.tag.viewtoggle(tags[screen][i]) + end + end), + awful.key({ modkey, "Shift" }, "#" .. i + 9, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.movetotag(tags[client.focus.screen][i]) + end + end), + awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, + function () + if client.focus and tags[client.focus.screen][i] then + awful.client.toggletag(tags[client.focus.screen][i]) + end + end)) +end + +clientbuttons = awful.util.table.join( + awful.button({ }, 1, function (c) client.focus = c; c:raise() end), + awful.button({ modkey }, 1, awful.mouse.client.move), + awful.button({ modkey }, 3, awful.mouse.client.resize)) + +-- Set keys +root.keys(globalkeys) +-- }}} + +-- {{{ Rules +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 } }, + { rule = { class = "MPlayer" }, + properties = { floating = true } }, + { rule = { class = "pinentry" }, + properties = { floating = true } }, + { rule = { class = "gimp" }, + properties = { floating = true } }, + -- Set Firefox to always map on tags number 2 of screen 1. + -- { rule = { class = "Firefox" }, + -- properties = { tag = tags[1][2] } }, +} +-- }}} + +-- {{{ Signals +-- Signal function to execute when a new client appears. +client.add_signal("manage", function (c, startup) + -- Add a titlebar + -- awful.titlebar.add(c, { modkey = modkey }) + + -- 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("focus", function(c) c.border_color = beautiful.border_focus end) +client.add_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) +-- }}} diff --git a/scratchpad.lua b/scratchpad.lua new file mode 100644 index 0000000..c196fc3 --- /dev/null +++ b/scratchpad.lua @@ -0,0 +1,136 @@ +--------------------------------------------------------------- +-- Basic scratchpad manager for the awesome window manager +--------------------------------------------------------------- +-- Adrian C. +-- Licensed under the WTFPL version 2 +-- * http://sam.zoy.org/wtfpl/COPYING +--------------------------------------------------------------- +-- To use this module add: +-- require("scratchpad") +-- to the top of your rc.lua, and call: +-- scratchpad.set(c, width, height, sticky, screen) +-- from a clientkeys binding, and: +-- scratchpad.toggle(screen) +-- from a globalkeys binding. +-- +-- Parameters: +-- c - Client to scratch or un-scratch +-- width - Width in absolute pixels, or width percentage +-- when < 1 (0.50 (50% of the screen) by default) +-- height - Height in absolute pixels, or height percentage +-- when < 1 (0.50 (50% of the screen) by default) +-- sticky - Visible on all tags, false by default +-- screen - Screen (optional), mouse.screen by default +--------------------------------------------------------------- + +-- Grab environment +local awful = require("awful") +local capi = { + mouse = mouse, + client = client, + screen = screen +} + +-- Scratchpad: Basic scratchpad manager for the awesome window manager +module("scratchpad") + +local scratch = {} + +-- Scratch the focused client, or un-scratch and tile it. If another +-- client is already scratched, replace it with the focused client. +function set(c, width, height, sticky, screen) + local width = width or 0.50 + local height = height or 0.50 + local sticky = sticky or false + local screen = screen or capi.mouse.screen + + local function setscratch(c) + -- Scratchpad is floating + awful.client.floating.set(c, true) + + -- Scratchpad geometry and placement + local screengeom = capi.screen[screen].workarea + + if width < 1 then width = screengeom.width * width end + if height < 1 then height = screengeom.height * height end + + c:geometry({ -- Client is always centered on screen + x = screengeom.x + (screengeom.width - width) / 2, + y = screengeom.y + (screengeom.height - height) / 2, + width = width, height = height + }) + + -- Scratchpad properties + c.ontop = true + c.above = true + c.skip_taskbar = true + if sticky then c.sticky = true end + if c.titlebar then awful.titlebar.remove(c) end + + -- Scratchpad should not loose focus + c:raise() + capi.client.focus = c + end + + -- Prepare a table for storing clients, + if not scratch["pad"] then scratch["pad"] = {} + -- add unmanage signal for scratchpad clients + capi.client.add_signal("unmanage", function (c) + local oc = scratch["pad"][screen] + if oc == c then + scratch["pad"][screen] = nil + end + end) + end + + -- If the scratcphad is emtpy, store the client, + if not scratch["pad"][screen] then + scratch["pad"][screen] = c + -- then apply geometry and properties + setscratch(c) + else -- If a client is already scratched, + local oc = scratch["pad"][screen] + -- compare it with the focused client + if oc == c then + -- If it matches then unscratch and clear the table + awful.client.floating.toggle(oc); oc.sticky = false + oc.ontop = false; oc.above = false + scratch["pad"][screen] = nil + else -- If they don't match, unscratch and replace it + oc.hidden = false; oc.sticky = false + oc.ontop = false; oc.above = false + awful.client.floating.toggle(oc) + scratch["pad"][screen] = c + setscratch(c) + end + end +end + +-- Move the scratchpad to the current workspace, focus and raise it +-- when it's hidden, or hide it when it's visible. +function toggle(screen) + local screen = screen or capi.mouse.screen + + -- Check if we have a client on storage, + if scratch["pad"] and + scratch["pad"][screen] ~= nil + then -- and get it out, to play + local c = scratch["pad"][screen] + + -- If it's visible on another tag hide it, + if c:isvisible() == false then c.hidden = true; + -- and move it to the current worskpace + awful.client.movetotag(awful.tag.selected(screen), c) + end + + -- Focus and raise if it's hidden, + if c.hidden then + awful.placement.centered(c) + c.hidden = false + c:raise() + capi.client.focus = c + else -- hide it if it's not + c.hidden = true + end + end +end diff --git a/teardrop.lua b/teardrop.lua new file mode 100644 index 0000000..f9ce7bb --- /dev/null +++ b/teardrop.lua @@ -0,0 +1,128 @@ +---------------------------------------------------------------- +-- Drop-down applications manager for the awesome window manager +---------------------------------------------------------------- +-- Adrian C. +-- Licensed under the WTFPL version 2 +-- * http://sam.zoy.org/wtfpl/COPYING +---------------------------------------------------------------- +-- To use this module add: +-- require("teardrop") +-- to the top of your rc.lua, and call it from a keybinding: +-- teardrop(prog, vert, horiz, width, height, sticky, screen) +-- +-- Parameters: +-- prog - Program to run; "urxvt", "gmrun", "thunderbird" +-- vert - Vertical; "bottom", "center" or "top" (default) +-- horiz - Horizontal; "left", "right" or "center" (default) +-- width - Width in absolute pixels, or width percentage +-- when < 1 (0.9999 (99.9% of the screen) by default) +-- height - Height in absolute pixels, or height percentage +-- when < 1 (0.25 (25% of the screen) by default) +-- sticky - Visible on all tags, false by default +-- screen - Screen (optional), mouse.screen by default +---------------------------------------------------------------- + +-- Grab environment +local pairs = pairs +local awful = require("awful") +local setmetatable = setmetatable +local capi = { + mouse = mouse, + client = client, + screen = screen +} + +-- Teardrop: Drop-down applications manager for the awesome window manager +module("teardrop") + +local dropdown = {} + +-- Create a new window for the drop-down application when it doesn't +-- exist, or toggle between hidden and visible states when it does +function toggle(prog, vert, horiz, width, height, sticky, screen) + local vert = vert or "top" + local horiz = horiz or "center" + local width = width or 0.9999 + local height = height or 0.25 + local sticky = sticky or false + local screen = screen or capi.mouse.screen + + if not dropdown[prog] then + dropdown[prog] = {} + + -- Add unmanage signal for teardrop programs + capi.client.add_signal("unmanage", function (c) + for scr, cl in pairs(dropdown[prog]) do + if cl == c then + dropdown[prog][scr] = nil + end + end + end) + end + + if not dropdown[prog][screen] then + spawnw = function (c) + dropdown[prog][screen] = c + + -- Teardrop clients are floaters + awful.client.floating.set(c, true) + + -- Client geometry and placement + local screengeom = capi.screen[screen].workarea + + if width < 1 then width = screengeom.width * width end + if height < 1 then height = screengeom.height * height end + + if horiz == "left" then x = screengeom.x + elseif horiz == "right" then x = screengeom.width - width + else x = screengeom.x+(screengeom.width-width)/2 end + + if vert == "bottom" then y = screengeom.height + screengeom.y - height + elseif vert == "center" then y = screengeom.y+(screengeom.height-height)/2 + else y = screengeom.y - screengeom.y end + + -- Client properties + c:geometry({ x = x, y = y, width = width, height = height }) + c.ontop = true + c.above = true + c.skip_taskbar = true + if sticky then c.sticky = true end + if c.titlebar then awful.titlebar.remove(c) end + + c:raise() + capi.client.focus = c + capi.client.remove_signal("manage", spawnw) + end + + -- Add manage signal and spawn the program + capi.client.add_signal("manage", spawnw) + awful.util.spawn(prog, false) + else + -- Get a running client + c = dropdown[prog][screen] + + -- Switch the client to the current workspace + if c:isvisible() == false then c.hidden = true; + awful.client.movetotag(awful.tag.selected(screen), c) + end + + -- Focus and raise if hidden + if c.hidden then + -- Make sure it is centered + if vert == "center" then awful.placement.center_vertical(c) end + if horiz == "center" then awful.placement.center_horizontal(c) end + c.hidden = false + c:raise() + capi.client.focus = c + else -- Hide and detach tags if not + c.hidden = true + local ctags = c:tags() + for i, v in pairs(ctags) do + ctags[i] = nil + end + c:tags(ctags) + end + end +end + +setmetatable(_M, { __call = function(_, ...) return toggle(...) end }) diff --git a/theme.lua b/theme.lua new file mode 100644 index 0000000..df83de0 --- /dev/null +++ b/theme.lua @@ -0,0 +1,142 @@ +------------------------------- +-- "Zenburn" awesome theme -- +-- By Adrian C. (anrxc) -- +------------------------------- + + +-- {{{ Main +theme = {} +confdir = awful.util.getdir("config") +theme.wallpaper_cmd = { "/usr/bin/nitrogen --restore" } +--theme.wallpaper_cmd = { "awsetbg /usr/share/awesome/themes/zenburn/zenburn-background.png" } +-- }}} + + +-- {{{ Styles +theme.font = "fixed 6" + +-- {{{ Colors +theme.fg_normal = "#DCDCCC" +theme.fg_focus = "#F0DFAF" +theme.fg_urgent = "#CC9393" +theme.bg_normal = "#3F3F3F" +theme.bg_focus = "#1E2320" +theme.bg_urgent = "#3F3F3F" +-- }}} + +-- {{{ Borders +theme.border_width = "1" +theme.border_normal = "#3F3F3F" +theme.border_focus = "#6F6F6F" +theme.border_marked = "#CC9393" +-- }}} + +-- {{{ Titlebars +theme.titlebar_bg_focus = "#5F5F5F" +theme.titlebar_bg_normal = "#3F3F3F" +-- theme.titlebar_[normal|focus] +-- }}} + +-- {{{ Widgets +theme.fg_widget = "#AECF96" +theme.fg_center_widget = "#88A175" +theme.fg_end_widget = "#FF5656" +theme.fg_off_widget = "#494B4F" +theme.fg_netup_widget = "#7F9F7F" +theme.fg_netdn_widget = "#CC9393" +theme.bg_widget = "#3F3F3F" +theme.border_widget = "#3F3F3F" +-- }}} + +-- {{{ Mouse finder +theme.mouse_finder_color = "#CC9393" +-- theme.mouse_finder_[timeout|animate_timeout|radius|factor] +-- }}} + +-- {{{ Tooltips +-- theme.tooltip_[font|opacity|fg_color|bg_color|border_width|border_color] +-- }}} + +-- {{{ Taglist and Tasklist +-- theme.[taglist|tasklist]_[bg|fg]_[focus|urgent] +-- }}} + +-- {{{ Menu +-- theme.menu_[height|width] +-- theme.menu_[bg|fg]_[normal|focus] +-- theme.menu_[border_color|border_width] +-- }}} +-- }}} + + +-- {{{ Icons +-- +-- {{{ Taglist icons +theme.taglist_squares_sel = confdir .. "/icons/taglist/squarefw.png" +theme.taglist_squares_unsel = confdir .. "/icons/taglist/squarew.png" +--theme.taglist_squares_resize = "false" +-- }}} + +-- {{{ Misc icons +--theme.awesome_icon = confdir .. "/icons/awesome.png" +--theme.menu_submenu_icon = "/usr/share/awesome/themes/default/submenu.png" +--theme.tasklist_floating_icon = "/usr/share/awesome/themes/default/tasklist/floatingw.png" +-- }}} + +-- {{{ Layout icons +theme.layout_tile = confdir .. "/icons/layouts/tilew.png" +theme.layout_tileleft = confdir .. "/icons/layouts/tileleftw.png" +theme.layout_tilebottom = confdir .. "/icons/layouts/tilebottomw.png" +theme.layout_tiletop = confdir .. "/icons/layouts/tiletopw.png" +theme.layout_fairv = confdir .. "/icons/layouts/fairvw.png" +theme.layout_fairh = confdir .. "/icons/layouts/fairhw.png" +theme.layout_spiral = confdir .. "/icons/layouts/spiralw.png" +theme.layout_dwindle = confdir .. "/icons/layouts/dwindlew.png" +theme.layout_max = confdir .. "/icons/layouts/maxw.png" +theme.layout_fullscreen = confdir .. "/icons/layouts/fullscreenw.png" +theme.layout_magnifier = confdir .. "/icons/layouts/magnifierw.png" +theme.layout_floating = confdir .. "/icons/layouts/floatingw.png" +-- }}} + +-- {{{ Widget icons +theme.widget_cpu = confdir .. "/icons/cpu.png" +theme.widget_bat = confdir .. "/icons/bat.png" +theme.widget_mem = confdir .. "/icons/mem.png" +theme.widget_fs = confdir .. "/icons/disk.png" +theme.widget_net = confdir .. "/icons/down.png" +theme.widget_netup = confdir .. "/icons/up.png" +theme.widget_mail = confdir .. "/icons/mail.png" +theme.widget_vol = confdir .. "/icons/vol.png" +theme.widget_org = confdir .. "/icons/cal.png" +theme.widget_date = confdir .. "/icons/time.png" +theme.widget_crypto = confdir .. "/icons/crypto.png" +-- }}} + +-- {{{ Titlebar icons +theme.titlebar_close_button_focus = confdir .. "/icons/titlebar/close_focus.png" +theme.titlebar_close_button_normal = confdir .. "/icons/titlebar/close_normal.png" + +theme.titlebar_ontop_button_focus_active = confdir .. "/icons/titlebar/ontop_focus_active.png" +theme.titlebar_ontop_button_normal_active = confdir .. "/icons/titlebar/ontop_normal_active.png" +theme.titlebar_ontop_button_focus_inactive = confdir .. "/icons/titlebar/ontop_focus_inactive.png" +theme.titlebar_ontop_button_normal_inactive = confdir .. "/icons/titlebar/ontop_normal_inactive.png" + +theme.titlebar_sticky_button_focus_active = confdir .. "/icons/titlebar/sticky_focus_active.png" +theme.titlebar_sticky_button_normal_active = confdir .. "/icons/titlebar/sticky_normal_active.png" +theme.titlebar_sticky_button_focus_inactive = confdir .. "/icons/titlebar/sticky_focus_inactive.png" +theme.titlebar_sticky_button_normal_inactive = confdir .. "/icons/titlebar/sticky_normal_inactive.png" + +theme.titlebar_floating_button_focus_active = confdir .. "/icons/titlebar/floating_focus_active.png" +theme.titlebar_floating_button_normal_active = confdir .. "/icons/titlebar/floating_normal_active.png" +theme.titlebar_floating_button_focus_inactive = confdir .. "/icons/titlebar/floating_focus_inactive.png" +theme.titlebar_floating_button_normal_inactive = confdir .. "/icons/titlebar/floating_normal_inactive.png" + +theme.titlebar_maximized_button_focus_active = confdir .. "/icons/titlebar/maximized_focus_active.png" +theme.titlebar_maximized_button_normal_active = confdir .. "/icons/titlebar/maximized_normal_active.png" +theme.titlebar_maximized_button_focus_inactive = confdir .. "/icons/titlebar/maximized_focus_inactive.png" +theme.titlebar_maximized_button_normal_inactive = confdir .. "/icons/titlebar/maximized_normal_inactive.png" +-- }}} +-- }}} + + +return theme diff --git a/wicked.lua b/wicked.lua new file mode 100644 index 0000000..064d928 --- /dev/null +++ b/wicked.lua @@ -0,0 +1,848 @@ +--------------------------------------------------------------------------- +-- Wicked widgets for the awesome window manager +--------------------------------------------------------------------------- +-- Lucas de Vries +-- Licensed under the WTFPL +-- Version: v1.0pre-awe3.0rc4 +--------------------------------------------------------------------------- + +-- Require libs +require("awful") + +---- {{{ Grab environment +local ipairs = ipairs +local pairs = pairs +local print = print +local type = type +local tonumber = tonumber +local tostring = tostring +local math = math +local table = table +local awful = awful +local os = os +local io = io +local string = string + +-- Grab C API +local capi = +{ + awesome = awesome, + screen = screen, + client = client, + mouse = mouse, + button = button, + titlebar = titlebar, + widget = widget, + hooks = hooks, + keygrabber = keygrabber +} + +-- }}} + +-- Wicked: Widgets for the awesome window manager +module("wicked") + +---- {{{ Initialise variables +local registered = {} +local widget_cache = {} + +-- Initialise function tables +widgets = {} +helper = {} + +local nets = {} +local cpu_total = {} +local cpu_active = {} +local cpu_usage = {} + +-- }}} + +---- {{{ Helper functions + +----{{{ Max width +function helper.max_width(str, width) + l = str:len() + + if l > width then + r = math.floor(width/2) + a = str:sub(1,r) + b = str:sub(l-r, l) + str = a .. "..." .. b + end + + return str +end +----}}} + +----{{{ Force a fixed width on a string with spaces +function helper.fixed_width(str, width) + l = str:len() + n = width-l + if n >= 0 then + for i = 1, n do + str = str.." " + end + else + str = str:sub(0, l+n) + end + return str +end +----}}} + +---- {{{ Format a string with args +function helper.format(format, args) + -- TODO: Find a more efficient way to do this + + -- Format a string + for var,val in pairs(args) do + format = string.gsub(format, '$'..var, val) + end + + -- Return formatted string + return format +end +-- }}} + +---- {{{ Padd a number to a minimum amount of digits +function helper.padd(number, padding) + s = tostring(number) + + if padding == nil then + return s + end + + for i=1,padding do + if math.floor(number/math.pow(10,(i-1))) == 0 then + s = "0"..s + end + end + + if number == 0 then + s = s:sub(2) + end + + return s +end +-- }}} + +---- {{{ Convert amount of bytes to string +function helper.bytes_to_string(bytes, sec, padding) + if bytes == nil or tonumber(bytes) == nil then + return '' + end + + bytes = tonumber(bytes) + + signs = {} + signs[1] = ' b' + signs[2] = 'KiB' + signs[3] = 'MiB' + signs[4] = 'GiB' + signs[5] = 'TiB' + + sign = 1 + + while bytes/1024 > 1 and signs[sign+1] ~= nil do + bytes = bytes/1024 + sign = sign+1 + end + + bytes = bytes*10 + bytes = math.floor(bytes)/10 + + if padding then + bytes = helper.padd(bytes*10, padding+1) + bytes = bytes:sub(1, bytes:len()-1).."."..bytes:sub(bytes:len()) + end + + if sec then + return tostring(bytes)..signs[sign]..'ps' + else + return tostring(bytes)..signs[sign] + end +end +-- }}} + +---- {{{ Split by whitespace +function helper.splitbywhitespace(str) + values = {} + start = 1 + splitstart, splitend = string.find(str, ' ', start) + + while splitstart do + m = string.sub(str, start, splitstart-1) + if m:gsub(' ','') ~= '' then + table.insert(values, m) + end + + start = splitend+1 + splitstart, splitend = string.find(str, ' ', start) + end + + m = string.sub(str, start) + if m:gsub(' ','') ~= '' then + table.insert(values, m) + end + + return values +end +-- }}} + +--{{{ Escape a string +function helper.escape(text) + if text then + text = text:gsub("&", "&") + text = text:gsub("<", "<") + text = text:gsub(">", ">") + text = text:gsub("'", "'") + text = text:gsub("\"", """) + end + return text +end + +-- }}} + +-- }}} + +---- {{{ Widget types + +---- {{{ MPD widget type +function widgets.mpd() + ---- Get data from mpc + local nowplaying_file = io.popen('mpc') + local nowplaying = nowplaying_file:read() + + -- Close the command + nowplaying_file:close() + + -- Check that it's not nil + if nowplaying == nil then + return {''} + end + + -- Escape + nowplaying = helper.escape(nowplaying) + + -- Return it + return {nowplaying} +end + +widget_cache[widgets.mpd] = {} +-- }}} + +---- {{{ MOCP widget type +function widgets.mocp(format, max_width) + local playing = '' + + ---- Get data from mocp + local info = io.popen('mocp -i') + local state = info:read() + state = state.gsub(state, 'State: ', '') + + if (state == "PLAY") then + local file = info:read() + file = file.gsub(file, 'File: ', '') + local title = info:read() + title = title.gsub(title, 'Title: ', '') + local artist = info:read() + artist = artist.gsub(artist, 'Artist: ', '') + local songtitle = info:read() + songtitle = songtitle.gsub(songtitle, 'SongTitle: ', '') + local album = info:read() + album = album.gsub(album, 'Album: ', '') + + -- Try artist - (song)title + if (artist:len() > 0) then + playing = artist .. ' - ' .. (songtitle ~= '' and songtitle or title) + + -- Else try title or songtitle + elseif (artist:len() == 0 and (title:len() > 0 or songtitle:len() > 0)) then + playing = (title ~= '' and title or songtitle) + + -- Else use the filename + else + file = string.reverse(file) + i = string.find(file, '/') + if (i ~= nil) then + file = string.sub(file, 0, i-1) + end + playing = string.reverse(file) + end + else + playing = state + end + + -- Close file + info:close() + + -- Apply maximum width + if (max_width ~= nil) then + playing = helper.max_width(playing, max_width) + end + + playing = helper.escape(playing) + + -- Return it + return {playing} +end + +widget_cache[widgets.mocp] = {} +-- }}} + +---- {{{ CPU widget type +function widgets.cpu(format, padding) + -- Calculate CPU usage for all available CPUs / cores and return the + -- usage + + -- Perform a new measurement + ---- Get /proc/stat + local cpu_lines = {} + local cpu_usage_file = io.open('/proc/stat') + for line in cpu_usage_file:lines() do + if string.sub(line, 1, 3) == 'cpu' then + table.insert(cpu_lines, helper.splitbywhitespace(line)) + end + end + cpu_usage_file:close() + + ---- Ensure tables are initialized correctly + while #cpu_total < #cpu_lines do + table.insert(cpu_total, 0) + end + while #cpu_active < #cpu_lines do + table.insert(cpu_active, 0) + end + while #cpu_usage < #cpu_lines do + table.insert(cpu_usage, 0) + end + + ---- Setup tables + total_new = {} + active_new = {} + diff_total = {} + diff_active = {} + + for i,v in ipairs(cpu_lines) do + ---- Calculate totals + total_new[i] = 0 + for j = 2, #v do + total_new[i] = total_new[i] + v[j] + end + active_new[i] = v[2] + v[3] + v[4] + + ---- Calculate percentage + diff_total[i] = total_new[i] - cpu_total[i] + diff_active[i] = active_new[i] - cpu_active[i] + cpu_usage[i] = math.floor(diff_active[i] / diff_total[i] * 100) + + ---- Store totals + cpu_total[i] = total_new[i] + cpu_active[i] = active_new[i] + end + + if padding ~= nil then + for k,v in pairs(cpu_usage) do + if type(padding) == "table" then + p = padding[k] + else + p = padding + end + + cpu_usage[k] = helper.padd(cpu_usage[k], p) + end + end + + return cpu_usage +end + +widget_cache[widgets.cpu] = {} +-- }}} + +---- {{{ Memory widget type +function widgets.mem(format, padding) + -- Return MEM usage values + local f = io.open('/proc/meminfo') + + ---- Get data + for line in f:lines() do + line = helper.splitbywhitespace(line) + + if line[1] == 'MemTotal:' then + mem_total = math.floor(line[2]/1024) + elseif line[1] == 'MemFree:' then + free = math.floor(line[2]/1024) + elseif line[1] == 'Buffers:' then + buffers = math.floor(line[2]/1024) + elseif line[1] == 'Cached:' then + cached = math.floor(line[2]/1024) + end + end + f:close() + + ---- Calculate percentage + mem_free=free+buffers+cached + mem_inuse=mem_total-mem_free + mem_usepercent = math.floor(mem_inuse/mem_total*100) + + if padding then + if type(padding) == "table" then + mem_usepercent = helper.padd(mem_usepercent, padding[1]) + mem_inuse = helper.padd(mem_inuse, padding[2]) + mem_total = helper.padd(mem_total, padding[3]) + mem_free = helper.padd(mem_free, padding[4]) + else + mem_usepercent = helper.padd(mem_usepercent, padding) + mem_inuse = helper.padd(mem_inuse, padding) + mem_total = helper.padd(mem_total, padding) + mem_free = helper.padd(mem_free, padding) + end + end + + return {mem_usepercent, mem_inuse, mem_total, mem_free} +end + +widget_cache[widgets.mem] = {} +-- }}} + +---- {{{ Swap widget type +function widgets.swap(format, padding) + -- Return SWAP usage values + local f = io.open('/proc/meminfo') + + ---- Get data + for line in f:lines() do + line = helper.splitbywhitespace(line) + + if line[1] == 'SwapTotal:' then + swap_total = math.floor(line[2]/1024) + elseif line[1] == 'SwapFree:' then + free = math.floor(line[2]/1024) + elseif line[1] == 'SwapCached:' then + cached = math.floor(line[2]/1024) + end + end + f:close() + + ---- Calculate percentage + swap_free=free+cached + swap_inuse=swap_total-swap_free + swap_usepercent = math.floor(swap_inuse/swap_total*100) + + if padding then + if type(padding) == "table" then + swap_usepercent = helper.padd(swap_usepercent, padding[1]) + swap_inuse = helper.padd(swap_inuse, padding[2]) + swap_total = helper.padd(swap_total, padding[3]) + swap_free = helper.padd(swap_free, padding[4]) + else + swap_usepercent = helper.padd(swap_usepercent, padding) + swap_inuse = helper.padd(swap_inuse, padding) + swap_total = helper.padd(swap_total, padding) + swap_free = helper.padd(swap_free, padding) + end + end + + return {swap_usepercent, swap_inuse, swap_total, swap_free} +end + +widget_cache[widgets.swap] = {} +-- }}} + +---- {{{ Date widget type +function widgets.date(format) + -- Get format + if format == nil then + return os.date() + else + return os.date(format) + end +end +-- }}} + +---- {{{ Filesystem widget type +function widgets.fs(format, padding) + local f = io.popen('df -hP') + local args = {} + + for line in f:lines() do + vars = helper.splitbywhitespace(line) + + if vars[1] ~= 'Filesystem' and #vars == 6 then + vars[5] = vars[5]:gsub('%%','') + + if padding then + if type(padding) == "table" then + vars[2] = helper.padd(vars[2], padding[1]) + vars[3] = helper.padd(vars[3], padding[2]) + vars[4] = helper.padd(vars[4], padding[3]) + vars[5] = helper.padd(vars[5], padding[4]) + else + vars[2] = helper.padd(vars[2], padding) + vars[3] = helper.padd(vars[3], padding) + vars[4] = helper.padd(vars[4], padding) + vars[5] = helper.padd(vars[5], padding) + end + end + + args['{'..vars[6]..' size}'] = vars[2] + args['{'..vars[6]..' used}'] = vars[3] + args['{'..vars[6]..' avail}'] = vars[4] + args['{'..vars[6]..' usep}'] = vars[5] + end + end + + f:close() + return args +end +-- }}} + +---- {{{ Net widget type +function widgets.net(format, padding) + local f = io.open('/proc/net/dev') + args = {} + + for line in f:lines() do + line = helper.splitbywhitespace(line) + + local p = line[1]:find(':') + if p ~= nil then + name = line[1]:sub(0,p-1) + line[1] = line[1]:sub(p+1) + + if tonumber(line[1]) == nil then + line[1] = line[2] + line[9] = line[10] + end + + if padding then + args['{'..name..' rx}'] = helper.bytes_to_string(line[1], nil, padding) + args['{'..name..' tx}'] = helper.bytes_to_string(line[9], nil, padding) + else + args['{'..name..' rx}'] = helper.bytes_to_string(line[1]) + args['{'..name..' tx}'] = helper.bytes_to_string(line[9]) + end + + args['{'..name..' rx_b}'] = math.floor(line[1]*10)/10 + args['{'..name..' tx_b}'] = math.floor(line[9]*10)/10 + + args['{'..name..' rx_kb}'] = math.floor(line[1]/1024*10)/10 + args['{'..name..' tx_kb}'] = math.floor(line[9]/1024*10)/10 + + args['{'..name..' rx_mb}'] = math.floor(line[1]/1024/1024*10)/10 + args['{'..name..' tx_mb}'] = math.floor(line[9]/1024/1024*10)/10 + + args['{'..name..' rx_gb}'] = math.floor(line[1]/1024/1024/1024*10)/10 + args['{'..name..' tx_gb}'] = math.floor(line[9]/1024/1024/1024*10)/10 + + if nets[name] == nil then + nets[name] = {} + args['{'..name..' down}'] = 'n/a' + args['{'..name..' up}'] = 'n/a' + + args['{'..name..' down_b}'] = 0 + args['{'..name..' up_b}'] = 0 + + args['{'..name..' down_kb}'] = 0 + args['{'..name..' up_kb}'] = 0 + + args['{'..name..' down_mb}'] = 0 + args['{'..name..' up_mb}'] = 0 + + args['{'..name..' down_gb}'] = 0 + args['{'..name..' up_gb}'] = 0 + + nets[name].time = os.time() + else + interval = os.time()-nets[name].time + nets[name].time = os.time() + + down = (line[1]-nets[name][1])/interval + up = (line[9]-nets[name][2])/interval + + if padding then + args['{'..name..' down}'] = helper.bytes_to_string(down, true, padding) + args['{'..name..' up}'] = helper.bytes_to_string(up, true, padding) + else + args['{'..name..' down}'] = helper.bytes_to_string(down, true) + args['{'..name..' up}'] = helper.bytes_to_string(up, true) + end + + args['{'..name..' down_b}'] = math.floor(down*10)/10 + args['{'..name..' up_b}'] = math.floor(up*10)/10 + + args['{'..name..' down_kb}'] = math.floor(down/1024*10)/10 + args['{'..name..' up_kb}'] = math.floor(up/1024*10)/10 + + args['{'..name..' down_mb}'] = math.floor(down/1024/1024*10)/10 + args['{'..name..' up_mb}'] = math.floor(up/1024/1024*10)/10 + + args['{'..name..' down_gb}'] = math.floor(down/1024/1024/1024*10)/10 + args['{'..name..' up_gb}'] = math.floor(up/1024/1024/1024*10)/10 + end + + nets[name][1] = line[1] + nets[name][2] = line[9] + end + end + + f:close() + return args +end +widget_cache[widgets.net] = {} +-- }}} + +---- {{{ Uptime widget type +function widgets.uptime(format, padding) + --Get uptime from /proc/uptime + local f = io.open("/proc/uptime") + uptime_line = f:read() + + f:close() + + args = {} + --/proc/uptime has the format " " + if uptime_line:find(" ") ~= nil then + + pend = uptime_line:find(" ",0,true) + + uptime_line_part = uptime_line:sub(0,pend-1) + + total_uptime = math.floor( tonumber(uptime_line_part) ) + + uptime_days = math.floor( total_uptime / (3600 * 24) ) + uptime_hours = math.floor( ( total_uptime % (3600 * 24) ) / 3600 ) + uptime_minutes = math.floor( ( ( total_uptime % (3600 * 24) ) % 3600 ) / 60 ) + uptime_seconds = math.floor( ( ( total_uptime % (3600 * 24) ) % 3600) % 60 ) + + if padding then + + if type(padding) == "table" then + total_uptime = helper.padd(total_uptime , padding[1]) + uptime_days = helper.padd(uptime_days , padding[2]) + uptime_hours = helper.padd(uptime_hours , padding[3]) + uptime_minutes = helper.padd(uptime_minutes , padding[4]) + uptime_seconds = helper.padd(uptime_seconds , padding[5]) + else + total_uptime = helper.padd(total_uptime , padding) + uptime_days = helper.padd(uptime_days , padding) + uptime_hours = helper.padd(uptime_hours , padding) + uptime_minutes = helper.padd(uptime_minutes , padding) + uptime_seconds = helper.padd(uptime_seconds , padding) + end + + end + end + + return {total_uptime, uptime_days, uptime_hours, uptime_minutes, uptime_seconds} + +end +widget_cache[widgets.uptime] = {} +-- }}} + +-- For backwards compatibility: custom function +widgets["function"] = function () + return {} +end + +-- }}} + +---- {{{ Main functions +---- {{{ Register widget +function register(widget, wtype, format, timer, field, padd) + local reg = {} + local widget = widget + + -- Set properties + reg.type = wtype + reg.format = format + reg.timer = timer + reg.field = field + reg.padd = padd + reg.widget = widget + + -- Update function + reg.update = function () + update(widget, reg) + end + + -- Default to timer=1 + if reg.timer == nil then + reg.timer = 1 + end + + -- Allow using a string widget type + if type(reg.type) == "string" then + reg.type = widgets[reg.type] + end + + -- Register reg object + regregister(reg) + + -- Return reg object for reuse + return reg +end +-- }}} + +-- {{{ Register from reg object +function regregister(reg) + if not reg.running then + -- Put widget in table + if registered[reg.widget] == nil then + registered[reg.widget] = {} + table.insert(registered[reg.widget], reg) + else + already = false + + for w, i in pairs(registered) do + if w == reg.widget then + for k,v in pairs(i) do + if v == reg then + already = true + break + end + end + + if already then + break + end + end + end + + if not already then + table.insert(registered[reg.widget], reg) + end + end + + -- Start timer + if reg.timer > 0 then + awful.hooks.timer.register(reg.timer, reg.update) + end + + -- Initial update + reg.update() + + -- Set running + reg.running = true + end +end +-- }}} + +-- {{{ Unregister widget +function unregister(widget, keep, reg) + if reg == nil then + for w, i in pairs(registered) do + if w == widget then + for k,v in pairs(i) do + reg = unregister(w, keep, v) + end + end + end + + return reg + end + + if not keep then + for w, i in pairs(registered) do + if w == widget then + for k,v in pairs(i) do + if v == reg then + table.remove(registered[w], k) + end + end + end + end + end + + awful.hooks.timer.unregister(reg.update) + + reg.running = false + return reg +end +-- }}} + +-- {{{ Suspend wicked, halt all widget updates +function suspend() + for w, i in pairs(registered) do + for k,v in pairs(i) do + unregister(w, true, v) + end + end +end +-- }}} + +-- {{{ Activate wicked, restart all widget updates +function activate(widget) + for w, i in pairs(registered) do + if widget == nil or w == widget then + for k,v in pairs(i) do + regregister(v) + end + end + end +end +-- }}} + +-- {{{ Enable caching for a widget type +function enable_caching(widget) + if widget_cache[widget] == nil then + widget_cache[widget] = {} + end +end +-- }}} + +---- {{{ Update widget +function update(widget, reg, disablecache) + -- Check if there are any equal widgets + if reg == nil then + for w, i in pairs(registered) do + if w == widget then + for k,v in pairs(i) do + update(w, v, disablecache) + end + end + end + + return + end + + local t = os.time() + local data = {} + + -- Check if we have output chached for this widget, + -- newer than last widget update. + if widget_cache[reg.type] ~= nil then + local c = widget_cache[reg.type] + + if c.time == nil or c.time <= t-reg.timer or disablecache then + c.time = t + c.data = reg.type(reg.format, reg.padd) + end + + data = c.data + else + data = reg.type(reg.format, reg.padd) + end + + if type(data) == "table" then + if type(reg.format) == "string" then + data = helper.format(reg.format, data) + elseif type(reg.format) == "function" then + data = reg.format(widget, data) + end + end + + if reg.field == nil then + widget.text = data + elseif widget.plot_data_add ~= nil then + widget:plot_data_add(reg.field, tonumber(data)) + elseif widget.bar_data_add ~= nil then + widget:bar_data_add(reg.field, tonumber(data)) + end + return data +end + +-- }}} + +-- }}} + +-- vim: set filetype=lua fdm=marker tabstop=4 shiftwidth=4 nu: diff --git a/zenburn.lua b/zenburn.lua new file mode 100644 index 0000000..ad1979f --- /dev/null +++ b/zenburn.lua @@ -0,0 +1,141 @@ +------------------------------- +-- "Zenburn" awesome theme -- +-- By Adrian C. (anrxc) -- +------------------------------- + + +-- {{{ Main +theme = {} +theme.confdir = awful.util.getdir("config") +theme.wallpaper_cmd = { "/usr/bin/nitrogen --restore" } +--theme.wallpaper_cmd = { "awsetbg /usr/share/awesome/themes/zenburn/zenburn-background.png" } +-- }}} + + +-- {{{ Styles +theme.font = "Profont 8" + +-- {{{ Colors +theme.fg_normal = "#DCDCCC" +theme.fg_focus = "#F0DFAF" +theme.fg_urgent = "#CC9393" +theme.bg_normal = "#3F3F3F" +theme.bg_focus = "#1E2320" +theme.bg_urgent = "#3F3F3F" +-- }}} + +-- {{{ Borders +theme.border_width = "1" +theme.border_normal = "#3F3F3F" +theme.border_focus = "#6F6F6F" +theme.border_marked = "#CC9393" +-- }}} + +-- {{{ Titlebars +theme.titlebar_bg_focus = "#3F3F3F" +theme.titlebar_bg_normal = "#3F3F3F" +-- theme.titlebar_[normal|focus] +-- }}} + +-- {{{ Widgets +theme.fg_widget = "#AECF96" +theme.fg_center_widget = "#88A175" +theme.fg_end_widget = "#FF5656" +theme.fg_off_widget = "#494B4F" +theme.fg_netup_widget = "#7F9F7F" +theme.fg_netdn_widget = "#CC9393" +theme.bg_widget = "#3F3F3F" +theme.border_widget = "#3F3F3F" +-- }}} + +-- {{{ Mouse finder +theme.mouse_finder_color = "#CC9393" +-- theme.mouse_finder_[timeout|animate_timeout|radius|factor] +-- }}} + +-- {{{ Tooltips +-- theme.tooltip_[font|opacity|fg_color|bg_color|border_width|border_color] +-- }}} + +-- {{{ Taglist and Tasklist +-- theme.[taglist|tasklist]_[bg|fg]_[focus|urgent] +-- }}} + +-- {{{ Menu +-- theme.menu_[bg|fg]_[normal|focus] +-- theme.menu_[height|width|border_color|border_width] +-- }}} +-- }}} + + +-- {{{ Icons +-- +-- {{{ Taglist icons +theme.taglist_squares_sel = theme.confdir .. "/icons/taglist/squarefz.png" +theme.taglist_squares_unsel = theme.confdir .. "/icons/taglist/squareza.png" +--theme.taglist_squares_resize = "false" +-- }}} + +-- {{{ Misc icons +--theme.awesome_icon = theme.confdir .. "/icons/awesome.png" +--theme.menu_submenu_icon = "/usr/share/awesome/themes/default/submenu.png" +--theme.tasklist_floating_icon = "/usr/share/awesome/themes/default/tasklist/floatingw.png" +-- }}} + +-- {{{ Layout icons +theme.layout_tile = theme.confdir .. "/icons/layouts/tile.png" +theme.layout_tileleft = theme.confdir .. "/icons/layouts/tileleft.png" +theme.layout_tilebottom = theme.confdir .. "/icons/layouts/tilebottom.png" +theme.layout_tiletop = theme.confdir .. "/icons/layouts/tiletop.png" +theme.layout_fairv = theme.confdir .. "/icons/layouts/fairv.png" +theme.layout_fairh = theme.confdir .. "/icons/layouts/fairh.png" +theme.layout_spiral = theme.confdir .. "/icons/layouts/spiral.png" +theme.layout_dwindle = theme.confdir .. "/icons/layouts/dwindle.png" +theme.layout_max = theme.confdir .. "/icons/layouts/max.png" +theme.layout_fullscreen = theme.confdir .. "/icons/layouts/fullscreen.png" +theme.layout_magnifier = theme.confdir .. "/icons/layouts/magnifier.png" +theme.layout_floating = theme.confdir .. "/icons/layouts/floating.png" +-- }}} + +-- {{{ Widget icons +theme.widget_cpu = theme.confdir .. "/icons/cpu.png" +theme.widget_bat = theme.confdir .. "/icons/bat.png" +theme.widget_mem = theme.confdir .. "/icons/mem.png" +theme.widget_fs = theme.confdir .. "/icons/disk.png" +theme.widget_net = theme.confdir .. "/icons/down.png" +theme.widget_netup = theme.confdir .. "/icons/up.png" +theme.widget_mail = theme.confdir .. "/icons/mail.png" +theme.widget_vol = theme.confdir .. "/icons/vol.png" +theme.widget_org = theme.confdir .. "/icons/cal.png" +theme.widget_date = theme.confdir .. "/icons/time.png" +theme.widget_crypto = theme.confdir .. "/icons/crypto.png" +-- }}} + +-- {{{ Titlebar icons +theme.titlebar_close_button_focus = theme.confdir .. "/icons/titlebar/close_focus.png" +theme.titlebar_close_button_normal = theme.confdir .. "/icons/titlebar/close_normal.png" + +theme.titlebar_ontop_button_focus_active = theme.confdir .. "/icons/titlebar/ontop_focus_active.png" +theme.titlebar_ontop_button_normal_active = theme.confdir .. "/icons/titlebar/ontop_normal_active.png" +theme.titlebar_ontop_button_focus_inactive = theme.confdir .. "/icons/titlebar/ontop_focus_inactive.png" +theme.titlebar_ontop_button_normal_inactive = theme.confdir .. "/icons/titlebar/ontop_normal_inactive.png" + +theme.titlebar_sticky_button_focus_active = theme.confdir .. "/icons/titlebar/sticky_focus_active.png" +theme.titlebar_sticky_button_normal_active = theme.confdir .. "/icons/titlebar/sticky_normal_active.png" +theme.titlebar_sticky_button_focus_inactive = theme.confdir .. "/icons/titlebar/sticky_focus_inactive.png" +theme.titlebar_sticky_button_normal_inactive = theme.confdir .. "/icons/titlebar/sticky_normal_inactive.png" + +theme.titlebar_floating_button_focus_active = theme.confdir .. "/icons/titlebar/floating_focus_active.png" +theme.titlebar_floating_button_normal_active = theme.confdir .. "/icons/titlebar/floating_normal_active.png" +theme.titlebar_floating_button_focus_inactive = theme.confdir .. "/icons/titlebar/floating_focus_inactive.png" +theme.titlebar_floating_button_normal_inactive = theme.confdir .. "/icons/titlebar/floating_normal_inactive.png" + +theme.titlebar_maximized_button_focus_active = theme.confdir .. "/icons/titlebar/maximized_focus_active.png" +theme.titlebar_maximized_button_normal_active = theme.confdir .. "/icons/titlebar/maximized_normal_active.png" +theme.titlebar_maximized_button_focus_inactive = theme.confdir .. "/icons/titlebar/maximized_focus_inactive.png" +theme.titlebar_maximized_button_normal_inactive = theme.confdir .. "/icons/titlebar/maximized_normal_inactive.png" +-- }}} +-- }}} + + +return theme