summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenji Dial <benji6283@gmail.com>2021-06-21 17:47:13 -0400
committerBenji Dial <benji6283@gmail.com>2021-06-21 17:47:13 -0400
commitf57e2eabe0a10c9732c83532e01654a499fb8dcf (patch)
treecbf91a23fcdd65e0ea7ed55b0940ca7042d59bef /src
parent83835306d57461205a7bcfef9f4c3e06bc504006 (diff)
downloadportland-os-f57e2eabe0a10c9732c83532e01654a499fb8dcf.tar.gz
many, many changes; settings is broken
Diffstat (limited to 'src')
-rw-r--r--src/kernel/drive.c79
-rw-r--r--src/kernel/drive.h5
-rw-r--r--src/kernel/fat.c1
-rw-r--r--src/kernel/idt.c111
-rw-r--r--src/kernel/kbd.c9
-rw-r--r--src/kernel/log.c4
-rw-r--r--src/kernel/main.c13
-rw-r--r--src/kernel/settings.c9
-rw-r--r--src/kernel/window.c12
-rw-r--r--src/user/filetest/filetest.c2
-rw-r--r--src/user/highway/main.c2
-rw-r--r--src/user/include/cxx/raleigh/d/dialog.h14
-rw-r--r--src/user/include/cxx/raleigh/s/text_flower.h40
-rw-r--r--src/user/include/cxx/raleigh/util.h4
-rw-r--r--src/user/include/cxx/raleigh/w/entry.h67
-rw-r--r--src/user/include/cxx/raleigh/w/label.h16
-rw-r--r--src/user/include/cxx/raleigh/widget.h2
-rw-r--r--src/user/include/cxx/raleigh/window.h2
-rw-r--r--src/user/include/cxx/structs/alist.h63
-rw-r--r--src/user/include/cxx/structs/duple.h1
-rw-r--r--src/user/include/cxx/structs/map.h7
-rw-r--r--src/user/include/knob/block.h1
-rw-r--r--src/user/include/knob/file.h4
-rw-r--r--src/user/include/knob/heap.h2
-rw-r--r--src/user/include/libterm/terminal.h8
-rw-r--r--src/user/include/pland/syscall.h16
-rw-r--r--src/user/init/init.c11
-rw-r--r--src/user/knob/block.c24
-rw-r--r--src/user/knob/file.c6
-rw-r--r--src/user/knob/heap.c217
-rw-r--r--src/user/knob/task.c4
-rw-r--r--src/user/libfont/fonts.c4
-rw-r--r--src/user/meminfo/meminfo.cpp39
-rw-r--r--src/user/mkpopup/main.cpp50
-rw-r--r--src/user/raleigh/d/dialog.cpp27
-rw-r--r--src/user/raleigh/s/text_flower.cpp96
-rw-r--r--src/user/raleigh/util.cpp16
-rw-r--r--src/user/raleigh/w/entry.cpp362
-rw-r--r--src/user/raleigh/w/label.cpp49
-rw-r--r--src/user/raleigh/window.cpp8
-rw-r--r--src/user/runtimes/cxx/extra.ld5
-rw-r--r--src/user/settings/color_editor.cpp16
-rw-r--r--src/user/settings/color_editor.h19
-rw-r--r--src/user/settings/color_kind.cpp36
-rw-r--r--src/user/settings/color_kind.h8
-rw-r--r--src/user/settings/editor.cpp30
-rw-r--r--src/user/settings/editor.h20
-rw-r--r--src/user/settings/main.cpp190
-rw-r--r--src/user/settings/model.cpp60
-rw-r--r--src/user/settings/model.h60
-rw-r--r--src/user/settings/str_editor.cpp17
-rw-r--r--src/user/settings/str_editor.h19
-rw-r--r--src/user/settings/string_kind.cpp52
-rw-r--r--src/user/settings/string_kind.h8
54 files changed, 1089 insertions, 858 deletions
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