lua: color pushlstring gets real len
[awesome.git] / lib / tabulous.lua.in
blobf3e34e9532f75608c70312776e4ac54358771309
1 ---------------------------------------------------------------------------
2 -- @author Lucas de Vries <lucasdevries@gmail.com>
3 -- @author Julien Danjou <julien@danjou.info>
4 -- @copyright 2008 Julien Danjou, Lucas de Vries
5 -- @release @AWESOME_VERSION@
6 ---------------------------------------------------------------------------
8 -- Grab environment we need
9 local capi = { client = client }
10 local table = table
11 local pairs = pairs
12 local awful = require('awful')
13 local otable = otable
15 --- tabulous: fabulous tabs for awesome
16 module("tabulous")
18 local tabbed_tags = otable() -- all tab tables, indexed by tab
19 local tabbed = {} -- the current tag tab table
21 local active_tag
23 -- Hook creation
24 awful.hooks.user.create('tabbed')
25 awful.hooks.user.create('untabbed')
26 awful.hooks.user.create('tabdisplay')
27 awful.hooks.user.create('tabhide')
29 ---------------
30 -- Functions --
31 ---------------
33 --- Find a key in a table.
34 -- @param table The table to look into
35 -- @param value The value to find.
36 -- @return The key or nil if not found.
37 function findkey(table, value)
38 for k, v in pairs(table) do
39 if v == value then
40 return k
41 end
42 end
43 end
45 --- Swaand select which client in tab is displayed.
46 -- @param tabindex The tab index.
47 -- @param cl The client to show.
48 function display(tabindex, cl)
49 local p = tabbed[tabindex][1]
50 if cl and p ~= cl then
51 tabbed[tabindex][1] = cl
53 cl.hide = false
54 cl:swap(p)
55 p.hide = true
56 capi.client.focus = cl
57 awful.hooks.user.call('tabhide', p)
58 awful.hooks.user.call('tabdisplay', cl)
59 end
60 end
62 --- Check if the client is in the given tabindex.
63 -- @param tabindex The tab index.
64 -- @param cl The client
65 -- @return The key.
66 function tabindex_check(tabindex, cl)
67 local c = cl or capi.client.focus
68 return findkey(tabbed[tabindex][2], c)
69 end
71 --- Find the tab index or return nil if not tabbed.
72 -- @param cl The client to search.
73 -- @return The tab index.
74 function tabindex_get(cl)
75 local c = cl or capi.client.focus
77 for tabindex, tabdisplay in pairs(tabbed) do
78 -- Loop through all tab displays
79 local me = tabindex_check(tabindex, c)
81 if me ~= nil then
82 return tabindex
83 end
84 end
86 return nil
87 end
89 --- Get all clients on a tabbed display.
90 -- @param tabindex The tab index.
91 -- @return All tabbed clients.
92 function clients_get(tabindex)
93 if tabbed[tabindex] == nil then return nil end
94 return tabbed[tabindex][2]
95 end
97 --- Get the displayed client on a tabbed display.
98 -- @param tabindex The tab index.
99 -- @return The displayed client.
100 function displayed_get(tabindex)
101 if tabbed[tabindex] == nil then return nil end
102 return tabbed[tabindex][1]
105 --- Get a client by tab number.
106 -- @param tabindex The tab index.
107 -- @param pos The position in the tab.
108 -- @return The client at the given position.
109 function position_get(tabindex, pos)
110 if tabbed[tabindex] == nil then return nil end
111 return tabbed[tabindex][2][pos]
114 --- Get the next client in a tab display.
115 -- @param tabindex The tab index.
116 -- @param cl The current client.
117 -- @return The next client.
118 function next(tabindex, cl)
119 local c = cl or tabbed[tabindex][1]
121 local i = findkey(tabbed[tabindex][2], c)
123 if i == nil then
124 return nil
127 if tabbed[tabindex][2][i+1] == nil then
128 return tabbed[tabindex][2][1]
131 return tabbed[tabindex][2][i + 1]
134 --- Get the previous client in a tabdisplay
135 -- @param tabindex The tab index.
136 -- @param cl The current client.
137 -- @return The previous client.
138 function prev(tabindex, cl)
139 local c = cl or tabbed[tabindex][1]
141 local i = findkey(tabbed[tabindex][2], c)
143 if i == nil then
144 return nil
147 if tabbed[tabindex][2][i-1] == nil then
148 return tabbed[tabindex][2][table.maxn(tabbed[tabindex][2])]
151 return tabbed[tabindex][2][i - 1]
154 --- Remove a client from a tabbed display.
155 -- @param cl The client to remove.
156 -- @return True if the client has been untabbed.
157 function untab(cl)
158 local c = cl or capi.client.focus
159 local tabindex = tabindex_get(c)
161 if tabindex == nil then return false end
163 local cindex = findkey(tabbed[tabindex][2], c)
165 if tabbed[tabindex][1] == c then
166 display(tabindex, next(tabindex, c))
169 table.remove(tabbed[tabindex][2], cindex)
171 if table.maxn(tabbed[tabindex][2]) == 0 then
172 -- Table is empty now, remove the tabbed display
173 table.remove(tabbed, tabindex)
176 c.hide = false
177 awful.hooks.user.call('untabbed', c)
180 --- Untab all clients in a tabbed display.
181 -- @param tabindex The tab index.
182 function untab_all(tabindex)
183 for i,c in pairs(tabbed[tabindex][2]) do
184 c.hide = false
185 awful.hooks.user.call('untabbed', c)
188 if tabbed[tabindex] ~= nil then
189 table.remove(tabbed, tabindex)
193 --- Create a new tabbed display with client as the master.
194 -- @param cl The client to set into the tab, focused one otherwise.
195 -- @return The created tab index.
196 function tab_create(cl)
197 local c = cl or capi.client.focus
199 if not c then return end
201 table.insert(tabbed, {
202 c, -- Window currently being displayed
203 { c } -- List of windows in tabbed display
206 awful.hooks.user.call('tabbed', c)
207 return tabindex_get(c)
210 --- Add a client to a tabbed display.
211 -- @param tabindex The tab index.
212 -- @param cl The client to add, or the focused one otherwise.
213 function tab(tabindex, cl)
214 local c = cl or capi.client.focus
216 if tabbed[tabindex] ~= nil then
217 local x = tabindex_get(c)
219 if x == nil then
220 -- Add untabbed client to tabindex
221 table.insert(tabbed[tabindex][2], c)
222 display(tabindex, c)
224 awful.hooks.user.call('tabbed', c)
225 elseif x ~= tabindex then
226 -- Merge two tabbed views
227 local cc = tabbed[tabindex][1]
228 local clients = clients_get(x)
229 untab_all(x)
231 tabindex = tabindex_get(cc)
233 for i,b in pairs(clients) do
234 tab(tabindex, b)
240 --- Start autotabbing, this automatically tabs new clients when the current
241 -- client is tabbed.
242 function autotab_start()
243 awful.hooks.manage.register(function (c)
244 local sel = capi.client.focus
245 local index = tabindex_get(sel)
247 if index ~= nil then
248 -- Currently focussed client is tabbed,
249 -- add the new window to the tabbed display
250 tab(index, c)
252 end)
255 --- Update the tabbing when current tags changes, by unactivating
256 -- all tabs that are not in the current tag (and activating the good one)
257 function update_tabbing()
258 -- do nothing if nothing changed
259 if active_tag == awful.tag.selected() then return end
261 -- needed for initialisation
262 active_tag = active_tag or awful.tag.selected()
264 -- save the tabbed list for the old active tag
265 tabbed_tags[active_tag] = tabbed
267 -- update the active tag and switch to the new tabbed list
268 active_tag = awful.tag.selected()
269 tabbed = tabbed_tags[active_tag] or {}
271 -- update show/hide on the clients
272 for tag,tabs in pairs(tabbed_tags) do
273 if tag == active_tag then
274 -- hide all clients that are not tab masters
275 for i,tab in pairs(tabs) do
276 for i,c in pairs(tab[2]) do
277 c.hide = true
279 tab[1].hide = false
281 else
282 -- unhide all clients
283 for i,tab in pairs(tabs) do
284 for i,c in pairs(tab[2]) do
285 c.hide = false
292 --- Keep tabulous in sync when a client is focused but was hidden in a tab
293 -- (show the client and hide the previous one)
294 function hook_focus(cl)
295 local c = cl or awful.client.focus
296 local i = tabindex_get(c)
297 if i and tabbed[i][1] ~= c then
298 display(i, c)
302 -- Keep tabulous in sync when focus change
303 awful.hooks.focus.register(hook_focus)
304 -- update the tabbing when the tags changes
305 awful.hooks.arrange.register(update_tabbing)
307 -- Set up hook so we don't leave lost hidden clients
308 awful.hooks.unmanage.register(untab)
311 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80