status_t BasicTerminalBuffer::_ResizeHistory(int32 width, int32 historyCapacity) { if (width == fWidth && historyCapacity == HistoryCapacity()) return B_OK; if (historyCapacity <= 0) { // new history capacity is 0 -- delete the old history object delete fHistory; fHistory = NULL; return B_OK; } HistoryBuffer* history = new(std::nothrow) HistoryBuffer; if (history == NULL) return B_NO_MEMORY; status_t error = history->Init(width, historyCapacity); if (error != B_OK) { delete history; return error; } // Transfer the lines from the old history to the new one. if (fHistory != NULL) { int32 historySize = min_c(HistorySize(), historyCapacity); TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth); for (int32 i = historySize - 1; i >= 0; i--) { TerminalLine* line = fHistory->GetTerminalLineAt(i, lineBuffer); if (line->length > width) _TruncateLine(line, width); history->AddLine(line); } } delete fHistory; fHistory = history; return B_OK; }
status_t BasicTerminalBuffer::_ResizeRewrap(int32 width, int32 height, int32 historyCapacity) { //debug_printf("BasicTerminalBuffer::_ResizeRewrap(): (%ld, %ld, history: %ld) -> " //"(%ld, %ld, history: %ld)\n", fWidth, fHeight, HistoryCapacity(), width, height, //historyCapacity); // The width stays the same. _ResizeSimple() does exactly what we need. if (width == fWidth) return _ResizeSimple(width, height, historyCapacity); // The width changes. We have to allocate a new line array, a new history // and re-wrap all lines. TerminalLine** screen = _AllocateLines(width, height); if (screen == NULL) return B_NO_MEMORY; HistoryBuffer* history = NULL; if (historyCapacity > 0) { history = new(std::nothrow) HistoryBuffer; if (history == NULL) { _FreeLines(screen, height); return B_NO_MEMORY; } status_t error = history->Init(width, historyCapacity); if (error != B_OK) { _FreeLines(screen, height); delete history; return error; } } int32 historySize = HistorySize(); int32 totalLines = historySize + fHeight; // re-wrap TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth); TermPos cursor; int32 destIndex = 0; int32 sourceIndex = 0; int32 sourceX = 0; int32 destTotalLines = 0; int32 destScreenOffset = 0; int32 maxDestTotalLines = INT_MAX; bool newDestLine = true; bool cursorSeen = false; TerminalLine* sourceLine = _HistoryLineAt(-historySize, lineBuffer); while (sourceIndex < totalLines) { TerminalLine* destLine = screen[destIndex]; if (newDestLine) { // Clear a new dest line before using it. If we're about to // overwrite an previously written line, we push it to the // history first, though. if (history != NULL && destTotalLines >= height) history->AddLine(screen[destIndex]); destLine->Clear(fAttributes, width); newDestLine = false; } int32 sourceLeft = sourceLine->length - sourceX; int32 destLeft = width - destLine->length; //debug_printf(" source: %ld, left: %ld, dest: %ld, left: %ld\n", //sourceIndex, sourceLeft, destIndex, destLeft); if (sourceIndex == historySize && sourceX == 0) { destScreenOffset = destTotalLines; if (destLeft == 0 && sourceLeft > 0) destScreenOffset++; maxDestTotalLines = destScreenOffset + height; //debug_printf(" destScreenOffset: %ld\n", destScreenOffset); } int32 toCopy = min_c(sourceLeft, destLeft); // If the last cell to copy is the first cell of a // full-width char, don't copy it yet. if (toCopy > 0 && IS_WIDTH( sourceLine->cells[sourceX + toCopy - 1].attributes)) { //debug_printf(" -> last char is full-width -- don't copy it\n"); toCopy--; } // translate the cursor position if (fCursor.y + historySize == sourceIndex && fCursor.x >= sourceX && (fCursor.x < sourceX + toCopy || (destLeft >= sourceLeft && sourceX + sourceLeft <= fCursor.x))) { cursor.x = destLine->length + fCursor.x - sourceX; cursor.y = destTotalLines; if (cursor.x >= width) { // The cursor was in free space after the official end // of line. cursor.x = width - 1; } //debug_printf(" cursor: (%ld, %ld)\n", cursor.x, cursor.y); cursorSeen = true; } if (toCopy > 0) { memcpy(destLine->cells + destLine->length, sourceLine->cells + sourceX, toCopy * sizeof(TerminalCell)); destLine->length += toCopy; } destLine->attributes = sourceLine->attributes; bool nextDestLine = false; if (toCopy == sourceLeft) { if (!sourceLine->softBreak) nextDestLine = true; sourceIndex++; sourceX = 0; sourceLine = _HistoryLineAt(sourceIndex - historySize, lineBuffer); } else { destLine->softBreak = true; nextDestLine = true; sourceX += toCopy; } if (nextDestLine) { destIndex = (destIndex + 1) % height; destTotalLines++; newDestLine = true; if (cursorSeen && destTotalLines >= maxDestTotalLines) break; } } // If the last source line had a soft break, the last dest line // won't have been counted yet. if (!newDestLine) { destIndex = (destIndex + 1) % height; destTotalLines++; } //debug_printf(" total lines: %ld -> %ld\n", totalLines, destTotalLines); if (destTotalLines - destScreenOffset > height) destScreenOffset = destTotalLines - height; cursor.y -= destScreenOffset; // When there are less lines (starting with the screen offset) than // there's room in the screen, clear the remaining screen lines. for (int32 i = destTotalLines; i < destScreenOffset + height; i++) { // Move the line we're going to clear to the history, if that's a // line we've written earlier. TerminalLine* line = screen[i % height]; if (history != NULL && i >= height) history->AddLine(line); line->Clear(fAttributes, width); } // Update the values _FreeLines(fScreen, fHeight); delete fHistory; fScreen = screen; fHistory = history; if (fWidth != width) { status_t error = _ResetTabStops(width); if (error != B_OK) return error; } //debug_printf(" cursor: (%ld, %ld) -> (%ld, %ld)\n", fCursor.x, fCursor.y, //cursor.x, cursor.y); fCursor.x = cursor.x; fCursor.y = cursor.y; fSoftWrappedCursor = false; //debug_printf(" screen offset: %ld -> %ld\n", fScreenOffset, destScreenOffset % height); fScreenOffset = destScreenOffset % height; //debug_printf(" height %ld -> %ld\n", fHeight, height); //debug_printf(" width %ld -> %ld\n", fWidth, width); fHeight = height; fWidth = width; fScrollTop = 0; fScrollBottom = fHeight - 1; fOriginMode = fSavedOriginMode = false; return B_OK; }
status_t ArpRemoteTerminal::PutConfiguration(const BMessage* values) { if( !values ) return B_BAD_VALUE; // Use the ArpMessage interface for extracting our values, since it // provides some convenience functions for working with colors // and fonts. ArpMessage msg(*values); int i; const bool locked = LockLooper(); try { int32 mode = 0; bool hasMode = msg.HasInt32(ModeConfigName); if( hasMode ) TermSetMode((mode=msg.GetInt32(ModeConfigName, TermMode()))); if( msg.HasString(LFCharsConfigName) ) TermSetLFChars(msg.GetString(LFCharsConfigName, TermLFChars())); else if( hasMode && (mode&1<<1) ) TermSetLFChars("\n"); if( msg.HasString(CRCharsConfigName) ) TermSetCRChars(msg.GetString(CRCharsConfigName, TermCRChars())); else if( hasMode && (mode&1<<1) ) TermSetCRChars("\n\r"); if( msg.HasString(EnterStreamConfigName) ) TermSetEnterStream(msg.GetString(EnterStreamConfigName, TermEnterStream())); else if( hasMode && (mode&1<<6) ) TermSetEnterStream("\n"); if( msg.HasFont(PlainFontConfigName) ) { BFont font(&GetStyledFont(TERM_STYLEPLAIN)); if( msg.FindFont(PlainFontConfigName, &font) == B_OK ) { SetFont(&font); } } if( msg.HasInt32(EncodingConfigName) ) TermSetEncoding(msg.GetInt32(EncodingConfigName, TermEncoding())); if( msg.HasInt32(StyleConfigName) ) TermSetStyle(msg.GetInt32(StyleConfigName, TermStyle())); if( msg.HasFloat("Tint Foreground") ) { SetTintForeground(msg.GetFloat("Tint Foreground", 1.75)); } if( msg.HasFloat("Tint Background") ) { SetTintBackground(msg.GetFloat("Tint Background", .25)); } { char* name; type_code type; int32 count; for( i=0; msg.GetInfo(B_RGB_COLOR_TYPE,i,&name,&type,&count)==B_OK; i++ ) { int32 idx = ColorVar2Index(name); if( idx >= 0 ) { bool bg=false; TermColorID col = ColorIndex2ID(idx, &bg); if( bg ) backcolor_from_msg(msg, name, 0, col); else forecolor_from_msg(msg, name, 0, col); } } } if( msg.HasInt32(NumRowsConfigName) || msg.HasInt32(NumColsConfigName) ) { int32 r=0,c=0; TermGetFixedSize(&r, &c); TermSetFixedSize(msg.GetInt32(NumRowsConfigName, r), msg.GetInt32(NumColsConfigName, c)); } if( msg.HasInt32(RegionTopConfigName) || msg.HasInt32(RegionBottomConfigName) || msg.HasInt32(RegionLeftConfigName) || msg.HasInt32(RegionRightConfigName) ) { int32 t=0, b=0, l=0, r=0; TermGetRegion(&t, &b, &l, &r); TermSetRegion(msg.GetInt32(RegionTopConfigName, t), msg.GetInt32(RegionBottomConfigName, b), msg.GetInt32(RegionLeftConfigName, l), msg.GetInt32(RegionRightConfigName, r)); } if( msg.HasInt32(AutoScrollConfigName) ) SetAutoScrollMode((AutoScrollType)msg.GetInt32(AutoScrollConfigName, AutoScrollMode())); if( msg.HasInt32(HistoryUseConfigName) ) SetHistoryUse((HistoryUseType)msg.GetInt32(HistoryUseConfigName, HistoryUse())); if( msg.HasInt32(HistorySizeConfigName) ) SetHistorySize(msg.GetInt32(HistorySizeConfigName, HistorySize())); if( msg.HasBool(VerifyPasteConfigName) ) SetPasteVerified(msg.GetBool(VerifyPasteConfigName, PasteVerified())); if( msg.HasBool(RMBPasteConfigName) ) SetRMBPaste(msg.GetBool(RMBPasteConfigName, RMBPaste())); if( msg.HasString(CurEmulatorConfigName) ) { const char* name = msg.GetString(CurEmulatorConfigName, 0); if( name ) { const ArpEmulationType* type = Emulator().EmulationType(); if( !type || strcmp(name, type->Name) ) { delete SetEmulator(name); } } } TermClean(); } catch(...) { if( locked ) UnlockLooper(); throw; } ReportChange(&msg); if( locked ) UnlockLooper(); return msg.GetError(); }
status_t ArpRemoteTerminal::GetConfiguration(BMessage* values) const { if( !values ) return B_BAD_VALUE; // Use the ArpMessage interface for adding our values, since it // provides some convenience functions for working with colors // and fonts. ArpMessage msg(*values); int i; const bool locked = const_cast<ArpRemoteTerminal*>(this)->LockLooper(); try { ArpD(cdb << ADH << "Getting settings; initial error = " << (msg.GetError()) << endl); msg.SetInt32(ModeConfigName, TermMode()); msg.SetString(LFCharsConfigName, TermLFChars()); msg.SetString(CRCharsConfigName, TermCRChars()); msg.SetString(EnterStreamConfigName, TermEnterStream()); msg.SetFont(PlainFontConfigName, &GetStyledFont(TERM_STYLEPLAIN)); msg.SetInt32(EncodingConfigName, TermEncoding()); msg.SetInt32(StyleConfigName, TermStyle()); const char* varName; for( i=0; (varName=ColorIndex2Var(i)) != 0; i++ ) { bool bg=false; TermColorID col = ColorIndex2ID(i, &bg); if( bg ) msg.SetRGBColor(varName, ArpColor(TermTextBackground(col))); else msg.SetRGBColor(varName, ArpColor(TermTextForeground(col))); } { int32 r=0,c=0; TermGetFixedSize(&r, &c); msg.SetInt32(NumRowsConfigName, r); msg.SetInt32(NumColsConfigName, c); } { int32 t=0, b=0, l=0, r=0; TermGetRegion(&t, &b, &l, &r); msg.SetInt32(RegionTopConfigName, t); msg.SetInt32(RegionBottomConfigName, b); msg.SetInt32(RegionLeftConfigName, l); msg.SetInt32(RegionRightConfigName, r); } msg.SetInt32(AutoScrollConfigName, AutoScrollMode()); msg.SetInt32(HistoryUseConfigName, HistoryUse()); msg.SetInt32(HistorySizeConfigName, HistorySize()); msg.SetBool(VerifyPasteConfigName, PasteVerified()); msg.SetBool(RMBPasteConfigName, RMBPaste()); const ArpEmulationType* type = Emulator().EmulationType(); if( type ) { msg.AddString(CurEmulatorConfigName, type->Synonym ? type->Synonym : type->Name); } ArpD(cdb << ADH << "Got settings; final error = " << (msg.GetError()) << endl); if( msg.GetError() == B_NO_ERROR ) { *values = msg; } } catch(...) { if( locked ) const_cast<ArpRemoteTerminal*>(this)->UnlockLooper(); throw; } if( locked ) const_cast<ArpRemoteTerminal*>(this)->UnlockLooper(); return msg.GetError(); }