summaryrefslogtreecommitdiff
path: root/libraries/pake
diff options
context:
space:
mode:
authorBenji Dial <benji@benjidial.net>2024-07-29 19:59:52 -0400
committerBenji Dial <benji@benjidial.net>2024-07-29 19:59:52 -0400
commite6c3a80b01ffb52079783cddd9be6d392d0f7039 (patch)
tree148276b9878f287bc81638f90249ec4d7b86eaf0 /libraries/pake
parentbe691582ee12613278af24cb5a824eeb357f6324 (diff)
downloadhilbert-os-e6c3a80b01ffb52079783cddd9be6d392d0f7039.tar.gz
redesign compositor protocol, start widget library
Diffstat (limited to 'libraries/pake')
-rw-r--r--libraries/pake/include/pake/dirtiable-image.hpp27
-rw-r--r--libraries/pake/include/pake/widget.hpp19
-rw-r--r--libraries/pake/include/pake/widgets/fixed-text.hpp31
-rw-r--r--libraries/pake/include/pake/window.hpp32
-rw-r--r--libraries/pake/makefile12
-rw-r--r--libraries/pake/source/dirtiable-image.cpp80
-rw-r--r--libraries/pake/source/widgets/fixed-text.cpp41
-rw-r--r--libraries/pake/source/window.cpp78
8 files changed, 320 insertions, 0 deletions
diff --git a/libraries/pake/include/pake/dirtiable-image.hpp b/libraries/pake/include/pake/dirtiable-image.hpp
new file mode 100644
index 0000000..af09ade
--- /dev/null
+++ b/libraries/pake/include/pake/dirtiable-image.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <daguerre/image.hpp>
+#include <list>
+
+namespace pake {
+
+ struct region {
+ int start_x;
+ int start_y;
+ int width;
+ int height;
+ };
+
+ struct dirtiable_image {
+
+ daguerre::image<daguerre::hilbert_color> image;
+ daguerre::image<bool> dirty;
+
+ std::vector<region> get_dirty_regions();
+ void clear_dirty();
+
+ dirtiable_image(int width, int height);
+
+ };
+
+}
diff --git a/libraries/pake/include/pake/widget.hpp b/libraries/pake/include/pake/widget.hpp
new file mode 100644
index 0000000..dad5651
--- /dev/null
+++ b/libraries/pake/include/pake/widget.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <pake/dirtiable-image.hpp>
+
+namespace pake {
+
+ class widget {
+
+ public:
+ virtual ~widget() {}
+
+ virtual void render(
+ dirtiable_image &onto, int x_off, int y_off, bool force) = 0;
+
+ virtual void notify_size(int width, int height) = 0;
+
+ };
+
+}
diff --git a/libraries/pake/include/pake/widgets/fixed-text.hpp b/libraries/pake/include/pake/widgets/fixed-text.hpp
new file mode 100644
index 0000000..c6dafab
--- /dev/null
+++ b/libraries/pake/include/pake/widgets/fixed-text.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <daguerre/fixed-font.hpp>
+#include <pake/widget.hpp>
+
+namespace pake::widgets {
+
+ class fixed_text : public widget {
+
+ const daguerre::fixed_font<bool> *font;
+ daguerre::hilbert_color bg, fg;
+ std::string text;
+
+ int width, height;
+
+ public:
+ //TODO: look up font in some kind of catalogue
+ fixed_text(
+ std::string &&text,
+ const daguerre::fixed_font<bool> *font,
+ daguerre::hilbert_color bg,
+ daguerre::hilbert_color fg);
+
+ virtual void render(
+ dirtiable_image &onto, int x_off, int y_off, bool force) override;
+
+ virtual void notify_size(int width, int height) override;
+
+ };
+
+}
diff --git a/libraries/pake/include/pake/window.hpp b/libraries/pake/include/pake/window.hpp
new file mode 100644
index 0000000..bb63b9d
--- /dev/null
+++ b/libraries/pake/include/pake/window.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <pake/dirtiable-image.hpp>
+#include <pake/widget.hpp>
+#include <memory>
+
+namespace pake {
+
+ class window {
+
+ euler::syscall::stream_handle socket;
+
+ int width;
+ int height;
+
+ dirtiable_image contents;
+ std::unique_ptr<widget> root;
+
+ public:
+ window(int width, int height, const std::string &title);
+ ~window();
+
+ void show();
+ void hide();
+
+ void set_root(std::unique_ptr<widget> &&w);
+
+ void render_and_send_to_compositor();
+
+ };
+
+}
diff --git a/libraries/pake/makefile b/libraries/pake/makefile
new file mode 100644
index 0000000..28e7d37
--- /dev/null
+++ b/libraries/pake/makefile
@@ -0,0 +1,12 @@
+SOURCES = \
+ widgets/fixed-text.cpp dirtiable-image.cpp window.cpp
+
+build/%.cpp.o: source/%.cpp
+ @mkdir -p $(@D)
+ $(HILBERT_CC) -c $^ -o $@
+
+build/libpake.a: $(SOURCES:%=build/%.o)
+ $(HILBERT_AR) rcs $@ $^
+
+clean:
+ rm -rf build
diff --git a/libraries/pake/source/dirtiable-image.cpp b/libraries/pake/source/dirtiable-image.cpp
new file mode 100644
index 0000000..9e5c979
--- /dev/null
+++ b/libraries/pake/source/dirtiable-image.cpp
@@ -0,0 +1,80 @@
+#include <pake/dirtiable-image.hpp>
+
+namespace pake {
+
+ struct dirty_region_builder {
+
+ std::vector<region> regions_not_on_bottom;
+ std::list<region> regions_on_bottom;
+
+ void add_row(const std::vector<region> &row) {
+
+ std::list<region> new_regions_on_bottom;
+
+ for (auto i = row.begin(); i < row.end(); ++i) {
+ bool expanded = false;
+ for (auto j = regions_on_bottom.begin(); j != regions_on_bottom.end(); ++j)
+ if (i->start_x == j->start_x && i->width == j->width) {
+ j->height += i->height;
+ new_regions_on_bottom.push_back(*j);
+ regions_on_bottom.erase(j);
+ expanded = true;
+ break;
+ }
+ if (!expanded)
+ new_regions_on_bottom.push_back(*i);
+ }
+
+ for (auto i = regions_on_bottom.begin(); i != regions_on_bottom.end(); ++i)
+ regions_not_on_bottom.push_back(*i);
+
+ regions_on_bottom = std::move(new_regions_on_bottom);
+
+ }
+
+ };
+
+ std::vector<region> dirtiable_image::get_dirty_regions() {
+
+ dirty_region_builder builder;
+
+ std::vector<region> row;
+
+ for (int y = 0; y < dirty.height; ++y) {
+
+ int r = 0;
+ for (int x = 0; x < dirty.width; ++x)
+ if (!dirty.at(x, y)) {
+ if (r != x)
+ row.push_back({
+ .start_x = r, .start_y = y,
+ .width = x - r, .height = 1
+ });
+ r = x + 1;
+ }
+ if (r != dirty.width)
+ row.push_back({
+ .start_x = r, .start_y = y,
+ .width = dirty.width - r, .height = 1
+ });
+
+ builder.add_row(row);
+ row.clear();
+
+ }
+
+ builder.add_row(row);
+ return builder.regions_not_on_bottom;
+
+ }
+
+ void dirtiable_image::clear_dirty() {
+ dirty.fill(false);
+ }
+
+ dirtiable_image::dirtiable_image(int width, int height)
+ : image(width, height), dirty(width, height) {
+ dirty.fill(false);
+ }
+
+}
diff --git a/libraries/pake/source/widgets/fixed-text.cpp b/libraries/pake/source/widgets/fixed-text.cpp
new file mode 100644
index 0000000..9ae55dc
--- /dev/null
+++ b/libraries/pake/source/widgets/fixed-text.cpp
@@ -0,0 +1,41 @@
+#include <pake/widgets/fixed-text.hpp>
+
+static void draw_if_true(
+ daguerre::hilbert_color &out, const bool &in,
+ const daguerre::hilbert_color &param) {
+ if (in) out = param;
+}
+
+namespace pake::widgets {
+
+ fixed_text::fixed_text(
+ std::string &&text,
+ const daguerre::fixed_font<bool> *font,
+ daguerre::hilbert_color bg,
+ daguerre::hilbert_color fg)
+ : font(font), bg(bg), fg(fg), text(std::move(text)) {}
+
+ void fixed_text::render(
+ dirtiable_image &onto, int x_off, int y_off, bool force) {
+
+ if (force) {
+ onto.image.fill( bg, x_off, y_off, width, height);
+ onto.dirty.fill(true, x_off, y_off, width, height);
+ //TODO: have options for alignment
+ //TODO: check overflow
+ onto.image.render_text(
+ *font, fg, x_off, y_off,
+ text.data(), draw_if_true);
+ onto.dirty.fill(
+ true, x_off, y_off,
+ font->glyph_width * text.size(),
+ font->glyph_height);
+ }
+
+ }
+
+ void fixed_text::notify_size(int width, int height) {
+ this->width = width; this->height = height;
+ }
+
+}
diff --git a/libraries/pake/source/window.cpp b/libraries/pake/source/window.cpp
new file mode 100644
index 0000000..c1c773f
--- /dev/null
+++ b/libraries/pake/source/window.cpp
@@ -0,0 +1,78 @@
+#include <pake/window.hpp>
+#include <cassert>
+
+//TODO: handle errors on socket connection, read, and write
+
+namespace pake {
+
+ window::window(int width, int height, const std::string &title)
+ : width(width), height(height), contents(width, height), root() {
+
+ euler::syscall::connect_to_socket("hilbert.compositor", socket);
+
+ assert(width >= 0 && height >= 0);
+
+ struct [[gnu::packed]] { uint8_t type; uint32_t width; uint32_t height; }
+ dimensions_pkt = {.type = 0x02, .width = (uint32_t)width, .height = (uint32_t)height };
+ euler::syscall::write_to_stream(socket, sizeof(dimensions_pkt), &dimensions_pkt);
+
+ assert(title.size() <= UINT32_MAX);
+
+ struct [[gnu::packed]] { uint8_t type; uint32_t length; }
+ title_pkt = {.type = 0x03, .length = (uint32_t)title.size() };
+ euler::syscall::write_to_stream(socket, sizeof(title_pkt), &title_pkt);
+ euler::syscall::write_to_stream(socket, title.size(), title.data());
+
+ }
+
+ window::~window() {
+ euler::syscall::close_stream(socket);
+ }
+
+ void window::show() {
+ uint8_t packet = 0;
+ euler::syscall::write_to_stream(socket, 1, &packet);
+ }
+
+ void window::hide() {
+ uint8_t packet = 1;
+ euler::syscall::write_to_stream(socket, 1, &packet);
+ }
+
+ void window::set_root(std::unique_ptr<widget> &&w) {
+ root = std::move(w);
+ root->notify_size(width, height);
+ root->render(contents, 0, 0, true);
+ }
+
+ void window::render_and_send_to_compositor() {
+
+ root->render(contents, 0, 0, false);
+ auto dirties = contents.get_dirty_regions();
+
+ for (auto it = dirties.cbegin(); it != dirties.cend(); ++it) {
+
+ struct [[gnu::packed]] {
+ uint8_t type;
+ uint32_t start_x; uint32_t start_y;
+ uint32_t width; uint32_t height;
+ } update_pkt = {
+ .type = 0x04,
+ .start_x = (uint32_t)it->start_x, .start_y = (uint32_t)it->start_y,
+ . width = (uint32_t)it-> width, . height = (uint32_t)it-> height
+ };
+
+ euler::syscall::write_to_stream(socket, sizeof(update_pkt), &update_pkt);
+
+ for (int y = it->start_y; y < it->start_y + it->height; ++y)
+ euler::syscall::write_to_stream(socket,
+ it->width * sizeof(daguerre::hilbert_color),
+ &contents.image.at(it->start_x, y));
+
+ }
+
+ contents.clear_dirty();
+
+ }
+
+}