[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:
parent
11e93c2dbf
commit
0ccfea330a
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
-- Include awesome library, with lots of useful function!
|
-- Include awesome library, with lots of useful function!
|
||||||
require("awful")
|
require("awful")
|
||||||
-- Include another library, which defines useful tabular system
|
|
||||||
require("tabulous")
|
|
||||||
|
|
||||||
-- {{{ Colors and fonts
|
-- {{{ Colors and fonts
|
||||||
awesome.font_set("sans 8")
|
awesome.font_set("sans 8")
|
||||||
|
@ -176,11 +174,6 @@ keybinding.new({ modkey, "Shift" }, "space", function () awful.layout.inc(layout
|
||||||
|
|
||||||
-- Menu
|
-- Menu
|
||||||
keybinding.new({ modkey }, "F1", function () awful.menu("Run: ", mymenubox, awful.spawn) end):add()
|
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
|
-- {{{ Hooks
|
||||||
|
|
21
awful.lua
21
awful.lua
|
@ -17,6 +17,7 @@ end
|
||||||
-- Grab environment we need
|
-- Grab environment we need
|
||||||
local ipairs = ipairs
|
local ipairs = ipairs
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
|
local unpack = unpack
|
||||||
local awesome = awesome
|
local awesome = awesome
|
||||||
local screen = screen
|
local screen = screen
|
||||||
local client = client
|
local client = client
|
||||||
|
@ -26,8 +27,6 @@ local os = os
|
||||||
local table = table
|
local table = table
|
||||||
local hooks = hooks
|
local hooks = hooks
|
||||||
local keygrabber = keygrabber
|
local keygrabber = keygrabber
|
||||||
local print = print
|
|
||||||
local table = table
|
|
||||||
|
|
||||||
-- Reset env
|
-- Reset env
|
||||||
setfenv(1, P)
|
setfenv(1, P)
|
||||||
|
@ -303,6 +302,24 @@ end
|
||||||
P.hooks = {}
|
P.hooks = {}
|
||||||
P.myhooks = {}
|
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
|
for name, hook in pairs(hooks) do
|
||||||
if name ~= 'timer' then
|
if name ~= 'timer' then
|
||||||
P.hooks[name] = function (f)
|
P.hooks[name] = function (f)
|
||||||
|
|
280
tabulous.lua
280
tabulous.lua
|
@ -1,8 +1,11 @@
|
||||||
-----------------------------------------------
|
----------------------------------------------------
|
||||||
-- tabulous: Fabulous tabs for awesome --
|
-- tabulous: Fabulous tabs for awesome --
|
||||||
-- --
|
-- --
|
||||||
-- © 2008 Julien Danjou <julien@danjou.info> --
|
-- © 2008 Julien Danjou <julien@danjou.info> --
|
||||||
-----------------------------------------------
|
-- © 2008 Lucas de Vries <lucasdevries@gmail.com> --
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
require('awful')
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
-- Module loading --
|
-- Module loading --
|
||||||
|
@ -18,125 +21,218 @@ end
|
||||||
local client = client
|
local client = client
|
||||||
local table = table
|
local table = table
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local rawset = rawset
|
local awful = awful
|
||||||
local setmetatable = setmetatable
|
|
||||||
|
|
||||||
-- Reset env
|
-- Reset env
|
||||||
setfenv(1, P)
|
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 = {}
|
local tabbed = {}
|
||||||
|
|
||||||
-- Define a special index method.
|
awful.hooks.userhook_create('tabbed')
|
||||||
-- This is useful because we need to compare clients with __eq() to be sure
|
awful.hooks.userhook_create('untabbed')
|
||||||
-- that the key are identical. Otherwise Lua assume that each object is different.
|
awful.hooks.userhook_create('tabdisplay')
|
||||||
local function tabbed_index(table, key)
|
awful.hooks.userhook_create('tabhide')
|
||||||
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 })
|
|
||||||
|
|
||||||
---------------
|
---------------
|
||||||
-- Functions --
|
-- Functions --
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
-- Get the next tab
|
-- Find the key in a table
|
||||||
local function client_nexttab(s)
|
local function findkey(table, cl)
|
||||||
local sel = s or client.focus_get()
|
for i, c in pairs(table) do
|
||||||
if sel and tabbed[sel] then
|
if c == cl then
|
||||||
return tabbed[sel]
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get the previous tab
|
-- Check if the client is in the given tabindex
|
||||||
local function client_prevtab(c, stopc)
|
local function client_in_tabindex(tabindex, cl)
|
||||||
local sel = c or client.focus_get()
|
local c = cl or client.focus_get()
|
||||||
local stop = stopc or sel
|
return findkey(tabbed[tabindex], c)
|
||||||
if sel and tabbed[sel] then
|
end
|
||||||
if stop == tabbed[sel] then
|
|
||||||
return sel
|
-- 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
|
||||||
|
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
|
||||||
|
|
||||||
|
-- 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
|
else
|
||||||
return client_prevtab(tabbed[sel], stop)
|
return tabbed[tabindex][2][i+1]
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Tab a client with another one
|
-- Get the previous client in a tabdisplay
|
||||||
local function client_tab(c1, s)
|
local function client_prev(tabindex, cl)
|
||||||
local sel = s or client.focus_get()
|
local c = cl or tabbed[tabindex][1]
|
||||||
if c1 and sel and c1 ~= sel then
|
|
||||||
if tabbed[c1] then
|
local i = findkey(tabbed[tabindex][2], c)
|
||||||
tabbed[sel] = tabbed[c1]
|
|
||||||
tabbed[c1] = sel
|
if i == nil then
|
||||||
elseif tabbed[sel] then
|
return nil
|
||||||
tabbed[c1] = tabbed[sel]
|
end
|
||||||
tabbed[sel] = c1
|
|
||||||
|
if tabbed[tabindex][2][i-1] == nil then
|
||||||
|
return tabbed[tabindex][2][table.maxn(tabbed[tabindex][2])]
|
||||||
else
|
else
|
||||||
tabbed[c1] = sel
|
return tabbed[tabindex][2][i-1]
|
||||||
tabbed[sel] = c1
|
|
||||||
end
|
|
||||||
c1:hide()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Untab a client
|
-- Remove a client from a tabbed display
|
||||||
local function client_untab(c)
|
local function client_untab(cl)
|
||||||
local sel = c or client.focus_get()
|
local c = cl or client.focus_get()
|
||||||
if sel and tabbed[sel] then
|
local tabindex = client_find_tabindex(c)
|
||||||
local p = client_prevtab(sel)
|
if tabindex == nil then return false end
|
||||||
tabbed[p] = tabbed[sel]
|
|
||||||
tabbed[sel] = nil
|
local cindex = findkey(tabbed[tabindex][2], c)
|
||||||
p:unhide()
|
|
||||||
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Focus the next tab
|
-- Get all clients on a tabbed display
|
||||||
local function client_focusnexttab(s)
|
local function client_get_clients(tabindex)
|
||||||
local sel = s or client.focus_get()
|
return tabbed[tabindex][2]
|
||||||
local n = client_nexttab(sel)
|
|
||||||
if n then
|
|
||||||
sel:hide()
|
|
||||||
n:unhide()
|
|
||||||
n:focus_set()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Focus the previous tab
|
-- Get the displayed client on a tabbed display
|
||||||
local function client_focusprevtab(s)
|
local function client_get_displayed(tabindex)
|
||||||
local sel = s or client.focus_get()
|
return tabbed[tabindex][1]
|
||||||
local p = client_prevtab(sel)
|
|
||||||
if p then
|
|
||||||
sel:hide()
|
|
||||||
p:unhide()
|
|
||||||
p:focus_set()
|
|
||||||
end
|
|
||||||
end
|
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.tab = client_tab
|
||||||
P.untab = client_untab
|
P.untab = client_untab
|
||||||
P.focusnext = client_focusnexttab
|
P.untab_all = client_untab_all
|
||||||
P.focusprev = client_focusprevtab
|
|
||||||
P.next = client_nexttab
|
P.next = client_next
|
||||||
P.prev = client_prevtab
|
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
|
return P
|
||||||
|
|
Loading…
Reference in New Issue