Shifty
From awesome
| Languages: |
English • Français |
Contents |
[edit] What's Shifty
Short answer: what's not?!
Long answer: Shifty is an Awesome 3 extension that implements dynamic tagging. It also implements fine client matching configuration allowing YOU to be the master of YOUR desktop only by setting two simple config variables and some keybindings! Here are a few ways of how shifty makes awesome awesomer:
- on-the-fly tag creation and disposal
- advanced client matching
- easy moving of clients between tags
- tag add/rename prompt in taglist (with completion, now configurable NEW )
- reordering tags and configurable positioning
- tag name guessing, automagic no-config client grouping
- customizable keybindgs per client and tag -- NEW
- simple yet powerful configuration
The module has gone a long way since I started it and is in active development - improvements happen daily. Be sure to check the changelog for details.
The code is still pre-release quality but the module is fully functional. It might suffer from some limitations, a lot of which will be down to the fact that I use Awesome my way and your way may vary. Shifty has the potential of encompassing many different approaches and for that reason testing and comments are needed and in fact much appreciated.
[edit] Videos
To see an early version of Shifty in action check: http://silenceisdefeat.com/~koniu/shifty.ogv mirror
Another video showing off a few improved features is here but might be a bit confusing (ie. features tags disappearing without apparent reason). Maybe one day I'll make a proper one, this one is to catch your eye: http://silenceisdefeat.com/~koniu/shifty-new.ogv [5MB - sorry]
And a new video giving a glimpse of possibilities given by per-tag/client keybindings. It is this piece of my rc.lua in action creating a special tag for development using git. http://silenceisdefeat.com/~koniu/gittags.avi [3.3MB]
[edit] Getting Shifty
If you want to try Shifty, depending on the awesome release you're using, your options are:
Version for awesome git master
http://git.mercenariesguild.net/?p=awesome.git;a=blob;f=lib/shifty.lua.in;hb=shifty-master [raw]
Version for awesome 3.3.*
http://git.mercenariesguild.net/?p=awesome.git;a=blob;f=lib/shifty.lua.in;hb=shifty [raw]
[edit] Using Shifty
1. First, you need to save shifty.lua in your ~/.config/awesome
1.5. The instructions below are not entirely up to date so if you're lazy and just want to try things out quickly, a nearly default rc.lua designed to work with shifty can be found here:
- shifty-master: http://silenceisdefeat.com/~koniu/awesome/shifty.rc.lua
- bioe007 version: http://github.com/bioe007/awesome-configs/blob/master/shifty.rc.lua [raw]
2. Load the module:
require('shifty')
3. Remove all the existing tag creation/settings code from your rc.lua.
4. Disable the default manage hook in rc.lua. You can do that by adding this as its first line:
if true then return end
5. Somewhere near the top of rc.lua add some tag and client presets. Example:
shifty.config.tags = {
["1:sys"] = { init = true, position = 1, screen = 1, mwfact = 0.60 },
["3:www"] = { exclusive = true, max_clients = 1, position = 3, spawn = "firefox" },
["2:term"] = { persist = true, position = 2, },
["ardour"] = { nopopup = true, leave_kills = true, },
["p2p"] = { icon = "/usr/share/pixmaps/p2p.png", icon_only = true, },
["gimp"] = { layout = "tile", mwfact = 0.18, icon="/usr/share/pixmaps/gimp.png", },
["fs"] = { rel_index = 1, },
}
shifty.config.apps = {
{ match = { "htop", "Wicd", "jackctl" }, tag = "1:sys", screen = 1, },
{ match = {"Iceweasel.*", "Firefox.*" }, tag = "3:www", },
{ match = {"urxvt" }, tag = "2:term", screen = 1, },
{ match = {"foobar2000.exe", }, tag = "fb", nopopup = true, },
{ match = {"Ardour.*", "Jamin", }, tag = "ardour", },
{ match = {"Live.*", }, tag = "live", nopopup = true, },
{ match = {"Deluge","nicotine" }, tag = "p2p", },
{ match = {"Gimp","Ufraw" }, tag = { "graph", "gimp" } },
{ match = {"gimp%-image%-window" }, slave = true, },
{ match = {"gqview" }, tag = { "graph", "gqview" } },
{ match = { "Pcmanfm" }, tag = "fs", },
{ match = {"gcolor2", "xmag" }, intrusive = true, },
{ match = {"gcolor2" }, geometry = { 100,100,nil,nil }, },
{ match = {"recordMyDesktop", "MPlayer", "xmag",
}, float = true, },
{ match = { "" }, 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 ), }, },
}
shifty.config.defaults = {
layout = "max",
run = function(tag) naughty.notify({ text = tag.name }) end,
}
shifty.init()
In the above example:
- tag gimp will have text and icon on it, while tag p2p will only have an icon (icon_only).
- persist causes tag term not to be destroyed when last terminal is closed.
- init causes tag sys to be created on startup. Implies persist.
- screen causes tag sys to be only created on screen 1.
- position causes tag sys to always be inserted as 1st in the list, term as 2nd and www as 3rd.
- mwfact sets the master window size factor to 0.60 (60%) in the tag
- nopopup causes tag ardour not to be focused on creation.
- leave_kills causes tag ardour, after closing last window, not to be destroyed until you switch to another tag. Note that tags won't be destroyed unless they've been used (ie. have had a client).
- exclusive causes any clients opened in tag www but not matched to it in config.apps to be moved to a new tag, unless they're flagged with intrusive like gcolor2 and xmag.
- max_clients causes tag www to accept only one client. If more than one browser window is opened, a new www tag will be created for it. You can cycle through all of them with modkey+3.
- rel_index = 1 causes tag fs to always open next to the current tag and not at the end. rel_index = 0 would create it at current position of the taglist (before current tag).
- spawn defines name of the program (firefox) to be executed when tag www is created; combined with position allows running firefox by pressing modkey+3.
- run defines a function that will be run on tag creation; in the example above it will cause naughty to display a popup with a name every time a tag is created.
- float, will make recordMyDesktop, MPlayer and xmag clients float.
- geometry, causes gcolor2 window to be created at 100, 100 coordinates. Table format is {x,y,w,h}.
- slave, causes GIMP image widows to be slaves (we want the toolbox to be the master).
config.tags and config.defaults takes: layout, mwfact, nmaster, ncol, exclusive, solitary, persist, nopopup, leave_kills, position, icon, icon_only, sweep_delay, keys, overload_keys, index, rel_index, run, spawn, screen.
config.apps takes: screen, tag, float, geometry, slave, nopopup, nofocus, intrusive, fullscreen, honorsizehints, kill, ontop, below, above, buttons, keys, hide, minimized, dockable, urgent, opacity, titlebar, run, sticky, wfact, struts.
config.guess_name. If set to true (default) shifty will attempt to guess new tag name from client's class. This has effect only when a client is unmatched and being opened when there's no tags or current tag is solitary or exclusive. commit
config.guess_position. If set to true (default) shifty will check first character of a tag name for being a number and set tag's position according to that. Providing position explicitly overrides this. commit
config.remember_index. If set to true (default) shifty will keep track of tag's taglist index and if closed reopen the tag at the same place. Specifying position, index or rel_index overrides this. commit
config.layouts. If set (to a table of layout functions), enables setting layouts by short name commit
config.clientkeys. Default table of client keys. commit
config.globalkeys. Default table of global keys. commit
config.prompt_sources. config.prompt_matchers. Config for completion commit
Running shifty.init() after config variables are set creates tags configured with init flag.
Note that client-tag matching (config.apps) is done against role, instance, class, type and title. It supports patterns through string.find so if you're matching something else then title you should probably use a match as exact as feasible ("^Iceweasel$").
In tag field of config.apps you can even provide tag names that don't have presets in config.tags, they'll be created with the name from config.apps and according to config.defaults (if any).
Take notice of the { match = "" }, ... entry in config.apps - you need that if you want to have client buttons.
6. After taglist definitions in rc.lua, add this (note that mytaglist must be a table of taglists, not a single taglist object):
shifty.taglist = mytaglist
7. Add some keybindings to rc.lua. Eg:
awful.key({ }, "XF86Back", awful.tag.viewprev),
awful.key({ }, "XF86Forward", awful.tag.viewnext),
awful.key({ modkey }, "XF86Back", shifty.shift_prev),
awful.key({ modkey }, "XF86Forward", shifty.shift_next),
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),
8. Replace mod+i (numerical) keybindings loop with one like this:
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
Note that Shifty operates numerical bindings according to attribute position (how it works) with a function called getpos()
Function shifty.getpos() is meant to handle mod+i combination by mapping tags' position attribute.
- if tag with position i exists, switches to it (provided that 2nd argument, switch, is true)
- if there's more than one tag with position i, mod+i will cycle through all of of them
- if position i tag doesn't exist, a new tag at that position will be created using config.tags preset
- if there's no preset it creates a tag called "i: " and runs prompt to assign name
9. Following keytables' (globalkeys, clientkeys) definitions tell shifty what's going on:
-- Set keys root.keys(globalkeys) shifty.config.globalkeys = globalkeys shifty.config.clientkeys = clientkeys
10. You made it! Now when you start Awesome there'll be no tags created unless you preconfigured some with init flag. In former case, opening a window that doesn't have a preset will create a new tag named after client's class (or "new" if shifty.config.guess is unset/false). If you open Firefox, a new tag 'www' will be created. If you open a terminal a new tag 'term' will be created. If you switch to 'www' and run yet another terminal, it'll switch to tag 'term' and open the new one there. If you set nopopup for 'term' matched clients, they'd still open in the preset tag, but in the background (ie. without switching to that tag). Etc, etc.
[edit] Valid shifty.config.apps valiables
- startup
- geometry
- float
- slave
- border_width
- nopopup
- intrusive
- fullscreen
- honorsizehints
- kill
- ontop
- above
- below
- buttons
- nofocus
- keys
- hidden
- minimized
- dockable
- urgent
- opacity
- titlebar
- run
- sticky
- wfact
- struts
- skip_taskbar
- props
[edit] Development
[edit] Support
If you run into trouble or have suggestions/comments, talk to koniu or bioe007 at #awesome, use the mailing list or simply use the talk page here. Note that API might occasionaly change, so check with this page and the changelog, especially if you updated and something stopped working. If you do choose to use it please try to stay as up-to-date with shifty and awesome git - changes/improvements/fixes are happening all the time.
[edit] Bugs
- awful.tag.history is one level resulting in erratic switches eg. when deleting several tags in a row
- when renaming a tag from one preset to another, the layout is not always overridden and stays at old preset
- rename prompt alignment is weird with taglist_squares [done 1 2]
[edit] TODO
- update wiki instructions [partially done]
- allow matching clients to multiple tags: done
- test multi-screen more
- fix history
- clean and split up set/match, especially: target screen/tag calculation and tag indexing
- make use of awful.client.property{set,get}
- allow aligning tags to the right side of the taglist
- rethink client matching syntax
- more specific matching (match = { class = "URxvt", inst = "urxvt", }) with possibly more matchers (geom)
- logic and aggregation: AND vs OR
[edit] Shifty vs Eminent
Shifty was inspired by Eminent and in the past reused little bits of its code. Eminent was another extension of the same kind (dynamic tagging). It had been developed when awesome's API wasn't as flexible and suffered from a number of shortcomings (tags were actually pre-created but empty tags remained hidden).

