awful.mouse: Add a generic mousegrabber
Previously, all layouts had their own mouse grabbing logic. The new one is based on the client request::geometry feature.
This commit is contained in:
parent
e93e2913b6
commit
f8f57fb6b7
|
@ -26,7 +26,9 @@ local capi =
|
|||
mousegrabber = mousegrabber,
|
||||
}
|
||||
|
||||
local mouse = {}
|
||||
local mouse = {
|
||||
resize = require("awful.mouse.resize")
|
||||
}
|
||||
|
||||
mouse.client = {}
|
||||
mouse.wibox = {}
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- An extandable mouse resizing handler.
|
||||
--
|
||||
-- This module offer a resizing and moving mechanism for drawable such as
|
||||
-- clients and wiboxes.
|
||||
--
|
||||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2016 Emmanuel Lepage Vallee
|
||||
-- @release @AWESOME_VERSION@
|
||||
-- @submodule awful.mouse
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local aplace = require("awful.placement")
|
||||
local capi = {mousegrabber = mousegrabber}
|
||||
|
||||
local module = {}
|
||||
|
||||
local mode = "live"
|
||||
local req = "request::geometry"
|
||||
local callbacks = {enter={}, move={}, leave={}}
|
||||
|
||||
--- Set the resize mode.
|
||||
-- The available modes are:
|
||||
--
|
||||
-- * **live**: Resize the layout everytime the mouse move
|
||||
-- * **after**: Resize the layout only when the mouse is released
|
||||
--
|
||||
-- Some clients, such as XTerm, may lose information if resized too often.
|
||||
--
|
||||
-- @tparam string m The mode
|
||||
function module.set_mode(m)
|
||||
assert(m == "live" or m == "after")
|
||||
mode = m
|
||||
end
|
||||
|
||||
--- Add a initialization callback.
|
||||
-- This callback will be executed before the mouse grabbing start
|
||||
-- @tparam function cb The callback (or nil)
|
||||
-- @tparam[default=other] string context The callback context
|
||||
function module.add_enter_callback(cb, context)
|
||||
context = context or "other"
|
||||
callbacks.enter[context] = callbacks.enter[context] or {}
|
||||
table.insert(callbacks.enter[context], cb)
|
||||
end
|
||||
|
||||
--- Add a "move" callback.
|
||||
-- This callback is executed in "after" mode (see `set_mode`) instead of
|
||||
-- applying the operation.
|
||||
-- @tparam function cb The callback (or nil)
|
||||
-- @tparam[default=other] string context The callback context
|
||||
function module.add_move_callback(cb, context)
|
||||
context = context or "other"
|
||||
callbacks.move[context] = callbacks.move[context] or {}
|
||||
table.insert(callbacks.move[context], cb)
|
||||
end
|
||||
|
||||
--- Add a "leave" callback
|
||||
-- This callback is executed just before the `mousegrabber` stop
|
||||
-- @tparam function cb The callback (or nil)
|
||||
-- @tparam[default=other] string context The callback context
|
||||
function module.add_leave_callback(cb, context)
|
||||
context = context or "other"
|
||||
callbacks.leave[context] = callbacks.leave[context] or {}
|
||||
table.insert(callbacks.leave[context], cb)
|
||||
end
|
||||
|
||||
-- Resize, the drawable
|
||||
--
|
||||
-- Valid `args` are:
|
||||
--
|
||||
-- * *enter_callback*: A function called before the `mousegrabber` start
|
||||
-- * *move_callback*: A function called when the mouse move
|
||||
-- * *leave_callback*: A function called before the `mousegrabber` is released
|
||||
-- * *mode*: The resize mode
|
||||
--
|
||||
-- @tparam client client A client
|
||||
-- @tparam[default=mouse.resize] string context The resizing context
|
||||
-- @tparam[opt={}] table args A set of `awful.placement` arguments
|
||||
local function handler(_, client, context, args) --luacheck: no unused_args
|
||||
args = args or {}
|
||||
context = context or "mouse.resize"
|
||||
|
||||
local placement = args.placement
|
||||
|
||||
if type(placement) == "string" and aplace[placement] then
|
||||
placement = aplace[placement]
|
||||
end
|
||||
|
||||
-- Extend the table with the default arguments
|
||||
args = setmetatable(
|
||||
{
|
||||
placement = placement or aplace.resize_to_mouse,
|
||||
mode = args.mode or mode,
|
||||
pretend = true,
|
||||
},
|
||||
{__index = args or {}}
|
||||
)
|
||||
|
||||
local geo
|
||||
|
||||
for _, cb in ipairs(callbacks.enter[context] or {}) do
|
||||
geo = cb(client, args)
|
||||
|
||||
if geo == false then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if args.enter_callback then
|
||||
geo = args.enter_callback(client, args)
|
||||
|
||||
if geo == false then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
geo = nil
|
||||
|
||||
-- Execute the placement function and use request::geometry
|
||||
capi.mousegrabber.run(function (_mouse)
|
||||
if not client.valid then return end
|
||||
|
||||
-- Resize everytime the mouse move (default behavior)
|
||||
if args.mode == "live" then
|
||||
-- Get the new geometry
|
||||
geo = setmetatable(args.placement(client, args),{__index=args})
|
||||
end
|
||||
|
||||
-- Execute the move callbacks. This can be used to add features such as
|
||||
-- snap or adding fancy graphical effects.
|
||||
for _, cb in ipairs(callbacks.move[context] or {}) do
|
||||
-- If something is returned, assume it is a modified geometry
|
||||
geo = cb(client, geo, args) or geo
|
||||
|
||||
if geo == false then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if args.move_callback then
|
||||
geo = args.move_callback(client, geo, args)
|
||||
|
||||
if geo == false then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- In case it was modified
|
||||
setmetatable(geo,{__index=args})
|
||||
|
||||
if args.mode == "live" then
|
||||
-- Ask the resizing handler to resize the client
|
||||
client:emit_signal( req, context, geo)
|
||||
end
|
||||
|
||||
-- Quit when the button is released
|
||||
for _,v in pairs(_mouse.buttons) do
|
||||
if v then return true end
|
||||
end
|
||||
|
||||
-- Only resize after the mouse is released, this avoid losing content
|
||||
-- in resize sensitive apps such as XTerm or allow external modules
|
||||
-- to implement custom resizing
|
||||
if args.mode == "after" then
|
||||
-- Get the new geometry
|
||||
geo = args.placement(client, args)
|
||||
|
||||
-- Ask the resizing handler to resize the client
|
||||
client:emit_signal( req, context, geo)
|
||||
end
|
||||
|
||||
geo = nil
|
||||
|
||||
for _, cb in ipairs(callbacks.leave[context] or {}) do
|
||||
geo = cb(client, geo, args)
|
||||
end
|
||||
|
||||
if args.leave_callback then
|
||||
geo = args.leave_callback(client, geo, args)
|
||||
end
|
||||
|
||||
if not geo then return false end
|
||||
|
||||
-- In case it was modified
|
||||
setmetatable(geo,{__index=args})
|
||||
|
||||
client:emit_signal( req, context, geo)
|
||||
|
||||
return false
|
||||
end, "cross")
|
||||
end
|
||||
|
||||
return setmetatable(module, {__call=handler})
|
Loading…
Reference in New Issue