* Change the line history to a more compact format. We reserve
lines * (width + 8) bytes which is only a little more than a sixth of what it was before. The effect on performance is relatively small. In my tests I measured about 2% slowdown. * Fixed artifacts after soft-wrapped lines. * Re-enabled cursor blinking. I changed it so that the cursor is 1s shown and 0.5s hidden (instead of 1s each). Tell me what you think. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25957 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,14 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "HistoryBuffer.h"
|
||||||
#include "TermPos.h"
|
#include "TermPos.h"
|
||||||
#include "UTF8Char.h"
|
#include "UTF8Char.h"
|
||||||
|
|
||||||
|
|
||||||
class BString;
|
class BString;
|
||||||
class TerminalCharClassifier;
|
class TerminalCharClassifier;
|
||||||
|
struct TerminalLine;
|
||||||
|
|
||||||
|
|
||||||
struct TerminalBufferDirtyInfo {
|
struct TerminalBufferDirtyInfo {
|
||||||
@@ -54,7 +56,8 @@ public:
|
|||||||
|
|
||||||
int32 Width() const { return fWidth; }
|
int32 Width() const { return fWidth; }
|
||||||
int32 Height() const { return fHeight; }
|
int32 Height() const { return fHeight; }
|
||||||
int32 HistorySize() const { return fHistorySize; }
|
inline int32 HistorySize() const;
|
||||||
|
inline int32 HistoryCapacity() const;
|
||||||
|
|
||||||
TerminalBufferDirtyInfo& DirtyInfo() { return fDirtyInfo; }
|
TerminalBufferDirtyInfo& DirtyInfo() { return fDirtyInfo; }
|
||||||
|
|
||||||
@@ -125,40 +128,32 @@ public:
|
|||||||
void SetScrollRegion(int32 top, int32 bot);
|
void SetScrollRegion(int32 top, int32 bot);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct Cell {
|
|
||||||
UTF8Char character;
|
|
||||||
uint16 attributes;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Line {
|
|
||||||
int16 length;
|
|
||||||
bool softBreak; // soft line break
|
|
||||||
Cell cells[1];
|
|
||||||
|
|
||||||
inline void Clear()
|
|
||||||
{
|
|
||||||
length = 0;
|
|
||||||
softBreak = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual void NotifyListener();
|
virtual void NotifyListener();
|
||||||
|
|
||||||
inline int32 _LineIndex(int32 index) const;
|
inline int32 _LineIndex(int32 index) const;
|
||||||
inline Line* _LineAt(int32 index) const;
|
inline TerminalLine* _LineAt(int32 index) const;
|
||||||
inline Line* _HistoryLineAt(int32 index) const;
|
inline TerminalLine* _HistoryLineAt(int32 index,
|
||||||
|
TerminalLine* lineBuffer) const;
|
||||||
|
|
||||||
inline void _Invalidate(int32 top, int32 bottom);
|
inline void _Invalidate(int32 top, int32 bottom);
|
||||||
inline void _CursorChanged();
|
inline void _CursorChanged();
|
||||||
|
|
||||||
static Line** _AllocateLines(int32 width, int32 count);
|
static TerminalLine** _AllocateLines(int32 width, int32 count);
|
||||||
static void _FreeLines(Line** lines, int32 count);
|
static void _FreeLines(TerminalLine** lines, int32 count);
|
||||||
void _ClearLines(int32 first, int32 last);
|
void _ClearLines(int32 first, int32 last);
|
||||||
|
|
||||||
|
status_t _ResizeHistory(int32 width,
|
||||||
|
int32 historyCapacity);
|
||||||
|
status_t _ResizeSimple(int32 width, int32 height,
|
||||||
|
int32 historyCapacity);
|
||||||
|
status_t _ResizeRewrap(int32 width, int32 height,
|
||||||
|
int32 historyCapacity);
|
||||||
|
|
||||||
void _Scroll(int32 top, int32 bottom,
|
void _Scroll(int32 top, int32 bottom,
|
||||||
int32 numLines);
|
int32 numLines);
|
||||||
void _SoftBreakLine();
|
void _SoftBreakLine();
|
||||||
void _PadLineToCursor();
|
void _PadLineToCursor();
|
||||||
|
static void _TruncateLine(TerminalLine* line, int32 length);
|
||||||
void _InsertGap(int32 width);
|
void _InsertGap(int32 width);
|
||||||
bool _GetPartialLineString(BString& string,
|
bool _GetPartialLineString(BString& string,
|
||||||
int32 row, int32 startColumn,
|
int32 row, int32 startColumn,
|
||||||
@@ -176,10 +171,9 @@ protected:
|
|||||||
int32 fScrollBottom; // last line to scroll (incl.)
|
int32 fScrollBottom; // last line to scroll (incl.)
|
||||||
|
|
||||||
// line buffers for the history (ring buffer)
|
// line buffers for the history (ring buffer)
|
||||||
Line** fHistory;
|
TerminalLine** fScreen;
|
||||||
int32 fHistoryCapacity;
|
|
||||||
int32 fScreenOffset; // index of screen line 0
|
int32 fScreenOffset; // index of screen line 0
|
||||||
int32 fHistorySize;
|
HistoryBuffer* fHistory;
|
||||||
|
|
||||||
// cursor position (origin: (0, 0))
|
// cursor position (origin: (0, 0))
|
||||||
TermPos fCursor;
|
TermPos fCursor;
|
||||||
@@ -194,6 +188,20 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BasicTerminalBuffer::HistorySize() const
|
||||||
|
{
|
||||||
|
return fHistory != NULL ? fHistory->Size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BasicTerminalBuffer::HistoryCapacity() const
|
||||||
|
{
|
||||||
|
return fHistory != NULL ? fHistory->Capacity() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BasicTerminalBuffer::InsertChar(const char* c, int32 length, uint32 attributes)
|
BasicTerminalBuffer::InsertChar(const char* c, int32 length, uint32 attributes)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HistoryBuffer.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include "TermConst.h"
|
||||||
|
|
||||||
|
|
||||||
|
HistoryBuffer::HistoryBuffer()
|
||||||
|
:
|
||||||
|
fLines(NULL),
|
||||||
|
fWidth(0),
|
||||||
|
fCapacity(0),
|
||||||
|
fNextLine(0),
|
||||||
|
fSize(0),
|
||||||
|
fBuffer(NULL),
|
||||||
|
fBufferSize(0),
|
||||||
|
fBufferAllocationOffset(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HistoryBuffer::~HistoryBuffer()
|
||||||
|
{
|
||||||
|
delete[] fLines;
|
||||||
|
delete[] fBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
HistoryBuffer::Init(int32 width, int32 capacity)
|
||||||
|
{
|
||||||
|
if (width <= 0 || capacity <= 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
int32 bufferSize = (width + 4) * capacity;
|
||||||
|
|
||||||
|
if (capacity > 0) {
|
||||||
|
fLines = new(std::nothrow) HistoryLine[capacity];
|
||||||
|
fBuffer = new(std::nothrow) uint8[bufferSize];
|
||||||
|
|
||||||
|
if (fLines == NULL || fBuffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
fWidth = width;
|
||||||
|
fCapacity = capacity;
|
||||||
|
fNextLine = 0;
|
||||||
|
fSize = 0;
|
||||||
|
fBufferSize = bufferSize;
|
||||||
|
fBufferAllocationOffset = 0;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HistoryBuffer::Clear()
|
||||||
|
{
|
||||||
|
fNextLine = 0;
|
||||||
|
fSize = 0;
|
||||||
|
fBufferAllocationOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TerminalLine*
|
||||||
|
HistoryBuffer::GetTerminalLineAt(int32 index, TerminalLine* buffer) const
|
||||||
|
{
|
||||||
|
HistoryLine* line = LineAt(index);
|
||||||
|
if (line == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int32 charCount = 0;
|
||||||
|
const char* chars = line->Chars();
|
||||||
|
buffer->length = 0;
|
||||||
|
uint16 attributes = 0;
|
||||||
|
AttributesRun* attributesRun = line->AttributesRuns();
|
||||||
|
int32 attributesRunCount = line->attributesRunCount;
|
||||||
|
int32 nextAttributesAt = attributesRunCount > 0
|
||||||
|
? attributesRun->offset : INT_MAX;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < line->byteLength;) {
|
||||||
|
// get attributes
|
||||||
|
if (charCount == nextAttributesAt) {
|
||||||
|
if (attributesRunCount > 0) {
|
||||||
|
attributes = attributesRun->attributes;
|
||||||
|
nextAttributesAt = attributesRun->offset + attributesRun->length;
|
||||||
|
attributesRun++;
|
||||||
|
attributesRunCount--;
|
||||||
|
} else {
|
||||||
|
attributes = 0;
|
||||||
|
nextAttributesAt = INT_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy character
|
||||||
|
TerminalCell& cell = buffer->cells[charCount++];
|
||||||
|
int32 charLength = UTF8Char::ByteCount(chars[i]);
|
||||||
|
cell.character.SetTo(chars + i, charLength);
|
||||||
|
i += charLength;
|
||||||
|
|
||||||
|
// set attributes
|
||||||
|
cell.attributes = attributes;
|
||||||
|
|
||||||
|
// full width char?
|
||||||
|
if (cell.character.IsFullWidth()) {
|
||||||
|
cell.attributes |= A_WIDTH;
|
||||||
|
charCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->length = charCount;
|
||||||
|
buffer->softBreak = line->softBreak;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HistoryBuffer::AddLine(const TerminalLine* line)
|
||||||
|
{
|
||||||
|
//debug_printf("HistoryBuffer::AddLine(%p): length: %d\n", line, line->length);
|
||||||
|
// determine the amount of memory we need for the line
|
||||||
|
uint16 attributes = 0;
|
||||||
|
int32 attributesRuns = 0;
|
||||||
|
int32 byteLength = 0;
|
||||||
|
for (int32 i = 0; i < line->length; i++) {
|
||||||
|
const TerminalCell& cell = line->cells[i];
|
||||||
|
byteLength += cell.character.ByteCount();
|
||||||
|
if ((cell.attributes & CHAR_ATTRIBUTES) != attributes) {
|
||||||
|
attributes = cell.attributes & CHAR_ATTRIBUTES;
|
||||||
|
if (attributes != 0)
|
||||||
|
attributesRuns++;
|
||||||
|
}
|
||||||
|
if (IS_WIDTH(cell.attributes))
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug_printf(" attributesRuns: %ld, byteLength: %ld\n", attributesRuns, byteLength);
|
||||||
|
|
||||||
|
// allocate and translate the line
|
||||||
|
HistoryLine* historyLine = _AllocateLine(attributesRuns, byteLength);
|
||||||
|
|
||||||
|
attributes = 0;
|
||||||
|
AttributesRun* attributesRun = historyLine->AttributesRuns();
|
||||||
|
|
||||||
|
char* chars = historyLine->Chars();
|
||||||
|
for (int32 i = 0; i < line->length; i++) {
|
||||||
|
const TerminalCell& cell = line->cells[i];
|
||||||
|
|
||||||
|
// copy char
|
||||||
|
int32 charLength = cell.character.ByteCount();
|
||||||
|
memcpy(chars, cell.character.bytes, charLength);
|
||||||
|
chars += charLength;
|
||||||
|
|
||||||
|
// deal with attributes
|
||||||
|
if ((cell.attributes & CHAR_ATTRIBUTES) != attributes) {
|
||||||
|
// terminate the previous attributes run
|
||||||
|
if (attributes != 0) {
|
||||||
|
attributesRun->length = i - attributesRun->offset;
|
||||||
|
attributesRun++;
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes = cell.attributes & CHAR_ATTRIBUTES;
|
||||||
|
|
||||||
|
// init the new one
|
||||||
|
if (attributes != 0) {
|
||||||
|
attributesRun->attributes = attributes;
|
||||||
|
attributesRun->offset = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_WIDTH(cell.attributes))
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
historyLine->softBreak = line->softBreak;
|
||||||
|
//debug_printf(" line: \"%.*s\", history size now: %ld\n", historyLine->byteLength, historyLine->Chars(), fSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HistoryBuffer::AddEmptyLines(int32 count)
|
||||||
|
{
|
||||||
|
if (count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (count > fCapacity)
|
||||||
|
count = fCapacity;
|
||||||
|
|
||||||
|
if (count + fSize > fCapacity)
|
||||||
|
DropLines(count + fSize - fCapacity);
|
||||||
|
|
||||||
|
// All lines use the same buffer address, since they don't use any memory.
|
||||||
|
AttributesRun* attributesRun
|
||||||
|
= (AttributesRun*)(fBuffer + fBufferAllocationOffset);
|
||||||
|
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
HistoryLine* line = _LineAt(fNextLine++);
|
||||||
|
line->attributesRuns = attributesRun;
|
||||||
|
line->attributesRunCount = 0;
|
||||||
|
line->byteLength = 0;
|
||||||
|
line->softBreak = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fSize += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HistoryBuffer::DropLines(int32 count)
|
||||||
|
{
|
||||||
|
if (count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (count < fSize) {
|
||||||
|
fSize -= count;
|
||||||
|
} else {
|
||||||
|
fSize = 0;
|
||||||
|
fNextLine = 0;
|
||||||
|
fBufferAllocationOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HistoryLine*
|
||||||
|
HistoryBuffer::_AllocateLine(int32 attributesRuns, int32 byteLength)
|
||||||
|
{
|
||||||
|
// we need at least one spare line slot
|
||||||
|
int32 toDrop = 0;
|
||||||
|
if (fSize == fCapacity)
|
||||||
|
toDrop = 1;
|
||||||
|
|
||||||
|
int32 bytesNeeded = attributesRuns * sizeof(AttributesRun) + byteLength;
|
||||||
|
|
||||||
|
if (fBufferAllocationOffset + bytesNeeded > fBufferSize) {
|
||||||
|
// drop all lines after the allocation index
|
||||||
|
for (; toDrop < fSize; toDrop++) {
|
||||||
|
HistoryLine* line = _LineAt(fSize - toDrop - 1);
|
||||||
|
int32 offset = (uint8*)line->AttributesRuns() - fBuffer;
|
||||||
|
if (offset < fBufferAllocationOffset)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fBufferAllocationOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop all lines interfering
|
||||||
|
int32 nextOffset = (fBufferAllocationOffset + bytesNeeded + 1) & ~1;
|
||||||
|
for (; toDrop < fSize; toDrop++) {
|
||||||
|
HistoryLine* line = _LineAt(fSize - toDrop - 1);
|
||||||
|
int32 offset = (uint8*)line->AttributesRuns() - fBuffer;
|
||||||
|
if (offset + line->BufferSize() <= fBufferAllocationOffset
|
||||||
|
|| offset >= nextOffset) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropLines(toDrop);
|
||||||
|
|
||||||
|
// init the line
|
||||||
|
HistoryLine* line = &fLines[fNextLine];
|
||||||
|
fNextLine = (fNextLine + 1) % fCapacity;
|
||||||
|
fSize++;
|
||||||
|
line->attributesRuns = (AttributesRun*)(fBuffer + fBufferAllocationOffset);
|
||||||
|
line->attributesRunCount = attributesRuns;
|
||||||
|
line->byteLength = byteLength;
|
||||||
|
|
||||||
|
fBufferAllocationOffset = (fBufferAllocationOffset + bytesNeeded + 1) & ~1;
|
||||||
|
// DropLines() may have changed fBufferAllocationOffset, so don't use
|
||||||
|
// nextOffset.
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef HISTORY_BUFFER_H
|
||||||
|
#define HISTORY_BUFFER_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include "TerminalLine.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct HistoryLine;
|
||||||
|
struct TerminalLine;
|
||||||
|
|
||||||
|
|
||||||
|
class HistoryBuffer {
|
||||||
|
public:
|
||||||
|
HistoryBuffer();
|
||||||
|
~HistoryBuffer();
|
||||||
|
|
||||||
|
status_t Init(int32 width, int32 capacity);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
int32 Width() const { return fWidth; }
|
||||||
|
int32 Capacity() const { return fCapacity; }
|
||||||
|
int32 Size() const { return fSize; }
|
||||||
|
|
||||||
|
inline HistoryLine* LineAt(int32 index) const;
|
||||||
|
TerminalLine* GetTerminalLineAt(int32 index,
|
||||||
|
TerminalLine* buffer) const;
|
||||||
|
|
||||||
|
void AddLine(const TerminalLine* line);
|
||||||
|
void AddEmptyLines(int32 count);
|
||||||
|
void DropLines(int32 count);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HistoryLine* _AllocateLine(int32 attributesRuns,
|
||||||
|
int32 byteLength);
|
||||||
|
inline HistoryLine* _LineAt(int32 index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HistoryLine* fLines;
|
||||||
|
int32 fWidth;
|
||||||
|
int32 fCapacity;
|
||||||
|
int32 fNextLine;
|
||||||
|
int32 fSize;
|
||||||
|
uint8* fBuffer;
|
||||||
|
int32 fBufferSize;
|
||||||
|
int32 fBufferAllocationOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline HistoryLine*
|
||||||
|
HistoryBuffer::_LineAt(int32 index) const
|
||||||
|
{
|
||||||
|
return &fLines[(fCapacity + fNextLine - index - 1) % fCapacity];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline HistoryLine*
|
||||||
|
HistoryBuffer::LineAt(int32 index) const
|
||||||
|
{
|
||||||
|
return index >= 0 && index < fSize ? _LineAt(index) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // HISTORY_BUFFER_H
|
||||||
@@ -11,6 +11,7 @@ Application Terminal :
|
|||||||
CodeConv.cpp
|
CodeConv.cpp
|
||||||
Coding.cpp
|
Coding.cpp
|
||||||
FindWindow.cpp
|
FindWindow.cpp
|
||||||
|
HistoryBuffer.cpp
|
||||||
MenuUtil.cpp
|
MenuUtil.cpp
|
||||||
Terminal.cpp
|
Terminal.cpp
|
||||||
PrefHandler.cpp
|
PrefHandler.cpp
|
||||||
|
|||||||
@@ -161,18 +161,19 @@ enum{
|
|||||||
#define IN_STRING 0xFF
|
#define IN_STRING 0xFF
|
||||||
|
|
||||||
// TermBuffer extended attribute
|
// TermBuffer extended attribute
|
||||||
#define A_WIDTH 0x8000
|
#define A_WIDTH 0x8000
|
||||||
#define BOLD 0x4000
|
#define BOLD 0x4000
|
||||||
#define UNDERLINE 0x2000
|
#define UNDERLINE 0x2000
|
||||||
#define INVERSE 0x1000
|
#define INVERSE 0x1000
|
||||||
#define MOUSE 0x0800
|
#define MOUSE 0x0800
|
||||||
#define FORESET 0x0400
|
#define FORESET 0x0400
|
||||||
#define BACKSET 0x0200
|
#define BACKSET 0x0200
|
||||||
#define FONT 0x0100
|
#define FONT 0x0100
|
||||||
#define RESERVE 0x0080
|
#define RESERVE 0x0080
|
||||||
#define DUMPCR 0x0040
|
#define DUMPCR 0x0040
|
||||||
#define FORECOLOR 0x0038
|
#define FORECOLOR 0x0038
|
||||||
#define BACKCOLOR 0x0007
|
#define BACKCOLOR 0x0007
|
||||||
|
#define CHAR_ATTRIBUTES 0x773f
|
||||||
|
|
||||||
#define IS_WIDTH(x) (((x) & A_WIDTH) )
|
#define IS_WIDTH(x) (((x) & A_WIDTH) )
|
||||||
#define IS_BOLD(x) (((x) & BOLD) )
|
#define IS_BOLD(x) (((x) & BOLD) )
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ static const uint32 kAutoScroll = 'AScr';
|
|||||||
|
|
||||||
static const bigtime_t kSyncUpdateGranularity = 100000; // 0.1 s
|
static const bigtime_t kSyncUpdateGranularity = 100000; // 0.1 s
|
||||||
|
|
||||||
|
static const int32 kCursorBlinkIntervals = 3;
|
||||||
|
static const int32 kCursorVisibleIntervals = 2;
|
||||||
|
static const bigtime_t kCursorBlinkInterval = 500000;
|
||||||
|
|
||||||
static const rgb_color kBlackColor = { 0, 0, 0, 255 };
|
static const rgb_color kBlackColor = { 0, 0, 0, 255 };
|
||||||
static const rgb_color kWhiteColor = { 255, 255, 255, 255 };
|
static const rgb_color kWhiteColor = { 255, 255, 255, 255 };
|
||||||
|
|
||||||
@@ -198,11 +202,8 @@ TermView::TermView(BRect frame, int32 argc, const char **argv, int32 historySize
|
|||||||
fFontHeight(0),
|
fFontHeight(0),
|
||||||
fFontAscent(0),
|
fFontAscent(0),
|
||||||
fFrameResized(false),
|
fFrameResized(false),
|
||||||
fLastCursorTime(0),
|
fLastActivityTime(0),
|
||||||
fCursorDrawFlag(true),
|
fCursorState(0),
|
||||||
fCursorStatus(true),
|
|
||||||
fCursorBlinkingFlag(true),
|
|
||||||
fCursorRedrawFlag(true),
|
|
||||||
fCursorHeight(0),
|
fCursorHeight(0),
|
||||||
fCursor(0, 0),
|
fCursor(0, 0),
|
||||||
fTermRows(ROWS_DEFAULT),
|
fTermRows(ROWS_DEFAULT),
|
||||||
@@ -244,11 +245,8 @@ TermView::TermView(int rows, int columns, int32 argc, const char **argv, int32 h
|
|||||||
fFontHeight(0),
|
fFontHeight(0),
|
||||||
fFontAscent(0),
|
fFontAscent(0),
|
||||||
fFrameResized(false),
|
fFrameResized(false),
|
||||||
fLastCursorTime(0),
|
fLastActivityTime(0),
|
||||||
fCursorDrawFlag(true),
|
fCursorState(0),
|
||||||
fCursorStatus(true),
|
|
||||||
fCursorBlinkingFlag(true),
|
|
||||||
fCursorRedrawFlag(true),
|
|
||||||
fCursorHeight(0),
|
fCursorHeight(0),
|
||||||
fCursor(0, 0),
|
fCursor(0, 0),
|
||||||
fTermRows(rows),
|
fTermRows(rows),
|
||||||
@@ -302,11 +300,8 @@ TermView::TermView(BMessage *archive)
|
|||||||
fFontHeight(0),
|
fFontHeight(0),
|
||||||
fFontAscent(0),
|
fFontAscent(0),
|
||||||
fFrameResized(false),
|
fFrameResized(false),
|
||||||
fLastCursorTime(0),
|
fLastActivityTime(0),
|
||||||
fCursorDrawFlag(true),
|
fCursorState(0),
|
||||||
fCursorStatus(true),
|
|
||||||
fCursorBlinkingFlag(true),
|
|
||||||
fCursorRedrawFlag(true),
|
|
||||||
fCursorHeight(0),
|
fCursorHeight(0),
|
||||||
fCursor(0, 0),
|
fCursor(0, 0),
|
||||||
fTermRows(ROWS_DEFAULT),
|
fTermRows(ROWS_DEFAULT),
|
||||||
@@ -379,8 +374,7 @@ TermView::_InitObject(int32 argc, const char **argv)
|
|||||||
return error;
|
return error;
|
||||||
fTextBuffer->SetEncoding(fEncoding);
|
fTextBuffer->SetEncoding(fEncoding);
|
||||||
|
|
||||||
error = fVisibleTextBuffer->Init(fTermColumns, fTermRows + 2,
|
error = fVisibleTextBuffer->Init(fTermColumns, fTermRows + 2, 0);
|
||||||
fTermRows + 2);
|
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@@ -503,7 +497,7 @@ TermView::SetTermSize(int rows, int columns, bool resize)
|
|||||||
{
|
{
|
||||||
BAutolock _(fTextBuffer);
|
BAutolock _(fTextBuffer);
|
||||||
if (fTextBuffer->ResizeTo(columns, rows) != B_OK
|
if (fTextBuffer->ResizeTo(columns, rows) != B_OK
|
||||||
|| fVisibleTextBuffer->ResizeTo(columns, rows + 2, rows + 2)
|
|| fVisibleTextBuffer->ResizeTo(columns, rows + 2, 0)
|
||||||
!= B_OK) {
|
!= B_OK) {
|
||||||
return Bounds();
|
return Bounds();
|
||||||
}
|
}
|
||||||
@@ -718,6 +712,7 @@ TermView::Clear()
|
|||||||
BAutolock _(fTextBuffer);
|
BAutolock _(fTextBuffer);
|
||||||
fTextBuffer->Clear();
|
fTextBuffer->Clear();
|
||||||
}
|
}
|
||||||
|
fVisibleTextBuffer->Clear();
|
||||||
|
|
||||||
//debug_printf("Invalidate()\n");
|
//debug_printf("Invalidate()\n");
|
||||||
Invalidate();
|
Invalidate();
|
||||||
@@ -750,59 +745,6 @@ TermView::_InvalidateTextRange(TermPos start, TermPos end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TermView::BlinkCursor()
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if (fCursorDrawFlag
|
|
||||||
&& fCursorBlinkingFlag
|
|
||||||
&& Window()->IsActive()) {
|
|
||||||
if (fCursorStatus)
|
|
||||||
_TermDraw(fCurPos, fCurPos);
|
|
||||||
else
|
|
||||||
DrawCursor();
|
|
||||||
|
|
||||||
fCursorStatus = !fCursorStatus;
|
|
||||||
fLastCursorTime = system_time();
|
|
||||||
}
|
|
||||||
#endif // 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! Draw / Clear cursor.
|
|
||||||
void
|
|
||||||
TermView::SetCurDraw(bool flag)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if (!flag) {
|
|
||||||
if (fCursorStatus)
|
|
||||||
_TermDraw(fCurPos, fCurPos);
|
|
||||||
|
|
||||||
fCursorStatus = false;
|
|
||||||
fCursorDrawFlag = false;
|
|
||||||
} else {
|
|
||||||
if (!fCursorDrawFlag) {
|
|
||||||
fCursorDrawFlag = true;
|
|
||||||
fCursorStatus = true;
|
|
||||||
|
|
||||||
if (LockLooper()) {
|
|
||||||
DrawCursor();
|
|
||||||
UnlockLooper();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//! Sets cursor Blinking flag.
|
|
||||||
void
|
|
||||||
TermView::SetCurBlinking(bool flag)
|
|
||||||
{
|
|
||||||
fCursorBlinkingFlag = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TermView::_AttachShell(Shell *shell)
|
TermView::_AttachShell(Shell *shell)
|
||||||
{
|
{
|
||||||
@@ -905,6 +847,8 @@ TermView::_DrawCursor()
|
|||||||
UTF8Char character;
|
UTF8Char character;
|
||||||
uint16 attr;
|
uint16 attr;
|
||||||
|
|
||||||
|
bool cursorVisible = _IsCursorVisible();
|
||||||
|
|
||||||
bool selected = _CheckSelectedRegion(TermPos(fCursor.x, fCursor.y));
|
bool selected = _CheckSelectedRegion(TermPos(fCursor.x, fCursor.y));
|
||||||
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
|
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
|
||||||
character, attr) == A_CHAR) {
|
character, attr) == A_CHAR) {
|
||||||
@@ -920,18 +864,52 @@ TermView::_DrawCursor()
|
|||||||
buffer[bytes] = '\0';
|
buffer[bytes] = '\0';
|
||||||
|
|
||||||
_DrawLinePart(fCursor.x * fFontWidth, (int32)rect.top, attr, buffer,
|
_DrawLinePart(fCursor.x * fFontWidth, (int32)rect.top, attr, buffer,
|
||||||
width, selected, true, this);
|
width, selected, cursorVisible, this);
|
||||||
} else {
|
} else {
|
||||||
if (selected)
|
if (selected)
|
||||||
SetHighColor(fSelectBackColor);
|
SetHighColor(fSelectBackColor);
|
||||||
else
|
else
|
||||||
SetHighColor(fCursorBackColor);
|
SetHighColor(cursorVisible ? fCursorBackColor : fTextBackColor);
|
||||||
|
|
||||||
FillRect(rect);
|
FillRect(rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TermView::_IsCursorVisible() const
|
||||||
|
{
|
||||||
|
return fCursorState < kCursorVisibleIntervals;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::_BlinkCursor()
|
||||||
|
{
|
||||||
|
bool wasVisible = _IsCursorVisible();
|
||||||
|
|
||||||
|
bigtime_t now = system_time();
|
||||||
|
if (Window()->IsActive() && now - fLastActivityTime >= kCursorBlinkInterval)
|
||||||
|
fCursorState = (fCursorState + 1) % kCursorBlinkIntervals;
|
||||||
|
else
|
||||||
|
fCursorState = 0;
|
||||||
|
|
||||||
|
if (wasVisible != _IsCursorVisible())
|
||||||
|
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::_ActivateCursor(bool invalidate)
|
||||||
|
{
|
||||||
|
fLastActivityTime = system_time();
|
||||||
|
if (invalidate && fCursorState != 0)
|
||||||
|
_BlinkCursor();
|
||||||
|
else
|
||||||
|
fCursorState = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Update scroll bar range and knob size.
|
//! Update scroll bar range and knob size.
|
||||||
void
|
void
|
||||||
TermView::_UpdateScrollBarRange()
|
TermView::_UpdateScrollBarRange()
|
||||||
@@ -983,10 +961,6 @@ TermView::AttachedToWindow()
|
|||||||
BMessage message(kUpdateSigWinch);
|
BMessage message(kUpdateSigWinch);
|
||||||
fWinchRunner = new (std::nothrow) BMessageRunner(thisMessenger,
|
fWinchRunner = new (std::nothrow) BMessageRunner(thisMessenger,
|
||||||
&message, 500000);
|
&message, 500000);
|
||||||
|
|
||||||
BMessage blinkMessage(kBlinkCursor);
|
|
||||||
fCursorBlinkRunner = new (std::nothrow) BMessageRunner(thisMessenger,
|
|
||||||
&blinkMessage, 1000000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1009,8 +983,6 @@ TermView::Draw(BRect updateRect)
|
|||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// BAutolock _(fTextBuffer);
|
|
||||||
|
|
||||||
// debug_printf("TermView::Draw((%f, %f) - (%f, %f))\n", updateRect.left,
|
// debug_printf("TermView::Draw((%f, %f) - (%f, %f))\n", updateRect.left,
|
||||||
// updateRect.top, updateRect.right, updateRect.bottom);
|
// updateRect.top, updateRect.right, updateRect.bottom);
|
||||||
// {
|
// {
|
||||||
@@ -1027,8 +999,6 @@ TermView::Draw(BRect updateRect)
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// _SynchronizeWithTextBuffer(&updateRect);
|
|
||||||
|
|
||||||
int32 x1 = (int32)(updateRect.left) / fFontWidth;
|
int32 x1 = (int32)(updateRect.left) / fFontWidth;
|
||||||
int32 x2 = (int32)(updateRect.right) / fFontWidth;
|
int32 x2 = (int32)(updateRect.right) / fFontWidth;
|
||||||
|
|
||||||
@@ -1045,7 +1015,6 @@ TermView::Draw(BRect updateRect)
|
|||||||
int32 k = x1;
|
int32 k = x1;
|
||||||
char buf[fTermColumns * 4 + 1];
|
char buf[fTermColumns * 4 + 1];
|
||||||
|
|
||||||
// if (fTextBuffer->IsFullWidthChar(j, k))
|
|
||||||
if (fVisibleTextBuffer->IsFullWidthChar(j - firstVisible, k))
|
if (fVisibleTextBuffer->IsFullWidthChar(j - firstVisible, k))
|
||||||
k--;
|
k--;
|
||||||
|
|
||||||
@@ -1056,7 +1025,6 @@ TermView::Draw(BRect updateRect)
|
|||||||
int32 lastColumn = x2;
|
int32 lastColumn = x2;
|
||||||
bool insideSelection = _CheckSelectedRegion(j, i, lastColumn);
|
bool insideSelection = _CheckSelectedRegion(j, i, lastColumn);
|
||||||
uint16 attr;
|
uint16 attr;
|
||||||
// int32 count = fTextBuffer->GetString(j, i, lastColumn, buf, attr);
|
|
||||||
int32 count = fVisibleTextBuffer->GetString(j - firstVisible, i,
|
int32 count = fVisibleTextBuffer->GetString(j - firstVisible, i,
|
||||||
lastColumn, buf, attr);
|
lastColumn, buf, attr);
|
||||||
|
|
||||||
@@ -1079,8 +1047,6 @@ TermView::Draw(BRect updateRect)
|
|||||||
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
|
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
|
||||||
attr, buf, count, insideSelection, false, this);
|
attr, buf, count, insideSelection, false, this);
|
||||||
i += count;
|
i += count;
|
||||||
if (i >= fTermColumns)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1141,8 +1107,21 @@ void
|
|||||||
TermView::WindowActivated(bool active)
|
TermView::WindowActivated(bool active)
|
||||||
{
|
{
|
||||||
BView::WindowActivated(active);
|
BView::WindowActivated(active);
|
||||||
if (active == false) {
|
if (active) {
|
||||||
|
// start cursor blinking
|
||||||
|
if (fCursorBlinkRunner == NULL) {
|
||||||
|
BMessage blinkMessage(kBlinkCursor);
|
||||||
|
fCursorBlinkRunner = new (std::nothrow) BMessageRunner(
|
||||||
|
BMessenger(this), &blinkMessage, kCursorBlinkInterval);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// DoIMConfirm();
|
// DoIMConfirm();
|
||||||
|
|
||||||
|
// make sure the cursor becomes visible
|
||||||
|
fCursorState = 0;
|
||||||
|
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
|
||||||
|
delete fCursorBlinkRunner;
|
||||||
|
fCursorBlinkRunner = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,6 +1141,8 @@ TermView::KeyDown(const char *bytes, int32 numBytes)
|
|||||||
currentMessage->FindInt32("key", &key);
|
currentMessage->FindInt32("key", &key);
|
||||||
currentMessage->FindInt32("raw_char", &rawChar);
|
currentMessage->FindInt32("raw_char", &rawChar);
|
||||||
|
|
||||||
|
_ActivateCursor(true);
|
||||||
|
|
||||||
// Terminal filters RET, ENTER, F1...F12, and ARROW key code.
|
// Terminal filters RET, ENTER, F1...F12, and ARROW key code.
|
||||||
// TODO: Cleanup
|
// TODO: Cleanup
|
||||||
if (numBytes == 1) {
|
if (numBytes == 1) {
|
||||||
@@ -1441,7 +1422,7 @@ TermView::MessageReceived(BMessage *msg)
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
case kBlinkCursor:
|
case kBlinkCursor:
|
||||||
BlinkCursor();
|
_BlinkCursor();
|
||||||
break;
|
break;
|
||||||
case kUpdateSigWinch:
|
case kUpdateSigWinch:
|
||||||
_UpdateSIGWINCH();
|
_UpdateSIGWINCH();
|
||||||
@@ -1738,6 +1719,7 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop,
|
|||||||
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
|
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
|
||||||
fCursor = cursor;
|
fCursor = cursor;
|
||||||
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
|
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
|
||||||
|
_ActivateCursor(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.Reset();
|
info.Reset();
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ public:
|
|||||||
void SelectAll();
|
void SelectAll();
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
// Cursor setting
|
|
||||||
void BlinkCursor();
|
|
||||||
void SetCurDraw(bool flag);
|
|
||||||
void SetCurBlinking(bool flag);
|
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
void GetFrameSize(float *width, float *height);
|
void GetFrameSize(float *width, float *height);
|
||||||
bool Find(const BString &str, bool forwardSearch, bool matchCase, bool matchWord);
|
bool Find(const BString &str, bool forwardSearch, bool matchCase, bool matchWord);
|
||||||
@@ -126,6 +121,10 @@ private:
|
|||||||
void _DrawCursor();
|
void _DrawCursor();
|
||||||
void _InvalidateTextRange(TermPos start, TermPos end);
|
void _InvalidateTextRange(TermPos start, TermPos end);
|
||||||
|
|
||||||
|
bool _IsCursorVisible() const;
|
||||||
|
void _BlinkCursor();
|
||||||
|
void _ActivateCursor(bool invalidate);
|
||||||
|
|
||||||
void _DoPrint(BRect updateRect);
|
void _DoPrint(BRect updateRect);
|
||||||
void _UpdateScrollBarRange();
|
void _UpdateScrollBarRange();
|
||||||
void _DoFileDrop(entry_ref &ref);
|
void _DoFileDrop(entry_ref &ref);
|
||||||
@@ -185,11 +184,8 @@ private:
|
|||||||
bool fFrameResized;
|
bool fFrameResized;
|
||||||
|
|
||||||
// Cursor Blinking, draw flag.
|
// Cursor Blinking, draw flag.
|
||||||
bigtime_t fLastCursorTime;
|
bigtime_t fLastActivityTime;
|
||||||
bool fCursorDrawFlag;
|
int32 fCursorState;
|
||||||
bool fCursorStatus;
|
|
||||||
bool fCursorBlinkingFlag;
|
|
||||||
bool fCursorRedrawFlag;
|
|
||||||
int fCursorHeight;
|
int fCursorHeight;
|
||||||
|
|
||||||
// Cursor position.
|
// Cursor position.
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef TERMINAL_LINE_H
|
||||||
|
#define TERMINAL_LINE_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include "UTF8Char.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct TerminalCell {
|
||||||
|
UTF8Char character;
|
||||||
|
uint16 attributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct TerminalLine {
|
||||||
|
int16 length;
|
||||||
|
bool softBreak; // soft line break
|
||||||
|
TerminalCell cells[1];
|
||||||
|
|
||||||
|
inline void Clear()
|
||||||
|
{
|
||||||
|
length = 0;
|
||||||
|
softBreak = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct AttributesRun {
|
||||||
|
uint16 attributes;
|
||||||
|
uint16 offset; // character offset
|
||||||
|
uint16 length; // length of the run in characters
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct HistoryLine {
|
||||||
|
AttributesRun* attributesRuns;
|
||||||
|
uint16 attributesRunCount; // number of attribute runs
|
||||||
|
uint16 byteLength : 15; // number of bytes in the line
|
||||||
|
bool softBreak : 1; // soft line break;
|
||||||
|
|
||||||
|
AttributesRun* AttributesRuns() const
|
||||||
|
{
|
||||||
|
return attributesRuns;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Chars() const
|
||||||
|
{
|
||||||
|
return (char*)(attributesRuns + attributesRunCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 BufferSize() const
|
||||||
|
{
|
||||||
|
return attributesRunCount * sizeof(AttributesRun) + byteLength;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TERMINAL_LINE_H
|
||||||
@@ -55,6 +55,12 @@ struct UTF8Char {
|
|||||||
return ByteCount(bytes[0]);
|
return ByteCount(bytes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsFullWidth() const
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsSpace() const
|
bool IsSpace() const
|
||||||
{
|
{
|
||||||
// TODO: Support multi-byte chars!
|
// TODO: Support multi-byte chars!
|
||||||
|
|||||||
Reference in New Issue
Block a user