add basic multi-window support

This commit is contained in:
hippoz 2022-10-26 22:13:07 +03:00
parent 035522591f
commit e6be3bb378
Signed by: hippoz
GPG key ID: 7C52899193467641
7 changed files with 111 additions and 13 deletions

View file

@ -26,6 +26,7 @@ raven_source_files = [
'./src/Box.cpp',
'./src/Styles.cpp',
'./src/Painter.cpp',
'./src/Application.cpp',
'./src/Window.cpp',
'./src/Widget.cpp',
'./src/SvgWidget.cpp',
@ -61,6 +62,7 @@ raven_header_files = [
'./src/Styles.hpp',
'./src/Widget.hpp',
'./src/SvgWidget.hpp',
'./src/Application.hpp',
'./src/Window.hpp'
]

55
src/Application.cpp Normal file
View file

@ -0,0 +1,55 @@
#include "Application.hpp"
#include <poll.h>
namespace Raven {
void Application::add_window(std::shared_ptr<Window> window) {
m_windows.push_back(window);
update_fds();
}
void Application::update_fds() {
for (int i = 0; i < RAVEN_APPLICATION_MAX_WINDOWS; i++) {
m_fds[i].fd = -1;
m_fds[i].events = 0;
m_fds[i].revents = 0;
}
for (size_t i = 0; i < m_windows.size(); i++) {
m_fds[i].fd = m_windows[i]->file_descriptor();
m_fds[i].events = POLL_IN;
}
}
int Application::turn() {
if (m_fds_need_update) {
update_fds();
m_fds_need_update = false;
}
if (poll(m_fds, m_windows.size(), -1) > 0) {
for (size_t i = 0; i < m_windows.size(); i++) {
if (m_fds[i].revents & POLLIN) {
m_windows[i]->run(false);
}
}
} else {
return 1;
}
return 0;
}
int Application::run() {
// Make sure any pending events are dealt with before starting the loop
for (size_t i = 0; i < m_windows.size(); i++) {
m_windows[i]->run(false);
}
for (;;) {
int ret = turn();
if (ret != 0) {
return ret;
}
}
return 0;
}
}

34
src/Application.hpp Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include <memory>
#include <vector>
#include <poll.h>
#include "Window.hpp"
namespace Raven {
#define RAVEN_APPLICATION_MAX_WINDOWS 1023
class Application {
public:
Application() {}
void add_window(std::shared_ptr<Window>);
int turn();
int run();
template<class... Args>
std::shared_ptr<Window> add_window(Args&&... args) {
std::shared_ptr<Window> child = std::make_shared<Window>(std::forward<Args>(args)...);
add_window(child);
return child;
}
private:
void update_fds();
std::vector<std::shared_ptr<Window>> m_windows;
struct pollfd m_fds[RAVEN_APPLICATION_MAX_WINDOWS];
bool m_fds_need_update { true };
};
}

View file

@ -5,7 +5,7 @@
#include "cairomm/enums.h"
#include "cairomm/refptr.h"
#include "cairomm/surface.h"
#include "raven/Widget.hpp"
#include "Widget.hpp"
#include "librsvg/rsvg.h"
namespace Raven {

View file

@ -69,6 +69,10 @@ bool Window::spawn_window() {
return true;
}
int Window::file_descriptor() {
return m_x_display ? XConnectionNumber(m_x_display) : -1;
}
bool Window::dispatch_to_main_widget(Event &event) {
if (!m_main_widget)
return false;
@ -157,7 +161,6 @@ void Window::swallow_batches() {
void Window::run(bool block) {
XEvent e;
bool is_loop_batch_started = false;
swallow_batches();
@ -167,9 +170,9 @@ void Window::run(bool block) {
else
break;
if (!is_loop_batch_started) {
if (!m_is_loop_batch_started) {
start_batch();
is_loop_batch_started = true;
m_is_loop_batch_started = true;
}
switch (e.type) {
case MapNotify: {
@ -254,9 +257,9 @@ void Window::run(bool block) {
callback();
m_microtasks.pop();
}
if (is_loop_batch_started) {
if (m_is_loop_batch_started) {
end_batch();
is_loop_batch_started = false;
m_is_loop_batch_started = false;
}
}
}

View file

@ -20,6 +20,8 @@ public:
bool spawn_window();
void run(bool block);
int file_descriptor();
void start_batch();
void end_batch();
void swallow_batches();
@ -64,6 +66,7 @@ private:
Box m_invalidated_area {0, 0, 0, 0};
bool m_did_relayout_during_batch { false };
std::queue<std::function<void()>> m_microtasks;
bool m_is_loop_batch_started { false };
Display *m_x_display { nullptr };
XIM m_xim { nullptr };

View file

@ -1,4 +1,5 @@
#include "Label.hpp"
#include "Application.hpp"
#include "ColumnLayout.hpp"
#include "ListView.hpp"
#include "TextInput.hpp"
@ -20,10 +21,13 @@
#include <string>
int main() {
Raven::Window window {};
window.spawn_window();
Raven::Application application {};
auto window = application.add_window();
auto main_widget = window.set_main_widget<Raven::Widget>();
window->spawn_window();
auto main_widget = window->set_main_widget<Raven::Widget>();
auto main_widget_layout = main_widget->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
main_widget_layout->set_margin(8);
main_widget_layout->set_spacing(8);
@ -54,8 +58,6 @@ int main() {
delete_button->set_style(&Raven::raised_button_style);
delete_button->set_grows(true);
content->add<Raven::Label>("Edit an item");
auto edit_row = content->add<Raven::Widget>();
edit_row->set_style(&Raven::raised_widget_style);
auto edit_row_layout = edit_row->set_layout<Raven::BoxLayout>(Raven::Direction::Horizontal);
@ -96,6 +98,5 @@ int main() {
}
list_view->elements_updated();
window.run(true);
return 0;
return application.run();
}