Hello,

i reloaded tabulous from heaven.

The first patch is tabulous itself. The second one is a patch against
tasklist to display something like Tab[1/3] in the name of tabbed
client.

I wonder if awful.tab would be a better and standard name than tabulous.

I refactored tabulous and tried to cleanup the code at the maximum. I
removed the hook on tag. I cant find a utility to that one (was
unhidding client not in the first selected tag). Am I wrong?
Now the code support multiple tag.

The autotab_start feature seem's wrong when using teardrop for
example. I dont think it's the good way to implement it, as well as
the function was there before with the same implementation. I should I
get ride of it? (maybe this belong to a user modified rc.lua)

There is a little issues with tab, when switching from one tab to
another there is a little flickering and sometime focus is not on the
good client. I thing lua/c hacking is needed to remove it, and I dont
know Awesome so well to do that for now. Because now the following
happens:
--keep the client at the same place
cl:swap(p)
--ouch
cl.hidden = false
--double ouch
p.hidden = true
--Bang! (insert a little sleep here and the focus is always good)
capi.client.focus = cl


I would like to display a new tabbar upside the client window to
switch between each client in a tab, but I wonder if it would not be
better to wait for the $FS542 ? Titlebar seems a little broken in
HEAD.
From f5e9914753733b7f743e6553930f18637349dc5c Mon Sep 17 00:00:00 2001
From: Cedric GESTES <cta...@gmail.com>
Date: Fri, 28 Aug 2009 03:20:35 +0200
Subject: [PATCH] tabulous : fixed, improved and imported again

Signed-off-by: Cedric GESTES <cta...@gmail.com>
---
 lib/tabulous.lua.in |  384 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 384 insertions(+), 0 deletions(-)
 create mode 100644 lib/tabulous.lua.in

diff --git a/lib/tabulous.lua.in b/lib/tabulous.lua.in
new file mode 100644
index 0000000..e837f6b
--- /dev/null
+++ b/lib/tabulous.lua.in
@@ -0,0 +1,384 @@
+---------------------------------------------------------------------------
+-- @author Lucas de Vries &lt;lucasdevr...@gmail.com&gt;
+-- @author Julien Danjou &lt;jul...@danjou.info&gt;
+-- @author Cedric GESTES &lt;cta...@gmail.com&gt;
+-- @copyright 2008 Julien Danjou, Lucas de Vries
+-- @copyright 2009 Cedric GESTES
+-- @release @AWESOME_VERSION@
+---------------------------------------------------------------------------
+
+------------------------
+--- Samples keybindings:
+-- --- Tabulous, tab manipulation
+-- <code>
+--  globalkeys = awful.util.table.join(globalkeys,
+-- -- remove the focused client from the tab
+-- awful.key({ modkey, "Shift"   }, "y", tabulous.tab_remove),
+-- -- cycle through clients in a tab
+-- awful.key({ modkey,           }, "y", tabulous.tab_cycle),
+-- -- create a new tab and/or add the next client to the tab
+-- awful.key({ modkey, "Control" }, "y", tabulous.tab_add_next_client),
+-- -- create a tab from all marked clients
+-- awful.key({ modkey, 'Shift'   }, "t", tabulous.tab_create_from_marked)
+-- )
+-- </code>
+-- the autotab_start function can be used to append client to the current tab
+-- when a client is created and the current focused client is tabbed
+
+--------------------
+--- Emitted Signals:
+-- client:("tabbed")   when a client is added to a tab
+-- client:("untabbed") when a client is removed from a tab
+-- client:("tabhide")  when a client is hidden in a tab
+-- client:("tabshow")  when a client is shown in a tab
+
+--------------------------
+--- Possible Improvements:
+-- the tab_display function is not perfect (there is flickering)
+
+
+---------------------------------------------------------------------------
+local table             = table
+local pairs             = pairs
+local setmetatable      = setmetatable
+local aclient           = require("awful.client")
+local atag              = require("awful.tag")
+local util              = require("awful.util")
+
+local capi = {
+    client = client,
+}
+
+--- Fabulous tabs
+module("tabulous")
+
+-- the tabs table indexed by tabindex
+-- for each tab there is a tabs[x] there is:
+-- x is the tabindex
+-- tabs[x].active  is the active client in the tab
+-- tabs[x].clients is the list of clients in the tab
+local tabs      = {}
+
+
+------------------------------
+--     Client Helper        --
+------------------------------
+
+
+--- Check if the client is in the given tabindex.
+-- @param tabindex The tab index.
+-- @param cl The client
+-- @return The key.
+function client_index(tabindex, cl)
+    local c = cl or capi.client.focus
+    return util.table.hasitem(tabs[tabindex].clients, c)
+end
+
+--- Find the tab index or return nil if not tabs.
+-- @param cl The client to search.
+-- @return The tab index.
+function client_tabindex(cl)
+    local c = cl or capi.client.focus
+
+    for tabindex, tabdisplay in pairs(tabs) do
+        -- Loop through all tab displays
+        local me = client_index(tabindex, c)
+        if me ~= nil then
+            return tabindex
+        end
+    end
+    return nil
+end
+
+--- Get a client by tab number.
+-- @param tabindex The tab index.
+-- @param pos The position in the tab.
+-- @return The client at the given position.
+function client_get(tabindex, pos)
+    if tabs[tabindex] == nil then return nil end
+    return tabs[tabindex].clients[pos]
+end
+
+
+
+
+
+------------------------------
+--     Tab Handling         --
+------------------------------
+
+
+--- Create a new tabbed display with client as the master.
+-- @param cl The client to set into the tab, focused one otherwise.
+-- @return The created tab index.
+function tab_create(cl)
+    local c = cl or capi.client.focus
+
+    if not c then return end
+
+    local t = {}
+    t.active  = c
+    t.clients = { c }
+    table.insert(tabs, t)
+    c:emit_signal("tabbed")
+    return client_tabindex(c)
+end
+
+-- Get the number of client in a tab
+-- @param tabindex The tab index.
+-- @return the number of client in a tab
+function tab_count(tabindex)
+   if tabs[tabindex] == nil then
+      return 0
+   end
+   return table.getn(tabs[tabindex].clients)
+end
+
+--- Get all clients on a tabs display.
+-- @param tabindex The tab index.
+-- @return All tabs clients.
+function tab_clients(tabindex)
+    if tabs[tabindex] == nil then return nil end
+    return tabs[tabindex].clients
+end
+
+
+
+--- Get the displayed client on a tabs display.
+-- @param tabindex The tab index.
+-- @return The displayed client.
+function tab_current(tabindex)
+    if tabs[tabindex] == nil then return nil end
+    return tabs[tabindex].active
+end
+
+--- Get the next client in a tab display.
+-- @param tabindex The tab index.
+-- @param cl The current client.
+-- @return The next client.
+function tab_next(tabindex, cl)
+    local c = cl or tabs[tabindex].active
+    local i = util.table.hasitem(tabs[tabindex].clients, c)
+
+    if i == nil then
+        return nil
+    end
+    if tabs[tabindex].clients[i + 1] == nil then
+        return tabs[tabindex].clients[1]
+    end
+    return tabs[tabindex].clients[i + 1]
+end
+
+--- Get the previous client in a tabdisplay
+-- @param tabindex The tab index.
+-- @param cl The current client.
+-- @return The previous client.
+function tab_prev(tabindex, cl)
+    local c = cl or tabs[tabindex].active
+    local i = util.table.hasitem(tabs[tabindex].clients, c)
+
+    if i == nil then
+        return nil
+    end
+    if i == 1 then
+        return tabs[tabindex].clients[table.maxn(tabs[tabindex].clients)]
+    end
+    return tabs[tabindex].clients[i - 1]
+end
+
+--- Remove a client from a tabs display.
+-- @param cl The client to remove.
+-- @return True if the client has been untabs.
+function tab_remove(cl)
+    local c             = cl or capi.client.focus
+    local tabindex      = client_tabindex(c)
+
+    if tabindex == nil then
+        return false
+    end
+    local cindex = util.table.hasitem(tabs[tabindex].clients, c)
+    if tabs[tabindex].active == c then
+        tab_display(tabindex, tab_next(tabindex, c), false)
+    end
+    table.remove(tabs[tabindex].clients, cindex)
+    if table.maxn(tabs[tabindex].clients) == 0 then
+        -- Table is empty now, remove the tabs display
+        table.remove(tabs, tabindex)
+    end
+    c.hidden = false
+    c:emit_signal("untabbed")
+    return true
+end
+
+--- Untab all clients in a tabs display.
+-- @param tabindex The tab index.
+function tab_removeall(tabindex)
+    for i,c in pairs(tabs[tabindex].clients) do
+        c.hidden = false
+        c:emit_signal("untabbed")
+    end
+    if tabs[tabindex] ~= nil then
+        table.remove(tabs, tabindex)
+    end
+end
+
+--- Add a client to a tabs display.
+-- @param tabindex The tab index.
+-- @param cl The client to add, or the focused one otherwise.
+function tab_add(tabindex, cl)
+    local c = cl or capi.client.focus
+
+    if tabs[tabindex] == nil then
+        return
+    end
+    local x = client_tabindex(c)
+    if x == nil then
+        -- Add untabbed client to tabindex
+        table.insert(tabs[tabindex].clients, c)
+        tab_display(tabindex, c)
+        c:emit_signal("tabbed")
+    elseif x ~= tabindex then
+        -- Merge two tabbed views
+        local cc = tabs[tabindex].active
+        local clients = tab_clients(x)
+        tab_removeall(x)
+        tabindex = client_tabindex(cc)
+        for i,b in pairs(clients) do
+            tab_add(tabindex, b)
+        end
+    end
+end
+
+
+--- Swaand select which client in tab is displayed.
+-- @param tabindex The tab index.
+-- @param cl The client to show.
+-- this is not perfect in fact swap/hidden/hidden/focus should be done
+-- at the same time to avoid flicking
+function tab_display(tabindex, cl, swap)
+    local p = tabs[tabindex].active or cl
+    if cl and p ~= cl then
+        tabs[tabindex].active = cl
+
+        --dont swap when removing client
+        if swap ~= false then
+            cl:swap(p)
+        end
+        cl.hidden = false
+        p.hidden = true
+
+        p:emit_signal("tabhide")
+        cl:emit_signal("tabshow")
+        capi.client.focus = cl
+    end
+end
+
+
+--- Keep tabulous in sync when a client is focused but was hidden in a tab
+--  (show the client and hide the previous one)
+function tab_focus(cl)
+    local c = cl or awful.client.focus
+    local i = client_tabindex(c)
+
+    if i and tabs[i].active ~= c then
+        tab_display(i, c)
+    end
+end
+
+
+------------------------------
+--     Helper Function      --
+------------------------------
+
+
+
+--- cycle throught tab clients
+-- @param cl The client to that own the tab
+-- @param the way to cycle (-1 or 1)
+function tab_cycle(cl, idx)
+    local c = cl or capi.client.focus
+    local i = idx or 1
+    local tabview = client_tabindex(c)
+
+    if tabview == nil then
+        return
+    end
+    if i == 1 then
+        n = tab_next(tabview)
+    else
+        n = tab_prev(tabview)
+    end
+    tab_display(tabview, n)
+end
+
+
+--- create a tab or add the next focused client to the tab
+function tab_add_next_client()
+    local tabview    = client_tabindex()
+    local nextclient = aclient.next(1)
+
+    if not tabview then
+        tabview = client_tabindex(nextclient)
+
+        if not tabview then
+            tabview = tab_create()
+            tab_add(tabview, nextclient)
+        else
+            tab_add(tabview, capi.client.focus)
+        end
+    else
+        tab_add(tabview, nextclient)
+    end
+end
+
+--- create a new tab from all marked client
+function tab_create_from_marked()
+    local tabview       = client_tabindex()
+    local clients       = aclient.getmarked()
+
+    if not tabview then
+        tabview = tab_create(clients[1])
+        table.remove(clients, 1)
+    end
+
+    for k,c in pairs(clients) do
+        tab_add(tabview, c)
+    end
+end
+
+
+--- Start autotabbing, this automatically tabs new clients when the current
+-- client is tabbed.
+function autotab_start()
+    capi.client.add_signal("manage", function (c, startup)
+        local sel       = capi.client.focus
+        local index     = nil
+
+        --if the current client is already focused => get prev from history
+        if sel == c then
+            sel = aclient.focus.history.get(c.screen, 1)
+        end
+
+        index = client_tabindex(sel)
+
+        --do nothing on startup
+        if startup then
+            return
+        end
+        if index ~= nil then
+            -- Currently focused client is tabbed,
+            -- add the new window to the tabbed display
+            tab_add(index, c)
+        end
+    end)
+end
+
+
+-- Keep tabulous in sync when a client is focused but was hidden in a tab
+capi.client.add_signal("focus", tab_focus)
+
+-- rearrange the tab when a window is killed
+capi.client.add_signal("unmanage", tab_remove)
+
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
-- 
1.6.0.4

From b9b7b9ecb2563c30a9781b341ca27f931b07b7ba Mon Sep 17 00:00:00 2001
From: Cedric GESTES <cta...@gmail.com>
Date: Fri, 28 Aug 2009 02:52:48 +0200
Subject: [PATCH] tasklist : display Tab[i/c] in the name if the client is tabbed

Signed-off-by: Cedric GESTES <cta...@gmail.com>
---
 lib/awful/widget/tasklist.lua.in |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/lib/awful/widget/tasklist.lua.in b/lib/awful/widget/tasklist.lua.in
index 448a38d..ac70979 100644
--- a/lib/awful/widget/tasklist.lua.in
+++ b/lib/awful/widget/tasklist.lua.in
@@ -18,10 +18,17 @@ local client = require("awful.client")
 local util = require("awful.util")
 local tag = require("awful.tag")
 local layout = require("awful.widget.layout")
+local atab = require("tabulous")
+local tostring = tostring
 
 --- Tasklist widget module for awful
 module("awful.widget.tasklist")
 
+-- configuration
+display = {}
+display.tab = true
+
+
 -- Public structures
 label = {}
 
@@ -103,6 +110,15 @@ local function widget_tasklist_label_common(c, args)
     else
         name = util.escape(c.name) or util.escape("<untitled>")
     end
+
+    local tabidx = atab.client_tabindex(c)
+    if display.tab and tabidx then
+        local tabcount = atab.tab_count(tabidx)
+        local cidx = atab.client_index(tabidx, c) or 0
+        local tabtext = "Tab[" .. tostring(cidx) .. "/" .. tostring(tabcount) .. "] "
+        name = tabtext .. name
+    end
+
     if capi.client.focus == c then
         bg = bg_focus
         if fg_focus then
-- 
1.6.0.4

Reply via email to