ldoc: fix usage of @usage, which is <code> automatically
[awesome.git] / lib / awful / client.lua.in
blobfb4edb7c3465172efe299f61f96e70bdce7e82b5
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou &lt;julien@danjou.info&gt;
3 -- @copyright 2008 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
8 local util = require("awful.util")
9 local tag = require("awful.tag")
10 local pairs = pairs
11 local type = type
12 local ipairs = ipairs
13 local table = table
14 local math = math
15 local setmetatable = setmetatable
16 local capi =
18 client = client,
19 mouse = mouse,
20 screen = screen,
21 awesome = awesome,
24 -- we use require("awful.screen") inside functions to prevent circular dependencies.
25 local screen
27 --- Useful client manipulation functions.
28 -- awful.client
29 local client = {}
32 -- Private data
33 client.data = {}
34 client.data.focus = {}
35 client.data.urgent = {}
36 client.data.marked = {}
37 client.data.properties = setmetatable({}, { __mode = 'k' })
38 client.data.persistent_properties_registered = {} -- keys are names of persistent properties, value always true
39 client.data.persistent_properties_loaded = setmetatable({}, { __mode = 'k' }) -- keys are clients, value always true
41 -- Functions
42 client.urgent = {}
43 client.focus = {}
44 client.focus.history = {}
45 client.swap = {}
46 client.floating = {}
47 client.dockable = {}
48 client.property = {}
49 client.shape = require("awful.client.shape")
51 ---
52 -- Jump to the given client. Takes care of focussing the screen, the right tag,
53 -- etc.
54 -- @param c the client to jump to
55 -- @param merge If true then merge tags when clients are not visible.
56 function client.jumpto(c, merge)
57 local s = capi.client.focus and capi.client.focus.screen or capi.mouse.screen
58 -- focus the screen
59 if s ~= c.screen then
60 capi.mouse.screen = c.screen
61 end
63 -- Try to make client visible, this also covers e.g. sticky
64 local t = c:tags()[1]
65 if t and not c:isvisible() then
66 if merge then
67 t.selected = true
68 else
69 tag.viewonly(t)
70 end
71 end
73 -- focus the client
74 capi.client.focus = c
75 c:raise()
76 end
78 --- Get the first client that got the urgent hint.
79 -- @return The first urgent client.
80 function client.urgent.get()
81 if #client.data.urgent > 0 then
82 return client.data.urgent[1]
83 else
84 -- fallback behaviour: iterate through clients and get the first urgent
85 local clients = capi.client.get()
86 for k, cl in pairs(clients) do
87 if cl.urgent then
88 return cl
89 end
90 end
91 end
92 end
94 --- Jump to the client that received the urgent hint first.
95 -- @param merge If true then merge tags when clients are not visible.
96 function client.urgent.jumpto(merge)
97 local c = client.urgent.get()
98 if c then
99 client.jumpto(c, merge)
103 --- Adds client to urgent stack.
104 -- @param c The client object.
105 -- @param prop The property which is updated.
106 function client.urgent.add(c, prop)
107 if type(c) == "client" and prop == "urgent" and c.urgent then
108 table.insert(client.data.urgent, c)
112 --- Remove client from urgent stack.
113 -- @param c The client object.
114 function client.urgent.delete(c)
115 for k, cl in ipairs(client.data.urgent) do
116 if c == cl then
117 table.remove(client.data.urgent, k)
118 break
123 --- Remove a client from the focus history
124 -- @param c The client that must be removed.
125 function client.focus.history.delete(c)
126 for k, v in ipairs(client.data.focus) do
127 if v == c then
128 table.remove(client.data.focus, k)
129 break
134 --- Filter out window that we do not want handled by focus.
135 -- This usually means that desktop, dock and splash windows are
136 -- not registered and cannot get focus.
137 -- @param c A client.
138 -- @return The same client if it's ok, nil otherwise.
139 function client.focus.filter(c)
140 if c.type == "desktop"
141 or c.type == "dock"
142 or c.type == "splash"
143 or not c.focusable then
144 return nil
146 return c
149 --- Update client focus history.
150 -- @param c The client that has been focused.
151 function client.focus.history.add(c)
152 -- Remove the client if its in stack
153 client.focus.history.delete(c)
154 -- Record the client has latest focused
155 table.insert(client.data.focus, 1, c)
158 --- Get the latest focused client for a screen in history.
159 -- @param screen The screen number to look for.
160 -- @param idx The index: 0 will return first candidate,
161 -- 1 will return second, etc.
162 -- @return A client.
163 function client.focus.history.get(screen, idx)
164 -- When this counter is equal to idx, we return the client
165 local counter = 0
166 local vc = client.visible(screen)
167 for k, c in ipairs(client.data.focus) do
168 if c.screen == screen then
169 for j, vcc in ipairs(vc) do
170 if vcc == c then
171 if counter == idx then
172 return c
174 -- We found one, increment the counter only.
175 counter = counter + 1
176 break
181 -- Argh nobody found in history, give the first one visible if there is one
182 -- that passes the filter.
183 if counter == 0 then
184 for k, v in ipairs(vc) do
185 if client.focus.filter(v) then
186 return v
192 --- Focus the previous client in history.
193 function client.focus.history.previous()
194 local sel = capi.client.focus
195 local s
196 if sel then
197 s = sel.screen
198 else
199 s = capi.mouse.screen
201 local c = client.focus.history.get(s, 1)
202 if c then capi.client.focus = c end
205 --- Get visible clients from a screen.
206 -- @param screen The screen number, or nil for all screens.
207 -- @return A table with all visible clients.
208 function client.visible(screen)
209 local cls = capi.client.get(screen)
210 local vcls = {}
211 for k, c in pairs(cls) do
212 if c:isvisible() then
213 table.insert(vcls, c)
216 return vcls
219 --- Get visible and tiled clients
220 -- @param screen The screen number, or nil for all screens.
221 -- @return A table with all visible and tiled clients.
222 function client.tiled(screen)
223 local clients = client.visible(screen)
224 local tclients = {}
225 -- Remove floating clients
226 for k, c in pairs(clients) do
227 if not client.floating.get(c)
228 and not c.fullscreen
229 and not c.maximized_vertical
230 and not c.maximized_horizontal then
231 table.insert(tclients, c)
234 return tclients
237 --- Get a client by its relative index to the focused window.
238 -- @param i The index. Use 1 to get next, -1 to get previous.
239 -- @param c Optional client.
240 -- @return A client, or nil if no client is available.
241 function client.next(i, c)
242 -- Get currently focused client
243 local sel = c or capi.client.focus
244 if sel then
245 -- Get all visible clients
246 local cls = client.visible(sel.screen)
247 local fcls = {}
248 -- Remove all non-normal clients
249 for idx, c in ipairs(cls) do
250 if client.focus.filter(c) or c == sel then
251 table.insert(fcls, c)
254 cls = fcls
255 -- Loop upon each client
256 for idx, c in ipairs(cls) do
257 if c == sel then
258 -- Cycle
259 return cls[util.cycle(#cls, idx + i)]
265 --- Focus a client by the given direction.
266 -- @param dir The direction, can be either "up", "down", "left" or "right".
267 -- @param c Optional client.
268 function client.focus.bydirection(dir, c)
269 local sel = c or capi.client.focus
270 if sel then
271 local cltbl = client.visible(sel.screen)
272 local geomtbl = {}
273 for i,cl in ipairs(cltbl) do
274 geomtbl[i] = cl:geometry()
277 local target = util.get_rectangle_in_direction(dir, geomtbl, sel:geometry())
279 -- If we found a client to focus, then do it.
280 if target then
281 capi.client.focus = cltbl[target]
286 --- Focus a client by the given direction. Moves across screens.
287 -- @param dir The direction, can be either "up", "down", "left" or "right".
288 -- @param c Optional client.
289 function client.focus.global_bydirection(dir, c)
290 screen = screen or require("awful.screen")
291 local sel = c or capi.client.focus
292 local scr = capi.mouse.screen
293 if sel then
294 scr = sel.screen
297 -- change focus inside the screen
298 client.focus.bydirection(dir, sel)
300 -- if focus not changed, we must change screen
301 if sel == capi.client.focus then
302 screen.focus_bydirection(dir, scr)
303 if scr ~= capi.mouse.screen then
304 local cltbl = client.visible(capi.mouse.screen)
305 local geomtbl = {}
306 for i,cl in ipairs(cltbl) do
307 geomtbl[i] = cl:geometry()
309 local target = util.get_rectangle_in_direction(dir, geomtbl, capi.screen[scr].geometry)
311 if target then
312 capi.client.focus = cltbl[target]
318 --- Focus a client by its relative index.
319 -- @param i The index.
320 -- @param c Optional client.
321 function client.focus.byidx(i, c)
322 local target = client.next(i, c)
323 if target then
324 capi.client.focus = target
328 --- Swap a client with another client in the given direction
329 -- @param dir The direction, can be either "up", "down", "left" or "right".
330 -- @param c Optional client.
331 function client.swap.bydirection(dir, c)
332 local sel = c or capi.client.focus
333 if sel then
334 local cltbl = client.visible(sel.screen)
335 local geomtbl = {}
336 for i,cl in ipairs(cltbl) do
337 geomtbl[i] = cl:geometry()
339 local target = util.get_rectangle_in_direction(dir, geomtbl, sel:geometry())
341 -- If we found a client to swap with, then go for it
342 if target then
343 cltbl[target]:swap(sel)
348 --- Swap a client with another client in the given direction. Swaps across screens.
349 -- @param dir The direction, can be either "up", "down", "left" or "right".
350 -- @param c Optional client.
351 function client.swap.global_bydirection(dir, c)
352 screen = screen or require("awful.screen")
353 local sel = c or capi.client.focus
354 local scr = capi.mouse.screen
355 if sel then
356 scr = sel.screen
359 if sel then
360 -- move focus
361 client.focus.global_bydirection(dir, sel)
362 local c = capi.client.focus
364 -- swapping inside a screen
365 if sel.screen == c.screen and sel ~= c then
366 c:swap(sel)
368 -- swapping to an empty screen
369 elseif sel.screen ~= c.screen and sel == c then
370 client.movetoscreen(sel, capi.mouse.screen)
372 --swapping to a nonempty screen
373 elseif sel.screen ~= c.screen and sel ~= c then
374 client.movetoscreen(sel, c.screen)
375 client.movetoscreen(c, scr)
378 screen.focus(sel.screen)
379 capi.client.focus = sel
383 --- Swap a client by its relative index.
384 -- @param i The index.
385 -- @param c Optional client, otherwise focused one is used.
386 function client.swap.byidx(i, c)
387 local sel = c or capi.client.focus
388 local target = client.next(i, sel)
389 if target then
390 target:swap(sel)
394 --- Cycle clients.
395 -- @param clockwise True to cycle clients clockwise.
396 -- @param screen Optional screen where to cycle clients.
397 function client.cycle(clockwise, screen)
398 local screen = screen or capi.mouse.screen
399 local cls = client.visible(screen)
400 -- We can't rotate without at least 2 clients, buddy.
401 if #cls >= 2 then
402 local c = table.remove(cls, 1)
403 if clockwise then
404 for i = #cls, 1, -1 do
405 c:swap(cls[i])
407 else
408 for _, rc in pairs(cls) do
409 c:swap(rc)
415 --- Get the master window.
416 -- @param screen Optional screen number, otherwise screen mouse is used.
417 -- @return The master window.
418 function client.getmaster(screen)
419 local s = screen or capi.mouse.screen
420 return client.visible(s)[1]
423 --- Set the client as master: put it at the beginning of other windows.
424 -- @param c The window to set as master.
425 function client.setmaster(c)
426 local cls = util.table.reverse(capi.client.get(c.screen))
427 for k, v in pairs(cls) do
428 c:swap(v)
432 --- Set the client as slave: put it at the end of other windows.
433 -- @param c The window to set as slave.
434 function client.setslave(c)
435 local cls = capi.client.get(c.screen)
436 for k, v in pairs(cls) do
437 c:swap(v)
441 --- Move/resize a client relative to current coordinates.
442 -- @param x The relative x coordinate.
443 -- @param y The relative y coordinate.
444 -- @param w The relative width.
445 -- @param h The relative height.
446 -- @param c The optional client, otherwise focused one is used.
447 function client.moveresize(x, y, w, h, c)
448 local sel = c or capi.client.focus
449 local geometry = sel:geometry()
450 geometry['x'] = geometry['x'] + x
451 geometry['y'] = geometry['y'] + y
452 geometry['width'] = geometry['width'] + w
453 geometry['height'] = geometry['height'] + h
454 sel:geometry(geometry)
457 --- Move a client to a tag.
458 -- @param target The tag to move the client to.
459 -- @param c Optional client to move, otherwise the focused one is used.
460 function client.movetotag(target, c)
461 local sel = c or capi.client.focus
462 local s = tag.getscreen(target)
463 if sel and s then
464 -- Set client on the same screen as the tag.
465 sel.screen = s
466 sel:tags({ target })
470 --- Toggle a tag on a client.
471 -- @param target The tag to toggle.
472 -- @param c Optional client to toggle, otherwise the focused one is used.
473 function client.toggletag(target, c)
474 local sel = c or capi.client.focus
475 -- Check that tag and client screen are identical
476 if sel and sel.screen == tag.getscreen(target) then
477 local tags = sel:tags()
478 local index = nil;
479 for i, v in ipairs(tags) do
480 if v == target then
481 index = i
482 break
485 if index then
486 -- If it's the only tag for the window, stop.
487 if #tags == 1 then return end
488 tags[index] = nil
489 else
490 tags[#tags + 1] = target
492 sel:tags(tags)
496 --- Move a client to a screen. Default is next screen, cycling.
497 -- @param c The client to move.
498 -- @param s The screen number, default to current + 1.
499 function client.movetoscreen(c, s)
500 screen = screen or require("awful.screen")
501 local sel = c or capi.client.focus
502 if sel then
503 local sc = capi.screen.count()
504 if not s then
505 s = sel.screen + 1
507 if s > sc then s = 1 elseif s < 1 then s = sc end
508 sel.screen = s
509 screen.focus(s)
513 --- Mark a client, and then call 'marked' hook.
514 -- @param c The client to mark, the focused one if not specified.
515 -- @return True if the client has been marked. False if the client was already marked.
516 function client.mark(c)
517 local cl = c or capi.client.focus
518 if cl then
519 for k, v in pairs(client.data.marked) do
520 if cl == v then
521 return false
525 table.insert(client.data.marked, cl)
527 -- Call callback
528 cl:emit_signal("marked")
529 return true
533 --- Unmark a client and then call 'unmarked' hook.
534 -- @param c The client to unmark, or the focused one if not specified.
535 -- @return True if the client has been unmarked. False if the client was not marked.
536 function client.unmark(c)
537 local cl = c or capi.client.focus
539 for k, v in pairs(client.data.marked) do
540 if cl == v then
541 table.remove(client.data.marked, k)
542 cl:emit_signal("unmarked")
543 return true
547 return false
550 --- Check if a client is marked.
551 -- @param c The client to check, or the focused one otherwise.
552 function client.ismarked(c)
553 local cl = c or capi.client.focus
554 if cl then
555 for k, v in pairs(client.data.marked) do
556 if cl == v then
557 return true
561 return false
564 --- Toggle a client as marked.
565 -- @param c The client to toggle mark.
566 function client.togglemarked(c)
567 local cl = c or capi.client.focus
569 if not client.mark(c) then
570 client.unmark(c)
574 --- Return the marked clients and empty the marked table.
575 -- @return A table with all marked clients.
576 function client.getmarked()
577 for k, v in pairs(client.data.marked) do
578 v:emit_signal("unmarked")
581 t = client.data.marked
582 client.data.marked = {}
583 return t
586 --- Set a client floating state, overriding auto-detection.
587 -- Floating client are not handled by tiling layouts.
588 -- @param c A client.
589 -- @param s True or false.
590 function client.floating.set(c, s)
591 local c = c or capi.client.focus
592 if c and client.property.get(c, "floating") ~= s then
593 client.property.set(c, "floating", s)
594 local scr = c.screen
595 if s == true then
596 c:geometry(client.property.get(c, "floating_geometry"))
598 c.screen = scr
602 local function store_floating_geometry(c)
603 if client.floating.get(c) then
604 client.property.set(c, "floating_geometry", c:geometry())
608 -- Store the initial client geometry.
609 capi.client.connect_signal("new", function(c)
610 local function store_init_geometry(c)
611 client.property.set(c, "floating_geometry", c:geometry())
612 c:disconnect_signal("property::border_width", store_init_geometry)
614 c:connect_signal("property::border_width", store_init_geometry)
615 end)
617 capi.client.connect_signal("property::geometry", store_floating_geometry)
619 --- Return if a client has a fixe size or not.
620 -- @param c The client.
621 function client.isfixed(c)
622 local c = c or capi.client.focus
623 if not c then return end
624 local h = c.size_hints
625 if h.min_width and h.max_width
626 and h.max_height and h.min_height
627 and h.min_width > 0 and h.max_width > 0
628 and h.max_height > 0 and h.min_height > 0
629 and h.min_width == h.max_width
630 and h.min_height == h.max_height then
631 return true
633 return false
636 --- Get a client floating state.
637 -- @param c A client.
638 -- @return True or false. Note that some windows might be floating even if you
639 -- did not set them manually. For example, windows with a type different than
640 -- normal.
641 function client.floating.get(c)
642 local c = c or capi.client.focus
643 if c then
644 local value = client.property.get(c, "floating")
645 if value ~= nil then
646 return value
648 if c.type ~= "normal"
649 or c.fullscreen
650 or c.maximized_vertical
651 or c.maximized_horizontal
652 or client.isfixed(c) then
653 return true
655 return false
659 --- Toggle the floating state of a client between 'auto' and 'true'.
660 -- @param c A client.
661 function client.floating.toggle(c)
662 local c = c or capi.client.focus
663 -- If it has been set to floating
664 if client.floating.get(c) then
665 client.floating.set(c, false)
666 else
667 client.floating.set(c, true)
671 --- Remove the floating information on a client.
672 -- @param c The client.
673 function client.floating.delete(c)
674 client.floating.set(c, nil)
677 --- Restore (=unminimize) a random client.
678 -- @param s The screen to use.
679 -- @return The restored client if some client was restored, otherwise nil.
680 function client.restore(s)
681 local s = s or (capi.client.focus and capi.client.focus.screen) or capi.mouse.screen
682 local cls = capi.client.get(s)
683 local tags = tag.selectedlist(s)
684 local mcls = {}
685 for k, c in pairs(cls) do
686 local ctags = c:tags()
687 if c.minimized then
688 for k, t in ipairs(tags) do
689 if util.table.hasitem(ctags, t) then
690 c.minimized = false
691 return c
696 return nil
699 -- Normalize a set of numbers to 1
700 -- @param set the set of numbers to normalize
701 -- @param num the number of numbers to normalize
702 local function normalize(set, num)
703 local num = num or #set
704 local total = 0
705 if num then
706 for i = 1,num do
707 total = total + set[i]
709 for i = 1,num do
710 set[i] = set[i] / total
712 else
713 for i,v in ipairs(set) do
714 total = total + v
717 for i,v in ipairs(set) do
718 set[i] = v / total
723 --- Calculate a client's column number, index in that column, and
724 -- number of visible clients in this column.
725 -- @param c the client
726 -- @return col the column number
727 -- @return idx index of the client in the column
728 -- @return num the number of visible clients in the column
729 function client.idx(c)
730 local c = c or capi.client.focus
731 if not c then return end
733 local clients = client.tiled(c.screen)
734 local idx = nil
735 for k, cl in ipairs(clients) do
736 if cl == c then
737 idx = k
738 break
742 local t = tag.selected(c.screen)
743 local nmaster = tag.getnmaster(t)
744 if idx <= nmaster then
745 return {idx = idx, col=0, num=nmaster}
747 local nother = #clients - nmaster
748 idx = idx - nmaster
750 -- rather than regenerate the column number we can calculate it
751 -- based on the how the tiling algorithm places clients we calculate
752 -- the column, we could easily use the for loop in the program but we can
753 -- calculate it.
754 local ncol = tag.getncol(t)
755 -- minimum number of clients per column
756 local percol = math.floor(nother / ncol)
757 -- number of columns with an extra client
758 local overcol = math.fmod(nother, ncol)
759 -- number of columns filled with [percol] clients
760 local regcol = ncol - overcol
762 local col = math.floor( (idx - 1) / percol) + 1
763 if col > regcol then
764 -- col = math.floor( (idx - (percol*regcol) - 1) / (percol + 1) ) + regcol + 1
765 -- simplified
766 col = math.floor( (idx + regcol + percol) / (percol+1) )
767 -- calculate the index in the column
768 idx = idx - percol*regcol - (col - regcol - 1) * (percol+1)
769 percol = percol+1
770 else
771 idx = idx - percol*(col-1)
774 return {idx = idx, col=col, num=percol}
778 --- Set the window factor of a client
779 -- @param wfact the window factor value
780 -- @param c the client
781 function client.setwfact(wfact, c)
782 -- get the currently selected window
783 local c = c or capi.client.focus
784 if not c or not c:isvisible() then return end
786 local t = tag.selected(c.screen)
787 local w = client.idx(c)
789 local cls = client.tiled(tag.getscreen(t))
790 local nmaster = tag.getnmaster(t)
792 -- n is the number of windows currently visible for which we have to be concerned with the properties
793 local data = tag.getproperty(t, "windowfact") or {}
794 local colfact = data[w.col]
796 colfact[w.idx] = wfact
797 local rest = 1-wfact
799 -- calculate the current denominator
800 local total = 0
801 for i = 1,w.num do
802 if i ~= w.idx then
803 total = total + colfact[i]
807 -- normalize the windows
808 for i = 1,w.num do
809 if i ~= w.idx then
810 colfact[i] = (colfact[i] * rest) / total
814 t:emit_signal("property::windowfact")
817 --- Increment a client's window factor
818 -- @param add amount to increase the client's window
819 -- @param c the client
820 function client.incwfact(add, c)
821 local c = c or capi.client.focus
822 if not c then return end
824 local t = tag.selected(c.screen)
826 local w = client.idx(c)
828 local nmaster = tag.getnmaster(t)
829 local data = tag.getproperty(t, "windowfact") or {}
830 local colfact = data[w.col]
831 curr = colfact[w.idx] or 1
832 colfact[w.idx] = curr + add
834 -- keep our ratios normalized
835 normalize(colfact, w.num)
837 t:emit_signal("property::windowfact")
840 --- Get a client dockable state.
841 -- @param c A client.
842 -- @return True or false. Note that some windows might be dockable even if you
843 -- did not set them manually. For example, windows with a type "utility", "toolbar"
844 -- or "dock"
845 function client.dockable.get(c)
846 local value = client.property.get(c, "dockable")
848 -- Some sane defaults
849 if value == nil then
850 if (c.type == "utility" or c.type == "toolbar" or c.type == "dock") then
851 value = true
852 else
853 value = false
857 return value
860 --- Set a client dockable state, overriding auto-detection.
861 -- With this enabled you can dock windows by moving them from the center
862 -- to the edge of the workarea.
863 -- @param c A client.
864 -- @param value True or false.
865 function client.dockable.set(c, value)
866 client.property.set(c, "dockable", value)
869 --- Get a client property.
870 -- @param c The client.
871 -- @param prop The property name.
872 -- @return The property.
873 function client.property.get(c, prop)
874 if not client.data.persistent_properties_loaded[c] then
875 client.data.persistent_properties_loaded[c] = true
876 for p in pairs(client.data.persistent_properties_registered) do
877 local value = c:get_xproperty("awful.client.property." .. prop)
878 if value ~= nil then
879 client.property.set(c, p, value)
883 if client.data.properties[c] then
884 return client.data.properties[c][prop]
888 --- Set a client property.
889 -- This properties are internal to awful. Some are used to move clients, etc.
890 -- @param c The client.
891 -- @param prop The property name.
892 -- @param value The value.
893 function client.property.set(c, prop, value)
894 if not client.data.properties[c] then
895 client.data.properties[c] = {}
897 if client.data.persistent_properties_registered[prop] then
898 c:set_xproperty("awful.client.property." .. prop, value)
900 client.data.properties[c][prop] = value
901 c:emit_signal("property::" .. prop)
904 --- Set a client property to be persistent across restarts (via X properties).
905 -- @param prop The property name.
906 -- @param type The type (used for register_xproperty).
907 -- One of "string", "number" or "boolean".
908 function client.property.persist(prop, type)
909 local xprop = "awful.client.property." .. prop
910 capi.awesome.register_xproperty(xprop, type)
911 client.data.persistent_properties_registered[prop] = true
913 -- Make already-set properties persistent
914 for c, tab in pairs(client.data.properties) do
915 if client.data.properties[c] and client.data.properties[c][prop] ~= nil then
916 c:set_xproperty(xprop, client.data.properties[c][prop])
922 -- Returns an iterator to cycle through, starting from the client in focus or
923 -- the given index, all clients that match a given criteria.
925 -- @param filter a function that returns true to indicate a positive match
926 -- @param start what index to start iterating from. Defaults to using the
927 -- index of the currently focused client.
928 -- @param s which screen to use. nil means all screens.
930 -- @usage
931 -- -- e.g. to un-minimize all urxvt instances:
932 -- local urxvt = function (c)
933 -- return awful.rules.match(c, {class = "URxvt"})
934 -- end
936 -- for c in awful.client.iterate(urxvt) do
937 -- c.minimized = false
938 -- end
939 function client.iterate(filter, start, s)
940 local clients = capi.client.get(s)
941 local focused = capi.client.focus
942 local start = start or util.table.hasitem(clients, focused)
943 return util.table.iterate(clients, filter, start)
947 -- Switch to a client matching the given condition if running, else spawn it.
949 -- If multiple clients match the given condition then the next one is
950 -- focussed.
952 -- @param cmd the command to execute
953 -- @param matcher a function that returns true to indicate a matching client
954 -- @param merge if true then merge tags when clients are not visible
956 -- @usage
957 -- -- run or raise urxvt (perhaps, with tabs) on modkey + semicolon
958 -- awful.key({ modkey, }, 'semicolon', function ()
959 -- local matcher = function (c)
960 -- return awful.rules.match(c, {class = 'URxvt'})
961 -- end
962 -- awful.client.run_or_raise('urxvt', matcher)
963 -- end);
964 function client.run_or_raise(cmd, matcher, merge)
965 local clients = capi.client.get()
966 local findex = util.table.hasitem(clients, capi.client.focus) or 1
967 local start = util.cycle(#clients, findex + 1)
969 for c in client.iterate(matcher, start) do
970 client.jumpto(c, merge)
971 return
974 -- client not found, spawn it
975 util.spawn(cmd)
978 -- Register standards signals
979 capi.client.add_signal("property::floating_geometry")
980 capi.client.add_signal("property::floating")
981 capi.client.add_signal("property::dockable")
982 capi.client.add_signal("marked")
983 capi.client.add_signal("unmarked")
985 capi.client.connect_signal("focus", client.focus.history.add)
986 capi.client.connect_signal("unmanage", client.focus.history.delete)
988 capi.client.connect_signal("property::urgent", client.urgent.add)
989 capi.client.connect_signal("focus", client.urgent.delete)
990 capi.client.connect_signal("unmanage", client.urgent.delete)
992 capi.client.connect_signal("unmanage", client.floating.delete)
994 -- Register persistent properties
995 client.property.persist("floating", "boolean")
997 return client
999 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80