1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 18:18:12 +00:00

WindowServer: Implement simple window shadows

This implements simple window shadows around most windows, including
tooltips. Because this method uses a bitmap for the shadow bits,
it is limited to rectangular window frames. For non-rectangular
window frames we'll need to implement a more sophisticated algorithm.
This commit is contained in:
Tom 2021-02-08 17:27:51 -07:00 committed by Andreas Kling
parent 72fdab7bfb
commit 0ce4b9d7db
14 changed files with 234 additions and 70 deletions

View file

@ -151,7 +151,7 @@ void Compositor::compose()
// Mark window regions as dirty that need to be re-rendered
wm.for_each_visible_window_from_back_to_front([&](Window& window) {
auto frame_rect = window.frame().rect();
auto frame_rect = window.frame().render_rect();
for (auto& dirty_rect : dirty_screen_rects.rects()) {
auto invalidate_rect = dirty_rect.intersected(frame_rect);
if (!invalidate_rect.is_empty()) {
@ -173,12 +173,12 @@ void Compositor::compose()
if (transparency_rects.is_empty())
return IterationDecision::Continue;
auto frame_rect = window.frame().rect();
auto frame_rect = window.frame().render_rect();
auto& dirty_rects = window.dirty_rects();
wm.for_each_visible_window_from_back_to_front([&](Window& w) {
if (&w == &window)
return IterationDecision::Continue;
auto frame_rect2 = w.frame().rect();
auto frame_rect2 = w.frame().render_rect();
if (!frame_rect2.intersects(frame_rect))
return IterationDecision::Continue;
transparency_rects.for_each_intersected(w.dirty_rects(), [&](const Gfx::IntRect& intersected_dirty) {
@ -206,6 +206,9 @@ void Compositor::compose()
auto cursor_rect = current_cursor_rect();
bool need_to_draw_cursor = false;
auto back_painter = *m_back_painter;
auto temp_painter = *m_temp_painter;
auto check_restore_cursor_back = [&](const Gfx::IntRect& rect) {
if (!need_to_draw_cursor && rect.intersects(cursor_rect)) {
// Restore what's behind the cursor if anything touches the area of the cursor
@ -225,26 +228,18 @@ void Compositor::compose()
auto prepare_transparency_rect = [&](const Gfx::IntRect& rect) {
dbgln_if(COMPOSE_DEBUG, " -> flush transparent: {}", rect);
ASSERT(!flush_rects.intersects(rect));
bool have_rect = false;
for (auto& r : flush_transparent_rects.rects()) {
if (r == rect) {
have_rect = true;
break;
}
if (r == rect)
return;
}
if (!have_rect) {
flush_transparent_rects.add(rect);
check_restore_cursor_back(rect);
}
flush_transparent_rects.add(rect);
check_restore_cursor_back(rect);
};
if (!m_cursor_back_bitmap || m_invalidated_cursor)
check_restore_cursor_back(cursor_rect);
auto back_painter = *m_back_painter;
auto temp_painter = *m_temp_painter;
auto paint_wallpaper = [&](Gfx::Painter& painter, const Gfx::IntRect& rect) {
// FIXME: If the wallpaper is opaque and covers the whole rect, no need to fill with color!
painter.fill_rect(rect, background_color);
@ -277,7 +272,7 @@ void Compositor::compose()
});
auto compose_window = [&](Window& window) -> IterationDecision {
auto frame_rect = window.frame().rect();
auto frame_rect = window.frame().render_rect();
if (!frame_rect.intersects(ws.rect()))
return IterationDecision::Continue;
auto frame_rects = frame_rect.shatter(window.rect());
@ -849,7 +844,7 @@ bool Compositor::any_opaque_window_above_this_one_contains_rect(const Window& a_
return IterationDecision::Continue;
if (!window.is_opaque())
return IterationDecision::Continue;
if (window.frame().rect().contains(rect)) {
if (window.frame().render_rect().contains(rect)) {
found_containing_window = true;
return IterationDecision::Break;
}
@ -907,7 +902,7 @@ void Compositor::recompute_occlusions()
Gfx::DisjointRectSet visible_rects(screen_rect);
bool have_transparent = false;
WindowManager::the().for_each_visible_window_from_front_to_back([&](Window& w) {
auto window_frame_rect = w.frame().rect().intersected(screen_rect);
auto window_frame_rect = w.frame().render_rect().intersected(screen_rect);
w.transparency_wallpaper_rects().clear();
auto& visible_opaque = w.opaque_rects();
auto& transparency_rects = w.transparency_rects();
@ -948,7 +943,7 @@ void Compositor::recompute_occlusions()
if (w2.is_minimized())
return IterationDecision::Continue;
auto window_frame_rect2 = w2.frame().rect().intersected(screen_rect);
auto window_frame_rect2 = w2.frame().render_rect().intersected(screen_rect);
auto covering_rect = window_frame_rect2.intersected(window_frame_rect);
if (covering_rect.is_empty())
return IterationDecision::Continue;
@ -1026,7 +1021,7 @@ void Compositor::recompute_occlusions()
// Determine what transparent window areas need to render the wallpaper first
WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& w) {
auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects();
if ((w.is_opaque() && w.frame().is_opaque()) || w.is_minimized()) {
if (w.is_minimized()) {
transparency_wallpaper_rects.clear();
return IterationDecision::Continue;
}
@ -1053,7 +1048,7 @@ void Compositor::recompute_occlusions()
}
wm.for_each_visible_window_from_back_to_front([&](Window& w) {
auto window_frame_rect = w.frame().rect().intersected(screen_rect);
auto window_frame_rect = w.frame().render_rect().intersected(screen_rect);
if (w.is_minimized() || window_frame_rect.is_empty())
return IterationDecision::Continue;