much improved paint and reflow scheduling

This commit is contained in:
hippoz 2022-10-15 21:35:00 +03:00
parent 002318c213
commit dd894d1024
Signed by: hippoz
GPG key ID: 7C52899193467641
6 changed files with 63 additions and 20 deletions

View file

@ -95,4 +95,28 @@ double Box::clamp_for_dimension(Direction direction, double value) {
}
}
Box Box::united(const Box &other) {
if (is_null()) {
return other;
}
if (other.is_null()) {
return *this;
}
Box rect;
rect.set_left(std::min(left(), other.left()));
rect.set_top(std::min(top(), other.top()));
rect.set_right(std::max(right(), other.right()));
rect.set_bottom(std::max(bottom(), other.bottom()));
return rect;
}
bool Box::is_null() const {
return !(m_x && m_y && m_width && m_height);
}
std::string Box::debug() {
return "Box(" + std::to_string(m_x) + ", " + std::to_string(m_y) + ", " + std::to_string(m_width) + ", " + std::to_string(m_height) + ")";
}
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "Point.hpp"
#include <string>
namespace Raven {
@ -51,6 +52,11 @@ public:
double min_height() const { return m_min_height; }
double max_width() const { return m_max_width; }
double max_height() const { return m_max_height; }
double top() const { return y(); }
double bottom() const { return y() + height() - 1; }
double left() const { return x(); }
double right() const { return x() + width() - 1; }
bool is_null() const;
double dimension_at(Direction direction) { return direction == Direction::Horizontal ? width() : height(); }
double max_dimension_at(Direction direction) { return direction == Direction::Horizontal ? max_width() : max_height(); }
double min_dimension_at(Direction direction) { return direction == Direction::Horizontal ? min_width() : min_height(); }
@ -60,6 +66,10 @@ public:
void set_y(double y) { m_y = y; }
void set_width(double width);
void set_height(double height);
void set_top(double top) { set_y(top); }
void set_bottom(double bottom) { set_height(bottom - y() + 1); }
void set_right(double right) { set_width(right - x() + 1); }
void set_left(double left) { set_x(left); }
void set_max_width(double max_width) { m_max_width = max_width; set_width(m_width); }
void set_max_height(double max_height) { m_max_height = max_height; set_height(m_height); }
@ -73,6 +83,9 @@ public:
bool contains_box(const Box &other) const;
Box offset(double x, double y);
Box united(const Box &other);
std::string debug();
};
}

View file

@ -192,18 +192,18 @@ void Widget::handle_repaint_rect(RepaintRectEvent &event) {
}
void Widget::handle_relayout_subtree(RelayoutSubtreeEvent &event) {
on_layout(); // hack
on_layout();
m_window_relative = compute_window_relative();
for (auto child : m_children) {
child->dispatch_event(event);
}
if (m_layout) {
m_layout->run();
}
for (auto child : m_children) {
child->dispatch_event(event);
}
on_after_layout();
}

View file

@ -76,9 +76,10 @@ bool Window::dispatch_to_main_widget(Event &event) {
}
void Window::repaint(Box geometry) {
m_did_repaint_during_batch = true;
if (m_batches)
if (m_batches) {
m_invalidated_area = m_invalidated_area.united(geometry);
return;
}
auto event = RepaintRectEvent(true, geometry);
dispatch_to_main_widget(event);
@ -116,7 +117,6 @@ void Window::reflow() {
}
void Window::start_batch() {
//INFO << "New batch started. Current count: " << m_batches << std::endl;
m_batches++;
}
@ -127,7 +127,6 @@ void Window::end_batch() {
// we are only interested in performing batch operations for the last batch
if (m_batches > 1) {
m_batches--;
//INFO << "Consumed batch. Current count: " << m_batches << std::endl;
return;
}
@ -135,17 +134,17 @@ void Window::end_batch() {
if (m_did_relayout_during_batch) {
reflow();
} else if (m_did_repaint_during_batch) {
repaint();
} else if (!m_invalidated_area.is_null()) {
repaint(m_invalidated_area);
}
m_did_relayout_during_batch = false;
m_did_repaint_during_batch = false;
INFO << "Performed all batch actions." << std::endl;
m_invalidated_area = {0, 0, 0, 0};
}
void Window::run(bool block) {
XEvent e;
bool is_loop_batch_started = false;
for (;;) {
if (block || XPending(m_x_display))
@ -153,10 +152,13 @@ void Window::run(bool block) {
else
break;
if (!is_loop_batch_started) {
start_batch();
is_loop_batch_started = true;
}
switch (e.type) {
case MapNotify: {
INFO << "[X11 EVENT] MapNotify" << std::endl;
end_batch();
break;
}
case ConfigureNotify: {
@ -210,14 +212,16 @@ void Window::run(bool block) {
}
}
if (XPending(m_x_display) == 0 && !m_microtasks.empty()) {
start_batch();
if (XPending(m_x_display) == 0) {
while (!m_microtasks.empty()) {
auto callback = m_microtasks.front();
callback();
m_microtasks.pop();
}
if (is_loop_batch_started) {
end_batch();
is_loop_batch_started = false;
}
}
}
}

View file

@ -59,8 +59,8 @@ private:
Box m_rect { 0, 0, 800, 600 };
Painter m_painter {};
Cairo::RefPtr<Cairo::XlibSurface> m_xlib_surface { nullptr };
int m_batches { 1 };
bool m_did_repaint_during_batch { false };
int m_batches { 0 };
Box m_invalidated_area {0, 0, 0, 0};
bool m_did_relayout_during_batch { false };
std::queue<std::function<void()>> m_microtasks;

View file

@ -21,6 +21,7 @@
int main() {
Raven::Window window {};
window.spawn_window();
window.start_batch();
auto main_widget = window.set_main_widget<Raven::Widget>();
auto main_widget_layout = main_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
@ -66,6 +67,7 @@ int main() {
}
list_view->elements_updated();
window.end_batch();
window.run(true);
return 0;
}