summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--applications/goldman/source/socket.cpp143
-rw-r--r--applications/goldman/source/window.hpp6
-rw-r--r--applications/hello/makefile2
-rw-r--r--applications/hello/source/main.cpp43
-rw-r--r--documentation/compositor.txt48
-rw-r--r--euler/include/cassert12
-rw-r--r--euler/include/condition_variable3
-rw-r--r--euler/include/mutex2
-rw-r--r--euler/include/std/condition-variable.hpp13
-rw-r--r--euler/include/std/list.hpp19
-rw-r--r--euler/include/std/unique-lock.hpp (renamed from euler/include/std/unique_lock.hpp)0
-rw-r--r--euler/include/std/vector.hpp18
-rw-r--r--libraries/daguerre/include/daguerre/image.hpp2
-rw-r--r--libraries/daguerre/include/daguerre/impl/image.hpp8
-rw-r--r--libraries/goldman/include/goldman/protocol.hpp85
-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
-rw-r--r--makefile13
24 files changed, 506 insertions, 231 deletions
diff --git a/applications/goldman/source/socket.cpp b/applications/goldman/source/socket.cpp
index b175fe9..9ebd644 100644
--- a/applications/goldman/source/socket.cpp
+++ b/applications/goldman/source/socket.cpp
@@ -8,114 +8,95 @@
struct socket_state {
euler::syscall::stream_handle socket;
- std::vector<window *> windows;
- daguerre::hilbert_color window_bg = euler::syscall::encode_color(0, 0, 0);
+ window *w;
- bool try_open_window() {
+ bool try_show_window() {
- struct [[gnu::packed]] {
- uint32_t width;
- uint32_t height;
- } body;
-
- if (euler::syscall::read_from_stream(socket, sizeof(body), &body) !=
- euler::syscall::stream_result::success)
+ if (w->is_shown)
return false;
- window *w = new window(body.width, body.height);
- w->contents.fill(window_bg);
+ r->lock();
+ r->add_window(w);
+ r->unlock();
+ r->dispatch_render();
+ return true;
- uint16_t wid = 0;
+ }
- while (wid < windows.size())
- if (windows[wid] != 0)
- ++wid;
- else
- break;
+ bool try_hide_window() {
- if (wid == windows.size())
- windows.push_back(w);
- else
- windows[wid] = w;
+ if (!w->is_shown)
+ return false;
r->lock();
- r->add_window(w);
+ r->remove_window(w);
r->unlock();
-
- struct [[gnu::packed]] {
- uint8_t type;
- uint16_t the_window;
- } response {
- .type = 0x00,
- .the_window = wid
- };
-
- return
- euler::syscall::write_to_stream(socket, sizeof(response), &response) ==
- euler::syscall::stream_result::success;
+ r->dispatch_render();
+ return true;
}
- bool try_update_window_region() {
+ bool try_set_window_dimensions() {
- struct [[gnu::packed]] {
- uint16_t window;
- uint32_t start_x;
- uint32_t start_y;
- uint32_t width;
- uint32_t height;
- } body_head;
-
- if (euler::syscall::read_from_stream(socket, sizeof(body_head), &body_head) !=
+ struct [[gnu::packed]] { uint32_t width; uint32_t height; } packet;
+ if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) !=
euler::syscall::stream_result::success)
return false;
- std::vector<daguerre::hilbert_color> data(body_head.width * body_head.height);
-
- if (euler::syscall::read_from_stream(socket, data.size() * 4, data.data()) !=
- euler::syscall::stream_result::success)
+ if (packet.width > __INT_MAX__ || packet.height > __INT_MAX__)
return false;
- daguerre::image<daguerre::hilbert_color>
- data_as_image(body_head.width, body_head.height, data.data(), body_head.width, false);
-
- if (body_head.window >= windows.size() || !windows[body_head.window])
- return false;
+ r->lock();
+ w->contents = daguerre::image<daguerre::hilbert_color>(
+ packet.width, packet.height);
+ r->unlock();
+ return true;
- window *w = windows[body_head.window];
+ }
- r->lock();
+ bool try_set_window_title() {
- if ((int)body_head.start_x + data_as_image.width > w->contents.width ||
- (int)body_head.start_y + data_as_image.height > w->contents.height) {
- r->unlock();
+ uint32_t length;
+ if (euler::syscall::read_from_stream(socket, 4, &length) !=
+ euler::syscall::stream_result::success)
return false;
- }
- w->contents.copy_from(data_as_image, body_head.start_x, body_head.start_y);
+ std::string title;
+ title.resize(length);
+ if (euler::syscall::read_from_stream(socket, length, title.data()) !=
+ euler::syscall::stream_result::success)
+ return false;
+ r->lock();
+ w->title = std::move(title);
r->unlock();
r->dispatch_render();
return true;
}
- bool try_close_window() {
-
- uint16_t wid;
+ bool try_update_window_region() {
- if (euler::syscall::read_from_stream(socket, 2, &wid) !=
+ struct [[gnu::packed]] {
+ uint32_t start_x; uint32_t start_y; uint32_t width; uint32_t height;
+ } packet;
+ if (euler::syscall::read_from_stream(socket, sizeof(packet), &packet) !=
euler::syscall::stream_result::success)
return false;
- if (wid >= windows.size() || !windows[wid])
+ static_assert(__INT_MAX__ <= __UINT64_MAX__);
+ if ((uint64_t)packet.start_x + packet. width > (uint64_t)w->contents. width ||
+ (uint64_t)packet.start_y + packet.height > (uint64_t)w->contents.height)
return false;
- r->lock();
-
- r->remove_window(windows[wid]);
- windows[wid] = 0;
+ daguerre::image<daguerre::hilbert_color> content(packet.width, packet.height);
+ if (euler::syscall::read_from_stream(
+ socket, packet.width * packet.height * 4, content.buffer) !=
+ euler::syscall::stream_result::success)
+ return false;
+ r->lock();
+ w->contents.copy_from(content, packet.start_x, packet.start_y);
r->unlock();
r->dispatch_render();
return true;
@@ -130,9 +111,11 @@ struct socket_state {
return false;
switch (type) {
- case 0x00: return try_open_window();
- case 0x01: return try_update_window_region();
- case 0x02: return try_close_window();
+ case 0x00: return try_show_window();
+ case 0x01: return try_hide_window();
+ case 0x02: return try_set_window_dimensions();
+ case 0x03: return try_set_window_title();
+ case 0x04: return try_update_window_region();
default: return false;
}
@@ -144,18 +127,20 @@ struct socket_state {
euler::syscall::set_thread_name("socket thread");
+ window *w = new window();
socket_state *state = new socket_state {
- .socket = socket, .windows = {} };
+ .socket = socket, .w = w };
+
while (state->try_process_request()) ;
- r->lock();
- for (unsigned i = 0; i < state->windows.size(); ++i) {
- r->remove_window(state->windows[i]);
- delete state->windows[i];
+ if (w->is_shown) {
+ r->lock();
+ r->remove_window(w);
+ r->unlock();
}
- r->unlock();
delete state;
+ delete w;
euler::syscall::close_stream(socket);
euler::syscall::end_this_thread(0);
diff --git a/applications/goldman/source/window.hpp b/applications/goldman/source/window.hpp
index 008af2f..4d5b0e1 100644
--- a/applications/goldman/source/window.hpp
+++ b/applications/goldman/source/window.hpp
@@ -9,6 +9,10 @@ struct window {
int x;
int y;
- window(int width, int height) : contents(width, height), x(0), y(0) {}
+ bool is_shown;
+
+ std::string title;
+
+ window() : x(0), y(0), is_shown(false) {}
};
diff --git a/applications/hello/makefile b/applications/hello/makefile
index 5e12644..ea0b09a 100644
--- a/applications/hello/makefile
+++ b/applications/hello/makefile
@@ -6,7 +6,7 @@ build/%.cpp.o: source/%.cpp
$(HILBERT_CC) -c $^ -o $@
build/hello.elf: $(SOURCES:%=build/%.o)
- $(HILBERT_CC) $^ -ldaguerre -o $@
+ $(HILBERT_CC) $^ -ldaguerre -lpake -o $@
clean:
rm -rf build
diff --git a/applications/hello/source/main.cpp b/applications/hello/source/main.cpp
index 3f132c6..1f45407 100644
--- a/applications/hello/source/main.cpp
+++ b/applications/hello/source/main.cpp
@@ -1,37 +1,30 @@
-#include <goldman/protocol.hpp>
+#include <pake/widgets/fixed-text.hpp>
#include <daguerre/psf.hpp>
+#include <pake/window.hpp>
-template <class color_t>
-void overlay(color_t &to, const bool &from, const color_t &param) {
- if (from)
- to = param;
-}
+daguerre::fixed_font<bool> *font;
int main(int, char **) {
- auto bg = euler::syscall::encode_color(0xaa, 0xaa, 0xaa);
- auto fg = euler::syscall::encode_color(0x00, 0x00, 0x00);
-
- daguerre::image<daguerre::hilbert_color> image(300, 200);
- image.fill(bg);
+ font = new daguerre::fixed_font<bool>(
+ daguerre::try_load_psf("/assets/terminus-bold-18x10.psf").value());
- auto font = daguerre::try_load_psf("/assets/terminus-bold-18x10.psf");
- image.render_text(*font, fg, 10, 10, "Hello, world!", &overlay);
+ pake::widgets::fixed_text *text =
+ new pake::widgets::fixed_text("Hello, world!", font,
+ euler::syscall::encode_color(0xaa, 0xaa, 0xaa),
+ euler::syscall::encode_color(0x00, 0x00, 0x00));
- euler::syscall::stream_handle s;
- euler::syscall::connect_to_socket("hilbert.compositor", s);
+ pake::window w(300, 200, "Hello");
+ w.set_root(std::unique_ptr<pake::widget>(text));
+ w.render_and_send_to_compositor();
+ w.show();
- goldman::protocol::send_open_window(s, 300, 200);
+ //TODO: call event loop
+ euler::syscall::stream_handle h1, h2;
+ euler::syscall::create_private_socket(h1, h2);
uint8_t byte;
- euler::syscall::read_from_stream(s, 1, &byte);
-
- auto w = goldman::protocol::get_window_opened_body(s);
-
- goldman::protocol::send_update_window_region(
- s, w, 0, 0, 300, 200, image.buffer, image.buffer_pitch);
-
- euler::syscall::read_from_stream(s, 1, &byte);
- __builtin_unreachable();
+ while (1)
+ euler::syscall::read_from_stream(h1, 1, &byte);
}
diff --git a/documentation/compositor.txt b/documentation/compositor.txt
index 38bd482..8346db7 100644
--- a/documentation/compositor.txt
+++ b/documentation/compositor.txt
@@ -1,13 +1,9 @@
compositors listen on the socket id "hilbert.compositor".
-when a window is opened by an application, that window can only be referred to
-on that socket. the opaque value given in the "window opened" message refers to
-that window in future messages on that socket. it is guaranteed to be distinct
-for different windows on the same socket, and in no way guaranteed to be
-distinct for different windows on different sockets. the window is bound
-just to the socket, not to the application. if the socket where a window
-was created is gifted to a new process, the new process has complete control
-over the window, and the compositor does not need to be informed.
+there is a one-to-one correspondence between sockets to the compositor and
+windows. when a socket is opened, a window is created, and when a socket is
+closed, its window is destroyed. this socket can be gifted to another process,
+and the other process then becomes the window's owner.
data types:
@@ -18,32 +14,28 @@ data types:
color rectangle:
multiple hilbert colors, top to bottom by row, left to right within row
- window:
- opaque word (given in "window opened" message after "open window" message)
-
messages from applications to compositor:
- open window:
+ show window:
byte: 0x00
- dword: window width
- dword: window height
- update window region:
+ hide window:
byte: 0x01
- window: the window
- dword: start x
- dword: start y
- dword: width
- dword: height
- color rectangle: the data
- close window:
+ set window dimensions:
byte: 0x02
- window: the window
+ dword: width
+ dword: height
-messages from compositor to application:
+ set window title:
+ byte: 0x03
+ dword: length in bytes
+ bytes: title
- window opened:
- byte: 0x00
- window: the window
- these come in the order the open window requests were received
+ update window region:
+ byte: 0x04
+ dword: start x
+ dword: start y
+ dword: width
+ dword: height
+ color rectangle: new content
diff --git a/euler/include/cassert b/euler/include/cassert
new file mode 100644
index 0000000..415790d
--- /dev/null
+++ b/euler/include/cassert
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace euler {
+
+ [[noreturn]] inline void assert_failed() {
+ //TODO: log error and abort
+ while (1) ;
+ }
+
+}
+
+#define assert(cond) ((cond) ? (void)0 : ::euler::assert_failed());
diff --git a/euler/include/condition_variable b/euler/include/condition_variable
new file mode 100644
index 0000000..ec327eb
--- /dev/null
+++ b/euler/include/condition_variable
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <std/condition-variable.hpp>
diff --git a/euler/include/mutex b/euler/include/mutex
index 7a03381..7eefb3e 100644
--- a/euler/include/mutex
+++ b/euler/include/mutex
@@ -1,4 +1,4 @@
#pragma once
-#include <std/unique_lock.hpp>
+#include <std/unique-lock.hpp>
#include <std/mutex.hpp>
diff --git a/euler/include/std/condition-variable.hpp b/euler/include/std/condition-variable.hpp
new file mode 100644
index 0000000..0568373
--- /dev/null
+++ b/euler/include/std/condition-variable.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <mutex>
+
+namespace std {
+
+ class condition_variable {
+
+ //TODO
+
+ };
+
+}
diff --git a/euler/include/std/list.hpp b/euler/include/std/list.hpp
index 77eaaec..c0d6e21 100644
--- a/euler/include/std/list.hpp
+++ b/euler/include/std/list.hpp
@@ -19,11 +19,11 @@ namespace std {
node *the_node;
- bool operator ==(const generic_iterator &other) {
+ bool operator ==(const generic_iterator &other) const {
return the_node == other.the_node;
}
- bool operator !=(const generic_iterator &other) {
+ bool operator !=(const generic_iterator &other) const {
return the_node != other.the_node;
}
@@ -82,13 +82,14 @@ namespace std {
return iterator { .the_node = r };
}
- iterator begin() const noexcept {
- return iterator { .the_node = first_node };
- }
+ iterator begin() noexcept { return iterator { .the_node = first_node }; }
+ iterator end() noexcept { return iterator { .the_node = 0 }; }
- iterator end() const noexcept {
- return iterator { .the_node = 0 };
- }
+ const_iterator begin() const noexcept { return iterator { .the_node = first_node }; }
+ const_iterator end() const noexcept { return iterator { .the_node = 0 }; }
+
+ const_iterator cbegin() const noexcept { return iterator { .the_node = first_node }; }
+ const_iterator cend() const noexcept { return iterator { .the_node = 0 }; }
size_t remove(const T &value) {
size_t removed = 0;
@@ -140,6 +141,7 @@ namespace std {
clear();
for (node *n = other.first_node; n; n = n->next)
push_back(n->value);
+ return *this;
}
list &operator =(list &&other) {
@@ -150,6 +152,7 @@ namespace std {
other.first_node = 0;
other.last_node = 0;
other.count = 0;
+ return *this;
}
};
diff --git a/euler/include/std/unique_lock.hpp b/euler/include/std/unique-lock.hpp
index 14b3645..14b3645 100644
--- a/euler/include/std/unique_lock.hpp
+++ b/euler/include/std/unique-lock.hpp
diff --git a/euler/include/std/vector.hpp b/euler/include/std/vector.hpp
index 1c35d9d..8cd02b4 100644
--- a/euler/include/std/vector.hpp
+++ b/euler/include/std/vector.hpp
@@ -131,6 +131,12 @@ namespace std {
}
+ void clear() {
+ for (size_type i = 0; i < _size; ++i)
+ std::destroy_at(_data + i);
+ _size = 0;
+ }
+
constexpr size_type size() const noexcept {
return _size;
}
@@ -188,6 +194,18 @@ namespace std {
++_size;
}
+ using iterator = T *;
+ using const_iterator = const T *;
+
+ iterator begin() noexcept { return _data; }
+ iterator end() noexcept { return _data + _size; }
+
+ const_iterator begin() const noexcept { return _data; }
+ const_iterator end() const noexcept { return _data + _size; }
+
+ const_iterator cbegin() const noexcept { return _data; }
+ const_iterator cend() const noexcept { return _data + _size; }
+
};
}
diff --git a/libraries/daguerre/include/daguerre/image.hpp b/libraries/daguerre/include/daguerre/image.hpp
index 4c44dd0..a55f43b 100644
--- a/libraries/daguerre/include/daguerre/image.hpp
+++ b/libraries/daguerre/include/daguerre/image.hpp
@@ -55,6 +55,8 @@ namespace daguerre {
~image();
void fill(const color_t &color);
+ void fill(
+ const color_t &color, int start_x, int start_y, int width, int height);
//does not check bounds
color_t &at(int x, int y);
diff --git a/libraries/daguerre/include/daguerre/impl/image.hpp b/libraries/daguerre/include/daguerre/impl/image.hpp
index 9160951..6cf2ca9 100644
--- a/libraries/daguerre/include/daguerre/impl/image.hpp
+++ b/libraries/daguerre/include/daguerre/impl/image.hpp
@@ -104,6 +104,14 @@ namespace daguerre {
}
template <class color_t>
+ void image<color_t>::fill(
+ const color_t &color, int start_x, int start_y, int width, int height) {
+ for (int y = start_y; y < start_y + height; ++y)
+ for (int x = 0; x < start_x + width; ++x)
+ buffer[y * buffer_pitch + x] = color;
+ }
+
+ template <class color_t>
color_t &image<color_t>::at(int x, int y) {
return buffer[y * buffer_pitch + x];
}
diff --git a/libraries/goldman/include/goldman/protocol.hpp b/libraries/goldman/include/goldman/protocol.hpp
deleted file mode 100644
index b7f4d51..0000000
--- a/libraries/goldman/include/goldman/protocol.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#pragma once
-
-#include <euler/syscall.hpp>
-#include <memory>
-
-//TODO: handle stream errors, make thread safe
-
-namespace goldman::protocol {
-
- typedef euler::syscall::encoded_color color;
- typedef uint16_t window;
-
- static inline void send_open_window(
- euler::syscall::stream_handle socket, uint32_t width, uint32_t height) {
-
- struct [[gnu::packed]] {
- uint8_t type;
- uint32_t width;
- uint32_t height;
- } packet {
- .type = 0x00,
- .width = width,
- .height = height
- };
-
- euler::syscall::write_to_stream(socket, sizeof(packet), &packet);
-
- }
-
- void send_update_window_region(
- euler::syscall::stream_handle socket, window the_window,
- uint32_t start_x, uint32_t start_y, uint32_t width,
- uint32_t height, const color *the_data, size_t data_pitch) {
-
- struct [[gnu::packed]] {
- uint8_t type;
- window the_window;
- uint32_t start_x;
- uint32_t start_y;
- uint32_t width;
- uint32_t height;
- } packet_head {
- .type = 0x01,
- .the_window = the_window,
- .start_x = start_x,
- .start_y = start_y,
- .width = width,
- .height = height
- };
-
- euler::syscall::write_to_stream(socket, sizeof(packet_head), &packet_head);
- for (uint32_t y = 0; y < height; ++y)
- euler::syscall::write_to_stream(
- socket, width * sizeof(color), the_data + data_pitch * y);
-
- }
-
- void send_close_window(
- euler::syscall::stream_handle socket, window the_window) {
-
- struct [[gnu::packed]] {
- uint8_t type;
- window the_window;
- } packet {
- .type = 0x02,
- .the_window = the_window
- };
-
- euler::syscall::write_to_stream(socket, sizeof(packet), &packet);
-
- }
-
- enum class response_id : uint8_t {
- window_opened
- };
-
- window get_window_opened_body(euler::syscall::stream_handle socket) {
-
- window w;
- euler::syscall::read_from_stream(socket, sizeof(w), &w);
- return w;
-
- }
-
-}
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();
+
+ }
+
+}
diff --git a/makefile b/makefile
index c3f4ad3..8a04f0e 100644
--- a/makefile
+++ b/makefile
@@ -8,7 +8,7 @@ HILBERT_NASM = nasm -f elf64
HILBERT_CC = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-c++ -std=c++20 \
${EXTRA_CC_ARGS} -static -mno-sse -I include -I $(abspath euler/include) \
-I $(abspath libraries/daguerre/include) -I ${MINTSUKI_HEADERS_DIR} \
- -I $(abspath libraries/goldman/include)
+ -I $(abspath libraries/pake/include)
HILBERT_AR = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ar
HILBERT_LD = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ld -z noexecstack
@@ -25,6 +25,7 @@ LIBSTDCPP_DEP = toolchain/.libstdcpp-done
EULER_DEP = toolchain/.euler-done
DAGUERRE_DEP = toolchain/.daguerre-done
+PAKE_DEP = toolchain/.pake-done
APP_DEPS = ${EULER_DEP}
LIBRARY_DEPS = ${LIBSTDCPP_DEP}
@@ -37,13 +38,14 @@ run: build/disk.iso
gdb -x qemu.gdb
clean:
- rm -rf build ${EULER_DEP} ${DAGUERRE_DEP}
+ rm -rf build ${EULER_DEP} ${DAGUERRE_DEP} ${PAKE_DEP}
make -C euler clean
make -C kernel clean
make -C applications/init clean
make -C applications/goldman clean
make -C applications/hello clean
make -C libraries/daguerre clean
+ make -C libraries/pake clean
clean-dependencies: clean
rm -rf toolchain dependencies
@@ -110,6 +112,11 @@ ${DAGUERRE_DEP}: ${LIBRARY_DEPS}
cp libraries/daguerre/build/libdaguerre.a ${LIB_DIR}/
touch $@
+${PAKE_DEP}: ${LIBRARY_DEPS}
+ +make -C libraries/pake build/libpake.a
+ cp libraries/pake/build/libpake.a ${LIB_DIR}/
+ touch $@
+
kernel/build/kernel.elf: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP} ${LIMINE_DEP}
+make -C kernel build/kernel.elf
@@ -119,7 +126,7 @@ applications/init/build/init.elf: ${APP_DEPS}
applications/goldman/build/goldman.elf: ${APP_DEPS} ${DAGUERRE_DEP}
+make -C applications/goldman build/goldman.elf
-applications/hello/build/hello.elf: ${APP_DEPS} ${DAGUERRE_DEP}
+applications/hello/build/hello.elf: ${APP_DEPS} ${DAGUERRE_DEP} ${PAKE_DEP}
+make -C applications/hello build/hello.elf
build/initfs.tgz: applications/init/build/init.elf \