1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2008 Julien Danjou
4 ---------------------------------------------------------------------------
6 -- Grab environment we need
10 local loadstring
= loadstring
16 local setmetatable
= setmetatable
27 keygrabber
= keygrabber
30 --- awful: AWesome Functions very UsefuL
33 -- Local variable handling theme
36 -- Various public structures
46 client
.focus
.history
= {}
47 client
.focus
.history
.data
= {}
51 tag.history
.data
.past
= {}
52 tag.history
.data
.current
= {}
54 titlebar
.data
= otable()
57 widget
.taglist
.label
= {}
59 widget
.tasklist
.label
= {}
63 -- @param i An absolute index to fit into #t.
64 -- @return The object at new index.
65 local function cycle(t
, i
)
66 while i
> t
do i
= i
- t
end
67 while i
< 1 do i
= i
+ t
end
71 --- Remove a client from the focus history
72 -- @param c The client that must be removed.
73 function client
.focus
.history
.delete(c
)
74 for k
, v
in ipairs(client
.focus
.history
.data
) do
76 table.remove(client
.focus
.history
.data
, k
)
82 --- Update client focus history.
83 -- @param c The client that has been focused.
84 function client
.focus
.history
.add(c
)
85 -- Remove the client if its in stack
86 client
.focus
.history
.delete(c
)
87 -- Record the client has latest focused
88 table.insert(client
.focus
.history
.data
, 1, c
)
91 --- Get the latest focused client for a screen in history.
92 -- @param screen The screen number to look for.
93 -- @param idx The index: 0 will return first candidate,
94 -- 1 will return second, etc.
96 function client
.focus
.history
.get(screen
, idx
)
97 -- When this counter is equal to idx, we return the client
99 local vc
= capi
.client
.visible_get(screen
)
100 for k
, c
in ipairs(client
.focus
.history
.data
) do
101 if c
.screen
== screen
then
102 for j
, vcc
in ipairs(vc
) do
104 if counter
== idx
then
107 -- We found one, increment the counter only.
108 counter
= counter
+ 1
114 -- Argh nobody found in history, give the first one visible if there is one
120 --- Focus the previous client in history.
121 function client
.focus
.history
.previous()
122 local sel
= capi
.client
.focus_get()
127 s
= capi
.mouse
.screen
129 local c
= client
.focus
.history
.get(s
, 1)
130 if c
then c
:focus_set() end
133 --- Get a client by its relative index to the focused window.
134 -- @usage Set i to 1 to get next, -1 to get previous.
135 -- @param i The index.
136 -- @param c Optional client.
137 -- @return A client, or nil if no client is available.
138 function client
.next(i
, c
)
139 -- Get currently focused client
140 local sel
= c
or capi
.client
.focus_get()
142 -- Get all visible clients
143 local cls
= capi
.client
.visible_get(sel
.screen
)
144 -- Loop upon each client
145 for idx
, c
in ipairs(cls
) do
148 return cls
[cycle(#cls
, idx
+i
)]
154 --- Return true whether client B is in the right direction
155 -- compared to client A.
156 -- @param dir The direction.
157 -- @param cA The first client.
158 -- @param cB The second client.
159 -- @return True if B is in the direction of A.
160 local function is_in_direction(dir
, cA
, cB
)
162 return cA
['y'] > cB
['y']
163 elseif dir
== "down" then
164 return cA
['y'] < cB
['y']
165 elseif dir
== "left" then
166 return cA
['x'] > cB
['x']
167 elseif dir
== "right" then
168 return cA
['x'] < cB
['x']
173 --- Calculate distance between two points.
174 -- i.e: if we want to move to the right, we will take the right border
175 -- of the currently focused client and the left side of the checked client.
176 -- This avoid the focus of an upper client when you move to the right in a
177 -- tilebottom layout with nmaster=2 and 5 clients open, for instance.
178 -- @param dir The direction.
179 -- @param cA The first client.
180 -- @param cB The second client.
181 -- @return The distance between the clients.
182 local function calculate_distance(dir
, cA
, cB
)
189 yB
= yB
+ cB
['height']
190 elseif dir
== "down" then
191 yA
= yA
+ cA
['height']
192 elseif dir
== "left" then
193 xB
= xB
+ cB
['width']
194 elseif dir
== "right" then
195 xA
= xA
+ cA
['width']
198 return math
.sqrt(math
.pow(xB
- xA
, 2) + math
.pow(yB
- yA
, 2))
201 --- Focus a client by the given direction.
202 -- @param dir The direction, can be either "up", "down", "left" or "right".
203 -- @param c Optional client.
204 function client
.focusbydirection(dir
, c
)
205 local sel
= c
or capi
.client
.focus_get()
207 local coords
= sel
.coords
210 local cls
= capi
.client
.visible_get(sel
.screen
)
212 -- We check each client.
213 for i
, c
in ipairs(cls
) do
214 -- Check coords to see if client is located in the right direction.
215 if is_in_direction(dir
, coords
, c
.coords
) then
217 -- Calculate distance between focused client and checked client.
218 dist
= calculate_distance(dir
, coords
, c
.coords
)
220 -- If distance is shorter then keep the client.
221 if not target
or dist
< dist_min
then
228 -- If we found a client to focus, then do it.
235 --- Focus a client by its relative index.
236 -- @param i The index.
237 -- @param c Optional client.
238 function client
.focusbyidx(i
, c
)
239 local target
= client
.next(i
, c
)
245 --- Swap a client by its relative index.
246 -- @param i The index.
247 -- @param c Optional client, otherwise focused one is used.
248 function client
.swap(i
, c
)
249 local sel
= c
or capi
.client
.focus_get()
250 local target
= client
.next(i
, sel
)
256 --- Get the master window.
257 -- @param screen Optional screen number, otherwise screen mouse is used.
258 -- @return The master window.
259 function client
.master(screen
)
260 local s
= screen
or capi
.mouse
.screen
261 return capi
.client
.visible_get(s
)[1]
264 --- Move/resize a client relative to current coordinates.
265 -- @param x The relative x coordinate.
266 -- @param y The relative y coordinate.
267 -- @param w The relative width.
268 -- @param h The relative height.
269 -- @param c The optional client, otherwise focused one is used.
270 function client
.moveresize(x
, y
, w
, h
, c
)
271 local sel
= c
or capi
.client
.focus_get()
272 local coords
= sel
.coords
273 coords
['x'] = coords
['x'] + x
274 coords
['y'] = coords
['y'] + y
275 coords
['width'] = coords
['width'] + w
276 coords
['height'] = coords
['height'] + h
280 --- Maximize a client to use the full workarea.
281 -- @param c A client, or the focused one if nil.
282 function client
.maximize(c
)
283 local sel
= c
or capi
.client
.focus_get()
286 local ws
= capi
.screen
[sel
.screen
].workarea
287 ws
.width
= ws
.width
- 2 * sel
.border_width
288 ws
.height
= ws
.height
- 2 * sel
.border_width
293 --- Give the focus to a screen, and move pointer.
294 -- @param Screen number.
295 function screen
.focus(i
)
296 local sel
= capi
.client
.focus_get()
301 s
= capi
.mouse
.screen
303 s
= cycle(capi
.screen
.count(), s
+ i
)
304 local c
= client
.focus
.history
.get(s
, 0)
305 if c
then c
:focus_set() end
306 -- Move the mouse on the screen
307 capi
.mouse
.coords
= capi
.screen
[s
].coords
310 --- Compare 2 tables of tags.
311 -- @param a The first table.
312 -- @param b The second table of tags.
313 -- @return True if the tables are identical, false otherwise.
314 local function tag_compare_select(a
, b
)
315 if not a
or not b
then
318 -- Quick size comparison
322 for ka
, va
in pairs(a
) do
323 if b
[ka
] ~= va
.selected
then
327 for kb
, vb
in pairs(b
) do
328 if a
[kb
].selected
~= vb
then
335 --- Update the tag history.
336 -- @param screen The screen number.
337 function tag.history
.update(screen
)
338 local curtags
= capi
.screen
[screen
].tags
339 if not tag_compare_select(curtags
, tag.history
.data
.current
[screen
]) then
340 tag.history
.data
.past
[screen
] = tag.history
.data
.current
[screen
]
341 tag.history
.data
.current
[screen
] = {}
342 for k
, v
in ipairs(curtags
) do
343 tag.history
.data
.current
[screen
][k
] = v
.selected
348 -- Revert tag history.
349 -- @param screen The screen number.
350 function tag.history
.restore(screen
)
351 local s
= screen
or capi
.mouse
.screen
352 local tags
= capi
.screen
[s
].tags
353 for k
, t
in pairs(tags
) do
354 t
.selected
= tag.history
.data
.past
[s
][k
]
358 --- Return a table with all visible tags
359 -- @param s Screen number.
360 -- @return A table with all selected tags.
361 function tag.selectedlist(s
)
362 local screen
= s
or capi
.mouse
.screen
363 local tags
= capi
.screen
[screen
].tags
365 for i
, t
in pairs(tags
) do
367 vtags
[#vtags
+ 1] = t
373 --- Return only the first visible tag.
374 -- @param s Screen number.
375 function tag.selected(s
)
376 return tag.selectedlist(s
)[1]
379 --- Set master width factor.
380 -- @param mwfact Master width factor.
381 function tag.setmwfact(mwfact
)
382 local t
= tag.selected()
388 --- Increase master width factor.
389 -- @param add Value to add to master width factor.
390 function tag.incmwfact(add
)
391 local t
= tag.selected()
393 t
.mwfact
= t
.mwfact
+ add
397 --- Set the number of master windows.
398 -- @param nmaster The number of master windows.
399 function tag.setnmaster(nmaster
)
400 local t
= tag.selected()
406 --- Increase the number of master windows.
407 -- @param add Value to add to number of master windows.
408 function tag.incnmaster(add
)
409 local t
= tag.selected()
411 t
.nmaster
= t
.nmaster
+ add
415 --- Set number of column windows.
416 -- @param ncol The number of column.
417 function tag.setncol(ncol
)
418 local t
= tag.selected()
424 --- Increase number of column windows.
425 -- @param add Value to add to number of column windows.
426 function tag.incncol(add
)
427 local t
= tag.selected()
429 t
.ncol
= t
.ncol
+ add
434 -- @param Optional screen number.
435 function tag.viewnone(screen
)
436 local tags
= capi
.screen
[screen
or capi
.mouse
.screen
].tags
437 for i
, t
in pairs(tags
) do
442 --- View a tag by its index.
443 -- @param i The relative index to see.
444 -- @param screen Optional screen number.
445 function tag.viewidx(i
, screen
)
446 local tags
= capi
.screen
[screen
or capi
.mouse
.screen
].tags
447 local sel
= tag.selected()
449 for k
, t
in ipairs(tags
) do
451 tags
[cycle(#tags
, k
+ i
)].selected
= true
456 --- View next tag. This is the same as tag.viewidx(1).
457 function tag.viewnext()
458 return tag.viewidx(1)
461 --- View previous tag. This is the same a tag.viewidx(-1).
462 function tag.viewprev()
463 return tag.viewidx(-1)
467 -- @param t The tag object.
468 function tag.viewonly(t
)
469 tag.viewnone(t
.screen
)
473 --- View only a set of tags.
474 -- @param tags A table with tags to view only.
475 -- @param screen Optional screen number of the tags.
476 function tag.viewmore(tags
, screen
)
478 for i
, t
in pairs(tags
) do
483 --- Move a client to a tag.
484 -- @param target The tag to move the client to.
485 -- @para c Optional client to move, otherwise the focused one is used.
486 function client
.movetotag(target
, c
)
487 local sel
= c
or capi
.client
.focus_get();
489 -- Check that tag and client screen are identical
490 if sel
.screen
~= target
.screen
then return end
491 local tags
= { target
}
496 --- Toggle a tag on a client.
497 -- @param target The tag to toggle.
498 -- @param c Optional client to toggle, otherwise the focused one is used.
499 function client
.toggletag(target
, c
)
500 local sel
= c
or capi
.client
.focus_get();
501 -- Check that tag and client screen are identical
502 if sel
and sel
.screen
== target
.screen
then
503 local tags
= client
.tags
507 tags
[target
] = target
513 --- Toggle the floating status of a client.
514 -- @param c Optional client, the focused on if not set.
515 function client
.togglefloating(c
)
516 local sel
= c
or capi
.client
.focus_get();
518 sel
.floating
= not sel
.floating
522 --- Move a client to a screen. Default is next screen, cycling.
523 -- @param c The client to move.
524 -- @param s The screen number, default to current + 1.
525 function client
.movetoscreen(c
, s
)
526 local sel
= c
or capi
.client
.focus_get();
528 local sc
= capi
.screen
.count()
532 if s
> sc
then s
= 1 elseif s
< 1 then s
= sc
end
534 capi
.mouse
.coords
= capi
.screen
[s
].coords
539 --- Get the current layout name.
540 -- @param screen The screen number.
541 function layout
.get(screen
)
542 local t
= tag.selected(screen
)
548 --- Create a new userhook (for external libs).
549 -- @param name Hook name.
550 function hooks
.user
.create(name
)
552 hooks
[name
].callbacks
= {}
553 hooks
[name
].register
= function (f
)
554 table.insert(hooks
[name
].callbacks
, f
)
556 hooks
[name
].unregister
= function (f
)
557 for k
, h
in ipairs(hooks
[name
].callbacks
) do
559 table.remove(hooks
[name
].callbacks
, k
)
566 --- Call a created userhook (for external libs).
567 -- @param name Hook name.
568 function hooks
.user
.call(name
, ...)
569 for name
, callback
in pairs(hooks
[name
].callbacks
) do
574 -- Just set an awful mark to a client to move it later.
575 local awfulmarked
= {}
576 hooks
.user
.create('marked')
577 hooks
.user
.create('unmarked')
579 --- Mark a client, and then call 'marked' hook.
580 -- @param c The client to mark, the focused one if not specified.
581 -- @return True if the client has been marked. False if the client was already marked.
582 function client
.mark (c
)
583 local cl
= c
or capi
.client
.focus_get()
585 for k
, v
in pairs(awfulmarked
) do
591 table.insert(awfulmarked
, cl
)
594 hooks
.user
.call('marked', cl
)
599 --- Unmark a client and then call 'unmarked' hook.
600 -- @param c The client to unmark, or the focused one if not specified.
601 -- @return True if the client has been unmarked. False if the client was not marked.
602 function client
.unmark(c
)
603 local cl
= c
or capi
.client
.focus_get()
605 for k
, v
in pairs(awfulmarked
) do
607 table.remove(awfulmarked
, k
)
608 hooks
.user
.call('unmarked', cl
)
616 --- Check if a client is marked.
617 -- @param c The client to check, or the focused one otherwise.
618 function client
.ismarked(c
)
619 local cl
= c
or capi
.client
.focus_get()
621 for k
, v
in pairs(awfulmarked
) do
630 --- Toggle a client as marked.
631 -- @param c The client to toggle mark.
632 function client
.togglemarked(c
)
633 local cl
= c
or capi
.client
.focus_get()
635 if not client
.mark(c
) then
640 --- Return the marked clients and empty the marked table.
641 -- @return A table with all marked clients.
642 function client
.getmarked()
643 for k
, v
in pairs(awfulmarked
) do
644 hooks
.user
.call('unmarked', v
)
652 --- Change the layout of the current tag.
653 -- @param layouts A table of layouts.
654 -- @param i Relative index.
655 function layout
.inc(layouts
, i
)
656 local t
= tag.selected()
657 local number_of_layouts
= 0
658 local rev_layouts
= {}
659 for i
, v
in ipairs(layouts
) do
661 number_of_layouts
= number_of_layouts
+ 1
664 local cur_layout
= layout
.get()
665 local new_layout_index
= (rev_layouts
[cur_layout
] + i
) % number_of_layouts
666 if new_layout_index
== 0 then
667 new_layout_index
= number_of_layouts
669 t
.layout
= layouts
[new_layout_index
]
673 --- Set the layout of the current tag by name.
674 -- @param layout Layout name.
675 function layout
.set(layout
)
676 local t
= tag.selected()
682 -- Autodeclare awful.hooks.* functions
683 -- mapped to awesome hooks.* functions
684 for name
, hook
in pairs(capi
.hooks
) do
685 if name
~= 'timer' then
687 hooks
[name
].register
= function (f
)
688 if not hooks
[name
].callbacks
then
689 hooks
[name
].callbacks
= {}
691 for i
, callback
in ipairs(hooks
[name
].callbacks
) do
697 table.insert(hooks
[name
].callbacks
, f
)
699 hooks
[name
].unregister
= function (f
)
700 if hooks
[name
].callbacks
then
701 for k
, h
in ipairs(hooks
[name
].callbacks
) do
703 table.remove(hooks
[name
].callbacks
, k
)
711 hooks
[name
].register
= function (time
, f
, runnow
)
712 if type(time
) ~= 'number' or type(f
) ~= 'function' then
715 if not hooks
[name
].callbacks
then
716 hooks
[name
].callbacks
= {}
717 hook(1, function (...)
718 for i
, callback
in ipairs(hooks
[name
].callbacks
) do
719 if callback
['counter'] >= callback
['timer'] then
720 callback
['counter'] = 1
721 callback
['callback'](...)
723 callback
['counter'] = callback
['counter'] + 1
730 table.insert(hooks
[name
].callbacks
, { callback
= f
, timer
= time
, counter
= time
})
732 table.insert(hooks
[name
].callbacks
, { callback
= f
, timer
= time
, counter
= 0 })
735 hooks
[name
].unregister
= function (f
)
736 if hooks
[name
].callbacks
then
737 for k
, h
in ipairs(hooks
[name
].callbacks
) do
738 if h
.callback
== f
then
739 table.remove(hooks
[name
].callbacks
, k
)
749 -- @param cmd The command.
750 -- @return The os.execute() return value.
752 return os
.execute(cmd
.. "&")
756 -- @return The return value of Lua code.
758 return assert(loadstring("return " .. s
))()
761 --- Use bash completion system to complete command and filename.
762 -- @param command The command line.
763 -- @param cur_pos The cursor position.
764 -- @paran ncomp The element number to complete.
765 -- @return The new commande and the new cursor position.
766 function completion
.bash(command
, cur_pos
, ncomp
)
770 local cword_index
= 0
771 local cword_start
= 0
774 local comptype
= "file"
776 -- do nothing if we are on a letter, i.e. not at len + 1 or on a space
777 if cur_pos
~= #command
+ 1 and command
:sub(cur_pos
, cur_pos
) ~= " " then
778 return command
, cur_pos
779 elseif #command
== 0 then
780 return command
, cur_pos
783 while wend
<= #command
do
784 wend
= command
:find(" ", wstart
)
785 if not wend
then wend
= #command
+ 1 end
786 table.insert(words
, command
:sub(wstart
, wend
- 1))
787 if cur_pos
>= wstart
and cur_pos
<= wend
+ 1 then
796 if cword_index
== 1 then
800 local c
= io
.popen("/usr/bin/env bash -c 'compgen -A " .. comptype
.. " " .. words
[cword_index
] .. "'")
804 local line
= c
:read("*line")
805 if not line
then break end
806 table.insert(output
, line
)
811 -- no completion, return
813 return command
, cur_pos
817 while ncomp
> #output
do
818 ncomp
= ncomp
- #output
821 local str
= command
:sub(1, cword_start
- 1) .. output
[ncomp
] .. command
:sub(cword_end
)
822 cur_pos
= cword_end
+ #output
[ncomp
] + 1
827 --- Draw the prompt text with a cursor.
828 -- @param text The text.
829 -- @param text_color The text color.
830 -- @param cursor_color The cursor color.
831 -- @param cursor_pos The cursor position.
832 local function prompt_text_with_cursor(text
, text_color
, cursor_color
, cursor_pos
)
834 if not text
then text
= "" end
835 if #text
< cursor_pos
then
838 char
= escape(text
:sub(cursor_pos
, cursor_pos
))
840 local text_start
= escape(text
:sub(1, cursor_pos
- 1))
841 local text_end
= escape(text
:sub(cursor_pos
+ 1))
842 return text_start
.. "<span background=\"" .. cursor_color
.. "\" foreground=\"" .. text_color
.. "\">" .. char
.. "</span>" .. text_end
845 --- Run a prompt in a box.
846 -- @param args A table with optional arguments: fg_cursor, bg_cursor, prompt.
847 -- @param textbox The textbox to use for the prompt.
848 -- @param exe_callback The callback function to call with command as argument when finished.
849 -- @param completion_callback The callback function to call to get completion.
850 function prompt(args
, textbox
, exe_callback
, completion_callback
)
851 if not args
then args
= {} end
853 local command_before_comp
854 local cur_pos_before_comp
855 local prompt
= args
.prompt
or ""
856 local inv_col
= args
.fg_cursor
or theme
.fg_focus
or "black"
857 local cur_col
= args
.bg_cursor
or theme
.bg_focus
or "white"
858 -- The cursor position
860 -- The completion element to use on completion request.
862 if not textbox
or not exe_callback
then
865 textbox
.text
= prompt
.. prompt_text_with_cursor(text
, inv_col
, cur_col
, cur_pos
)
868 local has_ctrl
= false
870 -- Compute modifiers keys
871 for k
, v
in ipairs(mod) do
872 if v
== "Control" then has_ctrl
= true end
877 if key
== "c" or key
== "g" then
880 elseif key
== "j" or key
== "m" then
882 exec_callback(command
)
886 if key
== "Return" then
888 exe_callback(command
)
890 elseif key
== "Escape" then
900 elseif key
== "b" then
902 cur_pos
= cur_pos
- 1
904 elseif key
== "d" then
905 if cur_pos
<= #command
then
906 command
= command
:sub(1, cur_pos
- 1) .. command
:sub(cur_pos
+ 1)
908 elseif key
== "e" then
909 cur_pos
= #command
+ 1
910 elseif key
== "f" then
911 if cur_pos
<= #command
then
912 cur_pos
= cur_pos
+ 1
914 elseif key
== "h" then
916 command
= command
:sub(1, cur_pos
- 2) .. command
:sub(cur_pos
)
917 cur_pos
= cur_pos
- 1
919 elseif key
== "k" then
920 command
= command
:sub(1, cur_pos
- 1)
921 elseif key
== "u" then
922 command
= command
:sub(cur_pos
, #command
)
924 elseif key
== "w" then
927 local cword_start
= 1
929 while wend
< cur_pos
do
930 wend
= command
:find(" ", wstart
)
931 if not wend
then wend
= #command
+ 1 end
932 if cur_pos
>= wstart
and cur_pos
<= wend
+ 1 then
934 cword_end
= cur_pos
- 1
939 command
= command
:sub(1, cword_start
- 1) .. command
:sub(cword_end
+ 1)
940 cur_pos
= cword_start
943 if completion_callback
then
945 if key
:byte() == 9 then
947 command_before_comp
= command
948 cur_pos_before_comp
= cur_pos
950 command
, cur_pos
= completion_callback(command_before_comp
, cur_pos_before_comp
, ncomp
)
959 if key
== "Home" then
961 elseif key
== "End" then
962 cur_pos
= #command
+ 1
963 elseif key
== "BackSpace" then
965 command
= command
:sub(1, cur_pos
- 2) .. command
:sub(cur_pos
)
966 cur_pos
= cur_pos
- 1
969 elseif key
:byte() == 127 then
970 command
= command
:sub(1, cur_pos
- 1) .. command
:sub(cur_pos
+ 1)
971 elseif key
== "Left" then
972 cur_pos
= cur_pos
- 1
973 elseif key
== "Right" then
974 cur_pos
= cur_pos
+ 1
976 -- len() is UTF-8 aware but #key is not,
977 -- so check that we have one UTF-8 char but advance the cursor of # position
978 if key
:len() == 1 then
979 command
= command
:sub(1, cur_pos
- 1) .. key
.. command
:sub(cur_pos
)
980 cur_pos
= cur_pos
+ #key
985 elseif cur_pos
> #command
+ 1 then
986 cur_pos
= #command
+ 1
991 textbox
.text
= prompt
.. prompt_text_with_cursor(command
, inv_col
, cur_col
, cur_pos
)
997 --- Escape a string from XML char.
998 -- Useful to set raw text in textbox.
999 -- @param text Text to escape.
1000 -- @return Escape text.
1001 function escape(text
)
1003 text
= text
:gsub("&", "&")
1004 text
= text
:gsub("<", "<")
1005 text
= text
:gsub(">", ">")
1006 text
= text
:gsub("'", "'")
1007 text
= text
:gsub("\"", """)
1012 --- Unescape a string from entities.
1013 -- @param text Text to unescape.
1014 -- @return Unescaped text.
1015 function unescape(text
)
1017 text
= text
:gsub("&", "&")
1018 text
= text
:gsub("<", "<")
1019 text
= text
:gsub(">", ">")
1020 text
= text
:gsub("'", "'")
1021 text
= text
:gsub(""", "\"")
1026 --- Return labels for a taglist widget with all tag from screen.
1027 -- It returns the tag name and set a special
1028 -- foreground and background color for selected tags.
1029 -- @param t The tag.
1030 -- @param args The arguments table.
1031 -- bg_focus The background color for selected tag.
1032 -- fg_focus The foreground color for selected tag.
1033 -- bg_urgent The background color for urgent tags.
1034 -- fg_urgent The foreground color for urgent tags.
1035 -- @return A string to print.
1036 function widget
.taglist
.label
.all(t
, args
)
1037 if not args
then args
= {} end
1038 local fg_focus
= args
.fg_focus
or theme
.fg_focus
1039 local bg_focus
= args
.bg_focus
or theme
.bg_focus
1040 local fg_urgent
= args
.fg_urgent
or theme
.fg_urgent
1041 local bg_urgent
= args
.bg_urgent
or theme
.bg_urgent
1043 local background
= ""
1044 local sel
= capi
.client
.focus_get()
1045 local bg_color
= nil
1046 local fg_color
= nil
1051 if sel
and sel
.tags
[t
] then
1052 background
= "resize=\"true\" image=\"@AWESOME_ICON_PATH@/taglist/squarefw.png\""
1053 elseif bg_urgent
and fg_urgent
then
1054 for k
, c
in pairs(t
.clients
) do
1055 background
= "resize=\"true\" image=\"@AWESOME_ICON_PATH@/taglist/squarew.png\""
1057 bg_color
= bg_urgent
1058 fg_color
= fg_urgent
1063 if bg_color
and fg_color
then
1064 text
= "<bg "..background
.." color='"..bg_color
.."'/> <span color='"..fg_color
.."'>"..escape(t
.name
).."</span> "
1066 text
= " <bg "..background
.." />"..escape(t
.name
).." "
1071 --- Return labels for a taglist widget with all *non empty* tags from screen.
1072 -- It returns the tag name and set a special
1073 -- foreground and background color for selected tags.
1074 -- @param t The tag.
1075 -- @param args The arguments table.
1076 -- bg_focus The background color for selected tag.
1077 -- fg_focus The foreground color for selected tag.
1078 -- bg_urgent The background color for urgent tags.
1079 -- fg_urgent The foreground color for urgent tags.
1080 -- @return A string to print.
1081 function widget
.taglist
.label
.noempty(t
, args
)
1082 if #t
.clients
> 0 then
1083 if not args
then args
= {} end
1084 local fg_focus
= args
.fg_focus
or theme
.fg_focus
1085 local bg_focus
= args
.bg_focus
or theme
.bg_focus
1086 local fg_urgent
= args
.fg_urgent
or theme
.fg_urgent
1087 local bg_urgent
= args
.bg_urgent
or theme
.bg_urgent
1088 local bg_color
= nil
1089 local fg_color
= nil
1096 if bg_urgent
and fg_urgent
then
1097 for k
, c
in pairs(t
.clients
) do
1099 bg_color
= bg_urgent
1100 fg_color
= fg_urgent
1105 if fg_color
and bg_color
then
1106 text
= "<bg color='" .. bg_color
.. "'/> <span color='" .. fg_color
.. "'>" .. escape(t
.name
) .. "</span> "
1108 text
= " " .. escape(t
.name
) .. " "
1114 local function widget_tasklist_label_common(c
, args
)
1115 if not args
then args
= {} end
1116 local fg_focus
= args
.fg_focus
or theme
.fg_focus
1117 local bg_focus
= args
.bg_focus
or theme
.bg_focus
1118 local fg_urgent
= args
.fg_urgent
or theme
.fg_urgent
1119 local bg_urgent
= args
.bg_urgent
or theme
.bg_urgent
1123 text
= "<bg image=\"@AWESOME_ICON_PATH@/tasklist/floatingw.png\" align=\"right\"/>"
1126 name
= escape(c
.icon_name
)
1128 name
= escape(c
.name
)
1130 if capi
.client
.focus_get() == c
then
1131 text
= text
.. " <bg color='"..bg_focus
.."'/><span color='"..fg_focus
.."'>"..name
.."</span> "
1132 elseif c
.urgent
and bg_urgent
and fg_urgent
then
1133 text
= text
.. " <bg color='"..bg_urgent
.."'/><span color='"..fg_urgent
.."'>"..name
.."</span> "
1135 text
= text
.. " "..name
.." "
1140 --- Return labels for a tasklist widget with clients from all tags and screen.
1141 -- It returns the client name and set a special
1142 -- foreground and background color for focused client.
1143 -- It also puts a special icon for floating windows.
1144 -- @param c The client.
1145 -- @param screen The screen we are drawing on.
1146 -- @param args The arguments table.
1147 -- bg_focus The background color for focused client.
1148 -- fg_focus The foreground color for focused client.
1149 -- bg_urgent The background color for urgent clients.
1150 -- fg_urgent The foreground color for urgent clients.
1151 -- @return A string to print.
1152 function widget
.tasklist
.label
.allscreen(c
, screen
, args
)
1153 return widget_tasklist_label_common(c
, args
)
1156 --- Return labels for a tasklist widget with clients from all tags.
1157 -- It returns the client name and set a special
1158 -- foreground and background color for focused client.
1159 -- It also puts a special icon for floating windows.
1160 -- @param c The client.
1161 -- @param screen The screen we are drawing on.
1162 -- @param args The arguments table.
1163 -- bg_focus The background color for focused client.
1164 -- fg_focus The foreground color for focused client.
1165 -- bg_urgent The background color for urgent clients.
1166 -- fg_urgent The foreground color for urgent clients.
1167 -- @return A string to print.
1168 function widget
.tasklist
.label
.alltags(c
, screen
, args
)
1169 -- Only print client on the same screen as this widget
1170 if c
.screen
~= screen
then return end
1171 return widget_tasklist_label_common(c
, args
)
1174 --- Return labels for a tasklist widget with clients from currently selected tags.
1175 -- It returns the client name and set a special
1176 -- foreground and background color for focused client.
1177 -- It also puts a special icon for floating windows.
1178 -- @param c The client.
1179 -- @param screen The screen we are drawing on.
1180 -- @param args The arguments table.
1181 -- bg_focus The background color for focused client.
1182 -- fg_focus The foreground color for focused client.
1183 -- bg_urgent The background color for urgent clients.
1184 -- fg_urgent The foreground color for urgent clients.
1185 -- @return A string to print.
1186 function widget
.tasklist
.label
.currenttags(c
, screen
, args
)
1187 -- Only print client on the same screen as this widget
1188 if c
.screen
~= screen
then return end
1189 for k
, t
in ipairs(capi
.screen
[screen
].tags
) do
1190 if t
.selected
and c
.tags
[t
] then
1191 return widget_tasklist_label_common(c
, args
)
1196 --- Create a standard titlebar.
1197 -- @param c The client.
1198 -- @param args Arguments.
1199 -- fg: the foreground color.
1200 -- bg: the background color.
1201 -- fg_focus: the foreground color for focused window.
1202 -- fg_focus: the background color for focused window.
1203 function titlebar
.add(c
, args
)
1204 if not args
then args
= {} end
1206 titlebar
.data
[c
] = {}
1207 titlebar
.data
[c
].fg
= args
.fg
or theme
.fg_normal
1208 titlebar
.data
[c
].bg
= args
.bg
or theme
.bg_normal
1209 titlebar
.data
[c
].fg_focus
= args
.fg_focus
or theme
.fg_focus
1210 titlebar
.data
[c
].bg_focus
= args
.bg_focus
or theme
.bg_focus
1214 if args
.fg
then targs
.fg
= args
.fg
end
1215 if args
.bg
then targs
.bg
= args
.bg
end
1216 local tb
= capi
.titlebar(targs
)
1218 local title
= capi
.widget({ type = "textbox", name
= "title", align
= "flex" })
1219 title
:mouse_add(capi
.mouse({ }, 1, function (t
) t
.client
:mouse_move() end))
1220 title
:mouse_add(capi
.mouse({ args
.modkey
}, 3, function (t
) t
.client
:mouse_resize() end))
1222 local close_button
= capi
.widget({ type = "textbox", name
= "close", align
= "right" })
1223 close_button
:mouse_add(capi
.mouse({ }, 1, function (t
) t
.client
:kill() end))
1227 capi
.widget({ type = "appicon", name
= "appicon", align
= "left" }),
1237 --- Update a titlebar. This should be called in some hooks.
1238 -- @param c The client to update.
1239 function titlebar
.update(c
)
1240 if c
.titlebar
and titlebar
.data
[c
] then
1241 local widgets
= c
.titlebar
.widgets
1243 for k
, v
in ipairs(widgets
) do
1244 if v
.name
== "title" then title
= v
end
1245 if v
.name
== "close" then close
= v
end
1246 if title
and close
then break end
1249 title
.text
= " " .. escape(c
.name
)
1251 if capi
.client
.focus_get() == c
then
1252 c
.titlebar
.fg
= titlebar
.data
[c
].fg_focus
1253 c
.titlebar
.bg
= titlebar
.data
[c
].bg_focus
1255 close
.text
= "<bg image=\"@AWESOME_ICON_PATH@/titlebar/closer.png\" resize=\"true\"/>"
1258 c
.titlebar
.fg
= titlebar
.data
[c
].fg
1259 c
.titlebar
.bg
= titlebar
.data
[c
].bg
1261 close
.text
= "<bg image=\"@AWESOME_ICON_PATH@/titlebar/close.png\" resize=\"true\"/>"
1267 --- Remove a titlebar from a client.
1268 -- @param c The client.
1269 function titlebar
.remove(c
)
1271 titlebar
.data
[c
] = nil
1274 --- Set the beautiful theme if any.
1275 -- @param The beautiful theme.
1276 function beautiful
.register(btheme
)
1284 -- Register standards hooks
1285 hooks
.arrange
.register(tag.history
.update
)
1287 hooks
.focus
.register(client
.focus
.history
.add
)
1288 hooks
.unmanage
.register(client
.focus
.history
.delete
)
1290 hooks
.focus
.register(titlebar
.update
)
1291 hooks
.unfocus
.register(titlebar
.update
)
1292 hooks
.titleupdate
.register(titlebar
.update
)
1293 hooks
.unmanage
.register(titlebar
.remove)
1295 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80