From 22d656903563f75678f3634964731ccf93355dfd Mon Sep 17 00:00:00 2001 From: ache Date: Mon, 13 Mar 2017 23:17:19 +0100 Subject: Init commit --- lib/awful/layout/init.lua | 323 +++++++++++++++++++++++++++++++++ lib/awful/layout/suit/corner.lua | 204 +++++++++++++++++++++ lib/awful/layout/suit/fair.lua | 108 +++++++++++ lib/awful/layout/suit/floating.lua | 112 ++++++++++++ lib/awful/layout/suit/init.lua | 19 ++ lib/awful/layout/suit/magnifier.lua | 147 +++++++++++++++ lib/awful/layout/suit/max.lua | 61 +++++++ lib/awful/layout/suit/spiral.lua | 89 +++++++++ lib/awful/layout/suit/tile.lua | 348 ++++++++++++++++++++++++++++++++++++ 9 files changed, 1411 insertions(+) create mode 100644 lib/awful/layout/init.lua create mode 100644 lib/awful/layout/suit/corner.lua create mode 100644 lib/awful/layout/suit/fair.lua create mode 100644 lib/awful/layout/suit/floating.lua create mode 100644 lib/awful/layout/suit/init.lua create mode 100644 lib/awful/layout/suit/magnifier.lua create mode 100644 lib/awful/layout/suit/max.lua create mode 100644 lib/awful/layout/suit/spiral.lua create mode 100644 lib/awful/layout/suit/tile.lua (limited to 'lib/awful/layout') diff --git a/lib/awful/layout/init.lua b/lib/awful/layout/init.lua new file mode 100644 index 0000000..dfce562 --- /dev/null +++ b/lib/awful/layout/init.lua @@ -0,0 +1,323 @@ +--------------------------------------------------------------------------- +--- Layout module for awful +-- +-- @author Julien Danjou <julien@danjou.info> +-- @copyright 2008 Julien Danjou +-- @module awful.layout +--------------------------------------------------------------------------- + +-- Grab environment we need +local ipairs = ipairs +local type = type +local util = require("awful.util") +local capi = { + screen = screen, + mouse = mouse, + awesome = awesome, + client = client, + tag = tag +} +local tag = require("awful.tag") +local client = require("awful.client") +local ascreen = require("awful.screen") +local timer = require("gears.timer") + +local function get_screen(s) + return s and capi.screen[s] +end + +local layout = {} + +layout.suit = require("awful.layout.suit") + +layout.layouts = { + layout.suit.floating, + layout.suit.tile, + layout.suit.tile.left, + layout.suit.tile.bottom, + layout.suit.tile.top, + layout.suit.fair, + layout.suit.fair.horizontal, + layout.suit.spiral, + layout.suit.spiral.dwindle, + layout.suit.max, + layout.suit.max.fullscreen, + layout.suit.magnifier, + layout.suit.corner.nw, + layout.suit.corner.ne, + layout.suit.corner.sw, + layout.suit.corner.se, +} + +--- The default list of layouts. +-- +-- The default value is: +-- +-- awful.layout.suit.floating, +-- awful.layout.suit.tile, +-- awful.layout.suit.tile.left, +-- awful.layout.suit.tile.bottom, +-- awful.layout.suit.tile.top, +-- awful.layout.suit.fair, +-- awful.layout.suit.fair.horizontal, +-- awful.layout.suit.spiral, +-- awful.layout.suit.spiral.dwindle, +-- awful.layout.suit.max, +-- awful.layout.suit.max.fullscreen, +-- awful.layout.suit.magnifier, +-- awful.layout.suit.corner.nw, +-- awful.layout.suit.corner.ne, +-- awful.layout.suit.corner.sw, +-- awful.layout.suit.corner.se, +-- +-- @field layout.layouts + + +-- This is a special lock used by the arrange function. +-- This avoids recurring call by emitted signals. +local arrange_lock = false +-- Delay one arrange call per screen. +local delayed_arrange = {} + +--- Get the current layout. +-- @param screen The screen. +-- @return The layout function. +function layout.get(screen) + screen = screen or capi.mouse.screen + local t = get_screen(screen).selected_tag + return tag.getproperty(t, "layout") or layout.suit.floating +end + +--- Change the layout of the current tag. +-- @param i Relative index. +-- @param s The screen. +-- @param[opt] layouts A table of layouts. +function layout.inc(i, s, layouts) + if type(i) == "table" then + -- Older versions of this function had arguments (layouts, i, s), but + -- this was changed so that 'layouts' can be an optional parameter + layouts, i, s = i, s, layouts + end + s = get_screen(s or ascreen.focused()) + local t = s.selected_tag + layouts = layouts or layout.layouts + if t then + local curlayout = layout.get(s) + local curindex + for k, v in ipairs(layouts) do + if v == curlayout or curlayout._type == v then + curindex = k + break + end + end + if not curindex then + -- Safety net: handle cases where another reference of the layout + -- might be given (e.g. when (accidentally) cloning it). + for k, v in ipairs(layouts) do + if v.name == curlayout.name then + curindex = k + break + end + end + end + if curindex then + local newindex = util.cycle(#layouts, curindex + i) + layout.set(layouts[newindex], t) + end + end +end + +--- Set the layout function of the current tag. +-- @param _layout Layout name. +-- @tparam[opt=mouse.screen.selected_tag] tag t The tag to modify. +function layout.set(_layout, t) + t = t or capi.mouse.screen.selected_tag + t.layout = _layout +end + +--- Get the layout parameters used for the screen +-- +-- This should give the same result as "arrange", but without the "geometries" +-- parameter, as this is computed during arranging. +-- +-- If `t` is given, `screen` is ignored, if none are given, the mouse screen is +-- used. +-- +-- @tparam[opt] tag t The tag to query +-- @param[opt] screen The screen +-- @treturn table A table with the workarea (x, y, width, height), the screen +-- geometry (x, y, width, height), the clients, the screen and sometime, a +-- "geometries" table with client as keys and geometry as value +function layout.parameters(t, screen) + screen = get_screen(screen) + t = t or screen.selected_tag + + screen = get_screen(t and t.screen or 1) + + local p = {} + + local clients = client.tiled(screen) + local gap_single_client = true + + if(t and t.gap_single_client ~= nil) then + gap_single_client = t.gap_single_client + end + + local min_clients = gap_single_client and 1 or 2 + local useless_gap = t and (#clients >= min_clients and t.gap or 0) or 0 + + p.workarea = screen:get_bounding_geometry { + honor_padding = true, + honor_workarea = true, + margins = useless_gap, + } + + p.geometry = screen.geometry + p.clients = clients + p.screen = screen.index + p.padding = screen.padding + p.useless_gap = useless_gap + + return p +end + +--- Arrange a screen using its current layout. +-- @param screen The screen to arrange. +function layout.arrange(screen) + screen = get_screen(screen) + if not screen or delayed_arrange[screen] then return end + delayed_arrange[screen] = true + + timer.delayed_call(function() + if not screen.valid then + -- Screen was removed + delayed_arrange[screen] = nil + return + end + if arrange_lock then return end + arrange_lock = true + + local p = layout.parameters(nil, screen) + + local useless_gap = p.useless_gap + + p.geometries = setmetatable({}, {__mode = "k"}) + layout.get(screen).arrange(p) + for c, g in pairs(p.geometries) do + g.width = math.max(1, g.width - c.border_width * 2 - useless_gap * 2) + g.height = math.max(1, g.height - c.border_width * 2 - useless_gap * 2) + g.x = g.x + useless_gap + g.y = g.y + useless_gap + c:geometry(g) + end + arrange_lock = false + delayed_arrange[screen] = nil + + screen:emit_signal("arrange") + end) +end + +--- Get the current layout name. +-- @param _layout The layout. +-- @return The layout name. +function layout.getname(_layout) + _layout = _layout or layout.get() + return _layout.name +end + +local function arrange_prop_nf(obj) + if not client.object.get_floating(obj) then + layout.arrange(obj.screen) + end +end + +local function arrange_prop(obj) layout.arrange(obj.screen) end + +capi.client.connect_signal("property::size_hints_honor", arrange_prop_nf) +capi.client.connect_signal("property::struts", arrange_prop) +capi.client.connect_signal("property::minimized", arrange_prop_nf) +capi.client.connect_signal("property::sticky", arrange_prop_nf) +capi.client.connect_signal("property::fullscreen", arrange_prop_nf) +capi.client.connect_signal("property::maximized_horizontal", arrange_prop_nf) +capi.client.connect_signal("property::maximized_vertical", arrange_prop_nf) +capi.client.connect_signal("property::border_width", arrange_prop_nf) +capi.client.connect_signal("property::hidden", arrange_prop_nf) +capi.client.connect_signal("property::floating", arrange_prop) +capi.client.connect_signal("property::geometry", arrange_prop_nf) +capi.client.connect_signal("property::screen", function(c, old_screen) + if old_screen then + layout.arrange(old_screen) + end + layout.arrange(c.screen) +end) + +local function arrange_tag(t) + layout.arrange(t.screen) +end + +capi.tag.connect_signal("property::master_width_factor", arrange_tag) +capi.tag.connect_signal("property::master_count", arrange_tag) +capi.tag.connect_signal("property::column_count", arrange_tag) +capi.tag.connect_signal("property::layout", arrange_tag) +capi.tag.connect_signal("property::windowfact", arrange_tag) +capi.tag.connect_signal("property::selected", arrange_tag) +capi.tag.connect_signal("property::activated", arrange_tag) +capi.tag.connect_signal("property::useless_gap", arrange_tag) +capi.tag.connect_signal("property::master_fill_policy", arrange_tag) +capi.tag.connect_signal("tagged", arrange_tag) + +capi.screen.connect_signal("property::workarea", layout.arrange) +capi.screen.connect_signal("padding", layout.arrange) + +capi.client.connect_signal("raised", function(c) layout.arrange(c.screen) end) +capi.client.connect_signal("lowered", function(c) layout.arrange(c.screen) end) +capi.client.connect_signal("list", function() + for screen in capi.screen do + layout.arrange(screen) + end + end) + +--- Default handler for `request::geometry` signals for tiled clients with +-- the "mouse.move" context. +-- @tparam client c The client +-- @tparam string context The context +-- @tparam table hints Additional hints +function layout.move_handler(c, context, hints) --luacheck: no unused args + -- Quit if it isn't a mouse.move on a tiled layout, that's handled elsewhere + if c.floating then return end + if context ~= "mouse.move" then return end + + if capi.mouse.screen ~= c.screen then + c.screen = capi.mouse.screen + end + + local l = c.screen.selected_tag and c.screen.selected_tag.layout or nil + if l == layout.suit.floating then return end + + local c_u_m = capi.mouse.current_client + if c_u_m and not c_u_m.floating then + if c_u_m ~= c then + c:swap(c_u_m) + end + end +end + +capi.client.connect_signal("request::geometry", layout.move_handler) + +-- When a screen is moved, make (floating) clients follow it +capi.screen.connect_signal("property::geometry", function(s, old_geom) + local geom = s.geometry + local xshift = geom.x - old_geom.x + local yshift = geom.y - old_geom.y + for _, c in ipairs(capi.client.get(s)) do + local cgeom = c:geometry() + c:geometry({ + x = cgeom.x + xshift, + y = cgeom.y + yshift + }) + end +end) + +return layout + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/corner.lua b/lib/awful/layout/suit/corner.lua new file mode 100644 index 0000000..4b746c9 --- /dev/null +++ b/lib/awful/layout/suit/corner.lua @@ -0,0 +1,204 @@ +--------------------------------------------------------------------------- +-- Corner layout. +-- Display master client in a corner of the screen, and slaves in one +-- column and one row around the master. +-- See Pull Request for example : https://github.com/awesomeWM/awesome/pull/251 +-- @module awful.layout +-- @author Alexis Brenon <brenon.alexis+awesomewm@gmail.com> +-- @copyright 2015 Alexis Brenon + +-- Grab environment we need +local ipairs = ipairs +local math = math +local capi = {screen = screen} + +--- The cornernw layout layoutbox icon. +-- @beautiful beautiful.layout_cornernw +-- @param surface +-- @see gears.surface + +--- The cornerne layout layoutbox icon. +-- @beautiful beautiful.layout_cornerne +-- @param surface +-- @see gears.surface + +--- The cornersw layout layoutbox icon. +-- @beautiful beautiful.layout_cornersw +-- @param surface +-- @see gears.surface + +--- The cornerse layout layoutbox icon. +-- @beautiful beautiful.layout_cornerse +-- @param surface +-- @see gears.surface + +-- Actually arrange clients of p.clients for corner layout +-- @param p Mandatory table containing required informations for layouts +-- (clients to arrange, workarea geometry, etc.) +-- @param orientation String indicating in which corner is the master window. +-- Available values are : NE, NW, SW, SE +local function do_corner(p, orientation) + local t = p.tag or capi.screen[p.screen].selected_tag + local wa = p.workarea + local cls = p.clients + + if #cls == 0 then return end + + local master = {} + local column = {} + local row = {} + -- Use the nmaster field of the tag in a cheaty way + local row_privileged = ((cls[1].screen.selected_tag.master_count % 2) == 0) + + local master_factor = cls[1].screen.selected_tag.master_width_factor + master.width = master_factor * wa.width + master.height = master_factor * wa.height + + local number_privileged_win = math.ceil((#cls - 1)/2) + local number_unprivileged_win = (#cls - 1) - number_privileged_win + + -- Define some obvious parameters + column.width = wa.width - master.width + column.x_increment = 0 + row.height = wa.height - master.height + row.y_increment = 0 + + -- Place master at the right place and move row and column accordingly + column.y = wa.y + row.x = wa.x + if orientation:match('N.') then + master.y = wa.y + row.y = master.y + master.height + elseif orientation:match('S.') then + master.y = wa.y + wa.height - master.height + row.y = wa.y + end + if orientation:match('.W') then + master.x = wa.x + column.x = master.x + master.width + elseif orientation:match('.E') then + master.x = wa.x + wa.width - master.width + column.x = wa.x + end + -- At this point, master is in a corner + -- but row and column are overlayed in the opposite corner... + + -- Reduce the unprivileged slaves to remove overlay + -- and define actual width and height + if row_privileged then + row.width = wa.width + row.number_win = number_privileged_win + column.y = master.y + column.height = master.height + column.number_win = number_unprivileged_win + else + column.height = wa.height + column.number_win = number_privileged_win + row.x = master.x + row.width = master.width + row.number_win = number_unprivileged_win + end + + column.win_height = column.height/column.number_win + column.win_width = column.width + column.y_increment = column.win_height + column.win_idx = 0 + + row.win_width = row.width/row.number_win + row.win_height = row.height + row.x_increment = row.win_width + row.win_idx = 0 + + -- Extend master if there is only a few windows and "expand" policy is set + if #cls < 3 then + if row_privileged then + master.x = wa.x + master.width = wa.width + else + master.y = wa.y + master.height = wa.height + end + if #cls < 2 then + if t.master_fill_policy == "expand" then + master = wa + else + master.x = master.x + (wa.width - master.width)/2 + master.y = master.y + (wa.height - master.height)/2 + end + end + end + + for i, c in ipairs(cls) do + local g + -- Handle master window + if i == 1 then + g = { + x = master.x, + y = master.y, + width = master.width, + height = master.height + } + -- handle column windows + elseif i % 2 == 0 then + g = { + x = column.x + column.win_idx * column.x_increment, + y = column.y + column.win_idx * column.y_increment, + width = column.win_width, + height = column.win_height + } + column.win_idx = column.win_idx + 1 + else + g = { + x = row.x + row.win_idx * row.x_increment, + y = row.y + row.win_idx * row.y_increment, + width = row.win_width, + height = row.win_height + } + row.win_idx = row.win_idx + 1 + end + p.geometries[c] = g + end +end + +local corner = {} +corner.row_privileged = false + +--- Corner layout. +-- Display master client in a corner of the screen, and slaves in one +-- column and one row around the master. +-- @clientlayout awful.layout.suit.corner.nw +corner.nw = { + name = "cornernw", + arrange = function (p) return do_corner(p, "NW") end + } + +--- Corner layout. +-- Display master client in a corner of the screen, and slaves in one +-- column and one row around the master. +-- @clientlayout awful.layout.suit.corner.ne +corner.ne = { + name = "cornerne", + arrange = function (p) return do_corner(p, "NE") end + } + +--- Corner layout. +-- Display master client in a corner of the screen, and slaves in one +-- column and one row around the master. +-- @clientlayout awful.layout.suit.corner.sw +corner.sw = { + name = "cornersw", + arrange = function (p) return do_corner(p, "SW") end + } + +--- Corner layout. +-- Display master client in a corner of the screen, and slaves in one +-- column and one row around the master. +-- @clientlayout awful.layout.suit.corner.se +corner.se = { + name = "cornerse", + arrange = function (p) return do_corner(p, "SE") end + } + +return corner + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/fair.lua b/lib/awful/layout/suit/fair.lua new file mode 100644 index 0000000..161b6ed --- /dev/null +++ b/lib/awful/layout/suit/fair.lua @@ -0,0 +1,108 @@ +--------------------------------------------------------------------------- +--- Fair layouts module for awful. +-- +-- @author Josh Komoroske +-- @copyright 2012 Josh Komoroske +-- @module awful.layout +--------------------------------------------------------------------------- + +-- Grab environment we need +local ipairs = ipairs +local math = math + +--- The fairh layout layoutbox icon. +-- @beautiful beautiful.layout_fairh +-- @param surface +-- @see gears.surface + +--- The fairv layout layoutbox icon. +-- @beautiful beautiful.layout_fairv +-- @param surface +-- @see gears.surface + +local fair = {} + +local function do_fair(p, orientation) + local wa = p.workarea + local cls = p.clients + + -- Swap workarea dimensions, if our orientation is "east" + if orientation == 'east' then + wa.width, wa.height = wa.height, wa.width + wa.x, wa.y = wa.y, wa.x + end + + if #cls > 0 then + local rows, cols + if #cls == 2 then + rows, cols = 1, 2 + else + rows = math.ceil(math.sqrt(#cls)) + cols = math.ceil(#cls / rows) + end + + for k, c in ipairs(cls) do + k = k - 1 + local g = {} + + local row, col + row = k % rows + col = math.floor(k / rows) + + local lrows, lcols + if k >= rows * cols - rows then + lrows = #cls - (rows * cols - rows) + lcols = cols + else + lrows = rows + lcols = cols + end + + if row == lrows - 1 then + g.height = wa.height - math.ceil(wa.height / lrows) * row + g.y = wa.height - g.height + else + g.height = math.ceil(wa.height / lrows) + g.y = g.height * row + end + + if col == lcols - 1 then + g.width = wa.width - math.ceil(wa.width / lcols) * col + g.x = wa.width - g.width + else + g.width = math.ceil(wa.width / lcols) + g.x = g.width * col + end + + g.y = g.y + wa.y + g.x = g.x + wa.x + + -- Swap window dimensions, if our orientation is "east" + if orientation == 'east' then + g.width, g.height = g.height, g.width + g.x, g.y = g.y, g.x + end + + p.geometries[c] = g + end + end +end + +--- Horizontal fair layout. +-- @param screen The screen to arrange. +fair.horizontal = {} +fair.horizontal.name = "fairh" +function fair.horizontal.arrange(p) + return do_fair(p, "east") +end + +--- Vertical fair layout. +-- @param screen The screen to arrange. +fair.name = "fairv" +function fair.arrange(p) + return do_fair(p, "south") +end + +return fair + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/floating.lua b/lib/awful/layout/suit/floating.lua new file mode 100644 index 0000000..b769435 --- /dev/null +++ b/lib/awful/layout/suit/floating.lua @@ -0,0 +1,112 @@ +--------------------------------------------------------------------------- +--- Dummy function for floating layout +-- +-- @author Gregor Best +-- @copyright 2008 Gregor Best +-- @module awful.layout +--------------------------------------------------------------------------- + +-- Grab environment we need +local ipairs = ipairs +local capi = +{ + mouse = mouse, + mousegrabber = mousegrabber +} + +--- The floating layout layoutbox icon. +-- @beautiful beautiful.layout_floating +-- @param surface +-- @see gears.surface + +local floating = {} + +--- Jump mouse cursor to the client's corner when resizing it. +floating.resize_jump_to_corner = true + +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 + + local prev_coords = {} + local coordinates_delta = {x=0,y=0} + if floating.resize_jump_to_corner then + -- Warp mouse pointer + capi.mouse.coords({ x = x, y = y }) + else + local corner_x, corner_y = x, y + local mouse_coords = capi.mouse.coords() + x = mouse_coords.x + y = mouse_coords.y + coordinates_delta = {x=corner_x-x,y=corner_y-y} + end + + capi.mousegrabber.run(function (_mouse) + if not c.valid then return false end + + _mouse.x = _mouse.x + coordinates_delta.x + _mouse.y = _mouse.y + coordinates_delta.y + for _, v in ipairs(_mouse.buttons) do + if v then + local ng + prev_coords = { x =_mouse.x, y = _mouse.y } + 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 prev_coords.x == _mouse.x and prev_coords.y == _mouse.y + end, corner .. "_corner") +end + +function floating.arrange() +end + +--- The floating layout. +-- @clientlayout awful.layout.suit. + +floating.name = "floating" + +return floating + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/init.lua b/lib/awful/layout/suit/init.lua new file mode 100644 index 0000000..57a49fa --- /dev/null +++ b/lib/awful/layout/suit/init.lua @@ -0,0 +1,19 @@ +--------------------------------------------------------------------------- +--- Suits for awful +-- @author Julien Danjou <julien@danjou.info> +-- @copyright 2008 Julien Danjou +-- @module awful.layout +--------------------------------------------------------------------------- + +return +{ + corner = require("awful.layout.suit.corner"); + max = require("awful.layout.suit.max"); + tile = require("awful.layout.suit.tile"); + fair = require("awful.layout.suit.fair"); + floating = require("awful.layout.suit.floating"); + magnifier = require("awful.layout.suit.magnifier"); + spiral = require("awful.layout.suit.spiral"); +} + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/magnifier.lua b/lib/awful/layout/suit/magnifier.lua new file mode 100644 index 0000000..f30d7ee --- /dev/null +++ b/lib/awful/layout/suit/magnifier.lua @@ -0,0 +1,147 @@ +--------------------------------------------------------------------------- +--- Magnifier layout module for awful +-- +-- @author Julien Danjou <julien@danjou.info> +-- @copyright 2008 Julien Danjou +-- @module awful.layout +--------------------------------------------------------------------------- + +-- Grab environment we need +local ipairs = ipairs +local math = math +local capi = +{ + client = client, + screen = screen, + mouse = mouse, + mousegrabber = mousegrabber +} + +--- The magnifier layout layoutbox icon. +-- @beautiful beautiful.layout_magnifier +-- @param surface +-- @see gears.surface + +local magnifier = {} + +function magnifier.mouse_resize_handler(c, corner, x, y) + capi.mouse.coords({ x = x, y = y }) + + local wa = 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 + + local prev_coords = {} + capi.mousegrabber.run(function (_mouse) + if not c.valid then return false end + + for _, v in ipairs(_mouse.buttons) do + if v then + prev_coords = { x =_mouse.x, y = _mouse.y } + 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 + c.screen.selected_tag.master_width_factor + = math.min(math.max(0.01, mwfact), 0.99) + return true + end + end + return prev_coords.x == _mouse.x and prev_coords.y == _mouse.y + end, corner .. "_corner") +end + +function magnifier.arrange(p) + -- Fullscreen? + local area = p.workarea + local cls = p.clients + local focus = p.focus or capi.client.focus + local t = p.tag or capi.screen[p.screen].selected_tag + local mwfact = t.master_width_factor + local fidx + + -- Check that the focused window is on the right screen + if focus and focus.screen ~= p.screen then focus = nil end + + -- If no window is focused or focused window is not tiled, take the first tiled one. + if (not focus or focus.floating) and #cls > 0 then + focus = cls[1] + fidx = 1 + end + + -- Abort if no clients are present + if not focus then return end + + local geometry = {} + if #cls > 1 then + geometry.width = area.width * math.sqrt(mwfact) + geometry.height = area.height * math.sqrt(mwfact) + geometry.x = area.x + (area.width - geometry.width) / 2 + geometry.y = area.y + (area.height - geometry.height) /2 + else + geometry.x = area.x + geometry.y = area.y + geometry.width = area.width + geometry.height = area.height + end + + local g = { + x = geometry.x, + y = geometry.y, + width = geometry.width, + height = geometry.height + } + p.geometries[focus] = g + + if #cls > 1 then + geometry.x = area.x + geometry.y = area.y + geometry.height = area.height / (#cls - 1) + geometry.width = area.width + + -- We don't know the focus window index. Try to find it. + if not fidx then + for k, c in ipairs(cls) do + if c == focus then + fidx = k + break + end + end + end + + -- First move clients that are before focused client. + for k = fidx + 1, #cls do + p.geometries[cls[k]] = { + x = geometry.x, + y = geometry.y, + width = geometry.width, + height = geometry.height + } + geometry.y = geometry.y + geometry.height + end + + -- Then move clients that are after focused client. + -- So the next focused window will be the one at the top of the screen. + for k = 1, fidx - 1 do + p.geometries[cls[k]] = { + x = geometry.x, + y = geometry.y, + width = geometry.width, + height = geometry.height + } + geometry.y = geometry.y + geometry.height + end + end +end + +--- The magnifier layout. +-- @clientlayout awful.layout.suit.magnifier + +magnifier.name = "magnifier" + +return magnifier + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/max.lua b/lib/awful/layout/suit/max.lua new file mode 100644 index 0000000..2cd1812 --- /dev/null +++ b/lib/awful/layout/suit/max.lua @@ -0,0 +1,61 @@ +--------------------------------------------------------------------------- +--- Maximized and fullscreen layouts module for awful +-- +-- @author Julien Danjou <julien@danjou.info> +-- @copyright 2008 Julien Danjou +-- @module awful.layout +--------------------------------------------------------------------------- + +-- Grab environment we need +local pairs = pairs + +local max = {} + +--- The max layout layoutbox icon. +-- @beautiful beautiful.layout_max +-- @param surface +-- @see gears.surface + +--- The fullscreen layout layoutbox icon. +-- @beautiful beautiful.layout_fullscreen +-- @param surface +-- @see gears.surface + +local function fmax(p, fs) + -- Fullscreen? + local area + if fs then + area = p.geometry + else + area = p.workarea + end + + for _, c in pairs(p.clients) do + local g = { + x = area.x, + y = area.y, + width = area.width, + height = area.height + } + p.geometries[c] = g + end +end + +--- Maximized layout. +-- @clientlayout awful.layout.suit.max.name +max.name = "max" +function max.arrange(p) + return fmax(p, false) +end + +--- Fullscreen layout. +-- @clientlayout awful.layout.suit.max.fullscreen +max.fullscreen = {} +max.fullscreen.name = "fullscreen" +function max.fullscreen.arrange(p) + return fmax(p, true) +end + +return max + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/spiral.lua b/lib/awful/layout/suit/spiral.lua new file mode 100644 index 0000000..0a7eb9b --- /dev/null +++ b/lib/awful/layout/suit/spiral.lua @@ -0,0 +1,89 @@ +--------------------------------------------------------------------------- +--- Dwindle and spiral layouts +-- +-- @author Uli Schlachter <psychon@znc.in> +-- @copyright 2009 Uli Schlachter +-- @copyright 2008 Julien Danjou +-- +-- @module awful.layout +--------------------------------------------------------------------------- + +-- Grab environment we need +local ipairs = ipairs +local math = math + +--- The spiral layout layoutbox icon. +-- @beautiful beautiful.layout_spiral +-- @param surface +-- @see gears.surface + +--- The dwindle layout layoutbox icon. +-- @beautiful beautiful.layout_dwindle +-- @param surface +-- @see gears.surface + +local spiral = {} + +local function do_spiral(p, _spiral) + local wa = p.workarea + local cls = p.clients + local n = #cls + local old_width, old_height = wa.width, 2 * wa.height + + for k, c in ipairs(cls) do + if k % 2 == 0 then + wa.width, old_width = math.ceil(old_width / 2), wa.width + if k ~= n then + wa.height, old_height = math.floor(wa.height / 2), wa.height + end + else + wa.height, old_height = math.ceil(old_height / 2), wa.height + if k ~= n then + wa.width, old_width = math.floor(wa.width / 2), wa.width + end + end + + if k % 4 == 0 and _spiral then + wa.x = wa.x - wa.width + elseif k % 2 == 0 then + wa.x = wa.x + old_width + elseif k % 4 == 3 and k < n and _spiral then + wa.x = wa.x + math.ceil(old_width / 2) + end + + if k % 4 == 1 and k ~= 1 and _spiral then + wa.y = wa.y - wa.height + elseif k % 2 == 1 and k ~= 1 then + wa.y = wa.y + old_height + elseif k % 4 == 0 and k < n and _spiral then + wa.y = wa.y + math.ceil(old_height / 2) + end + + local g = { + x = wa.x, + y = wa.y, + width = wa.width, + height = wa.height + } + p.geometries[c] = g + end +end + +--- Dwindle layout. +-- @clientlayout awful.layout.suit.spiral.dwindle +spiral.dwindle = {} +spiral.dwindle.name = "dwindle" +function spiral.dwindle.arrange(p) + return do_spiral(p, false) +end + +--- Spiral layout. +-- @clientlayout awful.layout.suit.spiral.name +spiral.name = "spiral" +function spiral.arrange(p) + return do_spiral(p, true) +end + +return spiral + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/awful/layout/suit/tile.lua b/lib/awful/layout/suit/tile.lua new file mode 100644 index 0000000..9fa263c --- /dev/null +++ b/lib/awful/layout/suit/tile.lua @@ -0,0 +1,348 @@ +--------------------------------------------------------------------------- +--- Tiled layouts module for awful +-- +-- @author Donald Ephraim Curtis <dcurtis@cs.uiowa.edu> +-- @author Julien Danjou <julien@danjou.info> +-- @copyright 2009 Donald Ephraim Curtis +-- @copyright 2008 Julien Danjou +-- @module awful.layout +--------------------------------------------------------------------------- + +-- Grab environment we need +local tag = require("awful.tag") +local client = require("awful.client") +local ipairs = ipairs +local math = math +local capi = +{ + mouse = mouse, + screen = screen, + mousegrabber = mousegrabber +} + +local tile = {} + +--- The tile layout layoutbox icon. +-- @beautiful beautiful.layout_tile +-- @param surface +-- @see gears.surface + +--- The tile top layout layoutbox icon. +-- @beautiful beautiful.layout_tiletop +-- @param surface +-- @see gears.surface + +--- The tile bottom layout layoutbox icon. +-- @beautiful beautiful.layout_tilebottom +-- @param surface +-- @see gears.surface + +--- The tile left layout layoutbox icon. +-- @beautiful beautiful.layout_tileleft +-- @param surface +-- @see gears.surface + +--- Jump mouse cursor to the client's corner when resizing it. +tile.resize_jump_to_corner = true + +local function mouse_resize_handler(c, _, _, _, orientation) + orientation = orientation or "tile" + local wa = c.screen.workarea + local mwfact = c.screen.selected_tag.master_width_factor + local cursor + local g = c:geometry() + local offset = 0 + local corner_coords + local coordinates_delta = {x=0,y=0} + + 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 + corner_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 + corner_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 + corner_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 + corner_coords = { y = wa.y + wa.height * (1 - mwfact), x= g.x + offset } + end + if tile.resize_jump_to_corner then + capi.mouse.coords(corner_coords) + else + local mouse_coords = capi.mouse.coords() + coordinates_delta = { + x = corner_coords.x - mouse_coords.x, + y = corner_coords.y - mouse_coords.y, + } + end + + local prev_coords = {} + capi.mousegrabber.run(function (_mouse) + if not c.valid then return false end + + _mouse.x = _mouse.x + coordinates_delta.x + _mouse.y = _mouse.y + coordinates_delta.y + for _, v in ipairs(_mouse.buttons) do + if v then + prev_coords = { x =_mouse.x, y = _mouse.y } + local fact_x = (_mouse.x - wa.x) / wa.width + local fact_y = (_mouse.y - wa.y) / wa.height + local new_mwfact + + local geom = 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 (geom.y+geom.height+15) > (wa.y+wa.height) then + wfact_y = (geom.y + geom.height - _mouse.y) / wa.height + else + wfact_y = (_mouse.y - geom.y) / wa.height + end + + if (geom.x+geom.width+15) > (wa.x+wa.width) then + wfact_x = (geom.x + geom.width - _mouse.x) / wa.width + else + wfact_x = (_mouse.x - geom.x) / wa.width + end + + + if orientation == "tile" then + new_mwfact = fact_x + wfact = wfact_y + elseif orientation == "left" then + new_mwfact = 1 - fact_x + wfact = wfact_y + elseif orientation == "bottom" then + new_mwfact = fact_y + wfact = wfact_x + else + new_mwfact = 1 - fact_y + wfact = wfact_x + end + + c.screen.selected_tag.master_width_factor + = math.min(math.max(new_mwfact, 0.01), 0.99) + client.setwfact(math.min(math.max(wfact,0.01), 0.99), c) + return true + end + end + return prev_coords.x == _mouse.x and prev_coords.y == _mouse.y + end, cursor) +end + +local function tile_group(gs, cls, wa, orientation, fact, group) + -- get our orientation right + local height = "height" + local width = "width" + local x = "x" + local y = "y" + if orientation == "top" or orientation == "bottom" then + height = "width" + width = "height" + x = "y" + y = "x" + end + + -- make this more generic (not just width) + local available = wa[width] - (group.coord - wa[x]) + + -- find our total values + local total_fact = 0 + local min_fact = 1 + local size = group.size + for c = group.first,group.last do + -- determine the width/height based on the size_hint + local i = c - group.first +1 + local size_hints = cls[c].size_hints + local size_hint = size_hints["min_"..width] or size_hints["base_"..width] or 0 + size = math.max(size_hint, size) + + -- calculate the height + if not fact[i] then + fact[i] = min_fact + else + min_fact = math.min(fact[i],min_fact) + end + total_fact = total_fact + fact[i] + end + size = math.max(1, math.min(size, available)) + + local coord = wa[y] + local used_size = 0 + local unused = wa[height] + for c = group.first,group.last do + local geom = {} + local hints = {} + local i = c - group.first +1 + geom[width] = size + geom[height] = math.max(1, math.floor(unused * fact[i] / total_fact)) + geom[x] = group.coord + geom[y] = coord + gs[cls[c]] = geom + hints.width, hints.height = cls[c]:apply_size_hints(geom.width, geom.height) + coord = coord + hints[height] + unused = unused - hints[height] + total_fact = total_fact - fact[i] + used_size = math.max(used_size, hints[width]) + end + + return used_size +end + +local function do_tile(param, orientation) + local t = param.tag or capi.screen[param.screen].selected_tag + orientation = orientation or "right" + + -- This handles all different orientations. + local width = "width" + local x = "x" + if orientation == "top" or orientation == "bottom" then + width = "height" + x = "y" + end + + local gs = param.geometries + local cls = param.clients + local nmaster = math.min(t.master_count, #cls) + local nother = math.max(#cls - nmaster,0) + + local mwfact = t.master_width_factor + local wa = param.workarea + local ncol = t.column_count + + local data = tag.getdata(t).windowfact + + if not data then + data = {} + tag.getdata(t).windowfact = data + end + + local coord = wa[x] + local place_master = true + if orientation == "left" or orientation == "top" then + -- if we are on the left or top we need to render the other windows first + place_master = false + end + + local grow_master = t.master_fill_policy == "expand" + -- this was easier than writing functions because there is a lot of data we need + for _ = 1,2 do + if place_master and nmaster > 0 then + local size = wa[width] + if nother > 0 or not grow_master then + size = math.min(wa[width] * mwfact, wa[width] - (coord - wa[x])) + end + if nother == 0 and not grow_master then + coord = coord + (wa[width] - size)/2 + end + if not data[0] then + data[0] = {} + end + coord = coord + tile_group(gs, cls, wa, orientation, data[0], {first=1, last=nmaster, coord = coord, size = size}) + end + + if not place_master and nother > 0 then + local last = nmaster + + -- we have to modify the work area size to consider left and top views + local wasize = wa[width] + if nmaster > 0 and (orientation == "left" or orientation == "top") then + wasize = wa[width] - wa[width]*mwfact + end + for i = 1,ncol do + -- Try to get equal width among remaining columns + local size = math.min( (wasize - (coord - wa[x])) / (ncol - i + 1) ) + local first = last + 1 + last = last + math.floor((#cls - last)/(ncol - i + 1)) + -- tile the column and update our current x coordinate + if not data[i] then + data[i] = {} + end + coord = coord + tile_group(gs, cls, wa, orientation, data[i], { first = first, last = last, coord = coord, size = size }) + end + end + place_master = not place_master + end + +end + +--- The main tile algo, on the right. +-- @param screen The screen number to tile. +-- @clientlayout awful.layout.suit.tile.top +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 the left. +-- @param screen The screen number to tile. +-- @clientlayout awful.layout.suit.tile.left +tile.left = {} +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 the bottom. +-- @param screen The screen number to tile. +-- @clientlayout awful.layout.suit.tile.bottom +tile.bottom = {} +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 the top. +-- @param screen The screen number to tile. +-- @clientlayout awful.layout.suit.tile.top +tile.top = {} +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 + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- cgit v1.2.3-54-g00ecf