From 1924ee9e6ec0f90e2fa9716555e947870661553d Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 16 Mar 2014 14:58:14 +0100 Subject: [PATCH] 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 --- lib/gears/color.lua.in | 51 +++++++++++++++++++++++++++++++++++++++ lib/wibox/drawable.lua.in | 25 ++++++++++++++++--- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/lib/gears/color.lua.in b/lib/gears/color.lua.in index 5b94e04f..8c14b8c1 100644 --- a/lib/gears/color.lua.in +++ b/lib/gears/color.lua.in @@ -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 diff --git a/lib/wibox/drawable.lua.in b/lib/wibox/drawable.lua.in index 8458e5c0..666a69ec 100644 --- a/lib/wibox/drawable.lua.in +++ b/lib/wibox/drawable.lua.in @@ -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)