From 2b9ec2257605335ec43aab01e2b7bd8107850f1b Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Fri, 22 Nov 2019 19:13:32 +0300 Subject: [PATCH] WindowServer: Optimize backing store placement for resizing windows When a window is being resized, its size may differ from the size of its backing store. In this case, peek at the direction the window is being resized in, and render the backing store at the same place as it was previously. https://github.com/SerenityOS/serenity/issues/52 --- Servers/WindowServer/WSCompositor.cpp | 60 +++++++++++++++++------- Servers/WindowServer/WSWindowManager.cpp | 7 +++ Servers/WindowServer/WSWindowManager.h | 1 + 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/Servers/WindowServer/WSCompositor.cpp b/Servers/WindowServer/WSCompositor.cpp index 4a9ac744d8..98c16dd5b2 100644 --- a/Servers/WindowServer/WSCompositor.cpp +++ b/Servers/WindowServer/WSCompositor.cpp @@ -151,24 +151,52 @@ void WSCompositor::compose() window.frame().paint(*m_back_painter); if (!backing_store) continue; - Rect dirty_rect_in_window_coordinates = Rect::intersection(dirty_rect, window.rect()); - if (dirty_rect_in_window_coordinates.is_empty()) + + // Decide where we would paint this window's backing store. + // This is subtly different from widow.rect(), because window + // size may be different from its backing store size. This + // happens when the window has been resized and the client + // has not yet attached a new backing store. In this case, + // we want to try to blit the backing store at the same place + // it was previously, and fill the rest of the window with its + // background color. + Rect backing_rect; + backing_rect.set_size(backing_store->size()); + switch (WSWindowManager::the().resize_direction_of_window(window)) { + case ResizeDirection::None: + case ResizeDirection::Right: + case ResizeDirection::Down: + case ResizeDirection::DownRight: + backing_rect.set_location(window.rect().location()); + break; + case ResizeDirection::Left: + case ResizeDirection::Up: + case ResizeDirection::UpLeft: + backing_rect.set_right_without_resize(window.rect().right()); + backing_rect.set_bottom_without_resize(window.rect().bottom()); + break; + case ResizeDirection::UpRight: + backing_rect.set_left(window.rect().left()); + backing_rect.set_bottom_without_resize(window.rect().bottom()); + break; + case ResizeDirection::DownLeft: + backing_rect.set_right_without_resize(window.rect().right()); + backing_rect.set_top(window.rect().top()); + break; + } + + Rect dirty_rect_in_backing_coordinates = dirty_rect + .intersected(window.rect()) + .intersected(backing_rect) + .translated(-backing_rect.location()); + + if (dirty_rect_in_backing_coordinates.is_empty()) continue; - dirty_rect_in_window_coordinates.move_by(-window.position()); - auto dst = window.position(); - dst.move_by(dirty_rect_in_window_coordinates.location()); + auto dst = backing_rect.location().translated(dirty_rect_in_backing_coordinates.location()); - m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity()); - - if (backing_store->width() < window.width()) { - Rect right_fill_rect { window.x() + backing_store->width(), window.y(), window.width() - backing_store->width(), window.height() }; - m_back_painter->fill_rect(right_fill_rect, window.background_color()); - } - - if (backing_store->height() < window.height()) { - Rect bottom_fill_rect { window.x(), window.y() + backing_store->height(), window.width(), window.height() - backing_store->height() }; - m_back_painter->fill_rect(bottom_fill_rect, window.background_color()); - } + m_back_painter->blit(dst, *backing_store, dirty_rect_in_backing_coordinates, window.opacity()); + for (auto background_rect : window.rect().shatter(backing_rect)) + m_back_painter->fill_rect(background_rect, window.background_color()); } return IterationDecision::Continue; }; diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index 1f1a196ae6..a9ca19f2f9 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -1108,6 +1108,13 @@ void WSWindowManager::set_resize_candidate(WSWindow& window, ResizeDirection dir m_resize_direction = direction; } +ResizeDirection WSWindowManager::resize_direction_of_window(const WSWindow& window) +{ + if (&window != m_resize_window) + return ResizeDirection::None; + return m_resize_direction; +} + Rect WSWindowManager::maximized_window_rect(const WSWindow& window) const { Rect rect = WSScreen::the().rect(); diff --git a/Servers/WindowServer/WSWindowManager.h b/Servers/WindowServer/WSWindowManager.h index 64063a8907..3929adf7df 100644 --- a/Servers/WindowServer/WSWindowManager.h +++ b/Servers/WindowServer/WSWindowManager.h @@ -123,6 +123,7 @@ public: void set_resize_candidate(WSWindow&, ResizeDirection); void clear_resize_candidate(); + ResizeDirection resize_direction_of_window(const WSWindow&); bool any_opaque_window_contains_rect(const Rect&); bool any_opaque_window_above_this_one_contains_rect(const WSWindow&, const Rect&);