Merge branch 'master' of github.com:dankamongmen/notcurses

This commit is contained in:
nick black 2021-03-21 23:08:21 -04:00
commit 96244bb3ff
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
11 changed files with 133 additions and 36 deletions

View File

@ -3403,7 +3403,12 @@ API void ncreader_destroy(struct ncreader* n, char** contents);
// Dump selected Notcurses state to the supplied 'debugfp'. Output is freeform,
// and subject to change. It includes geometry of all planes, from all piles.
API void notcurses_debug(struct notcurses* nc, FILE* debugfp)
API void notcurses_debug(const struct notcurses* nc, FILE* debugfp)
__attribute__ ((nonnull (1, 2)));
// Dump selected configuration capabilities to 'debugfp'. Output is freeform,
// and subject to change.
API void notcurses_debug_caps(const struct notcurses* nc, FILE* debugfp)
__attribute__ ((nonnull (1, 2)));
// replaced by ncvisual_media_defblitter(). this original version never returns

View File

@ -1,5 +1,60 @@
#include "internal.h"
static inline char
capyn(const char* cap){
return cap ? 'y' : 'n';
}
static inline char
capbool(bool cap){
return cap ? 'y' : 'n';
}
static void
tinfo_debug_caps(const tinfo* ti, FILE* debugfp, int rows, int cols,
unsigned images, unsigned videos){
const char indent[] = " ";
fprintf(debugfp, "%sColors: %u rgb: %c ccc: %c setaf: %c setbf: %c\n",
indent, ti->colors, capbool(ti->RGBflag), capbool(ti->CCCflag), capyn(ti->setaf), capyn(ti->setab));
fprintf(debugfp, "%ssgr: %c sgr0: %c\n",
indent, capyn(ti->sgr), capyn(ti->sgr0));
fprintf(debugfp, "%sop: %c fgop: %c bgop: %c\n",
indent, capyn(ti->op), capyn(ti->fgop), capyn(ti->bgop));
fprintf(debugfp, "%srows: %u cols: %u rpix: %u cpix: %u (%dx%d)\n",
indent, rows, cols, ti->cellpixy, ti->cellpixx, rows * ti->cellpixy, cols * ti->cellpixx);
if(!ti->pixel_query_done){
fprintf(debugfp, "%sno bitmap graphics information yet\n", indent);
}else{
if(!ti->sixel_supported){
fprintf(debugfp, "%sdidn't detect bitmap graphics support\n", indent);
}else if(ti->sixel_maxy || ti->color_registers){
fprintf(debugfp, "%smax bitmap size: %dx%d colorregs: %u\n",
indent, ti->sixel_maxy, ti->sixel_maxx, ti->color_registers);
}else{
fprintf(debugfp, "%sRGBA pixel graphics supported\n", indent);
}
}
fprintf(debugfp, "%sUTF8: %c sextants: %c braille: %c images: %c videos: %c\n",
indent, capbool(ti->utf8), capbool(ti->sextants), capbool(ti->braille),
capbool(images), capbool(videos));
if(ti->bg_collides_default){
fprintf(debugfp, "%sbackground of 0x%06lx is considered transparent\n", indent, ti->bg_collides_default & 0xfffffful);
}else{
fprintf(debugfp, "%sbackground isn't interpreted as transparent\n", indent);
}
fprintf(debugfp, "%scup: %c vpa: %c hpa: %c\n",
indent, capyn(ti->cup), capyn(ti->vpa), capyn(ti->hpa));
}
void notcurses_debug_caps(const notcurses* nc, FILE* debugfp){
int rows, cols;
notcurses_stddim_yx_const(nc, &rows, &cols);
bool images, videos;
images = notcurses_canopen_images(nc);
videos = notcurses_canopen_videos(nc);
tinfo_debug_caps(&nc->tcache, debugfp, rows, cols, images, videos);
}
static void
ncpile_debug(const ncpile* p, FILE* debugfp){
fprintf(debugfp, " ************************* %16p pile ****************************\n", p);
@ -31,7 +86,7 @@ ncpile_debug(const ncpile* p, FILE* debugfp){
}
}
void notcurses_debug(notcurses* nc, FILE* debugfp){
void notcurses_debug(const notcurses* nc, FILE* debugfp){
const ncpile* p = ncplane_pile(nc->stdplane);
fprintf(debugfp, " -------------------------- notcurses debug state -----------------------------\n");
const ncpile* p0 = p;

View File

@ -522,14 +522,13 @@ ncdirectv* ncdirect_render_frame(ncdirect* n, const char* file,
ncvisual_destroy(ncv);
return NULL;
}
blitterargs bargs = {
.pixel = {
.celldimx = n->tcache.cellpixx,
.celldimy = n->tcache.cellpixy,
.colorregs = n->tcache.color_registers,
.sprixelid = n->tcache.sprixelnonce++,
},
};
blitterargs bargs = {};
if(bset->geom == NCBLIT_PIXEL){
bargs.pixel.celldimx = n->tcache.cellpixx;
bargs.pixel.celldimy = n->tcache.cellpixy;
bargs.pixel.colorregs = n->tcache.color_registers;
bargs.pixel.sprixelid = n->tcache.sprixelnonce++;
}
if(ncvisual_blit(ncv, disprows, dispcols, ncdv, bset,
0, 0, leny, lenx, &bargs)){
ncvisual_destroy(ncv);
@ -684,7 +683,7 @@ ncdirect* ncdirect_core_init(const char* termtype, FILE* outfp, uint64_t flags){
if(ncvisual_init(NCLOGLEVEL_SILENT)){
goto err;
}
if(interrogate_terminfo(&ret->tcache, shortname_term, utf8)){
if(interrogate_terminfo(&ret->tcache, ret->ctermfd, shortname_term, utf8)){
goto err;
}
update_term_dimensions(ret->ctermfd, NULL, NULL, &ret->tcache);

View File

@ -269,7 +269,6 @@ typedef struct tinfo {
char* cuf; // move N cells right
char* cud; // move N cells down
char* cuf1; // move 1 cell right
char* cub1; // move 1 cell left
char* home; // home cursor
char* civis; // hide cursor
char* cnorm; // restore cursor to default state
@ -288,8 +287,6 @@ typedef struct tinfo {
char* initc; // set a palette entry's RGB value
char* oc; // restore original colors
char* clearscr; // erase screen and home cursor
char* cleareol; // clear to end of line
char* clearbol; // clear to beginning of line
char* sc; // push the cursor location onto the stack
char* rc; // pop the cursor location off the stack
char* smkx; // enter keypad transmit mode (keypad_xmit)
@ -323,6 +320,7 @@ typedef struct tinfo {
// means leaving out the pixels (and likely resizes the string). for kitty,
// this means dialing down their alpha to 0 (in equivalent space).
int (*pixel_cell_wipe)(const struct notcurses* nc, sprixel* s, int y, int x);
int (*pixel_clear_all)(const struct notcurses* nc);
bool pixel_query_done; // have we yet performed pixel query?
bool sextants; // do we have (good, vetted) Unicode 13 sextant support?
bool braille; // do we have Braille support? (linux console does not)
@ -482,7 +480,7 @@ int terminfostr(char** gseq, const char* name);
// load |ti| from the terminfo database, which must already have been
// initialized. set |utf8| if we've verified UTF8 output encoding.
int interrogate_terminfo(tinfo* ti, const char* termname, unsigned utf8);
int interrogate_terminfo(tinfo* ti, int fd, const char* termname, unsigned utf8);
void free_terminfo_cache(tinfo* ti);
@ -730,7 +728,9 @@ sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int placey, int pl
int sprixelid, int dimy, int dimx, int pixy, int pixx);
API int sprite_wipe_cell(const notcurses* nc, sprixel* s, int y, int x);
int sprite_kitty_annihilate(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
int sprite_kitty_clear_all(const notcurses* nc);
int sprite_sixel_annihilate(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
int sprite_clear_all(const notcurses* nc);
static inline void
pool_release(egcpool* pool, nccell* c){

View File

@ -81,6 +81,7 @@ base64_rgba3(const uint32_t* pixels, size_t pcount, char* b64){
// available in the chunk.
static inline int
kitty_null(char* triplet, int skip, int max, int pleft){
//fprintf(stderr, "SKIP/MAX/PLEFT %d/%d/%d\n", skip, max, pleft);
if(pleft > 3){
pleft = 3;
}
@ -124,15 +125,15 @@ int sprite_kitty_cell_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell
// if the cell is on the right or bottom borders, it might only be partially
// filled by actual graphic data, and we need to cap our target area.
int targx = xpixels;
if(xcell * xpixels > s->pixx){
targx -= ((xcell * xpixels) - s->pixx);
if((xcell + 1) * xpixels > s->pixx){
targx = s->pixx - xcell * xpixels;
}
int targy = ypixels;
if(ycell * ypixels > s->pixy){
targy -= ((ycell * ypixels) - s->pixy);
if((ycell + 1) * ypixels > s->pixy){
targy = s->pixy - ycell * ypixels;
}
//fprintf(stderr, "TARGET AREA: %d x %d\n", targy, targx);
char* c = s->glyph;
//fprintf(stderr, "TARGET AREA: %d x %d @ %dx%d of %d/%d (%d/%d) len %zu\n", targy, targx, ycell, xcell, s->dimy, s->dimx, s->pixy, s->pixx, strlen(c));
// every pixel was 4 source bytes, 32 bits, 6.33 base64 bytes. every 3 input pixels is
// 12 bytes (96 bits), an even 16 base64 bytes. there is chunking to worry about. there
// are up to 768 pixels in a chunk.
@ -141,7 +142,7 @@ int sprite_kitty_cell_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell
int chunkedhandled = 0;
const int chunks = totalpixels / RGBA_MAXLEN + !!(totalpixels % RGBA_MAXLEN);
while(targy && chunkedhandled < chunks){ // need to null out |targy| rows of |targx| pixels, track with |thisrow|
//fprintf(stderr, "CHUNK %d NEXTPIXEL: %d\n", chunkedhandled, nextpixel);
//fprintf(stderr, "CHUNK %d NEXTPIXEL: %d NEXTCHUNK: %d\n", chunkedhandled, nextpixel, nextchunk);
while(*c != ';'){
++c;
}
@ -152,6 +153,7 @@ int sprite_kitty_cell_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell
inchunk = RGBA_MAXLEN;
}
const int curpixel = chunkedhandled * RGBA_MAXLEN;
// a full chunk is 4096 + 2 + 7 (5005)
while(nextpixel - curpixel < RGBA_MAXLEN && thisrow){
// our next pixel is within this chunk. find the pixel offset of the
// first pixel (within the chunk).
@ -164,15 +166,21 @@ int sprite_kitty_cell_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell
//fprintf(stderr, "pixoffset: %d next: %d tripbytes: %d tripskip: %d thisrow: %d\n", pixoffset, nextpixel, tripbytes, tripskip, thisrow);
// the maximum number of pixels we can convert is the minimum of the
// pixels remaining in the target row, and the pixels left in the chunk.
//fprintf(stderr, "inchunk: %d total: %d triples: %d\n", inchunk, totalpixels, triples);
int chomped = kitty_null(c + tripbytes, tripskip, thisrow, inchunk - triples * 3);
assert(chomped >= 0);
thisrow -= chomped;
nextpixel += chomped;
//fprintf(stderr, "POSTCHIMP CHOMP: %d pixoffset: %d next: %d tripbytes: %d tripskip: %d thisrow: %d\n", chomped, pixoffset, nextpixel, tripbytes, tripskip, thisrow);
if(thisrow == 0){
//fprintf(stderr, "CLEARED ROW, TARGY: %d\n", targy - 1);
if(--targy == 0){
return 0;
}
thisrow = targx;
nextpixel += s->dimx * xpixels - targx;
//fprintf(stderr, "BUMP IT: %d %d %d %d\n", nextpixel, s->pixx, targx, chomped);
nextpixel += s->pixx - targx + chomped;
}else{
nextpixel += chomped;
}
}
c += RGBA_MAXLEN * 4 * 4 / 3; // 4bpp * 4/3 for base64, 4096b per chunk
@ -274,3 +282,7 @@ int kitty_blit(ncplane* nc, int linesize, const void* data, int begy, int begx,
}
return r;
}
int sprite_kitty_clear_all(const notcurses* nc){
return tty_emit("\e_Ga=d\e\\", nc->ttyfd);
}

View File

@ -1007,7 +1007,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
}
const char* shortname_term = termname();
// const char* longname_term = longname();
if(interrogate_terminfo(&ret->tcache, shortname_term, utf8)){
if(interrogate_terminfo(&ret->tcache, ret->ttyfd, shortname_term, utf8)){
goto err;
}
int dimy, dimx;
@ -1034,6 +1034,10 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){
goto err;
}
if(ret->ttyfd >= 0){
if(sprite_clear_all(ret)){
free_plane(ret->stdplane);
goto err;
}
if(ret->tcache.smkx && tty_emit(ret->tcache.smkx, ret->ttyfd)){
free_plane(ret->stdplane);
goto err;

View File

@ -421,6 +421,7 @@ write_sixel_data(FILE* fp, int lenx, sixeltable* stab){
// doesn't seem to work with at least xterm; we instead use '\ePq'
// FIXME i think we can print DESDM on the first one, and never again
fprintf(fp, "\e[?80h\ePq");
//fprintf(fp, "\ePq");
// Set Raster Attributes - pan/pad=1 (pixel aspect ratio), Ph=lenx, Pv=leny
// using Ph/Pv causes a background to be drawn using color register 0 for all

View File

@ -72,3 +72,10 @@ int sprite_wipe_cell(const notcurses* nc, sprixel* s, int ycell, int xcell){
}
return r;
}
int sprite_clear_all(const notcurses* nc){
if(!nc->tcache.pixel_clear_all){
return 0;
}
return nc->tcache.pixel_clear_all(nc);
}

View File

@ -62,6 +62,7 @@ apply_term_heuristics(tinfo* ti, const char* termname){
ti->sixel_supported = true;
ti->pixel_cell_wipe = sprite_kitty_cell_wipe;
ti->pixel_destroy = sprite_kitty_annihilate;
ti->pixel_clear_all = sprite_kitty_clear_all;
set_pixel_blitter(kitty_blit);
/*}else if(strstr(termname, "alacritty")){
ti->sextants = true; // alacritty https://github.com/alacritty/alacritty/issues/4409 */
@ -86,7 +87,7 @@ void free_terminfo_cache(tinfo* ti){
// termname is just the TERM environment variable. some details are not
// exposed via terminfo, and we must make heuristic decisions based on
// the detected terminal type, yuck :/.
int interrogate_terminfo(tinfo* ti, const char* termname, unsigned utf8){
int interrogate_terminfo(tinfo* ti, int fd, const char* termname, unsigned utf8){
memset(ti, 0, sizeof(*ti));
ti->utf8 = utf8;
ti->RGBflag = query_rgb();
@ -137,8 +138,6 @@ int interrogate_terminfo(tinfo* ti, const char* termname, unsigned utf8){
terminfostr(&ti->oc, "oc"); // restore defaults to all colors
terminfostr(&ti->home, "home"); // home the cursor
terminfostr(&ti->clearscr, "clear");// clear screen, home cursor
terminfostr(&ti->cleareol, "el"); // clear to end of line
terminfostr(&ti->clearbol, "el1"); // clear to beginning of line
terminfostr(&ti->cuu, "cuu"); // move N up
terminfostr(&ti->cud, "cud"); // move N down
terminfostr(&ti->hpa, "hpa"); // set horizontal position
@ -146,32 +145,31 @@ int interrogate_terminfo(tinfo* ti, const char* termname, unsigned utf8){
terminfostr(&ti->cuf, "cuf"); // n non-destructive spaces
terminfostr(&ti->cub, "cub"); // n non-destructive backspaces
terminfostr(&ti->cuf1, "cuf1"); // non-destructive space
terminfostr(&ti->cub1, "cub1"); // non-destructive backspace
terminfostr(&ti->sc, "sc"); // push ("save") cursor
terminfostr(&ti->rc, "rc"); // pop ("restore") cursor
// Some terminals cannot combine certain styles with colors. Don't advertise
// support for the style in that case.
int nocolor_stylemask = tigetnum("ncv");
if(nocolor_stylemask > 0){
if(nocolor_stylemask & WA_STANDOUT){ // ncv is composed of terminfo bits, not ours
if(nocolor_stylemask & A_STANDOUT){ // ncv is composed of terminfo bits, not ours
ti->standout = NULL;
}
if(nocolor_stylemask & WA_UNDERLINE){
if(nocolor_stylemask & A_UNDERLINE){
ti->uline = NULL;
}
if(nocolor_stylemask & WA_REVERSE){
if(nocolor_stylemask & A_REVERSE){
ti->reverse = NULL;
}
if(nocolor_stylemask & WA_BLINK){
if(nocolor_stylemask & A_BLINK){
ti->blink = NULL;
}
if(nocolor_stylemask & WA_DIM){
if(nocolor_stylemask & A_DIM){
ti->dim = NULL;
}
if(nocolor_stylemask & WA_BOLD){
if(nocolor_stylemask & A_BOLD){
ti->bold = NULL;
}
if(nocolor_stylemask & WA_ITALIC){
if(nocolor_stylemask & A_ITALIC){
ti->italics = NULL;
}
// can't do anything about struck! :/
@ -186,7 +184,7 @@ int interrogate_terminfo(tinfo* ti, const char* termname, unsigned utf8){
terminfostr(&ti->struckoff, "rmxx"); // cancel strikeout
// if the keypad neen't be explicitly enabled, smkx is not present
if(ti->smkx){
if(putp(tiparm(ti->smkx)) != OK){
if(tty_emit(tiparm(ti->smkx), fd) < 0){
fprintf(stderr, "Error entering keypad transmit mode\n");
return -1;
}

View File

@ -153,6 +153,7 @@ void ncls_thread(const lsContext* ctx) {
if(faken){
ctx->nc.raster_image(faken, ctx->alignment);
}
std::cout << '\n';
pthread_mutex_unlock(&outmtx);
}else if(!keep_working){
pthread_mutex_unlock(&mtx);

15
src/poc/caps-rendered.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <notcurses/notcurses.h>
int main(void){
notcurses_options nopts = {
.flags = NCOPTION_NO_ALTERNATE_SCREEN,
};
struct notcurses* nc = notcurses_init(&nopts, NULL);
if(nc == NULL){
return EXIT_FAILURE;
}
notcurses_check_pixel_support(nc);
notcurses_debug_caps(nc, stdout);
return notcurses_stop(nc) ? EXIT_FAILURE : EXIT_SUCCESS;
}