added simple vertical tiling window manager

This commit is contained in:
Christian Burger 2022-05-03 11:23:32 +02:00
parent f8db9dc660
commit 0462a68c54
9 changed files with 140 additions and 20 deletions

View file

@ -53,7 +53,8 @@
"iostream": "cpp", "iostream": "cpp",
"stdexcept": "cpp", "stdexcept": "cpp",
"typeinfo": "cpp", "typeinfo": "cpp",
"pointers": "cpp" "pointers": "cpp",
"list": "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": [

16
App.cpp
View file

@ -4,6 +4,8 @@
#include "App.hpp" #include "App.hpp"
#include "Debug.hpp" #include "Debug.hpp"
#include <NCurses/VerticalTilingWindowManager.hpp>
#include <NCurses/Window.hpp>
#include <NCurses/PtyWindow.hpp> #include <NCurses/PtyWindow.hpp>
#include <unistd.h> #include <unistd.h>
@ -20,13 +22,15 @@ namespace krikkel::NCurses
int DemoApp::run() int DemoApp::run()
{ {
std::mutex writeMutex; std::mutex ncursesMutex;
VerticalTilingWindowManager windowManager(Root_Window, &ncursesMutex);
PtyWindow *ptyWindow = new PtyWindow(&writeMutex new Window(&windowManager);
, Root_Window->lines() PtyWindow *ptyWindow = new PtyWindow(&ncursesMutex, 0, 0, 0, 0);
, Root_Window->cols() windowManager.addWindow(ptyWindow);
, 0 new Window(&windowManager);
, 0); windowManager.updateLayout();
windowManager.refresh();
if(fork() == 0) if(fork() == 0)
{ {

View file

@ -13,7 +13,7 @@ set(CMAKE_CXX_STANDARD 17)
include(CTest) include(CTest)
enable_testing() 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 ### path to own system includes
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/include") include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/include")
@ -44,7 +44,7 @@ target_link_libraries(NCursesDemoApp NCurses)
### installation and packaging ### installation and packaging
set(NCURSES_SYSTEM_INCLUDE "include/NCurses") 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}") VERSION "${CMAKE_PROJECT_VERSION}")
include(GNUInstallDirs) include(GNUInstallDirs)
install(TARGETS NCurses ARCHIVE install(TARGETS NCurses ARCHIVE

View file

@ -18,8 +18,8 @@ namespace krikkel::NCurses
using gsl::narrow; using gsl::narrow;
using std::lock_guard; using std::lock_guard;
PtyWindow::PtyWindow(std::mutex *writeToNCursesMutex, int lines, int columns, int y, int x) PtyWindow::PtyWindow(std::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
@ -239,7 +239,7 @@ namespace krikkel::NCurses
character = *vTermCell.chars; character = *vTermCell.chars;
{ {
lock_guard nCursesLock(*writeToNCursesMutex); lock_guard nCursesLock(*ncursesMutex);
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);
@ -249,14 +249,14 @@ namespace krikkel::NCurses
int PtyWindow::refresh() int PtyWindow::refresh()
{ {
lock_guard nCursesLock(*writeToNCursesMutex); lock_guard nCursesLock(*ncursesMutex);
move(cursorY, cursorX); move(cursorY, cursorX);
return NCursesWindow::refresh(); return NCursesWindow::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)
{ {
{ {
lock_guard writeLock(writeToPseudoTerminalMutex); lock_guard writeLock(writeToPseudoTerminalMutex);
@ -269,8 +269,8 @@ namespace krikkel::NCurses
vterm_set_size(pseudoTerminal, rows, cols); vterm_set_size(pseudoTerminal, rows, cols);
} }
{ {
lock_guard nCursesLock(*writeToNCursesMutex); lock_guard nCursesLock(*ncursesMutex);
return NCursesWindow::wresize(rows, cols); return Window::wresize(rows, cols);
} }
} }

View file

@ -0,0 +1,63 @@
/**
* @author Christian Burger (christian@krikkel.de)
*/
#include <NCurses/VerticalTilingWindowManager.hpp>
#include <NCurses/Window.hpp>
#include <ncursesw/ncurses.h>
#include <algorithm>
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<Window *>::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);
}
}

View file

@ -3,9 +3,17 @@
*/ */
#include <NCurses/Window.hpp> #include <NCurses/Window.hpp>
#include <NCurses/VerticalTilingWindowManager.hpp>
namespace krikkel::NCurses 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) Window::Window(int lines, int columns, int y, int x)
: NCursesWindow(lines, columns, y, x) : NCursesWindow(lines, columns, y, x)
{} {}
@ -37,4 +45,9 @@ namespace krikkel::NCurses
return SingleUserInput(result, input); return SingleUserInput(result, input);
} }
int Window::resize(int rows, int cols)
{
return NCursesWindow::wresize(rows, cols);
}
} }

View file

@ -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>
@ -21,7 +21,7 @@ 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::mutex *ncursesMutex, int lines, int columns, int y, int x);
~PtyWindow(); ~PtyWindow();
int getFdPtyClient() const; int getFdPtyClient() const;
@ -30,14 +30,14 @@ namespace krikkel::NCurses
void writeKeyToClient(VTermKey key); void writeKeyToClient(VTermKey key);
int refresh() override; int refresh() override;
int wresize(int rows, int cols); virtual 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::mutex writeToPseudoTerminalMutex;
std::mutex *writeToNCursesMutex; std::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

View file

@ -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 <ncursesw/cursesw.h>
#include <list>
#include <mutex>
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<Window *> stack;
void resizeWindowInStack(Window *window, uint16_t y, uint16_t height, uint16_t width);
};
}
#endif /* C10F5DF3_1DB4_4714_A84D_115F492F5CDC */

View file

@ -36,9 +36,12 @@ inline int UNDEF(get_wch)(wint_t *character) { get_wch(character); }
namespace krikkel::NCurses namespace krikkel::NCurses
{ {
class VerticalTilingWindowManager;
class Window : public NCursesWindow class Window : public NCursesWindow
{ {
public: public:
Window(VerticalTilingWindowManager *windowManager);
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);
@ -46,6 +49,7 @@ namespace krikkel::NCurses
int get_wch(wint_t *character); int get_wch(wint_t *character);
SingleUserInput readSingleUserInput(); SingleUserInput readSingleUserInput();
virtual int resize(int rows, int cols);
}; };
} }