When we don't have an actual terminal in ncdirect, return
placeholder 80x24 for ncdirect_dim_y()/ncdirect_dim_x(), but
don't go querying e.g. a redirected file for its dimensions.
Similarly, only request info about cursor position from a true
TTY (we're otherwise likely to hang, or at best get meaningless
data). Rewrite 'direct' PoC to use ncdirect_dim_*().
Add tty_emit(). Closes#752.
* Some things go to the FILE* we're provided. Some can only go to a controlling terminal. Check to see if the FILE we're given is a TTY. If not, open up /dev/tty #752.
* term_emit(): fflush() can return EAGAIN. Loop on it to eliminate a rare error on shutdown that particularly affected unit tests (where we start and shut down Notcurses many times in a row).
* sgr poc: check return value of setlocale()
* drone: run all unit tests
* CMake: add some tests using PoCs
* ncneofetch: print even small palettes
sometimes when we call fflush(ttyfp), we get EAGAIN. we can
loop on this and force the flush. without it, we (fairly rarely)
get errors on shutdown, sometimes manifesting as unit test
failures (especially in the rust wrappers). #742
in ncdirect_render_image(), we want to emit newlines if and
only if we did not hit the right border. we want to emit
cuds (cursor downs) if and only if we've hit the bottom
border. this resolves all mysteries of blank lines, eliminating
a FIXME. it also fixes ncneofetch's image display on very
wide terminals. closes#756. also removes the display semaphore
in ncneofetch, using a more natural pthread_join().
Use ctermid(3) to identify the controlling terminal device.
When one exists, open(2) it up, and retain this file descriptor
across the life of the ncdirect context. Allow a failure, since
not everything requires such an fd. This will be used for tty-
specific activity such as ioctl()s and escape sequences
involving terminal replies (such as get absolute cursor
position). #752
When we don't have a pidfd available on which to poll(2) (this
is true of Linux pre-5.3, and FreeBSD), we can't rely on a
child death breaking our poll loop. Instead, in this case launch
a second thread, which just sits on a blocking waitpid(2). If
it gets an exit, it calls the completion callback, triggering
the teardown. Closes#728, and ought lets us run the test suite
on FreeBSD.
CELL_ALPHA_OPAQUE et al were defined as 0..3, meaning
CELL_ALPHA_SHIFT had to be used to compare them to their
channel representations. Instead, define them in said
representation outright, eliminating the need to shift while
retaining arithmetic properties, and zero initialization for
CELL_ALPHA_OPAQUE. Eliminate CELL_ALPHA_SHIFT #738.
We're not using NCBLIT_2x2 by default because it warps the
aspect ratio. If we're using NCSCALE_STRETCH, though, we've
(1) already indicated that aspect ratio isn't terribly
important to us and (2) are trying to maximize the space.
Since NCBLIT_2x2 is best for large images anyway, make it
the default when NCSCALE_STRECTH is being used.
Remove all explicit uses of NCBLIT_2x2 when NCSCALE_STRETCH
is being used in notcurses-demo.
Add convenience function ncplane_home(). Add an ncblitter_e param
to ncplane_qrcode(), and split int maxversion into value-result
int* ymax and int* xmax. Write the actual sizes of the resulting
visual into these parameters. Update the qrcode demo. Add the
qrcode PoC. Update demos to ncplane_home(), where possible.
ncplane_qrcode() now takes an ncblitter_e and two value-result int*s
in the place of a single value int. The final size of the displayed qrcode
is written to *ymax and *xmax. If the code can't fit within the specified
dimensions, an error is returned. Standard rules for pluggable blitters
apply regarding fallback etc. #699
The Plot unit tests were reaching directly into the objects,
which meant the implementations couldn't include anything
we didn't want public. This was annoying, so I've changed it.
This required adding ncdplot_sample() and ncuplot_sample(),
which we should have had anyway.
Each plane has a "base cell", which like all other cells is
initialized to the null glyph, opaque default foreground color,
and opaque default background color. Prior to this change, at
each cell of a plane, we decided whether to use that cell (the
"viscell") or the base cell depending on whether the viscell had
a non-null glyph. We now evaluate each component independently.
If the viscell has a null glyph, we use the base cell's glyph.
If the viscell has a default foreground, we use the base's fg.
If the viscell has a default background, we use the base's bg.
This was done because (a) it seems more intuitive (if I set a cell
to red, I expect red, not red iff there's a glyph in that cell
for this plane), and (b) because otherwise it was impossible to
do a multicolor overlay without blowing away underlying glyphs
(since without a glyph, you always reduced to the same base cell,
which could have only one fore- and background per render).
Existing code will need to change any instances where cells
lacking glyphs are colored, and those colors are not desired.
Since any such coloring had no effect before, it seems unlikely
that any ought exist (this did bring to light an instance in
the "qrcode" demo where we were staining overmuch of the plane).
This closes#395, the last big open worry regarding our API.
In order to properly determine the scaling of an ncvisual to
be rendered, ncvisual_geom() needs know the blitting method.
For this reason, it took an ncblitter_e argument. It also,
however, needs handle degradation, which means knowing whether
NCVISUAL_OPTIONS_NODEGRADE is in use. It thus really wants the
struct ncvisual_options. Pass and accept it. Closes#697, and
fixes the "yield" demo in ASCII mode (#696).
Very simple take at ncplane_puttext(), a new function for linebroken text. Also some very basic unit tests. I doubt this works very well yet, but it handles the simplest cases #682. Added nclog(), internal function for logging. #520
Whip the ol' llama's ass (fix ncvisual rotation)
* notcurses: flush cursor change requests #673
* rotator: verify ncplane_rgba and ncblit_rgba
* ncblit: rename, accept ncblitter_e #674
* rotator: render from rgba
* rotator: get to rotation
* rotator: add a pi/4 turn at the end
* normal: reuse incoming plane for rendering #672
* rotator poc: rotate a fullplane gradient #672
* normal demo: place visual correctly
* rotator: verify ncplane_rgba and ncblit_rgba
* ncblit: rename, accept ncblitter_e #674
* rotator: render from rgba
* rotator: add a pi/4 turn at the end
* normal: reuse incoming plane for rendering #672
* rotator poc: rotate a fullplane gradient #672
* normal demo: place visual correctly
* rotator poc: throw some red into gradient
* rotator poc: done #662
* oiio: ncvisual_resize() needs set ibuf pointer #662
* normal: only need erase at top of loop
* visual poc: shorter delay
* normal demo: center rendered visual
* comment ncvisual_resize() call
* ncvisual_rotate: call ncvisual_details_seed()
* ffmpeg ncvisual: fix rotation #662
Since notcurses-view is now rendering to the standard plane, and
ncvisual is no longer bound to a plane, there's no need to call
ncplane_resize() (and doing so fails, since you can't resize the
standard plane). Remove the call, leave the check. Fixes resizing.
When we first begin operations, we need emit a cursor homing, which
we were not doing for the first line. As a result, the first row
didn't show up until you rendered something else, and even then
didn't show up unless you changed it (as it was otherwise undamaged).
This explains a lot of mystery behavior in notcurses-demo that I've
long told myself I'd hallucinated or imagined. Hurrah! but also
supershittytothemax! Thanks Marek Habersack for pointing out something
which led to an experiment which led to chasing this down once and
forever. Closes#619, w00t!
If we're in ASCII mode, no blitter except for NCBLIT_1x1 is going to
work. Whenever NCBLIT_DEFAULT is provided, select NCBLIT_1x1 if we're
in ASCII mode. Add NCVISUAL_OPTIONS_MAYDEGRADE and
NCPLOT_OPTIONS_MAYDEGRADE. Both serve to allow smooth degradation when a
blitter other than NCBLIT_DEFAULT has been provided. Closes#637.
Make calc_gradient_cell() static inline so our templated ncppplot
implementation can use it (ugh). When using NCBLIT_1x1 for plots in
ASCII mode, use space rather than full block, and invert colors.
Use NCBLIT_DEFAULT in the demo for the FPS plot.
This represents an essentially complete rewrite of ncvisual and associated code. It had two major goals:
Improve the ncvisual API based off lessons learned, pursuant to the upcoming API freeze. In particular, I wanted to:
decouple ncvisuals from ncplanes. It should be possible to render a ncvisual to multiple planes, with different scaling each time. It should be possible to create an ncvisual without a plane, etc.
normalize the various ways of constructing an ncvisual -- file, memory, plane, etc.
Support multiple blitters, from 7-bit ASCII to Sixel. This required writing the blitters in several cases, and they're not yet in their final implementations (but the API is fine)
I have not yet unified Plots and Visuals, and might not, given that the Plot code works fine. We could at this point implement Plots in terms of Visuals, though -- the blitter backend range has been unified. Sixel is not yet implemented, though it is listed.
There is a new POC tool, blitter. It renders its arguments using all possible blitter+scaling combinations. Another new POC, resize, displays its argument, then resizes it to the screen size and displays that, explicitly making use of ncvisual_resize() rather than a scaling parameter to ncvisual_render().
This also eliminates some memory leaks and bugs we were seeing in trunk, and brings in Sixel scaffolding.
The C++ wrapper will also need patching back up; I cut most of it down while wrestling with this crap, urk.
Closes#638, #562, and #622.
This is to make it possible, in the future, to create multiple instances
of `NotCurses` for multiple terminals. The first instance of
`NotCurses` becomes the default one, so that any instances of other
classes that aren't explicitly created with a pointer to another
`NotCurses` instance still work as expected.
Note that currently trying to call `notcurses_init` twice results in the
following error for me:
0x55555559bfc0 is already registered for signals
Couldn't drop signals: 0x55555559bfc0 != 0x5555555b6720
terminate called after throwing an instance of 'ncpp::init_error*'
Program received signal SIGABRT, Aborted.
The error is signalled by `setup_signals` and the pointer shown in the
message points to the first `struct notcurses` instance created.
Fixes: https://github.com/dankamongmen/notcurses/issues/616
SIGSEGV was caused by an invalid cast.
Short explanation: PEBKAC
Long explanation: `Selector.hh`, `Plot.hh` and `MultiSelector.hh` did
not include `Plane.hh`, they merely declared `class Plane;` because
inclusion of `Plane.hh` would cause circular dependencies to appear and
the compiler would be unhappy. On top of that, yours truly wrenched the
compiler's hands and caused it to believe that a pointer to `Plane` is
really a pointer to `ncplane*` which was quite a silly thing to do as
the compiler, not having included `Plane.hh` and thus not knowing full
definition of the type, wasn't able to look up the type cast operator in
`Plane`.
Don't abuse `reinterpret_cast`, kids!
Replace the singly-linked z-axis with a doubly-linked list,
and reimplement all z-axis moves as O(1) functions.
Eliminate ncplane_move_{above/below}_unsafe(), as there are no
longer unsafe moves.