Compare commits

..

No commits in common. "78672521c49dfbdb0f39a63ef4886a88b5ef1b1d" and "ae6130f095c50d3681e117f2153851a6e530b201" have entirely different histories.

8 changed files with 384 additions and 465 deletions

View file

@ -1,17 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${default}"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}

View file

@ -55,8 +55,5 @@
"typeinfo": "cpp", "typeinfo": "cpp",
"pointers": "cpp" "pointers": "cpp"
}, },
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
"C_Cpp.default.includePath": [
"${workspaceFolder}/include"
]
} }

View file

@ -4,12 +4,11 @@
#include "App.hpp" #include "App.hpp"
#include "Debug.hpp" #include "Debug.hpp"
#include <NCursesPtyWindow/PtyWindow.hpp> #include <NCursesPtyWindow/Window.hpp>
#include <unistd.h> #include <unistd.h>
#include <utmp.h> #include <utmp.h>
#include <cstdlib> #include <cstdlib>
#include <mutex>
namespace krikkel::NCursesPtyWindow namespace krikkel::NCursesPtyWindow
{ {
@ -22,7 +21,7 @@ namespace krikkel::NCursesPtyWindow
{ {
std::mutex writeMutex; std::mutex writeMutex;
PtyWindow *ptyWindow = new PtyWindow(&writeMutex Window *ptyWindow = new Window(&writeMutex
, Root_Window->lines() , Root_Window->lines()
, Root_Window->cols() , Root_Window->cols()
, 0 , 0

View file

@ -13,7 +13,7 @@ set(CMAKE_CXX_STANDARD 17)
include(CTest) include(CTest)
enable_testing() enable_testing()
add_library(NCursesPtyWindow Window.cpp PtyWindow.cpp SingleUserInput.cpp Debug.cpp) add_library(NCursesPtyWindow Window.cpp SingleUserInput.cpp Debug.cpp)
### path to own system includes ### path to own system includes
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/include") include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/include")

View file

@ -1,328 +0,0 @@
/**
* @author Christian Burger (christian@krikkel.de)
*/
#include <NCursesPtyWindow/PtyWindow.hpp>
#include "Debug.hpp"
#include <cstdio>
#include <unistd.h>
#include <sys/select.h>
#include <gsl/gsl>
#include <cctype>
#include <termios.h>
#include <fcntl.h>
namespace krikkel::NCursesPtyWindow
{
using gsl::narrow;
using std::lock_guard;
PtyWindow::PtyWindow(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x)
: writeToNCursesMutex(writeToNCursesMutex), Window(lines, columns, y, x)
{
// to get the original terminal we need to shutdown ncurses for a moment
/// @todo maybe try `reset_prog_mode()` and `reset_shell_mode()` instead
::endwin();
tcgetattr(STDIN_FILENO, &terminalParameters);
::refresh();
winsize windowSize =
{
.ws_row = narrow<short unsigned int>(this->height())
, .ws_col = narrow<short unsigned int>(this->width())
};
openpty(&fdPtyHost, &fdPtyClient, NULL, &terminalParameters, &windowSize);
pseudoTerminal = vterm_new(windowSize.ws_row, windowSize.ws_col);
vterm_set_utf8(pseudoTerminal, true);
pseudoTerminalScreen = vterm_obtain_screen(pseudoTerminal);
vterm_screen_reset(pseudoTerminalScreen, true);
vterm_screen_set_callbacks(pseudoTerminalScreen, &screenCallbacks, this);
vterm_output_set_callback(pseudoTerminal, &staticHandlerOutput, this);
vterm_screen_enable_altscreen(pseudoTerminalScreen, true);
//raw(); //— cbreak might suffice
//noecho(); — already set
//nodelay(true); — @todo needs some reprogramming
keypad(true);
nonl();
/// @todo block all signals, this thread does not handle any
readPtyClientThread =
std::thread(&PtyWindow::readFromPtyClientThreadMethod, this);
}
PtyWindow::~PtyWindow()
{
close(fdPtyHost);
close(fdPtyClient);
vterm_free(pseudoTerminal);
}
int PtyWindow::getFdPtyClient() const
{
return fdPtyClient;
}
void PtyWindow::writeToClient(const char *output, size_t length)
{
lock_guard writeLock(writeToPseudoTerminalMutex);
write(fdPtyHost, output, length);
__debug_log("written to PTY client: '" + __debug_make_bytes_printable(std::string(output, length)) + '\'');
}
void PtyWindow::writeUnicodeCharToClient(wint_t character)
{
vterm_keyboard_unichar(pseudoTerminal, character, VTERM_MOD_NONE);
}
void PtyWindow::writeKeyToClient(VTermKey key)
{
__debug_log("writing key: " + std::to_string(key));
vterm_keyboard_key(pseudoTerminal, key, VTERM_MOD_NONE);
}
void PtyWindow::readFromPtyClientThreadMethod()
{
/// @todo in theory, there is no need for a timeout or select …
/// file descriptor is blocking
while(1)
{
readFromPtyClient();
struct timeval timeout = { .tv_sec = 0, .tv_usec = 200000 };
fd_set readFds;
FD_ZERO(&readFds);
FD_SET(fdPtyHost, &readFds);
if(select(fdPtyHost + 1, &readFds, NULL, NULL, &timeout) < 0)
break;
}
}
void PtyWindow::readFromPtyClient()
{
size_t bytesRead = read(fdPtyHost, ptyClientOutputBuffer, PTY_CLIENT_OUTPUT_BUFFER_SIZE);
if(bytesRead != -1 && bytesRead != 0)
{
lock_guard writeLock(writeToPseudoTerminalMutex);
vterm_input_write(pseudoTerminal, ptyClientOutputBuffer, bytesRead);
}
__debug_log("read from PTY client: '" + __debug_make_bytes_printable(std::string(ptyClientOutputBuffer, bytesRead)) + '\'');
}
VTermScreenCallbacks PtyWindow::screenCallbacks =
{
.damage = staticHandlerDamage,
.moverect = staticHandlerMoveRect,
.movecursor = staticHandlerMoveCursor,
.settermprop = staticHandlerSetTermProp,
.bell = staticHandlerBell,
.resize = staticHandlerResize,
.sb_pushline = staticHandlerPushLine,
.sb_popline = staticHandlerPopLine,
};
int PtyWindow::handlerDamage(VTermRect rect)
{
for(int x = rect.start_col; x < rect.end_col; ++x)
for(int y = rect.start_row; y < rect.end_row; ++y)
copyPtyCellToNCursesWindow(x, y);
refresh();
return 0;
}
int PtyWindow::handlerMoveRect(VTermRect dest, VTermRect src)
{
__debug_log("(unimplemented) move content in rectangle from ("
+ std::to_string(src.start_col) + ", "
+ std::to_string(src.start_row) + ", "
+ std::to_string(src.end_col) + ", "
+ std::to_string(src.end_row) + ") "
+ "size: " + std::to_string((src.start_col - src.end_col) * (src.start_row - src.end_row))
+ " to ("
+ std::to_string(dest.start_col) + ", "
+ std::to_string(dest.start_row) + ", "
+ std::to_string(dest.end_col) + ", "
+ std::to_string(dest.end_row) + ") "
+ "size: " + std::to_string((dest.start_col - dest.end_col) * (dest.start_row - dest.end_row)));
return 0;
}
int PtyWindow::handlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible)
{
/// @todo maybe use `mvcur()` instead?
cursorX = pos.col;
cursorY = pos.row;
refresh();
return 0;
}
int PtyWindow::handlerSetTermProp(VTermProp prop, VTermValue *val)
{
/// @todo maybe use "vterm_get_prop_type() —> bool, number, string"?
__debug_stringify_switch_begin(handlerSetTermProp, prop, val);
__debug_stringify_switch_case(VTERM_PROP_CURSORVISIBLE);
__debug_stringify_switch_case(VTERM_PROP_CURSORBLINK);
__debug_stringify_switch_case(VTERM_PROP_ALTSCREEN);
__debug_stringify_switch_case(VTERM_PROP_REVERSE);
__debug_stringify_switch_case_end_bool(val->boolean);
__debug_stringify_switch_case(VTERM_PROP_TITLE);
__debug_stringify_switch_case(VTERM_PROP_ICONNAME);
__debug_stringify_switch_case_end_string(val->string);
__debug_stringify_switch_case(VTERM_PROP_CURSORSHAPE);
__debug_stringify_switch_case(VTERM_PROP_MOUSE);
__debug_stringify_switch_case_end_number(val->number);
__debug_stringify_switch_end(prop);
__debug_log(std::string("unimplemented handler called: ")
+ __debug_stringify_get_string(handlerSetTermProp)
);
return 0;
}
int PtyWindow::handlerBell()
{
beep();
return 0;
}
int PtyWindow::handlerResize(int rows, int cols)
{
__debug_log("unimplemented handler called");
return 0;
}
int PtyWindow::handlerPushLine(int cols, const VTermScreenCell *cells)
{
__debug_log("(unimplemented) push line with " + std::to_string(cols) + " columns");
return 0;
}
int PtyWindow::handlerPopLine(int cols, VTermScreenCell *cells)
{
__debug_log("unimplemented handler called");
return 0;
}
attr_t PtyWindow::extractAttributesFromVTermCell(VTermScreenCell vTermCell)
{
attr_t result = A_NORMAL;
//__debug_log("unimplemented method called");
return result;
}
short PtyWindow::extractColorFromVTermCell(VTermScreenCell vTermCell)
{
//__debug_log("unimplemented method called");
return 0;
}
void PtyWindow::copyPtyCellToNCursesWindow(int x, int y)
{
VTermPos cellPosition = {y, x};
VTermScreenCell vTermCell;
cchar_t converted;
attr_t formatting;
short colorPair;
wchar_t character;
vterm_screen_get_cell(pseudoTerminalScreen, cellPosition, &vTermCell);
formatting = extractAttributesFromVTermCell(vTermCell);
colorPair = extractColorFromVTermCell(vTermCell);
if(vTermCell.chars[0] == 0)
character = ' ';
else
character = *vTermCell.chars;
{
lock_guard nCursesLock(*writeToNCursesMutex);
setcchar(&converted, &character, formatting, colorPair, NULL);
move(cellPosition.row, cellPosition.col);
chgat(1, formatting, colorPair, NULL);
add_wch(&converted);
}
}
int PtyWindow::refresh()
{
lock_guard nCursesLock(*writeToNCursesMutex);
move(cursorY, cursorX);
return NCursesWindow::refresh();
}
/// @todo potential racing condition where drawing into terminal while
/// resizing?
int PtyWindow::wresize(int rows, int cols)
{
lock_guard nCursesLock(*writeToNCursesMutex);
lock_guard writeLock(writeToPseudoTerminalMutex);
winsize windowSize =
{
.ws_row = narrow<unsigned short>(rows)
, .ws_col = narrow<unsigned short>(cols)
};
ioctl(fdPtyHost, TIOCSWINSZ, &windowSize);
vterm_set_size(pseudoTerminal, rows, cols);
return NCursesWindow::wresize(rows, cols);
}
int PtyWindow::staticHandlerDamage(VTermRect rect, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerDamage(rect);
}
int PtyWindow::staticHandlerMoveRect(VTermRect dest, VTermRect src, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerMoveRect(dest, src);
}
int PtyWindow::staticHandlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerMoveCursor(pos, oldpos, visible);
}
int PtyWindow::staticHandlerSetTermProp(VTermProp prop, VTermValue *val, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerSetTermProp(prop, val);
}
int PtyWindow::staticHandlerBell(void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerBell();
}
int PtyWindow::staticHandlerResize(int rows, int cols, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerResize(rows, cols);
}
int PtyWindow::staticHandlerPushLine(int cols, const VTermScreenCell *cells, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerPushLine(cols, cells);
}
int PtyWindow::staticHandlerPopLine(int cols, VTermScreenCell *cells, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
return instance->handlerPopLine(cols, cells);
}
void PtyWindow::staticHandlerOutput(const char *s, size_t len, void *user)
{
PtyWindow *instance = static_cast<PtyWindow *>(user);
__debug_log("output handler writing to client: '" + __debug_make_bytes_printable(std::string(s, len)) + "'");
instance->writeToClient(s, len);
}
}

View file

@ -3,31 +3,84 @@
*/ */
#include <NCursesPtyWindow/Window.hpp> #include <NCursesPtyWindow/Window.hpp>
#include "Debug.hpp"
#include <cstdio>
#include <unistd.h>
#include <sys/select.h>
#include <gsl/gsl>
#include <cctype>
#include <termios.h>
#include <fcntl.h>
namespace krikkel::NCursesPtyWindow namespace krikkel::NCursesPtyWindow
{ {
Window::Window(int lines, int columns, int y, int x) using gsl::narrow;
: NCursesWindow(lines, columns, y, x) using std::lock_guard;
{}
int Window::addnwstr(const wchar_t *wstr, int n) Window::Window(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x)
: writeToNCursesMutex(writeToNCursesMutex), NCursesWindow(lines, columns, y, x)
{ {
return ::waddnwstr(w, wstr, n); // to get the original terminal we need to shutdown ncurses for a moment
/// @todo maybe try `reset_prog_mode()` and `reset_shell_mode()` instead
::endwin();
tcgetattr(STDIN_FILENO, &terminalParameters);
::refresh();
winsize windowSize =
{
.ws_row = narrow<short unsigned int>(this->height())
, .ws_col = narrow<short unsigned int>(this->width())
};
openpty(&fdPtyHost, &fdPtyClient, NULL, &terminalParameters, &windowSize);
pseudoTerminal = vterm_new(windowSize.ws_row, windowSize.ws_col);
vterm_set_utf8(pseudoTerminal, true);
pseudoTerminalScreen = vterm_obtain_screen(pseudoTerminal);
vterm_screen_reset(pseudoTerminalScreen, true);
vterm_screen_set_callbacks(pseudoTerminalScreen, &screenCallbacks, this);
vterm_output_set_callback(pseudoTerminal, &staticHandlerOutput, this);
vterm_screen_enable_altscreen(pseudoTerminalScreen, true);
//raw(); //— cbreak might suffice
//noecho(); — already set
//nodelay(true); — @todo needs some reprogramming
keypad(true);
nonl();
/// @todo block all signals, this thread does not handle any
readPtyClientThread =
std::thread(&Window::readFromPtyClientThreadMethod, this);
} }
int Window::add_wch(const cchar_t *character) Window::~Window()
{ {
return ::wadd_wch(w, character); close(fdPtyHost);
close(fdPtyClient);
vterm_free(pseudoTerminal);
} }
int Window::ins_wch(const cchar_t *character) int Window::getFdPtyClient() const
{ {
return ::wins_wch(w, character); return fdPtyClient;
} }
int Window::get_wch(wint_t *character) void Window::writeToClient(const char *output, size_t length)
{ {
return ::wget_wch(w, character); lock_guard writeLock(writeToPseudoTerminalMutex);
write(fdPtyHost, output, length);
__debug_log("written to PTY client: '" + __debug_make_bytes_printable(std::string(output, length)) + '\'');
}
void Window::writeUnicodeCharToClient(wint_t character)
{
vterm_keyboard_unichar(pseudoTerminal, character, VTERM_MOD_NONE);
}
void Window::writeKeyToClient(VTermKey key)
{
__debug_log("writing key: " + std::to_string(key));
vterm_keyboard_key(pseudoTerminal, key, VTERM_MOD_NONE);
} }
SingleUserInput Window::readSingleUserInput() SingleUserInput Window::readSingleUserInput()
@ -37,4 +90,256 @@ namespace krikkel::NCursesPtyWindow
return SingleUserInput(result, input); return SingleUserInput(result, input);
} }
void Window::readFromPtyClientThreadMethod()
{
/// @todo in theory, there is no need for a timeout or select …
/// file descriptor is blocking
while(1)
{
readFromPtyClient();
struct timeval timeout = { .tv_sec = 0, .tv_usec = 200000 };
fd_set readFds;
FD_ZERO(&readFds);
FD_SET(fdPtyHost, &readFds);
if(select(fdPtyHost + 1, &readFds, NULL, NULL, &timeout) < 0)
break;
}
}
void Window::readFromPtyClient()
{
size_t bytesRead = read(fdPtyHost, ptyClientOutputBuffer, PTY_CLIENT_OUTPUT_BUFFER_SIZE);
if(bytesRead != -1 && bytesRead != 0)
{
lock_guard writeLock(writeToPseudoTerminalMutex);
vterm_input_write(pseudoTerminal, ptyClientOutputBuffer, bytesRead);
}
__debug_log("read from PTY client: '" + __debug_make_bytes_printable(std::string(ptyClientOutputBuffer, bytesRead)) + '\'');
}
VTermScreenCallbacks Window::screenCallbacks =
{
.damage = staticHandlerDamage,
.moverect = staticHandlerMoveRect,
.movecursor = staticHandlerMoveCursor,
.settermprop = staticHandlerSetTermProp,
.bell = staticHandlerBell,
.resize = staticHandlerResize,
.sb_pushline = staticHandlerPushLine,
.sb_popline = staticHandlerPopLine,
};
int Window::handlerDamage(VTermRect rect)
{
for(int x = rect.start_col; x < rect.end_col; ++x)
for(int y = rect.start_row; y < rect.end_row; ++y)
copyPtyCellToNCursesWindow(x, y);
refresh();
return 0;
}
int Window::handlerMoveRect(VTermRect dest, VTermRect src)
{
__debug_log("(unimplemented) move content in rectangle from ("
+ std::to_string(src.start_col) + ", "
+ std::to_string(src.start_row) + ", "
+ std::to_string(src.end_col) + ", "
+ std::to_string(src.end_row) + ") "
+ "size: " + std::to_string((src.start_col - src.end_col) * (src.start_row - src.end_row))
+ " to ("
+ std::to_string(dest.start_col) + ", "
+ std::to_string(dest.start_row) + ", "
+ std::to_string(dest.end_col) + ", "
+ std::to_string(dest.end_row) + ") "
+ "size: " + std::to_string((dest.start_col - dest.end_col) * (dest.start_row - dest.end_row)));
return 0;
}
int Window::handlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible)
{
/// @todo maybe use `mvcur()` instead?
cursorX = pos.col;
cursorY = pos.row;
refresh();
return 0;
}
int Window::handlerSetTermProp(VTermProp prop, VTermValue *val)
{
/// @todo maybe use "vterm_get_prop_type() —> bool, number, string"?
__debug_stringify_switch_begin(handlerSetTermProp, prop, val);
__debug_stringify_switch_case(VTERM_PROP_CURSORVISIBLE);
__debug_stringify_switch_case(VTERM_PROP_CURSORBLINK);
__debug_stringify_switch_case(VTERM_PROP_ALTSCREEN);
__debug_stringify_switch_case(VTERM_PROP_REVERSE);
__debug_stringify_switch_case_end_bool(val->boolean);
__debug_stringify_switch_case(VTERM_PROP_TITLE);
__debug_stringify_switch_case(VTERM_PROP_ICONNAME);
__debug_stringify_switch_case_end_string(val->string);
__debug_stringify_switch_case(VTERM_PROP_CURSORSHAPE);
__debug_stringify_switch_case(VTERM_PROP_MOUSE);
__debug_stringify_switch_case_end_number(val->number);
__debug_stringify_switch_end(prop);
__debug_log(std::string("unimplemented handler called: ")
+ __debug_stringify_get_string(handlerSetTermProp)
);
return 0;
}
int Window::handlerBell()
{
beep();
return 0;
}
int Window::handlerResize(int rows, int cols)
{
__debug_log("unimplemented handler called");
return 0;
}
int Window::handlerPushLine(int cols, const VTermScreenCell *cells)
{
__debug_log("(unimplemented) push line with " + std::to_string(cols) + " columns");
return 0;
}
int Window::handlerPopLine(int cols, VTermScreenCell *cells)
{
__debug_log("unimplemented handler called");
return 0;
}
attr_t Window::extractAttributesFromVTermCell(VTermScreenCell vTermCell)
{
attr_t result = A_NORMAL;
//__debug_log("unimplemented method called");
return result;
}
short Window::extractColorFromVTermCell(VTermScreenCell vTermCell)
{
//__debug_log("unimplemented method called");
return 0;
}
void Window::copyPtyCellToNCursesWindow(int x, int y)
{
VTermPos cellPosition = {y, x};
VTermScreenCell vTermCell;
cchar_t converted;
attr_t formatting;
short colorPair;
wchar_t character;
vterm_screen_get_cell(pseudoTerminalScreen, cellPosition, &vTermCell);
formatting = extractAttributesFromVTermCell(vTermCell);
colorPair = extractColorFromVTermCell(vTermCell);
if(vTermCell.chars[0] == 0)
character = ' ';
else
character = *vTermCell.chars;
{
lock_guard nCursesLock(*writeToNCursesMutex);
setcchar(&converted, &character, formatting, colorPair, NULL);
move(cellPosition.row, cellPosition.col);
chgat(1, formatting, colorPair, NULL);
add_wch(&converted);
}
}
int Window::add_wch(const cchar_t *character)
{
return ::wadd_wch(w, character);
}
int Window::get_wch(wint_t *character)
{
return ::wget_wch(w, character);
}
int Window::refresh()
{
lock_guard nCursesLock(*writeToNCursesMutex);
move(cursorY, cursorX);
return NCursesWindow::refresh();
}
/// @todo potential racing condition where drawing into terminal while
/// resizing?
int Window::wresize(int rows, int cols)
{
lock_guard nCursesLock(*writeToNCursesMutex);
lock_guard writeLock(writeToPseudoTerminalMutex);
winsize windowSize =
{
.ws_row = narrow<unsigned short>(rows)
, .ws_col = narrow<unsigned short>(cols)
};
ioctl(fdPtyHost, TIOCSWINSZ, &windowSize);
vterm_set_size(pseudoTerminal, rows, cols);
return NCursesWindow::wresize(rows, cols);
}
int Window::staticHandlerDamage(VTermRect rect, void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerDamage(rect);
}
int Window::staticHandlerMoveRect(VTermRect dest, VTermRect src, void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerMoveRect(dest, src);
}
int Window::staticHandlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerMoveCursor(pos, oldpos, visible);
}
int Window::staticHandlerSetTermProp(VTermProp prop, VTermValue *val, void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerSetTermProp(prop, val);
}
int Window::staticHandlerBell(void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerBell();
}
int Window::staticHandlerResize(int rows, int cols, void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerResize(rows, cols);
}
int Window::staticHandlerPushLine(int cols, const VTermScreenCell *cells, void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerPushLine(cols, cells);
}
int Window::staticHandlerPopLine(int cols, VTermScreenCell *cells, void *user)
{
Window *instance = static_cast<Window *>(user);
return instance->handlerPopLine(cols, cells);
}
void Window::staticHandlerOutput(const char *s, size_t len, void *user)
{
Window *instance = static_cast<Window *>(user);
__debug_log("output handler writing to client: '" + __debug_make_bytes_printable(std::string(s, len)) + "'");
instance->writeToClient(s, len);
}
} }

View file

@ -1,76 +0,0 @@
/**
* @brief `ncurses` window displaying contents of a pseudo terminal
* @author Christian Burger (christian@krikkel.de)
*/
#ifndef __WINDOW_H__
#define __WINDOW_H__
#include "SingleUserInput.hpp"
#include "Window.hpp"
#include <cursesw.h>
#include <pty.h>
#include <vterm.h>
#include <string>
#include <thread>
#include <mutex>
namespace krikkel::NCursesPtyWindow
{
class PtyWindow : public Window
{
public:
PtyWindow(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x);
~PtyWindow();
int getFdPtyClient() const;
void writeToClient(const char * string, size_t length);
void writeUnicodeCharToClient(wint_t character);
void writeKeyToClient(VTermKey key);
int refresh() override;
int wresize(int rows, int cols);
private:
int fdPtyHost, fdPtyClient;
struct termios terminalParameters;
VTerm *pseudoTerminal;
std::mutex writeToPseudoTerminalMutex;
std::mutex *writeToNCursesMutex;
VTermScreen *pseudoTerminalScreen;
static VTermScreenCallbacks screenCallbacks;
/// @todo one line is at most 4096 chars long
static const uint16_t PTY_CLIENT_OUTPUT_BUFFER_SIZE = 2 * 4096;
char ptyClientOutputBuffer[PTY_CLIENT_OUTPUT_BUFFER_SIZE];
uint16_t cursorX, cursorY;
std::thread readPtyClientThread;
void readFromPtyClientThreadMethod();
void readFromPtyClient();
int handlerDamage(VTermRect rect);
int handlerMoveRect(VTermRect dest, VTermRect src);
int handlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible);
int handlerSetTermProp(VTermProp prop, VTermValue *val);
int handlerBell();
int handlerResize(int rows, int cols);
int handlerPushLine(int cols, const VTermScreenCell *cells);
int handlerPopLine(int cols, VTermScreenCell *cells);
attr_t extractAttributesFromVTermCell(VTermScreenCell cell);
short extractColorFromVTermCell(VTermScreenCell cell);
void copyPtyCellToNCursesWindow(int x, int y);
static int staticHandlerDamage(VTermRect rect, void *user);
static int staticHandlerMoveRect(VTermRect dest, VTermRect src, void *user);
static int staticHandlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
static int staticHandlerSetTermProp(VTermProp prop, VTermValue *val, void *user);
static int staticHandlerBell(void *user);
static int staticHandlerResize(int rows, int cols, void *user);
static int staticHandlerPushLine(int cols, const VTermScreenCell *cells, void *user);
static int staticHandlerPopLine(int cols, VTermScreenCell *cells, void *user);
static void staticHandlerOutput(const char *s, size_t len, void *user);
};
}
#endif // __WINDOW_H__

View file

@ -1,35 +1,28 @@
/** /**
* @brief Providing wide character methods missing in NCursesWindow. * @brief `ncurses` window displaying contents of a pseudo terminal
* @author Christian Burger (christian@krikkel.de) * @author Christian Burger (christian@krikkel.de)
*/ */
#ifndef A2C3FDB7_7A85_4527_BC85_366E14149EB8 #ifndef __WINDOW_H__
#define A2C3FDB7_7A85_4527_BC85_366E14149EB8 #define __WINDOW_H__
#include "SingleUserInput.hpp" #include "SingleUserInput.hpp"
#include <ncursesw/cursesw.h> #include <cursesw.h>
#include <pty.h>
#ifdef addnwstr #include <vterm.h>
inline int UNDEF(addnwstr)(const wchar_t *wstr, int n) { addnwstr(wstr, n); } #include <string>
#undef addnwstr #include <thread>
#define addnwstr UNDEF(addnwstr) #include <mutex>
#endif
#ifdef add_wch #ifdef add_wch
inline int UNDEF(add_wch)(const cchar_t *character) { add_wch(character); } inline void UNDEF(add_wch)(const cchar_t *character) { add_wch(character); }
#undef add_wch #undef add_wch
#define add_wch UNDEF(add_wch) #define add_wch UNDEF(add_wch)
#endif #endif
#ifdef ins_wch
inline int UNDEF(ins_wch)(cchar_t *character) { ins_wch(character); }
#undef ins_wch
#define ins_wch UNDEF(ins_wch)
#endif
#ifdef get_wch #ifdef get_wch
inline int UNDEF(get_wch)(wint_t *character) { get_wch(character); } inline void UNDEF(get_wch)(wint_t *character) { get_wch(character); }
#undef get_wch #undef get_wch
#define get_wch UNDEF(get_wch) #define get_wch UNDEF(get_wch)
#endif #endif
@ -39,14 +32,60 @@ namespace krikkel::NCursesPtyWindow
class Window : public NCursesWindow class Window : public NCursesWindow
{ {
public: public:
Window(int lines, int columns, int y, int x); Window(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x);
int addnwstr(const wchar_t *wstr, int n); ~Window();
int add_wch(const cchar_t *character);
int ins_wch(const cchar_t *character); int getFdPtyClient() const;
int get_wch(wint_t *character); void writeToClient(const char * string, size_t length);
void writeUnicodeCharToClient(wint_t character);
void writeKeyToClient(VTermKey key);
SingleUserInput readSingleUserInput(); SingleUserInput readSingleUserInput();
int add_wch(const cchar_t *character);
int get_wch(wint_t *character);
int refresh() override;
int wresize(int rows, int cols);
private:
int fdPtyHost, fdPtyClient;
struct termios terminalParameters;
VTerm *pseudoTerminal;
std::mutex writeToPseudoTerminalMutex;
std::mutex *writeToNCursesMutex;
VTermScreen *pseudoTerminalScreen;
static VTermScreenCallbacks screenCallbacks;
/// @todo one line is at most 4096 chars long
static const uint16_t PTY_CLIENT_OUTPUT_BUFFER_SIZE = 2 * 4096;
char ptyClientOutputBuffer[PTY_CLIENT_OUTPUT_BUFFER_SIZE];
uint16_t cursorX, cursorY;
std::thread readPtyClientThread;
void readFromPtyClientThreadMethod();
void readFromPtyClient();
int handlerDamage(VTermRect rect);
int handlerMoveRect(VTermRect dest, VTermRect src);
int handlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible);
int handlerSetTermProp(VTermProp prop, VTermValue *val);
int handlerBell();
int handlerResize(int rows, int cols);
int handlerPushLine(int cols, const VTermScreenCell *cells);
int handlerPopLine(int cols, VTermScreenCell *cells);
attr_t extractAttributesFromVTermCell(VTermScreenCell cell);
short extractColorFromVTermCell(VTermScreenCell cell);
void copyPtyCellToNCursesWindow(int x, int y);
static int staticHandlerDamage(VTermRect rect, void *user);
static int staticHandlerMoveRect(VTermRect dest, VTermRect src, void *user);
static int staticHandlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
static int staticHandlerSetTermProp(VTermProp prop, VTermValue *val, void *user);
static int staticHandlerBell(void *user);
static int staticHandlerResize(int rows, int cols, void *user);
static int staticHandlerPushLine(int cols, const VTermScreenCell *cells, void *user);
static int staticHandlerPopLine(int cols, VTermScreenCell *cells, void *user);
static void staticHandlerOutput(const char *s, size_t len, void *user);
}; };
} }
#endif // __WINDOW_H__
#endif /* A2C3FDB7_7A85_4527_BC85_366E14149EB8 */