mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
* README/CMake: only require doctest 2.3.5 * man pages: remove talk of locking #290 * Remove locking from notcurses core #290 * Purge locking from notcurses core #290
This commit is contained in:
parent
887d4f1f79
commit
e5d6685c92
@ -32,7 +32,7 @@ pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0)
|
||||
pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0)
|
||||
endif()
|
||||
find_library(LIBRT rt)
|
||||
find_package(doctest 2.3.6 REQUIRED)
|
||||
find_package(doctest 2.3.5 REQUIRED)
|
||||
|
||||
# libnotcurses
|
||||
file(GLOB NCSRCS CONFIGURE_DEPENDS src/lib/*.c)
|
||||
|
13
README.md
13
README.md
@ -113,7 +113,7 @@ that fine library.
|
||||
* (build) CMake 3.14.0+
|
||||
* (build+runtime) From NCURSES: terminfo 6.1+
|
||||
* (OPTIONAL) (build+runtime) From FFMpeg: libswscale 5.0+, libavformat 57.0+, libavutil 56.0+
|
||||
* (OPTIONAL) (testing) [Doctest](https://github.com/onqtam/doctest) 2.3.6+
|
||||
* (OPTIONAL) (testing) [Doctest](https://github.com/onqtam/doctest) 2.3.5+
|
||||
* (OPTIONAL) (documentation) [pandoc](https://pandoc.org/index.html) 1.19.2+
|
||||
* (OPTIONAL) (python bindings): Python 3.7+, CFFI 1.13.2+
|
||||
* (OPTIONAL) (rust bindings, colloquy): rust 1.40.0+, cargo 0.40.0+, cmake-rs 0.1.42+
|
||||
@ -292,7 +292,8 @@ int notcurses_resize(struct notcurses* n, int* RESTRICT y, int* RESTRICT x);
|
||||
|
||||
// Return our current idea of the terminal dimensions in rows and cols.
|
||||
static inline void
|
||||
notcurses_term_dim_yx(struct notcurses* n, int* RESTRICT rows, int* RESTRICT cols){
|
||||
notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols){
|
||||
ncplane_dim_yx(notcurses_stdplane(n), rows, cols);
|
||||
}
|
||||
|
||||
@ -396,7 +397,7 @@ typedef enum {
|
||||
// according to 'align' within ncplane 'n'. Returns INT_MAX on invalid 'align'.
|
||||
// Undefined behavior on negative 'c'.
|
||||
static inline int
|
||||
ncplane_align(struct ncplane* n, ncalign_e align, int c){
|
||||
ncplane_align(const struct ncplane* n, ncalign_e align, int c){
|
||||
if(align == NCALIGN_LEFT){
|
||||
return 0;
|
||||
}
|
||||
@ -672,14 +673,14 @@ void ncplane_yx(struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
|
||||
void ncplane_dim_yx(struct ncplane* n, int* RESTRICT rows, int* RESTRICT cols);
|
||||
|
||||
static inline int
|
||||
ncplane_dim_y(struct ncplane* n){
|
||||
ncplane_dim_y(const struct ncplane* n){
|
||||
int dimy;
|
||||
ncplane_dim_yx(n, &dimy, NULL);
|
||||
return dimy;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ncplane_dim_x(struct ncplane* n){
|
||||
ncplane_dim_x(const struct ncplane* n){
|
||||
int dimx;
|
||||
ncplane_dim_yx(n, NULL, &dimx);
|
||||
return dimx;
|
||||
@ -705,7 +706,7 @@ void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
|
||||
void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Return the current styling for this ncplane.
|
||||
unsigned ncplane_styles(struct ncplane* n);
|
||||
unsigned ncplane_styles(const struct ncplane* n);
|
||||
|
||||
// Set the ncplane's base cell to this cell. It will be used for purposes of
|
||||
// rendering anywhere that the ncplane's gcluster is 0. Erasing the ncplane
|
||||
|
@ -13,4 +13,6 @@ LICENSE=Apache-2.0
|
||||
USE_GITHUB=yes
|
||||
GH_ACCOUNT=dankamongmen
|
||||
|
||||
# deps: doxygen, dia, doctest (not present?), ffmpeg
|
||||
|
||||
.include <bsd.port.mk>
|
||||
|
@ -102,13 +102,17 @@ A few high-level widgets are included, all built atop ncplanes:
|
||||
|
||||
## Threads
|
||||
|
||||
Notcurses explicitly supports use in multithreaded environments. Most functions
|
||||
are safe to call concurrently, with exceptions including those which destroy
|
||||
resources (**ncplane_destroy(3)**, **ncvisual_destroy(3)**, **notcurses_stop(3)**,
|
||||
etc.). Multiple threads interacting with the same ncplane will block one another,
|
||||
but threads operating on distinct ncplanes can run concurrently.
|
||||
**notcurses_render(3)** blocks the majority of functions. Input functions only
|
||||
block other input functions, not ncplane manipulation.
|
||||
Notcurses explicitly supports use in multithreaded environments, but it does
|
||||
not itself perform any locking. It is safe to output to multiple distinct
|
||||
ncplanes at the same time. It is safe to output to ncplanes while adding or
|
||||
deleting some other ncplane. It is **not** safe for multiple threads to output to
|
||||
the same ncplane. It is **not** safe to add, delete, or reorder ncplanes
|
||||
from multiple threads, and it is never safe to invoke **notcurses_render**
|
||||
while any other thread is touching that notcurses object (aside from input
|
||||
functions; read on).
|
||||
|
||||
Only one thread may call **notcurses_getc** or any other input-related thread
|
||||
at a time, but it **is** safe to call for input while another thread renders.
|
||||
|
||||
Since multiple threads can concurrently manipulate distinct ncplanes, peak
|
||||
performance sometimes requires dividing the screen into several planes, and
|
||||
|
@ -112,6 +112,10 @@ Like any other notcurses function, it is an error to call **notcurses_getc(3)**
|
||||
during or after a call to **notcurses_stop(3)**. If a thread is always sitting
|
||||
on blocking input, it can be tricky to guarantee that this doesn't happen.
|
||||
|
||||
Only one thread may call into the input stack at once, but unlike almost every
|
||||
other function in notcurses, **notcurses_getc** and friends can be called
|
||||
concurrently with **notcurses_render**.
|
||||
|
||||
# BUGS
|
||||
|
||||
Failed escape sequences are not yet played back in their entirety; only an
|
||||
@ -134,6 +138,7 @@ registers as **NCKEY_ENTER**. This will likely change in the future.
|
||||
**poll(2)**,
|
||||
**cfmakeraw(3)**,
|
||||
**notcurses(3)**,
|
||||
**notcurses_render(3)**,
|
||||
**notcurses_resize(3)**,
|
||||
**termios(3)**,
|
||||
**terminfo(5)**,
|
||||
|
@ -48,11 +48,11 @@ notcurses_ncplane - operations on notcurses planes
|
||||
|
||||
**void* ncplane_userptr(struct ncplane* n);**
|
||||
|
||||
**void ncplane_dim_yx(struct ncplane* n, int* restrict rows, int* restrict cols);**
|
||||
**void ncplane_dim_yx(const struct ncplane* n, int* restrict rows, int* restrict cols);**
|
||||
|
||||
**static inline int ncplane_dim_y(struct ncplane* n);**
|
||||
**static inline int ncplane_dim_y(const struct ncplane* n);**
|
||||
|
||||
**static inline int ncplane_dim_x(struct ncplane* n);**
|
||||
**static inline int ncplane_dim_x(const struct ncplane* n);**
|
||||
|
||||
**int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);**
|
||||
|
||||
@ -108,7 +108,7 @@ notcurses_ncplane - operations on notcurses planes
|
||||
|
||||
**void ncplane_styles_off(struct ncplane* n, unsigned stylebits);**
|
||||
|
||||
**unsigned ncplane_styles(struct ncplane* n);**
|
||||
**unsigned ncplane_styles(const struct ncplane* n);**
|
||||
|
||||
**void ncplane_greyscale(struct ncplane* n);**
|
||||
|
||||
@ -137,6 +137,10 @@ anywhere. In addition to its framebuffer--a rectilinear matrix of cells
|
||||
**notcurses_drop_planes** destroys all ncplanes other than the stdplane. Any
|
||||
references to such planes are, of course, invalidated.
|
||||
|
||||
It is an error for two threads to concurrently access a single ncplane. So long
|
||||
as rendering is not taking place, however, multiple threads may safely output
|
||||
to multiple ncplanes.
|
||||
|
||||
# RETURN VALUES
|
||||
|
||||
**ncplane_new(3)**, **ncplane_aligned(3)**, and **ncplane_dup(3)** all return a
|
||||
@ -154,9 +158,6 @@ All other functions cannot fail (and return **void**).
|
||||
|
||||
# NOTES
|
||||
|
||||
It would be reasonable to expect many of these functions to accept `const struct notcurses`
|
||||
parameters. Alas, almost all must manipulate the mutex contained within the object.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
**notcurses(3)**, **notcurses_cell(3)**, **notcurses_output(3)**,
|
||||
|
@ -23,17 +23,20 @@ ncplanes. Most of the notcurses statistics are updated as a result of a
|
||||
render (see notcurses_stats(3)), and **notcurses_resize(3)** is called
|
||||
internally *following* the render.
|
||||
|
||||
While **notcurses_render** is called, you **must not call any other functions
|
||||
on the same notcurses context**, with the one exception of **notcurses_getc**
|
||||
(and its input-related helpers).
|
||||
|
||||
A render operation consists of two logical phases: generation of the rendered
|
||||
scene, and blitting this scene to the terminal (these two phases might actually
|
||||
be interleaved, streaming the output as it is rendered). All ncplanes are
|
||||
locked while generating the frame. Frame generation requires determining an
|
||||
extended grapheme cluster, foreground color, background color, and style for
|
||||
each cell of the physical terminal. Writing the scene requires synthesizing
|
||||
a set of UTF-8-encoded characters and escape codes appropriate for the terminal
|
||||
(relying on terminfo(5)), and writing this sequence to the output **FILE**. If
|
||||
the **renderfp** value was not NULL in the original call to notcurses_init(3),
|
||||
the frame will be written to that **FILE** as well. This write does not affect
|
||||
statistics.
|
||||
be interleaved, streaming the output as it is rendered). Frame generation
|
||||
requires determining an extended grapheme cluster, foreground color, background
|
||||
color, and style for each cell of the physical terminal. Writing the scene
|
||||
requires synthesizing a set of UTF-8-encoded characters and escape codes
|
||||
appropriate for the terminal (relying on terminfo(5)), and writing this
|
||||
sequence to the output **FILE**. If the **renderfp** value was not NULL in the
|
||||
original call to notcurses_init(3), the frame will be written to that **FILE**
|
||||
as well. This write does not affect statistics.
|
||||
|
||||
Each cell can be rendered in isolation, though synthesis of the stream carries
|
||||
dependencies between cells.
|
||||
|
@ -416,23 +416,24 @@ typedef struct ncstats {
|
||||
} ncstats;
|
||||
|
||||
// Acquire an atomic snapshot of the notcurses object's stats.
|
||||
API void notcurses_stats(struct notcurses* nc, ncstats* stats);
|
||||
API void notcurses_stats(const struct notcurses* nc, ncstats* stats);
|
||||
|
||||
// Reset all cumulative stats (immediate ones, such as fbbytes, are not reset).
|
||||
API void notcurses_reset_stats(struct notcurses* nc, ncstats* stats);
|
||||
|
||||
// Return the dimensions of this ncplane.
|
||||
API void ncplane_dim_yx(struct ncplane* n, int* RESTRICT rows, int* RESTRICT cols);
|
||||
API void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols);
|
||||
|
||||
static inline int
|
||||
ncplane_dim_y(struct ncplane* n){
|
||||
ncplane_dim_y(const struct ncplane* n){
|
||||
int dimy;
|
||||
ncplane_dim_yx(n, &dimy, NULL);
|
||||
return dimy;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ncplane_dim_x(struct ncplane* n){
|
||||
ncplane_dim_x(const struct ncplane* n){
|
||||
int dimx;
|
||||
ncplane_dim_yx(n, NULL, &dimx);
|
||||
return dimx;
|
||||
@ -550,7 +551,7 @@ API void* ncplane_userptr(struct ncplane* n);
|
||||
// according to 'align' within ncplane 'n'. Returns INT_MAX on invalid 'align'.
|
||||
// Undefined behavior on negative 'c'.
|
||||
static inline int
|
||||
ncplane_align(struct ncplane* n, ncalign_e align, int c){
|
||||
ncplane_align(const struct ncplane* n, ncalign_e align, int c){
|
||||
if(align == NCALIGN_LEFT){
|
||||
return 0;
|
||||
}
|
||||
@ -907,7 +908,7 @@ channel_b(unsigned channel){
|
||||
// Extract the three 8-bit R/G/B components from a 32-bit channel.
|
||||
static inline unsigned
|
||||
channel_rgb(unsigned channel, unsigned* RESTRICT r, unsigned* RESTRICT g,
|
||||
unsigned* RESTRICT b){
|
||||
unsigned* RESTRICT b){
|
||||
*r = channel_r(channel);
|
||||
*g = channel_g(channel);
|
||||
*b = channel_b(channel);
|
||||
@ -1495,7 +1496,7 @@ API void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
|
||||
API void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Return the current styling for this ncplane.
|
||||
API unsigned ncplane_styles(struct ncplane* n);
|
||||
API unsigned ncplane_styles(const struct ncplane* n);
|
||||
|
||||
// Called for each delta performed in a fade on ncp. If anything but 0 is returned,
|
||||
// the fading operation ceases immediately, and that value is propagated out. If provided
|
||||
|
@ -109,7 +109,7 @@ int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);
|
||||
void ncplane_cursor_yx(struct ncplane* n, int* y, int* x);
|
||||
int ncplane_move_yx(struct ncplane* n, int y, int x);
|
||||
void ncplane_yx(struct ncplane* n, int* y, int* x);
|
||||
void ncplane_dim_yx(struct ncplane* n, int* rows, int* cols);
|
||||
void ncplane_dim_yx(const struct ncplane* n, int* rows, int* cols);
|
||||
int ncplane_putc_yx(struct ncplane* n, int y, int x, const cell* c);
|
||||
int ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c);
|
||||
int ncplane_move_top(struct ncplane* n);
|
||||
@ -149,7 +149,7 @@ int ncplane_set_bg_palindex(struct ncplane* n, int idx);
|
||||
void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
|
||||
void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
|
||||
void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
|
||||
unsigned ncplane_styles(struct ncplane* n);
|
||||
unsigned ncplane_styles(const struct ncplane* n);
|
||||
typedef struct ncstats {
|
||||
uint64_t renders; // number of successful notcurses_render() runs
|
||||
uint64_t failed_renders; // number of aborted renders, should be 0
|
||||
|
@ -13,12 +13,10 @@ typedef struct planepalette {
|
||||
// the maxima across each of the six components.
|
||||
static int
|
||||
alloc_ncplane_palette(ncplane* n, planepalette* pp){
|
||||
ncplane_lock(n);
|
||||
ncplane_dim_yx(n, &pp->rows, &pp->cols);
|
||||
// add an additional element for the background cell
|
||||
int size = pp->rows * pp->cols + 1;
|
||||
if((pp->channels = malloc(sizeof(*pp->channels) * size)) == NULL){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
pp->maxr = pp->maxg = pp->maxb = 0;
|
||||
@ -75,7 +73,6 @@ alloc_ncplane_palette(ncplane* n, planepalette* pp){
|
||||
if(bb > pp->maxbb){
|
||||
pp->maxbb = bb;
|
||||
}
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,6 @@ typedef struct ncdirect {
|
||||
} ncdirect;
|
||||
|
||||
typedef struct notcurses {
|
||||
pthread_mutex_t lock;
|
||||
ncplane* top; // the contents of our topmost plane (initially entire screen)
|
||||
ncplane* stdscr;// aliases some plane from the z-buffer, covers screen
|
||||
|
||||
@ -318,16 +317,6 @@ void input_free_esctrie(struct esctrie** trie);
|
||||
// initialize libav
|
||||
int ncvisual_init(int loglevel);
|
||||
|
||||
static inline void
|
||||
ncplane_lock(const ncplane* n){
|
||||
pthread_mutex_lock(&n->nc->lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ncplane_unlock(const ncplane* n){
|
||||
pthread_mutex_unlock(&n->nc->lock);
|
||||
}
|
||||
|
||||
static inline int
|
||||
fbcellidx(int row, int rowlen, int col){
|
||||
return row * rowlen + col;
|
||||
|
@ -191,8 +191,7 @@ int ncplane_at_cursor(ncplane* n, cell* c){
|
||||
return cell_duplicate(n, c, &n->fb[nfbcellidx(n, n->y, n->x)]);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ncplane_at_yx_locked(ncplane* n, int y, int x, cell* c){
|
||||
int ncplane_at_yx(ncplane* n, int y, int x, cell* c){
|
||||
int ret = -1;
|
||||
if(y < n->leny && x < n->lenx){
|
||||
if(y >= 0 && x >= 0){
|
||||
@ -202,19 +201,11 @@ ncplane_at_yx_locked(ncplane* n, int y, int x, cell* c){
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ncplane_at_yx(ncplane* n, int y, int x, cell* c){
|
||||
int ret = -1;
|
||||
pthread_mutex_lock(&n->nc->lock);
|
||||
ret = ncplane_at_yx_locked(n, y, x, c);
|
||||
pthread_mutex_unlock(&n->nc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cell* ncplane_cell_ref_yx(ncplane* n, int y, int x){
|
||||
return &n->fb[nfbcellidx(n, y, x)];
|
||||
}
|
||||
|
||||
void ncplane_dim_yx(ncplane* n, int* rows, int* cols){
|
||||
void ncplane_dim_yx(const ncplane* n, int* rows, int* cols){
|
||||
if(rows){
|
||||
*rows = n->leny;
|
||||
}
|
||||
@ -263,10 +254,8 @@ term_verify_seq(char** gseq, const char* name){
|
||||
static void
|
||||
free_plane(ncplane* p){
|
||||
if(p){
|
||||
ncplane_lock(p);
|
||||
--p->nc->stats.planes;
|
||||
p->nc->stats.fbbytes -= sizeof(*p->fb) * p->leny * p->lenx;
|
||||
ncplane_unlock(p);
|
||||
egcpool_dump(&p->pool);
|
||||
free(p->fb);
|
||||
free(p);
|
||||
@ -300,13 +289,11 @@ ncplane_create(notcurses* nc, int rows, int cols, int yoff, int xoff){
|
||||
p->channels = 0;
|
||||
egcpool_init(&p->pool);
|
||||
cell_init(&p->basecell);
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
p->z = nc->top;
|
||||
nc->top = p;
|
||||
p->nc = nc;
|
||||
nc->stats.fbbytes += fbsize;
|
||||
++nc->stats.planes;
|
||||
pthread_mutex_unlock(&nc->lock);
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -741,17 +728,13 @@ stash_stats(notcurses* nc){
|
||||
reset_stats(&nc->stats);
|
||||
}
|
||||
|
||||
void notcurses_stats(notcurses* nc, ncstats* stats){
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
void notcurses_stats(const notcurses* nc, ncstats* stats){
|
||||
memcpy(stats, &nc->stats, sizeof(*stats));
|
||||
pthread_mutex_unlock(&nc->lock);
|
||||
}
|
||||
|
||||
void notcurses_reset_stats(notcurses* nc, ncstats* stats){
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
memcpy(stats, &nc->stats, sizeof(*stats));
|
||||
stash_stats(nc);
|
||||
pthread_mutex_unlock(&nc->lock);
|
||||
}
|
||||
|
||||
// Convert a notcurses log level to its ffmpeg equivalent.
|
||||
@ -847,10 +830,6 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
|
||||
if(ret == NULL){
|
||||
return ret;
|
||||
}
|
||||
if(pthread_mutex_init(&ret->lock, NULL)){
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->stats.fbbytes = 0;
|
||||
ret->stashstats.fbbytes = 0;
|
||||
reset_stats(&ret->stats);
|
||||
@ -973,8 +952,8 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
|
||||
return ret;
|
||||
|
||||
err:
|
||||
// FIXME looks like we have some memory leaks on this error path?
|
||||
tcsetattr(ret->ttyfd, TCSANOW, &ret->tpreserved);
|
||||
pthread_mutex_destroy(&ret->lock);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
@ -1033,7 +1012,6 @@ int notcurses_stop(notcurses* nc){
|
||||
free(nc->lastframe);
|
||||
free(nc->rstate.mstream);
|
||||
input_free_esctrie(&nc->inputescapes);
|
||||
ret |= pthread_mutex_destroy(&nc->lock);
|
||||
stash_stats(nc);
|
||||
if(!nc->suppress_banner){
|
||||
double avg = 0;
|
||||
@ -1098,21 +1076,15 @@ uint32_t ncplane_attr(const ncplane* n){
|
||||
}
|
||||
|
||||
void ncplane_set_fg_default(struct ncplane* n){
|
||||
ncplane_lock(n);
|
||||
channels_set_fg_default(&n->channels);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
void ncplane_set_bg_default(struct ncplane* n){
|
||||
ncplane_lock(n);
|
||||
channels_set_bg_default(&n->channels);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
void ncplane_set_bg_rgb_clipped(ncplane* n, int r, int g, int b){
|
||||
ncplane_lock(n);
|
||||
channels_set_bg_rgb_clipped(&n->channels, r, g, b);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
int ncplane_set_bg_rgb(ncplane* n, int r, int g, int b){
|
||||
@ -1120,9 +1092,7 @@ int ncplane_set_bg_rgb(ncplane* n, int r, int g, int b){
|
||||
}
|
||||
|
||||
void ncplane_set_fg_rgb_clipped(ncplane* n, int r, int g, int b){
|
||||
ncplane_lock(n);
|
||||
channels_set_fg_rgb_clipped(&n->channels, r, g, b);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
int ncplane_set_fg_rgb(ncplane* n, int r, int g, int b){
|
||||
@ -1130,48 +1100,30 @@ int ncplane_set_fg_rgb(ncplane* n, int r, int g, int b){
|
||||
}
|
||||
|
||||
int ncplane_set_fg(ncplane* n, unsigned channel){
|
||||
int ret;
|
||||
ncplane_lock(n);
|
||||
ret = channels_set_fg(&n->channels, channel);
|
||||
ncplane_unlock(n);
|
||||
return ret;
|
||||
return channels_set_fg(&n->channels, channel);
|
||||
}
|
||||
|
||||
int ncplane_set_bg(ncplane* n, unsigned channel){
|
||||
int ret;
|
||||
ncplane_lock(n);
|
||||
ret = channels_set_bg(&n->channels, channel);
|
||||
ncplane_unlock(n);
|
||||
return ret;
|
||||
return channels_set_bg(&n->channels, channel);
|
||||
}
|
||||
|
||||
int ncplane_set_fg_alpha(ncplane* n, int alpha){
|
||||
int ret;
|
||||
ncplane_lock(n);
|
||||
ret = channels_set_fg_alpha(&n->channels, alpha);
|
||||
ncplane_unlock(n);
|
||||
return ret;
|
||||
return channels_set_fg_alpha(&n->channels, alpha);
|
||||
}
|
||||
|
||||
int ncplane_set_bg_alpha(ncplane *n, int alpha){
|
||||
int ret;
|
||||
ncplane_lock(n);
|
||||
ret = channels_set_bg_alpha(&n->channels, alpha);
|
||||
ncplane_unlock(n);
|
||||
return ret;
|
||||
return channels_set_bg_alpha(&n->channels, alpha);
|
||||
}
|
||||
|
||||
int ncplane_set_fg_palindex(ncplane* n, int idx){
|
||||
if(idx < 0 || idx >= NCPALETTESIZE){
|
||||
return -1;
|
||||
}
|
||||
ncplane_lock(n);
|
||||
n->channels |= CELL_FGDEFAULT_MASK;
|
||||
n->channels |= CELL_FG_PALETTE;
|
||||
n->channels &= ~(CELL_ALPHA_MASK << 32u);
|
||||
n->attrword &= 0xffff00ff;
|
||||
n->attrword |= (idx << 8u);
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1179,40 +1131,24 @@ int ncplane_set_bg_palindex(ncplane* n, int idx){
|
||||
if(idx < 0 || idx >= NCPALETTESIZE){
|
||||
return -1;
|
||||
}
|
||||
ncplane_lock(n);
|
||||
n->channels |= CELL_BGDEFAULT_MASK;
|
||||
n->channels |= CELL_BG_PALETTE;
|
||||
n->channels &= ~CELL_ALPHA_MASK;
|
||||
n->attrword &= 0xffffff00;
|
||||
n->attrword |= idx;
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncplane_set_base_cell(ncplane* ncp, const cell* c){
|
||||
ncplane_lock(ncp);
|
||||
int ret = cell_duplicate(ncp, &ncp->basecell, c);
|
||||
ncplane_unlock(ncp);
|
||||
if(ret < 0){
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
return cell_duplicate(ncp, &ncp->basecell, c);
|
||||
}
|
||||
|
||||
int ncplane_set_base(ncplane* ncp, uint64_t channels, uint32_t attrword, const char* egc){
|
||||
int ret;
|
||||
ncplane_lock(ncp);
|
||||
ret = cell_prime(ncp, &ncp->basecell, egc, attrword, channels);
|
||||
ncplane_unlock(ncp);
|
||||
return ret;
|
||||
return cell_prime(ncp, &ncp->basecell, egc, attrword, channels);
|
||||
}
|
||||
|
||||
int ncplane_base(ncplane* ncp, cell* c){
|
||||
int ret;
|
||||
ncplane_lock(ncp);
|
||||
ret = cell_duplicate(ncp, c, &ncp->basecell);
|
||||
ncplane_unlock(ncp);
|
||||
return ret;
|
||||
return cell_duplicate(ncp, c, &ncp->basecell);
|
||||
}
|
||||
|
||||
const char* cell_extended_gcluster(const struct ncplane* n, const cell* c){
|
||||
@ -1232,66 +1168,52 @@ advance_cursor(ncplane* n, int cols){
|
||||
|
||||
// 'n' ends up above 'above'
|
||||
int ncplane_move_above_unsafe(ncplane* restrict n, ncplane* restrict above){
|
||||
ncplane_lock(n);
|
||||
if(n->z == above){
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
ncplane** aa = find_above_ncplane(above);
|
||||
if(aa == NULL){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
n->z = above; // attach above below n
|
||||
*aa = n; // spline n in above
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 'n' ends up below 'below'
|
||||
int ncplane_move_below_unsafe(ncplane* restrict n, ncplane* restrict below){
|
||||
ncplane_lock(n);
|
||||
if(below->z == n){
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
n->z = below->z; // reattach subbelow list to n
|
||||
below->z = n; // splice n in below
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncplane_move_top(ncplane* n){
|
||||
ncplane_lock(n);
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
n->z = n->nc->top;
|
||||
n->nc->top = n;
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncplane_move_bottom(ncplane* n){
|
||||
ncplane_lock(n);
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
@ -1301,15 +1223,11 @@ int ncplane_move_bottom(ncplane* n){
|
||||
}
|
||||
*an = n;
|
||||
n->z = NULL;
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncplane_cursor_move_yx(ncplane* n, int y, int x){
|
||||
ncplane_lock(n);
|
||||
int ret = ncplane_cursor_move_yx_locked(n, y, x);
|
||||
ncplane_unlock(n);
|
||||
return ret;
|
||||
return ncplane_cursor_move_yx_locked(n, y, x);
|
||||
}
|
||||
|
||||
void ncplane_cursor_yx(ncplane* n, int* y, int* x){
|
||||
@ -1333,14 +1251,11 @@ cell_obliterate(ncplane* n, cell* c){
|
||||
}
|
||||
|
||||
int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
|
||||
ncplane_lock(n);
|
||||
if(ncplane_cursor_move_yx_locked(n, y, x)){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
bool wide = cell_double_wide_p(c);
|
||||
if(wide && (n->x + 1 == n->lenx)){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
// A wide character obliterates anything to its immediate right (and marks
|
||||
@ -1358,7 +1273,6 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
|
||||
}
|
||||
}
|
||||
if(cell_duplicate(n, targ, c) < 0){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
int cols = 1;
|
||||
@ -1382,7 +1296,6 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
|
||||
}
|
||||
}
|
||||
advance_cursor(n, cols);
|
||||
ncplane_unlock(n);
|
||||
return cols;
|
||||
}
|
||||
|
||||
@ -1492,31 +1405,21 @@ int notcurses_palette_size(const notcurses* nc){
|
||||
|
||||
// turn on any specified stylebits
|
||||
void ncplane_styles_on(ncplane* n, unsigned stylebits){
|
||||
ncplane_lock(n);
|
||||
n->attrword |= (stylebits & NCSTYLE_MASK);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
// turn off any specified stylebits
|
||||
void ncplane_styles_off(ncplane* n, unsigned stylebits){
|
||||
ncplane_lock(n);
|
||||
n->attrword &= ~(stylebits & NCSTYLE_MASK);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
// set the current stylebits to exactly those provided
|
||||
void ncplane_styles_set(ncplane* n, unsigned stylebits){
|
||||
ncplane_lock(n);
|
||||
n->attrword = (n->attrword & ~NCSTYLE_MASK) | ((stylebits & NCSTYLE_MASK));
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
unsigned ncplane_styles(ncplane* n){
|
||||
unsigned ret;
|
||||
ncplane_lock(n);
|
||||
ret = (n->attrword & NCSTYLE_MASK);
|
||||
ncplane_unlock(n);
|
||||
return ret;
|
||||
unsigned ncplane_styles(const ncplane* n){
|
||||
return (n->attrword & NCSTYLE_MASK);
|
||||
}
|
||||
|
||||
// i hate the big allocation and two copies here, but eh what you gonna do?
|
||||
@ -1807,30 +1710,24 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
|
||||
}
|
||||
|
||||
int ncplane_move_yx(ncplane* n, int y, int x){
|
||||
ncplane_lock(n);
|
||||
if(n == n->nc->stdscr){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
n->absy = y;
|
||||
n->absx = x;
|
||||
ncplane_unlock(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ncplane_yx(const ncplane* n, int* y, int* x){
|
||||
ncplane_lock(n);
|
||||
if(y){
|
||||
*y = n->absy;
|
||||
}
|
||||
if(x){
|
||||
*x = n->absx;
|
||||
}
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
void ncplane_erase(ncplane* n){
|
||||
ncplane_lock(n);
|
||||
// we must preserve the background, but a pure cell_duplicate() would be
|
||||
// wiped out by the egcpool_dump(). do a duplication (to get the attrword
|
||||
// and channels), and then reload.
|
||||
@ -1840,7 +1737,6 @@ void ncplane_erase(ncplane* n){
|
||||
egcpool_init(&n->pool);
|
||||
cell_load(n, &n->basecell, egc);
|
||||
free(egc);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
void notcurses_cursor_enable(notcurses* nc){
|
||||
@ -1891,11 +1787,9 @@ bool notcurses_canchangecolor(const notcurses* nc){
|
||||
|
||||
palette256* palette256_new(notcurses* nc){
|
||||
palette256* p = malloc(sizeof(*p));
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
if(p){
|
||||
memcpy(p, &nc->palette, sizeof(*p));
|
||||
}
|
||||
pthread_mutex_unlock(&nc->lock);
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -1904,7 +1798,6 @@ int palette256_use(notcurses* nc, const palette256* p){
|
||||
if(!nc->CCCflag){
|
||||
return -1;
|
||||
}
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
for(size_t z = 0 ; z < sizeof(p->chans) / sizeof(*p->chans) ; ++z){
|
||||
if(nc->palette.chans[z] != p->chans[z]){
|
||||
nc->palette.chans[z] = p->chans[z];
|
||||
@ -1912,7 +1805,6 @@ int palette256_use(notcurses* nc, const palette256* p){
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
pthread_mutex_unlock(&nc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1940,7 +1832,6 @@ rgb_greyscale(int r, int g, int b){
|
||||
}
|
||||
|
||||
void ncplane_greyscale(ncplane *n){
|
||||
ncplane_lock(n);
|
||||
for(int y = 0 ; y < n->leny ; ++y){
|
||||
for(int x = 0 ; x < n->lenx ; ++x){
|
||||
cell* c = &n->fb[nfbcellidx(n, y, x)];
|
||||
@ -1953,7 +1844,6 @@ void ncplane_greyscale(ncplane *n){
|
||||
cell_set_bg_rgb(c, gy, gy, gy);
|
||||
}
|
||||
}
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
|
||||
// if this is not polyfillable cell, we return 0. if it is, we attempt to fill
|
||||
@ -1998,13 +1888,11 @@ ncplane_polyfill_locked(ncplane* n, int y, int x, const cell* c){
|
||||
// at the initial step only, invalid y, x is an error, so explicitly check.
|
||||
int ncplane_polyfill_yx(ncplane* n, int y, int x, const cell* c){
|
||||
int ret = -1;
|
||||
ncplane_lock(n);
|
||||
if(y < n->leny && x < n->lenx){
|
||||
if(y >= 0 && x >= 0){
|
||||
ret = ncplane_polyfill_locked(n, y, x, c);
|
||||
}
|
||||
}
|
||||
ncplane_unlock(n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,6 @@
|
||||
#include <sys/poll.h>
|
||||
#include "internal.h"
|
||||
|
||||
static void
|
||||
mutex_unlock(void* vlock){
|
||||
pthread_mutex_unlock(vlock);
|
||||
}
|
||||
|
||||
static int
|
||||
blocking_write(int fd, const char* buf, size_t buflen){
|
||||
//fprintf(stderr, "writing %zu to %d...\n", buflen, fd);
|
||||
@ -36,8 +31,6 @@ blocking_write(int fd, const char* buf, size_t buflen){
|
||||
|
||||
int notcurses_refresh(notcurses* nc){
|
||||
int ret;
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
pthread_cleanup_push(mutex_unlock, &nc->lock);
|
||||
if(nc->rstate.mstream == NULL){
|
||||
ret = -1; // haven't rendered yet, and thus don't know what should be there
|
||||
}else if(blocking_write(nc->ttyfd, nc->rstate.mstream, nc->rstate.mstrsize)){
|
||||
@ -45,7 +38,6 @@ int notcurses_refresh(notcurses* nc){
|
||||
}else{
|
||||
ret = 0;
|
||||
}
|
||||
pthread_cleanup_pop(1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -962,8 +954,6 @@ int notcurses_render(notcurses* nc){
|
||||
struct timespec start, done;
|
||||
int ret;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
pthread_cleanup_push(mutex_unlock, &nc->lock);
|
||||
int bytes = -1;
|
||||
size_t crenderlen = sizeof(struct crender) * nc->stdscr->leny * nc->stdscr->lenx;
|
||||
struct crender* crender = malloc(crenderlen);
|
||||
@ -977,13 +967,11 @@ int notcurses_render(notcurses* nc){
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &done);
|
||||
update_render_stats(&done, &start, &nc->stats, bytes);
|
||||
ret = bytes >= 0 ? 0 : -1;
|
||||
pthread_cleanup_pop(1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* notcurses_at_yx(notcurses* nc, int y, int x, cell* c){
|
||||
char* egc = NULL;
|
||||
pthread_mutex_lock(&nc->lock);
|
||||
if(nc->lastframe){
|
||||
if(y >= 0 && y < nc->lfdimy){
|
||||
if(x >= 0 || x < nc->lfdimx){
|
||||
@ -995,6 +983,5 @@ char* notcurses_at_yx(notcurses* nc, int y, int x, cell* c){
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&nc->lock);
|
||||
return egc;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user