1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
---------------------------------------------------------------------------
--- 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
-- @submodule mouse
---------------------------------------------------------------------------
local aplace = require("awful.placement")
local capi = {mousegrabber = mousegrabber}
local beautiful = require("beautiful")
local module = {}
local mode = "live"
local req = "request::geometry"
local callbacks = {enter={}, move={}, leave={}}
local cursors = {
["mouse.move" ] = "fleur",
["mouse.resize" ] = "cross",
["mouse.resize_left" ] = "sb_h_double_arrow",
["mouse.resize_right" ] = "sb_h_double_arrow",
["mouse.resize_top" ] = "sb_v_double_arrow",
["mouse.resize_bottom" ] = "sb_v_double_arrow",
["mouse.resize_top_left" ] = "top_left_corner",
["mouse.resize_top_right" ] = "top_right_corner",
["mouse.resize_bottom_left" ] = "bottom_left_corner",
["mouse.resize_bottom_right"] = "bottom_right_corner",
}
--- The resize cursor name.
-- @beautiful beautiful.cursor_mouse_resize
-- @tparam[opt=cross] string cursor
--- The move cursor name.
-- @beautiful beautiful.cursor_mouse_move
-- @tparam[opt=fleur] string cursor
--- 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.
--
-- @function awful.mouse.resize.set_mode
-- @tparam string m The mode
function module.set_mode(m)
assert(m == "live" or m == "after")
mode = m
end
--- Add an initialization callback.
-- This callback will be executed before the mouse grabbing starts.
-- @function awful.mouse.resize.add_enter_callback
-- @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.
-- @function awful.mouse.resize.add_move_callback
-- @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
-- @function awful.mouse.resize.add_leave_callback
-- @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
--
-- @function awful.mouse.resize
-- @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
-- Select the cursor
local tcontext = context:gsub('[.]', '_')
local corner = args.corner and ("_".. args.corner) or ""
local cursor = beautiful["cursor_"..tcontext]
or cursors[context..corner]
or cursors[context]
or "fleur"
-- 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, cursor)
end
return setmetatable(module, {__call=handler})
|