Browse Source

WindowServer: Fix some gliches when overlays are moved or removed

Keep track of areas that overlays were rendered to when we recompute
occlusions. This allows us to then easily figure out areas where
overlays were moved from or removed from.
Tom 2 năm trước cách đây
mục cha
commit
9ff1fa1cf3

+ 26 - 11
Userland/Services/WindowServer/Compositor.cpp

@@ -1000,19 +1000,23 @@ void Compositor::add_overlay(Overlay& overlay)
     if (!did_insert)
     if (!did_insert)
         m_overlay_list.append(overlay);
         m_overlay_list.append(overlay);
 
 
-    overlay.clear_invalidated();
+    overlay.invalidate();
     overlay_rects_changed();
     overlay_rects_changed();
-    auto& rect = overlay.rect();
-    if (!rect.is_empty())
-        invalidate_screen(rect);
 }
 }
 
 
 void Compositor::remove_overlay(Overlay& overlay)
 void Compositor::remove_overlay(Overlay& overlay)
 {
 {
-    auto& current_render_rect = overlay.current_render_rect();
-    if (!current_render_rect.is_empty())
-        invalidate_screen(current_render_rect);
     m_overlay_list.remove(overlay);
     m_overlay_list.remove(overlay);
+
+    auto last_rendered_rect = overlay.current_render_rect();
+    if (!last_rendered_rect.is_empty()) {
+        // We need to invalidate the entire area. While recomputing occlusions
+        // will detect areas no longer occupied by overlays, if there are other
+        // overlays intersecting with the overlay that was removed, then that
+        // area would not get re-rendered.
+        invalidate_screen(last_rendered_rect);
+    }
+
     overlay_rects_changed();
     overlay_rects_changed();
 }
 }
 
 
@@ -1133,8 +1137,6 @@ void Compositor::overlay_rects_changed()
     m_overlay_rects_changed = true;
     m_overlay_rects_changed = true;
     m_invalidated_any = true;
     m_invalidated_any = true;
     invalidate_occlusions();
     invalidate_occlusions();
-    for (auto& rect : m_overlay_rects.rects())
-        invalidate_screen(rect);
     start_compose_async_timer();
     start_compose_async_timer();
 }
 }
 
 
@@ -1144,13 +1146,19 @@ void Compositor::recompute_overlay_rects()
     // regular window contents. This effectively just forces those areas to
     // regular window contents. This effectively just forces those areas to
     // be rendered as transparency areas, which allows us to render these
     // be rendered as transparency areas, which allows us to render these
     // flicker-free.
     // flicker-free.
+    swap(m_last_rendered_overlay_rects, m_overlay_rects);
     m_overlay_rects.clear_with_capacity();
     m_overlay_rects.clear_with_capacity();
     for (auto& overlay : m_overlay_list) {
     for (auto& overlay : m_overlay_list) {
         auto& render_rect = overlay.rect();
         auto& render_rect = overlay.rect();
         m_overlay_rects.add(render_rect);
         m_overlay_rects.add(render_rect);
 
 
+        // Invalidate areas that are no longer in the rendered area because the overlay was moved.
+        auto previous_rects = overlay.current_render_rect().shatter(render_rect);
+        for (auto& rect : previous_rects)
+            invalidate_screen(rect);
+
         // Save the rectangle we are using for rendering from now on
         // Save the rectangle we are using for rendering from now on
-        overlay.did_recompute_occlusions();
+        bool needs_invalidation = overlay.apply_render_rect();
 
 
         // Cache which screens this overlay are rendered on
         // Cache which screens this overlay are rendered on
         overlay.m_screens.clear_with_capacity();
         overlay.m_screens.clear_with_capacity();
@@ -1160,8 +1168,15 @@ void Compositor::recompute_overlay_rects()
             return IterationDecision::Continue;
             return IterationDecision::Continue;
         });
         });
 
 
-        invalidate_screen(render_rect);
+        if (needs_invalidation)
+            invalidate_screen(render_rect);
     }
     }
+
+    // Invalidate rects that are not going to get rendered anymore, e.g.
+    // because overlays were removed or rectangles were changed
+    auto no_longer_rendered_rects = m_last_rendered_overlay_rects.shatter(m_overlay_rects);
+    for (auto& rect : no_longer_rendered_rects.rects())
+        invalidate_screen(rect);
 }
 }
 
 
 void Compositor::recompute_occlusions()
 void Compositor::recompute_occlusions()

+ 1 - 0
Userland/Services/WindowServer/Compositor.h

@@ -226,6 +226,7 @@ private:
 
 
     IntrusiveList<&Overlay::m_list_node> m_overlay_list;
     IntrusiveList<&Overlay::m_list_node> m_overlay_list;
     Gfx::DisjointIntRectSet m_overlay_rects;
     Gfx::DisjointIntRectSet m_overlay_rects;
+    Gfx::DisjointIntRectSet m_last_rendered_overlay_rects;
     Gfx::DisjointIntRectSet m_dirty_screen_rects;
     Gfx::DisjointIntRectSet m_dirty_screen_rects;
     Gfx::DisjointIntRectSet m_opaque_wallpaper_rects;
     Gfx::DisjointIntRectSet m_opaque_wallpaper_rects;
     Gfx::DisjointIntRectSet m_transparent_wallpaper_rects;
     Gfx::DisjointIntRectSet m_transparent_wallpaper_rects;

+ 5 - 6
Userland/Services/WindowServer/Overlays.cpp

@@ -13,7 +13,8 @@ namespace WindowServer {
 
 
 Overlay::~Overlay()
 Overlay::~Overlay()
 {
 {
-    Compositor::the().remove_overlay(*this);
+    if (is_enabled())
+        Compositor::the().remove_overlay(*this);
 }
 }
 
 
 bool Overlay::invalidate()
 bool Overlay::invalidate()
@@ -21,9 +22,8 @@ bool Overlay::invalidate()
     if (m_invalidated)
     if (m_invalidated)
         return false;
         return false;
     m_invalidated = true;
     m_invalidated = true;
-    // m_current_rect should only get updated by recompute_overlay_rects()
-    if (!m_current_rect.is_empty())
-        Compositor::the().invalidate_screen(m_current_rect);
+    if (is_enabled())
+        Compositor::the().overlay_rects_changed();
     return true;
     return true;
 }
 }
 
 
@@ -45,8 +45,6 @@ void Overlay::set_rect(Gfx::IntRect const& rect)
     auto previous_rect = m_rect;
     auto previous_rect = m_rect;
     m_rect = rect;
     m_rect = rect;
     invalidate();
     invalidate();
-    if (is_enabled())
-        Compositor::the().overlay_rects_changed();
     rect_changed(previous_rect);
     rect_changed(previous_rect);
 }
 }
 
 
@@ -257,6 +255,7 @@ void WindowGeometryOverlay::update_rect()
             rect.set_bottom_without_resize(desktop_rect.bottom());
             rect.set_bottom_without_resize(desktop_rect.bottom());
 
 
         set_rect(rect);
         set_rect(rect);
+        invalidate_content(); // needed in case the rectangle itself doesn't change. But the contents did.
     } else {
     } else {
         set_enabled(false);
         set_enabled(false);
     }
     }

+ 3 - 2
Userland/Services/WindowServer/Overlays.h

@@ -56,11 +56,12 @@ protected:
     virtual void rect_changed(Gfx::IntRect const&) {};
     virtual void rect_changed(Gfx::IntRect const&) {};
 
 
 private:
 private:
-    void clear_invalidated() { m_invalidated = false; }
-    void did_recompute_occlusions()
+    [[nodiscard]] bool apply_render_rect()
     {
     {
+        bool needs_invalidation = m_invalidated;
         m_invalidated = false;
         m_invalidated = false;
         m_current_rect = m_rect;
         m_current_rect = m_rect;
+        return needs_invalidation;
     }
     }
 
 
     Gfx::IntRect m_rect;
     Gfx::IntRect m_rect;