awful.client: Add a missing "local"
[awesome.git] / lib / awful / client.lua.in
blob0d69884438ca61a4bba55db651d4ff7e2d52d957
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 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,
23 --- Useful client manipulation functions.
24 -- awful.client
25 local client = {}
27 -- Private data
28 client.data = {}
29 client.data.focus = {}
30 client.data.urgent = {}
31 client.data.marked = {}
32 client.data.properties = setmetatable({}, { __mode = 'k' })
34 -- Functions
35 client.urgent = {}
36 client.focus = {}
37 client.focus.history = {}
38 client.swap = {}
39 client.floating = {}
40 client.dockable = {}
41 client.property = {}
43 ---
44 -- Jump to the given client. Takes care of focussing the screen, the right tag,
45 -- etc.
46 -- @param c the client to jump to
47 -- @param merge If true then merge tags when clients are not visible.
48 function client.jumpto(c, merge)
49 local s = capi.client.focus and capi.client.focus.screen or capi.mouse.screen
50 -- focus the screen
51 if s ~= c.screen then
52 capi.mouse.screen = c.screen
53 end
55 -- Try to make client visible, this also covers e.g. sticky
56 local t = c:tags()[1]
57 if t and not c:isvisible() then
58 if merge then
59 t.selected = true
60 else
61 tag.viewonly(t)
62 end
63 end
65 -- focus the client
66 capi.client.focus = c
67 c:raise()
68 end
70 --- Get the first client that got the urgent hint.
71 -- @return The first urgent client.
72 function client.urgent.get()
73 if #client.data.urgent > 0 then
74 return client.data.urgent[1]
75 else
76 -- fallback behaviour: iterate through clients and get the first urgent
77 local clients = capi.client.get()
78 for k, cl in pairs(clients) do
79 if cl.urgent then
80 return cl
81 end
82 end
83 end
84 end
86 --- Jump to the client that received the urgent hint first.
87 -- @param merge If true then merge tags when clients are not visible.
88 function client.urgent.jumpto(merge)
89 local c = client.urgent.get()
90 if c then
91 client.jumpto(c, merge)
92 end
93 end
95 --- Adds client to urgent stack.
96 -- @param c The client object.
97 -- @param prop The property which is updated.
98 function client.urgent.add(c, prop)
99 if type(c) == "client" and prop == "urgent" and c.urgent then
100 table.insert(client.data.urgent, c)
104 --- Remove client from urgent stack.
105 -- @param c The client object.
106 function client.urgent.delete(c)
107 for k, cl in ipairs(client.data.urgent) do
108 if c == cl then
109 table.remove(client.data.urgent, k)
110 break
115 --- Remove a client from the focus history
116 -- @param c The client that must be removed.
117 function client.focus.history.delete(c)
118 for k, v in ipairs(client.data.focus) do
119 if v == c then
120 table.remove(client.data.focus, k)
121 break
126 --- Filter out window that we do not want handled by focus.
127 -- This usually means that desktop, dock and splash windows are
128 -- not registered and cannot get focus.
129 -- @param c A client.
130 -- @return The same client if it's ok, nil otherwise.
131 function client.focus.filter(c)
132 if c.type == "desktop"
133 or c.type == "dock"
134 or c.type == "splash"
135 or not c.focusable then
136 return nil
138 return c
141 --- Update client focus history.
142 -- @param c The client that has been focused.
143 function client.focus.history.add(c)
144 -- Remove the client if its in stack
145 client.focus.history.delete(c)
146 -- Record the client has latest focused
147 table.insert(client.data.focus, 1, c)
150 --- Get the latest focused client for a screen in history.
151 -- @param screen The screen number to look for.
152 -- @param idx The index: 0 will return first candidate,
153 -- 1 will return second, etc.
154 -- @return A client.
155 function client.focus.history.get(screen, idx)
156 -- When this counter is equal to idx, we return the client
157 local counter = 0
158 local vc = client.visible(screen)
159 for k, c in ipairs(client.data.focus) do
160 if c.screen == screen then
161 for j, vcc in ipairs(vc) do
162 if vcc == c then
163 if counter == idx then
164 return c
166 -- We found one, increment the counter only.
167 counter = counter + 1
168 break
173 -- Argh nobody found in history, give the first one visible if there is one
174 -- that passes the filter.
175 if counter == 0 then
176 for k, v in ipairs(vc) do
177 if client.focus.filter(v) then
178 return v
184 --- Focus the previous client in history.
185 function client.focus.history.previous()
186 local sel = capi.client.focus
187 local s
188 if sel then
189 s = sel.screen
190 else
191 s = capi.mouse.screen
193 local c = client.focus.history.get(s, 1)
194 if c then capi.client.focus = c end
197 --- Get visible clients from a screen.
198 -- @param screen The screen number, or nil for all screens.
199 -- @return A table with all visible clients.
200 function client.visible(screen)
201 local cls = capi.client.get(screen)
202 local vcls = {}
203 for k, c in pairs(cls) do
204 if c:isvisible() then
205 table.insert(vcls, c)
208 return vcls
211 --- Get visible and tiled clients
212 -- @param screen The screen number, or nil for all screens.
213 -- @return A table with all visible and tiled clients.
214 function client.tiled(screen)
215 local clients = client.visible(screen)
216 local tclients = {}
217 -- Remove floating clients
218 for k, c in pairs(clients) do
219 if not client.floating.get(c) then
220 table.insert(tclients, c)
223 return tclients
226 --- Get a client by its relative index to the focused window.
227 -- @usage Set i to 1 to get next, -1 to get previous.
228 -- @param i The index.
229 -- @param c Optional client.
230 -- @return A client, or nil if no client is available.
231 function client.next(i, c)
232 -- Get currently focused client
233 local sel = c or capi.client.focus
234 if sel then
235 -- Get all visible clients
236 local cls = client.visible(sel.screen)
237 local fcls = {}
238 -- Remove all non-normal clients
239 for idx, c in ipairs(cls) do
240 if client.focus.filter(c) or c == sel then
241 table.insert(fcls, c)
244 cls = fcls
245 -- Loop upon each client
246 for idx, c in ipairs(cls) do
247 if c == sel then
248 -- Cycle
249 return cls[util.cycle(#cls, idx + i)]
255 -- Return true whether client B is in the right direction
256 -- compared to client A.
257 -- @param dir The direction.
258 -- @param cA The first client.
259 -- @param cB The second client.
260 -- @return True if B is in the direction of A.
261 local function is_in_direction(dir, cA, cB)
262 local gA = cA:geometry()
263 local gB = cB:geometry()
264 if dir == "up" then
265 return gA.y > gB.y
266 elseif dir == "down" then
267 return gA.y < gB.y
268 elseif dir == "left" then
269 return gA.x > gB.x
270 elseif dir == "right" then
271 return gA.x < gB.x
273 return false
276 -- Calculate distance between two points.
277 -- i.e: if we want to move to the right, we will take the right border
278 -- of the currently focused client and the left side of the checked client.
279 -- This avoid the focus of an upper client when you move to the right in a
280 -- tilebottom layout with nmaster=2 and 5 clients open, for instance.
281 -- @param dir The direction.
282 -- @param cA The first client.
283 -- @param cB The second client.
284 -- @return The distance between the clients.
285 local function calculate_distance(dir, cA, cB)
286 local gA = cA:geometry()
287 local gB = cB:geometry()
289 if dir == "up" then
290 gB.y = gB.y + gB.height
291 elseif dir == "down" then
292 gA.y = gA.y + gA.height
293 elseif dir == "left" then
294 gB.x = gB.x + gB.width
295 elseif dir == "right" then
296 gA.x = gA.x + gA.width
299 return math.sqrt(math.pow(gB.x - gA.x, 2) + math.pow(gB.y - gA.y, 2))
302 -- Get the nearest client in the given direction.
303 -- @param dir The direction, can be either "up", "down", "left" or "right".
304 -- @param c Optional client to get a client relative to. Else focussed is used.
305 local function get_client_in_direction(dir, c)
306 local sel = c or capi.client.focus
307 if sel then
308 local geometry = sel:geometry()
309 local dist, dist_min
310 local target = nil
311 local cls = client.visible(sel.screen)
313 -- We check each client.
314 for i, c in ipairs(cls) do
315 -- Check geometry to see if client is located in the right direction.
316 if is_in_direction(dir, sel, c) then
318 -- Calculate distance between focused client and checked client.
319 dist = calculate_distance(dir, sel, c)
321 -- If distance is shorter then keep the client.
322 if not target or dist < dist_min then
323 target = c
324 dist_min = dist
329 return target
333 --- Focus a client by the given direction.
334 -- @param dir The direction, can be either "up", "down", "left" or "right".
335 -- @param c Optional client.
336 function client.focus.bydirection(dir, c)
337 local sel = c or capi.client.focus
338 if sel then
339 local target = get_client_in_direction(dir, sel)
341 -- If we found a client to focus, then do it.
342 if target then
343 capi.client.focus = target
348 --- Focus a client by its relative index.
349 -- @param i The index.
350 -- @param c Optional client.
351 function client.focus.byidx(i, c)
352 local target = client.next(i, c)
353 if target then
354 capi.client.focus = target
358 --- Swap a client with another client in the given direction
359 -- @param dir The direction, can be either "up", "down", "left" or "right".
360 -- @param c Optional client.
361 function client.swap.bydirection(dir, c)
362 local sel = c or capi.client.focus
363 if sel then
364 local target = get_client_in_direction(dir, sel)
366 -- If we found a client to swap with, then go for it
367 if target then
368 target:swap(sel)
373 --- Swap a client by its relative index.
374 -- @param i The index.
375 -- @param c Optional client, otherwise focused one is used.
376 function client.swap.byidx(i, c)
377 local sel = c or capi.client.focus
378 local target = client.next(i, sel)
379 if target then
380 target:swap(sel)
384 --- Cycle clients.
385 -- @param clockwise True to cycle clients clockwise.
386 -- @param screen Optional screen where to cycle clients.
387 function client.cycle(clockwise, screen)
388 local screen = screen or capi.mouse.screen
389 local cls = client.visible(screen)
390 -- We can't rotate without at least 2 clients, buddy.
391 if #cls >= 2 then
392 local c = table.remove(cls, 1)
393 if clockwise then
394 for i = #cls, 1, -1 do
395 c:swap(cls[i])
397 else
398 for _, rc in pairs(cls) do
399 c:swap(rc)
405 --- Get the master window.
406 -- @param screen Optional screen number, otherwise screen mouse is used.
407 -- @return The master window.
408 function client.getmaster(screen)
409 local s = screen or capi.mouse.screen
410 return client.visible(s)[1]
413 --- Set the client as slave: put it at the end of other windows.
414 -- @param c The window to set as slave.
415 function client.setslave(c)
416 local cls = capi.client.get(c.screen)
417 for k, v in pairs(cls) do
418 c:swap(v)
422 --- Move/resize a client relative to current coordinates.
423 -- @param x The relative x coordinate.
424 -- @param y The relative y coordinate.
425 -- @param w The relative width.
426 -- @param h The relative height.
427 -- @param c The optional client, otherwise focused one is used.
428 function client.moveresize(x, y, w, h, c)
429 local sel = c or capi.client.focus
430 local geometry = sel:geometry()
431 geometry['x'] = geometry['x'] + x
432 geometry['y'] = geometry['y'] + y
433 geometry['width'] = geometry['width'] + w
434 geometry['height'] = geometry['height'] + h
435 sel:geometry(geometry)
438 --- Move a client to a tag.
439 -- @param target The tag to move the client to.
440 -- @param c Optional client to move, otherwise the focused one is used.
441 function client.movetotag(target, c)
442 local sel = c or capi.client.focus
443 if sel and target.screen then
444 -- Set client on the same screen as the tag.
445 sel.screen = target.screen
446 sel:tags({ target })
450 --- Toggle a tag on a client.
451 -- @param target The tag to toggle.
452 -- @param c Optional client to toggle, otherwise the focused one is used.
453 function client.toggletag(target, c)
454 local sel = c or capi.client.focus
455 -- Check that tag and client screen are identical
456 if sel and sel.screen == target.screen then
457 local tags = sel:tags()
458 local index = nil;
459 for i, v in ipairs(tags) do
460 if v == target then
461 index = i
462 break
465 if index then
466 -- If it's the only tag for the window, stop.
467 if #tags == 1 then return end
468 tags[index] = nil
469 else
470 tags[#tags + 1] = target
472 sel:tags(tags)
476 --- Move a client to a screen. Default is next screen, cycling.
477 -- @param c The client to move.
478 -- @param s The screen number, default to current + 1.
479 function client.movetoscreen(c, s)
480 local sel = c or capi.client.focus
481 if sel then
482 local sc = capi.screen.count()
483 if not s then
484 s = sel.screen + 1
486 if s > sc then s = 1 elseif s < 1 then s = sc end
487 sel.screen = s
488 capi.mouse.coords(capi.screen[s].geometry)
492 --- Mark a client, and then call 'marked' hook.
493 -- @param c The client to mark, the focused one if not specified.
494 -- @return True if the client has been marked. False if the client was already marked.
495 function client.mark(c)
496 local cl = c or capi.client.focus
497 if cl then
498 for k, v in pairs(client.data.marked) do
499 if cl == v then
500 return false
504 table.insert(client.data.marked, cl)
506 -- Call callback
507 cl:emit_signal("marked")
508 return true
512 --- Unmark a client and then call 'unmarked' hook.
513 -- @param c The client to unmark, or the focused one if not specified.
514 -- @return True if the client has been unmarked. False if the client was not marked.
515 function client.unmark(c)
516 local cl = c or capi.client.focus
518 for k, v in pairs(client.data.marked) do
519 if cl == v then
520 table.remove(client.data.marked, k)
521 cl:emit_signal("unmarked")
522 return true
526 return false
529 --- Check if a client is marked.
530 -- @param c The client to check, or the focused one otherwise.
531 function client.ismarked(c)
532 local cl = c or capi.client.focus
533 if cl then
534 for k, v in pairs(client.data.marked) do
535 if cl == v then
536 return true
540 return false
543 --- Toggle a client as marked.
544 -- @param c The client to toggle mark.
545 function client.togglemarked(c)
546 local cl = c or capi.client.focus
548 if not client.mark(c) then
549 client.unmark(c)
553 --- Return the marked clients and empty the marked table.
554 -- @return A table with all marked clients.
555 function client.getmarked()
556 for k, v in pairs(client.data.marked) do
557 v:emit_signal("unmarked")
560 t = client.data.marked
561 client.data.marked = {}
562 return t
565 --- Set a client floating state, overriding auto-detection.
566 -- Floating client are not handled by tiling layouts.
567 -- @param c A client.
568 -- @param s True or false.
569 function client.floating.set(c, s)
570 local c = c or capi.client.focus
571 if c and client.property.get(c, "floating") ~= s then
572 client.property.set(c, "floating", s)
573 local screen = c.screen
574 if s == true then
575 c:geometry(client.property.get(c, "floating_geometry"))
577 c.screen = screen
581 local function store_floating_geometry(c)
582 if client.floating.get(c) then
583 client.property.set(c, "floating_geometry", c:geometry())
587 -- Store the initial client geometry.
588 capi.client.connect_signal("new", function(c)
589 local function store_init_geometry(c)
590 client.property.set(c, "floating_geometry", c:geometry())
591 c:disconnect_signal("property::border_width", store_init_geometry)
593 c:connect_signal("property::border_width", store_init_geometry)
594 end)
596 capi.client.connect_signal("manage", function(c)
597 c:connect_signal("property::geometry", store_floating_geometry)
598 end)
600 --- Return if a client has a fixe size or not.
601 -- @param c The client.
602 function client.isfixed(c)
603 local c = c or capi.client.focus
604 if not c then return end
605 local h = c.size_hints
606 if h.min_width and h.max_width
607 and h.max_height and h.min_height
608 and h.min_width > 0 and h.max_width > 0
609 and h.max_height > 0 and h.min_height > 0
610 and h.min_width == h.max_width
611 and h.min_height == h.max_height then
612 return true
614 return false
617 --- Get a client floating state.
618 -- @param c A client.
619 -- @return True or false. Note that some windows might be floating even if you
620 -- did not set them manually. For example, windows with a type different than
621 -- normal.
622 function client.floating.get(c)
623 local c = c or capi.client.focus
624 if c then
625 local value = client.property.get(c, "floating")
626 if value ~= nil then
627 return value
629 if c.type ~= "normal"
630 or c.fullscreen
631 or c.maximized_vertical
632 or c.maximized_horizontal
633 or client.isfixed(c) then
634 return true
636 return false
640 --- Toggle the floating state of a client between 'auto' and 'true'.
641 -- @param c A client.
642 function client.floating.toggle(c)
643 local c = c or capi.client.focus
644 -- If it has been set to floating
645 if client.floating.get(c) then
646 client.floating.set(c, false)
647 else
648 client.floating.set(c, true)
652 --- Remove the floating information on a client.
653 -- @param c The client.
654 function client.floating.delete(c)
655 client.floating.set(c, nil)
658 --- Restore (=unminimize) a random client.
659 -- @param s The screen to use.
660 -- @return True if some client was restored.
661 function client.restore(s)
662 local s = s or (capi.client.focus and capi.client.focus.screen) or capi.mouse.screen
663 local cls = capi.client.get(s)
664 local tags = tag.selectedlist(s)
665 local mcls = {}
666 for k, c in pairs(cls) do
667 local ctags = c:tags()
668 if c.minimized then
669 for k, t in ipairs(tags) do
670 if util.table.hasitem(ctags, t) then
671 c.minimized = false
672 return true
677 return false
680 -- Normalize a set of numbers to 1
681 -- @param set the set of numbers to normalize
682 -- @param num the number of numbers to normalize
683 local function normalize(set, num)
684 local num = num or #set
685 local total = 0
686 if num then
687 for i = 1,num do
688 total = total + set[i]
690 for i = 1,num do
691 set[i] = set[i] / total
693 else
694 for i,v in ipairs(set) do
695 total = total + v
698 for i,v in ipairs(set) do
699 set[i] = v / total
704 --- Calculate a client's column number, index in that column, and
705 -- number of visible clients in this column.
706 -- @param c the client
707 -- @return col the column number
708 -- @return idx index of the client in the column
709 -- @return num the number of visible clients in the column
710 function client.idx(c)
711 local c = c or capi.client.focus
712 if not c then return end
714 local clients = client.tiled(c.screen)
715 local idx = nil
716 for k, cl in ipairs(clients) do
717 if cl == c then
718 idx = k
719 break
723 local t = tag.selected(c.screen)
724 local nmaster = tag.getnmaster(t)
725 if idx <= nmaster then
726 return {idx = idx, col=0, num=nmaster}
728 local nother = #clients - nmaster
729 idx = idx - nmaster
731 -- rather than regenerate the column number we can calculate it
732 -- based on the how the tiling algorithm places clients we calculate
733 -- the column, we could easily use the for loop in the program but we can
734 -- calculate it.
735 local ncol = tag.getncol(t)
736 -- minimum number of clients per column
737 local percol = math.floor(nother / ncol)
738 -- number of columns with an extra client
739 local overcol = math.fmod(nother, ncol)
740 -- number of columns filled with [percol] clients
741 local regcol = ncol - overcol
743 local col = math.floor( (idx - 1) / percol) + 1
744 if col > regcol then
745 -- col = math.floor( (idx - (percol*regcol) - 1) / (percol + 1) ) + regcol + 1
746 -- simplified
747 col = math.floor( (idx + regcol + percol) / (percol+1) )
748 -- calculate the index in the column
749 idx = idx - percol*regcol - (col - regcol - 1) * (percol+1)
750 percol = percol+1
751 else
752 idx = idx - percol*(col-1)
755 return {idx = idx, col=col, num=percol}
759 --- Set the window factor of a client
760 -- @param wfact the window factor value
761 -- @param c the client
762 function client.setwfact(wfact, c)
763 -- get the currently selected window
764 local c = c or capi.client.focus
765 if not c or not c:isvisible() then return end
767 local t = tag.selected(c.screen)
768 local w = client.idx(c)
770 local cls = client.tiled(t.screen)
771 local nmaster = tag.getnmaster(t)
773 -- n is the number of windows currently visible for which we have to be concerned with the properties
774 local data = tag.getproperty(t, "windowfact") or {}
775 local colfact = data[w.col]
777 colfact[w.idx] = wfact
778 local rest = 1-wfact
780 -- calculate the current denominator
781 local total = 0
782 for i = 1,w.num do
783 if i ~= w.idx then
784 total = total + colfact[i]
788 -- normalize the windows
789 for i = 1,w.num do
790 if i ~= w.idx then
791 colfact[i] = (colfact[i] * rest) / total
795 t:emit_signal("property::windowfact")
798 --- Increment a client's window factor
799 -- @param add amount to increase the client's window
800 -- @param c the client
801 function client.incwfact(add, c)
802 local c = c or capi.client.focus
803 if not c then return end
805 local t = tag.selected(c.screen)
807 local w = client.idx(c)
809 local nmaster = tag.getnmaster(t)
810 local data = tag.getproperty(t, "windowfact") or {}
811 local colfact = data[w.col]
812 curr = colfact[w.idx] or 1
813 colfact[w.idx] = curr + add
815 -- keep our ratios normalized
816 normalize(colfact, w.num)
818 t:emit_signal("property::windowfact")
821 --- Get a client dockable state.
822 -- @param c A client.
823 -- @return True or false. Note that some windows might be dockable even if you
824 -- did not set them manually. For example, windows with a type "utility", "toolbar"
825 -- or "dock"
826 function client.dockable.get(c)
827 local value = client.property.get(c, "dockable")
829 -- Some sane defaults
830 if value == nil then
831 if (c.type == "utility" or c.type == "toolbar" or c.type == "dock") then
832 value = true
833 else
834 value = false
838 return value
841 --- Set a client dockable state, overriding auto-detection.
842 -- With this enabled you can dock windows by moving them from the center
843 -- to the edge of the workarea.
844 -- @param c A client.
845 -- @param value True or false.
846 function client.dockable.set(c, value)
847 client.property.set(c, "dockable", value)
850 --- Get a client property.
851 -- @param c The client.
852 -- @param prop The property name.
853 -- @return The property.
854 function client.property.get(c, prop)
855 if client.data.properties[c] then
856 return client.data.properties[c][prop]
860 --- Set a client property.
861 -- This properties are internal to awful. Some are used to move clients, etc.
862 -- @param c The client.
863 -- @param prop The property name.
864 -- @param value The value.
865 function client.property.set(c, prop, value)
866 if not client.data.properties[c] then
867 client.data.properties[c] = {}
869 client.data.properties[c][prop] = value
870 c:emit_signal("property::" .. prop)
874 -- Returns an iterator to cycle through, starting from the client in focus or
875 -- the given index, all clients that match a given criteria.
877 -- @param filter a function that returns true to indicate a positive match
878 -- @param start what index to start iterating from. Defaults to using the
879 -- index of the currently focused client.
880 -- @param s which screen to use. nil means all screens.
882 -- @usage e.g.: un-minimize all urxvt instances
883 -- <p><code>
884 -- local urxvt = function (c) <br/>
885 -- return awful.rules.match(c, {class = "URxvt"}) <br/>
886 -- end <br/>
887 -- </br>
888 -- for c in awful.client.iterate(urxvt) do <br/>
889 -- c.minimized = false <br/>
890 -- end <br/>
891 -- </code></p>
892 function client.iterate(filter, start, s)
893 local clients = capi.client.get(s)
894 local focused = capi.client.focus
895 local start = start or util.table.hasitem(clients, focused)
896 return util.table.iterate(clients, filter, start)
900 -- <p>Switch to a client matching the given condition if running, else spawn it.
901 -- If multiple clients match the given condition then the next one is
902 -- focussed.</p>
904 -- @param cmd the command to execute
905 -- @param matcher a function that returns true to indicate a matching client
906 -- @param merge if true then merge tags when clients are not visible
908 -- @usage run or raise urxvt (perhaps, with tabs) on modkey + semicolon
909 -- <p><code>
910 -- awful.key({ modkey, }, 'semicolon', function () <br/>
911 -- local matcher = function (c) <br/>
912 -- return awful.rules.match(c, {class = 'URxvt'}) <br/>
913 -- end <br/>
914 -- awful.client.run_or_raise('urxvt', matcher)
915 -- end);
916 -- </code></p>
917 function client.run_or_raise(cmd, matcher, merge)
918 local clients = capi.client.get()
919 local findex = util.table.hasitem(clients, capi.client.focus) or 1
920 local start = util.cycle(#clients, findex + 1)
922 for c in iterate(matcher, start) do
923 client.jumpto(c, merge)
924 return
927 -- client not found, spawn it
928 util.spawn(cmd)
931 -- Register standards signals
932 capi.client.add_signal("property::floating_geometry")
933 capi.client.add_signal("property::floating")
934 capi.client.add_signal("property::dockable")
936 capi.client.connect_signal("focus", client.focus.history.add)
937 capi.client.connect_signal("unmanage", client.focus.history.delete)
939 capi.client.connect_signal("manage", function(c) c:connect_signal("property::urgent", client.urgent.add) end)
940 capi.client.connect_signal("focus", client.urgent.delete)
941 capi.client.connect_signal("unmanage", client.urgent.delete)
943 capi.client.connect_signal("unmanage", client.floating.delete)
945 return client
947 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80