[tabulous] Improve

I've attached a patch file which improves on the recently added
tabulous lib a lot, using it will require a bit more config-end logic,
but it's much more powerful and allows for things such as tabbars and
autotabbing.

List of changes:
* [awful] Add awful.hooks.userhook_create and
awful.hooks.userhook_call so external libs can easily add their own
hooks (tabulous uses these)
* Tabulous now uses a tabindex system, instead of a messy circular
table, every set of tabs is now a tabbed view, this is more practical
and allows for the same order to be retained even if the focus shifts
(otherwise, the currently focussed tag would always be the first one
in the tabbar)
* Tabulous now exports a number of extra functions that will help you
in managing your tabs efficiently
* Tabulous now has an autotab_start() function you can call
(preferably right after the require so any other hooks you may have
set up won't interfere with it), when this is on, any newly created
windows will automatically be tabbed into the current tabbed view if
you have one selected (if the focussed window is not part of a tabbed
view, tabulous will do nothing)
* Tabulous bugfixes

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Lucas de Vries 2008-06-11 07:47:57 +02:00 committed by Julien Danjou
parent 11e93c2dbf
commit 0ccfea330a
3 changed files with 211 additions and 105 deletions

View File

@ -2,8 +2,6 @@
-- Include awesome library, with lots of useful function!
require("awful")
-- Include another library, which defines useful tabular system
require("tabulous")
-- {{{ Colors and fonts
awesome.font_set("sans 8")
@ -176,11 +174,6 @@ keybinding.new({ modkey, "Shift" }, "space", function () awful.layout.inc(layout
-- Menu
keybinding.new({ modkey }, "F1", function () awful.menu("Run: ", mymenubox, awful.spawn) end):add()
-- Tabulous, tab manipulation
keybinding.new({ modkey, "Control" }, "y", function () tabulous.tab(awful.client.next(1)) end):add()
keybinding.new({ modkey, "Shift" }, "y", tabulous.untab):add()
keybinding.new({ modkey }, "y", tabulous.focusnext):add()
-- }}}
-- {{{ Hooks

View File

@ -17,6 +17,7 @@ end
-- Grab environment we need
local ipairs = ipairs
local pairs = pairs
local unpack = unpack
local awesome = awesome
local screen = screen
local client = client
@ -26,8 +27,6 @@ local os = os
local table = table
local hooks = hooks
local keygrabber = keygrabber
local print = print
local table = table
-- Reset env
setfenv(1, P)
@ -303,6 +302,24 @@ end
P.hooks = {}
P.myhooks = {}
-- Create a new userhook (for external libs)
local function userhook_create(name)
P.myhooks[name] = {}
P.hooks[name] = function (f)
table.insert(P.myhooks[name], {callback = f})
end
end
-- Call a created userhook (for external libs
local function userhook_call(name, args)
for i,o in pairs(P.myhooks[name]) do
P.myhooks[name][i]['callback'](unpack(args))
end
end
P.hooks['userhook_create'] = userhook_create
P.hooks['userhook_call'] = userhook_call
for name, hook in pairs(hooks) do
if name ~= 'timer' then
P.hooks[name] = function (f)

View File

@ -1,8 +1,11 @@
-----------------------------------------------
-- tabulous: Fabulous tabs for awesome --
-- --
-- © 2008 Julien Danjou <julien@danjou.info> --
-----------------------------------------------
----------------------------------------------------
-- tabulous: Fabulous tabs for awesome --
-- --
-- © 2008 Julien Danjou <julien@danjou.info> --
-- © 2008 Lucas de Vries <lucasdevries@gmail.com> --
----------------------------------------------------
require('awful')
--------------------
-- Module loading --
@ -18,125 +21,218 @@ end
local client = client
local table = table
local pairs = pairs
local rawset = rawset
local setmetatable = setmetatable
local awful = awful
-- Reset env
setfenv(1, P)
-- The tab datastructure.
-- It contains keys which are clients. If a c1 is a client,
-- then if tabbed[c1] exists it must contains a client c2.
-- And if so, tabbed[c2] must contain c1.
-- It's cycling i.e. tabbed[c1] = c2, tabbed[c2] = c3, tabbed[c3] = c1
local tabbed = {}
-- Define a special index method.
-- This is useful because we need to compare clients with __eq() to be sure
-- that the key are identical. Otherwise Lua assume that each object is different.
local function tabbed_index(table, key)
for k, v in pairs(table) do
if k == key then
return v
end
end
return nil
end
-- Same as tabbed_index, cheat!
local function tabbed_newindex(table, key, value)
for k, v in pairs(table) do
if k == key then
rawset(table, k, value)
return
end
end
rawset(table, key, value)
end
-- Set the metatable for tabbed
setmetatable(tabbed, { __index = tabbed_index, __newindex = tabbed_newindex })
awful.hooks.userhook_create('tabbed')
awful.hooks.userhook_create('untabbed')
awful.hooks.userhook_create('tabdisplay')
awful.hooks.userhook_create('tabhide')
---------------
-- Functions --
---------------
-- Get the next tab
local function client_nexttab(s)
local sel = s or client.focus_get()
if sel and tabbed[sel] then
return tabbed[sel]
end
end
-- Get the previous tab
local function client_prevtab(c, stopc)
local sel = c or client.focus_get()
local stop = stopc or sel
if sel and tabbed[sel] then
if stop == tabbed[sel] then
return sel
else
return client_prevtab(tabbed[sel], stop)
-- Find the key in a table
local function findkey(table, cl)
for i, c in pairs(table) do
if c == cl then
return i
end
end
return nil
end
-- Tab a client with another one
local function client_tab(c1, s)
local sel = s or client.focus_get()
if c1 and sel and c1 ~= sel then
if tabbed[c1] then
tabbed[sel] = tabbed[c1]
tabbed[c1] = sel
elseif tabbed[sel] then
tabbed[c1] = tabbed[sel]
tabbed[sel] = c1
else
tabbed[c1] = sel
tabbed[sel] = c1
-- Swap which tab is displayed
local function client_display(tabindex, cl)
local p = tabbed[tabindex][1]
if cl and p ~= cl then
cl:unhide()
cl:swap(p)
p:hide()
cl:focus_set()
tabbed[tabindex][1] = cl
awful.hooks.userhook_call('tabhide', {p})
awful.hooks.userhook_call('tabdisplay', {cl})
end
end
-- Check if the client is in the given tabindex
local function client_in_tabindex(tabindex, cl)
local c = cl or client.focus_get()
return findkey(tabbed[tabindex], c)
end
-- Find the tab index or return nil if not tabbed
local function client_find_tabindex(cl)
local c = cl or client.focus_get()
for tabindex, tabdisplay in pairs(tabbed) do
-- Loop through all tab displays
local me = client_in_tabindex(tabindex, c)
if me ~= nil then
return tabindex
end
c1:hide()
end
return nil
end
-- Create a new tabbed display with client as the master
local function client_tab_create(cl)
local c = cl or client.focus_get()
table.insert(tabbed, {
c, -- Window currently being displayed
{ c } -- List of windows in tabbed display
})
awful.hooks.userhook_call('tabbed', {c})
return client_find_tabindex(c)
end
-- Add a client to a tabbed display
local function client_tab(tabindex, cl)
local c = cl or client.focus_get()
if tabbed[tabindex] ~= nil and client_find_tabindex(c) == nil then
table.insert(tabbed[tabindex][2], c)
client_display(tabindex, c)
awful.hooks.userhook_call('tabbed', {c})
end
end
-- Untab a client
local function client_untab(c)
local sel = c or client.focus_get()
if sel and tabbed[sel] then
local p = client_prevtab(sel)
tabbed[p] = tabbed[sel]
tabbed[sel] = nil
p:unhide()
-- Get the next client in a tabdisplay
local function client_next(tabindex, cl)
local c = cl or tabbed[tabindex][1]
local i = findkey(tabbed[tabindex][2], c)
if i == nil then
return nil
end
if tabbed[tabindex][2][i+1] == nil then
return tabbed[tabindex][2][1]
else
return tabbed[tabindex][2][i+1]
end
end
-- Focus the next tab
local function client_focusnexttab(s)
local sel = s or client.focus_get()
local n = client_nexttab(sel)
if n then
sel:hide()
n:unhide()
n:focus_set()
-- Get the previous client in a tabdisplay
local function client_prev(tabindex, cl)
local c = cl or tabbed[tabindex][1]
local i = findkey(tabbed[tabindex][2], c)
if i == nil then
return nil
end
if tabbed[tabindex][2][i-1] == nil then
return tabbed[tabindex][2][table.maxn(tabbed[tabindex][2])]
else
return tabbed[tabindex][2][i-1]
end
end
-- Focus the previous tab
local function client_focusprevtab(s)
local sel = s or client.focus_get()
local p = client_prevtab(sel)
if p then
sel:hide()
p:unhide()
p:focus_set()
-- Remove a client from a tabbed display
local function client_untab(cl)
local c = cl or client.focus_get()
local tabindex = client_find_tabindex(c)
if tabindex == nil then return false end
local cindex = findkey(tabbed[tabindex][2], c)
if tabbed[tabindex][1] == c then
client_display(tabindex, client_next(tabindex, c))
end
table.remove(tabbed[tabindex][2], cindex)
if table.maxn(tabbed[tabindex][2]) == o then
-- Table is empty now, remove the tabbed display
table.remove(tabbed, tabindex)
end
c:unhide()
awful.hooks.userhook_call('untabbed', {c})
end
-- Untab all clients in a tabbed display
local function client_untab_all(tabindex)
for i,c in pairs(tabbed[tabindex][2]) do
awful.hooks.userhook_call('untabbed', {c})
end
if tabbed[tabindex] ~= nil then
table.remove(tabbed, tabindex)
end
end
-- Get all clients on a tabbed display
local function client_get_clients(tabindex)
return tabbed[tabindex][2]
end
-- Get the displayed client on a tabbed display
local function client_get_displayed(tabindex)
return tabbed[tabindex][1]
end
-- Get a client by tab number
local function client_get_position(tabindex, pos)
if tabbed[tabindex] == nil then return nil end
return tabbed[tabindex][2][pos]
end
-- Start autotabbing, this automatically
-- tabs new clients when the current client
-- is tabbed
local function autotab_start()
awful.hooks.manage(function (c)
local sel = client.focus_get()
local index = client_find_tabindex(sel)
if index ~= nil then
-- Currently focussed client is tabbed,
-- add the new window to the tabbed display
client_tab(index, c)
end
end)
end
-- Set up hook so we don't leave lost hidden clients
awful.hooks.unmanage(function (c) client_untab(c) end)
P.findkey = findkey
P.display = client_display
P.tabindex_check = client_in_tabindex
P.tabindex_get = client_find_tabindex
P.tab_create = client_tab_create
P.tab = client_tab
P.untab = client_untab
P.focusnext = client_focusnexttab
P.focusprev = client_focusprevtab
P.next = client_nexttab
P.prev = client_prevtab
P.untab_all = client_untab_all
P.next = client_next
P.prev = client_prev
P.clients_get = client_get_clients
P.displayed_get = client_get_displayed
P.position_get = client_get_position
P.autotab_start = autotab_start
P.tabbed = tabbed
return P