Rust wrapper work (#454)

* packaging: s/libtinfo/Terminfo/g
* rust: add stddim_yx()
* rust: check for valid init in unit tests
* rust: serialize up tests
* constify notcurses_term_dim_yx()
* rust: add dim wrappers
* remove notcurses_resize() from public API #367
* call notcurses_resize() from notcurses_refresh() #367
This commit is contained in:
Nick Black 2020-04-08 05:39:41 -04:00 committed by GitHub
parent e276a36264
commit c2a645e9af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 246 additions and 179 deletions

View File

@ -2,8 +2,8 @@ This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.2.6 (not yet released)
* `ncplane_putsimple_yx()` and `ncplane_putstr_yx()` has been exported as a
static inline function.
* `ncplane_putsimple_yx()` and `ncplane_putstr_yx()` have been exported as
static inline functions.
* `ncplane_set_scrolling()` has been added, allowing control over whether a
plane scrolls. All planes, including the standard plane, do not scroll by
default. If scrolling is enabled, text output via the `*put*` family of
@ -15,6 +15,12 @@ rearrangements of Notcurses.
* `ncplot_add_sample()` and `ncplot_set_sample()` have been changed to accept
a `uint64_t` rather than `int64_t`, since negative samples do not
currently make sense. Plots were made more accurate in general.
* `notcurses_term_dim_yx()` now accepts a `const struct notcurses*`.
* `notcurses_resize()` is no longer exported. It was never necessary to call
this in response to a resize, despite confusing documentation that could
have been read to suggest otherwise. If you're in a long block on input, and
get an `NCKEY_RESIZE`, just call `notcurses_refresh()` (which now calls
`notcurses_resize()` internally, as `notcurses_render()` always has).
* 1.2.5
* Add ncplot, with support for sliding-windowed horizontal histograms.

View File

@ -296,22 +296,18 @@ Utility functions operating on the toplevel `notcurses` object include:
// Return the topmost ncplane, of which there is always at least one.
struct ncplane* notcurses_top(struct notcurses* n);
// Refresh our idea of the terminal's dimensions, reshaping the standard plane
// if necessary, without a fresh render. References to ncplanes (and the
// egcpools underlying cells) remain valid following a resize operation.
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(const struct notcurses* n, int* restrict rows,
int* restrict cols){
ncplane_dim_yx(notcurses_stdplane(n), rows, cols);
ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
}
// Refresh the physical screen to match what was last rendered (i.e., without
// reflecting any changes since the last call to notcurses_render()). This is
// primarily useful if the screen is externally corrupted.
int notcurses_refresh(struct notcurses* n);
// primarily useful if the screen is externally corrupted, or if an
// NCKEY_RESIZE event has been read and you're not ready to render.
int notcurses_refresh(struct notcurses* n, int* restrict y, int* restrict x);
// Returns a 16-bit bitmask in the LSBs of supported curses-style attributes
// (NCSTYLE_UNDERLINE, NCSTYLE_BOLD, etc.) The attribute is only

10
debian/control vendored
View File

@ -40,7 +40,7 @@ Depends:
Description: Character graphics and TUI library (C++ development)
notcurses facilitates the creation of modern TUI programs,
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
an API similar to that of Curses, and rides atop Terminfo.
.
These files are necessary for C++ development using notcurses.
@ -52,7 +52,7 @@ Depends: ${misc:Depends}, ${shlibs:Depends}
Description: Character graphics and TUI library (C++ wrappers)
notcurses facilitates the creation of modern TUI programs,
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
an API similar to that of Curses, and rides atop Terminfo.
.
These files underlie the C++ wrappers for notcurses.
@ -101,7 +101,7 @@ Depends:
Description: Character graphics and TUI library demos
notcurses facilitates the creation of modern TUI programs,
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
an API similar to that of Curses, and rides atop Terminfo.
.
These utilities from the notcurses project include notcurses-demo
(a demonstration of various libnotcurses capabilities) and
@ -117,7 +117,7 @@ Depends: ncurses-term, ${misc:Depends}
Description: Multimedia used by notcurses-bin
notcurses facilitates the creation of modern TUI programs,
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
an API similar to that of Curses, and rides atop Terminfo.
.
This package contains multimedia used by notcurses-demo
and notcurses-tester from the notcurses-bin package.
@ -131,6 +131,6 @@ Provides: ${python3:Provides}
Description: Character graphics and TUI library (Python)
notcurses facilitates the creation of modern TUI programs,
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
an API similar to that of Curses, and rides atop Terminfo.
.
These files are necessary for Python development using notcurses.

View File

@ -41,8 +41,8 @@
<a href="notcurses_output.3.html">notcurses_output</a>—drawing text on <tt>ncplane</tt>s<br/>
<a href="notcurses_palette.3.html">notcurses_palette</a>—operations on notcurses palettes<br/>
<a href="notcurses_plot.3.html">notcurses_palette</a>—drawing histograms and lineplots<br/>
<a href="notcurses_refresh.3.html">notcurses_refresh</a>—refresh an externally-damaged display<br/>
<a href="notcurses_render.3.html">notcurses_render</a>—sync the physical display<br/>
<a href="notcurses_resize.3.html">notcurses_resize</a>—resize the standard plane based off screen size<br/>
<a href="notcurses_selector.3.html">notcurses_selector</a>—high-level widget for selecting one item from a set<br/>
<a href="notcurses_multiselector.3.html">notcurses_multiselector</a>—high-level widget for selecting items from a set<br/>
<a href="notcurses_stats.3.html">notcurses_stats</a>—notcurses runtime statistics<br/>

View File

@ -146,8 +146,8 @@ previous action.
**notcurses_palette(3)**,
**notcurses_plot(3)**,
**notcurses_reel(3)**,
**notcurses_refresh(3)**,
**notcurses_render(3)**,
**notcurses_resize(3)**,
**notcurses_selector(3)**,
**notcurses_stats(3)**,
**notcurses_stdplane(3)**, **notcurses_stop(3)**,

View File

@ -92,8 +92,8 @@ a handler for this signal. The handler causes notcurses to update its idea of
the terminal's size using **TIOCGWINSZ** (see **ioctl_tty(2)**), and generates an
**NCKEY_RESIZE** input event (see **notcurses_input(3)**. This signal handler can be
inhibited by setting **no_winch_sighandler** to **true**. If this is done, the
caller should probably watch for the signal, and invoke **notcurses_resize()**
upon its receipt.
caller should probably watch for the signal, and invoke **notcurses_refresh(3)**
or **notcurses_render(3)** upon its receipt.
A resize event does not invalidate any references returned earlier by
notcurses. The content of any new screen area is undefined until the next call
@ -109,7 +109,7 @@ Thus, in the absence of **no_winch_sighandler**, **SIGWINCH** results in:
* a **TIOCGWINSZ** **ioctl** to retrieve the new screen size
* queuing of a **NCKEY_RESIZE** input event (if there is space in the queue)
Upon the next call to **notcurses_render(3)** or **notcurses_resize(3)**, the
Upon the next call to **notcurses_render(3)** or **notcurses_refresh(3)**, the
standard plane (see **notcurses_stdplane(3)**) will be resized to the new
screen size. The next **notcurses_render(3)** call will function as expected
across the new screen geometry.
@ -123,5 +123,5 @@ across the new screen geometry.
# SEE ALSO
**getenv(3)**, **termios(3)**, **notcurses(3)**, **notcurses_input(3)**,
**notcurses_ncplane(3)**, **notcurses_render(3)**, **notcurses_resize(3)**,
**notcurses_ncplane(3)**, **notcurses_refresh(3)**, **notcurses_render(3)**,
**notcurses_stop(3)**, **terminfo(5)**, **signal(7)**

View File

@ -91,7 +91,7 @@ found in **<notcurses.h>**. For more details, consult **terminfo(5)**.
Unless the **SIGWINCH** handler has been inhibited (see **notcurses_init(3)**),
notcurses will automatically catch screen resizes, and synthesize an
**NCKEY_RESIZE** event. Upon receiving this event, the user may call
**notcurses_resize(3)** to force an immediate reflow, or just wait until the
**notcurses_refresh(3)** to force an immediate reflow, or just wait until the
next call to **notcurses_render(3)**, when notcurses will pick up the resize
itself. If the **SIGWINCH** handler is inhibited, **NCKEY_RESIZE** is never
generated.
@ -139,8 +139,8 @@ registers as **NCKEY_ENTER**. This will likely change in the future.
**poll(2)**,
**cfmakeraw(3)**,
**notcurses(3)**,
**notcurses_refresh(3)**,
**notcurses_render(3)**,
**notcurses_resize(3)**,
**termios(3)**,
**terminfo(5)**,
**ascii(7)**,

View File

@ -0,0 +1,66 @@
% notcurses_refresh(3)
% nick black <nickblack@linux.com>
% v1.2.5
# NAME
notcurses_refresh - redraw an externally-damaged display
# SYNOPSIS
**#include <notcurses.h>**
**int notcurses_refresh(const struct notcurses* nc, int* restrict rows, int* restrict cols);**
# DESCRIPTION
**notcurses_refresh** clears the screen, homes the cursor, checks the current
terminal geometry, and repaints the most recently rendered frame. It can be
called concurrently with all other Notcurses functions save
**notcurses_render**. **notcurses_refresh** ought be called when the screen is
externally damaged (as occurs when another program writes to the terminal, or
if your program writes to the terminal using standard I/O). It is necessary to
use **notcurses_refresh** in such a case (as opposed to simply calling
**notcurses_render**), since **notcurses_render** optimizes its output by only
writing internally-damaged cells. Notcurses has no way of knowing about
external corruption; by tradition, Ctrl+L is bound to **notcurses_refresh**,
and the user is responsible for requesting a hard redraw.
A secondary use of this function is when the program is blocking on input (and
perhaps not ready to render), and receives an **NCKEY_RESIZE** event (see
**notcurses_input**). In this case, **notcurses_refresh** will acquire the new
screen parameters, and repaint what it can. If you're prepared to call
**notcurses_render**, it's better to do that in this case, and thus avoid
unnecessary screen redrawing.
If **rows** and/or **cols** is not NULL, they receive the new geometry.
# NOTES
If your program **is** in a render loop (i.e. rendering as quickly as
possible, or at least at the refresh rate), there's not much point in
erecting the machinery to trigger **notcurses_refresh** based off
**NCKEY_RESIZE**. The latter is generated based upon receipt of the **SIGWINCH**
signal, which is fundamentally racy with regards to the rest of the program.
If your program truly relies on timely invocation of **notcurses_refresh**,
it's a broken program. If you don't rely on it in a causal fashion, then just
wait for the upcoming render.
Highest performance in a rendering loop would actually call for disabling
Notcurses's **SIGWINCH** handling in the call to **notcurses_init**, so that no
time is spent handling a signal you're not going to use.
# RETURN VALUES
Returns 0 on success, and -1 on failure. The causes for failure include system
error, programming error, closing of output, or allocation failure. None
of these are particularly good things, and the most reasonable response to a
**notcurses_refresh** failure is either to ignore it, or to weep and exit.
# SEE ALSO
**notcurses_init(3)**,
**notcurses_input(3)**,
**notcurses_render(3)**,
**termios(3)**,
**signal(7)**

View File

@ -20,8 +20,8 @@ notcurses_render - sync the physical display to the virtual ncplanes
ncplanes. It is necessary to call **notcurses_render** to generate any visible
output; the various notcurses_output(3) calls only draw to the virtual
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.
render (see notcurses_stats(3)), and screen geometry is refreshed (similarly to
**notcurses_refresh**) *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**
@ -35,7 +35,7 @@ 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**
original call to **notcurses_init**, 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
@ -85,5 +85,5 @@ purposes of color blending.
# SEE ALSO
**notcurses(3)**, **notcurses_cell(3)**, **notcurses_ncplane(3)**,
**notcurses_output(3)**, **notcurses_resize(3)**, **notcurses_stats(3)**,
**notcurses_output(3)**, **notcurses_refresh(3)**, **notcurses_stats(3)**,
**console_codes(4)**, **utf-8(7)**

View File

@ -1,64 +0,0 @@
% notcurses_resize(3)
% nick black <nickblack@linux.com>
% v1.2.5
# NAME
notcurses_resize - resizeialize a notcurses instance
# SYNOPSIS
**#include <notcurses.h>**
**int notcurses_resize(const struct notcurses* nc, int* rows, int* cols);**
# DESCRIPTION
**notcurses_resize** causes notcurses to retrieve the screen's current size
using **termios(3)**. If it has changed, notcurses will resize the standard
plane appropriately. Like any other **ncplane_resize(3)** operation, lost
space will be culled from the standard plane, while new space will be
populated by the standard plane's base cell. Other planes are unaffected.
**notcurses_resize** does *not* result in a rendering operation.
**notcurses_render(3)** calls this function following a render+raster cycle. It
is thus not necessary to call it yourself unless both of the following are
true:
* Your program is in an event loop rather than a rendering loop (i.e. it calls **notcurses_render(3)** only based on external events), and
* Your program makes use of the standard plane, or the standard plane's dimensions.
If this is the case, you might call **notcurses_resize** based on an
**NCKEY_RESIZE** event on the input channel (see **notcurses_input(3)**),
so that you can write to the standard plane using its new size prior to a
render. If you have no changes, and just want to render what you have (with
more or less now visible), it is sufficient to simply call **notcurses_render(3)**.
If **rows** and/or **cols** is not NULL, they receive the new geometry.
# NOTES
If your program **is** in a render loop (i.e. rendering as quickly as
possible, or at least at the refresh rate), there's not much point in
erecting the machinery to trigger **notcurses_resize** based off
**NCKEY_RESIZE**. The latter is generated based upon receipt of the **SIGWINCH**
signal, which is fundamentally racy with regards to the rest of the program.
If your program truly relies on timely invocation of **notcurses_resize()**,
it's a broken program. If you don't rely on it in a causal fashion, then just
wait for the upcoming render.
Highest performance in a rendering loop would actually call for disabling
notcurses SIGWINCH handling in the call to **notcurses_init(3)**, so that no
time is spent handling a signal you're not going to use.
# RETURN VALUES
Returns 0 on success, and -1 on failure. The causes for failure include system
error, programming error, closing of output, or allocation failure. None
of these are particularly good things, and the most reasonable response to a
**notcurses_resize** failure is probably to weep.
# SEE ALSO
**notcurses_init(3)**, **notcurses_input(3)**, **notcurses_ncplane(3)**,
**notcurses_render(3)**, **termios(3)**, **signal(7)**

View File

@ -145,16 +145,6 @@ namespace ncpp
return notcurses_render (nc) == 0;
}
bool resize (int *rows, int *cols) const noexcept
{
return notcurses_resize (nc, rows, cols) == 0;
}
bool resize (int &rows, int &cols) const noexcept
{
return resize (&rows, &cols) == 0;
}
void get_term_dim (int *rows, int *cols) const noexcept
{
notcurses_term_dim_yx (nc, rows, cols);
@ -165,9 +155,14 @@ namespace ncpp
get_term_dim (&rows, &cols);
}
bool refresh () const noexcept
bool refresh (int* rows, int* cols) const noexcept
{
return notcurses_refresh (nc) == 0;
return notcurses_refresh (nc, rows, cols) == 0;
}
bool refresh (int& rows, int& cols) const noexcept
{
return refresh (&rows, &cols) == 0;
}
int get_palette_size () const noexcept

View File

@ -666,15 +666,11 @@ API int notcurses_mouse_enable(struct notcurses* n);
// Disable mouse events. Any events in the input queue can still be delivered.
API int notcurses_mouse_disable(struct notcurses* n);
// Refresh our idea of the terminal's dimensions, reshaping the standard plane
// if necessary, without a fresh render. References to ncplanes (and the
// egcpools underlying cells) remain valid following a resize operation.
API int notcurses_resize(struct notcurses* n, int* RESTRICT y, int* RESTRICT x);
// Refresh the physical screen to match what was last rendered (i.e., without
// reflecting any changes since the last call to notcurses_render()). This is
// primarily useful if the screen is externally corrupted.
API int notcurses_refresh(struct notcurses* n);
// primarily useful if the screen is externally corrupted, or if an
// NCKEY_RESIZE event has been read and you're not ready to render.
API int notcurses_refresh(struct notcurses* n, int* RESTRICT y, int* RESTRICT x);
// Return the dimensions of this ncplane.
API void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
@ -709,8 +705,8 @@ ncplane_dim_x(const struct ncplane* n){
// 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){
ncplane_dim_yx(notcurses_stdplane(n), rows, cols);
notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows, int* RESTRICT cols){
ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
}
// Retrieve the contents of the specified cell as last rendered. The EGC is

View File

@ -97,8 +97,7 @@ int ncplane_set_base(struct ncplane* ncp, uint64_t channels, uint32_t attrword,
int ncplane_base(struct ncplane* ncp, cell* c);
struct ncplane* notcurses_top(struct notcurses* n);
void notcurses_drop_planes(struct notcurses* nc);
int notcurses_refresh(struct notcurses* n);
int notcurses_resize(struct notcurses* n, int* y, int* x);
int notcurses_refresh(struct notcurses* n, int* restrict y, int* restrict x);
struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols, int yoff, int xoff, void* opaque);
struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque);
struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);

View File

@ -14,3 +14,8 @@ homepage = "https://nick-black.com/dankwiki/index.php/Notcurses"
libnotcurses-sys = "^1.2.5"
libc = "0.2.66"
libc-stdhandle = ">= 0.1.0"
[dev-dependencies]
all_asserts = ">= 1.0.0"
serial_test = "*"
serial_test_derive = "*"

View File

@ -14,6 +14,22 @@ pub fn ncplane_putstr(_n: *mut ffi::ncplane, _str: &str) -> i32 {
}
}
pub fn ncplane_dim_y(_n: *const ffi::ncplane) -> i32 {
unsafe {
let mut y = 0;
ffi::ncplane_dim_yx(_n, &mut y, std::ptr::null_mut());
return y;
}
}
pub fn ncplane_dim_x(_n: *const ffi::ncplane) -> i32 {
unsafe {
let mut x = 0;
ffi::ncplane_dim_yx(_n, std::ptr::null_mut(), &mut x);
return x;
}
}
pub fn render(_n: *mut ffi::notcurses) -> std::result::Result<(), std::io::Error> {
unsafe {
let r = ffi::notcurses_render(_n);
@ -24,15 +40,32 @@ pub fn render(_n: *mut ffi::notcurses) -> std::result::Result<(), std::io::Error
}
}
pub fn stddim_yx(_n: *mut ffi::notcurses, _dimy: &mut i32, _dimx: &mut i32) -> *mut ffi::ncplane {
unsafe {
let stdplane = ffi::notcurses_stdplane(_n);
ffi::ncplane_dim_yx(stdplane, _dimy, _dimx);
return stdplane;
}
}
pub fn dim_yx(_n: *const ffi::notcurses, _dimy: &mut i32, _dimx: &mut i32) {
unsafe {
ffi::ncplane_dim_yx(ffi::notcurses_stdplane_const(_n), _dimy, _dimx);
}
}
#[cfg(test)]
mod tests {
use super::*;
use all_asserts;
use serial_test_derive::serial; // serialize tests w/ ffi::notcurses_init()
extern {
static stdout: *mut ffi::_IO_FILE;
}
#[test]
#[serial]
fn create_context() {
unsafe {
let _ = libc::setlocale(libc::LC_ALL, std::ffi::CString::new("").unwrap().as_ptr());
@ -51,7 +84,33 @@ mod tests {
margin_l: 0,
};
let nc = ffi::notcurses_init(&opts, stdout);
ffi::notcurses_stop(nc);
assert_ne!(std::ptr::null(), nc);
let mut dimy = 0;
let mut dimx = 0;
dim_yx(nc, &mut dimy, &mut dimx);
all_asserts::assert_lt!(0, dimy);
all_asserts::assert_lt!(0, dimx);
assert_eq!(0, ffi::notcurses_stop(nc));
}
}
#[test]
#[serial]
fn stdplane_dims() {
unsafe {
let _ = libc::setlocale(libc::LC_ALL, std::ffi::CString::new("").unwrap().as_ptr());
let nc = ffi::notcurses_init(std::ptr::null(), stdout);
assert_ne!(std::ptr::null(), nc);
let mut dimsy = 0;
let mut dimsx = 0;
let _stdplane = stddim_yx(nc, &mut dimsy, &mut dimsx);
all_asserts::assert_lt!(0, dimsy);
all_asserts::assert_lt!(0, dimsx);
let dimy = ncplane_dim_y(_stdplane);
let dimx = ncplane_dim_x(_stdplane);
assert_eq!(dimy, dimsy);
assert_eq!(dimx, dimsx);
assert_eq!(0, ffi::notcurses_stop(nc));
}
}
}

View File

@ -17,7 +17,7 @@ chunli_draw(struct notcurses* nc, const char* ext, int count, const cell* b){
timespec_div(&demodelay, 10, &iterdelay);
for(int i = 0 ; i < count ; ++i){
int averr;
notcurses_resize(nc, &dimy, &dimx);
notcurses_refresh(nc, &dimy, &dimx);
snprintf(file, sizeof(file), "chunli%d.%s", i + 1, ext);
chuns[i].path = find_data(file);
chuns[i].ncv = ncvisual_open_plane(nc, chuns[i].path, &averr, 0, 0, NCSCALE_NONE);
@ -54,7 +54,7 @@ int chunli_demo(struct notcurses* nc){
struct timespec iterdelay;
timespec_div(&demodelay, 10, &iterdelay);
int averr, dimx, dimy;
notcurses_resize(nc, &dimy, &dimx);
notcurses_refresh(nc, &dimy, &dimx);
cell b = CELL_TRIVIAL_INITIALIZER;
cell_set_fg_alpha(&b, CELL_ALPHA_TRANSPARENT);
cell_set_bg_alpha(&b, CELL_ALPHA_TRANSPARENT);

View File

@ -111,7 +111,7 @@ ultramegaok_demo(void* vnc){
}
if(id == 'L' && ni.ctrl){
lock_demo_render();
notcurses_refresh(nc);
notcurses_refresh(nc, NULL, NULL);
unlock_demo_render();
continue;
}

View File

@ -364,7 +364,7 @@ ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
case NCKEY_UP: ncreel_prev(pr); break;
case NCKEY_DOWN: ncreel_next(pr); break;
case NCKEY_DEL: kill_active_tablet(pr, &tctxs); break;
case NCKEY_RESIZE: notcurses_resize(nc, &dimy, NULL); break;
case NCKEY_RESIZE: notcurses_render(nc); break;
default: ncplane_printf_yx(w, 3, 2, "Unknown keycode (0x%x)\n", rw); break;
}
if(newtablet){
@ -376,6 +376,7 @@ ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
if(timespec_subtract_ns(&cur, &deadline) >= 0){
break;
}
dimy = ncplane_dim_y(w);
}while(!aborted);
while(tctxs){
kill_tablet(&tctxs);

View File

@ -577,7 +577,7 @@ int witherworm_demo(struct notcurses* nc){
return 1;
}
if(key == NCKEY_RESIZE){
notcurses_resize(nc, &maxy, &maxx);
DEMO_RENDER(nc);
}
}while(key == NCKEY_RESIZE);
if(key == 'q'){

View File

@ -18,7 +18,7 @@ static int dimy, dimx;
const char* nckeystr(char32_t spkey){
switch(spkey){ // FIXME
case NCKEY_RESIZE:
NotCurses::get_instance ().resize(&dimy, &dimx);
NotCurses::get_instance().refresh(&dimy, &dimx);
return "resize event";
case NCKEY_INVALID: return "invalid";
case NCKEY_LEFT: return "left";

View File

@ -620,6 +620,12 @@ cell_duplicate_far(egcpool* tpool, cell* targ, const ncplane* splane, const cell
return ulen;
}
int ncplane_resize_internal(ncplane* n, int keepy, int keepx,
int keepleny, int keeplenx, int yoff, int xoff,
int ylen, int xlen);
int update_term_dimensions(int fd, int* rows, int* cols);
#ifdef __cplusplus
}
#endif

View File

@ -216,8 +216,7 @@ void ncplane_dim_yx(const ncplane* n, int* rows, int* cols){
// anyone calling this needs ensure the ncplane's framebuffer is updated
// to reflect changes in geometry.
static int
update_term_dimensions(int fd, int* rows, int* cols){
int update_term_dimensions(int fd, int* rows, int* cols){
struct winsize ws;
int i = ioctl(fd, TIOCGWINSZ, &ws);
if(i < 0){
@ -391,9 +390,8 @@ ncplane* ncplane_dup(ncplane* n, void* opaque){
}
// can be used on stdscr, unlike ncplane_resize() which prohibits it.
static int
ncplane_resize_internal(ncplane* n, int keepy, int keepx, int keepleny,
int keeplenx, int yoff, int xoff, int ylen, int xlen){
int ncplane_resize_internal(ncplane* n, int keepy, int keepx, int keepleny,
int keeplenx, int yoff, int xoff, int ylen, int xlen){
if(keepleny < 0 || keeplenx < 0){ // can't retain negative size
//fprintf(stderr, "Can't retain negative size %dx%d\n", keepleny, keeplenx);
return -1;
@ -494,48 +492,6 @@ int ncplane_resize(ncplane* n, int keepy, int keepx, int keepleny,
yoff, xoff, ylen, xlen);
}
// Call this when the screen size changes. Acquires the new size, and copies
// what can be copied from the old stdscr. Assumes that the screen is always
// anchored in the same place.
int notcurses_resize(notcurses* n, int* rows, int* cols){
int r, c;
if(rows == NULL){
rows = &r;
}
if(cols == NULL){
cols = &c;
}
int oldrows = n->stdscr->leny;
int oldcols = n->stdscr->lenx;
if(update_term_dimensions(n->ttyfd, rows, cols)){
return -1;
}
// FIXME can we emerge from the previous call with rows/cols <= 0?
*rows -= n->margin_t + n->margin_b;
if(*rows <= 0){
*rows = 1;
}
*cols -= n->margin_l + n->margin_r;
if(*cols <= 0){
*cols = 1;
}
if(*rows == oldrows && *cols == oldcols){
return 0; // no change
}
int keepy = *rows;
if(keepy > oldrows){
keepy = oldrows;
}
int keepx = *cols;
if(keepx > oldcols){
keepx = oldcols;
}
if(ncplane_resize_internal(n->stdscr, 0, 0, keepy, keepx, 0, 0, *rows, *cols)){
return -1;
}
return 0;
}
// find the pointer on the z-index referencing the specified plane. writing to
// this pointer will remove the plane (and everything below it) from the stack.
static ncplane**

View File

@ -4,6 +4,47 @@
#include <sys/poll.h>
#include "internal.h"
// Check whether the terminal geometry has changed, and if so, copies what can
// be copied from the old stdscr. Assumes that the screen is always anchored in
// the same place.
int notcurses_resize(notcurses* n, int* restrict rows, int* restrict cols){
int r, c;
if(rows == NULL){
rows = &r;
}
if(cols == NULL){
cols = &c;
}
int oldrows = n->stdscr->leny;
int oldcols = n->stdscr->lenx;
if(update_term_dimensions(n->ttyfd, rows, cols)){
return -1;
}
*rows -= n->margin_t + n->margin_b;
if(*rows <= 0){
*rows = 1;
}
*cols -= n->margin_l + n->margin_r;
if(*cols <= 0){
*cols = 1;
}
if(*rows == oldrows && *cols == oldcols){
return 0; // no change
}
int keepy = *rows;
if(keepy > oldrows){
keepy = oldrows;
}
int keepx = *cols;
if(keepx > oldcols){
keepx = oldcols;
}
if(ncplane_resize_internal(n->stdscr, 0, 0, keepy, keepx, 0, 0, *rows, *cols)){
return -1;
}
return 0;
}
static int
blocking_write(int fd, const char* buf, size_t buflen){
//fprintf(stderr, "writing %zu to %d...\n", buflen, fd);
@ -998,8 +1039,13 @@ home_cursor(notcurses* nc, bool flush){
return -1;
}
int notcurses_refresh(notcurses* nc){
// FIXME need reflow in the event we've been resized
int notcurses_refresh(notcurses* nc, int* restrict dimy, int* restrict dimx){
if(notcurses_resize(nc, dimy, dimx)){
return -1;
}
if(nc->lfdimx == 0 || nc->lfdimy == 0){
return 0;
}
if(home_cursor(nc, true)){
return -1;
}
@ -1024,6 +1070,8 @@ int notcurses_render(notcurses* nc){
struct timespec start, done;
int ret;
clock_gettime(CLOCK_MONOTONIC, &start);
int dimy, dimx;
notcurses_resize(nc, &dimy, &dimx);
int bytes = -1;
const size_t crenderlen = sizeof(struct crender) * nc->stdscr->leny * nc->stdscr->lenx;
struct crender* crender = malloc(crenderlen);
@ -1032,8 +1080,6 @@ int notcurses_render(notcurses* nc){
bytes = notcurses_rasterize(nc, crender);
}
free(crender);
int dimy, dimx;
notcurses_resize(nc, &dimy, &dimx);
clock_gettime(CLOCK_MONOTONIC, &done);
update_render_stats(&done, &start, &nc->stats, bytes);
ret = bytes >= 0 ? 0 : -1;

View File

@ -2,7 +2,7 @@ int main(void) {
if(setlocale(LC_ALL, "") == nullptr){
return EXIT_FAILURE;
}
srand(time(NULL));
srand(time(nullptr));
std::atomic_bool gameover = false;
notcurses_options ncopts{};
ncpp::NotCurses nc(ncopts);
@ -19,7 +19,7 @@ int main(void) {
case NCKEY_LEFT: case 'h': t.MoveLeft(); break;
case NCKEY_RIGHT: case 'l': t.MoveRight(); break;
case NCKEY_DOWN: case 'j': t.MoveDown(); break;
case 'L': if(ni.ctrl){ notcurses_refresh(nc); } break;
case 'L': if(ni.ctrl){ notcurses_refresh(nc, nullptr, nullptr); } break;
case 'z': t.RotateCcw(); break;
case 'x': t.RotateCw(); break;
default:

View File

@ -198,10 +198,10 @@ int main(int argc, char** argv){
break;
}else if(ie == NCKey::Resize){
--i; // rerun with the new size
if(!nc.resize(&dimy, &dimx)){
if(!nc.refresh(&dimy, &dimx)){
return EXIT_FAILURE;
}
if(!ncv->get_plane ()->resize(dimy, dimx)){
if(!ncv->get_plane()->resize(dimy, dimx)){
nc.stop();
return EXIT_FAILURE;
}

View File

@ -42,11 +42,11 @@ TEST_CASE("NotcursesBase") {
}
}
SUBCASE("ResizeSameSize") {
SUBCASE("RefreshSameSize") {
int x, y;
notcurses_term_dim_yx(nc_, &y, &x);
int newx, newy;
CHECK(0 == notcurses_resize(nc_, &newy, &newx));
CHECK(0 == notcurses_refresh(nc_, &newy, &newx));
CHECK(newx == x);
CHECK(newy == y);
}

View File

@ -11,7 +11,7 @@ BuildRequires: gnupg2 cmake make gcc-c++ ncurses-devel pandoc python3-devel
%description
notcurses facilitates the creation of modern TUI programs,
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
an API similar to that of Curses, and rides atop Terminfo.
%prep
%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}'