diff --git a/.vscode/settings.json b/.vscode/settings.json index a6e43ad..0109953 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -53,7 +53,8 @@ "iostream": "cpp", "stdexcept": "cpp", "typeinfo": "cpp", - "pointers": "cpp" + "pointers": "cpp", + "list": "cpp" }, "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "C_Cpp.default.includePath": [ diff --git a/App.cpp b/App.cpp index e3d2e8b..d2d14bd 100644 --- a/App.cpp +++ b/App.cpp @@ -4,6 +4,8 @@ #include "App.hpp" #include "Debug.hpp" +#include +#include #include #include @@ -20,13 +22,15 @@ namespace krikkel::NCurses int DemoApp::run() { - std::mutex writeMutex; + std::mutex ncursesMutex; + VerticalTilingWindowManager windowManager(Root_Window, &ncursesMutex); - PtyWindow *ptyWindow = new PtyWindow(&writeMutex - , Root_Window->lines() - , Root_Window->cols() - , 0 - , 0); + new Window(&windowManager); + PtyWindow *ptyWindow = new PtyWindow(&ncursesMutex, 0, 0, 0, 0); + windowManager.addWindow(ptyWindow); + new Window(&windowManager); + windowManager.updateLayout(); + windowManager.refresh(); if(fork() == 0) { diff --git a/CMakeLists.txt b/CMakeLists.txt index 4be58ad..d6b353c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ set(CMAKE_CXX_STANDARD 17) include(CTest) enable_testing() -add_library(NCurses Window.cpp PtyWindow.cpp SingleUserInput.cpp Debug.cpp) +add_library(NCurses Window.cpp PtyWindow.cpp SingleUserInput.cpp Debug.cpp VerticalTilingWindowManager.cpp) ### path to own system includes include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/include") @@ -44,7 +44,7 @@ target_link_libraries(NCursesDemoApp NCurses) ### installation and packaging set(NCURSES_SYSTEM_INCLUDE "include/NCurses") -set_target_properties(NCurses PROPERTIES PUBLIC_HEADER "${NCURSES_SYSTEM_INCLUDE}/Window.hpp;${NCURSES_SYSTEM_INCLUDE}/SingleUserInput.hpp;${NCURSES_SYSTEM_INCLUDE}/PtyWindow.hpp" +set_target_properties(NCurses PROPERTIES PUBLIC_HEADER "${NCURSES_SYSTEM_INCLUDE}/Window.hpp;${NCURSES_SYSTEM_INCLUDE}/SingleUserInput.hpp;${NCURSES_SYSTEM_INCLUDE}/PtyWindow.hpp;${NCURSES_SYSTEM_INCLUDE}/VerticalTilingWindowManager.hpp;" VERSION "${CMAKE_PROJECT_VERSION}") include(GNUInstallDirs) install(TARGETS NCurses ARCHIVE diff --git a/PtyWindow.cpp b/PtyWindow.cpp index 53cbe3b..96095a4 100644 --- a/PtyWindow.cpp +++ b/PtyWindow.cpp @@ -18,8 +18,8 @@ namespace krikkel::NCurses 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) + PtyWindow::PtyWindow(std::mutex *ncursesMutex, int lines, int columns, int y, int x) + : ncursesMutex(ncursesMutex), 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 @@ -239,7 +239,7 @@ namespace krikkel::NCurses character = *vTermCell.chars; { - lock_guard nCursesLock(*writeToNCursesMutex); + lock_guard nCursesLock(*ncursesMutex); setcchar(&converted, &character, formatting, colorPair, NULL); move(cellPosition.row, cellPosition.col); chgat(1, formatting, colorPair, NULL); @@ -249,14 +249,14 @@ namespace krikkel::NCurses int PtyWindow::refresh() { - lock_guard nCursesLock(*writeToNCursesMutex); + lock_guard nCursesLock(*ncursesMutex); move(cursorY, cursorX); return NCursesWindow::refresh(); } /// @todo potential racing condition where drawing into terminal while /// resizing? - int PtyWindow::wresize(int rows, int cols) + int PtyWindow::resize(int rows, int cols) { { lock_guard writeLock(writeToPseudoTerminalMutex); @@ -269,8 +269,8 @@ namespace krikkel::NCurses vterm_set_size(pseudoTerminal, rows, cols); } { - lock_guard nCursesLock(*writeToNCursesMutex); - return NCursesWindow::wresize(rows, cols); + lock_guard nCursesLock(*ncursesMutex); + return Window::wresize(rows, cols); } } diff --git a/VerticalTilingWindowManager.cpp b/VerticalTilingWindowManager.cpp new file mode 100644 index 0000000..ccd9878 --- /dev/null +++ b/VerticalTilingWindowManager.cpp @@ -0,0 +1,63 @@ +/** + * @author Christian Burger (christian@krikkel.de) + */ + +#include +#include +#include +#include + +namespace krikkel::NCurses +{ + using std::list; + using std::mutex; + using std::lock_guard; + using std::find; + + VerticalTilingWindowManager::VerticalTilingWindowManager(NCursesWindow *rootWindow, mutex *ncursesMutex) + : rootWindow(rootWindow), ncursesMutex(ncursesMutex) + {} + + void VerticalTilingWindowManager::addWindow(Window *window) + { + stack.push_back(window); + } + + void VerticalTilingWindowManager::refresh() + { + rootWindow->refresh(); + for(Window *window : stack) + window->refresh(); + } + + void VerticalTilingWindowManager::updateLayout() + { + int availableWidth = rootWindow->width(); + int availableHeight = rootWindow->height(); + int windowHeight = availableHeight / stack.size() - 1; + if((windowHeight + 1) * stack.size() < availableHeight) + ++windowHeight; + + list::iterator it = stack.begin(); + uint16_t y = 0; + for(size_t index = 0 + ; index < stack.size() - 1 + ; ++index) + { + resizeWindowInStack(*it++, y, windowHeight, availableWidth); + y += windowHeight; + { + lock_guard lock(*ncursesMutex); + rootWindow->move(y++, 0); + rootWindow->hline(availableWidth); + } + } + resizeWindowInStack(*it, y, availableHeight - y, availableWidth); + } + + void VerticalTilingWindowManager::resizeWindowInStack(Window *window, uint16_t y, uint16_t height, uint16_t width) + { + window->resize(height, width); + window->mvwin(y, 0); + } +} \ No newline at end of file diff --git a/Window.cpp b/Window.cpp index b2fe52b..4629571 100644 --- a/Window.cpp +++ b/Window.cpp @@ -3,9 +3,17 @@ */ #include +#include namespace krikkel::NCurses { + Window::Window(VerticalTilingWindowManager *windowManager) + : NCursesWindow(0, 0, 0, 0) + { + windowManager->addWindow(this); + windowManager->updateLayout(); + } + Window::Window(int lines, int columns, int y, int x) : NCursesWindow(lines, columns, y, x) {} @@ -37,4 +45,9 @@ namespace krikkel::NCurses return SingleUserInput(result, input); } + int Window::resize(int rows, int cols) + { + return NCursesWindow::wresize(rows, cols); + } + } \ No newline at end of file diff --git a/include/NCurses/PtyWindow.hpp b/include/NCurses/PtyWindow.hpp index d54f934..4c0456b 100644 --- a/include/NCurses/PtyWindow.hpp +++ b/include/NCurses/PtyWindow.hpp @@ -1,12 +1,12 @@ /** * @brief `ncurses` window displaying contents of a pseudo terminal * @author Christian Burger (christian@krikkel.de) + * @todo remove all invalid constructors */ #ifndef __WINDOW_H__ #define __WINDOW_H__ -#include "SingleUserInput.hpp" #include "Window.hpp" #include @@ -21,7 +21,7 @@ namespace krikkel::NCurses class PtyWindow : public Window { public: - PtyWindow(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x); + PtyWindow(std::mutex *ncursesMutex, int lines, int columns, int y, int x); ~PtyWindow(); int getFdPtyClient() const; @@ -30,14 +30,14 @@ namespace krikkel::NCurses void writeKeyToClient(VTermKey key); int refresh() override; - int wresize(int rows, int cols); + virtual int resize(int rows, int cols) override; private: int fdPtyHost, fdPtyClient; struct termios terminalParameters; VTerm *pseudoTerminal; std::mutex writeToPseudoTerminalMutex; - std::mutex *writeToNCursesMutex; + std::mutex *ncursesMutex; VTermScreen *pseudoTerminalScreen; static VTermScreenCallbacks screenCallbacks; /// @todo one line is at most 4096 chars long diff --git a/include/NCurses/VerticalTilingWindowManager.hpp b/include/NCurses/VerticalTilingWindowManager.hpp new file mode 100644 index 0000000..3171dd5 --- /dev/null +++ b/include/NCurses/VerticalTilingWindowManager.hpp @@ -0,0 +1,35 @@ +/** + * @brief Window manager + * @author Christian Burger (christian@krikkel.de) + */ + +#ifndef C10F5DF3_1DB4_4714_A84D_115F492F5CDC +#define C10F5DF3_1DB4_4714_A84D_115F492F5CDC + +#include +#include +#include + +namespace krikkel::NCurses +{ + class Window; + + class VerticalTilingWindowManager + { + public: + VerticalTilingWindowManager(NCursesWindow *rootWindow, std::mutex *ncursesMutex); + void addWindow(Window *window); + void refresh(); + void updateLayout(); + + private: + NCursesWindow *rootWindow; + std::mutex *ncursesMutex; + std::list stack; + + void resizeWindowInStack(Window *window, uint16_t y, uint16_t height, uint16_t width); + }; +} + + +#endif /* C10F5DF3_1DB4_4714_A84D_115F492F5CDC */ diff --git a/include/NCurses/Window.hpp b/include/NCurses/Window.hpp index 6e6b2fb..73b383d 100644 --- a/include/NCurses/Window.hpp +++ b/include/NCurses/Window.hpp @@ -36,9 +36,12 @@ inline int UNDEF(get_wch)(wint_t *character) { get_wch(character); } namespace krikkel::NCurses { + class VerticalTilingWindowManager; + class Window : public NCursesWindow { public: + Window(VerticalTilingWindowManager *windowManager); Window(int lines, int columns, int y, int x); int addnwstr(const wchar_t *wstr, int n); int add_wch(const cchar_t *character); @@ -46,6 +49,7 @@ namespace krikkel::NCurses int get_wch(wint_t *character); SingleUserInput readSingleUserInput(); + virtual int resize(int rows, int cols); }; }