summaryrefslogtreecommitdiff
path: root/awesome/lib/awful/client.lua
diff options
context:
space:
mode:
Diffstat (limited to 'awesome/lib/awful/client.lua')
-rw-r--r--awesome/lib/awful/client.lua1238
1 files changed, 0 insertions, 1238 deletions
diff --git a/awesome/lib/awful/client.lua b/awesome/lib/awful/client.lua
deleted file mode 100644
index 809c055..0000000
--- a/awesome/lib/awful/client.lua
+++ /dev/null
@@ -1,1238 +0,0 @@
----------------------------------------------------------------------------
---- Useful client manipulation functions.
---
--- @author Julien Danjou <julien@danjou.info>
--- @copyright 2008 Julien Danjou
--- @module client
----------------------------------------------------------------------------
-
--- Grab environment we need
-local util = require("awful.util")
-local spawn = require("awful.spawn")
-local object = require("gears.object")
-local grect = require("gears.geometry").rectangle
-local pairs = pairs
-local type = type
-local ipairs = ipairs
-local table = table
-local math = math
-local setmetatable = setmetatable
-local capi =
-{
- client = client,
- mouse = mouse,
- screen = screen,
- awesome = awesome,
-}
-
-local function get_screen(s)
- return s and capi.screen[s]
-end
-
--- We use a metatable to prevent circular dependency loops.
-local screen
-do
- screen = setmetatable({}, {
- __index = function(_, k)
- screen = require("awful.screen")
- return screen[k]
- end,
- __newindex = error -- Just to be sure in case anything ever does this
- })
-end
-local client = {object={}}
-
--- Private data
-client.data = {}
-client.data.marked = {}
-client.data.persistent_properties_registered = {} -- keys are names of persistent properties, value always true
-
--- Functions
-client.urgent = require("awful.client.urgent")
-client.swap = {}
-client.floating = {}
-client.dockable = {}
-client.property = {}
-client.shape = require("awful.client.shape")
-client.focus = require("awful.client.focus")
-
---- Jump to the given client.
--- Takes care of focussing the screen, the right tag, etc.
---
--- @deprecated awful.client.jumpto
--- @see client.jump_to
--- @client c the client to jump to
--- @tparam bool|function merge If true then merge tags (select the client's
--- first tag additionally) when the client is not visible.
--- If it is a function, it will be called with the client and its first
--- tag as arguments.
-function client.jumpto(c, merge)
- util.deprecate("Use c:jump_to(merge) instead of awful.client.jumpto")
- client.object.jump_to(c, merge)
-end
-
---- Jump to the given client.
--- Takes care of focussing the screen, the right tag, etc.
---
--- @function client.jump_to
--- @tparam bool|function merge If true then merge tags (select the client's
--- first tag additionally) when the client is not visible.
--- If it is a function, it will be called with the client and its first
--- tag as arguments.
-function client.object.jump_to(self, merge)
- local s = get_screen(screen.focused())
- -- focus the screen
- if s ~= get_screen(self.screen) then
- screen.focus(self.screen)
- end
-
- self.minimized = false
-
- -- Try to make client visible, this also covers e.g. sticky.
- if not self:isvisible() then
- local t = self.first_tag
- if merge then
- if type(merge) == "function" then
- merge(self, t)
- elseif t then
- t.selected = true
- end
- elseif t then
- t:view_only()
- end
- end
-
- self:emit_signal("request::activate", "client.jumpto", {raise=true})
-end
-
---- Get visible clients from a screen.
---
--- @deprecated awful.client.visible
--- @see screen.clients
--- @tparam[opt] integer|screen s The screen, or nil for all screens.
--- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
--- @treturn table A table with all visible clients.
-function client.visible(s, stacked)
- local cls = capi.client.get(s, stacked)
- local vcls = {}
- for _, c in pairs(cls) do
- if c:isvisible() then
- table.insert(vcls, c)
- end
- end
- return vcls
-end
-
---- Get visible and tiled clients
---
--- @deprecated awful.client.tiled
--- @see screen.tiled_clients
--- @tparam integer|screen s The screen, or nil for all screens.
--- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
--- @treturn table A table with all visible and tiled clients.
-function client.tiled(s, stacked)
- local clients = client.visible(s, stacked)
- local tclients = {}
- -- Remove floating clients
- for _, c in pairs(clients) do
- if not client.object.get_floating(c)
- and not c.fullscreen
- and not c.maximized_vertical
- and not c.maximized_horizontal then
- table.insert(tclients, c)
- end
- end
- return tclients
-end
-
---- Get a client by its relative index to another client.
--- If no client is passed, the focused client will be used.
---
--- @function awful.client.next
--- @tparam int i The index. Use 1 to get the next, -1 to get the previous.
--- @client[opt] sel The client.
--- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
--- @return A client, or nil if no client is available.
---
--- @usage -- focus the next window in the index
--- awful.client.next(1)
--- -- focus the previous
--- awful.client.next(-1)
-function client.next(i, sel, stacked)
- -- Get currently focused client
- sel = sel or capi.client.focus
- if sel then
- -- Get all visible clients
- local cls = client.visible(sel.screen, stacked)
- local fcls = {}
- -- Remove all non-normal clients
- for _, c in ipairs(cls) do
- if client.focus.filter(c) or c == sel then
- table.insert(fcls, c)
- end
- end
- cls = fcls
- -- Loop upon each client
- for idx, c in ipairs(cls) do
- if c == sel then
- -- Cycle
- return cls[util.cycle(#cls, idx + i)]
- end
- end
- end
-end
-
---- Swap a client with another client in the given direction.
--- @function awful.client.swap.bydirection
--- @tparam string dir The direction, can be either "up", "down", "left" or "right".
--- @client[opt=focused] c The client.
--- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-function client.swap.bydirection(dir, c, stacked)
- local sel = c or capi.client.focus
- if sel then
- local cltbl = client.visible(sel.screen, stacked)
- local geomtbl = {}
- for i,cl in ipairs(cltbl) do
- geomtbl[i] = cl:geometry()
- end
- local target = grect.get_in_direction(dir, geomtbl, sel:geometry())
-
- -- If we found a client to swap with, then go for it
- if target then
- cltbl[target]:swap(sel)
- end
- end
-end
-
---- Swap a client with another client in the given direction. Swaps across screens.
--- @function awful.client.swap.global_bydirection
--- @param dir The direction, can be either "up", "down", "left" or "right".
--- @client[opt] sel The client.
-function client.swap.global_bydirection(dir, sel)
- sel = sel or capi.client.focus
- local scr = get_screen(sel and sel.screen or screen.focused())
-
- if sel then
- -- move focus
- client.focus.global_bydirection(dir, sel)
- local c = capi.client.focus
-
- -- swapping inside a screen
- if get_screen(sel.screen) == get_screen(c.screen) and sel ~= c then
- c:swap(sel)
-
- -- swapping to an empty screen
- elseif get_screen(sel.screen) ~= get_screen(c.screen) and sel == c then
- sel:move_to_screen(screen.focused())
-
- -- swapping to a nonempty screen
- elseif get_screen(sel.screen) ~= get_screen(c.screen) and sel ~= c then
- sel:move_to_screen(c.screen)
- c:move_to_screen(scr)
- end
-
- screen.focus(sel.screen)
- sel:emit_signal("request::activate", "client.swap.global_bydirection",
- {raise=false})
- end
-end
-
---- Swap a client by its relative index.
--- @function awful.client.swap.byidx
--- @param i The index.
--- @client[opt] c The client, otherwise focused one is used.
-function client.swap.byidx(i, c)
- local sel = c or capi.client.focus
- local target = client.next(i, sel)
- if target then
- target:swap(sel)
- end
-end
-
---- Cycle clients.
---
--- @function awful.client.cycle
--- @param clockwise True to cycle clients clockwise.
--- @param[opt] s The screen where to cycle clients.
--- @tparam[opt=false] boolean stacked Use stacking order? (top to bottom)
-function client.cycle(clockwise, s, stacked)
- s = s or screen.focused()
- local cls = client.visible(s, stacked)
- -- We can't rotate without at least 2 clients, buddy.
- if #cls >= 2 then
- local c = table.remove(cls, 1)
- if clockwise then
- for i = #cls, 1, -1 do
- c:swap(cls[i])
- end
- else
- for _, rc in pairs(cls) do
- c:swap(rc)
- end
- end
- end
-end
-
---- Get the master window.
---
--- @legacylayout awful.client.getmaster
--- @screen_or_idx[opt=awful.screen.focused()] s The screen.
--- @return The master window.
-function client.getmaster(s)
- s = s or screen.focused()
- return client.visible(s)[1]
-end
-
---- Set the client as master: put it at the beginning of other windows.
---
--- @legacylayout awful.client.setmaster
--- @client c The window to set as master.
-function client.setmaster(c)
- local cls = util.table.reverse(capi.client.get(c.screen))
- for _, v in pairs(cls) do
- c:swap(v)
- end
-end
-
---- Set the client as slave: put it at the end of other windows.
--- @legacylayout awful.client.setslave
--- @client c The window to set as slave.
-function client.setslave(c)
- local cls = capi.client.get(c.screen)
- for _, v in pairs(cls) do
- c:swap(v)
- end
-end
-
---- Move/resize a client relative to current coordinates.
--- @deprecated awful.client.moveresize
--- @param x The relative x coordinate.
--- @param y The relative y coordinate.
--- @param w The relative width.
--- @param h The relative height.
--- @client[opt] c The client, otherwise focused one is used.
--- @see client.relative_move
-function client.moveresize(x, y, w, h, c)
- util.deprecate("Use c:relative_move(x, y, w, h) instead of awful.client.moveresize")
- client.object.relative_move(c or capi.client.focus, x, y, w, h)
-end
-
---- Move/resize a client relative to current coordinates.
--- @function client.relative_move
--- @see geometry
--- @tparam[opt=c.x] number x The relative x coordinate.
--- @tparam[opt=c.y] number y The relative y coordinate.
--- @tparam[opt=c.width] number w The relative width.
--- @tparam[opt=c.height] number h The relative height.
-function client.object.relative_move(self, x, y, w, h)
- local geometry = self:geometry()
- geometry['x'] = geometry['x'] + x
- geometry['y'] = geometry['y'] + y
- geometry['width'] = geometry['width'] + w
- geometry['height'] = geometry['height'] + h
- self:geometry(geometry)
-end
-
---- Move a client to a tag.
--- @deprecated awful.client.movetotag
--- @param target The tag to move the client to.
--- @client[opt] c The client to move, otherwise the focused one is used.
--- @see client.move_to_tag
-function client.movetotag(target, c)
- util.deprecate("Use c:move_to_tag(target) instead of awful.client.movetotag")
- client.object.move_to_tag(c or capi.client.focus, target)
-end
-
---- Move a client to a tag.
--- @function client.move_to_tag
--- @tparam tag target The tag to move the client to.
-function client.object.move_to_tag(self, target)
- local s = target.screen
- if self and s then
- if self == capi.client.focus then
- self:emit_signal("request::activate", "client.movetotag", {raise=true})
- end
- -- Set client on the same screen as the tag.
- self.screen = s
- self:tags({ target })
- end
-end
-
---- Toggle a tag on a client.
--- @deprecated awful.client.toggletag
--- @param target The tag to toggle.
--- @client[opt] c The client to toggle, otherwise the focused one is used.
--- @see client.toggle_tag
-function client.toggletag(target, c)
- util.deprecate("Use c:toggle_tag(target) instead of awful.client.toggletag")
- client.object.toggle_tag(c or capi.client.focus, target)
-end
-
---- Toggle a tag on a client.
--- @function client.toggle_tag
--- @tparam tag target The tag to move the client to.
-function client.object.toggle_tag(self, target)
- -- Check that tag and client screen are identical
- if self and get_screen(self.screen) == get_screen(target.screen) then
- local tags = self:tags()
- local index = nil;
- for i, v in ipairs(tags) do
- if v == target then
- index = i
- break
- end
- end
- if index then
- -- If it's the only tag for the window, stop.
- if #tags == 1 then return end
- tags[index] = nil
- else
- tags[#tags + 1] = target
- end
- self:tags(tags)
- end
-end
-
---- Move a client to a screen. Default is next screen, cycling.
--- @deprecated awful.client.movetoscreen
--- @client c The client to move.
--- @param s The screen, default to current + 1.
--- @see screen
--- @see client.move_to_screen
-function client.movetoscreen(c, s)
- util.deprecate("Use c:move_to_screen(s) instead of awful.client.movetoscreen")
- client.object.move_to_screen(c or capi.client.focus, s)
-end
-
---- Move a client to a screen. Default is next screen, cycling.
--- @function client.move_to_screen
--- @tparam[opt=c.screen.index+1] screen s The screen, default to current + 1.
--- @see screen
--- @see request::activate
-function client.object.move_to_screen(self, s)
- if self then
- local sc = capi.screen.count()
- if not s then
- s = self.screen.index + 1
- end
- if type(s) == "number" then
- if s > sc then s = 1 elseif s < 1 then s = sc end
- end
- s = get_screen(s)
- if get_screen(self.screen) ~= s then
- local sel_is_focused = self == capi.client.focus
- self.screen = s
- screen.focus(s)
-
- if sel_is_focused then
- self:emit_signal("request::activate", "client.movetoscreen",
- {raise=true})
- end
- end
- end
-end
-
---- Tag a client with the set of current tags.
--- @function client.to_selected_tags
--- @see screen.selected_tags
-function client.object.to_selected_tags(self)
- local tags = {}
-
- for _, t in ipairs(self:tags()) do
- if get_screen(t.screen) == get_screen(self.screen) then
- table.insert(tags, t)
- end
- end
-
- if self.screen then
- if #tags == 0 then
- tags = self.screen.selected_tags
- end
-
- if #tags == 0 then
- tags = self.screen.tags
- end
- end
-
- if #tags ~= 0 then
- self:tags(tags)
- end
-end
-
---- If a client is marked or not.
---
--- **Signal:**
---
--- * *marked* (for legacy reasons, use `property::marked`)
--- * *unmarked* (for legacy reasons, use `property::marked`)
--- * *property::marked*
---
--- @property marked
--- @param boolean
-
---- The border color when the client is focused.
---
--- @beautiful beautiful.border_marked
--- @param string
---
-
-function client.object.set_marked(self, value)
- local is_marked = self.marked
-
- if value == false and is_marked then
- for k, v in pairs(client.data.marked) do
- if self == v then
- table.remove(client.data.marked, k)
- end
- end
- self:emit_signal("unmarked")
- elseif not is_marked and value then
- self:emit_signal("marked")
- table.insert(client.data.marked, self)
- end
-
- client.property.set(self, "marked", value)
-end
-
-function client.object.get_marked(self)
- return client.property.get(self, "marked")
-end
-
---- Mark a client, and then call 'marked' hook.
--- @deprecated awful.client.mark
--- @client c The client to mark, the focused one if not specified.
-function client.mark(c)
- util.deprecate("Use c.marked = true instead of awful.client.mark")
- client.object.set_marked(c or capi.client.focus, true)
-end
-
---- Unmark a client and then call 'unmarked' hook.
--- @deprecated awful.client.unmark
--- @client c The client to unmark, or the focused one if not specified.
-function client.unmark(c)
- util.deprecate("Use c.marked = false instead of awful.client.unmark")
- client.object.set_marked(c or capi.client.focus, false)
-end
-
---- Check if a client is marked.
--- @deprecated awful.client.ismarked
--- @client c The client to check, or the focused one otherwise.
-function client.ismarked(c)
- util.deprecate("Use c.marked instead of awful.client.ismarked")
- return client.object.get_marked(c or capi.client.focus)
-end
-
---- Toggle a client as marked.
--- @deprecated awful.client.togglemarked
--- @client c The client to toggle mark.
-function client.togglemarked(c)
- util.deprecate("Use c.marked = not c.marked instead of awful.client.togglemarked")
- c = c or capi.client.focus
- if c then
- c.marked = not c.marked
- end
-end
-
---- Return the marked clients and empty the marked table.
--- @function awful.client.getmarked
--- @return A table with all marked clients.
-function client.getmarked()
- local copy = util.table.clone(client.data.marked, false)
-
- for _, v in pairs(copy) do
- client.property.set(v, "marked", false)
- v:emit_signal("unmarked")
- end
-
- client.data.marked = {}
-
- return copy
-end
-
---- Set a client floating state, overriding auto-detection.
--- Floating client are not handled by tiling layouts.
--- @deprecated awful.client.floating.set
--- @client c A client.
--- @param s True or false.
-function client.floating.set(c, s)
- util.deprecate("Use c.floating = true instead of awful.client.floating.set")
- client.object.set_floating(c, s)
-end
-
--- Set a client floating state, overriding auto-detection.
--- Floating client are not handled by tiling layouts.
--- @client c A client.
--- @param s True or false.
-function client.object.set_floating(c, s)
- c = c or capi.client.focus
- if c and client.property.get(c, "floating") ~= s then
- client.property.set(c, "floating", s)
- local scr = c.screen
- if s == true then
- c:geometry(client.property.get(c, "floating_geometry"))
- end
- c.screen = scr
- end
-end
-
-local function store_floating_geometry(c)
- if client.object.get_floating(c) then
- client.property.set(c, "floating_geometry", c:geometry())
- end
-end
-
--- Store the initial client geometry.
-capi.client.connect_signal("new", function(cl)
- local function store_init_geometry(c)
- client.property.set(c, "floating_geometry", c:geometry())
- c:disconnect_signal("property::border_width", store_init_geometry)
- end
- cl:connect_signal("property::border_width", store_init_geometry)
-end)
-
-capi.client.connect_signal("property::geometry", store_floating_geometry)
-
---- Return if a client has a fixed size or not.
--- This function is deprecated, use `c.is_fixed`
--- @client c The client.
--- @deprecated awful.client.isfixed
--- @see is_fixed
--- @see size_hints_honor
-function client.isfixed(c)
- util.deprecate("Use c.is_fixed instead of awful.client.isfixed")
- c = c or capi.client.focus
- return client.object.is_fixed(c)
-end
-
---- Return if a client has a fixed size or not.
---
--- **Signal:**
---
--- * *property::is_fixed*
---
--- This property is read only.
--- @property is_fixed
--- @param boolean The floating state
--- @see size_hints
--- @see size_hints_honor
-
-function client.object.is_fixed(c)
- if not c then return end
- local h = c.size_hints
- if h.min_width and h.max_width
- and h.max_height and h.min_height
- and h.min_width > 0 and h.max_width > 0
- and h.max_height > 0 and h.min_height > 0
- and h.min_width == h.max_width
- and h.min_height == h.max_height then
- return true
- end
- return false
-end
-
---- Get a client floating state.
--- @client c A client.
--- @see floating
--- @deprecated awful.client.floating.get
--- @return True or false. Note that some windows might be floating even if you
--- did not set them manually. For example, windows with a type different than
--- normal.
-function client.floating.get(c)
- util.deprecate("Use c.floating instead of awful.client.floating.get")
- return client.object.get_floating(c)
-end
-
---- The client floating state.
--- If the client is part of the tiled layout or free floating.
---
--- Note that some windows might be floating even if you
--- did not set them manually. For example, windows with a type different than
--- normal.
---
--- **Signal:**
---
--- * *property::floating*
---
--- @property floating
--- @param boolean The floating state
-
-function client.object.get_floating(c)
- c = c or capi.client.focus
- if c then
- local value = client.property.get(c, "floating")
- if value ~= nil then
- return value
- end
- if c.type ~= "normal"
- or c.fullscreen
- or c.maximized_vertical
- or c.maximized_horizontal
- or client.object.is_fixed(c) then
- return true
- end
- return false
- end
-end
-
---- Toggle the floating state of a client between 'auto' and 'true'.
--- Use `c.floating = not c.floating`
--- @deprecated awful.client.floating.toggle
--- @client c A client.
--- @see floating
-function client.floating.toggle(c)
- c = c or capi.client.focus
- -- If it has been set to floating
- client.object.set_floating(c, not client.object.get_floating(c))
-end
-
--- Remove the floating information on a client.
--- @client c The client.
-function client.floating.delete(c)
- client.object.set_floating(c, nil)
-end
-
---- The x coordinates.
---
--- **Signal:**
---
--- * *property::x*
---
--- @property x
--- @param integer
-
---- The y coordinates.
---
--- **Signal:**
---
--- * *property::y*
---
--- @property y
--- @param integer
-
---- The width of the wibox.
---
--- **Signal:**
---
--- * *property::width*
---
--- @property width
--- @param width
-
---- The height of the wibox.
---
--- **Signal:**
---
--- * *property::height*
---
--- @property height
--- @param height
-
--- Add the geometry helpers to match the wibox API
-for _, v in ipairs {"x", "y", "width", "height"} do
- client.object["get_"..v] = function(c)
- return c:geometry()[v]
- end
-
- client.object["set_"..v] = function(c, value)
- return c:geometry({[v] = value})
- end
-end
-
-
---- Restore (=unminimize) a random client.
--- @function awful.client.restore
--- @param s The screen to use.
--- @return The restored client if some client was restored, otherwise nil.
-function client.restore(s)
- s = s or screen.focused()
- local cls = capi.client.get(s)
- local tags = s.selected_tags
- for _, c in pairs(cls) do
- local ctags = c:tags()
- if c.minimized then
- for _, t in ipairs(tags) do
- if util.table.hasitem(ctags, t) then
- c.minimized = false
- return c
- end
- end
- end
- end
- return nil
-end
-
---- Normalize a set of numbers to 1
--- @param set the set of numbers to normalize
--- @param num the number of numbers to normalize
-local function normalize(set, num)
- num = num or #set
- local total = 0
- if num then
- for i = 1,num do
- total = total + set[i]
- end
- for i = 1,num do
- set[i] = set[i] / total
- end
- else
- for _,v in ipairs(set) do
- total = total + v
- end
-
- for i,v in ipairs(set) do
- set[i] = v / total
- end
- end
-end
-
---- Calculate a client's column number, index in that column, and
--- number of visible clients in this column.
---
--- @legacylayout awful.client.idx
--- @client c the client
--- @return col the column number
--- @return idx index of the client in the column
--- @return num the number of visible clients in the column
-function client.idx(c)
- c = c or capi.client.focus
- if not c then return end
-
- -- Only check the tiled clients, the others un irrelevant
- local clients = client.tiled(c.screen)
- local idx = nil
- for k, cl in ipairs(clients) do
- if cl == c then
- idx = k
- break
- end
- end
-
- local t = c.screen.selected_tag
- local nmaster = t.master_count
-
- -- This will happen for floating or maximized clients
- if not idx then return nil end
-
- if idx <= nmaster then
- return {idx = idx, col=0, num=nmaster}
- end
- local nother = #clients - nmaster
- idx = idx - nmaster
-
- -- rather than regenerate the column number we can calculate it
- -- based on the how the tiling algorithm places clients we calculate
- -- the column, we could easily use the for loop in the program but we can
- -- calculate it.
- local ncol = t.column_count
- -- minimum number of clients per column
- local percol = math.floor(nother / ncol)
- -- number of columns with an extra client
- local overcol = math.fmod(nother, ncol)
- -- number of columns filled with [percol] clients
- local regcol = ncol - overcol
-
- local col = math.floor( (idx - 1) / percol) + 1
- if col > regcol then
- -- col = math.floor( (idx - (percol*regcol) - 1) / (percol + 1) ) + regcol + 1
- -- simplified
- col = math.floor( (idx + regcol + percol) / (percol+1) )
- -- calculate the index in the column
- idx = idx - percol*regcol - (col - regcol - 1) * (percol+1)
- percol = percol+1
- else
- idx = idx - percol*(col-1)
- end
-
- return {idx = idx, col=col, num=percol}
-end
-
-
---- Set the window factor of a client
---
--- @legacylayout awful.client.setwfact
--- @param wfact the window factor value
--- @client c the client
-function client.setwfact(wfact, c)
- -- get the currently selected window
- c = c or capi.client.focus
- if not c or not c:isvisible() then return end
-
- local w = client.idx(c)
-
- if not w then return end
-
- local t = c.screen.selected_tag
-
- -- n is the number of windows currently visible for which we have to be concerned with the properties
- local data = t.windowfact or {}
- local colfact = data[w.col]
-
- local need_normalize = colfact ~= nil
-
- if not need_normalize then
- colfact = {}
- end
-
- colfact[w.idx] = wfact
-
- if not need_normalize then
- t:emit_signal("property::windowfact")
- return
- end
-
- local rest = 1-wfact
-
- -- calculate the current denominator
- local total = 0
- for i = 1,w.num do
- if i ~= w.idx then
- total = total + colfact[i]
- end
- end
-
- -- normalize the windows
- for i = 1,w.num do
- if i ~= w.idx then
- colfact[i] = (colfact[i] * rest) / total
- end
- end
-
- t:emit_signal("property::windowfact")
-end
-
---- Change window factor of a client.
---
--- @legacylayout awful.client.incwfact
--- @tparam number add Amount to increase/decrease the client's window factor.
--- Should be between `-current_window_factor` and something close to
--- infinite. The normalisation then ensures that the sum of all factors is 1.
--- @client c the client
-function client.incwfact(add, c)
- c = c or capi.client.focus
- if not c then return end
-
- local t = c.screen.selected_tag
- local w = client.idx(c)
- local data = t.windowfact or {}
- local colfact = data[w.col] or {}
- local curr = colfact[w.idx] or 1
- colfact[w.idx] = curr + add
-
- -- keep our ratios normalized
- normalize(colfact, w.num)
-
- t:emit_signal("property::windowfact")
-end
-
---- Get a client dockable state.
---
--- @client c A client.
--- @return True or false. Note that some windows might be dockable even if you
--- did not set them manually. For example, windows with a type "utility",
--- "toolbar" or "dock"
--- @deprecated awful.client.dockable.get
-function client.dockable.get(c)
- util.deprecate("Use c.dockable instead of awful.client.dockable.get")
- return client.object.get_dockable(c)
-end
-
---- If the client is dockable.
--- A dockable client is an application confined to the edge of the screen. The
--- space it occupy is substracted from the `screen.workarea`.
---
--- **Signal:**
---
--- * *property::dockable*
---
--- @property dockable
--- @param boolean The dockable state
-
-function client.object.get_dockable(c)
- local value = client.property.get(c, "dockable")
-
- -- Some sane defaults
- if value == nil then
- if (c.type == "utility" or c.type == "toolbar" or c.type == "dock") then
- value = true
- else
- value = false
- end
- end
-
- return value
-end
-
---- Set a client dockable state, overriding auto-detection.
--- With this enabled you can dock windows by moving them from the center
--- to the edge of the workarea.
---
--- @client c A client.
--- @param value True or false.
--- @deprecated awful.client.dockable.set
-function client.dockable.set(c, value)
- util.deprecate("Use c.dockable = value instead of awful.client.dockable.set")
- client.property.set(c, "dockable", value)
-end
-
---- Get a client property.
---
--- This method is deprecated. It is now possible to use `c.value` directly.
---
--- @client c The client.
--- @param prop The property name.
--- @return The property.
--- @deprecated awful.client.property.get
-function client.property.get(c, prop)
- if not c.data._persistent_properties_loaded then
- c.data._persistent_properties_loaded = true
- for p in pairs(client.data.persistent_properties_registered) do
- local value = c:get_xproperty("awful.client.property." .. p)
- if value ~= nil then
- client.property.set(c, p, value)
- end
- end
- end
- if c.data.awful_client_properties then
- return c.data.awful_client_properties[prop]
- end
-end
-
---- Set a client property.
---
--- This method is deprecated. It is now possible to use `c.value = value`
--- directly.
---
--- @client c The client.
--- @param prop The property name.
--- @param value The value.
--- @deprecated awful.client.property.set
-function client.property.set(c, prop, value)
- if not c.data.awful_client_properties then
- c.data.awful_client_properties = {}
- end
- if c.data.awful_client_properties[prop] ~= value then
- if client.data.persistent_properties_registered[prop] then
- c:set_xproperty("awful.client.property." .. prop, value)
- end
- c.data.awful_client_properties[prop] = value
- c:emit_signal("property::" .. prop)
- end
-end
-
---- Set a client property to be persistent across restarts (via X properties).
---
--- @function awful.client.property.persist
--- @param prop The property name.
--- @param kind The type (used for register_xproperty).
--- One of "string", "number" or "boolean".
-function client.property.persist(prop, kind)
- local xprop = "awful.client.property." .. prop
- capi.awesome.register_xproperty(xprop, kind)
- client.data.persistent_properties_registered[prop] = true
-
- -- Make already-set properties persistent
- for c in pairs(capi.client.get()) do
- if c.data.awful_client_properties and c.data.awful_client_properties[prop] ~= nil then
- c:set_xproperty(xprop, c.data.awful_client_properties[prop])
- end
- end
-end
-
----
--- Returns an iterator to cycle through, starting from the client in focus or
--- the given index, all clients that match a given criteria.
---
--- @param filter a function that returns true to indicate a positive match
--- @param start what index to start iterating from. Defaults to using the
--- index of the currently focused client.
--- @param s which screen to use. nil means all screens.
---
--- @function awful.client.iterate
--- @usage -- un-minimize all urxvt instances
--- local urxvt = function (c)
--- return awful.rules.match(c, {class = "URxvt"})
--- end
---
--- for c in awful.client.iterate(urxvt) do
--- c.minimized = false
--- end
-function client.iterate(filter, start, s)
- local clients = capi.client.get(s)
- local focused = capi.client.focus
- start = start or util.table.hasitem(clients, focused)
- return util.table.iterate(clients, filter, start)
-end
-
---- Switch to a client matching the given condition if running, else spawn it.
--- If multiple clients match the given condition then the next one is
--- focussed.
---
--- @param cmd the command to execute
--- @param matcher a function that returns true to indicate a matching client
--- @tparam bool|function merge If true then merge tags (select the client's
--- first tag additionally) when the client is not visible.
--- If it is a function, it will be called with the client as argument.
---
--- @function awful.client.run_or_raise
--- @usage -- run or raise urxvt (perhaps, with tabs) on modkey + semicolon
--- awful.key({ modkey, }, 'semicolon', function ()
--- local matcher = function (c)
--- return awful.rules.match(c, {class = 'URxvt'})
--- end
--- awful.client.run_or_raise('urxvt', matcher)
--- end);
-function client.run_or_raise(cmd, matcher, merge)
- local clients = capi.client.get()
- local findex = util.table.hasitem(clients, capi.client.focus) or 1
- local start = util.cycle(#clients, findex + 1)
-
- local c = client.iterate(matcher, start)()
- if c then
- c:jump_to(merge)
- else
- -- client not found, spawn it
- spawn(cmd)
- end
-end
-
---- Get a matching transient_for client (if any).
--- @deprecated awful.client.get_transient_for_matching
--- @see client.get_transient_for_matching
--- @client c The client.
--- @tparam function matcher A function that should return true, if
--- a matching parent client is found.
--- @treturn client.client|nil The matching parent client or nil.
-function client.get_transient_for_matching(c, matcher)
- util.deprecate("Use c:get_transient_for_matching(matcher) instead of"..
- "awful.client.get_transient_for_matching")
-
- return client.object.get_transient_for_matching(c, matcher)
-end
-
---- Get a matching transient_for client (if any).
--- @function client.get_transient_for_matching
--- @tparam function matcher A function that should return true, if
--- a matching parent client is found.
--- @treturn client.client|nil The matching parent client or nil.
-function client.object.get_transient_for_matching(self, matcher)
- local tc = self.transient_for
- while tc do
- if matcher(tc) then
- return tc
- end
- tc = tc.transient_for
- end
- return nil
-end
-
---- Is a client transient for another one?
--- @deprecated awful.client.is_transient_for
--- @see client.is_transient_for
--- @client c The child client (having transient_for).
--- @client c2 The parent client to check.
--- @treturn client.client|nil The parent client or nil.
-function client.is_transient_for(c, c2)
- util.deprecate("Use c:is_transient_for(c2) instead of"..
- "awful.client.is_transient_for")
- return client.object.is_transient_for(c, c2)
-end
-
---- Is a client transient for another one?
--- @function client.is_transient_for
--- @client c2 The parent client to check.
--- @treturn client.client|nil The parent client or nil.
-function client.object.is_transient_for(self, c2)
- local tc = self
- while tc.transient_for do
- if tc.transient_for == c2 then
- return tc
- end
- tc = tc.transient_for
- end
- return nil
-end
-
--- Register standards signals
-
---- The last geometry when client was floating.
--- @signal property::floating_geometry
-
---- Emited when a client need to get a titlebar.
--- @signal request::titlebars
--- @tparam[opt=nil] string content The context (like "rules")
--- @tparam[opt=nil] table hints Some hints.
-
---- The client marked signal (deprecated).
--- @signal .marked
-
---- The client unmarked signal (deprecated).
--- @signal unmarked
-
--- Add clients during startup to focus history.
--- This used to happen through ewmh.activate, but that only handles visible
--- clients now.
-capi.client.connect_signal("manage", function (c)
- if awesome.startup then
- client.focus.history.add(c)
- end
-end)
-capi.client.connect_signal("unmanage", client.focus.history.delete)
-
-capi.client.connect_signal("unmanage", client.floating.delete)
-
--- Connect to "focus" signal, and allow to disable tracking.
-do
- local disabled_count = 1
- --- Disable history tracking.
- --
- -- See `awful.client.focus.history.enable_tracking` to enable it again.
- -- @treturn int The internal value of `disabled_count` (calls to this
- -- function without calling `awful.client.focus.history.enable_tracking`).
- -- @function awful.client.focus.history.disable_tracking
- function client.focus.history.disable_tracking()
- disabled_count = disabled_count + 1
- if disabled_count == 1 then
- capi.client.disconnect_signal("focus", client.focus.history.add)
- end
- return disabled_count
- end
-
- --- Enable history tracking.
- --
- -- This is the default, but can be disabled
- -- through `awful.client.focus.history.disable_tracking`.
- -- @treturn boolean True if history tracking has been enabled.
- -- @function awful.client.focus.history.enable_tracking
- function client.focus.history.enable_tracking()
- assert(disabled_count > 0)
- disabled_count = disabled_count - 1
- if disabled_count == 0 then
- capi.client.connect_signal("focus", client.focus.history.add)
- end
- return disabled_count == 0
- end
-
- --- Is history tracking enabled?
- -- @treturn bool True if history tracking is enabled.
- -- @treturn int The number of times that tracking has been disabled.
- -- @function awful.client.focus.history.is_enabled
- function client.focus.history.is_enabled()
- return disabled_count == 0, disabled_count
- end
-end
-client.focus.history.enable_tracking()
-
--- Register persistent properties
-client.property.persist("floating", "boolean")
-
--- Extend the luaobject
-object.properties(capi.client, {
- getter_class = client.object,
- setter_class = client.object,
- getter_fallback = client.property.get,
- setter_fallback = client.property.set,
-})
-
-return client
-
--- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80