Compare commits
15 commits
2601d78453
...
f48641bb58
Author | SHA1 | Date | |
---|---|---|---|
Christian Burger | f48641bb58 | ||
Christian Burger | 3be5336ca0 | ||
Christian Burger | 0a086ff604 | ||
Christian Burger | 9ddb769cb4 | ||
Christian Burger | 4fb2e6a976 | ||
Christian Burger | 7e7372ee52 | ||
Christian Burger | a801752620 | ||
Christian Burger | 792f12c96c | ||
Christian Burger | 1357a7f6bf | ||
Christian Burger | b723aa5f33 | ||
Christian Burger | 320f5ba63a | ||
Christian Burger | e42711f123 | ||
Christian Burger | b9e32941fb | ||
Christian Burger | 0462a68c54 | ||
Christian Burger | f8db9dc660 |
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
|
@ -5,10 +5,10 @@
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "(gdb) start NCursesPtyApp",
|
"name": "(gdb) start kNCursesDemoApp",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/build/NCursesPtyApp",
|
"program": "${workspaceFolder}/build/kNCursesDemoApp",
|
||||||
"args": [],
|
"args": [],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
|
@ -29,10 +29,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "(gdb) attach to running NCursesPtyApp",
|
"name": "(gdb) attach to running kNCursesDemoApp",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "attach",
|
"request": "attach",
|
||||||
"program": "${workspaceFolder}/build/NCursesPtyApp",
|
"program": "${workspaceFolder}/build/kNCursesDemoApp",
|
||||||
"processId": "${command:pickProcess}",
|
"processId": "${command:pickProcess}",
|
||||||
"MIMode": "gdb",
|
"MIMode": "gdb",
|
||||||
"setupCommands": [
|
"setupCommands": [
|
||||||
|
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -53,7 +53,10 @@
|
||||||
"iostream": "cpp",
|
"iostream": "cpp",
|
||||||
"stdexcept": "cpp",
|
"stdexcept": "cpp",
|
||||||
"typeinfo": "cpp",
|
"typeinfo": "cpp",
|
||||||
"pointers": "cpp"
|
"pointers": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"mutex": "cpp"
|
||||||
},
|
},
|
||||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||||
"C_Cpp.default.includePath": [
|
"C_Cpp.default.includePath": [
|
||||||
|
|
64
App.cpp
64
App.cpp
|
@ -1,64 +0,0 @@
|
||||||
/**
|
|
||||||
* @author Christian Burger (christian@krikkel.de)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "App.hpp"
|
|
||||||
#include "Debug.hpp"
|
|
||||||
#include <NCursesPtyWindow/PtyWindow.hpp>
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <utmp.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
|
||||||
{
|
|
||||||
App::App() : NCursesApplication(false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int App::run()
|
|
||||||
{
|
|
||||||
std::mutex writeMutex;
|
|
||||||
|
|
||||||
PtyWindow *ptyWindow = new PtyWindow(&writeMutex
|
|
||||||
, Root_Window->lines()
|
|
||||||
, Root_Window->cols()
|
|
||||||
, 0
|
|
||||||
, 0);
|
|
||||||
|
|
||||||
if(fork() == 0)
|
|
||||||
{
|
|
||||||
const char *shellPath = getenv("SHELL");
|
|
||||||
if(!shellPath)
|
|
||||||
shellPath = "/bin/bash";
|
|
||||||
|
|
||||||
login_tty(ptyWindow->getFdPtyClient());
|
|
||||||
const int sizeArg = 2;
|
|
||||||
const char *arg[sizeArg] = {shellPath, NULL};
|
|
||||||
fprintf(stderr, "<CTRL>+C exits shell.\n\n");
|
|
||||||
execv(shellPath, const_cast<char * const *>(arg));
|
|
||||||
fprintf(stderr, "Well, well, well … could not start a shell. We "
|
|
||||||
"tried `%s`. Maybe set `SHELL` environment variable"
|
|
||||||
" to a working value?", shellPath);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
while(true)
|
|
||||||
{
|
|
||||||
SingleUserInput input = ptyWindow->readSingleUserInput();
|
|
||||||
if(input.isNormalKey())
|
|
||||||
ptyWindow->writeUnicodeCharToClient(input.getRawInput());
|
|
||||||
if(input.isFunctionKey())
|
|
||||||
{
|
|
||||||
if(input.getRawInput() == KEY_RESIZE)
|
|
||||||
ptyWindow->wresize(Root_Window->lines(), Root_Window->cols());
|
|
||||||
else
|
|
||||||
ptyWindow->writeKeyToClient(input.mapKeyNcursesToVTerm());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
23
App.hpp
23
App.hpp
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* @brief demo application for the library
|
|
||||||
* @author Christian Burger (christian@krikkel.de)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef A3B2AE4E_0A39_468C_8CCA_E6508166702A
|
|
||||||
#define A3B2AE4E_0A39_468C_8CCA_E6508166702A
|
|
||||||
|
|
||||||
#include <cursesapp.h>
|
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
|
||||||
{
|
|
||||||
class App : public NCursesApplication
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
App();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int run() override;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* A3B2AE4E_0A39_468C_8CCA_E6508166702A */
|
|
|
@ -4,8 +4,8 @@
|
||||||
cmake_minimum_required(VERSION 3.16.3)
|
cmake_minimum_required(VERSION 3.16.3)
|
||||||
|
|
||||||
include("cmake/version.cmake")
|
include("cmake/version.cmake")
|
||||||
project(NCursesPtyWindow
|
project(kNCurses
|
||||||
HOMEPAGE_URL "https://gitea.xndr.de/christian/NCursesPtyWindow"
|
HOMEPAGE_URL "https://gitea.xndr.de/christian/kNCurses"
|
||||||
VERSION ${SEMANTIC_VERSION})
|
VERSION ${SEMANTIC_VERSION})
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
@ -13,7 +13,9 @@ 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(kNCurses Window.cpp PtyWindow.cpp SingleUserInput.cpp Debug.cpp
|
||||||
|
TilingWindowManager.cpp VerticalTilingWindowManager.cpp
|
||||||
|
HorizontalTilingWindowManager.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")
|
||||||
|
@ -21,34 +23,41 @@ include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/include")
|
||||||
### libraries
|
### libraries
|
||||||
|
|
||||||
include("cmake/ncurses.cmake")
|
include("cmake/ncurses.cmake")
|
||||||
target_link_libraries(NCursesPtyWindow ${CURSES_LIBRARIES})
|
target_link_libraries(kNCurses ${CURSES_LIBRARIES})
|
||||||
|
|
||||||
include("cmake/gsl.cmake")
|
include("cmake/gsl.cmake")
|
||||||
|
|
||||||
include("cmake/libvterm.cmake")
|
include("cmake/libvterm.cmake")
|
||||||
if(EXISTS libvtermProject)
|
if(EXISTS libvtermProject)
|
||||||
add_dependencies(NCursesPtyWindow libvtermProject)
|
add_dependencies(kNCurses libvtermProject)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(NCursesPtyWindow ${LIBVTERM_LIBRARY})
|
target_link_libraries(kNCurses ${LIBVTERM_LIBRARY})
|
||||||
|
|
||||||
find_library(UTIL_LIBRARY util)
|
find_library(UTIL_LIBRARY util)
|
||||||
target_link_libraries(NCursesPtyWindow ${UTIL_LIBRARY})
|
target_link_libraries(kNCurses ${UTIL_LIBRARY})
|
||||||
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG true)
|
set(THREADS_PREFER_PTHREAD_FLAG true)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
target_link_libraries(NCursesPtyWindow Threads::Threads)
|
target_link_libraries(kNCurses Threads::Threads)
|
||||||
|
|
||||||
### demo application
|
### demo application
|
||||||
add_executable(NCursesPtyApp main.cpp App.cpp)
|
add_executable(kNCursesDemoApp main.cpp DemoApp.cpp)
|
||||||
target_link_libraries(NCursesPtyApp NCursesPtyWindow)
|
target_link_libraries(kNCursesDemoApp kNCurses)
|
||||||
|
|
||||||
### installation and packaging
|
### installation and packaging
|
||||||
set(NCURSES_PTY_WINDOW_SYSTEM_INCLUDE "include/NCursesPtyWindow")
|
set(NCURSES_SYSTEM_INCLUDE "include/kNCurses")
|
||||||
set_target_properties(NCursesPtyWindow PROPERTIES PUBLIC_HEADER "${NCURSES_PTY_WINDOW_SYSTEM_INCLUDE}/Window.hpp;${NCURSES_PTY_WINDOW_SYSTEM_INCLUDE}/SingleUserInput.hpp;${NCURSES_PTY_WINDOW_SYSTEM_INCLUDE}/PtyWindow.hpp"
|
set_target_properties(kNCurses PROPERTIES
|
||||||
|
PUBLIC_HEADER "${NCURSES_SYSTEM_INCLUDE}/Window.hpp;
|
||||||
|
${NCURSES_SYSTEM_INCLUDE}/SingleUserInput.hpp;
|
||||||
|
${NCURSES_SYSTEM_INCLUDE}/PtyWindow.hpp;
|
||||||
|
${NCURSES_SYSTEM_INCLUDE}/TilingWindowManager.hpp;
|
||||||
|
${NCURSES_SYSTEM_INCLUDE}/VerticalTilingWindowManager.hpp;
|
||||||
|
${NCURSES_SYSTEM_INCLUDE}/HorizontalTilingWindowManager.hpp;
|
||||||
|
"
|
||||||
VERSION "${CMAKE_PROJECT_VERSION}")
|
VERSION "${CMAKE_PROJECT_VERSION}")
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
install(TARGETS NCursesPtyWindow ARCHIVE
|
install(TARGETS kNCurses ARCHIVE
|
||||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/NCursesPtyWindow/")
|
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kNCurses/")
|
||||||
|
|
||||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||||
|
|
142
DemoApp.cpp
Normal file
142
DemoApp.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/**
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DemoApp.hpp"
|
||||||
|
#include "Debug.hpp"
|
||||||
|
#include <kNCurses/VerticalTilingWindowManager.hpp>
|
||||||
|
#include <kNCurses/HorizontalTilingWindowManager.hpp>
|
||||||
|
#include <kNCurses/Window.hpp>
|
||||||
|
#include <kNCurses/PtyWindow.hpp>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
using std::scoped_lock;
|
||||||
|
|
||||||
|
DemoApp::DemoApp() : NCursesApplication(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int DemoApp::run()
|
||||||
|
{
|
||||||
|
setUpWindows();
|
||||||
|
forkShell();
|
||||||
|
mainLoop();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemoApp::setUpWindows()
|
||||||
|
{
|
||||||
|
windowManager
|
||||||
|
= new VerticalTilingWindowManager(Root_Window, &ncursesMutex);
|
||||||
|
topWindowManager
|
||||||
|
= new HorizontalTilingWindowManager(new Window(), &ncursesMutex);
|
||||||
|
bottomWindowManager
|
||||||
|
= new HorizontalTilingWindowManager(new Window(), &ncursesMutex);
|
||||||
|
|
||||||
|
windowManager->addWindow(topWindowManager);
|
||||||
|
ptyWindow = new PtyWindow(&ncursesMutex, 0, 0, 0, 0);
|
||||||
|
windowManager->addWindow(ptyWindow);
|
||||||
|
windowManager->addWindow(bottomWindowManager);
|
||||||
|
windowManager->updateLayout();
|
||||||
|
windowManager->refresh();
|
||||||
|
|
||||||
|
dummyWindowTopLeft = new Window();
|
||||||
|
topWindowManager->addWindow(dummyWindowTopLeft, 1);
|
||||||
|
dummyWindowTopLeft->addstr("t\no\np\n \nl\ne\nf\nt\n w\ni\nn\nd\no\nw");
|
||||||
|
dummyWindowTopRight = new Window(topWindowManager);
|
||||||
|
dummyWindowTopRight->addstr("top right window");
|
||||||
|
|
||||||
|
topWindowManager->updateLayout();
|
||||||
|
topWindowManager->refresh();
|
||||||
|
|
||||||
|
dummyWindowBottomLeft = new Window(bottomWindowManager);
|
||||||
|
dummyWindowBottomLeft->addstr("bottom left window");
|
||||||
|
dummyWindowBottomRight = new Window(bottomWindowManager);
|
||||||
|
dummyWindowBottomRight->addstr("bottom right window");
|
||||||
|
|
||||||
|
bottomWindowManager->updateLayout();
|
||||||
|
bottomWindowManager->refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemoApp::forkShell()
|
||||||
|
{
|
||||||
|
if(fork() == 0)
|
||||||
|
{
|
||||||
|
const char *shellPath = getenv("SHELL");
|
||||||
|
if(!shellPath)
|
||||||
|
shellPath = "/bin/bash";
|
||||||
|
|
||||||
|
login_tty(ptyWindow->getFdPtyClient());
|
||||||
|
const int sizeArg = 2;
|
||||||
|
const char *arg[sizeArg] = {shellPath, NULL};
|
||||||
|
fprintf(stderr, "<CTRL>+C exits shell.\n\n");
|
||||||
|
execv(shellPath, const_cast<char * const *>(arg));
|
||||||
|
fprintf(stderr, "Well, well, well … could not start a shell. We "
|
||||||
|
"tried `%s`. Maybe set `SHELL` environment variable"
|
||||||
|
" to a working value?", shellPath);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemoApp::mainLoop()
|
||||||
|
{
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
SingleUserInput input = windowManager->readSingleUserInput();
|
||||||
|
if(input.isNormalKey())
|
||||||
|
{
|
||||||
|
ptyWindow->writeUnicodeCharToClient(input.getRawInput());
|
||||||
|
{
|
||||||
|
scoped_lock lock(ncursesMutex);
|
||||||
|
dummyWindowTopRight->addch(input.getRawInput());
|
||||||
|
dummyWindowTopRight->refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(input.isFunctionKey())
|
||||||
|
{
|
||||||
|
switch(input.getRawInput())
|
||||||
|
{
|
||||||
|
case KEY_RESIZE:
|
||||||
|
windowManager->updateLayout();
|
||||||
|
break;
|
||||||
|
case KEY_F(1):
|
||||||
|
if(topWindowManager->isHidden())
|
||||||
|
windowManager->showWindow(topWindowManager);
|
||||||
|
else
|
||||||
|
windowManager->hideWindow(topWindowManager);
|
||||||
|
windowManager->updateLayout();
|
||||||
|
windowManager->refresh();
|
||||||
|
break;
|
||||||
|
case KEY_F(2):
|
||||||
|
if(ptyWindow->isHidden())
|
||||||
|
windowManager->showWindow(ptyWindow);
|
||||||
|
else
|
||||||
|
windowManager->hideWindow(ptyWindow);
|
||||||
|
windowManager->updateLayout();
|
||||||
|
windowManager->refresh();
|
||||||
|
break;
|
||||||
|
case KEY_F(3):
|
||||||
|
if(bottomWindowManager->isHidden())
|
||||||
|
windowManager->showWindow(bottomWindowManager);
|
||||||
|
else
|
||||||
|
windowManager->hideWindow(bottomWindowManager);
|
||||||
|
windowManager->updateLayout();
|
||||||
|
windowManager->refresh();
|
||||||
|
break;
|
||||||
|
case KEY_F(5):
|
||||||
|
windowManager->refresh();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ptyWindow->writeFunctionKeyToClient(input.mapKeyNcursesToVTerm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
DemoApp.hpp
Normal file
39
DemoApp.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* @brief demo application for the library
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef A3B2AE4E_0A39_468C_8CCA_E6508166702A
|
||||||
|
#define A3B2AE4E_0A39_468C_8CCA_E6508166702A
|
||||||
|
|
||||||
|
#include <cursesapp.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
class VerticalTilingWindowManager;
|
||||||
|
class HorizontalTilingWindowManager;
|
||||||
|
class Window;
|
||||||
|
class PtyWindow;
|
||||||
|
|
||||||
|
class DemoApp : public NCursesApplication
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DemoApp();
|
||||||
|
|
||||||
|
private:
|
||||||
|
VerticalTilingWindowManager *windowManager;
|
||||||
|
HorizontalTilingWindowManager *topWindowManager, *bottomWindowManager;
|
||||||
|
Window *dummyWindowTopLeft, *dummyWindowTopRight
|
||||||
|
, *dummyWindowBottomLeft, *dummyWindowBottomRight;
|
||||||
|
PtyWindow *ptyWindow;
|
||||||
|
std::recursive_mutex ncursesMutex;
|
||||||
|
|
||||||
|
int run() override;
|
||||||
|
void setUpWindows();
|
||||||
|
void forkShell();
|
||||||
|
void mainLoop();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* A3B2AE4E_0A39_468C_8CCA_E6508166702A */
|
40
HorizontalTilingWindowManager.cpp
Normal file
40
HorizontalTilingWindowManager.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Debug.hpp"
|
||||||
|
#include <kNCurses/HorizontalTilingWindowManager.hpp>
|
||||||
|
#include <kNCurses/Window.hpp>
|
||||||
|
#include <ncursesw/ncurses.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
using std::recursive_mutex;
|
||||||
|
|
||||||
|
HorizontalTilingWindowManager::HorizontalTilingWindowManager(NCursesWindow *rootWindow, std::recursive_mutex *ncursesMutex)
|
||||||
|
: TilingWindowManager(rootWindow, ncursesMutex)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void HorizontalTilingWindowManager::resizeAndMoveWindow(Window *window, windowDimension dimension, windowPosition position)
|
||||||
|
{
|
||||||
|
__debug_log("(" + std::to_string(position + begx()) + ", " + std::to_string(0 + begy()) + ", " + std::to_string(dimension) + ", " + std::to_string(height()) + ")");
|
||||||
|
window->resize(height(), dimension);
|
||||||
|
window->mvwin(0 + begy(), position + begx());
|
||||||
|
}
|
||||||
|
|
||||||
|
TilingWindowManager::windowDimension HorizontalTilingWindowManager::getAvailableSpace()
|
||||||
|
{
|
||||||
|
return width();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HorizontalTilingWindowManager::windowBorder()
|
||||||
|
{
|
||||||
|
vline(height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HorizontalTilingWindowManager::moveCursor(TilingWindowManager::windowPosition position)
|
||||||
|
{
|
||||||
|
move(0, position);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
* @author Christian Burger (christian@krikkel.de)
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <NCursesPtyWindow/PtyWindow.hpp>
|
#include <kNCurses/PtyWindow.hpp>
|
||||||
#include "Debug.hpp"
|
#include "Debug.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -13,13 +13,14 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
using gsl::narrow;
|
using gsl::narrow;
|
||||||
using std::lock_guard;
|
using std::scoped_lock;
|
||||||
|
using std::recursive_mutex;
|
||||||
|
|
||||||
PtyWindow::PtyWindow(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x)
|
PtyWindow::PtyWindow(recursive_mutex *ncursesMutex, int lines, int columns, int y, int x)
|
||||||
: writeToNCursesMutex(writeToNCursesMutex), Window(lines, columns, y, x)
|
: ncursesMutex(ncursesMutex), Window(lines, columns, y, x)
|
||||||
{
|
{
|
||||||
// to get the original terminal we need to shutdown ncurses for a moment
|
// to get the original terminal we need to shutdown ncurses for a moment
|
||||||
/// @todo maybe try `reset_prog_mode()` and `reset_shell_mode()` instead
|
/// @todo maybe try `reset_prog_mode()` and `reset_shell_mode()` instead
|
||||||
|
@ -43,9 +44,10 @@ namespace krikkel::NCursesPtyWindow
|
||||||
vterm_screen_enable_altscreen(pseudoTerminalScreen, true);
|
vterm_screen_enable_altscreen(pseudoTerminalScreen, true);
|
||||||
|
|
||||||
//raw(); // — cbreak might suffice
|
//raw(); // — cbreak might suffice
|
||||||
//noecho(); — already set
|
//noecho(); // — already set by NCursesWindow
|
||||||
//nodelay(true); — @todo needs some reprogramming
|
keypad(true); /// — already set by NCursesWindow
|
||||||
keypad(true);
|
//meta(true); // — already set by NCursesWindow
|
||||||
|
//nodelay(true); // — @todo would need some programming, not sure if useful
|
||||||
nonl();
|
nonl();
|
||||||
|
|
||||||
/// @todo block all signals, this thread does not handle any
|
/// @todo block all signals, this thread does not handle any
|
||||||
|
@ -65,21 +67,22 @@ namespace krikkel::NCursesPtyWindow
|
||||||
return fdPtyClient;
|
return fdPtyClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtyWindow::writeToClient(const char *output, size_t length)
|
void PtyWindow::writeToPtyClient(const char *output, size_t length)
|
||||||
{
|
{
|
||||||
lock_guard writeLock(writeToPseudoTerminalMutex);
|
|
||||||
write(fdPtyHost, output, length);
|
write(fdPtyHost, output, length);
|
||||||
__debug_log("written to PTY client: '" + __debug_make_bytes_printable(std::string(output, length)) + '\'');
|
//__debug_log("written to PTY client: '" + __debug_make_bytes_printable(std::string(output, length)) + '\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtyWindow::writeUnicodeCharToClient(wint_t character)
|
void PtyWindow::writeUnicodeCharToClient(wint_t character)
|
||||||
{
|
{
|
||||||
|
scoped_lock lock(ptyMutex);
|
||||||
vterm_keyboard_unichar(pseudoTerminal, character, VTERM_MOD_NONE);
|
vterm_keyboard_unichar(pseudoTerminal, character, VTERM_MOD_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtyWindow::writeKeyToClient(VTermKey key)
|
void PtyWindow::writeFunctionKeyToClient(VTermKey key)
|
||||||
{
|
{
|
||||||
__debug_log("writing key: " + std::to_string(key));
|
scoped_lock lock(ptyMutex);
|
||||||
|
//__debug_log("writing key: " + std::to_string(key));
|
||||||
vterm_keyboard_key(pseudoTerminal, key, VTERM_MOD_NONE);
|
vterm_keyboard_key(pseudoTerminal, key, VTERM_MOD_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +108,10 @@ namespace krikkel::NCursesPtyWindow
|
||||||
size_t bytesRead = read(fdPtyHost, ptyClientOutputBuffer, PTY_CLIENT_OUTPUT_BUFFER_SIZE);
|
size_t bytesRead = read(fdPtyHost, ptyClientOutputBuffer, PTY_CLIENT_OUTPUT_BUFFER_SIZE);
|
||||||
if(bytesRead != -1 && bytesRead != 0)
|
if(bytesRead != -1 && bytesRead != 0)
|
||||||
{
|
{
|
||||||
lock_guard writeLock(writeToPseudoTerminalMutex);
|
scoped_lock lock(ptyMutex, *ncursesMutex);
|
||||||
vterm_input_write(pseudoTerminal, ptyClientOutputBuffer, bytesRead);
|
vterm_input_write(pseudoTerminal, ptyClientOutputBuffer, bytesRead);
|
||||||
}
|
}
|
||||||
__debug_log("read from PTY client: '" + __debug_make_bytes_printable(std::string(ptyClientOutputBuffer, bytesRead)) + '\'');
|
//__debug_log("read from PTY client: '" + __debug_make_bytes_printable(std::string(ptyClientOutputBuffer, bytesRead)) + '\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
VTermScreenCallbacks PtyWindow::screenCallbacks =
|
VTermScreenCallbacks PtyWindow::screenCallbacks =
|
||||||
|
@ -125,6 +128,8 @@ namespace krikkel::NCursesPtyWindow
|
||||||
|
|
||||||
int PtyWindow::handlerDamage(VTermRect rect)
|
int PtyWindow::handlerDamage(VTermRect rect)
|
||||||
{
|
{
|
||||||
|
scoped_lock lock(ptyMutex, *ncursesMutex);
|
||||||
|
|
||||||
for(int x = rect.start_col; x < rect.end_col; ++x)
|
for(int x = rect.start_col; x < rect.end_col; ++x)
|
||||||
for(int y = rect.start_row; y < rect.end_row; ++y)
|
for(int y = rect.start_row; y < rect.end_row; ++y)
|
||||||
copyPtyCellToNCursesWindow(x, y);
|
copyPtyCellToNCursesWindow(x, y);
|
||||||
|
@ -153,7 +158,7 @@ namespace krikkel::NCursesPtyWindow
|
||||||
|
|
||||||
int PtyWindow::handlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible)
|
int PtyWindow::handlerMoveCursor(VTermPos pos, VTermPos oldpos, int visible)
|
||||||
{
|
{
|
||||||
/// @todo maybe use `mvcur()` instead?
|
scoped_lock lock(*ncursesMutex);
|
||||||
cursorX = pos.col;
|
cursorX = pos.col;
|
||||||
cursorY = pos.row;
|
cursorY = pos.row;
|
||||||
refresh();
|
refresh();
|
||||||
|
@ -238,9 +243,9 @@ namespace krikkel::NCursesPtyWindow
|
||||||
else
|
else
|
||||||
character = *vTermCell.chars;
|
character = *vTermCell.chars;
|
||||||
|
|
||||||
{
|
//__debug_log(std::string("written '") + (char) character + std::string("' ") + std::to_string(x) + ", " + std::to_string(y));
|
||||||
lock_guard nCursesLock(*writeToNCursesMutex);
|
|
||||||
setcchar(&converted, &character, formatting, colorPair, NULL);
|
setcchar(&converted, &character, formatting, colorPair, NULL);
|
||||||
|
{
|
||||||
move(cellPosition.row, cellPosition.col);
|
move(cellPosition.row, cellPosition.col);
|
||||||
chgat(1, formatting, colorPair, NULL);
|
chgat(1, formatting, colorPair, NULL);
|
||||||
add_wch(&converted);
|
add_wch(&converted);
|
||||||
|
@ -249,17 +254,18 @@ namespace krikkel::NCursesPtyWindow
|
||||||
|
|
||||||
int PtyWindow::refresh()
|
int PtyWindow::refresh()
|
||||||
{
|
{
|
||||||
lock_guard nCursesLock(*writeToNCursesMutex);
|
//__debug_log("refreshing");
|
||||||
|
scoped_lock lock(*ncursesMutex);
|
||||||
move(cursorY, cursorX);
|
move(cursorY, cursorX);
|
||||||
return NCursesWindow::refresh();
|
return Window::refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @todo potential racing condition where drawing into terminal while
|
/// @todo potential racing condition where drawing into terminal while
|
||||||
/// resizing?
|
/// resizing?
|
||||||
int PtyWindow::wresize(int rows, int cols)
|
int PtyWindow::resize(int rows, int cols)
|
||||||
{
|
{
|
||||||
{
|
scoped_lock lock(ptyMutex, *ncursesMutex);
|
||||||
lock_guard writeLock(writeToPseudoTerminalMutex);
|
|
||||||
winsize windowSize =
|
winsize windowSize =
|
||||||
{
|
{
|
||||||
.ws_row = narrow<unsigned short>(rows)
|
.ws_row = narrow<unsigned short>(rows)
|
||||||
|
@ -267,11 +273,8 @@ namespace krikkel::NCursesPtyWindow
|
||||||
};
|
};
|
||||||
ioctl(fdPtyHost, TIOCSWINSZ, &windowSize);
|
ioctl(fdPtyHost, TIOCSWINSZ, &windowSize);
|
||||||
vterm_set_size(pseudoTerminal, rows, cols);
|
vterm_set_size(pseudoTerminal, rows, cols);
|
||||||
}
|
|
||||||
{
|
return Window::resize(rows, cols);
|
||||||
lock_guard nCursesLock(*writeToNCursesMutex);
|
|
||||||
return NCursesWindow::wresize(rows, cols);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PtyWindow::staticHandlerDamage(VTermRect rect, void *user)
|
int PtyWindow::staticHandlerDamage(VTermRect rect, void *user)
|
||||||
|
@ -325,7 +328,6 @@ namespace krikkel::NCursesPtyWindow
|
||||||
void PtyWindow::staticHandlerOutput(const char *s, size_t len, void *user)
|
void PtyWindow::staticHandlerOutput(const char *s, size_t len, void *user)
|
||||||
{
|
{
|
||||||
PtyWindow *instance = static_cast<PtyWindow *>(user);
|
PtyWindow *instance = static_cast<PtyWindow *>(user);
|
||||||
__debug_log("output handler writing to client: '" + __debug_make_bytes_printable(std::string(s, len)) + "'");
|
instance->writeToPtyClient(s, len);
|
||||||
instance->writeToClient(s, len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
* @author Christian Burger (christian@krikkel.de)
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <NCursesPtyWindow/SingleUserInput.hpp>
|
#include <kNCurses/SingleUserInput.hpp>
|
||||||
#include "Debug.hpp"
|
#include "Debug.hpp"
|
||||||
|
|
||||||
#include <vterm.h>
|
#include <vterm.h>
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
#define KEY_ALT_BACKSPACE 127
|
#define KEY_ALT_BACKSPACE 127
|
||||||
#define KEY_ALT_ALT_BACKSPACE '\b'
|
#define KEY_ALT_ALT_BACKSPACE '\b'
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
SingleUserInput::SingleUserInput(int _resultGetWchCall, wint_t _input)
|
SingleUserInput::SingleUserInput(int _resultGetWchCall, wint_t _input)
|
||||||
: input(_input), resultGetWchCall(_resultGetWchCall)
|
: input(_input), resultGetWchCall(_resultGetWchCall)
|
||||||
|
@ -42,7 +42,7 @@ namespace krikkel::NCursesPtyWindow
|
||||||
// it is only processing user input, it is not time critical enough for
|
// it is only processing user input, it is not time critical enough for
|
||||||
// the wasted space
|
// the wasted space
|
||||||
|
|
||||||
// @tode unmapped keys: keys erase
|
// @todo unmapped keys: keys erase
|
||||||
if(resultGetWchCall == OK)
|
if(resultGetWchCall == OK)
|
||||||
switch(input)
|
switch(input)
|
||||||
{
|
{
|
||||||
|
|
145
TilingWindowManager.cpp
Normal file
145
TilingWindowManager.cpp
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
/**
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kNCurses/TilingWindowManager.hpp>
|
||||||
|
#include <kNCurses/Window.hpp>
|
||||||
|
#include "Debug.hpp"
|
||||||
|
|
||||||
|
#include <ncursesw/ncurses.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
using std::list;
|
||||||
|
using std::pair;
|
||||||
|
using std::recursive_mutex;
|
||||||
|
using std::scoped_lock;
|
||||||
|
|
||||||
|
TilingWindowManager::TilingWindowManager(NCursesWindow *rootWindow, recursive_mutex *ncursesMutex)
|
||||||
|
: Window(*rootWindow), ncursesMutex(ncursesMutex)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void TilingWindowManager::addWindow(Window *window, windowDimension size)
|
||||||
|
{
|
||||||
|
WindowStackElement stackElement(window, size);
|
||||||
|
stack.push_back(stackElement);
|
||||||
|
visibleStack.push_back(stackElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TilingWindowManager::hideWindow(Window *window)
|
||||||
|
{
|
||||||
|
if(window->hidden)
|
||||||
|
return;
|
||||||
|
|
||||||
|
visibleStack.remove_if(
|
||||||
|
[window](WindowStackElement element)
|
||||||
|
{
|
||||||
|
return element.first == window;
|
||||||
|
});
|
||||||
|
window->hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TilingWindowManager::showWindow(Window *window)
|
||||||
|
{
|
||||||
|
if(!window->hidden)
|
||||||
|
return;
|
||||||
|
|
||||||
|
list<WindowStackElement>::iterator currentVisibleWindowElement = visibleStack.begin();
|
||||||
|
for(WindowStackElement currentWindowElement : stack)
|
||||||
|
{
|
||||||
|
if(currentWindowElement.first == window)
|
||||||
|
{
|
||||||
|
visibleStack.insert(currentVisibleWindowElement, currentWindowElement);
|
||||||
|
window->hidden = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(currentWindowElement != (*currentVisibleWindowElement))
|
||||||
|
continue;
|
||||||
|
++currentVisibleWindowElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int TilingWindowManager::resize(int rows, int cols)
|
||||||
|
{
|
||||||
|
int result = Window::resize(rows, cols);
|
||||||
|
updateLayout();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TilingWindowManager::refresh()
|
||||||
|
{
|
||||||
|
scoped_lock lock(*ncursesMutex);
|
||||||
|
|
||||||
|
int result = Window::refresh();
|
||||||
|
|
||||||
|
for(WindowStackElement stackElement : visibleStack)
|
||||||
|
// @todo there are return values; compound them?
|
||||||
|
stackElement.first->refresh();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TilingWindowManager::updateLayout()
|
||||||
|
{
|
||||||
|
scoped_lock lock(*ncursesMutex);
|
||||||
|
|
||||||
|
size_t stackSize = visibleStack.size();
|
||||||
|
if(stackSize == 0)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unitSize = getRelativeUnitSizeForVisibleWindows(getAvailableSpace()) - 1;
|
||||||
|
windowPosition position = 0;
|
||||||
|
auto lastButNotLeast = prev(visibleStack.end());
|
||||||
|
for(auto stackElementIterator = visibleStack.begin()
|
||||||
|
; stackElementIterator != lastButNotLeast
|
||||||
|
; ++stackElementIterator)
|
||||||
|
{
|
||||||
|
WindowStackElement stackElement = *stackElementIterator;
|
||||||
|
Window *window = stackElement.first;
|
||||||
|
if(!window->isHidden())
|
||||||
|
{
|
||||||
|
int windowShift;
|
||||||
|
int windowSize = stackElement.second;
|
||||||
|
if(windowSize < 0)
|
||||||
|
windowShift = unitSize * (-windowSize);
|
||||||
|
else
|
||||||
|
windowShift = windowSize;
|
||||||
|
|
||||||
|
resizeAndMoveWindow(window, windowShift, position);
|
||||||
|
position += windowShift;
|
||||||
|
__debug_log("drawing line at " + std::to_string(position));
|
||||||
|
moveCursor(position++);
|
||||||
|
windowBorder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resizeAndMoveWindow((*lastButNotLeast).first, getAvailableSpace() - position, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TilingWindowManager::windowDimension TilingWindowManager::getRelativeUnitSizeForVisibleWindows(windowDimension spaceAvailable)
|
||||||
|
{
|
||||||
|
uint16_t numberOfRelativeUnits = 0;
|
||||||
|
windowDimension absoluteSum = 0;
|
||||||
|
list<WindowStackElement>::iterator windowIterator = stack.begin();
|
||||||
|
|
||||||
|
for(WindowStackElement stackElement : visibleStack)
|
||||||
|
{
|
||||||
|
windowDimension size = stackElement.second;
|
||||||
|
if(size < 0)
|
||||||
|
numberOfRelativeUnits -= size;
|
||||||
|
else
|
||||||
|
absoluteSum += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
windowDimension relativeUnitSize = (spaceAvailable - absoluteSum) / numberOfRelativeUnits;
|
||||||
|
windowDimension remainder = (spaceAvailable - absoluteSum - relativeUnitSize * numberOfRelativeUnits);
|
||||||
|
if(remainder > 0 && remainder * 2 < numberOfRelativeUnits)
|
||||||
|
++relativeUnitSize;
|
||||||
|
|
||||||
|
return relativeUnitSize;
|
||||||
|
}
|
||||||
|
}
|
41
VerticalTilingWindowManager.cpp
Normal file
41
VerticalTilingWindowManager.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Debug.hpp"
|
||||||
|
#include <kNCurses/VerticalTilingWindowManager.hpp>
|
||||||
|
#include <kNCurses/Window.hpp>
|
||||||
|
#include <ncursesw/ncurses.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
using std::recursive_mutex;
|
||||||
|
|
||||||
|
VerticalTilingWindowManager::VerticalTilingWindowManager(NCursesWindow *rootWindow, std::recursive_mutex *ncursesMutex)
|
||||||
|
: TilingWindowManager(rootWindow, ncursesMutex)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void VerticalTilingWindowManager::resizeAndMoveWindow(Window *window, windowDimension dimension, windowPosition position)
|
||||||
|
{
|
||||||
|
__debug_log("(" + std::to_string(0 + begx()) + ", " + std::to_string(position + begy()) + ", " + std::to_string(width()) + ", " + std::to_string(dimension) + ")");
|
||||||
|
window->resize(dimension, width());
|
||||||
|
window->mvwin(position + begy(), 0 + begx());
|
||||||
|
}
|
||||||
|
|
||||||
|
TilingWindowManager::windowDimension VerticalTilingWindowManager::getAvailableSpace()
|
||||||
|
{
|
||||||
|
return height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerticalTilingWindowManager::windowBorder()
|
||||||
|
{
|
||||||
|
hline(width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerticalTilingWindowManager::moveCursor(TilingWindowManager::windowPosition position)
|
||||||
|
{
|
||||||
|
move(position, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
Window.cpp
35
Window.cpp
|
@ -2,10 +2,25 @@
|
||||||
* @author Christian Burger (christian@krikkel.de)
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <NCursesPtyWindow/Window.hpp>
|
#include <kNCurses/Window.hpp>
|
||||||
|
#include <kNCurses/VerticalTilingWindowManager.hpp>
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
|
Window::Window() : NCursesWindow(0, 0, 0, 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Window::Window(TilingWindowManager *windowManager)
|
||||||
|
: NCursesWindow(0, 0, 0, 0)
|
||||||
|
{
|
||||||
|
windowManager->addWindow(this);
|
||||||
|
windowManager->updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::Window(const NCursesWindow &window)
|
||||||
|
: NCursesWindow(window)
|
||||||
|
{}
|
||||||
|
|
||||||
Window::Window(int lines, int columns, int y, int x)
|
Window::Window(int lines, int columns, int y, int x)
|
||||||
: NCursesWindow(lines, columns, y, x)
|
: NCursesWindow(lines, columns, y, x)
|
||||||
{}
|
{}
|
||||||
|
@ -30,6 +45,11 @@ namespace krikkel::NCursesPtyWindow
|
||||||
return ::wget_wch(w, character);
|
return ::wget_wch(w, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Window::isHidden()
|
||||||
|
{
|
||||||
|
return hidden;
|
||||||
|
}
|
||||||
|
|
||||||
SingleUserInput Window::readSingleUserInput()
|
SingleUserInput Window::readSingleUserInput()
|
||||||
{
|
{
|
||||||
wint_t input;
|
wint_t input;
|
||||||
|
@ -37,4 +57,15 @@ namespace krikkel::NCursesPtyWindow
|
||||||
return SingleUserInput(result, input);
|
return SingleUserInput(result, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Window::resize(int rows, int cols)
|
||||||
|
{
|
||||||
|
return NCursesWindow::wresize(rows, cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Window::refresh()
|
||||||
|
{
|
||||||
|
if(!hidden)
|
||||||
|
return NCursesWindow::refresh();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
31
include/kNCurses/HorizontalTilingWindowManager.hpp
Normal file
31
include/kNCurses/HorizontalTilingWindowManager.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
* @brief Window manager
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef B7BCF793_2FAB_49CC_9E00_CDEA370D38F9
|
||||||
|
#define B7BCF793_2FAB_49CC_9E00_CDEA370D38F9
|
||||||
|
|
||||||
|
#include "TilingWindowManager.hpp"
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
class Window;
|
||||||
|
class SingleUserInput;
|
||||||
|
|
||||||
|
class HorizontalTilingWindowManager : public TilingWindowManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HorizontalTilingWindowManager(NCursesWindow *rootWindow, std::recursive_mutex *ncursesMutex);
|
||||||
|
|
||||||
|
void resizeAndMoveWindow(Window *window
|
||||||
|
, windowDimension dimension
|
||||||
|
, windowPosition position) override;
|
||||||
|
windowDimension getAvailableSpace() override;
|
||||||
|
void windowBorder() override;
|
||||||
|
void moveCursor(windowPosition position) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* B7BCF793_2FAB_49CC_9E00_CDEA370D38F9 */
|
|
@ -1,12 +1,12 @@
|
||||||
/**
|
/**
|
||||||
* @brief `ncurses` window displaying contents of a pseudo terminal
|
* @brief `ncurses` window displaying contents of a pseudo terminal
|
||||||
* @author Christian Burger (christian@krikkel.de)
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
* @todo remove all invalid constructors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __WINDOW_H__
|
#ifndef __WINDOW_H__
|
||||||
#define __WINDOW_H__
|
#define __WINDOW_H__
|
||||||
|
|
||||||
#include "SingleUserInput.hpp"
|
|
||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
|
|
||||||
#include <cursesw.h>
|
#include <cursesw.h>
|
||||||
|
@ -16,28 +16,27 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
class PtyWindow : public Window
|
class PtyWindow : public Window
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PtyWindow(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x);
|
PtyWindow(std::recursive_mutex *ncursesMutex, int lines, int columns, int y, int x);
|
||||||
~PtyWindow();
|
~PtyWindow();
|
||||||
|
|
||||||
int getFdPtyClient() const;
|
int getFdPtyClient() const;
|
||||||
void writeToClient(const char * string, size_t length);
|
|
||||||
void writeUnicodeCharToClient(wint_t character);
|
void writeUnicodeCharToClient(wint_t character);
|
||||||
void writeKeyToClient(VTermKey key);
|
void writeFunctionKeyToClient(VTermKey key);
|
||||||
|
|
||||||
int refresh() override;
|
int refresh() override;
|
||||||
int wresize(int rows, int cols);
|
int resize(int rows, int cols) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fdPtyHost, fdPtyClient;
|
int fdPtyHost, fdPtyClient;
|
||||||
struct termios terminalParameters;
|
struct termios terminalParameters;
|
||||||
VTerm *pseudoTerminal;
|
VTerm *pseudoTerminal;
|
||||||
std::mutex writeToPseudoTerminalMutex;
|
std::recursive_mutex ptyMutex;
|
||||||
std::mutex *writeToNCursesMutex;
|
std::recursive_mutex *ncursesMutex;
|
||||||
VTermScreen *pseudoTerminalScreen;
|
VTermScreen *pseudoTerminalScreen;
|
||||||
static VTermScreenCallbacks screenCallbacks;
|
static VTermScreenCallbacks screenCallbacks;
|
||||||
/// @todo one line is at most 4096 chars long
|
/// @todo one line is at most 4096 chars long
|
||||||
|
@ -48,6 +47,7 @@ namespace krikkel::NCursesPtyWindow
|
||||||
std::thread readPtyClientThread;
|
std::thread readPtyClientThread;
|
||||||
void readFromPtyClientThreadMethod();
|
void readFromPtyClientThreadMethod();
|
||||||
void readFromPtyClient();
|
void readFromPtyClient();
|
||||||
|
void writeToPtyClient(const char * string, size_t length);
|
||||||
|
|
||||||
int handlerDamage(VTermRect rect);
|
int handlerDamage(VTermRect rect);
|
||||||
int handlerMoveRect(VTermRect dest, VTermRect src);
|
int handlerMoveRect(VTermRect dest, VTermRect src);
|
|
@ -9,7 +9,7 @@
|
||||||
#include <cursesw.h>
|
#include <cursesw.h>
|
||||||
#include <vterm_keycodes.h>
|
#include <vterm_keycodes.h>
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
class SingleUserInput
|
class SingleUserInput
|
||||||
{
|
{
|
61
include/kNCurses/TilingWindowManager.hpp
Normal file
61
include/kNCurses/TilingWindowManager.hpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/**
|
||||||
|
* @brief Window manager for tiling (template pattern, abstract parent)
|
||||||
|
*
|
||||||
|
* A window manager contains windows of a given size, lays them out and can hide
|
||||||
|
* or show them. There is no concrete window manager for tiling horizontally and
|
||||||
|
* vertically at the same time. Instead nesting the window managers is adviced,
|
||||||
|
* since the window manager classes are derived from windows in the end.
|
||||||
|
*
|
||||||
|
* This is an abstract class used by the concrete classes
|
||||||
|
* `VerticalTilingWindowManager` and `HorizontalTilingWindowManager`. Both
|
||||||
|
* specify the virtual and protected, declared but undefined methods used by the
|
||||||
|
* public interface to facilitate the function depending on the orientation
|
||||||
|
* (horizontally or vertically).
|
||||||
|
*
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C51BA18F_0915_43B9_BD5D_129F0CDBC1CD
|
||||||
|
#define C51BA18F_0915_43B9_BD5D_129F0CDBC1CD
|
||||||
|
|
||||||
|
#include "Window.hpp"
|
||||||
|
#include <list>
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
class SingleUserInput;
|
||||||
|
|
||||||
|
class TilingWindowManager : public Window
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// @todo figure out more appropiate names …
|
||||||
|
typedef int16_t windowDimension;
|
||||||
|
typedef uint16_t windowPosition;
|
||||||
|
typedef std::pair<Window *, windowDimension> WindowStackElement;
|
||||||
|
|
||||||
|
TilingWindowManager(NCursesWindow *rootWindow, std::recursive_mutex *ncursesMutex);
|
||||||
|
void addWindow(Window *window, windowDimension size = -1);
|
||||||
|
int resize(int rows, int cols) override;
|
||||||
|
int refresh() override;
|
||||||
|
void updateLayout();
|
||||||
|
|
||||||
|
void hideWindow(Window *window);
|
||||||
|
void showWindow(Window *window);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::recursive_mutex *ncursesMutex;
|
||||||
|
std::list<WindowStackElement> stack, visibleStack;
|
||||||
|
|
||||||
|
windowDimension getRelativeUnitSizeForVisibleWindows(windowDimension spaceAvailable);
|
||||||
|
virtual void resizeAndMoveWindow(Window *window
|
||||||
|
, windowDimension dimension
|
||||||
|
, windowPosition position) = 0;
|
||||||
|
virtual void windowBorder() = 0;
|
||||||
|
virtual windowDimension getAvailableSpace() = 0;
|
||||||
|
virtual void moveCursor(windowPosition position) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* C51BA18F_0915_43B9_BD5D_129F0CDBC1CD */
|
31
include/kNCurses/VerticalTilingWindowManager.hpp
Normal file
31
include/kNCurses/VerticalTilingWindowManager.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
* @brief Window manager
|
||||||
|
* @author Christian Burger (christian@krikkel.de)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C10F5DF3_1DB4_4714_A84D_115F492F5CDC
|
||||||
|
#define C10F5DF3_1DB4_4714_A84D_115F492F5CDC
|
||||||
|
|
||||||
|
#include "TilingWindowManager.hpp"
|
||||||
|
|
||||||
|
namespace krikkel::NCurses
|
||||||
|
{
|
||||||
|
class Window;
|
||||||
|
class SingleUserInput;
|
||||||
|
|
||||||
|
class VerticalTilingWindowManager : public TilingWindowManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VerticalTilingWindowManager(NCursesWindow *rootWindow, std::recursive_mutex *ncursesMutex);
|
||||||
|
|
||||||
|
void resizeAndMoveWindow(Window *window
|
||||||
|
, windowDimension dimension
|
||||||
|
, windowPosition position) override;
|
||||||
|
windowDimension getAvailableSpace() override;
|
||||||
|
void windowBorder() override;
|
||||||
|
void moveCursor(windowPosition position) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* C10F5DF3_1DB4_4714_A84D_115F492F5CDC */
|
|
@ -34,18 +34,31 @@ inline int UNDEF(get_wch)(wint_t *character) { get_wch(character); }
|
||||||
#define get_wch UNDEF(get_wch)
|
#define get_wch UNDEF(get_wch)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace krikkel::NCursesPtyWindow
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
|
class TilingWindowManager;
|
||||||
|
|
||||||
class Window : public NCursesWindow
|
class Window : public NCursesWindow
|
||||||
{
|
{
|
||||||
|
friend class TilingWindowManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Window();
|
||||||
|
Window(TilingWindowManager *windowManager);
|
||||||
|
Window(const NCursesWindow &window);
|
||||||
Window(int lines, int columns, int y, int x);
|
Window(int lines, int columns, int y, int x);
|
||||||
int addnwstr(const wchar_t *wstr, int n);
|
int addnwstr(const wchar_t *wstr, int n);
|
||||||
int add_wch(const cchar_t *character);
|
int add_wch(const cchar_t *character);
|
||||||
int ins_wch(const cchar_t *character);
|
int ins_wch(const cchar_t *character);
|
||||||
int get_wch(wint_t *character);
|
int get_wch(wint_t *character);
|
||||||
|
|
||||||
|
bool isHidden();
|
||||||
SingleUserInput readSingleUserInput();
|
SingleUserInput readSingleUserInput();
|
||||||
|
virtual int resize(int rows, int cols);
|
||||||
|
virtual int refresh() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool hidden = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue