drawin: Only redraw on move with translucent background

If a drawable has an opaque background, we don't need pseudo transparency and
thus its content don't change when it is moved. However, when we need pseudo
transparency, then we have to redraw the drawable to apply the new background.

Previously we just always did the redraw. This commit adds a helper function
gears.color.create_opaque_pattern() that analyzes a cairo pattern for
transparency. We use this new function to only redraw-on-move when there is
actual pseudo transparency in effect. Otherwise, this redraw can be skipped.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2014-03-16 14:58:14 +01:00
parent 40e28be700
commit 1924ee9e6e
2 changed files with 73 additions and 3 deletions

View File

@ -202,6 +202,57 @@ function color.create_pattern(col)
return color.create_solid_pattern(col)
end
--- Check if a pattern is opaque.
-- A pattern is transparent if the background on which it gets drawn (with
-- operator OVER) doesn't influence the visual result.
-- @param col An argument that create_pattern() accepts
-- @return The pattern if it is surely opaque, else nil
function color.create_opaque_pattern(col)
local pattern = color.create_pattern(col)
local type = pattern:get_type()
local extend = pattern:get_extend()
if type == "SOLID" then
local status, r, g, b, a = pattern:get_rgba()
if a ~= 1 then
return
end
return pattern
elseif type == "SURFACE" then
if pattern:get_surface():get_content() ~= "COLOR" then
-- The surface has an alpha channel which *might* be non-opaque
return
end
-- Only the "NONE" extend mode is forbidden, everything else doesn't
-- introduce transparent parts
if pattern:get_extend() == "NONE" then
return
end
return pattern
elseif type == "LINEAR" then
local status, stops = pattern:get_color_stop_count()
-- No color stops or extend NONE -> pattern *might* contain transparency
if stops == 0 or pattern:get_extend() == "NONE" then
return
end
-- Now check if any of the color stops contain transparency
for i = 0, stops - 1 do
local status, offset, r, g, b, a = pattern:get_color_stop_rgba(i)
if a ~= 1 then
return
end
end
return pattern
end
-- Unknown type, e.g. mesh or raster source or unsupported type (radial
-- gradients can do weird self-intersections)
end
function color.mt:__call(...)
return color.create_pattern(...)
end

View File

@ -129,6 +129,24 @@ function drawable:set_bg(c)
if type(c) == "string" or type(c) == "table" then
c = color(c)
end
-- If the background is completely opaque, we don't need to redraw when
-- the drawable is moved
-- XXX: This isn't needed when awesome.composite_manager_running is true,
-- but a compositing manager could stop/start and we'd have to properly
-- handle this. So for now we choose the lazy approach.
local redraw_on_move = not color.create_opaque_pattern(c)
if self._redraw_on_move ~= redraw_on_move then
self._redraw_on_move = redraw_on_move
if redraw_on_move then
self.drawable:connect_signal("property::x", self.draw)
self.drawable:connect_signal("property::y", self.draw)
else
self.drawable:disconnect_signal("property::x", self.draw)
self.drawable:disconnect_signal("property::y", self.draw)
end
end
self.background_color = c
self.draw()
end
@ -235,9 +253,10 @@ function drawable.new(d, widget_arg)
end
drawables[ret.draw] = true
d:connect_signal("property::surface", ret.draw)
-- We don't need width/height, because this case emits property::surface
d:connect_signal("property::x", ret.draw)
d:connect_signal("property::y", ret.draw)
-- Currently we aren't redrawing on move (signals not connected).
-- :set_bg() will later recompute this.
ret._redraw_on_move = false
-- Set the default background
ret:set_bg(beautiful.bg_normal)