diff --git a/NEWS.md b/NEWS.md index 97e2518da..3a35409d2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,10 @@ This document attempts to list user-visible changes and any major internal rearrangements of Notcurses. * 2.3.14 (not yet released) + * `ncneofetch` has been changed to use "CLI mode" instead of Direct Mode, + as a proof of concept. It is very likely that Direct Mode will be + deprecated for ABI3. New code ought not be written using it. + * Added `ncplane_scrollup()` and `ncplane_scrollup_child()`. * Fixed grotesque errors in `ncplane_set_*_palindex()`. * 2.3.13 (2021-08-04) diff --git a/USAGE.md b/USAGE.md index 3e608825f..24c7a0a45 100644 --- a/USAGE.md +++ b/USAGE.md @@ -883,6 +883,15 @@ scrolling is enabled). // controlled with ncplane_set_scrolling(). Returns true if scrolling was // previously enabled, or false if it was disabled. bool ncplane_set_scrolling(struct ncplane* n, bool scrollp); + +// Effect |r| scroll events on the plane |n|. Returns an error if |n| is not +// a scrolling plane, and otherwise returns the number of lines scrolled. +int ncplane_scrollup(struct ncplane* n, int r); + +// Scroll |n| up until |child| is no longer hidden beneath it. Returns an +// error if |child| is not a child of |n|, or |n| is not scrolling, or |child| +// is fixed. Returns the number of scrolling events otherwise (might be 0). +int ncplane_scrollup_child(struct ncplane* n, const struct ncplane* child); ``` Planes can be freely resized, though they must retain a positive size in diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index 566cb3315..07be0063f 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -209,6 +209,10 @@ typedef struct ncplane_options { **bool ncplane_scrolling_p(const struct ncplane* ***n***);** +**int ncplane_scrollup(struct ncplane* ***n***, int ***r***);** + +**int ncplane_scrollup_child(struct ncplane* ***n***, const struct ncplane* ***child***);** + **int ncplane_rotate_cw(struct ncplane* ***n***);** **int ncplane_rotate_ccw(struct ncplane* ***n***);** diff --git a/include/notcurses/ncport.h b/include/notcurses/ncport.h index ec94187b2..f36d4ccc2 100644 --- a/include/notcurses/ncport.h +++ b/include/notcurses/ncport.h @@ -5,37 +5,30 @@ extern "C" { #endif -// take host byte order and turn it into network (reverse on LE, no-op on BE), -// then reverse that, guaranteeing LE. htole(x) == ltohe(x). -#if defined(__linux__) || defined(__gnu_hurd__) -#include -#include -#include -#include -#define htole(x) (__bswap_32(htonl(x))) -#elif defined(__APPLE__) -#include -#include -#include -#include -#define htole(x) (OSSwapInt32(htonl(x))) -#elif defined(__MINGW64__) -#define htole(x) (x) // FIXME +// Platform-dependent preprocessor material (includes and definitions) needed +// to compile against Notcurses. A critical definition is htole(), which forces +// 32-bit values to little-endian (as used in the nccell gcluster field). This +// ought be defined so that it's a a no-op on little-endian builds. + +#if defined(__MINGW64__) // Windows // FIXME placeholders, need real solutions here #define wcwidth(w) 1 -#define wcswidth(w, s) (s) -#define sigset_t int -#define sigemptyset(x) -#define O_CLOEXEC O_NOINHERIT -#define O_NONBLOCK 0 -#define O_DIRECTORY 0 -#define S_IFLNK 0 -#else // bsd +#define htole(x) (x) // FIXME are all windows installs LE? +#else // Non-Windows, UNIX-common #include #include +#include +#if defined(__linux__) || defined(__gnu_hurd__) // Linux/Hurd +#include +#define htole(x) (__bswap_32(htonl(x))) +#elif defined(__APPLE__) // macOS +#include +#define htole(x) (OSSwapInt32(htonl(x))) +#else // BSD #include #define htole(x) (bswap32(htonl(x))) #endif +#endif #ifdef __cplusplus } // extern "C" diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index bd1274e1e..9c3ebb75f 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1570,8 +1570,23 @@ API int ncplane_move_below(struct ncplane* RESTRICT n, struct ncplane* RESTRICT below); // Return the plane below this one, or NULL if this is at the bottom. -API struct ncplane* ncplane_below(struct ncplane* n); -API struct ncplane* ncplane_above(struct ncplane* n); +API struct ncplane* ncplane_below(struct ncplane* n) + __attribute__ ((nonnull (1))); + +// Return the plane above this one, or NULL if this is at the top. +API struct ncplane* ncplane_above(struct ncplane* n) + __attribute__ ((nonnull (1))); + +// Effect |r| scroll events on the plane |n|. Returns an error if |n| is not +// a scrolling plane, and otherwise returns the number of lines scrolled. +API int ncplane_scrollup(struct ncplane* n, int r) + __attribute__ ((nonnull (1))); + +// Scroll |n| up until |child| is no longer hidden beneath it. Returns an +// error if |child| is not a child of |n|, or |n| is not scrolling, or |child| +// is fixed. Returns the number of scrolling events otherwise (might be 0). +API int ncplane_scrollup_child(struct ncplane* n, const struct ncplane* child) + __attribute__ ((nonnull (1, 2))); // Rotate the plane π/2 radians clockwise or counterclockwise. This cannot // be performed on arbitrary planes, because glyphs cannot be arbitrarily diff --git a/src/compat/compat.h b/src/compat/compat.h index e89f4f179..aa8fcb19f 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -17,6 +17,7 @@ extern "C" { #ifdef __MINGW64__ #include +#define wcswidth(w, s) (s) #define tcgetattr(x, y) -1 #define tcsetattr(x, y, z) -1 #define ECHO 0 @@ -27,6 +28,10 @@ extern "C" { #define TCSAFLUSH 0 #define TCSANOW 0 #define O_NOCTTY 0 +#define O_CLOEXEC O_NOINHERIT +#define O_NONBLOCK 0 +#define O_DIRECTORY 0 +#define S_IFLNK 0 #define SA_SIGINFO 0 #define SA_RESETHAND 0 #define SIGQUIT 0 diff --git a/src/demo/unicodeblocks.c b/src/demo/unicodeblocks.c index b9b16b6c0..c10ca8920 100644 --- a/src/demo/unicodeblocks.c +++ b/src/demo/unicodeblocks.c @@ -200,8 +200,8 @@ int unicodeblocks_demo(struct notcurses* nc){ { .name = "CJK Compatibility Ideographs, Alphabetic Presentation Forms", .start = 0xfa00, }, { .name = "Arabic Presentation Forms-A", .start = 0xfc00, }, { .name = "Halfwidth and Fullwidth Forms", .start = 0xfe00, }, - { .name = "Linear B Syllabary, Linear B Ideograms, Aegean Numbers, Phaistos Disc", .start = 0x10000, }, - { .name = "Lycian, Carian, Coptic Epact Numbers, Old Italic, Gothic, Old Permic", .start = 0x10200, }, + { .name = "Linear B Syllabary, Linear B Ideograms, Aegean, Phaistos Disc", .start = 0x10000, }, + { .name = "Lycian, Carian, Coptic Epact, Old Italic, Gothic, Old Permic", .start = 0x10200, }, { .name = "Cuneiform", .start = 0x12000, }, { .name = "Cuneiform (cont.)", .start = 0x12200, }, { .name = "Byzantine Musical Symbols, Musical Symbols", .start = 0x1d000, }, @@ -278,10 +278,10 @@ int unicodeblocks_demo(struct notcurses* nc){ if(ncplane_set_fg_rgb8(n, 0x40, 0xc0, 0x40)){ return -1; } - if(ncplane_cursor_move_yx(n, 6 + BLOCKSIZE / CHUNKSIZE, 2)){ + if(ncplane_cursor_move_yx(n, 6 + BLOCKSIZE / CHUNKSIZE, 4)){ return -1; } - if(ncplane_printf(n, "%*.*s", maxx - 4, maxx - 4, "") <= 0){ + if(ncplane_printf(n, "%*.*s", maxx - 8, maxx - 8, "") <= 0){ return -1; } if(ncplane_printf_aligned(n, 6 + BLOCKSIZE / CHUNKSIZE, NCALIGN_CENTER, "%s", description) <= 0){ diff --git a/src/fetch/main.c b/src/fetch/main.c index 64dcc1648..2a83c0291 100644 --- a/src/fetch/main.c +++ b/src/fetch/main.c @@ -48,7 +48,12 @@ typedef struct fetched_info { static void free_fetched_info(fetched_info* fi){ free(fi->cpu_model); + free(fi->hostname); free(fi->username); + free(fi->kernel); + free(fi->kernver); + free(fi->distro_pretty); + free(fi->term); } static int @@ -337,7 +342,7 @@ xnu_ncneofetch(fetched_info* fi){ .logofile = "/System/Library/PrivateFrameworks/LoginUIKit.framework/Versions/A/Frameworks/LoginUICore.framework/Versions/A/Resources/apple@2x.png", }; fi->neologo = get_neofetch_art("Darwin"); - fi->distro_pretty = "OS X 11.4 (Big Sur)"; // FIXME + fi->distro_pretty = strdup("OS X 11.4 (Big Sur)"); // FIXME return &fbsd; } @@ -380,9 +385,11 @@ static int infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheight){ const int planewidth = 72; int dimy; + int y; struct ncplane* std = notcurses_stddim_yx(nc, &dimy, NULL); + ncplane_cursor_yx(std, &y, NULL); struct ncplane_options nopts = { - .y = dimy - planeheight, + .y = y, .x = NCALIGN_CENTER, .rows = planeheight, .cols = planewidth, @@ -428,7 +435,6 @@ infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheigh }else{ ncplane_printf_aligned(infop, 4, NCALIGN_LEFT, " TERM: %s", fi->term); } - free(fi->term); ncplane_printf_aligned(infop, 4, NCALIGN_RIGHT, "Screen0: %dx%d ", fi->dimx, fi->dimy); ncplane_printf_aligned(infop, 5, NCALIGN_LEFT, " LANG: %s", fi->lang); #ifndef __MINGW64__ @@ -469,6 +475,7 @@ infoplane_notcurses(struct notcurses* nc, const fetched_info* fi, int planeheigh ncchannels_set_fg_rgb8(&channels, 0, 0, 0); ncchannels_set_bg_rgb8(&channels, 0x50, 0x50, 0x50); ncplane_set_base(infop, " ", 0, channels); + ncplane_scrollup_child(std, infop); if(notcurses_render(nc)){ return -1; } @@ -522,7 +529,7 @@ neologo_present(struct notcurses* nc, const char* nlogo){ struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); const int leftpad = (dimx - maxlinelen) / 2; for(int i = 0 ; i < linecount ; ++i){ - printf("%*.*s%s", leftpad, leftpad, "", lines[i]); + ncplane_printf(n, "%*.*s%s", leftpad, leftpad, "", lines[i]); free(lines[i]); } free(lines); @@ -542,6 +549,8 @@ display_thread(void* vmarshal){ struct marshal* m = vmarshal; drawpalette(m->nc); notcurses_render(m->nc); + ncplane_set_bg_default(notcurses_stdplane(m->nc)); + ncplane_set_fg_default(notcurses_stdplane(m->nc)); // we've just rendered, so any necessary scrolling has been performed. draw // our image wherever the palette ended, and then scroll as necessary to // make that new plane visible. @@ -553,6 +562,8 @@ display_thread(void* vmarshal){ ncv = ncvisual_from_file(m->dinfo->logofile); } if(ncv){ + int y; + ncplane_cursor_yx(notcurses_stdplane_const(m->nc), &y, NULL); struct ncvisual_options vopts = { .x = NCALIGN_CENTER, .blitter = NCBLIT_PIXEL, @@ -561,7 +572,14 @@ display_thread(void* vmarshal){ }; struct ncplane* iplane = ncvisual_render(m->nc, ncv, &vopts); ncvisual_destroy(ncv); - notcurses_render(m->nc); + if(iplane){ + ncplane_move_yx(iplane, y, 0); + ncplane_scrollup_child(notcurses_stdplane(m->nc), iplane); + notcurses_render(m->nc); + ncplane_cursor_move_yx(notcurses_stdplane(m->nc), + ncplane_abs_y(iplane) + ncplane_dim_y(iplane), 0); + return NULL; + } } } if(m->neologo){ @@ -627,13 +645,11 @@ ncneofetch(struct notcurses* nc){ } int main(void){ - if(setlocale(LC_ALL, "") == NULL){ - fprintf(stderr, "Warning: couldn't set locale based off LANG\n"); - } struct notcurses_options opts = { - .flags = NCOPTION_SUPPRESS_BANNERS | NCOPTION_INHIBIT_SETLOCALE - | NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_NO_CLEAR_BITMAPS - | NCOPTION_PRESERVE_CURSOR, + .flags = NCOPTION_SUPPRESS_BANNERS + | NCOPTION_NO_ALTERNATE_SCREEN + | NCOPTION_NO_CLEAR_BITMAPS + | NCOPTION_PRESERVE_CURSOR, }; struct notcurses* nc = notcurses_init(&opts, NULL); if(nc == NULL){ diff --git a/src/lib/kitty.c b/src/lib/kitty.c index 05c63d506..3ff686833 100644 --- a/src/lib/kitty.c +++ b/src/lib/kitty.c @@ -1145,10 +1145,8 @@ int kitty_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f, } if(animated){ fbuf_free(&s->glyph); - s->invalidated = SPRIXEL_LOADED; - }else{ - s->invalidated = SPRIXEL_LOADED; } + s->invalidated = SPRIXEL_LOADED; return ret; } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index f0702fd37..0a7672a63 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -1544,6 +1544,43 @@ void scroll_down(ncplane* n){ } } +int ncplane_scrollup(ncplane* n, int r){ + if(!ncplane_scrolling_p(n)){ + logerror("can't scroll %d on non-scrolling plane\n", r); + return -1; + } + if(r < 0){ + logerror("can't scroll %d lines\n", r); + return -1; + } + while(r-- > 0){ + scroll_down(n); + } + return 0; +} + +// Scroll |n| up until |child| is no longer hidden beneath it. Returns an +// error if |child| is not a child of |n|, or |n| is not scrolling, or |child| +// is fixed. Returns the number of scrolling events otherwise (might be 0). +int ncplane_scrollup_child(ncplane* n, const ncplane* child){ + if(ncplane_parent_const(child) != n){ + logerror("not a child of specified plane\n"); + return -1; + } + if(child->fixedbound){ + logerror("child plane is fixed\n"); + return -1; + } + int parend = ncplane_abs_y(n) + ncplane_dim_y(n); // where parent ends + int chend = ncplane_abs_y(child) + ncplane_dim_y(child); // where child ends + if(chend <= parend){ + return 0; + } + int r = chend - parend; // how many rows we need scroll parent + int ret = ncplane_scrollup(n, r); + return ret; +} + int nccell_width(const ncplane* n __attribute__ ((unused)), const nccell* c){ return nccell_cols(c); } diff --git a/src/lib/render.c b/src/lib/render.c index 60b5bd49d..0c92c11d9 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -840,7 +840,7 @@ clean_sprixels(notcurses* nc, ncpile* p, fbuf* f){ } continue; // don't account as an elision } - if(s->invalidated == SPRIXEL_MOVED || s->invalidated == SPRIXEL_INVALIDATED){ + if(s->invalidated == SPRIXEL_MOVED || s->invalidated == SPRIXEL_INVALIDATED || s->invalidated == SPRIXEL_UNSEEN){ int y, x; ncplane_yx(s->n, &y, &x); //fprintf(stderr, "1 MOVING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n); @@ -929,6 +929,7 @@ rasterize_scrolls(ncpile* p, fbuf* f){ if(goto_location(p->nc, f, p->dimy, 0)){ return -1; } + // FIXME if bce is set, we need reset background color while(p->scrolls){ if(fbuf_putc(f, '\n') < 0){ return -1; @@ -955,9 +956,9 @@ rasterize_sprixels(notcurses* nc, ncpile* p, fbuf* f){ while( (s = *parent) ){ //fprintf(stderr, "YARR HARR HARR SPIRXLE %u STATE %d\n", s->id, s->invalidated); if(s->invalidated == SPRIXEL_INVALIDATED){ -//fprintf(stderr, "3 DRAWING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n); - int y,x; + int y, x; ncplane_yx(s->n, &y, &x); +//fprintf(stderr, "3 DRAWING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n); int r = sprite_draw(&nc->tcache, p, s, f, y + nc->margin_t, x + nc->margin_l); if(r < 0){ return -1; @@ -966,7 +967,7 @@ rasterize_sprixels(notcurses* nc, ncpile* p, fbuf* f){ nc->rstate.hardcursorpos = true; }else if(s->invalidated == SPRIXEL_LOADED){ if(nc->tcache.pixel_commit){ - int y,x; + int y, x; ncplane_yx(s->n, &y, &x); if(goto_location(nc, f, y + nc->margin_t, x + nc->margin_l)){ return -1; diff --git a/src/lib/sixel.c b/src/lib/sixel.c index b862a4e66..9e588e683 100644 --- a/src/lib/sixel.c +++ b/src/lib/sixel.c @@ -933,7 +933,13 @@ int sixel_draw(const tinfo* ti, const ncpile* p, sprixel* s, fbuf* f, } if(s->invalidated == SPRIXEL_MOVED){ for(int yy = s->movedfromy ; yy < s->movedfromy + s->dimy && yy < p->dimy ; ++yy){ + if(yy < 0){ + continue; + } for(int xx = s->movedfromx ; xx < s->movedfromx + s->dimx && xx < p->dimx ; ++xx){ + if(xx < 0){ + continue; + } struct crender *r = &p->crender[yy * p->dimx + xx]; if(!r->sprixel || sprixel_state(r->sprixel, yy, xx) != SPRIXCELL_OPAQUE_SIXEL){ r->s.damaged = 1; diff --git a/src/lib/sprite.c b/src/lib/sprite.c index 78ade957a..f1a3fbad8 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -67,7 +67,7 @@ sprixel* sprixel_recycle(ncplane* n){ // store the original (absolute) coordinates from which we moved, so that // we can invalidate them in sprite_draw(). void sprixel_movefrom(sprixel* s, int y, int x){ - if(s->invalidated != SPRIXEL_HIDE){ + if(s->invalidated != SPRIXEL_HIDE && s->invalidated != SPRIXEL_UNSEEN){ if(s->invalidated != SPRIXEL_MOVED){ // FIXME if we're Sixel, we need to effect any wipes that were run // (we normally don't because redisplaying sixel doesn't change @@ -168,7 +168,7 @@ int sprixel_load(sprixel* spx, fbuf* f, int pixy, int pixx, fbuf_free(&spx->glyph); memcpy(&spx->glyph, f, sizeof(*f)); } - spx->invalidated = SPRIXEL_INVALIDATED; + spx->invalidated = SPRIXEL_UNSEEN; spx->pixx = pixx; spx->pixy = pixy; spx->parse_start = parse_start; diff --git a/src/lib/sprite.h b/src/lib/sprite.h index 5b5140fa7..9312f73ab 100644 --- a/src/lib/sprite.h +++ b/src/lib/sprite.h @@ -17,8 +17,9 @@ struct blitterargs; typedef enum { SPRIXEL_QUIESCENT, // up-to-date and visible at the proper place + SPRIXEL_UNSEEN, // not yet loaded, invisible, but wants loading SPRIXEL_LOADED, // loaded, but not yet made visible (kitty-only) - SPRIXEL_INVALIDATED, // not up-to-date, need reload, trumps MOVED + SPRIXEL_INVALIDATED, // not up-to-date, need reload SPRIXEL_HIDE, // queued for destruction SPRIXEL_MOVED, // visible, up-to-date, but in the wrong place } sprixel_e; diff --git a/src/poc/ncwidth.c b/src/poc/ncwidth.c index ad398ce6b..12c87dcd3 100644 --- a/src/poc/ncwidth.c +++ b/src/poc/ncwidth.c @@ -4,6 +4,7 @@ #include #include #include +#include #include static int