mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-10 01:29:05 -04:00
Merge branch 'master' of github.com:dankamongmen/notcurses
This commit is contained in:
commit
96244bb3ff
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
15
src/poc/caps-rendered.c
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user