diff --git a/NEWS.md b/NEWS.md index ca747bc0d..5c5bf0147 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,11 @@ This document attempts to list user-visible changes and any major internal rearrangements of Notcurses. +* 2.4.1 (not yet released) + * `notcurses_check_pixel_support()` still returns 0 if there is no support + for bitmap graphics, but now returns an `ncpixelimple_e` to differentiate + the pixel backend otherwise. This result is strictly informative. + * 2.4.0 (2021-09-06) * Mouse events in the Linux console are now reported from GPM when built with `-DUSE_GPM=on`. diff --git a/USAGE.md b/USAGE.md index ec5ecbff8..8dc2a0611 100644 --- a/USAGE.md +++ b/USAGE.md @@ -334,10 +334,10 @@ bool notcurses_cansextants(const struct notcurses* nc); // Can we draw Braille? The Linux console cannot. bool notcurses_canbraille(const struct notcurses* nc); -// This function must successfully return before NCBLIT_PIXEL is available. -// Returns -1 on error, 0 for no support, or 1 if pixel output is supported. -// Must not be called concurrently with either input or rasterization. -int notcurses_check_pixel_support(struct notcurses* nc); +// Returns a non-zero constant corresponding to some pixel-blitting +// mechanism if bitmap support (via any mechanism) has been detected, +// or else 0 (NCPIXEL_NONE). +ncpixelimpl_e notcurses_check_pixel_support(struct notcurses* nc); ``` ## Direct mode diff --git a/doc/man/man3/notcurses_capabilities.3.md b/doc/man/man3/notcurses_capabilities.3.md index cff094370..04388cb64 100644 --- a/doc/man/man3/notcurses_capabilities.3.md +++ b/doc/man/man3/notcurses_capabilities.3.md @@ -36,7 +36,7 @@ notcurses_capabilities - runtime capability detection **bool notcurses_canbraille(const struct notcurses* ***nc***);** -**int notcurses_check_pixel_support(struct notcurses* ***nc***);** +**ncpixelimpl_e notcurses_check_pixel_support(struct notcurses* ***nc***);** # DESCRIPTION @@ -86,8 +86,9 @@ quadrants and halfblocks, respectively. **notcurses_canbraille** returns **true** if Unicode Braille is expected to work on the terminal. None of these functions return **true** unless UTF-8 encoding is in use. -**notcurses_check_pixel_support** returns 1 if bitmap support (via any -mechanism) has been detected, and otherwise 0. +**notcurses_check_pixel_support** returns a non-zero pixel implementation +if bitmap support (via any mechanism) has been detected, and otherwise 0 +(**NCPIXEL_NONE**). # NOTES @@ -95,8 +96,6 @@ Some terminals advertise support for TrueColor, but then downsample or otherwise degrade the provided RGB. In this case **notcurses_cantruecolor** will return **true**, but the full spectrum will not be available. -# RETURN VALUES - # SEE ALSO **notcurses(3)**, diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index b80c0d342..8268be1b8 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -540,7 +540,7 @@ ncchannels_set_bg_default(uint64_t* channels){ // An nccell corresponds to a single character cell on some plane, which can be // occupied by a single grapheme cluster (some root spacing glyph, along with // possible combining characters, which might span multiple columns). At any -// cell, we can have a theoretically arbitrarily long UTF-8 string, a foreground +// cell, we can have a theoretically arbitrarily long UTF-8 EGC, a foreground // color, a background color, and an attribute set. Valid grapheme cluster // contents include: // @@ -1423,8 +1423,20 @@ API bool notcurses_cansextant(const struct notcurses* nc) API bool notcurses_canbraille(const struct notcurses* nc) __attribute__ ((nonnull (1))) __attribute__ ((pure)); +// pixel blitting implementations. informative only; don't special-case +// based off any of this information! +typedef enum { + NCPIXEL_NONE = 0, + NCPIXEL_SIXEL, // sixel + NCPIXEL_LINUXFB, // linux framebuffer + NCPIXEL_ITERM2, // iTerm2 + NCPIXEL_KITTY_STATIC, // kitty prior to C=1 and animation + NCPIXEL_KITTY_ANIMATED, // kitty with animation but not selfref + NCPIXEL_KITTY_SELFREF, // kitty with reflexive composition +} ncpixelimpl_e; + // Can we blit pixel-accurate bitmaps? -API int notcurses_check_pixel_support(const struct notcurses* nc) +API ncpixelimpl_e notcurses_check_pixel_support(const struct notcurses* nc) __attribute__ ((nonnull (1))) __attribute__ ((pure)); // whenever a new field is added here, ensure we add the proper rule to diff --git a/src/demo/hud.c b/src/demo/hud.c index 2087a0478..f9848752e 100644 --- a/src/demo/hud.c +++ b/src/demo/hud.c @@ -663,6 +663,7 @@ int fpsgraph_init(struct notcurses* nc){ memset(&opts, 0, sizeof(opts)); opts.flags = NCPLOT_OPTION_LABELTICKSD | NCPLOT_OPTION_EXPONENTIALD | + NCPLOT_OPTION_DETECTMAXONLY | NCPLOT_OPTION_PRINTSAMPLE; opts.gridtype = NCBLIT_BRAILLE; opts.legendstyle = NCSTYLE_ITALIC | NCSTYLE_BOLD; diff --git a/src/info/main.c b/src/info/main.c index 502064754..e8f8e84d7 100644 --- a/src/info/main.c +++ b/src/info/main.c @@ -341,33 +341,36 @@ tinfo_debug_bitmaps(struct ncplane* n, const tinfo* ti, const char* indent){ ti->bg_collides_default & 0xfffffful, (ti->bg_collides_default & 0x01000000) ? "" : "not "); finish_line(n); - if(!ti->pixel_draw && !ti->pixel_draw_late){ - ncplane_printf(n, "%sno bitmap graphics detected", indent); - }else{ // we do have support; draw one - if(ti->color_registers){ + ncpixelimpl_e blit = notcurses_check_pixel_support(ncplane_notcurses(n)); + switch(blit){ + case NCPIXEL_NONE: + ncplane_printf(n, "%sno bitmap graphics detected", indent); + break; + case NCPIXEL_SIXEL: if(ti->sixel_maxy){ ncplane_printf(n, "%smax sixel size: %dx%d colorregs: %u", indent, ti->sixel_maxy, ti->sixel_maxx, ti->color_registers); }else{ ncplane_printf(n, "%ssixel colorregs: %u", indent, ti->color_registers); } - }else if(ti->pixel_draw_late){ + break; + case NCPIXEL_LINUXFB: ncplane_printf(n, "%sframebuffer graphics supported", indent); - }else if(ti->sixel_maxy_pristine){ + break; + case NCPIXEL_ITERM2: + ncplane_printf(n, "%siTerm2 graphics supported", indent); + break; + case NCPIXEL_KITTY_STATIC: ncplane_printf(n, "%srgba pixel graphics support", indent); - }else{ - ncplane_printf(n, "%srgba pixel animation support", indent); - } + break; + case NCPIXEL_KITTY_ANIMATED: + ncplane_printf(n, "%s1st gen rgba pixel animation support", indent); + break; + case NCPIXEL_KITTY_SELFREF: + ncplane_printf(n, "%s2nd gen rgba pixel animation support", indent); + break; } finish_line(n); - /* - ncplane_putstr(n, "\U0001F918"); - ncplane_putstr(n, "\U0001F918\u200d\U0001F3FB"); - ncplane_putstr(n, "\U0001F918\u200d\U0001F3FC"); - ncplane_putstr(n, "\U0001F918\u200d\U0001F3FD"); - ncplane_putstr(n, "\U0001F918\u200d\U0001F3FE"); - ncplane_putstr(n, "\U0001F918\u200d\U0001F3FF"); - */ } static void diff --git a/src/lib/kitty.c b/src/lib/kitty.c index 0f315b3fb..9b7a3027f 100644 --- a/src/lib/kitty.c +++ b/src/lib/kitty.c @@ -346,81 +346,11 @@ uint8_t* kitty_trans_auxvec(const tinfo* ti){ return a; } -// we lay a cell-sixed animation block atop the graphic, giving it a -// cell id with which we can delete it in O(1) for a rebuild. this -// way, we needn't delete and redraw the entire sprixel. -int kitty_wipe_animation(sprixel* s, int ycell, int xcell){ - if(init_sprixel_animation(s)){ - return -1; - } - logdebug("wiping sprixel %u at %d/%d\n", s->id, ycell, xcell); - fbuf* f = &s->glyph; - if(fbuf_puts(f, "\x1b_Ga=f,x=") < 0){ - return -1; - } - if(fbuf_putint(f, xcell * s->cellpxx) < 0){ - return -1; - } - if(fbuf_puts(f, ",y=") < 0){ - return -1; - } - if(fbuf_putint(f, ycell * s->cellpxy)){ - return -1; - } - if(fbuf_puts(f, ",s=") < 0){ - return -1; - } - if(fbuf_putint(f, s->cellpxx)){ - return -1; - } - if(fbuf_puts(f, ",v=") < 0){ - return -1; - } - if(fbuf_putint(f, s->cellpxy)){ - return -1; - } - if(fbuf_puts(f, ",i=") < 0){ - return -1; - } - if(fbuf_putint(f, s->id)){ - return -1; - } - if(fbuf_puts(f, ",X=1,r=1,q=2;") < 0){ - return -1; - } - // FIXME ought be smaller around the fringes! - int totalp = s->cellpxy * s->cellpxx; - // FIXME preserve so long as cellpixel geom stays constant? - for(int p = 0 ; p + 3 <= totalp ; p += 3){ - if(fbuf_putn(f, "AAAAAAAAAAAAAAAA", strlen("AAAAAAAAAAAAAAAA")) < 0){ - return -1; - } - } - if(totalp % 3 == 1){ - if(fbuf_putn(f, "AAAAAA==", strlen("AAAAAA==")) < 0){ - return -1; - } - }else if(totalp % 3 == 2){ - if(fbuf_putn(f, "AAAAAAAAAAA=", strlen("AAAAAAAAAAA=")) < 0){ - return -1; - } - } - // FIXME need chunking for cells of 768+ pixels - if(fbuf_putn(f, "\x1b\\", 2) < 0){ - return -1; - } - s->invalidated = SPRIXEL_INVALIDATED; - return 1; -} - -// FIXME merge back with kitty_wipe_animation -int kitty_wipe_selfref(sprixel* s, int ycell, int xcell){ - if(init_sprixel_animation(s)){ - return -1; - } - logdebug("Wiping sprixel %u at %d/%d\n", s->id, ycell, xcell); - fbuf* f = &s->glyph; - if(fbuf_printf(f, "\e_Ga=f,x=%d,y=%d,s=%d,v=%d,i=%d,X=1,r=2,c=1,q=2;", +// just dump the wipe into the fbuf -- don't manipulate any state. used both +// by the wipe proper, and when blitting a new frame with annihilations. +static int +kitty_blit_wipe_selfref(sprixel* s, fbuf* f, int ycell, int xcell){ + if(fbuf_printf(f, "\x1b_Ga=f,x=%d,y=%d,s=%d,v=%d,i=%d,X=1,r=2,c=1,q=2;", xcell * s->cellpxx, ycell * s->cellpxy, s->cellpxx, s->cellpxy, s->id) < 0){ return -1; @@ -449,13 +379,45 @@ int kitty_wipe_selfref(sprixel* s, int ycell, int xcell){ #undef DUONULLALPHA } // FIXME need chunking for cells of 768+ pixels - if(fbuf_printf(f, "\e\\\e_Ga=a,i=%d,c=2,q=2;\e\\", s->id) < 0){ + if(fbuf_printf(f, "\x1b\\\x1b_Ga=a,i=%d,c=2,q=2\x1b\\", s->id) < 0){ + return -1; + } + return 0; +} + +// we lay a cell-sixed animation block atop the graphic, giving it a +// cell id with which we can delete it in O(1) for a rebuild. this +// way, we needn't delete and redraw the entire sprixel. +int kitty_wipe_animation(sprixel* s, int ycell, int xcell){ + if(init_sprixel_animation(s)){ + return -1; + } + logdebug("wiping sprixel %u at %d/%d\n", s->id, ycell, xcell); + fbuf* f = &s->glyph; + if(kitty_blit_wipe_selfref(s, f, ycell, xcell) < 0){ return -1; } s->invalidated = SPRIXEL_INVALIDATED; return 1; } +int kitty_wipe_selfref(sprixel* s, int ycell, int xcell){ + if(init_sprixel_animation(s)){ + return -1; + } + const int tyx = xcell + ycell * s->dimx; + int state = s->n->tam[tyx].state; + void* auxvec = s->n->tam[tyx].auxvector; + logdebug("Wiping sprixel %u at %d/%d auxvec: %p state: %d\n", s->id, ycell, xcell, auxvec, state); + fbuf* f = &s->glyph; + if(kitty_blit_wipe_selfref(s, f, ycell, xcell)){ + return -1; + } + s->invalidated = SPRIXEL_INVALIDATED; + memcpy(auxvec, &state, sizeof(state)); + return 1; +} + sprixel* kitty_recycle(ncplane* n){ assert(n->sprite); sprixel* hides = n->sprite; @@ -717,6 +679,31 @@ destroy_deflator(unsigned animated, z_stream* zctx, int pixy, int pixx){ } } +// if we're KITTY_SELFREF, and we're blitting a secondary frame, we need +// carry through the TAM's annihilation entires...but we also need load the +// frame *without* annihilations, lest we be unable to build it. we thus go +// back through the TAM following a selfref blit, and any sprixcells which +// are annihilated will have their annhilation appended to the main blit. +// ought only be called for KITTY_SELFREF. +static int +finalize_multiframe_selfref(sprixel* s, fbuf* f){ + int prewiped = 0; + for(int y = 0 ; y < s->dimy ; ++y){ + for(int x = 0 ; x < s->dimx ; ++x){ + int tyxidx = y * s->dimx + x; + int state = s->n->tam[tyxidx].state; + if(state >= SPRIXCELL_ANNIHILATED){ + if(kitty_blit_wipe_selfref(s, f, y, x)){ + return -1; + } + ++prewiped; + } + } + } + loginfo("transitively wiped %d/%d\n", prewiped, s->dimy * s->dimx); + return 0; +} + // we can only write 4KiB at a time. we're writing base64-encoded RGBA. each // pixel is 4B raw (32 bits). each chunk of three pixels is then 12 bytes, or // 16 base64-encoded bytes. 4096 / 16 == 256 3-pixel groups, or 768 pixels. @@ -752,6 +739,9 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols, int targetout = 0; // number of pixels expected out after this chunk //fprintf(stderr, "total: %d chunks = %d, s=%d,v=%d\n", total, chunks, lenx, leny); char out[17]; // three pixels base64 to no more than 17 bytes + // set high if we are (1) reloading a frame with (2) annihilated cells copied over + // from the TAM and (3) we are KITTY_SELFREF. calls finalize_multiframe_selfref(). + bool selfref_annihilated = false; while(chunks--){ // q=2 has been able to go on chunks other than the last chunk since // 2021-03, but there's no harm in this small bit of backwards compat. @@ -832,16 +822,30 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols, // transparent, but we need to update the auxiliary vector. const int vyx = (y % cdimy) * cdimx + (x % cdimx); tam[tyx].auxvector[vyx] = ncpixel_a(source[e]); + wipe[e] = 1; + }else if(level == KITTY_SELFREF){ + selfref_annihilated = true; + }else{ + wipe[e] = 1; } if(rgba_trans_p(source[e], transcolor)){ ncpixel_set_a(&source[e], 0); // in case it was transcolor if(x % cdimx == 0 && y % cdimy == 0){ tam[tyx].state = SPRIXCELL_ANNIHILATED_TRANS; + if(level == KITTY_SELFREF){ + *tam[tyx].auxvector = SPRIXCELL_TRANSPARENT; + } + }else if(level == KITTY_SELFREF && tam[tyx].state == SPRIXCELL_ANNIHILATED_TRANS){ + *tam[tyx].auxvector = SPRIXCELL_MIXED_KITTY; } }else{ + if(x % cdimx == 0 && y % cdimy == 0 && level == KITTY_SELFREF){ + *tam[tyx].auxvector = SPRIXCELL_OPAQUE_KITTY; + }else if(level == KITTY_SELFREF && *tam[tyx].auxvector == SPRIXCELL_TRANSPARENT){ + *tam[tyx].auxvector = SPRIXCELL_MIXED_KITTY; + } tam[tyx].state = SPRIXCELL_ANNIHILATED; } - wipe[e] = 1; }else{ wipe[e] = 0; if(rgba_trans_p(source[e], transcolor)){ @@ -885,6 +889,11 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols, if(finalize_deflator(&zctx, f, leny, lenx)){ goto err; } + if(selfref_annihilated){ + if(finalize_multiframe_selfref(s, f)){ + goto err; + } + } } scrub_tam_boundaries(tam, leny, lenx, cdimy, cdimx); destroy_deflator(animated, &zctx, leny, lenx); diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index edc9630ee..964d8e1dc 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -984,11 +984,8 @@ recursive_lock_init(pthread_mutex_t *lock){ #endif } -int notcurses_check_pixel_support(const notcurses* nc){ - if(nc->tcache.pixel_draw || nc->tcache.pixel_draw_late){ - return 1; - } - return 0; +ncpixelimpl_e notcurses_check_pixel_support(const notcurses* nc){ + return nc->tcache.pixel_implementation; } // FIXME cut this up into a few distinct pieces, yearrrgh diff --git a/src/lib/plot.c b/src/lib/plot.c index 7b6a23e51..1083f5256 100644 --- a/src/lib/plot.c +++ b/src/lib/plot.c @@ -198,10 +198,12 @@ int redraw_pixelplot_##T(nc##X##plot* ncp){ \ } \ } \ if(ncp->plot.printsample){ \ - int lastslot = ncp->plot.slotstart ? ncp->plot.slotstart - 1 : ncp->plot.slotcount - 1; \ ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \ ncplane_set_channels(ncp->plot.ncp, ncp->plot.maxchannels); \ - ncplane_printf_aligned(ncp->plot.ncp, 0, NCALIGN_RIGHT, "%" PRIu64, (uint64_t)ncp->slots[lastslot]); \ + /* FIXME is this correct for double? */ \ + /* we use idx, and thus get an immediate count, changing as we load it. + * if you want a stable summary, print the previous slot */ \ + ncplane_printf_aligned(ncp->plot.ncp, 0, NCALIGN_RIGHT, "%" PRIu64, (uint64_t)ncp->slots[idx]); \ } \ ncplane_home(ncp->plot.ncp); \ struct ncvisual* ncv = ncvisual_from_rgba(pixels, dimy * states, dimx * scale * 4, dimx * scale); \ @@ -391,10 +393,9 @@ int redraw_plot_##T(nc##X##plot* ncp){ \ } \ } \ if(ncp->plot.printsample){ \ - int lastslot = ncp->plot.slotstart ? ncp->plot.slotstart - 1 : ncp->plot.slotcount - 1; \ ncplane_set_styles(ncp->plot.ncp, ncp->plot.legendstyle); \ ncplane_set_channels(ncp->plot.ncp, ncp->plot.maxchannels); \ - ncplane_printf_aligned(ncp->plot.ncp, 0, NCALIGN_RIGHT, "%" PRIu64, (uint64_t)ncp->slots[lastslot]); \ + ncplane_printf_aligned(ncp->plot.ncp, 0, NCALIGN_RIGHT, "%" PRIu64, (uint64_t)ncp->slots[idx]); \ } \ ncplane_home(ncp->plot.ncp); \ return 0; \ @@ -416,11 +417,12 @@ create_##T(nc##X##plot* ncpp, ncplane* n, const ncplot_options* opts, const T mi return NULL; \ } \ if(opts->rangex < 0){ \ - logerror("Supplied negative independent range %d\n", opts->rangex); \ + logerror("error: supplied negative independent range %d\n", opts->rangex); \ ncplane_destroy(n); \ return NULL; \ } \ if(maxy < miny){ \ + logerror("error: supplied maxy < miny\n"); \ ncplane_destroy(n); \ return NULL; \ } \ @@ -487,7 +489,9 @@ create_##T(nc##X##plot* ncpp, ncplane* n, const ncplot_options* opts, const T mi ncpp->plot.printsample = opts->flags & NCPLOT_OPTION_PRINTSAMPLE; \ if( (ncpp->plot.detectdomain = (miny == maxy)) ){ \ ncpp->maxy = trueminy; \ - ncpp->miny = truemaxy; \ + if(!ncpp->plot.detectonlymax){ \ + ncpp->miny = truemaxy; \ + } \ } \ ncpp->plot.slotstart = 0; \ ncpp->plot.slotx = 0; \ diff --git a/src/lib/sprite.c b/src/lib/sprite.c index 0be384497..f14c197e6 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -23,11 +23,7 @@ void sprixel_debug(const sprixel* s, FILE* out){ for(int x = 0 ; x < s->dimx ; ++x){ if(s->n->tam[idx].state == SPRIXCELL_ANNIHILATED){ if(s->n->tam[idx].auxvector){ - fprintf(out, "%03d] ", idx); - for(int p = 0 ; p < s->cellpxx * s->cellpxy ; ++p){ - fprintf(out, "%02x ", s->n->tam[idx].auxvector[p]); - } - fprintf(out, "\n"); + fprintf(out, "%03d] %p\n", idx, s->n->tam[idx].auxvector); }else{ fprintf(out, "%03d] missing!\n", idx); } diff --git a/src/lib/termdesc.c b/src/lib/termdesc.c index 7ab617075..aa0034de0 100644 --- a/src/lib/termdesc.c +++ b/src/lib/termdesc.c @@ -67,6 +67,7 @@ setup_sixel_bitmaps(tinfo* ti, int fd, bool invert80){ ti->pixel_trans_auxvec = sixel_trans_auxvec; ti->sprixel_scale_height = 6; set_pixel_blitter(sixel_blit); + ti->pixel_implementation = NCPIXEL_SIXEL; sprite_init(ti, fd); } @@ -91,17 +92,20 @@ setup_kitty_bitmaps(tinfo* ti, int fd, kitty_graphics_e level){ ti->pixel_rebuild = kitty_rebuild; ti->sixel_maxy_pristine = INT_MAX; set_pixel_blitter(kitty_blit); + ti->pixel_implementation = NCPIXEL_KITTY_STATIC; }else{ if(level == KITTY_ANIMATION){ ti->pixel_wipe = kitty_wipe_animation; ti->pixel_rebuild = kitty_rebuild_animation; ti->sixel_maxy_pristine = 0; set_pixel_blitter(kitty_blit_animated); + ti->pixel_implementation = NCPIXEL_KITTY_ANIMATED; }else{ ti->pixel_wipe = kitty_wipe_selfref; ti->pixel_rebuild = kitty_rebuild_selfref; ti->sixel_maxy_pristine = 0; set_pixel_blitter(kitty_blit_selfref); + ti->pixel_implementation = NCPIXEL_KITTY_SELFREF; } } sprite_init(ti, fd); @@ -124,6 +128,7 @@ setup_fbcon_bitmaps(tinfo* ti, int fd){ ti->pixel_wipe = fbcon_wipe; ti->pixel_trans_auxvec = kitty_trans_auxvec; set_pixel_blitter(fbcon_blit); + ti->pixel_implementation = NCPIXEL_LINUXFB; sprite_init(ti, fd); } #endif @@ -521,9 +526,9 @@ apply_term_heuristics(tinfo* ti, const char* termname, queried_terminals_e qterm if(add_smulx_escapes(ti, tablelen, tableused)){ return -1; } - if(compare_versions(ti->termversion, "0.22.1") >= 0){ + /*if(compare_versions(ti->termversion, "0.22.1") >= 0){ setup_kitty_bitmaps(ti, ti->ttyfd, KITTY_SELFREF); - }else if(compare_versions(ti->termversion, "0.20.0") >= 0){ + }else*/ if(compare_versions(ti->termversion, "0.20.0") >= 0){ setup_kitty_bitmaps(ti, ti->ttyfd, KITTY_ANIMATION); }else{ setup_kitty_bitmaps(ti, ti->ttyfd, KITTY_ALWAYS_SCROLLS); diff --git a/src/lib/termdesc.h b/src/lib/termdesc.h index 6a39fdc1d..144559b71 100644 --- a/src/lib/termdesc.h +++ b/src/lib/termdesc.h @@ -151,7 +151,9 @@ typedef struct tinfo { // bg_collides_default is either 0x0000000 or (if in use) 0x1RRGGBB. uint32_t bg_collides_default; - // bitmap support. if we support bitmaps, pixel_draw will be non-NULL + // bitmap support. if we support bitmaps, pixel_implementation will be a + // value other than NCPIXEL_NONE. + ncpixelimpl_e pixel_implementation; // wipe out a cell's worth of pixels from within a sprixel. for sixel, this // means leaving out the pixels (and likely resizes the string). for kitty, // this means dialing down their alpha to 0 (in equivalent space).