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",
|
"stdexcept": "cpp",
|
||||||
"typeinfo": "cpp",
|
"typeinfo": "cpp",
|
||||||
"pointers": "cpp",
|
"pointers": "cpp",
|
||||||
"list": "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": [
|
||||||
|
|
45
App.cpp
45
App.cpp
|
@ -22,10 +22,11 @@ namespace krikkel::NCurses
|
||||||
|
|
||||||
int DemoApp::run()
|
int DemoApp::run()
|
||||||
{
|
{
|
||||||
std::mutex ncursesMutex;
|
std::recursive_mutex ncursesMutex;
|
||||||
VerticalTilingWindowManager windowManager(Root_Window, &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);
|
PtyWindow *ptyWindow = new PtyWindow(&ncursesMutex, 0, 0, 0, 0);
|
||||||
windowManager.addWindow(ptyWindow);
|
windowManager.addWindow(ptyWindow);
|
||||||
new Window(&windowManager);
|
new Window(&windowManager);
|
||||||
|
@ -51,17 +52,49 @@ namespace krikkel::NCurses
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
SingleUserInput input = ptyWindow->readSingleUserInput();
|
SingleUserInput input = windowManager.readSingleUserInput();
|
||||||
if(input.isNormalKey())
|
if(input.isNormalKey())
|
||||||
|
{
|
||||||
|
std::lock_guard lock(ncursesMutex);
|
||||||
ptyWindow->writeUnicodeCharToClient(input.getRawInput());
|
ptyWindow->writeUnicodeCharToClient(input.getRawInput());
|
||||||
|
dummyWindow->addch(input.getRawInput());
|
||||||
|
dummyWindow->refresh();
|
||||||
|
}
|
||||||
if(input.isFunctionKey())
|
if(input.isFunctionKey())
|
||||||
{
|
{
|
||||||
if(input.getRawInput() == KEY_RESIZE)
|
switch(input.getRawInput())
|
||||||
ptyWindow->wresize(Root_Window->lines(), Root_Window->cols());
|
{
|
||||||
else
|
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());
|
ptyWindow->writeKeyToClient(input.mapKeyNcursesToVTerm());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,9 @@ namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
using gsl::narrow;
|
using gsl::narrow;
|
||||||
using std::lock_guard;
|
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)
|
: 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
|
||||||
|
@ -67,19 +68,21 @@ namespace krikkel::NCurses
|
||||||
|
|
||||||
void PtyWindow::writeToClient(const char *output, size_t length)
|
void PtyWindow::writeToClient(const char *output, size_t length)
|
||||||
{
|
{
|
||||||
lock_guard writeLock(writeToPseudoTerminalMutex);
|
lock_guard lock(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)
|
||||||
{
|
{
|
||||||
|
lock_guard lock(writeToPseudoTerminalMutex);
|
||||||
vterm_keyboard_unichar(pseudoTerminal, character, VTERM_MOD_NONE);
|
vterm_keyboard_unichar(pseudoTerminal, character, VTERM_MOD_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtyWindow::writeKeyToClient(VTermKey key)
|
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);
|
vterm_keyboard_key(pseudoTerminal, key, VTERM_MOD_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +111,7 @@ namespace krikkel::NCurses
|
||||||
lock_guard writeLock(writeToPseudoTerminalMutex);
|
lock_guard writeLock(writeToPseudoTerminalMutex);
|
||||||
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 =
|
||||||
|
@ -238,9 +241,10 @@ namespace krikkel::NCurses
|
||||||
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(*ncursesMutex);
|
|
||||||
setcchar(&converted, &character, formatting, colorPair, NULL);
|
setcchar(&converted, &character, formatting, colorPair, NULL);
|
||||||
|
{
|
||||||
|
lock_guard lock(*ncursesMutex);
|
||||||
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,9 +253,10 @@ namespace krikkel::NCurses
|
||||||
|
|
||||||
int PtyWindow::refresh()
|
int PtyWindow::refresh()
|
||||||
{
|
{
|
||||||
lock_guard nCursesLock(*ncursesMutex);
|
//__debug_log("refreshing");
|
||||||
|
lock_guard 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
|
||||||
|
@ -269,8 +274,8 @@ namespace krikkel::NCurses
|
||||||
vterm_set_size(pseudoTerminal, rows, cols);
|
vterm_set_size(pseudoTerminal, rows, cols);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
lock_guard nCursesLock(*ncursesMutex);
|
lock_guard lock(*ncursesMutex);
|
||||||
return Window::wresize(rows, cols);
|
return Window::resize(rows, cols);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +330,6 @@ namespace krikkel::NCurses
|
||||||
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->writeToClient(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
|
// 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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,44 +10,80 @@
|
||||||
namespace krikkel::NCurses
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
using std::list;
|
using std::list;
|
||||||
using std::mutex;
|
using std::recursive_mutex;
|
||||||
using std::lock_guard;
|
using std::lock_guard;
|
||||||
using std::find;
|
using std::find;
|
||||||
|
|
||||||
VerticalTilingWindowManager::VerticalTilingWindowManager(NCursesWindow *rootWindow, mutex *ncursesMutex)
|
VerticalTilingWindowManager::VerticalTilingWindowManager(NCursesWindow *rootWindow, recursive_mutex *ncursesMutex)
|
||||||
: rootWindow(rootWindow), ncursesMutex(ncursesMutex)
|
: rootWindow(new Window(*rootWindow)), ncursesMutex(ncursesMutex)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void VerticalTilingWindowManager::addWindow(Window *window)
|
void VerticalTilingWindowManager::addWindow(Window *window)
|
||||||
{
|
{
|
||||||
stack.push_back(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()
|
void VerticalTilingWindowManager::refresh()
|
||||||
{
|
{
|
||||||
|
lock_guard lock(*ncursesMutex);
|
||||||
|
|
||||||
rootWindow->refresh();
|
rootWindow->refresh();
|
||||||
for(Window *window : stack)
|
for(Window *window : visibleStack)
|
||||||
window->refresh();
|
window->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SingleUserInput VerticalTilingWindowManager::readSingleUserInput()
|
||||||
|
{
|
||||||
|
return rootWindow->readSingleUserInput();
|
||||||
|
}
|
||||||
|
|
||||||
void VerticalTilingWindowManager::updateLayout()
|
void VerticalTilingWindowManager::updateLayout()
|
||||||
{
|
{
|
||||||
|
lock_guard lock(*ncursesMutex);
|
||||||
int availableWidth = rootWindow->width();
|
int availableWidth = rootWindow->width();
|
||||||
int availableHeight = rootWindow->height();
|
int availableHeight = rootWindow->height();
|
||||||
int windowHeight = availableHeight / stack.size() - 1;
|
size_t stackSize = visibleStack.size();
|
||||||
if((windowHeight + 1) * stack.size() < availableHeight)
|
int windowHeight = availableHeight / stackSize - 1;
|
||||||
|
|
||||||
|
if((windowHeight + 1) * stackSize < availableHeight)
|
||||||
++windowHeight;
|
++windowHeight;
|
||||||
|
|
||||||
list<Window *>::iterator it = stack.begin();
|
|
||||||
uint16_t y = 0;
|
uint16_t y = 0;
|
||||||
|
list<Window *>::iterator it = visibleStack.begin();
|
||||||
for(size_t index = 0
|
for(size_t index = 0
|
||||||
; index < stack.size() - 1
|
; index < visibleStack.size() - 1
|
||||||
; ++index)
|
; ++index)
|
||||||
{
|
{
|
||||||
resizeWindowInStack(*it++, y, windowHeight, availableWidth);
|
resizeWindowInStack(*it++, y, windowHeight, availableWidth);
|
||||||
y += windowHeight;
|
y += windowHeight;
|
||||||
{
|
{
|
||||||
lock_guard lock(*ncursesMutex);
|
|
||||||
rootWindow->move(y++, 0);
|
rootWindow->move(y++, 0);
|
||||||
rootWindow->hline(availableWidth);
|
rootWindow->hline(availableWidth);
|
||||||
}
|
}
|
||||||
|
|
10
Window.cpp
10
Window.cpp
|
@ -14,6 +14,10 @@ namespace krikkel::NCurses
|
||||||
windowManager->updateLayout();
|
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)
|
||||||
{}
|
{}
|
||||||
|
@ -50,4 +54,10 @@ namespace krikkel::NCurses
|
||||||
return NCursesWindow::wresize(rows, cols);
|
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
|
class PtyWindow : public Window
|
||||||
{
|
{
|
||||||
public:
|
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();
|
~PtyWindow();
|
||||||
|
|
||||||
int getFdPtyClient() const;
|
int getFdPtyClient() const;
|
||||||
|
@ -36,8 +36,8 @@ namespace krikkel::NCurses
|
||||||
int fdPtyHost, fdPtyClient;
|
int fdPtyHost, fdPtyClient;
|
||||||
struct termios terminalParameters;
|
struct termios terminalParameters;
|
||||||
VTerm *pseudoTerminal;
|
VTerm *pseudoTerminal;
|
||||||
std::mutex writeToPseudoTerminalMutex;
|
std::recursive_mutex writeToPseudoTerminalMutex;
|
||||||
std::mutex *ncursesMutex;
|
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
|
||||||
|
|
|
@ -13,19 +13,24 @@
|
||||||
namespace krikkel::NCurses
|
namespace krikkel::NCurses
|
||||||
{
|
{
|
||||||
class Window;
|
class Window;
|
||||||
|
class SingleUserInput;
|
||||||
|
|
||||||
class VerticalTilingWindowManager
|
class VerticalTilingWindowManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VerticalTilingWindowManager(NCursesWindow *rootWindow, std::mutex *ncursesMutex);
|
VerticalTilingWindowManager(NCursesWindow *rootWindow, std::recursive_mutex *ncursesMutex);
|
||||||
void addWindow(Window *window);
|
void addWindow(Window *window);
|
||||||
void refresh();
|
void refresh();
|
||||||
void updateLayout();
|
void updateLayout();
|
||||||
|
|
||||||
|
void hideWindow(Window *window);
|
||||||
|
void showWindow(Window *window);
|
||||||
|
SingleUserInput readSingleUserInput();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NCursesWindow *rootWindow;
|
Window *rootWindow;
|
||||||
std::mutex *ncursesMutex;
|
std::recursive_mutex *ncursesMutex;
|
||||||
std::list<Window *> stack;
|
std::list<Window *> stack, visibleStack;
|
||||||
|
|
||||||
void resizeWindowInStack(Window *window, uint16_t y, uint16_t height, uint16_t width);
|
void resizeWindowInStack(Window *window, uint16_t y, uint16_t height, uint16_t width);
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,8 +40,11 @@ namespace krikkel::NCurses
|
||||||
|
|
||||||
class Window : public NCursesWindow
|
class Window : public NCursesWindow
|
||||||
{
|
{
|
||||||
|
friend class VerticalTilingWindowManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Window(VerticalTilingWindowManager *windowManager);
|
Window(VerticalTilingWindowManager *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);
|
||||||
|
@ -50,6 +53,10 @@ namespace krikkel::NCurses
|
||||||
|
|
||||||
SingleUserInput readSingleUserInput();
|
SingleUserInput readSingleUserInput();
|
||||||
virtual int resize(int rows, int cols);
|
virtual int resize(int rows, int cols);
|
||||||
|
virtual int refresh() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool hidden = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue