Compare commits

..

No commits in common. 'master' and 'v3.0.1' have entirely different histories.

@ -5,23 +5,18 @@ name: debian-unstable
steps:
- name: debian-build
image: debian:unstable-slim
image: dankamongmen/unstable_builder:2021-11-14a
commands:
- export LANG=en_US.UTF-8
- export TERM=xterm
- apt-get update -y
- apt-get install -y ncurses-dev pkgconf libqrcodegen-dev libavdevice-dev cmake build-essential doctest-dev libunistring-dev libdeflate-dev libgpm-dev pandoc locales
- echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
- locale-gen
- mkdir build
- cd build
- cmake .. -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC=off -DUSE_GPM=on -DUSE_QRCODEGEN=on -DDFSG_BUILD=on -DBUILD_FFI_LIBRARY=on
- cmake .. -DCMAKE_BUILD_TYPE=Release -DUSE_STATIC=off -DUSE_GPM=on -DUSE_QRCODEGEN=on -DDFSG_BUILD=on
- make -j2
- ./notcurses-info
- ctest --output-on-failure
- make install
- ldconfig
- apt-get install -y python3-setuptools python3-wheel python3-pip python3-pypandoc python3-cffi-backend
- cd ../cffi
- LDFLAGS=-L/usr/local/lib CFLAGS=-I/usr/local/include python3 setup.py sdist build install
- env LD_LIBRARY_PATH=/usr/local/lib ./notcurses-pydemo > /dev/null
@ -41,7 +36,6 @@ steps:
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DUSE_DEFLATE=off -DUSE_MULTIMEDIA=oiio -DUSE_QRCODEGEN=on ..
- make -j2
- ./notcurses-info
- ctest --output-on-failure
- make install
- ldconfig
@ -66,7 +60,6 @@ steps:
- cd build
- cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_DOCTEST=off -DUSE_QRCODEGEN=on -DUSE_MULTIMEDIA=none ..
- make -j2
- ./notcurses-info
- ctest --output-on-failure
- make install
- ldconfig
@ -81,7 +74,7 @@ name: alpine-edge
steps:
- name: alpine-edge
image: dankamongmen/edge_builder:2022-01-07a
image: dankamongmen/edge_builder:2021-11-28a
commands:
- export LANG=en_US.UTF-8
- export TERM=vt100
@ -89,7 +82,6 @@ steps:
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DUSE_PANDOC=off ..
- make -j2
- ./notcurses-info
- ctest --output-on-failure
---
kind: pipeline
@ -98,7 +90,7 @@ name: gentoo
steps:
- name: gentoo
image: dankamongmen/gentoo:2022-02-07a
image: dankamongmen/gentoo:2021-12-06a
commands:
- export LANG=C.UTF-8
- export TERM=xterm
@ -106,5 +98,4 @@ steps:
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DUSE_PANDOC=off -DUSE_DOCTEST=off -DUSE_DEFLATE=off ..
- make -j2
- ./notcurses-info
- ctest --output-on-failure

@ -26,15 +26,13 @@ jobs:
ffmpeg \
libdeflate \
libunistring \
ncurses \
pkg-config
ncurses
- uses: actions/checkout@v2
- name: cmake
run: |
mkdir build && cd build
env PKG_CONFIG_PATH="/opt/homebrew/opt/ncurses/lib/pkgconfig" \
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_PANDOC=off
@ -55,19 +53,19 @@ jobs:
cd build
sudo make install
#- name: python wrappers (old)
#run: |
#python3 -m pip install --upgrade pip
#pip3 install cffi pypandoc
#cd cffi
#python3 setup.py sdist build
- name: python wrappers (old)
run: |
python3 -m pip install --upgrade pip
pip install cffi pypandoc
cd cffi
python3 setup.py sdist build
#sudo python3 setup.py install
#notcurses-pydemo > /dev/null
#ncdirect-pydemo > /dev/null
#- name: python wrappers (new)
#run: |
#cd python
#python3 setup.py build
- name: python wrappers (new)
run: |
cd python
python3 setup.py build
#sudo python3 setup.py install
#python3 examples/000-print-version.py

@ -26,7 +26,9 @@ jobs:
cmake \
doctest-dev \
ffmpeg \
libavdevice-dev \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libdeflate-dev \
libncurses-dev \
libqrcodegen-dev \

@ -16,7 +16,7 @@ jobs:
COLORTERM: truecolor
TERM: xterm
name: 🏁 build, test, & install
runs-on: windows-2022
runs-on: windows-latest
steps:
@ -30,6 +30,7 @@ jobs:
git
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-doctest
mingw-w64-ucrt-x86_64-ilmbase
mingw-w64-ucrt-x86_64-openimageio
mingw-w64-ucrt-x86_64-libdeflate
mingw-w64-ucrt-x86_64-libunistring

@ -1,6 +1,6 @@
# 3.14.0 introduced NAME_WLE
cmake_minimum_required(VERSION 3.14.0)
project(notcurses VERSION 3.0.9
project(notcurses VERSION 3.0.1
DESCRIPTION "Blingful UI for modern terminal emulators"
HOMEPAGE_URL "https://nick-black.com/dankwiki/index.php/notcurses"
LANGUAGES C)
@ -23,8 +23,6 @@ option(USE_DEFLATE "Use libdeflate instead of libz" ON)
option(USE_DOXYGEN "Build HTML cross reference with doxygen" OFF)
option(USE_GPM "Enable libgpm console mouse support" OFF)
option(USE_PANDOC "Build man pages and HTML reference with pandoc" ON)
option(BUILD_EXECUTABLES "Build executables" ON)
option(BUILD_FFI_LIBRARY "Build ffi library (containing all symbols which are static inline)" ON)
option(USE_POC "Build small, uninstalled proof-of-concept binaries" ON)
option(USE_QRCODEGEN "Enable libqrcodegen QR code support" OFF)
option(USE_STATIC "Build static libraries (in addition to shared)" ON)
@ -48,10 +46,6 @@ elseif(${USE_MULTIMEDIA} STREQUAL "oiio")
elseif(NOT ${USE_MULTIMEDIA} STREQUAL "none")
message(FATAL_ERROR "USE_MULTIMEDIA must be one of 'oiio', 'ffmpeg', 'none' (was '${USE_MULTIMEDIA}').")
endif()
if (NOT BUILD_EXECUTABLES AND USE_POC)
message(WARNING "Disabling USE_POC since BUILD_EXECUTABLES=OFF")
set(USE_POC OFF)
endif()
if(${USE_CXX})
enable_language(CXX)
@ -107,14 +101,12 @@ set_package_properties(terminfo PROPERTIES TYPE REQUIRED)
set(PKGCONF_REQ_PRIV "${TERMINFO_LIBRARIES}")
if(${USE_FFMPEG})
pkg_check_modules(AVCODEC REQUIRED libavcodec>=57.0)
pkg_check_modules(AVDEVICE REQUIRED libavdevice>=57.0)
pkg_check_modules(AVFORMAT REQUIRED libavformat>=57.0)
pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0)
pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0)
set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND FFMpeg)
elseif(${USE_OIIO})
pkg_check_modules(OPENIMAGEIO REQUIRED OpenImageIO>=2.1)
set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND OpenImageIO)
find_package(OpenImageIO 2.1 REQUIRED)
endif()
endif()
@ -130,7 +122,7 @@ endif()
if(MSVC)
add_compile_options(/W4)
else()
add_compile_options(-Wall -Wextra -W -Wshadow -Wvla -Wstrict-aliasing=2)
add_compile_options(-Wall -Wextra -W -Wshadow -Wvla)
# -ffast-math dies on NaNs we draw from libav (by -ffinite-math-only)
add_compile_options(-fno-signed-zeros -fno-trapping-math -fassociative-math)
add_compile_options(-fno-math-errno -freciprocal-math -funsafe-math-optimizations)
@ -147,7 +139,7 @@ find_package(Threads)
set_package_properties(Threads PROPERTIES TYPE REQUIRED)
# platform-specific logics
if(WIN32)
set(LIBRT wsock32 ws2_32 secur32)
set(LIBRT wsock32 ws2_32 Secur32)
elseif(NOT APPLE)
find_library(LIBM m REQUIRED)
find_library(LIBRT rt REQUIRED)
@ -167,8 +159,6 @@ endif()
# this is going to be true for anything lacking pkg-config/CMake support.
# unigbrk.h was introduced in libunistring 0.9.4, 2010-02-14.
unset(HAVE_UNISTRING_H CACHE)
find_path(UNISTRING_INCLUDE unigbrk.h)
set(CMAKE_REQUIRED_INCLUDES ${UNISTRING_INCLUDE})
check_include_file("unigbrk.h" HAVE_UNISTRING_H)
if(NOT "${HAVE_UNISTRING_H}")
message(FATAL_ERROR "Couldn't find unigbrk.h from GNU libunistring")
@ -218,7 +208,7 @@ file(GLOB COMPATSRC CONFIGURE_DEPENDS src/compat/*.c)
############################################################################
# libnotcurses-core (core shared library, core static library)
file(GLOB NCCORESRCS CONFIGURE_DEPENDS src/lib/*.c)
file(GLOB NCCORESRCS CONFIGURE_DEPENDS src/lib/*.c src/lib/*.cpp)
add_library(notcurses-core SHARED ${NCCORESRCS} ${COMPATSRC})
if(${USE_STATIC})
add_library(notcurses-core-static STATIC ${NCCORESRCS} ${COMPATSRC})
@ -365,7 +355,6 @@ if(${USE_FFMPEG})
target_include_directories(notcurses
PRIVATE
"${AVCODEC_INCLUDE_DIRS}"
"${AVDEVICE_INCLUDE_DIRS}"
"${AVFORMAT_INCLUDE_DIRS}"
"${AVUTIL_INCLUDE_DIRS}"
"${SWSCALE_INCLUDE_DIRS}"
@ -373,7 +362,6 @@ target_include_directories(notcurses
target_include_directories(notcurses-static
PRIVATE
"${AVCODEC_STATIC_INCLUDE_DIRS}"
"${AVDEVICE_STATIC_INCLUDE_DIRS}"
"${AVFORMAT_STATIC_INCLUDE_DIRS}"
"${AVUTIL_STATIC_INCLUDE_DIRS}"
"${SWSCALE_STATIC_INCLUDE_DIRS}"
@ -381,7 +369,6 @@ target_include_directories(notcurses-static
target_link_libraries(notcurses
PRIVATE
"${AVCODEC_LIBRARIES}"
"${AVDEVICE_LIBRARIES}"
"${AVFORMAT_LIBRARIES}"
"${SWSCALE_LIBRARIES}"
"${AVUTIL_LIBRARIES}"
@ -389,7 +376,6 @@ target_link_libraries(notcurses
target_link_libraries(notcurses-static
PRIVATE
"${AVCODEC_STATIC_LIBRARIES}"
"${AVDEVICE_STATIC_LIBRARIES}"
"${AVFORMAT_STATIC_LIBRARIES}"
"${SWSCALE_STATIC_LIBRARIES}"
"${AVUTIL_STATIC_LIBRARIES}"
@ -397,7 +383,6 @@ target_link_libraries(notcurses-static
target_link_directories(notcurses
PRIVATE
"${AVCODEC_LIBRARY_DIRS}"
"${AVDEVICE_LIBRARY_DIRS}"
"${AVFORMAT_LIBRARY_DIRS}"
"${SWSCALE_LIBRARY_DIRS}"
"${AVUTIL_LIBRARY_DIRS}"
@ -405,7 +390,6 @@ target_link_directories(notcurses
target_link_directories(notcurses-static
PRIVATE
"${AVCODEC_STATIC_LIBRARY_DIRS}"
"${AVDEVICE_STATIC_LIBRARY_DIRS}"
"${AVFORMAT_STATIC_LIBRARY_DIRS}"
"${SWSCALE_STATIC_LIBRARY_DIRS}"
"${AVUTIL_STATIC_LIBRARY_DIRS}"
@ -419,60 +403,6 @@ target_link_directories(notcurses PRIVATE ${OIIO_LIBRARY_DIRS})
target_link_directories(notcurses-static PRIVATE ${OIIO_STATIC_LIBRARY_DIRS})
endif()
#######################################
# libnotcurses-ffi (ffi shared library)
if(${BUILD_FFI_LIBRARY})
file(GLOB NCFFISRCS CONFIGURE_DEPENDS src/libffi/*.c src/libffi/*.cpp)
add_library(notcurses-ffi SHARED ${NCFFISRCS})
target_compile_options(notcurses-ffi PUBLIC -fkeep-inline-functions)
target_compile_definitions(notcurses-ffi PUBLIC NOTCURSES_FFI)
# don't want these on freebsd/dragonfly/osx
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_compile_definitions(notcurses-ffi
PUBLIC
_XOPEN_SOURCE=700 # wcwidth(3) requires _XOPEN_SOURCE, and is in our headers
PRIVATE
_GNU_SOURCE _DEFAULT_SOURCE
)
endif()
set_target_properties(notcurses-ffi PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
target_include_directories(notcurses-ffi
BEFORE
PRIVATE
include
src
"${CMAKE_REQUIRED_INCLUDES}"
"${PROJECT_BINARY_DIR}/include"
"${TERMINFO_INCLUDE_DIRS}"
"${libdeflate_INCLUDE_DIRS}"
"${ZLIB_INCLUDE_DIRS}"
)
target_link_libraries(notcurses-ffi
PRIVATE
"${libdeflate}"
"${ZLIB_LIBRARIES}"
"${TERMINFO_LIBRARIES}"
"${LIBM}"
"${unistring}"
"${gpm}"
"notcurses-core"
PUBLIC
Threads::Threads
"${LIBRT}"
)
target_link_directories(notcurses-ffi
PRIVATE
"${TERMINFO_LIBRARY_DIRS}"
"${libdeflate_LIBRARY_DIRS}"
"${ZLIB_LIBRARY_DIRS}"
)
endif()
############################################################################
if(${USE_CXX})
# libnotcurses++ (C++ wrappers)
@ -536,6 +466,7 @@ set(NCPP_COMPILE_OPTIONS
-fno-strict-aliasing
-ffunction-sections
-fno-rtti
-fpic
)
set(NCPP_COMPILE_DEFINITIONS_PUBLIC
@ -545,45 +476,22 @@ set(NCPP_COMPILE_DEFINITIONS_PUBLIC
target_compile_options(notcurses++
PRIVATE
${NCPP_COMPILE_OPTIONS}
-fPIC
)
target_compile_options(notcurses++-static
PRIVATE
${NCPP_COMPILE_OPTIONS}
-fPIE
)
)
target_compile_definitions(notcurses++
PUBLIC
${NCPP_COMPILE_DEFINITIONS_PUBLIC}
)
)
target_compile_definitions(notcurses++-static
PUBLIC
${NCPP_COMPILE_DEFINITIONS_PUBLIC}
)
endif()
target_compile_options(notcurses-core
PRIVATE
-fPIC
)
target_compile_options(notcurses-core-static
PRIVATE
-fPIE
)
target_compile_options(notcurses
PRIVATE
-fPIC
)
target_compile_options(notcurses-static
PRIVATE
-fPIE
)
)
file(GLOB NOTCURSES_HEADERS
CONFIGURE_DEPENDS
@ -600,6 +508,7 @@ file(GLOB NCPP_INTERNAL_HEADERS
CONFIGURE_DEPENDS
LIST_DIRECTORIES false
${PROJECT_SOURCE_DIR}/include/ncpp/internal/*.hh)
endif()
export(PACKAGE notcurses)
@ -645,13 +554,6 @@ if(${USE_CXX})
endif()
endif()
# documentation source, processed by pandoc into XHTML and man pages. declare
# them here so that we can filter out man pages for binaries which aren't
# going to be installed.
file(GLOB MANSOURCE1 CONFIGURE_DEPENDS doc/man/man1/*.md)
file(GLOB MANSOURCE3 CONFIGURE_DEPENDS doc/man/man3/*.md)
if(BUILD_EXECUTABLES)
############################################################################
# notcurses-demo
file(GLOB DEMOSRCS CONFIGURE_DEPENDS src/demo/*.c)
@ -782,6 +684,11 @@ target_link_libraries(ncneofetch
"${LIBRT}"
)
# documentation source, processed by pandoc into XHTML and man pages. declare
# them here so that we can filter out man pages for binaries which aren't
# going to be installed.
file(GLOB MANSOURCE1 CONFIGURE_DEPENDS doc/man/man1/*.md)
file(GLOB MANSOURCE3 CONFIGURE_DEPENDS doc/man/man3/*.md)
# all further binaries require multimedia and C++ support
if(${USE_CXX})
@ -824,9 +731,6 @@ target_link_libraries(ncplayer
)
endif()
endif()
else()
set(MANSOURCE1 "") # no executables were built
endif() # BUILD_EXECUTABLES
############################################################################
# testing
@ -881,18 +785,7 @@ add_test(
NAME ncpp_build_exceptions
COMMAND ncpp_build_exceptions
)
# provide an empty source
add_test(
NAME input-devnull
COMMAND sh -c "./notcurses-input -v < /dev/null"
)
# provide an ASCII file
add_test(
NAME input-text
COMMAND sh -c "./notcurses-input < ${CMAKE_SOURCE_DIR}/COPYRIGHT"
)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS notcurses-input)
LIST(APPEND TESTBINS ncpp_build ncpp_build_exceptions input-devnull input-text)
LIST(APPEND TESTBINS ncpp_build ncpp_build_exceptions)
endif()
add_test(
NAME sgr-direct
@ -906,20 +799,11 @@ add_test(
NAME rgb
COMMAND rgb
)
LIST(APPEND TESTBINS notcurses-info sgr-direct sgr-full rgb)
if(${USE_CXX})
add_test(
NAME rgbbg
COMMAND rgbbg
)
LIST(APPEND TESTBINS rgbbg)
endif()
if(${USE_QRCODEGEN})
add_test(
NAME qrcode
COMMAND qrcode
)
endif()
LIST(APPEND TESTBINS notcurses-info sgr-direct sgr-full rgb rgbbg)
set_tests_properties(
${TESTBINS} PROPERTIES RUN_SERIAL TRUE
)
@ -1017,13 +901,6 @@ configure_file(tools/notcurses.pc.in
${CMAKE_CURRENT_BINARY_DIR}/notcurses.pc
@ONLY
)
if(${BUILD_FFI_LIBRARY})
configure_file(tools/notcurses-ffi.pc.in
${CMAKE_CURRENT_BINARY_DIR}/notcurses-ffi.pc
@ONLY
)
endif()
configure_file(tools/notcurses++.pc.in
${CMAKE_CURRENT_BINARY_DIR}/notcurses++.pc
@ONLY
@ -1092,13 +969,6 @@ install(FILES
DESTINATION ${PKGCONFIG_DIR}
)
if(${BUILD_FFI_LIBRARY})
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/notcurses-ffi.pc
DESTINATION ${PKGCONFIG_DIR}
)
endif()
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/notcurses++.pc
DESTINATION ${PKGCONFIG_DIR}
@ -1112,19 +982,19 @@ list(FILTER TESTDATA EXCLUDE REGEX ".*osp$")
install(FILES ${TESTDATA} DESTINATION ${CMAKE_INSTALL_DATADIR}/notcurses)
endif()
list(FILTER MANPAGES1 EXCLUDE REGEX "tfman.1")
install(FILES ${MANPAGES1} DESTINATION ${CMAKE_INSTALL_DATADIR}/man/man1)
install(FILES ${MANPAGES3} DESTINATION ${CMAKE_INSTALL_DATADIR}/man/man3)
file(GLOB MARKDOWN CONFIGURE_DEPENDS *.md)
list(FILTER MARKDOWN EXCLUDE REGEX "INSTALL.md")
install(FILES ${MARKDOWN} DESTINATION ${CMAKE_INSTALL_DOCDIR})
if(BUILD_EXECUTABLES)
install(TARGETS notcurses-demo DESTINATION bin)
install(TARGETS notcurses-info DESTINATION bin)
install(TARGETS ncneofetch DESTINATION bin)
if(NOT WIN32)
install(TARGETS tfman DESTINATION bin)
endif()
#if(NOT WIN32)
#install(TARGETS tfman DESTINATION bin)
#endif()
if(${USE_CXX})
install(TARGETS notcurses-input DESTINATION bin)
install(TARGETS nctetris DESTINATION bin)
@ -1133,11 +1003,7 @@ install(TARGETS ncls DESTINATION bin)
install(TARGETS ncplayer DESTINATION bin)
endif()
endif()
endif() # BUILD_EXECUTABLES
if(${BUILD_FFI_LIBRARY})
LIST(APPEND INSTLIBS notcurses-ffi)
endif()
LIST(APPEND INSTLIBS notcurses-core notcurses)
if(${USE_STATIC})
LIST(APPEND INSTLIBS notcurses-core-static notcurses-static)

@ -1,4 +1,4 @@
Copyright 2019-2024 Nick Black
Copyright 2019-2021 Nick Black
Copyright 2019-2021 Marek Habersack
Copyright 2020-2021 José Luis Cruz
Copyright 2020-2021 igo95862
@ -17,7 +17,7 @@ See the License for the specific language governing permissions and
limitations under the License.
The contents of src/fetch/ncart.c are extracted from Neofetch,
copyright 2015-2024 Dylan Araps under the MIT License:
copyright 2015-2021 Dylan Araps under the MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

@ -16,12 +16,13 @@ There are no submodules. Dependencies are fairly minimal.
Install build dependencies:
`apt-get install build-essential cmake doctest-dev libavdevice-dev libdeflate-dev libgpm-dev libncurses-dev libqrcodegen-dev libswscale-dev libunistring-dev pandoc pkg-config`
`apt-get install build-essential cmake doctest-dev libavformat-dev libavutil-dev libdeflate-dev libgpm-dev libncurses-dev libqrcodegen-dev libswscale-dev libunistring-dev pandoc pkg-config`
If you only intend to build core Notcurses (without multimedia support), you
can omit `libavdevice-dev` from this list. `zlib1g-dev` can be substituted for
`libdeflate-dev`; build with `-DUSE_DEFLATE=off` in this case. If you don't
want to generate QR codes, you can omit 'libqrcodegen-dev'.
can omit `libavformat-dev`, `libavutil-dev`, and `libswscale-dev` from this
list. `zlib1g-dev` can be substituted for `libdeflate-dev`; build with
`-DUSE_DEFLATE=off` in this case. If you don't want to generate QR codes, you can
omit 'libqrcodegen-dev'.
If you want to build the Python wrappers, you'll also need:
@ -119,19 +120,19 @@ To set the C compiler, export `CC`. To set the C++ compiler, export `CXX`. The
`CMAKE_BUILD_TYPE` CMake variable can be defined to any of its standard values,
but must be `Debug` for use of `USE_COVERAGE`.
* `DFSG_BUILD`: leave out all content considered non-free under the Debian Free Software Guidelines (default `off`)
* `BUILD_TESTING`: build test targets (default `on`)
* `BUILD_EXECUTABLES`: build executables (in addition to libs) (default `on`)
* `BUILD_FFI_LIBRARY`: Build ffi library (containing all symbols which are static inline) (default `on`)
* `USE_ASAN`: build with AddressSanitizer (default `off`)
* `USE_CXX`: build C++ code (requires a C++ compiler) (default `on`)
* `USE_COVERAGE`: build coverage support (for developers, requires use of Clang) (default `off`)
* `USE_DOCTEST`: build `notcurses-tester` with Doctest, requires `BUILD_TESTING` and `USE_CXX` (default `on`)
* `USE_DOXYGEN`: build interlinked HTML documentation with Doxygen (default `off`)
* `USE_GPM`: build GPM console mouse support via libgpm (default `off`)
* `USE_MULTIMEDIA`: `ffmpeg` for FFmpeg, `oiio` for OpenImageIO, `none` for none (default `ffmpeg`)
* `DFSG_BUILD=off`: leave out all content considered non-free under the Debian Free
Software Guidelines
* `BUILD_TESTING=on`: build test targets
* `USE_ASAN=off`: build with AddressSanitizer
* `USE_CXX=on`: build C++ code (requires a C++ compiler)
* `USE_COVERAGE=off`: build coverage support (for developers, requires use of Clang)
* `USE_DOCTEST=on`: build `notcurses-tester` with Doctest, requires `BUILD_TESTING`
* `USE_DOCTEST=on` requires `USE_CXX=on`
* `USE_DOXYGEN=off`: build interlinked HTML documentation with Doxygen
* `USE_GPM=off`: build GPM console mouse support via libgpm
* `USE_MULTIMEDIA=ffmpeg`: `ffmpeg` for FFmpeg, `oiio` for OpenImageIO, `none` for none
* `oiio` cannot be used with `USE_CXX=off`
* `USE_PANDOC`: build man pages with pandoc (default `on`)
* `USE_POC`: build small, uninstalled proof-of-concept binaries (default `on`)
* `USE_QRCODEGEN`: build qrcode support via libqrcodegen (default `off`)
* `USE_STATIC`: build static libraries (in addition to shared ones) (default `on`)
* `USE_PANDOC=on`: build man pages with pandoc
* `USE_POC=on`: build small, uninstalled proof-of-concept binaries
* `USE_QRCODEGEN=off`: build qrcode support via libqrcodegen
* `USE_STATIC=on`: build static libraries (in addition to shared ones)

@ -1,71 +1,7 @@
This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 3.0.10 (upcoming)
* We now normalize the return of `nl_langinfo()` according to the behavior
of glibc's `_nl_normalize_charset()`, supporting some atypical synonyms
of `UTF-8`.
* Fixed a bug in `ncsixel_as_rgba()` (called by `ncvisual_from_sixel()`)
that broke loading of sixels having more than 12 rows (sixel generation
from images worked fine). Thanks, waveplate!
* Reject illegal geometries in `ncvisual_from_*()`.
* 3.0.9 (2022-12-10)
* Eliminated infinite loop in `ncplane_move_family_above()`.
Thanks, drewt!
* 3.0.8 (2022-04-06)
* Bugfix release, but also support curled underlines in Contour.
* 3.0.7 (2022-02-20)
* Tab characters may now be used with `ncplane_put*()`. See
`ncplane_output.3` for more information.
* 3.0.6 (2022-02-09)
* `ncplane_set_[fb]channel()`, `ncplane_[fb]channel()`,
`ncplane_channels()`, `ncplane_set_channels()`,
`ncchannels_set_[fb]channel()`, and `ncchannels_[fb]channel()` now
function only on the 28 alpha + coloring bits of their respective
channels, which is almost certainly what you wanted in the first place.
* Restore `nccell_set_[fb]channel()` and friends, using these semantics.
* 3.0.5 (2022-01-21)
* The Hyper and Super modifiers are now supported. CapsLock and NumLock
can further be disambiguated when using the Kitty protocol. The
new functions `ncinput_super_p()` and friends have been added.
* `ncinput` has a new field, `modifiers`. The old `alt`, `shift`, and
`ctrl` booleans are now deprecated, and will be removed in 4.0.
* `ncmenu_section` **must** now specify any expected modifiers for their
shortucts using `modifiers`. Setting any of `alt`, `shift`, or
`ctrl` will see `ncmenu_create()` fail.
* `ncinput_equal_p()` considers `NCTYPE_UNKNOWN` equal to `NCTYPE_PRESS`.
* Added `ncpalette_get()` for orthogonality's sake.
* 3.0.4 (2022-01-08)
* We now use level 2 of `XTMODKEYS`, providing better differentiation
of keyboard modifiers. We now unpack the Meta modifier.
* Added `ncinput_shift_p()`, `ncinput_alt_p()`, `ncinput_ctrl_p()`,
and `ncinput_meta_p()` to test for various modifiers in `ncinput`s.
* When support is advertised, the 1016 mouse protocol will be used
to provide pixel-level detail. See the `{yx}px` fields of `ncinput`.
* 3.0.3 (2022-01-02)
* No user-visible changes to the API, but Sixel quantization has been
rewritten. It is now substantially faster, though quality has gone
down for some images. I'll be working on bringing it back for 3.0.4.
* 3.0.2 (2021-12-21)
* Added `ncplane_cursor_y()` and `ncplane_cursor_x()`.
* Added `NCOPTION_SCROLLING`, equivalent to calling
`ncplane_set_scrolling(true)` on the standard plane.
* Added `NCOPTION_CLI_MODE`, an alias for the bitwise OR of
`NCOPTION_SCROLLING`, `NCOPTION_NO_CLEAR_BITMAPS`,
`NCOPTION_NO_ALTERNATE_SCREEN`, and `NCOPTION_PRESERVE_CURSOR`.
* Added `ncvisual_from_sixel()`.
* The control sequence corresponding to a pixel-blitted `ncvisual()`
can be retrieved by using `ncplane_at_yx()` on the sprixel plane.
* 3.0.1 (2021-12-14)
* 3.0.1 (not yet released)
* Added the `NCPLANE_OPTION_VSCROLL` flag. Creating an `ncplane` with this
flag is equivalent to immediately calling `ncplane_set_scrolling(true)`.
* Added the `NCPLANE_OPTION_AUTOGROW` flag and the `ncplane_set_autogrow()`

@ -13,9 +13,9 @@ replacement for NCURSES on existing systems.
for more information, see [dankwiki](https://nick-black.com/dankwiki/index.php/Notcurses)
and the [man pages](https://notcurses.com). in addition, there is
[Doxygen](https://notcurses.com/html/) output. To subscribe to the
[mailing list](https://groups.google.com/forum/#!forum/notcurses), send an email
to notcurses+subscribe@googlegroups.com (the email contents don't matter). i wrote a coherent
[Doxygen](https://notcurses.com/html/) output. there is a
[mailing list](https://groups.google.com/forum/#!forum/notcurses) which can be reached
via notcurses@googlegroups.com. i wrote a coherent
[guidebook](https://nick-black.com/htp-notcurses.pdf), which is available for
free download (or [paperback purchase](https://amazon.com/dp/B086PNVNC9)).
@ -82,8 +82,8 @@ Why use this non-standard library?
and transparent regions. All APIs natively support 24-bit color, quantized
down as necessary for the terminal.
* Portable support for bitmapped graphics, using Sixel, Kitty,
and even the Linux framebuffer console.
* Portable support for bitmapped graphics, whether using Sixel, Kitty, the iTerm2
protocol, or even the Linux framebuffer console.
* Support for unambiguous [keyboard protocols](https://sw.kovidgoyal.net/kitty/keyboard-protocol/).
@ -112,14 +112,14 @@ may well be possible to use still older versions. Let me know of any successes!
* (build+runtime) GNU [libunistring](https://www.gnu.org/software/libunistring/) 0.9.10+
* (OPTIONAL) (build+runtime) [libgpm](https://www.nico.schottelius.org/software/gpm/) 1.20+
* (OPTIONAL) (build+runtime) From QR-Code-generator: [libqrcodegen](https://github.com/nayuki/QR-Code-generator) 1.5.0+
* (OPTIONAL) (build+runtime) From [FFmpeg](https://www.ffmpeg.org/): libswscale 5.0+, libavformat 57.0+, libavutil 56.0+, libavdevice 57.0+
* (OPTIONAL) (build+runtime) From [FFmpeg](https://www.ffmpeg.org/): libswscale 5.0+, libavformat 57.0+, libavutil 56.0+
* (OPTIONAL) (build+runtime) [OpenImageIO](https://github.com/OpenImageIO/oiio) 2.15.0+, requires C++
* (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](https://pypi.org/project/cffi/) 1.13.2+, [pypandoc](https://pypi.org/project/pypandoc/) 1.5+
* (runtime) Linux 2.6+, FreeBSD 11+, DragonFly BSD 5.9+, Windows 10 v1093+, or macOS 11.4+
* (runtime) Linux 5.3+, FreeBSD 11+, DragonFly BSD 5.9+, Windows 10 v1093+, or macOS 11.4+
More information on building and installation is available in [INSTALL.md](INSTALL.md).
[Here's more information](INSTALL.md) on building and installation.
### Wrappers
@ -131,9 +131,6 @@ others are external.
| -------- | ----------------------------- | ---------- |
| Ada | Jeremy Grosser | [JeremyGrosser/notcursesada](https://github.com/JeremyGrosser/notcursesada) |
| C++ | Marek Habersack, nick black | internal |
| Dart | Nelson Fernandez | [kascote/dart_notcurses](https://github.com/kascote/dart_notcurses) |
| Julia | Dheepak Krishnamurthy | [kdheepak/Notcurses.jl](https://github.com/kdheepak/Notcurses.jl) |
| Nim | Michael S. Bradley, Jr. | [michaelsbradleyjr/nim-notcurses](https://github.com/michaelsbradleyjr/nim-notcurses) |
| Python | nick black | internal |
| Python | igo95862 | internal |
| Rust | José Luis Cruz | [dankamongmen/libnotcurses-sys](https://github.com/dankamongmen/libnotcurses-sys) |
@ -141,7 +138,7 @@ others are external.
## Included tools
Nine executables are installed as part of Notcurses:
Nine binaries are installed as part of Notcurses:
* `ncls`: an `ls` that displays multimedia in the terminal
* `ncneofetch`: a [neofetch](https://github.com/dylanaraps/neofetch) ripoff
* `ncplayer`: renders visual media (images/videos)
@ -150,7 +147,6 @@ Nine executables are installed as part of Notcurses:
* `notcurses-info`: detect and print terminal capabilities/diagnostics
* `notcurses-input`: decode and print keypresses
* `notcurses-tester`: unit testing
* `tfman`: a swank manual browser
To run `notcurses-demo` from a checkout, provide the `data` directory via
the `-p` argument. Demos requiring data files will otherwise abort. The base
@ -176,7 +172,7 @@ directly:
* [Differences from](doc/CURSES.md) Curses and adapting Curses programs.
If you (understandably) want to avoid the large Pandoc stack, but still enjoy
manual pages, I publish a tarball with generated man/XHTML along with
manual page goodness, I publish a tarball with generated man/XHTML along with
each release. Download it, and install the contents as you deem fit.
## Environment notes
@ -256,9 +252,10 @@ If things break or seem otherwise lackluster, **please** consult the
<details>
<summary>Can I write a CLI program (scrolling, fits in with the shell, etc.)
with Notcurses?</summary>
Yes! Use the <code>NCOPTION_CLI_MODE</code> flag (an alias for several
real flags; see <a href="https://notcurses.com/notcurses_init.3.html"><code>notcurses_init(1)</code></a>
for more information). You still must explicitly render.
Yes! Use the flags <code>NCOPTION_NO_ALTERNATE_SCREEN</code>,
<code>NCOPTION_NO_CLEAR_BITMAPS</code>, and <code>NCOPTION_PRESERVE_CURSOR</code>,
and call <code>ncplane_set_scrolling()</code> on the standard plane. You
still must explicitly render.
</details>
<details>
@ -279,10 +276,10 @@ If things break or seem otherwise lackluster, **please** consult the
<details>
<summary>We're paying by the electron, and have no C++ compiler. Can we still
enjoy Notcurses goodness?</summary>
Some of it! You won't be able to build several executables, nor the NCPP C++
Some of it! You won't be able to build several binaries, nor the NCPP C++
wrappers, nor can you build with the OpenImageIO multimedia backend (OIIO
ships C++ headers). You'll be able to build the main library, though, as
well as <code>notcurses-demo</code> (and maybe a few other programs).
well as <code>notcurses-demo</code> (and maybe a few other binaries).
Use <code>-DUSE_CXX=off</code>.
</details>
@ -297,7 +294,8 @@ If things break or seem otherwise lackluster, **please** consult the
<details>
<summary>Does it work with hardware terminals?</summary>
With the correct <code>TERM</code> value, many hardware terminals are
supported. In general, if the terminfo database entry indicates mandatory
supported. The VT100 is sadly unsupported due to its extensive need for
delays. In general, if the terminfo database entry indicates mandatory
delays, Notcurses will not currently support that terminal properly. It's
known that Notcurses can drive the VT320 and VT340, including Sixel graphics
on the latter.
@ -431,6 +429,13 @@ If things break or seem otherwise lackluster, **please** consult the
handy if you've got a reference to a valid <code>nccell</code> anyway.
</details>
<details>
<summary>I compiled with AddressSanitizer, and ASAN throws an exception on
program exit.</summary>
Yeah, I think it has something to do with our signal handling, don't know
yet, sorry.
</details>
<details>
<summary>I ran my Notcurses program under <code>valgrind</code>/ASAN, and
it shows memory leaks from <code>libtinfo.so</code>, what's up with that?</summary>

@ -69,7 +69,6 @@ relies on the font. Patches to correct/complete this table are very welcome!
| [Alacritty](https://github.com/alacritty/alacritty) | ✅ | ✅ |❌ |`TERM=alacritty` `COLORTERM=24bit` | [Sixel support WIP](https://github.com/ayosec/alacritty/tree/graphics) |
| [cool-retro-term](https://github.com/Swordfish90/cool-retro-term) | ❌ | ❌ |✅ | `TERM=xterm-256color` `COLORTERM=24bit` | Accepts RGB. No `initc` despite claiming to be XTerm. |
| [Contour](https://github.com/christianparpart/contour) | ✅ | ✅ |✅ |`TERM=contour` | Sixel support. |
| [Darktile](https://github.com/liamg/darktile) | ? | ? | ? | `TERM=xterm-256color` | ? |
| [ETerm](https://github.com/mej/Eterm) | | | | `TERM=Eterm` | Doesn't reply to Send Device Attributes |
| [FBterm](https://github.com/zhangyuanwei/fbterm) | ❌ | ? |? |`TERM=fbterm` | 256 colors, no RGB color. |
| [foot](https://codeberg.org/dnkl/foot) | ✅ | ✅ |✅ |`TERM=foot` | Sixel support. |
@ -91,7 +90,7 @@ relies on the font. Patches to correct/complete this table are very welcome!
| [Tabby](https://github.com/Eugeny/tabby) | ? | ? | ? | ? | |
| [Terminal.app](https://en.wikipedia.org/wiki/Terminal_(macOS)) | ✅ | ❌ | ❌ | `TERM=xterm-256color`| No RGB; no `ccc` despite wanting `xterm-256color`. |
| [Terminator](https://github.com/software-jessies-org/jessies/wiki/Terminatorhttps://github.com/software-jessies-org/jessies/wiki/Terminator) | ✅ | ? |? | ? | |
| [Terminology](https://github.com/borisfaure/terminology) | ❌ | ❌ |✅ | `TERM=terminology` | Identified via DA3 before XTVERSION. 256 colors, no RGB. |
| [Terminology](https://github.com/borisfaure/terminology) | ❌ | ❌ |✅ | `TERM=terminology` | Identified via DA3. 256 colors, no RGB. |
| [Tilda](https://github.com/lanoxx/tilda) | | ? |? | ? | |
| [tmux](https://github.com/tmux/tmux/wiki) | ✅ | ❌ |n/a |`TERM=tmux-256color` `COLORTERM=24bit`| `tmux.conf` must apply `Tc`; see below. `bce` is available with the `tmux-256color-bce` definition. |
| [WezTerm](https://github.com/wez/wezterm) | ✅ | ✅ |? |`TERM=wezterm` `COLORTERM=24bit` | See below. |
@ -104,21 +103,6 @@ relies on the font. Patches to correct/complete this table are very welcome!
Note that `xfce4-terminal`, `gnome-terminal`, etc. are essentially skinning
atop the common GNOME [VTE ("Virtual TErminal")](https://gitlab.gnome.org/GNOME/vte) library.
### XTerm
XTerm is extensively configurable. I recommend the following settings, assuming
a compatible build:
```
xterm*directColor: true
XTerm*allowTcapOps: true
XTerm*disallowedTcapOps:
XTerm*decGraphicsID: 340
XTerm*decTerminalID: 420
XTerm*numColorRegisters: 256
XTerm*sixelScrolling: true
```
### Kitty
Kitty has some interesting, atypical behaviors. Foremost among these is that
@ -171,7 +155,7 @@ You'll then need `COLORTERM=24bit` defined within your tmux environment.
### iTerm2
You're recommended to change "Report terminal type" to `iterm2`.
You're recommented to change "Report terminal type" to `iterm2`.
You're recommended to enable "Use Unicode version 9+ widths" under
`Profiles/Text`.

@ -131,16 +131,6 @@ typedef enum {
// eventually preventing Notcurses from processing terminal messages.
#define NCOPTION_DRAIN_INPUT 0x0100
// Prepare the standard plane in scrolling mode, useful for CLIs. This is
// equivalent to calling ncplane_set_scrolling(notcurses_stdplane(nc), true).
#define NCOPTION_SCROLLING 0x0200ull
// "CLI mode" is just setting these four options.
#define NCOPTION_CLI_MODE (NCOPTION_NO_ALTERNATE_SCREEN \
|NCOPTION_NO_CLEAR_BITMAPS \
|NCOPTION_PRESERVE_CURSOR \
|NCOPTION_SCROLLING)
// Configuration for notcurses_init().
typedef struct notcurses_options {
// The name of the terminfo database entry describing this terminal. If NULL,
@ -729,7 +719,7 @@ notcurses_get_blocking(struct notcurses* n, ncinput* ni){
static inline bool
ncinput_nomod_p(const ncinput* ni){
return !(ni->modifiers);
return !ni->alt && !ni->ctrl && !ni->shift;
}
```
@ -1272,20 +1262,6 @@ int ncplane_cursor_move_rel(struct ncplane* n, int y, int x);
// Get the current position of the cursor within n. y and/or x may be NULL.
void ncplane_cursor_yx(const struct ncplane* n, int* restrict y, int* restrict x);
static inline unsigned
ncplane_cursor_y(const struct ncplane* n){
unsigned y;
ncplane_cursor_yx(n, &y, NULL);
return y;
}
static inline unsigned
ncplane_cursor_x(const struct ncplane* n){
unsigned x;
ncplane_cursor_yx(n, NULL, &x);
return x;
}
// Replace the cell at the specified coordinates with the provided cell 'c',
// and advance the cursor by the width of the cell (but not past the end of the
// plane). On success, returns the number of columns the cursor was advanced.
@ -1303,7 +1279,7 @@ ncplane_putc(struct ncplane* n, const nccell* c){
// This works whether the underlying char is signed or unsigned.
static inline int
ncplane_putchar_yx(struct ncplane* n, int y, int x, char c){
nccell ce = CELL_INITIALIZER(c, ncplane_styles(n), ncplane_channels(n));
nccell ce = CELL_INITIALIZER(c, ncplane_attr(n), ncplane_channels(n));
return ncplane_putc_yx(n, y, x, &ce);
}
@ -1520,6 +1496,14 @@ of [Unicode Annex #14](http://www.unicode.org/reports/tr14/tr14-34.html).
// determine whether the write completed by inspecting '*bytes'.
int ncplane_puttext(struct ncplane* n, int y, ncalign_e align,
const char* text, size_t* bytes);
// Like ncplane_puttext(), we're going for an orderly presentation of (possibly
// bulk) text. Unlike ncplane_puttext(), we're going to grow the plane as
// necessary to present it. If the plane is scrolling, we'll grow the bottom
// out; we'll otherwise grow out to the right. Either way, no actual scrolling
// will occur.
int ncplane_growtext(struct ncplane* n, int y, ncalign_e align,
const char* text, size_t* bytes);
```
Lines and boxes can be drawn, interpolating their colors between their two
@ -1804,40 +1788,26 @@ Helpers are provided to manipulate an `ncplane`'s `channels` member. They are
all implemented in terms of the lower-level [Channels API](#channels).
```c
// Get the current colors and alpha values for ncplane 'n'.
// Get the current channels or attribute word for ncplane 'n'.
uint64_t ncplane_channels(const struct ncplane* n);
uint16_t ncplane_attr(const struct ncplane* n);
// Get the current styling for the ncplane 'n'.
uint16_t ncplane_styles(const struct ncplane* n);
// Set the alpha and coloring bits of the plane's current channels from a
// 64-bit pair of channels.
API void ncplane_set_channels(struct ncplane* n, uint64_t channels)
__attribute__ ((nonnull (1)));
// Set an entire 32-bit channel of the plane 'n'
int ncplane_set_fchannel(struct ncplane* n, uint32_t channel);
int ncplane_set_bchannel(struct ncplane* n, uint32_t channel);
// Extract the background alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
static inline uint32_t
ncplane_bchannel(const struct ncplane* n){
return ncchannels_bchannel(ncplane_channels(n));
// Extract the 32-bit working background channel from an ncplane.
static inline unsigned
ncplane_bchannel(const struct ncplane* nc){
return ncchannels_bchannel(ncplane_channels(nc));
}
// Extract the foreground alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
static inline uint32_t
ncplane_fchannel(const struct ncplane* n){
return ncchannels_fchannel(ncplane_channels(n));
// Extract the 32-bit working foreground channel from an ncplane.
static inline unsigned
ncplane_fchannel(const struct ncplane* nc){
return ncchannels_fchannel(ncplane_channels(nc));
}
// Set the background alpha and coloring bits of the plane's current
// channels from a single 32-bit value.
uint64_t ncplane_set_bchannel(struct ncplane* n, uint32_t channel);
__attribute__ ((nonnull (1)));
// Set the foreground alpha and coloring bits of the plane's current
// channels from a single 32-bit value.
uint64_t ncplane_set_fchannel(struct ncplane* n, uint32_t channel);
// Extract 24 bits of working foreground RGB from an ncplane, shifted to LSBs.
static inline unsigned
ncplane_fg_rgb(const struct ncplane* nc){
@ -1900,8 +1870,8 @@ void ncplane_set_fg_default(struct ncplane* n);
void ncplane_set_bg_default(struct ncplane* n);
// Provide a palette index on [0..255].
int ncplane_set_fg_palindex(struct ncplane* n, unsigned idx);
int ncplane_set_bg_palindex(struct ncplane* n, unsigned idx);
int ncplane_set_fg_palindex(struct ncplane* n, int idx);
int ncplane_set_bg_palindex(struct ncplane* n, int idx);
```
## Cells
@ -2264,15 +2234,13 @@ Helpers are provided to manipulate an `nccell`'s `channels` member. They are
all implemented in terms of the lower-level [Channels API](#channels).
```c
// Extract the background alpha and coloring bits from a cell's channels
// as a single 32-bit value.
// Extract the 32-bit background channel from a cell.
static inline uint32_t
nccell_bchannel(const nccell* cl){
return ncchannels_bchannel(cl->channels);
}
// Extract the foreground alpha and coloring bits from a cell's channels
// as a single 32-bit value.
// Extract the 32-bit foreground channel from a cell.
static inline uint32_t
nccell_fchannel(const nccell* cl){
return ncchannels_fchannel(cl->channels);
@ -2830,10 +2798,10 @@ struct ncprogbar* ncprogbar_create(struct ncplane* n, const ncprogbar_options* o
#define NCPROGBAR_OPTION_RETROGRADE 0x0001u // proceed left/down
typedef struct ncprogbar_options {
uint32_t ulchannel; // upper-left channel. in the context of a progress bar,
uint32_t urchannel; // "up" is the direction we are progressing towards, and
uint32_t blchannel; // "bottom" is the direction of origin. for monochromatic
uint32_t brchannel; // bar, all four channels ought be the same.
// channels for the maximum and minimum points. linear interpolation will be
// applied across the domain between these two.
uint64_t maxchannels;
uint64_t minchannels;
uint64_t flags;
} ncprogbar_options;
@ -3157,31 +3125,13 @@ ncchannel_set_default(uint32_t* channel){
return *channel &= ~NC_BGDEFAULT_MASK;
}
// Extract the background alpha and coloring bits from a 64-bit channel pair.
static inline uint64_t
ncchannels_channels(uint64_t channels){
return ncchannels_bchannel(channels) |
((uint64_t)ncchannels_fchannel(channels) << 32u);
}
// Set the alpha and coloring bits of a channel pair from another channel pair.
static inline uint64_t
ncchannels_set_channels(uint64_t* dst, uint64_t channels){
ncchannels_set_bchannel(dst, channels & 0xffffffffull);
ncchannels_set_fchannel(dst, (channels >> 32u) & 0xffffffffull);
return *dst;
}
// Extract the background alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
// Extract the 32-bit background channel from a channel pair.
static inline unsigned
ncchannels_bchannel(uint64_t channels){
return channels & (NC_BG_RGB_MASK | NC_BG_PALETTE |
NC_BGDEFAULT_MASK | NC_BG_ALPHA_MASK);
return channels & 0xfffffffflu;
}
// Extract the foreground alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
// Extract the 32-bit foreground channel from a channel pair.
static inline uint32_t
ncchannels_fchannel(uint64_t channels){
return ncchannels_bchannel(channels >> 32u);
@ -3193,20 +3143,10 @@ static inline uint64_t
ncchannels_reverse(uint64_t channels){
const uint64_t raw = ((uint64_t)ncchannels_bchannel(channels) << 32u) +
ncchannels_fchannel(channels);
const uint64_t statemask = ((NC_NOBACKGROUND_MASK | NC_BG_ALPHA_MASK) << 32u) |
NC_NOBACKGROUND_MASK | NC_BG_ALPHA_MASK;
const uint64_t statemask = (NC_NOBACKGROUND_MASK | NC_FG_ALPHA_MASK |
NC_BG_ALPHA_MASK | (NC_NOBACKGROUND_MASK >> 32u));
uint64_t ret = raw & ~statemask;
ret |= channels & statemask;
if(ncchannels_bg_alpha(ret) != NCALPHA_OPAQUE){
if(!ncchannels_bg_rgb_p(ret)){
ncchannels_set_bg_alpha(&ret, NCALPHA_OPAQUE);
}
}
if(ncchannels_fg_alpha(ret) != NCALPHA_OPAQUE){
if(!ncchannels_fg_rgb_p(ret)){
ncchannels_set_fg_alpha(&ret, NCALPHA_OPAQUE);
}
}
return ret;
}
@ -3234,32 +3174,14 @@ ncchannels_bg_alpha(uint64_t channels){
return ncchannel_alpha(channels_bchannel(channels));
}
// Extract the 24-bit RGB value from a 32-bit channel.
// Only valid if ncchannel_rgb_p() would return true for the channel.
static inline uint32_t
ncchannel_rgb(uint32_t channel){
return channel & NC_BG_RGB_MASK;
}
// Extract the three 8-bit R/G/B components from a 32-bit channel.
// Only valid if ncchannel_rgb_p() would return true for the channel.
static inline uint32_t
ncchannel_rgb8(uint32_t channel, unsigned* restrict r, unsigned* restrict g,
unsigned* restrict b){
*r = ncchannel_r(channel);
*g = ncchannel_g(channel);
*b = ncchannel_b(channel);
return channel;
}
// Extract 24 bits of foreground RGB from 'channels', split into subchannels.
static inline uint32_t
static inline unsigned
ncchannels_fg_rgb8(uint64_t channels, unsigned* r, unsigned* g, unsigned* b){
return ncchannel_rgb8(channels_fchannel(channels), r, g, b);
}
// Extract 24 bits of background RGB from 'channels', split into subchannels.
static inline uint32_t
static inline unsigned
ncchannels_bg_rgb8(uint64_t channels, unsigned* r, unsigned* g, unsigned* b){
return ncchannel_rgb8(channels_bchannel(channels), r, g, b);
}
@ -3418,9 +3340,6 @@ struct ncvisual* ncvisual_from_bgra(struct notcurses* nc, const void* bgra,
struct ncvisual* ncvisual_from_palidx(const void* data, int rows,
int rowstride, int cols, int palsize,
int pstride, const uint32_t* palette);
// Construct an ncvisual from a nul-terminated Sixel control sequence.
struct ncvisual* ncvisual_from_sixel(const char* s, unsigned leny, unsigned lenx);
```
`ncvisual`s can also be loaded from the contents of a plane:
@ -3671,6 +3590,7 @@ have only one frame), until it returns `NCERR_EOF`:
// Open a visual at 'file', extracting a codec and parameters.
struct ncvisual* ncvisual_from_file(const char* file);
// extract the next frame from an ncvisual. returns NCERR_EOF on end of file,
// and NCERR_SUCCESS on success, otherwise some other NCERR.
int ncvisual_decode(struct ncvisual* nc);

1
cffi/.gitignore vendored

@ -1 +0,0 @@
.eggs/

@ -1,4 +1,4 @@
Copyright 2019-2022 Nick Black
Copyright 2019-2021 Nick Black
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

@ -1,6 +1,6 @@
% notcurses-pydemo(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -49,7 +49,7 @@ except ImportError:
setup(
name="notcurses",
version="3.0.9",
version="3.0.1",
packages=['notcurses'],
scripts=['notcurses-pydemo', 'ncdirect-pydemo'],
package_dir={'': 'src'},

@ -1,207 +0,0 @@
From 1af86bbfa0a2d7e50d9535834b3bfc241bf334d8 Mon Sep 17 00:00:00 2001
From: nick black <dankamongmen@gmail.com>
Date: Mon, 24 Jan 2022 00:33:21 -0500
Subject: [PATCH] console: answer OSC 10 and 11
XTerm and many other terminal emulators implement
Operating System Commands 10 and 11, allowing the
default foreground/background to be set and queried.
Extend the VT control sequence parser to recognize
and support these queries.
The VT already implements two OSCs, for changing
and resetting the palette. In doing so (many years
ago), it broke from the ANSI standard, and did not
require an ST terminator. Read all about it in
xterm(1) (see "brokenLinuxOSC"). I have followed this
grand tradition, and similarly not required ST.
Note that ST can still be safely sent by a client
program, as the VT consumes it. Indeed, my Notcurses
library does exactly this.
"Don't VTs always have black backgrounds?" Nope, you
can change the default background color with any
number of ANSI sequences, and then use the VT's
Private CSI "ESC [ 8 ]" to make the current color pair
the default attributes. Try it at home with, say:
printf %b '\e[46m' '\e[8]' '\e[H\e[J'
The response follows XTerm's effective lead, using
%02x/%02x/%02x to format the RGB value, rather than
the %02x%02x%02x preferred by the preexisting
P (set palette) OSC. This was done to simplify
client libraries. Note that the spirit of the law,
that the reply is a "control sequence of the same
form which can be used to set", cannot be easily
honored given the semantics of the Linux private CSI
sequence. So it goes.
As a result, notcurses-info now properly detects the
default colors dynamically. Where it used to say:
no known default fg no known default bg
It now says on boot:
notcurses 3.0.4 on Linux 5.16.0nlb VT
...
default fg 0xaaaaaa default bg 0x000000
and after a change like that above:
notcurses 3.0.4 on Linux 5.16.0nlb VT
...
default fg 0xaaaaaa default bg 0xaa5500
This is necessary to produce readable multicolor text
while respecting the user's background choice.
Signed-off-by: nick black <dankamongmen@gmail.com>
---
drivers/tty/vt/vt.c | 67 ++++++++++++++++++++++++++++------
include/linux/console_struct.h | 1 +
2 files changed, 58 insertions(+), 11 deletions(-)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index f8c87c4d7399..a10629bcaaa1 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1878,6 +1878,31 @@ int mouse_reporting(void)
return vc_cons[fg_console].d->vc_report_mouse;
}
+/* handle the OSC query specified by vc->vc_oscmd. we currently handle only 10
+ * and 11 (default foreground and default background, respectively).
+ */
+static void handle_osc_query(struct tty_struct *tty, const struct vc_data *vc)
+{
+ char buf[20];
+ int len, idx;
+ /* response payload conforms to XTerm: %02x/%02x/%02x for R, G, and B. */
+ switch (vc->vc_oscmd) {
+ case 10: /* get default foreground */
+ idx = vc->vc_def_color & 0x0f;
+ break;
+ case 11: /* get default background */
+ idx = (vc->vc_def_color & 0xf0) >> 4;
+ break;
+ default:
+ return;
+ }
+ /* transpose internal BGR to RGB on output */
+ len = snprintf(buf, sizeof(buf), "\x1b]%d;rgb:%02x/%02x/%02x\x1b\\",
+ vc->vc_oscmd, vc->vc_palette[idx * 3 + 2],
+ vc->vc_palette[idx * 3 + 1], vc->vc_palette[idx * 3]);
+ respond_string(buf, len, tty->port);
+}
+
/* console_lock is held */
static void set_mode(struct vc_data *vc, int on_off)
{
@@ -2075,8 +2100,8 @@ static void restore_cur(struct vc_data *vc)
}
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
- EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd,
- ESpalette, ESosc, ESapc, ESpm, ESdcs };
+ EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore,
+ ESpalette, ESosc, ESoscmd, ESoscparam, ESapc, ESpm, ESdcs };
/* console_lock is held (except via vc_init()) */
static void reset_terminal(struct vc_data *vc, int do_clear)
@@ -2230,7 +2255,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
vc->vc_state = ESsquare;
return;
case ']':
- vc->vc_state = ESnonstd;
+ vc->vc_state = ESosc;
return;
case '_':
vc->vc_state = ESapc;
@@ -2287,7 +2312,10 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
return;
}
return;
- case ESnonstd:
+ case ESosc:
+ /* Operating System Commands are traditionally terminated with an ST
+ * or a BEL, but Linux historically eschews said terminators.
+ */
if (c=='P') { /* palette escape sequence */
for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
vc->vc_par[vc->vc_npar] = 0;
@@ -2297,9 +2325,10 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
} else if (c=='R') { /* reset palette */
reset_palette(vc);
vc->vc_state = ESnormal;
- } else if (c>='0' && c<='9')
- vc->vc_state = ESosc;
- else
+ } else if (isdigit(c)) {
+ vc->vc_oscmd = c - '0';
+ vc->vc_state = ESoscmd;
+ } else
vc->vc_state = ESnormal;
return;
case ESpalette:
@@ -2348,7 +2377,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
if (c == ';' && vc->vc_npar < NPAR - 1) {
vc->vc_npar++;
return;
- } else if (c>='0' && c<='9') {
+ } else if (isdigit(c)) {
vc->vc_par[vc->vc_npar] *= 10;
vc->vc_par[vc->vc_npar] += c - '0';
return;
@@ -2556,7 +2585,23 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
return;
case ESapc:
return;
- case ESosc:
+ case ESoscmd: /* extract the first OSC param, the command */
+ if (isdigit(c)) {
+ vc->vc_oscmd *= 10;
+ vc->vc_oscmd += c - '0';
+ } else if (c == ';') {
+ vc->vc_state = ESoscparam;
+ } else {
+ vc->vc_state = ESnormal;
+ }
+ return;
+ case ESoscparam: /* extract second OSC param */
+ /* All recognized numeric OSC commands take only '?', indicating a query.
+ * See note above regarding ESosc about lack of OSC terminator ST.
+ */
+ if (c == '?')
+ handle_osc_query(tty, vc);
+ vc->vc_state = ESnormal;
return;
case ESpm:
return;
@@ -3441,8 +3486,8 @@ static void con_cleanup(struct tty_struct *tty)
}
static int default_color = 7; /* white */
-static int default_italic_color = 2; // green (ASCII)
-static int default_underline_color = 3; // cyan (ASCII)
+static int default_italic_color = 2; /* green */
+static int default_underline_color = 3; /* cyan */
module_param_named(color, default_color, int, S_IRUGO | S_IWUSR);
module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index d5b9c8d40c18..6d4fa51b62de 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -128,6 +128,7 @@ struct vc_data {
/* VT terminal data */
unsigned int vc_state; /* Escape sequence parser state */
unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */
+ unsigned int vc_oscmd; /* Operating System Command selector */
/* data for manual vt switching */
struct vt_mode vt_mode;
struct pid *vt_pid;
--
2.34.1

@ -38,7 +38,7 @@ PROJECT_NAME = Notcurses
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 3.0.9
PROJECT_NUMBER = 3.0.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

@ -38,7 +38,7 @@
</a>
</div>
<iframe align="right" width="560" height="315" src="https://www.youtube.com/embed/dcjkezf1ARY" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2><a href="https://nick-black.com/dankwiki/index.php/Notcurses">notcurses</a> manual pages (<a href="https://github.com/dankamongmen/notcurses/releases/tag/v3.0.9">v3.0.9</a>)</h2>
<h2><a href="https://nick-black.com/dankwiki/index.php/Notcurses">notcurses</a> manual pages (<a href="https://github.com/dankamongmen/notcurses/releases/tag/v3.0.1">v3.0.1</a>)</h2>
<a href="notcurses.3.html">notcurses(3)</a>—a blingful TUI library<br/>
<h3>Executables (section 1)</h3>
<a href="ncls.1.html">ncls</a>—list files, displaying multimedia along with them<br/>
@ -89,7 +89,7 @@
<center>
<small>
“Profound changes are imminent in the ancient craft of the Beautiful.”
© 2019-2022 <a href="mailto:nickblack@linux.com">nickblack@linux.com</a>
© 2019-2021 <a href="mailto:nickblack@linux.com">nickblack@linux.com</a>
</small>
</center>
</div>

@ -1,6 +1,6 @@
% ncls(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -21,7 +21,7 @@ ncls - List paths with rendering of multimedia
**-l**: use a long listing format.
**-L**: dereference symbolic links
**-L**: when showing file information for a symbolic link, show information for the file the link references rather than for the link itself.
**-R**: list subdirectories recursively.

@ -1,6 +1,6 @@
% ncneofetch(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% ncplayer(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,10 +1,10 @@
% nctetris(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
nctetris - Тетрис in the terminal
nctetris - Render images and video to a terminal
# SYNOPSIS
@ -12,7 +12,7 @@ nctetris - Тетрис in the terminal
# DESCRIPTION
**nctetris** implements a Tetris clone using Notcurses.
**nctetris** implements Tetris using Notcurses.
The goal is to complete horizontal lines, without allowing tetriminos to
reach the top of the screen. The falling tetrimino can be rotated counter-

@ -1,6 +1,6 @@
% notcurses-demo(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -74,7 +74,7 @@ terminal, and will refuse to run in anything smaller than 80x24.
**-V**|**--version**: Print the program name and version, and exit with success.
***demospec***: Select which demos to run, and what order to run them in. The
default is **ixetunchdmbkywjgarvlsfqzo**. See above for a list of demos.
default is **ixetunchmdbkywjgarvlsfqzo**. See above for a list of demos.
Default margins are all 0, and thus the full screen will be rendered. Using
**-m**, margins can be supplied. Provide a single number to set all four margins

@ -1,6 +1,6 @@
% notcurses-info(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -45,6 +45,7 @@ The next five lines describe properties of the terminal environment:
* af: Foreground color can be set
* ab: Background color can be set
* sum: Synchronized Update Mode is supported
* cup: Arbitrary cursor moves
* vpa: Cursor can be moved to an absolute vertical coordinate
* hpa: Cursor can be moved to an absolute horizontal coordinate
* sgr0: Styling can be reset via a single escape
@ -52,7 +53,6 @@ The next five lines describe properties of the terminal environment:
* fgop: Foreground can be reset via a single escape
* bgop: Background can be reset via a single escape
* bce: The back-color-erase property is in play
* rect: Rectangular editing is available
* The second line is more of the same:
* bold: Boldface is available
@ -75,12 +75,9 @@ The next five lines describe properties of the terminal environment:
* vid: Video can be decoded
* indn: Multiple-line scrolling is available
* gpm: Connection is established to the GPM server
* kbd: The Kitty keyboard protocol is in use
* The fourth line indicates the default background color, and whether that
color is treated as transparent by the terminal (only **kitty** is known
to do this), and the default foreground color. **pmouse** indicates
whether pixel-precise mouse events are supported.
color is treated as transparent.
* The fifth line describes the available bitmap graphics. If Sixels are
available, the maximum number of color registers and maximum Sixel
@ -89,9 +86,6 @@ The next five lines describe properties of the terminal environment:
with "rgba graphics are available"; if Kitty's animation support is also
present, that will be reported with "rgba pixel animation support".
To the right of this material is the Notcurses homepage's URI, and the
Notcurses logo (the latter only if bitmap graphics are available).
The final eleven lines, only printed when in a UTF8 locale, show various
Unicode glyphs. The first four lines include the quadrant, sextant, and
box-drawing characters. The next four lines include the entire Braille set.

@ -1,6 +1,6 @@
% notcurses-input(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -8,7 +8,7 @@ notcurses-input - Read and display input events
# SYNOPSIS
**notcurses-input** [**-v**] [**-m**]
**notcurses-input** [**-v**]
# DESCRIPTION
@ -21,19 +21,11 @@ of modifier indicators:
* 'A'/'a': Alt was or was not pressed.
* 'C'/'c': Ctrl was or was not pressed.
* 'S'/'s': Shift was or was not pressed.
* 'U'/'u': Super was or was not pressed
* 'M'/'m': Meta was or was not pressed.
* 'H'/'h': Hyper was or was not pressed.
* 'X'/'x': CapsLock was or was not pressed.
* '#'/'.': NumLock was or was not pressed.
* 'L'/'R'/'P'/'u': Key was a release, repeat, press, or of unknown type.
By default, mice events are enabled.
# OPTIONS
**-v**: Increase verbosity.
**-m**: Inhibit mice events.
# NOTES

@ -1,6 +1,6 @@
% notcurses-tester(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -8,7 +8,7 @@ notcurses-tester - Notcurses unit testing
# SYNOPSIS
**notcurses-tester** [**-p datadir**] [**-lN**]
**notcurses-tester** [**-p datadir**] [**-l**]
# DESCRIPTION
@ -20,8 +20,7 @@ if these are in an irregular location, supply **-p**.
**-p** ***path***: Look in the specified ***path*** for data files.
**-lN**: Enable diagnostics/logging at level ***N***. ***N*** must be
between -1 and 7.
**-l**: Enable all possible diagnostics/logging.
# NOTES

@ -1,6 +1,6 @@
% tfman(1)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -8,7 +8,7 @@ tfman - Swank manual page browser
# SYNOPSIS
**tfman** [**-h**] [**-V**] [**-q**] files
**tfman** [**-h**] [**-V**] files
# DESCRIPTION
@ -21,34 +21,18 @@ tfman - Swank manual page browser
**-h**: Print help information, and exit with success.
**-q**: Don't wait for any input, and don't use the alternate screen.
files: Files to render.
If successfully loaded and parsed, the top of the page will be visible.
In the lower right corner is a listing of page sections. By default, the
page browser is in use; press Tab to move between the page browser and
the structure browser. Press 's' to toggle the structure browser's
visibility.
**tfman** can identify gzipped manual pages, and inflate them on the fly.
# NOTES
The following keypresses are recognized:
* **Ctrl-L**: Redraw the screen.
* **q**: Quit.
* **k**/**up**: Move up by one line.
* **b**/**pgup**: Move up by one page.
* **h**/**left**: Move up by one section.
* **j**/**down**: Move down by one line.
* **f**/**pgdown**: Move down by one page.
* **l**/**right**: Move down by one section.
* **g**/**home**: Go to first line in file.
* **s**: Toggle the structure browser's visibility.
The mouse wheel can also be used to move up and down within the active browser.
# NOTES
# BUGS

@ -1,6 +1,6 @@
% notcurses(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_capabilities(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -69,7 +69,7 @@ for which the terminal advertises support.
**notcurses_palette_size** returns the size of the terminal's palette, used
for palette-indexed color. It will always return at least 1. This is
independent of RGB TrueColor support. No terminal is known to support
independent of RGB TrueColor support. No terminal is know to support
more than 256-indexed color.
**notcurses_cantruecolor** returns **true** if the terminal advertises
@ -115,4 +115,4 @@ will return **true**, but the full spectrum will not be available.
**notcurses(3)**,
**notcurses_init(3)**,
**notcurses_visual(3)**,
**utf8(7)**
utf8(7)

@ -1,6 +1,6 @@
% notcurses_cell(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -78,14 +78,10 @@ typedef struct nccell {
**char* nccell_extract(const struct ncplane* ***n***, const nccell* ***c***, uint16_t* ***stylemask***, uint64_t* ***channels***);**
**uint64_t nccell_channels(const nccell* ***c***);**
**uint32_t nccell_bchannel(const nccell* ***c***);**
**uint32_t nccell_fchannel(const nccell* ***c***);**
**uint64_t nccell_set_channels(nccell* ***c***, uint64_t ***channels***);**
**uint64_t nccell_set_bchannel(nccell* ***c***, uint32_t ***channel***);**
**uint64_t nccell_set_fchannel(nccell* ***c***, uint32_t ***channel***);**
@ -118,9 +114,9 @@ typedef struct nccell {
**bool nccell_bg_default_p(const nccell* ***c***);**
**int nccell_set_fg_palindex(nccell* ***cl***, unsigned ***idx***);**
**int nccell_set_fg_palindex(nccell* ***cl***, int ***idx***);**
**int nccell_set_bg_palindex(nccell* ***cl***, unsigned ***idx***);**
**int nccell_set_bg_palindex(nccell* ***cl***, int ***idx***);**
**uint32_t nccell_fg_palindex(const nccell* ***cl***);**

@ -1,6 +1,6 @@
% notcurses_channels(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -25,8 +25,6 @@ notcurses_channels - operations on notcurses channels
**uint32_t ncchannel_b(uint32_t ***channel***);**
**uint32_t ncchannel_rgb(uint32_t ***channel***);**
**uint32_t ncchannel_rgb8(uint32_t ***channel***, uint32_t* restrict ***r***, uint32_t* restrict ***g***, uint32_t* restrict ***b***);**
**int ncchannel_set_rgb8(uint32_t* ***channel***, unsigned ***r***, unsigned ***g***, unsigned ***b***);**
@ -79,31 +77,20 @@ notcurses_channels - operations on notcurses channels
**bool ncchannel_palindex_p(uint32_t ***channel***);**
**int ncchannel_set_palindex(uint32_t* ***channel***, unsigned ***idx***);**
**int ncchannel_set_palindex(uint32_t* ***channel***, int ***idx***);**
**unsigned ncchannels_fg_palindex(uint64_t ***channels***);**
**unsigned ncchannels_bg_palindex(uint64_t ***channels***);**
**int ncchannels_set_fg_palindex(uint64_t* ***channels***, unsigned ***idx***);**
**int ncchannels_set_bg_palindex(uint64_t* ***channels***, unsigned ***idx***);**
**int ncchannels_set_fg_palindex(uint64_t* ***channels***, int ***idx***);**
**uint64_t ncchannels_set_channels(uint64_t* ***dst***, uint64_t ***channels***);**
**uint64_t ncchannels_channels(uint64_t ***channels***);**
**int ncchannels_set_bg_palindex(uint64_t* ***channels***, int ***idx***);**
**uint64_t ncchannels_combine(uint32_t ***fchan***, uint32_t ***bchan***);**
# DESCRIPTION
Channels ought not be manually manipulated. They contain several bits used
"behind the scenes", and e.g. direct assignment is likely to lead to strange
and infrequent failures. To assign one channel pair to another, use
**ncchannels_set_channels**. To assign a channel to a channel pair's
foreground, use **ncchannels_set_fchannel**. To assign a channel to a channel
pair's background, use **ncchannels_set_bchannel**.
**ncchannel_palindex** extracts the palette index from a channel. The channel
must be palette-indexed, or the return value is meaningless. Verify palette
indexing with **ncchannel_palindex_p**. A channel can be set to palette

@ -1,6 +1,6 @@
% notcurses_core(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_direct(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_fade(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_fds(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_init(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -20,12 +20,6 @@ notcurses_init - initialize a Notcurses instance
#define NCOPTION_NO_ALTERNATE_SCREEN 0x0040ull
#define NCOPTION_NO_FONT_CHANGES 0x0080ull
#define NCOPTION_DRAIN_INPUT 0x0100ull
#define NCOPTION_SCROLLING 0x0200ull
#define NCOPTION_CLI_MODE (NCOPTION_NO_ALTERNATE_SCREEN \
|NCOPTION_NO_CLEAR_BITMAPS \
|NCOPTION_PRESERVE_CURSOR \
|NCOPTION_SCROLLING)
typedef enum {
NCLOGLEVEL_SILENT, // print nothing once fullscreen service begins
@ -176,16 +170,6 @@ zero. The following flags are defined:
eventually prevent Notcurses from processing messages from the terminal. It
will furthermore avoid wasting time processing useless input.
* **NCOPTION_SCROLLING**: Enable scrolling on the standard plane. This is
equivalent to calling **ncplane_set_scrolling(stdn, true)** on some
standard plane ***stdn***.
**NCOPTION_CLI_MODE** is provided as an alias for the bitwise OR of
**NCOPTION_SCROLLING**, **NCOPTION_NO_ALTERNATE_SCREEN**,
**NCOPTION_PRESERVE_CURSOR**, and **NCOPTION_NO_CLEAR_BITMAPS**. If
writing a CLI, it is recommended to use **NCOPTION_CLI_MODE** rather
than explicitly listing these options.
**notcurses_default_foreground** returns the default foreground color, if it
could be detected. **notcurses_default_background** returns the default
background color, if it could be detected.
@ -296,13 +280,6 @@ rendered-mode programs:
* **-k** ought be mapped to **NCOPTION_NO_ALTERNATE_SCREEN**.
* Ctrl+L ought be mapped to **notcurses_refresh(3)**.
# BUGS
The introductory diagnostics are not currently emitted when the alternate
screen is used. They ought be printed to the regular screen before entering
the alternate screen. They are displayed normally when
**NCOPTION_NO_ALTERNATE_SCREEN** is used.
# SEE ALSO
**fwide(3)**,

@ -1,6 +1,6 @@
% notcurses_input(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -14,35 +14,23 @@ notcurses_input - input via notcurses
struct timespec;
struct notcurses;
typedef enum {
NCTYPE_UNKNOWN,
NCTYPE_PRESS,
NCTYPE_REPEAT,
NCTYPE_RELEASE,
} ncintype_e;
// An input event. Cell coordinates are currently defined only for mouse
// events. It is not guaranteed that we can set the modifiers for a given
// ncinput. We encompass single Unicode codepoints, not complete EGCs.
// FIXME for abi4, combine the bools into |modifiers|
typedef struct ncinput {
uint32_t id; // Unicode codepoint or synthesized NCKEY event
int y, x; // y/x cell coordinate of event, -1 for undefined
char utf8[5]; // utf8 representation, if one exists
// DEPRECATED do not use! going away in 4.0
bool alt; // was alt held?
bool shift; // was shift held?
bool ctrl; // was ctrl held?
// END DEPRECATION
ncintype_e evtype;
unsigned modifiers;// bitmask over NCKEY_MOD_*
int ypx, xpx; // pixel offsets within cell, -1 for undefined
uint32_t eff_text[5]; // Effective utf32 representation, taking
// modifier keys into account. This can be multiple
// codepoints. Array is zero-terminated.
uint32_t id; // Unicode codepoint
int y; // Y cell coordinate of event, -1 for undefined
int x; // X cell coordinate of event, -1 for undefined
char utf8[5]; // utf8 representation, when one exists
bool alt; // Was Alt held during the event?
bool shift; // Was Shift held during the event?
bool ctrl; // Was Ctrl held during the event?
enum {
EVTYPE_UNKNOWN,
EVTYPE_PRESS,
EVTYPE_REPEAT,
EVTYPE_RELEASE,
} evtype;
int ypx, xpx; // pixel offsets within cell, -1 for undefined
} ncinput;
#define NCMICE_NO_EVENTS 0
#define NCMICE_MOVE_EVENT 0x1
#define NCMICE_BUTTON_EVENT 0x2
@ -62,7 +50,7 @@ typedef struct ncinput {
**uint32_t notcurses_get_blocking(struct notcurses* ***n***, ncinput* ***ni***);**
**int notcurses_mice_enable(struct notcurses* ***n***, unsigned ***eventmask***);**
**int cnotcurses_mice_enable(struct notcurses* ***n***, unsigned ***eventmask***);**
**int notcurses_mice_disable(struct notcurses* ***n***);**
@ -74,18 +62,6 @@ typedef struct ncinput {
**int notcurses_linesigs_enable(struct notcurses* ***n***);**
**bool ncinput_shift_p(const struct ncinput* ***n***);**
**bool ncinput_ctrl_p(const struct ncinput* ***n***);**
**bool ncinput_alt_p(const struct ncinput* ***n***);**
**bool ncinput_meta_p(const struct ncinput* ***n***);**
**bool ncinput_super_p(const struct ncinput* ***n***);**
**bool ncinput_hyper_p(const struct ncinput* ***n***);**
# DESCRIPTION
notcurses supports input from keyboards and mice, and any device that looks
@ -117,19 +93,13 @@ be called without the possibility of blocking.
**ncinput_equal_p** compares two **ncinput** structs for data equality (i.e.
not considering padding), returning **true** if they represent the same
input (though not necessarily the same input event). Note that
**NCTYPE_UNKNOWN** and **NCTYPE_PRESS** are considered equivalent for the
purposes of **ncinput_equal_p**.
input (though not necessarily the same input event).
**notcurses_linesigs_disable** disables conversion of inputs **INTR**, **QUIT**,
**SUSP**, and **DSUSP** into **SIGINT**, **SIGQUIT**, and **SIGTSTP**. These
conversions are enabled by default. **notcurses_linesigs_enable** undoes this
action, but signals in the interim are permanently lost.
**ncinput_shift_p**, **ncinput_ctrl_p**, **ncinput_alt_p**, and
**ncinput_meta_p** test ***n*** to see if the relevant modifier is set.
This is preferably to directly accessing the struct members.
## Mice
For mouse events, the additional fields ***y***, ***x***, ***ypx***, and
@ -218,23 +188,19 @@ for input readiness. Instead, use the file descriptor returned by
Notcurses (it is possible that future versions will process input in their own
contexts).
The full list of synthesized events is available in **<notcurses/nckeys.h>**.
When support is detected, the Kitty keyboard disambiguation protocol will be
requested. This eliminates most of the **BUGS** mentioned below.
In API4, the various **bool** modifier fields will go away, and these statuses
will be merged into the ***modifiers*** bitmask. You are encouraged to use
**ncinput_shift_p** and friends to future-proof your code.
The full list of synthesized events is available in **<notcurses/nckeys.h>**.
# BUGS
Notcurses attempts to use the XTMODKEYS and Kitty keyboard disambiguation
protocols. When supported, they eliminate most of these issues.
The Shift key is traditionally not indicated in conjunction with typical
Unicode text. If e.g. Shift is used to generate a capital letter 'A', ***id***
will equal 'A', and ***shift*** will be **false**. Similarly, when Ctrl is
pressed along with a letter, the letter will currently always be reported in
its uppercase form. E.g., if Shift, Ctrl, and 'a' are all pressed, this is
indistinguishable from Ctrl and 'A'.
The Shift key is not indicated in conjunction with typical Unicode text.
If e.g. Shift is used to generate a capital letter 'A', ***id*** will equal 'A',
and ***shift*** will be **false**. Similarly, when Ctrl is pressed along with a
letter, the letter will currently always be reported in its uppercase form.
E.g., if Shift, Ctrl, and 'a' are all pressed, this is indistinguishable from
Ctrl and 'A'.
Ctrl pressed along with 'J' or 'M', whether Shift is pressed or not,
currently registers as **NCKEY_ENTER**. This will likely change in the
@ -245,13 +211,6 @@ issues are resolved. You can determine whether the protocol is in use
by examining the output of **notcurses-info(1)**. If the **kbd** property
is indicated, you're using the Kitty protocol.
Note that eff_text will always return the effective text value of the key,
taking into account any meta keys pressed. (So shift-a will always return
'A' in this field, regardless of if the Kitty keyboard disambiguation
protocol is used.) This field generally only can be trusted on
**NCTYPE_PRESS** and **NCTYPE_REPEAT** events, however. Also note that
this is a (zero-terminated) array as it can return multiple codepoints.
Mouse events in the left margins will never be delivered to the
application (as is intended), but mouse events in the bottom and right margins
sometimes can be if the event occurs prior to a window resize.

@ -1,6 +1,6 @@
% notcurses_lines(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_menu(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -87,11 +87,6 @@ menu sections, clicks to dismiss the menu, Escape to dismiss the menu, left
and right to change menu sections, and up and down to change menu items (these
latter are only consumed if there is an actively unrolled section).
Items can be disabled with **ncmenu_item_set_status**. Pass **false** to
disable the item, or **true** to enable it. All items are enabled by
default. A disabled item will not be returned with **ncmenu_mouse_selected**,
nor reached with **ncmenu_nextsection** nor **ncmenu_prevsection**.
# RETURN VALUES
**ncmenu_create** returns **NULL** on error, or a pointer to a valid new ncmenu.

@ -1,6 +1,6 @@
% notcurses_metric(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -33,12 +33,12 @@ notcurses_metric - fixed-width numeric output with metric suffixes
# DESCRIPTION
**ncnmetric** (and the helper wrappers **nc[qib]prefix**) accept
very large (or very small) non-negative integers, and prepare formatted output
**ncmetric** (and the helper wrappers **qprefix** and **bprefix**) accept
very large (or very small) non-negative numbers, and prepare formatted output
of a maximum width using metric suffixes. The suffix can represent arbitrary
amounts of growth, but is designed for 1000 (**NCPREFIX**) or 1024
(**NCIPREFIX**). 1024 is used for "digital units of information", i.e. kibibytes
and gibibits. **ncnmetric** supports the large suffixes KMGTPEZY (Kilo, Mega,
and gibibits. **ncmetric** supports the large suffixes KMGTPEZY (Kilo, Mega,
Giga, Tera, Peta, Exa, Zetta, and Yotta) and the small suffixes mµnpfazy
(Milli, Micro, Nano, Pico, Femto, Atto, Zepto, and Yocto). This covers the
range 1e24 (one septillion) through 1e-24, sufficing for all possible values of
@ -62,19 +62,19 @@ Three helper functions are provided to simplify these common cases:
// Mega, kilo, gigafoo. Use NCPREFIXSTRLEN + 1 and NCPREFIXCOLUMNS.
static inline const char*
ncqprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
return ncnmetric(val, decimal, buf, omitdec, 1000, '\0');
return ncmetric(val, decimal, buf, omitdec, 1000, '\0');
}
// Mibi, kebi, gibibytes sans 'i' suffix. Use NCIPREFIXSTRLEN + 1.
static inline const char*
nciprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
return ncnmetric(val, decimal, buf, omitdec, 1024, '\0');
return ncmetric(val, decimal, buf, omitdec, 1024, '\0');
}
// Mibi, kebi, gibibytes. Use NCBPREFIXSTRLEN + 1 and NCBPREFIXCOLUMNS.
static inline const char*
ncbprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
return ncnmetric(val, decimal, buf, omitdec, 1024, 'i');
return ncmetric(val, decimal, buf, omitdec, 1024, 'i');
}
```
@ -101,7 +101,7 @@ suffix, and u is the ***uprefix***. The minimum-width output will take the form
single-column value such as 5 is passed for ***val***.
Three more defines are provided to simplify formatted fixed-width output using
the results of **ncnmetric**. Each of these macros accepts a character buffer
the results of **ncmetric**. Each of these macros accepts a character buffer
holding the result of the call, and expand to *two* arguments:
* **NCPREFIXFMT(x)**
@ -116,8 +116,7 @@ to ensure that the output is always **NCPREFIXCOLUMNS** wide.
# RETURN VALUES
**NULL** if input parameters were invalid, or if **notcurses_init**
has not been successfully called. Otherwise, a pointer to ***buf***,
**NULL** if input parameters were invalid. Otherwise, a pointer to ***buf***,
filled in with the formatted output.
# EXAMPLES
@ -140,13 +139,7 @@ filled in with the formatted output.
# BUGS
This function is difficult to understand, and takes too many arguments.
If UTF-8 is available, 'µ' (U+00B5 MICRO SIGN) will be used in place of
'u' (U+0075 LATIN SMALL LETTER U) for the 'micro-' prefix. This is
determined by **notcurses_init**/**ncdirect_init**. Once UTF-8 is detected,
it is used for the lifetime of the process. The alternative would require
accepting a **const struct notcurses** (and associated API break).
This function is difficult to understand.
# SEE ALSO
@ -154,5 +147,4 @@ accepting a **const struct notcurses** (and associated API break).
**notcurses(3)**,
**notcurses_output(3)**,
**setlocale(3)**,
**snprintf(3)**,
**utf-8(7)**
**snprintf(3)**

@ -1,6 +1,6 @@
% notcurses_multiselector(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -76,8 +76,6 @@ on the scroll arrows will be handled.
**ncmultiselector_destroy** destroys the backing **ncplane**, as does
**ncmultiselector_create** in the event of any error.
As no flags exist, the **flags** option ought always be 0.
# RETURN VALUES
**ncmultiselector_create** returns **NULL** on an error, in which case the

@ -1,6 +1,6 @@
% notcurses_output(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -76,6 +76,8 @@ notcurses_output - output to ncplanes
**int ncplane_puttext(struct ncplane* ***n***, int ***y***, ncalign_e ***align***, const char* ***text***, size_t* ***bytes***);**
**int ncplane_growtext(struct ncplane* ***n***, int ***y***, ncalign_e ***align***, const char* ***text***, size_t* ***bytes***);**
# DESCRIPTION
These functions write EGCs (Extended Grapheme Clusters) to the specified
@ -91,6 +93,7 @@ These functions write EGCs (Extended Grapheme Clusters) to the specified
* **ncplane_vprintf()**: formatted output using **va_list**
* **ncplane_printf()**: formatted output using variadic arguments
* **ncplane_puttext()**: multi-line, line-broken, aligned text
* **ncplane_growtext()**: **ncplane_growtext()** with an autogrowing plane
All of these use the **ncplane**'s active styling, save **notcurses_putc()**,
which uses the **nccell**'s styling. Functions accepting a single EGC expect a series
@ -100,12 +103,8 @@ breaks. For more information, consult [Unicode® Standard Annex #29](https://uni
Functions accepting a set of EGCs must consist of a series of well-formed EGCs,
broken by cluster breaks, terminated by the appropriate NUL terminator.
Control characters are rejected, aside from two exceptions: a horizontal tab
(**'\\t'**, 0x09), and a newline (**'\\n'**, 0x0a) *when the output plane
is in scrolling mode*. A newline outside of scrolling mode will be rejected.
A tab will advance to the next tab stop, filling the space between with spaces.
Tab stops are separated by eight columns, and the first character of each line
is a tab stop.
Control characters are rejected, except for a newline when the output plane
is in scrolling mode. A newline outside of scrolling mode will be rejected.
These functions output to the **ncplane**'s current cursor location. Aside from
**ncplane_puttext()**, they *do not* move to the next line upon reaching the

@ -1,6 +1,6 @@
% notcurses_palette(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -27,8 +27,6 @@ typedef struct ncpalette {
**int ncpalette_set(ncpalette* ***p***, int ***idx***, unsigned ***rgb***);**
**int ncpalette_get(const ncpalette* ***p***, int ***idx***, uint32_t* ***palent***);**
**int ncpalette_get_rgb8(const ncpalette* ***p***, int ***idx***, int* restrict ***r***, int* restrict ***g***, int* restrict ***b***);**
**void ncpalette_free(ncpalette* ***p***);**

@ -1,6 +1,6 @@
% notcurses_pile(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_plane(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -135,10 +135,6 @@ typedef struct ncplane_options {
**void ncplane_cursor_yx(const struct ncplane* ***n***, unsigned* restrict ***y***, unsigned* restrict ***x***);**
**unsigned ncplane_cursor_y(const struct ncplane* ***n***);**
**unsigned ncplane_cursor_x(const struct ncplane* ***n***);**
**void ncplane_translate(const struct ncplane* ***src***, const struct ncplane* ***dst***, int* restrict ***y***, int* restrict ***x***);**
**bool ncplane_translate_abs(const struct ncplane* ***n***, int* restrict ***y***, int* restrict ***x***);**
@ -151,26 +147,14 @@ typedef struct ncplane_options {
**static inline unsigned ncplane_fchannel(struct ncplane* ***nc***);**
**uint64_t ncplane_set_bchannel(struct ncplane* ***nc***, uint32_t ***channel***);**
**uint64_t ncplane_set_fchannel(struct ncplane* ***nc***, uint32_t ***channel***);**
**static inline unsigned ncplane_fg_rgb(struct ncplane* ***nc***);**
**static inline unsigned ncplane_bg_rgb(struct ncplane* ***nc***);**
**static inline unsigned ncplane_fg_rgb8(struct ncplane* ***nc***);**
**int ncplane_set_fg_rgb(struct ncplane* ***n***, uint32_t ***channel***);**
**int ncplane_set_bg_rgb(struct ncplane* ***n***, uint32_t ***channel***);**
**static inline unsigned ncplane_bg_rgb8(struct ncplane* ***nc***);**
**static inline unsigned ncplane_fg_alpha(struct ncplane* ***nc***);**
**static inline unsigned ncplane_bg_alpha(struct ncplane* ***nc***);**
**int ncplane_set_fg_alpha(struct ncplane* ***n***, unsigned ***alpha***);**
**int ncplane_set_bg_alpha(struct ncplane* ***n***, unsigned ***alpha***);**
**static inline unsigned ncplane_fg_rgb8(struct ncplane* ***n***, unsigned* ***r***, unsigned* ***g***, unsigned* ***b***);**
**static inline unsigned ncplane_bg_rgb8(struct ncplane* ***n***, unsigned* ***r***, unsigned* ***g***, unsigned* ***b***);**
@ -183,13 +167,21 @@ typedef struct ncplane_options {
**void ncplane_set_bg_rgb8_clipped(struct ncplane* ***n***, int ***r***, int ***g***, int ***b***);**
**int ncplane_set_fg_rgb8(struct ncplane* ***n***, uint32_t ***channel***);**
**int ncplane_set_bg_rgb8(struct ncplane* ***n***, uint32_t ***channel***);**
**void ncplane_set_fg_default(struct ncplane* ***n***);**
**void ncplane_set_bg_default(struct ncplane* ***n***);**
**int ncplane_set_fg_palindex(struct ncplane* ***n***, unsigned ***idx***);**
**int ncplane_set_fg_alpha(struct ncplane* ***n***, unsigned ***alpha***);**
**int ncplane_set_bg_alpha(struct ncplane* ***n***, unsigned ***alpha***);**
**int ncplane_set_fg_palindex(struct ncplane* ***n***, int ***idx***);**
**int ncplane_set_bg_palindex(struct ncplane* ***n***, unsigned ***idx***);**
**int ncplane_set_bg_palindex(struct ncplane* ***n***, int ***idx***);**
**uint16_t ncplane_styles(const struct ncplane* ***n***);**
@ -241,7 +233,7 @@ typedef struct ncplane_options {
# DESCRIPTION
Ncplanes are the fundamental drawing object of Notcurses. All output functions
Ncplanes are the fundamental drawing object of notcurses. All output functions
take a **struct ncplane** as an argument. They can be any size, and placed
anywhere. In addition to its framebuffer--a rectilinear matrix of **nccell**s
(see **notcurses_cell(3)**)--an ncplane is defined by:
@ -310,7 +302,7 @@ the rendering area. A plane can be moved off-screen entirely, in which case
it will not be visible following rasterization; it can also be partially
off-screen.
A plane has a virtual cursor; set its new position with **ncplane_cursor_move_yx**.
A plane has a virtual cursor; Set its new position with **ncplane_cursor_move_yx**.
Specifying -1 as one or both coordinates will hold that axis constant. You may
move a cursor relatively to its current position with **ncplane_cursor_move_rel**.
Unless coordinates are specified for a call, action takes place at the plane's
@ -379,10 +371,6 @@ secondary column of a wide glyph with **ncplane_at_yx_cell** will fill in
the **nccell** argument such that **nccell_extended_gcluster(3)** returns an
empty string, and **nccell_wide_right_p(3)** returns **true**.
If **ncplane_at_yx** is invoked upon a sprixel plane, the control sequence will
be returned for any valid coordinates (note that this may be quite large).
This does not apply to **ncplane_at_yx_cell**, which will return an error.
**ncplane_set_name** sets the plane's name, freeing any old name. ***name***
may be **NULL**. **ncplane_set_name** duplicates the provided name internally.
@ -403,7 +391,7 @@ sequence) to set the base cell. **ncplane_set_base** does the same with
## Piles
A single Notcurses context is made up of one or more piles. A pile is a
A single **notcurses** context is made up of one or more piles. A pile is a
set of one or more **ncplane**s, including the partial orderings made up of
their binding and z-axis pointers. A pile has a top and bottom **ncplane**
(this might be a single plane), and one or more root planes (planes which are

@ -1,6 +1,6 @@
% notcurses_plot(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -16,10 +16,8 @@ struct ncprogbar;
#define NCPROGBAR_OPTION_RETROGRADE 0x0001u // proceed left/down
typedef struct ncprogbar_options {
uint32_t ulchannel; // upper-left channel. in the context of a progress bar,
uint32_t urchannel; // "up" is the direction we are progressing towards, and
uint32_t blchannel; // "bottom" is the direction of origin. for monochromatic
uint32_t brchannel; // bar, all four channels ought be the same.
uint64_t maxchannels;
uint64_t minchannels;
uint64_t flags;
} ncprogbar_options;
```

@ -1,6 +1,6 @@
% notcurses_reader(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_reel(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_refresh(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_render(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_selector(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
@ -89,8 +89,6 @@ on the scroll arrows will be handled.
**ncselector_destroy** destroys the backing **ncplane**, as does
**ncselector_create** in the event of any error.
As no flags exist, the **flags** option ought always be 0.
# RETURN VALUES
**ncselector_create** returns **NULL** on an error, in which case the passed

@ -1,6 +1,6 @@
% notcurses_stats(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_stdplane(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_stop(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,5 +1,5 @@
% notcurses_tabbed(3)
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_tree(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_util(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME

@ -1,6 +1,6 @@
% notcurses_visual(3)
% nick black <nickblack@linux.com>
% v3.0.9
% v3.0.1
# NAME
notcurses_visual - notcurses multimedia
@ -61,7 +61,7 @@ typedef struct ncvgeom {
unsigned begy, begx; // upper-left corner of used region
unsigned leny, lenx; // geometry of used region
unsigned maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
ncblitter_e blitter; // blitter that will be used
ncblitter_e blitter;i // blitter that will be used
} ncvgeom;
```
@ -89,7 +89,7 @@ typedef struct ncvgeom {
**struct ncplane* ncvisual_blit(struct notcurses* ***nc***, struct ncvisual* ***ncv***, const struct ncvisual_options* ***vopts***);**
**struct ncplane* ncvisualplane_create(struct notcurses* ***nc***, const struct ncplane_options* ***opts***, struct ncvisual* ***ncv***, struct ncvisual_options* ***vopts***);**
**static inline struct ncplane* ncvisualplane_create(struct notcurses* ***nc***, const struct ncplane_options* ***opts***, struct ncvisual* ***ncv***, struct ncvisual_options* ***vopts***);**
**int ncvisual_simple_streamer(struct ncplane* ***n***, struct ncvisual* ***ncv***, const struct timespec* ***disptime***, void* ***curry***);**
@ -121,8 +121,6 @@ typedef struct ncvgeom {
**int ncplane_qrcode(struct ncplane* ***n***, unsigned* ***ymax***, unsigned* ***xmax***, const void* ***data***, size_t ***len***)**
**struct ncvisual* ncvisual_from_sixel(const char* ***s***, unsigned ***leny***, unsigned ***lenx***);**
# DESCRIPTION
An **ncvisual** is a virtual pixel framebuffer. They can be created from
@ -132,8 +130,6 @@ If Notcurses was built against a multimedia engine (FFMpeg or OpenImageIO),
image and video files can be loaded into visuals using
**ncvisual_from_file**. **ncvisual_from_file** discovers the container
and codecs, but does not verify that the entire file is well-formed.
If Notcurses was built against FFMpeg, **ncvisual_from_file** can also handle
multimedia devices such as webcams.
**ncvisual_decode** ought be invoked to recover subsequent frames, once
per frame. **ncvisual_decode_loop** will return to the first frame,
as if **ncvisual_decode** had never been called.

@ -4,8 +4,7 @@
* Review the testing checklist (doc/testing-checklist.md)
* clang-tidy check with something like:
* `cmake "-DCMAKE_CXX_CLANG_TIDY=/usr/bin/clang-tidy-15\;-checks=-*,clang-analyzer-*,modernize-*,performance-*" ..`
or
* `cmake "-DCMAKE_CXX_CLANG_TIDY=/usr/bin/clang-tidy-11;-checks=-*,clang-analyzer-*,modernize-*,performance-*" ..`
* `scan-build cmake .. && scan-build make`
* Verify that rust + python compile

@ -136,10 +136,10 @@ namespace ncpp
struct EvType
{
static constexpr ncintype_e Unknown = NCTYPE_UNKNOWN;
static constexpr ncintype_e Press = NCTYPE_PRESS;
static constexpr ncintype_e Repeat = NCTYPE_REPEAT;
static constexpr ncintype_e Release = NCTYPE_RELEASE;
static constexpr unsigned Unknown = ncinput::NCTYPE_UNKNOWN;
static constexpr unsigned Press = ncinput::NCTYPE_PRESS;
static constexpr unsigned Repeat = ncinput::NCTYPE_REPEAT;
static constexpr unsigned Release = ncinput::NCTYPE_RELEASE;
};
}

@ -483,16 +483,6 @@ namespace ncpp
get_cursor_yx (&y, &x);
}
unsigned cursor_y() const noexcept
{
return ncplane_cursor_y(plane);
}
unsigned cursor_x() const noexcept
{
return ncplane_cursor_x(plane);
}
int putc (const Cell &c) const NOEXCEPT_MAYBE
{
return error_guard<int> (ncplane_putc (plane, c), -1);
@ -843,6 +833,16 @@ namespace ncpp
return ncplane_fg_alpha (plane);
}
uint64_t set_fchannel (uint32_t channel) const noexcept
{
return ncplane_set_fchannel (plane, channel);
}
uint64_t set_bchannel (uint32_t channel) const noexcept
{
return ncplane_set_bchannel (plane, channel);
}
void set_channels (uint64_t channels) const noexcept
{
ncplane_set_channels (plane, channels);
@ -901,7 +901,7 @@ namespace ncpp
bool set_bg_rgb8 (int r, int g, int b, bool clipped = false) const NOEXCEPT_MAYBE
{
if (clipped) {
ncplane_set_bg_rgb8_clipped (plane, r, g, b);
ncplane_set_fg_rgb8_clipped (plane, r, g, b);
return true;
}

@ -7,11 +7,7 @@
extern "C" {
#endif
#ifdef NOTCURSES_FFI
#define static API
#endif
#ifndef __MINGW32__
#ifndef __MINGW64__
#define API __attribute__((visibility("default")))
#else
#define API __declspec(dllexport)

@ -1,24 +1,10 @@
#ifndef NOTCURSES_NCKEYS
#define NOTCURSES_NCKEYS
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef NOTCURSES_FFI
#define static API
#endif
#ifndef __MINGW32__
#define API __attribute__((visibility("default")))
#else
#define API __declspec(dllexport)
#endif
#define ALLOC __attribute__((malloc)) __attribute__((warn_unused_result))
// Synthesized input events, i.e. any input event we can report that isn't
// representative of some Unicode. This covers both keyboard and mouse events,
// as well as signals and even window events.
@ -188,13 +174,15 @@ nckey_synthesized_p(uint32_t w){
return w >= PRETERUNICODEBASE && w <= NCKEY_EOF;
}
// Synonyms and aliases (so far as we're concerned)
// Synonyms (so far as we're concerned)
#define NCKEY_SCROLL_UP NCKEY_BUTTON4
#define NCKEY_SCROLL_DOWN NCKEY_BUTTON5
#define NCKEY_RETURN NCKEY_ENTER
#define NCKEY_TAB 0x09
#define NCKEY_ESC 0x1b
#define NCKEY_SPACE 0x20
// Just aliases, ma'am, from the 128 characters common to ASCII+UTF8
#define NCKEY_TAB 0x09
#define NCKEY_ESC 0x1b
#define NCKEY_SPACE 0x20
// Is this uint32_t from the Private Use Area in the BMP (Plane 0)?
static inline bool
@ -214,17 +202,6 @@ nckey_supppuab_p(uint32_t w){
return w >= 0x100000 && w <= 0x10fffd; // 65,534 codepoints
}
// used with the modifiers bitmask. definitions come straight from the kitty
// keyboard protocol.
#define NCKEY_MOD_SHIFT 1
#define NCKEY_MOD_ALT 2
#define NCKEY_MOD_CTRL 4
#define NCKEY_MOD_SUPER 8
#define NCKEY_MOD_HYPER 16
#define NCKEY_MOD_META 32
#define NCKEY_MOD_CAPSLOCK 64
#define NCKEY_MOD_NUMLOCK 128
#ifdef __cplusplus
} // extern "C"
#endif

@ -10,7 +10,7 @@ extern "C" {
// 32-bit values to little-endian (as used in the nccell gcluster field). This
// ought be defined so that it's a a no-op on little-endian builds.
#ifndef __MINGW32__ // All but Windows
#ifndef __MINGW64__ // All but Windows
#include <netinet/in.h>
#endif
@ -26,7 +26,7 @@ extern "C" {
#define htole(x) (__bswap_32(htonl(x)))
#define wcwidth(w) 1 // FIXME lol, no
#define wcswidth(w, s) (int)(wcslen(w)) // FIXME lol, no
#elif defined(__MINGW32__) // Windows
#elif defined(__MINGW64__) // Windows
#include <string.h>
#define wcwidth(w) 1 // FIXME lol, no
#define wcswidth(w, s) (int)(wcslen(w)) // FIXME lol, no

@ -79,7 +79,7 @@ extern "C" {
#define NCSUITSBLACK L"\u2660\u2663\u2665\u2666" // ♠♣♥♦
#define NCSUITSWHITE L"\u2661\u2662\u2664\u2667" // ♡♢♤♧
#define NCCHESSBLACK L"\u265f\u265c\u265e\u265d\u265b\u265a" // ♟♜♞♝♛♚
#define NCCHESSWHITE L"\u2659\u2656\u2658\u2657\u2655\u2654" // ♙♖♘♗♕♔
#define NCCHESSWHITE L"\u265f\u265c\u265e\u265d\u265b\u265a" // ♙♖♘♗♕♔
#define NCDICE L"\u2680\u2681\u2682\u2683\u2684\u2685" // ⚀⚁⚂⚃⚄⚅
#define NCMUSICSYM L"\u2669\u266A\u266B\u266C\u266D\u266E\u266F" // ♩♪♫♬♭♮♯

@ -24,11 +24,7 @@ extern "C" {
#define RESTRICT restrict
#endif
#ifdef NOTCURSES_FFI
#define static API
#endif
#ifndef __MINGW32__
#ifndef __MINGW64__
#define API __attribute__((visibility("default")))
#else
#define API __declspec(dllexport)
@ -125,20 +121,20 @@ typedef enum {
// initialize a 32-bit channel pair with specified RGB
#define NCCHANNEL_INITIALIZER(r, g, b) \
(((uint32_t)(r) << 16u) + ((uint32_t)(g) << 8u) + (b) + NC_BGDEFAULT_MASK)
(((uint32_t)r << 16u) + ((uint32_t)g << 8u) + (b) + NC_BGDEFAULT_MASK)
// initialize a 64-bit channel pair with specified RGB fg/bg
#define NCCHANNELS_INITIALIZER(fr, fg, fb, br, bg, bb) \
((NCCHANNEL_INITIALIZER((fr), (fg), (fb)) << 32ull) + \
(NCCHANNEL_INITIALIZER((br), (bg), (bb))))
((NCCHANNEL_INITIALIZER(fr, fg, fb) << 32ull) + \
(NCCHANNEL_INITIALIZER(br, bg, bb)))
// These lowest-level functions directly manipulate a channel. Users will
// typically manipulate ncplanes' and nccells' channels through their APIs,
// rather than calling these explicitly.
// These lowest-level functions manipulate a channel encodings directly. Users
// will typically manipulate ncplanes' and nccells' channels through their
// APIs, rather than calling these explicitly.
// Extract the 2-bit alpha component from a 32-bit channel. It is not
// shifted down, and can be directly compared to NCALPHA_* values.
static inline uint32_t
static inline unsigned
ncchannel_alpha(uint32_t channel){
return channel & NC_BG_ALPHA_MASK;
}
@ -151,7 +147,7 @@ ncchannel_set_alpha(uint32_t* channel, unsigned alpha){
if(alpha & ~NC_BG_ALPHA_MASK){
return -1;
}
*channel = (uint32_t)alpha | (*channel & (uint32_t)~NC_BG_ALPHA_MASK);
*channel = alpha | (*channel & ~NC_BG_ALPHA_MASK);
if(alpha != NCALPHA_OPAQUE){
*channel |= NC_BGDEFAULT_MASK;
}
@ -167,7 +163,7 @@ ncchannel_default_p(uint32_t channel){
// Mark the channel as using its default color. Alpha is set opaque.
static inline uint32_t
ncchannel_set_default(uint32_t* channel){
*channel &= (uint32_t)~NC_BGDEFAULT_MASK; // turn off not-default bit
*channel &= ~NC_BGDEFAULT_MASK; // turn off not-default bit
ncchannel_set_alpha(channel, NCALPHA_OPAQUE);
return *channel;
}
@ -186,10 +182,10 @@ ncchannel_palindex(uint32_t channel){
}
// Mark the channel as using the specified palette color. It is an error if
// the index is greater than NCPALETTESIZE. Alpha is set opaque.
// the index is negative, or greater than NCPALETTESIZE. Alpha is set opaque.
static inline int
ncchannel_set_palindex(uint32_t* channel, unsigned idx){
if(idx >= NCPALETTESIZE){
ncchannel_set_palindex(uint32_t* channel, int idx){
if(idx < 0 || idx >= NCPALETTESIZE){
return -1;
}
ncchannel_set_alpha(channel, NCALPHA_OPAQUE);
@ -201,7 +197,8 @@ ncchannel_set_palindex(uint32_t* channel, unsigned idx){
// Is this channel using RGB color?
static inline bool
ncchannel_rgb_p(uint32_t channel){
return !(ncchannel_default_p(channel) || ncchannel_palindex_p(channel));
// bitwise or is intentional (allows compiler more freedom)
return !(ncchannel_default_p(channel) | ncchannel_palindex_p(channel));
}
// Extract the 8-bit red component from a 32-bit channel. Only valid if
@ -225,16 +222,9 @@ ncchannel_b(uint32_t channel){
return (channel & 0x0000ffu);
}
// Extract the 24-bit RGB value from a 32-bit channel.
// Only valid if ncchannel_rgb_p() would return true for the channel.
static inline uint32_t
ncchannel_rgb(uint32_t channel){
return channel & NC_BG_RGB_MASK;
}
// Extract the three 8-bit R/G/B components from a 32-bit channel.
// Only valid if ncchannel_rgb_p() would return true for the channel.
static inline uint32_t
static inline unsigned
ncchannel_rgb8(uint32_t channel, unsigned* RESTRICT r, unsigned* RESTRICT g,
unsigned* RESTRICT b){
*r = ncchannel_r(channel);
@ -254,7 +244,7 @@ ncchannel_set_rgb8(uint32_t* channel, unsigned r, unsigned g, unsigned b){
uint32_t c = (r << 16u) | (g << 8u) | b;
// clear the existing rgb bits, clear the palette index indicator, set
// the not-default bit, and or in the new rgb.
*channel = (uint32_t)((*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | c);
*channel = (*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | c;
return 0;
}
@ -264,7 +254,7 @@ ncchannel_set(uint32_t* channel, uint32_t rgb){
if(rgb > 0xffffffu){
return -1;
}
*channel = (uint32_t)((*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | rgb);
*channel = (*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | rgb;
return 0;
}
@ -291,32 +281,22 @@ ncchannel_set_rgb8_clipped(uint32_t* channel, int r, int g, int b){
if(b <= -1){
b = 0;
}
uint32_t c = (uint32_t)((r << 16u) | (g << 8u) | b);
*channel = (uint32_t)((*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | c);
uint32_t c = (r << 16u) | (g << 8u) | b;
*channel = (*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | c;
}
// Extract the background alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
// Extract the 32-bit background channel from a channel pair.
static inline uint32_t
ncchannels_bchannel(uint64_t channels){
return channels & (NC_BG_RGB_MASK | NC_BG_PALETTE |
NC_BGDEFAULT_MASK | NC_BG_ALPHA_MASK);
return channels & 0xfffffffflu;
}
// Extract the foreground alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
// Extract the 32-bit foreground channel from a channel pair.
static inline uint32_t
ncchannels_fchannel(uint64_t channels){
return ncchannels_bchannel(channels >> 32u);
}
// Extract the background alpha and coloring bits from a 64-bit channel pair.
static inline uint64_t
ncchannels_channels(uint64_t channels){
return ncchannels_bchannel(channels) |
((uint64_t)ncchannels_fchannel(channels) << 32u);
}
static inline bool
ncchannels_bg_rgb_p(uint64_t channels){
return ncchannel_rgb_p(ncchannels_bchannel(channels));
@ -333,32 +313,16 @@ ncchannels_bg_alpha(uint64_t channels){
return ncchannel_alpha(ncchannels_bchannel(channels));
}
// Set the background alpha and coloring bits of the 64-bit channel pair
// from a single 32-bit value.
// Set the 32-bit background channel of a channel pair.
static inline uint64_t
ncchannels_set_bchannel(uint64_t* channels, uint32_t channel){
// drop the background color and alpha bit
*channels &= ((0xffffffffllu << 32u) | NC_NOBACKGROUND_MASK);
*channels |= (uint32_t)(channel & ~NC_NOBACKGROUND_MASK);
return *channels;
return *channels = (*channels & 0xffffffff00000000llu) | channel;
}
// Set the foreground alpha and coloring bits of the 64-bit channel pair
// from a single 32-bit value.
// Set the 32-bit foreground channel of a channel pair.
static inline uint64_t
ncchannels_set_fchannel(uint64_t* channels, uint32_t channel){
// drop the foreground color and alpha bit
*channels &= (0xffffffffllu | ((uint64_t)NC_NOBACKGROUND_MASK << 32u));
*channels |= (uint64_t)(channel & ~NC_NOBACKGROUND_MASK) << 32u;
return *channels;
}
// Set the alpha and coloring bits of a channel pair from another channel pair.
static inline uint64_t
ncchannels_set_channels(uint64_t* dst, uint64_t channels){
ncchannels_set_bchannel(dst, channels & 0xffffffffull);
ncchannels_set_fchannel(dst, (uint32_t)((channels >> 32u) & 0xffffffffull));
return *dst;
return *channels = (*channels & 0xfffffffflu) | ((uint64_t)channel << 32u);
}
// Set the 2-bit alpha component of the background channel.
@ -440,13 +404,13 @@ ncchannels_bg_palindex(uint64_t channels){
// Extract 24 bits of foreground RGB from 'channels', shifted to LSBs.
static inline uint32_t
ncchannels_fg_rgb(uint64_t channels){
return ncchannel_rgb(ncchannels_fchannel(channels));
return ncchannels_fchannel(channels) & NC_BG_RGB_MASK;
}
// Extract 24 bits of background RGB from 'channels', shifted to LSBs.
static inline uint32_t
ncchannels_bg_rgb(uint64_t channels){
return ncchannel_rgb(ncchannels_bchannel(channels));
return ncchannels_bchannel(channels) & NC_BG_RGB_MASK;
}
// Extract 24 bits of foreground RGB from 'channels', split into subchannels.
@ -482,7 +446,7 @@ ncchannels_set_fg_rgb8_clipped(uint64_t* channels, int r, int g, int b){
}
static inline int
ncchannels_set_fg_palindex(uint64_t* channels, unsigned idx){
ncchannels_set_fg_palindex(uint64_t* channels, int idx){
uint32_t channel = ncchannels_fchannel(*channels);
if(ncchannel_set_palindex(&channel, idx) < 0){
return -1;
@ -525,7 +489,7 @@ ncchannels_set_bg_rgb8_clipped(uint64_t* channels, int r, int g, int b){
// Set the cell's background palette index, set the background palette index
// bit, set it background-opaque, and clear the background default color bit.
static inline int
ncchannels_set_bg_palindex(uint64_t* channels, unsigned idx){
ncchannels_set_bg_palindex(uint64_t* channels, int idx){
uint32_t channel = ncchannels_bchannel(*channels);
if(ncchannel_set_palindex(&channel, idx) < 0){
return -1;
@ -597,8 +561,7 @@ ncchannels_set_bg_default(uint64_t* channels){
// returned, and the number of valid bytes and columns will be written into
// *|validbytes| and *|validwidth| (assuming them non-NULL). If the entire
// string is valid, *|validbytes| and *|validwidth| reflect the entire string.
API int ncstrwidth(const char* egcs, int* validbytes, int* validwidth)
__attribute__ ((nonnull (1)));
API int ncstrwidth(const char* egcs, int* validbytes, int* validwidth);
// input functions like notcurses_get() return ucs32-encoded uint32_t. convert
// a series of uint32_t to utf8. result must be at least 4 bytes per input
@ -606,8 +569,7 @@ API int ncstrwidth(const char* egcs, int* validbytes, int* validwidth)
// the number of bytes used is returned, or -1 if passed illegal ucs32, or too
// small of a buffer.
API int notcurses_ucs32_to_utf8(const uint32_t* ucs32, unsigned ucs32count,
unsigned char* resultbuf, size_t buflen)
__attribute__ ((nonnull (1, 3)));
unsigned char* resultbuf, size_t buflen);
// An nccell corresponds to a single character cell on some plane, which can be
// occupied by a single grapheme cluster (some root spacing glyph, along with
@ -726,7 +688,6 @@ typedef struct nccell {
// protect against such misuse here. problems *will* ensue. similarly, do not
// set channel flags other than colors/alpha. we assign non-printing glyphs
// a width of 1 to match utf8_egc_len()'s behavior for whitespace/NUL.
// FIXME can we enforce this with static_assert?
#define NCCELL_INITIALIZER(c, s, chan) { .gcluster = (htole(c)), .gcluster_backstop = 0,\
.width = (uint8_t)((wcwidth(c) < 0 || !c) ? 1 : wcwidth(c)), .stylemask = (s), .channels = (chan), }
// python fails on #define CELL_CHAR_INITIALIZER(c) CELL_INITIALIZER(c, 0, 0)
@ -790,13 +751,13 @@ nccell_styles(const nccell* c){
// whether they're actively supported or not.
static inline void
nccell_on_styles(nccell* c, unsigned stylebits){
c->stylemask |= (uint16_t)(stylebits & NCSTYLE_MASK);
c->stylemask |= (stylebits & NCSTYLE_MASK);
}
// Remove the specified styles (in the LSBs) from the nccell's existing spec.
static inline void
nccell_off_styles(nccell* c, unsigned stylebits){
c->stylemask &= (uint16_t)~(stylebits & NCSTYLE_MASK);
c->stylemask &= ~(stylebits & NCSTYLE_MASK);
}
// Use the default color for the foreground.
@ -812,30 +773,15 @@ nccell_set_bg_default(nccell* c){
}
static inline int
nccell_set_fg_alpha(nccell* c, unsigned alpha){
nccell_set_fg_alpha(nccell* c, int alpha){
return ncchannels_set_fg_alpha(&c->channels, alpha);
}
static inline int
nccell_set_bg_alpha(nccell* c, unsigned alpha){
nccell_set_bg_alpha(nccell* c, int alpha){
return ncchannels_set_bg_alpha(&c->channels, alpha);
}
static inline uint64_t
nccell_set_bchannel(nccell* c, uint32_t channel){
return ncchannels_set_bchannel(&c->channels, channel);
}
static inline uint64_t
nccell_set_fchannel(nccell* c, uint32_t channel){
return ncchannels_set_fchannel(&c->channels, channel);
}
static inline uint64_t
nccell_set_channels(nccell* c, uint64_t channels){
return ncchannels_set_channels(&c->channels, channels);
}
// Is the cell part of a multicolumn element?
static inline bool
nccell_double_wide_p(const nccell* c){
@ -859,25 +805,6 @@ nccell_wide_left_p(const nccell* c){
API __attribute__ ((returns_nonnull)) const char*
nccell_extended_gcluster(const struct ncplane* n, const nccell* c);
static inline uint64_t
nccell_channels(const nccell* c){
return ncchannels_channels(c->channels);
}
// Extract the background alpha and coloring bits from a cell's channels
// as a single 32-bit value.
static inline uint32_t
nccell_bchannel(const nccell* cl){
return ncchannels_bchannel(cl->channels);
}
// Extract the foreground alpha and coloring bits from a cell's channels
// as a single 32-bit value.
static inline uint32_t
nccell_fchannel(const nccell* cl){
return ncchannels_fchannel(cl->channels);
}
// return the number of columns occupied by 'c'. see ncstrwidth() for an
// equivalent for multiple EGCs.
static inline unsigned
@ -1028,15 +955,8 @@ typedef enum {
// eventually preventing Notcurses from processing terminal messages.
#define NCOPTION_DRAIN_INPUT 0x0100ull
// Prepare the standard plane in scrolling mode, useful for CLIs. This is
// equivalent to calling ncplane_set_scrolling(notcurses_stdplane(nc), true).
#define NCOPTION_SCROLLING 0x0200ull
// "CLI mode" is just setting these four options.
#define NCOPTION_CLI_MODE (NCOPTION_NO_ALTERNATE_SCREEN \
|NCOPTION_NO_CLEAR_BITMAPS \
|NCOPTION_PRESERVE_CURSOR \
|NCOPTION_SCROLLING)
// "CLI mode" is just NCOPTION_NO_CLEAR_BITMAPS | NCOPTION_NO_ALTERNATE_SCREEN |
// NCOPTION_PRESERVE_CURSOR, plus enabling scrolling on the standard plane.
// Configuration for notcurses_init().
typedef struct notcurses_options {
@ -1190,103 +1110,39 @@ nckey_mouse_p(uint32_t r){
return r >= NCKEY_MOTION && r <= NCKEY_BUTTON11;
}
typedef enum {
NCTYPE_UNKNOWN,
NCTYPE_PRESS,
NCTYPE_REPEAT,
NCTYPE_RELEASE,
} ncintype_e;
// Note: changing this also means adding kitty_cb_atxt functions in
// in.c otherwise extra codepoints won't be picked up.
#define NCINPUT_MAX_EFF_TEXT_CODEPOINTS 4
// An input event. Cell coordinates are currently defined only for mouse
// events. It is not guaranteed that we can set the modifiers for a given
// ncinput. We encompass single Unicode codepoints, not complete EGCs.
// FIXME for abi4, combine the bools into |modifiers|
typedef struct ncinput {
uint32_t id; // Unicode codepoint or synthesized NCKEY event
int y, x; // y/x cell coordinate of event, -1 for undefined
char utf8[5]; // utf8 representation, if one exists
// DEPRECATED do not use! going away in 4.0
bool alt; // was alt held?
bool shift; // was shift held?
bool ctrl; // was ctrl held?
// END DEPRECATION
ncintype_e evtype;
unsigned modifiers;// bitmask over NCKEY_MOD_*
// FIXME kitty protocol also exposes hyper, meta, caps_lock, num_lock
enum {
NCTYPE_UNKNOWN,
NCTYPE_PRESS,
NCTYPE_REPEAT,
NCTYPE_RELEASE,
} evtype;
int ypx, xpx; // pixel offsets within cell, -1 for undefined
uint32_t eff_text[NCINPUT_MAX_EFF_TEXT_CODEPOINTS]; // Effective
// utf32 representation, taking modifier
// keys into account. This can be multiple
// codepoints. Array is zero-terminated.
} ncinput;
static inline bool
ncinput_shift_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_SHIFT);
}
static inline bool
ncinput_ctrl_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_CTRL);
}
static inline bool
ncinput_alt_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_ALT);
}
static inline bool
ncinput_meta_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_META);
}
static inline bool
ncinput_super_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_SUPER);
}
static inline bool
ncinput_hyper_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_HYPER);
}
static inline bool
ncinput_capslock_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_CAPSLOCK);
}
static inline bool
ncinput_numlock_p(const ncinput* n){
return (n->modifiers & NCKEY_MOD_NUMLOCK);
}
// compare two ncinput structs for data equality. NCTYPE_PRESS and
// NCTYPE_UNKNOWN are considered to be equivalent. NCKEY_MOD_CAPSLOCK
// and NCKEY_MOD_NUMLOCK are not considered relevant.
// compare two ncinput structs for data equality.
static inline bool
ncinput_equal_p(const ncinput* n1, const ncinput* n2){
// don't need to check ->utf8; it's derived from id
if(n1->id != n2->id){
return false;
}
if(n1->y != n2->y || n1->x != n2->x){
return false;
}
// don't need to check deprecated alt, ctrl, shift
if((n1->modifiers & ~(unsigned)(NCKEY_MOD_CAPSLOCK | NCKEY_MOD_NUMLOCK))
!= (n2->modifiers & ~(unsigned)(NCKEY_MOD_CAPSLOCK | NCKEY_MOD_NUMLOCK))){
if(n1->alt != n2->alt || n1->shift != n2->shift || n1->ctrl != n2->ctrl){
return false;
}
if(n1->evtype != n2->evtype){
if((n1->evtype != NCTYPE_UNKNOWN && n1->evtype != NCTYPE_PRESS) ||
(n2->evtype != NCTYPE_UNKNOWN && n2->evtype != NCTYPE_PRESS)){
return false;
}
}
if(n1->ypx != n2->ypx || n1->xpx != n2->xpx){
return false;
}
return true;
@ -1333,7 +1189,7 @@ notcurses_get_blocking(struct notcurses* n, ncinput* ni){
// Was 'ni' free of modifiers?
static inline bool
ncinput_nomod_p(const ncinput* ni){
return !(ni->modifiers);
return !(ni->alt | ni->ctrl | ni->shift);
}
#define NCMICE_NO_EVENTS 0
@ -1383,6 +1239,12 @@ API const struct notcurses* ncplane_notcurses_const(const struct ncplane* n)
API void ncplane_dim_yx(const struct ncplane* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
__attribute__ ((nonnull (1)));
// Get a reference to the standard plane (one matching our current idea of the
// terminal size) for this terminal. The standard plane always exists, and its
// origin is always at the uppermost, leftmost cell of the terminal.
API struct ncplane* notcurses_stdplane(struct notcurses* nc);
API const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
// notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x!
static inline struct ncplane*
notcurses_stddim_yx(struct notcurses* nc, unsigned* RESTRICT y, unsigned* RESTRICT x){
@ -1585,7 +1447,8 @@ typedef struct ncpalette {
} ncpalette;
// Create a new palette store. It will be initialized with notcurses' best
// knowledge of the currently configured palette.
// knowledge of the currently configured palette. The palette upon startup
// cannot be reliably detected, sadly.
API ALLOC ncpalette* ncpalette_new(struct notcurses* nc)
__attribute__ ((nonnull (1)));
@ -1611,21 +1474,12 @@ ncpalette_set(ncpalette* p, int idx, unsigned rgb){
return ncchannel_set(&p->chans[idx], rgb);
}
static inline int
ncpalette_get(const ncpalette* p, int idx, uint32_t* palent){
if(idx < 0 || (size_t)idx > sizeof(p->chans) / sizeof(*p->chans)){
return -1;
}
*palent = ncchannel_rgb(p->chans[idx]);
return 0;
}
static inline int
ncpalette_get_rgb8(const ncpalette* p, int idx, unsigned* RESTRICT r, unsigned* RESTRICT g, unsigned* RESTRICT b){
if(idx < 0 || (size_t)idx > sizeof(p->chans) / sizeof(*p->chans)){
return -1;
}
return (int)ncchannel_rgb8(p->chans[idx], r, g, b);
return ncchannel_rgb8(p->chans[idx], r, g, b);
}
// Free the palette store 'p'.
@ -2002,22 +1856,18 @@ API int ncplane_scrollup_child(struct ncplane* n, const struct ncplane* child)
// characters, spaces, half blocks, and full blocks. The plane must have
// an even number of columns. Use the ncvisual rotation for a more
// flexible approach.
API int ncplane_rotate_cw(struct ncplane* n)
__attribute__ ((nonnull (1)));
API int ncplane_rotate_ccw(struct ncplane* n)
__attribute__ ((nonnull (1)));
API int ncplane_rotate_cw(struct ncplane* n);
API int ncplane_rotate_ccw(struct ncplane* n);
// Retrieve the current contents of the cell under the cursor. The EGC is
// returned, or NULL on error. This EGC must be free()d by the caller. The
// stylemask and channels are written to 'stylemask' and 'channels', respectively.
API char* ncplane_at_cursor(const struct ncplane* n, uint16_t* stylemask, uint64_t* channels)
__attribute__ ((nonnull (1)));
API char* ncplane_at_cursor(struct ncplane* n, uint16_t* stylemask, uint64_t* channels);
// Retrieve the current contents of the cell under the cursor into 'c'. This
// cell is invalidated if the associated plane is destroyed. Returns the number
// of bytes in the EGC, or -1 on error.
API int ncplane_at_cursor_cell(struct ncplane* n, nccell* c)
__attribute__ ((nonnull (1, 2)));
API int ncplane_at_cursor_cell(struct ncplane* n, nccell* c);
// Retrieve the current contents of the specified cell. The EGC is returned, or
// NULL on error. This EGC must be free()d by the caller. The stylemask and
@ -2025,20 +1875,16 @@ API int ncplane_at_cursor_cell(struct ncplane* n, nccell* c)
// represents how the cell will be used during rendering, and thus integrates
// any base cell where appropriate. If called upon the secondary columns of a
// wide glyph, the EGC will be returned (i.e. this function does not distinguish
// between the primary and secondary columns of a wide glyph). If called on a
// sprixel plane, its control sequence is returned for all valid locations.
// between the primary and secondary columns of a wide glyph).
API char* ncplane_at_yx(const struct ncplane* n, int y, int x,
uint16_t* stylemask, uint64_t* channels)
__attribute__ ((nonnull (1)));
uint16_t* stylemask, uint64_t* channels);
// Retrieve the current contents of the specified cell into 'c'. This cell is
// invalidated if the associated plane is destroyed. Returns the number of
// bytes in the EGC, or -1 on error. Unlike ncplane_at_yx(), when called upon
// the secondary columns of a wide glyph, the return can be distinguished from
// the primary column (nccell_wide_right_p(c) will return true). It is an
// error to call this on a sprixel plane (unlike ncplane_at_yx()).
API int ncplane_at_yx_cell(struct ncplane* n, int y, int x, nccell* c)
__attribute__ ((nonnull (1, 4)));
// the primary column (nccell_wide_right_p(c) will return true).
API int ncplane_at_yx_cell(struct ncplane* n, int y, int x, nccell* c);
// Create a flat string from the EGCs of the selected region of the ncplane
// 'n'. Start at the plane's 'begy'x'begx' coordinate (which must lie on the
@ -2046,24 +1892,20 @@ API int ncplane_at_yx_cell(struct ncplane* n, int y, int x, nccell* c)
// 'lenx' can be specified as 0 to go through the boundary of the plane.
// -1 can be specified for 'begx'/'begy' to use the current cursor location.
API char* ncplane_contents(struct ncplane* n, int begy, int begx,
unsigned leny, unsigned lenx)
__attribute__ ((nonnull (1)));
unsigned leny, unsigned lenx);
// Manipulate the opaque user pointer associated with this plane.
// ncplane_set_userptr() returns the previous userptr after replacing
// it with 'opaque'. the others simply return the userptr.
API void* ncplane_set_userptr(struct ncplane* n, void* opaque)
__attribute__ ((nonnull (1)));
API void* ncplane_userptr(struct ncplane* n)
__attribute__ ((nonnull (1)));
API void* ncplane_set_userptr(struct ncplane* n, void* opaque);
API void* ncplane_userptr(struct ncplane* n);
// Find the center coordinate of a plane, preferring the top/left in the
// case of an even number of rows/columns (in such a case, there will be one
// more cell to the bottom/right of the center than the top/left). The
// center is then modified relative to the plane's origin.
API void ncplane_center_abs(const struct ncplane* n, int* RESTRICT y,
int* RESTRICT x)
__attribute__ ((nonnull (1)));
int* RESTRICT x);
// Create an RGBA flat array from the selected region of the ncplane 'nc'.
// Start at the plane's 'begy'x'begx' coordinate (which must lie on the
@ -2099,7 +1941,7 @@ notcurses_align(int availu, ncalign_e align, int u){
// 'align'. Undefined behavior on negative 'c'.
static inline int
ncplane_halign(const struct ncplane* n, ncalign_e align, int c){
return notcurses_align((int)ncplane_dim_x(n), align, c);
return notcurses_align(ncplane_dim_x(n), align, c);
}
// Return the row at which 'r' rows ought start in order to be aligned
@ -2107,7 +1949,7 @@ ncplane_halign(const struct ncplane* n, ncalign_e align, int c){
// 'align'. Undefined behavior on negative 'r'.
static inline int
ncplane_valign(const struct ncplane* n, ncalign_e align, int r){
return notcurses_align((int)ncplane_dim_y(n), align, r);
return notcurses_align(ncplane_dim_y(n), align, r);
}
// Move the cursor to the specified position (the cursor needn't be visible).
@ -2130,25 +1972,11 @@ API void ncplane_home(struct ncplane* n)
API void ncplane_cursor_yx(const struct ncplane* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
__attribute__ ((nonnull (1)));
static inline unsigned
ncplane_cursor_y(const struct ncplane* n){
unsigned y;
ncplane_cursor_yx(n, &y, NULL);
return y;
}
static inline unsigned
ncplane_cursor_x(const struct ncplane* n){
unsigned x;
ncplane_cursor_yx(n, NULL, &x);
return x;
}
// Get the current colors and alpha values for ncplane 'n'.
// Get the current channels or attribute word for ncplane 'n'.
API uint64_t ncplane_channels(const struct ncplane* n)
__attribute__ ((nonnull (1)));
// Get the current styling for the ncplane 'n'.
// Return the current styling for this ncplane.
API uint16_t ncplane_styles(const struct ncplane* n)
__attribute__ ((nonnull (1)));
@ -2166,9 +1994,8 @@ ncplane_putc(struct ncplane* n, const nccell* c){
}
// Replace the cell at the specified coordinates with the provided 7-bit char
// 'c'. Advance the cursor by 1. On success, returns the number of columns the
// cursor was advanced. On failure, returns -1. This works whether the
// underlying char is signed or unsigned.
// 'c'. Advance the cursor by 1. On success, returns 1. On failure, returns -1.
// This works whether the underlying char is signed or unsigned.
static inline int
ncplane_putchar_yx(struct ncplane* n, int y, int x, char c){
nccell ce = NCCELL_INITIALIZER((uint32_t)c, ncplane_styles(n), ncplane_channels(n));
@ -2192,8 +2019,7 @@ API int ncplane_putchar_stained(struct ncplane* n, char c)
// On failure, -1 is returned. The number of bytes converted from gclust is
// written to 'sbytes' if non-NULL.
API int ncplane_putegc_yx(struct ncplane* n, int y, int x, const char* gclust,
size_t* sbytes)
__attribute__ ((nonnull (1, 4)));
size_t* sbytes);
// Call ncplane_putegc_yx() at the current cursor location.
static inline int
@ -2296,7 +2122,7 @@ ncplane_putstr_aligned(struct ncplane* n, int y, ncalign_e align, const char* s)
ncstrwidth(s, &validbytes, &validwidth);
int xpos = ncplane_halign(n, align, validwidth);
if(xpos < 0){
xpos = 0;
return -1;
}
return ncplane_putstr_yx(n, y, xpos, s);
}
@ -2333,9 +2159,9 @@ API int ncplane_putnstr_aligned(struct ncplane* n, int y, ncalign_e align, size_
static inline int
ncplane_putnstr_yx(struct ncplane* n, int y, int x, size_t s, const char* gclusters){
int ret = 0;
size_t offset = 0;
int offset = 0;
//fprintf(stderr, "PUT %zu at %d/%d [%.*s]\n", s, y, x, (int)s, gclusters);
while(offset < s && gclusters[offset]){
while((size_t)offset < s && gclusters[offset]){
size_t wcs;
int cols = ncplane_putegc_yx(n, y, x, gclusters + offset, &wcs);
if(cols < 0){
@ -2388,7 +2214,7 @@ ncplane_putwstr_aligned(struct ncplane* n, int y, ncalign_e align,
int width = wcswidth(gclustarr, INT_MAX);
int xpos = ncplane_halign(n, align, width);
if(xpos < 0){
xpos = 0;
return -1;
}
return ncplane_putwstr_yx(n, y, xpos, gclustarr);
}
@ -2416,7 +2242,7 @@ ncplane_pututf32_yx(struct ncplane* n, int y, int x, uint32_t u){
memset(&ps, 0, sizeof(ps));
// this isn't going to be valid for reconstructued surrogate pairs...
// we need our own, or to use unistring or something.
size_t s = wcrtomb(utf8c, (wchar_t)u, &ps);
size_t s = wcrtomb(utf8c, u, &ps);
if(s == (size_t)-1){
return -1;
}
@ -2426,7 +2252,7 @@ ncplane_pututf32_yx(struct ncplane* n, int y, int x, uint32_t u){
static inline int
ncplane_putwc_yx(struct ncplane* n, int y, int x, wchar_t w){
return ncplane_pututf32_yx(n, y, x, (uint32_t)w);
return ncplane_pututf32_yx(n, y, x, w);
}
// Write 'w' at the current cursor position, using the plane's current styling.
@ -2456,7 +2282,7 @@ ncplane_putwc_utf32(struct ncplane* n, const wchar_t* w, unsigned* wchars){
utf32 += (w[1] & 0x3fflu);
}else{
*wchars = 1;
utf32 = (uint32_t)*w;
utf32 = *w;
}
return ncplane_pututf32_yx(n, -1, -1, utf32);
}
@ -2829,7 +2655,7 @@ nccell_set_fg_rgb(nccell* c, uint32_t channel){
// Set the cell's foreground palette index, set the foreground palette index
// bit, set it foreground-opaque, and clear the foreground default color bit.
static inline int
nccell_set_fg_palindex(nccell* cl, unsigned idx){
nccell_set_fg_palindex(nccell* cl, int idx){
return ncchannels_set_fg_palindex(&cl->channels, idx);
}
@ -2861,7 +2687,7 @@ nccell_set_bg_rgb(nccell* c, uint32_t channel){
// Set the cell's background palette index, set the background palette index
// bit, set it background-opaque, and clear the background default color bit.
static inline int
nccell_set_bg_palindex(nccell* cl, unsigned idx){
nccell_set_bg_palindex(nccell* cl, int idx){
return ncchannels_set_bg_palindex(&cl->channels, idx);
}
@ -2894,47 +2720,29 @@ nccell_bg_palindex_p(const nccell* cl){
return ncchannels_bg_palindex_p(cl->channels);
}
// Extract the background alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
// Extract the 32-bit working background channel from an ncplane.
static inline uint32_t
ncplane_bchannel(const struct ncplane* n){
return ncchannels_bchannel(ncplane_channels(n));
}
// Extract the foreground alpha and coloring bits from a 64-bit channel
// pair as a single 32-bit value.
// Extract the 32-bit working foreground channel from an ncplane.
static inline uint32_t
ncplane_fchannel(const struct ncplane* n){
return ncchannels_fchannel(ncplane_channels(n));
}
// Set the alpha and coloring bits of the plane's current channels from a
// 64-bit pair of channels.
API void ncplane_set_channels(struct ncplane* n, uint64_t channels)
__attribute__ ((nonnull (1)));
// Set the background alpha and coloring bits of the plane's current
// channels from a single 32-bit value.
API uint64_t ncplane_set_bchannel(struct ncplane* n, uint32_t channel)
__attribute__ ((nonnull (1)));
// Set the foreground alpha and coloring bits of the plane's current
// channels from a single 32-bit value.
API uint64_t ncplane_set_fchannel(struct ncplane* n, uint32_t channel)
__attribute__ ((nonnull (1)));
API void ncplane_set_channels(struct ncplane* n, uint64_t channels);
// Set the specified style bits for the ncplane 'n', whether they're actively
// supported or not.
API void ncplane_set_styles(struct ncplane* n, unsigned stylebits)
__attribute__ ((nonnull (1)));
API void ncplane_set_styles(struct ncplane* n, unsigned stylebits);
// Add the specified styles to the ncplane's existing spec.
API void ncplane_on_styles(struct ncplane* n, unsigned stylebits)
__attribute__ ((nonnull (1)));
API void ncplane_on_styles(struct ncplane* n, unsigned stylebits);
// Remove the specified styles from the ncplane's existing spec.
API void ncplane_off_styles(struct ncplane* n, unsigned stylebits)
__attribute__ ((nonnull (1)));
API void ncplane_off_styles(struct ncplane* n, unsigned stylebits);
// Extract 24 bits of working foreground RGB from an ncplane, shifted to LSBs.
static inline uint32_t
@ -2984,6 +2792,10 @@ ncplane_bg_rgb8(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b){
return ncchannels_bg_rgb8(ncplane_channels(n), r, g, b);
}
// Set an entire 32-bit channel of the plane
API uint64_t ncplane_set_fchannel(struct ncplane* n, uint32_t channel);
API uint64_t ncplane_set_bchannel(struct ncplane* n, uint32_t channel);
// Set the current fore/background color using RGB specifications. If the
// terminal does not support directly-specified 3x8b cells (24-bit "TrueColor",
// indicated by the "RGB" terminfo capability), the provided values will be
@ -3007,8 +2819,8 @@ API void ncplane_set_bg_default(struct ncplane* n);
// Set the ncplane's foreground palette index, set the foreground palette index
// bit, set it foreground-opaque, and clear the foreground default color bit.
API int ncplane_set_fg_palindex(struct ncplane* n, unsigned idx);
API int ncplane_set_bg_palindex(struct ncplane* n, unsigned idx);
API int ncplane_set_fg_palindex(struct ncplane* n, int idx);
API int ncplane_set_bg_palindex(struct ncplane* n, int idx);
// Set the alpha parameters for ncplane 'n'.
API int ncplane_set_fg_alpha(struct ncplane* n, int alpha);
@ -3072,7 +2884,7 @@ API void ncfadectx_free(struct ncfadectx* nctx);
// have loaded before the error are nccell_release()d. There must be at least
// six EGCs in gcluster.
static inline int
nccells_load_box(struct ncplane* n, uint16_t styles, uint64_t channels,
nccells_load_box(struct ncplane* n, uint32_t styles, uint64_t channels,
nccell* ul, nccell* ur, nccell* ll, nccell* lr,
nccell* hl, nccell* vl, const char* gclusters){
int ulen;
@ -3262,27 +3074,21 @@ API ALLOC struct ncvisual* ncvisual_from_file(const char* file)
// memory at 'rgba'. 'rgba' is laid out as 'rows' lines, each of which is
// 'rowstride' bytes in length. Each line has 'cols' 32-bit 8bpc RGBA pixels
// followed by possible padding (there will be 'rowstride' - 'cols' * 4 bytes
// of padding). The total size of 'rgba' is thus ('rows' * 'rowstride') bytes,
// of which ('rows' * 'cols' * 4) bytes are actual non-padding data. It is an
// error if any argument is not positive, if 'rowstride' is not a multiple of
// 4, or if 'rowstride' is less than 'cols' * 4.
// of padding). The total size of 'rgba' is thus (rows * rowstride) bytes, of
// which (rows * cols * 4) bytes are actual non-padding data.
API ALLOC struct ncvisual* ncvisual_from_rgba(const void* rgba, int rows,
int rowstride, int cols)
__attribute__ ((nonnull (1)));
// ncvisual_from_rgba(), but the pixels are 3-byte RGB. A is filled in
// throughout using 'alpha'. It is an error if 'rows', 'rowstride', or 'cols'
// is not positive, if 'rowstride' is not a multiple of 3, or if 'rowstride'
// is less than 'cols' * 3.
// throughout using 'alpha'.
API ALLOC struct ncvisual* ncvisual_from_rgb_packed(const void* rgba, int rows,
int rowstride, int cols,
int alpha)
__attribute__ ((nonnull (1)));
// ncvisual_from_rgba(), but the pixels are 4-byte RGBx. A is filled in
// throughout using 'alpha'. It is an error if 'rows', 'cols', or 'rowstride'
// are not positive, if 'rowstride' is not a multiple of 4, or if 'rowstride'
// is less than 'cols' * 4.
// throughout using 'alpha'. rowstride must be a multiple of 4.
API ALLOC struct ncvisual* ncvisual_from_rgb_loose(const void* rgba, int rows,
int rowstride, int cols,
int alpha)
@ -3291,8 +3097,6 @@ API ALLOC struct ncvisual* ncvisual_from_rgb_loose(const void* rgba, int rows,
// ncvisual_from_rgba(), but 'bgra' is arranged as BGRA. note that this is a
// byte-oriented layout, despite being bunched in 32-bit pixels; the lowest
// memory address ought be B, and A is reached by adding 3 to that address.
// It is an error if 'rows', 'cols', or 'rowstride' are not positive, if
// 'rowstride' is not a multiple of 4, or if 'rowstride' is less than 'cols' * 4.
API ALLOC struct ncvisual* ncvisual_from_bgra(const void* bgra, int rows,
int rowstride, int cols)
__attribute__ ((nonnull (1)));
@ -3300,9 +3104,6 @@ API ALLOC struct ncvisual* ncvisual_from_bgra(const void* bgra, int rows,
// ncvisual_from_rgba(), but 'data' is 'pstride'-byte palette-indexed pixels,
// arranged in 'rows' lines of 'rowstride' bytes each, composed of 'cols'
// pixels. 'palette' is an array of at least 'palsize' ncchannels.
// It is an error if 'rows', 'cols', 'rowstride', or 'pstride' are not
// positive, if 'rowstride' is not a multiple of 'pstride', or if 'rowstride'
// is less than 'cols' * 'pstride'.
API ALLOC struct ncvisual* ncvisual_from_palidx(const void* data, int rows,
int rowstride, int cols,
int palsize, int pstride,
@ -3321,10 +3122,6 @@ API ALLOC struct ncvisual* ncvisual_from_plane(const struct ncplane* n,
unsigned leny, unsigned lenx)
__attribute__ ((nonnull (1)));
// Construct an ncvisual from a nul-terminated Sixel control sequence.
API ALLOC struct ncvisual* ncvisual_from_sixel(const char* s, unsigned leny, unsigned lenx)
__attribute__ ((nonnull (1)));
#define NCVISUAL_OPTION_NODEGRADE 0x0001ull // fail rather than degrade
#define NCVISUAL_OPTION_BLEND 0x0002ull // use NCALPHA_BLEND with visual
#define NCVISUAL_OPTION_HORALIGNED 0x0004ull // x is an alignment, not absolute
@ -3390,7 +3187,7 @@ typedef struct ncvgeom {
unsigned cdimy, cdimx; // terminal cell geometry when this was calculated
unsigned rpixy, rpixx; // rendered pixel geometry (per visual_options)
unsigned rcelly, rcellx; // rendered cell geometry (per visual_options)
unsigned scaley, scalex; // source pixels per filled cell
unsigned scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
unsigned begy, begx; // upper-left corner of used region
unsigned leny, lenx; // geometry of used region
unsigned maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
@ -3584,25 +3381,25 @@ API int ncblit_rgb_loose(const void* data, int linesize,
// Extract the 8-bit alpha component from a pixel
static inline unsigned
ncpixel_a(uint32_t pixel){
return (htole(pixel) & 0xff000000u) >> 24u;
return (htole(pixel) & 0xff000000ul) >> 24u;
}
// Extract the 8-bit red component from an ABGR pixel
static inline unsigned
ncpixel_r(uint32_t pixel){
return (htole(pixel) & 0x000000ffu);
return (htole(pixel) & 0x000000fful);
}
// Extract the 8-bit green component from an ABGR pixel
static inline unsigned
ncpixel_g(uint32_t pixel){
return (htole(pixel) & 0x0000ff00u) >> 8u;
return (htole(pixel) & 0x0000ff00ul) >> 8u;
}
// Extract the 8-bit blue component from an ABGR pixel
static inline unsigned
ncpixel_b(uint32_t pixel){
return (htole(pixel) & 0x00ff0000u) >> 16u;
return (htole(pixel) & 0x00ff0000ul) >> 16u;
}
// Set the 8-bit alpha component of an ABGR pixel
@ -3611,7 +3408,7 @@ ncpixel_set_a(uint32_t* pixel, unsigned a){
if(a > 255){
return -1;
}
*pixel = htole((htole(*pixel) & 0x00ffffffu) | (a << 24u));
*pixel = htole((htole(*pixel) & 0x00fffffful) | (a << 24u));
return 0;
}
@ -3621,7 +3418,7 @@ ncpixel_set_r(uint32_t* pixel, unsigned r){
if(r > 255){
return -1;
}
*pixel = htole((htole(*pixel) & 0xffffff00u) | r);
*pixel = htole((htole(*pixel) & 0xffffff00ul) | r);
return 0;
}
@ -3631,7 +3428,7 @@ ncpixel_set_g(uint32_t* pixel, unsigned g){
if(g > 255){
return -1;
}
*pixel = htole((htole(*pixel) & 0xffff00ffu) | (g << 8u));
*pixel = htole((htole(*pixel) & 0xffff00fful) | (g << 8u));
return 0;
}
@ -3641,19 +3438,22 @@ ncpixel_set_b(uint32_t* pixel, unsigned b){
if(b > 255){
return -1;
}
*pixel = htole((htole(*pixel) & 0xff00ffffu) | (b << 16u));
*pixel = htole((htole(*pixel) & 0xff00fffful) | (b << 16u));
return 0;
}
// Construct a libav-compatible ABGR pixel, clipping at [0, 255).
static inline uint32_t
ncpixel(unsigned r, unsigned g, unsigned b){
ncpixel(int r, int g, int b){
uint32_t pixel = 0;
ncpixel_set_a(&pixel, 0xff);
if(r < 0) r = 0;
if(r > 255) r = 255;
ncpixel_set_r(&pixel, r);
if(g < 0) g = 0;
if(g > 255) g = 255;
ncpixel_set_g(&pixel, g);
if(b < 0) b = 0;
if(b > 255) b = 255;
ncpixel_set_b(&pixel, b);
return pixel;
@ -3801,7 +3601,8 @@ API struct ncplane* nctablet_plane(struct nctablet* t);
//
// You are encouraged to consult notcurses_metric(3).
API const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal,
char* buf, int omitdec, uintmax_t mult, int uprefix)
char* buf, int omitdec, uintmax_t mult,
int uprefix)
__attribute__ ((nonnull (4)));
// The number of columns is one fewer, as the STRLEN expressions must leave
@ -3823,7 +3624,7 @@ API const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal,
#define NCMETRICFWIDTH(x, cols) \
((int)(strlen(x) - ncstrwidth(x, NULL, NULL) + (cols)))
#define NCPREFIXFMT(x) NCMETRICFWIDTH((x), NCPREFIXCOLUMNS), (x)
#define NCIPREFIXFMT(x) NCMETRICFWIDTH((x), NCIPREFIXCOLUMNS), (x)
#define NCIPREFIXFMT(x) NCMETRIXFWIDTH((x), NCIPREFIXCOLUMNS), (x)
#define NCBPREFIXFMT(x) NCMETRICFWIDTH((x), NCBPREFIXCOLUMNS), (x)
// Mega, kilo, gigafoo. Use PREFIXSTRLEN + 1 and PREFIXCOLUMNS.
@ -3915,7 +3716,7 @@ typedef struct ncselector_options {
uint64_t titlechannels;// title channels
uint64_t footchannels; // secondary and footer channels
uint64_t boxchannels; // border channels
uint64_t flags; // bitfield of NCSELECTOR_OPTION_*, currently unused
uint64_t flags; // bitfield of NCSELECTOR_OPTION_*
} ncselector_options;
API ALLOC struct ncselector* ncselector_create(struct ncplane* n, const ncselector_options* opts)
@ -3994,7 +3795,7 @@ typedef struct ncmultiselector_options {
uint64_t titlechannels;// title channels
uint64_t footchannels; // secondary and footer channels
uint64_t boxchannels; // border channels
uint64_t flags; // bitfield of NCMULTISELECTOR_OPTION_*, currently unused
uint64_t flags; // bitfield of NCMULTISELECTOR_OPTION_*
} ncmultiselector_options;
API ALLOC struct ncmultiselector* ncmultiselector_create(struct ncplane* n, const ncmultiselector_options* opts)

@ -13,22 +13,34 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from time import sleep
from notcurses import Notcurses
nc = Notcurses()
plane = nc.stdplane()
y_dimension, x_dimension = plane.dim_yx()
stdplane = nc.stdplane()
red = 0x80
green = 0x80
blue = 0x80
y_dimension, x_dimension = stdplane.dim_yx()
for y in range(y_dimension):
for x in range(x_dimension):
y_frac = round(y / y_dimension * 256)
x_frac = round(x / x_dimension * 256)
plane.set_fg_rgb8(128, y_frac, x_frac)
plane.set_bg_rgb8(x_frac, 128, y_frac)
plane.putstr_yx(y, x, 'X')
stdplane.set_fg_rgb8(red, green, blue)
stdplane.set_bg_rgb8(blue, red, green)
stdplane.putstr_yx(y, x, 'X')
blue += 2
if blue == 256:
blue = 0
green += 2
if green == 256:
green = 0
red = (red + 2) % 256
nc.render()
sleep(5)
sleep(5)

@ -14,27 +14,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from notcurses import Notcurses
nc = Notcurses()
std_plane = nc.stdplane()
from notcurses import get_std_plane
std_plane = get_std_plane()
std_plane.putstr("Enter string!")
nc.render()
nc.mice_enable()
std_plane.context.render()
std_plane.context.enable_cursor()
std_plane.context.enable_mouse()
while True:
# Get an input event and print its properties
inp = nc.get_blocking()
p = std_plane.context.get_input_blocking()
std_plane.erase()
std_plane.putstr_yx(1, 4, f"Code point: {hex(inp.id)}")
std_plane.putstr_yx(2, 4, f"Y pos: {inp.y}")
std_plane.putstr_yx(3, 4, f"X pos: {inp.x}")
std_plane.putstr_yx(4, 4, f"UTF-8: {inp.utf8!r}")
std_plane.putstr_yx(5, 4, f"Event type: {inp.evtype}")
std_plane.putstr_yx(6, 4, f"Modifiers: {bin(inp.modifiers)}")
std_plane.putstr_yx(7, 4, f"Y pixel offset: {inp.ypx}")
std_plane.putstr_yx(8, 4, f"X pixel offset: {inp.xpx}")
std_plane.putstr_yx(10, 4, "Press CTRL+C to exit.")
nc.render()
std_plane.putstr(f"Code point: {repr(p.code)}",
y_pos=0, x_pos=0)
std_plane.putstr(f"Y pos: {p.y_pos}", y_pos=1, x_pos=0)
std_plane.putstr(f"X pos: {p.x_pos}", y_pos=2, x_pos=0)
std_plane.putstr(f"Is alt: {p.is_alt}", y_pos=3, x_pos=0)
std_plane.putstr(f"Is shift: {p.is_shift}", y_pos=4, x_pos=0)
std_plane.putstr(f"Is ctrl: {p.is_ctrl}", y_pos=5, x_pos=0)
std_plane.putstr("Press CTRL+C to exit.", y_pos=7, x_pos=0)
std_plane.context.render()

@ -1,37 +0,0 @@
from time import sleep
import notcurses as nc
notcurses = nc.Notcurses()
plane = notcurses.stdplane()
BOX_CHARS = (
nc.NCBOXASCII,
nc.NCBOXDOUBLE,
nc.NCBOXHEAVY,
nc.NCBOXLIGHT,
nc.NCBOXOUTER,
nc.NCBOXROUND,
)
COLORS = (
(None, None),
(None, nc.rgb(128, 128, 128)), # default on grey
(nc.rgb(255, 0, 0), None), # red on default
(nc.rgb(0, 255, 0), nc.rgb(0, 0, 255)), # green on blue
)
SY = 7
SX = 10
for y, (fg, bg) in enumerate(COLORS):
for x, box_chars in enumerate(BOX_CHARS):
plane.cursor_move_yx(y * SY + 1, x * SX + 1);
nc.box(
plane, (y + 1) * SY - 1, (x + 1) * SX - 1,
box_chars,
fg=fg, bg=bg,
# ctlword=0x1f9
)
notcurses.render()
sleep(5)

@ -15,8 +15,7 @@
# limitations under the License.
from .notcurses import (
NcPlane, Notcurses, NcInput,
ncchannel_alpha, ncchannel_b, ncchannel_default_p,
NcPlane, Notcurses, ncchannel_alpha, ncchannel_b, ncchannel_default_p,
ncchannel_g, ncchannel_palindex, ncchannel_palindex_p, ncchannel_r,
ncchannel_rgb8, ncchannel_rgb_initializer, ncchannel_set,
ncchannel_set_alpha, ncchannel_set_default, ncchannel_set_palindex,
@ -35,8 +34,6 @@ from .notcurses import (
ncchannels_set_fg_rgb, ncchannels_set_fg_rgb8,
ncchannels_set_fg_rgb8_clipped, ncstrwidth, notcurses_version,
notcurses_version_components,
NCBOXASCII, NCBOXDOUBLE, NCBOXHEAVY, NCBOXLIGHT, NCBOXOUTER, NCBOXROUND,
box, rgb,
)
__all__ = (
@ -63,6 +60,4 @@ __all__ = (
'ncchannels_set_fg_rgb8_clipped',
'ncstrwidth', 'notcurses_version', 'notcurses_version_components',
'box', 'rgb',
)

@ -166,9 +166,9 @@ static PyObject *
python_ncchannel_set_palindex(PyObject *Py_UNUSED(self), PyObject *args)
{
unsigned long ncchannel = {0};
unsigned int idx = {0};
int idx = {0};
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "kI", &ncchannel, &idx));
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "ki", &ncchannel, &idx));
uint32_t ncchannel_fixed_size = (uint32_t)ncchannel;
@ -398,9 +398,9 @@ static PyObject *
python_ncchannels_set_fg_palindex(PyObject *Py_UNUSED(self), PyObject *args)
{
unsigned long long ncchannels = {0};
unsigned int idx = {0};
int idx = {0};
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "KI", &ncchannels, &idx));
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "Ki", &ncchannels, &idx));
uint64_t ncchannels_fixed_size = (uint64_t)ncchannels;
@ -473,9 +473,9 @@ static PyObject *
python_ncchannels_set_bg_palindex(PyObject *Py_UNUSED(self), PyObject *args)
{
unsigned long long ncchannels = {0};
unsigned int idx = {0};
int idx = {0};
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "KI", &ncchannels, &idx));
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "Ki", &ncchannels, &idx));
uint64_t ncchannels_fixed_size = (uint64_t)ncchannels;

@ -181,95 +181,32 @@ Notcurses_bottom(NotcursesObject *self, PyObject *Py_UNUSED(args))
}
static PyObject *
Notcurses_inputready_fd(NotcursesObject *self, PyObject *Py_UNUSED(args))
{
int input_fd = notcurses_inputready_fd(self->notcurses_ptr);
return PyLong_FromLong((long)input_fd);
}
static PyObject *
build_NcInput(uint32_t const id, ncinput const *const ni)
Notcurses_getc(NotcursesObject *Py_UNUSED(self), PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(kwds))
{
if (id == (uint32_t)-1)
{
PyErr_Format(PyExc_RuntimeError, "notcurses_get_nblock return -1");
return NULL;
}
else if (id == 0)
// No input event.
Py_RETURN_NONE;
else
{
PyObject *input = GNU_PY_CHECK(PyStructSequence_New(NcInput_Type));
PyObject *utf8 = GNU_PY_CHECK(PyUnicode_FromStringAndSize(ni->utf8, (Py_ssize_t)strlen(ni->utf8)));
PyStructSequence_SET_ITEM(input, 0, PyLong_FromLong(ni->id));
PyStructSequence_SET_ITEM(input, 1, PyLong_FromLong(ni->y));
PyStructSequence_SET_ITEM(input, 2, PyLong_FromLong(ni->x));
PyStructSequence_SET_ITEM(input, 3, utf8);
PyStructSequence_SET_ITEM(input, 4, PyLong_FromLong(ni->evtype));
PyStructSequence_SET_ITEM(input, 5, PyLong_FromLong(ni->modifiers));
PyStructSequence_SET_ITEM(input, 6, PyLong_FromLong(ni->ypx));
PyStructSequence_SET_ITEM(input, 7, PyLong_FromLong(ni->xpx));
return input;
}
}
static inline struct timespec secs_to_timespec(double const sec) {
assert(sec >= 0);
struct timespec const timespec = {
.tv_sec = (time_t)sec,
.tv_nsec = (long)((sec - (double)(time_t)sec) * 1E+9) };
return timespec;
PyErr_SetString(PyExc_NotImplementedError, "TODO when ncinput is implemented");
return NULL;
}
static PyObject *
Notcurses_get(NotcursesObject *self, PyObject *args, PyObject *kw)
Notcurses_inputready_fd(NotcursesObject *self, PyObject *Py_UNUSED(args))
{
static char *keywords[] = {"deadline", NULL};
PyObject* deadline_arg;
if (!PyArg_ParseTupleAndKeywords(args, kw, "O", keywords, &deadline_arg))
return NULL;
struct timespec timespec;
struct timespec *ts;
if (deadline_arg == Py_None)
// No deadline.
ts = NULL;
else
{
double const deadline = PyFloat_AsDouble(deadline_arg);
if (PyErr_Occurred())
// Can't convert to float sec.
return NULL;
if (deadline < 0)
{
PyErr_Format(PyExc_ValueError, "negative deadline");
return NULL;
}
timespec = secs_to_timespec(deadline);
ts = &timespec;
}
int input_fd = notcurses_inputready_fd(self->notcurses_ptr);
struct ncinput ni;
uint32_t const id = notcurses_get(self->notcurses_ptr, ts, &ni);
return build_NcInput(id, &ni);
return PyLong_FromLong((long)input_fd);
}
static PyObject *
Notcurses_get_nblock(NotcursesObject *self, PyObject *Py_UNUSED(args))
Notcurses_getc_nblock(NotcursesObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
{
struct ncinput ni;
uint32_t const id = notcurses_get_nblock(self->notcurses_ptr, &ni);
return build_NcInput(id, &ni);
PyErr_SetString(PyExc_NotImplementedError, "TODO when ncinput is implemented");
return NULL;
}
static PyObject *
Notcurses_get_blocking(NotcursesObject *self, PyObject *Py_UNUSED(args))
Notcurses_getc_blocking(NotcursesObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
{
struct ncinput ni;
uint32_t const id = notcurses_get_blocking(self->notcurses_ptr, &ni);
return build_NcInput(id, &ni);
PyErr_SetString(PyExc_NotImplementedError, "TODO when ncinput is implemented");
return NULL;
}
static PyObject *
@ -278,7 +215,6 @@ Notcurses_mice_enable(NotcursesObject *self, PyObject *Py_UNUSED(args))
CHECK_NOTCURSES(notcurses_mice_enable(self->notcurses_ptr, NCMICE_BUTTON_EVENT));
Py_RETURN_NONE;
}
static PyObject *
Notcurses_mice_disable(NotcursesObject *self, PyObject *Py_UNUSED(args))
{
@ -503,10 +439,10 @@ static PyMethodDef Notcurses_methods[] = {
{"top", (PyCFunction)Notcurses_top, METH_NOARGS, "Return the topmost ncplane of the standard pile."},
{"bottom", (PyCFunction)Notcurses_bottom, METH_NOARGS, "Return the bottommost ncplane of the standard pile."},
{"get", (void *)Notcurses_get, METH_VARARGS | METH_KEYWORDS, "See ppoll(2) for more detail. Provide a None 'ts' to block at length, a 'ts' of 0 for non-blocking operation, and otherwise a timespec to bound blocking. Signals in sigmask (less several we handle internally) will be atomically masked and unmasked per ppoll(2). It should generally contain all signals. Returns a single Unicode code point, or (char32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an event is processed, the return value is the 'id' field from that event. 'ni' may be NULL."},
{"getc", (void *)Notcurses_getc, METH_VARARGS | METH_KEYWORDS, "See ppoll(2) for more detail. Provide a None 'ts' to block at length, a 'ts' of 0 for non-blocking operation, and otherwise a timespec to bound blocking. Signals in sigmask (less several we handle internally) will be atomically masked and unmasked per ppoll(2). It should generally contain all signals. Returns a single Unicode code point, or (char32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an event is processed, the return value is the 'id' field from that event. 'ni' may be NULL."},
{"inputready_fd", (PyCFunction)Notcurses_inputready_fd, METH_NOARGS, "Get a file descriptor suitable for input event poll()ing. When this descriptor becomes available, you can call notcurses_getc_nblock(), and input ought be ready. This file descriptor is *not* necessarily the file descriptor associated with stdin (but it might be!)."},
{"get_nblock", (PyCFunction)Notcurses_get_nblock, METH_NOARGS, "Get input event without blocking. If no event is ready, returns None."},
{"get_blocking", (PyCFunction)Notcurses_get_blocking, METH_NOARGS, "Get input event completely blocking until and event or signal received."},
{"getc_nblock", (PyCFunction)Notcurses_getc_nblock, METH_NOARGS, "Get input event without blocking. If no event is ready, returns None."},
{"getc_blocking", (PyCFunction)Notcurses_getc_blocking, METH_NOARGS, "Get input event completely blocking until and event or signal received."},
{"mice_enable", (PyCFunction)Notcurses_mice_enable, METH_NOARGS, "Enable the mouse in \"button-event tracking\" mode with focus detection and UTF8-style extended coordinates. On success mouse events will be published to getc()"},
{"mice_disable", (PyCFunction)Notcurses_mice_disable, METH_NOARGS, "Disable mouse events. Any events in the input queue can still be delivered."},

@ -1,142 +0,0 @@
#include <Python.h>
#include <stdint.h>
#include "notcurses-python.h"
// TODO: alpha flags on channels
// TODO: indexed color channels
// TODO: perimeter function
// TODO: rationalize coordinate / size args
// TODO: provide a way to set channels for each corner
// TODO: docstrings
// TODO: unit tests
/*
* Converts borrowed `obj` to a channel value in `channel`. Returns 1 on
* success.
*/
static int
to_channel(PyObject* obj, uint32_t* channel) {
// None → default color.
if (obj == Py_None) {
*channel = 0;
return 1;
}
// A single long → channel value.
long long const value = PyLong_AsLongLong(obj);
if (PyErr_Occurred())
PyErr_Clear();
// And fall through.
else if (value & ~0xffffffffll) {
PyErr_Format(PyExc_ValueError, "invalid channel: %lld", value);
return 0;
}
else {
*channel = (uint32_t) value;
return 1;
}
PyErr_Format(PyExc_TypeError, "not a channel: %R", obj);
return 0;
}
static PyObject*
pync_meth_box(PyObject* Py_UNUSED(self), PyObject* args, PyObject* kwargs) {
static char* keywords[] = {
"plane", "ystop", "xstop", "box_chars", "styles", "fg", "bg",
"ctlword", NULL
};
NcPlaneObject* plane_arg;
unsigned ystop;
unsigned xstop;
const char* box_chars = NCBOXASCII;
uint16_t styles = 0;
PyObject* fg_arg = 0;
PyObject* bg_arg = 0;
unsigned ctlword = 0;
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "O!II|s$HOOI:box", keywords,
&NcPlane_Type, &plane_arg,
&ystop, &xstop, &box_chars,
&styles, &fg_arg, &bg_arg, &ctlword))
return NULL;
uint32_t fg;
if (!to_channel(fg_arg, &fg))
return NULL;
uint32_t bg;
if (!to_channel(bg_arg, &bg))
return NULL;
uint64_t const channels = (uint64_t) fg << 32 | bg;
struct ncplane* const plane = plane_arg->ncplane_ptr;
if (!notcurses_canutf8(ncplane_notcurses(plane)))
// No UTF-8 support; force ASCII.
box_chars = NCBOXASCII;
int ret;
nccell ul = NCCELL_TRIVIAL_INITIALIZER;
nccell ur = NCCELL_TRIVIAL_INITIALIZER;
nccell ll = NCCELL_TRIVIAL_INITIALIZER;
nccell lr = NCCELL_TRIVIAL_INITIALIZER;
nccell hl = NCCELL_TRIVIAL_INITIALIZER;
nccell vl = NCCELL_TRIVIAL_INITIALIZER;
ret = nccells_load_box(
plane, styles, channels, &ul, &ur, &ll, &lr, &hl, &vl, box_chars);
if (ret == -1) {
PyErr_Format(PyExc_RuntimeError, "nccells_load_box returned %i", ret);
return NULL;
}
ret = ncplane_box(plane, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword);
if (ret < 0)
PyErr_Format(PyExc_RuntimeError, "nplane_box returned %i", ret);
nccell_release(plane, &ul);
nccell_release(plane, &ur);
nccell_release(plane, &ll);
nccell_release(plane, &lr);
nccell_release(plane, &hl);
nccell_release(plane, &vl);
if (ret < 0)
return NULL;
else
Py_RETURN_NONE;
}
static PyObject*
pync_meth_rgb(PyObject* Py_UNUSED(self), PyObject* args) {
int r;
int g;
int b;
if (!PyArg_ParseTuple(args, "iii", &r, &g, &b))
return NULL;
if ((r & ~0xff) == 0 && (g & ~0xff) == 0 && (b & ~0xff) == 0)
return PyLong_FromLong(
0x40000000u | (uint32_t) r << 16 | (uint32_t) g << 8 | (uint32_t) b);
else {
PyErr_Format(PyExc_ValueError, "invalid rgb: (%d, %d, %d)", r, g, b);
return NULL;
}
}
struct PyMethodDef pync_methods[] = {
{
"box",
(void*) pync_meth_box,
METH_VARARGS | METH_KEYWORDS,
"FIXME: Docs."
},
{
"rgb",
(void*) pync_meth_rgb,
METH_VARARGS,
"FIXME: Docs."
},
{NULL, NULL, 0, NULL}
};

@ -15,8 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <Python.h>
#include "notcurses-python.h"
PyObject *traceback_format_exception = NULL;
@ -29,39 +27,15 @@ Notcurses_module_free(PyObject *Py_UNUSED(self))
Py_XDECREF(new_line_unicode);
}
extern PyMethodDef pync_methods[];
static struct PyModuleDef NotcursesMiscModule = {
PyModuleDef_HEAD_INIT,
.m_name = "Notcurses",
.m_doc = "Notcurses python module",
.m_size = -1,
.m_methods = pync_methods,
.m_methods = NULL,
.m_free = (freefunc)Notcurses_module_free,
};
static PyStructSequence_Field NcInput_fields[] = {
{"id", "Unicode codepoint or synthesized NCKEY event"},
{"y", "y cell coordinate of event, -1 for undefined"},
{"x", "x cell coordinate of event, -1 for undefined"},
{"utf8", "utf8 representation, if one exists"},
// Note: alt, shift, ctrl fields deprecated in C API are omitted.
{"evtype", NULL},
{"modifiers", "bitmask over NCKEY_MOD_*"},
{"ypx", "y pixel offset within cell, -1 for undefined"},
{"xpx", "x pixel offset within cell, -1 for undefined"},
{NULL, NULL},
};
static struct PyStructSequence_Desc NcInput_desc = {
.name = "NcInput",
.doc = "Notcurses input event",
.fields = NcInput_fields,
.n_in_sequence = 8,
};
PyTypeObject *NcInput_Type;
PyMODINIT_FUNC
PyInit_notcurses(void)
{
@ -79,25 +53,12 @@ PyInit_notcurses(void)
GNU_PY_MODULE_ADD_OBJECT(py_module, (PyObject *)&Notcurses_Type, "Notcurses");
GNU_PY_MODULE_ADD_OBJECT(py_module, (PyObject *)&NcPlane_Type, "NcPlane");
NcInput_Type = PyStructSequence_NewType(&NcInput_desc);
if (NcInput_Type == NULL)
return NULL;
GNU_PY_MODULE_ADD_OBJECT(py_module, (PyObject *)NcInput_Type, "NcInput");
// background cannot be highcontrast, only foreground
GNU_PY_CHECK_INT(PyModule_AddIntMacro(py_module, NCALPHA_HIGHCONTRAST));
GNU_PY_CHECK_INT(PyModule_AddIntMacro(py_module, NCALPHA_TRANSPARENT));
GNU_PY_CHECK_INT(PyModule_AddIntMacro(py_module, NCALPHA_BLEND));
GNU_PY_CHECK_INT(PyModule_AddIntMacro(py_module, NCALPHA_OPAQUE));
// FIXME: Better, attributes of an object such as an enum.
GNU_PY_CHECK_INT(PyModule_AddStringMacro(py_module, NCBOXASCII));
GNU_PY_CHECK_INT(PyModule_AddStringMacro(py_module, NCBOXDOUBLE));
GNU_PY_CHECK_INT(PyModule_AddStringMacro(py_module, NCBOXHEAVY));
GNU_PY_CHECK_INT(PyModule_AddStringMacro(py_module, NCBOXLIGHT));
GNU_PY_CHECK_INT(PyModule_AddStringMacro(py_module, NCBOXOUTER));
GNU_PY_CHECK_INT(PyModule_AddStringMacro(py_module, NCBOXROUND));
// if this bit is set, we are *not* using the default background color
GNU_PY_CHECK_INT(PyModule_AddIntMacro(py_module, NC_BGDEFAULT_MASK));
// extract these bits to get the background RGB value

@ -122,6 +122,12 @@ typedef struct
struct nccell nccell;
} NcCellObject;
typedef struct
{
PyObject_HEAD;
struct ncinput ncinput;
} NcInputObject;
typedef struct
{
PyObject_HEAD;
@ -134,8 +140,6 @@ typedef struct
struct ncpalette ncpalette;
} Palette256Object;
extern PyTypeObject *NcInput_Type;
// Imports
extern PyObject *traceback_format_exception;

@ -302,17 +302,6 @@ def ncchannels_set_bg_default(channels: int, /) -> int:
# endregion ncchannel
class NcInput:
id: int
y: int
x: int
utf8: str
evtype: int
modifiers: int
xpx: int
ypx: int
class Notcurses:
"""Notcurses context."""
@ -348,20 +337,20 @@ class Notcurses:
"""Return the bottommost ncplane of the standard pile."""
raise NotImplementedError('Stub')
def inputready_fd(self) -> int:
"""Get a file descriptor suitable for input event poll."""
def getc(self) -> str:
"""Get a single unicode codepoint of input."""
raise NotImplementedError('Stub')
def get(self, deadline: Optional[float]) -> NcInput:
"""Reads an input event. If no event is ready, returns None."""
def inputready_fd(self) -> int:
"""Get a file descriptor suitable for input event poll."""
raise NotImplementedError('Stub')
def get_nblock(self) -> NcInput:
def getc_nblock(self) -> str:
"""Get input event without blocking. If no event is ready,
returns None."""
raise NotImplementedError('Stub')
def get_blocking(self) -> NcInput:
def getc_blocking(self) -> str:
"""Get input event completely blocking until and event or signal
received."""
raise NotImplementedError('Stub')

@ -1088,7 +1088,7 @@ NcPlane_set_fg_rgb8(NcPlaneObject *self, PyObject *args)
{
unsigned r = 0, g = 0, b = 0;
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "III", &r, &g, &b));
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "kkk", &r, &g, &b));
CHECK_NOTCURSES(ncplane_set_fg_rgb8(self->ncplane_ptr, r, g, b));
@ -1100,7 +1100,7 @@ NcPlane_set_bg_rgb8(NcPlaneObject *self, PyObject *args)
{
unsigned r = 0, g = 0, b = 0;
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "III", &r, &g, &b));
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "kkk", &r, &g, &b));
CHECK_NOTCURSES(ncplane_set_bg_rgb8(self->ncplane_ptr, r, g, b));
@ -1174,8 +1174,8 @@ NcPlane_set_bg_default(NcPlaneObject *self, PyObject *Py_UNUSED(args))
static PyObject *
NcPlane_set_fg_palindex(NcPlaneObject *self, PyObject *args)
{
unsigned idx = 0;
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "I", &idx));
int idx = 0;
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "i", &idx));
ncplane_set_fg_palindex(self->ncplane_ptr, idx);
Py_RETURN_NONE;
@ -1184,8 +1184,8 @@ NcPlane_set_fg_palindex(NcPlaneObject *self, PyObject *args)
static PyObject *
NcPlane_set_bg_palindex(NcPlaneObject *self, PyObject *args)
{
unsigned idx = 0;
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "I", &idx));
int idx = 0;
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "i", &idx));
ncplane_set_bg_palindex(self->ncplane_ptr, idx);
Py_RETURN_NONE;
@ -1650,15 +1650,6 @@ NcPlane_pile_render_to_file(NcPlaneObject *self, PyObject *args)
Py_RETURN_NONE;
}
static PyObject *
NcPlane_scrollup(NcPlaneObject *self, PyObject *args)
{
int r;
GNU_PY_CHECK_BOOL(PyArg_ParseTuple(args, "i", &r));
CHECK_NOTCURSES(ncplane_scrollup(self->ncplane_ptr, r));
Py_RETURN_NONE;
}
/*
static PyObject *
NcPlane_(NcPlaneObject *self, PyObject *args)
@ -1684,7 +1675,7 @@ static PyMethodDef NcPlane_methods[] = {
{"translate", (void *)NcPlane_translate, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("provided a coordinate relative to the origin of 'src', map it to the same absolute coordinate relative to the origin of 'dst'.")},
{"translate_abs", (PyCFunction)NcPlane_translate_abs, METH_VARARGS, PyDoc_STR("Fed absolute 'y'/'x' coordinates, determine whether that coordinate is within the ncplane.")},
{"set_scrolling", (PyCFunction)NcPlane_set_scrolling, METH_VARARGS, PyDoc_STR("All planes are created with scrolling disabled. Returns true if scrolling was previously enabled, or false if it was disabled.")},
{"set_scrolling", (PyCFunction)NcPlane_set_scrolling, METH_NOARGS, PyDoc_STR("All planes are created with scrolling disabled. Returns true if scrolling was previously enabled, or false if it was disabled.")},
{"resize", (void *)NcPlane_resize, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Resize the specified ncplane.")},
{"resize_simple", (PyCFunction)NcPlane_resize_simple, METH_VARARGS, PyDoc_STR("Resize the plane, retaining what data we can (everything, unless we're shrinking in some dimension). Keep the origin where it is.")},
@ -1811,7 +1802,7 @@ static PyMethodDef NcPlane_methods[] = {
{"cells_load_box", (void *)NcPlane_cells_load_box, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Load up six cells with the EGCs necessary to draw a box.")},
{"cells_rounded_box", (void *)NcPlane_cells_rounded_box, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Load up six cells with the EGCs necessary to draw a round box.")},
{"perimeter_rounded", (void *)NcPlane_perimeter_rounded, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Draw a perimeter around plane.")},
{"perimeter_rounded", (void *)NcPlane_perimeter_rounded, METH_VARARGS, PyDoc_STR("Draw a perimeter around plane.")},
{"rounded_box_sized", (void *)NcPlane_rounded_box_sized, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Draw a round box around plane.")},
{"cells_double_box", (void *)NcPlane_cells_double_box, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Draw a double box with cells.")},
@ -1849,8 +1840,6 @@ static PyMethodDef NcPlane_methods[] = {
{"pile_render_to_buffer", (PyCFunction)NcPlane_pile_render_to_buffer, METH_NOARGS, "Perform the rendering and rasterization portion of notcurses_render() and write it to bytes object instead of terminal."},
{"render_to_file", (PyCFunction)NcPlane_pile_render_to_file, METH_VARARGS, "Write the last rendered frame, in its entirety, to file descriptor. If render() has not yet been called, nothing will be written."},
{"scrollup", (PyCFunction)NcPlane_scrollup, METH_VARARGS, "Effect scroll events on the plane."},
// {"", (PyCFunction) NULL, METH_VARARGS, PyDoc_STR("")},
{NULL, NULL, 0, NULL},
};

@ -38,7 +38,7 @@ if environ.get('LDFLAGS') is None:
setup(
name="notcurses",
version="3.0.9",
version="3.0.1",
packages=['notcurses'],
ext_modules=[
Extension(
@ -46,7 +46,6 @@ setup(
sources=[
'notcurses/channels.c',
'notcurses/context.c',
'notcurses/functions.c',
'notcurses/main.c',
'notcurses/misc.c',
'notcurses/plane.c',

@ -1,7 +1,7 @@
#include "compat/compat.h"
#include <builddef.h>
#include <pthread.h>
#ifdef __MINGW32__
#ifdef __MINGW64__
#include <string.h>
#include <stdlib.h>
#include <synchapi.h>
@ -178,7 +178,7 @@ int pthread_condmonotonic_init(pthread_cond_t* cond){
}
// FIXME we need a solution for this on macos/windows
#ifndef __APPLE__
#ifndef __MINGW32__
#ifndef __MINGW64__
if(pthread_condattr_setclock(&cat, CLOCK_MONOTONIC)){
pthread_condattr_destroy(&cat);
return -1;

@ -19,13 +19,13 @@ extern "C" {
#define TIMER_ABSTIME 1
#endif
#ifdef __MINGW32__
#ifdef __MINGW64__
static inline char
path_separator(void){
return '\\';
}
#define NL "\r\n"
#include <lmcons.h>
#include <Lmcons.h>
#include <winsock2.h>
#define tcgetattr(x, y) (0)
#define tcsetattr(x, y, z) (0)
@ -147,7 +147,7 @@ notcurses_data_path(const char* ddir, const char* f){
#ifdef __cplusplus
}
#else
#ifdef __MINGW32__
#ifdef __MINGW64__
char* strndup(const char* str, size_t size);
#endif
#endif

@ -131,7 +131,7 @@ determine_totalmoves(struct ncplane* std, struct ncplane* left, struct ncplane*
static int
spin_cycle(const char* utf8, int iters){
int offsets[10]; // no cycles longer than this
mbstate_t mbs = { 0 };
mbstate_t mbs = { };
int offset = 0;
size_t s;
int o = 0;
@ -268,7 +268,7 @@ make_pbars(struct ncplane* column, struct ncprogbar** left, struct ncprogbar** r
return -1;
}
ncplane_set_base(leftp, " ", 0, NCCHANNELS_INITIALIZER(0xdd, 0xdd, 0xdd, 0x1b, 0x1b, 0x1b));
ncprogbar_options popts = { 0 };
ncprogbar_options popts = { };
ncchannel_set_rgb8(&popts.brchannel, 0, 0, 0);
ncchannel_set_rgb8(&popts.blchannel, 0, 0xff, 0);
ncchannel_set_rgb8(&popts.urchannel, 0, 0, 0xff);

@ -131,10 +131,6 @@ get_ships(struct notcurses* nc, struct ship* ships, unsigned shipcount){
}
unsigned cdimy, cdimx;
ncplane_pixel_geom(notcurses_stdplane(nc), NULL, NULL, &cdimy, &cdimx, NULL, NULL);
if(cdimy == 0 || cdimx == 0){
ncvisual_destroy(wmv);
return 0;
}
if(ncvisual_resize(wmv, cdimy * SHIPHEIGHT, cdimx * SHIPWIDTH)){
ncvisual_destroy(wmv);
return -1;
@ -144,7 +140,7 @@ get_ships(struct notcurses* nc, struct ship* ships, unsigned shipcount){
.y = 30,//rand() % (ncplane_dim_y(notcurses_stdplane_const(nc)) - SHIPHEIGHT),
.x = 30,//rand() % (ncplane_dim_x(notcurses_stdplane_const(nc)) - SHIPWIDTH),
.blitter = NCBLIT_PIXEL,
.flags = NCVISUAL_OPTION_CHILDPLANE,
.flags = NCVISUAL_OPTION_NODEGRADE | NCVISUAL_OPTION_CHILDPLANE,
};
for(unsigned s = 0 ; s < shipcount ; ++s){
if((ships[s].n = ncvisual_blit(nc, wmv, &vopts)) == NULL){
@ -223,7 +219,7 @@ int box_demo(struct notcurses* nc, uint64_t startns){
int y = 1, x = 0;
ncplane_dim_yx(n, &ylen, &xlen);
--ylen;
while((int)ylen - y >= targy && (int)xlen - x >= targx){
while(ylen - y >= targy && xlen - x >= targx){
if(ncplane_cursor_move_yx(n, y, x)){
return -1;
}
@ -240,8 +236,9 @@ int box_demo(struct notcurses* nc, uint64_t startns){
int iters = 100;
struct timespec iterdelay;
ns_to_timespec(timespec_to_ns(&demodelay) * 3 / iters, &iterdelay);
struct ship ships[3] = {0};
if(notcurses_canopen_images(nc)){
int bitmaps = notcurses_canopen_images(nc) && notcurses_check_pixel_support(nc);
struct ship ships[3] = {};
if(bitmaps > 0){
if(get_ships(nc, ships, sizeof(ships) / sizeof(*ships))){
return -1;
}
@ -255,7 +252,7 @@ int box_demo(struct notcurses* nc, uint64_t startns){
ncplane_dim_yx(n, &ylen, &xlen);
--ylen;
move_ships(nc, ships, sizeof(ships) / sizeof(*ships));
while((int)ylen - y >= targy && (int)xlen - x >= targx){
while(ylen - y >= targy && xlen - x >= targx){
if(ncplane_cursor_move_yx(n, y, x)){
return -1;
}

@ -10,17 +10,18 @@
#include <stdlib.h>
#include <inttypes.h>
#include <stdatomic.h>
#include <notcurses/direct.h>
#include "demo.h"
// (non-)ansi terminal definition-4-life
static const unsigned MIN_SUPPORTED_ROWS = 24;
static const unsigned MIN_SUPPORTED_COLS = 76; // allow a bit of margin, sigh
static const int MIN_SUPPORTED_ROWS = 24;
static const int MIN_SUPPORTED_COLS = 76; // allow a bit of margin, sigh
static char *datadir;
static int democount;
static demoresult* results;
static const char DEFAULT_DEMO[] = "ixetunchdmbkywjgarvlsfqzo";
static const char DEFAULT_DEMO[] = "ixetunchmdbkywjgarvlsfqzo";
atomic_bool interrupted = ATOMIC_VAR_INIT(false);
// checked following demos, whether aborted, failed, or otherwise
@ -100,48 +101,40 @@ static struct {
};
static void
usage_option(struct ncplane* n, const char* op){
ncplane_set_fg_rgb8(n, 0x80, 0x80, 0x80);
ncplane_printf(n, " [ ");
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0x80);
ncplane_printf(n, "%s", op);
ncplane_set_fg_rgb8(n, 0x80, 0x80, 0x80);
ncplane_printf(n, " ] ");
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0xff);
usage_option(FILE* out, struct ncdirect* n, const char* op){
if(n) ncdirect_set_fg_rgb8(n, 0x80, 0x80, 0x80);
fprintf(out, " [ ");
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0x80);
fprintf(out, "%s", op);
if(n) ncdirect_set_fg_rgb8(n, 0x80, 0x80, 0x80);
fprintf(out, " ] ");
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0xff);
}
static void
usage_expo(struct ncplane* n, const char* op, const char* expo){
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0x80);
ncplane_printf(n, " %s: ", op);
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0xff);
ncplane_printf(n, "%s\n", expo);
usage_expo(FILE* out, struct ncdirect* n, const char* op, const char* expo){
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0x80);
fprintf(out, " %s: ", op);
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0xff);
fprintf(out, "%s\n", expo);
}
static void
usage(const char* exe, int status){
FILE* out = status == EXIT_SUCCESS ? stdout : stderr;
struct notcurses_options opts = {0};
opts.flags = NCOPTION_CLI_MODE
| NCOPTION_DRAIN_INPUT
| NCOPTION_SUPPRESS_BANNERS;
struct notcurses* nc = notcurses_init(&opts, out);
if(!nc){
exit(status);
}
struct ncplane* n = notcurses_stdplane(nc);
ncplane_set_fg_rgb8(n, 0x00, 0xc0, 0xc0);
ncplane_putstr(n, "usage: ");
ncplane_set_fg_rgb8(n, 0x80, 0xff, 0x80);
ncplane_printf(n, "%s ", exe);
struct ncdirect* n = ncdirect_init(NULL, out, 0);
if(n) ncdirect_set_fg_rgb8(n, 0x00, 0xc0, 0xc0);
fprintf(out, "usage: ");
if(n) ncdirect_set_fg_rgb8(n, 0x80, 0xff, 0x80);
fprintf(out, "%s ", exe);
const char* options[] = { "-hVkc", "-m margins", "-p path", "-l loglevel",
"-d mult", "-J jsonfile", "demospec",
NULL };
for(const char** op = options ; *op ; ++op){
usage_option(n, *op);
usage_option(out, n, *op);
}
ncplane_putstr(n, "\n\n");
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0xff);
fprintf(out, "\n\n");
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0xff);
const char* optexpo[] = {
"-h|--help", "this message",
"-V|--version", "print program name and version",
@ -154,41 +147,40 @@ usage(const char* exe, int status){
};
for(const char** op = optexpo ; *op ; op += 2){
const char* expo = op[1];
usage_expo(n, *op, expo);
usage_expo(out, n, *op, expo);
}
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0x80);
ncplane_printf(n, " -l:");
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0xff);
ncplane_printf(n, " logging level (%d: silent..%d: manic)\n", NCLOGLEVEL_SILENT, NCLOGLEVEL_TRACE);
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0x80);
ncplane_printf(n, " -p:");
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0xff);
ncplane_printf(n, " data file path (default: %s)\n", notcurses_data_dir());
ncplane_printf(n, "\nspecify demos via their first letter. repetitions are allowed.\n");
ncplane_set_fg_rgb8(n, 0x80, 0xff, 0x80);
ncplane_printf(n, " default spec: %s\n\n", DEFAULT_DEMO);
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0xff);
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0x80);
fprintf(out, " -l:");
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0xff);
fprintf(out, " logging level (%d: silent..%d: manic)\n", NCLOGLEVEL_SILENT, NCLOGLEVEL_TRACE);
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0x80);
fprintf(out, " -p:");
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0xff);
fprintf(out, " data file path (default: %s)\n", NOTCURSES_SHARE);
fprintf(out, "\nspecify demos via their first letter. repetitions are allowed.\n");
if(n) ncdirect_set_fg_rgb8(n, 0x80, 0xff, 0x80);
fprintf(out, " default spec: %s\n\n", DEFAULT_DEMO);
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0xff);
int printed = 0;
for(size_t i = 0 ; i < sizeof(demos) / sizeof(*demos) ; ++i){
if(demos[i].name){
if(printed % 5 == 0){
ncplane_printf(n, " ");
fprintf(out, " ");
}
// U+24D0: CIRCLED LATIN SMALL LETTER A
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0x80);
ncplane_printf(n, "%lc ", (wint_t)(*demos[i].name - 'a' + 0x24d0));
ncplane_set_fg_rgb8(n, 0xff, 0xff, 0xff);
ncplane_printf(n, "%-*.*s", 8, 8, demos[i].name + 1);
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0x80);
fprintf(out, "%lc ", *demos[i].name - 'a' + 0x24d0);
if(n) ncdirect_set_fg_rgb8(n, 0xff, 0xff, 0xff);
fprintf(out, "%-*.*s", 8, 8, demos[i].name + 1);
if(++printed % 5 == 0){
ncplane_printf(n, "\n");
fprintf(out, "\n");
}
}
}
if(printed % 5){
ncplane_printf(n, "\n");
fprintf(out, "\n");
}
notcurses_render(nc);
notcurses_stop(nc);
ncdirect_stop(n);
exit(status);
}
@ -297,7 +289,7 @@ handle_opts(int argc, char** argv, notcurses_options* opts, FILE** json_output){
opts->flags |= NCOPTION_NO_ALTERNATE_SCREEN;
break;
case 'p':
datadir = strdup(optarg);
datadir = optarg;
break;
case 'd':{
float f;
@ -325,9 +317,6 @@ handle_opts(int argc, char** argv, notcurses_options* opts, FILE** json_output){
fprintf(stderr, "Extra argument: %s\n", argv[optind + 1]);
usage(*argv, EXIT_FAILURE);
}
if(datadir == NULL){
datadir = notcurses_data_dir();
}
const char* spec = argv[optind];
return spec;
}
@ -511,7 +500,7 @@ scrub_stdplane(struct notcurses* nc){
}
int main(int argc, char** argv){
#ifndef __MINGW32__
#ifndef __MINGW64__
sigset_t sigmask;
// ensure SIGWINCH is delivered only to a thread doing input
sigemptyset(&sigmask);
@ -520,7 +509,7 @@ int main(int argc, char** argv){
#endif
const char* spec;
FILE* json = NULL; // emit JSON summary to this file? (-J)
notcurses_options nopts = {0};
notcurses_options nopts = {};
if((spec = handle_opts(argc, argv, &nopts, &json)) == NULL){
if(argv[optind] != NULL){
usage(*argv, EXIT_FAILURE);
@ -603,7 +592,6 @@ int main(int argc, char** argv){
if(json && summary_json(json, spec, dimy, dimx)){
return EXIT_FAILURE;
}
free(datadir);
return r ? EXIT_FAILURE : EXIT_SUCCESS;
err:

@ -101,16 +101,13 @@ int dragon_demo(struct notcurses* nc, uint64_t startns){
.n = n,
.y = 1,
.scaling = NCSCALE_STRETCH,
.flags = NCVISUAL_OPTION_CHILDPLANE,
};
struct ncplane* dn = ncvisual_blit(nc, ncv, &vopts);
if(dn == NULL){
if(ncvisual_blit(nc, ncv, &vopts) == NULL){
ncvisual_destroy(ncv);
return -1;
}
DEMO_RENDER(nc);
demo_nanosleep(nc, &scaled);
ncplane_destroy(dn);
}while(lasttotal != r);
ncvisual_destroy(ncv);
return 0;

@ -13,7 +13,7 @@ drop_bricks(struct notcurses* nc, struct ncplane** arr, int arrcount){
// 5 * demodelay total
ns_to_timespec(timespec_to_ns(&demodelay) / arrcount / 2, &iterdelay);
// we've got a range of up to 10% total blocks falling at any given time. they
// accelerate as they fall. [ranges, range) covers the active range.
// accelerate as they fall. [ranges, reange) covers the active range.
int ranges = 0;
int rangee = 0;
const int FALLINGMAX = arrcount < 10 ? 1 : arrcount / 10;
@ -33,11 +33,7 @@ drop_bricks(struct notcurses* nc, struct ncplane** arr, int arrcount){
}
}
do{
int e = demo_render(nc);
if(e){
free(speeds);
return e;
}
DEMO_RENDER(nc);
// don't allow gaps in the active range. so long as felloff is true, we've only handled
// planes which have fallen off the screen, and can be collected.
bool felloff = true;

@ -249,43 +249,43 @@ bool menu_or_hud_key(struct notcurses *nc, const struct ncinput *ni){
memcpy(&tmpni, ni, sizeof(tmpni));
}
}else{
if(ni->evtype == NCTYPE_RELEASE){
return false;
}
memcpy(&tmpni, ni, sizeof(tmpni));
}
if(tmpni.evtype == NCTYPE_RELEASE){
return false;
}
// toggle the HUD
if(tmpni.id == 'H' && !ncinput_alt_p(&tmpni) && !ncinput_ctrl_p(&tmpni)){
if(tmpni.id == 'H' && !tmpni.alt && !tmpni.ctrl){
hud_toggle(nc);
return true;
}
if(tmpni.id == 'P' && !ncinput_alt_p(&tmpni) && !ncinput_ctrl_p(&tmpni)){
if(tmpni.id == 'P' && !tmpni.alt && !tmpni.ctrl){
fpsplot_toggle(nc);
return true;
}
if(tmpni.id == 'U' && !ncinput_alt_p(&tmpni) && ncinput_ctrl_p(&tmpni)){
if(tmpni.id == 'U' && !tmpni.alt && tmpni.ctrl){
about_toggle(nc);
return true;
}
if(tmpni.id == 'd' && ncinput_alt_p(&tmpni)){
if(tmpni.id == 'd' && tmpni.alt && !tmpni.ctrl){
debug_toggle(nc);
return true;
}
if(tmpni.id == 'L' && !ncinput_alt_p(&tmpni) && ncinput_ctrl_p(&tmpni)){
if(tmpni.id == 'L' && !tmpni.alt && tmpni.ctrl){
if(menu){
ncmenu_rollup(menu);
}
notcurses_refresh(nc, NULL, NULL);
return true;
}
if(tmpni.id == 'R' && !ncinput_alt_p(&tmpni) && ncinput_ctrl_p(&tmpni)){
if(tmpni.id == 'R' && !tmpni.alt && tmpni.ctrl){
if(menu){
ncmenu_rollup(menu);
}
interrupt_and_restart_demos();
return true;
}
if(tmpni.id == 'q' && !ncinput_alt_p(&tmpni)){
if(tmpni.id == 'q' && !tmpni.alt && !tmpni.ctrl){
if(menu){
ncmenu_rollup(menu);
}
@ -305,23 +305,23 @@ struct ncmenu* menu_create(struct notcurses* nc){
struct ncmenu_item demo_items[] = {
{ .desc = MENUSTR_TOGGLE_HUD, .shortcut = { .id = 'H', }, },
{ .desc = MENUSTR_TOGGLE_PLOT, .shortcut = { .id = 'P', }, },
{ .desc = MENUSTR_REDRAW_SCREEN, .shortcut = { .id = 'L', .modifiers = NCKEY_MOD_CTRL }, },
{ .desc = MENUSTR_REDRAW_SCREEN, .shortcut = { .id = 'L', .ctrl = true }, },
{ .desc = NULL, },
{ .desc = MENUSTR_RESTART, .shortcut = { .id = 'R', .modifiers = NCKEY_MOD_CTRL, }, },
{ .desc = MENUSTR_RESTART, .shortcut = { .id = 'R', .ctrl = true, }, },
{ .desc = MENUSTR_QUIT, .shortcut = { .id = 'q', }, },
};
struct ncmenu_item help_items[] = {
{ .desc = MENUSTR_ABOUT, .shortcut = { .id = 'U', .modifiers = NCKEY_MOD_CTRL, }, },
{ .desc = MENUSTR_DEBUG, .shortcut = { .id = 'd', .modifiers = NCKEY_MOD_ALT, }, },
{ .desc = MENUSTR_ABOUT, .shortcut = { .id = 'U', .ctrl = true, }, },
{ .desc = MENUSTR_DEBUG, .shortcut = { .id = 'd', .alt = true, }, },
};
struct ncmenu_section sections[] = {
{ .name = "notcurses-demo", .items = demo_items,
.itemcount = sizeof(demo_items) / sizeof(*demo_items),
.shortcut = { .id = 'o', .modifiers = NCKEY_MOD_ALT, }, },
.shortcut = { .id = 'o', .alt = true, }, },
{ .name = NULL, .items = NULL, .itemcount = 0, },
{ .name = "help", .items = help_items,
.itemcount = sizeof(help_items) / sizeof(*help_items),
.shortcut = { .id = 'h', .modifiers = NCKEY_MOD_ALT, }, },
.shortcut = { .id = 'h', .alt = true, }, },
};
uint64_t headerchannels = 0;
uint64_t sectionchannels = 0;

@ -125,9 +125,6 @@ ultramegaok_demo(void* vnc){
if(id == 0){
continue;
}
if(id == NCKEY_EOF){
break;
}
// go ahead and pass keyboard through to demo, even if it was a 'q' (this
// might cause the demo to exit immediately, as is desired). we can't just
// mess with the menu/HUD in our own context, as the demo thread(s) might
@ -154,7 +151,7 @@ int input_dispatcher(struct notcurses* nc){
}
// freebsd doesn't have eventfd :/ and apple doesn't even have pipe2() =[ =[
// omg windows doesn't have pipe() fml FIXME
#ifndef __MINGW32__
#ifndef __MINGW64__
#if defined(__APPLE__)
if(pipe(input_pipefds)){
#else

@ -3611,7 +3611,7 @@ unicode14(struct ncplane* title, int y){
struct ncplane*
makegroup(struct ncplane* title, int y, const char* emoji, const char* name){
mbstate_t mbs = {0};
mbstate_t mbs = {};
size_t count = mbsrtowcs(NULL, &emoji, 0, &mbs);
if(count == (size_t)-1){
fprintf(stderr, "couldn't convert %s\n", emoji);

@ -234,26 +234,11 @@ ncreel_demo_core(struct notcurses* nc, uint64_t startns){
}
// Press a for a new nc above the current, c for a new one below the
// current, and b for a new block at arbitrary placement.
struct ncplane_options legendops = {
.rows = 4,
.cols = dimx - 2,
.x = 0,
.y = 0,
};
struct ncplane* lplane = ncplane_create(std, &legendops);
if(lplane == NULL){
ncreel_destroy(nr);
return -1;
}
ncplane_on_styles(lplane, NCSTYLE_BOLD | NCSTYLE_ITALIC);
ncplane_set_fg_rgb8(lplane, 58, 150, 221);
uint64_t channels = 0;
ncchannels_set_fg_alpha(&channels, NCALPHA_TRANSPARENT);
ncchannels_set_bg_alpha(&channels, NCALPHA_TRANSPARENT);
ncplane_set_base(lplane, "", 0, channels);
ncplane_set_bg_default(lplane);
ncplane_printf_yx(lplane, 1, 2, "a, b, c create tablets, DEL deletes.");
ncplane_off_styles(lplane, NCSTYLE_BOLD | NCSTYLE_ITALIC);
ncplane_on_styles(std, NCSTYLE_BOLD | NCSTYLE_ITALIC);
ncplane_set_fg_rgb8(std, 58, 150, 221);
ncplane_set_bg_default(std);
ncplane_printf_yx(std, 1, 2, "a, b, c create tablets, DEL deletes.");
ncplane_off_styles(std, NCSTYLE_BOLD | NCSTYLE_ITALIC);
struct timespec deadline;
ns_to_timespec((timespec_to_ns(&demodelay) * 5) + startns, &deadline);
unsigned id = 0;
@ -263,20 +248,20 @@ ncreel_demo_core(struct notcurses* nc, uint64_t startns){
newtablet = new_tabletctx(nr, &id);
if(newtablet == NULL){
ncreel_destroy(nr);
ncplane_destroy(lplane);
return -1;
}
newtablet->next = tctxs;
tctxs = newtablet;
}
do{
ncplane_set_styles(lplane, NCSTYLE_NONE);
ncplane_set_fg_rgb8(lplane, 197, 15, 31);
ncplane_set_styles(std, NCSTYLE_NONE);
ncplane_set_fg_rgb8(std, 197, 15, 31);
int count = ncreel_tabletcount(nr);
ncplane_on_styles(lplane, NCSTYLE_BOLD);
ncplane_printf_yx(lplane, 2, 2, "%d tablet%s", count, count == 1 ? "" : "s");
ncplane_off_styles(lplane, NCSTYLE_BOLD);
ncplane_set_fg_rgb8(lplane, 0, 55, 218);
ncplane_on_styles(std, NCSTYLE_BOLD);
ncplane_printf_yx(std, 2, 2, "%d tablet%s", count, count == 1 ? "" : "s");
ncplane_off_styles(std, NCSTYLE_BOLD);
// FIXME wclrtoeol(w);
ncplane_set_fg_rgb8(std, 0, 55, 218);
uint32_t rw;
ncinput ni;
pthread_mutex_lock(&renderlock);
@ -289,7 +274,6 @@ ncreel_demo_core(struct notcurses* nc, uint64_t startns){
kill_tablet(&tctxs);
}
ncreel_destroy(nr);
ncplane_destroy(lplane);
return renderret;
}
if((rw = handle_input(nc, &deadline, &ni)) == (uint32_t)-1){
@ -316,7 +300,7 @@ ncreel_demo_core(struct notcurses* nc, uint64_t startns){
break;
case NCKEY_DEL: kill_active_tablet(nr, &tctxs); break;
case NCKEY_RESIZE: notcurses_render(nc); break;
default: ncplane_printf_yx(lplane, 3, 2, "Unknown keycode (0x%lx)\n", (unsigned long)rw); break;
default: ncplane_printf_yx(std, 3, 2, "Unknown keycode (0x%lx)\n", (unsigned long)rw); break;
}
if(newtablet){
newtablet->next = tctxs;
@ -333,7 +317,6 @@ ncreel_demo_core(struct notcurses* nc, uint64_t startns){
kill_tablet(&tctxs);
}
ncreel_destroy(nr);
ncplane_destroy(lplane);
return aborted ? 1 : 0;
}

@ -4,20 +4,6 @@ static struct marshal {
struct ncvisual_options pipopts;
} marsh;
#define PIPCOLUMNS 18
static int
pip_resize_cb(struct ncplane* n){
int absx = ncplane_abs_x(n);
int width = ncplane_dim_x(n);
int pwidth = ncplane_dim_x(ncplane_parent(n));
int pabsx = ncplane_abs_x(ncplane_parent(n));
if(absx + width == pabsx + pwidth){
return 0;
}
return ncplane_move_yx(n, 1, pabsx + pwidth - width);
}
// pip is non-NULL iff we can do pixel rendering
static inline int
streamer(struct ncvisual* ncv, struct ncvisual_options* vopts,
@ -28,10 +14,9 @@ streamer(struct ncvisual* ncv, struct ncvisual_options* vopts,
.y = 1,
.x = NCALIGN_RIGHT,
.rows = 12,
.cols = PIPCOLUMNS,
.cols = 18,
.flags = NCPLANE_OPTION_HORALIGNED,
.name = "pip",
.resizecb = pip_resize_cb,
};
marsh.pipopts.n = ncplane_create(vopts->n, &nopts);
if(marsh.pipopts.n == NULL){

@ -14,7 +14,7 @@
#include <langinfo.h>
#include <sys/utsname.h>
#include <sys/sysinfo.h>
#elif !defined(__MINGW32__)
#elif !defined(__MINGW64__)
#include <langinfo.h>
#include <sys/sysctl.h>
#include <sys/utsname.h>
@ -83,7 +83,7 @@ static int
fetch_env_vars(struct notcurses* nc, fetched_info* fi){
#if defined(__APPLE__)
fi->desktop = "Aqua";
#elif defined(__MINGW32__)
#elif defined(__MINGW64__)
fi->desktop = "Metro";
#else
fi->desktop = getenv("XDG_CURRENT_DESKTOP");
@ -118,7 +118,7 @@ fallback_cpuinfo(void){
static int
fetch_bsd_cpuinfo(fetched_info* fi){
#if defined(__linux__) || defined(__gnu_hurd__) || defined(__MINGW32__)
#if defined(__linux__) || defined(__gnu_hurd__) || defined(__MINGW64__)
(void)fi;
#else
size_t len = sizeof(fi->core_count);
@ -140,8 +140,8 @@ fetch_bsd_cpuinfo(fetched_info* fi){
static int
fetch_windows_cpuinfo(fetched_info* fi){
#ifdef __MINGW32__
SYSTEM_INFO info = {0};
#ifdef __MINGW64__
SYSTEM_INFO info = {};
GetSystemInfo(&info);
switch(info.wProcessorArchitecture){
case PROCESSOR_ARCHITECTURE_AMD64:
@ -257,10 +257,6 @@ linux_ncneofetch(fetched_info* fi){
.name = "fedora",
// from redhat-lsb-core package
.logofile = "/usr/share/pixmaps/fedora-logo.png",
}, {
.name = "ubuntu",
// package source? FIXME
.logofile = "/usr/share/unity/icons/launcher_bfb.png",
}, {
.name = NULL,
.logofile = NULL,
@ -337,7 +333,7 @@ typedef enum {
static ncneo_kernel_e
get_kernel(fetched_info* fi){
#ifndef __MINGW32__
#ifndef __MINGW64__
struct utsname uts;
if(uname(&uts)){
fprintf(stderr, "Failure invoking uname (%s)\n", strerror(errno));
@ -703,7 +699,7 @@ neologo_present(struct notcurses* nc, const char* nlogo){
ncplane_set_fg_default(n);
ncplane_set_styles(n, NCSTYLE_BOLD | NCSTYLE_ITALIC);
if(notcurses_canopen_images(nc)){
ncplane_putstr_aligned(n, -1, NCALIGN_CENTER, "(no bitmap is known for your distro)\n");
ncplane_putstr_aligned(n, -1, NCALIGN_CENTER, "(no image file is known for your distro)\n");
}else{
ncplane_putstr_aligned(n, -1, NCALIGN_CENTER, "(notcurses was compiled without image support)\n");
}
@ -762,15 +758,12 @@ display_thread(void* vmarshal){
return NULL;
}
}
unsigned nl;
ncplane_cursor_yx(notcurses_stdplane(m->nc), &nl, NULL);
m->nextline = nl;
return NULL;
}
static int
ncneofetch(struct notcurses* nc){
fetched_info fi = {0};
fetched_info fi = {};
ncneo_kernel_e kern = get_kernel(&fi);
switch(kern){
case NCNEO_LINUX:

@ -949,7 +949,6 @@ const struct neofetch_art ncarts[] = {
{ "openEuler", openEuler },
{ "GNOME", GNOME },
{ "SmartOS", SmartOS },
{ "ubuntu", ubuntu_old },
{ NULL, NULL }
};

@ -64,7 +64,7 @@ wvizn(struct ncplane* n, const wchar_t* wp, int nnn){
}
static int
braille_viz(struct ncplane* n, wint_t l, const wchar_t* egcs, wchar_t r,
braille_viz(struct ncplane* n, wchar_t l, const wchar_t* egcs, wchar_t r,
const char* indent, const wchar_t* bounds, wchar_t r8, wchar_t l8,
const wchar_t* trailer){
ncplane_printf(n, "%s%lc", indent, l);
@ -139,7 +139,7 @@ emoji_viz(struct ncplane* n){
"\U0001f3f4\u200d\u2620\ufe0f" // pirate flag
"\U0001f93d\U0001f3fc\u200d\u2640\ufe0f" // type-3 woman playing water polo
;
ncplane_set_bg_default(n);
ncplane_set_bg_rgb(n, 0);
size_t bytes;
for(const char* e = emoji ; *e ; e += bytes){
if(ncplane_putegc(n, e, &bytes) < 0){
@ -270,7 +270,7 @@ vertviz(struct ncplane* n, wchar_t l, wchar_t li, wchar_t ri, wchar_t r,
}
static int
unicodedumper(struct notcurses* nc, struct ncplane* n, const char* indent){
unicodedumper(struct ncplane* n, const char* indent){
if(notcurses_canutf8(ncplane_notcurses_const(n))){
// all NCHALFBLOCKS are contained within NCQUADBLOCKS
ncplane_printf(n, "%s%ls⎧", indent, NCQUADBLOCKS);
@ -324,23 +324,13 @@ unicodedumper(struct notcurses* nc, struct ncplane* n, const char* indent){
emoji_viz(n);
unsigned y, x;
ncplane_cursor_yx(n, &y, &x);
ncpalette* npal = ncpalette_new(nc);
unsigned r, g, b;
// if we weren't able to detect the palette, we'll just have a black
// background throughout the unicode section. otherwise, our gradient
// will be based off the existing palette.
ncpalette_get_rgb8(npal, 4, &r, &g, &b);
uint64_t ur = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, r, g, b);
ncpalette_get_rgb8(npal, 5, &r, &g, &b);
uint64_t lr = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, r, g, b);
ncpalette_get_rgb8(npal, 6, &r, &g, &b);
uint64_t ul = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, r, g, b);
ncpalette_get_rgb8(npal, 7, &r, &g, &b);
uint64_t ll = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, r, g, b);
ncpalette_free(npal);
ncplane_stain(n, y - 16, 0, 15, 80, ul, ur, ll, lr);
uint64_t ur = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x1B, 0xd8, 0x8E);
uint64_t lr = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0xdB, 0x18, 0x8E);
uint64_t ul = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x19, 0x19, 0x70);
uint64_t ll = NCCHANNELS_INITIALIZER(0xff, 0xff, 0xff, 0x19, 0x19, 0x70);
ncplane_stain(n, y - 16, 0, 16, 80, ul, ur, ll, lr);
ncplane_set_styles(n, NCSTYLE_BOLD | NCSTYLE_ITALIC);
ncplane_cursor_move_yx(n, y - 12, 55);
ncplane_cursor_move_yx(n, y - 12, 54);
wviz(n, L"🯁🯂🯃https://notcurses.com");
ncplane_set_styles(n, NCSTYLE_NONE);
}
@ -364,7 +354,7 @@ display_logo(struct ncplane* n, const char* path){
struct ncvisual_options vopts = {
.n = n,
.y = y - 3,
.x = 55,
.x = 54,
.blitter = NCBLIT_PIXEL,
.flags = NCVISUAL_OPTION_CHILDPLANE | NCVISUAL_OPTION_NODEGRADE,
};
@ -393,7 +383,6 @@ tinfo_debug_bitmaps(struct ncplane* n, const tinfo* ti, const char* indent){
}else{
ncplane_printf(n, "default bg 0x%06x", bg);
}
tinfo_debug_cap(n, " pmouse", ti->pixelmice);
finish_line(n);
ncpixelimpl_e blit = notcurses_check_pixel_support(ncplane_notcurses(n));
switch(blit){
@ -433,6 +422,7 @@ tinfo_debug_caps(struct ncplane* n, const tinfo* ti, const char* indent){
tinfo_debug_cap(n, "af", get_escape(ti, ESCAPE_SETAF));
tinfo_debug_cap(n, "ab", get_escape(ti, ESCAPE_SETAB));
tinfo_debug_cap(n, "sum", get_escape(ti, ESCAPE_BSUM));
tinfo_debug_cap(n, "cup", get_escape(ti, ESCAPE_CUP));
tinfo_debug_cap(n, "vpa", get_escape(ti, ESCAPE_VPA));
tinfo_debug_cap(n, "hpa", get_escape(ti, ESCAPE_HPA));
tinfo_debug_cap(n, "sgr0", get_escape(ti, ESCAPE_SGR0));
@ -440,7 +430,6 @@ tinfo_debug_caps(struct ncplane* n, const tinfo* ti, const char* indent){
tinfo_debug_cap(n, "fgop", get_escape(ti, ESCAPE_FGOP));
tinfo_debug_cap(n, "bgop", get_escape(ti, ESCAPE_BGOP));
tinfo_debug_cap(n, "bce", ti->bce);
tinfo_debug_cap(n, "rect", get_escape(ti, ESCAPE_DECERA));
finish_line(n);
}
@ -513,18 +502,14 @@ int main(int argc, const char** argv){
notcurses_stop(nc);
return EXIT_FAILURE;
}
ncplane_set_fg_alpha(stdn, NCALPHA_HIGHCONTRAST);
ncplane_set_fg_rgb(stdn, 0xffffff);
ncplane_set_scrolling(stdn, true);
tinfo_debug_caps(stdn, &nc->tcache, indent);
tinfo_debug_styles(nc, stdn, indent);
tinfo_debug_bitmaps(stdn, &nc->tcache, indent);
unicodedumper(nc, stdn, indent);
char* path = notcurses_data_path(NULL, "notcurses.png");
unicodedumper(stdn, indent);
char* path = prefix_data("notcurses.png");
if(path){
if(notcurses_canpixel(nc)){
display_logo(stdn, path); // let it fail
}
display_logo(stdn, path); // let it fail
free(path);
}
if(notcurses_render(nc)){

@ -7,7 +7,6 @@
#include <cstring>
#include <cstdlib>
#include <clocale>
#include <getopt.h>
#include <iostream>
#include <ncpp/Plane.hh>
#include <ncpp/NotCurses.hh>
@ -126,7 +125,7 @@ const char* nckeystr(char32_t spkey){
case NCKEY_EXIT: return "exit";
case NCKEY_PRINT: return "print";
case NCKEY_REFRESH: return "refresh";
case NCKEY_SEPARATOR: return "separator";
case NCKEY_SEPARATOR: return "seperator";
case NCKEY_CAPS_LOCK: return "caps lock";
case NCKEY_SCROLL_LOCK: return "scroll lock";
case NCKEY_NUM_LOCK: return "num lock";
@ -311,13 +310,13 @@ int input_demo(ncpp::NotCurses* nc) {
if(r == 0){ // interrupted by signal
continue;
}
if((r == 'D' && ncinput_ctrl_p(&ni)) || r == NCKEY_EOF){
if(((r == 'D' || r == 'd') && ni.ctrl) || r == NCKEY_EOF){
done = true;
tid.join();
ncuplot_destroy(plot);
return 0;
}
if(r == 'L' && ncinput_ctrl_p(&ni)){
if((r == 'L' || r == 'l') && ni.ctrl){
mtx.lock();
if(!nc->refresh(nullptr, nullptr)){
mtx.unlock();
@ -329,16 +328,8 @@ int input_demo(ncpp::NotCurses* nc) {
break;
}
n->set_fg_rgb8(0xd0, 0xd0, 0xd0);
n->printf("%c%c%c%c%c%c%c%c%c ",
ncinput_shift_p(&ni) ? 'S' : 's',
ncinput_alt_p(&ni) ? 'A' : 'a',
ncinput_ctrl_p(&ni) ? 'C' : 'c',
ncinput_super_p(&ni) ? 'U' : 'u',
ncinput_hyper_p(&ni) ? 'H' : 'h',
ncinput_meta_p(&ni) ? 'M' : 'm',
ncinput_capslock_p(&ni) ? 'X' : 'x',
ncinput_numlock_p(&ni) ? '#' : '.',
evtype_to_char(&ni));
n->printf("%c%c%c%c ", ni.alt ? 'A' : 'a', ni.ctrl ? 'C' : 'c',
ni.shift ? 'S' : 's', evtype_to_char(&ni));
if(r < 0x80){
n->set_fg_rgb8(128, 250, 64);
if(n->printf("ASCII: [0x%02x (%03d)] '%lc'", r, r,
@ -352,7 +343,7 @@ int input_demo(ncpp::NotCurses* nc) {
break;
}
if(NCKey::IsMouse(r)){
if(n->printf(-1, NCAlign::Right, " %d/%d", ni.x, ni.y) < 0){
if(n->printf(-1, NCAlign::Right, " x: %d y: %d", ni.x, ni.y) < 0){
break;
}
}
@ -361,16 +352,6 @@ int input_demo(ncpp::NotCurses* nc) {
n->printf("Unicode: [0x%08x] '%s'", r, ni.utf8);
}
}
if(ni.eff_text[0] != ni.id || ni.eff_text[1] != 0){
n->printf(" effective text '");
for (int c=0; ni.eff_text[c]!=0; c++){
unsigned char egc[5]={0};
if(notcurses_ucs32_to_utf8(&ni.eff_text[c], 1, egc, 4)>=0){
n->printf("%s", egc);
}
}
n->printf("'");
}
unsigned x;
n->get_cursor_yx(nullptr, &x);
for(unsigned i = x ; i < n->get_dim_x() ; ++i){
@ -411,7 +392,7 @@ int input_demo(ncpp::NotCurses* nc) {
static void
usage(const char* arg0, FILE* fp){
fprintf(fp, "usage: %s [ -v ] [ -m ]\n", arg0);
fprintf(fp, "usage: %s [ -v ]\n", arg0);
if(fp == stderr){
exit(EXIT_FAILURE);
}
@ -428,29 +409,18 @@ int main(int argc, char** argv){
nopts.margin_r = 2;
nopts.margin_b = 2;
nopts.loglevel = NCLOGLEVEL_ERROR;
bool nomice = false;
int opt;
while((opt = getopt(argc, argv, "vm")) != -1){
switch(opt){
case 'm':
nomice = true;
break;
case 'v':
nopts.loglevel = NCLOGLEVEL_TRACE;
break;
default:
usage(argv[0], stderr);
break;
}
}
if(argv[optind]){ // non-option argument was provided
if(argc > 2){
usage(argv[0], stderr);
}else if(argc == 2){
if(strcmp(argv[1], "-v") == 0){
nopts.loglevel = NCLOGLEVEL_TRACE;
}else{
usage(argv[0], stderr);
}
}
nopts.flags = NCOPTION_INHIBIT_SETLOCALE;
NotCurses nc(nopts);
if(!nomice){
nc.mouse_enable(NCMICE_ALL_EVENTS);
}
nc.mouse_enable(NCMICE_ALL_EVENTS);
int ret = input_demo(&nc);
if(!nc.stop() || ret){
return EXIT_FAILURE;

@ -53,7 +53,7 @@ uint32_t esctrie_id(const esctrie* e){
// returns the idx of the new node, or 0 on failure (idx is 1-biased).
// *invalidates any existing escnode pointers!*
static unsigned
static inline unsigned
create_esctrie_node(automaton* a, int special){
if(a->poolused == a->poolsize){
unsigned newsize = a->poolsize ? a->poolsize * 2 : 512;
@ -92,7 +92,7 @@ void input_free_esctrie(automaton* a){
static int
esctrie_make_kleene(automaton* a, esctrie* e, unsigned follow, esctrie* term){
if(e->ntype != NODE_SPECIAL){
logerror("can't make node type %d string", e->ntype);
logerror("can't make node type %d string\n", e->ntype);
return -1;
}
for(unsigned i = 0 ; i < 0x80 ; ++i){
@ -108,11 +108,11 @@ esctrie_make_kleene(automaton* a, esctrie* e, unsigned follow, esctrie* term){
static int
esctrie_make_function(esctrie* e, triefunc fxn){
if(e->ntype != NODE_SPECIAL){
logerror("can't make node type %d function", e->ntype);
logerror("can't make node type %d function\n", e->ntype);
return -1;
}
if(e->trie){
logerror("can't make followed function");
logerror("can't make followed function\n");
return -1;
}
e->ntype = NODE_FUNCTION;
@ -123,11 +123,11 @@ esctrie_make_function(esctrie* e, triefunc fxn){
static esctrie*
esctrie_make_string(automaton* a, esctrie* e, unsigned rxvtstyle){
if(e->ntype == NODE_STRING){
logerror("repeated string node");
logerror("repeated string node\n");
return NULL;
}
if(e->ntype != NODE_SPECIAL){
logerror("can't make node type %d string", e->ntype);
logerror("can't make node type %d string\n", e->ntype);
return NULL;
}
for(int i = 0 ; i < 0x80 ; ++i){
@ -135,7 +135,7 @@ esctrie_make_string(automaton* a, esctrie* e, unsigned rxvtstyle){
continue;
}
if(e->trie[i]){
logerror("can't make %c-followed string", i);
logerror("can't make %c-followed string\n", i);
return NULL;
}
}
@ -178,7 +178,7 @@ esctrie_make_string(automaton* a, esctrie* e, unsigned rxvtstyle){
term->ntype = NODE_SPECIAL;
e = term;
}
logdebug("made string: %u", esctrie_idx(a, e));
logdebug("made string: %u\n", esctrie_idx(a, e));
return e;
}
@ -207,7 +207,7 @@ link_kleene(automaton* a, esctrie* e, unsigned follow){
for(unsigned int i = 0 ; i < 0x80 ; ++i){
if(i == follow){
if(e->trie[i]){
logerror("drain terminator already registered");
logerror("drain terminator already registered\n");
return NULL;
}
e->trie[follow] = esctrie_idx(a, term);
@ -221,7 +221,7 @@ link_kleene(automaton* a, esctrie* e, unsigned follow){
// phase 1 of the numeric algorithm; find a φ node on e. not sure what
// to do if we have non-φ links at every digit...punt for now FIXME.
static unsigned
static inline unsigned
get_phi_node(automaton* a, esctrie* e){
// find a linked NODE_NUMERIC, if one exists. we'll want to reuse it.
int nonphis = 0;
@ -229,7 +229,7 @@ get_phi_node(automaton* a, esctrie* e){
for(int i = '0' ; i <= '9' ; ++i){
if( (targ = esctrie_from_idx(a, e->trie[i])) ){
if(targ->ntype == NODE_NUMERIC){
logtrace("found existing phi node %u[%c]->%u", esctrie_idx(a, e), i, esctrie_idx(a, targ));
logtrace("found existing phi node %u[%c]->%u\n", esctrie_idx(a, e), i, esctrie_idx(a, targ));
break;
}else{
++nonphis;
@ -241,7 +241,7 @@ get_phi_node(automaton* a, esctrie* e){
// one, be sure to mark it numeric, and add all digit links back to itself.
if(targ == NULL){
if(nonphis == 10){
logerror("ten non-phi links from %u", esctrie_idx(a, e));
logerror("ten non-phi links from %u\n", esctrie_idx(a, e));
return 0;
}
if((targ = esctrie_from_idx(a, create_esctrie_node(a, 0))) == 0){
@ -257,7 +257,7 @@ get_phi_node(automaton* a, esctrie* e){
}
// phase 2 of the numeric algorithm; find a ή node for |successor| on |phi|.
static unsigned
static inline unsigned
get_eta_node(automaton* a, esctrie* phi, unsigned successor){
unsigned phiidx = esctrie_idx(a, phi);
unsigned etaidx = phi->trie[successor];
@ -275,22 +275,22 @@ get_eta_node(automaton* a, esctrie* phi, unsigned successor){
// |e| is a known-standard node reached by our prefix; go ahead and prep both
// phi and eta links from it.
static void
static inline void
add_phi_and_eta_chain(const automaton *a, esctrie* e, unsigned phi,
unsigned follow, unsigned eta){
//logtrace("working with %u phi: %u follow: %u eta: %u", esctrie_idx(a, e), phi, follow, eta);
//logtrace("working with %u phi: %u follow: %u eta: %u\n", esctrie_idx(a, e), phi, follow, eta);
for(int i = '0' ; i <= '9' ; ++i){
esctrie* chain = esctrie_from_idx(a, e->trie[i]);
if(chain == NULL){
//logdebug("linking %u[%d] to %u", esctrie_idx(a, e), i, phi);
//logdebug("linking %u[%d] to %u\n", esctrie_idx(a, e), i, phi);
e->trie[i] = phi;
}else if(chain->ntype == NODE_SPECIAL){
//logdebug("propagating along %u[%c]", e->trie[i], i);
//logdebug("propagating along %u[%c]\n", e->trie[i], i);
add_phi_and_eta_chain(a, esctrie_from_idx(a, e->trie[i]), phi, follow, eta);
}
}
if(e->trie[follow] == 0){
//logdebug("linking %u[%u] to %u", esctrie_idx(a, e), follow, eta);
//logdebug("linking %u[%u] to %u\n", esctrie_idx(a, e), follow, eta);
e->trie[follow] = eta;
}
}
@ -300,11 +300,11 @@ add_phi_and_eta_chain(const automaton *a, esctrie* e, unsigned phi,
// non-phi chains from those nodes) and linking them to phi, and finding all
// nodes which are prefixes of eta (all numeric non-phi chains from the
// previous set) and linking them to eta. |e| is the path thus far.
static void
static inline void
add_phi_and_eta_recurse(automaton* a, esctrie* e, const char* prefix,
int pfxlen, esctrie* phi, unsigned follow,
esctrie* eta, unsigned inphi){
//logtrace("working with %u %d prefix [%*.*s]", esctrie_idx(a, e), pfxlen, pfxlen, pfxlen, prefix);
//logtrace("working with %u %d prefix [%*.*s]\n", esctrie_idx(a, e), pfxlen, pfxlen, pfxlen, prefix);
// if pfxlen == 0, we found a match for our fixed prefix. start adding phi
// links whereever we can. where we find chained numerics, add an eta link.
if(pfxlen == 0){
@ -316,39 +316,29 @@ add_phi_and_eta_recurse(automaton* a, esctrie* e, const char* prefix,
++prefix;
--pfxlen;
if(*prefix != 'N'){
logerror("illegal wildcard in prefix %c", *prefix);
logerror("illegal wildcard in prefix %c\n", *prefix);
return;
}
++prefix;
--pfxlen;
// Optimization: get_phi_node will set the trie[i] for i='0'..'9' to the exact
// same linked tri index. If that happens, there is no need to to the (expensive)
// add_phi_and_eta_recurse call ten times, only the first time is enough.
unsigned linked_tri_seen_last = UINT_MAX;
for(int i = '0' ; i <= '9' ; ++i){
if(e->trie[i] == 0){
//logdebug("linking %u[%d] to %u", esctrie_idx(a, e), i, esctrie_idx(a, phi));
//logdebug("linking %u[%d] to %u\n", esctrie_idx(a, e), i, esctrie_idx(a, phi));
e->trie[i] = esctrie_idx(a, phi);
}else{
if(e->trie[i] != linked_tri_seen_last){
add_phi_and_eta_recurse(a, esctrie_from_idx(a, e->trie[i]),
add_phi_and_eta_recurse(a, esctrie_from_idx(a, e->trie[i]),
prefix, pfxlen, phi, follow, eta, 1);
linked_tri_seen_last = e->trie[i];
}
}
}
}else{
if(inphi){
//same optimization as above
unsigned linked_tri_seen_last = UINT_MAX;
for(int i = '0' ; i <= '9' ; ++i){
if(e->trie[i] == 0){
//logdebug("linking %u[%d] to %u", esctrie_idx(a, e), i, esctrie_idx(a, phi));
//logdebug("linking %u[%d] to %u\n", esctrie_idx(a, e), i, esctrie_idx(a, phi));
e->trie[i] = esctrie_idx(a, phi);
}else if(e->trie[i] != esctrie_idx(a, e) && e->trie[i] != linked_tri_seen_last){
}else if(e->trie[i] != esctrie_idx(a, e)){
add_phi_and_eta_recurse(a, esctrie_from_idx(a, e->trie[i]),
prefix, pfxlen, phi, follow, eta, 1);
linked_tri_seen_last = e->trie[i];
prefix, pfxlen, phi, follow, eta, 1);
}
}
}
@ -361,7 +351,7 @@ add_phi_and_eta_recurse(automaton* a, esctrie* e, const char* prefix,
}
// |prefix| does *not* lead with an escape, and does not include the numeric.
static void
static inline void
add_phi_and_eta(automaton* a, const char* prefix, size_t pfxlen,
esctrie* phi, unsigned follow, esctrie* eta){
esctrie* esc = esctrie_from_idx(a, a->escapes);
@ -374,7 +364,7 @@ add_phi_and_eta(automaton* a, const char* prefix, size_t pfxlen,
// accept any digit and transition to a numeric node. |e| is the culmination of
// the prefix before the numeric. |follow| is the successor of the numeric.
// here's our approach:
// - find a link to a numeric from e. there can only be one node (though it
// - find a link to a numeric from e. there can only be one node (thought it
// might have many links), so we can use the first one we find.
// - if there is no such numeric node linked from e, create one.
// (FIXME if all ten digits are occupied, what would we do?)
@ -387,7 +377,7 @@ add_phi_and_eta(automaton* a, const char* prefix, size_t pfxlen,
static esctrie*
link_numeric(automaton* a, const char* prefix, int pfxlen,
esctrie* e, unsigned char follow){
logdebug("adding numeric with follow %c following %*.*s", follow, pfxlen, pfxlen, prefix);
logdebug("adding numeric with follow %c following %*.*s\n", follow, pfxlen, pfxlen, prefix);
unsigned phiidx = get_phi_node(a, e);
if(phiidx == 0){
return NULL;
@ -400,8 +390,8 @@ link_numeric(automaton* a, const char* prefix, int pfxlen,
}
phi = esctrie_from_idx(a, phiidx);
esctrie* eta = esctrie_from_idx(a, etaidx);
logtrace("phi node: %u->%u", esctrie_idx(a, e), esctrie_idx(a, phi));
logtrace("eta node: %u philink[%c]: %u", esctrie_idx(a, eta), follow, phi->trie[follow]);
logtrace("phi node: %u->%u\n", esctrie_idx(a, e), esctrie_idx(a, phi));
logtrace("eta node: %u philink[%c]: %u\n", esctrie_idx(a, eta), follow, phi->trie[follow]);
// eta is now bound to phi, and phi links something at all digits, but no
// other links are guaranteed. walk the automaton, finding all possible
// prefixes of φ (and linking to φ) and all possible prefixes of ή (and
@ -424,7 +414,7 @@ insert_path(automaton* a, const char* seq){
while( (c = *seq++) ){
if(c == '\\'){
if(inescape){
logerror("illegal escape: \\");
logerror("illegal escape: \\\n");
return NULL;
}
inescape = true;
@ -432,7 +422,7 @@ insert_path(automaton* a, const char* seq){
if(c == 'N'){
// a numeric must be followed by some terminator
if(!*seq){
logerror("illegal numeric terminator");
logerror("illegal numeric terminator\n");
return NULL;
}
c = *seq++;
@ -449,7 +439,7 @@ insert_path(automaton* a, const char* seq){
}else if(c == 'D'){ // drain (kleene closure)
// a kleene must be followed by some terminator
if(!*seq){
logerror("illegal kleene terminator");
logerror("illegal kleene terminator\n");
return NULL;
}
c = *seq++;
@ -458,7 +448,7 @@ insert_path(automaton* a, const char* seq){
return NULL;
}
}else{
logerror("illegal escape: %u", c);
logerror("illegal escape: %u\n", c);
return NULL;
}
inescape = false;
@ -488,11 +478,11 @@ insert_path(automaton* a, const char* seq){
}
eptr = esctrie_from_idx(a, eidx);
eptr = esctrie_from_idx(a, eptr->trie[c]);
logtrace("added fixed %c %u as %u", c, c, esctrie_idx(a, eptr));
logtrace("added fixed %c %u as %u\n", c, c, esctrie_idx(a, eptr));
}
}
if(inescape){
logerror("illegal escape at end of line");
logerror("illegal escape at end of line\n");
return NULL;
}
return eptr;
@ -511,9 +501,9 @@ int inputctx_add_cflow(automaton* a, const char* seq, triefunc fxn){
// multiple input escapes might map to the same input
int inputctx_add_input_escape(automaton* a, const char* esc, uint32_t special,
unsigned modifiers){
unsigned shift, unsigned ctrl, unsigned alt){
if(esc[0] != NCKEY_ESC || strlen(esc) < 2){ // assume ESC prefix + content
logerror("not an escape (0x%x)", special);
logerror("not an escape (0x%x)\n", special);
return -1;
}
esctrie* eptr = insert_path(a, esc + 1);
@ -524,17 +514,16 @@ int inputctx_add_input_escape(automaton* a, const char* esc, uint32_t special,
// an example, see "kend" and "kc1" in st ("simple term" from suckless) :/.
if(eptr->ni.id){ // already had one here!
if(eptr->ni.id != special){
logwarn("already added escape (got 0x%x, wanted 0x%x)", eptr->ni.id, special);
logwarn("already added escape (got 0x%x, wanted 0x%x)\n", eptr->ni.id, special);
}
}else{
eptr->ni.id = special;
eptr->ni.shift = modifiers & NCKEY_MOD_SHIFT;
eptr->ni.ctrl = modifiers & NCKEY_MOD_CTRL;
eptr->ni.alt = modifiers & NCKEY_MOD_ALT;
eptr->ni.shift = shift;
eptr->ni.ctrl = ctrl;
eptr->ni.alt = alt;
eptr->ni.y = 0;
eptr->ni.x = 0;
eptr->ni.modifiers = modifiers;
logdebug("added 0x%08x to %u", special, esctrie_idx(a, eptr));
logdebug("added 0x%08x to %u\n", special, esctrie_idx(a, eptr));
}
return 0;
}
@ -546,7 +535,7 @@ int inputctx_add_input_escape(automaton* a, const char* esc, uint32_t special,
int walk_automaton(automaton* a, struct inputctx* ictx, unsigned candidate,
ncinput* ni){
if(candidate >= 0x80){
logerror("eight-bit char %u in control sequence", candidate);
logerror("eight-bit char %u in control sequence\n", candidate);
return -1;
}
esctrie* e = esctrie_from_idx(a, a->state);
@ -577,7 +566,7 @@ int walk_automaton(automaton* a, struct inputctx* ictx, unsigned candidate,
ni->alt = true;
return 1;
}
loginfo("unexpected transition on %u[%u]",
loginfo("unexpected transition on %u[%u]\n",
esctrie_idx(a, e), candidate);
return -1;
}

@ -34,7 +34,8 @@ typedef struct automaton {
void input_free_esctrie(automaton *a);
int inputctx_add_input_escape(automaton* a, const char* esc,
uint32_t special, unsigned modifiers);
uint32_t special, unsigned shift,
unsigned ctrl, unsigned alt);
int inputctx_add_cflow(automaton* a, const char* csi, triefunc fxn)
__attribute__ ((nonnull (1, 2)));

@ -2,8 +2,6 @@
#include <curses.h>
#ifdef USE_DEFLATE
#include <libdeflate.h>
#else
#include <zlib.h>
#endif
// only invoked without suppress banners flag. prints various warnings based on
@ -66,13 +64,8 @@ int init_banner(const notcurses* nc, fbuf* f){
const char* ncursesver = curses_version();
const char* ncver = strchr(ncursesver, ' ');
ncver = ncver ? ncver + 1 : ncursesver;
#ifdef USE_DEFLATE
fbuf_printf(f, "%u colors" NL "%s%s%s (%s)" NL "%sterminfo %s libdeflate %s GPM %s" NL,
nc->tcache.caps.colors, clreol,
#else
fbuf_printf(f, "%u colors" NL "%s%s%s (%s)" NL "%sterminfo %s zlib %s GPM %s" NL,
nc->tcache.caps.colors, clreol,
#endif
#ifdef __clang__
"", // name is contained in __VERSION__
#else
@ -96,7 +89,7 @@ int init_banner(const notcurses* nc, fbuf* f){
#ifdef USE_DEFLATE
LIBDEFLATE_VERSION_STRING,
#else
ZLIB_VERSION,
"n/a",
#endif
gpm_version());
fbuf_puts(f, clreol); // for ncvisual banner

@ -5,22 +5,6 @@
extern "C" {
#endif
// convert a base64 character into its equivalent integer 0..63
static inline int
b64idx(char b64){
if(b64 >= 'A' && b64 <= 'Z'){
return b64 - 'A';
}else if(b64 >= 'a' && b64 <= 'z'){
return b64 - 'a' + 26;
}else if(b64 >= '0' && b64 <= '9'){
return b64 - '0' + 52;
}else if(b64 == '+'){
return 62;
}else{
return 63;
}
}
// lookup table for base64
static unsigned const char b64subs[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

@ -94,7 +94,6 @@ tria_blit_ascii(ncplane* nc, int linesize, const void* data,
nccell_set_bg_alpha(c, NCALPHA_TRANSPARENT);
nccell_set_fg_alpha(c, NCALPHA_TRANSPARENT);
cell_set_blitquadrants(c, 0, 0, 0, 0);
nccell_release(nc, c);
}else{
nccell_set_fg_rgb8(c, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2]);
nccell_set_bg_rgb8(c, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2]);
@ -148,7 +147,6 @@ tria_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
nccell_set_bg_alpha(c, NCALPHA_TRANSPARENT);
if(rgba_trans_q(rgbbase_up, transcolor) && rgba_trans_q(rgbbase_down, transcolor)){
nccell_set_fg_alpha(c, NCALPHA_TRANSPARENT);
nccell_release(nc, c);
}else if(rgba_trans_q(rgbbase_up, transcolor)){ // down has the color
if(pool_blit_direct(&nc->pool, c, "\u2584", strlen("\u2584"), 1) <= 0){
return -1;
@ -500,8 +498,6 @@ quadrant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
return -1;
}
++total;
}else{
nccell_release(nc, c);
}
}
}
@ -703,8 +699,6 @@ sextant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
return -1;
}
++total;
}else{
nccell_release(nc, c);
}
}
}
@ -997,11 +991,11 @@ const char* notcurses_str_blitter(ncblitter_e blitfxn){
int ncblit_bgrx(const void* data, int linesize, const struct ncvisual_options* vopts){
if(vopts->leny <= 0 || vopts->lenx <= 0){
logerror("invalid lengths %u %u", vopts->leny, vopts->lenx);
logerror("invalid lenghts %u %u\n", vopts->leny, vopts->lenx);
return -1;
}
if(vopts->n == NULL){
logerror("prohibited null plane");
logerror("prohibited null plane\n");
return -1;
}
void* rdata = bgra_to_rgba(data, vopts->leny, &linesize, vopts->lenx, 0xff);
@ -1043,11 +1037,11 @@ int ncblit_rgb_packed(const void* data, int linesize,
int ncblit_rgba(const void* data, int linesize, const struct ncvisual_options* vopts){
if(vopts->leny <= 0 || vopts->lenx <= 0){
logerror("invalid lengths %u %u", vopts->leny, vopts->lenx);
logerror("invalid lenghts %u %u\n", vopts->leny, vopts->lenx);
return -1;
}
if(vopts->n == NULL){
logerror("prohibited null plane");
logerror("prohibited null plane\n");
return -1;
}
struct ncvisual* ncv = ncvisual_from_rgba(data, vopts->leny, linesize, vopts->lenx);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save