client: Add an `activate` method.

This method aims to provide a centralized, declarative API to focus
clients. Currently, there is tons of code using "request::activate",
including `rc.lua` and have extra boilerplate code around it to
handle some corner case (such as minimization and clients already
having the focus).

This code takes room, is repetitive and force some imperative logic
to be in `rc.lua`.
This commit is contained in:
Emmanuel Lepage Vallee 2019-10-19 18:29:59 -04:00 committed by Emmanuel Lepage-Vallee
parent 6eef064da5
commit cd253ed815
1 changed files with 66 additions and 0 deletions

View File

@ -14,6 +14,7 @@ local object = require("gears.object")
local grect = require("gears.geometry").rectangle local grect = require("gears.geometry").rectangle
local gmath = require("gears.math") local gmath = require("gears.math")
local gtable = require("gears.table") local gtable = require("gears.table")
local amousec = require("awful.mouse.client")
local pairs = pairs local pairs = pairs
local type = type local type = type
local ipairs = ipairs local ipairs = ipairs
@ -1388,6 +1389,71 @@ function client.object.set_shape(self, shape)
set_shape(self) set_shape(self)
end end
--- Activate (focus) a client.
--
-- This method is the correct way to focus a client. While
-- `client.focus = my_client` works and is commonly used in older code, it has
-- some drawbacks. The most obvious one is that it bypasses the activate
-- filters. It also doesn't handle minimized clients well and requires a lot
-- of boilerplate code to make work properly.
--
-- The valid `args.actions` are:
--
-- * **mouse_move**: Move the client when the mouse cursor moves until the
-- mouse buttons are release.
-- * **mouse_resize**: Resize the client when the mouse cursor moves until the
-- mouse buttons are release.
-- * **mouse_center**: Move the mouse cursor to the center of the client if it
-- isn't already within its geometry,
-- * **toggle_minimization**: If the client is already active, minimize it.
--
-- @method activate
-- @tparam table args
-- @tparam[opt=other] string args.context Why was this activate called?
-- @tparam[opt=true] boolean args.raise Raise the client to the top of its layer.
-- @tparam[opt=false] boolean args.force Force the activation even for unfocusable
-- clients.
-- @tparam[opt=false] boolean args.switch_to_tags
-- @tparam[opt=false] boolean args.switch_to_tag
-- @tparam[opt=false] boolean args.action Once activated, perform an action.
-- @tparam[opt=false] boolean args.toggle_minimization
-- @see awful.ewmh.add_activate_filter
-- @see request::activate
function client.object.activate(c, args)
local new_args = setmetatable({}, {__index = args or {}})
-- Set the default arguments.
new_args.raise = new_args.raise == nil and true or args.raise
if c == capi.client.focus and new_args.action == "toggle_minimization" then
c.minimized = true
else
c:emit_signal(
"request::activate",
new_args.context or "other",
new_args
)
end
if new_args.action and new_args.action == "mouse_move" then
amousec.move(c)
elseif new_args.action and new_args.action == "mouse_resize" then
amousec.resize(c)
elseif new_args.action and new_args.action == "mouse_center" then
local coords, geo = mouse.mouse.coords(), c:geometry()
coords.width, coords.height = 1,1
if not grect.area_intersect_area(geo, coords) then
-- Do not use `awful.placement` to avoid an useless circular
-- dependency. Centering is *very* simple.
mouse.mouse.coords {
x = geo.x + math.ceil(geo.width /2),
y = geo.y + math.ceil(geo.height/2)
}
end
end
end
-- Register standards signals -- Register standards signals
--- The last geometry when client was floating. --- The last geometry when client was floating.