much improved paint and reflow scheduling
This commit is contained in:
parent
002318c213
commit
dd894d1024
6 changed files with 63 additions and 20 deletions
24
src/Box.cpp
24
src/Box.cpp
|
@ -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) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
13
src/Box.hpp
13
src/Box.hpp
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
@ -51,6 +52,11 @@ public:
|
||||||
double min_height() const { return m_min_height; }
|
double min_height() const { return m_min_height; }
|
||||||
double max_width() const { return m_max_width; }
|
double max_width() const { return m_max_width; }
|
||||||
double max_height() const { return m_max_height; }
|
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 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 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(); }
|
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_y(double y) { m_y = y; }
|
||||||
void set_width(double width);
|
void set_width(double width);
|
||||||
void set_height(double height);
|
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_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); }
|
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;
|
bool contains_box(const Box &other) const;
|
||||||
|
|
||||||
Box offset(double x, double y);
|
Box offset(double x, double y);
|
||||||
|
Box united(const Box &other);
|
||||||
|
|
||||||
|
std::string debug();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,18 +192,18 @@ void Widget::handle_repaint_rect(RepaintRectEvent &event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::handle_relayout_subtree(RelayoutSubtreeEvent &event) {
|
void Widget::handle_relayout_subtree(RelayoutSubtreeEvent &event) {
|
||||||
on_layout(); // hack
|
on_layout();
|
||||||
|
|
||||||
m_window_relative = compute_window_relative();
|
m_window_relative = compute_window_relative();
|
||||||
|
|
||||||
for (auto child : m_children) {
|
|
||||||
child->dispatch_event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_layout) {
|
if (m_layout) {
|
||||||
m_layout->run();
|
m_layout->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto child : m_children) {
|
||||||
|
child->dispatch_event(event);
|
||||||
|
}
|
||||||
|
|
||||||
on_after_layout();
|
on_after_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,9 +76,10 @@ bool Window::dispatch_to_main_widget(Event &event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::repaint(Box geometry) {
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto event = RepaintRectEvent(true, geometry);
|
auto event = RepaintRectEvent(true, geometry);
|
||||||
dispatch_to_main_widget(event);
|
dispatch_to_main_widget(event);
|
||||||
|
@ -116,7 +117,6 @@ void Window::reflow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::start_batch() {
|
void Window::start_batch() {
|
||||||
//INFO << "New batch started. Current count: " << m_batches << std::endl;
|
|
||||||
m_batches++;
|
m_batches++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,6 @@ void Window::end_batch() {
|
||||||
// we are only interested in performing batch operations for the last batch
|
// we are only interested in performing batch operations for the last batch
|
||||||
if (m_batches > 1) {
|
if (m_batches > 1) {
|
||||||
m_batches--;
|
m_batches--;
|
||||||
//INFO << "Consumed batch. Current count: " << m_batches << std::endl;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,17 +134,17 @@ void Window::end_batch() {
|
||||||
|
|
||||||
if (m_did_relayout_during_batch) {
|
if (m_did_relayout_during_batch) {
|
||||||
reflow();
|
reflow();
|
||||||
} else if (m_did_repaint_during_batch) {
|
} else if (!m_invalidated_area.is_null()) {
|
||||||
repaint();
|
repaint(m_invalidated_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_did_relayout_during_batch = false;
|
m_did_relayout_during_batch = false;
|
||||||
m_did_repaint_during_batch = false;
|
m_invalidated_area = {0, 0, 0, 0};
|
||||||
INFO << "Performed all batch actions." << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::run(bool block) {
|
void Window::run(bool block) {
|
||||||
XEvent e;
|
XEvent e;
|
||||||
|
bool is_loop_batch_started = false;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (block || XPending(m_x_display))
|
if (block || XPending(m_x_display))
|
||||||
|
@ -153,10 +152,13 @@ void Window::run(bool block) {
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (!is_loop_batch_started) {
|
||||||
|
start_batch();
|
||||||
|
is_loop_batch_started = true;
|
||||||
|
}
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case MapNotify: {
|
case MapNotify: {
|
||||||
INFO << "[X11 EVENT] MapNotify" << std::endl;
|
INFO << "[X11 EVENT] MapNotify" << std::endl;
|
||||||
end_batch();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ConfigureNotify: {
|
case ConfigureNotify: {
|
||||||
|
@ -210,14 +212,16 @@ void Window::run(bool block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (XPending(m_x_display) == 0 && !m_microtasks.empty()) {
|
if (XPending(m_x_display) == 0) {
|
||||||
start_batch();
|
|
||||||
while (!m_microtasks.empty()) {
|
while (!m_microtasks.empty()) {
|
||||||
auto callback = m_microtasks.front();
|
auto callback = m_microtasks.front();
|
||||||
callback();
|
callback();
|
||||||
m_microtasks.pop();
|
m_microtasks.pop();
|
||||||
}
|
}
|
||||||
end_batch();
|
if (is_loop_batch_started) {
|
||||||
|
end_batch();
|
||||||
|
is_loop_batch_started = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,8 @@ private:
|
||||||
Box m_rect { 0, 0, 800, 600 };
|
Box m_rect { 0, 0, 800, 600 };
|
||||||
Painter m_painter {};
|
Painter m_painter {};
|
||||||
Cairo::RefPtr<Cairo::XlibSurface> m_xlib_surface { nullptr };
|
Cairo::RefPtr<Cairo::XlibSurface> m_xlib_surface { nullptr };
|
||||||
int m_batches { 1 };
|
int m_batches { 0 };
|
||||||
bool m_did_repaint_during_batch { false };
|
Box m_invalidated_area {0, 0, 0, 0};
|
||||||
bool m_did_relayout_during_batch { false };
|
bool m_did_relayout_during_batch { false };
|
||||||
std::queue<std::function<void()>> m_microtasks;
|
std::queue<std::function<void()>> m_microtasks;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
int main() {
|
int main() {
|
||||||
Raven::Window window {};
|
Raven::Window window {};
|
||||||
window.spawn_window();
|
window.spawn_window();
|
||||||
|
window.start_batch();
|
||||||
|
|
||||||
auto main_widget = window.set_main_widget<Raven::Widget>();
|
auto main_widget = window.set_main_widget<Raven::Widget>();
|
||||||
auto main_widget_layout = main_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
|
auto main_widget_layout = main_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
|
||||||
|
@ -66,6 +67,7 @@ int main() {
|
||||||
}
|
}
|
||||||
list_view->elements_updated();
|
list_view->elements_updated();
|
||||||
|
|
||||||
|
window.end_batch();
|
||||||
window.run(true);
|
window.run(true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue