2016-05-23 05:56:45 +02:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
-- A container capable of changing the background color, foreground color
|
|
|
|
-- widget shape.
|
2016-05-24 19:38:37 +02:00
|
|
|
--
|
|
|
|
--@DOC_wibox_container_defaults_background_EXAMPLE@
|
2016-05-23 05:56:45 +02:00
|
|
|
-- @author Uli Schlachter
|
|
|
|
-- @copyright 2010 Uli Schlachter
|
|
|
|
-- @classmod wibox.container.background
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
local base = require("wibox.widget.base")
|
|
|
|
local color = require("gears.color")
|
|
|
|
local surface = require("gears.surface")
|
|
|
|
local beautiful = require("beautiful")
|
|
|
|
local cairo = require("lgi").cairo
|
2017-03-08 21:18:33 +01:00
|
|
|
local gtable = require("gears.table")
|
2019-03-12 19:13:21 +01:00
|
|
|
local gshape = require("gears.shape")
|
2019-04-05 23:03:12 +02:00
|
|
|
local gdebug = require("gears.debug")
|
2016-05-23 05:56:45 +02:00
|
|
|
local setmetatable = setmetatable
|
|
|
|
local type = type
|
|
|
|
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
|
|
|
|
|
|
|
local background = { mt = {} }
|
|
|
|
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
-- Make sure a surface pattern is freed *now*
|
|
|
|
local function dispose_pattern(pattern)
|
|
|
|
local status, s = pattern:get_surface()
|
|
|
|
if status == "SUCCESS" then
|
|
|
|
s:finish()
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
end
|
2016-05-23 05:56:45 +02:00
|
|
|
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
-- Prepare drawing the children of this widget
|
|
|
|
function background:before_draw_children(context, cr, width, height)
|
2019-03-12 19:13:21 +01:00
|
|
|
local bw = self._private.shape_border_width or 0
|
|
|
|
local shape = self._private.shape or (bw > 0 and gshape.rectangle or nil)
|
|
|
|
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
-- Redirect drawing to a temporary surface if there is a shape
|
2019-03-12 19:13:21 +01:00
|
|
|
if shape then
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
cr:push_group_with_content(cairo.Content.COLOR_ALPHA)
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
-- Draw the background
|
2016-05-26 07:18:20 +02:00
|
|
|
if self._private.background then
|
2019-01-27 11:30:08 +01:00
|
|
|
cr:save()
|
2016-05-26 07:18:20 +02:00
|
|
|
cr:set_source(self._private.background)
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
cr:rectangle(0, 0, width, height)
|
|
|
|
cr:fill()
|
2019-01-27 11:30:08 +01:00
|
|
|
cr:restore()
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
2016-05-26 07:18:20 +02:00
|
|
|
if self._private.bgimage then
|
2019-01-27 11:30:08 +01:00
|
|
|
cr:save()
|
2016-05-26 07:18:20 +02:00
|
|
|
if type(self._private.bgimage) == "function" then
|
|
|
|
self._private.bgimage(context, cr, width, height,unpack(self._private.bgimage_args))
|
2016-05-23 05:56:45 +02:00
|
|
|
else
|
2016-05-26 07:18:20 +02:00
|
|
|
local pattern = cairo.Pattern.create_for_surface(self._private.bgimage)
|
2016-05-23 05:56:45 +02:00
|
|
|
cr:set_source(pattern)
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
cr:rectangle(0, 0, width, height)
|
|
|
|
cr:fill()
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
2019-01-27 11:30:08 +01:00
|
|
|
cr:restore()
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
2019-02-01 15:28:29 +01:00
|
|
|
|
|
|
|
if self._private.foreground then
|
|
|
|
cr:set_source(self._private.foreground)
|
|
|
|
end
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Draw the border
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
function background:after_draw_children(_, cr, width, height)
|
2019-03-12 19:13:21 +01:00
|
|
|
local bw = self._private.shape_border_width or 0
|
|
|
|
local shape = self._private.shape or (bw > 0 and gshape.rectangle or nil)
|
|
|
|
|
|
|
|
if not shape then
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Okay, there is a shape. Get it as a path.
|
|
|
|
|
|
|
|
cr:translate(bw, bw)
|
2019-03-12 19:13:21 +01:00
|
|
|
shape(cr, width - 2*bw, height - 2*bw, unpack(self._private.shape_args or {}))
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
cr:translate(-bw, -bw)
|
|
|
|
|
|
|
|
if bw > 0 then
|
|
|
|
-- Now we need to do a border, somehow. We begin with another
|
|
|
|
-- temporary surface.
|
|
|
|
cr:push_group_with_content(cairo.Content.ALPHA)
|
|
|
|
|
|
|
|
-- Mark everything as "this is border"
|
|
|
|
cr:set_source_rgba(0, 0, 0, 1)
|
|
|
|
cr:paint()
|
|
|
|
|
|
|
|
-- Now remove the inside of the shape to get just the border
|
|
|
|
cr:set_operator(cairo.Operator.SOURCE)
|
|
|
|
cr:set_source_rgba(0, 0, 0, 0)
|
|
|
|
cr:fill_preserve()
|
|
|
|
|
|
|
|
local mask = cr:pop_group()
|
|
|
|
-- Now actually draw the border via the mask we just created.
|
2016-05-26 07:18:20 +02:00
|
|
|
cr:set_source(color(self._private.shape_border_color or self._private.foreground or beautiful.fg_normal))
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
cr:set_operator(cairo.Operator.SOURCE)
|
|
|
|
cr:mask(mask)
|
2016-05-23 05:56:45 +02:00
|
|
|
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
dispose_pattern(mask)
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
-- We now have the right content in a temporary surface. Copy it to the
|
|
|
|
-- target surface. For this, we need another mask
|
|
|
|
cr:push_group_with_content(cairo.Content.ALPHA)
|
2016-05-23 05:56:45 +02:00
|
|
|
|
Change the way the shape is done in the background container
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
2019-01-25 15:16:17 +01:00
|
|
|
-- Draw the border with 2 * border width (this draws both
|
|
|
|
-- inside and outside, only half of it is outside)
|
|
|
|
cr.line_width = 2 * bw
|
|
|
|
cr:set_source_rgba(0, 0, 0, 1)
|
|
|
|
cr:stroke_preserve()
|
|
|
|
|
|
|
|
-- Now fill the whole inside so that it is also include in the mask
|
|
|
|
cr:fill()
|
|
|
|
|
|
|
|
local mask = cr:pop_group()
|
|
|
|
local source = cr:pop_group() -- This pops what was pushed in before_draw_children
|
|
|
|
|
|
|
|
-- This now draws the content of the background widget to the actual
|
|
|
|
-- target, but only the part that is inside the mask
|
|
|
|
cr:set_operator(cairo.Operator.OVER)
|
|
|
|
cr:set_source(source)
|
|
|
|
cr:mask(mask)
|
|
|
|
|
|
|
|
dispose_pattern(mask)
|
|
|
|
dispose_pattern(source)
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Layout this widget
|
|
|
|
function background:layout(_, width, height)
|
2016-05-26 07:18:20 +02:00
|
|
|
if self._private.widget then
|
2019-03-12 19:13:21 +01:00
|
|
|
local bw = self._private.border_strategy == "inner" and
|
|
|
|
self._private.shape_border_width or 0
|
|
|
|
|
|
|
|
return { base.place_widget_at(
|
|
|
|
self._private.widget, bw, bw, width-2*bw, height-2*bw
|
|
|
|
) }
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Fit this widget into the given area
|
|
|
|
function background:fit(context, width, height)
|
2016-05-26 07:18:20 +02:00
|
|
|
if not self._private.widget then
|
2016-05-23 05:56:45 +02:00
|
|
|
return 0, 0
|
|
|
|
end
|
|
|
|
|
2019-03-12 19:13:21 +01:00
|
|
|
local bw = self._private.border_strategy == "inner" and
|
|
|
|
self._private.shape_border_width or 0
|
|
|
|
|
|
|
|
local w, h = base.fit_widget(
|
|
|
|
self, context, self._private.widget, width - 2*bw, height - 2*bw
|
|
|
|
)
|
|
|
|
|
|
|
|
return w+2*bw, h+2*bw
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
--- The widget displayed in the background widget.
|
|
|
|
-- @property widget
|
2016-05-23 05:56:45 +02:00
|
|
|
-- @tparam widget widget The widget to be disaplayed inside of the background
|
|
|
|
-- area
|
2016-05-26 08:09:18 +02:00
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
function background:set_widget(widget)
|
|
|
|
if widget then
|
|
|
|
base.check_widget(widget)
|
|
|
|
end
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.widget = widget
|
2016-05-23 05:56:45 +02:00
|
|
|
self:emit_signal("widget::layout_changed")
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
function background:get_widget()
|
|
|
|
return self._private.widget
|
|
|
|
end
|
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
-- Get children element
|
|
|
|
-- @treturn table The children
|
|
|
|
function background:get_children()
|
2016-05-26 07:18:20 +02:00
|
|
|
return {self._private.widget}
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Replace the layout children
|
|
|
|
-- This layout only accept one children, all others will be ignored
|
|
|
|
-- @tparam table children A table composed of valid widgets
|
|
|
|
function background:set_children(children)
|
|
|
|
self:set_widget(children[1])
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
--- The background color/pattern/gradient to use.
|
2016-05-23 06:09:57 +02:00
|
|
|
--@DOC_wibox_container_background_bg_EXAMPLE@
|
2016-05-26 08:09:18 +02:00
|
|
|
-- @property bg
|
|
|
|
-- @param bg A color string, pattern or gradient
|
|
|
|
-- @see gears.color
|
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
function background:set_bg(bg)
|
|
|
|
if bg then
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.background = color(bg)
|
2016-05-23 05:56:45 +02:00
|
|
|
else
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.background = nil
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
self:emit_signal("widget::redraw_needed")
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
function background:get_bg()
|
|
|
|
return self._private.background
|
|
|
|
end
|
|
|
|
|
|
|
|
--- The foreground (text) color/pattern/gradient to use.
|
2016-05-23 06:09:57 +02:00
|
|
|
--@DOC_wibox_container_background_fg_EXAMPLE@
|
2016-05-26 08:09:18 +02:00
|
|
|
-- @property fg
|
|
|
|
-- @param fg A color string, pattern or gradient
|
|
|
|
-- @see gears.color
|
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
function background:set_fg(fg)
|
|
|
|
if fg then
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.foreground = color(fg)
|
2016-05-23 05:56:45 +02:00
|
|
|
else
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.foreground = nil
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
self:emit_signal("widget::redraw_needed")
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
function background:get_fg()
|
|
|
|
return self._private.foreground
|
|
|
|
end
|
|
|
|
|
2019-03-12 19:13:21 +01:00
|
|
|
--- The background shape.
|
2016-05-26 08:09:18 +02:00
|
|
|
--
|
|
|
|
-- Use `set_shape` to set additional shape paramaters.
|
|
|
|
--
|
|
|
|
--@DOC_wibox_container_background_shape_EXAMPLE@
|
|
|
|
-- @property shape
|
|
|
|
-- @param shape A function taking a context, width and height as arguments
|
|
|
|
-- @see gears.shape
|
|
|
|
-- @see set_shape
|
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
--- Set the background shape.
|
|
|
|
--
|
|
|
|
-- Any other arguments will be passed to the shape function
|
|
|
|
-- @param shape A function taking a context, width and height as arguments
|
2016-05-26 08:09:18 +02:00
|
|
|
-- @see gears.shape
|
|
|
|
-- @see shape
|
2016-05-23 05:56:45 +02:00
|
|
|
function background:set_shape(shape, ...)
|
2016-08-05 07:13:20 +02:00
|
|
|
local args = {...}
|
|
|
|
|
|
|
|
if shape == self._private.shape and #args == 0 then return end
|
|
|
|
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.shape = shape
|
|
|
|
self._private.shape_args = {...}
|
2016-05-23 05:56:45 +02:00
|
|
|
self:emit_signal("widget::redraw_needed")
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
function background:get_shape()
|
|
|
|
return self._private.shape
|
|
|
|
end
|
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
--- When a `shape` is set, also draw a border.
|
|
|
|
--
|
2016-05-26 08:09:18 +02:00
|
|
|
-- See `wibox.container.background.shape` for an usage example.
|
2019-03-12 19:13:21 +01:00
|
|
|
-- @deprecatedproperty shape_border_width
|
2016-05-23 05:56:45 +02:00
|
|
|
-- @tparam number width The border width
|
2019-03-12 19:13:21 +01:00
|
|
|
-- @see border_width
|
|
|
|
|
|
|
|
--- Add a border of a specific width.
|
|
|
|
--
|
|
|
|
-- If the shape is set, the border will also be shaped.
|
|
|
|
--
|
|
|
|
-- See `wibox.container.background.shape` for an usage example.
|
|
|
|
-- @property border_width
|
|
|
|
-- @tparam[opt=0] number width The border width.
|
|
|
|
-- @see border_color
|
2016-05-26 08:09:18 +02:00
|
|
|
|
2019-03-12 19:13:21 +01:00
|
|
|
function background:set_border_width(width)
|
2016-08-05 07:13:20 +02:00
|
|
|
if self._private.shape_border_width == width then return end
|
|
|
|
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.shape_border_width = width
|
2016-05-23 05:56:45 +02:00
|
|
|
self:emit_signal("widget::redraw_needed")
|
|
|
|
end
|
|
|
|
|
2019-03-12 19:13:21 +01:00
|
|
|
function background:get_border_width()
|
2016-05-26 08:09:18 +02:00
|
|
|
return self._private.shape_border_width
|
|
|
|
end
|
|
|
|
|
2019-04-05 23:03:12 +02:00
|
|
|
function background.get_shape_border_width(...)
|
|
|
|
gdebug.deprecate("Use `border_width` instead of `shape_border_width`",
|
|
|
|
{deprecated_in=5})
|
|
|
|
|
|
|
|
return background.get_border_width(...)
|
|
|
|
end
|
|
|
|
|
|
|
|
function background.set_shape_border_width(...)
|
|
|
|
gdebug.deprecate("Use `border_width` instead of `shape_border_width`",
|
|
|
|
{deprecated_in=5})
|
|
|
|
|
|
|
|
background.set_border_width(...)
|
|
|
|
end
|
2019-03-12 19:13:21 +01:00
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
--- When a `shape` is set, also draw a border.
|
|
|
|
--
|
2016-05-26 08:09:18 +02:00
|
|
|
-- See `wibox.container.background.shape` for an usage example.
|
2019-03-12 19:13:21 +01:00
|
|
|
-- @deprecatedproperty shape_border_color
|
2016-05-26 07:18:20 +02:00
|
|
|
-- @param[opt=self._private.foreground] fg The border color, pattern or gradient
|
2016-05-26 08:09:18 +02:00
|
|
|
-- @see gears.color
|
2019-03-12 19:13:21 +01:00
|
|
|
-- @see border_color
|
2016-05-26 08:09:18 +02:00
|
|
|
|
2019-03-12 19:13:21 +01:00
|
|
|
--- Set the color for the border.
|
|
|
|
--
|
|
|
|
-- See `wibox.container.background.shape` for an usage example.
|
|
|
|
-- @property border_color
|
|
|
|
-- @param[opt=self._private.foreground] fg The border color, pattern or gradient
|
|
|
|
-- @see gears.color
|
|
|
|
-- @see border_width
|
|
|
|
|
|
|
|
function background:set_border_color(fg)
|
2016-08-05 07:13:20 +02:00
|
|
|
if self._private.shape_border_color == fg then return end
|
|
|
|
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.shape_border_color = fg
|
2016-05-23 05:56:45 +02:00
|
|
|
self:emit_signal("widget::redraw_needed")
|
|
|
|
end
|
|
|
|
|
2019-03-12 19:13:21 +01:00
|
|
|
function background:get_border_color()
|
2016-05-26 08:09:18 +02:00
|
|
|
return self._private.shape_border_color
|
|
|
|
end
|
|
|
|
|
2019-04-05 23:03:12 +02:00
|
|
|
function background.get_shape_border_color(...)
|
|
|
|
gdebug.deprecate("Use `border_color` instead of `shape_border_color`",
|
|
|
|
{deprecated_in=5})
|
|
|
|
|
|
|
|
return background.get_border_color(...)
|
|
|
|
end
|
|
|
|
|
|
|
|
function background.set_shape_border_color(...)
|
|
|
|
gdebug.deprecate("Use `border_color` instead of `shape_border_color`",
|
|
|
|
{deprecated_in=5})
|
|
|
|
|
|
|
|
background.set_border_color(...)
|
|
|
|
end
|
2019-03-12 19:13:21 +01:00
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
function background:set_shape_clip(value)
|
2019-01-28 14:55:53 +01:00
|
|
|
if value then return end
|
|
|
|
require("gears.debug").print_warning("shape_clip property of background container was removed."
|
|
|
|
.. " Use wibox.layout.stack instead if you want shape_clip=false.")
|
2016-05-23 05:56:45 +02:00
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
function background:get_shape_clip()
|
2019-01-28 14:55:53 +01:00
|
|
|
require("gears.debug").print_warning("shape_clip property of background container was removed."
|
|
|
|
.. " Use wibox.layout.stack instead if you want shape_clip=false.")
|
|
|
|
return true
|
2016-05-26 08:09:18 +02:00
|
|
|
end
|
|
|
|
|
2019-03-12 19:13:21 +01:00
|
|
|
--- How the border width affects the contained widget.
|
|
|
|
--
|
|
|
|
-- The valid values are:
|
|
|
|
--
|
|
|
|
-- * *none*: Just apply the border, do not affect the content size (default).
|
|
|
|
-- * *inner*: Squeeze the size of the content by the border width.
|
|
|
|
--
|
|
|
|
-- @property border_strategy
|
|
|
|
-- @param[opt="none"] string
|
|
|
|
|
|
|
|
function background:set_border_strategy(value)
|
|
|
|
self._private.border_strategy = value
|
|
|
|
self:emit_signal("widget::layout_changed")
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
--- The background image to use
|
2016-05-23 05:56:45 +02:00
|
|
|
-- If `image` is a function, it will be called with `(context, cr, width, height)`
|
|
|
|
-- as arguments. Any other arguments passed to this method will be appended.
|
2016-05-26 08:09:18 +02:00
|
|
|
-- @property bgimage
|
2016-05-23 05:56:45 +02:00
|
|
|
-- @param image A background image or a function
|
2016-05-26 08:09:18 +02:00
|
|
|
-- @see gears.surface
|
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
function background:set_bgimage(image, ...)
|
2016-05-26 07:18:20 +02:00
|
|
|
self._private.bgimage = type(image) == "function" and image or surface.load(image)
|
|
|
|
self._private.bgimage_args = {...}
|
2016-05-23 05:56:45 +02:00
|
|
|
self:emit_signal("widget::redraw_needed")
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
function background:get_bgimage()
|
|
|
|
return self._private.bgimage
|
|
|
|
end
|
|
|
|
|
2016-05-23 08:46:28 +02:00
|
|
|
--- Returns a new background container.
|
|
|
|
--
|
|
|
|
-- A background container applies a background and foreground color
|
|
|
|
-- to another widget.
|
2016-05-23 05:56:45 +02:00
|
|
|
-- @param[opt] widget The widget to display.
|
|
|
|
-- @param[opt] bg The background to use for that widget.
|
|
|
|
-- @param[opt] shape A `gears.shape` compatible shape function
|
2016-05-23 08:46:28 +02:00
|
|
|
-- @function wibox.container.background
|
2016-05-23 05:56:45 +02:00
|
|
|
local function new(widget, bg, shape)
|
2016-05-26 08:09:18 +02:00
|
|
|
local ret = base.make_widget(nil, nil, {
|
|
|
|
enable_properties = true,
|
|
|
|
})
|
2016-05-23 05:56:45 +02:00
|
|
|
|
2017-03-08 21:18:33 +01:00
|
|
|
gtable.crush(ret, background, true)
|
2016-05-23 05:56:45 +02:00
|
|
|
|
2016-05-26 07:18:20 +02:00
|
|
|
ret._private.shape = shape
|
2016-05-23 05:56:45 +02:00
|
|
|
|
|
|
|
ret:set_widget(widget)
|
|
|
|
ret:set_bg(bg)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
end
|
|
|
|
|
|
|
|
function background.mt:__call(...)
|
|
|
|
return new(...)
|
|
|
|
end
|
|
|
|
|
2016-05-26 08:09:18 +02:00
|
|
|
--@DOC_widget_COMMON@
|
|
|
|
|
2016-05-26 21:12:56 +02:00
|
|
|
--@DOC_object_COMMON@
|
|
|
|
|
2016-05-23 05:56:45 +02:00
|
|
|
return setmetatable(background, background.mt)
|
|
|
|
|
|
|
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|