Notcurses 3.0.13
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
render.c File Reference
#include <ctype.h>
#include <limits.h>
#include <unistd.h>
#include "internal.h"
#include "unixsig.h"
Include dependency graph for render.c:

Go to the source code of this file.

Macros

#define RGBESC1   "\x1b" "["
 
#define RGBESC2   "8;2;"
 
#define MIN_SUMODE_SIZE   BUFSIZ
 

Functions

void nccell_release (ncplane *n, nccell *c)
 
int nccell_duplicate (ncplane *n, nccell *targ, const nccell *c)
 
 __attribute__ ((nonnull(1, 2, 7)))
 
int ncplane_mergedown (ncplane *restrict src, ncplane *restrict dst, int begsrcy, int begsrcx, unsigned leny, unsigned lenx, int dsty, int dstx)
 
int ncplane_mergedown_simple (ncplane *restrict src, ncplane *restrict dst)
 
int term_fg_rgb8 (const tinfo *ti, fbuf *f, unsigned r, unsigned g, unsigned b)
 
int clear_and_home (notcurses *nc, tinfo *ti, fbuf *f)
 
int notcurses_refresh (notcurses *nc, unsigned *restrict dimy, unsigned *restrict dimx)
 
int ncpile_render_to_file (ncplane *n, FILE *fp)
 
int ncpile_rasterize (ncplane *n)
 
int ncpile_render (ncplane *n)
 
int ncpile_render_to_buffer (ncplane *p, char **buf, size_t *buflen)
 
char * notcurses_at_yx (notcurses *nc, unsigned yoff, unsigned xoff, uint16_t *stylemask, uint64_t *channels)
 
int ncdirect_set_bg_rgb_f (ncdirect *nc, unsigned rgb, fbuf *f)
 
int ncdirect_set_bg_rgb (ncdirect *nc, unsigned rgb)
 
int ncdirect_set_fg_rgb_f (ncdirect *nc, unsigned rgb, fbuf *f)
 
int ncdirect_set_fg_rgb (ncdirect *nc, unsigned rgb)
 
int notcurses_default_foreground (const struct notcurses *nc, uint32_t *fg)
 
int notcurses_default_background (const struct notcurses *nc, uint32_t *bg)
 
int notcurses_cursor_yx (const notcurses *nc, int *y, int *x)
 
int notcurses_cursor_enable (notcurses *nc, int y, int x)
 
int notcurses_cursor_disable (notcurses *nc)
 

Variables

sig_atomic_t sigcont_seen_for_render = 0
 

Macro Definition Documentation

◆ MIN_SUMODE_SIZE

#define MIN_SUMODE_SIZE   BUFSIZ

◆ RGBESC1

#define RGBESC1   "\x1b" "["

◆ RGBESC2

#define RGBESC2   "8;2;"

Function Documentation

◆ __attribute__()

__attribute__ ( (nonnull(1, 2, 7))  )

Definition at line 235 of file render.c.

238 {
239 unsigned y, x, dimy, dimx;
240 int offy, offx;
241 ncplane_dim_yx(p, &dimy, &dimx);
242 offy = p->absy - dstabsy;
243 offx = p->absx - dstabsx;
244//fprintf(stderr, "PLANE %p %d %d %d %d %d %d %p\n", p, dimy, dimx, offy, offx, dstleny, dstlenx, p->sprite);
245 // skip content above or to the left of the physical screen
246 unsigned starty, startx;
247 if(offy < 0){
248 starty = -offy;
249 }else{
250 starty = 0;
251 }
252 if(offx < 0){
253 startx = -offx;
254 }else{
255 startx = 0;
256 }
257 // if we're a sprixel, we must not register ourselves as the active
258 // glyph, but we *do* need to null out any cellregions that we've
259 // scribbled upon.
260 if(p->sprite){
261 if(pgeo_changed){
262 // do what on failure? FIXME
263 sprixel_rescale(p->sprite, ncplane_pile(p)->cellpxy, ncplane_pile(p)->cellpxx);
264 }
265 paint_sprixel(p, rvec, starty, startx, offy, offx, dstleny, dstlenx);
266 // decouple from the pile's sixel list
267 if(p->sprite->next){
268 p->sprite->next->prev = p->sprite->prev;
269 }
270 if(p->sprite->prev){
271 p->sprite->prev->next = p->sprite->next;
272 }else{
273 ncplane_pile(p)->sprixelcache = p->sprite->next;
274 }
275 // stick on the head of the running list: top sprixel is at end
276 if(*sprixelstack){
277 (*sprixelstack)->prev = p->sprite;
278 }
279 p->sprite->next = *sprixelstack;
280 p->sprite->prev = NULL;
281 *sprixelstack = p->sprite;
282 return;
283 }
284 for(y = starty ; y < dimy ; ++y){
285 const int absy = y + offy;
286 // once we've passed the physical screen's bottom, we're done
287 if(absy >= dstleny || absy < 0){
288 break;
289 }
290 for(x = startx ; x < dimx ; ++x){ // iteration for each cell
291 const int absx = x + offx;
292 if(absx >= dstlenx || absx < 0){
293 break;
294 }
295 struct crender* crender = &rvec[fbcellidx(absy, dstlenx, absx)];
296//fprintf(stderr, "p: %p damaged: %u %d/%d\n", p, crender->s.damaged, y, x);
297 nccell* targc = &crender->c;
298 if(nccell_wide_right_p(targc)){
299 continue;
300 }
301
302 if(nccell_fg_alpha(targc) > NCALPHA_OPAQUE){
303 const nccell* vis = &p->fb[nfbcellidx(p, y, x)];
304 if(nccell_fg_default_p(vis)){
305 vis = &p->basecell;
306 }
307 if(nccell_fg_alpha(vis) == NCALPHA_HIGHCONTRAST){
308 crender->s.highcontrast = true;
310 crender->hcfg = cell_fchannel(targc);
311 }
312 unsigned fgblends = crender->s.fgblends;
313 cell_blend_fchannel(ncplane_notcurses(p), targc, cell_fchannel(vis), &fgblends);
315 // crender->highcontrast can only be true if we just set it, since we're
316 // about to set targc opaque based on crender->highcontrast (and this
317 // entire stanza is conditional on targc not being NCALPHA_OPAQUE).
319 nccell_set_fg_alpha(targc, NCALPHA_OPAQUE);
320 }
321 }
322
323 // Background color takes effect independently of whether we have a
324 // glyph. If we've already locked in the background, it has no effect.
325 // If it's transparent, it has no effect. Otherwise, update the
326 // background channel and balpha.
327 // Evaluate the background first, in case we have HIGHCONTRAST fg text.
328 if(nccell_bg_alpha(targc) > NCALPHA_OPAQUE){
329 const nccell* vis = &p->fb[nfbcellidx(p, y, x)];
330 // to be on the blitter stacking path, we need
331 // 1) crender->s.blittedquads to be non-zero (we're below semigraphics)
332 // 2) cell_blittedquadrants(vis) to be non-zero (we're semigraphics)
333 // 3) somewhere crender is 0, blittedquads is 1 (we're visible)
334 if(!crender->s.blittedquads || !((~crender->s.blittedquads) & cell_blittedquadrants(vis))){
335 if(nccell_bg_default_p(vis)){
336 vis = &p->basecell;
337 }
338 unsigned bgblends = crender->s.bgblends;
339 cell_blend_bchannel(ncplane_notcurses(p), targc, cell_bchannel(vis), &bgblends);
341 }else{ // use the local foreground; we're stacking blittings
342 if(nccell_fg_default_p(vis)){
343 vis = &p->basecell;
344 }
345 unsigned bgblends = crender->s.bgblends;
346 cell_blend_bchannel(ncplane_notcurses(p), targc, cell_fchannel(vis), &bgblends);
349 }
350 }
351
352 // if we never loaded any content into the cell (or obliterated it by
353 // writing in a zero), use the plane's base cell.
354 // if we have no character in this cell, we continue to look for a
355 // character, but our foreground color will still be used unless it's
356 // been set to transparent. if that foreground color is transparent, we
357 // still use a character we find here, but its color will come entirely
358 // from cells underneath us.
359 if(!crender->p){
360 const nccell* vis = &p->fb[nfbcellidx(p, y, x)];
361 if(vis->gcluster == 0 && !nccell_double_wide_p(vis)){
362 vis = &p->basecell;
363 }
364 // if the following is true, we're a real glyph, and not the right-hand
365 // side of a wide glyph (nor the null codepoint).
366 if( (targc->gcluster = vis->gcluster) ){ // index copy only
368//fprintf(stderr, "damaged due to hide %d/%d\n", y, x);
369 crender->s.damaged = 1;
370 }
371 crender->s.blittedquads = cell_blittedquadrants(vis);
372 // we can't plop down a wide glyph if the next cell is beyond the
373 // screen, nor if we're bisected by a higher plane.
374 if(nccell_double_wide_p(vis)){
375 // are we on the last column of the real screen? if so, 0x20 us
376 if(absx >= dstlenx - 1){
377 targc->gcluster = htole(' ');
378 targc->width = 1;
379 // is the next cell occupied? if so, 0x20 us
380 }else if(crender[1].c.gcluster){
381//fprintf(stderr, "NULLING out %d/%d (%d/%d) due to %u\n", y, x, absy, absx, crender[1].c.gcluster);
382 targc->gcluster = htole(' ');
383 targc->width = 1;
384 }else{
385 targc->stylemask = vis->stylemask;
386 targc->width = vis->width;
387 }
388 }else{
389 targc->stylemask = vis->stylemask;
390 targc->width = vis->width;
391 }
392 crender->p = p;
393 }else if(nccell_wide_right_p(vis)){
394 crender->p = p;
395 targc->width = 0;
396 }
397 }
398 }
399 }
400}
const nccell * c
Definition egcpool.h:296
#define htole(x)
Definition ncport.h:36
notcurses * ncplane_notcurses(const ncplane *n)
Definition notcurses.c:2626
void ncplane_dim_yx(const ncplane *n, unsigned *rows, unsigned *cols)
Definition notcurses.c:301
int y
Definition notcurses.h:1905
#define NCALPHA_OPAQUE
Definition notcurses.h:108
int int x
Definition notcurses.h:1905
#define NCALPHA_HIGHCONTRAST
Definition notcurses.h:105
int sprixel_rescale(sprixel *spx, unsigned ncellpxy, unsigned ncellpxx)
Definition sprite.c:225
@ SPRIXEL_HIDE
Definition sprite.h:25
struct crender::@2 s
unsigned damaged
Definition internal.h:283
nccell c
Definition internal.h:266
unsigned fgblends
Definition internal.h:287
unsigned bgblends
Definition internal.h:288
sprixel * sprixel
Definition internal.h:268
const ncplane * p
Definition internal.h:267
unsigned hcfgblends
Definition internal.h:292
unsigned highcontrast
Definition internal.h:286
unsigned blittedquads
Definition internal.h:282
uint32_t hcfg
Definition internal.h:269
uint8_t width
Definition notcurses.h:702
uint16_t stylemask
Definition notcurses.h:703
uint32_t gcluster
Definition notcurses.h:693
nccell basecell
Definition internal.h:110
nccell * fb
Definition internal.h:77
sprixel_e invalidated
Definition sprite.h:143
return NULL
Definition termdesc.h:229
Here is the call graph for this function:

◆ clear_and_home()

int clear_and_home ( notcurses nc,
tinfo ti,
fbuf f 
)

Definition at line 1399 of file render.c.

1399 {
1400 // clear clears the screen and homes the cursor by itself
1401 const char* clearscr = get_escape(ti, ESCAPE_CLEAR);
1402 if(clearscr){
1403 if(fbuf_emit(f, clearscr) == 0){
1404 nc->rstate.x = nc->rstate.y = 0;
1405 return 0;
1406 }
1407 }
1408 if(emit_scrolls_track(nc, ncplane_dim_y(notcurses_stdplane_const(nc)), f)){
1409 return -1;
1410 }
1411 if(goto_location(nc, f, 0, 0, NULL)){
1412 return -1;
1413 }
1414 return 0;
1415}
const ncplane * notcurses_stdplane_const(const notcurses *nc)
Definition notcurses.c:703
rasterstate rstate
Definition internal.h:336
@ ESCAPE_CLEAR
Definition termdesc.h:80
Here is the call graph for this function:
Here is the caller graph for this function:

◆ nccell_duplicate()

int nccell_duplicate ( ncplane n,
nccell targ,
const nccell c 
)

Definition at line 133 of file render.c.

133 {
134 if(cell_duplicate_far(&n->pool, targ, n, c) < 0){
135 logerror("failed duplicating cell");
136 return -1;
137 }
138 return 0;
139}
#define logerror(fmt,...)
Definition logging.h:32
vopts n
Definition notcurses.h:3502
Here is the caller graph for this function:

◆ nccell_release()

void nccell_release ( ncplane n,
nccell c 
)

Definition at line 128 of file render.c.

128 {
129 pool_release(&n->pool, c);
130}
Here is the caller graph for this function:

◆ ncdirect_set_bg_rgb()

int ncdirect_set_bg_rgb ( ncdirect nc,
unsigned  rgb 
)

Definition at line 1667 of file render.c.

1667 {
1668 fbuf f = {0};
1669 if(fbuf_init_small(&f)){
1670 return -1;
1671 }
1672 if(ncdirect_set_bg_rgb_f(nc, rgb, &f)){
1673 fbuf_free(&f);
1674 return -1;
1675 }
1676 if(fbuf_finalize(&f, nc->ttyfp) < 0){
1677 return -1;
1678 }
1679 return 0;
1680}
int ncdirect_set_bg_rgb_f(ncdirect *nc, unsigned rgb, fbuf *f)
Definition render.c:1652
Definition fbuf.h:25
FILE * ttyfp
Definition internal.h:252
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncdirect_set_bg_rgb_f()

int ncdirect_set_bg_rgb_f ( ncdirect nc,
unsigned  rgb,
fbuf f 
)

Definition at line 1652 of file render.c.

1652 {
1653 if(rgb > 0xffffffu){
1654 return -1;
1655 }
1656 if(!ncdirect_bg_default_p(nc) && !ncdirect_bg_palindex_p(nc)
1657 && ncchannels_bg_rgb(nc->channels) == rgb){
1658 return 0;
1659 }
1660 if(term_bg_rgb8(&nc->tcache, f, (rgb & 0xff0000u) >> 16u, (rgb & 0xff00u) >> 8u, rgb & 0xffu)){
1661 return -1;
1662 }
1663 ncchannels_set_bg_rgb(&nc->channels, rgb);
1664 return 0;
1665}
uint64_t channels
Definition internal.h:254
tinfo tcache
Definition internal.h:253
Here is the caller graph for this function:

◆ ncdirect_set_fg_rgb()

int ncdirect_set_fg_rgb ( ncdirect nc,
unsigned  rgb 
)

Definition at line 1697 of file render.c.

1697 {
1698 fbuf f = {0};
1699 if(fbuf_init_small(&f)){
1700 return -1;
1701 }
1702 if(ncdirect_set_fg_rgb_f(nc, rgb, &f)){
1703 fbuf_free(&f);
1704 return -1;
1705 }
1706 if(fbuf_finalize(&f, nc->ttyfp) < 0){
1707 return -1;
1708 }
1709 return 0;
1710}
int ncdirect_set_fg_rgb_f(ncdirect *nc, unsigned rgb, fbuf *f)
Definition render.c:1682
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncdirect_set_fg_rgb_f()

int ncdirect_set_fg_rgb_f ( ncdirect nc,
unsigned  rgb,
fbuf f 
)

Definition at line 1682 of file render.c.

1682 {
1683 if(rgb > 0xffffffu){
1684 return -1;
1685 }
1686 if(!ncdirect_fg_default_p(nc) && !ncdirect_fg_palindex_p(nc)
1687 && ncchannels_fg_rgb(nc->channels) == rgb){
1688 return 0;
1689 }
1690 if(term_fg_rgb8(&nc->tcache, f, (rgb & 0xff0000u) >> 16u, (rgb & 0xff00u) >> 8u, rgb & 0xffu)){
1691 return -1;
1692 }
1693 ncchannels_set_fg_rgb(&nc->channels, rgb);
1694 return 0;
1695}
int term_fg_rgb8(const tinfo *ti, fbuf *f, unsigned r, unsigned g, unsigned b)
Definition render.c:743
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncpile_rasterize()

int ncpile_rasterize ( ncplane n)

Definition at line 1517 of file render.c.

1517 {
1518 struct timespec start, rasterdone, writedone;
1519 clock_gettime(CLOCK_MONOTONIC, &start);
1520 ncpile* pile = ncplane_pile(n);
1521 struct notcurses* nc = ncpile_notcurses(pile);
1522 const struct tinfo* ti = &ncplane_notcurses_const(n)->tcache;
1523 postpaint(nc, ti, nc->lastframe, pile->dimy, pile->dimx, pile->crender, &nc->pool);
1524 clock_gettime(CLOCK_MONOTONIC, &rasterdone);
1525 int bytes = notcurses_rasterize(nc, pile, &nc->rstate.f);
1526 clock_gettime(CLOCK_MONOTONIC, &writedone);
1527 pthread_mutex_lock(&nc->stats.lock);
1528 // accepts negative |bytes| as an indication of failure
1529 update_raster_bytes(&nc->stats.s, bytes);
1530 update_raster_stats(&rasterdone, &start, &nc->stats.s);
1531 update_write_stats(&writedone, &rasterdone, &nc->stats.s, bytes);
1532 pthread_mutex_unlock(&nc->stats.lock);
1533 // we want to refresh if the screen geometry changed (or if we were just
1534 // woken up from SIGSTOP), but we mustn't do so until after rasterizing
1535 // the solved rvec, since this might result in a geometry update.
1539 }
1540 if(bytes < 0){
1541 return -1;
1542 }
1543 return 0;
1544}
void update_write_stats(const struct timespec *time1, const struct timespec *time0, ncstats *stats, int bytes)
Definition stats.c:5
void update_raster_stats(const struct timespec *time1, const struct timespec *time0, ncstats *stats)
Definition stats.c:58
void update_raster_bytes(ncstats *stats, int bytes)
Definition stats.c:27
const notcurses * ncplane_notcurses_const(const ncplane *n)
Definition notcurses.c:2630
sig_atomic_t sigcont_seen_for_render
Definition render.c:7
int notcurses_refresh(notcurses *nc, unsigned *restrict dimy, unsigned *restrict dimx)
Definition render.c:1417
unsigned dimx
Definition internal.h:325
unsigned dimy
Definition internal.h:325
struct crender * crender
Definition internal.h:321
ncstats s
Definition internal.h:247
pthread_mutex_t lock
Definition internal.h:246
nccell * lastframe
Definition internal.h:341
ncsharedstats stats
Definition internal.h:356
tinfo tcache
Definition internal.h:360
egcpool pool
Definition internal.h:348
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncpile_render()

int ncpile_render ( ncplane n)

Definition at line 1569 of file render.c.

1569 {
1570 scroll_lastframe(ncplane_notcurses(n), ncplane_pile(n)->scrolls);
1571 struct timespec start, renderdone;
1572 clock_gettime(CLOCK_MONOTONIC, &start);
1574 ncpile* pile = ncplane_pile(n);
1575 // update our notion of screen geometry, and render against that
1576 unsigned pgeo_changed = 0;
1577 notcurses_resize_internal(n, NULL, NULL);
1578 if(pile->cellpxy != nc->tcache.cellpxy || pile->cellpxx != nc->tcache.cellpxx){
1579 pile->cellpxy = nc->tcache.cellpxy;
1580 pile->cellpxx = nc->tcache.cellpxx;
1581 pgeo_changed = 1;
1582 }
1583 if(engorge_crender_vector(pile)){
1584 return -1;
1585 }
1586 ncpile_render_internal(pile, pgeo_changed);
1587 clock_gettime(CLOCK_MONOTONIC, &renderdone);
1588 pthread_mutex_lock(&nc->stats.lock);
1589 update_render_stats(&renderdone, &start, &nc->stats.s);
1590 pthread_mutex_unlock(&nc->stats.lock);
1591 return 0;
1592}
void update_render_stats(const struct timespec *time1, const struct timespec *time0, ncstats *stats)
Definition stats.c:40
unsigned cellpxx
Definition internal.h:326
unsigned cellpxy
Definition internal.h:326
unsigned cellpxx
Definition termdesc.h:117
unsigned cellpxy
Definition termdesc.h:116
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncpile_render_to_buffer()

int ncpile_render_to_buffer ( ncplane p,
char **  buf,
size_t *  buflen 
)

Definition at line 1595 of file render.c.

1595 {
1596 if(ncpile_render(p)){
1597 return -1;
1598 }
1600 unsigned useasu = false; // no SUM with file
1601 fbuf_reset(&nc->rstate.f);
1602 int bytes = notcurses_rasterize_inner(nc, ncplane_pile(p), &nc->rstate.f, &useasu);
1603 pthread_mutex_lock(&nc->stats.lock);
1604 update_raster_bytes(&nc->stats.s, bytes);
1605 pthread_mutex_unlock(&nc->stats.lock);
1606 if(bytes < 0){
1607 return -1;
1608 }
1609 *buf = nc->rstate.f.buf;
1610 *buflen = nc->rstate.f.used;
1611 fbuf_reset(&nc->rstate.f);
1612 return 0;
1613}
int ncpile_render(ncplane *n)
Definition render.c:1569
char * buf
Definition fbuf.h:28
uint64_t used
Definition fbuf.h:27
Here is the call graph for this function:

◆ ncpile_render_to_file()

int ncpile_render_to_file ( ncplane n,
FILE *  fp 
)

Definition at line 1452 of file render.c.

1452 {
1454 ncpile* p = ncplane_pile(n);
1455 if(nc->lfdimx == 0 || nc->lfdimy == 0){
1456 return 0;
1457 }
1458 fbuf f = {0};
1459 if(fbuf_init(&f)){
1460 return -1;
1461 }
1462 const unsigned count = (nc->lfdimx > p->dimx ? nc->lfdimx : p->dimx) *
1463 (nc->lfdimy > p->dimy ? nc->lfdimy : p->dimy);
1464 p->crender = malloc(count * sizeof(*p->crender));
1465 if(p->crender == NULL){
1466 fbuf_free(&f);
1467 return -1;
1468 }
1469 init_rvec(p->crender, count);
1470 for(unsigned i = 0 ; i < count ; ++i){
1471 p->crender[i].s.damaged = 1;
1472 }
1473 int ret = raster_and_write(nc, p, &f);
1474 free(p->crender);
1475 if(ret > 0){
1476 if(fwrite(f.buf, f.used, 1, fp) == 1){
1477 ret = 0;
1478 }else{
1479 ret = -1;
1480 }
1481 }
1482 fbuf_free(&f);
1483 return ret;
1484}
free(duplicated)
unsigned lfdimx
Definition internal.h:350
unsigned lfdimy
Definition internal.h:351
Here is the call graph for this function:

◆ ncplane_mergedown()

int ncplane_mergedown ( ncplane *restrict  src,
ncplane *restrict  dst,
int  begsrcy,
int  begsrcx,
unsigned  leny,
unsigned  lenx,
int  dsty,
int  dstx 
)

Definition at line 514 of file render.c.

516 {
517//fprintf(stderr, "Merging down %d/%d @ %d/%d to %d/%d\n", leny, lenx, begsrcy, begsrcx, dsty, dstx);
518 if(dsty < 0){
519 if(dsty != -1){
520 logerror("invalid dsty %d", dsty);
521 return -1;
522 }
523 dsty = dst->y;
524 }
525 if(dstx < 0){
526 if(dstx != -1){
527 logerror("invalid dstx %d", dstx);
528 return -1;
529 }
530 dstx = dst->x;
531 }
532 if((unsigned)dsty >= dst->leny || (unsigned)dstx >= dst->lenx){
533 logerror("dest origin %u/%u ≥ dest dimensions %d/%d",
534 dsty, dstx, dst->leny, dst->lenx);
535 return -1;
536 }
537 if(begsrcy < 0){
538 if(begsrcy != -1){
539 logerror("invalid begsrcy %d", begsrcy);
540 return -1;
541 }
542 begsrcy = src->y;
543 }
544 if(begsrcx < 0){
545 if(begsrcx != -1){
546 logerror("invalid begsrcx %d", begsrcx);
547 return -1;
548 }
549 begsrcx = src->x;
550 }
551 if((unsigned)begsrcy >= src->leny || (unsigned)begsrcx >= src->lenx){
552 logerror("source origin %u/%u ≥ source dimensions %d/%d",
553 begsrcy, begsrcx, src->leny, src->lenx);
554 return -1;
555 }
556 if(leny == 0){
557 if((leny = src->leny - begsrcy) == 0){
558 logerror("source area was zero height");
559 return -1;
560 }
561 }
562 if(lenx == 0){
563 if((lenx = src->lenx - begsrcx) == 0){
564 logerror("source area was zero width");
565 return -1;
566 }
567 }
568 if(dst->leny - leny < (unsigned)dsty || dst->lenx - lenx < (unsigned)dstx){
569 logerror("dest len %u/%u ≥ dest dimensions %d/%d",
570 leny, lenx, dst->leny, dst->lenx);
571 return -1;
572 }
573 if(src->leny - leny < (unsigned)begsrcy || src->lenx - lenx < (unsigned)begsrcx){
574 logerror("source len %u/%u ≥ source dimensions %d/%d",
575 leny, lenx, src->leny, src->lenx);
576 return -1;
577 }
578 if(src->sprite || dst->sprite){
579 logerror("can't merge sprixel planes");
580 return -1;
581 }
582 const int totalcells = dst->leny * dst->lenx;
583 nccell* rendfb = calloc(totalcells, sizeof(*rendfb));
584 const size_t crenderlen = sizeof(struct crender) * totalcells;
585 struct crender* rvec = malloc(crenderlen);
586 if(!rendfb || !rvec){
587 logerror("error allocating render state for %ux%u", leny, lenx);
588 free(rendfb);
589 free(rvec);
590 return -1;
591 }
592 init_rvec(rvec, totalcells);
593 sprixel* s = NULL;
594 paint(src, rvec, dst->leny, dst->lenx, dst->absy, dst->absx, &s, 0);
595 assert(NULL == s);
596 paint(dst, rvec, dst->leny, dst->lenx, dst->absy, dst->absx, &s, 0);
597 assert(NULL == s);
598//fprintf(stderr, "Postpaint start (%dx%d)\n", dst->leny, dst->lenx);
599 const struct tinfo* ti = &ncplane_notcurses_const(dst)->tcache;
600 postpaint(ncplane_notcurses(dst), ti, rendfb, dst->leny, dst->lenx, rvec, &dst->pool);
601//fprintf(stderr, "Postpaint done (%dx%d)\n", dst->leny, dst->lenx);
602 free(dst->fb);
603 dst->fb = rendfb;
604 free(rvec);
605 return 0;
606}
assert(false)
sprixel * sprite
Definition internal.h:105
unsigned lenx
Definition internal.h:86
unsigned x
Definition internal.h:79
int absy
Definition internal.h:83
unsigned leny
Definition internal.h:86
unsigned y
Definition internal.h:79
int absx
Definition internal.h:83
egcpool pool
Definition internal.h:87
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ncplane_mergedown_simple()

int ncplane_mergedown_simple ( ncplane *restrict  src,
ncplane *restrict  dst 
)

Definition at line 608 of file render.c.

608 {
609 return ncplane_mergedown(src, dst, 0, 0, 0, 0, 0, 0);
610}
int ncplane_mergedown(ncplane *restrict src, ncplane *restrict dst, int begsrcy, int begsrcx, unsigned leny, unsigned lenx, int dsty, int dstx)
Definition render.c:514
Here is the call graph for this function:
Here is the caller graph for this function:

◆ notcurses_at_yx()

char * notcurses_at_yx ( notcurses nc,
unsigned  yoff,
unsigned  xoff,
uint16_t *  stylemask,
uint64_t *  channels 
)

Definition at line 1625 of file render.c.

1625 {
1626 if(nc->lastframe == NULL){
1627 logerror("haven't yet rendered");
1628 return NULL;
1629 }
1630 if(yoff >= nc->lfdimy){
1631 logerror("invalid coordinates: %u/%u", yoff, xoff);
1632 return NULL;
1633 }
1634 if(xoff >= nc->lfdimx){
1635 logerror("invalid coordinates: %u/%u", yoff, xoff);
1636 return NULL;
1637 }
1638 const nccell* srccell = &nc->lastframe[yoff * nc->lfdimx + xoff];
1639 if(nccell_wide_right_p(srccell)){
1640 return notcurses_at_yx(nc, yoff, xoff - 1, stylemask, channels);
1641 }
1642 if(stylemask){
1643 *stylemask = srccell->stylemask;
1644 }
1645 if(channels){
1646 *channels = srccell->channels;
1647 }
1648//fprintf(stderr, "COPYING: %d from %p\n", srccell->gcluster, &nc->pool);
1649 return pool_egc_copy(&nc->pool, srccell);
1650}
char * notcurses_at_yx(notcurses *nc, unsigned yoff, unsigned xoff, uint16_t *stylemask, uint64_t *channels)
Definition render.c:1625
uint64_t channels
Definition notcurses.h:723
Here is the call graph for this function:
Here is the caller graph for this function:

◆ notcurses_cursor_disable()

int notcurses_cursor_disable ( notcurses nc)

Definition at line 1772 of file render.c.

1772 {
1773 if(nc->cursorx < 0 || nc->cursory < 0){
1774 logerror("cursor is not enabled");
1775 return -1;
1776 }
1777 const char* cinvis = get_escape(&nc->tcache, ESCAPE_CIVIS);
1778 if(cinvis){
1779 if(!tty_emit(cinvis, nc->tcache.ttyfd) && !ncflush(nc->ttyfp)){
1780 nc->cursory = -1;
1781 nc->cursorx = -1;
1782 return 0;
1783 }
1784 }
1785 return -1;
1786}
int cursorx
Definition internal.h:354
int cursory
Definition internal.h:353
FILE * ttyfp
Definition internal.h:359
int ttyfd
Definition termdesc.h:109
@ ESCAPE_CIVIS
Definition termdesc.h:54
Here is the caller graph for this function:

◆ notcurses_cursor_enable()

int notcurses_cursor_enable ( notcurses nc,
int  y,
int  x 
)

Definition at line 1738 of file render.c.

1738 {
1739 if(y < 0 || x < 0){
1740 logerror("illegal cursor placement: %d, %d", y, x);
1741 return -1;
1742 }
1743 // if we're already at the demanded location, we must already be visible, and
1744 // we needn't move the cursor -- return success immediately.
1745 if(nc->cursory == y && nc->cursorx == x){
1746 return 0;
1747 }
1748 fbuf f = {0};
1749 if(fbuf_init_small(&f)){
1750 return -1;
1751 }
1752 // updates nc->rstate.cursor{y,x}
1753 if(goto_location(nc, &f, y + nc->margin_t, x + nc->margin_l, nc->rstate.lastsrcp)){
1754 fbuf_free(&f);
1755 return -1;
1756 }
1757 if(nc->cursory < 0){ // we weren't visible before, need cnorm
1758 const char* cnorm = get_escape(&nc->tcache, ESCAPE_CNORM);
1759 if(!cnorm || fbuf_emit(&f, cnorm)){
1760 fbuf_free(&f);
1761 return -1;
1762 }
1763 }
1764 if(fbuf_finalize(&f, nc->ttyfp)){
1765 return -1;
1766 }
1767 nc->cursory = y;
1768 nc->cursorx = x;
1769 return 0;
1770}
int margin_l
Definition internal.h:364
int margin_t
Definition internal.h:364
const ncplane * lastsrcp
Definition internal.h:140
@ ESCAPE_CNORM
Definition termdesc.h:55
Here is the caller graph for this function:

◆ notcurses_cursor_yx()

int notcurses_cursor_yx ( const notcurses nc,
int *  y,
int *  x 
)

Definition at line 1732 of file render.c.

1732 {
1733 *y = nc->rstate.y;
1734 *x = nc->rstate.x;
1735 return 0;
1736}

◆ notcurses_default_background()

int notcurses_default_background ( const struct notcurses nc,
uint32_t *  bg 
)

Definition at line 1722 of file render.c.

1722 {
1723 const tinfo* ti = &nc->tcache;
1724 if(ti->bg_collides_default & 0x80000000){
1725 logerror("default background could not be determined");
1726 return -1;
1727 }
1729 return 0;
1730}
#define NC_BG_RGB_MASK
Definition notcurses.h:120
uint32_t bg_collides_default
Definition termdesc.h:127

◆ notcurses_default_foreground()

int notcurses_default_foreground ( const struct notcurses nc,
uint32_t *  fg 
)

Definition at line 1712 of file render.c.

1712 {
1713 const tinfo* ti = &nc->tcache;
1714 if(ti->fg_default & 0x80000000){
1715 logerror("default foreground could not be determined");
1716 return -1;
1717 }
1718 *fg = ti->fg_default & NC_BG_RGB_MASK;
1719 return 0;
1720}
uint32_t fg_default
Definition termdesc.h:130

◆ notcurses_refresh()

int notcurses_refresh ( notcurses nc,
unsigned *restrict  dimy,
unsigned *restrict  dimx 
)

Definition at line 1417 of file render.c.

1417 {
1418 if(notcurses_resize(nc, dimy, dimx)){
1419 return -1;
1420 }
1421 fbuf_reset(&nc->rstate.f);
1422 if(clear_and_home(nc, &nc->tcache, &nc->rstate.f)){
1423 return -1;
1424 }
1425 if(fbuf_flush(&nc->rstate.f, nc->ttyfp)){
1426 return -1;
1427 }
1428 if(nc->lfdimx == 0 || nc->lfdimy == 0){
1429 return 0;
1430 }
1431 ncpile p = {0};
1432 p.dimy = nc->lfdimy;
1433 p.dimx = nc->lfdimx;
1434 const int count = p.dimy * p.dimx;
1435 p.crender = malloc(count * sizeof(*p.crender));
1436 if(p.crender == NULL){
1437 return -1;
1438 }
1439 init_rvec(p.crender, count);
1440 for(int i = 0 ; i < count ; ++i){
1441 p.crender[i].s.damaged = 1;
1442 }
1443 int ret = notcurses_rasterize(nc, &p, &nc->rstate.f);
1444 free(p.crender);
1445 if(ret < 0){
1446 return -1;
1447 }
1448 ++nc->stats.s.refreshes;
1449 return 0;
1450}
int clear_and_home(notcurses *nc, tinfo *ti, fbuf *f)
Definition render.c:1399
uint64_t refreshes
Definition notcurses.h:1807
Here is the call graph for this function:
Here is the caller graph for this function:

◆ term_fg_rgb8()

int term_fg_rgb8 ( const tinfo ti,
fbuf f,
unsigned  r,
unsigned  g,
unsigned  b 
)

Definition at line 743 of file render.c.

743 {
744 // We typically want to use tputs() and tiperm() to acquire and write the
745 // escapes, as these take into account terminal-specific delays, padding,
746 // etc. For the case of DirectColor, there is no suitable terminfo entry, but
747 // we're also in that case working with hopefully more robust terminals.
748 // If it doesn't work, eh, it doesn't work. Fuck the world; save yourself.
749 if(ti->caps.rgb){
750 return term_esc_rgb(f, true, r, g, b);
751 }else{
752 const char* setaf = get_escape(ti, ESCAPE_SETAF);
753 if(setaf){
754 // For 256-color indexed mode, start constructing a palette based off
755 // the inputs *if we can change the palette*. If more than 256 are used on
756 // a single screen, start... combining close ones? For 8-color mode, simple
757 // interpolation. I have no idea what to do for 88 colors. FIXME
758 if(ti->caps.colors >= 256){
759 return fbuf_emit(f, tiparm(setaf, rgb_quantize_256(r, g, b)));
760 }else if(ti->caps.colors >= 8){
761 return fbuf_emit(f, tiparm(setaf, rgb_quantize_8(r, g, b)));
762 }
763 }
764 }
765 return 0;
766}
int r
Definition fbuf.h:226
unsigned colors
Definition notcurses.h:1637
nccapabilities caps
Definition termdesc.h:111
@ ESCAPE_SETAF
Definition termdesc.h:48
Here is the caller graph for this function:

Variable Documentation

◆ sigcont_seen_for_render

sig_atomic_t sigcont_seen_for_render = 0

Definition at line 7 of file render.c.