From d04aae8b80964ab6a3ab7725baf930d2320d4133 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 17 Jun 2008 22:49:06 +0000 Subject: [PATCH] * Some preparations for DEC private mode settings support. * Implemented alternate screen buffer support. Not used by any program yet, since we still use the beterm termcap entry. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26003 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/terminal/BasicTerminalBuffer.cpp | 32 +++++-- src/apps/terminal/BasicTerminalBuffer.h | 10 +- src/apps/terminal/TermParse.cpp | 83 ++++++++++++++++- src/apps/terminal/TermParse.h | 2 + src/apps/terminal/TermView.cpp | 24 +++-- src/apps/terminal/TerminalBuffer.cpp | 108 ++++++++++++++++++++++ src/apps/terminal/TerminalBuffer.h | 14 +++ 7 files changed, 253 insertions(+), 20 deletions(-) diff --git a/src/apps/terminal/BasicTerminalBuffer.cpp b/src/apps/terminal/BasicTerminalBuffer.cpp index 49b6229443..5f10d66448 100644 --- a/src/apps/terminal/BasicTerminalBuffer.cpp +++ b/src/apps/terminal/BasicTerminalBuffer.cpp @@ -120,6 +120,7 @@ BasicTerminalBuffer::Init(int32 width, int32 height, int32 historySize) fScreenOffset = 0; fOverwriteMode = true; + fAlternateScreenActive = false; fScreen = _AllocateLines(width, height); if (fScreen == NULL) @@ -162,12 +163,10 @@ BasicTerminalBuffer::ResizeTo(int32 width, int32 height, int32 historyCapacity) if (width == fWidth && height == fHeight) return SetHistoryCapacity(historyCapacity); - // TODO: When alternate screen support is implemented, do that only when - // not using the alternate screen. - if (true) - return _ResizeRewrap(width, height, historyCapacity); + if (fAlternateScreenActive) + return _ResizeSimple(width, height, historyCapacity); - return _ResizeSimple(width, height, historyCapacity); + return _ResizeRewrap(width, height, historyCapacity); } @@ -179,11 +178,13 @@ BasicTerminalBuffer::SetHistoryCapacity(int32 historyCapacity) void -BasicTerminalBuffer::Clear() +BasicTerminalBuffer::Clear(bool resetCursor) { fScreenOffset = 0; _ClearLines(0, fHeight - 1); - fCursor.SetTo(0, 0); + + if (resetCursor) + fCursor.SetTo(0, 0); if (fHistory != NULL) fHistory->Clear(); @@ -585,7 +586,8 @@ BasicTerminalBuffer::InsertLF() if (fCursor.y == fScrollBottom) { _Scroll(fScrollTop, fScrollBottom, 1); } else { - fCursor.y++; + if (fCursor.y < fHeight - 1) + fCursor.y++; _CursorChanged(); } } @@ -731,7 +733,7 @@ BasicTerminalBuffer::SetCursor(int32 x, int32 y) { //debug_printf("BasicTerminalBuffer::SetCursor(%d, %d)\n", x, y); x = restrict_value(x, 0, fWidth - 1); - y = restrict_value(y, fScrollTop, fScrollBottom); + y = restrict_value(y, 0, fHeight - 1); if (x != fCursor.x || y != fCursor.y) { fCursor.x = x; fCursor.y = y; @@ -775,6 +777,18 @@ BasicTerminalBuffer::NotifyListener() // #pragma mark - private methods +void +BasicTerminalBuffer::_InvalidateAll() +{ + fDirtyInfo.invalidateAll = true; + + if (!fDirtyInfo.messageSent) { + NotifyListener(); + fDirtyInfo.messageSent = true; + } +} + + /* static */ TerminalLine** BasicTerminalBuffer::_AllocateLines(int32 width, int32 count) { diff --git a/src/apps/terminal/BasicTerminalBuffer.h b/src/apps/terminal/BasicTerminalBuffer.h index 3f6c341a98..538bdfa393 100644 --- a/src/apps/terminal/BasicTerminalBuffer.h +++ b/src/apps/terminal/BasicTerminalBuffer.h @@ -21,6 +21,7 @@ struct TerminalBufferDirtyInfo { int32 linesScrolled; // number of lines added to the history int32 dirtyTop; // dirty line range int32 dirtyBottom; // + bool invalidateAll; bool messageSent; // listener has been notified bool IsDirtyRegionValid() const @@ -41,6 +42,7 @@ struct TerminalBufferDirtyInfo { linesScrolled = 0; dirtyTop = INT_MAX; dirtyBottom = INT_MIN; + invalidateAll = false; messageSent = false; } }; @@ -61,11 +63,11 @@ public: TerminalBufferDirtyInfo& DirtyInfo() { return fDirtyInfo; } - status_t ResizeTo(int32 width, int32 height); - status_t ResizeTo(int32 width, int32 height, + virtual status_t ResizeTo(int32 width, int32 height); + virtual status_t ResizeTo(int32 width, int32 height, int32 historyCapacity); status_t SetHistoryCapacity(int32 historyCapacity); - void Clear(); + void Clear(bool resetCursor); void SynchronizeWith( const BasicTerminalBuffer* other, @@ -139,6 +141,7 @@ protected: inline void _Invalidate(int32 top, int32 bottom); inline void _CursorChanged(); + void _InvalidateAll(); static TerminalLine** _AllocateLines(int32 width, int32 count); static void _FreeLines(TerminalLine** lines, int32 count); @@ -182,6 +185,7 @@ protected: TermPos fSavedCursor; bool fOverwriteMode; // false for insert + bool fAlternateScreenActive; int fEncoding; diff --git a/src/apps/terminal/TermParse.cpp b/src/apps/terminal/TermParse.cpp index 1f910a7934..8495085168 100644 --- a/src/apps/terminal/TermParse.cpp +++ b/src/apps/terminal/TermParse.cpp @@ -790,13 +790,15 @@ TermParse::EscParse() case CASE_DECSET: /* DECSET */ - // dpmodes(term, bitset); + for (int i = 0; i < nparam; i++) + _DecPrivateModeSet(param[i]); parsestate = groundtable; break; case CASE_DECRST: /* DECRST */ - // dpmodes(term, bitclr); + for (int i = 0; i < nparam; i++) + _DecPrivateModeReset(param[i]); parsestate = groundtable; break; @@ -1070,3 +1072,80 @@ TermParse::_DeviceStatusReport(int n) return; } } + + +void +TermParse::_DecPrivateModeSet(int value) +{ + switch (value) { + case 1: + // Application Cursor Keys (whatever that means). + // Not supported yet. + break; + case 5: + // Reverse Video (inverses colors for the complete screen + // -- when followed by normal video, that's shortly flashes the + // screen). + // Not supported yet. + break; + case 12: + // Start Blinking Cursor. + // Not supported yet. + break; + case 25: + // Show Cursor + // Not supported yet. + break; + case 1034: + // Interpret "meta" key, sets eighth bit. + // Not supported yet. + break; + case 1049: + // Save cursor as in DECSC and use Alternate Screen Buffer, clearing + // it first. + fBuffer->SaveCursor(); + fBuffer->UseAlternateScreenBuffer(); + break; + } +} + + +void +TermParse::_DecPrivateModeReset(int value) +{ + switch (value) { + case 1: + // Normal Cursor Keys (whatever that means). + // Not supported yet. + break; + case 3: + // 80 Column Mode. + // Not supported yet. + break; + case 4: + // Jump (Fast) Scroll. + // Not supported yet. + break; + case 5: + // Normal Video (Leaves Reverse Video, cf. there). + // Not supported yet. + break; + case 12: + // Stop Blinking Cursor. + // Not supported yet. + break; + case 25: + // Hide Cursor + // Not supported yet. + break; + case 1034: + // Don’t interpret "meta" key. + // Not supported yet. + break; + case 1049: + // Use Normal Screen Buffer and restore cursor as in DECRC. + fBuffer->RestoreCursor(); + fBuffer->UseNormalScreenBuffer(); + break; + } +} diff --git a/src/apps/terminal/TermParse.h b/src/apps/terminal/TermParse.h index 7ca02fcea4..4e881ff8d7 100644 --- a/src/apps/terminal/TermParse.h +++ b/src/apps/terminal/TermParse.h @@ -76,6 +76,8 @@ private: status_t _ReadParserBuffer(); void _DeviceStatusReport(int n); + void _DecPrivateModeSet(int value); + void _DecPrivateModeReset(int value); int fFd; diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index 386b002ef5..54cd472cd0 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -710,9 +710,9 @@ TermView::Clear() { BAutolock _(fTextBuffer); - fTextBuffer->Clear(); + fTextBuffer->Clear(true); } - fVisibleTextBuffer->Clear(); + fVisibleTextBuffer->Clear(true); //debug_printf("Invalidate()\n"); Invalidate(); @@ -1563,10 +1563,6 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop, { TerminalBufferDirtyInfo& info = fTextBuffer->DirtyInfo(); int32 linesScrolled = info.linesScrolled; - BRect bounds = Bounds(); - int32 firstVisible = _LineAt(0); - int32 lastVisible = _LineAt(bounds.bottom); - int32 historySize = fTextBuffer->HistorySize(); //debug_printf("TermView::_SynchronizeWithTextBuffer(): dirty: %ld - %ld, " //"scrolled: %ld, visible dirty: %ld - %ld\n", info.dirtyTop, info.dirtyBottom, @@ -1630,6 +1626,22 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop, fScrolledSinceLastSync = 0; } + // Simple case first -- complete invalidation. + if (info.invalidateAll) { + Invalidate(); + _UpdateScrollBarRange(); + int32 offset = _LineAt(0); + fVisibleTextBuffer->SynchronizeWith(fTextBuffer, offset, offset, + offset + fTextBuffer->Height() + 2); + info.Reset(); + return; + } + + BRect bounds = Bounds(); + int32 firstVisible = _LineAt(0); + int32 lastVisible = _LineAt(bounds.bottom); + int32 historySize = fTextBuffer->HistorySize(); + bool doScroll = false; if (linesScrolled > 0) { _UpdateScrollBarRange(); diff --git a/src/apps/terminal/TerminalBuffer.cpp b/src/apps/terminal/TerminalBuffer.cpp index 0d837208a4..21b899791b 100644 --- a/src/apps/terminal/TerminalBuffer.cpp +++ b/src/apps/terminal/TerminalBuffer.cpp @@ -5,6 +5,8 @@ #include "TerminalBuffer.h" +#include + #include #include "Coding.h" @@ -18,6 +20,9 @@ TerminalBuffer::TerminalBuffer() : BLocker("terminal buffer"), fEncoding(M_UTF8), + fAlternateScreen(NULL), + fAlternateHistory(NULL), + fAlternateScreenOffset(0), fListenerValid(false) { } @@ -25,6 +30,8 @@ TerminalBuffer::TerminalBuffer() TerminalBuffer::~TerminalBuffer() { + delete fAlternateScreen; + delete fAlternateHistory; } @@ -34,6 +41,10 @@ TerminalBuffer::Init(int32 width, int32 height, int32 historySize) if (Sem() < 0) return Sem(); + fAlternateScreen = _AllocateLines(width, height); + if (fAlternateScreen == NULL) + return B_NO_MEMORY; + return BasicTerminalBuffer::Init(width, height, historySize); } @@ -95,3 +106,100 @@ TerminalBuffer::NotifyListener() if (fListenerValid) fListener.SendMessage(MSG_TERMINAL_BUFFER_CHANGED); } + + +status_t +TerminalBuffer::ResizeTo(int32 width, int32 height) +{ + int32 historyCapacity = 0; + if (!fAlternateScreenActive) + historyCapacity = HistoryCapacity(); + else if (fAlternateHistory != NULL) + historyCapacity = fAlternateHistory->Capacity(); + + return ResizeTo(width, height, historyCapacity); +} + + +status_t +TerminalBuffer::ResizeTo(int32 width, int32 height, int32 historyCapacity) +{ + // switch to the normal screen buffer first + bool alternateScreenActive = fAlternateScreenActive; + if (alternateScreenActive) + _SwitchScreenBuffer(); + + int32 oldWidth = fWidth; + int32 oldHeight = fHeight; + + // Resize the normal screen buffer/history. + status_t error = BasicTerminalBuffer::ResizeTo(width, height, + historyCapacity); + if (error != B_OK) { + if (alternateScreenActive) + _SwitchScreenBuffer(); + return error; + } + + TermPos cursor = fCursor; + + // Switch to the alternate screen buffer and resize it. + if (fAlternateScreen != NULL) { + _SwitchScreenBuffer(); + + fWidth = oldWidth; + fHeight = oldHeight; + fCursor.SetTo(0, 0); + + error = BasicTerminalBuffer::ResizeTo(width, height, 0); + if (error != B_OK) { + // This sucks -- we can't do anything about it. Delete the + // alternate screen buffer. + _FreeLines(fAlternateScreen, oldHeight); + fAlternateScreen = NULL; + } + + // Switch back. + if (!alternateScreenActive) + _SwitchScreenBuffer(); + + fWidth = width; + fHeight = height; + fCursor = cursor; + } + + return error; +} + + +void +TerminalBuffer::UseAlternateScreenBuffer() +{ + if (fAlternateScreenActive || fAlternateScreen == NULL) + return; + + _SwitchScreenBuffer(); + Clear(false); + _InvalidateAll(); +} + + +void +TerminalBuffer::UseNormalScreenBuffer() +{ + if (!fAlternateScreenActive) + return; + + _SwitchScreenBuffer(); + _InvalidateAll(); +} + + +void +TerminalBuffer::_SwitchScreenBuffer() +{ + std::swap(fScreen, fAlternateScreen); + std::swap(fHistory, fAlternateHistory); + std::swap(fScreenOffset, fAlternateScreenOffset); + fAlternateScreenActive = !fAlternateScreenActive; +} diff --git a/src/apps/terminal/TerminalBuffer.h b/src/apps/terminal/TerminalBuffer.h index 31287d88f1..9785603e08 100644 --- a/src/apps/terminal/TerminalBuffer.h +++ b/src/apps/terminal/TerminalBuffer.h @@ -28,12 +28,26 @@ public: void SetTitle(const char* title); void NotifyQuit(int32 reason); + virtual status_t ResizeTo(int32 width, int32 height); + virtual status_t ResizeTo(int32 width, int32 height, + int32 historyCapacity); + + void UseAlternateScreenBuffer(); + void UseNormalScreenBuffer(); + protected: virtual void NotifyListener(); +private: + void _SwitchScreenBuffer(); + private: int fEncoding; + TerminalLine** fAlternateScreen; + HistoryBuffer* fAlternateHistory; + int32 fAlternateScreenOffset; + // listener/dirty region management BMessenger fListener; bool fListenerValid;