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`
This commit is contained in:
parent
0462a68c54
commit
b9e32941fb
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -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": [
|
||||
|
|
45
App.cpp
45
App.cpp
|
@ -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,17 +52,49 @@ 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
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
{
|
||||
lock_guard nCursesLock(*ncursesMutex);
|
||||
//__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 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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
10
Window.cpp
10
Window.cpp
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue