tag.lua: move() re-index tags
[awesome.git] / lib / awful / tag.lua.in
blobe2dc3b5aadd1a06d170d5d6220ab409f2caa4e00
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2008 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
8 local util = require("awful.util")
9 local pairs = pairs
10 local ipairs = ipairs
11 local table = table
12 local setmetatable = setmetatable
13 local capi =
15 tag = tag,
16 screen = screen,
17 mouse = mouse,
18 client = client
21 --- Useful functions for tag manipulation.
22 module("awful.tag")
24 -- Private data
25 local data = {}
26 data.history = {}
27 data.tags = setmetatable({}, { __mode = 'k' })
29 -- History functions
30 history = {}
31 history.limit = 20
33 --- Move a tag to an absolute position in the screen[]:tags() table.
34 -- @param new_index Integer absolute position in the table to insert.
35 function move(new_index, target_tag)
36 local target_tag = target_tag or selected()
37 local scr = target_tag.screen
38 local tmp_tags = capi.screen[scr]:tags()
40 if (not new_index) or (new_index < 1) or (new_index > #tmp_tags) then
41 return
42 end
44 for i, t in ipairs(tmp_tags) do
45 if t == target_tag then
46 table.remove(tmp_tags, i)
47 break
48 end
49 end
51 table.insert(tmp_tags, new_index, target_tag)
52 capi.screen[scr]:tags(tmp_tags)
53 end
55 --- Create a set of tags and attach it to a screen.
56 -- @param names The tag name, in a table
57 -- @param screen The tag screen, or 1 if not set.
58 -- @param layout The layout or layout table to set for this tags by default.
59 -- @return A table with all created tags.
60 function new(names, screen, layout)
61 local screen = screen or 1
62 local tags = {}
63 for id, name in ipairs(names) do
64 tags[#tags + 1] = capi.tag { name = name }
65 tags[#tags].screen = screen
66 -- Select the first tag.
67 if id == 1 then
68 tags[#tags].selected = true
69 end
70 setproperty(tags[#tags], "layout", layout and (layout[#tags] or layout[1]) or layout)
71 end
72 return tags
73 end
75 --- Update the tag history.
76 -- @param obj Screen object.
77 function history.update(obj)
78 local s = obj.index
79 local curtags = capi.screen[s]:tags()
80 -- create history table
81 if not data.history[s] then
82 data.history[s] = {}
83 -- limit history
84 elseif #data.history[s] >= history.limit then
85 for i = history.limit, #data.history[s] do
86 data.history[s][i] = nil
87 end
88 end
89 -- store previously selected tags in the history table
90 table.insert(data.history[s], 1, data.history[s].current)
91 data.history[s].previous = data.history[s][1]
92 -- store currently selected tags
93 data.history[s].current = setmetatable(selectedlist(s), { __mode = 'v' })
94 end
96 --- Revert tag history.
97 -- @param screen The screen number.
98 -- @param idx Index in history. Defaults to "previous" which is a special index
99 -- toggling between last two selected sets of tags. Number (eg 1) will go back
100 -- to the given index in history.
101 function history.restore(screen, idx)
102 local s = screen or capi.mouse.screen
103 local i = idx or "previous"
104 local sel = selectedlist(s)
105 -- do nothing if history empty
106 if not data.history[s] or not data.history[s][i] then return end
107 -- if all tags been deleted, try next entry
108 if #data.history[s][i] == 0 then
109 if i == "previous" then i = 0 end
110 history.restore(s, i + 1)
111 return
113 -- deselect all tags
114 viewnone(s)
115 -- select tags from the history entry
116 for _, t in ipairs(data.history[s][i]) do
117 t.selected = true
119 -- update currently selected tags table
120 data.history[s].current = data.history[s][i]
121 -- store previously selected tags
122 data.history[s].previous = setmetatable(sel, { __mode = 'v' })
123 -- remove the reverted history entry
124 if i ~= "previous" then table.remove(data.history[s], i) end
127 --- Return a table with all visible tags
128 -- @param s Screen number.
129 -- @return A table with all selected tags.
130 function selectedlist(s)
131 local screen = s or capi.mouse.screen
132 local tags = capi.screen[screen]:tags()
133 local vtags = {}
134 for i, t in pairs(tags) do
135 if t.selected then
136 vtags[#vtags + 1] = t
139 return vtags
142 --- Return only the first visible tag.
143 -- @param s Screen number.
144 function selected(s)
145 return selectedlist(s)[1]
148 --- Set master width factor.
149 -- @param mwfact Master width factor.
150 function setmwfact(mwfact, t)
151 local t = t or selected()
152 if mwfact >= 0 and mwfact <= 1 then
153 setproperty(t, "mwfact", mwfact)
157 --- Increase master width factor.
158 -- @param add Value to add to master width factor.
159 function incmwfact(add, t)
160 setmwfact(getmwfact(t) + add)
163 --- Get master width factor.
164 -- @param t Optional tag.
165 function getmwfact(t)
166 local t = t or selected()
167 return getproperty(t, "mwfact") or 0.5
170 --- Set the number of master windows.
171 -- @param nmaster The number of master windows.
172 -- @param t Optional tag.
173 function setnmaster(nmaster, t)
174 local t = t or selected()
175 if nmaster >= 0 then
176 setproperty(t, "nmaster", nmaster)
180 --- Get the number of master windows.
181 -- @param t Optional tag.
182 function getnmaster(t)
183 local t = t or selected()
184 return getproperty(t, "nmaster") or 1
187 --- Increase the number of master windows.
188 -- @param add Value to add to number of master windows.
189 function incnmaster(add, t)
190 setnmaster(getnmaster(t) + add)
194 --- Set the tag icon
195 -- @param icon the icon to set, either path or image object
196 -- @param tag the tag
197 function seticon(icon, tag)
198 local tag = tag or selected()
199 setproperty(tag, "icon", icon)
202 --- Get the tag icon
203 -- @param t the tag
204 function geticon(tag)
205 local tag = tag or selected()
206 return getproperty(tag, "icon")
209 --- Set number of column windows.
210 -- @param ncol The number of column.
211 function setncol(ncol, t)
212 local t = t or selected()
213 if ncol >= 1 then
214 setproperty(t, "ncol", ncol)
218 --- Get number of column windows.
219 -- @param t Optional tag.
220 function getncol(t)
221 local t = t or selected()
222 return getproperty(t, "ncol") or 1
225 --- Increase number of column windows.
226 -- @param add Value to add to number of column windows.
227 function incncol(add, t)
228 setncol(getncol(t) + add)
231 --- View no tag.
232 -- @param Optional screen number.
233 function viewnone(screen)
234 local tags = capi.screen[screen or capi.mouse.screen]:tags()
235 for i, t in pairs(tags) do
236 t.selected = false
240 --- View a tag by its taglist index.
241 -- @param i The relative index to see.
242 -- @param screen Optional screen number.
243 function viewidx(i, screen)
244 local screen = screen and screen.index or capi.mouse.screen
245 local tags = capi.screen[screen]:tags()
246 local showntags = {}
247 for k, t in ipairs(tags) do
248 if not getproperty(t, "hide") then
249 table.insert(showntags, t)
252 local sel = selected(screen)
253 viewnone(screen)
254 for k, t in ipairs(showntags) do
255 if t == sel then
256 showntags[util.cycle(#showntags, k + i)].selected = true
259 capi.screen[screen]:emit_signal("tag::history::update")
262 --- View next tag. This is the same as tag.viewidx(1).
263 -- @param screen The screen number.
264 function viewnext(screen)
265 return viewidx(1, screen)
268 --- View previous tag. This is the same a tag.viewidx(-1).
269 -- @param screen The screen number.
270 function viewprev(screen)
271 return viewidx(-1, screen)
274 --- View only a tag.
275 -- @param t The tag object.
276 function viewonly(t)
277 local tags = capi.screen[t.screen]:tags()
278 -- First, untag everyone except the viewed tag.
279 for _, tag in pairs(tags) do
280 if tag ~= t then
281 tag.selected = false
284 -- Then, set this one to selected.
285 -- We need to do that in 2 operations so we avoid flickering and several tag
286 -- selected at the same time.
287 t.selected = true
288 capi.screen[t.screen]:emit_signal("tag::history::update")
291 --- View only a set of tags.
292 -- @param tags A table with tags to view only.
293 -- @param screen Optional screen number of the tags.
294 function viewmore(tags, screen)
295 local screen_tags = capi.screen[screen or capi.mouse.screen]:tags()
296 for _, tag in ipairs(screen_tags) do
297 if not util.table.hasitem(tags, tag) then
298 tag.selected = false
301 for _, tag in ipairs(tags) do
302 tag.selected = true
304 capi.screen[screen]:emit_signal("tag::history::update")
307 --- Toggle selection of a tag
308 -- @param tag Tag to be toggled
309 function viewtoggle(t)
310 t.selected = not t.selected
311 capi.screen[t.screen]:emit_signal("tag::history::update")
314 --- Get tag data table.
315 -- @param tag The Tag.
316 -- @return The data table.
317 function getdata(tag)
318 return data.tags[tag]
321 --- Get a tag property.
322 -- @param tag The tag.
323 -- @param prop The property name.
324 -- @return The property.
325 function getproperty(tag, prop)
326 if data.tags[tag] then
327 return data.tags[tag][prop]
331 --- Set a tag property.
332 -- This properties are internal to awful. Some are used to draw taglist, or to
333 -- handle layout, etc.
334 -- @param tag The tag.
335 -- @param prop The property name.
336 -- @param value The value.
337 function setproperty(tag, prop, value)
338 if not data.tags[tag] then
339 data.tags[tag] = {}
341 data.tags[tag][prop] = value
342 tag:emit_signal("property::" .. prop)
345 --- Tag a client with the set of current tags.
346 -- @param c The client to tag.
347 -- @param startup Optional: don't do anything if true.
348 function withcurrent(c, startup)
349 if startup ~= true and c.sticky == false then
350 if #c:tags() == 0 then
351 c:tags(selectedlist(c.screen))
356 local function attached_add_signal_screen(screen, sig, func)
357 capi.screen[screen]:add_signal("tag::attach", function (s, tag)
358 tag:add_signal(sig, func)
359 end)
360 capi.screen[screen]:add_signal("tag::detach", function (s, tag)
361 tag:remove_signal(sig, func)
362 end)
363 for _, tag in ipairs(capi.screen[screen]:tags()) do
364 tag:add_signal(sig, func)
368 --- Add a signal to all attached tag and all tag that will be attached in the
369 -- future. When a tag is detach from the screen, its signal is removed.
370 -- @param screen The screen concerned, or all if nil.
371 function attached_add_signal(screen, ...)
372 if screen then
373 attached_add_signal_screen(screen, ...)
374 else
375 for screen = 1, capi.screen.count() do
376 attached_add_signal_screen(screen, ...)
381 -- Register standards signals
382 capi.client.add_signal("manage", function(c, startup)
383 -- If we are not managing this application at startup,
384 -- move it to the screen where the mouse is.
385 -- We only do it for "normal" windows (i.e. no dock, etc).
386 if not startup
387 and c.type ~= "desktop"
388 and c.type ~= "dock"
389 and c.type ~= "splash" then
390 if c.transient_for then
391 c.screen = c.transient_for.screen
392 if not c.sticky then
393 c:tags(c.transient_for:tags())
395 else
396 c.screen = capi.mouse.screen
399 c:add_signal("property::screen", withcurrent)
400 end)
402 capi.client.add_signal("manage", withcurrent)
404 for s = 1, capi.screen.count() do
405 capi.screen[s]:add_signal("tag::history::update", history.update)
408 setmetatable(_M, { __call = function (_, ...) return new(...) end })
410 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80