Merge pull request #824 from Elv13/rules_refactor
Rules refactor, part 1 This fix the following awful.rules bugs: * **x**: Broken when "border_width" is set or left titlebars are used * **y**: Borken when"border_width" is set or top titlebars are used * **width**: See above + right litlebar * **height**: Same as above * **switchtotag**: Have a race with the "manage" -> "tag.withcurrent" code in `awful.tag` * **tag**: Had dead code * **screen**: Had a race condition with switchtotag * **urgent**: Had a race with screen and another with switchtotag+focus * **focusable**: Was broken yet again when request::activate was introduced (and also because of FS1098, that I also fixed) * **no_overlap**: The "no_overlap" call in rc.lua "manage" section conflict with the geometry rules as the hints are not set (idk why). * **size_hints_honor**: If set to false, it would be applied too late, causing height and width offsets due to placement or various geometry related properties
This commit is contained in:
commit
cdc6909bc7
|
@ -29,7 +29,7 @@ install:
|
|||
|
||||
# Install build dependencies.
|
||||
# See also `apt-cache showsrc awesome | grep -E '^(Version|Build-Depends)'`.
|
||||
- sudo apt-get install -y libcairo2-dev xmlto asciidoc libpango1.0-dev libxcb-xtest0-dev libxcb-icccm4-dev libxcb-randr0-dev libxcb-keysyms1-dev libxcb-xinerama0-dev libdbus-1-dev libxdg-basedir-dev libstartup-notification0-dev imagemagick libxcb1-dev libxcb-shape0-dev libxcb-util0-dev libx11-xcb-dev libxcb-cursor-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev
|
||||
- sudo apt-get install -y libcairo2-dev gtk+3.0 xmlto asciidoc libpango1.0-dev libxcb-xtest0-dev libxcb-icccm4-dev libxcb-randr0-dev libxcb-keysyms1-dev libxcb-xinerama0-dev libdbus-1-dev libxdg-basedir-dev libstartup-notification0-dev imagemagick libxcb1-dev libxcb-shape0-dev libxcb-util0-dev libx11-xcb-dev libxcb-cursor-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev
|
||||
|
||||
# Deps for functional tests.
|
||||
- sudo apt-get install -y dbus-x11 xterm xdotool xterm xvfb rxvt-unicode
|
||||
|
|
105
awesomerc.lua
105
awesomerc.lua
|
@ -1,7 +1,6 @@
|
|||
-- Standard awesome library
|
||||
local gears = require("gears")
|
||||
local awful = require("awful")
|
||||
awful.rules = require("awful.rules")
|
||||
require("awful.autofocus")
|
||||
-- Widget and layout library
|
||||
local wibox = require("wibox")
|
||||
|
@ -431,7 +430,10 @@ awful.rules.rules = {
|
|||
focus = awful.client.focus.filter,
|
||||
raise = true,
|
||||
keys = clientkeys,
|
||||
buttons = clientbuttons } },
|
||||
buttons = clientbuttons,
|
||||
placement = awful.placement.no_overlap+awful.placement.no_offscreen
|
||||
}
|
||||
},
|
||||
|
||||
-- Floating clients.
|
||||
{ rule_any = {
|
||||
|
@ -459,6 +461,11 @@ awful.rules.rules = {
|
|||
}
|
||||
}, properties = { floating = true }},
|
||||
|
||||
-- Add titlebars to normal clients and dialogs
|
||||
{ rule_any = {type = { "normal", "dialog" }
|
||||
}, properties = { titlebars_enabled = true }
|
||||
},
|
||||
|
||||
-- Set Firefox to always map on the tag named "2" on screen 1.
|
||||
-- { rule = { class = "Firefox" },
|
||||
-- properties = { screen = 1, tag = "2" } },
|
||||
|
@ -468,62 +475,58 @@ awful.rules.rules = {
|
|||
-- {{{ Signals
|
||||
-- Signal function to execute when a new client appears.
|
||||
client.connect_signal("manage", function (c)
|
||||
if not awesome.startup then
|
||||
-- Set the windows at the slave,
|
||||
-- i.e. put it at the end of others instead of setting it master.
|
||||
-- awful.client.setslave(c)
|
||||
-- Set the windows at the slave,
|
||||
-- i.e. put it at the end of others instead of setting it master.
|
||||
-- if not awesome.startup then awful.client.setslave(c) end
|
||||
|
||||
-- Put windows in a smart way, only if they do not set an initial position.
|
||||
if not c.size_hints.user_position and not c.size_hints.program_position then
|
||||
awful.placement.no_overlap(c)
|
||||
awful.placement.no_offscreen(c)
|
||||
end
|
||||
elseif not c.size_hints.user_position and not c.size_hints.program_position then
|
||||
if awesome.startup and
|
||||
not c.size_hints.user_position
|
||||
and not c.size_hints.program_position then
|
||||
-- Prevent clients from being unreachable after screen count changes.
|
||||
awful.placement.no_offscreen(c)
|
||||
end
|
||||
end)
|
||||
|
||||
local titlebars_enabled = true
|
||||
if titlebars_enabled and (c.type == "normal" or c.type == "dialog") then
|
||||
-- buttons for the titlebar
|
||||
local buttons = awful.util.table.join(
|
||||
awful.button({ }, 1, function()
|
||||
client.focus = c
|
||||
c:raise()
|
||||
awful.mouse.client.move(c)
|
||||
end),
|
||||
awful.button({ }, 3, function()
|
||||
client.focus = c
|
||||
c:raise()
|
||||
awful.mouse.client.resize(c)
|
||||
end)
|
||||
)
|
||||
-- Add a titlebar if titlebars_enabled is set to true in the rules.
|
||||
client.connect_signal("request::titlebars", function(c)
|
||||
-- buttons for the titlebar
|
||||
local buttons = awful.util.table.join(
|
||||
awful.button({ }, 1, function()
|
||||
client.focus = c
|
||||
c:raise()
|
||||
awful.mouse.client.move(c)
|
||||
end),
|
||||
awful.button({ }, 3, function()
|
||||
client.focus = c
|
||||
c:raise()
|
||||
awful.mouse.client.resize(c)
|
||||
end)
|
||||
)
|
||||
|
||||
awful.titlebar(c) : setup {
|
||||
{ -- Left
|
||||
awful.titlebar.widget.iconwidget(c),
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
awful.titlebar(c) : setup {
|
||||
{ -- Left
|
||||
awful.titlebar.widget.iconwidget(c),
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
},
|
||||
{ -- Middle
|
||||
{ -- Title
|
||||
align = "center",
|
||||
widget = awful.titlebar.widget.titlewidget(c)
|
||||
},
|
||||
{ -- Middle
|
||||
{ -- Title
|
||||
align = "center",
|
||||
widget = awful.titlebar.widget.titlewidget(c)
|
||||
},
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.flex.horizontal
|
||||
},
|
||||
{ -- Right
|
||||
awful.titlebar.widget.floatingbutton (c),
|
||||
awful.titlebar.widget.maximizedbutton(c),
|
||||
awful.titlebar.widget.stickybutton (c),
|
||||
awful.titlebar.widget.ontopbutton (c),
|
||||
awful.titlebar.widget.closebutton (c),
|
||||
layout = wibox.layout.fixed.horizontal()
|
||||
},
|
||||
layout = wibox.layout.align.horizontal
|
||||
}
|
||||
end
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.flex.horizontal
|
||||
},
|
||||
{ -- Right
|
||||
awful.titlebar.widget.floatingbutton (c),
|
||||
awful.titlebar.widget.maximizedbutton(c),
|
||||
awful.titlebar.widget.stickybutton (c),
|
||||
awful.titlebar.widget.ontopbutton (c),
|
||||
awful.titlebar.widget.closebutton (c),
|
||||
layout = wibox.layout.fixed.horizontal()
|
||||
},
|
||||
layout = wibox.layout.align.horizontal
|
||||
}
|
||||
end)
|
||||
|
||||
-- Enable sloppy focus
|
||||
|
|
2
ewmh.c
2
ewmh.c
|
@ -399,7 +399,7 @@ ewmh_process_desktop(client_t *c, uint32_t desktop)
|
|||
if(desktop == 0xffffffff)
|
||||
{
|
||||
luaA_object_push(L, c);
|
||||
lua_pushnil(L);
|
||||
lua_pushboolean(L, true);
|
||||
luaA_object_emit_signal(L, -2, "request::tag", 1);
|
||||
/* Pop the client, arguments are already popped */
|
||||
lua_pop(L, 1);
|
||||
|
|
|
@ -1114,6 +1114,12 @@ capi.client.add_signal("property::floating")
|
|||
|
||||
capi.client.add_signal("property::dockable")
|
||||
|
||||
--- Emited when a client need to get a titlebar.
|
||||
-- @signal request::titlebars
|
||||
-- @tparam[opt=nil] string content The context (like "rules")
|
||||
-- @tparam[opt=nil] table hints Some hints.
|
||||
capi.client.add_signal("request::titlebars")
|
||||
|
||||
--- The client marked signal (deprecated).
|
||||
-- @signal .marked
|
||||
capi.client.add_signal("marked")
|
||||
|
|
|
@ -12,71 +12,14 @@ local client = client
|
|||
local screen = screen
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local util = require("awful.util")
|
||||
local aclient = require("awful.client")
|
||||
local aplace = require("awful.placement")
|
||||
|
||||
local ewmh = {}
|
||||
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
local function store_geometry(window, reqtype)
|
||||
if not data[window] then data[window] = {} end
|
||||
if not data[window][reqtype] then data[window][reqtype] = {} end
|
||||
data[window][reqtype] = window:geometry()
|
||||
data[window][reqtype].screen = window.screen
|
||||
end
|
||||
|
||||
--- Maximize a window horizontally.
|
||||
--
|
||||
-- @param window The window.
|
||||
-- @param set Set or unset the maximized values.
|
||||
local function maximized_horizontal(window, set)
|
||||
if set then
|
||||
store_geometry(window, "maximized_horizontal")
|
||||
local g = screen[window.screen].workarea
|
||||
local bw = window.border_width or 0
|
||||
window:geometry { width = g.width - 2*bw, x = g.x }
|
||||
elseif data[window] and data[window].maximized_horizontal
|
||||
and data[window].maximized_horizontal.x
|
||||
and data[window].maximized_horizontal.width then
|
||||
local g = data[window].maximized_horizontal
|
||||
window:geometry { width = g.width, x = g.x }
|
||||
end
|
||||
end
|
||||
|
||||
--- Maximize a window vertically.
|
||||
--
|
||||
-- @param window The window.
|
||||
-- @param set Set or unset the maximized values.
|
||||
local function maximized_vertical(window, set)
|
||||
if set then
|
||||
store_geometry(window, "maximized_vertical")
|
||||
local g = screen[window.screen].workarea
|
||||
local bw = window.border_width or 0
|
||||
window:geometry { height = g.height - 2*bw, y = g.y }
|
||||
elseif data[window] and data[window].maximized_vertical
|
||||
and data[window].maximized_vertical.y
|
||||
and data[window].maximized_vertical.height then
|
||||
local g = data[window].maximized_vertical
|
||||
window:geometry { height = g.height, y = g.y }
|
||||
end
|
||||
end
|
||||
|
||||
--- Fullscreen a window.
|
||||
--
|
||||
-- @param window The window.
|
||||
-- @param set Set or unset the fullscreen values.
|
||||
local function fullscreen(window, set)
|
||||
if set then
|
||||
store_geometry(window, "fullscreen")
|
||||
data[window].fullscreen.border_width = window.border_width
|
||||
window.border_width = 0
|
||||
window:geometry(screen[window.screen].geometry)
|
||||
elseif data[window] and data[window].fullscreen then
|
||||
window.border_width = data[window].fullscreen.border_width
|
||||
window:geometry(data[window].fullscreen)
|
||||
end
|
||||
end
|
||||
|
||||
local function screen_change(window)
|
||||
if data[window] then
|
||||
for _, reqtype in ipairs({ "maximized_vertical", "maximized_horizontal", "fullscreen" }) do
|
||||
|
@ -162,6 +105,10 @@ end
|
|||
-- @tparam[opt] table hints A table with additional hints:
|
||||
-- @tparam[opt=false] boolean hints.raise should the client be raised?
|
||||
function ewmh.activate(c, context, hints) -- luacheck: no unused args
|
||||
hints = hints or {}
|
||||
|
||||
if c.focusable == false and not hints.force then return end
|
||||
|
||||
if c:isvisible() then
|
||||
client.focus = c
|
||||
end
|
||||
|
@ -177,8 +124,14 @@ end
|
|||
--
|
||||
-- @client c A client to tag
|
||||
-- @tag[opt] t A tag to use. If omitted, then the client is made sticky.
|
||||
function ewmh.tag(c, t)
|
||||
-- @tparam[opt={}] table hints Extra information
|
||||
function ewmh.tag(c, t, hints) --luacheck: no unused
|
||||
-- There is nothing to do
|
||||
if not t and #c:tags() > 0 then return end
|
||||
|
||||
if not t then
|
||||
c:to_selected_tags()
|
||||
elseif type(t) == "boolean" and t then
|
||||
c.sticky = true
|
||||
else
|
||||
c.screen = t.screen
|
||||
|
@ -192,12 +145,60 @@ function ewmh.urgent(c, urgent)
|
|||
end
|
||||
end
|
||||
|
||||
-- Map the state to the action name
|
||||
local context_mapper = {
|
||||
maximized_vertical = "maximize_vertically",
|
||||
maximized_horizontal = "maximize_horizontally",
|
||||
fullscreen = "maximize"
|
||||
}
|
||||
|
||||
--- Move and resize the client.
|
||||
--
|
||||
-- This is the default geometry request handler.
|
||||
--
|
||||
-- @tparam client c The client
|
||||
-- @tparam string context The context
|
||||
-- @tparam[opt={}] table hints The hints to pass to the handler
|
||||
function ewmh.geometry(c, context, hints)
|
||||
context = context or ""
|
||||
|
||||
local original_context = context
|
||||
|
||||
-- Now, map it to something useful
|
||||
context = context_mapper[context] or context
|
||||
|
||||
local props = util.table.clone(hints or {}, false)
|
||||
props.store_geometry = props.store_geometry==nil and true or props.store_geometry
|
||||
|
||||
-- If it is a known placement function, then apply it, otherwise let
|
||||
-- other potential handler resize the client (like in-layout resize or
|
||||
-- floating client resize)
|
||||
if aplace[context] then
|
||||
|
||||
-- Check if it correspond to a boolean property
|
||||
local state = c[original_context]
|
||||
|
||||
-- If the property is boolean and it correspond to the undo operation,
|
||||
-- restore the stored geometry.
|
||||
if state == false then
|
||||
aplace.restore(c,{context=context})
|
||||
return
|
||||
end
|
||||
|
||||
local honor_default = original_context ~= "fullscreen"
|
||||
|
||||
if props.honor_workarea == nil then
|
||||
props.honor_workarea = honor_default
|
||||
end
|
||||
|
||||
aplace[context](c, props)
|
||||
end
|
||||
end
|
||||
|
||||
client.connect_signal("request::activate", ewmh.activate)
|
||||
client.connect_signal("request::tag", ewmh.tag)
|
||||
client.connect_signal("request::urgent", ewmh.urgent)
|
||||
client.connect_signal("request::maximized_horizontal", maximized_horizontal)
|
||||
client.connect_signal("request::maximized_vertical", maximized_vertical)
|
||||
client.connect_signal("request::fullscreen", fullscreen)
|
||||
client.connect_signal("request::geometry", ewmh.geometry)
|
||||
client.connect_signal("property::screen", screen_change)
|
||||
client.connect_signal("property::border_width", geometry_change)
|
||||
client.connect_signal("property::geometry", geometry_change)
|
||||
|
|
|
@ -56,6 +56,7 @@ return
|
|||
tooltip = require("awful.tooltip");
|
||||
ewmh = require("awful.ewmh");
|
||||
titlebar = require("awful.titlebar");
|
||||
rules = require("awful.rules");
|
||||
spawn = spawn;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,12 @@
|
|||
-- * Re-use the same functions for the `mouse`, `client`s, `screen`s and `wibox`es
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
-- It is possible to compose placement function using the `+` or `*` operator:
|
||||
--
|
||||
-- local f = (awful.placement.right + awful.placement.left)
|
||||
-- f(client.focus)
|
||||
--
|
||||
-- ### Common arguments
|
||||
--
|
||||
-- **honor_workarea** (*boolean*):
|
||||
|
@ -39,6 +44,11 @@
|
|||
--
|
||||
-- **attach** (*boolean*):
|
||||
--
|
||||
-- **store_geometry** (*boolean*):
|
||||
--
|
||||
-- Keep a single history of each type of placement. It can be restored using
|
||||
-- `awful.placement.restore` by setting the right `context` argument.
|
||||
--
|
||||
-- When either the parent or the screen geometry change, call the placement
|
||||
-- function again.
|
||||
--
|
||||
|
@ -73,7 +83,37 @@ local function get_screen(s)
|
|||
return s and capi.screen[s]
|
||||
end
|
||||
|
||||
local placement = {}
|
||||
local wrap_client = nil
|
||||
|
||||
local function compose(w1, w2)
|
||||
return wrap_client(function(...)
|
||||
w1(...)
|
||||
w2(...)
|
||||
return --It make no sense to keep a return value
|
||||
end)
|
||||
end
|
||||
|
||||
wrap_client = function(f)
|
||||
return setmetatable({is_placement=true}, {
|
||||
__call = function(_,...) return f(...) end,
|
||||
__add = compose, -- Composition is usually defined as +
|
||||
__mul = compose -- Make sense if you think of the functions as matrices
|
||||
})
|
||||
end
|
||||
|
||||
local placement_private = {}
|
||||
|
||||
-- The module is a proxy in front of the "real" functions.
|
||||
-- This allow syntax like:
|
||||
--
|
||||
-- (awful.placement.no_overlap + awful.placement.no_offscreen)(c)
|
||||
--
|
||||
local placement = setmetatable({}, {
|
||||
__index = placement_private,
|
||||
__newindex = function(_, k, f)
|
||||
placement_private[k] = wrap_client(f)
|
||||
end
|
||||
})
|
||||
|
||||
-- 3x3 matrix of the valid sides and corners
|
||||
local corners3x3 = {{"top_left" , "top" , "top_right" },
|
||||
|
@ -103,6 +143,26 @@ local align_map = {
|
|||
-- Store function -> keys
|
||||
local reverse_align_map = {}
|
||||
|
||||
--- Add a context to the arguments.
|
||||
-- This function extend the argument table. The context is used by some
|
||||
-- internal helper methods. If there already is a context, it has priority and
|
||||
-- is kept.
|
||||
local function add_context(args, context)
|
||||
return setmetatable({context = (args or {}).context or context }, {__index=args})
|
||||
end
|
||||
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
--- Store a drawable geometry (per context) in a weak table.
|
||||
-- @param d The drawin
|
||||
-- @tparam string reqtype The context.
|
||||
local function store_geometry(d, reqtype)
|
||||
if not data[d] then data[d] = {} end
|
||||
if not data[d][reqtype] then data[d][reqtype] = {} end
|
||||
data[d][reqtype] = d:geometry()
|
||||
data[d][reqtype].screen = d.screen
|
||||
end
|
||||
|
||||
--- Get the area covered by a drawin.
|
||||
-- @param d The drawin
|
||||
-- @tparam[opt=nil] table new_geo A new geometry
|
||||
|
@ -112,8 +172,8 @@ local function area_common(d, new_geo, ignore_border_width)
|
|||
-- The C side expect no arguments, nil isn't valid
|
||||
local geometry = new_geo and d:geometry(new_geo) or d:geometry()
|
||||
local border = ignore_border_width and 0 or d.border_width or 0
|
||||
geometry.x = geometry.x - border
|
||||
geometry.y = geometry.y - border
|
||||
geometry.x = geometry.x
|
||||
geometry.y = geometry.y
|
||||
geometry.width = geometry.width + 2 * border
|
||||
geometry.height = geometry.height + 2 * border
|
||||
return geometry
|
||||
|
@ -128,6 +188,12 @@ end
|
|||
-- @tparam[opt=false] boolean ignore_border_width Ignore the border
|
||||
-- @treturn table A table with *x*, *y*, *width* and *height*.
|
||||
local function geometry_common(obj, args, new_geo, ignore_border_width)
|
||||
|
||||
-- Store the current geometry in a singleton-memento
|
||||
if args.store_geometry and new_geo and args.context then
|
||||
store_geometry(obj, args.context)
|
||||
end
|
||||
|
||||
-- It's a mouse
|
||||
if obj.coords then
|
||||
local coords = new_geo and obj.coords(new_geo) or obj.coords()
|
||||
|
@ -381,6 +447,7 @@ end
|
|||
-- @tparam[opt={}] table args The arguments
|
||||
-- @treturn string The corner name
|
||||
function placement.closest_corner(d, args)
|
||||
args = add_context(args, "closest_corner")
|
||||
d = d or capi.client.focus
|
||||
|
||||
local sgeo = get_parent_geometry(d, args)
|
||||
|
@ -409,7 +476,7 @@ function placement.closest_corner(d, args)
|
|||
|
||||
-- Transpose the corner back to the original size
|
||||
local new_args = setmetatable({position = corner}, {__index=args})
|
||||
placement.align(d, new_args)
|
||||
placement_private.align(d, new_args)
|
||||
|
||||
return corner
|
||||
end
|
||||
|
@ -420,6 +487,11 @@ end
|
|||
-- @tparam[opt=client's screen] integer screen The screen.
|
||||
-- @treturn table The new client geometry.
|
||||
function placement.no_offscreen(c, screen)
|
||||
--HACK necessary for composition to work. The API will be changed soon
|
||||
if type(screen) == "table" then
|
||||
screen = nil
|
||||
end
|
||||
|
||||
c = c or capi.client.focus
|
||||
local geometry = area_common(c)
|
||||
screen = get_screen(screen or c.screen or a_screen.getbycoord(geometry.x, geometry.y))
|
||||
|
@ -439,7 +511,10 @@ function placement.no_offscreen(c, screen)
|
|||
geometry.y = screen_geometry.y
|
||||
end
|
||||
|
||||
return c:geometry({ x = geometry.x, y = geometry.y })
|
||||
return c:geometry {
|
||||
x = geometry.x,
|
||||
y = geometry.y
|
||||
}
|
||||
end
|
||||
|
||||
--- Place the client where there's place available with minimum overlap.
|
||||
|
@ -567,7 +642,7 @@ end
|
|||
-- @tparam drawable d A drawable (like `client`, `mouse` or `wibox`)
|
||||
-- @tparam[opt={}] table args Other arguments
|
||||
function placement.align(d, args)
|
||||
args = args or {}
|
||||
args = add_context(args, "align")
|
||||
d = d or capi.client.focus
|
||||
|
||||
if not d or not args.position then return end
|
||||
|
@ -584,8 +659,8 @@ function placement.align(d, args)
|
|||
)
|
||||
|
||||
geometry_common(d, args, {
|
||||
x = (pos.x and math.ceil(sgeo.x + pos.x) or dgeo.x) + bw ,
|
||||
y = (pos.y and math.ceil(sgeo.y + pos.y) or dgeo.y) + bw ,
|
||||
x = (pos.x and math.ceil(sgeo.x + pos.x) or dgeo.x) ,
|
||||
y = (pos.y and math.ceil(sgeo.y + pos.y) or dgeo.y) ,
|
||||
width = math.ceil(dgeo.width ) - 2*bw,
|
||||
height = math.ceil(dgeo.height ) - 2*bw,
|
||||
})
|
||||
|
@ -596,8 +671,9 @@ end
|
|||
-- Add the alias functions
|
||||
for k in pairs(align_map) do
|
||||
placement[k] = function(d, args)
|
||||
local new_args = setmetatable({position = k}, {__index=args})
|
||||
placement.align(d, new_args)
|
||||
args = add_context(args, k)
|
||||
args.position = k
|
||||
placement_private.align(d, args)
|
||||
end
|
||||
reverse_align_map[placement[k]] = k
|
||||
end
|
||||
|
@ -636,7 +712,7 @@ end
|
|||
-- @tparam[opt=client.focus] drawable d A drawable (like `client` or `wibox`)
|
||||
-- @tparam[opt={}] table args The arguments
|
||||
function placement.stretch(d, args)
|
||||
args = args or {}
|
||||
args = add_context(args, "stretch")
|
||||
|
||||
d = d or capi.client.focus
|
||||
if not d or not args.direction then return end
|
||||
|
@ -644,8 +720,8 @@ function placement.stretch(d, args)
|
|||
-- In case there is multiple directions, call `stretch` for each of them
|
||||
if type(args.direction) == "table" then
|
||||
for _, dir in ipairs(args.direction) do
|
||||
local new_args = setmetatable({direction = dir}, {__index=args})
|
||||
placement.stretch(dir, new_args)
|
||||
args.direction = dir
|
||||
placement_private.stretch(dir, args)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
@ -656,15 +732,15 @@ function placement.stretch(d, args)
|
|||
local bw = d.border_width or 0
|
||||
|
||||
if args.direction == "left" then
|
||||
ngeo.x = sgeo.x + bw
|
||||
ngeo.x = sgeo.x
|
||||
ngeo.width = dgeo.width + (dgeo.x - ngeo.x)
|
||||
elseif args.direction == "right" then
|
||||
ngeo.width = sgeo.width - ngeo.x - bw
|
||||
ngeo.width = sgeo.width - ngeo.x - 2*bw
|
||||
elseif args.direction == "up" then
|
||||
ngeo.y = sgeo.y + bw
|
||||
ngeo.y = sgeo.y
|
||||
ngeo.height = dgeo.height + (dgeo.y - ngeo.y)
|
||||
elseif args.direction == "down" then
|
||||
ngeo.height = sgeo.height - dgeo.y - bw
|
||||
ngeo.height = sgeo.height - dgeo.y - 2*bw
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
|
@ -681,8 +757,9 @@ end
|
|||
-- Add the alias functions
|
||||
for _,v in ipairs {"left", "right", "up", "down"} do
|
||||
placement["stretch_"..v] = function(d, args)
|
||||
local new_args = setmetatable({direction = v}, {__index=args})
|
||||
placement.stretch(d, new_args)
|
||||
args = add_context(args, "stretch_"..v)
|
||||
args.direction = v
|
||||
placement_private.stretch(d, args)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -704,7 +781,7 @@ end
|
|||
-- @tparam[opt=client.focus] drawable d A drawable (like `client` or `wibox`)
|
||||
-- @tparam[opt={}] table args The arguments
|
||||
function placement.maximize(d, args)
|
||||
args = args or {}
|
||||
args = add_context(args, "maximize")
|
||||
d = d or capi.client.focus
|
||||
|
||||
if not d then return end
|
||||
|
@ -714,12 +791,12 @@ function placement.maximize(d, args)
|
|||
local bw = d.border_width or 0
|
||||
|
||||
if (not args.axis) or args.axis :match "vertical" then
|
||||
ngeo.y = sgeo.y + bw
|
||||
ngeo.y = sgeo.y
|
||||
ngeo.height = sgeo.height - 2*bw
|
||||
end
|
||||
|
||||
if (not args.axis) or args.axis :match "horizontal" then
|
||||
ngeo.x = sgeo.x + bw
|
||||
ngeo.x = sgeo.x
|
||||
ngeo.width = sgeo.width - 2*bw
|
||||
end
|
||||
|
||||
|
@ -731,9 +808,9 @@ end
|
|||
-- Add the alias functions
|
||||
for _, v in ipairs {"vertically", "horizontally"} do
|
||||
placement["maximize_"..v] = function(d2, args)
|
||||
args = args or {}
|
||||
local new_args = setmetatable({axis = v}, {__index=args})
|
||||
placement.maximize(d2, new_args)
|
||||
args = add_context(args, "maximize_"..v)
|
||||
args.axis = v
|
||||
placement_private.maximize(d2, args)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -741,6 +818,25 @@ end
|
|||
|
||||
---@DOC_awful_placement_maximize_horizontally_EXAMPLE@
|
||||
|
||||
--- Restore the geometry.
|
||||
-- @tparam[opt=client.focus] drawable d A drawable (like `client` or `wibox`)
|
||||
-- @tparam[opt={}] table args The arguments
|
||||
-- @treturn boolean If the geometry was restored
|
||||
function placement.restore(d, args)
|
||||
if not args or not args.context then return false end
|
||||
d = d or capi.client.focus
|
||||
|
||||
if not data[d] then return false end
|
||||
|
||||
local memento = data[d][args.context]
|
||||
|
||||
if not memento then return false end
|
||||
|
||||
memento.screen = nil --TODO use it
|
||||
d:geometry(memento)
|
||||
return true
|
||||
end
|
||||
|
||||
return placement
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -9,12 +9,15 @@
|
|||
|
||||
-- Grab environment we need
|
||||
local client = client
|
||||
local awesome = awesome
|
||||
local screen = screen
|
||||
local table = table
|
||||
local type = type
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local atag = require("awful.tag")
|
||||
local util = require("awful.util")
|
||||
local a_place = require("awful.placement")
|
||||
|
||||
local rules = {}
|
||||
|
||||
|
@ -188,6 +191,7 @@ end
|
|||
--- Apply awful.rules.rules to a client.
|
||||
-- @client c The client.
|
||||
function rules.apply(c)
|
||||
|
||||
local props = {}
|
||||
local callbacks = {}
|
||||
|
||||
|
@ -205,36 +209,253 @@ function rules.apply(c)
|
|||
rules.execute(c, props, callbacks)
|
||||
end
|
||||
|
||||
local function add_to_tag(c, t)
|
||||
if not t then return end
|
||||
|
||||
local tags = c:tags()
|
||||
table.insert(tags, t)
|
||||
c:tags(tags)
|
||||
end
|
||||
|
||||
--- Extra rules properties.
|
||||
--
|
||||
-- These properties are used in the rules only and are not sent to the client
|
||||
-- afterward.
|
||||
--
|
||||
-- To add a new properties, just do:
|
||||
--
|
||||
-- function awful.rules.extra_properties.my_new_property(c, value, props)
|
||||
-- -- do something
|
||||
-- end
|
||||
--
|
||||
-- By default, the table has the following functions:
|
||||
--
|
||||
-- * geometry
|
||||
-- * switchtotag
|
||||
--
|
||||
-- @tfield table awful.rules.extra_properties
|
||||
rules.extra_properties = {}
|
||||
|
||||
--- Extra high priority properties.
|
||||
--
|
||||
-- Some properties, such as anything related to tags, geometry or focus, will
|
||||
-- cause a race condition if set in the main property section. This is why
|
||||
-- they have a section for them.
|
||||
--
|
||||
-- To add a new properties, just do:
|
||||
--
|
||||
-- function awful.rules.high_priority_properties.my_new_property(c, value, props)
|
||||
-- -- do something
|
||||
-- end
|
||||
--
|
||||
-- By default, the table has the following functions:
|
||||
--
|
||||
-- * tag
|
||||
-- * new_tag
|
||||
--
|
||||
-- @tfield table awful.rules.high_priority_properties
|
||||
rules.high_priority_properties = {}
|
||||
|
||||
rules.delayed_properties = {}
|
||||
|
||||
local force_ignore = {
|
||||
titlebars_enabled=true, focus=true, screen=true, x=true,
|
||||
y=true, width=true, height=true, geometry=true,placement=true,
|
||||
border_width=true,floating=true,size_hints_honor=true
|
||||
}
|
||||
|
||||
function rules.high_priority_properties.tag(c, value)
|
||||
if value then
|
||||
if type(value) == "string" then
|
||||
value = atag.find_by_name(nil, value)
|
||||
end
|
||||
|
||||
c:tags{ value }
|
||||
end
|
||||
end
|
||||
|
||||
function rules.delayed_properties.switchtotag(c, value)
|
||||
if not value then return end
|
||||
|
||||
local selected_tags = {}
|
||||
|
||||
for _,v in ipairs(c.screen.selected_tags) do
|
||||
selected_tags[v] = true
|
||||
end
|
||||
|
||||
local tags = c:tags()
|
||||
|
||||
for _, t in ipairs(tags) do
|
||||
t.selected = true
|
||||
selected_tags[t] = nil
|
||||
end
|
||||
|
||||
for t in pairs(selected_tags) do
|
||||
t.selected = false
|
||||
end
|
||||
end
|
||||
|
||||
function rules.extra_properties.geometry(c, _, props)
|
||||
local cur_geo = c:geometry()
|
||||
|
||||
local new_geo = type(props.geometry) == "function"
|
||||
and props.geometry(c, props) or props.geometry or {}
|
||||
|
||||
for _, v in ipairs {"x", "y", "width", "height"} do
|
||||
new_geo[v] = type(props[v]) == "function" and props[v](c, props)
|
||||
or props[v] or new_geo[v] or cur_geo[v]
|
||||
end
|
||||
|
||||
c:geometry(new_geo) --TODO use request::geometry
|
||||
end
|
||||
|
||||
--- Create a new tag based on a rule.
|
||||
-- @tparam client c The client
|
||||
-- @tparam boolean|function|string value The value.
|
||||
-- @treturn tag The new tag
|
||||
function rules.high_priority_properties.new_tag(c, value)
|
||||
local ty = type(value)
|
||||
local t = nil
|
||||
|
||||
if ty == "boolean" then
|
||||
-- Create a new tag named after the client class
|
||||
t = atag.add(c.class or "N/A", {screen=c.screen, volatile=true})
|
||||
elseif ty == "string" then
|
||||
-- Create a tag named after "value"
|
||||
t = atag.add(value, {screen=c.screen, volatile=true})
|
||||
elseif ty == "table" then
|
||||
-- Assume a table of tags properties
|
||||
t = atag.add(value.name or c.class or "N/A", value)
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
|
||||
add_to_tag(c, t)
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
function rules.extra_properties.placement(c, value)
|
||||
-- Avoid problems
|
||||
if awesome.startup and
|
||||
(c.size_hints.user_position or c.size_hints.program_position) then
|
||||
return
|
||||
end
|
||||
|
||||
local ty = type(value)
|
||||
|
||||
local args = {
|
||||
honor_workarea = true,
|
||||
honor_padding = true
|
||||
}
|
||||
|
||||
if ty == "function" or (ty == "table" and
|
||||
getmetatable(value) and getmetatable(value).__call
|
||||
) then
|
||||
value(c, args)
|
||||
elseif ty == "string" and a_place[value] then
|
||||
a_place[value](c, args)
|
||||
end
|
||||
end
|
||||
|
||||
function rules.extra_properties.tags(c, value)
|
||||
local current = c:tags()
|
||||
c:tags(util.table.merge(current, value))
|
||||
end
|
||||
|
||||
--- Apply properties and callbacks to a client.
|
||||
-- @client c The client.
|
||||
-- @tab props Properties to apply.
|
||||
-- @tab[opt] callbacks Callbacks to apply.
|
||||
function rules.execute(c, props, callbacks)
|
||||
local handle_later = { focus = true, switchtotag = true }
|
||||
local switchtotag = props.switchtotag
|
||||
-- This has to be done first, as it will impact geometry related props.
|
||||
if props.titlebars_enabled then
|
||||
c:emit_signal("request::titlebars", "rules", {properties=props})
|
||||
end
|
||||
|
||||
-- Border width will also cause geometry related properties to fail
|
||||
if props.border_width then
|
||||
c.border_width = type(props.border_width) == "function" and
|
||||
props.border_width(c, props) or props.border_width
|
||||
end
|
||||
|
||||
-- Size hints will be re-applied when setting width/height unless it is
|
||||
-- disabled first
|
||||
if props.size_hints_honor ~= nil then
|
||||
c.size_hints_honor = type(props.size_hints_honor) == "function" and props.size_hints_honor(c,props)
|
||||
or props.size_hints_honor
|
||||
end
|
||||
|
||||
-- Geometry will only work if floating is true, otherwise the "saved"
|
||||
-- geometry will be restored.
|
||||
if props.floating then
|
||||
c.floating = type(props.floating) == "function" and props.floating(c,props)
|
||||
or props.floating
|
||||
end
|
||||
|
||||
-- Before requesting a tag, make sure the screen is right
|
||||
if props.screen then
|
||||
c.screen = type(props.screen) == "function" and screen[props.screen(c,props)]
|
||||
or screen[props.screen]
|
||||
end
|
||||
|
||||
-- Some properties need to be handled first. For example, many properties
|
||||
-- depend that the client is tagged, this isn't yet the case.
|
||||
for prop, handler in pairs(rules.high_priority_properties) do
|
||||
local value = props[prop]
|
||||
|
||||
if value ~= nil then
|
||||
if type(value) == "function" then
|
||||
value = value(c, props)
|
||||
end
|
||||
|
||||
handler(c, value)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- By default, rc.lua use no_overlap+no_offscreen placement. This has to
|
||||
-- be executed before x/y/width/height/geometry as it would otherwise
|
||||
-- always override the user specified position with the default rule.
|
||||
if props.placement then
|
||||
-- It may be a function, so this one doesn't execute it like others
|
||||
rules.extra_properties.placement(c, props.placement, props)
|
||||
end
|
||||
|
||||
-- Make sure the tag is selected before the main rules are called.
|
||||
-- Otherwise properties like "urgent" or "focus" may fail because they
|
||||
-- will be overiden by various callbacks.
|
||||
-- Previously, this was done in a second client.manage callback, but caused
|
||||
-- a race condition where the order the require() would change the output.
|
||||
c:emit_signal("request::tag", nil, {reason="rules"})
|
||||
|
||||
-- By default, rc.lua use no_overlap+no_offscreen placement. This has to
|
||||
-- be executed before x/y/width/height/geometry as it would otherwise
|
||||
-- always override the user specified position with the default rule.
|
||||
if props.placement then
|
||||
-- It may be a function, so this one doesn't execute it like others
|
||||
rules.extra_properties.placement(c, props.placement, props)
|
||||
end
|
||||
|
||||
-- Now that the tags and screen are set, handle the geometry
|
||||
if props.height or props.width or props.x or props.y or props.geometry then
|
||||
rules.extra_properties.geometry(c, nil, props)
|
||||
end
|
||||
|
||||
-- As most race conditions should now have been avoided, apply the remaining
|
||||
-- properties.
|
||||
for property, value in pairs(props) do
|
||||
if property ~= "focus" and type(value) == "function" then
|
||||
value = value(c)
|
||||
value = value(c, props)
|
||||
end
|
||||
if property == "screen" then
|
||||
-- Support specifying screens by name ("VGA1")
|
||||
c.screen = screen[value]
|
||||
elseif property == "tag" then
|
||||
local t = value
|
||||
if type(t) == "string" then
|
||||
t = atag.find_by_name(props.screen, t)
|
||||
end
|
||||
c.screen = t.screen
|
||||
c:tags({ t })
|
||||
elseif property == "height" or property == "width" or
|
||||
property == "x" or property == "y" then
|
||||
local geo = c:geometry();
|
||||
geo[property] = value
|
||||
c:geometry(geo);
|
||||
elseif not handle_later[property] then
|
||||
if type(c[property]) == "function" then
|
||||
|
||||
local ignore = rules.high_priority_properties[property] or
|
||||
rules.delayed_properties[property] or force_ignore[property]
|
||||
|
||||
if not ignore then
|
||||
if rules.extra_properties[property] then
|
||||
rules.extra_properties[property](c, value)
|
||||
elseif type(c[property]) == "function" then
|
||||
c[property](c, value)
|
||||
else
|
||||
c[property] = value
|
||||
|
@ -242,11 +463,6 @@ function rules.execute(c, props, callbacks)
|
|||
end
|
||||
end
|
||||
|
||||
-- Only do this after the tag has been (possibly) set
|
||||
if switchtotag and c.first_tag then
|
||||
c.first_tag:view_only()
|
||||
end
|
||||
|
||||
-- Apply all callbacks.
|
||||
if callbacks then
|
||||
for _, callback in pairs(callbacks) do
|
||||
|
@ -254,6 +470,21 @@ function rules.execute(c, props, callbacks)
|
|||
end
|
||||
end
|
||||
|
||||
-- Apply the delayed properties
|
||||
for prop, handler in pairs(rules.delayed_properties) do
|
||||
if not force_ignore[prop] then
|
||||
local value = props[prop]
|
||||
|
||||
if value ~= nil then
|
||||
if type(value) == "function" then
|
||||
value = value(c, props)
|
||||
end
|
||||
|
||||
handler(c, value, props)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Do this at last so we do not erase things done by the focus signal.
|
||||
if props.focus and (type(props.focus) ~= "function" or props.focus(c)) then
|
||||
c:emit_signal('request::activate', "rules", {raise=true})
|
||||
|
|
|
@ -29,10 +29,6 @@ local function get_screen(s)
|
|||
return s and capi.screen[s]
|
||||
end
|
||||
|
||||
-- awful.client is required() at the end of this file so the miss_handler is set
|
||||
-- before it is being required.
|
||||
local client
|
||||
|
||||
local tag = {object = {}, mt = {} }
|
||||
|
||||
-- Private data
|
||||
|
@ -1370,11 +1366,6 @@ object.properties(capi.tag, {
|
|||
setter_fallback = tag.setproperty,
|
||||
})
|
||||
|
||||
-- fix a load loop
|
||||
client = require("awful.client")
|
||||
capi.client.connect_signal("manage", function(c) client.object.to_selected_tags(c) end)
|
||||
|
||||
|
||||
return setmetatable(tag, tag.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -1697,9 +1697,9 @@ client_set_fullscreen(lua_State *L, int cidx, bool s)
|
|||
client_set_ontop(L, cidx, false);
|
||||
}
|
||||
int abs_cidx = luaA_absindex(L, cidx); \
|
||||
lua_pushboolean(L, s);
|
||||
lua_pushstring(L, "fullscreen");
|
||||
c->fullscreen = s;
|
||||
luaA_object_emit_signal(L, abs_cidx, "request::fullscreen", 1);
|
||||
luaA_object_emit_signal(L, abs_cidx, "request::geometry", 1);
|
||||
luaA_object_emit_signal(L, abs_cidx, "property::fullscreen", 0);
|
||||
/* Force a client resize, so that titlebars get shown/hidden */
|
||||
client_resize_do(c, c->geometry, true);
|
||||
|
@ -1730,10 +1730,10 @@ client_get_maximized(client_t *c)
|
|||
if(c->maximized_##type != s) \
|
||||
{ \
|
||||
int abs_cidx = luaA_absindex(L, cidx); \
|
||||
lua_pushboolean(L, s); \
|
||||
int max_before = client_get_maximized(c); \
|
||||
c->maximized_##type = s; \
|
||||
luaA_object_emit_signal(L, abs_cidx, "request::maximized_" #type, 1); \
|
||||
lua_pushstring(L, "maximized_"#type);\
|
||||
luaA_object_emit_signal(L, abs_cidx, "request::geometry", 1); \
|
||||
luaA_object_emit_signal(L, abs_cidx, "property::maximized_" #type, 0); \
|
||||
if(max_before != client_get_maximized(c)) \
|
||||
luaA_object_emit_signal(L, abs_cidx, "property::maximized", 0); \
|
||||
|
@ -3446,17 +3446,14 @@ client_class_setup(lua_State *L)
|
|||
*/
|
||||
signal_add(&client_class.signals, "request::activate");
|
||||
/**
|
||||
* @signal request::fullscreen
|
||||
* @signal request::geometry
|
||||
* @tparam client c The client
|
||||
* @tparam string context Why and what to resize. This is used for the
|
||||
* handlers to know if they are capable of applying the new geometry.
|
||||
* @tparam[opt={}] table Additional arguments. Each context handler may
|
||||
* interpret this differently.
|
||||
*/
|
||||
signal_add(&client_class.signals, "request::fullscreen");
|
||||
/**
|
||||
* @signal request::maximized_horizontal
|
||||
*/
|
||||
signal_add(&client_class.signals, "request::maximized_horizontal");
|
||||
/**
|
||||
* @signal request::maximized_vertical
|
||||
*/
|
||||
signal_add(&client_class.signals, "request::maximized_vertical");
|
||||
signal_add(&client_class.signals, "request::geometry");
|
||||
/**
|
||||
* @signal request::tag
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
local spawn = require("awful.spawn")
|
||||
|
||||
-- This file provide a simple, yet flexible, test client.
|
||||
-- It is used to test the `awful.rules`
|
||||
|
||||
return function(class, title)
|
||||
title = title or 'Awesome test client'
|
||||
|
||||
local cmd = {"lua" , "-e", table.concat {
|
||||
"local lgi = require 'lgi';",
|
||||
"local Gtk = lgi.require('Gtk');",
|
||||
"Gtk.init();",
|
||||
"local class = '",
|
||||
class or 'test_app',"';",
|
||||
"local window = Gtk.Window {",
|
||||
" default_width = 100,",
|
||||
" default_height = 100,",
|
||||
" title = '",title,
|
||||
"'};",
|
||||
"window:set_wmclass(class, class);",
|
||||
"local app = Gtk.Application {",
|
||||
" application_id = 'org.awesomewm.tests.",class,
|
||||
"'};",
|
||||
"function app:on_activate()",
|
||||
" window.application = self;",
|
||||
" window:show_all();",
|
||||
"end;",
|
||||
"app:run {''}"
|
||||
}}
|
||||
|
||||
spawn(cmd)
|
||||
end
|
|
@ -10,6 +10,6 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.bottom(client.focus)
|
||||
|
||||
assert(c.x == screen[1].geometry.width/2-40/2--DOC_HIDE
|
||||
and c.y==screen[1].geometry.height-30-c.border_width--DOC_HIDE
|
||||
assert(c.x == screen[1].geometry.width/2-40/2-c.border_width--DOC_HIDE
|
||||
and c.y==screen[1].geometry.height-30-2*c.border_width--DOC_HIDE
|
||||
and c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -11,8 +11,8 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
awful.placement.bottom_left(client.focus)
|
||||
|
||||
assert( --DOC_HIDE
|
||||
c.x == c.border_width --DOC_HIDE
|
||||
and c.y == screen[1].geometry.height-30-c.border_width --DOC_HIDE
|
||||
c.x == 0 --DOC_HIDE
|
||||
and c.y+2*c.border_width == screen[1].geometry.height-30 --DOC_HIDE
|
||||
and c.width == 40--DOC_HIDE
|
||||
and c.height == 30--DOC_HIDE
|
||||
) --DOC_HIDE
|
||||
|
|
|
@ -10,6 +10,6 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.bottom_right(client.focus)
|
||||
|
||||
assert(c.x == screen[1].geometry.width-40-c.border_width) --DOC_HIDE
|
||||
assert(c.y==screen[1].geometry.height-30-c.border_width) --DOC_HIDE
|
||||
assert(c.x == screen[1].geometry.width-40-2*c.border_width) --DOC_HIDE
|
||||
assert(c.y==screen[1].geometry.height-30-2*c.border_width) --DOC_HIDE
|
||||
assert(c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -9,6 +9,6 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.center_horizontal(client.focus)
|
||||
|
||||
assert(c.x == screen[1].geometry.width/2-40/2)--DOC_HIDE
|
||||
assert(c.x == screen[1].geometry.width/2-40/2-c.border_width)--DOC_HIDE
|
||||
assert(c.y==35)--DOC_HIDE
|
||||
assert(c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -10,5 +10,6 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.centered(client.focus)
|
||||
|
||||
assert(c.x == screen[1].geometry.width/2-40/2 and c.y==screen[1].geometry.height/2-30/2--DOC_HIDE
|
||||
and c.width==40 and c.height==30)--DOC_HIDE
|
||||
assert(c.x == screen[1].geometry.width/2-40/2-c.border_width) --DOC_HIDE
|
||||
assert(c.y==screen[1].geometry.height/2-30/2-c.border_width) --DOC_HIDE
|
||||
assert(c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -8,49 +8,50 @@ mouse.coords {x=100,y=100} --DOC_HIDE
|
|||
-- Move the mouse to the closest corner of the focused client
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c})
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x-bw and mouse.coords().y == (c.y) + (c.height)/2) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x) --DOC_HIDE
|
||||
assert(mouse.coords().y == (c.y) + (c.height)/2+bw) --DOC_HIDE
|
||||
|
||||
-- Top left --DOC_HIDE
|
||||
mouse.coords {x=60,y=40} --DOC_HIDE
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c}) --DOC_HIDE
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x-bw and mouse.coords().y == c.y-bw) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x and mouse.coords().y == c.y) --DOC_HIDE
|
||||
|
||||
-- Top right --DOC_HIDE
|
||||
mouse.coords {x=230,y=50} --DOC_HIDE
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c}) --DOC_HIDE
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width+bw and mouse.coords().y == c.y-bw) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width+2*bw and mouse.coords().y == c.y) --DOC_HIDE
|
||||
|
||||
-- Right --DOC_HIDE
|
||||
mouse.coords {x=240,y=140} --DOC_HIDE
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c}) --DOC_HIDE
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width+bw and mouse.coords().y == c.y+c.height/2) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width+2*bw and mouse.coords().y == c.y+c.height/2+bw) --DOC_HIDE
|
||||
|
||||
-- Bottom right --DOC_HIDE
|
||||
mouse.coords {x=210,y=190} --DOC_HIDE
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c}) --DOC_HIDE
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width+bw and mouse.coords().y == c.y+c.height+bw) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width+2*bw and mouse.coords().y == c.y+c.height+2*bw) --DOC_HIDE
|
||||
|
||||
-- Bottom --DOC_HIDE
|
||||
mouse.coords {x=130,y=190} --DOC_HIDE
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c}) --DOC_HIDE
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width/2 and mouse.coords().y == c.y + c.height + bw) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x+c.width/2+bw and mouse.coords().y == c.y + c.height + 2*bw) --DOC_HIDE
|
||||
|
||||
-- Top --DOC_HIDE
|
||||
mouse.coords {x=130,y=30} --DOC_HIDE
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c}) --DOC_HIDE
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x + c.width/2 and mouse.coords().y == c.y-bw) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x + c.width/2+bw and mouse.coords().y == c.y) --DOC_HIDE
|
||||
|
||||
-- Bottom left + outside of "c" --DOC_HIDE
|
||||
mouse.coords {x=0,y=230} --DOC_HIDE
|
||||
awful.placement.closest_corner(mouse, {include_sides=true, parent=c}) --DOC_HIDE
|
||||
mouse.push_history() --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x-bw and mouse.coords().y == c.y+c.height+bw) --DOC_HIDE
|
||||
assert(mouse.coords().x == c.x and mouse.coords().y == c.y+c.height+2*bw) --DOC_HIDE
|
||||
|
||||
-- It is possible to emulate the mouse API to get the closest corner of
|
||||
-- random area
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
screen[1]._resize {width = 128, height = 96} --DOC_HIDE
|
||||
local awful = {placement = require("awful.placement")} --DOC_HIDE
|
||||
local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
||||
|
||||
local f = (awful.placement.right + awful.placement.left)
|
||||
f(client.focus)
|
||||
|
||||
assert(c.x == 0 and c.y==screen[1].geometry.height/2-30/2-c.border_width--DOC_HIDE
|
||||
and c.width==40 and c.height==30)--DOC_HIDE
|
|
@ -10,5 +10,5 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.left(client.focus)
|
||||
|
||||
assert(c.x == c.border_width and c.y==screen[1].geometry.height/2-30/2--DOC_HIDE
|
||||
assert(c.x == 0 and c.y==screen[1].geometry.height/2-30/2-c.border_width--DOC_HIDE
|
||||
and c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -10,6 +10,6 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.right(client.focus)
|
||||
|
||||
assert(c.x == screen[1].geometry.width-40-c.border_width --DOC_HIDE
|
||||
and c.y==screen[1].geometry.height/2-30/2--DOC_HIDE
|
||||
and c.width==40 and c.height==30)--DOC_HIDE
|
||||
assert(c.x == screen[1].geometry.width-40-2*c.border_width) --DOC_HIDE
|
||||
assert( c.y==screen[1].geometry.height/2-30/2-c.border_width)--DOC_HIDE
|
||||
assert( c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -13,5 +13,5 @@ placement.stretch_down(client.focus)
|
|||
assert(c.x==45) --DOC_HIDE
|
||||
assert(c.y==35) --DOC_HIDE
|
||||
assert(c.width == 40) --DOC_HIDE
|
||||
assert(c.y+c.height == --DOC_HIDE
|
||||
assert(c.y+c.height+2*c.border_width == --DOC_HIDE
|
||||
screen[1].geometry.y + screen[1].geometry.height) --DOC_HIDE
|
||||
|
|
|
@ -10,5 +10,5 @@ local placement = require("awful.placement") --DOC_HIDE
|
|||
local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
||||
placement.stretch_left(client.focus)
|
||||
|
||||
assert(c.x == c.border_width and c.y == 35 and c.height == 30 --DOC_HIDE
|
||||
and c.width == 45+40) --DOC_HIDE
|
||||
assert(c.x == 0 and c.y == 35 and c.height == 30) --DOC_HIDE
|
||||
print(c.width-2*c.border_width == 45+40) --DOC_HIDE
|
||||
|
|
|
@ -11,4 +11,4 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
placement.stretch_right(client.focus)
|
||||
|
||||
local right = screen[1].geometry.x + screen[1].geometry.width --DOC_HIDE
|
||||
assert(c.height == 30 and c.x == 45 and c.x+c.width+c.border_width == right) --DOC_HIDE
|
||||
assert(c.height == 30 and c.x == 45 and c.x+c.width+2*c.border_width == right) --DOC_HIDE
|
||||
|
|
|
@ -10,8 +10,8 @@ local placement = require("awful.placement") --DOC_HIDE
|
|||
local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
||||
placement.stretch_up(client.focus)
|
||||
|
||||
assert(c.y==c.border_width) --DOC_HIDE
|
||||
assert(c.y==0) --DOC_HIDE
|
||||
assert(c.x==45) --DOC_HIDE
|
||||
assert(c.width == 40) --DOC_HIDE
|
||||
print(c.height)
|
||||
assert(c.height == 35+30) --DOC_HIDE
|
||||
print(c.height-2*c.border_width,35+30)
|
||||
assert(c.height-2*c.border_width == 35+30) --DOC_HIDE
|
||||
|
|
|
@ -10,5 +10,7 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.top(client.focus)
|
||||
|
||||
assert(c.x == screen[1].geometry.width/2-40/2 and c.y==c.border_width--DOC_HIDE
|
||||
and c.width==40 and c.height==30)--DOC_HIDE
|
||||
assert(c.x == screen[1].geometry.width/2-40/2-c.border_width)
|
||||
assert(c.y==0) --DOC_HIDE
|
||||
assert( c.width==40) --DOC_HIDE
|
||||
assert(c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -10,4 +10,4 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.top_left(client.focus)
|
||||
|
||||
assert(c.x == c.border_width and c.y==c.border_width and c.width==40 and c.height==30)--DOC_HIDE
|
||||
assert(c.x == 0 and c.y==0 and c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -10,5 +10,5 @@ local c = client.gen_fake {x = 45, y = 35, width=40, height=30} --DOC_HIDE
|
|||
|
||||
awful.placement.top_right(client.focus)
|
||||
|
||||
assert(c.x == screen[1].geometry.width-40-c.border_width and c.y==c.border_width --DOC_HIDE
|
||||
assert(c.x == screen[1].geometry.width-40-2*c.border_width and c.y==0 --DOC_HIDE
|
||||
and c.width==40 and c.height==30)--DOC_HIDE
|
||||
|
|
|
@ -12,6 +12,7 @@ local function add_signals(c)
|
|||
c:add_signal("property::screen")
|
||||
c:add_signal("property::geometry")
|
||||
c:add_signal("request::geometry")
|
||||
c:add_signal("request::tag")
|
||||
c:add_signal("swapped")
|
||||
c:add_signal("raised")
|
||||
c:add_signal("property::_label") --Used internally
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local test_client = require("_client")
|
||||
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
||||
|
||||
local callback_called = false
|
||||
|
||||
-- Magic table to store tests
|
||||
local tests = {}
|
||||
|
||||
local tb_height = awful.util.round(beautiful.get_font_height() * 1.5)
|
||||
-- local border_width = beautiful.border_width
|
||||
|
||||
local function test_rule(rule)
|
||||
rule.rule = rule.rule or {}
|
||||
|
||||
-- Create a random class. The number need to be large as "rule1" and "rule10" would collide
|
||||
-- The math.ceil is necessary to remove the floating point, this create an invalid dbus name
|
||||
local class = string.format("rule%010d", 42+#tests)
|
||||
rule.rule.class = rule.rule.class or class
|
||||
|
||||
test_client(rule.rule.class, rule.properties.name or "Foo")
|
||||
if rule.test then
|
||||
local t = rule.test
|
||||
table.insert(tests, function() return t(rule.rule.class) end)
|
||||
rule.test = nil
|
||||
end
|
||||
|
||||
table.insert(awful.rules.rules, rule)
|
||||
end
|
||||
|
||||
-- Helper function to search clients
|
||||
local function get_client_by_class(class)
|
||||
for _, c in ipairs(client.get()) do
|
||||
if class == c.class then
|
||||
return c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Test callback and floating
|
||||
test_rule {
|
||||
properties = { floating = true },
|
||||
callback = function(c)
|
||||
assert(type(c) == "client")
|
||||
callback_called = true
|
||||
end,
|
||||
test = function(class)
|
||||
-- Test if callbacks works
|
||||
assert(callback_called)
|
||||
|
||||
-- Make sure "smart" dynamic properties are applied
|
||||
assert(get_client_by_class(class).floating)
|
||||
|
||||
-- The size should not have changed
|
||||
local geo = get_client_by_class(class):geometry()
|
||||
assert(geo.width == 100 and geo.height == 100+tb_height)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test ontop
|
||||
test_rule {
|
||||
properties = { ontop = true },
|
||||
test = function(class)
|
||||
-- Make sure C-API properties are applied
|
||||
assert(get_client_by_class(class).ontop)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test placement
|
||||
test_rule {
|
||||
properties = {
|
||||
floating = true,
|
||||
placement = "bottom_right"
|
||||
},
|
||||
test = function(class)
|
||||
-- Test placement
|
||||
local sgeo = mouse.screen.workarea
|
||||
local c = get_client_by_class(class)
|
||||
local geo = c:geometry()
|
||||
|
||||
assert(geo.y+geo.height+2*c.border_width == sgeo.y+sgeo.height)
|
||||
assert(geo.x+geo.width+2*c.border_width == sgeo.x+sgeo.width)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Create a tag named after the class name
|
||||
test_rule {
|
||||
properties = { new_tag=true },
|
||||
test = function(class)
|
||||
local c_new_tag1 = get_client_by_class(class)
|
||||
|
||||
assert(#c_new_tag1:tags()[1]:clients() == 1)
|
||||
assert(c_new_tag1:tags()[1].name == class)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Create a tag named Foo Tag with a magnifier layout
|
||||
test_rule {
|
||||
properties = {
|
||||
new_tag = {
|
||||
name = "Foo Tag",
|
||||
layout = awful.layout.suit.magnifier
|
||||
}
|
||||
},
|
||||
test = function(class)
|
||||
local t_new_tag2 = get_client_by_class(class):tags()[1]
|
||||
|
||||
assert( #t_new_tag2:clients() == 1 )
|
||||
assert( t_new_tag2.name == "Foo Tag" )
|
||||
assert( t_new_tag2.layout.name == "magnifier" )
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Create a tag named "Bar Tag"
|
||||
test_rule {
|
||||
properties = { new_tag= "Bar Tag" },
|
||||
test = function(class)
|
||||
local c_new_tag3 = get_client_by_class(class)
|
||||
assert(#c_new_tag3:tags()[1]:clients() == 1)
|
||||
assert(c_new_tag3:tags()[1].name == "Bar Tag")
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test if setting the geometry work
|
||||
test_rule {
|
||||
properties = {
|
||||
floating = true,
|
||||
x = 200,
|
||||
y = 200,
|
||||
width = 200,
|
||||
height = 200,
|
||||
},
|
||||
test = function(class)
|
||||
local c = get_client_by_class(class)
|
||||
local geo = c:geometry()
|
||||
|
||||
-- Give it some time
|
||||
if geo.y < 180 then return end
|
||||
|
||||
assert(geo.x == 200)
|
||||
assert(geo.y == 200)
|
||||
assert(geo.width == 200)
|
||||
assert(geo.height == 200)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test if setting a partial geometry preserve the other attributes
|
||||
test_rule {
|
||||
properties = {
|
||||
floating = true,
|
||||
x = 200,
|
||||
geometry = {
|
||||
height = 220
|
||||
}
|
||||
},
|
||||
test = function(class)
|
||||
local c = get_client_by_class(class)
|
||||
local geo = c:geometry()
|
||||
|
||||
-- Give it some time
|
||||
if geo.height < 200 then return end
|
||||
|
||||
assert(geo.x == 200)
|
||||
assert(geo.width == 100)
|
||||
assert(geo.height == 220)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test maximized_horizontal
|
||||
test_rule {
|
||||
properties = { maximized_horizontal = true },
|
||||
test = function(class)
|
||||
local c = get_client_by_class(class)
|
||||
-- Make sure C-API properties are applied
|
||||
|
||||
assert(c.maximized_horizontal)
|
||||
|
||||
local geo = c:geometry()
|
||||
local sgeo = c.screen.workarea
|
||||
|
||||
assert(geo.x==sgeo.x)
|
||||
|
||||
assert(geo.width+2*c.border_width==sgeo.width)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test maximized_vertical
|
||||
test_rule {
|
||||
properties = { maximized_vertical = true },
|
||||
test = function(class)
|
||||
local c = get_client_by_class(class)
|
||||
-- Make sure C-API properties are applied
|
||||
|
||||
assert(c.maximized_vertical)
|
||||
|
||||
local geo = c:geometry()
|
||||
local sgeo = c.screen.workarea
|
||||
|
||||
assert(geo.y==sgeo.y)
|
||||
|
||||
assert(geo.height+2*c.border_width==sgeo.height)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test fullscreen
|
||||
test_rule {
|
||||
properties = { fullscreen = true },
|
||||
test = function(class)
|
||||
local c = get_client_by_class(class)
|
||||
-- Make sure C-API properties are applied
|
||||
|
||||
assert(c.fullscreen)
|
||||
|
||||
local geo = c:geometry()
|
||||
local sgeo = c.screen.geometry
|
||||
|
||||
assert(geo.x==sgeo.x)
|
||||
assert(geo.y==sgeo.y)
|
||||
assert(geo.height+2*c.border_width==sgeo.height)
|
||||
assert(geo.width+2*c.border_width==sgeo.width)
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Test tag and switchtotag
|
||||
test_rule {
|
||||
properties = {
|
||||
tag = "9",
|
||||
switchtotag = true
|
||||
},
|
||||
test = function(class)
|
||||
local c = get_client_by_class(class)
|
||||
-- Make sure C-API properties are applied
|
||||
|
||||
assert(#c:tags() == 1)
|
||||
assert(c:tags()[1].name == "9")
|
||||
assert(c.screen.selected_tag.name == "9")
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
test_rule {
|
||||
properties = {
|
||||
tag = "8",
|
||||
switchtotag = false
|
||||
},
|
||||
test = function(class)
|
||||
local c = get_client_by_class(class)
|
||||
-- Make sure C-API properties are applied
|
||||
|
||||
assert(#c:tags() == 1)
|
||||
assert(c:tags()[1].name == "8")
|
||||
|
||||
assert(c.screen.selected_tag.name ~= "8")
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
-- Wait until all the auto-generated clients are ready
|
||||
local function spawn_clients()
|
||||
if #client.get() >= #tests then
|
||||
-- Set tiled
|
||||
awful.layout.inc(1)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
require("_runner").run_steps{spawn_clients, unpack(tests)}
|
|
@ -0,0 +1,243 @@
|
|||
--- Tests for drawing geometry
|
||||
|
||||
local runner = require( "_runner" )
|
||||
local awful = require( "awful" )
|
||||
local wibox = require( "wibox" )
|
||||
local beautiful = require( "beautiful" )
|
||||
|
||||
local w = nil
|
||||
local w1_draw, w2_draw
|
||||
|
||||
-- Disable automatic placement
|
||||
awful.rules.rules = {
|
||||
{ rule = { }, properties = {
|
||||
border_width = 0,
|
||||
size_hints_honor = false,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 100,
|
||||
border_color = beautiful.border_normal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local steps = {
|
||||
function()
|
||||
if #client.get() == 0 then
|
||||
return true
|
||||
end
|
||||
for _,c in ipairs(client.get()) do
|
||||
c:kill()
|
||||
end
|
||||
end,
|
||||
-- border_color should get applied via focus signal for first client on tag.
|
||||
function(count)
|
||||
if count == 1 then
|
||||
awful.spawn("xterm")
|
||||
else
|
||||
local c = client.get()[1]
|
||||
if c then
|
||||
assert(c.size_hints_honor == false )
|
||||
assert(c.border_width == 0 )
|
||||
assert(c:geometry().x == 0 )
|
||||
assert(c:geometry().y == 0 )
|
||||
assert(c:geometry().height == 100 )
|
||||
assert(c:geometry().width == 100 )
|
||||
|
||||
c:kill()
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
function()
|
||||
awful.rules.rules = {
|
||||
-- All clients will match this rule.
|
||||
{ rule = { },properties = {
|
||||
titlebars_enabled = true,
|
||||
border_width = 10,
|
||||
border_color = "#00ff00",
|
||||
size_hints_honor = false,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 100
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
end,
|
||||
function(count)
|
||||
if count == 1 then
|
||||
awful.spawn("xterm")
|
||||
else
|
||||
local c = client.get()[1]
|
||||
if c then
|
||||
assert(c.border_width == 10 )
|
||||
assert(c:geometry().x == 0 )
|
||||
assert(c:geometry().y == 0 )
|
||||
assert(c:geometry().height == 100 )
|
||||
assert(c:geometry().width == 100 )
|
||||
|
||||
c.border_width = 20
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
assert(c.border_width == 20 )
|
||||
assert(c:geometry().x == 0 )
|
||||
assert(c:geometry().y == 0 )
|
||||
assert(c:geometry().height == 100 )
|
||||
assert(c:geometry().width == 100 )
|
||||
|
||||
c.border_width = 0
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
|
||||
assert(not pcall(function() c.border_width = -2000 end))
|
||||
assert(c.border_width==0)
|
||||
|
||||
c.border_width = 125
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
|
||||
assert(c.border_width == 125 )
|
||||
assert(c:geometry().x == 0 )
|
||||
assert(c:geometry().y == 0 )
|
||||
assert(c:geometry().height == 100 )
|
||||
assert(c:geometry().width == 100 )
|
||||
|
||||
-- So it doesn't hide the other tests
|
||||
c:kill()
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
w = wibox {
|
||||
ontop = true,
|
||||
border_width = 20,
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 100,
|
||||
height = 100,
|
||||
visible = true,
|
||||
}
|
||||
|
||||
assert(w)
|
||||
assert(w.border_width == 20 )
|
||||
assert(w.width == 100 )
|
||||
assert(w.height == 100 )
|
||||
assert(w.x == 100 )
|
||||
assert(w.y == 100 )
|
||||
|
||||
w:setup {
|
||||
fit = function(_, _, _, height)
|
||||
return height, height -- A square taking the full height
|
||||
end,
|
||||
draw = function(_, _, cr, width, height)
|
||||
|
||||
assert(width == 100)
|
||||
assert(height == 100)
|
||||
|
||||
w1_draw = true
|
||||
cr:set_source_rgb(1, 0, 0) -- Red
|
||||
cr:arc(height/2, height/2, height/2, 0, math.pi*2)
|
||||
cr:fill()
|
||||
end,
|
||||
layout = wibox.widget.base.make_widget,
|
||||
}
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
w.border_width = 0
|
||||
assert(w1_draw)
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
assert(w.border_width == 0 )
|
||||
assert(w.width == 100 )
|
||||
assert(w.height == 100 )
|
||||
assert(w.x == 100 )
|
||||
assert(w.y == 100 )
|
||||
|
||||
w:setup {
|
||||
fit = function(_, _, _, height)
|
||||
return height, height -- A square taking the full height
|
||||
end,
|
||||
draw = function(_, _, cr, width, height)
|
||||
|
||||
assert(width == 100)
|
||||
assert(height == 100)
|
||||
|
||||
w2_draw = true
|
||||
cr:set_source_rgb(1, 0, 0) -- Red
|
||||
cr:arc(height/2, height/2, height/2, 0, math.pi*2)
|
||||
cr:fill()
|
||||
end,
|
||||
layout = wibox.widget.base.make_widget,
|
||||
}
|
||||
|
||||
w.visible = false
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
-- Remove the widget before the size change to avoid the asserts
|
||||
w:setup {
|
||||
fit = function(_, _, _, height)
|
||||
return height, height -- A square taking the full height
|
||||
end,
|
||||
draw = function(_, _, cr, _, height)
|
||||
cr:set_source_rgb(1, 0, 1) -- Purple
|
||||
cr:arc(height/2, height/2, height/2, 0, math.pi*2)
|
||||
cr:fill()
|
||||
end,
|
||||
layout = wibox.widget.base.make_widget,
|
||||
}
|
||||
|
||||
w.visible = true
|
||||
assert(w2_draw)
|
||||
|
||||
assert(w.border_width == 0 )
|
||||
assert(w.width == 100 )
|
||||
assert(w.height == 100 )
|
||||
assert(w.x == 100 )
|
||||
assert(w.y == 100 )
|
||||
|
||||
w.border_width = 5
|
||||
|
||||
w:geometry {
|
||||
x = 200,
|
||||
y = 200,
|
||||
width = 200,
|
||||
height = 200,
|
||||
}
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
assert(w.border_width == 5 )
|
||||
assert(w.width == 200 )
|
||||
assert(w.height == 200 )
|
||||
assert(w.x == 200 )
|
||||
assert(w.y == 200 )
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
runner.run_steps(steps)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,90 @@
|
|||
--- Tests maximize and fullscreen
|
||||
|
||||
local runner = require("_runner")
|
||||
local awful = require("awful")
|
||||
|
||||
local original_geo = nil
|
||||
|
||||
local steps = {
|
||||
function(count)
|
||||
if count == 1 then
|
||||
awful.spawn("xterm")
|
||||
else
|
||||
local c = client.get()[1]
|
||||
if c then
|
||||
original_geo = c:geometry()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
-- maximize horizontally
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
assert(not c.maximized_horizontal)
|
||||
assert(not c.maximized_vertical )
|
||||
assert(not c.fullscreen )
|
||||
|
||||
c.maximized_horizontal = true
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
|
||||
--local new_geo = c:geometry()
|
||||
--local sgeo = c.screen.workarea
|
||||
|
||||
--assert(new_geo.x-c.border_width==sgeo.x) --FIXME c:geometry({x=1}).x ~= 1
|
||||
|
||||
--assert(new_geo.width+2*c.border_width==sgeo.width) --FIXME off by 4px
|
||||
|
||||
c.maximized_horizontal = false
|
||||
return true
|
||||
end,
|
||||
-- Test restoring a geometry
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
|
||||
local new_geo = c:geometry()
|
||||
|
||||
for k,v in pairs(original_geo) do
|
||||
assert(new_geo[k] == v)
|
||||
end
|
||||
|
||||
c.fullscreen = true
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
|
||||
local new_geo = c:geometry()
|
||||
local sgeo = c.screen.geometry
|
||||
local bw = c.border_width
|
||||
|
||||
assert(c.fullscreen)
|
||||
assert(new_geo.x-bw==sgeo.x)
|
||||
assert(new_geo.y-bw==sgeo.y)
|
||||
assert(new_geo.x+new_geo.width+bw==sgeo.x+sgeo.width)
|
||||
assert(new_geo.y+new_geo.height+bw==sgeo.y+sgeo.height)
|
||||
|
||||
c.fullscreen = false
|
||||
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
local c = client.get()[1]
|
||||
|
||||
local new_geo = c:geometry()
|
||||
|
||||
for k,v in pairs(original_geo) do
|
||||
assert(new_geo[k] == v)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
runner.run_steps(steps)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -55,7 +55,7 @@ local steps = {
|
|||
root.fake_input("key_release", "2")
|
||||
root.fake_input("key_release", "Super_L")
|
||||
|
||||
elseif awful.tag.selectedlist()[1] == tags[awful.screen.focused()][2] then
|
||||
elseif awful.screen.focused().selected_tags[1] == tags[awful.screen.focused()][2] then
|
||||
assert(#client.get() == 1)
|
||||
local c = client.get()[1]
|
||||
assert(not c.urgent, "Client is not urgent anymore.")
|
||||
|
@ -79,11 +79,11 @@ local steps = {
|
|||
|
||||
awful.spawn("xterm")
|
||||
|
||||
elseif awful.tag.selectedlist()[1] == tags[awful.screen.focused()][2] then
|
||||
elseif awful.screen.focused().selected_tags[1] == tags[awful.screen.focused()][2] then
|
||||
assert(not urgent_cb_done)
|
||||
assert(awful.tag.getproperty(tags[awful.screen.focused()][2], "urgent") == false)
|
||||
assert(awful.tag.getproperty(tags[awful.screen.focused()][2], "urgent_count") == 0)
|
||||
assert(awful.tag.selectedlist()[2] == nil)
|
||||
assert(awful.screen.focused().selected_tags[2] == nil)
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
|
Loading…
Reference in New Issue