summaryrefslogtreecommitdiff
path: root/awesome/lib/awful/mouse/init.lua
blob: 03f7e89a70cfe448aa4b4ef79cce4b6e05f52f4e (plain)
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
---------------------------------------------------------------------------
--- Mouse module for awful
--
-- @author Julien Danjou <julien@danjou.info>
-- @copyright 2008 Julien Danjou
-- @module mouse
---------------------------------------------------------------------------

-- Grab environment we need
local layout = require("awful.layout")
local aplace = require("awful.placement")
local util = require("awful.util")
local type = type
local ipairs = ipairs
local capi =
{
    root = root,
    mouse = mouse,
    screen = screen,
    client = client,
    mousegrabber = mousegrabber,
}

local mouse = {
    resize = require("awful.mouse.resize"),
    snap   = require("awful.mouse.snap"),
    drag_to_tag = require("awful.mouse.drag_to_tag")
}

mouse.object = {}
mouse.client = {}
mouse.wibox = {}

--- The default snap distance.
-- @tfield integer awful.mouse.snap.default_distance
-- @tparam[opt=8] integer default_distance
-- @see awful.mouse.snap

--- Enable screen edges snapping.
-- @tfield[opt=true] boolean awful.mouse.snap.edge_enabled

--- Enable client to client snapping.
-- @tfield[opt=true] boolean awful.mouse.snap.client_enabled

--- Enable changing tag when a client is dragged to the edge of the screen.
-- @tfield[opt=false] integer awful.mouse.drag_to_tag.enabled

--- The snap outline background color.
-- @beautiful beautiful.snap_bg
-- @tparam color|string|gradient|pattern color

--- The snap outline width.
-- @beautiful beautiful.snap_border_width
-- @param integer

--- The snap outline shape.
-- @beautiful beautiful.snap_shape
-- @tparam function shape A `gears.shape` compatible function

--- Get the client object under the pointer.
-- @deprecated awful.mouse.client_under_pointer
-- @return The client object under the pointer, if one can be found.
-- @see current_client
function mouse.client_under_pointer()
    util.deprecate("Use mouse.current_client instead of awful.mouse.client_under_pointer()")

    return mouse.object.get_current_client()
end

--- Move a client.
-- @function awful.mouse.client.move
-- @param c The client to move, or the focused one if nil.
-- @param snap The pixel to snap clients.
-- @param finished_cb Deprecated, do not use
function mouse.client.move(c, snap, finished_cb) --luacheck: no unused args
    if finished_cb then
        util.deprecate("The mouse.client.move `finished_cb` argument is no longer"..
            " used, please use awful.mouse.resize.add_leave_callback(f, 'mouse.move')")
    end

    c = c or capi.client.focus

    if not c
        or c.fullscreen
        or c.type == "desktop"
        or c.type == "splash"
        or c.type == "dock" then
        return
    end

    -- Compute the offset
    local coords = capi.mouse.coords()
    local geo    = aplace.centered(capi.mouse,{parent=c, pretend=true})

    local offset = {
        x = geo.x - coords.x,
        y = geo.y - coords.y,
    }

    mouse.resize(c, "mouse.move", {
        placement = aplace.under_mouse,
        offset    = offset,
        snap      = snap
    })
end

mouse.client.dragtotag = { }

--- Move a client to a tag by dragging it onto the left / right side of the screen.
-- @deprecated awful.mouse.client.dragtotag.border
-- @param c The client to move
function mouse.client.dragtotag.border(c)
    util.deprecate("Use awful.mouse.snap.drag_to_tag_enabled = true instead "..
        "of awful.mouse.client.dragtotag.border(c). It will now be enabled.")

    -- Enable drag to border
    mouse.snap.drag_to_tag_enabled = true

    return mouse.client.move(c)
end

--- Move the wibox under the cursor.
-- @function awful.mouse.wibox.move
--@tparam wibox w The wibox to move, or none to use that under the pointer
function mouse.wibox.move(w)
    w = w or mouse.wibox_under_pointer()
    if not w then return end

    if not w
        or w.type == "desktop"
        or w.type == "splash"
        or w.type == "dock" then
        return
    end

    -- Compute the offset
    local coords = capi.mouse.coords()
    local geo    = aplace.centered(capi.mouse,{parent=w, pretend=true})

    local offset = {
        x = geo.x - coords.x,
        y = geo.y - coords.y,
    }

    mouse.resize(w, "mouse.move", {
        placement = aplace.under_mouse,
        offset    = offset
    })
end

--- Get a client corner coordinates.
-- @deprecated awful.mouse.client.corner
-- @tparam[opt=client.focus] client c The client to get corner from, focused one by default.
-- @tparam string corner The corner to use: auto, top_left, top_right, bottom_left,
-- bottom_right, left, right, top bottom. Default is auto, and auto find the
-- nearest corner.
-- @treturn string The corner name
-- @treturn number x The horizontal position
-- @treturn number y The vertical position
function mouse.client.corner(c, corner)
    util.deprecate(
        "Use awful.placement.closest_corner(mouse) or awful.placement[corner](mouse)"..
        " instead of awful.mouse.client.corner"
    )

    c = c or capi.client.focus
    if not c then return end

    local ngeo = nil

    if (not corner) or corner == "auto" then
        ngeo, corner = aplace.closest_corner(mouse, {parent = c})
    elseif corner and aplace[corner] then
        ngeo = aplace[corner](mouse, {parent = c})
    end

    return corner, ngeo and ngeo.x or nil, ngeo and ngeo.y or nil
end

--- Resize a client.
-- @function awful.mouse.client.resize
-- @param c The client to resize, or the focused one by default.
-- @tparam string corner The corner to grab on resize. Auto detected by default.
-- @tparam[opt={}] table args A set of `awful.placement` arguments
-- @treturn string The corner (or side) name
function mouse.client.resize(c, corner, args)
    c = c or capi.client.focus

    if not c then return end

    if c.fullscreen
        or c.type == "desktop"
        or c.type == "splash"
        or c.type == "dock" then
        return
    end

    -- Set some default arguments
    local new_args = setmetatable(
        {
            include_sides = (not args) or args.include_sides ~= false
        },
        {
            __index = args or {}
        }
    )

    -- Move the mouse to the corner
    if corner and aplace[corner] then
        aplace[corner](capi.mouse, {parent=c})
    else
        local _
        _, corner = aplace.closest_corner(capi.mouse, {
            parent        = c,
            include_sides = new_args.include_sides ~= false,
        })
    end

    new_args.corner = corner

    mouse.resize(c, "mouse.resize", new_args)

    return corner
end

--- Default handler for `request::geometry` signals with "mouse.resize" context.
-- @signalhandler awful.mouse.resize_handler
-- @tparam client c The client
-- @tparam string context The context
-- @tparam[opt={}] table hints The hints to pass to the handler
function mouse.resize_handler(c, context, hints)
    if hints and context and context:find("mouse.*") then
        -- This handler only handle the floating clients. If the client is tiled,
        -- then it let the layouts handle it.
        local t = c.screen.selected_tag
        local lay = t and t.layout or nil

        if (lay and lay == layout.suit.floating) or c.floating then
            c:geometry {
                x      = hints.x,
                y      = hints.y,
                width  = hints.width,
                height = hints.height,
            }
        elseif lay and lay.resize_handler then
            lay.resize_handler(c, context, hints)
        end
    end
end

-- Older layouts implement their own mousegrabber.
-- @tparam client c The client
-- @tparam table args Additional arguments
-- @treturn boolean This return false when the resize need to be aborted
mouse.resize.add_enter_callback(function(c, args) --luacheck: no unused args
    if c.floating then return end

    local l = c.screen.selected_tag and c.screen.selected_tag.layout or nil
    if l == layout.suit.floating then return end

    if l ~= layout.suit.floating and l.mouse_resize_handler then
        capi.mousegrabber.stop()

        local geo, corner = aplace.closest_corner(capi.mouse, {parent=c})

        l.mouse_resize_handler(c, corner, geo.x, geo.y)

        return false
    end
end, "mouse.resize")

--- Get the client currently under the mouse cursor.
-- @property current_client
-- @tparam client|nil The client

function mouse.object.get_current_client()
    local obj = capi.mouse.object_under_pointer()
    if type(obj) == "client" then
        return obj
    end
end

--- Get the wibox currently under the mouse cursor.
-- @property current_wibox
-- @tparam wibox|nil The wibox

function mouse.object.get_current_wibox()
    local obj = capi.mouse.object_under_pointer()
    if type(obj) == "drawin" and obj.get_wibox then
        return obj:get_wibox()
    end
end

--- Get the widgets currently under the mouse cursor.
--
-- @property current_widgets
-- @tparam nil|table list The widget list
-- @treturn table The list of widgets.The first element is the biggest
-- container while the last is the topmost widget. The table contains *x*, *y*,
-- *width*, *height* and *widget*.
-- @see wibox.find_widgets

function mouse.object.get_current_widgets()
    local w = mouse.object.get_current_wibox()
    if w then
        local geo, coords = w:geometry(), capi.mouse:coords()

        local list = w:find_widgets(coords.x - geo.x, coords.y - geo.y)

        local ret = {}

        for k, v in ipairs(list) do
            ret[k] = v.widget
        end

        return ret, list
    end
end

--- Get the topmost widget currently under the mouse cursor.
-- @property current_widget
-- @tparam widget|nil widget The widget
-- @treturn ?widget The widget
-- @see wibox.find_widgets
-- @see current_widget_geometry

function mouse.object.get_current_widget()
    local wdgs, geos = mouse.object.get_current_widgets()

    if wdgs then
        return wdgs[#wdgs], geos[#geos]
    end
end

--- Get the current widget geometry.
-- @property current_widget_geometry
-- @tparam ?table The geometry.
-- @see current_widget

function mouse.object.get_current_widget_geometry()
    local _, ret = mouse.object.get_current_widget()

    return ret
end

--- Get the current widget geometries.
-- @property current_widget_geometries
-- @tparam ?table A list of geometry tables.
-- @see current_widgets

function mouse.object.get_current_widget_geometries()
    local _, ret = mouse.object.get_current_widgets()

    return ret
end

--- True if the left mouse button is pressed.
-- @property is_left_mouse_button_pressed
-- @param boolean

--- True if the right mouse button is pressed.
-- @property is_right_mouse_button_pressed
-- @param boolean

--- True if the middle mouse button is pressed.
-- @property is_middle_mouse_button_pressed
-- @param boolean

for _, b in ipairs {"left", "right", "middle"} do
    mouse.object["is_".. b .."_mouse_button_pressed"] = function()
        return capi.mouse.coords().buttons[1]
    end
end

capi.client.connect_signal("request::geometry", mouse.resize_handler)

-- Set the cursor at startup
capi.root.cursor("left_ptr")

-- Implement the custom property handler
local props = {}

capi.mouse.set_newindex_miss_handler(function(_,key,value)
    if mouse.object["set_"..key] then
        mouse.object["set_"..key](value)
    elseif not mouse.object["get_"..key] then
        props[key] = value
    else
        -- If there is a getter, but no setter, then the property is read-only
        error("Cannot set '" .. tostring(key) .. " because it is read-only")
    end
end)

capi.mouse.set_index_miss_handler(function(_,key)
    if mouse.object["get_"..key] then
        return mouse.object["get_"..key]()
    else
        return props[key]
    end
end)

--- Get or set the mouse coords.
--
--
--
--![Usage example](../images/AUTOGEN_awful_mouse_coords.svg)
--
--**Usage example output**:
--
--    235
--
--
-- @usage
-- -- Get the position
--print(mouse.coords().x)
-- -- Change the position
--mouse.coords {
--    x = 185,
--    y = 10
--}
--
-- @tparam[opt=nil] table coords_table None or a table with x and y keys as mouse
--  coordinates.
-- @tparam[opt=nil] integer coords_table.x The mouse horizontal position
-- @tparam[opt=nil] integer coords_table.y The mouse vertical position
-- @tparam[opt=false] boolean silent Disable mouse::enter or mouse::leave events that
--  could be triggered by the pointer when moving.
-- @treturn integer table.x The horizontal position
-- @treturn integer table.y The vertical position
-- @treturn table table.buttons Table containing the status of buttons, e.g. field [1] is true
--  when button 1 is pressed.
-- @function mouse.coords


return mouse

-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80