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)