From 7a35f96a9a18a903b197fedc821a28cc35b22941 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 18 Sep 2025 12:24:33 +1000 Subject: [PATCH] attempt to lessen screentearing --- TODO.md | 6 +++++ cli/main.c | 61 ++++++++++++++++++++--------------------- cursetree/cursetree.c | 63 +++++++++++++++++++++++++++++++++++++++---- cursetree/cursetree.h | 1 + 4 files changed, 96 insertions(+), 35 deletions(-) diff --git a/TODO.md b/TODO.md index b982af8..f103fc7 100644 --- a/TODO.md +++ b/TODO.md @@ -12,3 +12,9 @@ then fork and exec shfx as child (+ close ptmx), then close pts as parent. - [ ] 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/cli/main.c b/cli/main.c index 00662e5..dd4f338 100644 --- a/cli/main.c +++ b/cli/main.c @@ -23,43 +23,44 @@ int main(int argc, char **argv) { init_pair(5, COLOR_BLACK, COLOR_YELLOW); 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); + // 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); + // append_child_node(tree->root, child2); + // append_child_node(tree->root, child3); + // append_child_node(tree->root, child4); + // append_child_node(tree->root, child5); 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)); + // 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)); - 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)); + // 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)); while (1) { - 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_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); } destroy_tree(tree); diff --git a/cursetree/cursetree.c b/cursetree/cursetree.c index 47cef7a..31504a8 100644 --- a/cursetree/cursetree.c +++ b/cursetree/cursetree.c @@ -1,11 +1,45 @@ +#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); @@ -34,10 +68,13 @@ static int __update_rec(struct ct_node *const node) { */ 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) { - sfflush(node->surface); + // 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++) { @@ -47,7 +84,17 @@ static int __update_rec(struct ct_node *const node) { } 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 @@ -58,8 +105,9 @@ void ct_update(struct ct_tree *const tree) { // wclear(tree->root->surface->win); // mvwprintw(tree->root->surface->win, 0, 0, " \r-1\n"); // wrefresh(tree->root->surface->win); - return; + break; case KEY_RESIZE: + // got_winch = 1; tree->root->flags |= NFLAG_RESIZE; break; default: @@ -69,7 +117,12 @@ void ct_update(struct ct_tree *const tree) { break; } - if (__update_rec(tree->root)) { - ct_redraw(); - } + // 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 index 2a31717..d066429 100644 --- a/cursetree/cursetree.h +++ b/cursetree/cursetree.h @@ -6,5 +6,6 @@ /* === 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 */