WindowServer: Factor out some parts of compose().

The main compositing loop was getting pretty unwieldy. Break out some parts
into functions so it's more understandable.
This commit is contained in:
Andreas Kling 2019-04-10 13:51:47 +02:00
parent f6543c5946
commit 30e2d62c38
4 changed files with 85 additions and 71 deletions

View file

@ -719,6 +719,58 @@ void WSWindowManager::clear_resize_candidate()
m_resize_candidate = nullptr;
}
bool WSWindowManager::any_opaque_window_contains_rect(const Rect& rect)
{
bool found_containing_window = false;
for_each_window([&] (WSWindow& window) {
if (!window.is_visible())
return IterationDecision::Continue;
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::Abort;
}
return IterationDecision::Continue;
});
return found_containing_window;
};
bool WSWindowManager::any_opaque_window_above_this_one_contains_rect(const WSWindow& a_window, const Rect& rect)
{
bool found_containing_window = false;
bool checking = false;
for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
if (&window == &a_window) {
checking = true;
return IterationDecision::Continue;
}
if (!checking)
return IterationDecision::Continue;
if (!window.is_visible())
return IterationDecision::Continue;
if (window.is_minimized())
return IterationDecision::Continue;
if (window.opacity() < 1.0f)
return IterationDecision::Continue;
if (window.has_alpha_channel())
return IterationDecision::Continue;
if (window.frame().rect().contains(rect)) {
found_containing_window = true;
return IterationDecision::Abort;
}
return IterationDecision::Continue;
});
return found_containing_window;
};
void WSWindowManager::compose()
{
auto dirty_rects = move(m_dirty_rects);
@ -729,52 +781,6 @@ void WSWindowManager::compose()
dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.rects().size());
#endif
auto any_opaque_window_contains_rect = [this] (const Rect& r) {
for (auto* window = m_windows_in_order.head(); window; window = window->next()) {
if (!window->is_visible())
continue;
if (window->is_minimized())
continue;
if (window->opacity() < 1.0f)
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?
continue;
}
if (window->frame().rect().contains(r))
return true;
}
return false;
};
auto any_opaque_window_above_this_one_contains_rect = [this] (const WSWindow& a_window, const Rect& rect) -> bool {
bool found = false;
bool checking = false;
for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
if (&window == &a_window) {
checking = true;
return IterationDecision::Continue;
}
if (!checking)
return IterationDecision::Continue;
if (!window.is_visible())
return IterationDecision::Continue;
if (window.is_minimized())
return IterationDecision::Continue;
if (window.opacity() < 1.0f)
return IterationDecision::Continue;
if (window.has_alpha_channel())
return IterationDecision::Continue;
if (window.frame().rect().contains(rect)) {
found = true;
return IterationDecision::Abort;
}
return IterationDecision::Continue;
});
return found;
};
auto any_dirty_rect_intersects_window = [&dirty_rects] (const WSWindow& window) {
auto window_frame_rect = window.frame().rect();
for (auto& dirty_rect : dirty_rects.rects()) {
@ -794,11 +800,11 @@ void WSWindowManager::compose()
}
for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
RetainPtr<GraphicsBitmap> backing_store = window.backing_store();
if (!any_dirty_rect_intersects_window(window))
return IterationDecision::Continue;
PainterStateSaver saver(*m_back_painter);
m_back_painter->add_clip_rect(window.frame().rect());
RetainPtr<GraphicsBitmap> backing_store = window.backing_store();
for (auto& dirty_rect : dirty_rects.rects()) {
if (any_opaque_window_above_this_one_contains_rect(window, dirty_rect))
continue;
@ -813,31 +819,12 @@ void WSWindowManager::compose()
dirty_rect_in_window_coordinates.move_by(-window.position());
auto dst = window.position();
dst.move_by(dirty_rect_in_window_coordinates.location());
if (window.opacity() == 1.0f)
m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates);
else
m_back_painter->blit_with_opacity(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity());
m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity());
}
return IterationDecision::Continue;
});
if (auto* window_being_moved_or_resized = m_drag_window ? m_drag_window.ptr() : (m_resize_window ? m_resize_window.ptr() : nullptr)) {
auto geometry_string = window_being_moved_or_resized->rect().to_string();
if (!window_being_moved_or_resized->size_increment().is_null()) {
int width_steps = (window_being_moved_or_resized->width() - window_being_moved_or_resized->base_size().width()) / window_being_moved_or_resized->size_increment().width();
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 = Rect { 0, 0, font().width(geometry_string) + 16, font().glyph_height() + 10 };
geometry_label_rect.center_within(window_being_moved_or_resized->rect());
m_back_painter->fill_rect(geometry_label_rect, Color::LightGray);
m_back_painter->draw_rect(geometry_label_rect, Color::DarkGray);
m_back_painter->draw_text(geometry_label_rect, geometry_string, TextAlignment::Center);
m_last_geometry_label_rect = geometry_label_rect;
} else {
m_last_geometry_label_rect = { };
}
draw_geometry_label();
draw_menubar();
draw_cursor();
@ -937,6 +924,27 @@ void WSWindowManager::draw_window_switcher()
m_switcher.draw();
}
void WSWindowManager::draw_geometry_label()
{
auto* window_being_moved_or_resized = m_drag_window ? m_drag_window.ptr() : (m_resize_window ? m_resize_window.ptr() : nullptr);
if (!window_being_moved_or_resized) {
m_last_geometry_label_rect = { };
return;
}
auto geometry_string = window_being_moved_or_resized->rect().to_string();
if (!window_being_moved_or_resized->size_increment().is_null()) {
int width_steps = (window_being_moved_or_resized->width() - window_being_moved_or_resized->base_size().width()) / window_being_moved_or_resized->size_increment().width();
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 = Rect { 0, 0, font().width(geometry_string) + 16, font().glyph_height() + 10 };
geometry_label_rect.center_within(window_being_moved_or_resized->rect());
m_back_painter->fill_rect(geometry_label_rect, Color::LightGray);
m_back_painter->draw_rect(geometry_label_rect, Color::DarkGray);
m_back_painter->draw_text(geometry_label_rect, geometry_string, TextAlignment::Center);
m_last_geometry_label_rect = geometry_label_rect;
}
void WSWindowManager::draw_cursor()
{
Rect cursor_rect = current_cursor_rect();

View file

@ -59,6 +59,7 @@ public:
void draw_cursor();
void draw_menubar();
void draw_window_switcher();
void draw_geometry_label();
Rect menubar_rect() const;
WSMenuBar* current_menubar() { return m_current_menubar.ptr(); }
@ -107,6 +108,9 @@ public:
void set_resize_candidate(WSWindow&, ResizeDirection);
void clear_resize_candidate();
bool any_opaque_window_contains_rect(const Rect&);
bool any_opaque_window_above_this_one_contains_rect(const WSWindow&, const Rect&);
private:
void process_mouse_event(const WSMouseEvent&, WSWindow*& event_window);
bool process_ongoing_window_resize(const WSMouseEvent&, WSWindow*& event_window);

View file

@ -271,8 +271,10 @@ void Painter::blit_with_alpha(const Point& position, const GraphicsBitmap& sourc
}
}
void Painter::blit(const Point& position, const GraphicsBitmap& source, const Rect& src_rect)
void Painter::blit(const Point& position, const GraphicsBitmap& source, const Rect& src_rect, float opacity)
{
if (opacity < 1.0f)
return blit_with_opacity(position, source, src_rect, opacity);
if (source.has_alpha_channel())
return blit_with_alpha(position, source, src_rect);
auto safe_src_rect = Rect::intersection(src_rect, source.rect());

View file

@ -26,8 +26,7 @@ public:
void draw_line(const Point&, const Point&, Color);
void draw_focus_rect(const Rect&);
void draw_scaled_bitmap(const Rect& dst_rect, const GraphicsBitmap&, const Rect& src_rect);
void blit(const Point&, const GraphicsBitmap&, const Rect& src_rect);
void blit_with_opacity(const Point&, const GraphicsBitmap&, const Rect& src_rect, float opacity);
void blit(const Point&, const GraphicsBitmap&, const Rect& src_rect, float opacity = 1.0f);
void draw_text(const Rect&, const char* text, int length, const Font&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None);
void draw_text(const Rect&, const char* text, int length, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None);
@ -61,6 +60,7 @@ protected:
void set_pixel_with_draw_op(dword& pixel, const Color&);
void fill_rect_with_draw_op(const Rect&, Color);
void blit_with_alpha(const Point&, const GraphicsBitmap&, const Rect& src_rect);
void blit_with_opacity(const Point&, const GraphicsBitmap&, const Rect& src_rect, float opacity);
struct State {
const Font* font;