2014-04-14 10:04:56 +02:00
|
|
|
---------------------------------------------------------------------------
|
2014-05-20 11:47:20 +02:00
|
|
|
--- Handle client shapes.
|
|
|
|
--
|
2014-04-14 10:04:56 +02:00
|
|
|
-- @author Uli Schlachter <psychon@znc.in>
|
|
|
|
-- @copyright 2014 Uli Schlachter
|
2016-04-11 05:27:19 +02:00
|
|
|
-- @submodule client
|
2014-04-14 10:04:56 +02:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- Grab environment we need
|
|
|
|
local surface = require("gears.surface")
|
|
|
|
local cairo = require("lgi").cairo
|
|
|
|
local capi =
|
|
|
|
{
|
|
|
|
client = client,
|
|
|
|
}
|
|
|
|
|
|
|
|
local shape = {}
|
|
|
|
shape.update = {}
|
|
|
|
|
2016-04-11 05:27:19 +02:00
|
|
|
--- Get one of a client's shapes and transform it to include window decorations.
|
2017-02-02 21:12:47 +01:00
|
|
|
-- @function awful.client.shape.get_transformed
|
2014-05-20 11:47:20 +02:00
|
|
|
-- @client c The client whose shape should be retrieved
|
2016-02-07 15:24:08 +01:00
|
|
|
-- @tparam string shape_name Either "bounding" or "clip"
|
|
|
|
function shape.get_transformed(c, shape_name)
|
|
|
|
local border = shape_name == "bounding" and c.border_width or 0
|
|
|
|
local shape_img = surface.load_silently(c["client_shape_" .. shape_name], false)
|
2017-02-02 21:12:47 +01:00
|
|
|
local _shape = c._shape
|
|
|
|
if not (shape_img or _shape) then return end
|
2014-04-14 10:04:56 +02:00
|
|
|
|
|
|
|
-- Get information about various sizes on the client
|
|
|
|
local geom = c:geometry()
|
|
|
|
local _, t = c:titlebar_top()
|
|
|
|
local _, b = c:titlebar_bottom()
|
|
|
|
local _, l = c:titlebar_left()
|
|
|
|
local _, r = c:titlebar_right()
|
|
|
|
|
|
|
|
-- Figure out the size of the shape that we need
|
|
|
|
local img_width = geom.width + 2*border
|
|
|
|
local img_height = geom.height + 2*border
|
|
|
|
local result = cairo.ImageSurface(cairo.Format.A1, img_width, img_height)
|
|
|
|
local cr = cairo.Context(result)
|
|
|
|
|
2017-02-02 21:12:47 +01:00
|
|
|
-- Fill everything (this paints the titlebars and border).
|
|
|
|
-- The `cr:paint()` below will have painted the whole surface, so
|
|
|
|
-- everything inside the client is currently meant to be visible
|
2014-04-14 10:04:56 +02:00
|
|
|
cr:paint()
|
|
|
|
|
2017-02-02 21:12:47 +01:00
|
|
|
if shape_img then
|
|
|
|
-- Draw the client's shape in the middle
|
|
|
|
cr:set_operator(cairo.Operator.SOURCE)
|
|
|
|
cr:set_source_surface(shape_img, border + l, border + t)
|
|
|
|
cr:rectangle(border + l, border + t, geom.width - l - r, geom.height - t - b)
|
|
|
|
cr:fill()
|
2017-08-04 13:13:22 +02:00
|
|
|
|
|
|
|
shape_img:finish()
|
2017-02-02 21:12:47 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
if _shape then
|
|
|
|
-- Draw the shape to an intermediate surface
|
|
|
|
cr:push_group()
|
|
|
|
-- Intersect what is drawn so far with the shape set by Lua.
|
|
|
|
if shape_name == "clip" then
|
|
|
|
-- Correct for the border offset
|
|
|
|
cr:translate(-c.border_width, -c.border_width)
|
|
|
|
end
|
|
|
|
-- Always call the shape with the size of the bounding shape
|
|
|
|
_shape(cr, geom.width + 2*c.border_width, geom.height + 2*c.border_width)
|
|
|
|
-- Now fill the "selected" part
|
|
|
|
cr:set_operator(cairo.Operator.SOURCE)
|
|
|
|
cr:set_source_rgba(1, 1, 1, 1)
|
|
|
|
cr:fill_preserve()
|
|
|
|
if shape_name == "clip" then
|
|
|
|
-- Remove an area of size c.border_width again (We use 2*bw since
|
|
|
|
-- half of that is on the outside)
|
|
|
|
cr:set_source_rgba(0, 0, 0, 0)
|
|
|
|
cr:set_line_width(2*c.border_width)
|
|
|
|
cr:stroke()
|
|
|
|
end
|
|
|
|
-- Combine the result with what we already have
|
|
|
|
cr:pop_group_to_source()
|
|
|
|
cr:set_operator(cairo.Operator.IN)
|
|
|
|
cr:paint()
|
|
|
|
end
|
|
|
|
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Update all of a client's shapes from the shapes the client set itself.
|
|
|
|
-- @function awful.client.shape.update.all
|
|
|
|
-- @client c The client to act on
|
|
|
|
function shape.update.all(c)
|
2017-02-04 07:20:56 +01:00
|
|
|
shape.update.bounding(c)
|
|
|
|
shape.update.clip(c)
|
2014-04-14 10:04:56 +02:00
|
|
|
end
|
|
|
|
|
2016-04-11 05:27:19 +02:00
|
|
|
--- Update a client's bounding shape from the shape the client set itself.
|
2017-02-02 21:12:47 +01:00
|
|
|
-- @function awful.client.shape.update.bounding
|
2014-05-20 11:47:20 +02:00
|
|
|
-- @client c The client to act on
|
2014-04-14 10:04:56 +02:00
|
|
|
function shape.update.bounding(c)
|
|
|
|
local res = shape.get_transformed(c, "bounding")
|
|
|
|
c.shape_bounding = res and res._native
|
|
|
|
-- Free memory
|
|
|
|
if res then
|
|
|
|
res:finish()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-04-11 05:27:19 +02:00
|
|
|
--- Update a client's clip shape from the shape the client set itself.
|
2017-02-02 21:12:47 +01:00
|
|
|
-- @function awful.client.shape.update.clip
|
2014-05-20 11:47:20 +02:00
|
|
|
-- @client c The client to act on
|
2014-04-14 10:04:56 +02:00
|
|
|
function shape.update.clip(c)
|
|
|
|
local res = shape.get_transformed(c, "clip")
|
|
|
|
c.shape_clip = res and res._native
|
|
|
|
-- Free memory
|
|
|
|
if res then
|
|
|
|
res:finish()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
capi.client.connect_signal("property::shape_client_bounding", shape.update.bounding)
|
|
|
|
capi.client.connect_signal("property::shape_client_clip", shape.update.clip)
|
2017-01-30 13:42:54 +01:00
|
|
|
capi.client.connect_signal("property::size", shape.update.all)
|
|
|
|
capi.client.connect_signal("property::border_width", shape.update.all)
|
2014-04-14 10:04:56 +02:00
|
|
|
|
|
|
|
return shape
|
|
|
|
|
|
|
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|