diff --git a/.gitmodules b/.gitmodules index e69de29..4269d4a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "shifty"] + path = shifty + url = http://bioe007@github.com/bioe007/awesome-shifty.git diff --git a/README.md b/README.md index 6fec876..68a63e9 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,6 @@ Here some of the things you may be interested in: also using notifications to change xrandr setup. This is pretty cool. - - I am sharing tags between screen with - [sharetags](http://awesome.naquadah.org/wiki/Shared_tags). I am - also giving names to tags: I access them with something like - `config.tags.emacs`. I need to try out shifty. - - Keybindings are "autodocumented". See `lib/keydoc.lua` to see how this works. The list of key bindings can be accessed with Mod4 + F1. diff --git a/lib/sharetags.lua b/lib/sharetags.lua deleted file mode 100644 index 3ba2703..0000000 --- a/lib/sharetags.lua +++ /dev/null @@ -1,356 +0,0 @@ --- 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("vbe/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.lua b/rc.lua index 871320c..2682a67 100644 --- a/rc.lua +++ b/rc.lua @@ -49,16 +49,8 @@ config.layouts = { awful.layout.suit.fair, awful.layout.suit.floating, } -config.tags = { - { layout = awful.layout.suit.fair, icon = "main" }, -- 1 - { name = "emacs", mwfact = 0.6, icon = "dev" }, - { name = "www", mwfact = 0.7, icon = "web" }, - { name = "im" , mwfact = 0.2, icon = "im" }, - { }, -- 5 - { }, -- 6 - { }, -- 7 -} config.hostname = awful.util.pread('uname -n'):gsub('\n', '') +config.browser = "conkeror" -- Remaining modules loadrc("xrun") -- xrun function @@ -68,8 +60,8 @@ loadrc("debug") -- debugging primitive `dbg()` loadrc("start") -- programs to run on start loadrc("bindings") -- keybindings loadrc("wallpaper") -- wallpaper settings -loadrc("tags") -- tags handling loadrc("widgets") -- widgets configuration +loadrc("tags") -- tags handling loadrc("xlock") -- lock screen loadrc("signals") -- window manager behaviour loadrc("rules") -- window rules diff --git a/rc/bindings.lua b/rc/bindings.lua index d4c68a8..6ff45c8 100644 --- a/rc/bindings.lua +++ b/rc/bindings.lua @@ -3,7 +3,6 @@ config.mouse = {} local volume = loadrc("volume", "vbe/volume") local brightness = loadrc("brightness", "vbe/brightness") local keydoc = loadrc("keydoc", "vbe/keydoc") -local sharetags = loadrc("sharetags", "vbe/sharetags") local function screenshot(client) if not client then @@ -32,13 +31,8 @@ local function toggle_window(filter) -- So, we have a client. if not cl:isvisible() then -- But it is not visible. So we will add it to the current - -- tag of the current screen. - local t = assert(awful.tag.selected(s)) - -- Before adding the tag to the client, we should ensure it - -- is on the same screen. - if s ~= cl.screen then - sharetags.tag_move(cl:tags()[1], s) - end + -- tag of the screen where it currently is + local t = assert(awful.tag.selected(cl.screen)) -- Add our tag to the client undo[#undo + 1] = { cl, t } awful.client.toggletag(t, cl) diff --git a/rc/rules.lua b/rc/rules.lua index 2bcc587..60a760d 100644 --- a/rc/rules.lua +++ b/rc/rules.lua @@ -8,14 +8,9 @@ awful.rules.rules = { focus = true, maximized_vertical = false, maximized_horizontal = false, - keys = config.keys.client, buttons = config.mouse.client }}, - -- Emacs - { rule = { class = "Emacs" }, - properties = { tag = config.tags.emacs }}, -- Browser stuff { rule = { role = "browser" }, - properties = { tag = config.tags.www }, callback = function(c) if not c.icon then local icon = icons.lookup({ name = "web-browser", @@ -36,9 +31,6 @@ awful.rules.rules = { { rule = { instance = "exe", class="Exe", instance="exe" }, properties = { floating = true }}, -- Flash with Chromium -- Pidgin - { rule = { class = "Pidgin" }, - except = { type = "dialog" }, - properties = { tag = config.tags.im }}, { rule = { class = "Pidgin" }, except = { role = "buddy_list" }, -- buddy_list is the master properties = { }, callback = awful.client.setslave }, diff --git a/rc/start.lua b/rc/start.lua index afb2df9..8c03230 100644 --- a/rc/start.lua +++ b/rc/start.lua @@ -1,6 +1,3 @@ --- Startup -local browser = "conkeror" - -- Setup display local xrandr = { naruto = "--output VGA1 --auto --output DVI1 --auto --left-of VGA1", @@ -23,8 +20,8 @@ local execute = { -- Read resources "xrdb -merge " .. awful.util.getdir("config") .. "/Xresources", -- Default browser - "xdg-mime default " .. browser .. ".desktop x-scheme-handler/http", - "xdg-mime default " .. browser .. ".desktop x-scheme-handler/https" + "xdg-mime default " .. config.browser .. ".desktop x-scheme-handler/http", + "xdg-mime default " .. config.browser .. ".desktop x-scheme-handler/https" } -- Keyboard/Mouse configuration @@ -66,8 +63,6 @@ xrun("polkit-gnome-authentication-agent-1", xrun("Bluetooth Applet", "bluetooth-applet") xrun("pidgin", "pidgin -n") -xrun("emacs") -xrun(browser) if config.hostname == "neo" then xrun("keepassx", "keepassx -min -lock") diff --git a/rc/tags.lua b/rc/tags.lua index c1ab4d6..b0ba5db 100644 --- a/rc/tags.lua +++ b/rc/tags.lua @@ -1,98 +1,141 @@ -- Tags -sharetags = loadrc("sharetags", "vbe/sharetags") +require("shifty") keydoc = loadrc("keydoc", "vbe/keydoc") -local otags = config.tags -config.tags = {} - -local names = {} -local layouts = {} -for i, v in ipairs(otags) do - names[i] = v.name or i - layouts[i] = v.layout or config.layouts[1] +local tagicon = function(icon) + return beautiful.icons .. "/taglist/" .. icon .. ".png" end -tags = sharetags.create_tags(names, layouts) +shifty.config.tags = { + ["3↭www"] = { + mwfact = 0.7, + exclusive = true, + max_clients = 1, + position = 3, + spawn = browser, + icon = tagicon("web") + }, + ["2↭emacs"] = { + mwfact = 0.6, + exclusive = true, + position = 2, + spawn = "emacs", + icon = tagicon("dev"), + }, + ["1↭xterm"] = { + layout = awful.layout.suit.fair, + exclusive = true, + position = 1, + slave = true, + spawn = config.terminal, + icon = tagicon("main"), + }, + ["4↭im"] = { + mwfact = 0.2, + exclusive = true, + position = 4, + icon = tagicon("im"), + nopopup = true + } +} --- Compute the maximum number of digit we need, limited to 9 -keynumber = math.min(9, #tags) +-- Also, see rules.lua +shifty.config.apps = { + { + match = { + "Iceweasel", + "Firefox", + "Chromium", + "Conkeror", + "Xulrunner-15.0" + }, + tag = "3↭www", + }, + { + match = { "emacs" }, + tag = "2↭emacs", + }, + { + match = { "Pidgin" }, + tag = "4↭im", + }, + { + match = { "URxvt" }, + -- tag = "1↭xterm", + intrusive = true, -- Display even on exclusive tags + }, +} + +shifty.config.defaults = { + layout = config.layouts[1], + floatBars = false, + mwfact = 0.6, + ncol = 1, + guess_name = true, + guess_position = true, +} +shifty.config.sloppy = false + +shifty.taglist = config.taglist -- Set in widget.lua +shifty.config.modkey = modkey +shifty.config.clientkeys = config.keys.client +shifty.init() config.keys.global = awful.util.table.join( config.keys.global, keydoc.group("Tag management"), - awful.key({ modkey }, "Escape", awful.tag.history.restore, "Switch to previous tag")) + awful.key({ modkey }, "Escape", awful.tag.history.restore, "Switch to previous tag"), + awful.key({ modkey }, "Left", awful.tag.viewprev, "View previous tag"), + awful.key({ modkey }, "Right", awful.tag.viewnext, "View next tag"), + awful.key({ modkey, "Shift"}, "o", + function() + local t = awful.tag.selected() + local s = awful.util.cycle(screen.count(), t.screen + 1) + awful.tag.history.restore() + t = shifty.tagtoscr(s, t) + awful.tag.viewonly(t) + end, + "Send tag to next screen")) + -- 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 - -- Name - config.tags[tags[i].name] = tags[i] - if tags[i].name ~= tostring(i) then - if screen.count() > 1 then - tags[i].name = tostring(i) .. "↭" .. tags[i].name - else - tags[i].name = tostring(i) - end - end - - -- Properties - for pname, pvalue in pairs(otags[i]) do - if pname == "icon" then - awful.tag.seticon(beautiful.icons .. "/taglist/" .. pvalue .. ".png", tags[i]) - elseif pname ~= "name" and pname ~= "layout" then - awful.tag.setproperty(tags[i], pname, pvalue) - end - end - - -- Key bindings - if i <= keynumber then - config.keys.global = awful.util.table.join( - config.keys.global, - keydoc.group("Tag management"), - awful.key({ modkey }, "#" .. i + 9, - function () - local t = tags[i] - if t.screen ~= mouse.screen then - if t.selected then - -- This tag is selected on another screen, let's swap - local currents = awful.tag.selectedlist(mouse.screen) - for _,current in pairs(currents) do - sharetags.tag_move(current, t.screen) - end - awful.tag.viewmore(currents, t.screen) - end - sharetags.tag_move(t, mouse.screen) - end - awful.tag.viewonly(tags[i]) - end, i == 5 and "Display only this tag" or nil), - awful.key({ modkey, "Control" }, "#" .. i + 9, - function () - local t = tags[i] - if t then - if t.screen ~= mouse.screen then - sharetags.tag_move(t, mouse.screen) - if not t.selected then - awful.tag.viewtoggle(t) - end - else - awful.tag.viewtoggle(t) - end - end - end, i == 5 and "Toggle display of this tag" or nil), - awful.key({ modkey, "Shift" }, "#" .. i + 9, - function () - if client.focus and tags[i] then - awful.client.movetotag(tags[i]) - end - end, i == 5 and "Move window to this tag" or nil), - awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, - function () - if client.focus and tags[i] then - awful.client.toggletag(tags[i]) - end - end, i == 5 and "Toggle this tag on this window" or nil), - keydoc.group("Misc")) - end +for i = 1, (shifty.config.maxtags or 9) do + config.keys.global = awful.util.table.join( + config.keys.global, + keydoc.group("Tag management"), + awful.key({ modkey }, i, + function () + local t = shifty.getpos(i) + local s = t.screen + local c = awful.client.focus.history.get(s, 0) + awful.tag.viewonly(t) + mouse.screen = s + if c then client.focus = c end + end, + i == 5 and "Display only this tag" or nil), + awful.key({ modkey, "Control" }, i, + function () + local t = shifty.getpos(i) + t.selected = not t.selected + end, + i == 5 and "Toggle display of this tag" or nil), + awful.key({ modkey, "Shift" }, i, + function () + if client.focus then + local t = shifty.getpos(i) + awful.client.movetotag(t) + end + end, + i == 5 and "Move window to this tag" or nil), + awful.key({ modkey, "Control", "Shift" }, i, + function () + if client.focus then + awful.client.toggletag(shifty.getpos(i)) + end + end, + i == 5 and "Toggle this tag on this window" or nil), + keydoc.group("Misc")) end diff --git a/rc/widgets.lua b/rc/widgets.lua index ccbd11b..1e2e230 100644 --- a/rc/widgets.lua +++ b/rc/widgets.lua @@ -250,7 +250,8 @@ for s = 1, screen.count() do end, tasklist.buttons) -- Create the taglist - taglist[s] = sharetags.taglist(s, sharetags.label.all) + taglist[s] = awful.widget.taglist.new(s, + awful.widget.taglist.label.all) -- Create the wibox wibox[s] = awful.wibox({ screen = s, fg = beautiful.fg_normal, @@ -299,3 +300,5 @@ config.keys.global = awful.util.table.join( config.keys.global, awful.key({ modkey }, "r", function () promptbox[mouse.screen]:run() end, "Prompt for a command")) + +config.taglist = taglist diff --git a/shifty b/shifty new file mode 160000 index 0000000..48a220f --- /dev/null +++ b/shifty @@ -0,0 +1 @@ +Subproject commit 48a220fd9435518e66f1e308ea3f5b7565105134