diff options
-rw-r--r-- | applications/clock/makefile | 12 | ||||
-rw-r--r-- | applications/clock/source/main.cpp | 63 | ||||
-rw-r--r-- | applications/init/source/main.cpp | 2 | ||||
-rw-r--r-- | documentation/kernel-interfaces/syscalls.txt | 10 | ||||
-rw-r--r-- | euler/include/ctime | 20 | ||||
-rw-r--r-- | euler/include/euler/syscall.hpp | 5 | ||||
-rw-r--r-- | euler/include/std/string.hpp | 10 | ||||
-rw-r--r-- | euler/makefile | 2 | ||||
-rw-r--r-- | euler/source/std/ctime.cpp | 58 | ||||
-rw-r--r-- | euler/source/syscall.cpp | 23 | ||||
-rw-r--r-- | kernel/include/hilbert/kernel/timer.hpp | 18 | ||||
-rw-r--r-- | kernel/include/hilbert/kernel/utility.hpp | 19 | ||||
-rw-r--r-- | kernel/makefile | 2 | ||||
-rw-r--r-- | kernel/source/entry.cpp | 2 | ||||
-rw-r--r-- | kernel/source/interrupts.asm | 26 | ||||
-rw-r--r-- | kernel/source/syscall.cpp | 30 | ||||
-rw-r--r-- | kernel/source/timer.asm | 162 | ||||
-rw-r--r-- | kernel/source/timer.cpp | 117 | ||||
-rw-r--r-- | libraries/pake/include/pake/widgets/fixed-text.hpp | 25 | ||||
-rw-r--r-- | libraries/pake/include/pake/window.hpp | 21 | ||||
-rw-r--r-- | libraries/pake/source/widgets/fixed-text.cpp | 12 | ||||
-rw-r--r-- | makefile | 9 | ||||
-rw-r--r-- | readme.txt | 10 |
23 files changed, 643 insertions, 15 deletions
diff --git a/applications/clock/makefile b/applications/clock/makefile new file mode 100644 index 0000000..949e6ce --- /dev/null +++ b/applications/clock/makefile @@ -0,0 +1,12 @@ +SOURCES = \ + main.cpp + +build/%.cpp.o: source/%.cpp + @mkdir -p $(@D) + $(HILBERT_CC) -c $^ -o $@ + +build/clock.elf: $(SOURCES:%=build/%.o) + $(HILBERT_CC) $^ -ldaguerre -lpake -o $@ + +clean: + rm -rf build diff --git a/applications/clock/source/main.cpp b/applications/clock/source/main.cpp new file mode 100644 index 0000000..3a1270d --- /dev/null +++ b/applications/clock/source/main.cpp @@ -0,0 +1,63 @@ +#include <pake/widgets/fixed-text.hpp> +#include <daguerre/psf.hpp> +#include <pake/window.hpp> +#include <ctime> + +static daguerre::fixed_font<bool> *font; + +std::string the_time() { + + time_t t = time(0); + + //convert to edt - TODO: timezones in euler + t -= 4 * 3600 * 1024; + + tm *gt = gmtime(&t); + + int hour = (gt->tm_hour - 1) % 12 + 1; + int min = gt->tm_min; + int sec = gt->tm_sec; + bool pm = gt->tm_hour >= 12; + + std::string s; + s.resize(8); + + s[0] = hour / 10 + '0'; s[1] = hour % 10 + '0'; + s[3] = min / 10 + '0'; s[4] = min % 10 + '0'; + + s[2] = sec % 2 == 0 ? ':' : ' '; + + s[5] = ' '; + s[6] = pm ? 'p' : 'a'; + s[7] = 'm'; + + if (s[0] == '0') + s.erase(0, 1); + + return s; + +} + +int main(int, char **) { + + font = new daguerre::fixed_font<bool>( + daguerre::try_load_psf("/assets/terminus/10x18-bold.psf").value()); + + pake::widgets::fixed_text *text = + new pake::widgets::fixed_text(the_time(), font, + euler::syscall::encode_color(0xaa, 0xaa, 0xaa), + euler::syscall::encode_color(0x00, 0x00, 0x00), + pake::halign::center, pake::valign::center); + + pake::window w(90, 28, "Clock"); + w.set_root(std::unique_ptr<pake::widget>(text)); + w.render_and_send_to_compositor(); + w.show(); + + while (1) { + euler::syscall::sleep(512); + text->set_text(the_time()); + w.render_and_send_to_compositor(); + } + +} diff --git a/applications/init/source/main.cpp b/applications/init/source/main.cpp index ca137a4..c281bc0 100644 --- a/applications/init/source/main.cpp +++ b/applications/init/source/main.cpp @@ -6,6 +6,6 @@ int main(int, char **) { euler::syscall::process_handle dummy; euler::syscall::start_process("/bin/compositor", {}, {}, dummy); - euler::syscall::start_process("/bin/hello", {}, {}, dummy); + euler::syscall::start_process("/bin/clock", {}, {}, dummy); return 0; } diff --git a/documentation/kernel-interfaces/syscalls.txt b/documentation/kernel-interfaces/syscalls.txt index 933ad34..f7dddba 100644 --- a/documentation/kernel-interfaces/syscalls.txt +++ b/documentation/kernel-interfaces/syscalls.txt @@ -4,6 +4,8 @@ rcx, rflags, r8-r11 are clobbered. interrupts (including the timer!) are disabled during system calls. +a "mibisecond" is a 1024th of a second + stream result: 0 = success 1 = bad handle @@ -203,3 +205,11 @@ set thread name: rax in: 24 rdi in: pointer to thread name rsi in: thread name length + +sleep: + rax in: 25 + rdi in: "mibiseconds" to sleep for + +get time: + rax in: 26 + rax out: "mibiseconds" since january 1st 2000 diff --git a/euler/include/ctime b/euler/include/ctime new file mode 100644 index 0000000..9cf1b1f --- /dev/null +++ b/euler/include/ctime @@ -0,0 +1,20 @@ +#pragma once + +#include <cstdint> + +typedef uint64_t time_t; + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +time_t time(time_t *arg); +tm *gmtime(const time_t *time); diff --git a/euler/include/euler/syscall.hpp b/euler/include/euler/syscall.hpp index 4a3daa4..043dcd4 100644 --- a/euler/include/euler/syscall.hpp +++ b/euler/include/euler/syscall.hpp @@ -159,6 +159,11 @@ namespace euler::syscall { void set_thread_name(const std::string &name); + void sleep(uint64_t mibiseconds); + + //out is mibiseconds since january 1st 2000 + uint64_t get_time(); + } #include <string> diff --git a/euler/include/std/string.hpp b/euler/include/std/string.hpp index 505ee69..c5a3d99 100644 --- a/euler/include/std/string.hpp +++ b/euler/include/std/string.hpp @@ -12,6 +12,8 @@ namespace std { std::vector<char> characters; public: + static const size_t npos = (size_t)-1; + constexpr string() : characters({'\0'}) {} constexpr string(const string &other) @@ -74,6 +76,14 @@ namespace std { return characters[pos]; } + constexpr string &erase(size_t index = 0, size_t count = npos) { + count = std::min(count, size() - index); + for (size_t i = index; i + count < size(); ++i) + characters[i] = characters[i + count]; + resize(size() - count); + return *this; + } + }; } diff --git a/euler/makefile b/euler/makefile index 62716f6..7574dea 100644 --- a/euler/makefile +++ b/euler/makefile @@ -1,6 +1,6 @@ LIBC_SOURCES = \ entry.cpp std/string.cpp std/cstring.cpp syscall.cpp std/cstdlib.cpp \ - heap.cpp syscall.asm std/cctype.cpp std/cstdio.cpp stream.cpp + heap.cpp syscall.asm std/cctype.cpp std/cstdio.cpp stream.cpp std/ctime.cpp clean: rm -rf build diff --git a/euler/source/std/ctime.cpp b/euler/source/std/ctime.cpp new file mode 100644 index 0000000..d83817a --- /dev/null +++ b/euler/source/std/ctime.cpp @@ -0,0 +1,58 @@ +#include <euler/syscall.hpp> +#include <ctime> + +time_t time(time_t *arg) { + time_t t = euler::syscall::get_time(); + if (arg) *arg = t; + return t; +} + +static tm static_tm; + +static int days_per_month[] = { + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +tm *gmtime(const time_t *time) { + + time_t t = *time / 1024; + + static_tm.tm_isdst = 0; + + static_tm.tm_sec = t % 60; t /= 60; + static_tm.tm_min = t % 60; t /= 60; + static_tm.tm_hour = t % 24; t /= 24; + static_tm.tm_wday = (t + 5) % 7 + 1; + static_tm.tm_year = (t / 1461) * 4 + 100; + + int days_into_quadyear = t % 1461; + + static_tm.tm_yday = 0; + static_tm.tm_mon = 0; + static_tm.tm_mday = 1; + + for (int i = 0; i < 48; ++i) { + if (days_into_quadyear >= days_per_month[i]) { + days_into_quadyear -= days_per_month[i]; + if (static_tm.tm_mon == 11) { + static_tm.tm_mon = 0; + static_tm.tm_yday = 0; + } + else { + ++static_tm.tm_mon; + static_tm.tm_yday += days_per_month[i]; + } + } + else { + static_tm.tm_yday += days_into_quadyear; + static_tm.tm_mday += days_into_quadyear; + break; + } + } + + return &static_tm; + +} diff --git a/euler/source/syscall.cpp b/euler/source/syscall.cpp index 0d30c4a..7637b10 100644 --- a/euler/source/syscall.cpp +++ b/euler/source/syscall.cpp @@ -407,4 +407,27 @@ namespace euler::syscall { } + void sleep(uint64_t mibiseconds) { + + uint64_t rax = 25; + uint64_t rdi = mibiseconds; + uint64_t rsi; + uint64_t rdx; + + __euler_do_syscall(rax, rdi, rsi, rdx); + + } + + uint64_t get_time() { + + uint64_t rax = 26; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + + __euler_do_syscall(rax, rdi, rsi, rdx); + return rax; + + } + } diff --git a/kernel/include/hilbert/kernel/timer.hpp b/kernel/include/hilbert/kernel/timer.hpp new file mode 100644 index 0000000..f4ce17e --- /dev/null +++ b/kernel/include/hilbert/kernel/timer.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <hilbert/kernel/application.hpp> + +namespace hilbert::kernel::timer { + + void init_timer(); + + //"mibiseconds" (1 second / 1024) since january 1st 2000 + extern uint64_t current_time; + + //when current_time >= sleeping_until, puts thread into paused threads + void register_sleeping_thread( + uint64_t sleeping_until, application::thread *thread); + + void on_timer_interrupt(); + +} diff --git a/kernel/include/hilbert/kernel/utility.hpp b/kernel/include/hilbert/kernel/utility.hpp index a21d3fe..b0ced32 100644 --- a/kernel/include/hilbert/kernel/utility.hpp +++ b/kernel/include/hilbert/kernel/utility.hpp @@ -126,6 +126,25 @@ namespace hilbert::kernel::utility { last = n; } + //if other == 0, then insert at the end + void insert_before(value_t &&value, node *other) { + node *n = new node {}; + n->value = value; + n->next = other; + if (other) { + n->prev = other->prev; + other->prev = n; + } + else { + n->prev = last; + last = n; + } + if (n->prev) + n->prev->next = n; + else + first = n; + } + void clear() { if (first) { for (node *n = first->next; n; n = n->next) diff --git a/kernel/makefile b/kernel/makefile index 6d32537..608e67e 100644 --- a/kernel/makefile +++ b/kernel/makefile @@ -2,7 +2,7 @@ SOURCES = \ storage/bd/memory.cpp storage/fs/tarfs.cpp application.asm application.cpp \ framebuffer.cpp interrupts.asm interrupts.cpp allocator.cpp storage.cpp \ syscall.cpp utility.cpp paging.asm paging.cpp entry.cpp input.cpp panic.cpp \ - vfile.cpp serial.asm app-memory.cpp load-app.cpp + vfile.cpp serial.asm app-memory.cpp load-app.cpp timer.cpp timer.asm build/%.asm.o: source/%.asm @mkdir -p $(@D) diff --git a/kernel/source/entry.cpp b/kernel/source/entry.cpp index efa70fd..73e79c7 100644 --- a/kernel/source/entry.cpp +++ b/kernel/source/entry.cpp @@ -7,6 +7,7 @@ #include <hilbert/kernel/serial.hpp> #include <hilbert/kernel/input.hpp> #include <hilbert/kernel/panic.hpp> +#include <hilbert/kernel/timer.hpp> #include <hilbert/kernel/vfile.hpp> #include <limine.h> @@ -179,6 +180,7 @@ extern "C" [[noreturn]] void entry() { if (!have_initfs) panic(0x5f8860); + timer::init_timer(); input::init_input(); application::init_applications(); diff --git a/kernel/source/interrupts.asm b/kernel/source/interrupts.asm index e4912ee..df8e7ce 100644 --- a/kernel/source/interrupts.asm +++ b/kernel/source/interrupts.asm @@ -267,6 +267,22 @@ isr_end: ret +extern on_rtc_interrupt + +rtc_isr: + + call isr_start + + call on_rtc_interrupt + + mov al, 0x20 + out 0x20, al + out 0xa0, al + + call isr_end + + iretq + extern on_keyboard_interrupt keyboard_isr: @@ -343,7 +359,7 @@ load_gdt_and_idt: out 0x21, al mov al, 0x01 out 0x21, al - mov al, 0xf9 ;mask all but irq 1 and 2 + mov al, 0xf9 ;mask all but irqs 1 and 2 out 0x21, al mov al, 0x11 @@ -354,9 +370,15 @@ load_gdt_and_idt: out 0xa1, al mov al, 0x01 out 0xa1, al - mov al, 0xef ;mask all but irq 12 + mov al, 0xee ;mask all but irqs 8 and 12 out 0xa1, al + ;register rtc interrupt + + mov rdi, 0x28 + mov rsi, rtc_isr + call set_isr + ;register keyboard and mouse interrupts mov rdi, 0x21 diff --git a/kernel/source/syscall.cpp b/kernel/source/syscall.cpp index c631df1..803f7d2 100644 --- a/kernel/source/syscall.cpp +++ b/kernel/source/syscall.cpp @@ -4,6 +4,7 @@ #include <hilbert/kernel/paging.hpp> #include <hilbert/kernel/input.hpp> #include <hilbert/kernel/panic.hpp> +#include <hilbert/kernel/timer.hpp> #include <hilbert/kernel/vfile.hpp> namespace hilbert::kernel::syscall { @@ -800,6 +801,29 @@ namespace hilbert::kernel::syscall { } + void sleep_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + + uint64_t mis = rdi; + set_zero(rax, rdi, rsi, rdx); + + auto *t = application::running_thread; + + timer::register_sleeping_thread( + timer::current_time + mis, t); + + application::yield(t->saved_state); + + } + + void get_time_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + + set_zero(rax, rdi, rsi, rdx); + rax = timer::current_time; + + } + void (*handlers[])( uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) = { @@ -827,11 +851,13 @@ namespace hilbert::kernel::syscall { &clear_socket_read_queue_syscall, &get_environment_variable_length_syscall, &get_environment_variable_value_syscall, - &set_thread_name_syscall + &set_thread_name_syscall, + &sleep_syscall, + &get_time_syscall }; - static constexpr int max_syscall_number = 24; + static constexpr int max_syscall_number = 26; } diff --git a/kernel/source/timer.asm b/kernel/source/timer.asm new file mode 100644 index 0000000..d5f6f73 --- /dev/null +++ b/kernel/source/timer.asm @@ -0,0 +1,162 @@ +bits 64 + +section .rodata + +section .text + +read_cmos_byte: +;dil in = register number +;al out = value +;rdx and rcx are not touched + + mov al, dil + out 0x70, al + in al, 0x71 + ret + +global enable_rtc_interrupts +enable_rtc_interrupts: + + ;secondary status register + mov dil, 11 + call read_cmos_byte + + ;enable interrupts + or al, 0x40 + mov cl, al + + ;do cmos write + mov al, 11 + out 0x70, al + mov al, cl + out 0x71, al + + ret + +global acknowledge_rtc_interrupt +acknowledge_rtc_interrupt: + mov dil, 12 + jmp read_cmos_byte + +convert_bcd: +;al in = byte (possibly bcd) +;al out = byte (not bcd) +;sil 0x02 = bcd +;does not touch rdx, rcx, sil + test sil, 0x02 + jz .no_convert + + mov dil, al + and dil, 0xf0 + and al, 0x0f + shr dil, 3 + add al, dil + shl dil, 2 + add al, dil + +.no_convert: + ret + +convert_hours: +;al in = byte (possibly bcd and 12 hour) +;al out = byte (not bcd or 12 hour) +;sil 0x02 = bcd, sil 0x01 = 12 hour +;does not touch rdx, rcx, sil + test sil, 0x01 + jz convert_bcd + + test al, 0x80 + jz .am + + and al, 0x7f + call convert_bcd + cmp al, 12 + je .noon + + add al, 12 + ret + +.noon: + ret + +.am: + call convert_bcd + cmp al, 12 + je .midnight + + ret + +.midnight: + xor al, al + ret + +global get_time_from_rtc +get_time_from_rtc: +;rax out = time (see timer.cpp for encoding) +;we assume the year is 20xx (sorry) + + mov dil, 11 + call read_cmos_byte + + shr al, 1 + not al + and al, 3 + mov sil, al + + xor rdx, rdx + +.outer_loop: + mov rcx, rdx + +.wait_for_update_loop: + ;status register - 0x80 is update in progress + mov dil, 10 + call read_cmos_byte + test al, 0x80 + jnz .wait_for_update_loop + + ;years + mov dil, 9 + call read_cmos_byte + call convert_bcd + mov dh, al + + ;months + mov dil, 8 + call read_cmos_byte + call convert_bcd + mov dl, al + + shl edx, 16 + + ;days + mov dil, 7 + call read_cmos_byte + call convert_bcd + mov dh, al + + ;hours + mov dil, 4 + call read_cmos_byte + call convert_hours + mov dl, al + + shl rdx, 16 + + ;minutes + mov dil, 2 + call read_cmos_byte + call convert_bcd + mov dh, al + + ;seconds + xor dil, dil + call read_cmos_byte + call convert_bcd + mov dl, al + + cmp rdx, rcx + jne .outer_loop + + mov rax, rdx + ret diff --git a/kernel/source/timer.cpp b/kernel/source/timer.cpp new file mode 100644 index 0000000..d6d37d7 --- /dev/null +++ b/kernel/source/timer.cpp @@ -0,0 +1,117 @@ +#include <hilbert/kernel/timer.hpp> + +namespace hilbert::kernel::timer { + + struct sleeping_thread { + uint64_t sleeping_until; + application::thread *thread; + }; + + //sorted ascending by sleeping_until + static utility::list<sleeping_thread> *sleeping_threads; + + uint64_t current_time; + + //output is + // seconds | (minutes << 8) | (hours << 16) | + // (days << 24) | ( months << 32) | (years << 40) + extern "C" uint64_t get_time_from_rtc(); + + //index is (year % 4) * 12 + month - 1; + //output is days from january 1st 2000 to [month] 1st [year] + static uint16_t month_table[] { + 0, 31, 60, 91, 121, 152, + 182, 213, 244, 274, 305, 335, + 366, 397, 425, 456, 486, 517, + 547, 578, 609, 639, 670, 700, + 731, 762, 790, 821, 851, 882, + 912, 943, 974, 1004, 1035, 1065, + 1096, 1127, 1155, 1186, 1216, 1247, + 1277, 1308, 1339, 1369, 1400, 1430 + }; + + //index is (year % 4) * 12 + month - 1; + //output is days in that month + static uint8_t month_table_2[] = { + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + + void clamp(uint8_t &value, uint8_t min, uint8_t max) { + if (value < min) + value = min; + else if (value > max) + value = max; + } + + extern "C" void enable_rtc_interrupts(); + + void init_timer() { + + sleeping_threads = new utility::list<sleeping_thread>(); + + uint64_t rtc_time = get_time_from_rtc(); + + uint8_t years = rtc_time >> 40; + uint8_t months = (rtc_time >> 32) & 0xff; + uint8_t days = (rtc_time >> 24) & 0xff; + uint8_t hours = (rtc_time >> 16) & 0xff; + uint8_t minutes = (rtc_time >> 8) & 0xff; + uint8_t seconds = rtc_time & 0xff; + + uint8_t month_table_index = + (years % 4) * 12 + months - 1; + + clamp( years, 0, 99); + clamp( months, 1, 12); + clamp( days, 1, month_table_2[month_table_index]); + clamp( hours, 0, 23); + clamp(minutes, 0, 59); + clamp(seconds, 0, 59); + + current_time = 1461 * (years / 4); + current_time += month_table[month_table_index]; + current_time += days - 1; + current_time *= 86400; + current_time += hours * 3600; + current_time += minutes * 60; + current_time += seconds; + current_time *= 1024; + + enable_rtc_interrupts(); + + } + + void register_sleeping_thread( + uint64_t sleeping_until, application::thread *thread) { + + auto *after = sleeping_threads->first; + while (after && after->value.sleeping_until < sleeping_until) + after = after->next; + + sleeping_threads->insert_before( + { .sleeping_until = sleeping_until, .thread = thread }, after); + + } + + extern "C" void acknowledge_rtc_interrupt(); + + extern "C" void on_rtc_interrupt() { + + ++current_time; + + while (sleeping_threads->first && + sleeping_threads->first->value.sleeping_until <= + current_time) { + application::paused_threads->insert( + sleeping_threads->first->value.thread); + sleeping_threads->remove(sleeping_threads->first); + } + + acknowledge_rtc_interrupt(); + + } + +} diff --git a/libraries/pake/include/pake/widgets/fixed-text.hpp b/libraries/pake/include/pake/widgets/fixed-text.hpp index dc2e277..fb8a49e 100644 --- a/libraries/pake/include/pake/widgets/fixed-text.hpp +++ b/libraries/pake/include/pake/widgets/fixed-text.hpp @@ -5,18 +5,36 @@ namespace pake::widgets { + //a widget that draws text with a daguerre::fixed_font<bool> class fixed_text : public widget { + //the font to use const daguerre::fixed_font<bool> *font; - daguerre::hilbert_color bg, fg; + + //background color of the widget + daguerre::hilbert_color bg; + + //color of the text + daguerre::hilbert_color fg; + + //the text to draw std::string text; + //has the text changed since the last draw to render + bool text_changed; + + //the width and height of this widget, as set by notify_size int width, height; + + //the alignment of the text within the region halign ha; valign va; public: - //TODO: look up font in some kind of catalogue + //text: the text to draw. this can be changed later by set_text. + //font: the font to use. TODO: pass a string and look up the font with that name + //bg: the background color of the widget. fg: the color of the text. + //ha, va: the alignment of the text within the widget fixed_text( std::string &&text, const daguerre::fixed_font<bool> *font, @@ -24,6 +42,9 @@ namespace pake::widgets { daguerre::hilbert_color fg, halign ha, valign va); + //change the text to draw + void set_text(std::string &&text); + virtual void render( dirtiable_image &onto, int x_off, int y_off, bool force) override; diff --git a/libraries/pake/include/pake/window.hpp b/libraries/pake/include/pake/window.hpp index bb63b9d..3f23d41 100644 --- a/libraries/pake/include/pake/window.hpp +++ b/libraries/pake/include/pake/window.hpp @@ -6,25 +6,46 @@ namespace pake { + //a window / a connection to the compositor. class window { + //the socket that connects us to the compositor euler::syscall::stream_handle socket; + //the size of the window int width; int height; + //the rendered contents of the window. pixels are dirty when + //the compositor has not been informed of them changing. dirtiable_image contents; + + //the root widget, or an unset pointer if there is no root widget set std::unique_ptr<widget> root; public: + //create a new window / connection to the compositor window(int width, int height, const std::string &title); + + //destroy the window / connection to the compositor ~window(); + //tell the compositor to show this window. you probably want to call + //set_root and render_and_send_to_compositor before calling this. void show(); + + //tell the compositor to hide this window void hide(); + //set the root widget. the widget is notified that its size is the + //size of the window, and then it is rendered with force = true. void set_root(std::unique_ptr<widget> &&w); + //get the root widget (assumes there is one) + widget *get_root(); + + //renders the root widget with force = false and + //then sends the new contents to the compositor. void render_and_send_to_compositor(); }; diff --git a/libraries/pake/source/widgets/fixed-text.cpp b/libraries/pake/source/widgets/fixed-text.cpp index c3a9a10..69c4046 100644 --- a/libraries/pake/source/widgets/fixed-text.cpp +++ b/libraries/pake/source/widgets/fixed-text.cpp @@ -15,12 +15,18 @@ namespace pake::widgets { daguerre::hilbert_color fg, halign ha, valign va) : font(font), bg(bg), fg(fg), - text(std::move(text)), ha(ha), va(va) {} + text(std::move(text)), + ha(ha), va(va) {} + + void fixed_text::set_text(std::string &&text) { + this->text = std::move(text); + text_changed = true; + } void fixed_text::render( dirtiable_image &onto, int x_off, int y_off, bool force) { - if (force) { + if (force || text_changed) { //TODO: check overflow @@ -54,6 +60,8 @@ namespace pake::widgets { *font, fg, x_off, y_off, text.data(), draw_if_true); + text_changed = false; + } } @@ -44,6 +44,7 @@ clean: make -C applications/init clean make -C applications/goldman clean make -C applications/hello clean + make -C applications/clock clean make -C libraries/daguerre clean make -C libraries/pake clean @@ -136,15 +137,21 @@ applications/goldman/build/goldman.elf: ${APP_DEPS} ${DAGUERRE_DEP} applications/hello/build/hello.elf: ${APP_DEPS} ${DAGUERRE_DEP} ${PAKE_DEP} +make -C applications/hello build/hello.elf +.PHONY: applications/clock/build/clock.elf +applications/clock/build/clock.elf: ${APP_DEPS} ${DAGUERRE_DEP} ${PAKE_DEP} + +make -C applications/clock build/clock.elf + build/initfs.tgz: applications/init/build/init.elf \ applications/goldman/build/goldman.elf \ - applications/hello/build/hello.elf + applications/hello/build/hello.elf \ + applications/clock/build/clock.elf @mkdir -p build rm -rf build/initfs cp -r skeleton build/initfs cp applications/init/build/init.elf build/initfs/bin/init cp applications/goldman/build/goldman.elf build/initfs/bin/goldman cp applications/hello/build/hello.elf build/initfs/bin/hello + cp applications/clock/build/clock.elf build/initfs/bin/clock cd build/initfs && tar czf ../initfs.tgz . build/disk.iso: kernel/build/kernel.elf build/initfs.tgz ${LIMINE_DEP} @@ -67,12 +67,16 @@ the following directories and files are released under the text in cc0.txt project structure: + - applications/clock: + a simple application that displays the current time in EDT. + - applications/goldman: - the default compositor, in a very early stage + the default compositor. - applications/init: - the initial program loaded by the kernel. currently it just - (attempts to) start /bin/compositor and then /bin/hello. + the initial program loaded by the kernel. currently it just starts the + compositor and the clock, but in the future it will read some kind of + configuration file and decide what to do based on that. - documentation: documentation. currently this directory is a bit disorganized, and has |