From 8d7b0feedd9de3cb41bcbc2deff26c9a8ab34450 Mon Sep 17 00:00:00 2001 From: Robert Siska Date: Thu, 23 Oct 2014 01:30:19 +0200 Subject: [PATCH] Layouts can define their own resizing handler (FS#1267) --- lib/awful/layout/suit/floating.lua.in | 69 +++++++++ lib/awful/layout/suit/magnifier.lua.in | 29 +++- lib/awful/layout/suit/tile.lua.in | 117 ++++++++++++++- lib/awful/mouse/init.lua.in | 194 +------------------------ 4 files changed, 217 insertions(+), 192 deletions(-) diff --git a/lib/awful/layout/suit/floating.lua.in b/lib/awful/layout/suit/floating.lua.in index b7e27170..d3f0d92d 100644 --- a/lib/awful/layout/suit/floating.lua.in +++ b/lib/awful/layout/suit/floating.lua.in @@ -5,9 +5,78 @@ --------------------------------------------------------------------------- --- Dummy function for floating layout +-- Grab environment we need +local math = math +local ipairs = ipairs +local capi = +{ + mouse = mouse, + mousegrabber = mousegrabber +} + -- awful.layout.suit.floating local floating = {} +function floating.mouse_resize_handler(c, corner, x, y) + local g = c:geometry() + + -- Do not allow maximized clients to be resized by mouse + local fixed_x = c.maximized_horizontal + local fixed_y = c.maximized_vertical + + -- Warp mouse pointer + capi.mouse.coords({ x = x, y = y }) + + capi.mousegrabber.run(function (_mouse) + for k, v in ipairs(_mouse.buttons) do + if v then + local ng + if corner == "bottom_right" then + ng = { width = _mouse.x - g.x, + height = _mouse.y - g.y } + elseif corner == "bottom_left" then + ng = { x = _mouse.x, + width = (g.x + g.width) - _mouse.x, + height = _mouse.y - g.y } + elseif corner == "top_left" then + ng = { x = _mouse.x, + width = (g.x + g.width) - _mouse.x, + y = _mouse.y, + height = (g.y + g.height) - _mouse.y } + else + ng = { width = _mouse.x - g.x, + y = _mouse.y, + height = (g.y + g.height) - _mouse.y } + end + if ng.width <= 0 then ng.width = nil end + if ng.height <= 0 then ng.height = nil end + if fixed_x then ng.width = g.width ng.x = g.x end + if fixed_y then ng.height = g.height ng.y = g.y end + c:geometry(ng) + -- Get real geometry that has been applied + -- in case we honor size hints + -- XXX: This should be rewritten when size + -- hints are available from Lua. + local rg = c:geometry() + + if corner == "bottom_right" then + ng = {} + elseif corner == "bottom_left" then + ng = { x = (g.x + g.width) - rg.width } + elseif corner == "top_left" then + ng = { x = (g.x + g.width) - rg.width, + y = (g.y + g.height) - rg.height } + else + ng = { y = (g.y + g.height) - rg.height } + end + c:geometry({ x = ng.x, y = ng.y }) + return true + end + end + return false + end, corner .. "_corner") +end + function floating.arrange() end diff --git a/lib/awful/layout/suit/magnifier.lua.in b/lib/awful/layout/suit/magnifier.lua.in index d9eafa86..172e3dbc 100644 --- a/lib/awful/layout/suit/magnifier.lua.in +++ b/lib/awful/layout/suit/magnifier.lua.in @@ -11,7 +11,9 @@ local tag = require("awful.tag") local capi = { client = client, - screen = screen + screen = screen, + mouse = mouse, + mousegrabber = mousegrabber } local client = require("awful.client") @@ -19,6 +21,31 @@ local client = require("awful.client") -- awful.layout.suit.magnifier local magnifier = {} +function magnifier.mouse_resize_handler(c, corner, x, y) + capi.mouse.coords({ x = x, y = y }) + + local wa = capi.screen[c.screen].workarea + local center_x = wa.x + wa.width / 2 + local center_y = wa.y + wa.height / 2 + local maxdist_pow = (wa.width^2 + wa.height^2) / 4 + + capi.mousegrabber.run(function (_mouse) + for k, v in ipairs(_mouse.buttons) do + if v then + local dx = center_x - _mouse.x + local dy = center_y - _mouse.y + local dist = dx^2 + dy^2 + + -- New master width factor + local mwfact = dist / maxdist_pow + tag.setmwfact(math.min(math.max(0.01, mwfact), 0.99), tag.selected(c.screen)) + return true + end + end + return false + end, corner .. "_corner") +end + function magnifier.arrange(p) -- Fullscreen? local area = p.workarea diff --git a/lib/awful/layout/suit/tile.lua.in b/lib/awful/layout/suit/tile.lua.in index 35ffb984..577c5d3d 100644 --- a/lib/awful/layout/suit/tile.lua.in +++ b/lib/awful/layout/suit/tile.lua.in @@ -7,14 +7,116 @@ --------------------------------------------------------------------------- -- Grab environment we need +local tag = require("awful.tag") +local client = require("awful.client") local ipairs = ipairs local math = math -local tag = require("awful.tag") +local capi = +{ + mouse = mouse, + screen = screen, + mousegrabber = mousegrabber +} --- Tiled layouts module for awful -- awful.layout.suit.tile local tile = {} +local function mouse_resize_handler(c, corner, x, y, orientation) + local orientation = orientation or "tile" + local wa = capi.screen[c.screen].workarea + local mwfact = tag.getmwfact() + local cursor + local g = c:geometry() + local offset = 0 + local x,y + if orientation == "tile" then + cursor = "cross" + if g.height+15 > wa.height then + offset = g.height * .5 + cursor = "sb_h_double_arrow" + elseif not (g.y+g.height+15 > wa.y+wa.height) then + offset = g.height + end + capi.mouse.coords({ x = wa.x + wa.width * mwfact, y = g.y + offset }) + elseif orientation == "left" then + cursor = "cross" + if g.height+15 >= wa.height then + offset = g.height * .5 + cursor = "sb_h_double_arrow" + elseif not (g.y+g.height+15 > wa.y+wa.height) then + offset = g.height + end + capi.mouse.coords({ x = wa.x + wa.width * (1 - mwfact), y = g.y + offset }) + elseif orientation == "bottom" then + cursor = "cross" + if g.width+15 >= wa.width then + offset = g.width * .5 + cursor = "sb_v_double_arrow" + elseif not (g.x+g.width+15 > wa.x+wa.width) then + offset = g.width + end + capi.mouse.coords({ y = wa.y + wa.height * mwfact, x = g.x + offset}) + else + cursor = "cross" + if g.width+15 >= wa.width then + offset = g.width * .5 + cursor = "sb_v_double_arrow" + elseif not (g.x+g.width+15 > wa.x+wa.width) then + offset = g.width + end + capi.mouse.coords({ y = wa.y + wa.height * (1 - mwfact), x= g.x + offset }) + end + + capi.mousegrabber.run(function (_mouse) + for k, v in ipairs(_mouse.buttons) do + if v then + local fact_x = (_mouse.x - wa.x) / wa.width + local fact_y = (_mouse.y - wa.y) / wa.height + local mwfact + + local g = c:geometry() + + + -- we have to make sure we're not on the last visible client where we have to use different settings. + local wfact + local wfact_x, wfact_y + if (g.y+g.height+15) > (wa.y+wa.height) then + wfact_y = (g.y + g.height - _mouse.y) / wa.height + else + wfact_y = (_mouse.y - g.y) / wa.height + end + + if (g.x+g.width+15) > (wa.x+wa.width) then + wfact_x = (g.x + g.width - _mouse.x) / wa.width + else + wfact_x = (_mouse.x - g.x) / wa.width + end + + + if orientation == "tile" then + mwfact = fact_x + wfact = wfact_y + elseif orientation == "left" then + mwfact = 1 - fact_x + wfact = wfact_y + elseif orientation == "bottom" then + mwfact = fact_y + wfact = wfact_x + else + mwfact = 1 - fact_y + wfact = wfact_x + end + + tag.setmwfact(math.min(math.max(mwfact, 0.01), 0.99), tag.selected(c.screen)) + client.setwfact(math.min(math.max(wfact,0.01), 0.99), c) + return true + end + end + return false + end, cursor) +end + local function tile_group(cls, wa, orientation, fact, group) -- get our orientation right local height = "height" @@ -152,6 +254,9 @@ end tile.right = {} tile.right.name = "tile" tile.right.arrange = do_tile +function tile.right.mouse_resize_handler(c, corner, x, y) + return mouse_resize_handler(c, corner, x, y) +end --- The main tile algo, on left. -- @param screen The screen number to tile. @@ -160,6 +265,9 @@ tile.left.name = "tileleft" function tile.left.arrange(p) return do_tile(p, "left") end +function tile.left.mouse_resize_handler(c, corner, x, y) + return mouse_resize_handler(c, corner, x, y, "left") +end --- The main tile algo, on bottom. -- @param screen The screen number to tile. @@ -168,6 +276,9 @@ tile.bottom.name = "tilebottom" function tile.bottom.arrange(p) return do_tile(p, "bottom") end +function tile.bottom.mouse_resize_handler(c, corner, x, y) + return mouse_resize_handler(c, corner, x, y, "bottom") +end --- The main tile algo, on top. -- @param screen The screen number to tile. @@ -176,8 +287,12 @@ tile.top.name = "tiletop" function tile.top.arrange(p) return do_tile(p, "top") end +function tile.top.mouse_resize_handler(c, corner, x, y) + return mouse_resize_handler(c, corner, x, y, "top") +end tile.arrange = tile.right.arrange +tile.mouse_resize_handler = tile.right.mouse_resize_handler tile.name = tile.right.name return tile diff --git a/lib/awful/mouse/init.lua.in b/lib/awful/mouse/init.lua.in index f98cf8d5..1fbab97c 100644 --- a/lib/awful/mouse/init.lua.in +++ b/lib/awful/mouse/init.lua.in @@ -335,183 +335,6 @@ function mouse.client.corner(c, corner) return corner, x, y end -local function client_resize_magnifier(c, corner) - local corner, x, y = mouse.client.corner(c, corner) - capi.mouse.coords({ x = x, y = y }) - - local wa = capi.screen[c.screen].workarea - local center_x = wa.x + wa.width / 2 - local center_y = wa.y + wa.height / 2 - local maxdist_pow = (wa.width^2 + wa.height^2) / 4 - - capi.mousegrabber.run(function (_mouse) - for k, v in ipairs(_mouse.buttons) do - if v then - local dx = center_x - _mouse.x - local dy = center_y - _mouse.y - local dist = dx^2 + dy^2 - - -- New master width factor - local mwfact = dist / maxdist_pow - tag.setmwfact(math.min(math.max(0.01, mwfact), 0.99), tag.selected(c.screen)) - return true - end - end - return false - end, corner .. "_corner") -end - -local function client_resize_tiled(c, lay) - local wa = capi.screen[c.screen].workarea - local mwfact = tag.getmwfact() - local cursor - local g = c:geometry() - local offset = 0 - local x,y - if lay == layout.suit.tile then - cursor = "cross" - if g.height+15 > wa.height then - offset = g.height * .5 - cursor = "sb_h_double_arrow" - elseif not (g.y+g.height+15 > wa.y+wa.height) then - offset = g.height - end - capi.mouse.coords({ x = wa.x + wa.width * mwfact, y = g.y + offset }) - elseif lay == layout.suit.tile.left then - cursor = "cross" - if g.height+15 >= wa.height then - offset = g.height * .5 - cursor = "sb_h_double_arrow" - elseif not (g.y+g.height+15 > wa.y+wa.height) then - offset = g.height - end - capi.mouse.coords({ x = wa.x + wa.width * (1 - mwfact), y = g.y + offset }) - elseif lay == layout.suit.tile.bottom then - cursor = "cross" - if g.width+15 >= wa.width then - offset = g.width * .5 - cursor = "sb_v_double_arrow" - elseif not (g.x+g.width+15 > wa.x+wa.width) then - offset = g.width - end - capi.mouse.coords({ y = wa.y + wa.height * mwfact, x = g.x + offset}) - else - cursor = "cross" - if g.width+15 >= wa.width then - offset = g.width * .5 - cursor = "sb_v_double_arrow" - elseif not (g.x+g.width+15 > wa.x+wa.width) then - offset = g.width - end - capi.mouse.coords({ y = wa.y + wa.height * (1 - mwfact), x= g.x + offset }) - end - - capi.mousegrabber.run(function (_mouse) - for k, v in ipairs(_mouse.buttons) do - if v then - local fact_x = (_mouse.x - wa.x) / wa.width - local fact_y = (_mouse.y - wa.y) / wa.height - local mwfact - - local g = c:geometry() - - - -- we have to make sure we're not on the last visible client where we have to use different settings. - local wfact - local wfact_x, wfact_y - if (g.y+g.height+15) > (wa.y+wa.height) then - wfact_y = (g.y + g.height - _mouse.y) / wa.height - else - wfact_y = (_mouse.y - g.y) / wa.height - end - - if (g.x+g.width+15) > (wa.x+wa.width) then - wfact_x = (g.x + g.width - _mouse.x) / wa.width - else - wfact_x = (_mouse.x - g.x) / wa.width - end - - - if lay == layout.suit.tile then - mwfact = fact_x - wfact = wfact_y - elseif lay == layout.suit.tile.left then - mwfact = 1 - fact_x - wfact = wfact_y - elseif lay == layout.suit.tile.bottom then - mwfact = fact_y - wfact = wfact_x - else - mwfact = 1 - fact_y - wfact = wfact_x - end - - tag.setmwfact(math.min(math.max(mwfact, 0.01), 0.99), tag.selected(c.screen)) - aclient.setwfact(math.min(math.max(wfact,0.01), 0.99), c) - return true - end - end - return false - end, cursor) -end - -local function client_resize_floating(c, corner, fixed_x, fixed_y) - local corner, x, y = mouse.client.corner(c, corner) - local g = c:geometry() - - -- Warp mouse pointer - capi.mouse.coords({ x = x, y = y }) - - capi.mousegrabber.run(function (_mouse) - for k, v in ipairs(_mouse.buttons) do - if v then - local ng - if corner == "bottom_right" then - ng = { width = _mouse.x - g.x, - height = _mouse.y - g.y } - elseif corner == "bottom_left" then - ng = { x = _mouse.x, - width = (g.x + g.width) - _mouse.x, - height = _mouse.y - g.y } - elseif corner == "top_left" then - ng = { x = _mouse.x, - width = (g.x + g.width) - _mouse.x, - y = _mouse.y, - height = (g.y + g.height) - _mouse.y } - else - ng = { width = _mouse.x - g.x, - y = _mouse.y, - height = (g.y + g.height) - _mouse.y } - end - if ng.width <= 0 then ng.width = nil end - if ng.height <= 0 then ng.height = nil end - if fixed_x then ng.width = g.width ng.x = g.x end - if fixed_y then ng.height = g.height ng.y = g.y end - c:geometry(ng) - -- Get real geometry that has been applied - -- in case we honor size hints - -- XXX: This should be rewritten when size - -- hints are available from Lua. - local rg = c:geometry() - - if corner == "bottom_right" then - ng = {} - elseif corner == "bottom_left" then - ng = { x = (g.x + g.width) - rg.width } - elseif corner == "top_left" then - ng = { x = (g.x + g.width) - rg.width, - y = (g.y + g.height) - rg.height } - else - ng = { y = (g.y + g.height) - rg.height } - end - c:geometry({ x = ng.x, y = ng.y }) - return true - end - end - return false - end, corner .. "_corner") -end - --- Resize a client. -- @param c The client to resize, or the focused one by default. -- @param corner The corner to grab on resize. Auto detected by default. @@ -527,22 +350,13 @@ function mouse.client.resize(c, corner) return end - -- Do not allow maximized clients to be resized by mouse - local fixed_x = c.maximized_horizontal - local fixed_y = c.maximized_vertical - local lay = layout.get(c.screen) + local corner, x, y = mouse.client.corner(c, corner) if lay == layout.suit.floating or aclient.floating.get(c) then - return client_resize_floating(c, corner, fixed_x, fixed_y) - elseif lay == layout.suit.tile - or lay == layout.suit.tile.left - or lay == layout.suit.tile.top - or lay == layout.suit.tile.bottom - then - return client_resize_tiled(c, lay) - elseif lay == layout.suit.magnifier then - return client_resize_magnifier(c, corner) + return layout.suit.floating.mouse_resize_handler(c, corner, x, y) + elseif lay.mouse_resize_handler then + return lay.mouse_resize_handler(c, corner, x, y) end end