diff --git a/.gitignore b/.gitignore index 915d39f..840bb0f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ bin/ build/ -logs/ sandbox/ # clangd diff --git a/Makefile b/Makefile index 40dc834..36b9358 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,6 @@ BUILD := build LIB := lib CLI := cli -CT := cursetree # === MACRO DEFINITIONS === define objpath @@ -19,13 +18,13 @@ endef define mkobj $(foreach DEP, $?, mkdir -p $(dir $(call objpath, $(DEP))) - $(CC) $(CFLAGS) $1 -o $(call objpath, $(DEP)) -c $(DEP)) + $(CC) $(CFLAGS) -o $(call objpath, $(DEP)) -c $(DEP)) $(LD) -r $(LDFLAGS) -o $@ $(call objpath, $?) endef # === BUILD TARGETS === -all: $(BUILD) $(BIN) $(addprefix $(BIN)/,pw-test dorne) +all: $(BUILD) $(BIN) $(addprefix $(BIN)/,pw-test shfx dorne) $(BIN)/pw-test: $(addprefix $(LIB)/, main.c) $(CC) $(CFLAGS) -o $(BUILD)/pw-test.o -c $^ $(CLD) $(CLDFLAGS) -lpipewire-0.3 -o $@ $(BUILD)/pw-test.o @@ -37,11 +36,11 @@ $(BUILD) $(BIN): mkdir -p $@ $(BUILD)/dorne.o: $(addprefix $(CLI)/, main.c) - $(call mkobj,-Icursetree) -$(BUILD)/cursetree.o: $(addprefix $(CT)/, cursetree.c tree.c node.c surface.c dims.c ncrswrap.c) - $(call mkobj,) -$(BUILD)/epty.o: $(addprefix $(CT)/, pty/child.c pty/epty.c pty/_pty.c) - $(call mkobj,) + $(mkobj) +$(BUILD)/cursetree.o: $(addprefix $(CLI)/, tree.c curse.c) + $(mkobj) +$(BUILD)/epty.o: $(addprefix $(CLI)/, child.c epty.c _pty.c) + $(mkobj) # === DEVELOPMENT TARGETS === .PHONY: debug run test @@ -56,4 +55,4 @@ test: clean run # === UTILITY TARGETS === .PHONY: clean clean: - - rm -rf $(BUILD) $(BIN) vgcore.* &>/dev/null logs/ + - rm -rf $(BUILD) $(BIN) vgcore.* &>/dev/null diff --git a/README.md b/README.md index 191dc54..271ecdf 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,6 @@ A personal functional music programming framework written in Haskell & C and packaged with Nix. ### Setup -Ensure that your system's version of ncurses has the following extensions: -- wide character support -- term resizing (see `man 3x resizeterm`) -> TODO: actually list which extensions are used and how to compile with them - ```bash nix build && nix develop -i ``` diff --git a/TODO.md b/TODO.md index f103fc7..36d892f 100644 --- a/TODO.md +++ b/TODO.md @@ -9,12 +9,4 @@ then fork and exec shfx as child (+ close ptmx), then close pts as parent. - [ ] Should I compile ncurses with --with-pthread? (see `man 3x ncurses`) What about --enable-widec? (are these just ligatures?) -- [ ] cursetree shits itself if width/height are 0 on bifurcation -- [ ] ensure NDEBUG is set for preprocessor to avoid statements if not debugging - - -- [ ] resize_node() is quite wasteful and results could definitely be cached for the next resize_node() call - -- I think this should help! - https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/windows.html#OTHERBORDERFUNCS diff --git a/cursetree/pty/_pty.c b/cli/_pty.c similarity index 100% rename from cursetree/pty/_pty.c rename to cli/_pty.c diff --git a/cursetree/pty/_pty.h b/cli/_pty.h similarity index 90% rename from cursetree/pty/_pty.h rename to cli/_pty.h index 652178f..3c80b95 100644 --- a/cursetree/pty/_pty.h +++ b/cli/_pty.h @@ -1,5 +1,5 @@ -#ifndef CURSETREE_PTY_H -#define CURSETREE_PTY_H +#ifndef DORNE_MKPTY_H +#define DORNE_MKPTY_H #include #include @@ -27,4 +27,4 @@ int setptsxy(const unsigned short rows, const unsigned short cols, const int fds); int getptsxy(unsigned short *rows, unsigned short *cols, const int fds); -#endif /* CURSETREE_PTY_H */ +#endif /* DORNE_MKPTY_H */ diff --git a/cursetree/pty/child.c b/cli/child.c similarity index 100% rename from cursetree/pty/child.c rename to cli/child.c diff --git a/cursetree/pty/child.h b/cli/child.h similarity index 72% rename from cursetree/pty/child.h rename to cli/child.h index 294b1c3..6ec3978 100644 --- a/cursetree/pty/child.h +++ b/cli/child.h @@ -1,5 +1,5 @@ -#ifndef CURSETREE_CHILD_H -#define CURSETREE_CHILD_H +#ifndef DORNE_CHILD_H +#define DORNE_CHILD_H #include @@ -11,4 +11,4 @@ struct d_child { int spawnchild(struct d_child *child); -#endif /* CURSETREE_CHILD_H */ +#endif /* DORNE_CHILD_H */ diff --git a/cursetree/ncrswrap.c b/cli/curse.c similarity index 62% rename from cursetree/ncrswrap.c rename to cli/curse.c index d81cc4b..3c465fe 100644 --- a/cursetree/ncrswrap.c +++ b/cli/curse.c @@ -1,10 +1,9 @@ #include #include -#include "_ncurses.h" - -#include "ncrswrap.h" +#include "curse.h" +#define BASE_DELAY 1000000 #define CRS_LOCALE "en_US.UTF-8" /* Set ncurses terminal mode (buffering, character processing, @@ -26,18 +25,6 @@ int termmode(const enum crs_termmode mode) { } } -void termsize(int *const width, int *const height) { - *width = COLS; - *height = LINES; -} - -struct ct_dims *termdims(void) { - struct ct_dims *dims = new_dims(0, 0, 0, 0); - termsize(&dims->width, &dims->height); - - return dims; -} - /* Apply a default IO configuration for an ncurses WINDOW. */ static inline void __conf_window(WINDOW *const win) { @@ -54,9 +41,8 @@ void init_ncurses(void) { // ncurses expects a locale for consistent behaviour setlocale(LC_ALL, CRS_LOCALE); - /* NCurses Initialisation */ + /* NCurses Init */ initscr(); - /* WARNING: no you shouldn't delwin(stdscr) it breaks everything... */ __conf_window(stdscr); start_color(); @@ -67,10 +53,6 @@ void init_ncurses(void) { curs_set(0); // hide cursor } -void end_ncurses(void) { - endwin(); -} - /* Initialise (with default IO configuration) a new ncurses WINDOW. */ WINDOW *new_window(const int x, const int y, const int width, @@ -81,34 +63,52 @@ WINDOW *new_window(const int x, const int y, const int width, return win; } -/* Initialise (with default IO configuration) a fullscreen ncurses WINDOW. +/* Initialise (with default IO configuration) the root ncurses WINDOW. + * NOTE: This is typically done via initscr(3x) and called "stdscr". */ -WINDOW *new_window_fs(void) { +WINDOW *root_window(void) { WINDOW *rootwin = new_window(0, 0, COLS, LINES); __conf_window(rootwin); return rootwin; } -// void destroy_window(WINDOW *) __attribute__((alias("delwin"))); - -// int winposx(WINDOW *) __attribute__((alias("getbegy"))); -// int winposy(WINDOW *) __attribute__((alias("getbegy"))); -// int winwidth(WINDOW *) __attribute__((alias("getmaxx"))); -// int winheight(WINDOW *) __attribute__((alias("getmaxy"))); - -// struct ct_dims *windims(WINDOW *win) { -// int x, y, width, height; -// winpos(win, x, y); -// winsize(win, width, height); -// return new_dims(x, y, width, height); -// } - /* Resize and move (if resized successfully) an ncurses WINDOW. * Returns ERR (1) on fail, and OK (0) on success. * NOTE: Failure occurs if width or height <= 0, * NOTE: or if the x,y coordinate is outside the screen bounds. */ -int resizemv_window(WINDOW *const win, const int x, const int y, - const int width, const int height) { +int resizemv_window(const int x, const int y, const int width, const int height, + WINDOW *const win) { return wresize(win, height, width) || mvwin(win, y, x); } + +/* +int main(const int argc, const char *const argv[]) { + init_ncurses(); + WINDOW *stdscr = new_window(0, 0, 0, 0); + + // Set background + wbkgd(stdscr, COLOR_PAIR(1)); + + attron(COLOR_PAIR(1)); + attron(A_BOLD); + int counter = 0; + while (1) { + mvprintw(0, 0, "COUNTER %d", counter++); + refresh(); + + switch (getch()) { + case 'q': + goto end; + default: + break; + } + + usleep(BASE_DELAY); + } + +end: + endwin(); + return 0; +} +*/ diff --git a/cli/curse.h b/cli/curse.h new file mode 100644 index 0000000..72f0e7e --- /dev/null +++ b/cli/curse.h @@ -0,0 +1,27 @@ +#ifndef DORNE_CURSE_H +#define DORNE_CURSE_H + +/* libncurses with wide-character support. */ +#include + +enum crs_termmode { + /* tty cbreak mode */ + TMODE_CBREAK, + /* tty raw mode */ + TMODE_RAW, + /* tty cooked mode (ISIG & IXON not modified)*/ + TMODE_NOCBREAK, + /* tty cooked mode (ISIG & IXON set) */ + TMODE_NORAW, +}; + +int termmode(const enum crs_termmode mode); + +void init_ncurses(void); +WINDOW *new_window(const int x, const int y, const int width, const int height); +WINDOW *root_window(void); + +int resizemv_window(const int x, const int y, const int width, const int height, + WINDOW *const win); + +#endif /* DORNE_CURSE_H */ diff --git a/cursetree/pty/epty.c b/cli/epty.c similarity index 100% rename from cursetree/pty/epty.c rename to cli/epty.c diff --git a/cli/epty.h b/cli/epty.h new file mode 100644 index 0000000..8dd18e4 --- /dev/null +++ b/cli/epty.h @@ -0,0 +1,8 @@ +#ifndef DORNE_EPTY_H +#define DORNE_EPTY_H + +#include + +pid_t forkepty(int *fdmx, int *fderr); + +#endif /* DORNE_EPTY_H */ diff --git a/cli/main.c b/cli/main.c index dd4f338..956a25e 100644 --- a/cli/main.c +++ b/cli/main.c @@ -4,66 +4,79 @@ #include -#include "cursetree.h" -#include "surface.h" +// #include "child.h" +#include "curse.h" +#include "tree.h" -#define nprintsfdims(nout, i, label, nin) \ - (mvwprintw((nout)->surface->win, (i), 0, "%s@(%d,%d) %dx%d", (label), \ - (nin)->surface->dims->x, (nin)->surface->dims->y, \ - (nin)->surface->dims->width, (nin)->surface->dims->height)) +// struct d_window { +// int ptmx; // fd +// }; + +// struct d_window new_window() { +// struct d_window w = { +// .ptmx = posix_openpt(O_RDWR | O_NOCTTY), +// }; +// } int main(int argc, char **argv) { - struct ct_tree *tree; - ct_init(&tree); + // struct d_child child; + // spawnchild(&child); - init_pair(1, COLOR_BLACK, COLOR_CYAN); - init_pair(2, COLOR_BLACK, COLOR_RED); - init_pair(3, COLOR_BLACK, COLOR_GREEN); - init_pair(4, COLOR_BLACK, COLOR_MAGENTA); - init_pair(5, COLOR_BLACK, COLOR_YELLOW); + struct crs_tree *tree; + init_tree(&tree); - struct ct_node *const child1 = new_node(bounds_none(), tree->root); - // struct ct_node *const child2 = new_node(bounds_none(), tree->root); - // struct ct_node *const child3 = new_node(bounds_none(), tree->root); - // struct ct_node *const child4 = new_node(bounds_none(), tree->root); - // struct ct_node *const child5 = new_node(bounds_none(), tree->root); - append_child_node(tree->root, child1); - // append_child_node(tree->root, child2); - // append_child_node(tree->root, child3); - // append_child_node(tree->root, child4); - // append_child_node(tree->root, child5); + init_pair(1, COLOR_CYAN, COLOR_CYAN); + init_pair(2, COLOR_RED, COLOR_RED); + init_pair(3, COLOR_MAGENTA, COLOR_MAGENTA); + init_pair(4, COLOR_YELLOW, COLOR_YELLOW); + init_pair(5, COLOR_GREEN, COLOR_GREEN); - wbkgd(child1->surface->win, COLOR_PAIR(1)); - // wbkgd(child2->surface->win, COLOR_PAIR(2)); - // wbkgd(child3->surface->win, COLOR_PAIR(3)); - // wbkgd(child4->surface->win, COLOR_PAIR(4)); - // wbkgd(child5->surface->win, COLOR_PAIR(5)); + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + /* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/ + bifurcate_window_node(&tree->root, AXIS_X, FALSE, 0.5); + bifurcate_window_node(&tree->root->child[0], AXIS_X, FALSE, 0.05); + bifurcate_window_node(&tree->root->child[1], AXIS_Y, FALSE, 0.7); + bifurcate_window_node(&tree->root->child[1]->child[1], AXIS_X, FALSE, 0.9); - // child3->axis = AXIS_Y; - // struct ct_node *const child3_1 = new_node(bounds_none(), child3); - // struct ct_node *const child3_2 = new_node(bounds_none(), child3); - // append_child_node(child3, child3_1); - // append_child_node(child3, child3_2); - // wbkgd(child3_1->surface->win, COLOR_PAIR(1)); - // wbkgd(child3_2->surface->win, COLOR_PAIR(5)); + wbkgd(tree->root->child[0]->child[0]->win, COLOR_PAIR(5)); + wbkgd(tree->root->child[0]->child[1]->win, COLOR_PAIR(3)); + wbkgd(tree->root->child[1]->child[0]->win, COLOR_PAIR(2)); + wbkgd(tree->root->child[1]->child[1]->child[0]->win, COLOR_PAIR(1)); + wbkgd(tree->root->child[1]->child[1]->child[1]->win, COLOR_PAIR(4)); + wrefresh(tree->root->child[0]->child[0]->win); + wrefresh(tree->root->child[0]->child[1]->win); + wrefresh(tree->root->child[1]->child[0]->win); + wrefresh(tree->root->child[1]->child[1]->child[0]->win); + wrefresh(tree->root->child[1]->child[1]->child[1]->win); + + /* NOTE : THIS IS VALID : NOTE */ + // refresh(); + // WINDOW *my_win = newwin(0, 0, 0, 0); + // wbkgd(my_win, COLOR_PAIR(1)); + // wrefresh(my_win); + + /* NOTE : THIS IS VALID : NOTE */ + // wbkgd(tree->root->win, COLOR_PAIR(2)); + // wrefresh(tree->root->win); while (1) { - ct_update(tree); - - // nprintsfdims(child2, 0, "R", tree->root); - // nprintsfdims(child2, 1, "1", child1); - // nprintsfdims(child2, 2, "2", child2); - // nprintsfdims(child2, 3, "3", child3); - // nprintsfdims(child2, 4, "4", child4); - // nprintsfdims(child2, 5, "5", child5); - - // nprintsfdims(child2, 7, "3_1", child3_1); - // nprintsfdims(child2, 8, "3_2", child3_2); - - ct_process(tree); + // refresh(); + usleep(100000); } destroy_tree(tree); + // endwin(); + // free(tree); return EXIT_SUCCESS; } diff --git a/cli/tree.c b/cli/tree.c new file mode 100644 index 0000000..0c0b975 --- /dev/null +++ b/cli/tree.c @@ -0,0 +1,245 @@ +#include +#include +#include + +#include "curse.h" +#include "tree.h" + +/* Internal allocator method for crs_node structures. + */ +static inline struct crs_node *__alloc_node(const enum crs_nodetype type) { + struct crs_node *node = (struct crs_node *)malloc(sizeof(struct crs_node)); + node->type = type; + return node; +} + +/* Construct a new window node (crs_node of type NODE_WIN). + */ +static struct crs_node *init_window_node(WINDOW *const win) { + struct crs_node *node = __alloc_node(NODE_WINDOW); + node->win = win; + + return node; +} + +static struct crs_node *auto_window_node(const struct crs_nodedims *dims) { + WINDOW *win = newwin(dims->height, dims->width, dims->y, dims->x); + return init_window_node(win); +} + +static struct crs_node *init_abstract_node(struct crs_node *node0, + struct crs_node *node1, + const enum crs_axis axis, + const float ratio, + struct crs_nodedims *dims) { + struct crs_node *node = __alloc_node(NODE_ABSTRACT); + node->axis = axis; + node->ratio = ratio; + node->dims = dims; + + node->child[0] = node0; + node->child[1] = node1; + return node; +} + +static void destroy_node(struct crs_node *node) { + if (node->type == NODE_WINDOW) { + /* Window Node */ + delwin(node->win); + goto end; + } + /* Abstract Node */ + assert(node->type == NODE_ABSTRACT); + destroy_node(node->child[0]); + destroy_node(node->child[1]); + free(node->dims); + +end: + free(node); +} + +static inline struct crs_nodedims *__dup_dims(const struct crs_nodedims *dims) { + struct crs_nodedims *dup; + dup = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); + memcpy(dup, dims, sizeof(struct crs_nodedims)); + + return dup; +} + +static struct crs_nodedims *get_dims(const struct crs_node *node) { + struct crs_nodedims *dims; + if (node->type == NODE_WINDOW) { + /* Window Node */ + dims = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); + // GET_WNODEDIMS(); + getbegyx(node->win, dims->y, dims->x); + getmaxyx(node->win, dims->height, dims->width); + printf("getx: %d\n", dims->x); + printf("gety: %d\n", dims->y); + printf("getwidth: %d\n", dims->width); + printf("getheight: %d\n", dims->height); + } else { + /* Abstract Node */ + assert(node->type == NODE_ABSTRACT); + dims = __dup_dims(node->dims); + } + + return dims; +} + +struct crs_nodedims term_dims(void) { + struct crs_nodedims dims; + getbegyx(stdscr, dims.y, dims.x); + getmaxyx(stdscr, dims.height, dims.width); + return dims; +} + +/* Calculate the dimensions for nodes resulting from a bifurcation. + * Returns 0 on success, and 1 on failure if any width/height are 0 characters. + * WARNING: This function does not guarantee the x,y positions returned + * WARNING: are valid screen coordinates. + */ +static int bifurcate_dims(const struct crs_node *parent, + const enum crs_axis axis, const float ratio, + struct crs_nodedims **dims0, + struct crs_nodedims **dims1) { + assert(0 < ratio && ratio < 1); + struct crs_nodedims *_dims0, *_dims1; + + _dims0 = get_dims(parent); + _dims1 = __dup_dims(_dims0); + + printf("widthP: %d\n", _dims0->width); + printf("heightP: %d\n", _dims0->height); + + if (axis == AXIS_X) { + _dims0->width *= ratio; + _dims1->width -= _dims0->width; + _dims1->x += _dims0->width; + } else { + _dims0->height *= ratio; + _dims1->height -= _dims0->height; + _dims1->y += _dims0->height; + } + + if (!_dims0->width || !_dims0->height || !_dims1->width || !_dims1->height) { + printf("width0: %d\n", _dims0->width); + printf("height0: %d\n", _dims0->height); + printf("width1: %d\n", _dims1->width); + printf("height1: %d\n", _dims1->height); + return 1; + } + + // propagate bifurcated dimensions + *dims0 = _dims0; + *dims1 = _dims1; + return 0; +} + +static void resize_node(struct crs_node *node, struct crs_nodedims *new_dims) { + if (node->type == NODE_WINDOW) { + /* Window Node */ + resizemv_window(new_dims->x, new_dims->y, new_dims->width, new_dims->height, + node->win); + free(new_dims); + } else { + /* Abstract Node */ + assert(node->type == NODE_ABSTRACT); + struct crs_nodedims *dims0, *dims1; + + free(node->dims); + node->dims = new_dims; + bifurcate_dims(node, node->axis, node->ratio, &dims0, &dims1); + + resize_node(node->child[0], dims0); + resize_node(node->child[1], dims1); + } +} + +/* Subdivide a window node's allocated region into two window nodes + * replacing the original node with an abstract node. + * Parameters: + * axis - controls which direction the subdivision occurs + * invert_axis - invert index of the original node in the new abstract node + */ +void bifurcate_window_node(struct crs_node **node, const enum crs_axis axis, + const int invert_axis, const float ratio) { + assert((*node)->type == NODE_WINDOW); + struct crs_nodedims *dims0, *dims1; + struct crs_node *node0, *node1; + + if (bifurcate_dims(*node, axis, ratio, &dims0, &dims1)) { + printf("FAILED TERRIBLY THE FUCK\n"); + exit(1); + return; + } + if (invert_axis) { + /* Inverted Bifurcation */ + node0 = auto_window_node(dims0); + node1 = *node; + resize_node(node1, dims1); + } else { + /* Non-Inverted Bifurcation */ + node0 = *node; + node1 = auto_window_node(dims1); + resize_node(node0, dims0); + } + + *node = init_abstract_node(node0, node1, axis, ratio, (*node)->dims); +} + +/* Collapse an abstract node, killing one child node and resizing + * the other to take its place. + */ +static void collapse_abstract_node(struct crs_node **node, + const int collapse_i) { + assert((*node)->type == NODE_ABSTRACT); + assert(0 <= collapse_i && collapse_i < NODE_CHILD_N); + + // WARNING: only works for NODE_CHILD_N=2 (binary trees) + destroy_node((*node)->child[!collapse_i]); + + struct crs_node *collapse_target = (*node)->child[collapse_i]; + free(*node); + *node = collapse_target; +} + +/* + */ +static struct crs_node *init_root_node(void) { + struct crs_nodedims rootdims; + WINDOW *rootwin; + + // rootdims = term_dims(); + // rootwin = new_window(rootdims.x, rootdims.y, + // rootdims.height, rootdims.height); + // rootwin = new_window(0, 0, 0, 0); + rootwin = root_window(); + return init_window_node(rootwin); +} + +int init_tree(struct crs_tree **const tree) { + *tree = (struct crs_tree *)malloc(sizeof(struct crs_tree)); + + /* Initialise NCurses Library & Standard Screen */ + init_ncurses(); + + (*tree)->root = init_root_node(); + + // (*tree)->root = __alloc_node(NODE_WINDOW); + // crs_init(&(*tree)->root->win); + + return EXIT_SUCCESS; +} + +void destroy_tree(struct crs_tree *const tree) { + /* WARNING: is it ok to delwin(stdscr) ?? */ + destroy_node(tree->root); + + endwin(); + free(tree); +} + +void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims) { + resize_node(tree->root, dims); +} diff --git a/cli/tree.h b/cli/tree.h new file mode 100644 index 0000000..c2263f1 --- /dev/null +++ b/cli/tree.h @@ -0,0 +1,61 @@ +#ifndef DORNE_TREE_H +#define DORNE_TREE_H + +#ifndef __NCURSES_H +typedef struct _win_st WINDOW; +#endif /* __NCURSES_H */ + +#define NODE_CHILD_N 2 + +/* MACRO: + * Get widnow node start x,y coordinates, width, & height. + * void NODEDIMS(struct crs_node *node, struct crs_nodedims dims); + */ +#define GET_WNODEDIMS(dims, node) \ + (getbegyx((node)->win, dims.y, dims.x)); \ + getmaxyx((node)->win, dims.y, dims.x) + +enum crs_nodetype { + NODE_WINDOW, + NODE_ABSTRACT, +}; + +/* Stores a node's starting x,y coordinates, width, & height. + * NOTE: Intended for interfunction communication. + */ +struct crs_nodedims { + int x, y, width, height; +}; + +enum crs_axis { + AXIS_X, + AXIS_Y, +}; + +struct crs_node { + enum crs_nodetype type; + // union value depends on crs_node.type + union { + WINDOW *win; + struct { + enum crs_axis axis; + float ratio; + struct crs_nodedims *dims; + struct crs_node *child[NODE_CHILD_N]; + }; + }; +}; + +struct crs_tree { + struct crs_node *root; +}; + +/* === External Interface === */ +int init_tree(struct crs_tree **const tree); +void destroy_tree(struct crs_tree *const tree); +void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims); + +void bifurcate_window_node(struct crs_node **node, const enum crs_axis axis, + const int invert_axis, const float ratio); + +#endif /* DORNE_TREE_H */ diff --git a/cursetree/_ncurses.h b/cursetree/_ncurses.h deleted file mode 100644 index dc92562..0000000 --- a/cursetree/_ncurses.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This file exists to isolate the ncurses instance being used - * ie ncurses, ncursesw, ncursest, ncursestw - */ - -/* libncurses with wide-character support. */ -#include diff --git a/cursetree/cursetree.c b/cursetree/cursetree.c deleted file mode 100644 index 31504a8..0000000 --- a/cursetree/cursetree.c +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include -#include - -#include "_ncurses.h" -#include "ncrswrap.h" -#include "ncurses.h" -#include "node.h" -#include "tree.h" - -volatile sig_atomic_t got_winch = 0; - -void handle_SIGWINCH(int sig) { - // endwin(); - // Needs to be called after an endwin() so ncurses will initialize - // itself with the new terminal dimensions. - got_winch = 1; -} - -/* - * If ncurses is configured to supply its own SIGWINCH handler, - * - on receipt of a SIGWINCH, the handler sets a flag - * - which is tested in wgetch(3X), doupdate(3X) and restartterm(3X), - * - in turn, calling the resizeterm function, - * - which ungetch's a KEY_RESIZE which will be read on the next call to - * wgetch. REF: `man resizeterm(3x)` - */ -static void bind_SIGWINCH(void) { - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = handle_SIGWINCH; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; /* Restart functions if - interrupted by handler */ - if (sigaction(SIGWINCH, &sa, NULL) == -1) { - perror("bind_SIGWINCH"); - exit(2); - } -} - -int ct_init(struct ct_tree **const tree) { - // bind_SIGWINCH(); - /* Initialise NCurses Library & Root Node */ - init_ncurses(); - init_tree(tree); - - return EXIT_SUCCESS; -} - -void ct_redraw(void) { - /* TODO: hide doupdate() behind some other method */ - /* flush ncurses virtual screen -> physical screen */ - doupdate(); -} - -/* Recursively search the tree for update requests. - * Returns: - * 0 - success (no action required) - * 1 - success (request: redraw the screen) - */ -static int __update_rec(struct ct_node *const node) { - int result = 0; - struct ct_dims *dims; - - if (node->flags & NFLAG_RESIZE) { - /* TODO: the child has requested a resizing, but resize_node() - * TODO: wastes CPU time resizing itself! - */ - dims = IS_ROOT_NODE(node) ? termdims() : dup_dims(node->surface->dims); - resize_node(node, dims); - node->flags &= ~NFLAG_RESIZE; - result = 1; - } - if (node->surface->updatereq) { - // TODO: is this necessary or does mvresize_win do this for us? - wnoutrefresh(node->surface->win); - node->surface->updatereq = 0; - } - - for (int i = 0; i < node->cindex; i++) { - result |= __update_rec(node->child[i]); - } - return result; -} - -void ct_update(struct ct_tree *const tree) { - // WARNING: update_rec does not flush the screen, wgetch will do that for us - if (__update_rec(tree->root)) { - doupdate(); - // redrawwin(curscr); - // wrefresh(curscr); - } -} - -void ct_process(struct ct_tree *const tree) { - const int key = wgetch(curscr); - // int key = -1; - - /* ncurses binds a SIGWINCH handler if SIGWINCH has SIG_DFL disposition - * when initscr(3x) is called. This handler emits KEY_RESIZE (decimal 410) to - * stdin. REF: manpages -> resizeterm(3x) initscr(3x) wgetch(3x) - */ - switch (key) { - case -1: - // wclear(tree->root->surface->win); - // mvwprintw(tree->root->surface->win, 0, 0, " \r-1\n"); - // wrefresh(tree->root->surface->win); - break; - case KEY_RESIZE: - // got_winch = 1; - tree->root->flags |= NFLAG_RESIZE; - break; - default: - // wclear(tree->root->surface->win); - // mvwprintw(tree->root->surface->win, 0, 0, " \r%d\n", key); - // wrefresh(tree->root->surface->win); - break; - } - - // if (got_winch == 1) { - // tree->root->flags |= NFLAG_RESIZE; - // got_winch = 0; - // } - - // if (__update_rec(tree->root)) { - // ct_redraw(); - // } -} diff --git a/cursetree/cursetree.h b/cursetree/cursetree.h deleted file mode 100644 index d066429..0000000 --- a/cursetree/cursetree.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CURSETREE_CURSETREE_H -#define CURSETREE_CURSETREE_H - -#include "tree.h" - -/* === External Interface === */ -int ct_init(struct ct_tree **const tree); -void ct_update(struct ct_tree *const tree); -void ct_process(struct ct_tree *const tree); - -#endif /* CURSETREE_CURSETREE_H */ diff --git a/cursetree/dims.c b/cursetree/dims.c deleted file mode 100644 index 771c68a..0000000 --- a/cursetree/dims.c +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include -#include -#include - -#include "dims.h" -#include "node.h" -#include "util.h" - -struct ct_dims *new_dims(const int x, const int y, const int width, const int height) { - struct ct_dims *dims; - - dims = (struct ct_dims *)malloc(sizeof(struct ct_dims)); - *dims = (struct ct_dims){ - .x = x, - .y = y, - .width = width, - .height = height, - }; - return dims; -} - -struct ct_dims *dup_dims(const struct ct_dims *const dims) { - struct ct_dims *dup; - dup = (struct ct_dims *)malloc(sizeof(struct ct_dims)); - memcpy(dup, dims, sizeof(struct ct_dims)); - - return dup; -} - -static struct ct_bounds *__bounds(const enum ct_boundtype type, const int wmin, - const int wmax, const int hmin, - const int hmax) { - struct ct_bounds *bounds; - - bounds = (struct ct_bounds *)malloc(sizeof(struct ct_bounds)); - *bounds = (struct ct_bounds){ - .type = type, - .wmin = wmin, - .wmax = wmax, - .hmin = hmin, - .hmax = hmax, - }; - return bounds; -} - -static inline void __clamp(int *const val, const int min, const int max, - const int do_ceiling) { - if (*val == __BOUND_UNLIMITED) - *val = do_ceiling ? max : min; - else - *val = clampi(*val, min, max); -} -#define CLAMP_ABS(val, is_max) \ - (__clamp(&val, __BOUND_ABS_MIN, __BOUND_ABS_MAX, is_max)) -#define CLAMP_REL(val, is_max) \ - (__clamp(&val, __BOUND_REL_MIN, __BOUND_REL_MAX, is_max)) - -struct ct_bounds *bounds_none(void) { - return __bounds(BOUND_NONE, __BOUND_ABS_MIN, __BOUND_ABS_MAX, __BOUND_ABS_MIN, - __BOUND_ABS_MAX); -} - -struct ct_bounds *bounds_absolute(int wmin, int wmax, - int hmin, int hmax) { - CLAMP_ABS(wmin, false); - CLAMP_ABS(wmax, true); - CLAMP_ABS(hmin, false); - CLAMP_ABS(hmax, true); - return __bounds(BOUND_ABSOLUTE, wmin, wmax, hmin, hmax); -} - -struct ct_bounds *bounds_relative(int wmin, int wmax, - int hmin, int hmax) { - CLAMP_REL(wmin, false); - CLAMP_REL(wmax, true); - CLAMP_REL(hmin, false); - CLAMP_REL(hmax, true); - return __bounds(BOUND_RELATIVE, wmin, wmax, hmin, hmax); -} - -struct ct_bounds *dup_bounds(const struct ct_bounds *const bounds) { - struct ct_bounds *dup; - dup = (struct ct_bounds *)malloc(sizeof(struct ct_bounds)); - memcpy(dup, bounds, sizeof(struct ct_bounds)); - - return dup; -} diff --git a/cursetree/dims.h b/cursetree/dims.h deleted file mode 100644 index 86417ba..0000000 --- a/cursetree/dims.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef CURSETREE_DIMS_H -#define CURSETREE_DIMS_H - -#define __BOUND_UNLIMITED (-1) -#define __BOUND_ABS_MIN (1) -#define __BOUND_ABS_MAX (INT_MAX / CINDEX_MAX - 1) -#define __BOUND_REL_MIN ((float)0) -#define __BOUND_REL_MAX ((float)1) - -enum ct_axis { - AXIS_X, - AXIS_Y, -}; - -enum ct_boundtype { - BOUND_NONE, - BOUND_ABSOLUTE, - BOUND_RELATIVE, -}; - -/* Stores a node's starting x,y coordinates, width, & height. - * NOTE: Intended for interfunction communication. - */ -struct ct_dims { - int x, y, width, height; -}; - -struct ct_bounds { - enum ct_boundtype type; - int wmin, wmax, hmin, hmax; -}; - -struct ct_dims *new_dims(const int x, const int y, const int width, const int height); -struct ct_dims *dup_dims(const struct ct_dims *const dims); - -struct ct_bounds *bounds_none(void); -struct ct_bounds *bounds_absolute(int wmin, int wmax, int hmin, int hmax); -struct ct_bounds *bounds_relative(int wmin, int wmax, int hmin, int hmax); -struct ct_bounds *dup_bounds(const struct ct_bounds *const bounds); - -#endif /* CURSETREE_DIMS_H */ diff --git a/cursetree/ncrswrap.h b/cursetree/ncrswrap.h deleted file mode 100644 index f21ffbf..0000000 --- a/cursetree/ncrswrap.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef CURSETREE_NCRSWRAP_H -#define CURSETREE_NCRSWRAP_H - -#include "dims.h" - -#ifndef __NCURSES_H -typedef struct _win_st WINDOW; -#endif /* __NCURSES_H */ - -enum crs_termmode { - /* tty cbreak mode */ - TMODE_CBREAK, - /* tty raw mode */ - TMODE_RAW, - /* tty cooked mode (ISIG & IXON not modified)*/ - TMODE_NOCBREAK, - /* tty cooked mode (ISIG & IXON set) */ - TMODE_NORAW, -}; - -int termmode(const enum crs_termmode mode); -void termsize(int *const width, int *const height); -struct ct_dims *termdims(void); - -void init_ncurses(void); -void end_ncurses(void); - -WINDOW *new_window(const int x, const int y, const int width, const int height); -WINDOW *new_window_fs(void); -void destroy_window(WINDOW *); - -int resizemv_window(WINDOW *const win, const int x, const int y, - const int width, const int height); - -#endif /* CURSETREE_NCRSWRAP_H */ diff --git a/cursetree/node.c b/cursetree/node.c deleted file mode 100644 index d3c4422..0000000 --- a/cursetree/node.c +++ /dev/null @@ -1,359 +0,0 @@ -#include -#include -#include -#include -#include - -#include "dims.h" -#include "node.h" -#include "surface.h" -#include "util.h" - -/* Internal allocator method for ct_node structures. - */ -static inline struct ct_node *__alloc_node(void) { - struct ct_node *node = (struct ct_node *)malloc(sizeof(struct ct_node)); - return node; -} - -/* Returns NULL if memory allocation failed. - * TODO: should dims be given as a parameter, or lazily computed in ct_update? - */ -struct ct_node *__node(struct ct_dims *const dims, - struct ct_bounds *const bounds, - struct ct_node *const parent) { - struct ct_node *node = __alloc_node(); - if (node != NULL) { - *node = (struct ct_node){ - .surface = new_surface(dims, bounds), - .flags = NFLAG_EMPTY, - - .parent = parent, - .child = (struct ct_node **)malloc(NODE_INIT_CHILDREN * - sizeof(struct ct_node *)), - .csize = NODE_INIT_CHILDREN, - .cindex = 0, - .axis = AXIS_X, - }; - } - - return node; -} - -struct ct_node *new_node(struct ct_bounds *const bounds, - struct ct_node *const parent) { - /* copy the parent's dimensions for now and request - * cursetree resize this node appropriately afterwards - * WARNING: new_node doesn't set the NFLAG_RESIZE request flag - * WARNING: that should be done by a function calling new_node - */ - return __node(dup_dims(parent->surface->dims), bounds, parent); -} - -/* WARNING: Do NOT use __destroy_node() to destroy a node's children! - * WARNING: Use the destroy_child_node() function instead. - */ -void __destroy_node(struct ct_node *const node) { - if (node == NULL) - return; - - // destroy children first - for (int j = 0; j < node->cindex; j++) { - __destroy_node(node->child[j]); - } - - destroy_surface(node->surface); - free(node); -} - -/* Surface Partition Dimensions */ -/* TODO: can I use unsigned short instead of int? */ -struct ct_spdims { - // Main Axis & Orthogonal Axis Sizes - int axm_size; - bool fixed; - int min, max; -}; - -/* - */ -int resize_node(struct ct_node *const node, struct ct_dims *dims) { - resize_surface(node->surface, dims); - dims = node->surface->dims; - - if (node->surface->bounds->wmin > dims->width || - node->surface->bounds->hmin > dims->height) { - node->flags |= NFLAG_SMALL; - return 1; - } else if (node->surface->bounds->wmax < dims->width || - node->surface->bounds->hmax < dims->height) { - node->flags |= NFLAG_LARGE; - return 1; - } - - if (!IS_PARENT_NODE(node)) - return 0; - - if (node->cbounds.wmin_abs + node->cbounds.wmin_rel * dims->width > - dims->width || - node->cbounds.hmin_abs + node->cbounds.hmin_rel * dims->height > - dims->height) { - node->flags |= NFLAG_SMALLCHILD; - return 1; - } - - int axm_size, axm_free; - size_t bounds_axm_min_offset, bounds_axm_max_offset; - size_t dims_axm_pos_offset, dims_axm_size_offset; - - if (node->axis == AXIS_X) { - axm_free = dims->width; - axm_size = dims->width; - - dims_axm_pos_offset = offsetof(struct ct_dims, x); - dims_axm_size_offset = offsetof(struct ct_dims, width); - bounds_axm_min_offset = offsetof(struct ct_bounds, wmin); - bounds_axm_max_offset = offsetof(struct ct_bounds, wmax); - } else { - assert(node->axis == AXIS_Y); - axm_free = dims->height; - axm_size = dims->height; - - dims_axm_pos_offset = offsetof(struct ct_dims, y); - dims_axm_size_offset = offsetof(struct ct_dims, height); - bounds_axm_min_offset = offsetof(struct ct_bounds, hmin); - bounds_axm_max_offset = offsetof(struct ct_bounds, hmax); - } - - struct ct_spdims cspdims[node->cindex]; - cindex parts_n = node->cindex; - memset(cspdims, 0, sizeof(struct ct_spdims) * node->cindex); - for (int i = 0; i < node->cindex; i++) { - cspdims[i].min = *(int *)((char *)node->child[i]->surface->bounds + - bounds_axm_min_offset); - cspdims[i].max = *(int *)((char *)node->child[i]->surface->bounds + - bounds_axm_max_offset); - - if (node->child[i]->surface->bounds->type == BOUND_RELATIVE) { - cspdims[i].min *= axm_size; - cspdims[i].max *= axm_size; - } - - cspdims[i].axm_size = 0; - } - - int split, new_size; - while (axm_free && parts_n) { - split = (axm_free > parts_n) ? (axm_free / parts_n) : 1; - for (int i = 0; i < node->cindex; i++) { - if (cspdims[i].fixed) - continue; - - new_size = - clampi(cspdims[i].axm_size + split, cspdims[i].min, cspdims[i].max); - - if (new_size == cspdims[i].axm_size) { - cspdims[i].fixed = true; - parts_n--; - continue; - } - - axm_free -= (new_size - cspdims[i].axm_size); - cspdims[i].axm_size = new_size; - - if (axm_free == 0) - break; - } - } - - struct ct_dims *cdims = dup_dims(dims); - /* NOTE: the statements below are done implicitly by dup_dims */ - // *(int*)(cdims + dims_axm_pos_offset) = *(int*)(dims + - // dims_axm_pos_offset); - // *(int*)(cdims + dims_axo_pos_offset) = *(int*)(dims + - // dims_axo_pos_offset); - // *(int*)(cdims + dims_axo_size_offset) = axo_size; - for (int i = 0; i < node->cindex; i++) { - *(int *)((char *)cdims + dims_axm_size_offset) = cspdims[i].axm_size; - resize_node(node->child[i], dup_dims(cdims)); - *(int *)((char *)cdims + dims_axm_pos_offset) += cspdims[i].axm_size; - } - free(cdims); - - return 0; -} - -static int __set_cbounds(struct ct_node *const parent, - const struct ct_node *const child, - const bool additive) { - /* child and parent w/h min aliases */ - int c_wmin, c_hmin; - int p_wmin_rel, p_hmin_rel; - - c_wmin = child->surface->bounds->wmin; - c_hmin = child->surface->bounds->hmin; - - if (!additive) { - c_wmin *= -1; - c_hmin *= -1; - } - - if (child->surface->bounds->type == BOUND_RELATIVE) { - parent->cbounds.wmin_abs++; - parent->cbounds.hmin_abs++; - - p_wmin_rel = parent->cbounds.wmin_rel + c_wmin; - p_hmin_rel = parent->cbounds.hmin_rel + c_wmin; - if (p_wmin_rel > __BOUND_REL_MAX || p_hmin_rel >= __BOUND_REL_MAX) - return 1; - - parent->cbounds.wmin_rel = p_wmin_rel; - parent->cbounds.hmin_rel = p_hmin_rel; - assert(parent->cbounds.wmin_rel >= __BOUND_REL_MIN); - assert(parent->cbounds.hmin_rel >= __BOUND_REL_MIN); - } else { - parent->cbounds.wmin_abs += c_wmin; - parent->cbounds.hmin_abs += c_hmin; - assert(parent->cbounds.wmin_abs >= __BOUND_ABS_MIN); - assert(parent->cbounds.hmin_abs >= __BOUND_ABS_MIN); - } - return 0; -} - -/* Returns: - * 0 -> success - * 1 -> failed (max child limit reached) - * 2 -> failed (cumulative relative bounds surpasses 100%) - */ -int insert_child_node(struct ct_node *const parent, struct ct_node *const child, - const cindex i) { - if (parent->cindex == CINDEX_MAX) - return 1; - else if (__set_cbounds(parent, child, true)) - return 2; - else if (parent->cindex == parent->csize) { - // grow child array size and clamp maximum - cindex new_csize = parent->csize * NODE_CHILDREN_GROWTH; - // check overflow - parent->csize = (parent->csize <= new_csize) ? new_csize : CINDEX_MAX; - - parent->child = - reallocarray(parent->child, parent->csize, sizeof(struct ct_node *)); - } - - // shift all children up for insertion - for (int j = parent->cindex; j > i; j--) { - parent->child[j] = parent->child[j - 1]; - } - // do insertion - parent->child[i] = child; - parent->cindex++; - // request cursetree recompute dimensions recursively from parent - parent->flags |= NFLAG_RESIZE; - return EXIT_SUCCESS; -} - -/* Returns: - * 0 -> success - * 1 -> failed (max child limit reached) - * 2 -> failed (cumulative relative bounds surpasses 100%) - */ -int append_child_node(struct ct_node *const parent, - struct ct_node *const child) { - return insert_child_node(parent, child, parent->cindex); -} - -/* Remove a child node from a parent node by index. - * Returns NULL if an invalid index was provided, otherwise returns - * a pointer to the child node removed. - * NOTE: This does NOT destroy the child node and should be - * NOTE: used when moving the child somewhere else. - * NOTE: Otherwise use destroy_child_node() instead. - */ -struct ct_node *remove_child_node(struct ct_node *const parent, - const cindex i) { - struct ct_node *child; - - if (i >= parent->cindex) - return NULL; - else if (parent->cindex <= parent->csize / NODE_CHILDREN_GROWTH) { - // shrink child array to avoid memory bloat - parent->csize /= NODE_CHILDREN_GROWTH; - parent->child = - reallocarray(parent->child, parent->csize, sizeof(struct ct_node *)); - } - - child = &parent[i]; - // shift all children down to fill removal - for (int j = i; j < parent->cindex; j++) { - parent->child[j] = parent->child[j + 1]; - } - parent->cindex--; - __set_cbounds(parent, child, false); - // request cursetree recompute dimensions recursively from parent - parent->flags |= NFLAG_RESIZE; - return child; -} - -/* Remove and destroy a child node by index. - * Returns 1 on failure (invalid index provided), and 0 on success. - * NOTE: Use remove_child_node() instead if the child should live. - */ -int destroy_child_node(struct ct_node *const parent, const cindex i) { - struct ct_node *child = remove_child_node(parent, i); - __destroy_node(child); - return (child == NULL); -} - -/* - * Returns: - * 0 -> success - * 1 -> failed (node has no parent) - * 2 -> failed (parent has no reference to node, CRITICAL) - */ -static int __index_as_child(const struct ct_node *const node, - int *const index) { - if (node->parent == NULL) - return 1; - - for (int i = 0; i < node->parent->cindex; i++) { - if (node->parent->child[i] == node) { - *index = i; - return 0; - } - } - - return 2; -} - -/* If preserve_bounds is set then upon collapse the new node maintains the - * original node's bounds struct. Otherwise the bounds of the child collapsed - * onto are used. - */ -void collapse_node(struct ct_node **const node, const int i, - const bool preserve_bounds) { - assert(0 <= i && i < (*node)->cindex); - int parent_index; - struct ct_node *const parent = (*node)->parent; - struct ct_node *collapse_target = remove_child_node(*node, i); - struct ct_dims *dims = dup_dims((*node)->surface->dims); - struct ct_bounds *bounds; - - if (preserve_bounds) { - bounds = dup_bounds((*node)->surface->bounds); - rebind_surface(collapse_target->surface, bounds); - } - - /* Destroy original node and point to the collapse_target */ - if (__index_as_child(*node, &parent_index)) { - /* __index_as_child fails (typically) because - * the *node is cursetree's root node. */ - __destroy_node(*node); - *node = collapse_target; - } else { - destroy_child_node(parent, parent_index); - insert_child_node(parent, collapse_target, parent_index); - } - - resize_node(collapse_target, dims); -} diff --git a/cursetree/node.h b/cursetree/node.h deleted file mode 100644 index 316b8e3..0000000 --- a/cursetree/node.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef CURSETREE_NODE_H -#define CURSETREE_NODE_H - -#include "dims.h" -#include "limits.h" -#include "surface.h" - -#ifndef __NCURSES_H -typedef struct _win_st WINDOW; -#endif /* __NCURSES_H */ - -#define NODE_INIT_CHILDREN 4 -#define NODE_CHILDREN_GROWTH 1.5 -#define CINDEX_MAX (UCHAR_MAX) - -#define NFLAG_EMPTY (0) -#define NFLAG_RESIZE (1 << 0) -#define NFLAG_SMALL (1 << 1) -#define NFLAG_SMALLCHILD (1 << 2) -#define NFLAG_LARGE (1 << 3) - -/* Child Index */ -typedef unsigned char cindex; - -struct ct_node { - struct ct_surface *surface; - unsigned char flags; - - struct ct_node *parent; - enum ct_axis axis; - struct ct_node **child; - cindex csize, cindex; - /* child imposed minimum bounds */ - struct { - int wmin_abs; - int hmin_abs; - int wmin_rel; - int hmin_rel; - } cbounds; -}; - -/* === External Interface === */ -#define IS_ROOT_NODE(node) (node->parent == NULL) -#define IS_PARENT_NODE(node) (node->cindex != 0) - -struct ct_node *__node(struct ct_dims *const dims, - struct ct_bounds *const bounds, - struct ct_node *const parent); -struct ct_node *new_node(struct ct_bounds *const bounds, - struct ct_node *const parent); -void __destroy_node(struct ct_node *const node); - -int resize_node(struct ct_node *const node, struct ct_dims *dims); - -int insert_child_node(struct ct_node *const parent, struct ct_node *const child, - const cindex i); -int append_child_node(struct ct_node *const parent, - struct ct_node *const child); -struct ct_node *remove_child_node(struct ct_node *const parent, - const cindex i); -int destroy_child_node(struct ct_node *const parent, const cindex i); - -void collapse_node(struct ct_node **const node, const int i, - const bool preserve_bounds); - -#endif /* CURSETREE_NODE_H */ diff --git a/cursetree/pty/epty.h b/cursetree/pty/epty.h deleted file mode 100644 index fa013bb..0000000 --- a/cursetree/pty/epty.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CURSETREE_EPTY_H -#define CURSETREE_EPTY_H - -#include - -pid_t forkepty(int *fdmx, int *fderr); - -#endif /* CURSETREE_EPTY_H */ diff --git a/cursetree/surface.c b/cursetree/surface.c deleted file mode 100644 index a028bc8..0000000 --- a/cursetree/surface.c +++ /dev/null @@ -1,81 +0,0 @@ -#include - -#include "ncrswrap.h" -#include "surface.h" -#include "_ncurses.h" -#include "ncurses.h" - -static inline struct ct_surface *__surface(struct ct_dims *const dims, - struct ct_bounds *const bounds, - WINDOW *const win) { - struct ct_surface *surface; - - surface = (struct ct_surface *)malloc(sizeof(struct ct_surface)); - *surface = (struct ct_surface){ - .dims = dims, - .bounds = bounds, - .win = win, - .updatereq = true, - }; - - return surface; -} - -struct ct_surface *new_surface(struct ct_dims *const dims, - struct ct_bounds *const bounds) { - WINDOW *const win = new_window(dims->x, dims->y, dims->width, dims->height); - return __surface(dims, bounds, win); -} - -void destroy_surface(const struct ct_surface *const surface) { - delwin(surface->win); - free(surface->dims); -} - -void resize_surface(struct ct_surface *const surface, - struct ct_dims *const dims) { - free(surface->dims); - surface->dims = dims; - surface->updatereq = true; - - resizemv_window(surface->win, dims->x, dims->y, dims->width, dims->height); -} - -void rebind_surface(struct ct_surface *const surface, - struct ct_bounds *const bounds) { - free(surface->bounds); - surface->bounds = bounds; -} - -int sfwidth(const struct ct_surface *const surface) { - return getmaxx(surface->win); -} - -int sfheight(const struct ct_surface *const surface) { - return getmaxy(surface->win); -} - -int sfposx(const struct ct_surface *const surface) { - return getbegx(surface->win); -} - -int sfposy(const struct ct_surface *const surface) { - return getbegy(surface->win); -} - -struct ct_dims *sfdims(const struct ct_surface *const surface) { - int x, y, width, height; - sfpos(surface, x, y); - sfsize(surface, width, height); - return new_dims(x, y, width, height); -} - -void sfclear(struct ct_surface *const surface) { - wclear(surface->win); - surface->updatereq = true; -} - -void sfflush(struct ct_surface *const surface) { - wnoutrefresh(surface->win); - surface->updatereq = false; -} diff --git a/cursetree/surface.h b/cursetree/surface.h deleted file mode 100644 index c84f7ee..0000000 --- a/cursetree/surface.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CURSETREE_SURFACE_H -#define CURSETREE_SURFACE_H - -#include "dims.h" - -#ifndef __NCURSES_H -typedef struct _win_st WINDOW; -#endif /* __NCURSES_H */ - -struct ct_surface { - struct ct_dims *dims; - struct ct_bounds *bounds; - WINDOW *win; - unsigned char updatereq; -}; - -struct ct_surface *new_surface(struct ct_dims *const dims, - struct ct_bounds *const bounds); -void destroy_surface(const struct ct_surface *const surface); - -void resize_surface(struct ct_surface *const surface, - struct ct_dims *const dims); -void rebind_surface(struct ct_surface *const surface, - struct ct_bounds *const bounds); - -#define sfpos(surface, x, y) (x = sfposx(surface), y = sfposy(surface)) -#define sfsize(surface, width, height) (width = sfwidth(surface), height = sfheight(surface)) - -int sfwidth(const struct ct_surface *const surface); -int sfheight(const struct ct_surface *const surface); -int sfposx(const struct ct_surface *const surface); -int sfposy(const struct ct_surface *const surface); -struct ct_dims *sfdims(const struct ct_surface *const surface); - -void sfclear(struct ct_surface *const surface); -void sfflush(struct ct_surface *const surface); - -#endif /* CURSETREE_SURFACE_H */ diff --git a/cursetree/tree.c b/cursetree/tree.c deleted file mode 100644 index 4f49aff..0000000 --- a/cursetree/tree.c +++ /dev/null @@ -1,38 +0,0 @@ -#include - -#include "ncrswrap.h" -#include "tree.h" - -/* - */ -static inline struct ct_node *__root_node(void) { - return __node(termdims(), bounds_none(), NULL); -} - -int init_tree(struct ct_tree **const tree) { - *tree = (struct ct_tree *)malloc(sizeof(struct ct_tree)); - (*tree)->root = __root_node(); - return EXIT_SUCCESS; -} - -void destroy_tree(struct ct_tree *const tree) { - __destroy_node(tree->root); - end_ncurses(); - free(tree); -} - -void resize_tree(struct ct_tree *const tree, struct ct_dims *const dims) { - resize_node(tree->root, dims); -} - -void switch_nodes(struct ct_node **const node0, struct ct_node **const node1) { - struct ct_node *const node0ptr = *node0; - struct ct_dims *const node0dims = dup_dims((*node0)->surface->dims); - struct ct_dims *const node1dims = dup_dims((*node1)->surface->dims); - - *node0 = *node1; - resize_node(*node0, node1dims); - - *node1 = node0ptr; - resize_node(*node1, node0dims); -} diff --git a/cursetree/tree.h b/cursetree/tree.h deleted file mode 100644 index a170143..0000000 --- a/cursetree/tree.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CURSETREE_TREE_H -#define CURSETREE_TREE_H - -#include "node.h" - -struct ct_tree { - struct ct_node *root; -}; - -/* === External Interface === */ -int init_tree(struct ct_tree **const tree); -void destroy_tree(struct ct_tree *const tree); -void resize_tree(struct ct_tree *const tree, struct ct_dims *const dims); - -#endif /* CURSETREE_TREE_H */ diff --git a/cursetree/util.h b/cursetree/util.h deleted file mode 100644 index 6b97a12..0000000 --- a/cursetree/util.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CURSETREE_UTIL_H -#define CURSETREE_UTIL_H - -static inline int clampi(int val, int min, int max) { - if (val > max) - return max; - else if (val < min) - return min; - return val; -} - -#endif /* CURSETREE_UTIL_H */ diff --git a/scripts/test b/scripts/test index 2e00268..6da6b71 100755 --- a/scripts/test +++ b/scripts/test @@ -9,10 +9,16 @@ fi MODE= REBUILD=true VALGRIND=false -TARGET=debug +TARGET=all PROGRAM="$1" MODE_ARG="$2" +if [[ ! -x "$PROGRAM" ]]; then + echo "[!] Invalid program: \"$PROGRAM\"" + echo "$USAGE" + exit 1 +fi + if [[ "$MODE_ARG" =~ run.* ]]; then MODE="$MODE_ARG" REBUILD=false @@ -20,7 +26,7 @@ fi if [[ "$MODE_ARG" =~ .*valgrind ]]; then MODE="$MODE_ARG" VALGRIND=true - PROXY='valgrind -s --log-file=logs/valgrind.log --leak-check=full --show-leak-kinds=all' + PROXY='valgrind -s --leak-check=full --show-leak-kinds=all' TARGET=debug fi @@ -33,16 +39,4 @@ fi if [[ "$REBUILD" == true ]]; then make clean $TARGET fi - -if [[ ! -x "$PROGRAM" ]]; then - echo "[!] Invalid program: \"$PROGRAM\"" - echo "$USAGE" - exit 1 -fi - -mkdir -p logs LD_LIBRARY_PATH=./lib $PROXY "$PROGRAM" $@ - -# If ncurses doesn't close gracefully, termios attributes -# will require reinitialisation (not a reset! don't clear the screen!) -tput init