commit c130561cb7bb6315e2ad936c20c007c2025d102c Author: Vincent Bernat Date: Fri Jul 6 14:19:54 2012 +0200 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5ec896 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*~ +/wallpapers diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f937846 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "themes/nice-and-clean-theme"] + path = themes/nice-and-clean-theme + url = https://github.com/waf/nice-and-clean-theme/ diff --git a/bin/build-wallpaper b/bin/build-wallpaper new file mode 100755 index 0000000..aad2c08 --- /dev/null +++ b/bin/build-wallpaper @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# Build a multi screen wallpaper + +# First argument is the directory where the wallpapers can be +# found. We use xinerama to know the dimension of each screen. + +import sys +import os +import re +import random +import string +import subprocess +import optparse + +import xcb +import xcb.xproto +import xcb.xinerama + +import Image + +parser = optparse.OptionParser() +parser.add_option("-d", "--directory", dest="directory", default=".", + help="search for images in DIRECTORY", metavar="DIRECTORY") +parser.add_option("-t", "--target", dest="target", default="background.jpg", + help="write background to FILE", metavar="FILE") +parser.add_option("-c", "--crop", dest="crop", action="store_true", + help="crop image instead of centering them") +options, args = parser.parse_args() + +assert not args, "No additional arguments are accepted" + +background = None + +# Get display size +display = xcb.connect() +root = display.get_setup().roots[0] +background = Image.new('RGB', (root.width_in_pixels, root.height_in_pixels)) + +# Query xinerama (not randr since the query is longer) +try: + xinerama = display(xcb.xinerama.key) +except xcb.ExtensionException: + xinerama = None +if not xinerama or not xinerama.IsActive().reply().state: + screens = [(background.size[0], background.size[1], 0, 0)] +else: + screens = [(screen.width, screen.height, screen.x_org, screen.y_org) + for screen in xinerama.QueryScreens().reply().screen_info] +screens.sort(key=lambda screen: -screen[0]*screen[1]) + +# Get as many random image as we have screens +images = [] +for root, _, files in os.walk(os.path.join(options.directory)): + for i in files: + if string.lower(os.path.splitext(i)[1]) in ('.jpg', + '.jpeg', + '.png'): + images.append(os.path.join(root, i)) +images = random.sample(images, + len(screens) + \ + random.randint(0, 3)) # Randomly favor larger images +images = [Image.open(os.path.join(options.directory, + image)) for image in images] +images.sort(key=lambda image: -image.size[0]*image.size[1]) + +for index in range(len(screens)): + x, y, offsetx, offsety = screens[index] + image = images[index] + + # Find the right size for the screen + imx, imy = x, image.size[1]*x/image.size[0] + if (options.crop and imy < y) or (not options.crop and imy > y): + imx, imy = image.size[0]*y/image.size[1], y + image = image.resize((imx, imy), Image.CUBIC) + if options.crop: + image = image.crop(((imx-x)/2, (imy-y)/2, + imx-(imx-x)/2, imy-(imy-y)/2)) + + # Include it + if options.crop: + background.paste(image, (offsetx, offsety)) + else: + background.paste(image, ((x-imx)/2 + offsetx, + (y-imy)/2 + offsety)) + +# Save +assert background, "Don't know the size of the display area" +background.save(options.target) diff --git a/rc.lua b/rc.lua new file mode 100644 index 0000000..d89c558 --- /dev/null +++ b/rc.lua @@ -0,0 +1,50 @@ +require("awful") +require("awful.autofocus") +require("awful.rules") +require("beautiful") +require("naughty") + +-- Simple function to load additional LUA files from rc/. +function loadrc(name) + local success + local result + local path = awful.util.getdir("config") .. "/rc/" .. name .. ".lua" + success, result = pcall(function() return dofile(path) end) + if not success then + return print("E: error loading RC file '" .. name .. "': " .. result) + end + return result +end + +-- Error handling +loadrc("errors") + +-- Global configuration +modkey = "Mod4" +config = {} +config.terminal = table.concat({"urxvtcd", + "++iso14755 +sb -si -sw -j -fn fixed -sl 2000", + "-fade 40 -sh 30 -bc -tint white -fg white -depth 32", + "--color4 RoyalBlue --color12 RoyalBlue", + "-bg rgba:0000/0000/0000/bbbb -fadecolor rgba:0000/0000/0000/6666"}, + " ") +config.layouts = { + awful.layout.suit.tile, + awful.layout.suit.magnifier, + awful.layout.suit.floating, +} +config.hostname = awful.util.pread('uname -n'):gsub('\n', '') + +-- Remaining modules +loadrc("theme") +loadrc("start") +loadrc("bindings") +loadrc("wallpaper") +loadrc("tags") +loadrc("widgets") +loadrc("xlock") +loadrc("signals") +loadrc("rules") + +root.keys(config.keys.global) +startapps() diff --git a/rc/bindings.lua b/rc/bindings.lua new file mode 100644 index 0000000..0784776 --- /dev/null +++ b/rc/bindings.lua @@ -0,0 +1,74 @@ +config.keys = {} +config.mouse = {} + +config.keys.global = awful.util.table.join( + -- Tag navigation + awful.key({ modkey, }, "Left", awful.tag.viewprev ), + awful.key({ modkey, }, "Right", awful.tag.viewnext ), + awful.key({ modkey, }, "Escape", awful.tag.history.restore), + + -- Focus + 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, }, "u", awful.client.urgent.jumpto), + + -- Layout manipulation + 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(config.layouts, 1) end), + awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(config.layouts, -1) end), + 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, }, "Tab", + function () + awful.client.focus.history.previous() + if client.focus then + client.focus:raise() + end + end), + + -- Spawn a terminal + awful.key({ modkey, }, "Return", function () awful.util.spawn(config.terminal) end), + + -- Restart awesome + awful.key({ modkey, "Control" }, "r", awesome.restart) +) + +config.keys.client = awful.util.table.join( + awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end), + awful.key({ modkey, }, "x", function (c) c:kill() end), + awful.key({ modkey, }, "o", awful.client.movetoscreen ), + 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, }, "t", function (c) c.ontop = not c.ontop end), + awful.key({ modkey, }, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c.maximized_vertical = not c.maximized_vertical + end), + awful.key({ modkey, }, "i", + function (c) + -- The client currently has the input focus, so it cannot be + -- minimized, since minimized clients can't have the focus. + c.minimized = true + end) +) + +config.mouse.client = 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)) diff --git a/rc/errors.lua b/rc/errors.lua new file mode 100644 index 0000000..1984f2e --- /dev/null +++ b/rc/errors.lua @@ -0,0 +1,31 @@ +require("awesome") +require("naughty") + +-- Check if awesome encountered an error during startup and fell back to +-- another config (This code will only ever execute for the fallback config) +if awesome.startup_errors then + naughty.notify({ preset = naughty.config.presets.critical, + title = "Oops, there were errors during startup!", + text = awesome.startup_errors }) +end + +-- Handle runtime errors after startup +do + local in_error = false + awesome.add_signal("debug::error", function (err) + -- Make sure we don't go into an endless error loop + if in_error then return end + in_error = true + + naughty.notify({ preset = naughty.config.presets.critical, + title = "Oops, an error happened!", + text = err }) + in_error = false + end) +end + +function dbg(vars) + local text = "" + for i=1, #vars do text = text .. vars[i] .. " | " end + naughty.notify({ text = text, timeout = 0 }) +end diff --git a/rc/rules.lua b/rc/rules.lua new file mode 100644 index 0000000..863d35f --- /dev/null +++ b/rc/rules.lua @@ -0,0 +1,21 @@ +awful.rules.rules = { + -- All clients will match this rule. + { rule = { }, + properties = { border_width = beautiful.border_width, + border_color = beautiful.border_normal, + focus = true, + keys = config.keys.client, + buttons = config.mouse.client }}, + { rule = { class = "Emacs" }, + properties = { tag = config.tags.emacs }}, + { rule = { name = "Iceweasel" }, + properties = { tag = config.tags.www }}, + { rule = { name = "Firefox" }, + properties = { tag = config.tags.www }}, + { rule = { name = "Chromium" }, + properties = { tag = config.tags.www }}, + { rule = { class = "Pidgin" }, + properties = { tag = config.tags.im }}, + { rule = { class = "URxvt" }, + properties = { }, callback = awful.client.setslave }, +} diff --git a/rc/sharetags.lua b/rc/sharetags.lua new file mode 100644 index 0000000..1eb94d1 --- /dev/null +++ b/rc/sharetags.lua @@ -0,0 +1,356 @@ +-- functions to share tags on multiple screens + +--{{{ Grab environment we need +local capi = { widget = widget, + screen = screen, + image = image, + client = client, + button = button } +local setmetatable = setmetatable +local math = math +local type = type +local pcall = pcall +local util = require("awful.util") +local tag = require("awful.tag") +local beautiful = require("beautiful") +local layout = require("awful.widget.layout") + +local awful = require("awful") +local mouse = mouse + +local pairs = pairs +local ipairs = ipairs +--}}} + +module("sharetags") + +--{{{ Private structures +tagwidgets = setmetatable({}, { __mode = 'k' }) +local cachedtags = {} +label = {} +--}}} + +--{{{ Functions + +--{{{ create_tags: create a table of tags and bind them to screens +-- @param names : list to label the tags +-- @param layouts : list of layouts for the tags +-- @return table of tag objects +function create_tags(names, layouts) + local tags = {} + local count = #names + if capi.screen.count() >= #names then + count = capi.screen.count() + 1 + end + for tagnumber = 1, count do + tags[tagnumber] = awful.tag.add(names[tagnumber], {}) + tag.setproperty(tags[tagnumber], "number", tagnumber) + -- Add tags to screen one by one + tags[tagnumber].screen = 1 + awful.layout.set(layouts[tagnumber], tags[tagnumber]) + end + for s = 1, capi.screen.count() do + -- I'm sure you want to see at least one tag. + tags[s].screen = s + tags[s].selected = true + end + cachedtags = tags + return tags +end +--}}} + +--{{{ tag_move: move a tag to a screen +-- @param t : the tag object to move +-- @param scr : the screen object to move to +function tag_move(t, scr) + local ts = t or awful.tag.selected() + local screen_target = scr or awful.util.cycle(capi.screen.count(), ts.screen + 1) + + if ts.screen and screen_target ~= ts.screen then + -- switch for tag + ts.screen = screen_target + -- switch for all clients on tag + if #ts:clients() > 0 then + for _ , c in ipairs(ts:clients()) do + if not c.sticky then + c.screen = screen_target + c:tags( {ts} ) + else + awful.client.toggletag(ts,c) + end + end + end + end +end +--}}} + +--{{{ tag_to_screen: move a tag to a screen if its not already there +-- @param t : the tag object to move +-- @param scr : the screen object to move to +function tag_to_screen(t, scr) + local ts = t or awful.tag.selected() + local screen_origin = ts.screen + local screen_target = scr or awful.util.cycle(capi.screen.count(), ts.screen + 1) + + awful.tag.history.restore(ts.screen,1) + -- move the tag only if we are on a different screen + if screen_origin ~= screen_target then + tag_move(ts, screen_target) + end + + awful.tag.viewonly(ts) + mouse.screen = ts.screen + if #ts:clients() > 0 then + local c = ts:clients()[1] + capi.client.focus = c + end +end +--}}} + +--{{{ Return labels for a taglist widget with all tag from screen. +-- It returns the tag name and set a special +-- foreground and background color for selected tags. +-- @param t The tag. +-- @param args The arguments table. +-- bg_focus The background color for selected tag. +-- fg_focus The foreground color for selected tag. +-- bg_urgent The background color for urgent tags. +-- fg_urgent The foreground color for urgent tags. +-- squares_sel Optional: a user provided image for selected squares. +-- squares_unsel Optional: a user provided image for unselected squares. +-- squares_resize Optional: true or false to resize squares. +-- @return A string to print, a background color, a background image and a +-- background resize value. +function label.all(t, args) + if not args then args = {} end + local theme = beautiful.get() + local fg_focus = args.fg_focus or theme.taglist_fg_focus or theme.fg_focus + local bg_focus = args.bg_focus or theme.taglist_bg_focus or theme.bg_focus + local fg_urgent = args.fg_urgent or theme.taglist_fg_urgent or theme.fg_urgent + local bg_urgent = args.bg_urgent or theme.taglist_bg_urgent or theme.bg_urgent + local bg_occupied = args.bg_occupied or theme.taglist_bg_occupied + local fg_occupied = args.fg_occupied or theme.taglist_fg_occupied + local taglist_squares_sel = args.squares_sel or theme.taglist_squares_sel + local taglist_squares_unsel = args.squares_unsel or theme.taglist_squares_unsel + local taglist_squares_resize = theme.taglist_squares_resize or args.squares_resize or "true" + local font = args.font or theme.taglist_font or theme.font or "" + local text = "" + local sel = capi.client.focus + local bg_color = nil + local fg_color = nil + local bg_image + local icon + local bg_resize = false + local is_selected = false + if not args.screen then + args.screen = t.screen + end + if t.selected and t.screen == args.screen then + bg_color = bg_focus + fg_color = fg_focus + end + if sel and sel.type ~= "desktop" then + if taglist_squares_sel then + -- Check that the selected clients is tagged with 't'. + local seltags = sel:tags() + for _, v in ipairs(seltags) do + if v == t then + bg_image = capi.image(taglist_squares_sel) + bg_resize = taglist_squares_resize == "true" + is_selected = true + break + end + end + end + end + if not is_selected then + local cls = t:clients() + if #cls > 0 then + if taglist_squares_unsel then + bg_image = capi.image(taglist_squares_unsel) + bg_resize = taglist_squares_resize == "true" + end + if bg_occupied then bg_color = bg_occupied end + if fg_occupied then fg_color = fg_occupied end + end + for k, c in pairs(cls) do + if c.urgent then + if bg_urgent then bg_color = bg_urgent end + if fg_urgent then fg_color = fg_urgent end + break + end + end + end + if not tag.getproperty(t, "icon_only") then + if fg_color then + text = text .. "" + text = " " .. text.. (util.escape(t.name) or "") .." " + else + text = text .. " " .. (util.escape(t.name) or "") .. " " + end + end + text = text .. "" + if tag.geticon(t) and type(tag.geticon(t)) == "image" then + icon = tag.geticon(t) + elseif tag.geticon(t) then + icon = capi.image(tag.geticon(t)) + end + + return text, bg_color, bg_image, icon +end +--}}} + +--{{{ list_update: update a list of widgets +-- @param screen : the screen to draw the taglist for +-- @param w : the widget container +-- @param label : label function to use +-- @param buttons : a table with button bindings to set +-- @param widgets : a table with widget style parameters +-- @param objects : the list of tags to be displayed +-- @param scr : the current screen +local function list_update(w, buttons, label, data, widgets, objects, scr) + -- Hack: if it has been registered as a widget in a wibox, + -- it's w.len since __len meta does not work on table until Lua 5.2. + -- Otherwise it's standard #w. + local len = (w.len or #w) / 2 + -- Add more widgets + if len < #objects then + for i = len * 2 + 1, #objects * 2, 2 do + local ib = capi.widget({ type = "imagebox", align = widgets.imagebox.align }) + local tb = capi.widget({ type = "textbox", align = widgets.textbox.align }) + + w[i] = ib + w[i + 1] = tb + w[i + 1]:margin({ left = widgets.textbox.margin.left, right = widgets.textbox.margin.right }) + w[i + 1].bg_resize = widgets.textbox.bg_resize or false + w[i + 1].bg_align = widgets.textbox.bg_align or "" + + if type(objects[math.floor(i / 2) + 1]) == "tag" then + tagwidgets[ib] = objects[math.floor(i / 2) + 1] + tagwidgets[tb] = objects[math.floor(i / 2) + 1] + end + end + -- Remove widgets + elseif len > #objects then + for i = #objects * 2 + 1, len * 2, 2 do + w[i] = nil + w[i + 1] = nil + end + end + + -- update widgets text + for k = 1, #objects * 2, 2 do + local o = objects[(k + 1) / 2] + if not o then + o = objects[(k-1) / 2] + end + if buttons then + -- Use a local variable so that the garbage collector doesn't strike + -- between now and the :buttons() call. + local btns = data[o] + if not btns then + btns = {} + data[o] = btns + for kb, b in ipairs(buttons) do + -- Create a proxy button object: it will receive the real + -- press and release events, and will propagate them the the + -- button object the user provided, but with the object as + -- argument. + local btn = capi.button { modifiers = b.modifiers, button = b.button } + btn:add_signal("press", function () b:emit_signal("press", o) end) + btn:add_signal("release", function () b:emit_signal("release", o) end) + btns[#btns + 1] = btn + end + end + w[k]:buttons(btns) + w[k + 1]:buttons(btns) + end + + args = { screen = scr } + local text, bg, bg_image, icon = label(o, args) + + -- Check if we got a valid text here, it might contain e.g. broken utf8. + if not pcall(function() w[k + 1].text = text end) then + w[k + 1].text = "Invalid" + end + + w[k + 1].bg, w[k + 1].bg_image = bg, bg_image + w[k].bg, w[k].image = bg, icon + if not w[k + 1].text then + w[k+1].visible = false + else + w[k+1].visible = true + end + if not w[k].image then + w[k].visible = false + else + w[k].visible = true + end + end +end +--}}} + +--{{{ taglist_update: update the taglist widget +-- @param screen : the screen to draw the taglist for +-- @param w : the taglist widget +-- @param label : label function to use +-- @param buttons : a table with button bindings to set +-- @param widgets : a table with widget style parameters +-- @param objects : the list of tags to be displayed +local function taglist_update (screen, w, label, buttons, data, widgets) + list_update(w, buttons, label, data, widgets, cachedtags, screen) +end +--}}} + +--{{{ taglist: create a taglist widget for the shared tags +-- @param screen : the screen to draw the taglist for +-- @param label : label function to use +-- @param buttons : a table with button bindings to set +function taglist(screen, label, buttons) + local w = { + layout = layout.horizontal.leftright + } + local widgets = { } + widgets.imagebox = { } + widgets.textbox = { ["margin"] = { ["left"] = 0, + ["right"] = 0}, + ["bg_resize"] = true + } + local data = setmetatable({}, { __mode = 'kv' }) + local u = function (s) + if s == screen then + taglist_update(s, w, label, buttons, data, widgets) + end + end + local uc = function (c) return u(c.screen) end + capi.client.add_signal("focus", uc) + capi.client.add_signal("unfocus", uc) + tag.attached_add_signal(screen, "property::selected", uc) + tag.attached_add_signal(screen, "property::icon", uc) + tag.attached_add_signal(screen, "property::hide", uc) + tag.attached_add_signal(screen, "property::name", uc) + capi.screen[screen]:add_signal("tag::attach", function(screen, tag) + u(screen.index) + end) + capi.screen[screen]:add_signal("tag::detach", function(screen, tag) + u(screen.index) + end) + capi.client.add_signal("new", function(c) + c:add_signal("property::urgent", uc) + c:add_signal("property::screen", function(c) + -- If client change screen, refresh it anyway since we don't from + -- which screen it was coming :-) + u(screen) + end) + c:add_signal("tagged", uc) + c:add_signal("untagged", uc) + end) + capi.client.add_signal("unmanage", uc) + u(screen) + return w +end +--}}} + +--}}} + +-- vim: fdm=marker: diff --git a/rc/signals.lua b/rc/signals.lua new file mode 100644 index 0000000..bde3b09 --- /dev/null +++ b/rc/signals.lua @@ -0,0 +1,29 @@ +-- Signal function to execute when a new client appears. +client.add_signal("manage", + function (c, startup) + -- Enable sloppy focus + c:add_signal("mouse::enter", + function(c) + if ((awful.layout.get(c.screen) ~= awful.layout.suit.magnifier or awful.client.getmaster(c.screen) == c) + and awful.client.focus.filter(c)) then + client.focus = c + end + end) + + if not startup then + -- 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 + c.opacity = 1 + end) +client.add_signal("unfocus", function(c) + c.border_color = beautiful.border_normal + c.opacity = 0.8 + end) diff --git a/rc/start.lua b/rc/start.lua new file mode 100644 index 0000000..d1bc89e --- /dev/null +++ b/rc/start.lua @@ -0,0 +1,79 @@ +-- Startup + +-- run a command only if the client does not already exist +xrun = function(name, cmd) + if os.execute("xwininfo -name '" .. name .. "' > /dev/null 2> /dev/null") == 0 then + return + end + awful.util.spawn_with_shell(cmd or name) +end + +-- Setup display +local xrandr = { + naruto = "--output VGA1 --auto --output DVI1 --auto --left-of VGA1", + neo = "--output HDMI-0 --auto --output DVI-0 --auto --right-of HDMI-0" +} +if xrandr[config.hostname] then + os.execute("xrandr " .. xrandr[config.hostname]) +end + +-- Spawn a composoting manager +awful.util.spawn("unagi", false) + +-- Start idempotent commands +local execute = { + -- Start PulseAudio + "pulseaudio --check || pulseaudio -D", + "xset -b", -- Disable bell + -- Enable numlock + "numlockx on", +} + +if config.hostname == "naruto" then + execute = awful.util.table.join( + execute, { + -- Keyboard configuration + "xset m 4 3", -- Mouse acceleration + "setxkbmap us '' compose:rwin ctrl:nocaps", + "xmodmap -e 'keysym Pause = XF86ScreenSaver'" }) +elseif config.hostname == "neo" then + execute = awful.util.table.join( + execute, { + -- Keyboard configuration + "xset m 3 3", -- Mouse acceleration + "setxkbmap us '' compose:rwin ctrl:nocaps", + "xmodmap -e 'keysym Pause = XF86ScreenSaver'"}) +elseif config.hostname == "guybrush" then + execute = awful.util.table.join( + execute, { + -- Keyboard configuration + "setxkbmap us '' compose:rctrl ctrl:nocaps", + "xmodmap -e 'keysym XF86AudioPlay = XF86ScreenSaver'", + -- Wheel emulation + "xinput set-int-prop 'TPPS/2 IBM TrackPoint' 'Evdev Wheel Emulation' 8 1", + "xinput set-int-prop 'TPPS/2 IBM TrackPoint' 'Evdev Wheel Emulation Button' 8 2", + "xinput set-int-prop 'TPPS/2 IBM TrackPoint' 'Evdev Wheel Emulation Axes' 8 6 7 4 5", + -- Disable touchpad + "xinput set-int-prop 'SynPS/2 Synaptics TouchPad' 'Synaptics Off' 8 1"}) +end + +os.execute(table.concat(execute, ";")) + +-- Spawn various X programs +startapps = function() + xrun("polkit-gnome-authentication-agent-1", + "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1") + xrun("Bluetooth Applet", + "bluetooth-applet") + + if config.hostname == "naruto" then + xrun("Pidgin", "pidgin") + elseif config.hostname == "neo" then + xrun("Pidgin", "pidgin") + xrun("keepassx", "keepassx -min -lock") + xrun("Transmission", "transmission-gtk -m") + elseif config.hostname == "guybrush" then + xrun("keepassx", "keepassx -min -lock") + -- xrun("nm-applet") + end +end diff --git a/rc/tags.lua b/rc/tags.lua new file mode 100644 index 0000000..bd30f4d --- /dev/null +++ b/rc/tags.lua @@ -0,0 +1,55 @@ +-- Tags + +loadrc("sharetags") + +local tags = { names = { "main", "emacs", "www", "im", 5 }, + layout = { awful.layout.suit.tile, + awful.layout.suit.tile, + awful.layout.suit.tile, + awful.layout.suit.tile, + awful.layout.suit.tile }} +tags = sharetags.create_tags(tags.names, tags.layout) +config.tags = {} + +-- Compute the maximum number of digit we need, limited to 9 +keynumber = math.min(9, #tags) + +-- 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, #tags do + config.tags[tags[i].name] = tags[i] + if i <= keynumber then + config.keys.global = awful.util.table.join( + config.keys.global, + awful.key({ modkey }, "#" .. i + 9, + function () + local t = tags[i] + if t.screen ~= mouse.screen then + sharetags.tag_move(t, mouse.screen) + end + awful.tag.viewonly(tags[i]) + end), + awful.key({ modkey, "Control" }, "#" .. i + 9, + function () + if tags[i] then + awful.tag.viewtoggle(tags[i]) + end + end), + awful.key({ modkey, "Shift" }, "#" .. i + 9, + function () + if client.focus and tags[i] then + awful.client.movetotag(tags[i]) + end + end), + awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, + function () + if client.focus and tags[i] then + awful.client.toggletag(tags[i]) + end + end)) + end +end + +awful.tag.setproperty(config.tags.emacs, "mwfact", 0.6) -- emacs +awful.tag.setproperty(config.tags.www, "mwfact", 0.7) -- www diff --git a/rc/theme.lua b/rc/theme.lua new file mode 100644 index 0000000..fec35b1 --- /dev/null +++ b/rc/theme.lua @@ -0,0 +1,33 @@ +-- Theme +beautiful.init(awful.util.getdir("config") .. "/themes/custom.lua") + +-- GTK stuff: we choose Adwaita theme which seems to be the only one +-- kept up-to-date with GTK2 and GTK3... + +-- Also see: http://developer.gnome.org/gtk3/3.2/GtkSettings.html +local gtk = 'gtk-font-name="' .. beautiful.font .. '"' .. [[ + +gtk-theme-name="Adwaita" +gtk-icon-theme-name="gnome-wine" +gtk-cursor-theme-name="oxy-cherry" +gtk-cursor-theme-size=0 +gtk-toolbar-style=GTK_TOOLBAR_BOTH +gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR +gtk-button-images=1 +gtk-menu-images=1 +gtk-xft-antialias=1 +gtk-xft-hinting=1 +gtk-xft-hintstyle="hintfull" +gtk-xft-rgba="rgb" +gtk-key-theme-name="Emacs" +]] + +local gtk2 = io.open(os.getenv("HOME") .. "/.gtkrc-2.0", "w") +gtk2:write(gtk) +gtk2:close() + +-- GTK3 is the same, but no double quotes for strings +local gtk3 = io.open(os.getenv("HOME") .. "/.config/gtk-3.0/settings.ini") +gtk3:write("[Settings]\n") +gtk3:write(gtk:gsub('"', '')) +gtk3:close() diff --git a/rc/wallpaper.lua b/rc/wallpaper.lua new file mode 100644 index 0000000..33e6915 --- /dev/null +++ b/rc/wallpaper.lua @@ -0,0 +1,25 @@ +-- Change wallpaper + +local wtimer = timer { timeout = 0 } + +config.wallpaper = {} +config.wallpaper.directory = awful.util.getdir("config") .. "/wallpapers" +config.wallpaper.current = awful.util.getdir("cache") .. "/current-wallpaper.png" + +-- We use fvwm-root because default backend for awsetbg does not seem +-- to accept to set multiscreen wallpapers. +local change = function() + awful.util.spawn_with_shell( + awful.util.getdir("config") .. "/bin/build-wallpaper " .. + "--crop --directory " .. config.wallpaper.directory .. + " --target " .. config.wallpaper.current .. + "&& fvwm-root -r " .. config.wallpaper.current) +end + +wtimer:add_signal("timeout", function() + change() + wtimer:stop() + wtimer.timeout = math.random(3000, 3600) + wtimer:start() + end) +wtimer:start() diff --git a/rc/widgets.lua b/rc/widgets.lua new file mode 100644 index 0000000..365ca6e --- /dev/null +++ b/rc/widgets.lua @@ -0,0 +1,150 @@ +-- Widgets + +require("vicious") + +-- Separator +local separator = widget({ type = "textbox" }) +separator.text = ' | ' + +-- Date +local datewidget = widget({ type = "textbox" }) +vicious.register(datewidget, vicious.widgets.date, + '%a %d/%m, %H:%M', 61) + +-- CPU usage +local cpuwidget = widget({ type = "textbox" }) +cpuwidget.text = 'CPU: ' +local cpugraph = awful.widget.graph() +cpugraph:set_width(45):set_height(12):set_max_value(100) +cpugraph:set_border_color(beautiful.fg_widget_border) +cpugraph:set_gradient_angle(0):set_gradient_colors({ + beautiful.fg_widget_start, beautiful.fg_widget_center, beautiful.fg_widget_end + }) +vicious.register(cpugraph, vicious.widgets.cpu, "$1") +local cpuvalue = widget({ type = "textbox" }) +vicious.register(cpuvalue, vicious.widgets.cpu, + function (widget, args) + return string.format(' %2d%%', args[1]) + end) + +-- Battery +local batwidget = nil +if config.hostname == "guybrush" then + batwidget = widget({ type = "textbox" }) + vicious.register(batwidget, vicious.widgets.bat, + 'BAT: ' .. + '$1 $2%', + 61, "BAT0") +end + +-- Memory usage +local memwidget = widget({ type = "textbox" }) +vicious.register(memwidget, vicious.widgets.mem, + 'Mem: ' .. + '$1%', + 13) + +-- Volume level +local volwidget = widget({ type = "textbox" }) +vicious.register(volwidget, vicious.widgets.volume, + 'Vol: ' .. + '$2 $1%', + 2, "Master") +volwidget:buttons(awful.util.table.join( + awful.button({ }, 1, function () awful.util.spawn("pavucontrol", false) end), + awful.button({ }, 4, function () awful.util.spawn("amixer -q -c 0 set Master 2dB+", false) end), + awful.button({ }, 5, function () awful.util.spawn("amixer -q -c 0 set Master 2dB-", false) end) +)) + +local systray = widget({ type = "systray" }) + +-- {{{ Wibox initialisation +local wibox = {} +local promptbox = {} +local layoutbox = {} + +local taglist = {} +taglist.buttons = awful.util.table.join( + awful.button({ }, 1, + function(t) + if t.screen ~= mouse.screen then + sharetags.tag_move(t, mouse.screen) + end + awful.tag.viewonly(t) + end), + awful.button({ modkey }, 1, awful.client.movetotag), + awful.button({ }, 3, + function(t) + if t.screen ~= mouse.screen then + sharetags.tag_move(t, mouse.screen) + end + awful.tag.viewtoggle(t) + end), + awful.button({ modkey }, 3, awful.client.toggletag), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev)) + +local tasklist = {} +tasklist.buttons = awful.util.table.join( + awful.button({ }, 1, function (c) + if c == client.focus then + c.minimized = true + else + if not c:isvisible() then + awful.tag.viewonly(c:tags()[1]) + end + -- This will also un-minimize + -- the client, if needed + client.focus = c + c:raise() + end + end)) + +for s = 1, screen.count() do + promptbox[s] = awful.widget.prompt({ layout = awful.widget.layout.horizontal.leftright }) + layoutbox[s] = awful.widget.layoutbox(s) + tasklist[s] = awful.widget.tasklist( + function(c) + return awful.widget.tasklist.label.currenttags(c, s) + end, tasklist.buttons) + + -- Create the taglist + taglist[s] = sharetags.taglist(s, sharetags.label.all, taglist.buttons) + -- Create the wibox + wibox[s] = awful.wibox({ screen = s, + fg = beautiful.fg_normal, + bg = beautiful.bg_widget, + position = "top", + height = 14, + }) + -- Add widgets to the wibox + local onfirst = function(what) + if s == 1 then return what end + return nil + end + local onsecond = function(what) + if s == 2 or screen.count() == 1 then return what end + return nil + end + + wibox[s].widgets = { + { + taglist[s], layoutbox[s], + separator, promptbox[s], + layout = awful.widget.layout.horizontal.leftright + }, + onfirst(systray), onfirst(seperator), + datewidget, separator, + onsecond(volwidget), onsecond(separator), + onsecond(batwidget), onsecond(batwidget and separator or nil), + onfirst(memwidget), onfirst(separator), + onfirst(cpuvalue), onfirst(cpugraph.widget), onfirst(cpuwidget), onfirst(separator), + tasklist[s], separator, + layout = awful.widget.layout.horizontal.rightleft } +end + +config.keys.global = awful.util.table.join( + config.keys.global, + awful.key({ modkey }, "r", function () promptbox[mouse.screen]:run() end)) diff --git a/rc/xlock.lua b/rc/xlock.lua new file mode 100644 index 0000000..f92e550 --- /dev/null +++ b/rc/xlock.lua @@ -0,0 +1,9 @@ +-- Lockscreen + +xrun("xautolock", + "xautolock -time 5 -locker 'i3lock -n -i " .. + awful.util.getdir("cache") .. "/current-wallpaper.png'") + +config.keys.global = awful.util.table.join( + config.keys.global, + awful.key({}, "XF86ScreenSaver", function() awful.util.spawn("xautolock -locknow", false) end)) diff --git a/themes/custom.lua b/themes/custom.lua new file mode 100644 index 0000000..3b9c163 --- /dev/null +++ b/themes/custom.lua @@ -0,0 +1,22 @@ +-- Small modifications to anrxc's zenburn theme + +local theme = loadrc("../themes/nice-and-clean-theme/theme") +if theme then + theme.wallpaper_cmd = { "/bin/true" } + theme.font = "Cantarell 9" + + theme.bg_normal = theme.bg_normal .. "99" + theme.bg_focus = theme.bg_focus .. "99" + theme.bg_urgent = theme.bg_urgent .. "99" + theme.bg_minimize = theme.bg_minimize .. "99" + theme.bg_widget = "#00000099" + theme.fg_widget_label = "#708090" + theme.fg_widget_value = "#FFFFFF" + theme.fg_widget_sep = "#FFFFFF" + theme.fg_widget_border = "#FFFFFF" + theme.fg_widget_clock = "#FF7F00" + theme.fg_widget_end = "#FFFFFF" + theme.fg_widget_center = "#FFCCCC" + theme.fg_widget_start = "#FF0000" + return theme +end diff --git a/themes/nice-and-clean-theme b/themes/nice-and-clean-theme new file mode 160000 index 0000000..687d77a --- /dev/null +++ b/themes/nice-and-clean-theme @@ -0,0 +1 @@ +Subproject commit 687d77ae6c2c2cfc38ca85f226006244384560d6