diff --git a/Services/WindowServer/Button.cpp b/Services/WindowServer/Button.cpp index e87e64a558..7265494b31 100644 --- a/Services/WindowServer/Button.cpp +++ b/Services/WindowServer/Button.cpp @@ -65,7 +65,7 @@ void Button::on_mouse_event(const MouseEvent& event) if (event.type() == Event::MouseDown && event.button() == MouseButton::Left) { m_pressed = true; wm.set_cursor_tracking_button(this); - wm.invalidate(screen_rect()); + m_frame.invalidate(m_relative_rect); return; } @@ -85,7 +85,7 @@ void Button::on_mouse_event(const MouseEvent& event) // However, we don't know that rect yet. We can make an educated // guess which also looks okay even when wrong: m_hovered = false; - wm.invalidate(screen_rect()); + m_frame.invalidate(m_relative_rect); } return; } @@ -95,7 +95,7 @@ void Button::on_mouse_event(const MouseEvent& event) m_hovered = rect().contains(event.position()); wm.set_hovered_button(m_hovered ? this : nullptr); if (old_hovered != m_hovered) - wm.invalidate(screen_rect()); + m_frame.invalidate(m_relative_rect); } if (event.type() == Event::MouseMove && event.buttons() & (unsigned)MouseButton::Left) { @@ -104,7 +104,7 @@ void Button::on_mouse_event(const MouseEvent& event) bool old_pressed = m_pressed; m_pressed = m_hovered; if (old_pressed != m_pressed) - wm.invalidate(screen_rect()); + m_frame.invalidate(m_relative_rect); } } diff --git a/Services/WindowServer/ClientConnection.cpp b/Services/WindowServer/ClientConnection.cpp index 154b7e0c3b..0af1a8f184 100644 --- a/Services/WindowServer/ClientConnection.cpp +++ b/Services/WindowServer/ClientConnection.cpp @@ -584,7 +584,7 @@ OwnPtr ClientConnection:: } if (message.flush_immediately()) - window.invalidate(); + window.invalidate(false); return make(); } diff --git a/Services/WindowServer/Compositor.cpp b/Services/WindowServer/Compositor.cpp index 7041007c26..1d4b095d58 100644 --- a/Services/WindowServer/Compositor.cpp +++ b/Services/WindowServer/Compositor.cpp @@ -32,11 +32,15 @@ #include "Window.h" #include "WindowManager.h" #include +#include #include #include #include #include +//#define COMPOSE_DEBUG +//#define OCCLUSIONS_DEBUG + namespace WindowServer { Compositor& Compositor::the() @@ -96,12 +100,15 @@ void Compositor::init_bitmaps() else m_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, size); + m_temp_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, size); + m_front_painter = make(*m_front_bitmap); m_back_painter = make(*m_back_bitmap); + m_temp_painter = make(*m_temp_bitmap); m_buffers_are_flipped = false; - invalidate(); + invalidate_screen(); } void Compositor::compose() @@ -111,26 +118,64 @@ void Compositor::compose() m_wallpaper_mode = mode_to_enum(wm.config()->read_entry("Background", "Mode", "simple")); auto& ws = Screen::the(); - auto dirty_rects = move(m_dirty_rects); - - if (dirty_rects.size() == 0) { + if (!m_invalidated_any) { // nothing dirtied since the last compose pass. return; } - dirty_rects.add(Gfx::IntRect::intersection(m_last_geometry_label_rect, Screen::the().rect())); - dirty_rects.add(Gfx::IntRect::intersection(m_last_cursor_rect, Screen::the().rect())); - dirty_rects.add(Gfx::IntRect::intersection(m_last_dnd_rect, Screen::the().rect())); - dirty_rects.add(Gfx::IntRect::intersection(current_cursor_rect(), Screen::the().rect())); + if (m_occlusions_dirty) { + m_occlusions_dirty = false; + recompute_occlusions(); + } - auto any_dirty_rect_intersects_window = [&dirty_rects](const Window& window) { - auto window_frame_rect = window.frame().rect(); - for (auto& dirty_rect : dirty_rects.rects()) { - if (dirty_rect.intersects(window_frame_rect)) - return true; + auto dirty_screen_rects = move(m_dirty_screen_rects); + dirty_screen_rects.add(m_last_geometry_label_rect.intersected(ws.rect())); + dirty_screen_rects.add(m_last_dnd_rect.intersected(ws.rect())); + if (m_invalidated_cursor) { + if (wm.dnd_client()) + dirty_screen_rects.add(wm.dnd_rect().intersected(ws.rect())); + } + + // 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(); + for (auto& dirty_rect : dirty_screen_rects.rects()) { + auto invalidate_rect = dirty_rect.intersected(frame_rect); + if (!invalidate_rect.is_empty()) { + auto inner_rect_offset = window.rect().location() - frame_rect.location(); + invalidate_rect.move_by(-(frame_rect.location() + inner_rect_offset)); + window.invalidate_no_notify(invalidate_rect); + m_invalidated_window = true; + } } - return false; - }; + window.prepare_dirty_rects(); + return IterationDecision::Continue; + }); + + // Any windows above or below a given window that need to be re-rendered + // also require us to re-render that window's intersecting area, regardless + // of whether that window has any dirty rectangles + wm.for_each_visible_window_from_back_to_front([&](Window& window) { + auto& transparency_rects = window.transparency_rects(); + if (transparency_rects.is_empty()) + return IterationDecision::Continue; + + auto frame_rect = window.frame().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(); + if (!frame_rect2.intersects(frame_rect)) + return IterationDecision::Continue; + transparency_rects.for_each_intersected(w.dirty_rects(), [&](const Gfx::IntRect& intersected_dirty) { + dirty_rects.add(intersected_dirty); + return IterationDecision::Continue; + }); + return IterationDecision::Continue; + }); + return IterationDecision::Continue; + }); Color background_color = wm.palette().desktop_background(); String background_color_entry = wm.config()->read_entry("Background", "Color", ""); @@ -138,50 +183,127 @@ void Compositor::compose() background_color = Color::from_string(background_color_entry).value_or(background_color); } - // Paint the wallpaper. - for (auto& dirty_rect : dirty_rects.rects()) { - if (any_opaque_window_contains_rect(dirty_rect)) - continue; +#ifdef COMPOSE_DEBUG + dbg() << "COMPOSE: invalidated: window:" << m_invalidated_window << " cursor:" << m_invalidated_cursor << " any: " << m_invalidated_any; + for (auto& r : dirty_screen_rects.rects()) + dbg() << "dirty screen: " << r; +#endif + Gfx::DisjointRectSet flush_rects; + Gfx::DisjointRectSet flush_transparent_rects; + Gfx::DisjointRectSet flush_special_rects; + auto cursor_rect = current_cursor_rect(); + bool need_to_draw_cursor = false; + + 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 + need_to_draw_cursor = true; + restore_cursor_back(); + } + }; + + auto prepare_rect = [&](const Gfx::IntRect& rect) { +#ifdef COMPOSE_DEBUG + dbg() << " -> flush opaque: " << rect; +#endif + ASSERT(!flush_rects.intersects(rect)); + ASSERT(!flush_transparent_rects.intersects(rect)); + flush_rects.add(rect); + check_restore_cursor_back(rect); + }; + + auto prepare_transparency_rect = [&](const Gfx::IntRect& rect) { + // This function may be called multiple times with the same + // rect as we walk the window stack from back to front. However, + // there should be no overlaps with flush_rects +#ifdef COMPOSE_DEBUG + dbg() << " -> flush transparent: " << rect; +#endif + ASSERT(!flush_rects.intersects(rect)); + bool have_rect = false; + for (auto& r : flush_transparent_rects.rects()) { + if (r == rect) { + have_rect = true; + break; + } + } + + if (!have_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, no need to fill with color! - m_back_painter->fill_rect(dirty_rect, background_color); + painter.fill_rect(rect, background_color); if (m_wallpaper) { if (m_wallpaper_mode == WallpaperMode::Simple) { - m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect); + painter.blit(rect.location(), *m_wallpaper, rect); } else if (m_wallpaper_mode == WallpaperMode::Center) { Gfx::IntPoint offset { ws.size().width() / 2 - m_wallpaper->size().width() / 2, ws.size().height() / 2 - m_wallpaper->size().height() / 2 }; - m_back_painter->blit_offset(dirty_rect.location(), *m_wallpaper, - dirty_rect, offset); + painter.blit_offset(rect.location(), *m_wallpaper, + rect, offset); } else if (m_wallpaper_mode == WallpaperMode::Tile) { - m_back_painter->draw_tiled_bitmap(dirty_rect, *m_wallpaper); + painter.draw_tiled_bitmap(rect, *m_wallpaper); } else if (m_wallpaper_mode == WallpaperMode::Scaled) { float hscale = (float)m_wallpaper->size().width() / (float)ws.size().width(); float vscale = (float)m_wallpaper->size().height() / (float)ws.size().height(); - m_back_painter->blit_scaled(dirty_rect, *m_wallpaper, dirty_rect, hscale, vscale); + // TODO: this may look ugly, we should scale to a backing bitmap and then blit + painter.blit_scaled(rect, *m_wallpaper, rect, hscale, vscale); } else { ASSERT_NOT_REACHED(); } } - } + }; + + m_opaque_wallpaper_rects.for_each_intersected(dirty_screen_rects, [&](const Gfx::IntRect& render_rect) { +#ifdef COMPOSE_DEBUG + dbg() << " render wallpaper opaque: " << render_rect; +#endif + prepare_rect(render_rect); + paint_wallpaper(back_painter, render_rect); + return IterationDecision::Continue; + }); auto compose_window = [&](Window& window) -> IterationDecision { - if (!any_dirty_rect_intersects_window(window)) + auto frame_rect = window.frame().rect(); + if (!frame_rect.intersects(ws.rect())) return IterationDecision::Continue; - Gfx::PainterStateSaver saver(*m_back_painter); - m_back_painter->add_clip_rect(window.frame().rect()); + auto frame_rects = frame_rect.shatter(window.rect()); + +#ifdef COMPOSE_DEBUG + dbg() << " window " << window.title() << " frame rect: " << frame_rect; +#endif + RefPtr backing_store = window.backing_store(); - for (auto& dirty_rect : dirty_rects.rects()) { - if (!window.is_fullscreen() && any_opaque_window_above_this_one_contains_rect(window, dirty_rect)) - continue; - Gfx::PainterStateSaver saver(*m_back_painter); - m_back_painter->add_clip_rect(dirty_rect); - if (!backing_store) - m_back_painter->fill_rect(dirty_rect, wm.palette().window()); - if (!window.is_fullscreen()) - window.frame().paint(*m_back_painter); - if (!backing_store) - continue; + auto compose_window_rect = [&](Gfx::Painter& painter, const Gfx::IntRect& rect) { + if (!window.is_fullscreen()) { + rect.for_each_intersected(frame_rects, [&](const Gfx::IntRect& intersected_rect) { + // TODO: Should optimize this to use a backing buffer + Gfx::PainterStateSaver saver(painter); + painter.add_clip_rect(intersected_rect); +#ifdef COMPOSE_DEBUG + dbg() << " render frame: " << intersected_rect; +#endif + window.frame().paint(painter); + return IterationDecision::Continue; + }); + } + + if (!backing_store) { + if (window.is_opaque()) + painter.fill_rect(window.rect().intersected(rect), wm.palette().window()); + return; + } // Decide where we would paint this window's backing store. // This is subtly different from widow.rect(), because window @@ -216,54 +338,178 @@ void Compositor::compose() break; } - Gfx::IntRect dirty_rect_in_backing_coordinates = dirty_rect - .intersected(window.rect()) + Gfx::IntRect dirty_rect_in_backing_coordinates = rect.intersected(window.rect()) .intersected(backing_rect) .translated(-backing_rect.location()); if (dirty_rect_in_backing_coordinates.is_empty()) - continue; + return; auto dst = backing_rect.location().translated(dirty_rect_in_backing_coordinates.location()); if (window.client() && window.client()->is_unresponsive()) { - m_back_painter->blit_filtered(dst, *backing_store, dirty_rect_in_backing_coordinates, [](Color src) { + painter.blit_filtered(dst, *backing_store, dirty_rect_in_backing_coordinates, [](Color src) { return src.to_grayscale().darkened(0.75f); }); } else { - m_back_painter->blit(dst, *backing_store, dirty_rect_in_backing_coordinates, window.opacity()); + 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, wm.palette().window()); + painter.fill_rect(background_rect, wm.palette().window()); + }; + + auto& dirty_rects = window.dirty_rects(); +#ifdef COMPOSE_DEBUG + for (auto& dirty_rect : dirty_rects.rects()) + dbg() << " dirty: " << dirty_rect; + for (auto& r : window.opaque_rects().rects()) + dbg() << " opaque: " << r; + for (auto& r : window.transparency_rects().rects()) + dbg() << " transparent: " << r; +#endif + + // Render opaque portions directly to the back buffer + auto& opaque_rects = window.opaque_rects(); + if (!opaque_rects.is_empty()) { + opaque_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) { +#ifdef COMPOSE_DEBUG + dbg() << " render opaque: " << render_rect; +#endif + prepare_rect(render_rect); + Gfx::PainterStateSaver saver(back_painter); + back_painter.add_clip_rect(render_rect); + compose_window_rect(back_painter, render_rect); + return IterationDecision::Continue; + }); + } + + // Render the wallpaper for any transparency directly covering + // the wallpaper + auto& transparency_wallpaper_rects = window.transparency_wallpaper_rects(); + if (!transparency_wallpaper_rects.is_empty()) { + transparency_wallpaper_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) { +#ifdef COMPOSE_DEBUG + dbg() << " render wallpaper: " << render_rect; +#endif + prepare_transparency_rect(render_rect); + paint_wallpaper(temp_painter, render_rect); + return IterationDecision::Continue; + }); + } + auto& transparency_rects = window.transparency_rects(); + if (!transparency_rects.is_empty()) { + transparency_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) { +#ifdef COMPOSE_DEBUG + dbg() << " render transparent: " << render_rect; +#endif + prepare_transparency_rect(render_rect); + Gfx::PainterStateSaver saver(temp_painter); + temp_painter.add_clip_rect(render_rect); + compose_window_rect(temp_painter, render_rect); + return IterationDecision::Continue; + }); } return IterationDecision::Continue; }; // Paint the window stack. - if (auto* fullscreen_window = wm.active_fullscreen_window()) { - compose_window(*fullscreen_window); - } else { - wm.for_each_visible_window_from_back_to_front([&](Window& window) { - return compose_window(window); - }); + if (m_invalidated_window) { + if (auto* fullscreen_window = wm.active_fullscreen_window()) { + compose_window(*fullscreen_window); + } else { + wm.for_each_visible_window_from_back_to_front([&](Window& window) { + compose_window(window); + window.clear_dirty_rects(); + return IterationDecision::Continue; + }); + } - draw_geometry_label(); + // Check that there are no overlapping transparent and opaque flush rectangles + ASSERT(![&]() { + for (auto& rect_transparent : flush_transparent_rects.rects()) { + for (auto& rect_opaque : flush_rects.rects()) { + if (rect_opaque.intersects(rect_transparent)) { + dbg() << "Transparent rect " << rect_transparent << " overlaps opaque rect: " << rect_opaque << ": " << rect_opaque.intersected(rect_transparent); + return true; + } + } + } + return false; + }()); + + // Copy anything rendered to the temporary buffer to the back buffer + for (auto& rect : flush_transparent_rects.rects()) + back_painter.blit(rect.location(), *m_temp_bitmap, rect); + + Gfx::IntRect geometry_label_rect; + if (draw_geometry_label(geometry_label_rect)) + flush_special_rects.add(geometry_label_rect); } - run_animations(); + m_invalidated_any = false; + m_invalidated_window = false; + m_invalidated_cursor = false; - draw_cursor(); + if (wm.dnd_client()) { + auto dnd_rect = wm.dnd_rect(); + + // TODO: render once into a backing bitmap, then just blit... + auto render_dnd = [&]() { + back_painter.fill_rect(dnd_rect, wm.palette().selection().with_alpha(200)); + if (!wm.dnd_text().is_empty()) { + auto text_rect = dnd_rect; + if (wm.dnd_bitmap()) + text_rect.move_by(wm.dnd_bitmap()->width(), 0); + back_painter.draw_text(text_rect, wm.dnd_text(), Gfx::TextAlignment::CenterLeft, wm.palette().selection_text()); + } + if (wm.dnd_bitmap()) { + back_painter.blit(dnd_rect.top_left(), *wm.dnd_bitmap(), wm.dnd_bitmap()->rect()); + } + }; + + dirty_screen_rects.for_each_intersected(dnd_rect, [&](const Gfx::IntRect& render_rect) { + Gfx::PainterStateSaver saver(back_painter); + back_painter.add_clip_rect(render_rect); + render_dnd(); + return IterationDecision::Continue; + }); + flush_transparent_rects.for_each_intersected(dnd_rect, [&](const Gfx::IntRect& render_rect) { + Gfx::PainterStateSaver saver(back_painter); + back_painter.add_clip_rect(render_rect); + render_dnd(); + return IterationDecision::Continue; + }); + m_last_dnd_rect = dnd_rect; + } else { + if (!m_last_dnd_rect.is_empty()) { + invalidate_screen(m_last_dnd_rect); + m_last_dnd_rect = {}; + } + } + + run_animations(flush_special_rects); + + if (need_to_draw_cursor) { + flush_rects.add(cursor_rect); + if (cursor_rect != m_last_cursor_rect) + flush_rects.add(m_last_cursor_rect); + draw_cursor(cursor_rect); + } if (m_flash_flush) { - for (auto& rect : dirty_rects.rects()) + for (auto& rect : flush_rects.rects()) m_front_painter->fill_rect(rect, Color::Yellow); } if (m_screen_can_set_buffer) flip_buffers(); - for (auto& r : dirty_rects.rects()) - flush(r); + for (auto& rect : flush_rects.rects()) + flush(rect); + for (auto& rect : flush_transparent_rects.rects()) + flush(rect); + for (auto& rect : flush_special_rects.rects()) + flush(rect); } void Compositor::flush(const Gfx::IntRect& a_rect) @@ -301,20 +547,35 @@ void Compositor::flush(const Gfx::IntRect& a_rect) } } -void Compositor::invalidate() +void Compositor::invalidate_screen() { - m_dirty_rects.clear_with_capacity(); - invalidate(Screen::the().rect()); + invalidate_screen(Screen::the().rect()); } -void Compositor::invalidate(const Gfx::IntRect& a_rect) +void Compositor::invalidate_screen(const Gfx::IntRect& screen_rect) { - auto rect = Gfx::IntRect::intersection(a_rect, Screen::the().rect()); - if (rect.is_empty()) + m_dirty_screen_rects.add(screen_rect.intersected(Screen::the().rect())); + + if (m_invalidated_any) return; - m_dirty_rects.add(rect); + m_invalidated_any = true; + m_invalidated_window = true; + start_compose_async_timer(); +} +void Compositor::invalidate_window() +{ + if (m_invalidated_window) + return; + m_invalidated_window = true; + m_invalidated_any = true; + + start_compose_async_timer(); +} + +void Compositor::start_compose_async_timer() +{ // We delay composition by a timer interval, but to not affect latency too // much, if a pending compose is not already scheduled, we also schedule an // immediate compose the next spin of the event loop. @@ -331,7 +592,7 @@ bool Compositor::set_background_color(const String& background_color) bool ret_val = wm.config()->sync(); if (ret_val) - Compositor::invalidate(); + Compositor::invalidate_screen(); return ret_val; } @@ -344,7 +605,7 @@ bool Compositor::set_wallpaper_mode(const String& mode) if (ret_val) { m_wallpaper_mode = mode_to_enum(mode); - Compositor::invalidate(); + Compositor::invalidate_screen(); } return ret_val; @@ -360,7 +621,7 @@ bool Compositor::set_wallpaper(const String& path, Function&& callba [this, path, callback = move(callback)](RefPtr bitmap) { m_wallpaper_path = path; m_wallpaper = move(bitmap); - invalidate(); + invalidate_screen(); callback(true); }); return true; @@ -375,7 +636,7 @@ void Compositor::flip_buffers() m_buffers_are_flipped = !m_buffers_are_flipped; } -void Compositor::run_animations() +void Compositor::run_animations(Gfx::DisjointRectSet& flush_rects) { static const int minimize_animation_steps = 10; @@ -403,12 +664,12 @@ void Compositor::run_animations() #endif m_back_painter->draw_rect(rect, Color::White); + flush_rects.add(rect); + invalidate_screen(rect); window.step_minimize_animation(); if (window.minimize_animation_index() >= minimize_animation_steps) window.end_minimize_animation(); - - invalidate(rect); } return IterationDecision::Continue; }); @@ -427,6 +688,7 @@ bool Compositor::set_resolution(int desired_width, int desired_height) } bool success = Screen::the().set_resolution(desired_width, desired_height); init_bitmaps(); + invalidate_occlusions(); compose(); return success; } @@ -439,19 +701,21 @@ Gfx::IntRect Compositor::current_cursor_rect() const void Compositor::invalidate_cursor() { - auto& wm = WindowManager::the(); - if (wm.dnd_client()) - invalidate(wm.dnd_rect()); - invalidate(current_cursor_rect()); + if (m_invalidated_cursor) + return; + m_invalidated_cursor = true; + m_invalidated_any = true; + + start_compose_async_timer(); } -void Compositor::draw_geometry_label() +bool Compositor::draw_geometry_label(Gfx::IntRect& geometry_label_rect) { auto& wm = WindowManager::the(); auto* window_being_moved_or_resized = wm.m_move_window ? wm.m_move_window.ptr() : (wm.m_resize_window ? wm.m_resize_window.ptr() : nullptr); if (!window_being_moved_or_resized) { m_last_geometry_label_rect = {}; - return; + return false; } auto geometry_string = window_being_moved_or_resized->rect().to_string(); if (!window_being_moved_or_resized->size_increment().is_null()) { @@ -459,39 +723,40 @@ void Compositor::draw_geometry_label() int height_steps = (window_being_moved_or_resized->height() - window_being_moved_or_resized->base_size().height()) / window_being_moved_or_resized->size_increment().height(); geometry_string = String::format("%s (%dx%d)", geometry_string.characters(), width_steps, height_steps); } - auto geometry_label_rect = Gfx::IntRect { 0, 0, wm.font().width(geometry_string) + 16, wm.font().glyph_height() + 10 }; + geometry_label_rect = Gfx::IntRect { 0, 0, wm.font().width(geometry_string) + 16, wm.font().glyph_height() + 10 }; geometry_label_rect.center_within(window_being_moved_or_resized->rect()); - m_back_painter->fill_rect(geometry_label_rect, wm.palette().window()); - m_back_painter->draw_rect(geometry_label_rect, wm.palette().threed_shadow2()); - m_back_painter->draw_text(geometry_label_rect, geometry_string, Gfx::TextAlignment::Center, wm.palette().window_text()); + auto& back_painter = *m_back_painter; + back_painter.fill_rect(geometry_label_rect, wm.palette().window()); + back_painter.draw_rect(geometry_label_rect, wm.palette().threed_shadow2()); + back_painter.draw_text(geometry_label_rect, geometry_string, Gfx::TextAlignment::Center, wm.palette().window_text()); m_last_geometry_label_rect = geometry_label_rect; + return true; } -void Compositor::draw_cursor() +void Compositor::draw_cursor(const Gfx::IntRect& cursor_rect) { auto& wm = WindowManager::the(); - Gfx::IntRect cursor_rect = current_cursor_rect(); - m_back_painter->blit(cursor_rect.location(), wm.active_cursor().bitmap(), wm.active_cursor().rect()); - - if (wm.dnd_client()) { - auto dnd_rect = wm.dnd_rect(); - m_back_painter->fill_rect(dnd_rect, wm.palette().selection().with_alpha(200)); - if (!wm.dnd_text().is_empty()) { - auto text_rect = dnd_rect; - if (wm.dnd_bitmap()) - text_rect.move_by(wm.dnd_bitmap()->width(), 0); - m_back_painter->draw_text(text_rect, wm.dnd_text(), Gfx::TextAlignment::CenterLeft, wm.palette().selection_text()); - } - if (wm.dnd_bitmap()) { - m_back_painter->blit(dnd_rect.top_left(), *wm.dnd_bitmap(), wm.dnd_bitmap()->rect()); - } - m_last_dnd_rect = dnd_rect; - } else { - m_last_dnd_rect = {}; + + if (!m_cursor_back_bitmap || m_cursor_back_bitmap->size() != cursor_rect.size()) { + m_cursor_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, cursor_rect.size()); + m_cursor_back_painter = make(*m_cursor_back_bitmap); } + + m_cursor_back_painter->blit({0, 0}, *m_back_bitmap, wm.active_cursor().rect().translated(cursor_rect.location()).intersected(Screen::the().rect())); + auto& back_painter = *m_back_painter; + back_painter.blit(cursor_rect.location(), wm.active_cursor().bitmap(), wm.active_cursor().rect()); + m_last_cursor_rect = cursor_rect; } +void Compositor::restore_cursor_back() +{ + if (!m_cursor_back_bitmap) + return; + + m_back_painter->blit(m_last_cursor_rect.location().constrained(Screen::the().rect()), *m_cursor_back_bitmap, { { 0, 0 }, m_last_cursor_rect.intersected(Screen::the().rect()).size() }); +} + void Compositor::notify_display_links() { ClientConnection::for_each_client([](auto& client) { @@ -514,28 +779,6 @@ void Compositor::decrement_display_link_count(Badge) m_display_link_notify_timer->stop(); } -bool Compositor::any_opaque_window_contains_rect(const Gfx::IntRect& rect) -{ - bool found_containing_window = false; - WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& window) { - if (window.is_minimized()) - return IterationDecision::Continue; - if (window.opacity() < 1.0f) - return IterationDecision::Continue; - if (window.has_alpha_channel()) { - // FIXME: Just because the window has an alpha channel doesn't mean it's not opaque. - // Maybe there's some way we could know this? - return IterationDecision::Continue; - } - if (window.frame().rect().contains(rect)) { - found_containing_window = true; - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); - return found_containing_window; -}; - bool Compositor::any_opaque_window_above_this_one_contains_rect(const Window& a_window, const Gfx::IntRect& rect) { bool found_containing_window = false; @@ -551,9 +794,7 @@ bool Compositor::any_opaque_window_above_this_one_contains_rect(const Window& a_ return IterationDecision::Continue; if (window.is_minimized()) return IterationDecision::Continue; - if (window.opacity() < 1.0f) - return IterationDecision::Continue; - if (window.has_alpha_channel()) + if (!window.is_opaque()) return IterationDecision::Continue; if (window.frame().rect().contains(rect)) { found_containing_window = true; @@ -578,6 +819,169 @@ void Compositor::recompute_occlusions() } return IterationDecision::Continue; }); + +#ifdef OCCLUSIONS_DEBUG + dbg() << "OCCLUSIONS:"; +#endif + + auto screen_rect = Screen::the().rect(); + + if (auto* fullscreen_window = wm.active_fullscreen_window()) { + WindowManager::the().for_each_visible_window_from_front_to_back([&](Window& w) { + auto& visible_opaque = w.opaque_rects(); + auto& transparency_rects = w.transparency_rects(); + auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects(); + if (&w == fullscreen_window) { + if (w.is_opaque()) { + visible_opaque = screen_rect; + transparency_rects.clear(); + transparency_wallpaper_rects.clear(); + } else { + visible_opaque.clear(); + transparency_rects = screen_rect; + transparency_wallpaper_rects = screen_rect; + } + } else { + visible_opaque.clear(); + transparency_rects.clear(); + transparency_wallpaper_rects.clear(); + } + return IterationDecision::Continue; + }); + + m_opaque_wallpaper_rects.clear(); + } else { + 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); + w.transparency_wallpaper_rects().clear(); + auto& visible_opaque = w.opaque_rects(); + auto& transparency_rects = w.transparency_rects(); + if (w.is_minimized() || window_frame_rect.is_empty()) { + visible_opaque.clear(); + transparency_rects.clear(); + return IterationDecision::Continue; + } + + Gfx::DisjointRectSet opaque_covering; + if (w.is_opaque()) { + visible_opaque = visible_rects.intersected(window_frame_rect); + transparency_rects.clear(); + } else { + visible_opaque.clear(); + transparency_rects = visible_rects.intersected(window_frame_rect); + } + + bool found_this_window = false; + WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& w2) { + if (!found_this_window) { + if (&w == &w2) + found_this_window = true; + return IterationDecision::Continue; + } + + if (w2.is_minimized()) + return IterationDecision::Continue; + auto window_frame_rect2 = w2.frame().rect().intersected(screen_rect); + auto covering_rect = window_frame_rect2.intersected(window_frame_rect); + if (covering_rect.is_empty()) + return IterationDecision::Continue; + + if (w2.is_opaque()) { + opaque_covering.add(covering_rect); + if (opaque_covering.contains(window_frame_rect)) { + // This window is entirely covered by another opaque window + visible_opaque.clear(); + transparency_rects.clear(); + return IterationDecision::Break; + } + + if (!visible_opaque.is_empty()) { + auto uncovered_opaque = visible_opaque.shatter(covering_rect); + visible_opaque = move(uncovered_opaque); + } + + if (!transparency_rects.is_empty()) { + auto uncovered_transparency = transparency_rects.shatter(covering_rect); + transparency_rects = move(uncovered_transparency); + } + } else { + visible_rects.for_each_intersected(covering_rect, [&](const Gfx::IntRect& intersected) { + transparency_rects.add(intersected); + if (!visible_opaque.is_empty()) { + auto uncovered_opaque = visible_opaque.shatter(intersected); + visible_opaque = move(uncovered_opaque); + } + return IterationDecision::Continue; + }); + } + + return IterationDecision::Continue; + }); + + if (!transparency_rects.is_empty()) + have_transparent = true; + + ASSERT(!visible_opaque.intersects(transparency_rects)); + + if (w.is_opaque()) { + // Determine visible area for the window below + auto visible_rects_below_window = visible_rects.shatter(window_frame_rect); + visible_rects = move(visible_rects_below_window); + } + return IterationDecision::Continue; + }); + + if (have_transparent) { + // 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.is_minimized()) { + transparency_wallpaper_rects.clear(); + return IterationDecision::Continue; + } + Gfx::DisjointRectSet& transparency_rects = w.transparency_rects(); + if (transparency_rects.is_empty()) { + transparency_wallpaper_rects.clear(); + return IterationDecision::Continue; + } + + transparency_wallpaper_rects = visible_rects.intersected(transparency_rects); + + auto remaining_visible = visible_rects.shatter(transparency_wallpaper_rects); + visible_rects = move(remaining_visible); + return IterationDecision::Continue; + }); + } + + m_opaque_wallpaper_rects = move(visible_rects); + } + +#ifdef OCCLUSIONS_DEBUG + for (auto& r : m_opaque_wallpaper_rects.rects()) + dbg() << " wallpaper opaque: " << r; +#endif + + wm.for_each_visible_window_from_back_to_front([&](Window& w) { + auto window_frame_rect = w.frame().rect().intersected(screen_rect); + if (w.is_minimized() || window_frame_rect.is_empty()) + return IterationDecision::Continue; + +#ifdef OCCLUSIONS_DEBUG + dbg() << " Window " << w.title() << " frame rect: " << window_frame_rect; + for (auto& r : w.opaque_rects().rects()) + dbg() << " opaque: " << r; + for (auto& r : w.transparency_wallpaper_rects().rects()) + dbg() << " transparent wallpaper: " << r; + for (auto& r : w.transparency_rects().rects()) + dbg() << " transparent: " << r; +#endif + ASSERT(!w.opaque_rects().intersects(m_opaque_wallpaper_rects)); + ASSERT(!w.transparency_rects().intersects(m_opaque_wallpaper_rects)); + ASSERT(!w.transparency_wallpaper_rects().intersects(m_opaque_wallpaper_rects)); + return IterationDecision::Continue; + }); } } diff --git a/Services/WindowServer/Compositor.h b/Services/WindowServer/Compositor.h index 50a06ff8b4..f5a41dcbd2 100644 --- a/Services/WindowServer/Compositor.h +++ b/Services/WindowServer/Compositor.h @@ -52,8 +52,9 @@ public: static Compositor& the(); void compose(); - void invalidate(); - void invalidate(const Gfx::IntRect&); + void invalidate_window(); + void invalidate_screen(); + void invalidate_screen(const Gfx::IntRect&); bool set_resolution(int desired_width, int desired_height); @@ -70,34 +71,45 @@ public: void increment_display_link_count(Badge); void decrement_display_link_count(Badge); - void recompute_occlusions(); + void invalidate_occlusions() { m_occlusions_dirty = true; } private: Compositor(); void init_bitmaps(); void flip_buffers(); void flush(const Gfx::IntRect&); - void draw_cursor(); - void draw_geometry_label(); void draw_menubar(); - void run_animations(); + void run_animations(Gfx::DisjointRectSet&); void notify_display_links(); - bool any_opaque_window_contains_rect(const Gfx::IntRect&); + void start_compose_async_timer(); + void recompute_occlusions(); bool any_opaque_window_above_this_one_contains_rect(const Window&, const Gfx::IntRect&); + void draw_cursor(const Gfx::IntRect&); + void restore_cursor_back(); + bool draw_geometry_label(Gfx::IntRect&); RefPtr m_compose_timer; RefPtr m_immediate_compose_timer; bool m_flash_flush { false }; bool m_buffers_are_flipped { false }; bool m_screen_can_set_buffer { false }; + bool m_occlusions_dirty { true }; + bool m_invalidated_any { true }; + bool m_invalidated_window { false }; + bool m_invalidated_cursor { false }; RefPtr m_front_bitmap; RefPtr m_back_bitmap; + RefPtr m_temp_bitmap; OwnPtr m_back_painter; OwnPtr m_front_painter; + OwnPtr m_temp_painter; - Gfx::DisjointRectSet m_dirty_rects; + Gfx::DisjointRectSet m_dirty_screen_rects; + Gfx::DisjointRectSet m_opaque_wallpaper_rects; + RefPtr m_cursor_back_bitmap; + OwnPtr m_cursor_back_painter; Gfx::IntRect m_last_cursor_rect; Gfx::IntRect m_last_dnd_rect; Gfx::IntRect m_last_geometry_label_rect; diff --git a/Services/WindowServer/Window.cpp b/Services/WindowServer/Window.cpp index fdeb542e42..8617af6b41 100644 --- a/Services/WindowServer/Window.cpp +++ b/Services/WindowServer/Window.cpp @@ -129,7 +129,7 @@ Window::~Window() void Window::destroy() { m_destroyed = true; - invalidate(); + set_visible(false); } void Window::set_title(const String& title) @@ -137,21 +137,23 @@ void Window::set_title(const String& title) if (m_title == title) return; m_title = title; + frame().invalidate_title_bar(); WindowManager::the().notify_title_changed(*this); } void Window::set_rect(const Gfx::IntRect& rect) { ASSERT(!rect.is_empty()); - Gfx::IntRect old_rect; if (m_rect == rect) return; - old_rect = m_rect; + auto old_rect = m_rect; m_rect = rect; if (!m_client && (!m_backing_store || old_rect.size() != rect.size())) { m_backing_store = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, m_rect.size()); } - m_frame.notify_window_rect_changed(old_rect, rect); + + invalidate(true); + m_frame.notify_window_rect_changed(old_rect, rect); // recomputes occlusions } void Window::set_rect_without_repaint(const Gfx::IntRect& rect) @@ -170,7 +172,8 @@ void Window::set_rect_without_repaint(const Gfx::IntRect& rect) } } - m_frame.notify_window_rect_changed(old_rect, rect); + invalidate(true); + m_frame.notify_window_rect_changed(old_rect, rect); // recomputes occlusions } void Window::handle_mouse_event(const MouseEvent& event) @@ -222,11 +225,12 @@ void Window::set_minimized(bool minimized) return; m_minimized = minimized; update_menu_item_text(PopupMenuItem::Minimize); + Compositor::the().invalidate_occlusions(); + Compositor::the().invalidate_screen(frame().rect()); if (!is_blocked_by_modal_window()) start_minimize_animation(); if (!minimized) request_update({ {}, size() }); - invalidate(); WindowManager::the().notify_minimization_state_changed(*this); } @@ -243,7 +247,11 @@ void Window::set_opacity(float opacity) { if (m_opacity == opacity) return; + bool was_opaque = is_opaque(); m_opacity = opacity; + if (was_opaque != is_opaque()) + Compositor::the().invalidate_occlusions(); + Compositor::the().invalidate_screen(frame().rect()); WindowManager::the().notify_opacity_changed(*this); } @@ -359,12 +367,21 @@ void Window::set_visible(bool b) if (m_visible == b) return; m_visible = b; - invalidate(); + + Compositor::the().invalidate_occlusions(); + if (m_visible) + invalidate(true); + else + Compositor::the().invalidate_screen(frame().rect()); } -void Window::invalidate() +void Window::invalidate(bool invalidate_frame) { - Compositor::the().invalidate(frame().rect()); + m_invalidated = true; + m_invalidated_all = true; + m_invalidated_frame |= invalidate_frame; + m_dirty_rects.clear(); + Compositor::the().invalidate_window(); } void Window::invalidate(const Gfx::IntRect& rect) @@ -374,16 +391,46 @@ void Window::invalidate(const Gfx::IntRect& rect) return; } - if (rect.is_empty()) { - invalidate(); - return; - } + if (invalidate_no_notify(rect)) + Compositor::the().invalidate_window(); +} + +bool Window::invalidate_no_notify(const Gfx::IntRect& rect) +{ + if (m_invalidated_all || rect.is_empty()) + return false; + auto outer_rect = frame().rect(); auto inner_rect = rect; inner_rect.move_by(position()); // FIXME: This seems slightly wrong; the inner rect shouldn't intersect the border part of the outer rect. inner_rect.intersect(outer_rect); - Compositor::the().invalidate(inner_rect); + if (inner_rect.is_empty()) + return false; + + m_invalidated = true; + m_dirty_rects.add(inner_rect.translated(-outer_rect.location())); + return true; +} + +void Window::prepare_dirty_rects() +{ + if (m_invalidated_all) { + if (m_invalidated_frame) + m_dirty_rects = frame().rect(); + else + m_dirty_rects = rect(); + } else { + m_dirty_rects.move_by(frame().rect().location()); + } +} + +void Window::clear_dirty_rects() +{ + m_invalidated_all = false; + m_invalidated_frame = false; + m_invalidated = false; + m_dirty_rects.clear_with_capacity(); } bool Window::is_active() const @@ -414,6 +461,8 @@ void Window::set_default_icon() void Window::request_update(const Gfx::IntRect& rect, bool ignore_occlusion) { + if (rect.is_empty()) + return; if (m_pending_paint_rects.is_empty()) { deferred_invoke([this, ignore_occlusion](auto&) { client()->post_paint_message(*this, ignore_occlusion); @@ -511,6 +560,7 @@ void Window::set_fullscreen(bool fullscreen) } else if (!m_saved_nonfullscreen_rect.is_empty()) { new_window_rect = m_saved_nonfullscreen_rect; } + Core::EventLoop::current().post_event(*this, make(m_rect, new_window_rect)); set_rect(new_window_rect); } diff --git a/Services/WindowServer/Window.h b/Services/WindowServer/Window.h index 5e0d582dd7..5a92d8453f 100644 --- a/Services/WindowServer/Window.h +++ b/Services/WindowServer/Window.h @@ -167,8 +167,13 @@ public: Gfx::IntSize size() const { return m_rect.size(); } - void invalidate(); + void invalidate(bool with_frame = true); void invalidate(const Gfx::IntRect&); + bool invalidate_no_notify(const Gfx::IntRect& rect); + + void prepare_dirty_rects(); + void clear_dirty_rects(); + Gfx::DisjointRectSet& dirty_rects() { return m_dirty_rects; } virtual void event(Core::Event&) override; @@ -262,6 +267,21 @@ public: bool default_positioned() const { return m_default_positioned; } void set_default_positioned(bool p) { m_default_positioned = p; } + bool is_invalidated() const { return m_invalidated; } + + bool is_opaque() const + { + if (opacity() < 1.0f) + return false; + if (has_alpha_channel()) + return false; + return true; + } + + Gfx::DisjointRectSet& opaque_rects() { return m_opaque_rects; } + Gfx::DisjointRectSet& transparency_rects() { return m_transparency_rects; } + Gfx::DisjointRectSet& transparency_wallpaper_rects() { return m_transparency_wallpaper_rects; } + private: void handle_mouse_event(const MouseEvent&); void update_menu_item_text(PopupMenuItem item); @@ -281,6 +301,10 @@ private: Gfx::IntRect m_rect; Gfx::IntRect m_saved_nonfullscreen_rect; Gfx::IntRect m_taskbar_rect; + Gfx::DisjointRectSet m_dirty_rects; + Gfx::DisjointRectSet m_opaque_rects; + Gfx::DisjointRectSet m_transparency_rects; + Gfx::DisjointRectSet m_transparency_wallpaper_rects; WindowType m_type { WindowType::Normal }; bool m_global_cursor_tracking_enabled { false }; bool m_automatic_cursor_tracking_enabled { false }; @@ -297,6 +321,9 @@ private: bool m_accessory { false }; bool m_destroyed { false }; bool m_default_positioned { false }; + bool m_invalidated { true }; + bool m_invalidated_all { true }; + bool m_invalidated_frame { true }; WindowTileType m_tiled { WindowTileType::None }; Gfx::IntRect m_untiled_rect; bool m_occluded { false }; diff --git a/Services/WindowServer/WindowFrame.cpp b/Services/WindowServer/WindowFrame.cpp index 505ac49cf0..73bccf7a25 100644 --- a/Services/WindowServer/WindowFrame.cpp +++ b/Services/WindowServer/WindowFrame.cpp @@ -234,17 +234,31 @@ Gfx::IntRect WindowFrame::rect() const void WindowFrame::invalidate_title_bar() { - Compositor::the().invalidate(title_bar_rect().translated(rect().location())); + invalidate(title_bar_rect()); +} + +void WindowFrame::invalidate(Gfx::IntRect relative_rect) +{ + auto frame_rect = rect(); + auto window_rect = m_window.rect(); + relative_rect.move_by(frame_rect.x() - window_rect.x(), frame_rect.y() - window_rect.y()); + m_window.invalidate(relative_rect); } void WindowFrame::notify_window_rect_changed(const Gfx::IntRect& old_rect, const Gfx::IntRect& new_rect) { layout_buttons(); - auto& wm = WindowManager::the(); - wm.invalidate(frame_rect_for_window(m_window, old_rect)); - wm.invalidate(frame_rect_for_window(m_window, new_rect)); - wm.notify_rect_changed(m_window, old_rect, new_rect); + auto old_frame_rect = frame_rect_for_window(m_window, old_rect); + auto& compositor = Compositor::the(); + for (auto& dirty : old_frame_rect.shatter(rect())) + compositor.invalidate_screen(dirty); + if (!m_window.is_opaque()) + compositor.invalidate_screen(rect()); + + compositor.invalidate_occlusions(); + + WindowManager::the().notify_rect_changed(m_window, old_rect, new_rect); } void WindowFrame::layout_buttons() diff --git a/Services/WindowServer/WindowFrame.h b/Services/WindowServer/WindowFrame.h index 6b8738cc4a..b398eb4709 100644 --- a/Services/WindowServer/WindowFrame.h +++ b/Services/WindowServer/WindowFrame.h @@ -47,6 +47,7 @@ public: void on_mouse_event(const MouseEvent&); void notify_window_rect_changed(const Gfx::IntRect& old_rect, const Gfx::IntRect& new_rect); void invalidate_title_bar(); + void invalidate(Gfx::IntRect relative_rect); Gfx::IntRect title_bar_rect() const; Gfx::IntRect title_bar_icon_rect() const; diff --git a/Services/WindowServer/WindowManager.cpp b/Services/WindowServer/WindowManager.cpp index de501efb5a..77c921a1fa 100644 --- a/Services/WindowServer/WindowManager.cpp +++ b/Services/WindowServer/WindowManager.cpp @@ -74,7 +74,8 @@ WindowManager::WindowManager(const Gfx::PaletteImpl& palette) reload_config(false); - invalidate(); + Compositor::the().invalidate_screen(); + Compositor::the().invalidate_occlusions(); Compositor::the().compose(); } @@ -188,7 +189,7 @@ void WindowManager::add_window(Window& window) if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher) m_switcher.refresh(); - Compositor::the().recompute_occlusions(); + Compositor::the().invalidate_occlusions(); if (window.listens_to_wm_events()) { for_each_window([&](Window& other_window) { @@ -228,6 +229,8 @@ void WindowManager::move_to_front_and_make_active(Window& window) for_each_window_in_modal_stack(window, [&](auto& w, bool is_stack_top) { move_window_to_front(w, is_stack_top, is_stack_top); }); + + Compositor::the().invalidate_occlusions(); } void WindowManager::do_move_to_front(Window& window, bool make_active, bool make_input) @@ -237,8 +240,6 @@ void WindowManager::do_move_to_front(Window& window, bool make_active, bool make m_windows_in_order.remove(&window); m_windows_in_order.append(&window); - Compositor::the().recompute_occlusions(); - if (make_active) set_active_window(&window, make_input); @@ -258,16 +259,18 @@ void WindowManager::do_move_to_front(Window& window, bool make_active, bool make void WindowManager::remove_window(Window& window) { - window.invalidate(); m_windows_in_order.remove(&window); auto* active = active_window(); auto* active_input = active_input_window(); if (active == &window || active_input == &window || (active && window.is_descendant_of(*active)) || (active_input && active_input != active && window.is_descendant_of(*active_input))) pick_new_active_window(&window); + + Compositor::the().invalidate_screen(window.frame().rect()); + if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher) m_switcher.refresh(); - Compositor::the().recompute_occlusions(); + Compositor::the().invalidate_occlusions(); for_each_window_listening_to_wm_events([&window](Window& listener) { if (!(listener.wm_event_mask() & WMEventMask::WindowRemovals)) @@ -345,7 +348,6 @@ void WindowManager::notify_title_changed(Window& window) #ifdef WINDOWMANAGER_DEBUG dbg() << "[WM] Window{" << &window << "} title set to \"" << window.title() << '"'; #endif - invalidate(window.frame().rect()); if (m_switcher.is_visible()) m_switcher.refresh(); @@ -375,8 +377,6 @@ void WindowManager::notify_rect_changed(Window& window, const Gfx::IntRect& old_ if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher) m_switcher.refresh(); - Compositor::the().recompute_occlusions(); - tell_wm_listeners_window_rect_changed(window); if (window.type() == WindowType::MenuApplet) @@ -387,7 +387,7 @@ void WindowManager::notify_rect_changed(Window& window, const Gfx::IntRect& old_ void WindowManager::notify_opacity_changed(Window&) { - Compositor::the().recompute_occlusions(); + Compositor::the().invalidate_occlusions(); } void WindowManager::notify_minimization_state_changed(Window& window) @@ -965,7 +965,6 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind if (new_opacity > 1.0f) new_opacity = 1.0f; window.set_opacity(new_opacity); - window.invalidate(); return; } @@ -1255,16 +1254,6 @@ void WindowManager::set_hovered_window(Window* window) Core::EventLoop::current().post_event(*m_hovered_window, make(Event::WindowEntered)); } -void WindowManager::invalidate() -{ - Compositor::the().invalidate(); -} - -void WindowManager::invalidate(const Gfx::IntRect& rect) -{ - Compositor::the().invalidate(rect); -} - const ClientConnection* WindowManager::active_client() const { if (m_active_window) @@ -1410,7 +1399,7 @@ bool WindowManager::update_theme(String theme_path, String theme_name) auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini"); wm_config->write_entry("Theme", "Name", theme_name); wm_config->sync(); - invalidate(); + Compositor::the().invalidate_screen(); return true; } diff --git a/Services/WindowServer/WindowManager.h b/Services/WindowServer/WindowManager.h index ec1306a7cc..eeece8f29a 100644 --- a/Services/WindowServer/WindowManager.h +++ b/Services/WindowServer/WindowManager.h @@ -138,10 +138,6 @@ public: const Cursor& drag_cursor() const { return *m_drag_cursor; } const Cursor& wait_cursor() const { return *m_wait_cursor; } - void invalidate(const Gfx::IntRect&); - void invalidate(); - void flush(const Gfx::IntRect&); - const Gfx::Font& font() const; const Gfx::Font& window_title_font() const; diff --git a/Services/WindowServer/WindowSwitcher.cpp b/Services/WindowServer/WindowSwitcher.cpp index f72a2287e1..e75e0ac93c 100644 --- a/Services/WindowServer/WindowSwitcher.cpp +++ b/Services/WindowServer/WindowSwitcher.cpp @@ -57,7 +57,7 @@ void WindowSwitcher::set_visible(bool visible) if (m_visible == visible) return; m_visible = visible; - Compositor::the().recompute_occlusions(); + Compositor::the().invalidate_occlusions(); if (m_switcher_window) m_switcher_window->set_visible(visible); if (!m_visible) @@ -162,7 +162,7 @@ void WindowSwitcher::select_window_at_index(int index) void WindowSwitcher::redraw() { draw(); - Compositor::the().invalidate(m_rect); + Compositor::the().invalidate_screen(m_rect); } Gfx::IntRect WindowSwitcher::item_rect(int index) const