awful: implement tag history
[awesome.git] / lib / awful.lua.in
blob11211438231c10eb93f78a7be401445d7631a2df
1 -----------------------------------------------
2 -- awful: AWesome Function very UsefuL --
3 -- Common useful awesome functions --
4 -- --
5 -- © 2008 Julien Danjou <julien@danjou.info> --
6 -----------------------------------------------
8 -- We usually are required as 'awful'
9 -- But that can be changed.
10 local P = {} -- package
11 if _REQUIREDNAME == nil then
12 awful = P
13 else
14 _G[_REQUIREDNAME] = P
15 end
17 -- Grab environment we need
18 local string = string
19 local assert = assert
20 local loadstring = loadstring
21 local ipairs = ipairs
22 local pairs = pairs
23 local unpack = unpack
24 local awesome = awesome
25 local screen = screen
26 local client = client
27 local tag = tag
28 local mouse = mouse
29 local titlebar = titlebar
30 local widget = widget
31 local os = os
32 local table = table
33 local hooks = hooks
34 local keygrabber = keygrabber
35 local io = io
37 -- Reset env
38 setfenv(1, P)
40 P.hooks = {}
41 P.myhooks = {}
42 P.prompt = {}
43 P.completion = {}
44 P.screen = {}
45 P.layout = {}
46 P.client = {}
47 P.tag = {}
48 P.tag.history = {}
49 P.tag.history.data = {}
50 P.tag.history.data.past = {}
51 P.tag.history.data.current = {}
52 P.titlebar = {}
53 P.widget = {}
54 P.widget.taglist = {}
55 P.widget.taglist.label = {}
56 P.widget.tasklist = {}
57 P.widget.tasklist.label = {}
59 --- Create a new userhook (for external libs).
60 -- @param name Hook name.
61 local function userhook_create(name)
62 P.myhooks[name] = {}
63 P.hooks[name] = function (f)
64 table.insert(P.myhooks[name], { callback = f })
65 end
66 end
68 --- Call a created userhook (for external libs).
69 -- @param name Hook name.
70 local function userhook_call(name, args)
71 for i, o in pairs(P.myhooks[name]) do
72 P.myhooks[name][i]['callback'](unpack(args))
73 end
74 end
76 --- Make i cycle.
77 -- @param t A length.
78 -- @param i An absolute index to fit into #t.
79 -- @return The object at new index.
80 local function cycle(t, i)
81 while i > t do i = i - t end
82 while i < 1 do i = i + t end
83 return i
84 end
86 --- Get a client by its relative index to the focused window.
87 -- @usage Set i to 1 to get next, -1 to get previous.
88 -- @param i The index.
89 -- @param c Optional client.
90 -- @return A client, or nil if no client is available.
91 function P.client.next(i, c)
92 -- Get currently focused client
93 local sel = c or client.focus_get()
94 if sel then
95 -- Get all visible clients
96 local cls = client.visible_get(sel.screen)
97 -- Loop upon each client
98 for idx, c in ipairs(cls) do
99 if c == sel then
100 -- Cycle
101 return cls[cycle(#cls, idx +i)]
107 --- Focus a client by its relative index.
108 -- @param i The index.
109 -- @param c Optional client.
110 function P.client.focus(i, c)
111 local target = P.client.next(i, c)
112 if target then
113 target:focus_set()
117 --- Swap a client by its relative index.
118 -- @param i The index.
119 -- @param c Optional client, otherwise focused one is used.
120 function P.client.swap(i, c)
121 local sel = c or client.focus_get()
122 local target = P.client.next(i, sel)
123 if target then
124 target:swap(sel)
128 --- Get the master window
129 -- @param screen Optional screen number, otherwise screen mouse is used.
130 -- @return The master window.
131 function P.client.master(screen)
132 local s = screen or mouse.screen
133 return client.visible_get(s)[1]
136 --- Move/resize a client relative to current coordinates.
137 -- @param x The relative x coordinate.
138 -- @param y The relative y coordinate.
139 -- @param w The relative width.
140 -- @param h The relative height.
141 -- @param c The optional client, otherwise focused one is used.
142 function P.client.moveresize(x, y, w, h, c)
143 local sel = c or client.focus_get()
144 local coords = sel.coords
145 coords['x'] = coords['x'] + x
146 coords['y'] = coords['y'] + y
147 coords['width'] = coords['width'] + w
148 coords['height'] = coords['height'] + h
149 sel.coords = coords
152 --- Maximize a client to use the full workspace area.
153 -- @param c A client, or the focused one if nil.
154 function P.client.maximize(c)
155 local sel = c or client.focus_get()
156 if sel then
157 sel.floating = true
158 local ws = screen.workspace_get(sel.screen)
159 ws.width = ws.width - 2 * sel.border_width
160 ws.height = ws.height - 2 * sel.border_width
161 sel.coords = ws
165 --- Give the focus to a screen, and move pointer.
166 -- @param Screen number.
167 function P.screen.focus(i)
168 local sel = client.focus_get()
169 local s
170 if sel then
171 s = sel.screen
172 else
173 s = mouse.screen
175 s = cycle(screen.count(), s + i)
176 screen.focus(s)
177 -- Move the mouse on the screen
178 mouse.coords = screen.coords_get(s)
181 --- Compare 2 tables of tags.
182 -- @param a The first table.
183 -- @param b The second table of tags.
184 -- @return True if the tables are identical, false otherwise.
185 local function tag_compare_select(a, b)
186 if not a or not b then
187 return false
189 -- Quick size comparison
190 if #a ~= #b then
191 return false
193 for ka, va in pairs(a) do
194 if b[ka] ~= va.selected then
195 return false
198 for kb, vb in pairs(b) do
199 if a[kb].selected ~= vb then
200 return false
203 return true
206 --- Update the tag history.
207 -- @param screen The screen number.
208 function P.tag.history.update(screen)
209 local curtags = tag.geti(screen)
210 if not tag_compare_select(curtags, P.tag.history.data.current[screen]) then
211 P.tag.history.data.past[screen] = P.tag.history.data.current[screen]
212 P.tag.history.data.current[screen] = {}
213 for k, v in ipairs(curtags) do
214 P.tag.history.data.current[screen][k] = v.selected
219 -- Revert tag history.
220 -- @param screen The screen number.
221 function P.tag.history.restore(screen)
222 local s = screen or mouse.screen
223 local tags = tag.geti(s)
224 for k, t in pairs(tags) do
225 t.selected = P.tag.history.data.past[s][k]
229 --- Return a table with all visible tags
230 -- @param s Screen number.
231 -- @return A table with all selected tags.
232 function P.tag.selectedlist(s)
233 local screen = s or mouse.screen
234 local tags = tag.geti(screen)
235 local vtags = {}
236 for i, t in pairs(tags) do
237 if t.selected then
238 vtags[#vtags + 1] = t
241 return vtags
244 --- Return only the first visible tag.
245 -- @param s Screen number.
246 function P.tag.selected(s)
247 return P.tag.selectedlist(s)[1]
250 --- Set master width factor.
251 -- @param mwfact Master width factor.
252 function P.tag.setmwfact(mwfact)
253 local t = P.tag.selected()
254 if t then
255 t.mwfact = mwfact
259 --- Increase master width factor.
260 -- @param add Value to add to master width factor.
261 function P.tag.incmwfact(add)
262 local t = P.tag.selected()
263 if t then
264 t.mwfact = t.mwfact + add
268 --- Set the number of master windows.
269 -- @param nmaster The number of master windows.
270 function P.tag.setnmaster(nmaster)
271 local t = P.tag.selected()
272 if t then
273 t.nmaster = nmaster
277 --- Increase the number of master windows.
278 -- @param add Value to add to number of master windows.
279 function P.tag.incnmaster(add)
280 local t = P.tag.selected()
281 if t then
282 t.nmaster = t.nmaster + add
286 --- Set number of column windows.
287 -- @param ncol The number of column.
288 function P.tag.setncol(ncol)
289 local t = P.tag.selected()
290 if t then
291 t.ncol = ncol
295 --- Increase number of column windows.
296 -- @param add Value to add to number of column windows.
297 function P.tag.incncol(add)
298 local t = P.tag.selected()
299 if t then
300 t.ncol = t.ncol + add
304 --- View no tag.
305 -- @param Optional screen number.
306 function P.tag.viewnone(screen)
307 local tags = tag.get(screen or mouse.screen)
308 for i, t in pairs(tags) do
309 t.selected = false
313 --- View a tag by its index.
314 -- @param i The relative index to see.
315 -- @param screen Optional screen number.
316 function P.tag.viewidx(i, screen)
317 local tags = tag.geti(screen or mouse.screen)
318 local sel = P.tag.selected()
319 P.tag.viewnone()
320 for k, t in ipairs(tags) do
321 if t == sel then
322 tags[cycle(#tags, k + i)].selected = true
327 --- View next tag. This is the same as tag.viewidx(1).
328 function P.tag.viewnext()
329 return P.tag.viewidx(1)
332 --- View previous tag. This is the same a tag.viewidx(-1).
333 function P.tag.viewprev()
334 return P.tag.viewidx(-1)
337 --- View only a tag.
338 -- @param t The tag object.
339 function P.tag.viewonly(t)
340 P.tag.viewnone()
341 t.selected = true
344 --- View only a set of tags.
345 -- @param tags A table with tags to view only.
346 -- @param screen Optional screen number of the tags.
347 function P.tag.viewmore(tags, screen)
348 P.tag.viewnone(screen)
349 for i, t in pairs(tags) do
350 t.selected = true
354 --- Move a client to a tag.
355 -- @param target The tag to move the client to.
356 -- @para c Optional client to move, otherwise the focused one is used.
357 function P.client.movetotag(target, c)
358 local sel = c or client.focus_get();
359 -- Check that tag and client screen are identical
360 if sel.screen ~= target.screen then return end
361 local tags = tag.get(sel.screen)
362 for k, t in pairs(tags) do
363 sel:tag(t, false)
365 sel:tag(target, true)
368 --- Toggle a tag on a client.
369 -- @param target The tag to toggle.
370 -- @param c Optional client to toggle, otherwise the focused one is used.
371 function P.client.toggletag(target, c)
372 local sel = c or client.focus_get();
373 -- Check that tag and client screen are identical
374 if sel.screen ~= target.screen then return end
375 local toggle = false
376 if sel then
377 -- Count how many tags has the client
378 -- an only toggle tag if the client has at least one tag other than target
379 for k, v in pairs(tag.get(sel.screen)) do
380 if target ~= v and sel:istagged(v) then
381 toggle = true
382 break
385 if toggle then
386 sel:tag(target, not sel:istagged(target))
391 --- Toggle the floating status of a client.
392 -- @param c Optional client, the focused on if not set.
393 function P.client.togglefloating(c)
394 local sel = c or client.focus_get();
395 if sel then
396 sel.floating = not sel.floating
400 --- Move a client to a screen. Default is next screen, cycling.
401 -- @param c The client to move.
402 -- @param s The screen number, default to current + 1.
403 function P.client.movetoscreen(c, s)
404 local sel = c or client.focus_get();
405 if sel then
406 local sc = screen.count()
407 if not s then
408 s = sel.screen + 1
410 if s > sc then s = 1 elseif s < 1 then s = sc end
411 sel.screen = s
412 mouse.coords = screen.coords_get(s)
413 sel:focus_set()
417 --- Get the current layout name.
418 -- @param screen The screen number.
419 function P.layout.get(screen)
420 local t = P.tag.selected(screen)
421 if t then
422 return t.layout
426 -- Just set an awful mark to a client to move it later.
427 local awfulmarked = {}
428 userhook_create('marked')
429 userhook_create('unmarked')
431 --- Mark a client, and then call 'marked' hook.
432 -- @param c The client to mark, the focused one if not specified.
433 -- @return True if the client has been marked. False if the client was already marked.
434 function P.client.mark (c)
435 local cl = c or client.focus_get()
436 if cl then
437 for k, v in pairs(awfulmarked) do
438 if cl == v then
439 return false
443 table.insert(awfulmarked, cl)
445 -- Call callback
446 userhook_call('marked', {cl})
447 return true
451 --- Unmark a client and then call 'unmarked' hook.
452 -- @param c The client to unmark, or the focused one if not specified.
453 -- @return True if the client has been unmarked. False if the client was not marked.
454 function P.client.unmark(c)
455 local cl = c or client.focus_get()
457 for k, v in pairs(awfulmarked) do
458 if cl == v then
459 table.remove(awfulmarked, k)
460 userhook_call('unmarked', {cl})
461 return true
465 return false
468 --- Check if a client is marked.
469 -- @param c The client to check, or the focused one otherwise.
470 function P.client.ismarked(c)
471 local cl = c or client.focus_get()
472 if cl then
473 for k, v in pairs(awfulmarked) do
474 if cl == v then
475 return true
479 return false
482 --- Toggle a client as marked.
483 -- @param c The client to toggle mark.
484 function P.client.togglemarked(c)
485 local cl = c or client.focus_get()
487 if not P.client.mark(c) then
488 P.client.unmark(c)
492 --- Return the marked clients and empty the marked table.
493 -- @return A table with all marked clients.
494 function P.client.getmarked()
495 for k, v in pairs(awfulmarked) do
496 userhook_call('unmarked', {v})
499 t = awfulmarked
500 awfulmarked = {}
501 return t
504 --- Change the layout of the current tag.
505 -- @param layouts A table of layouts.
506 -- @param i Relative index.
507 function P.layout.inc(layouts, i)
508 local t = P.tag.selected()
509 local number_of_layouts = 0
510 local rev_layouts = {}
511 for i, v in ipairs(layouts) do
512 rev_layouts[v] = i
513 number_of_layouts = number_of_layouts + 1
515 if t then
516 local cur_layout = layout.get()
517 local new_layout_index = (rev_layouts[cur_layout] + i) % number_of_layouts
518 if new_layout_index == 0 then
519 new_layout_index = number_of_layouts
521 t.layout = layouts[new_layout_index]
525 --- Set the layout of the current tag by name.
526 -- @param layout Layout name.
527 function P.layout.set(layout)
528 local t = P.tag.selected()
529 if t then
530 t.layout = layout
534 P.hooks['userhook_create'] = userhook_create
535 P.hooks['userhook_call'] = userhook_call
537 for name, hook in pairs(hooks) do
538 if name ~= 'timer' then
539 P.hooks[name] = function (f)
541 if P.myhooks[name] == nil then
542 P.myhooks[name] = {}
543 hooks[name](function (...)
545 for i, o in pairs(P.myhooks[name]) do
546 P.myhooks[name][i]['callback'](...)
549 end)
552 table.insert(P.myhooks[name], {callback = f})
554 else
555 P.hooks[name] = function (time, f, runnow)
557 if P.myhooks[name] == nil then
558 P.myhooks[name] = {}
559 hooks[name](1, function (...)
561 for i,o in pairs(P.myhooks[name]) do
562 if P.myhooks[name][i]['counter'] >= P.myhooks[name][i]['timer'] then
563 P.myhooks[name][i]['counter'] = 1
564 P.myhooks[name][i]['callback'](...)
565 else
566 P.myhooks[name][i]['counter'] = P.myhooks[name][i]['counter']+1
570 end)
573 if runnow then
574 table.insert(P.myhooks[name], {callback = f, timer = time, counter = time})
575 else
576 table.insert(P.myhooks[name], {callback = f, timer = time, counter = 0})
582 --- Spawn a program.
583 -- @param cmd The command.
584 -- @return The os.execute() return value.
585 function P.spawn(cmd)
586 return os.execute(cmd .. "&")
589 --- Eval Lua code.
590 -- @return The return value of Lua code.
591 function P.eval(s)
592 return assert(loadstring("return " .. s))()
595 --- Use bash completion system to complete command and filename.
596 -- @param command The command line.
597 -- @param cur_pos The cursor position.
598 -- @paran ncomp The element number to complete.
599 -- @return The new commande and the new cursor position.
600 function P.completion.bash(command, cur_pos, ncomp)
601 local wstart = 1
602 local wend = 1
603 local words = {}
604 local cword_index = 0
605 local cword_start = 0
606 local cword_end = 0
607 local i = 1
608 local comptype = "file"
610 -- do nothing if we are on a letter, i.e. not at len + 1 or on a space
611 if cur_pos ~= #command + 1 and command:sub(cur_pos, cur_pos) ~= " " then
612 return command, cur_pos
613 elseif #command == 0 then
614 return command, cur_pos
617 while wend <= #command do
618 wend = command:find(" ", wstart)
619 if not wend then wend = #command + 1 end
620 table.insert(words, command:sub(wstart, wend - 1))
621 if cur_pos >= wstart and cur_pos <= wend + 1 then
622 cword_start = wstart
623 cword_end = wend
624 cword_index = i
626 wstart = wend + 1
627 i = i + 1
630 if cword_index == 1 then
631 comptype = "command"
634 local c = io.popen("/usr/bin/env bash -c 'compgen -A " .. comptype .. " " .. words[cword_index] .. "'")
635 local output = {}
636 i = 0
637 while true do
638 local line = c:read("*line")
639 if not line then break end
640 table.insert(output, line)
643 c:close()
645 -- no completion, return
646 if #output == 0 then
647 return command, cur_pos
650 -- cycle
651 while ncomp > #output do
652 ncomp = ncomp - #output
655 local str = command:sub(1, cword_start - 1) .. output[ncomp] .. command:sub(cword_end)
656 cur_pos = cword_end + #output[ncomp] + 1
658 return str, cur_pos
661 --- Draw the prompt text with a cursor.
662 -- @param text The text.
663 -- @param text_color The text color.
664 -- @param cursor_color The cursor color.
665 -- @param cursor_pos The cursor position.
666 local function prompt_text_with_cursor(text, text_color, cursor_color, cursor_pos)
667 local char
668 if not text then text = "" end
669 if #text < cursor_pos then
670 char = " "
671 else
672 char = escape(text:sub(cursor_pos, cursor_pos))
674 local text_start = escape(text:sub(1, cursor_pos - 1))
675 local text_end = escape(text:sub(cursor_pos + 1))
676 return text_start .. "<span background=\"" .. cursor_color .. "\" foreground=\"" .. text_color .. "\">" .. char .. "</span>" .. text_end
679 --- Run a prompt in a box.
680 -- @param args A table with optional arguments: cursor_fg, cursor_bg, prompt.
681 -- @param textbox The textbox to use for the prompt.
682 -- @param exe_callback The callback function to call with command as argument when finished.
683 -- @param completion_callback The callback function to call to get completion.
684 function P.prompt(args, textbox, exe_callback, completion_callback)
685 if not args then return end
686 local command = ""
687 local command_before_comp
688 local cur_pos_before_comp
689 local prompt = args.prompt or ""
690 local inv_col = args.cursor_fg or "black"
691 local cur_col = args.cursor_bg or "white"
692 -- The cursor position
693 local cur_pos = 1
694 -- The completion element to use on completion request.
695 local ncomp = 1
696 if not textbox or not exe_callback then
697 return
699 textbox.text = prompt .. prompt_text_with_cursor(text, inv_col, cur_col, cur_pos)
700 keygrabber.run(
701 function (mod, key)
702 local has_ctrl = false
704 -- Compute modifiers keys
705 for k, v in ipairs(mod) do
706 if v == "Control" then has_ctrl = true end
709 -- Get out cases
710 if has_ctrl then
711 if key == "g" then
712 textbox.text = ""
713 return false
715 else
716 if key == "Return" then
717 textbox.text = ""
718 exe_callback(command)
719 return false
720 elseif key == "Escape" then
721 textbox.text = ""
722 return false
726 -- Control cases
727 if has_ctrl then
728 if key == "a" then
729 cur_pos = 1
730 elseif key == "e" then
731 cur_pos = #command + 1
732 elseif key == "w" then
733 local wstart = 1
734 local wend = 1
735 local cword_start = 1
736 local cword_end = 1
737 while wend < cur_pos do
738 wend = command:find(" ", wstart)
739 if not wend then wend = #command + 1 end
740 if cur_pos >= wstart and cur_pos <= wend + 1 then
741 cword_start = wstart
742 cword_end = cur_pos - 1
743 break
745 wstart = wend + 1
747 command = command:sub(1, cword_start - 1) .. command:sub(cword_end + 1)
748 cur_pos = cword_start
750 else
751 if completion_callback then
752 -- That's tab
753 if key:byte() == 9 then
754 if ncomp == 1 then
755 command_before_comp = command
756 cur_pos_before_comp = cur_pos
758 command, cur_pos = completion_callback(command_before_comp, cur_pos_before_comp, ncomp)
759 ncomp = ncomp + 1
760 key = ""
761 else
762 ncomp = 1
766 -- Typin cases
767 if key == "Home" then
768 cur_pos = 1
769 elseif key == "End" then
770 cur_pos = #command + 1
771 elseif key == "BackSpace" then
772 if cur_pos > 1 then
773 command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
774 cur_pos = cur_pos - 1
776 -- That's DEL
777 elseif key:byte() == 127 then
778 command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
779 elseif key == "Left" then
780 cur_pos = cur_pos - 1
781 elseif key == "Right" then
782 cur_pos = cur_pos + 1
783 else
784 -- len() is UTF-8 aware but #key is not,
785 -- so check that we have one UTF-8 char but advance the cursor of # position
786 if key:len() == 1 then
787 command = command:sub(1, cur_pos - 1) .. key .. command:sub(cur_pos)
788 cur_pos = cur_pos + #key
791 if cur_pos < 1 then
792 cur_pos = 1
793 elseif cur_pos > #command + 1 then
794 cur_pos = #command + 1
798 -- Update textbox
799 textbox.text = prompt .. prompt_text_with_cursor(command, inv_col, cur_col, cur_pos)
801 return true
802 end)
805 --- Escape a string from XML char.
806 -- Useful to set raw text in textbox.
807 -- @param text Text to escape.
808 -- @return Escape text.
809 function P.escape(text)
810 text = text:gsub("&", "&amp;")
811 text = text:gsub("<", "&lt;")
812 text = text:gsub(">", "&gt;")
813 text = text:gsub("'", "&apos;")
814 text = text:gsub("\"", "&quot;")
815 return text
818 --- Unescape a string from entities.
819 -- @param text Text to unescape.
820 -- @return Unescaped text.
821 function P.unescape(text)
822 text = text:gsub("&amp;", "&")
823 text = text:gsub("&lt;", "<")
824 text = text:gsub("&gt;", ">")
825 text = text:gsub("&apos;", "'")
826 text = text:gsub("&quot;", "\"")
827 return text
830 --- Return labels for a taglist widget with all tag from screen.
831 -- It returns the tag name and set a special
832 -- foreground and background color for selected tags.
833 -- @param t The tag.
834 -- @param bg_focus The background color for selected tag.
835 -- @param fg_focus The foreground color for selected tag.
836 -- @return A string to print.
837 function P.widget.taglist.label.all(t, bg_focus, fg_focus)
838 local text = ""
839 local background = ""
840 local sel = client.focus_get()
841 if sel and sel:istagged(t) then
842 background = "resize=\"true\" image=\"@AWESOME_ICON_PATH@/taglist/squarefw.png\""
843 else
844 for k, c in pairs(client.get()) do
845 if c:istagged(t) then
846 background = "resize=\"true\" image=\"@AWESOME_ICON_PATH@/taglist/squarew.png\""
847 break
851 if t.selected then
852 text = "<bg "..background.." color='"..bg_focus.."'/> <span color='"..fg_focus.."'>"..P.escape(t.name).."</span> "
853 else
854 text = " <bg "..background.." />"..P.escape(t.name).." "
856 return text
859 local function widget_tasklist_label_common(c, bg_focus, fg_focus)
860 local text = ""
861 if c.floating then
862 text = "<bg image=\"@AWESOME_ICON_PATH@/tasklist/floatingw.png\" align=\"right\"/>"
864 if client.focus_get() == c then
865 text = text .. " <bg color='"..bg_focus.."'/><span color='"..fg_focus.."'>"..P.escape(c.name).."</span> "
866 else
867 text = text .. " "..P.escape(c.name).." "
869 return text
872 --- Return labels for a tasklist widget with clients from all tags and screen.
873 -- It returns the client name and set a special
874 -- foreground and background color for focused client.
875 -- It also puts a special icon for floating windows.
876 -- @param c The client.
877 -- @param screen The screen we are drawing on.
878 -- @param bg_focus The background color for focused client.
879 -- @param fg_focus The foreground color for focused client.
880 -- @return A string to pring.
881 function P.widget.tasklist.label.allscreen(c, screen, bg_focus, fg_focus)
882 return widget_tasklist_label_common(c, bg_focus, fg_focus)
885 --- Return labels for a tasklist widget with clients from all tags.
886 -- It returns the client name and set a special
887 -- foreground and background color for focused client.
888 -- It also puts a special icon for floating windows.
889 -- @param c The client.
890 -- @param screen The screen we are drawing on.
891 -- @param bg_focus The background color for focused client.
892 -- @param fg_focus The foreground color for focused client.
893 -- @return A string to pring.
894 function P.widget.tasklist.label.alltags(c, screen, bg_focus, fg_focus)
895 -- Only print client on the same screen as this widget
896 if c.screen ~= screen then return end
897 return widget_tasklist_label_common(c, bg_focus, fg_focus)
900 --- Return labels for a tasklist widget with clients from currently selected tags.
901 -- It returns the client name and set a special
902 -- foreground and background color for focused client.
903 -- It also puts a special icon for floating windows.
904 -- @param c The client.
905 -- @param screen The screen we are drawing on.
906 -- @param bg_focus The background color for focused client.
907 -- @param fg_focus The foreground color for focused client.
908 -- @return A string to pring.
909 function P.widget.tasklist.label.currenttags(c, screen, bg_focus, fg_focus)
910 -- Only print client on the same screen as this widget
911 if c.screen ~= screen then return end
912 for k, t in pairs(tag.get(screen)) do
913 if t.selected and c:istagged(t) then
914 return widget_tasklist_label_common(c, bg_focus, fg_focus)
919 --- Create a standard titlebar.
920 -- @param args Arguments.
921 -- fg: the foreground color,
922 -- bg: the background color.
923 -- @return A brand new titlebar.
924 function P.titlebar.new(args)
925 local targs = {}
926 if args.fg then targs.fg = args.fg end
927 if args.bg then targs.bg = args.bg end
928 local tb = titlebar(targs)
929 tb:widget_add(widget({ type = "appicon", name = "appicon", align = "left" }))
930 local title = widget({ type = "textbox", name = "title", align = "flex" })
931 title:mouse_add(mouse({ args.modkey }, 1, function (t) t:client_get():mouse_move() end))
932 title:mouse_add(mouse({ args.modkey }, 3, function (t) t:client_get():mouse_resize() end))
933 tb:widget_add(title)
934 local close_button= widget({ type = "textbox", name = "close", align = "right" })
935 close_button:mouse_add(mouse({ }, 1, function (t) t:client_get():kill() end))
936 tb:widget_add(close_button)
937 return tb
940 --- Update a titlebar. This should be called in some hooks.
941 -- @param c The client to update.
942 -- @param bg The background color for normal client.
943 -- @param fg The foreground color for normal client.
944 -- @param bg_focus The background color for focused client.
945 -- @param fg_focus The foreground color for focused client.
946 function P.titlebar.update(c, bg, fg, bg_focus, fg_focus)
947 if c.titlebar then
948 local widgets = c.titlebar:widget_get()
949 if widgets.title then
950 widgets.title.text = " " .. P.escape(c.name)
952 if client.focus_get() == c then
953 c.titlebar.bg = bg_focus
954 c.titlebar.fg = fg_focus
955 if widgets.close then
956 widgets.close.text = "<bg image=\"@AWESOME_ICON_PATH@/titlebar/closer.png\" resize=\"true\"/>"
958 else
959 c.titlebar.bg = bg
960 c.titlebar.fg = fg
961 if widgets.close then
962 widgets.close.text = "<bg image=\"@AWESOME_ICON_PATH@/titlebar/close.png\" resize=\"true\"/>"
968 return P