diff options
61 files changed, 1118 insertions, 885 deletions
diff --git a/bochsrc b/bochsrc deleted file mode 100644 index 2c576c0..0000000 --- a/bochsrc +++ /dev/null @@ -1,5 +0,0 @@ -ata0-master: type=disk, mode=flat, path=out/disk.img -boot: disk -megs: 512 - -com1: enabled=1, mode=socket-server, dev=localhost:2345
\ No newline at end of file diff --git a/doc/internal/fstab.txt b/doc/internal/fstab.txt new file mode 100644 index 0000000..de2f3a6 --- /dev/null +++ b/doc/internal/fstab.txt @@ -0,0 +1,9 @@ +header: + uint32_t: number of entries + +for each entry: + uint32_t: uid + uint8_t: prefix length + chars: prefix + prefix has a trailing / if necessary + prefix does not have a leading /
\ No newline at end of file diff --git a/doc/ints.txt b/doc/ints.txt index eed79fa..8c755e0 100644 --- a/doc/ints.txt +++ b/doc/ints.txt @@ -33,19 +33,19 @@ table 1: function | eax | eax out | ebx | ecx | edx | esi | edi -------------------|------|-----------------|----------------|----------------|--------------|--------------|-------------- - open file | 0x00 | handle | drive number | path | | | + open file | 0x00 | handle | path | | | | close file | 0x01 | | handle | | | | file read | 0x02 | read | handle | file offset | count | buffer | get file size | 0x03 | size | handle | | | | - start task | 0x04 | handle | drive number | path | passed sz | passed dword | + start task | 0x04 | handle | path | passed sz | passed dword | | ipc send | 0x05 | written | task handle | max count | buffer | | ipc read | 0x06 | read | task handle | max count | buffer | | allocate ram | 0x07 | start pointer | pages | | | | memory info | 0x08 | see table 2 | see table 2 | | | | wait for task | 0x09 | | handle | | | | - enumerate dir | 0x0a | count | drive number | path | see table 3 | max | + enumerate dir | 0x0a | count | path | see table 3 | max | | system log | 0x0b | | message sz | | | | - count of dir | 0x0c | number of files | drive number | path | | | + count of dir | 0x0c | number of files | path | | | | new window | 0x0d | window handle | width | height | pixel buffer | | delete window | 0x0e | | window handle | | | | resize window | 0x0f | | window handle | width | height | pixel buffer | diff --git a/fs-skel/sys/startup.rc b/fs-skel/sys/startup.rc index c5fdb5d..6732da7 100644 --- a/fs-skel/sys/startup.rc +++ b/fs-skel/sys/startup.rc @@ -1 +1 @@ -bin/mkpopup Welcome to Portland OS!\n\nPress Win+Space to open a terminal with a shell.\nClick on a window to bring it to the top of the stack.\nLeft click and drag a window while holding Alt to move it.\nRight click on a window while holding Alt to send it to the bottom.\nType "dirlist bin" into a shell for a list of programs.\n\nPress Alt+F4 to close this window.
\ No newline at end of file +/bin/mkpopup Welcome to Portland OS!\n\nPress Win+Space to open a terminal with a shell.\nClick on a window to bring it to the top of the stack.\nLeft click and drag a window while holding Alt to move it.\nRight click on a window while holding Alt to send it to the bottom.\nType "dirlist bin" into a shell for a list of programs.\n\nPress Alt+F4 to close this window.
\ No newline at end of file diff --git a/fs-skel/sys/winspace.rc b/fs-skel/sys/winspace.rc index 3d038c5..b050f26 100644 --- a/fs-skel/sys/winspace.rc +++ b/fs-skel/sys/winspace.rc @@ -1 +1 @@ -bin/terminal bin/highway
\ No newline at end of file +/bin/terminal /bin/highway
\ No newline at end of file diff --git a/fs-skel/user/default.rc b/fs-skel/user/default.rc index 568c546..0178824 100644 --- a/fs-skel/user/default.rc +++ b/fs-skel/user/default.rc @@ -1 +1 @@ -set _path bin/
\ No newline at end of file +set _path /bin/
\ No newline at end of file @@ -14,9 +14,11 @@ out/disk.vdi: out/disk.img out/disk.img: out/kernel.bin out/boot.bin out/fs mkdir -p obj mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 129 -s 1 -S 512 obj/shadow.img 8192 + echo -n -e '\x01\x00\x00\x00uid \x00\x00\x00\x00' > out/fs/_fstab + dd if=obj/shadow.img of=out/fs/_fstab bs=1 seek=4 skip=39 count=4 conv=notrunc echo -n -e '\xeb\x3c' > obj/jmp.bin - dd if=obj/jmp.bin of=obj/shadow.img obs=2 conv=notrunc - dd if=out/boot.bin of=obj/shadow.img obs=1 seek=62 conv=notrunc + dd if=obj/jmp.bin of=obj/shadow.img bs=1 conv=notrunc + dd if=out/boot.bin of=obj/shadow.img bs=1 seek=62 conv=notrunc dd if=out/kernel.bin of=obj/shadow.img seek=1 conv=notrunc mv obj/shadow.img out/disk.img mcopy -i out/disk.img -s out/fs/* ::/ @@ -24,11 +26,11 @@ out/disk.img: out/kernel.bin out/boot.bin out/fs clean: rm -r obj out || true -qemu: out/disk.img +gdb: out/disk.img gdb -x qemu.gdb -bochs: out/disk.img - bochs -q +ddd: out/disk.img + ddd --debugger 'gdb -x qemu.gdb' out/fs/bin/%: obj/%.elf mkdir -p $(shell dirname $@) @@ -40,7 +42,7 @@ out/fs/bin/%: obj/%.elf out/fs: out/fs/bin/init out/fs/bin/highway out/fs/bin/meminfo \ out/fs/bin/terminal out/fs/bin/hello out/fs/bin/mkpopup \ - out/fs/bin/dirlist out/fs/bin/time \ + out/fs/bin/dirlist out/fs/bin/time \ out/fs/bin/filetest out/fs/bin/settings touch out/fs cp -r fs-skel/* out/fs/ @@ -106,7 +108,8 @@ obj/raleigh.so: obj/raleigh/runtime.po obj/raleigh/window.po \ obj/raleigh/w/vbox.po obj/raleigh/w/entry.po \ obj/raleigh/w/label.po obj/raleigh/w/colorpicker.po \ obj/raleigh/w/hbox.po obj/raleigh/w/multicontainer.po \ - obj/raleigh/d/dialog.po obj/raleigh/d/saving_window.po + obj/raleigh/d/dialog.po obj/raleigh/d/saving_window.po \ + obj/raleigh/s/text_flower.po ld ${partlink} $^ -o $@ obj/init.elf: obj/init/init.o obj/knob.so obj/c.rto @@ -118,7 +121,7 @@ obj/highway.elf: obj/highway/main.o obj/highway/cmds.o obj/highway/line.o \ ld ${clink} $^ -o $@ obj/meminfo.elf: obj/meminfo/meminfo.po obj/raleigh.so obj/libfont.so \ - obj/knob.so obj/cxx.rto + obj/knob.so obj/cxx.rto ld ${cxxlink} $^ -o $@ obj/terminal.elf: obj/terminal/main.o obj/libfont.so obj/knob.so \ @@ -136,10 +139,6 @@ obj/dirlist.elf: obj/dirlist/main.o obj/libterm.so obj/knob.so \ obj/c.rto ld ${clink} $^ -o $@ -#obj/ttt.elf: obj/ttt/main.o obj/popups.so obj/libfont.so \ -# obj/knob.so obj/c.rto -# ld ${clink} $^ -o $@ - obj/time.elf: obj/time/time.o obj/libterm.so obj/knob.so \ obj/c.rto ld ${clink} $^ -o $@ @@ -148,9 +147,8 @@ obj/filetest.elf: obj/filetest/filetest.o obj/libterm.so obj/knob.so \ obj/c.rto ld ${clink} $^ -o $@ -obj/settings.elf: obj/settings/main.po obj/settings/str_editor.po \ - obj/settings/model.po obj/settings/color_editor.po \ - obj/settings/editor.po \ +obj/settings.elf: obj/settings/main.po obj/settings/model.po \ + obj/settings/string_kind.po obj/settings/color_kind.po \ obj/raleigh.so obj/libfont.so \ obj/knob.so obj/cxx.rto ld ${cxxlink} $^ -o $@
\ No newline at end of file diff --git a/src/kernel/drive.c b/src/kernel/drive.c index bc1c67d..6a1d12e 100644 --- a/src/kernel/drive.c +++ b/src/kernel/drive.c @@ -1,5 +1,7 @@ #include "drive.h" #include "panic.h" +#include "pmap.h" +#include "util.h" #include "fat.h" #include "log.h" @@ -40,6 +42,7 @@ static inline void determine_fs(struct drive *d) { if (try_fat_init_drive(d)) return; + d->mapped_to = 0; d->fs_type = "Unknown"; d->get_file = &unknown_get_file; d->free_file = &unknown_no_call; @@ -58,7 +61,83 @@ static inline void determine_fs(struct drive *d) { //do not need to make ready or done void commit_drive(struct drive data) { determine_fs(&data); + data.mapped_to = 0; drives[n_drives] = data; data.done(drives + n_drives); ++n_drives; +} + +void map_path(const char *full, struct drive **d, const char **path) { + *d = 0; + *path = 0; + + switch (full[0]) { + case '/': + for (struct drive *i = drives; i < drives + n_drives; ++i) { + if (!i->mapped_to) + continue; + uint32_t j = 0; + while (1) { + if (!i->mapped_to[j]) { + if (!*path || (j >= *path - full)) { + *path = full + j + 1; + *d = i; + } + break; + } + else if (i->mapped_to[j] != full[j + 1]) + break; + ++j; + } + } + return; + + uint32_t id; + case ':': + id = 0; + for (uint32_t i = 1; i < 9; ++i) { + id *= 16; + const char c = full[i]; + if ((c >= '0') && (c <= '9')) + id += c - '0'; + else if ((c >= 'a') && (c <= 'f')) + id += c - 'a' + 10; + else + return; + } + if (full[9] != ':') + return; + for (struct drive *i = drives; i < drives + n_drives; ++i) + if (i->uid == id) { + *d = i; + *path = full + 10; + return; + } + } +} + +void map_drives() { + for (struct drive *d = drives; d < drives + n_drives; ++d) { + file_id_t fid = d->get_file(d, "_fstab"); + if (!fid) + continue; + + const uint32_t len = d->get_file_length(d, fid); + void *fstab = allocate_kernel_pages(len / 512 + 1); + fmcpy(fstab, d, fid, 0, len); + d->free_file(d, fid); + const uint32_t n_entries = *(uint32_t *)fstab; + + uint32_t next_id = *(uint32_t *)(fstab + 4); + fstab += 8; + for (uint32_t i = 0; i < n_entries; ++i) { + for (struct drive *dd = drives; dd < drives + n_drives; ++dd) + if (dd->uid == next_id) + dd->mapped_to = fstab + 4; + const uint32_t plen = *(uint32_t *)fstab; + next_id = *(uint32_t *)(fstab + 4 + plen); + *(char *)(fstab + 4 + plen) = '\0'; + fstab += 8 + plen; + } + } }
\ No newline at end of file diff --git a/src/kernel/drive.h b/src/kernel/drive.h index d09365d..e307324 100644 --- a/src/kernel/drive.h +++ b/src/kernel/drive.h @@ -22,6 +22,8 @@ struct directory_content_info { struct drive { char *drive_type; char *fs_type; + char *mapped_to; + uint32_t uid; uint32_t (*read_sectors) (const struct drive *d, uint32_t start, uint32_t count, void *buffer); uint32_t (*write_sectors)(const struct drive *d, uint32_t start, uint32_t count, const void *buffer); @@ -43,11 +45,14 @@ struct drive { fs_id_t fs_id; }; +void map_path(const char *full, struct drive **d, const char **path); + extern uint8_t n_drives; extern struct drive drives[MAX_DRIVES]; void init_drives(); void commit_drive(struct drive data); +void map_drives(); extern bool ignore_already_open; diff --git a/src/kernel/fat.c b/src/kernel/fat.c index b342267..008988c 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -521,6 +521,7 @@ bool try_fat_init_drive(struct drive *d) { return false; d->fs_type = "FAT16"; + d->uid = next_fi->volume_id; d->get_file = &fat_get_file; d->free_file = &fat_free_file; d->load_sector = &fat_load_sector; diff --git a/src/kernel/idt.c b/src/kernel/idt.c index 8de5448..61966e0 100644 --- a/src/kernel/idt.c +++ b/src/kernel/idt.c @@ -34,60 +34,95 @@ struct { .start = (uint32_t)idt }; -//file handles as (drive_number << 8) + file_id_t +bool verify_file_handle(uint32_t handle, struct drive **d, uint32_t *f) { + *d = drives + (handle >> 24); + *f = handle & 0x00ffffff; -uint32_t sc_open_file(uint32_t drive_number, char *path) { - return (drive_number << 8) + drives[drive_number].get_file(drives + drive_number, path); + if (!*f || (*d >= drives + n_drives)) { + logf(LOG_WARN, "syscall with file handle 0x%h", handle); + return false; + } + else + return true; +} + +uint32_t sc_open_file(const char *path) { + struct drive *did; + const char *sub; + map_path(path, &did, &sub); + if (!did) + return 0; + + const file_id_t fid = did->get_file(did, sub); + return fid ? ((did - drives) << 24) + fid : 0; } void sc_close_file(uint32_t handle) { - if (!handle) - return; - drives[handle >> 8].free_file(drives + (handle >> 8), handle & 0xff); + struct drive *d; + uint32_t f; + if (verify_file_handle(handle, &d, &f)) + d->free_file(d, f); } uint32_t sc_file_get_size(uint32_t handle) { - if (!handle) + struct drive *d; + uint32_t f; + if (verify_file_handle(handle, &d, &f)) + return d->get_file_length(d, f); + else return 0; - return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff); } void sc_file_set_size(uint32_t handle, uint32_t new_size) { - if (!handle) - return; - drives[handle >> 8].set_file_length(drives + (handle >> 8), handle & 0xff, new_size); + struct drive *d; + uint32_t f; + if (verify_file_handle(handle, &d, &f)) + d->set_file_length(d, f, new_size); } uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { - if (!handle) + struct drive *d; + uint32_t f; + if (verify_file_handle(handle, &d, &f)) { + const uint32_t l = d->get_file_length(d, f); + if (file_offset >= l) + return 0; + if (file_offset + count > l) + count = l - file_offset; + fmcpy(buffer, d, f, file_offset, count); + return count; + } + else return 0; - uint32_t len = sc_file_get_size(handle); - if (file_offset + count > len) - count = len - file_offset; - fmcpy(buffer, drives + (handle >> 8), handle & 0xff, file_offset, count); - return count; } uint32_t sc_file_write(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { - if (!handle) + struct drive *d; + uint32_t f; + if (verify_file_handle(handle, &d, &f)) { + if (!d->is_writable(d, f)) + return 0; + const uint32_t l = d->get_file_length(d, f); + if (file_offset >= l) + return 0; + if (file_offset + count > l) + count = l - file_offset; + mfcpy(d, f, file_offset, buffer, count); + return l; + } + else return 0; - const struct drive *const d = drives + (handle >> 8); - const fs_id_t fid = handle & 0xff; +} - if (!d->is_writable(d, fid)) +uint32_t sc_start_task(char *path, const char *pass, uint32_t io_task) { + struct drive *d; + const char *f; + map_path(path, &d, &f); + if (!d) return 0; - const uint32_t l = d->get_file_length(d, fid); - if (file_offset + count > l) - count = l - file_offset; - - mfcpy(d, fid, file_offset, buffer, count); - return count; -} - -uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t io_task) { switch_to_kernel_cr3(); - uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass, io_task); + uint32_t process_id = try_elf_run(d, vma_to_pma(active_task->page_directory, f), pass, io_task); switch_to_task_cr3(); return process_id; } @@ -126,12 +161,18 @@ void sc_wait_for_task(uint32_t handle) { add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1}); } -uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct directory_content_info *buffer, uint32_t max_entries) { //not static to ensure sysv abi - return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries); +uint32_t sc_enumerate_dir(const char *path, struct directory_content_info *buffer, uint32_t max_entries) { //not static to ensure sysv abi + struct drive *d; + const char *f; + map_path(path, &d, &f); + return d ? d->enumerate_dir(d, f, buffer, max_entries) : 0; } -uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { - return drives[drive_number].n_dir_entries(drives + drive_number, path); +uint32_t sc_count_of_dir(const char *path) { + struct drive *d; + const char *f; + map_path(path, &d, &f); + return d ? d->n_dir_entries(d, f) : 0; } void sc_get_next_window_action(struct window *w, struct window_action *action) { diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c index ce25397..3c49382 100644 --- a/src/kernel/kbd.c +++ b/src/kernel/kbd.c @@ -10,8 +10,8 @@ #include "kbd.h" #include "log.h" -#define SCANTAB_DIR "sys/scantabs/" -#define SCANTAB_DIR_LEN 13 +#define SCANTAB_DIR "/sys/scantabs/" +#define SCANTAB_DIR_LEN 14 enum { PS2_CMD = 0x64, @@ -97,7 +97,10 @@ void init_kbd() { scantab_path[SCANTAB_DIR_LEN + layout_len + 3] = 't'; scantab_path[SCANTAB_DIR_LEN + layout_len + 4] = '\0'; logf(LOG_INFO, "Using scantab file at \"%s\".", scantab_path); - file_id_t stf = drives->get_file(drives, scantab_path); + struct drive *d; + const char *f; + map_path(scantab_path, &d, &f); + file_id_t stf = drives->get_file(d, f); if (!stf) PANIC("could not load scantab file."); diff --git a/src/kernel/log.c b/src/kernel/log.c index 2819a2e..6bdda84 100644 --- a/src/kernel/log.c +++ b/src/kernel/log.c @@ -7,8 +7,8 @@ #define LOG_COM COM1 void init_log() { - //TODO: move old "sys/current.log" - //TODO: open new "sys/current.log" + //TODO: move old "/sys/current.log" + //TODO: open new "/sys/current.log" } static const char *const log_prefixes[] = { diff --git a/src/kernel/main.c b/src/kernel/main.c index 951e37f..24ec58f 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -40,6 +40,8 @@ void main() { ignore_already_open = true; + map_drives(); + init_log(); init_settings(); @@ -64,10 +66,15 @@ void main() { logf(LOG_INFO, ""); logf(LOG_INFO, "Drives:"); - for (uint8_t i = 0; i < n_drives; ++i) { - const struct drive *d = &drives[i]; + for (struct drive *d = drives; d < drives + n_drives; ++d) { const uint32_t free = d->get_free_sectors(d); - logf(LOG_INFO, " %s: %d%sk, %s (%d%sk free)", d->drive_type, d->n_sectors / 2, d->n_sectors % 2 ? ".5" : "", d->fs_type, free / 2, free % 2 ? ".5" : ""); + logf(LOG_INFO, " :%h:", d->uid); + logf(LOG_INFO, " %s (%d%skB free)", d->fs_type, free / 2, free % 2 ? ".5" : ""); + logf(LOG_INFO, " on %s (%d%skB)", d->drive_type, d->n_sectors / 2, d->n_sectors % 2 ? ".5" : ""); + if (d->mapped_to) + logf(LOG_INFO, " mapped to /%s", d->mapped_to); + else + logf(LOG_INFO, " not mapped"); } logf(LOG_INFO, ""); diff --git a/src/kernel/settings.c b/src/kernel/settings.c index 419341a..77f5ef8 100644 --- a/src/kernel/settings.c +++ b/src/kernel/settings.c @@ -5,7 +5,7 @@ #include <stdint.h> -#define SETTINGS_FILE "sys/settings.pls" +#define SETTINGS_FILE "/sys/settings.pls" static struct { uint32_t main_start; @@ -41,8 +41,13 @@ void close_settings() { fid = 0; } +#include "log.h" + void init_settings() { - fid = drives->get_file(drives, SETTINGS_FILE); + struct drive *d; + const char *f; + map_path(SETTINGS_FILE, &d, &f); + fid = drives->get_file(d, f); if (!fid) PANIC("could not open settings file at \"" SETTINGS_FILE "\"."); diff --git a/src/kernel/window.c b/src/kernel/window.c index 69babe4..9398420 100644 --- a/src/kernel/window.c +++ b/src/kernel/window.c @@ -409,7 +409,7 @@ struct window_action next_window_action(struct window *w) { return *action; } -#define RUN_COMMAND_FILE "sys/winspace.rc" +#define RUN_COMMAND_FILE "/sys/winspace.rc" enum wm_action { WM_MOVE_LEFT, @@ -462,7 +462,10 @@ void init_win() { mouse_y = (VBE_MODE_INFO->height - MOUSE_HEIGHT) / 2; blit_mouse(); - const file_id_t fid = drives->get_file(drives, RUN_COMMAND_FILE); + const struct drive *d; + const char *f; + map_path(RUN_COMMAND_FILE, &d, &f); + const file_id_t fid = drives->get_file(d, f); if (!fid) PANIC("Couldn't open " RUN_COMMAND_FILE "."); @@ -519,8 +522,11 @@ void on_action(struct window_action packet) { paint_all(); } break; + const struct drive *d; + const char *f; case WM_RUN_COMMAND: - if (!try_elf_run(drives, run_command, run_command_pass, 0)) + map_path(run_command, &d, &f); + if (!try_elf_run(d, f, run_command_pass, 0)) logf(LOG_ERROR, "Couldn't run program listed in " RUN_COMMAND_FILE "."); break; } diff --git a/src/user/filetest/filetest.c b/src/user/filetest/filetest.c index e7792ff..af01e1c 100644 --- a/src/user/filetest/filetest.c +++ b/src/user/filetest/filetest.c @@ -1,7 +1,7 @@ #include <libterm/terminal.h> #include <knob/file.h> -#define TEST_FILE "user/test.txt" +#define TEST_FILE "/user/test.txt" void main() { struct file *f = open_file(TEST_FILE); diff --git a/src/user/highway/main.c b/src/user/highway/main.c index bcc3e01..8aa40b8 100644 --- a/src/user/highway/main.c +++ b/src/user/highway/main.c @@ -8,7 +8,7 @@ #include "vars.h" void main(const char *arg) { - source(*arg ? arg : "user/default.rc"); + source(*arg ? arg : "/user/default.rc"); ensure_color(); term_add_sz("Portland Highway\nType \"help\" for help.\n"); diff --git a/src/user/include/cxx/raleigh/d/dialog.h b/src/user/include/cxx/raleigh/d/dialog.h index f207033..1712b03 100644 --- a/src/user/include/cxx/raleigh/d/dialog.h +++ b/src/user/include/cxx/raleigh/d/dialog.h @@ -14,15 +14,21 @@ namespace raleigh { YES, NO, CANCEL, - RETRY + RETRY, + OKAY }; - extern alist<duple<const char *, diag_result_t>> &yes_no_cancel; - extern alist<duple<const char *, diag_result_t>> &yes_no_retry; + + typedef alist<duple<const char *, diag_result_t>> button_list; + extern button_list &yes_no_cancel; + extern button_list &yes_no_retry; + extern button_list &okay_cancel; + extern button_list &okay; + class dialog : public window { public: //button names are copied //alist isn't needed past constructor - dialog(widget &top_part, alist<duple<const char *, diag_result_t>> buttons); + dialog(widget &top_part, button_list buttons); //zero means not set yet diag_result_t result; diff --git a/src/user/include/cxx/raleigh/s/text_flower.h b/src/user/include/cxx/raleigh/s/text_flower.h new file mode 100644 index 0000000..f5cfcca --- /dev/null +++ b/src/user/include/cxx/raleigh/s/text_flower.h @@ -0,0 +1,40 @@ +#ifndef RALEIGH_S_TEXT_FLOWER_H +#define RALEIGH_S_TEXT_FLOWER_H + +#include <libfont/fonts.h> +#include <structs/alist.h> + +namespace raleigh { + class text_flower { + public: + //max_rows or cols 0 means no limit + //s is not copied + text_flower(const char *s, uint32_t cols=50, uint32_t max_rows=0); + + uint32_t get_n_lines() __attribute__ ((pure)); + //not a copy + char *get_nth_line(uint32_t n) __attribute__ ((pure)); + uint32_t get_line_offset(uint32_t n) __attribute__ ((pure)); + + void draw_text(_pixel_t *start, uint32_t pitch, const struct font_info *fi, _pixel_t color); + void flow_text(); + + //call flow_text after any changes + const char *s; + + private: + alist<char *> lines; + alist<uint32_t> offsets; + + uint32_t max_rows; + uint32_t cols; + + //for use inside flow_text + const char *on_char; + const char *line_start; + uint32_t row_len; + void push_line(); + }; +} + +#endif
\ No newline at end of file diff --git a/src/user/include/cxx/raleigh/util.h b/src/user/include/cxx/raleigh/util.h index 9142b69..c366e80 100644 --- a/src/user/include/cxx/raleigh/util.h +++ b/src/user/include/cxx/raleigh/util.h @@ -5,6 +5,9 @@ #define RGB(R, G, B) ((_pixel_t){.r = 0x##R, .g = 0x##G, .b = 0x##B}) +#define RALEIGH_FG RGB(00, 00, 00) +#define RALEIGH_BG RGB(bf, bf, bf) + namespace raleigh { struct coord { uint32_t x; @@ -14,6 +17,7 @@ namespace raleigh { }; void show_error_and_quitf(const char *fmt, ...) __attribute__ ((noreturn)); + void show_error_popup_and_quitf(const char *fmt, ...) __attribute__ ((noreturn)); } #endif
\ No newline at end of file diff --git a/src/user/include/cxx/raleigh/w/entry.h b/src/user/include/cxx/raleigh/w/entry.h index c86b281..cc797b0 100644 --- a/src/user/include/cxx/raleigh/w/entry.h +++ b/src/user/include/cxx/raleigh/w/entry.h @@ -1,72 +1,61 @@ #ifndef RALEIGH_W_ENTRY_H #define RALEIGH_W_ENTRY_H +#include <raleigh/s/text_flower.h> #include <raleigh/widget.h> #include <libfont/fonts.h> namespace raleigh { class entry : public widget { public: - //default_text's data is copied, so it's okay if it changes or if the memory is freed entry(uint32_t rows=25, uint32_t cols=25, const char *default_text="", - const char *font="fixed-10", _pixel_t bg=RGB(ff, ff, ff), + const struct font_info *fi=get_font("fixed-10"), _pixel_t bg=RGB(ff, ff, ff), _pixel_t fg=RGB(00, 00, 00), _pixel_t border_color=RGB(00, 00, 00)); //not a copy - const char *get_contents(); - //s's data is copied + const char *get_contents() __attribute__ ((pure)); + //s is copied void set_contents(const char *s); - void notify_window_change() override; void paint(_pixel_t *pixbuf, uint32_t pitch) override; - void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override; void notify_has_opaque_parent(widget *parent) override; + void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override; void handle_key(struct key_packet kp) override; void on_focus() override; void on_unfocus() override; + private: + const struct font_info *fi; + _pixel_t border_color; + _pixel_t fg; + _pixel_t bg; uint32_t rows; uint32_t cols; - _pixel_t bg; - _pixel_t fg; - _pixel_t border_color; - struct font_info *fi; - char *data; - //line_indices[end_y + 1] == end_d - uint32_t *line_indices; + void left(); + void right(); + void up(); + void down(); - uint32_t cur_y; - uint32_t cur_x; - uint32_t cur_d; + void check_y(); + void check_x(); - //the row of the last character - uint32_t end_y; - //the column after the last character - uint32_t end_x; - //the index of the null terminator - uint32_t end_d; + void on_text_change(); + void on_cursor_change(); - bool has_focus; - bool had_focus_last_paint; - bool text_changed_since_last_paint; - uint32_t cur_y_last_paint; - uint32_t cur_x_last_paint; - uint32_t cur_d_last_paint; + alist<char> text_back; + text_flower flower; - //uses cur_x, not cur_d; sets both - //will not modify cur_y - void ensure_cursor_in_line(); + bool text_change; + bool cursor_change; - void paint_text(_pixel_t *pixbuf, uint32_t pitch); - //sets line_indices[from_y + 1 .. end_y + 1], end_y, end_x and end_d - void get_indices(uint32_t from_y, uint32_t from_x, uint32_t from_d); + bool was_cur_before; + uint32_t old_cur_x; + uint32_t old_cur_y; - //these four return true on success, and do not send a paint request to the window - bool cursor_left(); - bool cursor_right(); - bool cursor_up(); - bool cursor_down(); + bool is_cur; + uint32_t cur_x; + uint32_t cur_y; }; } diff --git a/src/user/include/cxx/raleigh/w/label.h b/src/user/include/cxx/raleigh/w/label.h index a78ce46..ebc6890 100644 --- a/src/user/include/cxx/raleigh/w/label.h +++ b/src/user/include/cxx/raleigh/w/label.h @@ -1,6 +1,7 @@ #ifndef RALEIGH_W_LABEL_H #define RALEIGH_W_LABEL_H +#include <raleigh/s/text_flower.h> #include <raleigh/widget.h> #include <libfont/fonts.h> @@ -8,20 +9,27 @@ namespace raleigh { class label : public widget { public: //value's data is copied - label(const char *value, const char *font="fixed-10", bool bg_transparent=true, - _pixel_t fg=RGB(00, 00, 00), _pixel_t bg=RGB(bf, bf, bf)); + label(const char *value, const char *font="fixed-10", + uint32_t cols=0, bool bg_transparent=true, + _pixel_t fg=RALEIGH_FG, _pixel_t bg=RALEIGH_BG); + ~label(); + + //new_value's data is copied void change_value(const char *new_value); void paint(_pixel_t *pixbuf, uint32_t pitch) override; void notify_has_opaque_parent(widget *parent) override; private: - char *value; - uint32_t v_size; const struct font_info *const fi; + uint32_t cols; bool bg_transparent; const _pixel_t fg; const _pixel_t bg; + + text_flower tf; + + coord determine_size(); }; } diff --git a/src/user/include/cxx/raleigh/widget.h b/src/user/include/cxx/raleigh/widget.h index b53718a..cbd499c 100644 --- a/src/user/include/cxx/raleigh/widget.h +++ b/src/user/include/cxx/raleigh/widget.h @@ -12,7 +12,7 @@ namespace raleigh { namespace raleigh { class widget { public: - //these three are set by window class (or parent widget) + //these four are set by window class (or parent widget) widget *parent;//set to zero when root widget window *w; coord window_offset; diff --git a/src/user/include/cxx/raleigh/window.h b/src/user/include/cxx/raleigh/window.h index 3448536..63a3786 100644 --- a/src/user/include/cxx/raleigh/window.h +++ b/src/user/include/cxx/raleigh/window.h @@ -20,7 +20,7 @@ namespace raleigh { friend void start_runtime(); public: //pass on_close to specify a close handler. if on_close returns false, the window will not be closed. - window(widget &root, _pixel_t bg_color=RGB(bf, bf, bf), bool (*on_close)(window_tag_t)=0, window_tag_t tag=0); + window(widget &root, _pixel_t bg_color=RALEIGH_BG, bool (*on_close)(window_tag_t)=0, window_tag_t tag=0); void add_keybind(struct key_packet kp, void (*handler)(window_tag_t)); void notify_needs_paint(widget &from); diff --git a/src/user/include/cxx/structs/alist.h b/src/user/include/cxx/structs/alist.h index 050f775..13a24c4 100644 --- a/src/user/include/cxx/structs/alist.h +++ b/src/user/include/cxx/structs/alist.h @@ -15,20 +15,67 @@ public: uint32_t expand_by; data *buf; - alist(uint32_t default_size=10, uint32_t expand_by=10) + alist(uint32_t default_size = 10, uint32_t expand_by = 10) : n_entries(0), buf_size(default_size), expand_by(expand_by), - buf((data *)get_block(default_size * sizeof(data))) {} + buf(new data[default_size]) {} + + //from is copied + alist(const data *from, uint32_t count, uint32_t extra_size = 10, uint32_t expand_by = 10) + : n_entries(count), buf_size(count + extra_size), expand_by(expand_by), + buf(new data[count + extra_size]) { + for (uint32_t i = 0; i < count; ++i) + buf[i] = from[i]; + } + + ~alist() { + delete[] buf; + } + + void copy_from(const data *from, uint32_t count) { + expand_to(count); + n_entries = count; + for (uint32_t i = 0; i < count; ++i) + buf[i] = from[i]; + } + + void expand_to(uint32_t size) { + if (size <= buf_size) + return; + data *const new_buf = new data[size * sizeof(data)]; + for (uint32_t i = 0; i < buf_size; ++i) + new_buf[i] = buf[i]; + delete[] buf; + buf = new_buf; + buf_size = size; + } + + void copy_from(const alist<data> &other) { + expand_to(n_entries = other.n_entries); + for (uint32_t i = 0; i < n_entries; ++i) + buf[i] = other.buf[i]; + } void add_back(data d) { - if (n_entries == buf_size) { - data *const new_buf = (data *)get_block((buf_size += expand_by) * sizeof(data)); - blockcpy(new_buf, buf, n_entries * sizeof(data)); - free_block(buf); - buf = new_buf; - } + if (n_entries == buf_size) + expand_to(buf_size + expand_by); buf[n_entries++] = d; } + void insert(uint32_t i, data d) { + if (n_entries == buf_size) + expand_to(buf_size + expand_by); + for (uint32_t n = n_entries; n > i; --n) + buf[n] = buf[n - 1]; + buf[i] = d; + ++n_entries; + } + + void remove(uint32_t i) { + --n_entries; + for (uint32_t n = i; n < n_entries; ++n) + buf[n] = buf[n + 1]; + } + //returns -1 if not found uint32_t index_of(data d) { for (uint32_t i = 0; i < n_entries; ++i) diff --git a/src/user/include/cxx/structs/duple.h b/src/user/include/cxx/structs/duple.h index 874e4f6..0b23c92 100644 --- a/src/user/include/cxx/structs/duple.h +++ b/src/user/include/cxx/structs/duple.h @@ -4,6 +4,7 @@ template<class at, class bt> class duple { public: + duple() : a(), b() {} duple(at a, bt b) : a(a), b(b) {} at a; diff --git a/src/user/include/cxx/structs/map.h b/src/user/include/cxx/structs/map.h index f9c477f..311bfa9 100644 --- a/src/user/include/cxx/structs/map.h +++ b/src/user/include/cxx/structs/map.h @@ -3,12 +3,7 @@ #include <structs/alist.h> -template<class type> -bool default_equals(type a, type b) { - return a == b; -} - -template<class key, class value, bool (*equals)(key, key) = &default_equals<key>> +template<class key, class value, bool (*equals)(key, key) = &key::operator==> class map { public: alist<key> keys; diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h index 27cb83b..5766245 100644 --- a/src/user/include/knob/block.h +++ b/src/user/include/knob/block.h @@ -16,6 +16,7 @@ uint32_t strcpy(char *to, const char *from); //allocates new memory char *strdup(const char *from); +char *strndup(const char *from, uint32_t new_len); //without null-terminator uint32_t strlen(const char *str) __attribute__ ((pure)); diff --git a/src/user/include/knob/file.h b/src/user/include/knob/file.h index 04fc201..f98a15c 100644 --- a/src/user/include/knob/file.h +++ b/src/user/include/knob/file.h @@ -10,13 +10,11 @@ extern "C" { struct file; -const char *remove_prefix(const char *path, uint8_t *dn_out); - struct file *open_file(const char *path); void close_file(struct file *f); uint32_t read_from_file(struct file *f, uint32_t max, void *buf); -uint32_t write_to_file(struct file *f, uint32_t max, void *buf); +uint32_t write_to_file(struct file *f, uint32_t max, const void *buf); //return value and max_length don't include null terminator uint32_t read_line_from_file(struct file *f, char *sz, uint32_t max_length); uint32_t seek_file_to(struct file *f, uint32_t to); diff --git a/src/user/include/knob/heap.h b/src/user/include/knob/heap.h index c0d7006..d7b0773 100644 --- a/src/user/include/knob/heap.h +++ b/src/user/include/knob/heap.h @@ -8,7 +8,7 @@ extern "C" { #include <stdint.h> void *get_block(uint32_t bytes) __attribute__ ((malloc)); -void free_block(void *block); +void free_block(const void *block); #ifdef __cplusplus } diff --git a/src/user/include/libterm/terminal.h b/src/user/include/libterm/terminal.h index 40536e0..a069a22 100644 --- a/src/user/include/libterm/terminal.h +++ b/src/user/include/libterm/terminal.h @@ -1,6 +1,10 @@ #ifndef LIBTERM_TERMINAL_H #define LIBTERM_TERMINAL_H +#ifdef __cplusplus +extern "C" { +#endif + #include <pland/syscall.h> #include <stdarg.h> @@ -32,4 +36,8 @@ void term_addf(const char *fmt, ...); struct key_packet term_get_key_blocking(); +#ifdef __cplusplus +} +#endif + #endif
\ No newline at end of file diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h index 1e040f4..566e7b8 100644 --- a/src/user/include/pland/syscall.h +++ b/src/user/include/pland/syscall.h @@ -127,8 +127,8 @@ static inline void _exit_task() { __builtin_unreachable(); } -static inline _file_handle_t _open_file(_drive_number_t drive_number, const char *path) { - return (_file_handle_t)_sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path); +static inline _file_handle_t _open_file(const char *path) { + return (_file_handle_t)_sc1(_SCN_OPEN_FILE, (uint32_t)path); } static inline void _close_file(_file_handle_t handle) { @@ -143,8 +143,8 @@ static inline uint32_t _file_size(_file_handle_t handle) { return _sc1(_SCN_FILE_SIZE, handle); } -static inline _task_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass, _task_handle_t stdio_task) { - return (_task_handle_t)_sc4(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass, (uint32_t)stdio_task); +static inline _task_handle_t _start_task(const char *path, const char *pass, _task_handle_t stdio_task) { + return (_task_handle_t)_sc3(_SCN_START_TASK, (uint32_t)path, (uint32_t)pass, (uint32_t)stdio_task); } static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const void *buffer) { @@ -183,12 +183,12 @@ static inline void _wait_for_task(_task_handle_t handle) { _sc1(_SCN_WAIT_FOR_TASK, handle); } -static inline uint32_t _enumerate_dir(_drive_number_t drive_number, const char *path, _dir_info_entry_t *buffer, uint32_t max_count) { - return _sc4(_SCN_ENUMERATE_DIR, drive_number, (uint32_t)path, (uint32_t)buffer, max_count); +static inline uint32_t _enumerate_dir(const char *path, _dir_info_entry_t *buffer, uint32_t max_count) { + return _sc3(_SCN_ENUMERATE_DIR, (uint32_t)path, (uint32_t)buffer, max_count); } -static inline uint32_t _count_of_dir(uint8_t drive_number, const char *path) { - return _sc2(_SCN_COUNT_OF_DIR, drive_number, (uint32_t)path); +static inline uint32_t _count_of_dir(const char *path) { + return _sc1(_SCN_COUNT_OF_DIR, (uint32_t)path); } static inline _window_handle_t _new_window(uint16_t width, uint16_t height, _pixel_t *pixel_buffer) { diff --git a/src/user/init/init.c b/src/user/init/init.c index 860c45f..0934943 100644 --- a/src/user/init/init.c +++ b/src/user/init/init.c @@ -1,7 +1,8 @@ +#include <knob/block.h> #include <knob/file.h> #include <knob/task.h> -#define STARTUP_FILE_PATH "sys/startup.rc" +#define STARTUP_FILE_PATH "/sys/startup.rc" #define CMD_BUF_LEN 1024 char cmdbuf[CMD_BUF_LEN]; @@ -16,11 +17,9 @@ void main() { while (read_line_from_file(f, cmdbuf, CMD_BUF_LEN - 1)) { if (cmdbuf[0] == '#') continue; - //syslogf(run_command(cmdbuf) - // ? "[init] Started %s." - // : "[init] Could not run %s." - //, cmdbuf); - run_command(cmdbuf, 0); + bool started = (bool)run_command(cmdbuf, 0); + str_trunc_fill(cmdbuf, 30); + syslogf(started ? "Started %s" : "Could not start %s", cmdbuf); } close_file(f); diff --git a/src/user/knob/block.c b/src/user/knob/block.c index 9f3f353..8b9971f 100644 --- a/src/user/knob/block.c +++ b/src/user/knob/block.c @@ -1,4 +1,5 @@ #include <knob/panic.h> +#include <knob/block.h> #include <knob/heap.h> #include <stdbool.h> #include <stdint.h> @@ -28,13 +29,22 @@ uint32_t strcpy(char *to, const char *from) { } char *strdup(const char *from) { - const char *end = from; - while (*(end++)) - ; - char *buf = get_block(end - from); - if (!buf) - PANIC("get_block returned 0 in strdup"); - blockcpy(buf, from, end - from); + const uint32_t len = strlen(from) + 1; + char *buf = get_block(len); + blockcpy(buf, from, len); + return buf; +} + +char *strndup(const char *from, uint32_t n) { + uint32_t len = strlen(from) + 1; + if (n < len) { + char *buf = get_block(n + 1); + blockcpy(buf, from, n); + buf[n] = '\0'; + return buf; + } + char *buf = get_block(len); + blockcpy(buf, from, len); return buf; } diff --git a/src/user/knob/file.c b/src/user/knob/file.c index 999778e..d844588 100644 --- a/src/user/knob/file.c +++ b/src/user/knob/file.c @@ -29,7 +29,7 @@ struct file { }; struct file *open_file(const char *path) { - _file_handle_t h = _open_file(0, path); + _file_handle_t h = _open_file(path); if (!h) return 0; @@ -125,13 +125,13 @@ void trunc_file(struct file *f) { //return value must be manually freed, unless it is a null pointer _dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out) { - uint32_t count = _count_of_dir(0, path); + uint32_t count = _count_of_dir(path); if (!count) { *count_out = 0; return 0; } _dir_info_entry_t *buffer = get_block(count * sizeof(_dir_info_entry_t)); - *count_out = _enumerate_dir(0, path, buffer, count); + *count_out = _enumerate_dir(path, buffer, count); return buffer; }
\ No newline at end of file diff --git a/src/user/knob/heap.c b/src/user/knob/heap.c index 6e57000..c4b810e 100644 --- a/src/user/knob/heap.c +++ b/src/user/knob/heap.c @@ -1,128 +1,141 @@ -#include <knob/format.h> - #include <pland/syscall.h> - +#include <pland/pcrt.h> #include <stdbool.h> #include <stdint.h> -//structure appears at the start of each block -struct block_header { - struct block_header *next; - struct block_header *prev; +#define MIN_NEW_CHUNK_PAGES 16 - //does not include header - uint32_t length; - bool allocated; +struct desc_page_head { + void *next_page;//0 for last one }; -static struct block_header *first_block = 0; +struct chunk_desc { + void *start;//0 for a desc not in use + uint32_t length; + bool available; +} __attribute__ ((packed)); +//without packing, it is 12 bytes and we get 341 per page +//with packing, it is 9 bytes and we get 454 per page +//maybe i should make available just the top bit of length +//then we get 511 per page, but length has a max of 2^31-1 + +static struct desc_page_head *first_desc_page = 0; +static struct desc_page_head *last_desc_page = 0; + +#define DESCS_PER_PAGE ((4096 - sizeof(struct desc_page_head)) / sizeof(struct chunk_desc)) +#define PAGE_AS_ARRAY(p) ((struct chunk_desc *)((void *)p + sizeof(struct desc_page_head))) + +static char size_was_buf[] = "size was ......... kB"; +//kb should be < 1 000 000 000 +static void log_size_was(uint32_t kb) { + for (int8_t d = 9; d != -1; --d) { + size_was_buf[9 + d] = (kb % 10) + '0'; + kb /= 10; + } + _system_log(size_was_buf); +} -static void add_header(struct block_header *bh) { - bh->next = first_block; - bh->prev = 0; - if (first_block) - first_block->prev = bh; - first_block = bh; +static const char *const hextab = "0123456789abcdef"; +static char caller_was_buf[] = "return address is 0x........"; +static void log_caller_was(void *addr) { + const uint32_t as_int = (uint32_t)addr; + for (uint8_t i = 0; i < 8; ++i) + caller_was_buf[27 - i] = hextab[(as_int >> (4 * i)) & 0xf]; + _system_log(caller_was_buf); } -//static const char *const hextab = "0123456789abcdef"; -//static char *const get_debug = "getting 0x........ byte block"; -//static char *const free_debug = "freeing 0x........ byte block"; +static struct desc_page_head *new_desc_page() { + struct desc_page_head *dph = _allocate_ram(1); + if (!dph) { + _system_log("knob heap could not allocate new descriptor page"); + log_size_was(4); + __pcrt_quit(); + } + dph->next_page = 0; + if (last_desc_page) + last_desc_page->next_page = dph; + last_desc_page = dph; + + struct chunk_desc *const a = PAGE_AS_ARRAY(dph); + for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i) + a[i].start = 0; -__attribute__ ((malloc)) -void *get_block(uint32_t bytes) { - if (!bytes) - return 0; -//for (uint8_t i = 0; i < 8; ++i) -// get_debug[10 + 7 - i] = hextab[(bytes >> (i * 4)) & 0xf]; -//_system_log(get_debug); - - struct block_header *header = 0; - for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) { - if (ptr->allocated) - continue; - if (ptr->length == bytes) { - header = ptr; - break; - } - if (ptr->length > bytes + sizeof(struct block_header)) { - struct block_header *bh = (void *)ptr + sizeof(struct block_header) + bytes; + return dph; +} + +static struct chunk_desc *unused_desc() { + for (struct desc_page_head *i = first_desc_page; i; i = i->next_page) { + struct chunk_desc *const a = PAGE_AS_ARRAY(i); + for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i) + if (!a[i].start) + return a + i; + } - bh->length = ptr->length - sizeof(struct block_header) - bytes; - bh->allocated = false; - add_header(bh); + return PAGE_AS_ARRAY(new_desc_page()); +} - ptr->length = bytes; - header = ptr; - break; +__attribute__ ((malloc)) +void *get_block(uint32_t bytes) { + if (!first_desc_page) + first_desc_page = new_desc_page(); + + struct chunk_desc *best_fit = 0; + + for (struct desc_page_head *i = first_desc_page; i; i = i->next_page) { + struct chunk_desc *const a = PAGE_AS_ARRAY(i); + for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i) { + if (!a[i].start || !a[i].available || (a[i].length < bytes)) + continue; + if (a[i].length == bytes) { + a[i].available = false; + return a[i].start; + } + if (!best_fit || (a[i].length < best_fit->length)) + best_fit = a + i; } } - if (!header) { - uint32_t size_with_header = bytes + sizeof(struct block_header); - if (!(size_with_header % 4096)) { - header = _allocate_ram(size_with_header / 4096); - if (!header) - return 0; - header->length = bytes; - add_header(header); + if (!best_fit) { + const uint32_t pages_needed = (bytes - 1) / 4096 + 1; + const uint32_t allocating = pages_needed < MIN_NEW_CHUNK_PAGES ? MIN_NEW_CHUNK_PAGES : pages_needed; + void *const new_chunk = _allocate_ram(allocating); + if (!new_chunk) { + _system_log("knob heap could not allocate new chunk"); + log_size_was(allocating * 4); + log_caller_was(__builtin_return_address(0)); + __pcrt_quit(); } - else { - uint32_t pages = (bytes + sizeof(struct block_header) * 2) / 4096 + 1; - header = _allocate_ram(pages); - if (!header) - return 0; - header->length = bytes; - add_header(header); - - struct block_header *bh = (void *)header + sizeof(struct block_header) + bytes; - bh->length = pages * 4096 - bytes - 2 * sizeof(struct block_header); - bh->allocated = false; - add_header(bh); + best_fit = unused_desc(); + best_fit->start = new_chunk; + best_fit->length = allocating * 4096; + + if (bytes == allocating * 4096) { + best_fit->available = false; + return new_chunk; } } - header->allocated = true; - return (void *)header + sizeof(struct block_header); -} - -static void remove_header(struct block_header *bh) { - if (bh == first_block) - first_block = bh->next; - if (bh->prev) - bh->prev->next = bh->next; - if (bh->next) - bh->next->prev = bh->prev; -} + void *const old_end = best_fit->start + best_fit->length; + void *const new_end = best_fit->start + bytes; -void free_block(void *block) { - struct block_header *header = block - sizeof(struct block_header); + best_fit->length = bytes; + best_fit->available = false; -//for (uint8_t i = 0; i < 8; ++i) -// free_debug[10 + 7 - i] = hextab[(header->length >> (i * 4)) & 0xf]; -//_system_log(free_debug); + struct chunk_desc *const leftover = unused_desc(); + leftover->start = new_end; + leftover->length = old_end - new_end; - header->allocated = false; + return best_fit->start; +} - void *after = block + header->length; - for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) { - if (ptr == after) { - if (!ptr->allocated) { - header->length += ptr->length + sizeof(struct block_header); - remove_header(ptr); +void free_block(const void *block) { + for (struct desc_page_head *i = first_desc_page; i; i = i->next_page) { + struct chunk_desc *const a = PAGE_AS_ARRAY(i); + for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i) + if (a[i].start == block) { + //TODO: consolidate this with surrounding free chunks + a[i].available = true; + return; } - break; - } } - - //we traverse the linked list twice. it would probably be more efficient - //to do both finding the after and finding the before in the same loop. - for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) - if ((void *)ptr + sizeof(struct block_header) + ptr->length == header) { - if (!ptr->allocated) { - ptr->length += sizeof(struct block_header) + header->length; - remove_header(header); - } - break; - } -}
\ No newline at end of file +} diff --git a/src/user/knob/task.c b/src/user/knob/task.c index 9bf2c83..ba0ac36 100644 --- a/src/user/knob/task.c +++ b/src/user/knob/task.c @@ -14,12 +14,12 @@ _task_handle_t run_command(const char *path, _task_handle_t stdio_task) { blockcpy(new_path, path, ptr - path); new_path[ptr - path] = '\0'; - _task_handle_t handle = _start_task(0, new_path, ptr + 1, stdio_task); + _task_handle_t handle = _start_task(new_path, ptr + 1, stdio_task); free_block(new_path); return handle; } - return _start_task(0, path, "", stdio_task); + return _start_task(path, "", stdio_task); } bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) { diff --git a/src/user/libfont/fonts.c b/src/user/libfont/fonts.c index d63a5d9..331fc47 100644 --- a/src/user/libfont/fonts.c +++ b/src/user/libfont/fonts.c @@ -8,8 +8,8 @@ #include "bdf.h" #include "pbf.h" -#define FONT_PATH "fonts/" -#define FONT_PATH_L 6 +#define FONT_PATH "/fonts/" +#define FONT_PATH_L 7 struct font_loader_t { const char *ext; diff --git a/src/user/meminfo/meminfo.cpp b/src/user/meminfo/meminfo.cpp index 03f7ae9..c750e8b 100644 --- a/src/user/meminfo/meminfo.cpp +++ b/src/user/meminfo/meminfo.cpp @@ -1,49 +1,24 @@ -#include <raleigh/w/padding.h> -#include <raleigh/w/vbox.h> #include <raleigh/w/label.h> - #include <raleigh/runtime.h> #include <raleigh/window.h> - #include <pland/syscall.h> #include <knob/format.h> -#include <pland/pcrt.h> using namespace raleigh; -label *kmem; -label *umem; +label *l; void refresh(window_tag_t) { - char *const kstr = format("kernel memory free: %uk", _kernel_dynamic_area_left() * 4); - char *const ustr = format("userspace memory free: %uk / %uk", _total_userspace_left() * 4, _total_userspace_size() * 4); - - kmem->change_value(kstr); - umem->change_value(ustr); - - free_block(kstr); - free_block(ustr); + char *fmt = format("Kernel memory free: %ukB\nUser memory free: %ukB\nF5 to refresh, Alt+F4 to quit", _kernel_dynamic_area_left() * 4, _total_userspace_left() * 4); + l->change_value(fmt); + free_block(fmt); } void main() { - kmem = new label(""); - umem = new label(""); - label msg("press Alt+F4 to quit, or F5 to refresh"); - - padding pkmem(*kmem, 1); - padding pumem(*umem, 1); - padding pmsg(msg, 1); - - dllist<widget &> ll; - ll.add_front(pmsg); - ll.add_front(pumem); - ll.add_front(pkmem); - vbox box(ll); - - padding pbox(box, 3); - window w(pbox); - w.add_keybind((struct key_packet){.key_id = key_packet::KEY_F5, .modifiers = key_packet::NO_MODS}, &refresh); + l = new label(""); + window w(*l); + w.add_keybind((key_packet){.key_id = key_packet::KEY_F5, .modifiers = key_packet::NO_MODS}, &refresh); refresh(0); w.show(); diff --git a/src/user/mkpopup/main.cpp b/src/user/mkpopup/main.cpp index 5e3310c..8b3746c 100644 --- a/src/user/mkpopup/main.cpp +++ b/src/user/mkpopup/main.cpp @@ -1,41 +1,35 @@ #include <raleigh/w/padding.h> #include <raleigh/w/label.h> -#include <raleigh/w/vbox.h> #include <raleigh/window.h> -#include <knob/block.h> using namespace raleigh; -widget *make_line(const char *str) { - return new label(str); -} - void main(const char *text) { - dllist<widget &> box_widgets; - - char *const data = strdup(text); - - char *this_string = data; - while (*this_string) { - char *i = this_string; - while (1) { - if (!i[0]) { - box_widgets.add_back(*make_line(this_string)); - this_string = i; - break; - } - if ((i[0] == '\\') && (i[1] == 'n')) { - i[0] = '\0'; - box_widgets.add_back(*make_line(this_string)); - this_string = i + 2; - break; - } - ++i; + char *unescaped = new char[strlen(text) + 1]; + char *ui = unescaped; + while (1) { + const uint32_t len = str_find_any(text, "\\"); + if (len) { + blockcpy(ui, text, len); + text += len; + ui += len; + } + if (!*text) + break; + if (text[1] == 'n') { + *(ui++) = '\n'; + text += 2; + } + else { + *(ui++) = '\\'; + ++text; } } + *ui = '\0'; - vbox box(box_widgets); - padding p(box, 4); + label l(unescaped); + delete[] unescaped; + padding p(l, 4); window w(p); w.show(); diff --git a/src/user/raleigh/d/dialog.cpp b/src/user/raleigh/d/dialog.cpp index 38ca310..33f137e 100644 --- a/src/user/raleigh/d/dialog.cpp +++ b/src/user/raleigh/d/dialog.cpp @@ -54,21 +54,36 @@ dialog::dialog(widget &top_part, alist<duple<const char *, diag_result_t>> butto main_box->add_end(*pbot); } -alist<duple<const char *, diag_result_t>> &mk_yes_no_cancel() { - alist<duple<const char *, diag_result_t>> *list = new alist<duple<const char *, diag_result_t>>(3, 1); +button_list &mk_yes_no_cancel() { + button_list *list = new button_list(3, 1); list->add_back(duple<const char *, diag_result_t>("Yes", YES)); list->add_back(duple<const char *, diag_result_t>("No", NO)); list->add_back(duple<const char *, diag_result_t>("Cancel", CANCEL)); return *list; } -alist<duple<const char *, diag_result_t>> &mk_yes_no_retry() { - alist<duple<const char *, diag_result_t>> *list = new alist<duple<const char *, diag_result_t>>(3, 1); +button_list &mk_yes_no_retry() { + button_list *list = new button_list(3, 1); list->add_back(duple<const char *, diag_result_t>("Yes", YES)); list->add_back(duple<const char *, diag_result_t>("No", NO)); list->add_back(duple<const char *, diag_result_t>("Retry", RETRY)); return *list; } -alist<duple<const char *, diag_result_t>> &raleigh::yes_no_cancel(mk_yes_no_cancel()); -alist<duple<const char *, diag_result_t>> &raleigh::yes_no_retry(mk_yes_no_retry());
\ No newline at end of file +button_list &mk_okay_cancel() { + button_list *list = new button_list(2, 1); + list->add_back(duple<const char *, diag_result_t>("Okay", OKAY)); + list->add_back(duple<const char *, diag_result_t>("Cancel", CANCEL)); + return *list; +} + +button_list &mk_okay() { + button_list *list = new button_list(1, 1); + list->add_back(duple<const char *, diag_result_t>("Okay", OKAY)); + return *list; +} + +button_list &raleigh::yes_no_cancel(mk_yes_no_cancel()); +button_list &raleigh::yes_no_retry(mk_yes_no_retry()); +button_list &raleigh::okay_cancel(mk_okay_cancel()); +button_list &raleigh::okay(mk_okay());
\ No newline at end of file diff --git a/src/user/raleigh/s/text_flower.cpp b/src/user/raleigh/s/text_flower.cpp new file mode 100644 index 0000000..bd4ecd8 --- /dev/null +++ b/src/user/raleigh/s/text_flower.cpp @@ -0,0 +1,96 @@ +#include <raleigh/s/text_flower.h> +#include <knob/block.h> + +namespace raleigh { + text_flower::text_flower(const char *s, uint32_t cols, uint32_t max_rows) + : s(s), lines(max_rows ? max_rows : 10), offsets(max_rows ? max_rows : 10), + max_rows(max_rows), cols(cols) { + flow_text(); + } + + __attribute__ ((pure)) + uint32_t text_flower::get_n_lines() { + return lines.n_entries; + } + + __attribute__ ((pure)) + char *text_flower::get_nth_line(uint32_t n) { + return lines.buf[n]; + } + + __attribute__ ((pure)) + uint32_t text_flower::get_line_offset(uint32_t n) { + return offsets.buf[n]; + } + + void text_flower::draw_text(_pixel_t *start, uint32_t pitch, const struct font_info *fi, _pixel_t color) { + for (uint32_t y = 0; y < lines.n_entries; ++y) { + const char *line = lines.buf[y]; + for (uint32_t x = 0; line[x]; ++x) + put_char_no_bg(fi, line[x], start + y * fi->space_height * pitch + x * fi->space_width, pitch, color); + } + } + + void text_flower::push_line() { + lines.add_back(strndup(line_start, row_len)); + offsets.add_back(line_start - s); + line_start = on_char; + row_len = 0; + if (max_rows && (lines.n_entries == max_rows)) + on_char = ""; + } + + void text_flower::flow_text() { + for (uint32_t i = 0; i < lines.n_entries; ++i) + free_block(lines.buf[i]); + + lines.n_entries = 0; + offsets.n_entries = 0; + line_start = on_char = s; + row_len = 0; + + while (*on_char) { + if (*on_char == '\n') { + ++on_char; + push_line(); + } + + else if (*on_char == ' ') { + ++on_char; + if (row_len != 0) { + if (++row_len == cols) + push_line(); + } + else + ++line_start; + } + + else { + uint32_t word_len = str_find_any(on_char, " \n"); + if (!cols) { + row_len += word_len; + on_char += word_len; + } + + else if (row_len + word_len <= cols) { + row_len += word_len; + on_char += word_len; + if (row_len == cols) + push_line(); + } + + else if (word_len > cols) { + on_char += cols - row_len; + row_len = cols; + push_line(); + } + + else + push_line(); + } + } + + if (row_len && (!max_rows || (lines.n_entries != max_rows))) + push_line(); + } +}
\ No newline at end of file diff --git a/src/user/raleigh/util.cpp b/src/user/raleigh/util.cpp index a300d01..1687ea6 100644 --- a/src/user/raleigh/util.cpp +++ b/src/user/raleigh/util.cpp @@ -1,3 +1,5 @@ +#include <raleigh/d/dialog.h> +#include <raleigh/w/label.h> #include <raleigh/util.h> #include <knob/format.h> #include <pland/pcrt.h> @@ -17,4 +19,18 @@ namespace raleigh { __pcrt_quit(); } + + __attribute__ ((noreturn)) + void show_error_popup_and_quitf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + char *ch = format_v(fmt, args); + label l(ch); + + dialog d(l, okay); + d.show_modal(); + + __pcrt_quit(); + } }
\ No newline at end of file diff --git a/src/user/raleigh/w/entry.cpp b/src/user/raleigh/w/entry.cpp index 3053413..54535cc 100644 --- a/src/user/raleigh/w/entry.cpp +++ b/src/user/raleigh/w/entry.cpp @@ -1,274 +1,210 @@ +#include <raleigh/s/text_flower.h> #include <raleigh/w/entry.h> -#include <knob/format.h> -#include <knob/block.h> -#include <knob/heap.h> -#include <knob/key.h> namespace raleigh { - void entry::set_contents(const char *s) { - const uint32_t l = strlen(s); - const uint32_t cl = l > rows * cols - 1 ? rows * cols - 1 : l; - blockcpy(data, s, cl); - data[cl] = '\0'; - - line_indices[0] = 0; - get_indices(0, 0, 0); - cur_x = end_x; - cur_y = end_y; - cur_d = end_d; - - next_paint_full = true; - if (w) - w->notify_needs_paint(*this); - } - entry::entry(uint32_t rows, uint32_t cols, const char *default_text, - const char *font, _pixel_t bg, _pixel_t fg, _pixel_t border_color) - : rows(rows), cols(cols), bg(bg), fg(fg), border_color(border_color), - fi(get_font(font)), data(new char[rows * cols]), - line_indices(new uint32_t[rows + 1]), has_focus(false) { + const struct font_info *fi, _pixel_t bg, _pixel_t fg, + _pixel_t border_color) + : fi(fi), border_color(border_color), fg(fg), bg(bg), rows(rows), + cols(cols), text_back(default_text, strlen(default_text) + 1), + flower(text_back.buf, cols, rows) { size = coord(fi->space_width * (cols - 1) + fi->char_width + 6, - fi->space_height * (rows - 1) + fi->char_height + 6); + fi->space_height * (rows - 1) + fi->char_height + 6);\ closest_opaque = this; - set_contents(default_text); } - void entry::get_indices(uint32_t from_y, uint32_t from_x, uint32_t from_d) { - while (1) { - const uint32_t ln = str_find_any(data + from_d, " \n"); - bool quit_after = !data[from_d + ln]; - if ((from_x + ln <= cols) || (ln >= cols)) { - from_x += ln; - from_d += ln; - if (data[from_d] == '\n') { - ++from_y; - from_x = 0; - line_indices[from_y] = from_d + 1; - } - else - ++from_x; - ++from_d; - if (from_x >= cols) { - ++from_y; - from_x = 0; - line_indices[from_y] = from_d; - } - if (quit_after) - break; - } - else { - ++from_y; - from_x = 0; - line_indices[from_y] = from_d; - } - } - line_indices[from_y + 1] = from_d; - end_y = from_y; - end_x = from_x; - end_d = from_d; + __attribute__ ((pure)) + const char *entry::get_contents() { + return text_back.buf; } - void entry::notify_window_change() {} - - void entry::paint_text(_pixel_t *pixbuf, uint32_t pitch) { - for (uint32_t y = 0; y <= end_y; ++y) { - const char *const line = data + line_indices[y]; - const uint32_t len = line_indices[y + 1] - line_indices[y] >= cols ? cols : line_indices[y + 1] - line_indices[y]; - for (uint32_t x = 0; x < len; ++x) - if ((line[x] != '\n') && line[x]) - put_char_no_bg(fi, line[x], pixbuf + (window_offset.y + 3 + y * fi->space_height) * pitch + (window_offset.x + 3 + x * fi->space_width), pitch, fg); - } + void entry::set_contents(const char *s) { + text_back.copy_from(s, strlen(s) + 1); + on_text_change(); } void entry::paint(_pixel_t *pixbuf, uint32_t pitch) { - _pixel_t *const cur_ptr = pixbuf + (window_offset.y + 3 + cur_y * fi->space_height) * pitch + (window_offset.x + 3 + cur_x * fi->space_width); - _pixel_t *const old_cur_ptr = pixbuf + (window_offset.y + 3 + cur_y_last_paint * fi->space_height) * pitch + (window_offset.x + 3 + cur_x_last_paint * fi->space_width); - if (next_paint_full) { - next_paint_full = false; - - for (uint32_t x = 0; x < size.x; ++x) { - pixbuf[(window_offset.y) * pitch + window_offset.x + x] = border_color; - pixbuf[(window_offset.y + size.y - 1) * pitch + window_offset.x + x] = border_color; + for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x) { + pixbuf[window_offset.y * pitch + x] = border_color; + pixbuf[(window_offset.y + size.y - 1) * pitch + x] = border_color; } - for (uint32_t y = 1; y < size.y - 1; ++y) { - pixbuf[(window_offset.y + y) * pitch + window_offset.x] = border_color; - pixbuf[(window_offset.y + y) * pitch + window_offset.x + size.x - 1] = border_color; + for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y) { + pixbuf[y * pitch + window_offset.x] = border_color; + pixbuf[y * pitch + window_offset.x + size.x - 1] = border_color; } + for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y) + for (uint32_t x = window_offset.x + 1; x < window_offset.x + size.x - 1; ++x) + pixbuf[y * pitch + x] = bg; + } - for (uint32_t y = 1; y < size.y - 1; ++y) - for (uint32_t x = 1; x < size.x - 1; ++x) - pixbuf[(window_offset.y + y) * pitch + (window_offset.x + x)] = bg; - - paint_text(pixbuf, pitch); + if (next_paint_full || text_change) { + for (uint32_t y = window_offset.y + 3; y < window_offset.y + size.y - 3; ++y) + for (uint32_t x = window_offset.x + 3; x < window_offset.x + size.x - 3; ++x) + pixbuf[y * pitch + x] = bg; + flower.draw_text(pixbuf + (window_offset.y + 3) * pitch + window_offset.x + 3, pitch, fi, fg); } - else if (text_changed_since_last_paint) { - for (uint32_t y = 3; y < size.y - 3; ++y) - for (uint32_t x = 3; x < size.x - 3; ++x) - pixbuf[(window_offset.y + y) * pitch + (window_offset.x + x)] = bg; - paint_text(pixbuf, pitch); - text_changed_since_last_paint = false; + else if ((cursor_change || !is_cur) && was_cur_before) { + const uint32_t y_start = window_offset.y + 3 + fi->space_height * old_cur_y; + const uint32_t x_start = window_offset.x + 3 + fi->space_width * old_cur_x; + if (old_cur_x == cols) + for (uint32_t y = y_start; y < y_start + fi->char_height; ++y) { + pixbuf[y * pitch + x_start] = bg; + pixbuf[y * pitch + x_start + 1] = bg; + } + else + put_char(fi, flower.get_nth_line(old_cur_y)[old_cur_x], + pixbuf + y_start * pitch + x_start, pitch, bg, fg); } - else if (had_focus_last_paint) { - for (uint32_t y = 0; y < fi->char_height; ++y) { - old_cur_ptr[y * pitch] = bg; - old_cur_ptr[y * pitch + 1] = bg; - } - if (data[cur_d_last_paint] && (data[cur_d_last_paint] != '\n') && (cur_d_last_paint < line_indices[cur_y_last_paint + 1])) - put_char_no_bg(fi, data[cur_d_last_paint], old_cur_ptr, pitch, fg); + if (is_cur) { + const uint32_t y_start = window_offset.y + 3 + fi->space_height * cur_y; + const uint32_t x_start = window_offset.x + 3 + fi->space_width * cur_x; + if (old_cur_x == cols) + for (uint32_t y = y_start; y < y_start + fi->char_height; ++y) { + pixbuf[y * pitch + x_start] = fg; + pixbuf[y * pitch + x_start + 1] = fg; + } } - if (has_focus) - for (uint32_t y = 0; y < fi->char_height; ++y) { - cur_ptr[y * pitch] = fg; - cur_ptr[y * pitch + 1] = fg; - } + next_paint_full = false; + text_change = false; + cursor_change = false; - cur_y_last_paint = cur_y; - cur_x_last_paint = cur_x; - cur_d_last_paint = cur_d; - had_focus_last_paint = has_focus; + was_cur_before = is_cur; + old_cur_x = cur_x; + old_cur_y = cur_y; } - void entry::ensure_cursor_in_line() { - cur_d = line_indices[cur_y] + cur_x; - if (cur_d >= line_indices[cur_y + 1]) { - cur_d = line_indices[cur_y + 1] - 1; - if (data[cur_d] && (data[cur_d] != '\n')) - ++cur_d; - cur_x = cur_d - line_indices[cur_y]; - } - } + void entry::notify_has_opaque_parent(widget *parent) {} void entry::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) { if (up || (click_type != mouse_packet::LEFT)) return; - if (window_coords.x - window_offset.x < 3) - window_coords.x = 3 + window_offset.x; - else if (window_coords.x - window_offset.x > size.x - 4) - window_coords.x = size.x - 4 + window_offset.x; - if (window_coords.y - window_offset.y < 3) - window_coords.y = 3 + window_offset.y; - else if (window_coords.y - window_offset.y > size.y - 4) - window_coords.y = size.y - 4 + window_offset.y; + if (window_coords.x < window_offset.x) + window_coords.x = window_offset.x; + if (window_coords.y < window_offset.y) + window_coords.y = window_offset.y; - cur_y = (window_coords.y - window_offset.y - 3) / fi->space_height; - cur_x = (window_coords.x - window_offset.x - 3) / fi->space_width; - if (cur_y > end_y) { - cur_y = end_y; - cur_x = end_x; - } - ensure_cursor_in_line(); + cur_x = (window_coords.x - window_offset.x) / fi->space_width; + cur_y = (window_coords.y - window_offset.y) / fi->space_height; - if (has_focus) - w->notify_needs_paint(*this); - else - w->focus(*this); + check_y(); + check_x(); + on_cursor_change(); } - void entry::notify_has_opaque_parent(widget *parent) {} + void entry::check_y() { + if (cur_y >= flower.get_n_lines()) + cur_y = flower.get_n_lines() - 1; + } - bool entry::cursor_left() { - if (cur_x) { - --cur_x; - --cur_d; - return true; - } - if (!cur_y) - return false; + void entry::check_x() { + if (cur_x > strlen(flower.get_nth_line(cur_y))) + cur_x = strlen(flower.get_nth_line(cur_y)); + } - --cur_y; - cur_x = line_indices[cur_y + 1] - line_indices[cur_y] - 1; - if (cur_x == cols) - --cur_x; - cur_d = line_indices[cur_y] + cur_x; - return true; + void entry::on_text_change() { + flower.s = text_back.buf; + flower.flow_text(); + text_change = true; + w->notify_needs_paint(*this); } - bool entry::cursor_right() { - if (cur_d >= (end_d - 1)) - return false; + void entry::on_cursor_change() { + cursor_change = true; + w->notify_needs_paint(*this); + } - ++cur_d; - ++cur_x; + void entry::handle_key(struct key_packet kp) { + const uint32_t pos = flower.get_line_offset(cur_y) + cur_x; + const char ch = key_to_char(kp); + + if (kp.key_id == kp.KEY_BSPACE) { + if (pos) { + text_back.remove(pos - 1); + left(); + on_text_change(); + } + } - if (cur_d >= line_indices[cur_y + 1]) { - cur_x = 0; - ++cur_y; - cur_d = line_indices[cur_y]; + else if (kp.key_id == kp.KEY_DELETE) { + if (pos != text_back.n_entries - 1) { + text_back.remove(pos); + on_text_change(); + } } - return true; + else if (kp.key_id == kp.KEY_LEFT_ARROW) + left(); + else if (kp.key_id == kp.KEY_RIGHT_ARROW) + right(); + else if (kp.key_id == kp.KEY_UP_ARROW) + up(); + else if (kp.key_id == kp.KEY_DOWN_ARROW) + down(); + + else if (ch) { + text_back.insert(pos, ch); + on_text_change(); + } } - bool entry::cursor_up() { - if (!cur_y) - return false; - - --cur_y; - ensure_cursor_in_line(); - return true; + void entry::left() { + if (cur_x) + --cur_x; + else if (cur_y) { + --cur_y; + check_x(); + } + else + return; + on_cursor_change(); } - bool entry::cursor_down() { - if (cur_y == end_y) - return false; + void entry::right() { + if (++cur_x <= strlen(flower.get_nth_line(cur_y))) + on_cursor_change(); + else if (cur_y != flower.get_n_lines()) { + ++cur_y; + cur_x = 0; + on_cursor_change(); + } + } - ++cur_y; - ensure_cursor_in_line(); - return true; + void entry::up() { + if (cur_y) { + --cur_y; + check_x(); + on_cursor_change(); + } + else if (!cur_x) { + cur_x = 0; + on_cursor_change(); + } } - void entry::handle_key(struct key_packet kp) { - switch (kp.key_id) { - case kp.KEY_LEFT_ARROW: - if (cursor_left() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_RIGHT_ARROW: - if (cursor_right() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_DOWN_ARROW: - if (cursor_down() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_UP_ARROW: - if (cursor_up() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_HOME: - if (cur_x) { - cur_x = 0; - if (has_focus) - w->notify_needs_paint(*this); - } - break; - case kp.KEY_END: - cur_x = cols; - ensure_cursor_in_line(); - if (has_focus) - w->notify_needs_paint(*this); - break; - default: - break; + void entry::down() { + if (cur_y != flower.get_n_lines()) { + ++cur_y; + check_x(); + on_cursor_change(); + } + else if (cur_x < strlen(flower.get_nth_line(cur_y))) { + cur_x = strlen(flower.get_nth_line(cur_y)); + on_cursor_change(); } } void entry::on_focus() { - has_focus = true; + is_cur = true; w->notify_needs_paint(*this); } void entry::on_unfocus() { - has_focus = false; + is_cur = false; w->notify_needs_paint(*this); } - - const char *entry::get_contents() { - return data; - } }
\ No newline at end of file diff --git a/src/user/raleigh/w/label.cpp b/src/user/raleigh/w/label.cpp index 21df2a2..e8be703 100644 --- a/src/user/raleigh/w/label.cpp +++ b/src/user/raleigh/w/label.cpp @@ -3,26 +3,36 @@ #include <knob/block.h> namespace raleigh { - label::label(const char *value, const char *font, bool bg_transparent, _pixel_t fg, _pixel_t bg) - : fi(get_font(font)), bg_transparent(bg_transparent), fg(fg), bg(bg) { + coord label::determine_size() { + uint32_t longest = 0; - v_size = strlen(value) + 1; - this->value = new char[v_size]; - blockcpy(this->value, value, v_size); - size = coord(fi->space_width * (v_size - 2) + fi->char_width, fi->char_height); + for (uint32_t i = 0; i < tf.get_n_lines(); ++i) + if (strlen(tf.get_nth_line(i)) > longest) + longest = strlen(tf.get_nth_line(i)); - closest_opaque = 0; + const int32_t width = fi->space_width * (longest - 1) + fi->char_width; + const int32_t height = fi->space_height * (tf.get_n_lines() - 1) + fi->char_height; + return coord(width < 0 ? 0 : width, height < 0 ? 0 : height); + } + + label::label(const char *value, const char *font, uint32_t cols, + bool bg_transparent, _pixel_t fg, _pixel_t bg) + : fi(get_font(font)), cols(cols), bg_transparent(bg_transparent), + fg(fg), bg(bg), tf(strdup(value), cols) { + + size = determine_size(); + closest_opaque = bg_transparent ? 0 : this; + } + + label::~label() { + free_block(tf.s); } void label::change_value(const char *new_value) { - delete[] value; - const uint32_t ns = strlen(new_value) + 1; - if (ns != v_size) { - v_size = ns; - value = new char[ns]; - set_size(coord(fi->space_width * (ns - 2) + fi->char_width, fi->char_height)); - } - blockcpy(value, new_value, ns); + free_block(tf.s); + tf.s = strdup(new_value); + tf.flow_text(); + set_size(determine_size()); w->notify_needs_paint(*this); } @@ -31,14 +41,11 @@ namespace raleigh { for (uint32_t y = window_offset.y; y < window_offset.y + size.y; ++y) for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x) pixbuf[y * pitch + x] = bg; - _pixel_t *ptr = pixbuf + window_offset.y * pitch + window_offset.x; - for (const char *c = value; *c; ++c) { - put_char_no_bg(fi, *c, ptr, pitch, fg); - ptr += fi->space_width; - } + tf.draw_text(pixbuf + window_offset.y * pitch + window_offset.x, pitch, fi, fg); } void label::notify_has_opaque_parent(widget *parent) { - closest_opaque = parent; + if (bg_transparent) + closest_opaque = parent; } }
\ No newline at end of file diff --git a/src/user/raleigh/window.cpp b/src/user/raleigh/window.cpp index 5fa82c3..607b58e 100644 --- a/src/user/raleigh/window.cpp +++ b/src/user/raleigh/window.cpp @@ -74,7 +74,13 @@ namespace raleigh { } void window::paint_full() { - for (uint32_t i = 0; i < size.x * size.y; ++i) + //syslogf("paint_full called with"); + //syslogf(" pixbuf = 0x%x", pixbuf); + //syslogf(" size.x = %u", size.x); + //syslogf(" size.y = %u", size.y); + + const uint32_t n = size.x * size.y; + for (uint32_t i = 0; i < n; ++i) pixbuf[i] = bg_color; root.next_paint_full = true; root.paint(pixbuf, size.x); diff --git a/src/user/runtimes/cxx/extra.ld b/src/user/runtimes/cxx/extra.ld index 048877e..df51439 100644 --- a/src/user/runtimes/cxx/extra.ld +++ b/src/user/runtimes/cxx/extra.ld @@ -8,4 +8,7 @@ _Znaj = get_block; _ZdlPvj = free_block; /* void operator delete[](void *) */ -_ZdaPv = free_block;
\ No newline at end of file +_ZdaPv = free_block; + +/* void operator delete[](void *, size_t) */ +_ZdaPvj = free_block;
\ No newline at end of file diff --git a/src/user/settings/color_editor.cpp b/src/user/settings/color_editor.cpp deleted file mode 100644 index 1673824..0000000 --- a/src/user/settings/color_editor.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "color_editor.h" - -color_editor::color_editor(struct setting *s, const char *sname) - : c(&s->data.color), p(s->data.color) { - editing_widget_ready(p, sname); -} - -#include <knob/format.h> - -void color_editor::set_data() { - const _pixel_t new_c = p.get_picked_color(); - if ((c->r != new_c.r) || (c->g != new_c.g) || (c->b != new_c.b)) { - *c = new_c; - main_w->is_saved = false; - } -}
\ No newline at end of file diff --git a/src/user/settings/color_editor.h b/src/user/settings/color_editor.h deleted file mode 100644 index c41ec3f..0000000 --- a/src/user/settings/color_editor.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef COLOR_EDITOR_H -#define COLOR_EDITOR_H - -#include <raleigh/w/colorpicker.h> - -#include "editor.h" -#include "model.h" - -class color_editor : public editor { -public: - color_editor(struct setting *s, const char *sname); - void set_data() override; - -private: - _pixel_t *c; - colorpicker p; -}; - -#endif
\ No newline at end of file diff --git a/src/user/settings/color_kind.cpp b/src/user/settings/color_kind.cpp new file mode 100644 index 0000000..08fb2d9 --- /dev/null +++ b/src/user/settings/color_kind.cpp @@ -0,0 +1,36 @@ +#include "color_kind.h" + +#include <raleigh/w/colorpicker.h> + +void write_color_main(uint32_t &data_offset, file *f, const backing_t backing) { + _pixel_t main[2]; + main[0] = *(const _pixel_t *)backing; + write_to_file(f, 8, main); +} + +void write_color_data(file *f, const backing_t backing) {} + +backing_t read_color_backing(file *f, uint32_t data_start) { + _pixel_t *p = new _pixel_t[1]; + read_from_file(f, 3, p); + return (backing_t)p; +} + +void load_into_picker(raleigh::colorpicker &e, _pixel_t *s) { + e.set_picked_color(*s); +} + +void save_from_picker(raleigh::colorpicker &e, _pixel_t *&s) { + *s = e.get_picked_color(); +} + +void open_color_editor(setting &s) { + do_common_editor<_pixel_t *, raleigh::colorpicker, &load_into_picker, &save_from_picker>(s); +} + +const setting_kind_info color_kind = { + &write_color_main, + &write_color_data, + &read_color_backing, + &open_color_editor +};
\ No newline at end of file diff --git a/src/user/settings/color_kind.h b/src/user/settings/color_kind.h new file mode 100644 index 0000000..b5a12c8 --- /dev/null +++ b/src/user/settings/color_kind.h @@ -0,0 +1,8 @@ +#ifndef COLOR_KIND_H +#define COLOR_KIND_H + +#include "model.h" + +extern const setting_kind_info color_kind; + +#endif
\ No newline at end of file diff --git a/src/user/settings/editor.cpp b/src/user/settings/editor.cpp deleted file mode 100644 index 1804a85..0000000 --- a/src/user/settings/editor.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include <raleigh/w/padding.h> -#include <raleigh/w/button.h> -#include <raleigh/w/label.h> -#include <raleigh/w/vbox.h> -#include "editor.h" - -bool editor_save(window_tag_t e) { - ((editor *)e)->set_data(); - return true; -} - -editor::editor() - : w(0) {} - -void editor::editing_widget_ready(widget &e, const char *s) { - label *l = new label(s); - padding *p = new padding(*l, 4); - - dllist<widget &> *list = new dllist<widget &>(); - list->add_back(*p); - list->add_back(e); - - vbox *box = new vbox(*list); - - w = new window(*box, RGB(bf, bf, bf), &editor_save, this); -} - -void editor::show() { - w->show(); -}
\ No newline at end of file diff --git a/src/user/settings/editor.h b/src/user/settings/editor.h deleted file mode 100644 index 2980884..0000000 --- a/src/user/settings/editor.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef EDITOR_H -#define EDITOR_H - -#include <raleigh/d/saving_window.h> - -using namespace raleigh; - -class editor { - friend bool editor_save(window_tag_t e); -public: - void show(); -protected: - editor(); - void editing_widget_ready(widget &e, const char *sname); - virtual void set_data() = 0; -private: - window *w; -}; - -#endif
\ No newline at end of file diff --git a/src/user/settings/main.cpp b/src/user/settings/main.cpp index 2045137..cb318b1 100644 --- a/src/user/settings/main.cpp +++ b/src/user/settings/main.cpp @@ -1,191 +1,35 @@ -#include <raleigh/d/saving_window.h> -#include <raleigh/w/padding.h> +#include "model.h" + #include <raleigh/w/button.h> #include <raleigh/w/label.h> #include <raleigh/w/vbox.h> -#include <structs/map.h> -#include <knob/format.h> -#include <knob/file.h> -#include <stdint.h> - -#include "color_editor.h" -#include "str_editor.h" -#include "model.h" -struct file_header { - uint32_t main_offset; - uint32_t main_entries; - uint32_t names_offset; - uint32_t data_offset; -} __attribute__ ((packed)); - -struct main_entry { - uint32_t name_offset; - uint8_t name_len; - enum : uint8_t { - STRING = 0, - COLOR - } kind; - uint16_t pad; - union { - struct { - uint32_t data_offset; - uint32_t data_len; - } as_string; - _pixel_t as_color; - }; -} __attribute__ ((packed)); - -#define SETTINGS_FILE "sys/settings.pls" +#define SETTINGS_FILE "/sys/settings.pls" using namespace raleigh; -bool save(save_tag_t) { - struct file *f = open_file(SETTINGS_FILE); - struct file_header fh; - fh.main_offset = sizeof(struct file_header); - fh.main_entries = settings.n_entries; - fh.names_offset = fh.main_offset + sizeof(struct main_entry) * settings.n_entries; - - uint32_t name_i = 0; - uint32_t data_i = 0; - seek_file_to(f, sizeof(struct file_header)); - struct main_entry me; - - for (struct setting *i = settings.buf; i < settings.buf + settings.n_entries; ++i) { - me.name_offset = name_i; - me.name_len = strlen(i->name); - name_i += me.name_len; - - switch (i->kind) { - case setting::STRING: - me.kind = main_entry::STRING; - me.as_string.data_offset = data_i; - me.as_string.data_len = strlen(i->data.string); - data_i += me.as_string.data_len; - break; - case setting::COLOR: - me.kind = main_entry::COLOR; - me.as_color = i->data.color; - break; - } - - write_to_file(f, sizeof(struct main_entry), &me); - } - - seek_file_to(f, fh.names_offset); - for (struct setting *i = settings.buf; i < settings.buf + settings.n_entries; ++i) - write_to_file(f, strlen(i->name), (void *)i->name); - - fh.data_offset = get_file_pos(f); - for (struct setting *i = settings.buf; i < settings.buf + settings.n_entries; ++i) - switch (i->kind) { - case setting::STRING: - write_to_file(f, strlen(i->data.string), (void *)i->data.string); - break; - default: - break; - } - - trunc_file(f); - seek_file_to(f, 0); - write_to_file(f, sizeof(struct file_header), &fh); - close_file(f); - - main_w->is_saved = true; - return true; -} - -void on_button_click(button_tag_t n) { - struct setting *const s = settings.buf + (uint32_t)n; - editor *e; - switch (s->kind) { - case setting::STRING: - e = new str_editor(s, s->name); - break; - case setting::COLOR: - e = new color_editor(s, s->name); - break; - default: - show_error_and_quitf("Internal model corrupted: setting %s had type 0x%2x.", s->name, s->kind); - } - e->show(); -} - -button *make_button(uint32_t i) { - label *l = new label(settings.buf[i].name); - padding *p = new padding(*l, 2); - return new button(*p, &on_button_click, (button_tag_t)i); +void on_button(button_tag_t tag) { + setting *s = (setting *)tag; + s->kind->open_editor(*s); } void main() { - struct file *f = open_file(SETTINGS_FILE); - - struct file_header file_head; - read_from_file(f, sizeof(struct file_header), &file_head); - - settings = alist<struct setting>(file_head.main_entries + 10); - - dllist<widget &> for_vbox; + settings_model sm(SETTINGS_FILE); - label l("Click a setting name below to edit its value."); - label l2("A restart is required for changes to take effect."); + label instructions("Click a button below to edit that setting."); - dllist<widget &> for_subbox; - for_subbox.add_back(l); - for_subbox.add_back(l2); - vbox subbox(for_subbox); + dllist<widget &> box_widgets; + box_widgets.add_back(instructions); - padding p_subbox(subbox, 2); - for_vbox.add_back(p_subbox); - - for (uint32_t i = 0; i < file_head.main_entries; ++i) { - struct main_entry entry; - seek_file_to(f, file_head.main_offset + i * sizeof(struct main_entry)); - read_from_file(f, sizeof(struct main_entry), &entry); - - char *const sname = new char[entry.name_len + 1]; - seek_file_to(f, file_head.names_offset + entry.name_offset); - read_from_file(f, entry.name_len, sname); - sname[entry.name_len] = '\0'; - - switch (entry.kind) { - char *sz; - struct setting s; - case main_entry::STRING: - sz = new char[entry.as_string.data_len + 1]; - seek_file_to(f, file_head.data_offset + entry.as_string.data_offset); - read_from_file(f, entry.as_string.data_len, sz); - sz[entry.as_string.data_len] = '\0'; - - s.kind = setting::STRING; - s.data.string = sz; - s.name = sname; - settings.add_back(s); - break; - - case main_entry::COLOR: - s.kind = setting::COLOR; - s.data.color = entry.as_color; - s.name = sname; - settings.add_back(s); - break; - default: - show_error_and_quitf("Refusing to open " SETTINGS_FILE ":\n\"%s\" has unrecognized type id 0x%2x.\nHighest known is 0x01.", sname, entry.kind); - } - - button *const b = make_button(settings.n_entries - 1); - - padding *p = new padding(*b, 2); - for_vbox.add_back(*p); + for (uint32_t i = 0; i < sm.settings.n_entries; ++i) { + label *l = new label(sm.settings.buf[i].name); + button *b = new button(*l, &on_button, (button_tag_t)&sm.settings.buf[i]); + box_widgets.add_back(*b); } - close_file(f); - - vbox box(for_vbox); - padding pbox(box, 2); + vbox box(box_widgets); + window w(box); + w.show(); - main_w = new saving_window(&save, 0, pbox); - main_w->show(); start_runtime(); }
\ No newline at end of file diff --git a/src/user/settings/model.cpp b/src/user/settings/model.cpp index e27de0d..db0a4ce 100644 --- a/src/user/settings/model.cpp +++ b/src/user/settings/model.cpp @@ -1,4 +1,58 @@ -#include "model.h" +#include <raleigh/util.h> -alist<struct setting> settings; -raleigh::saving_window *main_w;
\ No newline at end of file +#include "string_kind.h" +#include "color_kind.h" + +#define N_SETTING_KINDS 2 +const setting_kind_info *setting_kinds[] = { + &string_kind, + &color_kind +}; + +struct file_head { + uint32_t main_start; + uint32_t count; + uint32_t names_start; + uint32_t data_start; +} __attribute__ ((__packed__)); + +struct setting_head { + uint32_t name_offset; + uint8_t name_length; + uint8_t type; +} __attribute__ ((__packed__)); + +settings_model::settings_model(const char *from_file) + : settings() { + file *f = open_file(from_file); + + file_head header; + read_from_file(f, 16, &header); + settings.expand_to(header.count); + settings.n_entries = header.count; + + for (uint32_t i = 0; i < header.count; ++i) { + setting_head shead; + seek_file_to(f, header.main_start + i * 16); + read_from_file(f, sizeof(setting_head), &shead); + + char *name = new char[shead.name_length + 1]; + seek_file_to(f, header.names_start + shead.name_offset); + read_from_file(f, shead.name_length, name); + name[shead.name_length] = '\0'; + + if (shead.type >= N_SETTING_KINDS) + raleigh::show_error_popup_and_quitf("setting \"%s\" has unkown type 0x%2x.", name, shead.type); + + setting ns; + ns.name = name; + ns.kind = setting_kinds[shead.type]; + + seek_file_to(f, header.main_start + i * 16 + 8); + ns.backing = ns.kind->read_backing(f, header.data_start); + + settings.buf[i] = ns; + } + + close_file(f); +}
\ No newline at end of file diff --git a/src/user/settings/model.h b/src/user/settings/model.h index 0c9b1d2..410121f 100644 --- a/src/user/settings/model.h +++ b/src/user/settings/model.h @@ -1,24 +1,60 @@ #ifndef MODEL_H #define MODEL_H -#include <raleigh/d/saving_window.h> -#include <structs/alist.h> +#include <raleigh/d/dialog.h> +#include <raleigh/w/button.h> +#include <raleigh/w/label.h> +#include <raleigh/w/vbox.h> +#include <raleigh/window.h> +#include <structs/map.h> +#include <knob/file.h> -union setting_data { - char *string; - _pixel_t color; +typedef void *backing_t; + +struct setting; + +struct setting_kind_info { + void (*write_main)(uint32_t &data_offset, file *f, const backing_t backing); + void (*write_data)(file *f, const backing_t backing); + backing_t (*read_backing)(file *f, uint32_t data_start); + void (*open_editor)(setting &s); }; struct setting { - enum { - STRING, - COLOR - } kind; - union setting_data data; const char *name; + const setting_kind_info *kind; + void *backing; +}; + +class settings_model { +public: + settings_model(const char *from_file); + + void write_to_file(const char *to_file); + + alist<setting> settings; }; -extern alist<struct setting> settings; -extern raleigh::saving_window *main_w; +using namespace raleigh; + +template<class backing_type, class editing_widget, void (*load_into_widget)(editing_widget &ew, backing_type s), void (*save_from_widget)(editing_widget &ew, backing_type &s)> +void do_common_editor(setting &s) { + dllist<widget &> widgets; + + label l(s.name); + widgets.add_back(l); + + editing_widget ew; + load_into_widget(ew, (backing_type)s.backing); + widgets.add_back(ew); + + vbox box(widgets); + + dialog d(box, okay_cancel); + d.show_modal(); + + if (d.result == OKAY) + save_from_widget(ew, (backing_type &)s.backing); +} #endif
\ No newline at end of file diff --git a/src/user/settings/str_editor.cpp b/src/user/settings/str_editor.cpp deleted file mode 100644 index 5e86e96..0000000 --- a/src/user/settings/str_editor.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include <knob/block.h> - -#include "str_editor.h" - -str_editor::str_editor(struct setting *s, const char *sname) - : e(10, 25, s->data.string), s(&s->data.string) { - editing_widget_ready(e, sname); -} - -void str_editor::set_data() { - const char *const contents = e.get_contents(); - if (strequ(contents, *s)) - return; - delete *s; - *s = strdup(contents); - main_w->is_saved = false; -}
\ No newline at end of file diff --git a/src/user/settings/str_editor.h b/src/user/settings/str_editor.h deleted file mode 100644 index 02bd7d8..0000000 --- a/src/user/settings/str_editor.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef STR_EDITOR_H -#define STR_EDITOR_H - -#include <raleigh/w/entry.h> - -#include "editor.h" -#include "model.h" - -class str_editor : public editor { -public: - str_editor(struct setting *s, const char *sname); - void set_data() override; - -private: - entry e; - char **s; -}; - -#endif
\ No newline at end of file diff --git a/src/user/settings/string_kind.cpp b/src/user/settings/string_kind.cpp new file mode 100644 index 0000000..0afe102 --- /dev/null +++ b/src/user/settings/string_kind.cpp @@ -0,0 +1,52 @@ +#include "string_kind.h" + +#include <raleigh/w/entry.h> + +void write_string_main(uint32_t &data_offset, file *f, const backing_t backing) { + const uint32_t len = strlen((const char *)backing); + + uint32_t main[2]; + main[0] = data_offset; + main[1] = len; + + data_offset += len; + + write_to_file(f, 8, main); +} + +void write_string_data(file *f, const backing_t backing) { + const char *b = (const char *)backing; + write_to_file(f, strlen(b), b); +} + +backing_t read_string_backing(file *f, uint32_t data_start) { + uint32_t main[2]; + read_from_file(f, 8, main); + + seek_file_to(f, data_start + main[0]); + + char *buf = new char[main[1] + 1]; + read_from_file(f, main[1], buf); + buf[main[1]] = '\0'; + + return (backing_t)buf; +} + +void load_into_entry(raleigh::entry &e, const char *s) { + e.set_contents(s); +} + +void save_from_entry(raleigh::entry &e, const char *&s) { + s = e.get_contents(); +} + +void open_string_editor(setting &s) { + do_common_editor<const char *, raleigh::entry, &load_into_entry, &save_from_entry>(s); +} + +const setting_kind_info string_kind = { + &write_string_main, + &write_string_data, + &read_string_backing, + &open_string_editor +};
\ No newline at end of file diff --git a/src/user/settings/string_kind.h b/src/user/settings/string_kind.h new file mode 100644 index 0000000..b62244f --- /dev/null +++ b/src/user/settings/string_kind.h @@ -0,0 +1,8 @@ +#ifndef STRING_KIND_H +#define STRING_KIND_H + +#include "model.h" + +extern const setting_kind_info string_kind; + +#endif
\ No newline at end of file |