diff --git a/awesomerc.lua.in b/awesomerc.lua.in index e0b3ae61..a8501de7 100644 --- a/awesomerc.lua.in +++ b/awesomerc.lua.in @@ -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 diff --git a/awful.lua b/awful.lua index af5c75ed..1a7d4880 100644 --- a/awful.lua +++ b/awful.lua @@ -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) diff --git a/tabulous.lua b/tabulous.lua index aa16404a..ad7c31ec 100644 --- a/tabulous.lua +++ b/tabulous.lua @@ -1,8 +1,11 @@ ------------------------------------------------ --- tabulous: Fabulous tabs for awesome -- --- -- --- © 2008 Julien Danjou -- ------------------------------------------------ +---------------------------------------------------- +-- tabulous: Fabulous tabs for awesome -- +-- -- +-- © 2008 Julien Danjou -- +-- © 2008 Lucas de Vries -- +---------------------------------------------------- + +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