hide and show windows in window manager

* switching to recursive mutexes for now; easier to implement
* need to read user input from the window manager; hidden windows are
drawn when reading input from there
* note: occasional dead lock between PTY and ncurses mutex
* fixed type in class `SingleUserInput`
master
Christian Burger 2022-05-06 14:02:18 +02:00
parent 0462a68c54
commit b9e32941fb
9 changed files with 134 additions and 37 deletions

View File

@ -54,7 +54,9 @@
"stdexcept": "cpp",
"typeinfo": "cpp",
"pointers": "cpp",
"list": "cpp"
"list": "cpp",
"condition_variable": "cpp",
"mutex": "cpp"
},
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"C_Cpp.default.includePath": [

47
App.cpp
View File

@ -22,10 +22,11 @@ namespace krikkel::NCurses
int DemoApp::run()
{
std::mutex ncursesMutex;
std::recursive_mutex ncursesMutex;
VerticalTilingWindowManager windowManager(Root_Window, &ncursesMutex);
new Window(&windowManager);
Window *dummyWindow = new Window(&windowManager);
dummyWindow->move(0, 0);
PtyWindow *ptyWindow = new PtyWindow(&ncursesMutex, 0, 0, 0, 0);
windowManager.addWindow(ptyWindow);
new Window(&windowManager);
@ -51,15 +52,47 @@ namespace krikkel::NCurses
while(true)
{
SingleUserInput input = ptyWindow->readSingleUserInput();
SingleUserInput input = windowManager.readSingleUserInput();
if(input.isNormalKey())
{
std::lock_guard lock(ncursesMutex);
ptyWindow->writeUnicodeCharToClient(input.getRawInput());
dummyWindow->addch(input.getRawInput());
dummyWindow->refresh();
}
if(input.isFunctionKey())
{
if(input.getRawInput() == KEY_RESIZE)
ptyWindow->wresize(Root_Window->lines(), Root_Window->cols());
else
ptyWindow->writeKeyToClient(input.mapKeyNcursesToVTerm());
switch(input.getRawInput())
{
case KEY_RESIZE:
windowManager.updateLayout();
break;
case KEY_F(1):
windowManager.hideWindow(ptyWindow);
windowManager.updateLayout();
windowManager.refresh();
break;
case KEY_F(2):
windowManager.showWindow(ptyWindow);
windowManager.updateLayout();
windowManager.refresh();
break;
case KEY_F(3):
windowManager.hideWindow(dummyWindow);
windowManager.updateLayout();
windowManager.refresh();
break;
case KEY_F(4):
windowManager.showWindow(dummyWindow);
windowManager.updateLayout();
windowManager.refresh();
break;
case KEY_F(5):
windowManager.refresh();
break;
default:
ptyWindow->writeKeyToClient(input.mapKeyNcursesToVTerm());
}
}
}

View File

@ -17,8 +17,9 @@ namespace krikkel::NCurses
{
using gsl::narrow;
using std::lock_guard;
using std::recursive_mutex;
PtyWindow::PtyWindow(std::mutex *ncursesMutex, int lines, int columns, int y, int x)
PtyWindow::PtyWindow(recursive_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
@ -67,19 +68,21 @@ namespace krikkel::NCurses
void PtyWindow::writeToClient(const char *output, size_t length)
{
lock_guard writeLock(writeToPseudoTerminalMutex);
lock_guard lock(writeToPseudoTerminalMutex);
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)
{
lock_guard lock(writeToPseudoTerminalMutex);
vterm_keyboard_unichar(pseudoTerminal, character, VTERM_MOD_NONE);
}
void PtyWindow::writeKeyToClient(VTermKey key)
{
__debug_log("writing key: " + std::to_string(key));
lock_guard lock(writeToPseudoTerminalMutex);
//__debug_log("writing key: " + std::to_string(key));
vterm_keyboard_key(pseudoTerminal, key, VTERM_MOD_NONE);
}
@ -108,7 +111,7 @@ namespace krikkel::NCurses
lock_guard writeLock(writeToPseudoTerminalMutex);
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 =
@ -238,9 +241,10 @@ namespace krikkel::NCurses
else
character = *vTermCell.chars;
//__debug_log(std::string("written '") + (char) character + std::string("' ") + std::to_string(x) + ", " + std::to_string(y));
setcchar(&converted, &character, formatting, colorPair, NULL);
{
lock_guard nCursesLock(*ncursesMutex);
setcchar(&converted, &character, formatting, colorPair, NULL);
lock_guard lock(*ncursesMutex);
move(cellPosition.row, cellPosition.col);
chgat(1, formatting, colorPair, NULL);
add_wch(&converted);
@ -249,9 +253,10 @@ namespace krikkel::NCurses
int PtyWindow::refresh()
{
lock_guard nCursesLock(*ncursesMutex);
//__debug_log("refreshing");
lock_guard lock(*ncursesMutex);
move(cursorY, cursorX);
return NCursesWindow::refresh();
return Window::refresh();
}
/// @todo potential racing condition where drawing into terminal while
@ -269,8 +274,8 @@ namespace krikkel::NCurses
vterm_set_size(pseudoTerminal, rows, cols);
}
{
lock_guard nCursesLock(*ncursesMutex);
return Window::wresize(rows, cols);
lock_guard lock(*ncursesMutex);
return Window::resize(rows, cols);
}
}
@ -325,7 +330,6 @@ namespace krikkel::NCurses
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

@ -42,7 +42,7 @@ namespace krikkel::NCurses
// it is only processing user input, it is not time critical enough for
// the wasted space
// @tode unmapped keys: keys erase
// @todo unmapped keys: keys erase
if(resultGetWchCall == OK)
switch(input)
{

View File

@ -10,44 +10,80 @@
namespace krikkel::NCurses
{
using std::list;
using std::mutex;
using std::recursive_mutex;
using std::lock_guard;
using std::find;
VerticalTilingWindowManager::VerticalTilingWindowManager(NCursesWindow *rootWindow, mutex *ncursesMutex)
: rootWindow(rootWindow), ncursesMutex(ncursesMutex)
VerticalTilingWindowManager::VerticalTilingWindowManager(NCursesWindow *rootWindow, recursive_mutex *ncursesMutex)
: rootWindow(new Window(*rootWindow)), ncursesMutex(ncursesMutex)
{}
void VerticalTilingWindowManager::addWindow(Window *window)
{
stack.push_back(window);
visibleStack.push_back(window);
}
void VerticalTilingWindowManager::hideWindow(Window *window)
{
visibleStack.remove(window);
window->hidden = true;
}
void VerticalTilingWindowManager::showWindow(Window *window)
{
if(!window->hidden)
return;
list<Window *>::iterator currentVisibleWindow = visibleStack.begin();
for(Window *currentWindow : stack)
{
if(currentWindow == window)
{
visibleStack.insert(currentVisibleWindow, window);
window->hidden = false;
break;
}
if(currentWindow != (*currentVisibleWindow))
continue;
++currentVisibleWindow;
}
}
void VerticalTilingWindowManager::refresh()
{
lock_guard lock(*ncursesMutex);
rootWindow->refresh();
for(Window *window : stack)
for(Window *window : visibleStack)
window->refresh();
}
SingleUserInput VerticalTilingWindowManager::readSingleUserInput()
{
return rootWindow->readSingleUserInput();
}
void VerticalTilingWindowManager::updateLayout()
{
lock_guard lock(*ncursesMutex);
int availableWidth = rootWindow->width();
int availableHeight = rootWindow->height();
int windowHeight = availableHeight / stack.size() - 1;
if((windowHeight + 1) * stack.size() < availableHeight)
size_t stackSize = visibleStack.size();
int windowHeight = availableHeight / stackSize - 1;
if((windowHeight + 1) * stackSize < availableHeight)
++windowHeight;
list<Window *>::iterator it = stack.begin();
uint16_t y = 0;
list<Window *>::iterator it = visibleStack.begin();
for(size_t index = 0
; index < stack.size() - 1
; index < visibleStack.size() - 1
; ++index)
{
resizeWindowInStack(*it++, y, windowHeight, availableWidth);
y += windowHeight;
{
lock_guard lock(*ncursesMutex);
rootWindow->move(y++, 0);
rootWindow->hline(availableWidth);
}

View File

@ -14,6 +14,10 @@ namespace krikkel::NCurses
windowManager->updateLayout();
}
Window::Window(const NCursesWindow &window)
: NCursesWindow(window)
{}
Window::Window(int lines, int columns, int y, int x)
: NCursesWindow(lines, columns, y, x)
{}
@ -50,4 +54,10 @@ namespace krikkel::NCurses
return NCursesWindow::wresize(rows, cols);
}
int Window::refresh()
{
if(!hidden)
return NCursesWindow::refresh();
return 0;
}
}

View File

@ -21,7 +21,7 @@ namespace krikkel::NCurses
class PtyWindow : public Window
{
public:
PtyWindow(std::mutex *ncursesMutex, int lines, int columns, int y, int x);
PtyWindow(std::recursive_mutex *ncursesMutex, int lines, int columns, int y, int x);
~PtyWindow();
int getFdPtyClient() const;
@ -36,8 +36,8 @@ namespace krikkel::NCurses
int fdPtyHost, fdPtyClient;
struct termios terminalParameters;
VTerm *pseudoTerminal;
std::mutex writeToPseudoTerminalMutex;
std::mutex *ncursesMutex;
std::recursive_mutex writeToPseudoTerminalMutex;
std::recursive_mutex *ncursesMutex;
VTermScreen *pseudoTerminalScreen;
static VTermScreenCallbacks screenCallbacks;
/// @todo one line is at most 4096 chars long

View File

@ -13,19 +13,24 @@
namespace krikkel::NCurses
{
class Window;
class SingleUserInput;
class VerticalTilingWindowManager
{
public:
VerticalTilingWindowManager(NCursesWindow *rootWindow, std::mutex *ncursesMutex);
VerticalTilingWindowManager(NCursesWindow *rootWindow, std::recursive_mutex *ncursesMutex);
void addWindow(Window *window);
void refresh();
void updateLayout();
void hideWindow(Window *window);
void showWindow(Window *window);
SingleUserInput readSingleUserInput();
private:
NCursesWindow *rootWindow;
std::mutex *ncursesMutex;
std::list<Window *> stack;
Window *rootWindow;
std::recursive_mutex *ncursesMutex;
std::list<Window *> stack, visibleStack;
void resizeWindowInStack(Window *window, uint16_t y, uint16_t height, uint16_t width);
};

View File

@ -40,8 +40,11 @@ namespace krikkel::NCurses
class Window : public NCursesWindow
{
friend class VerticalTilingWindowManager;
public:
Window(VerticalTilingWindowManager *windowManager);
Window(const NCursesWindow &window);
Window(int lines, int columns, int y, int x);
int addnwstr(const wchar_t *wstr, int n);
int add_wch(const cchar_t *character);
@ -50,6 +53,10 @@ namespace krikkel::NCurses
SingleUserInput readSingleUserInput();
virtual int resize(int rows, int cols);
virtual int refresh() override;
protected:
bool hidden = false;
};
}