summaryrefslogtreecommitdiff
path: root/awesome/lib/awful/screen.lua
diff options
context:
space:
mode:
Diffstat (limited to 'awesome/lib/awful/screen.lua')
-rw-r--r--awesome/lib/awful/screen.lua477
1 files changed, 477 insertions, 0 deletions
diff --git a/awesome/lib/awful/screen.lua b/awesome/lib/awful/screen.lua
new file mode 100644
index 0000000..e36e622
--- /dev/null
+++ b/awesome/lib/awful/screen.lua
@@ -0,0 +1,477 @@
+---------------------------------------------------------------------------
+--- Screen module for awful
+--
+-- @author Julien Danjou <julien@danjou.info>
+-- @copyright 2008 Julien Danjou
+-- @module screen
+---------------------------------------------------------------------------
+
+-- Grab environment we need
+local capi =
+{
+ mouse = mouse,
+ screen = screen,
+ client = client,
+ awesome = awesome,
+}
+local util = require("awful.util")
+local object = require("gears.object")
+local grect = require("gears.geometry").rectangle
+
+local function get_screen(s)
+ return s and capi.screen[s]
+end
+
+-- we use require("awful.client") inside functions to prevent circular dependencies.
+local client
+
+local screen = {object={}}
+
+local data = {}
+data.padding = {}
+
+--- Take an input geometry and substract/add a delta.
+-- @tparam table geo A geometry (width, height, x, y) table.
+-- @tparam table delta A delta table (top, bottom, x, y).
+-- @treturn table A geometry (width, height, x, y) table.
+local function apply_geometry_ajustments(geo, delta)
+ return {
+ x = geo.x + (delta.left or 0),
+ y = geo.y + (delta.top or 0),
+ width = geo.width - (delta.left or 0) - (delta.right or 0),
+ height = geo.height - (delta.top or 0) - (delta.bottom or 0),
+ }
+end
+
+--- Get the square distance between a `screen` and a point.
+-- @deprecated awful.screen.getdistance_sq
+-- @param s Screen
+-- @param x X coordinate of point
+-- @param y Y coordinate of point
+-- @return The squared distance of the screen to the provided point.
+-- @see screen.get_square_distance
+function screen.getdistance_sq(s, x, y)
+ util.deprecate("Use s:get_square_distance(x, y) instead of awful.screen.getdistance_sq")
+ return screen.object.get_square_distance(s, x, y)
+end
+
+--- Get the square distance between a `screen` and a point.
+-- @function screen.get_square_distance
+-- @tparam number x X coordinate of point
+-- @tparam number y Y coordinate of point
+-- @treturn number The squared distance of the screen to the provided point.
+function screen.object.get_square_distance(self, x, y)
+ return grect.get_square_distance(get_screen(self).geometry, x, y)
+end
+
+--- Return the screen index corresponding to the given (pixel) coordinates.
+--
+-- The number returned can be used as an index into the global
+-- `screen` table/object.
+-- @function awful.screen.getbycoord
+-- @tparam number x The x coordinate
+-- @tparam number y The y coordinate
+-- @treturn ?number The screen index
+function screen.getbycoord(x, y)
+ local s, sgeos = capi.screen.primary, {}
+ for scr in capi.screen do
+ sgeos[scr] = scr.geometry
+ end
+ s = grect.get_closest_by_coord(sgeos, x, y) or s
+ return s and s.index
+end
+
+--- Move the focus to a screen.
+--
+-- This moves the mouse pointer to the last known position on the new screen,
+-- or keeps its position relative to the current focused screen.
+-- @function awful.screen.focus
+-- @screen _screen Screen number (defaults / falls back to mouse.screen).
+function screen.focus(_screen)
+ client = client or require("awful.client")
+ if type(_screen) == "number" and _screen > capi.screen.count() then _screen = screen.focused() end
+ _screen = get_screen(_screen)
+
+ -- screen and pos for current screen
+ local s = get_screen(capi.mouse.screen)
+ local pos
+
+ if not _screen.mouse_per_screen then
+ -- This is the first time we enter this screen,
+ -- keep relative mouse position on the new screen.
+ pos = capi.mouse.coords()
+ local relx = (pos.x - s.geometry.x) / s.geometry.width
+ local rely = (pos.y - s.geometry.y) / s.geometry.height
+
+ pos.x = _screen.geometry.x + relx * _screen.geometry.width
+ pos.y = _screen.geometry.y + rely * _screen.geometry.height
+ else
+ -- restore mouse position
+ pos = _screen.mouse_per_screen
+ end
+
+ -- save pointer position of current screen
+ s.mouse_per_screen = capi.mouse.coords()
+
+ -- move cursor without triggering signals mouse::enter and mouse::leave
+ capi.mouse.coords(pos, true)
+
+ local c = client.focus.history.get(_screen, 0)
+ if c then
+ c:emit_signal("request::activate", "screen.focus", {raise=false})
+ end
+end
+
+--- Move the focus to a screen in a specific direction.
+--
+-- This moves the mouse pointer to the last known position on the new screen,
+-- or keeps its position relative to the current focused screen.
+-- @function awful.screen.focus_bydirection
+-- @param dir The direction, can be either "up", "down", "left" or "right".
+-- @param _screen Screen.
+function screen.focus_bydirection(dir, _screen)
+ local sel = get_screen(_screen or screen.focused())
+ if sel then
+ local geomtbl = {}
+ for s in capi.screen do
+ geomtbl[s] = s.geometry
+ end
+ local target = grect.get_in_direction(dir, geomtbl, sel.geometry)
+ if target then
+ return screen.focus(target)
+ end
+ end
+end
+
+--- Move the focus to a screen relative to the current one,
+--
+-- This moves the mouse pointer to the last known position on the new screen,
+-- or keeps its position relative to the current focused screen.
+--
+-- @function awful.screen.focus_relative
+-- @tparam int offset Value to add to the current focused screen index. 1 to
+-- focus the next one, -1 to focus the previous one.
+function screen.focus_relative(offset)
+ return screen.focus(util.cycle(capi.screen.count(),
+ screen.focused().index + offset))
+end
+
+--- Get or set the screen padding.
+--
+-- @deprecated awful.screen.padding
+-- @param _screen The screen object to change the padding on
+-- @param[opt=nil] padding The padding, a table with 'top', 'left', 'right' and/or
+-- 'bottom' or a number value to apply set the same padding on all sides. Can be
+-- nil if you only want to retrieve padding
+-- @treturn table A table with left, right, top and bottom number values.
+-- @see padding
+function screen.padding(_screen, padding)
+ util.deprecate("Use _screen.padding = value instead of awful.screen.padding")
+ if padding then
+ screen.object.set_padding(_screen, padding)
+ end
+ return screen.object.get_padding(_screen)
+end
+
+--- The screen padding.
+--
+-- This adds a "buffer" section on each side of the screen.
+--
+-- **Signal:**
+--
+-- * *property::padding*
+--
+-- @property padding
+-- @param table
+-- @tfield integer table.left The padding on the left.
+-- @tfield integer table.right The padding on the right.
+-- @tfield integer table.top The padding on the top.
+-- @tfield integer table.bottom The padding on the bottom.
+
+function screen.object.get_padding(self)
+ local p = data.padding[self] or {}
+ -- Create a copy to avoid accidental mutation and nil values.
+ return {
+ left = p.left or 0,
+ right = p.right or 0,
+ top = p.top or 0,
+ bottom = p.bottom or 0,
+ }
+end
+
+function screen.object.set_padding(self, padding)
+ if type(padding) == "number" then
+ padding = {
+ left = padding,
+ right = padding,
+ top = padding,
+ bottom = padding,
+ }
+ end
+
+ self = get_screen(self)
+ if padding then
+ data.padding[self] = padding
+ self:emit_signal("padding")
+ end
+end
+
+--- Get the preferred screen in the context of a client.
+--
+-- This is exactly the same as `awful.screen.focused` except that it avoids
+-- clients being moved when Awesome is restarted.
+-- This is used in the default `rc.lua` to ensure clients get assigned to the
+-- focused screen by default.
+-- @tparam client c A client.
+-- @treturn screen The preferred screen.
+function screen.preferred(c)
+ return capi.awesome.startup and c.screen or screen.focused()
+end
+
+--- The defaults arguments for `awful.screen.focused`.
+-- @tfield[opt=nil] table awful.screen.default_focused_args
+
+--- Get the focused screen.
+--
+-- It is possible to set `awful.screen.default_focused_args` to override the
+-- default settings.
+--
+-- @function awful.screen.focused
+-- @tparam[opt] table args
+-- @tparam[opt=false] boolean args.client Use the client screen instead of the
+-- mouse screen.
+-- @tparam[opt=true] boolean args.mouse Use the mouse screen
+-- @treturn ?screen The focused screen object, or `nil` in case no screen is
+-- present currently.
+function screen.focused(args)
+ args = args or screen.default_focused_args or {}
+ return get_screen(
+ args.client and capi.client.focus and capi.client.focus.screen or capi.mouse.screen
+ )
+end
+
+--- Get a placement bounding geometry.
+--
+-- This method computes the different variants of the "usable" screen geometry.
+--
+-- @function screen.get_bounding_geometry
+-- @tparam[opt={}] table args The arguments
+-- @tparam[opt=false] boolean args.honor_padding Whether to honor the screen's padding.
+-- @tparam[opt=false] boolean args.honor_workarea Whether to honor the screen's workarea.
+-- @tparam[opt] int|table args.margins Apply some margins on the output.
+-- This can either be a number or a table with *left*, *right*, *top*
+-- and *bottom* keys.
+-- @tag[opt] args.tag Use this tag's screen.
+-- @tparam[opt] drawable args.parent A parent drawable to use as base geometry.
+-- @tab[opt] args.bounding_rect A bounding rectangle. This parameter is
+-- incompatible with `honor_workarea`.
+-- @treturn table A table with *x*, *y*, *width* and *height*.
+-- @usage local geo = screen:get_bounding_geometry {
+-- honor_padding = true,
+-- honor_workarea = true,
+-- margins = {
+-- left = 20,
+-- },
+-- }
+function screen.object.get_bounding_geometry(self, args)
+ args = args or {}
+
+ -- If the tag has a geometry, assume it is right
+ if args.tag then
+ self = args.tag.screen
+ end
+
+ self = get_screen(self or capi.mouse.screen)
+
+ local geo = args.bounding_rect or (args.parent and args.parent:geometry()) or
+ self[args.honor_workarea and "workarea" or "geometry"]
+
+ if (not args.parent) and (not args.bounding_rect) and args.honor_padding then
+ local padding = self.padding
+ geo = apply_geometry_ajustments(geo, padding)
+ end
+
+ if args.margins then
+ geo = apply_geometry_ajustments(geo,
+ type(args.margins) == "table" and args.margins or {
+ left = args.margins, right = args.margins,
+ top = args.margins, bottom = args.margins,
+ }
+ )
+ end
+ return geo
+end
+
+--- Get the list of visible clients for the screen.
+--
+-- Minimized and unmanaged clients are not included in this list as they are
+-- technically not on the screen.
+--
+-- The clients on tags that are currently not visible are not part of this list.
+--
+-- @property clients
+-- @param table The clients list, ordered from top to bottom.
+-- @see all_clients
+-- @see hidden_clients
+-- @see client.get
+
+function screen.object.get_clients(s)
+ local cls = capi.client.get(s, true)
+ local vcls = {}
+ for _, c in pairs(cls) do
+ if c:isvisible() then
+ table.insert(vcls, c)
+ end
+ end
+ return vcls
+end
+
+--- Get the list of clients assigned to the screen but not currently visible.
+--
+-- This includes minimized clients and clients on hidden tags.
+--
+-- @property hidden_clients
+-- @param table The clients list, ordered from top to bottom.
+-- @see clients
+-- @see all_clients
+-- @see client.get
+
+function screen.object.get_hidden_clients(s)
+ local cls = capi.client.get(s, true)
+ local vcls = {}
+ for _, c in pairs(cls) do
+ if not c:isvisible() then
+ table.insert(vcls, c)
+ end
+ end
+ return vcls
+end
+
+--- Get all clients assigned to the screen.
+--
+-- @property all_clients
+-- @param table The clients list, ordered from top to bottom.
+-- @see clients
+-- @see hidden_clients
+-- @see client.get
+
+function screen.object.get_all_clients(s)
+ return capi.client.get(s, true)
+end
+
+--- Get the list of tiled clients for the screen.
+--
+-- Same as `clients`, but excluding:
+--
+-- * fullscreen clients
+-- * maximized clients
+-- * floating clients
+--
+-- @property tiled_clients
+-- @param table The clients list, ordered from top to bottom.
+
+function screen.object.get_tiled_clients(s)
+ local clients = s.clients
+ local tclients = {}
+ -- Remove floating clients
+ for _, c in pairs(clients) do
+ if not c.floating
+ and not c.fullscreen
+ and not c.maximized_vertical
+ and not c.maximized_horizontal then
+ table.insert(tclients, c)
+ end
+ end
+ return tclients
+end
+
+--- Call a function for each existing and created-in-the-future screen.
+--
+-- @function awful.screen.connect_for_each_screen
+-- @tparam function func The function to call.
+-- @screen func.screen The screen.
+function screen.connect_for_each_screen(func)
+ for s in capi.screen do
+ func(s)
+ end
+ capi.screen.connect_signal("added", func)
+end
+
+--- Undo the effect of connect_for_each_screen.
+-- @function awful.screen.disconnect_for_each_screen
+-- @tparam function func The function that should no longer be called.
+function screen.disconnect_for_each_screen(func)
+ capi.screen.disconnect_signal("added", func)
+end
+
+--- A list of all tags on the screen.
+--
+-- This property is read only, use `tag.screen`, `awful.tag.add`,
+-- `awful.tag.new` or `t:delete()` to alter this list.
+--
+-- @property tags
+-- @param table
+-- @treturn table A table with all available tags.
+
+function screen.object.get_tags(s, unordered)
+ local tags = {}
+
+ for _, t in ipairs(root.tags()) do
+ if get_screen(t.screen) == s then
+ table.insert(tags, t)
+ end
+ end
+
+ -- Avoid infinite loop and save some time.
+ if not unordered then
+ table.sort(tags, function(a, b)
+ return (a.index or math.huge) < (b.index or math.huge)
+ end)
+ end
+ return tags
+end
+
+--- A list of all selected tags on the screen.
+-- @property selected_tags
+-- @param table
+-- @treturn table A table with all selected tags.
+-- @see tag.selected
+-- @see client.to_selected_tags
+
+function screen.object.get_selected_tags(s)
+ local tags = screen.object.get_tags(s, true)
+
+ local vtags = {}
+ for _, t in pairs(tags) do
+ if t.selected then
+ vtags[#vtags + 1] = t
+ end
+ end
+ return vtags
+end
+
+--- The first selected tag.
+-- @property selected_tag
+-- @param table
+-- @treturn ?tag The first selected tag or nil.
+-- @see tag.selected
+-- @see selected_tags
+
+function screen.object.get_selected_tag(s)
+ return screen.object.get_selected_tags(s)[1]
+end
+
+
+--- When the tag history changed.
+-- @signal tag::history::update
+
+-- Extend the luaobject
+object.properties(capi.screen, {
+ getter_class = screen.object,
+ setter_class = screen.object,
+ auto_emit = true,
+})
+
+return screen
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80