K&R formatting

This commit is contained in:
Petr Vanek
2010-10-01 16:08:14 +02:00
parent 88b5a11bb4
commit 57fd23bf39
40 changed files with 13725 additions and 12935 deletions
+279 -266
View File
@@ -39,328 +39,341 @@ using namespace Konsole;
static int blocksize = 0;
BlockArray::BlockArray()
: size(0),
current(size_t(-1)),
index(size_t(-1)),
lastmap(0),
lastmap_index(size_t(-1)),
lastblock(0), ion(-1),
length(0) {
// lastmap_index = index = current = size_t(-1);
if (blocksize == 0) {
blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
}
: size(0),
current(size_t(-1)),
index(size_t(-1)),
lastmap(0),
lastmap_index(size_t(-1)),
lastblock(0), ion(-1),
length(0)
{
// lastmap_index = index = current = size_t(-1);
if (blocksize == 0) {
blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
}
}
BlockArray::~BlockArray() {
setHistorySize(0);
assert(!lastblock);
}
size_t BlockArray::append(Block * block) {
if (!size) {
return size_t(-1);
}
++current;
if (current >= size) {
current = 0;
}
int rc;
rc = lseek(ion, current * blocksize, SEEK_SET);
if (rc < 0) {
perror("HistoryBuffer::add.seek");
BlockArray::~BlockArray()
{
setHistorySize(0);
return size_t(-1);
}
rc = write(ion, block, blocksize);
if (rc < 0) {
perror("HistoryBuffer::add.write");
setHistorySize(0);
return size_t(-1);
}
length++;
if (length > size) {
length = size;
}
++index;
delete block;
return current;
assert(!lastblock);
}
size_t BlockArray::newBlock() {
if (!size) {
return size_t(-1);
}
append(lastblock);
size_t BlockArray::append(Block * block)
{
if (!size) {
return size_t(-1);
}
lastblock = new Block();
return index + 1;
++current;
if (current >= size) {
current = 0;
}
int rc;
rc = lseek(ion, current * blocksize, SEEK_SET);
if (rc < 0) {
perror("HistoryBuffer::add.seek");
setHistorySize(0);
return size_t(-1);
}
rc = write(ion, block, blocksize);
if (rc < 0) {
perror("HistoryBuffer::add.write");
setHistorySize(0);
return size_t(-1);
}
length++;
if (length > size) {
length = size;
}
++index;
delete block;
return current;
}
Block * BlockArray::lastBlock() const {
return lastblock;
size_t BlockArray::newBlock()
{
if (!size) {
return size_t(-1);
}
append(lastblock);
lastblock = new Block();
return index + 1;
}
bool BlockArray::has(size_t i) const {
if (i == index + 1) {
return true;
}
if (i > index) {
return false;
}
if (index - i >= length) {
return false;
}
return true;
}
const Block * BlockArray::at(size_t i) {
if (i == index + 1) {
Block * BlockArray::lastBlock() const
{
return lastblock;
}
}
if (i == lastmap_index) {
return lastmap;
}
bool BlockArray::has(size_t i) const
{
if (i == index + 1) {
return true;
}
if (i > index) {
qDebug() << "BlockArray::at() i > index\n";
return 0;
}
if (i > index) {
return false;
}
if (index - i >= length) {
return false;
}
return true;
}
const Block * BlockArray::at(size_t i)
{
if (i == index + 1) {
return lastblock;
}
if (i == lastmap_index) {
return lastmap;
}
if (i > index) {
qDebug() << "BlockArray::at() i > index\n";
return 0;
}
// if (index - i >= length) {
// kDebug(1211) << "BlockArray::at() index - i >= length\n";
// return 0;
// }
size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
assert(j < size);
unmap();
assert(j < size);
unmap();
Block * block = (Block *)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
Block * block = (Block *)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
if (block == (Block *)-1) {
perror("mmap");
return 0;
}
lastmap = block;
lastmap_index = i;
return block;
}
void BlockArray::unmap() {
if (lastmap) {
int res = munmap((char *)lastmap, blocksize);
if (res < 0) {
perror("munmap");
if (block == (Block *)-1) {
perror("mmap");
return 0;
}
}
lastmap = 0;
lastmap_index = size_t(-1);
lastmap = block;
lastmap_index = i;
return block;
}
bool BlockArray::setSize(size_t newsize) {
return setHistorySize(newsize * 1024 / blocksize);
void BlockArray::unmap()
{
if (lastmap) {
int res = munmap((char *)lastmap, blocksize);
if (res < 0) {
perror("munmap");
}
}
lastmap = 0;
lastmap_index = size_t(-1);
}
bool BlockArray::setHistorySize(size_t newsize) {
bool BlockArray::setSize(size_t newsize)
{
return setHistorySize(newsize * 1024 / blocksize);
}
bool BlockArray::setHistorySize(size_t newsize)
{
// kDebug(1211) << "setHistorySize " << size << " " << newsize;
if (size == newsize) {
return false;
}
unmap();
if (!newsize) {
delete lastblock;
lastblock = 0;
if (ion >= 0) {
close(ion);
if (size == newsize) {
return false;
}
ion = -1;
current = size_t(-1);
return true;
}
if (!size) {
FILE * tmp = tmpfile();
if (!tmp) {
perror("konsole: cannot open temp file.\n");
unmap();
if (!newsize) {
delete lastblock;
lastblock = 0;
if (ion >= 0) {
close(ion);
}
ion = -1;
current = size_t(-1);
return true;
}
if (!size) {
FILE * tmp = tmpfile();
if (!tmp) {
perror("konsole: cannot open temp file.\n");
} else {
ion = dup(fileno(tmp));
if (ion<0) {
perror("konsole: cannot dup temp file.\n");
fclose(tmp);
}
}
if (ion < 0) {
return false;
}
assert(!lastblock);
lastblock = new Block();
size = newsize;
return false;
}
if (newsize > size) {
increaseBuffer();
size = newsize;
return false;
} else {
ion = dup(fileno(tmp));
if (ion<0) {
perror("konsole: cannot dup temp file.\n");
fclose(tmp);
}
decreaseBuffer(newsize);
ftruncate(ion, length*blocksize);
size = newsize;
return true;
}
if (ion < 0) {
return false;
}
assert(!lastblock);
lastblock = new Block();
size = newsize;
return false;
}
if (newsize > size) {
increaseBuffer();
size = newsize;
return false;
} else {
decreaseBuffer(newsize);
ftruncate(ion, length*blocksize);
size = newsize;
return true;
}
}
void moveBlock(FILE * fion, int cursor, int newpos, char * buffer2) {
int res = fseek(fion, cursor * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fread(buffer2, blocksize, 1, fion);
if (res != 1) {
perror("fread");
}
void moveBlock(FILE * fion, int cursor, int newpos, char * buffer2)
{
int res = fseek(fion, cursor * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fread(buffer2, blocksize, 1, fion);
if (res != 1) {
perror("fread");
}
res = fseek(fion, newpos * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fwrite(buffer2, blocksize, 1, fion);
if (res != 1) {
perror("fwrite");
}
// printf("moving block %d to %d\n", cursor, newpos);
res = fseek(fion, newpos * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fwrite(buffer2, blocksize, 1, fion);
if (res != 1) {
perror("fwrite");
}
// printf("moving block %d to %d\n", cursor, newpos);
}
void BlockArray::decreaseBuffer(size_t newsize) {
if (index < newsize) { // still fits in whole
return;
}
void BlockArray::decreaseBuffer(size_t newsize)
{
if (index < newsize) { // still fits in whole
return;
}
int offset = (current - (newsize - 1) + size) % size;
int offset = (current - (newsize - 1) + size) % size;
if (!offset) {
return;
}
if (!offset) {
return;
}
// The Block constructor could do somthing in future...
char * buffer1 = new char[blocksize];
// The Block constructor could do somthing in future...
char * buffer1 = new char[blocksize];
FILE * fion = fdopen(dup(ion), "w+b");
if (!fion) {
delete [] buffer1;
perror("fdopen/dup");
return;
}
int firstblock;
if (current <= newsize) {
firstblock = current + 1;
} else {
firstblock = 0;
}
size_t oldpos;
for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
oldpos = (size + cursor + offset) % size;
moveBlock(fion, oldpos, cursor, buffer1);
if (oldpos < newsize) {
cursor = oldpos;
} else {
cursor++;
}
}
current = newsize - 1;
length = newsize;
FILE * fion = fdopen(dup(ion), "w+b");
if (!fion) {
delete [] buffer1;
perror("fdopen/dup");
return;
}
int firstblock;
if (current <= newsize) {
firstblock = current + 1;
} else {
firstblock = 0;
}
size_t oldpos;
for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
oldpos = (size + cursor + offset) % size;
moveBlock(fion, oldpos, cursor, buffer1);
if (oldpos < newsize) {
cursor = oldpos;
} else {
cursor++;
}
}
current = newsize - 1;
length = newsize;
delete [] buffer1;
fclose(fion);
fclose(fion);
}
void BlockArray::increaseBuffer() {
if (index < size) { // not even wrapped once
return;
}
void BlockArray::increaseBuffer()
{
if (index < size) { // not even wrapped once
return;
}
int offset = (current + size + 1) % size;
if (!offset) { // no moving needed
return;
}
int offset = (current + size + 1) % size;
if (!offset) { // no moving needed
return;
}
// The Block constructor could do somthing in future...
char * buffer1 = new char[blocksize];
char * buffer2 = new char[blocksize];
// The Block constructor could do somthing in future...
char * buffer1 = new char[blocksize];
char * buffer2 = new char[blocksize];
int runs = 1;
int bpr = size; // blocks per run
int runs = 1;
int bpr = size; // blocks per run
if (size % offset == 0) {
bpr = size / offset;
runs = offset;
}
if (size % offset == 0) {
bpr = size / offset;
runs = offset;
}
FILE * fion = fdopen(dup(ion), "w+b");
if (!fion) {
perror("fdopen/dup");
delete [] buffer1;
delete [] buffer2;
return;
}
int res;
for (int i = 0; i < runs; i++) {
// free one block in chain
int firstblock = (offset + i) % size;
res = fseek(fion, firstblock * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fread(buffer1, blocksize, 1, fion);
if (res != 1) {
perror("fread");
}
int newpos = 0;
for (int j = 1, cursor=firstblock; j < bpr; j++) {
cursor = (cursor + offset) % size;
newpos = (cursor - offset + size) % size;
moveBlock(fion, cursor, newpos, buffer2);
}
res = fseek(fion, i * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fwrite(buffer1, blocksize, 1, fion);
if (res != 1) {
perror("fwrite");
}
}
current = size - 1;
length = size;
FILE * fion = fdopen(dup(ion), "w+b");
if (!fion) {
perror("fdopen/dup");
delete [] buffer1;
delete [] buffer2;
return;
}
int res;
for (int i = 0; i < runs; i++) {
// free one block in chain
int firstblock = (offset + i) % size;
res = fseek(fion, firstblock * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fread(buffer1, blocksize, 1, fion);
if (res != 1) {
perror("fread");
}
int newpos = 0;
for (int j = 1, cursor=firstblock; j < bpr; j++) {
cursor = (cursor + offset) % size;
newpos = (cursor - offset + size) % size;
moveBlock(fion, cursor, newpos, buffer2);
}
res = fseek(fion, i * blocksize, SEEK_SET);
if (res) {
perror("fseek");
}
res = fwrite(buffer1, blocksize, 1, fion);
if (res != 1) {
perror("fwrite");
}
}
current = size - 1;
length = size;
delete [] buffer1;
delete [] buffer2;
fclose(fion);
fclose(fion);
}
+72 -70
View File
@@ -30,98 +30,100 @@
#define BlockSize (1 << 12)
#define ENTRIES ((BlockSize - sizeof(size_t) ) / sizeof(unsigned char))
namespace Konsole {
namespace Konsole
{
struct Block {
Block() {
size = 0;
}
unsigned char data[ENTRIES];
size_t size;
Block() {
size = 0;
}
unsigned char data[ENTRIES];
size_t size;
};
// ///////////////////////////////////////////////////////
class BlockArray {
class BlockArray
{
public:
/**
* Creates a history file for holding
* maximal size blocks. If more blocks
* are requested, then it drops earlier
* added ones.
*/
BlockArray();
/**
* Creates a history file for holding
* maximal size blocks. If more blocks
* are requested, then it drops earlier
* added ones.
*/
BlockArray();
/// destructor
~BlockArray();
/// destructor
~BlockArray();
/**
* adds the Block at the end of history.
* This may drop other blocks.
*
* The ownership on the block is transfered.
* An unique index number is returned for accessing
* it later (if not yet dropped then)
*
* Note, that the block may be dropped completely
* if history is turned off.
*/
size_t append(Block * block);
/**
* adds the Block at the end of history.
* This may drop other blocks.
*
* The ownership on the block is transfered.
* An unique index number is returned for accessing
* it later (if not yet dropped then)
*
* Note, that the block may be dropped completely
* if history is turned off.
*/
size_t append(Block * block);
/**
* gets the block at the index. Function may return
* 0 if the block isn't available any more.
*
* The returned block is strictly readonly as only
* maped in memory - and will be invalid on the next
* operation on this class.
*/
const Block * at(size_t index);
/**
* gets the block at the index. Function may return
* 0 if the block isn't available any more.
*
* The returned block is strictly readonly as only
* maped in memory - and will be invalid on the next
* operation on this class.
*/
const Block * at(size_t index);
/**
* reorders blocks as needed. If newsize is null,
* the history is emptied completely. The indices
* returned on append won't change their semantic,
* but they may not be valid after this call.
*/
bool setHistorySize(size_t newsize);
/**
* reorders blocks as needed. If newsize is null,
* the history is emptied completely. The indices
* returned on append won't change their semantic,
* but they may not be valid after this call.
*/
bool setHistorySize(size_t newsize);
size_t newBlock();
size_t newBlock();
Block * lastBlock() const;
Block * lastBlock() const;
/**
* Convenient function to set the size in KBytes
* instead of blocks
*/
bool setSize(size_t newsize);
/**
* Convenient function to set the size in KBytes
* instead of blocks
*/
bool setSize(size_t newsize);
size_t len() const {
return length;
}
size_t len() const {
return length;
}
bool has(size_t index) const;
bool has(size_t index) const;
size_t getCurrent() const {
return current;
}
size_t getCurrent() const {
return current;
}
private:
void unmap();
void increaseBuffer();
void decreaseBuffer(size_t newsize);
void unmap();
void increaseBuffer();
void decreaseBuffer(size_t newsize);
size_t size;
// current always shows to the last inserted block
size_t current;
size_t index;
size_t size;
// current always shows to the last inserted block
size_t current;
size_t index;
Block * lastmap;
size_t lastmap_index;
Block * lastblock;
Block * lastmap;
size_t lastmap_index;
Block * lastblock;
int ion;
size_t length;
int ion;
size_t length;
};
+117 -110
View File
@@ -31,7 +31,8 @@
// Local
#include "CharacterColor.h"
namespace Konsole {
namespace Konsole
{
typedef unsigned char LineProperty;
@@ -54,93 +55,98 @@ static const int LINE_DOUBLEHEIGHT = (1 << 2);
* value, foreground and background colors and a set of rendition attributes
* which specify how it should be drawn.
*/
class Character {
class Character
{
public:
/**
* Constructs a new character.
*
* @param _c The unicode character value of this character.
* @param _f The foreground color used to draw the character.
* @param _b The color used to draw the character's background.
* @param _r A set of rendition flags which specify how this character is to be drawn.
*/
inline Character(quint16 _c = ' ',
CharacterColor _f = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),
CharacterColor _b = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),
quint8 _r = DEFAULT_RENDITION)
: character(_c), rendition(_r), foregroundColor(_f), backgroundColor(_b) {}
union {
/** The unicode character value for this character. */
quint16 character;
/**
* Experimental addition which allows a single Character instance to contain more than
* one unicode character.
* Constructs a new character.
*
* charSequence is a hash code which can be used to look up the unicode
* character sequence in the ExtendedCharTable used to create the sequence.
* @param _c The unicode character value of this character.
* @param _f The foreground color used to draw the character.
* @param _b The color used to draw the character's background.
* @param _r A set of rendition flags which specify how this character is to be drawn.
*/
quint16 charSequence;
};
inline Character(quint16 _c = ' ',
CharacterColor _f = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),
CharacterColor _b = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),
quint8 _r = DEFAULT_RENDITION)
: character(_c), rendition(_r), foregroundColor(_f), backgroundColor(_b) {}
/** A combination of RENDITION flags which specify options for drawing the character. */
quint8 rendition;
union {
/** The unicode character value for this character. */
quint16 character;
/**
* Experimental addition which allows a single Character instance to contain more than
* one unicode character.
*
* charSequence is a hash code which can be used to look up the unicode
* character sequence in the ExtendedCharTable used to create the sequence.
*/
quint16 charSequence;
};
/** The foreground color used to draw this character. */
CharacterColor foregroundColor;
/** The color used to draw this character's background. */
CharacterColor backgroundColor;
/** A combination of RENDITION flags which specify options for drawing the character. */
quint8 rendition;
/**
* Returns true if this character has a transparent background when
* it is drawn with the specified @p palette.
*/
bool isTransparent(const ColorEntry * palette) const;
/**
* Returns true if this character should always be drawn in bold when
* it is drawn with the specified @p palette, independent of whether
* or not the character has the RE_BOLD rendition flag.
*/
bool isBold(const ColorEntry * base) const;
/** The foreground color used to draw this character. */
CharacterColor foregroundColor;
/** The color used to draw this character's background. */
CharacterColor backgroundColor;
/**
* Compares two characters and returns true if they have the same unicode character value,
* rendition and colors.
*/
friend bool operator == (const Character & a, const Character & b);
/**
* Compares two characters and returns true if they have different unicode character values,
* renditions or colors.
*/
friend bool operator != (const Character & a, const Character & b);
/**
* Returns true if this character has a transparent background when
* it is drawn with the specified @p palette.
*/
bool isTransparent(const ColorEntry * palette) const;
/**
* Returns true if this character should always be drawn in bold when
* it is drawn with the specified @p palette, independent of whether
* or not the character has the RE_BOLD rendition flag.
*/
bool isBold(const ColorEntry * base) const;
/**
* Compares two characters and returns true if they have the same unicode character value,
* rendition and colors.
*/
friend bool operator == (const Character & a, const Character & b);
/**
* Compares two characters and returns true if they have different unicode character values,
* renditions or colors.
*/
friend bool operator != (const Character & a, const Character & b);
};
inline bool operator == (const Character & a, const Character & b) {
return a.character == b.character &&
a.rendition == b.rendition &&
a.foregroundColor == b.foregroundColor &&
a.backgroundColor == b.backgroundColor;
inline bool operator == (const Character & a, const Character & b)
{
return a.character == b.character &&
a.rendition == b.rendition &&
a.foregroundColor == b.foregroundColor &&
a.backgroundColor == b.backgroundColor;
}
inline bool operator != (const Character & a, const Character & b) {
return a.character != b.character ||
a.rendition != b.rendition ||
a.foregroundColor != b.foregroundColor ||
a.backgroundColor != b.backgroundColor;
inline bool operator != (const Character & a, const Character & b)
{
return a.character != b.character ||
a.rendition != b.rendition ||
a.foregroundColor != b.foregroundColor ||
a.backgroundColor != b.backgroundColor;
}
inline bool Character::isTransparent(const ColorEntry * base) const {
return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) &&
base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].transparent)
|| ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) &&
base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].transparent);
inline bool Character::isTransparent(const ColorEntry * base) const
{
return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) &&
base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].transparent)
|| ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) &&
base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].transparent);
}
inline bool Character::isBold(const ColorEntry * base) const {
return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) &&
base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].bold)
|| ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) &&
base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].bold);
inline bool Character::isBold(const ColorEntry * base) const
{
return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) &&
base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].bold)
|| ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) &&
base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].bold);
}
extern unsigned short vt100_graphics[32];
@@ -152,48 +158,49 @@ extern unsigned short vt100_graphics[32];
* character ( ushort ) so that it can occupy the same space in
* a structure.
*/
class ExtendedCharTable {
class ExtendedCharTable
{
public:
/** Constructs a new character table. */
ExtendedCharTable();
~ExtendedCharTable();
/** Constructs a new character table. */
ExtendedCharTable();
~ExtendedCharTable();
/**
* Adds a sequences of unicode characters to the table and returns
* a hash code which can be used later to look up the sequence
* using lookupExtendedChar()
*
* If the same sequence already exists in the table, the hash
* of the existing sequence will be returned.
*
* @param unicodePoints An array of unicode character points
* @param length Length of @p unicodePoints
*/
ushort createExtendedChar(ushort * unicodePoints , ushort length);
/**
* Looks up and returns a pointer to a sequence of unicode characters
* which was added to the table using createExtendedChar().
*
* @param hash The hash key returned by createExtendedChar()
* @param length This variable is set to the length of the
* character sequence.
*
* @return A unicode character sequence of size @p length.
*/
ushort * lookupExtendedChar(ushort hash , ushort & length) const;
/**
* Adds a sequences of unicode characters to the table and returns
* a hash code which can be used later to look up the sequence
* using lookupExtendedChar()
*
* If the same sequence already exists in the table, the hash
* of the existing sequence will be returned.
*
* @param unicodePoints An array of unicode character points
* @param length Length of @p unicodePoints
*/
ushort createExtendedChar(ushort * unicodePoints , ushort length);
/**
* Looks up and returns a pointer to a sequence of unicode characters
* which was added to the table using createExtendedChar().
*
* @param hash The hash key returned by createExtendedChar()
* @param length This variable is set to the length of the
* character sequence.
*
* @return A unicode character sequence of size @p length.
*/
ushort * lookupExtendedChar(ushort hash , ushort & length) const;
/** The global ExtendedCharTable instance. */
static ExtendedCharTable instance;
/** The global ExtendedCharTable instance. */
static ExtendedCharTable instance;
private:
// calculates the hash key of a sequence of unicode points of size 'length'
ushort extendedCharHash(ushort * unicodePoints , ushort length) const;
// tests whether the entry in the table specified by 'hash' matches the
// character sequence 'unicodePoints' of size 'length'
bool extendedCharMatch(ushort hash , ushort * unicodePoints , ushort length) const;
// internal, maps hash keys to character sequence buffers. The first ushort
// in each value is the length of the buffer, followed by the ushorts in the buffer
// themselves.
QHash<ushort,ushort *> extendedCharTable;
// calculates the hash key of a sequence of unicode points of size 'length'
ushort extendedCharHash(ushort * unicodePoints , ushort length) const;
// tests whether the entry in the table specified by 'hash' matches the
// character sequence 'unicodePoints' of size 'length'
bool extendedCharMatch(ushort hash , ushort * unicodePoints , ushort length) const;
// internal, maps hash keys to character sequence buffers. The first ushort
// in each value is the length of the buffer, followed by the ushorts in the buffer
// themselves.
QHash<ushort,ushort *> extendedCharTable;
};
}
+172 -165
View File
@@ -28,7 +28,8 @@
// Qt
#include <QtGui/QColor>
namespace Konsole {
namespace Konsole
{
/**
* An entry in a terminal display's color palette.
@@ -43,45 +44,46 @@ namespace Konsole {
* display should avoid drawing the background for any characters
* using the entry as a background.
*/
class ColorEntry {
class ColorEntry
{
public:
/**
* Constructs a new color palette entry.
*
* @param c The color value for this entry.
* @param tr Specifies that the color should be transparent when used as a background color.
* @param b Specifies that text drawn with this color should be bold.
*/
ColorEntry(QColor c, bool tr, bool b) : color(c), transparent(tr), bold(b) {}
/**
* Constructs a new color palette entry.
*
* @param c The color value for this entry.
* @param tr Specifies that the color should be transparent when used as a background color.
* @param b Specifies that text drawn with this color should be bold.
*/
ColorEntry(QColor c, bool tr, bool b) : color(c), transparent(tr), bold(b) {}
/**
* Constructs a new color palette entry with an undefined color, and
* with the transparent and bold flags set to false.
*/
ColorEntry() : transparent(false), bold(false) {}
/**
* Constructs a new color palette entry with an undefined color, and
* with the transparent and bold flags set to false.
*/
ColorEntry() : transparent(false), bold(false) {}
/**
* Sets the color, transparency and boldness of this color to those of @p rhs.
*/
void operator=(const ColorEntry & rhs) {
color = rhs.color;
transparent = rhs.transparent;
bold = rhs.bold;
}
/**
* Sets the color, transparency and boldness of this color to those of @p rhs.
*/
void operator=(const ColorEntry & rhs) {
color = rhs.color;
transparent = rhs.transparent;
bold = rhs.bold;
}
/** The color value of this entry for display. */
QColor color;
/** The color value of this entry for display. */
QColor color;
/**
* If true character backgrounds using this color should be transparent.
* This is not applicable when the color is used to render text.
*/
bool transparent;
/**
* If true characters drawn using this color should be bold.
* This is not applicable when the color is used to draw a character's background.
*/
bool bold;
/**
* If true character backgrounds using this color should be transparent.
* This is not applicable when the color is used to render text.
*/
bool transparent;
/**
* If true characters drawn using this color should be bold.
* This is not applicable when the color is used to draw a character's background.
*/
bool bold;
};
@@ -104,19 +106,19 @@ static const ColorEntry base_color_table[TABLE_COLORS] =
// gamma correction for the dim colors to compensate for bright X screens.
// It contains the 8 ansiterm/xterm colors in 2 intensities.
{
// Fixme: could add faint colors here, also.
// normal
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
// intensiv
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
// Fixme: could add faint colors here, also.
// normal
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
// intensiv
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
};
/* CharacterColor is a union of the various color spaces.
@@ -144,153 +146,158 @@ static const ColorEntry base_color_table[TABLE_COLORS] =
/**
* Describes the color of a single character in the terminal.
*/
class CharacterColor {
friend class Character;
class CharacterColor
{
friend class Character;
public:
/** Constructs a new CharacterColor whoose color and color space are undefined. */
CharacterColor()
: _colorSpace(COLOR_SPACE_UNDEFINED),
_u(0),
_v(0),
_w(0)
{}
/** Constructs a new CharacterColor whoose color and color space are undefined. */
CharacterColor()
: _colorSpace(COLOR_SPACE_UNDEFINED),
_u(0),
_v(0),
_w(0) {}
/**
* Constructs a new CharacterColor using the specified @p colorSpace and with
* color value @p co
*
* The meaning of @p co depends on the @p colorSpace used.
*
* TODO : Document how @p co relates to @p colorSpace
*
* TODO : Add documentation about available color spaces.
*/
CharacterColor(quint8 colorSpace, int co)
: _colorSpace(colorSpace),
_u(0),
_v(0),
_w(0) {
switch (colorSpace) {
case COLOR_SPACE_DEFAULT:
_u = co & 1;
break;
case COLOR_SPACE_SYSTEM:
_u = co & 7;
_v = (co >> 3) & 1;
break;
case COLOR_SPACE_256:
_u = co & 255;
break;
case COLOR_SPACE_RGB:
_u = co >> 16;
_v = co >> 8;
_w = co;
break;
default:
_colorSpace = COLOR_SPACE_UNDEFINED;
/**
* Constructs a new CharacterColor using the specified @p colorSpace and with
* color value @p co
*
* The meaning of @p co depends on the @p colorSpace used.
*
* TODO : Document how @p co relates to @p colorSpace
*
* TODO : Add documentation about available color spaces.
*/
CharacterColor(quint8 colorSpace, int co)
: _colorSpace(colorSpace),
_u(0),
_v(0),
_w(0) {
switch (colorSpace) {
case COLOR_SPACE_DEFAULT:
_u = co & 1;
break;
case COLOR_SPACE_SYSTEM:
_u = co & 7;
_v = (co >> 3) & 1;
break;
case COLOR_SPACE_256:
_u = co & 255;
break;
case COLOR_SPACE_RGB:
_u = co >> 16;
_v = co >> 8;
_w = co;
break;
default:
_colorSpace = COLOR_SPACE_UNDEFINED;
}
}
}
/**
* Returns true if this character color entry is valid.
*/
bool isValid() {
return _colorSpace != COLOR_SPACE_UNDEFINED;
}
/**
* Returns true if this character color entry is valid.
*/
bool isValid() {
return _colorSpace != COLOR_SPACE_UNDEFINED;
}
/**
* Toggles the value of this color between a normal system color and the corresponding intensive
* system color.
*
* This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
* color spaces.
*/
void toggleIntensive();
/**
* Toggles the value of this color between a normal system color and the corresponding intensive
* system color.
*
* This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
* color spaces.
*/
void toggleIntensive();
/**
* Returns the color within the specified color @palette
*
* The @p palette is only used if this color is one of the 16 system colors, otherwise
* it is ignored.
*/
QColor color(const ColorEntry * palette) const;
/**
* Returns the color within the specified color @palette
*
* The @p palette is only used if this color is one of the 16 system colors, otherwise
* it is ignored.
*/
QColor color(const ColorEntry * palette) const;
/**
* Compares two colors and returns true if they represent the same color value and
* use the same color space.
*/
friend bool operator == (const CharacterColor & a, const CharacterColor & b);
/**
* Compares two colors and returns true if they represent different color values
* or use different color spaces.
*/
friend bool operator != (const CharacterColor & a, const CharacterColor & b);
/**
* Compares two colors and returns true if they represent the same color value and
* use the same color space.
*/
friend bool operator == (const CharacterColor & a, const CharacterColor & b);
/**
* Compares two colors and returns true if they represent different color values
* or use different color spaces.
*/
friend bool operator != (const CharacterColor & a, const CharacterColor & b);
private:
quint8 _colorSpace;
quint8 _colorSpace;
// bytes storing the character color
quint8 _u;
quint8 _v;
quint8 _w;
// bytes storing the character color
quint8 _u;
quint8 _v;
quint8 _w;
};
inline bool operator == (const CharacterColor & a, const CharacterColor & b) {
return *reinterpret_cast<const quint32 *>(&a._colorSpace) ==
*reinterpret_cast<const quint32 *>(&b._colorSpace);
inline bool operator == (const CharacterColor & a, const CharacterColor & b)
{
return *reinterpret_cast<const quint32 *>(&a._colorSpace) ==
*reinterpret_cast<const quint32 *>(&b._colorSpace);
}
inline bool operator != (const CharacterColor & a, const CharacterColor & b) {
return *reinterpret_cast<const quint32 *>(&a._colorSpace) !=
*reinterpret_cast<const quint32 *>(&b._colorSpace);
inline bool operator != (const CharacterColor & a, const CharacterColor & b)
{
return *reinterpret_cast<const quint32 *>(&a._colorSpace) !=
*reinterpret_cast<const quint32 *>(&b._colorSpace);
}
inline const QColor color256(quint8 u, const ColorEntry * base) {
// 0.. 16: system colors
if (u < 8) {
return base[u+2 ].color;
}
u -= 8;
if (u < 8) {
return base[u+2+BASE_COLORS].color;
}
u -= 8;
inline const QColor color256(quint8 u, const ColorEntry * base)
{
// 0.. 16: system colors
if (u < 8) {
return base[u+2 ].color;
}
u -= 8;
if (u < 8) {
return base[u+2+BASE_COLORS].color;
}
u -= 8;
// 16..231: 6x6x6 rgb color cube
if (u < 216) return QColor(255*((u/36)%6)/5,
255*((u/ 6)%6)/5,
255*((u/ 1)%6)/5);
u -= 216;
// 16..231: 6x6x6 rgb color cube
if (u < 216) return QColor(255*((u/36)%6)/5,
255*((u/ 6)%6)/5,
255*((u/ 1)%6)/5);
u -= 216;
// 232..255: gray, leaving out black and white
int gray = u*10+8;
return QColor(gray,gray,gray);
// 232..255: gray, leaving out black and white
int gray = u*10+8;
return QColor(gray,gray,gray);
}
inline QColor CharacterColor::color(const ColorEntry * base) const {
switch (_colorSpace) {
inline QColor CharacterColor::color(const ColorEntry * base) const
{
switch (_colorSpace) {
case COLOR_SPACE_DEFAULT:
return base[_u+0+(_v?BASE_COLORS:0)].color;
return base[_u+0+(_v?BASE_COLORS:0)].color;
case COLOR_SPACE_SYSTEM:
return base[_u+2+(_v?BASE_COLORS:0)].color;
return base[_u+2+(_v?BASE_COLORS:0)].color;
case COLOR_SPACE_256:
return color256(_u,base);
return color256(_u,base);
case COLOR_SPACE_RGB:
return QColor(_u,_v,_w);
return QColor(_u,_v,_w);
case COLOR_SPACE_UNDEFINED:
return QColor();
}
return QColor();
}
Q_ASSERT(false); // invalid color space
Q_ASSERT(false); // invalid color space
return QColor();
return QColor();
}
inline void CharacterColor::toggleIntensive() {
if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT) {
_v = !_v;
}
inline void CharacterColor::toggleIntensive()
{
if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT) {
_v = !_v;
}
}
+33 -33
View File
@@ -6,45 +6,45 @@
using namespace Konsole;
static const ColorEntry whiteonblack_color_table[TABLE_COLORS] = {
// normal
ColorEntry(QColor(0xFF,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0x00,0x00,0x00), 1, 0 ), // Dfore, Dback
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
// intensiv
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
// normal
ColorEntry(QColor(0xFF,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0x00,0x00,0x00), 1, 0 ), // Dfore, Dback
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
// intensiv
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
};
static const ColorEntry greenonblack_color_table[TABLE_COLORS] = {
ColorEntry(QColor( 24, 240, 24), 0, 0), ColorEntry(QColor( 0, 0, 0), 1, 0),
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 178, 24, 24), 0, 0),
ColorEntry(QColor( 24, 178, 24), 0, 0), ColorEntry(QColor( 178, 104, 24), 0, 0),
ColorEntry(QColor( 24, 24, 178), 0, 0), ColorEntry(QColor( 178, 24, 178), 0, 0),
ColorEntry(QColor( 24, 178, 178), 0, 0), ColorEntry(QColor( 178, 178, 178), 0, 0),
// intensive colors
ColorEntry(QColor( 24, 240, 24), 0, 1 ), ColorEntry(QColor( 0, 0, 0), 1, 0 ),
ColorEntry(QColor( 104, 104, 104), 0, 0 ), ColorEntry(QColor( 255, 84, 84), 0, 0 ),
ColorEntry(QColor( 84, 255, 84), 0, 0 ), ColorEntry(QColor( 255, 255, 84), 0, 0 ),
ColorEntry(QColor( 84, 84, 255), 0, 0 ), ColorEntry(QColor( 255, 84, 255), 0, 0 ),
ColorEntry(QColor( 84, 255, 255), 0, 0 ), ColorEntry(QColor( 255, 255, 255), 0, 0 )
ColorEntry(QColor( 24, 240, 24), 0, 0), ColorEntry(QColor( 0, 0, 0), 1, 0),
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 178, 24, 24), 0, 0),
ColorEntry(QColor( 24, 178, 24), 0, 0), ColorEntry(QColor( 178, 104, 24), 0, 0),
ColorEntry(QColor( 24, 24, 178), 0, 0), ColorEntry(QColor( 178, 24, 178), 0, 0),
ColorEntry(QColor( 24, 178, 178), 0, 0), ColorEntry(QColor( 178, 178, 178), 0, 0),
// intensive colors
ColorEntry(QColor( 24, 240, 24), 0, 1 ), ColorEntry(QColor( 0, 0, 0), 1, 0 ),
ColorEntry(QColor( 104, 104, 104), 0, 0 ), ColorEntry(QColor( 255, 84, 84), 0, 0 ),
ColorEntry(QColor( 84, 255, 84), 0, 0 ), ColorEntry(QColor( 255, 255, 84), 0, 0 ),
ColorEntry(QColor( 84, 84, 255), 0, 0 ), ColorEntry(QColor( 255, 84, 255), 0, 0 ),
ColorEntry(QColor( 84, 255, 255), 0, 0 ), ColorEntry(QColor( 255, 255, 255), 0, 0 )
};
static const ColorEntry blackonlightyellow_color_table[TABLE_COLORS] = {
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 255, 255, 221), 1, 0),
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 178, 24, 24), 0, 0),
ColorEntry(QColor( 24, 178, 24), 0, 0), ColorEntry(QColor( 178, 104, 24), 0, 0),
ColorEntry(QColor( 24, 24, 178), 0, 0), ColorEntry(QColor( 178, 24, 178), 0, 0),
ColorEntry(QColor( 24, 178, 178), 0, 0), ColorEntry(QColor( 178, 178, 178), 0, 0),
ColorEntry(QColor( 0, 0, 0), 0, 1), ColorEntry(QColor( 255, 255, 221), 1, 0),
ColorEntry(QColor(104, 104, 104), 0, 0), ColorEntry(QColor( 255, 84, 84), 0, 0),
ColorEntry(QColor( 84, 255, 84), 0, 0), ColorEntry(QColor( 255, 255, 84), 0, 0),
ColorEntry(QColor( 84, 84, 255), 0, 0), ColorEntry(QColor( 255, 84, 255), 0, 0),
ColorEntry(QColor( 84, 255, 255), 0, 0), ColorEntry(QColor( 255, 255, 255), 0, 0)
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 255, 255, 221), 1, 0),
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 178, 24, 24), 0, 0),
ColorEntry(QColor( 24, 178, 24), 0, 0), ColorEntry(QColor( 178, 104, 24), 0, 0),
ColorEntry(QColor( 24, 24, 178), 0, 0), ColorEntry(QColor( 178, 24, 178), 0, 0),
ColorEntry(QColor( 24, 178, 178), 0, 0), ColorEntry(QColor( 178, 178, 178), 0, 0),
ColorEntry(QColor( 0, 0, 0), 0, 1), ColorEntry(QColor( 255, 255, 221), 1, 0),
ColorEntry(QColor(104, 104, 104), 0, 0), ColorEntry(QColor( 255, 84, 84), 0, 0),
ColorEntry(QColor( 84, 255, 84), 0, 0), ColorEntry(QColor( 255, 255, 84), 0, 0),
ColorEntry(QColor( 84, 84, 255), 0, 0), ColorEntry(QColor( 255, 84, 255), 0, 0),
ColorEntry(QColor( 84, 255, 255), 0, 0), ColorEntry(QColor( 255, 255, 255), 0, 0)
};
+299 -264
View File
@@ -63,115 +63,128 @@ using namespace Konsole;
*/
Emulation::Emulation() :
_currentScreen(0),
_codec(0),
_decoder(0),
_keyTranslator(0),
_usesMouse(false) {
_currentScreen(0),
_codec(0),
_decoder(0),
_keyTranslator(0),
_usesMouse(false)
{
// create screens with a default size
_screen[0] = new Screen(40,80);
_screen[1] = new Screen(40,80);
_currentScreen = _screen[0];
// create screens with a default size
_screen[0] = new Screen(40,80);
_screen[1] = new Screen(40,80);
_currentScreen = _screen[0];
QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) );
QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) );
QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) );
QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) );
// listen for mouse status changes
connect( this , SIGNAL(programUsesMouseChanged(bool)) ,
SLOT(usesMouseChanged(bool)) );
// listen for mouse status changes
connect( this , SIGNAL(programUsesMouseChanged(bool)) ,
SLOT(usesMouseChanged(bool)) );
}
bool Emulation::programUsesMouse() const {
return _usesMouse;
bool Emulation::programUsesMouse() const
{
return _usesMouse;
}
void Emulation::usesMouseChanged(bool usesMouse) {
_usesMouse = usesMouse;
void Emulation::usesMouseChanged(bool usesMouse)
{
_usesMouse = usesMouse;
}
ScreenWindow * Emulation::createWindow() {
ScreenWindow * window = new ScreenWindow();
window->setScreen(_currentScreen);
_windows << window;
ScreenWindow * Emulation::createWindow()
{
ScreenWindow * window = new ScreenWindow();
window->setScreen(_currentScreen);
_windows << window;
connect(window , SIGNAL(selectionChanged()),
this , SLOT(bufferedUpdate()));
connect(window , SIGNAL(selectionChanged()),
this , SLOT(bufferedUpdate()));
connect(this , SIGNAL(outputChanged()),
window , SLOT(notifyOutputChanged()) );
return window;
connect(this , SIGNAL(outputChanged()),
window , SLOT(notifyOutputChanged()) );
return window;
}
/*!
*/
Emulation::~Emulation() {
QListIterator<ScreenWindow *> windowIter(_windows);
Emulation::~Emulation()
{
QListIterator<ScreenWindow *> windowIter(_windows);
while (windowIter.hasNext()) {
delete windowIter.next();
}
while (windowIter.hasNext()) {
delete windowIter.next();
}
delete _screen[0];
delete _screen[1];
delete _decoder;
delete _screen[0];
delete _screen[1];
delete _decoder;
}
/*! change between primary and alternate _screen
*/
void Emulation::setScreen(int n) {
Screen * old = _currentScreen;
_currentScreen = _screen[n&1];
if (_currentScreen != old) {
old->setBusySelecting(false);
void Emulation::setScreen(int n)
{
Screen * old = _currentScreen;
_currentScreen = _screen[n&1];
if (_currentScreen != old) {
old->setBusySelecting(false);
// tell all windows onto this emulation to switch to the newly active _screen
QListIterator<ScreenWindow *> windowIter(_windows);
while ( windowIter.hasNext() ) {
windowIter.next()->setScreen(_currentScreen);
// tell all windows onto this emulation to switch to the newly active _screen
QListIterator<ScreenWindow *> windowIter(_windows);
while ( windowIter.hasNext() ) {
windowIter.next()->setScreen(_currentScreen);
}
}
}
}
void Emulation::clearHistory() {
_screen[0]->setScroll( _screen[0]->getScroll() , false );
void Emulation::clearHistory()
{
_screen[0]->setScroll( _screen[0]->getScroll() , false );
}
void Emulation::setHistory(const HistoryType & t) {
_screen[0]->setScroll(t);
void Emulation::setHistory(const HistoryType & t)
{
_screen[0]->setScroll(t);
showBulk();
showBulk();
}
const HistoryType & Emulation::history() {
return _screen[0]->getScroll();
const HistoryType & Emulation::history()
{
return _screen[0]->getScroll();
}
void Emulation::setCodec(const QTextCodec * qtc) {
Q_ASSERT( qtc );
void Emulation::setCodec(const QTextCodec * qtc)
{
Q_ASSERT( qtc );
_codec = qtc;
delete _decoder;
_decoder = _codec->makeDecoder();
_codec = qtc;
delete _decoder;
_decoder = _codec->makeDecoder();
emit useUtf8Request(utf8());
emit useUtf8Request(utf8());
}
void Emulation::setCodec(EmulationCodec codec) {
if ( codec == Utf8Codec ) {
setCodec( QTextCodec::codecForName("utf8") );
} else if ( codec == LocaleCodec ) {
setCodec( QTextCodec::codecForLocale() );
}
void Emulation::setCodec(EmulationCodec codec)
{
if ( codec == Utf8Codec ) {
setCodec( QTextCodec::codecForName("utf8") );
} else if ( codec == LocaleCodec ) {
setCodec( QTextCodec::codecForLocale() );
}
}
void Emulation::setKeyBindings(const QString & name) {
_keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
void Emulation::setKeyBindings(const QString & name)
{
_keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
}
QString Emulation::keyBindings() {
return _keyTranslator->name();
QString Emulation::keyBindings()
{
return _keyTranslator->name();
}
@@ -191,27 +204,27 @@ void Emulation::receiveChar(int c)
// process application unicode input to terminal
// this is a trivial scanner
{
c &= 0xff;
switch (c) {
c &= 0xff;
switch (c) {
case '\b' :
_currentScreen->BackSpace();
break;
_currentScreen->BackSpace();
break;
case '\t' :
_currentScreen->Tabulate();
break;
_currentScreen->Tabulate();
break;
case '\n' :
_currentScreen->NewLine();
break;
_currentScreen->NewLine();
break;
case '\r' :
_currentScreen->Return();
break;
_currentScreen->Return();
break;
case 0x07 :
emit stateSet(NOTIFYBELL);
break;
emit stateSet(NOTIFYBELL);
break;
default :
_currentScreen->ShowCharacter(c);
break;
};
_currentScreen->ShowCharacter(c);
break;
};
}
/* ------------------------------------------------------------------------- */
@@ -223,25 +236,28 @@ void Emulation::receiveChar(int c)
/*!
*/
void Emulation::sendKeyEvent( QKeyEvent * ev ) {
emit stateSet(NOTIFYNORMAL);
void Emulation::sendKeyEvent( QKeyEvent * ev )
{
emit stateSet(NOTIFYNORMAL);
if (!ev->text().isEmpty()) {
// A block of text
// Note that the text is proper unicode.
// We should do a conversion here, but since this
// routine will never be used, we simply emit plain ascii.
//emit sendBlock(ev->text().toAscii(),ev->text().length());
emit sendData(ev->text().toUtf8(),ev->text().length());
}
if (!ev->text().isEmpty()) {
// A block of text
// Note that the text is proper unicode.
// We should do a conversion here, but since this
// routine will never be used, we simply emit plain ascii.
//emit sendBlock(ev->text().toAscii(),ev->text().length());
emit sendData(ev->text().toUtf8(),ev->text().length());
}
}
void Emulation::sendString(const char *,int) {
// default implementation does nothing
void Emulation::sendString(const char *,int)
{
// default implementation does nothing
}
void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/) {
// default implementation does nothing
void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/)
{
// default implementation does nothing
}
// Unblocking, Byte to Unicode translation --------------------------------- --
@@ -251,28 +267,29 @@ void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int
TODO: Character composition from the old code. See #96536
*/
void Emulation::receiveData(const char * text, int length) {
emit stateSet(NOTIFYACTIVITY);
void Emulation::receiveData(const char * text, int length)
{
emit stateSet(NOTIFYACTIVITY);
bufferedUpdate();
bufferedUpdate();
QString unicodeText = _decoder->toUnicode(text,length);
QString unicodeText = _decoder->toUnicode(text,length);
//send characters to terminal emulator
for (int i=0; i<unicodeText.length(); i++) {
receiveChar(unicodeText[i].unicode());
}
//look for z-modem indicator
//-- someone who understands more about z-modems that I do may be able to move
//this check into the above for loop?
for (int i=0; i<length; i++) {
if (text[i] == '\030') {
if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0)) {
emit zmodemDetected();
}
//send characters to terminal emulator
for (int i=0; i<unicodeText.length(); i++) {
receiveChar(unicodeText[i].unicode());
}
//look for z-modem indicator
//-- someone who understands more about z-modems that I do may be able to move
//this check into the above for loop?
for (int i=0; i<length; i++) {
if (text[i] == '\030') {
if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0)) {
emit zmodemDetected();
}
}
}
}
}
//OLDER VERSION
@@ -327,62 +344,69 @@ void Emulation::receiveData(const char * text, int length) {
// Selection --------------------------------------------------------------- --
#if 0
void Emulation::onSelectionBegin(const int x, const int y, const bool columnmode) {
if (!connected) {
return;
}
_currentScreen->setSelectionStart( x,y,columnmode);
showBulk();
}
void Emulation::onSelectionExtend(const int x, const int y) {
if (!connected) {
return;
}
_currentScreen->setSelectionEnd(x,y);
showBulk();
}
void Emulation::setSelection(const bool preserve_line_breaks) {
if (!connected) {
return;
}
QString t = _currentScreen->selectedText(preserve_line_breaks);
if (!t.isNull()) {
QListIterator< TerminalDisplay * > viewIter(_views);
while (viewIter.hasNext()) {
viewIter.next()->setSelection(t);
void Emulation::onSelectionBegin(const int x, const int y, const bool columnmode)
{
if (!connected) {
return;
}
}
_currentScreen->setSelectionStart( x,y,columnmode);
showBulk();
}
void Emulation::testIsSelected(const int x, const int y, bool & selected) {
if (!connected) {
return;
}
selected=_currentScreen->isSelected(x,y);
void Emulation::onSelectionExtend(const int x, const int y)
{
if (!connected) {
return;
}
_currentScreen->setSelectionEnd(x,y);
showBulk();
}
void Emulation::clearSelection() {
if (!connected) {
return;
}
_currentScreen->clearSelection();
showBulk();
void Emulation::setSelection(const bool preserve_line_breaks)
{
if (!connected) {
return;
}
QString t = _currentScreen->selectedText(preserve_line_breaks);
if (!t.isNull()) {
QListIterator< TerminalDisplay * > viewIter(_views);
while (viewIter.hasNext()) {
viewIter.next()->setSelection(t);
}
}
}
void Emulation::testIsSelected(const int x, const int y, bool & selected)
{
if (!connected) {
return;
}
selected=_currentScreen->isSelected(x,y);
}
void Emulation::clearSelection()
{
if (!connected) {
return;
}
_currentScreen->clearSelection();
showBulk();
}
#endif
void Emulation::writeToStream( TerminalCharacterDecoder * _decoder ,
int startLine ,
int endLine) {
_currentScreen->writeToStream(_decoder,startLine,endLine);
int endLine)
{
_currentScreen->writeToStream(_decoder,startLine,endLine);
}
int Emulation::lineCount() {
// sum number of lines currently on _screen plus number of lines in history
return _currentScreen->getLines() + _currentScreen->getHistLines();
int Emulation::lineCount()
{
// sum number of lines currently on _screen plus number of lines in history
return _currentScreen->getLines() + _currentScreen->getHistLines();
}
// Refreshing -------------------------------------------------------------- --
@@ -392,124 +416,135 @@ int Emulation::lineCount() {
/*!
*/
void Emulation::showBulk() {
_bulkTimer1.stop();
_bulkTimer2.stop();
void Emulation::showBulk()
{
_bulkTimer1.stop();
_bulkTimer2.stop();
emit outputChanged();
emit outputChanged();
_currentScreen->resetScrolledLines();
_currentScreen->resetDroppedLines();
_currentScreen->resetScrolledLines();
_currentScreen->resetDroppedLines();
}
void Emulation::bufferedUpdate() {
_bulkTimer1.setSingleShot(true);
_bulkTimer1.start(BULK_TIMEOUT1);
if (!_bulkTimer2.isActive()) {
_bulkTimer2.setSingleShot(true);
_bulkTimer2.start(BULK_TIMEOUT2);
}
}
char Emulation::getErase() const {
return '\b';
}
void Emulation::setImageSize(int lines, int columns) {
//kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec();
Q_ASSERT( lines > 0 );
Q_ASSERT( columns > 0 );
_screen[0]->resizeImage(lines,columns);
_screen[1]->resizeImage(lines,columns);
emit imageSizeChanged(lines,columns);
bufferedUpdate();
}
QSize Emulation::imageSize() {
return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
}
ushort ExtendedCharTable::extendedCharHash(ushort * unicodePoints , ushort length) const {
ushort hash = 0;
for ( ushort i = 0 ; i < length ; i++ ) {
hash = 31*hash + unicodePoints[i];
}
return hash;
}
bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort * unicodePoints , ushort length) const {
ushort * entry = extendedCharTable[hash];
// compare given length with stored sequence length ( given as the first ushort in the
// stored buffer )
if ( entry == 0 || entry[0] != length ) {
return false;
}
// if the lengths match, each character must be checked. the stored buffer starts at
// entry[1]
for ( int i = 0 ; i < length ; i++ ) {
if ( entry[i+1] != unicodePoints[i] ) {
return false;
void Emulation::bufferedUpdate()
{
_bulkTimer1.setSingleShot(true);
_bulkTimer1.start(BULK_TIMEOUT1);
if (!_bulkTimer2.isActive()) {
_bulkTimer2.setSingleShot(true);
_bulkTimer2.start(BULK_TIMEOUT2);
}
}
return true;
}
ushort ExtendedCharTable::createExtendedChar(ushort * unicodePoints , ushort length) {
// look for this sequence of points in the table
ushort hash = extendedCharHash(unicodePoints,length);
// check existing entry for match
while ( extendedCharTable.contains(hash) ) {
if ( extendedCharMatch(hash,unicodePoints,length) ) {
// this sequence already has an entry in the table,
// return its hash
return hash;
char Emulation::getErase() const
{
return '\b';
}
void Emulation::setImageSize(int lines, int columns)
{
//kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec();
Q_ASSERT( lines > 0 );
Q_ASSERT( columns > 0 );
_screen[0]->resizeImage(lines,columns);
_screen[1]->resizeImage(lines,columns);
emit imageSizeChanged(lines,columns);
bufferedUpdate();
}
QSize Emulation::imageSize()
{
return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
}
ushort ExtendedCharTable::extendedCharHash(ushort * unicodePoints , ushort length) const
{
ushort hash = 0;
for ( ushort i = 0 ; i < length ; i++ ) {
hash = 31*hash + unicodePoints[i];
}
return hash;
}
bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort * unicodePoints , ushort length) const
{
ushort * entry = extendedCharTable[hash];
// compare given length with stored sequence length ( given as the first ushort in the
// stored buffer )
if ( entry == 0 || entry[0] != length ) {
return false;
}
// if the lengths match, each character must be checked. the stored buffer starts at
// entry[1]
for ( int i = 0 ; i < length ; i++ ) {
if ( entry[i+1] != unicodePoints[i] ) {
return false;
}
}
return true;
}
ushort ExtendedCharTable::createExtendedChar(ushort * unicodePoints , ushort length)
{
// look for this sequence of points in the table
ushort hash = extendedCharHash(unicodePoints,length);
// check existing entry for match
while ( extendedCharTable.contains(hash) ) {
if ( extendedCharMatch(hash,unicodePoints,length) ) {
// this sequence already has an entry in the table,
// return its hash
return hash;
} else {
// if hash is already used by another, different sequence of unicode character
// points then try next hash
hash++;
}
}
// add the new sequence to the table and
// return that index
ushort * buffer = new ushort[length+1];
buffer[0] = length;
for ( int i = 0 ; i < length ; i++ ) {
buffer[i+1] = unicodePoints[i];
}
extendedCharTable.insert(hash,buffer);
return hash;
}
ushort * ExtendedCharTable::lookupExtendedChar(ushort hash , ushort & length) const
{
// lookup index in table and if found, set the length
// argument and return a pointer to the character sequence
ushort * buffer = extendedCharTable[hash];
if ( buffer ) {
length = buffer[0];
return buffer+1;
} else {
// if hash is already used by another, different sequence of unicode character
// points then try next hash
hash++;
length = 0;
return 0;
}
}
// add the new sequence to the table and
// return that index
ushort * buffer = new ushort[length+1];
buffer[0] = length;
for ( int i = 0 ; i < length ; i++ ) {
buffer[i+1] = unicodePoints[i];
}
extendedCharTable.insert(hash,buffer);
return hash;
}
ushort * ExtendedCharTable::lookupExtendedChar(ushort hash , ushort & length) const {
// lookup index in table and if found, set the length
// argument and return a pointer to the character sequence
ushort * buffer = extendedCharTable[hash];
if ( buffer ) {
length = buffer[0];
return buffer+1;
} else {
length = 0;
return 0;
}
ExtendedCharTable::ExtendedCharTable()
{
}
ExtendedCharTable::ExtendedCharTable() {
}
ExtendedCharTable::~ExtendedCharTable() {
// free all allocated character buffers
QHashIterator<ushort,ushort *> iter(extendedCharTable);
while ( iter.hasNext() ) {
iter.next();
delete[] iter.value();
}
ExtendedCharTable::~ExtendedCharTable()
{
// free all allocated character buffers
QHashIterator<ushort,ushort *> iter(extendedCharTable);
while ( iter.hasNext() ) {
iter.next();
delete[] iter.value();
}
}
// global instance
+296 -294
View File
@@ -36,7 +36,8 @@
#include <QtCore/QTimer>
namespace Konsole {
namespace Konsole
{
class KeyboardTranslator;
class HistoryType;
@@ -51,21 +52,21 @@ class TerminalCharacterDecoder;
* These are the values used by Emulation::stateChanged()
*/
enum {
/** The emulation is currently receiving user input. */
NOTIFYNORMAL=0,
/**
* The terminal program has triggered a bell event
* to get the user's attention.
*/
NOTIFYBELL=1,
/**
* The emulation is currently receiving data from its
* terminal input.
*/
NOTIFYACTIVITY=2,
/** The emulation is currently receiving user input. */
NOTIFYNORMAL=0,
/**
* The terminal program has triggered a bell event
* to get the user's attention.
*/
NOTIFYBELL=1,
/**
* The emulation is currently receiving data from its
* terminal input.
*/
NOTIFYACTIVITY=2,
// unused here?
NOTIFYSILENCE=3
// unused here?
NOTIFYSILENCE=3
};
/**
@@ -117,347 +118,348 @@ enum {
* how long the emulation has been active/idle for and also respond to
* a 'bell' event in different ways.
*/
class Emulation : public QObject {
Q_OBJECT
class Emulation : public QObject
{
Q_OBJECT
public:
/** Constructs a new terminal emulation */
Emulation();
~Emulation();
/** Constructs a new terminal emulation */
Emulation();
~Emulation();
/**
* Creates a new window onto the output from this emulation. The contents
* of the window are then rendered by views which are set to use this window using the
* TerminalDisplay::setScreenWindow() method.
*/
ScreenWindow * createWindow();
/**
* Creates a new window onto the output from this emulation. The contents
* of the window are then rendered by views which are set to use this window using the
* TerminalDisplay::setScreenWindow() method.
*/
ScreenWindow * createWindow();
/** Returns the size of the screen image which the emulation produces */
QSize imageSize();
/** Returns the size of the screen image which the emulation produces */
QSize imageSize();
/**
* Returns the total number of lines, including those stored in the history.
*/
int lineCount();
/**
* Returns the total number of lines, including those stored in the history.
*/
int lineCount();
/**
* Sets the history store used by this emulation. When new lines
* are added to the output, older lines at the top of the screen are transferred to a history
* store.
*
* The number of lines which are kept and the storage location depend on the
* type of store.
*/
void setHistory(const HistoryType &);
/** Returns the history store used by this emulation. See setHistory() */
const HistoryType & history();
/** Clears the history scroll. */
void clearHistory();
/**
* Sets the history store used by this emulation. When new lines
* are added to the output, older lines at the top of the screen are transferred to a history
* store.
*
* The number of lines which are kept and the storage location depend on the
* type of store.
*/
void setHistory(const HistoryType &);
/** Returns the history store used by this emulation. See setHistory() */
const HistoryType & history();
/** Clears the history scroll. */
void clearHistory();
/**
* Copies the output history from @p startLine to @p endLine
* into @p stream, using @p decoder to convert the terminal
* characters into text.
*
* @param decoder A decoder which converts lines of terminal characters with
* appearance attributes into output text. PlainTextDecoder is the most commonly
* used decoder.
* @param startLine The first
*/
virtual void writeToStream(TerminalCharacterDecoder * decoder,int startLine,int endLine);
/**
* Copies the output history from @p startLine to @p endLine
* into @p stream, using @p decoder to convert the terminal
* characters into text.
*
* @param decoder A decoder which converts lines of terminal characters with
* appearance attributes into output text. PlainTextDecoder is the most commonly
* used decoder.
* @param startLine The first
*/
virtual void writeToStream(TerminalCharacterDecoder * decoder,int startLine,int endLine);
/** Returns the codec used to decode incoming characters. See setCodec() */
const QTextCodec * codec() {
return _codec;
}
/** Sets the codec used to decode incoming characters. */
void setCodec(const QTextCodec *);
/** Returns the codec used to decode incoming characters. See setCodec() */
const QTextCodec * codec() {
return _codec;
}
/** Sets the codec used to decode incoming characters. */
void setCodec(const QTextCodec *);
/**
* Convenience method.
* Returns true if the current codec used to decode incoming
* characters is UTF-8
*/
bool utf8() {
Q_ASSERT(_codec);
return _codec->mibEnum() == 106;
}
/**
* Convenience method.
* Returns true if the current codec used to decode incoming
* characters is UTF-8
*/
bool utf8() {
Q_ASSERT(_codec);
return _codec->mibEnum() == 106;
}
/** TODO Document me */
virtual char getErase() const;
/** TODO Document me */
virtual char getErase() const;
/**
* Sets the key bindings used to key events
* ( received through sendKeyEvent() ) into character
* streams to send to the terminal.
*/
void setKeyBindings(const QString & name);
/**
* Returns the name of the emulation's current key bindings.
* See setKeyBindings()
*/
QString keyBindings();
/**
* Sets the key bindings used to key events
* ( received through sendKeyEvent() ) into character
* streams to send to the terminal.
*/
void setKeyBindings(const QString & name);
/**
* Returns the name of the emulation's current key bindings.
* See setKeyBindings()
*/
QString keyBindings();
/**
* Copies the current image into the history and clears the screen.
*/
virtual void clearEntireScreen() =0;
/**
* Copies the current image into the history and clears the screen.
*/
virtual void clearEntireScreen() =0;
/** Resets the state of the terminal. */
virtual void reset() =0;
/** Resets the state of the terminal. */
virtual void reset() =0;
/**
* Returns true if the active terminal program wants
* mouse input events.
*
* The programUsesMouseChanged() signal is emitted when this
* changes.
*/
bool programUsesMouse() const;
/**
* Returns true if the active terminal program wants
* mouse input events.
*
* The programUsesMouseChanged() signal is emitted when this
* changes.
*/
bool programUsesMouse() const;
public slots:
/** Change the size of the emulation's image */
virtual void setImageSize(int lines, int columns);
/** Change the size of the emulation's image */
virtual void setImageSize(int lines, int columns);
/**
* Interprets a sequence of characters and sends the result to the terminal.
* This is equivalent to calling sendKeyEvent() for each character in @p text in succession.
*/
virtual void sendText(const QString & text) = 0;
/**
* Interprets a sequence of characters and sends the result to the terminal.
* This is equivalent to calling sendKeyEvent() for each character in @p text in succession.
*/
virtual void sendText(const QString & text) = 0;
/**
* Interprets a key press event and emits the sendData() signal with
* the resulting character stream.
*/
virtual void sendKeyEvent(QKeyEvent *);
/**
* Interprets a key press event and emits the sendData() signal with
* the resulting character stream.
*/
virtual void sendKeyEvent(QKeyEvent *);
/**
* Converts information about a mouse event into an xterm-compatible escape
* sequence and emits the character sequence via sendData()
*/
virtual void sendMouseEvent(int buttons, int column, int line, int eventType);
/**
* Converts information about a mouse event into an xterm-compatible escape
* sequence and emits the character sequence via sendData()
*/
virtual void sendMouseEvent(int buttons, int column, int line, int eventType);
/**
* Sends a string of characters to the foreground terminal process.
*
* @param string The characters to send.
* @param length Length of @p string or if set to a negative value, @p string will
* be treated as a null-terminated string and its length will be determined automatically.
*/
virtual void sendString(const char * string, int length = -1) = 0;
/**
* Sends a string of characters to the foreground terminal process.
*
* @param string The characters to send.
* @param length Length of @p string or if set to a negative value, @p string will
* be treated as a null-terminated string and its length will be determined automatically.
*/
virtual void sendString(const char * string, int length = -1) = 0;
/**
* Processes an incoming stream of characters. receiveData() decodes the incoming
* character buffer using the current codec(), and then calls receiveChar() for
* each unicode character in the resulting buffer.
*
* receiveData() also starts a timer which causes the outputChanged() signal
* to be emitted when it expires. The timer allows multiple updates in quick
* succession to be buffered into a single outputChanged() signal emission.
*
* @param buffer A string of characters received from the terminal program.
* @param len The length of @p buffer
*/
void receiveData(const char * buffer,int len);
/**
* Processes an incoming stream of characters. receiveData() decodes the incoming
* character buffer using the current codec(), and then calls receiveChar() for
* each unicode character in the resulting buffer.
*
* receiveData() also starts a timer which causes the outputChanged() signal
* to be emitted when it expires. The timer allows multiple updates in quick
* succession to be buffered into a single outputChanged() signal emission.
*
* @param buffer A string of characters received from the terminal program.
* @param len The length of @p buffer
*/
void receiveData(const char * buffer,int len);
signals:
/**
* Emitted when a buffer of data is ready to send to the
* standard input of the terminal.
*
* @param data The buffer of data ready to be sent
* @paran len The length of @p data in bytes
*/
void sendData(const char * data,int len);
/**
* Emitted when a buffer of data is ready to send to the
* standard input of the terminal.
*
* @param data The buffer of data ready to be sent
* @paran len The length of @p data in bytes
*/
void sendData(const char * data,int len);
/**
* Requests that sending of input to the emulation
* from the terminal process be suspended or resumed.
*
* @param suspend If true, requests that sending of
* input from the terminal process' stdout be
* suspended. Otherwise requests that sending of
* input be resumed.
*/
void lockPtyRequest(bool suspend);
/**
* Requests that sending of input to the emulation
* from the terminal process be suspended or resumed.
*
* @param suspend If true, requests that sending of
* input from the terminal process' stdout be
* suspended. Otherwise requests that sending of
* input be resumed.
*/
void lockPtyRequest(bool suspend);
/**
* Requests that the pty used by the terminal process
* be set to UTF 8 mode.
*
* TODO: More documentation
*/
void useUtf8Request(bool);
/**
* Requests that the pty used by the terminal process
* be set to UTF 8 mode.
*
* TODO: More documentation
*/
void useUtf8Request(bool);
/**
* Emitted when the activity state of the emulation is set.
*
* @param state The new activity state, one of NOTIFYNORMAL, NOTIFYACTIVITY
* or NOTIFYBELL
*/
void stateSet(int state);
/**
* Emitted when the activity state of the emulation is set.
*
* @param state The new activity state, one of NOTIFYNORMAL, NOTIFYACTIVITY
* or NOTIFYBELL
*/
void stateSet(int state);
/** TODO Document me */
void zmodemDetected();
/** TODO Document me */
void zmodemDetected();
/**
* Requests that the color of the text used
* to represent the tabs associated with this
* emulation be changed. This is a Konsole-specific
* extension from pre-KDE 4 times.
*
* TODO: Document how the parameter works.
*/
void changeTabTextColorRequest(int color);
/**
* Requests that the color of the text used
* to represent the tabs associated with this
* emulation be changed. This is a Konsole-specific
* extension from pre-KDE 4 times.
*
* TODO: Document how the parameter works.
*/
void changeTabTextColorRequest(int color);
/**
* This is emitted when the program running in the shell indicates whether or
* not it is interested in mouse events.
*
* @param usesMouse This will be true if the program wants to be informed about
* mouse events or false otherwise.
*/
void programUsesMouseChanged(bool usesMouse);
/**
* This is emitted when the program running in the shell indicates whether or
* not it is interested in mouse events.
*
* @param usesMouse This will be true if the program wants to be informed about
* mouse events or false otherwise.
*/
void programUsesMouseChanged(bool usesMouse);
/**
* Emitted when the contents of the screen image change.
* The emulation buffers the updates from successive image changes,
* and only emits outputChanged() at sensible intervals when
* there is a lot of terminal activity.
*
* Normally there is no need for objects other than the screen windows
* created with createWindow() to listen for this signal.
*
* ScreenWindow objects created using createWindow() will emit their
* own outputChanged() signal in response to this signal.
*/
void outputChanged();
/**
* Emitted when the contents of the screen image change.
* The emulation buffers the updates from successive image changes,
* and only emits outputChanged() at sensible intervals when
* there is a lot of terminal activity.
*
* Normally there is no need for objects other than the screen windows
* created with createWindow() to listen for this signal.
*
* ScreenWindow objects created using createWindow() will emit their
* own outputChanged() signal in response to this signal.
*/
void outputChanged();
/**
* Emitted when the program running in the terminal wishes to update the
* session's title. This also allows terminal programs to customize other
* aspects of the terminal emulation display.
*
* This signal is emitted when the escape sequence "\033]ARG;VALUE\007"
* is received in the input string, where ARG is a number specifying what
* should change and VALUE is a string specifying the new value.
*
* TODO: The name of this method is not very accurate since this method
* is used to perform a whole range of tasks besides just setting
* the user-title of the session.
*
* @param title Specifies what to change.
* <ul>
* <li>0 - Set window icon text and session title to @p newTitle</li>
* <li>1 - Set window icon text to @p newTitle</li>
* <li>2 - Set session title to @p newTitle</li>
* <li>11 - Set the session's default background color to @p newTitle,
* where @p newTitle can be an HTML-style string (#RRGGBB) or a named
* color (eg 'red', 'blue').
* See http://doc.trolltech.com/4.2/qcolor.html#setNamedColor for more
* details.
* </li>
* <li>31 - Supposedly treats @p newTitle as a URL and opens it (NOT IMPLEMENTED)</li>
* <li>32 - Sets the icon associated with the session. @p newTitle is the name
* of the icon to use, which can be the name of any icon in the current KDE icon
* theme (eg: 'konsole', 'kate', 'folder_home')</li>
* </ul>
* @param newTitle Specifies the new title
*/
/**
* Emitted when the program running in the terminal wishes to update the
* session's title. This also allows terminal programs to customize other
* aspects of the terminal emulation display.
*
* This signal is emitted when the escape sequence "\033]ARG;VALUE\007"
* is received in the input string, where ARG is a number specifying what
* should change and VALUE is a string specifying the new value.
*
* TODO: The name of this method is not very accurate since this method
* is used to perform a whole range of tasks besides just setting
* the user-title of the session.
*
* @param title Specifies what to change.
* <ul>
* <li>0 - Set window icon text and session title to @p newTitle</li>
* <li>1 - Set window icon text to @p newTitle</li>
* <li>2 - Set session title to @p newTitle</li>
* <li>11 - Set the session's default background color to @p newTitle,
* where @p newTitle can be an HTML-style string (#RRGGBB) or a named
* color (eg 'red', 'blue').
* See http://doc.trolltech.com/4.2/qcolor.html#setNamedColor for more
* details.
* </li>
* <li>31 - Supposedly treats @p newTitle as a URL and opens it (NOT IMPLEMENTED)</li>
* <li>32 - Sets the icon associated with the session. @p newTitle is the name
* of the icon to use, which can be the name of any icon in the current KDE icon
* theme (eg: 'konsole', 'kate', 'folder_home')</li>
* </ul>
* @param newTitle Specifies the new title
*/
void titleChanged(int title,const QString & newTitle);
void titleChanged(int title,const QString & newTitle);
/**
* Emitted when the program running in the terminal changes the
* screen size.
*/
void imageSizeChanged(int lineCount , int columnCount);
/**
* Emitted when the program running in the terminal changes the
* screen size.
*/
void imageSizeChanged(int lineCount , int columnCount);
/**
* Emitted when the terminal program requests to change various properties
* of the terminal display.
*
* A profile change command occurs when a special escape sequence, followed
* by a string containing a series of name and value pairs is received.
* This string can be parsed using a ProfileCommandParser instance.
*
* @param text A string expected to contain a series of key and value pairs in
* the form: name=value;name2=value2 ...
*/
void profileChangeCommandReceived(const QString & text);
/**
* Emitted when the terminal program requests to change various properties
* of the terminal display.
*
* A profile change command occurs when a special escape sequence, followed
* by a string containing a series of name and value pairs is received.
* This string can be parsed using a ProfileCommandParser instance.
*
* @param text A string expected to contain a series of key and value pairs in
* the form: name=value;name2=value2 ...
*/
void profileChangeCommandReceived(const QString & text);
protected:
virtual void setMode (int mode) = 0;
virtual void resetMode(int mode) = 0;
virtual void setMode (int mode) = 0;
virtual void resetMode(int mode) = 0;
/**
* Processes an incoming character. See receiveData()
* @p ch A unicode character code.
*/
virtual void receiveChar(int ch);
/**
* Processes an incoming character. See receiveData()
* @p ch A unicode character code.
*/
virtual void receiveChar(int ch);
/**
* Sets the active screen. The terminal has two screens, primary and alternate.
* The primary screen is used by default. When certain interactive programs such
* as Vim are run, they trigger a switch to the alternate screen.
*
* @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen
*/
void setScreen(int index);
/**
* Sets the active screen. The terminal has two screens, primary and alternate.
* The primary screen is used by default. When certain interactive programs such
* as Vim are run, they trigger a switch to the alternate screen.
*
* @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen
*/
void setScreen(int index);
enum EmulationCodec {
LocaleCodec = 0,
Utf8Codec = 1
};
void setCodec(EmulationCodec codec); // codec number, 0 = locale, 1=utf8
enum EmulationCodec {
LocaleCodec = 0,
Utf8Codec = 1
};
void setCodec(EmulationCodec codec); // codec number, 0 = locale, 1=utf8
QList<ScreenWindow *> _windows;
QList<ScreenWindow *> _windows;
Screen * _currentScreen; // pointer to the screen which is currently active,
// this is one of the elements in the screen[] array
Screen * _currentScreen; // pointer to the screen which is currently active,
// this is one of the elements in the screen[] array
Screen * _screen[2]; // 0 = primary screen ( used by most programs, including the shell
// scrollbars are enabled in this mode )
// 1 = alternate ( used by vi , emacs etc.
// scrollbars are not enabled in this mode )
Screen * _screen[2]; // 0 = primary screen ( used by most programs, including the shell
// scrollbars are enabled in this mode )
// 1 = alternate ( used by vi , emacs etc.
// scrollbars are not enabled in this mode )
//decodes an incoming C-style character stream into a unicode QString using
//the current text codec. (this allows for rendering of non-ASCII characters in text files etc.)
const QTextCodec * _codec;
QTextDecoder * _decoder;
//decodes an incoming C-style character stream into a unicode QString using
//the current text codec. (this allows for rendering of non-ASCII characters in text files etc.)
const QTextCodec * _codec;
QTextDecoder * _decoder;
const KeyboardTranslator * _keyTranslator; // the keyboard layout
const KeyboardTranslator * _keyTranslator; // the keyboard layout
protected slots:
/**
* Schedules an update of attached views.
* Repeated calls to bufferedUpdate() in close succession will result in only a single update,
* much like the Qt buffered update of widgets.
*/
void bufferedUpdate();
/**
* Schedules an update of attached views.
* Repeated calls to bufferedUpdate() in close succession will result in only a single update,
* much like the Qt buffered update of widgets.
*/
void bufferedUpdate();
private slots:
// triggered by timer, causes the emulation to send an updated screen image to each
// view
void showBulk();
// triggered by timer, causes the emulation to send an updated screen image to each
// view
void showBulk();
void usesMouseChanged(bool usesMouse);
void usesMouseChanged(bool usesMouse);
private:
bool _usesMouse;
QTimer _bulkTimer1;
QTimer _bulkTimer2;
bool _usesMouse;
QTimer _bulkTimer1;
QTimer _bulkTimer2;
};
+385 -334
View File
@@ -43,177 +43,195 @@
using namespace Konsole;
FilterChain::~FilterChain() {
QMutableListIterator<Filter *> iter(*this);
FilterChain::~FilterChain()
{
QMutableListIterator<Filter *> iter(*this);
while ( iter.hasNext() ) {
Filter * filter = iter.next();
iter.remove();
delete filter;
}
}
void FilterChain::addFilter(Filter * filter) {
append(filter);
}
void FilterChain::removeFilter(Filter * filter) {
removeAll(filter);
}
bool FilterChain::containsFilter(Filter * filter) {
return contains(filter);
}
void FilterChain::reset() {
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
iter.next()->reset();
}
}
void FilterChain::setBuffer(const QString * buffer , const QList<int>* linePositions) {
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
iter.next()->setBuffer(buffer,linePositions);
}
}
void FilterChain::process() {
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
iter.next()->process();
}
}
void FilterChain::clear() {
QList<Filter *>::clear();
}
Filter::HotSpot * FilterChain::hotSpotAt(int line , int column) const {
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
Filter * filter = iter.next();
Filter::HotSpot * spot = filter->hotSpotAt(line,column);
if ( spot != 0 ) {
return spot;
while ( iter.hasNext() ) {
Filter * filter = iter.next();
iter.remove();
delete filter;
}
}
return 0;
}
QList<Filter::HotSpot *> FilterChain::hotSpots() const {
QList<Filter::HotSpot *> list;
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
Filter * filter = iter.next();
list << filter->hotSpots();
}
return list;
void FilterChain::addFilter(Filter * filter)
{
append(filter);
}
void FilterChain::removeFilter(Filter * filter)
{
removeAll(filter);
}
bool FilterChain::containsFilter(Filter * filter)
{
return contains(filter);
}
void FilterChain::reset()
{
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
iter.next()->reset();
}
}
void FilterChain::setBuffer(const QString * buffer , const QList<int>* linePositions)
{
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
iter.next()->setBuffer(buffer,linePositions);
}
}
void FilterChain::process()
{
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
iter.next()->process();
}
}
void FilterChain::clear()
{
QList<Filter *>::clear();
}
Filter::HotSpot * FilterChain::hotSpotAt(int line , int column) const
{
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
Filter * filter = iter.next();
Filter::HotSpot * spot = filter->hotSpotAt(line,column);
if ( spot != 0 ) {
return spot;
}
}
return 0;
}
QList<Filter::HotSpot *> FilterChain::hotSpots() const
{
QList<Filter::HotSpot *> list;
QListIterator<Filter *> iter(*this);
while (iter.hasNext()) {
Filter * filter = iter.next();
list << filter->hotSpots();
}
return list;
}
//QList<Filter::HotSpot*> FilterChain::hotSpotsAtLine(int line) const;
TerminalImageFilterChain::TerminalImageFilterChain()
: _buffer(0)
, _linePositions(0) {
: _buffer(0)
, _linePositions(0)
{
}
TerminalImageFilterChain::~TerminalImageFilterChain() {
delete _buffer;
delete _linePositions;
TerminalImageFilterChain::~TerminalImageFilterChain()
{
delete _buffer;
delete _linePositions;
}
void TerminalImageFilterChain::setImage(const Character * const image , int lines , int columns, const QVector<LineProperty>& lineProperties) {
void TerminalImageFilterChain::setImage(const Character * const image , int lines , int columns, const QVector<LineProperty>& lineProperties)
{
//qDebug("%s %d", __FILE__, __LINE__);
if (empty()) {
return;
}
//qDebug("%s %d", __FILE__, __LINE__);
// reset all filters and hotspots
reset();
//qDebug("%s %d", __FILE__, __LINE__);
PlainTextDecoder decoder;
decoder.setTrailingWhitespace(false);
//qDebug("%s %d", __FILE__, __LINE__);
// setup new shared buffers for the filters to process on
QString * newBuffer = new QString();
QList<int>* newLinePositions = new QList<int>();
setBuffer( newBuffer , newLinePositions );
// free the old buffers
delete _buffer;
delete _linePositions;
_buffer = newBuffer;
_linePositions = newLinePositions;
QTextStream lineStream(_buffer);
decoder.begin(&lineStream);
for (int i=0 ; i < lines ; i++) {
_linePositions->append(_buffer->length());
decoder.decodeLine(image + i*columns,columns,LINE_DEFAULT);
// pretend that each line ends with a newline character.
// this prevents a link that occurs at the end of one line
// being treated as part of a link that occurs at the start of the next line
//
// the downside is that links which are spread over more than one line are not
// highlighted.
//
// TODO - Use the "line wrapped" attribute associated with lines in a
// terminal image to avoid adding this imaginary character for wrapped
// lines
if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) ) {
lineStream << QChar('\n');
if (empty()) {
return;
}
}
decoder.end();
//qDebug("%s %d", __FILE__, __LINE__);
// reset all filters and hotspots
reset();
//qDebug("%s %d", __FILE__, __LINE__);
PlainTextDecoder decoder;
decoder.setTrailingWhitespace(false);
//qDebug("%s %d", __FILE__, __LINE__);
// setup new shared buffers for the filters to process on
QString * newBuffer = new QString();
QList<int>* newLinePositions = new QList<int>();
setBuffer( newBuffer , newLinePositions );
// free the old buffers
delete _buffer;
delete _linePositions;
_buffer = newBuffer;
_linePositions = newLinePositions;
QTextStream lineStream(_buffer);
decoder.begin(&lineStream);
for (int i=0 ; i < lines ; i++) {
_linePositions->append(_buffer->length());
decoder.decodeLine(image + i*columns,columns,LINE_DEFAULT);
// pretend that each line ends with a newline character.
// this prevents a link that occurs at the end of one line
// being treated as part of a link that occurs at the start of the next line
//
// the downside is that links which are spread over more than one line are not
// highlighted.
//
// TODO - Use the "line wrapped" attribute associated with lines in a
// terminal image to avoid adding this imaginary character for wrapped
// lines
if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) ) {
lineStream << QChar('\n');
}
}
decoder.end();
// qDebug("%s %d", __FILE__, __LINE__);
}
Filter::Filter() :
_linePositions(0),
_buffer(0) {
_linePositions(0),
_buffer(0)
{
}
Filter::~Filter() {
QListIterator<HotSpot *> iter(_hotspotList);
while (iter.hasNext()) {
delete iter.next();
}
}
void Filter::reset() {
_hotspots.clear();
_hotspotList.clear();
}
void Filter::setBuffer(const QString * buffer , const QList<int>* linePositions) {
_buffer = buffer;
_linePositions = linePositions;
}
void Filter::getLineColumn(int position , int & startLine , int & startColumn) {
Q_ASSERT( _linePositions );
Q_ASSERT( _buffer );
for (int i = 0 ; i < _linePositions->count() ; i++) {
//kDebug() << "line position at " << i << " = " << _linePositions[i];
int nextLine = 0;
if ( i == _linePositions->count()-1 ) {
nextLine = _buffer->length() + 1;
} else {
nextLine = _linePositions->value(i+1);
Filter::~Filter()
{
QListIterator<HotSpot *> iter(_hotspotList);
while (iter.hasNext()) {
delete iter.next();
}
}
void Filter::reset()
{
_hotspots.clear();
_hotspotList.clear();
}
// kDebug() << "pos - " << position << " line pos(" << i<< ") " << _linePositions->value(i) <<
// " next = " << nextLine << " buffer len = " << _buffer->length();
void Filter::setBuffer(const QString * buffer , const QList<int>* linePositions)
{
_buffer = buffer;
_linePositions = linePositions;
}
if ( _linePositions->value(i) <= position && position < nextLine ) {
startLine = i;
startColumn = position - _linePositions->value(i);
return;
void Filter::getLineColumn(int position , int & startLine , int & startColumn)
{
Q_ASSERT( _linePositions );
Q_ASSERT( _buffer );
for (int i = 0 ; i < _linePositions->count() ; i++) {
//kDebug() << "line position at " << i << " = " << _linePositions[i];
int nextLine = 0;
if ( i == _linePositions->count()-1 ) {
nextLine = _buffer->length() + 1;
} else {
nextLine = _linePositions->value(i+1);
}
// kDebug() << "pos - " << position << " line pos(" << i<< ") " << _linePositions->value(i) <<
// " next = " << nextLine << " buffer len = " << _buffer->length();
if ( _linePositions->value(i) <= position && position < nextLine ) {
startLine = i;
startColumn = position - _linePositions->value(i);
return;
}
}
}
}
@@ -223,216 +241,245 @@ void Filter::getLineColumn(int position , int & startLine , int & startColumn) {
_buffer.append(text);
}*/
const QString * Filter::buffer() {
return _buffer;
const QString * Filter::buffer()
{
return _buffer;
}
Filter::HotSpot::~HotSpot() {
Filter::HotSpot::~HotSpot()
{
}
void Filter::addHotSpot(HotSpot * spot) {
_hotspotList << spot;
void Filter::addHotSpot(HotSpot * spot)
{
_hotspotList << spot;
for (int line = spot->startLine() ; line <= spot->endLine() ; line++) {
_hotspots.insert(line,spot);
}
}
QList<Filter::HotSpot *> Filter::hotSpots() const {
return _hotspotList;
}
QList<Filter::HotSpot *> Filter::hotSpotsAtLine(int line) const {
return _hotspots.values(line);
}
Filter::HotSpot * Filter::hotSpotAt(int line , int column) const {
QListIterator<HotSpot *> spotIter(_hotspots.values(line));
while (spotIter.hasNext()) {
HotSpot * spot = spotIter.next();
if ( spot->startLine() == line && spot->startColumn() > column ) {
continue;
for (int line = spot->startLine() ; line <= spot->endLine() ; line++) {
_hotspots.insert(line,spot);
}
if ( spot->endLine() == line && spot->endColumn() < column ) {
continue;
}
QList<Filter::HotSpot *> Filter::hotSpots() const
{
return _hotspotList;
}
QList<Filter::HotSpot *> Filter::hotSpotsAtLine(int line) const
{
return _hotspots.values(line);
}
Filter::HotSpot * Filter::hotSpotAt(int line , int column) const
{
QListIterator<HotSpot *> spotIter(_hotspots.values(line));
while (spotIter.hasNext()) {
HotSpot * spot = spotIter.next();
if ( spot->startLine() == line && spot->startColumn() > column ) {
continue;
}
if ( spot->endLine() == line && spot->endColumn() < column ) {
continue;
}
return spot;
}
return spot;
}
return 0;
return 0;
}
Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
: _startLine(startLine)
, _startColumn(startColumn)
, _endLine(endLine)
, _endColumn(endColumn)
, _type(NotSpecified) {
: _startLine(startLine)
, _startColumn(startColumn)
, _endLine(endLine)
, _endColumn(endColumn)
, _type(NotSpecified)
{
}
QString Filter::HotSpot::tooltip() const {
return QString();
QString Filter::HotSpot::tooltip() const
{
return QString();
}
QList<QAction *> Filter::HotSpot::actions() {
return QList<QAction *>();
QList<QAction *> Filter::HotSpot::actions()
{
return QList<QAction *>();
}
int Filter::HotSpot::startLine() const {
return _startLine;
int Filter::HotSpot::startLine() const
{
return _startLine;
}
int Filter::HotSpot::endLine() const {
return _endLine;
int Filter::HotSpot::endLine() const
{
return _endLine;
}
int Filter::HotSpot::startColumn() const {
return _startColumn;
int Filter::HotSpot::startColumn() const
{
return _startColumn;
}
int Filter::HotSpot::endColumn() const {
return _endColumn;
int Filter::HotSpot::endColumn() const
{
return _endColumn;
}
Filter::HotSpot::Type Filter::HotSpot::type() const {
return _type;
Filter::HotSpot::Type Filter::HotSpot::type() const
{
return _type;
}
void Filter::HotSpot::setType(Type type) {
_type = type;
void Filter::HotSpot::setType(Type type)
{
_type = type;
}
RegExpFilter::RegExpFilter() {
RegExpFilter::RegExpFilter()
{
}
RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
: Filter::HotSpot(startLine,startColumn,endLine,endColumn) {
setType(Marker);
: Filter::HotSpot(startLine,startColumn,endLine,endColumn)
{
setType(Marker);
}
void RegExpFilter::HotSpot::activate(QObject *) {
void RegExpFilter::HotSpot::activate(QObject *)
{
}
void RegExpFilter::HotSpot::setCapturedTexts(const QStringList & texts) {
_capturedTexts = texts;
void RegExpFilter::HotSpot::setCapturedTexts(const QStringList & texts)
{
_capturedTexts = texts;
}
QStringList RegExpFilter::HotSpot::capturedTexts() const {
return _capturedTexts;
QStringList RegExpFilter::HotSpot::capturedTexts() const
{
return _capturedTexts;
}
void RegExpFilter::setRegExp(const QRegExp & regExp) {
_searchText = regExp;
void RegExpFilter::setRegExp(const QRegExp & regExp)
{
_searchText = regExp;
}
QRegExp RegExpFilter::regExp() const {
return _searchText;
QRegExp RegExpFilter::regExp() const
{
return _searchText;
}
/*void RegExpFilter::reset(int)
{
_buffer = QString();
}*/
void RegExpFilter::process() {
int pos = 0;
const QString * text = buffer();
void RegExpFilter::process()
{
int pos = 0;
const QString * text = buffer();
Q_ASSERT( text );
Q_ASSERT( text );
// ignore any regular expressions which match an empty string.
// otherwise the while loop below will run indefinitely
static const QString emptyString("");
if ( _searchText.exactMatch(emptyString) ) {
return;
}
while(pos >= 0) {
pos = _searchText.indexIn(*text,pos);
if ( pos >= 0 ) {
int startLine = 0;
int endLine = 0;
int startColumn = 0;
int endColumn = 0;
//kDebug() << "pos from " << pos << " to " << pos + _searchText.matchedLength();
getLineColumn(pos,startLine,startColumn);
getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
//kDebug() << "start " << startLine << " / " << startColumn;
//kDebug() << "end " << endLine << " / " << endColumn;
RegExpFilter::HotSpot * spot = newHotSpot(startLine,startColumn,
endLine,endColumn);
spot->setCapturedTexts(_searchText.capturedTexts());
addHotSpot( spot );
pos += _searchText.matchedLength();
// if matchedLength == 0, the program will get stuck in an infinite loop
Q_ASSERT( _searchText.matchedLength() > 0 );
// ignore any regular expressions which match an empty string.
// otherwise the while loop below will run indefinitely
static const QString emptyString("");
if ( _searchText.exactMatch(emptyString) ) {
return;
}
while (pos >= 0) {
pos = _searchText.indexIn(*text,pos);
if ( pos >= 0 ) {
int startLine = 0;
int endLine = 0;
int startColumn = 0;
int endColumn = 0;
//kDebug() << "pos from " << pos << " to " << pos + _searchText.matchedLength();
getLineColumn(pos,startLine,startColumn);
getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
//kDebug() << "start " << startLine << " / " << startColumn;
//kDebug() << "end " << endLine << " / " << endColumn;
RegExpFilter::HotSpot * spot = newHotSpot(startLine,startColumn,
endLine,endColumn);
spot->setCapturedTexts(_searchText.capturedTexts());
addHotSpot( spot );
pos += _searchText.matchedLength();
// if matchedLength == 0, the program will get stuck in an infinite loop
Q_ASSERT( _searchText.matchedLength() > 0 );
}
}
}
}
RegExpFilter::HotSpot * RegExpFilter::newHotSpot(int startLine,int startColumn,
int endLine,int endColumn) {
return new RegExpFilter::HotSpot(startLine,startColumn,
endLine,endColumn);
int endLine,int endColumn)
{
return new RegExpFilter::HotSpot(startLine,startColumn,
endLine,endColumn);
}
RegExpFilter::HotSpot * UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
int endColumn) {
return new UrlFilter::HotSpot(startLine,startColumn,
endLine,endColumn);
int endColumn)
{
return new UrlFilter::HotSpot(startLine,startColumn,
endLine,endColumn);
}
UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
, _urlObject(new FilterObject(this)) {
setType(Link);
: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
, _urlObject(new FilterObject(this))
{
setType(Link);
}
QString UrlFilter::HotSpot::tooltip() const {
QString url = capturedTexts().first();
QString UrlFilter::HotSpot::tooltip() const
{
QString url = capturedTexts().first();
const UrlType kind = urlType();
const UrlType kind = urlType();
if ( kind == StandardUrl ) {
return QString();
} else if ( kind == Email ) {
return QString();
} else {
return QString();
}
}
UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const {
QString url = capturedTexts().first();
if ( FullUrlRegExp.exactMatch(url) ) {
return StandardUrl;
} else if ( EmailAddressRegExp.exactMatch(url) ) {
return Email;
} else {
return Unknown;
}
}
void UrlFilter::HotSpot::activate(QObject * object) {
QString url = capturedTexts().first();
const UrlType kind = urlType();
const QString & actionName = object ? object->objectName() : QString();
if ( actionName == "copy-action" ) {
//kDebug() << "Copying url to clipboard:" << url;
QApplication::clipboard()->setText(url);
return;
}
if ( !object || actionName == "open-action" ) {
if ( kind == StandardUrl ) {
// if the URL path does not include the protocol ( eg. "www.kde.org" ) then
// prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" )
if (!url.contains("://")) {
url.prepend("http://");
}
return QString();
} else if ( kind == Email ) {
url.prepend("mailto:");
return QString();
} else {
return QString();
}
}
UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
{
QString url = capturedTexts().first();
if ( FullUrlRegExp.exactMatch(url) ) {
return StandardUrl;
} else if ( EmailAddressRegExp.exactMatch(url) ) {
return Email;
} else {
return Unknown;
}
}
void UrlFilter::HotSpot::activate(QObject * object)
{
QString url = capturedTexts().first();
const UrlType kind = urlType();
const QString & actionName = object ? object->objectName() : QString();
if ( actionName == "copy-action" ) {
//kDebug() << "Copying url to clipboard:" << url;
QApplication::clipboard()->setText(url);
return;
}
if ( !object || actionName == "open-action" ) {
if ( kind == StandardUrl ) {
// if the URL path does not include the protocol ( eg. "www.kde.org" ) then
// prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" )
if (!url.contains("://")) {
url.prepend("http://");
}
} else if ( kind == Email ) {
url.prepend("mailto:");
}
// new KRun(url,QApplication::activeWindow());
}
}
}
// Note: Altering these regular expressions can have a major effect on the performance of the filters
@@ -450,48 +497,52 @@ const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+
// matches full url or email address
const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
EmailAddressRegExp.pattern()+')');
EmailAddressRegExp.pattern()+')');
UrlFilter::UrlFilter() {
setRegExp( CompleteUrlRegExp );
UrlFilter::UrlFilter()
{
setRegExp( CompleteUrlRegExp );
}
UrlFilter::HotSpot::~HotSpot() {
delete _urlObject;
UrlFilter::HotSpot::~HotSpot()
{
delete _urlObject;
}
void FilterObject::activated() {
_filter->activate(sender());
void FilterObject::activated()
{
_filter->activate(sender());
}
QList<QAction *> UrlFilter::HotSpot::actions() {
QList<QAction *> list;
QList<QAction *> UrlFilter::HotSpot::actions()
{
QList<QAction *> list;
const UrlType kind = urlType();
const UrlType kind = urlType();
QAction * openAction = new QAction(_urlObject);
QAction * copyAction = new QAction(_urlObject);;
QAction * openAction = new QAction(_urlObject);
QAction * copyAction = new QAction(_urlObject);;
Q_ASSERT( kind == StandardUrl || kind == Email );
Q_ASSERT( kind == StandardUrl || kind == Email );
if ( kind == StandardUrl ) {
openAction->setText(("Open Link"));
copyAction->setText(("Copy Link Address"));
} else if ( kind == Email ) {
openAction->setText(("Send Email To..."));
copyAction->setText(("Copy Email Address"));
}
if ( kind == StandardUrl ) {
openAction->setText(("Open Link"));
copyAction->setText(("Copy Link Address"));
} else if ( kind == Email ) {
openAction->setText(("Send Email To..."));
copyAction->setText(("Copy Email Address"));
}
// object names are set here so that the hotspot performs the
// correct action when activated() is called with the triggered
// action passed as a parameter.
openAction->setObjectName("open-action");
copyAction->setObjectName("copy-action");
// object names are set here so that the hotspot performs the
// correct action when activated() is called with the triggered
// action passed as a parameter.
openAction->setObjectName("open-action");
copyAction->setObjectName("copy-action");
QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
list << openAction;
list << copyAction;
list << openAction;
list << copyAction;
return list;
return list;
}
//#include "moc_Filter.cpp"
+233 -223
View File
@@ -33,7 +33,8 @@
// Local
#include "Character.h"
namespace Konsole {
namespace Konsole
{
/**
* A filter processes blocks of text looking for certain patterns (such as URLs or keywords from a list)
@@ -53,131 +54,133 @@ namespace Konsole {
* When processing the text they should create instances of Filter::HotSpot subclasses for sections of interest
* and add them to the filter's list of hotspots using addHotSpot()
*/
class Filter {
class Filter
{
public:
/**
* Represents an area of text which matched the pattern a particular filter has been looking for.
*
* Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ),
* and an action. When the user performs some activity such as a mouse-click in a hotspot area ( the exact
* action will depend on what is displaying the block of text which the filter is processing ), the hotspot's
* activate() method should be called. Depending on the type of hotspot this will trigger a suitable response.
*
* For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser.
* Hotspots may have more than one action, in which case the list of actions can be obtained using the
* actions() method. These actions may then be displayed in a popup menu or toolbar for example.
*/
class HotSpot {
public:
/**
* Constructs a new hotspot which covers the area from (@p startLine,@p startColumn) to (@p endLine,@p endColumn)
* in a block of text.
*/
HotSpot(int startLine , int startColumn , int endLine , int endColumn);
virtual ~HotSpot();
* Represents an area of text which matched the pattern a particular filter has been looking for.
*
* Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ),
* and an action. When the user performs some activity such as a mouse-click in a hotspot area ( the exact
* action will depend on what is displaying the block of text which the filter is processing ), the hotspot's
* activate() method should be called. Depending on the type of hotspot this will trigger a suitable response.
*
* For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser.
* Hotspots may have more than one action, in which case the list of actions can be obtained using the
* actions() method. These actions may then be displayed in a popup menu or toolbar for example.
*/
class HotSpot
{
public:
/**
* Constructs a new hotspot which covers the area from (@p startLine,@p startColumn) to (@p endLine,@p endColumn)
* in a block of text.
*/
HotSpot(int startLine , int startColumn , int endLine , int endColumn);
virtual ~HotSpot();
enum Type {
// the type of the hotspot is not specified
NotSpecified,
// this hotspot represents a clickable link
Link,
// this hotspot represents a marker
Marker
};
/** Returns the line when the hotspot area starts */
int startLine() const;
/** Returns the line where the hotspot area ends */
int endLine() const;
/** Returns the column on startLine() where the hotspot area starts */
int startColumn() const;
/** Returns the column on endLine() where the hotspot area ends */
int endColumn() const;
/**
* Returns the type of the hotspot. This is usually used as a hint for views on how to represent
* the hotspot graphically. eg. Link hotspots are typically underlined when the user mouses over them
*/
Type type() const;
/**
* Causes the an action associated with a hotspot to be triggered.
*
* @param object The object which caused the hotspot to be triggered. This is
* typically null ( in which case the default action should be performed ) or
* one of the objects from the actions() list. In which case the associated
* action should be performed.
*/
virtual void activate(QObject * object = 0) = 0;
/**
* Returns a list of actions associated with the hotspot which can be used in a
* menu or toolbar
*/
virtual QList<QAction *> actions();
/**
* Returns the text of a tooltip to be shown when the mouse moves over the hotspot, or
* an empty string if there is no tooltip associated with this hotspot.
*
* The default implementation returns an empty string.
*/
virtual QString tooltip() const;
protected:
/** Sets the type of a hotspot. This should only be set once */
void setType(Type type);
private:
int _startLine;
int _startColumn;
int _endLine;
int _endColumn;
Type _type;
enum Type {
// the type of the hotspot is not specified
NotSpecified,
// this hotspot represents a clickable link
Link,
// this hotspot represents a marker
Marker
};
/** Returns the line when the hotspot area starts */
int startLine() const;
/** Returns the line where the hotspot area ends */
int endLine() const;
/** Returns the column on startLine() where the hotspot area starts */
int startColumn() const;
/** Returns the column on endLine() where the hotspot area ends */
int endColumn() const;
/**
* Returns the type of the hotspot. This is usually used as a hint for views on how to represent
* the hotspot graphically. eg. Link hotspots are typically underlined when the user mouses over them
*/
Type type() const;
/**
* Causes the an action associated with a hotspot to be triggered.
*
* @param object The object which caused the hotspot to be triggered. This is
* typically null ( in which case the default action should be performed ) or
* one of the objects from the actions() list. In which case the associated
* action should be performed.
*/
virtual void activate(QObject * object = 0) = 0;
/**
* Returns a list of actions associated with the hotspot which can be used in a
* menu or toolbar
*/
virtual QList<QAction *> actions();
/** Constructs a new filter. */
Filter();
virtual ~Filter();
/** Causes the filter to process the block of text currently in its internal buffer */
virtual void process() = 0;
/**
* Returns the text of a tooltip to be shown when the mouse moves over the hotspot, or
* an empty string if there is no tooltip associated with this hotspot.
*
* The default implementation returns an empty string.
* Empties the filters internal buffer and resets the line count back to 0.
* All hotspots are deleted.
*/
virtual QString tooltip() const;
void reset();
protected:
/** Sets the type of a hotspot. This should only be set once */
void setType(Type type);
/** Adds a new line of text to the filter and increments the line count */
//void addLine(const QString& string);
private:
int _startLine;
int _startColumn;
int _endLine;
int _endColumn;
Type _type;
/** Returns the hotspot which covers the given @p line and @p column, or 0 if no hotspot covers that area */
HotSpot * hotSpotAt(int line , int column) const;
};
/** Returns the list of hotspots identified by the filter */
QList<HotSpot *> hotSpots() const;
/** Constructs a new filter. */
Filter();
virtual ~Filter();
/** Returns the list of hotspots identified by the filter which occur on a given line */
QList<HotSpot *> hotSpotsAtLine(int line) const;
/** Causes the filter to process the block of text currently in its internal buffer */
virtual void process() = 0;
/**
* Empties the filters internal buffer and resets the line count back to 0.
* All hotspots are deleted.
*/
void reset();
/** Adds a new line of text to the filter and increments the line count */
//void addLine(const QString& string);
/** Returns the hotspot which covers the given @p line and @p column, or 0 if no hotspot covers that area */
HotSpot * hotSpotAt(int line , int column) const;
/** Returns the list of hotspots identified by the filter */
QList<HotSpot *> hotSpots() const;
/** Returns the list of hotspots identified by the filter which occur on a given line */
QList<HotSpot *> hotSpotsAtLine(int line) const;
/**
* TODO: Document me
*/
void setBuffer(const QString * buffer , const QList<int>* linePositions);
/**
* TODO: Document me
*/
void setBuffer(const QString * buffer , const QList<int>* linePositions);
protected:
/** Adds a new hotspot to the list */
void addHotSpot(HotSpot *);
/** Returns the internal buffer */
const QString * buffer();
/** Converts a character position within buffer() to a line and column */
void getLineColumn(int position , int & startLine , int & startColumn);
/** Adds a new hotspot to the list */
void addHotSpot(HotSpot *);
/** Returns the internal buffer */
const QString * buffer();
/** Converts a character position within buffer() to a line and column */
void getLineColumn(int position , int & startLine , int & startColumn);
private:
QMultiHash<int,HotSpot *> _hotspots;
QList<HotSpot *> _hotspotList;
QMultiHash<int,HotSpot *> _hotspots;
QList<HotSpot *> _hotspotList;
const QList<int>* _linePositions;
const QString * _buffer;
const QList<int>* _linePositions;
const QString * _buffer;
};
/**
@@ -187,114 +190,119 @@ private:
* Subclasses can reimplement newHotSpot() to return custom hotspot types when matches for the regular expression
* are found.
*/
class RegExpFilter : public Filter {
class RegExpFilter : public Filter
{
public:
/**
* Type of hotspot created by RegExpFilter. The capturedTexts() method can be used to find the text
* matched by the filter's regular expression.
*/
class HotSpot : public Filter::HotSpot {
public:
HotSpot(int startLine, int startColumn, int endLine , int endColumn);
virtual void activate(QObject * object = 0);
/**
* Type of hotspot created by RegExpFilter. The capturedTexts() method can be used to find the text
* matched by the filter's regular expression.
*/
class HotSpot : public Filter::HotSpot
{
public:
HotSpot(int startLine, int startColumn, int endLine , int endColumn);
virtual void activate(QObject * object = 0);
/** Sets the captured texts associated with this hotspot */
void setCapturedTexts(const QStringList & texts);
/** Returns the texts found by the filter when matching the filter's regular expression */
QStringList capturedTexts() const;
private:
QStringList _capturedTexts;
};
/** Sets the captured texts associated with this hotspot */
void setCapturedTexts(const QStringList & texts);
/** Returns the texts found by the filter when matching the filter's regular expression */
QStringList capturedTexts() const;
private:
QStringList _capturedTexts;
};
/** Constructs a new regular expression filter */
RegExpFilter();
/** Constructs a new regular expression filter */
RegExpFilter();
/**
* Sets the regular expression which the filter searches for in blocks of text.
*
* Regular expressions which match the empty string are treated as not matching
* anything.
*/
void setRegExp(const QRegExp & text);
/** Returns the regular expression which the filter searches for in blocks of text */
QRegExp regExp() const;
/**
* Sets the regular expression which the filter searches for in blocks of text.
*
* Regular expressions which match the empty string are treated as not matching
* anything.
*/
void setRegExp(const QRegExp & text);
/** Returns the regular expression which the filter searches for in blocks of text */
QRegExp regExp() const;
/**
* Reimplemented to search the filter's text buffer for text matching regExp()
*
* If regexp matches the empty string, then process() will return immediately
* without finding results.
*/
virtual void process();
/**
* Reimplemented to search the filter's text buffer for text matching regExp()
*
* If regexp matches the empty string, then process() will return immediately
* without finding results.
*/
virtual void process();
protected:
/**
* Called when a match for the regular expression is encountered. Subclasses should reimplement this
* to return custom hotspot types
*/
virtual RegExpFilter::HotSpot * newHotSpot(int startLine,int startColumn,
int endLine,int endColumn);
/**
* Called when a match for the regular expression is encountered. Subclasses should reimplement this
* to return custom hotspot types
*/
virtual RegExpFilter::HotSpot * newHotSpot(int startLine,int startColumn,
int endLine,int endColumn);
private:
QRegExp _searchText;
QRegExp _searchText;
};
class FilterObject;
/** A filter which matches URLs in blocks of text */
class UrlFilter : public RegExpFilter {
class UrlFilter : public RegExpFilter
{
public:
/**
* Hotspot type created by UrlFilter instances. The activate() method opens a web browser
* at the given URL when called.
*/
class HotSpot : public RegExpFilter::HotSpot {
public:
HotSpot(int startLine,int startColumn,int endLine,int endColumn);
virtual ~HotSpot();
virtual QList<QAction *> actions();
/**
* Open a web browser at the current URL. The url itself can be determined using
* the capturedTexts() method.
* Hotspot type created by UrlFilter instances. The activate() method opens a web browser
* at the given URL when called.
*/
virtual void activate(QObject * object = 0);
class HotSpot : public RegExpFilter::HotSpot
{
public:
HotSpot(int startLine,int startColumn,int endLine,int endColumn);
virtual ~HotSpot();
virtual QString tooltip() const;
private:
enum UrlType {
StandardUrl,
Email,
Unknown
virtual QList<QAction *> actions();
/**
* Open a web browser at the current URL. The url itself can be determined using
* the capturedTexts() method.
*/
virtual void activate(QObject * object = 0);
virtual QString tooltip() const;
private:
enum UrlType {
StandardUrl,
Email,
Unknown
};
UrlType urlType() const;
FilterObject * _urlObject;
};
UrlType urlType() const;
FilterObject * _urlObject;
};
UrlFilter();
UrlFilter();
protected:
virtual RegExpFilter::HotSpot * newHotSpot(int,int,int,int);
virtual RegExpFilter::HotSpot * newHotSpot(int,int,int,int);
private:
static const QRegExp FullUrlRegExp;
static const QRegExp EmailAddressRegExp;
static const QRegExp FullUrlRegExp;
static const QRegExp EmailAddressRegExp;
// combined OR of FullUrlRegExp and EmailAddressRegExp
static const QRegExp CompleteUrlRegExp;
// combined OR of FullUrlRegExp and EmailAddressRegExp
static const QRegExp CompleteUrlRegExp;
};
class FilterObject : public QObject {
Q_OBJECT
class FilterObject : public QObject
{
Q_OBJECT
public:
FilterObject(Filter::HotSpot * filter) : _filter(filter) {}
FilterObject(Filter::HotSpot * filter) : _filter(filter) {}
private slots:
void activated();
void activated();
private:
Filter::HotSpot * _filter;
Filter::HotSpot * _filter;
};
/**
@@ -314,57 +322,59 @@ private:
* The hotSpots() and hotSpotsAtLine() method return all of the hotspots in the text and on
* a given line respectively.
*/
class FilterChain : protected QList<Filter *> {
class FilterChain : protected QList<Filter *>
{
public:
virtual ~FilterChain();
virtual ~FilterChain();
/** Adds a new filter to the chain. The chain will delete this filter when it is destroyed */
void addFilter(Filter * filter);
/** Removes a filter from the chain. The chain will no longer delete the filter when destroyed */
void removeFilter(Filter * filter);
/** Returns true if the chain contains @p filter */
bool containsFilter(Filter * filter);
/** Removes all filters from the chain */
void clear();
/** Adds a new filter to the chain. The chain will delete this filter when it is destroyed */
void addFilter(Filter * filter);
/** Removes a filter from the chain. The chain will no longer delete the filter when destroyed */
void removeFilter(Filter * filter);
/** Returns true if the chain contains @p filter */
bool containsFilter(Filter * filter);
/** Removes all filters from the chain */
void clear();
/** Resets each filter in the chain */
void reset();
/**
* Processes each filter in the chain
*/
void process();
/** Resets each filter in the chain */
void reset();
/**
* Processes each filter in the chain
*/
void process();
/** Sets the buffer for each filter in the chain to process. */
void setBuffer(const QString * buffer , const QList<int>* linePositions);
/** Sets the buffer for each filter in the chain to process. */
void setBuffer(const QString * buffer , const QList<int>* linePositions);
/** Returns the first hotspot which occurs at @p line, @p column or 0 if no hotspot was found */
Filter::HotSpot * hotSpotAt(int line , int column) const;
/** Returns a list of all the hotspots in all the chain's filters */
QList<Filter::HotSpot *> hotSpots() const;
/** Returns a list of all hotspots at the given line in all the chain's filters */
QList<Filter::HotSpot> hotSpotsAtLine(int line) const;
/** Returns the first hotspot which occurs at @p line, @p column or 0 if no hotspot was found */
Filter::HotSpot * hotSpotAt(int line , int column) const;
/** Returns a list of all the hotspots in all the chain's filters */
QList<Filter::HotSpot *> hotSpots() const;
/** Returns a list of all hotspots at the given line in all the chain's filters */
QList<Filter::HotSpot> hotSpotsAtLine(int line) const;
};
/** A filter chain which processes character images from terminal displays */
class TerminalImageFilterChain : public FilterChain {
class TerminalImageFilterChain : public FilterChain
{
public:
TerminalImageFilterChain();
virtual ~TerminalImageFilterChain();
TerminalImageFilterChain();
virtual ~TerminalImageFilterChain();
/**
* Set the current terminal image to @p image.
*
* @param image The terminal image
* @param lines The number of lines in the terminal image
* @param columns The number of columns in the terminal image
*/
void setImage(const Character * const image , int lines , int columns,
const QVector<LineProperty>& lineProperties);
/**
* Set the current terminal image to @p image.
*
* @param image The terminal image
* @param lines The number of lines in the terminal image
* @param columns The number of columns in the terminal image
*/
void setImage(const Character * const image , int lines , int columns,
const QVector<LineProperty>& lineProperties);
private:
QString * _buffer;
QList<int>* _linePositions;
QString * _buffer;
QList<int>* _linePositions;
};
}
+412 -345
View File
@@ -84,105 +84,113 @@ FIXME: There is noticeable decrease in speed, also. Perhaps,
*/
HistoryFile::HistoryFile()
: ion(-1),
length(0),
fileMap(0) {
if (tmpFile.open()) {
tmpFile.setAutoRemove(true);
ion = tmpFile.handle();
}
: ion(-1),
length(0),
fileMap(0)
{
if (tmpFile.open()) {
tmpFile.setAutoRemove(true);
ion = tmpFile.handle();
}
}
HistoryFile::~HistoryFile() {
if (fileMap) {
unmap();
}
HistoryFile::~HistoryFile()
{
if (fileMap) {
unmap();
}
}
//TODO: Mapping the entire file in will cause problems if the history file becomes exceedingly large,
//(ie. larger than available memory). HistoryFile::map() should only map in sections of the file at a time,
//to avoid this.
void HistoryFile::map() {
assert( fileMap == 0 );
void HistoryFile::map()
{
assert( fileMap == 0 );
fileMap = (char *)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 );
fileMap = (char *)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 );
//if mmap'ing fails, fall back to the read-lseek combination
if ( fileMap == MAP_FAILED ) {
readWriteBalance = 0;
fileMap = 0;
qDebug() << ": mmap'ing history failed. errno = " << errno;
}
}
void HistoryFile::unmap() {
int result = munmap( fileMap , length );
assert( result == 0 );
fileMap = 0;
}
bool HistoryFile::isMapped() {
return (fileMap != 0);
}
void HistoryFile::add(const unsigned char * bytes, int len) {
if ( fileMap ) {
unmap();
}
readWriteBalance++;
int rc = 0;
rc = lseek(ion,length,SEEK_SET);
if (rc < 0) {
perror("HistoryFile::add.seek");
return;
}
rc = write(ion,bytes,len);
if (rc < 0) {
perror("HistoryFile::add.write");
return;
}
length += rc;
}
void HistoryFile::get(unsigned char * bytes, int len, int loc) {
//count number of get() calls vs. number of add() calls.
//If there are many more get() calls compared with add()
//calls (decided by using MAP_THRESHOLD) then mmap the log
//file to improve performance.
readWriteBalance--;
if ( !fileMap && readWriteBalance < MAP_THRESHOLD ) {
map();
}
if ( fileMap ) {
for (int i=0; i<len; i++) {
bytes[i]=fileMap[loc+i];
//if mmap'ing fails, fall back to the read-lseek combination
if ( fileMap == MAP_FAILED ) {
readWriteBalance = 0;
fileMap = 0;
qDebug() << ": mmap'ing history failed. errno = " << errno;
}
} else {
}
void HistoryFile::unmap()
{
int result = munmap( fileMap , length );
assert( result == 0 );
fileMap = 0;
}
bool HistoryFile::isMapped()
{
return (fileMap != 0);
}
void HistoryFile::add(const unsigned char * bytes, int len)
{
if ( fileMap ) {
unmap();
}
readWriteBalance++;
int rc = 0;
if (loc < 0 || len < 0 || loc + len > length) {
fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
}
rc = lseek(ion,loc,SEEK_SET);
rc = lseek(ion,length,SEEK_SET);
if (rc < 0) {
perror("HistoryFile::get.seek");
return;
perror("HistoryFile::add.seek");
return;
}
rc = read(ion,bytes,len);
rc = write(ion,bytes,len);
if (rc < 0) {
perror("HistoryFile::get.read");
return;
perror("HistoryFile::add.write");
return;
}
}
length += rc;
}
int HistoryFile::len() {
return length;
void HistoryFile::get(unsigned char * bytes, int len, int loc)
{
//count number of get() calls vs. number of add() calls.
//If there are many more get() calls compared with add()
//calls (decided by using MAP_THRESHOLD) then mmap the log
//file to improve performance.
readWriteBalance--;
if ( !fileMap && readWriteBalance < MAP_THRESHOLD ) {
map();
}
if ( fileMap ) {
for (int i=0; i<len; i++) {
bytes[i]=fileMap[loc+i];
}
} else {
int rc = 0;
if (loc < 0 || len < 0 || loc + len > length) {
fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
}
rc = lseek(ion,loc,SEEK_SET);
if (rc < 0) {
perror("HistoryFile::get.seek");
return;
}
rc = read(ion,bytes,len);
if (rc < 0) {
perror("HistoryFile::get.read");
return;
}
}
}
int HistoryFile::len()
{
return length;
}
@@ -190,15 +198,18 @@ int HistoryFile::len() {
HistoryScroll::HistoryScroll(HistoryType * t)
: m_histType(t) {
: m_histType(t)
{
}
HistoryScroll::~HistoryScroll() {
delete m_histType;
HistoryScroll::~HistoryScroll()
{
delete m_histType;
}
bool HistoryScroll::hasScroll() {
return true;
bool HistoryScroll::hasScroll()
{
return true;
}
// History Scroll File //////////////////////////////////////
@@ -215,426 +226,482 @@ bool HistoryScroll::hasScroll() {
*/
HistoryScrollFile::HistoryScrollFile(const QString & logFileName)
: HistoryScroll(new HistoryTypeFile(logFileName)),
m_logFileName(logFileName) {
: HistoryScroll(new HistoryTypeFile(logFileName)),
m_logFileName(logFileName)
{
}
HistoryScrollFile::~HistoryScrollFile() {
HistoryScrollFile::~HistoryScrollFile()
{
}
int HistoryScrollFile::getLines() {
return index.len() / sizeof(int);
int HistoryScrollFile::getLines()
{
return index.len() / sizeof(int);
}
int HistoryScrollFile::getLineLen(int lineno) {
return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
int HistoryScrollFile::getLineLen(int lineno)
{
return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
}
bool HistoryScrollFile::isWrappedLine(int lineno) {
if (lineno>=0 && lineno <= getLines()) {
unsigned char flag;
lineflags.get((unsigned char *)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
return flag;
}
return false;
bool HistoryScrollFile::isWrappedLine(int lineno)
{
if (lineno>=0 && lineno <= getLines()) {
unsigned char flag;
lineflags.get((unsigned char *)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
return flag;
}
return false;
}
int HistoryScrollFile::startOfLine(int lineno) {
if (lineno <= 0) {
return 0;
}
if (lineno <= getLines()) {
int HistoryScrollFile::startOfLine(int lineno)
{
if (lineno <= 0) {
return 0;
}
if (lineno <= getLines()) {
if (!index.isMapped()) {
index.map();
if (!index.isMapped()) {
index.map();
}
int res;
index.get((unsigned char *)&res,sizeof(int),(lineno-1)*sizeof(int));
return res;
}
return cells.len();
}
void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
{
cells.get((unsigned char *)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
}
void HistoryScrollFile::addCells(const Character text[], int count)
{
cells.add((unsigned char *)text,count*sizeof(Character));
}
void HistoryScrollFile::addLine(bool previousWrapped)
{
if (index.isMapped()) {
index.unmap();
}
int res;
index.get((unsigned char *)&res,sizeof(int),(lineno-1)*sizeof(int));
return res;
}
return cells.len();
}
void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[]) {
cells.get((unsigned char *)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
}
void HistoryScrollFile::addCells(const Character text[], int count) {
cells.add((unsigned char *)text,count*sizeof(Character));
}
void HistoryScrollFile::addLine(bool previousWrapped) {
if (index.isMapped()) {
index.unmap();
}
int locn = cells.len();
index.add((unsigned char *)&locn,sizeof(int));
unsigned char flags = previousWrapped ? 0x01 : 0x00;
lineflags.add((unsigned char *)&flags,sizeof(unsigned char));
int locn = cells.len();
index.add((unsigned char *)&locn,sizeof(int));
unsigned char flags = previousWrapped ? 0x01 : 0x00;
lineflags.add((unsigned char *)&flags,sizeof(unsigned char));
}
// History Scroll Buffer //////////////////////////////////////
HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
: HistoryScroll(new HistoryTypeBuffer(maxLineCount))
,_historyBuffer()
,_maxLineCount(0)
,_usedLines(0)
,_head(0) {
setMaxNbLines(maxLineCount);
: HistoryScroll(new HistoryTypeBuffer(maxLineCount))
,_historyBuffer()
,_maxLineCount(0)
,_usedLines(0)
,_head(0)
{
setMaxNbLines(maxLineCount);
}
HistoryScrollBuffer::~HistoryScrollBuffer() {
delete[] _historyBuffer;
HistoryScrollBuffer::~HistoryScrollBuffer()
{
delete[] _historyBuffer;
}
void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells) {
_head++;
if ( _usedLines < _maxLineCount ) {
_usedLines++;
}
void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
{
_head++;
if ( _usedLines < _maxLineCount ) {
_usedLines++;
}
if ( _head >= _maxLineCount ) {
_head = 0;
}
if ( _head >= _maxLineCount ) {
_head = 0;
}
_historyBuffer[bufferIndex(_usedLines-1)] = cells;
_wrappedLine[bufferIndex(_usedLines-1)] = false;
_historyBuffer[bufferIndex(_usedLines-1)] = cells;
_wrappedLine[bufferIndex(_usedLines-1)] = false;
}
void HistoryScrollBuffer::addCells(const Character a[], int count) {
HistoryLine newLine(count);
qCopy(a,a+count,newLine.begin());
void HistoryScrollBuffer::addCells(const Character a[], int count)
{
HistoryLine newLine(count);
qCopy(a,a+count,newLine.begin());
addCellsVector(newLine);
addCellsVector(newLine);
}
void HistoryScrollBuffer::addLine(bool previousWrapped) {
_wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
void HistoryScrollBuffer::addLine(bool previousWrapped)
{
_wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
}
int HistoryScrollBuffer::getLines() {
return _usedLines;
int HistoryScrollBuffer::getLines()
{
return _usedLines;
}
int HistoryScrollBuffer::getLineLen(int lineNumber) {
Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
int HistoryScrollBuffer::getLineLen(int lineNumber)
{
Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
if ( lineNumber < _usedLines ) {
return _historyBuffer[bufferIndex(lineNumber)].size();
} else {
return 0;
}
if ( lineNumber < _usedLines ) {
return _historyBuffer[bufferIndex(lineNumber)].size();
} else {
return 0;
}
}
bool HistoryScrollBuffer::isWrappedLine(int lineNumber) {
Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
{
Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
if (lineNumber < _usedLines) {
//kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
return _wrappedLine[bufferIndex(lineNumber)];
} else {
return false;
}
if (lineNumber < _usedLines) {
//kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
return _wrappedLine[bufferIndex(lineNumber)];
} else {
return false;
}
}
void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character * buffer) {
if ( count == 0 ) {
return;
}
void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character * buffer)
{
if ( count == 0 ) {
return;
}
Q_ASSERT( lineNumber < _maxLineCount );
Q_ASSERT( lineNumber < _maxLineCount );
if (lineNumber >= _usedLines) {
memset(buffer, 0, count * sizeof(Character));
return;
}
if (lineNumber >= _usedLines) {
memset(buffer, 0, count * sizeof(Character));
return;
}
const HistoryLine & line = _historyBuffer[bufferIndex(lineNumber)];
const HistoryLine & line = _historyBuffer[bufferIndex(lineNumber)];
//kDebug() << "startCol " << startColumn;
//kDebug() << "line.size() " << line.size();
//kDebug() << "count " << count;
//kDebug() << "startCol " << startColumn;
//kDebug() << "line.size() " << line.size();
//kDebug() << "count " << count;
Q_ASSERT( startColumn <= line.size() - count );
Q_ASSERT( startColumn <= line.size() - count );
memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
}
void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount) {
HistoryLine * oldBuffer = _historyBuffer;
HistoryLine * newBuffer = new HistoryLine[lineCount];
void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
{
HistoryLine * oldBuffer = _historyBuffer;
HistoryLine * newBuffer = new HistoryLine[lineCount];
for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ ) {
newBuffer[i] = oldBuffer[bufferIndex(i)];
}
for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ ) {
newBuffer[i] = oldBuffer[bufferIndex(i)];
}
_usedLines = qMin(_usedLines,(int)lineCount);
_maxLineCount = lineCount;
_head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
_usedLines = qMin(_usedLines,(int)lineCount);
_maxLineCount = lineCount;
_head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
_historyBuffer = newBuffer;
delete[] oldBuffer;
_historyBuffer = newBuffer;
delete[] oldBuffer;
_wrappedLine.resize(lineCount);
_wrappedLine.resize(lineCount);
}
int HistoryScrollBuffer::bufferIndex(int lineNumber) {
Q_ASSERT( lineNumber >= 0 );
Q_ASSERT( lineNumber < _maxLineCount );
Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
int HistoryScrollBuffer::bufferIndex(int lineNumber)
{
Q_ASSERT( lineNumber >= 0 );
Q_ASSERT( lineNumber < _maxLineCount );
Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
if ( _usedLines == _maxLineCount ) {
return (_head+lineNumber+1) % _maxLineCount;
} else {
return lineNumber;
}
if ( _usedLines == _maxLineCount ) {
return (_head+lineNumber+1) % _maxLineCount;
} else {
return lineNumber;
}
}
// History Scroll None //////////////////////////////////////
HistoryScrollNone::HistoryScrollNone()
: HistoryScroll(new HistoryTypeNone()) {
: HistoryScroll(new HistoryTypeNone())
{
}
HistoryScrollNone::~HistoryScrollNone() {
HistoryScrollNone::~HistoryScrollNone()
{
}
bool HistoryScrollNone::hasScroll() {
return false;
bool HistoryScrollNone::hasScroll()
{
return false;
}
int HistoryScrollNone::getLines() {
return 0;
int HistoryScrollNone::getLines()
{
return 0;
}
int HistoryScrollNone::getLineLen(int) {
return 0;
int HistoryScrollNone::getLineLen(int)
{
return 0;
}
bool HistoryScrollNone::isWrappedLine(int /*lineno*/) {
return false;
bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
{
return false;
}
void HistoryScrollNone::getCells(int, int, int, Character []) {
void HistoryScrollNone::getCells(int, int, int, Character [])
{
}
void HistoryScrollNone::addCells(const Character [], int) {
void HistoryScrollNone::addCells(const Character [], int)
{
}
void HistoryScrollNone::addLine(bool) {
void HistoryScrollNone::addLine(bool)
{
}
// History Scroll BlockArray //////////////////////////////////////
HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
: HistoryScroll(new HistoryTypeBlockArray(size)) {
m_blockArray.setHistorySize(size); // nb. of lines.
: HistoryScroll(new HistoryTypeBlockArray(size))
{
m_blockArray.setHistorySize(size); // nb. of lines.
}
HistoryScrollBlockArray::~HistoryScrollBlockArray() {
HistoryScrollBlockArray::~HistoryScrollBlockArray()
{
}
int HistoryScrollBlockArray::getLines() {
return m_lineLengths.count();
int HistoryScrollBlockArray::getLines()
{
return m_lineLengths.count();
}
int HistoryScrollBlockArray::getLineLen(int lineno) {
if ( m_lineLengths.contains(lineno) ) {
return m_lineLengths[lineno];
} else {
return 0;
}
int HistoryScrollBlockArray::getLineLen(int lineno)
{
if ( m_lineLengths.contains(lineno) ) {
return m_lineLengths[lineno];
} else {
return 0;
}
}
bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/) {
return false;
bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
{
return false;
}
void HistoryScrollBlockArray::getCells(int lineno, int colno,
int count, Character res[]) {
if (!count) {
return;
}
int count, Character res[])
{
if (!count) {
return;
}
const Block * b = m_blockArray.at(lineno);
const Block * b = m_blockArray.at(lineno);
if (!b) {
memset(res, 0, count * sizeof(Character)); // still better than random data
return;
}
if (!b) {
memset(res, 0, count * sizeof(Character)); // still better than random data
return;
}
assert(((colno + count) * sizeof(Character)) < ENTRIES);
memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
assert(((colno + count) * sizeof(Character)) < ENTRIES);
memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
}
void HistoryScrollBlockArray::addCells(const Character a[], int count) {
Block * b = m_blockArray.lastBlock();
void HistoryScrollBlockArray::addCells(const Character a[], int count)
{
Block * b = m_blockArray.lastBlock();
if (!b) {
return;
}
if (!b) {
return;
}
// put cells in block's data
assert((count * sizeof(Character)) < ENTRIES);
// put cells in block's data
assert((count * sizeof(Character)) < ENTRIES);
memset(b->data, 0, ENTRIES);
memset(b->data, 0, ENTRIES);
memcpy(b->data, a, count * sizeof(Character));
b->size = count * sizeof(Character);
memcpy(b->data, a, count * sizeof(Character));
b->size = count * sizeof(Character);
size_t res = m_blockArray.newBlock();
assert (res > 0);
Q_UNUSED( res );
size_t res = m_blockArray.newBlock();
assert (res > 0);
Q_UNUSED( res );
m_lineLengths.insert(m_blockArray.getCurrent(), count);
m_lineLengths.insert(m_blockArray.getCurrent(), count);
}
void HistoryScrollBlockArray::addLine(bool) {
void HistoryScrollBlockArray::addLine(bool)
{
}
//////////////////////////////////////////////////////////////////////
// History Types
//////////////////////////////////////////////////////////////////////
HistoryType::HistoryType() {
HistoryType::HistoryType()
{
}
HistoryType::~HistoryType() {
HistoryType::~HistoryType()
{
}
//////////////////////////////
HistoryTypeNone::HistoryTypeNone() {
HistoryTypeNone::HistoryTypeNone()
{
}
bool HistoryTypeNone::isEnabled() const {
return false;
bool HistoryTypeNone::isEnabled() const
{
return false;
}
HistoryScroll * HistoryTypeNone::scroll(HistoryScroll * old) const {
delete old;
return new HistoryScrollNone();
HistoryScroll * HistoryTypeNone::scroll(HistoryScroll * old) const
{
delete old;
return new HistoryScrollNone();
}
int HistoryTypeNone::maximumLineCount() const {
return 0;
int HistoryTypeNone::maximumLineCount() const
{
return 0;
}
//////////////////////////////
HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
: m_size(size) {
: m_size(size)
{
}
bool HistoryTypeBlockArray::isEnabled() const {
return true;
bool HistoryTypeBlockArray::isEnabled() const
{
return true;
}
int HistoryTypeBlockArray::maximumLineCount() const {
return m_size;
int HistoryTypeBlockArray::maximumLineCount() const
{
return m_size;
}
HistoryScroll * HistoryTypeBlockArray::scroll(HistoryScroll * old) const {
delete old;
return new HistoryScrollBlockArray(m_size);
HistoryScroll * HistoryTypeBlockArray::scroll(HistoryScroll * old) const
{
delete old;
return new HistoryScrollBlockArray(m_size);
}
//////////////////////////////
HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
: m_nbLines(nbLines) {
: m_nbLines(nbLines)
{
}
bool HistoryTypeBuffer::isEnabled() const {
return true;
bool HistoryTypeBuffer::isEnabled() const
{
return true;
}
int HistoryTypeBuffer::maximumLineCount() const {
return m_nbLines;
int HistoryTypeBuffer::maximumLineCount() const
{
return m_nbLines;
}
HistoryScroll * HistoryTypeBuffer::scroll(HistoryScroll * old) const {
if (old) {
HistoryScrollBuffer * oldBuffer = dynamic_cast<HistoryScrollBuffer *>(old);
if (oldBuffer) {
oldBuffer->setMaxNbLines(m_nbLines);
return oldBuffer;
}
HistoryScroll * HistoryTypeBuffer::scroll(HistoryScroll * old) const
{
if (old) {
HistoryScrollBuffer * oldBuffer = dynamic_cast<HistoryScrollBuffer *>(old);
if (oldBuffer) {
oldBuffer->setMaxNbLines(m_nbLines);
return oldBuffer;
}
HistoryScroll * newScroll = new HistoryScrollBuffer(m_nbLines);
int lines = old->getLines();
int startLine = 0;
if (lines > (int) m_nbLines) {
startLine = lines - m_nbLines;
}
HistoryScroll * newScroll = new HistoryScrollBuffer(m_nbLines);
int lines = old->getLines();
int startLine = 0;
if (lines > (int) m_nbLines) {
startLine = lines - m_nbLines;
}
Character line[LINE_SIZE];
for(int i = startLine; i < lines; i++) {
int size = old->getLineLen(i);
if (size > LINE_SIZE) {
Character * tmp_line = new Character[size];
old->getCells(i, 0, size, tmp_line);
newScroll->addCells(tmp_line, size);
newScroll->addLine(old->isWrappedLine(i));
delete [] tmp_line;
} else {
old->getCells(i, 0, size, line);
newScroll->addCells(line, size);
newScroll->addLine(old->isWrappedLine(i));
}
Character line[LINE_SIZE];
for (int i = startLine; i < lines; i++) {
int size = old->getLineLen(i);
if (size > LINE_SIZE) {
Character * tmp_line = new Character[size];
old->getCells(i, 0, size, tmp_line);
newScroll->addCells(tmp_line, size);
newScroll->addLine(old->isWrappedLine(i));
delete [] tmp_line;
} else {
old->getCells(i, 0, size, line);
newScroll->addCells(line, size);
newScroll->addLine(old->isWrappedLine(i));
}
}
delete old;
return newScroll;
}
delete old;
return newScroll;
}
return new HistoryScrollBuffer(m_nbLines);
return new HistoryScrollBuffer(m_nbLines);
}
//////////////////////////////
HistoryTypeFile::HistoryTypeFile(const QString & fileName)
: m_fileName(fileName) {
: m_fileName(fileName)
{
}
bool HistoryTypeFile::isEnabled() const {
return true;
bool HistoryTypeFile::isEnabled() const
{
return true;
}
const QString & HistoryTypeFile::getFileName() const {
return m_fileName;
const QString & HistoryTypeFile::getFileName() const
{
return m_fileName;
}
HistoryScroll * HistoryTypeFile::scroll(HistoryScroll * old) const {
if (dynamic_cast<HistoryFile *>(old)) {
return old; // Unchanged.
}
HistoryScroll * newScroll = new HistoryScrollFile(m_fileName);
Character line[LINE_SIZE];
int lines = (old != 0) ? old->getLines() : 0;
for(int i = 0; i < lines; i++) {
int size = old->getLineLen(i);
if (size > LINE_SIZE) {
Character * tmp_line = new Character[size];
old->getCells(i, 0, size, tmp_line);
newScroll->addCells(tmp_line, size);
newScroll->addLine(old->isWrappedLine(i));
delete [] tmp_line;
} else {
old->getCells(i, 0, size, line);
newScroll->addCells(line, size);
newScroll->addLine(old->isWrappedLine(i));
HistoryScroll * HistoryTypeFile::scroll(HistoryScroll * old) const
{
if (dynamic_cast<HistoryFile *>(old)) {
return old; // Unchanged.
}
}
delete old;
return newScroll;
HistoryScroll * newScroll = new HistoryScrollFile(m_fileName);
Character line[LINE_SIZE];
int lines = (old != 0) ? old->getLines() : 0;
for (int i = 0; i < lines; i++) {
int size = old->getLineLen(i);
if (size > LINE_SIZE) {
Character * tmp_line = new Character[size];
old->getCells(i, 0, size, tmp_line);
newScroll->addCells(tmp_line, size);
newScroll->addLine(old->isWrappedLine(i));
delete [] tmp_line;
} else {
old->getCells(i, 0, size, line);
newScroll->addCells(line, size);
newScroll->addLine(old->isWrappedLine(i));
}
}
delete old;
return newScroll;
}
int HistoryTypeFile::maximumLineCount() const {
return 0;
int HistoryTypeFile::maximumLineCount() const
{
return 0;
}
+175 -163
View File
@@ -32,46 +32,48 @@
#include "BlockArray.h"
#include "Character.h"
namespace Konsole {
namespace Konsole
{
#if 1
/*
An extendable tmpfile(1) based buffer.
*/
class HistoryFile {
class HistoryFile
{
public:
HistoryFile();
virtual ~HistoryFile();
HistoryFile();
virtual ~HistoryFile();
virtual void add(const unsigned char * bytes, int len);
virtual void get(unsigned char * bytes, int len, int loc);
virtual int len();
virtual void add(const unsigned char * bytes, int len);
virtual void get(unsigned char * bytes, int len, int loc);
virtual int len();
//mmaps the file in read-only mode
void map();
//un-mmaps the file
void unmap();
//returns true if the file is mmap'ed
bool isMapped();
//mmaps the file in read-only mode
void map();
//un-mmaps the file
void unmap();
//returns true if the file is mmap'ed
bool isMapped();
private:
int ion;
int length;
QTemporaryFile tmpFile;
int ion;
int length;
QTemporaryFile tmpFile;
//pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed
char * fileMap;
//pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed
char * fileMap;
//incremented whenver 'add' is called and decremented whenever
//'get' is called.
//this is used to detect when a large number of lines are being read and processed from the history
//and automatically mmap the file for better performance (saves the overhead of many lseek-read calls).
int readWriteBalance;
//incremented whenver 'add' is called and decremented whenever
//'get' is called.
//this is used to detect when a large number of lines are being read and processed from the history
//and automatically mmap the file for better performance (saves the overhead of many lseek-read calls).
int readWriteBalance;
//when readWriteBalance goes below this threshold, the file will be mmap'ed automatically
static const int MAP_THRESHOLD = -1000;
//when readWriteBalance goes below this threshold, the file will be mmap'ed automatically
static const int MAP_THRESHOLD = -1000;
};
#endif
@@ -82,47 +84,48 @@ private:
//////////////////////////////////////////////////////////////////////
class HistoryType;
class HistoryScroll {
class HistoryScroll
{
public:
HistoryScroll(HistoryType *);
virtual ~HistoryScroll();
HistoryScroll(HistoryType *);
virtual ~HistoryScroll();
virtual bool hasScroll();
virtual bool hasScroll();
// access to history
virtual int getLines() = 0;
virtual int getLineLen(int lineno) = 0;
virtual void getCells(int lineno, int colno, int count, Character res[]) = 0;
virtual bool isWrappedLine(int lineno) = 0;
// access to history
virtual int getLines() = 0;
virtual int getLineLen(int lineno) = 0;
virtual void getCells(int lineno, int colno, int count, Character res[]) = 0;
virtual bool isWrappedLine(int lineno) = 0;
// backward compatibility (obsolete)
Character getCell(int lineno, int colno) {
Character res;
getCells(lineno,colno,1,&res);
return res;
}
// backward compatibility (obsolete)
Character getCell(int lineno, int colno) {
Character res;
getCells(lineno,colno,1,&res);
return res;
}
// adding lines.
virtual void addCells(const Character a[], int count) = 0;
// convenience method - this is virtual so that subclasses can take advantage
// of QVector's implicit copying
virtual void addCellsVector(const QVector<Character>& cells) {
addCells(cells.data(),cells.size());
}
// adding lines.
virtual void addCells(const Character a[], int count) = 0;
// convenience method - this is virtual so that subclasses can take advantage
// of QVector's implicit copying
virtual void addCellsVector(const QVector<Character>& cells) {
addCells(cells.data(),cells.size());
}
virtual void addLine(bool previousWrapped=false) = 0;
virtual void addLine(bool previousWrapped=false) = 0;
//
// FIXME: Passing around constant references to HistoryType instances
// is very unsafe, because those references will no longer
// be valid if the history scroll is deleted.
//
const HistoryType & getType() {
return *m_histType;
}
//
// FIXME: Passing around constant references to HistoryType instances
// is very unsafe, because those references will no longer
// be valid if the history scroll is deleted.
//
const HistoryType & getType() {
return *m_histType;
}
protected:
HistoryType * m_histType;
HistoryType * m_histType;
};
@@ -132,69 +135,71 @@ protected:
// File-based history (e.g. file log, no limitation in length)
//////////////////////////////////////////////////////////////////////
class HistoryScrollFile : public HistoryScroll {
class HistoryScrollFile : public HistoryScroll
{
public:
HistoryScrollFile(const QString & logFileName);
virtual ~HistoryScrollFile();
HistoryScrollFile(const QString & logFileName);
virtual ~HistoryScrollFile();
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual void addCells(const Character a[], int count);
virtual void addLine(bool previousWrapped=false);
virtual void addCells(const Character a[], int count);
virtual void addLine(bool previousWrapped=false);
private:
int startOfLine(int lineno);
int startOfLine(int lineno);
QString m_logFileName;
HistoryFile index; // lines Row(int)
HistoryFile cells; // text Row(Character)
HistoryFile lineflags; // flags Row(unsigned char)
QString m_logFileName;
HistoryFile index; // lines Row(int)
HistoryFile cells; // text Row(Character)
HistoryFile lineflags; // flags Row(unsigned char)
};
//////////////////////////////////////////////////////////////////////
// Buffer-based history (limited to a fixed nb of lines)
//////////////////////////////////////////////////////////////////////
class HistoryScrollBuffer : public HistoryScroll {
class HistoryScrollBuffer : public HistoryScroll
{
public:
typedef QVector<Character> HistoryLine;
typedef QVector<Character> HistoryLine;
HistoryScrollBuffer(unsigned int maxNbLines = 1000);
virtual ~HistoryScrollBuffer();
HistoryScrollBuffer(unsigned int maxNbLines = 1000);
virtual ~HistoryScrollBuffer();
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual void addCells(const Character a[], int count);
virtual void addCellsVector(const QVector<Character>& cells);
virtual void addLine(bool previousWrapped=false);
virtual void addCells(const Character a[], int count);
virtual void addCellsVector(const QVector<Character>& cells);
virtual void addLine(bool previousWrapped=false);
void setMaxNbLines(unsigned int nbLines);
unsigned int maxNbLines() {
return _maxLineCount;
}
void setMaxNbLines(unsigned int nbLines);
unsigned int maxNbLines() {
return _maxLineCount;
}
private:
int bufferIndex(int lineNumber);
int bufferIndex(int lineNumber);
HistoryLine * _historyBuffer;
QBitArray _wrappedLine;
int _maxLineCount;
int _usedLines;
int _head;
HistoryLine * _historyBuffer;
QBitArray _wrappedLine;
int _maxLineCount;
int _usedLines;
int _head;
//QVector<histline*> m_histBuffer;
//QBitArray m_wrappedLine;
//unsigned int m_maxNbLines;
//unsigned int m_nbLines;
//unsigned int m_arrayIndex;
//bool m_buffFilled;
//QVector<histline*> m_histBuffer;
//QBitArray m_wrappedLine;
//unsigned int m_maxNbLines;
//unsigned int m_nbLines;
//unsigned int m_arrayIndex;
//bool m_buffFilled;
};
/*class HistoryScrollBufferV2 : public HistoryScroll
@@ -216,122 +221,129 @@ public:
//////////////////////////////////////////////////////////////////////
// Nothing-based history (no history :-)
//////////////////////////////////////////////////////////////////////
class HistoryScrollNone : public HistoryScroll {
class HistoryScrollNone : public HistoryScroll
{
public:
HistoryScrollNone();
virtual ~HistoryScrollNone();
HistoryScrollNone();
virtual ~HistoryScrollNone();
virtual bool hasScroll();
virtual bool hasScroll();
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual void addCells(const Character a[], int count);
virtual void addLine(bool previousWrapped=false);
virtual void addCells(const Character a[], int count);
virtual void addLine(bool previousWrapped=false);
};
//////////////////////////////////////////////////////////////////////
// BlockArray-based history
//////////////////////////////////////////////////////////////////////
class HistoryScrollBlockArray : public HistoryScroll {
class HistoryScrollBlockArray : public HistoryScroll
{
public:
HistoryScrollBlockArray(size_t size);
virtual ~HistoryScrollBlockArray();
HistoryScrollBlockArray(size_t size);
virtual ~HistoryScrollBlockArray();
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual int getLines();
virtual int getLineLen(int lineno);
virtual void getCells(int lineno, int colno, int count, Character res[]);
virtual bool isWrappedLine(int lineno);
virtual void addCells(const Character a[], int count);
virtual void addLine(bool previousWrapped=false);
virtual void addCells(const Character a[], int count);
virtual void addLine(bool previousWrapped=false);
protected:
BlockArray m_blockArray;
QHash<int,size_t> m_lineLengths;
BlockArray m_blockArray;
QHash<int,size_t> m_lineLengths;
};
//////////////////////////////////////////////////////////////////////
// History type
//////////////////////////////////////////////////////////////////////
class HistoryType {
class HistoryType
{
public:
HistoryType();
virtual ~HistoryType();
HistoryType();
virtual ~HistoryType();
/**
* Returns true if the history is enabled ( can store lines of output )
* or false otherwise.
*/
virtual bool isEnabled() const = 0;
/**
* Returns true if the history size is unlimited.
*/
bool isUnlimited() const {
return maximumLineCount() == 0;
}
/**
* Returns the maximum number of lines which this history type
* can store or 0 if the history can store an unlimited number of lines.
*/
virtual int maximumLineCount() const = 0;
/**
* Returns true if the history is enabled ( can store lines of output )
* or false otherwise.
*/
virtual bool isEnabled() const = 0;
/**
* Returns true if the history size is unlimited.
*/
bool isUnlimited() const {
return maximumLineCount() == 0;
}
/**
* Returns the maximum number of lines which this history type
* can store or 0 if the history can store an unlimited number of lines.
*/
virtual int maximumLineCount() const = 0;
virtual HistoryScroll * scroll(HistoryScroll *) const = 0;
virtual HistoryScroll * scroll(HistoryScroll *) const = 0;
};
class HistoryTypeNone : public HistoryType {
class HistoryTypeNone : public HistoryType
{
public:
HistoryTypeNone();
HistoryTypeNone();
virtual bool isEnabled() const;
virtual int maximumLineCount() const;
virtual bool isEnabled() const;
virtual int maximumLineCount() const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
};
class HistoryTypeBlockArray : public HistoryType {
class HistoryTypeBlockArray : public HistoryType
{
public:
HistoryTypeBlockArray(size_t size);
HistoryTypeBlockArray(size_t size);
virtual bool isEnabled() const;
virtual int maximumLineCount() const;
virtual bool isEnabled() const;
virtual int maximumLineCount() const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
protected:
size_t m_size;
size_t m_size;
};
#if 1
class HistoryTypeFile : public HistoryType {
class HistoryTypeFile : public HistoryType
{
public:
HistoryTypeFile(const QString & fileName=QString());
HistoryTypeFile(const QString & fileName=QString());
virtual bool isEnabled() const;
virtual const QString & getFileName() const;
virtual int maximumLineCount() const;
virtual bool isEnabled() const;
virtual const QString & getFileName() const;
virtual int maximumLineCount() const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
protected:
QString m_fileName;
QString m_fileName;
};
class HistoryTypeBuffer : public HistoryType {
class HistoryTypeBuffer : public HistoryType
{
public:
HistoryTypeBuffer(unsigned int nbLines);
HistoryTypeBuffer(unsigned int nbLines);
virtual bool isEnabled() const;
virtual int maximumLineCount() const;
virtual bool isEnabled() const;
virtual int maximumLineCount() const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
virtual HistoryScroll * scroll(HistoryScroll *) const;
protected:
unsigned int m_nbLines;
unsigned int m_nbLines;
};
#endif
+690 -641
View File
File diff suppressed because it is too large Load Diff
+429 -406
View File
@@ -40,13 +40,14 @@ typedef void (*CleanUpFunction)();
* Helper class for K_GLOBAL_STATIC to clean up the object on library unload or application
* shutdown.
*/
class CleanUpGlobalStatic {
class CleanUpGlobalStatic
{
public:
CleanUpFunction func;
CleanUpFunction func;
inline ~CleanUpGlobalStatic() {
func();
}
inline ~CleanUpGlobalStatic() {
func();
}
};
@@ -111,7 +112,8 @@ static struct K_GLOBAL_STATIC_STRUCT_NAME(NAME) \
class QIODevice;
class QTextStream;
namespace Konsole {
namespace Konsole
{
/**
* A convertor which maps between key sequences pressed by the user and the
@@ -126,265 +128,267 @@ namespace Konsole {
* (Shift,Ctrl,Alt,Meta etc.) and state flags which indicate the state
* which the terminal must be in for the key sequence to apply.
*/
class KeyboardTranslator {
class KeyboardTranslator
{
public:
/**
* The meaning of a particular key sequence may depend upon the state which
* the terminal emulation is in. Therefore findEntry() may return a different
* Entry depending upon the state flags supplied.
*
* This enum describes the states which may be associated with with a particular
* entry in the keyboard translation entry.
*/
enum State {
/** Indicates that no special state is active */
NoState = 0,
/**
* TODO More documentation
*/
NewLineState = 1,
/**
* Indicates that the terminal is in 'Ansi' mode.
* TODO: More documentation
*/
AnsiState = 2,
/**
* TODO More documentation
*/
CursorKeysState = 4,
/**
* Indicates that the alternate screen ( typically used by interactive programs
* such as screen or vim ) is active
*/
AlternateScreenState = 8,
/** Indicates that any of the modifier keys is active. */
AnyModifierState = 16
};
Q_DECLARE_FLAGS(States,State)
/**
* This enum describes commands which are associated with particular key sequences.
*/
enum Command {
/** Indicates that no command is associated with this command sequence */
NoCommand = 0,
/** TODO Document me */
SendCommand = 1,
/** Scroll the terminal display up one page */
ScrollPageUpCommand = 2,
/** Scroll the terminal display down one page */
ScrollPageDownCommand = 4,
/** Scroll the terminal display up one line */
ScrollLineUpCommand = 8,
/** Scroll the terminal display down one line */
ScrollLineDownCommand = 16,
/** Toggles scroll lock mode */
ScrollLockCommand = 32,
/** Echos the operating system specific erase character. */
EraseCommand = 64
};
Q_DECLARE_FLAGS(Commands,Command)
/**
* Represents an association between a key sequence pressed by the user
* and the character sequence and commands associated with it for a particular
* KeyboardTranslator.
*/
class Entry {
public:
/**
* Constructs a new entry for a keyboard translator.
*/
Entry();
/**
* Returns true if this entry is null.
* This is true for newly constructed entries which have no properties set.
*/
bool isNull() const;
/** Returns the commands associated with this entry */
Command command() const;
/** Sets the command associated with this entry. */
void setCommand(Command command);
/**
* Returns the character sequence associated with this entry, optionally replacing
* wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed.
* The meaning of a particular key sequence may depend upon the state which
* the terminal emulation is in. Therefore findEntry() may return a different
* Entry depending upon the state flags supplied.
*
* TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code.
* Document them.
*
* @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in
* the entry should be replaced with a number to indicate the modifier keys being pressed.
*
* @param modifiers The keyboard modifiers being pressed.
* This enum describes the states which may be associated with with a particular
* entry in the keyboard translation entry.
*/
QByteArray text(bool expandWildCards = false,
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
/** Sets the character sequence associated with this entry */
void setText(const QByteArray & text);
enum State {
/** Indicates that no special state is active */
NoState = 0,
/**
* TODO More documentation
*/
NewLineState = 1,
/**
* Indicates that the terminal is in 'Ansi' mode.
* TODO: More documentation
*/
AnsiState = 2,
/**
* TODO More documentation
*/
CursorKeysState = 4,
/**
* Indicates that the alternate screen ( typically used by interactive programs
* such as screen or vim ) is active
*/
AlternateScreenState = 8,
/** Indicates that any of the modifier keys is active. */
AnyModifierState = 16
};
Q_DECLARE_FLAGS(States,State)
/**
* Returns the character sequence associated with this entry,
* with any non-printable characters replaced with escape sequences.
* This enum describes commands which are associated with particular key sequences.
*/
enum Command {
/** Indicates that no command is associated with this command sequence */
NoCommand = 0,
/** TODO Document me */
SendCommand = 1,
/** Scroll the terminal display up one page */
ScrollPageUpCommand = 2,
/** Scroll the terminal display down one page */
ScrollPageDownCommand = 4,
/** Scroll the terminal display up one line */
ScrollLineUpCommand = 8,
/** Scroll the terminal display down one line */
ScrollLineDownCommand = 16,
/** Toggles scroll lock mode */
ScrollLockCommand = 32,
/** Echos the operating system specific erase character. */
EraseCommand = 64
};
Q_DECLARE_FLAGS(Commands,Command)
/**
* Represents an association between a key sequence pressed by the user
* and the character sequence and commands associated with it for a particular
* KeyboardTranslator.
*/
class Entry
{
public:
/**
* Constructs a new entry for a keyboard translator.
*/
Entry();
/**
* Returns true if this entry is null.
* This is true for newly constructed entries which have no properties set.
*/
bool isNull() const;
/** Returns the commands associated with this entry */
Command command() const;
/** Sets the command associated with this entry. */
void setCommand(Command command);
/**
* Returns the character sequence associated with this entry, optionally replacing
* wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed.
*
* TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code.
* Document them.
*
* @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in
* the entry should be replaced with a number to indicate the modifier keys being pressed.
*
* @param modifiers The keyboard modifiers being pressed.
*/
QByteArray text(bool expandWildCards = false,
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
/** Sets the character sequence associated with this entry */
void setText(const QByteArray & text);
/**
* Returns the character sequence associated with this entry,
* with any non-printable characters replaced with escape sequences.
*
* eg. \\E for Escape, \\t for tab, \\n for new line.
*
* @param expandWildCards See text()
* @param modifiers See text()
*/
QByteArray escapedText(bool expandWildCards = false,
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
/** Returns the character code ( from the Qt::Key enum ) associated with this entry */
int keyCode() const;
/** Sets the character code associated with this entry */
void setKeyCode(int keyCode);
/**
* Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry.
* If a modifier is set in modifierMask() but not in modifiers(), this means that the entry
* only matches when that modifier is NOT pressed.
*
* If a modifier is not set in modifierMask() then the entry matches whether the modifier
* is pressed or not.
*/
Qt::KeyboardModifiers modifiers() const;
/** Returns the keyboard modifiers which are valid in this entry. See modifiers() */
Qt::KeyboardModifiers modifierMask() const;
/** See modifiers() */
void setModifiers( Qt::KeyboardModifiers modifiers );
/** See modifierMask() and modifiers() */
void setModifierMask( Qt::KeyboardModifiers modifiers );
/**
* Returns a bitwise-OR of the enabled state flags associated with this entry.
* If flag is set in stateMask() but not in state(), this means that the entry only
* matches when the terminal is NOT in that state.
*
* If a state is not set in stateMask() then the entry matches whether the terminal
* is in that state or not.
*/
States state() const;
/** Returns the state flags which are valid in this entry. See state() */
States stateMask() const;
/** See state() */
void setState( States state );
/** See stateMask() */
void setStateMask( States mask );
/**
* Returns the key code and modifiers associated with this entry
* as a QKeySequence
*/
//QKeySequence keySequence() const;
/**
* Returns this entry's conditions ( ie. its key code, modifier and state criteria )
* as a string.
*/
QString conditionToString() const;
/**
* Returns this entry's result ( ie. its command or character sequence )
* as a string.
*
* @param expandWildCards See text()
* @param modifiers See text()
*/
QString resultToString(bool expandWildCards = false,
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
/**
* Returns true if this entry matches the given key sequence, specified
* as a combination of @p keyCode , @p modifiers and @p state.
*/
bool matches( int keyCode ,
Qt::KeyboardModifiers modifiers ,
States flags ) const;
bool operator==(const Entry & rhs) const;
private:
void insertModifier( QString & item , int modifier ) const;
void insertState( QString & item , int state ) const;
QByteArray unescape(const QByteArray & text) const;
int _keyCode;
Qt::KeyboardModifiers _modifiers;
Qt::KeyboardModifiers _modifierMask;
States _state;
States _stateMask;
Command _command;
QByteArray _text;
};
/** Constructs a new keyboard translator with the given @p name */
KeyboardTranslator(const QString & name);
//KeyboardTranslator(const KeyboardTranslator& other);
/** Returns the name of this keyboard translator */
QString name() const;
/** Sets the name of this keyboard translator */
void setName(const QString & name);
/** Returns the descriptive name of this keyboard translator */
QString description() const;
/** Sets the descriptive name of this keyboard translator */
void setDescription(const QString & description);
/**
* Looks for an entry in this keyboard translator which matches the given
* key code, keyboard modifiers and state flags.
*
* eg. \\E for Escape, \\t for tab, \\n for new line.
* Returns the matching entry if found or a null Entry otherwise ( ie.
* entry.isNull() will return true )
*
* @param expandWildCards See text()
* @param modifiers See text()
* @param keyCode A key code from the Qt::Key enum
* @param modifiers A combination of modifiers
* @param state Optional flags which specify the current state of the terminal
*/
QByteArray escapedText(bool expandWildCards = false,
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
/** Returns the character code ( from the Qt::Key enum ) associated with this entry */
int keyCode() const;
/** Sets the character code associated with this entry */
void setKeyCode(int keyCode);
Entry findEntry(int keyCode ,
Qt::KeyboardModifiers modifiers ,
States state = NoState) const;
/**
* Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry.
* If a modifier is set in modifierMask() but not in modifiers(), this means that the entry
* only matches when that modifier is NOT pressed.
*
* If a modifier is not set in modifierMask() then the entry matches whether the modifier
* is pressed or not.
* Adds an entry to this keyboard translator's table. Entries can be looked up according
* to their key sequence using findEntry()
*/
Qt::KeyboardModifiers modifiers() const;
/** Returns the keyboard modifiers which are valid in this entry. See modifiers() */
Qt::KeyboardModifiers modifierMask() const;
/** See modifiers() */
void setModifiers( Qt::KeyboardModifiers modifiers );
/** See modifierMask() and modifiers() */
void setModifierMask( Qt::KeyboardModifiers modifiers );
void addEntry(const Entry & entry);
/**
* Returns a bitwise-OR of the enabled state flags associated with this entry.
* If flag is set in stateMask() but not in state(), this means that the entry only
* matches when the terminal is NOT in that state.
*
* If a state is not set in stateMask() then the entry matches whether the terminal
* is in that state or not.
* Replaces an entry in the translator. If the @p existing entry is null,
* then this is equivalent to calling addEntry(@p replacement)
*/
States state() const;
/** Returns the state flags which are valid in this entry. See state() */
States stateMask() const;
/** See state() */
void setState( States state );
/** See stateMask() */
void setStateMask( States mask );
void replaceEntry(const Entry & existing , const Entry & replacement);
/**
* Returns the key code and modifiers associated with this entry
* as a QKeySequence
* Removes an entry from the table.
*/
//QKeySequence keySequence() const;
void removeEntry(const Entry & entry);
/**
* Returns this entry's conditions ( ie. its key code, modifier and state criteria )
* as a string.
*/
QString conditionToString() const;
/**
* Returns this entry's result ( ie. its command or character sequence )
* as a string.
*
* @param expandWildCards See text()
* @param modifiers See text()
*/
QString resultToString(bool expandWildCards = false,
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
/**
* Returns true if this entry matches the given key sequence, specified
* as a combination of @p keyCode , @p modifiers and @p state.
*/
bool matches( int keyCode ,
Qt::KeyboardModifiers modifiers ,
States flags ) const;
bool operator==(const Entry & rhs) const;
private:
void insertModifier( QString & item , int modifier ) const;
void insertState( QString & item , int state ) const;
QByteArray unescape(const QByteArray & text) const;
int _keyCode;
Qt::KeyboardModifiers _modifiers;
Qt::KeyboardModifiers _modifierMask;
States _state;
States _stateMask;
Command _command;
QByteArray _text;
};
/** Constructs a new keyboard translator with the given @p name */
KeyboardTranslator(const QString & name);
//KeyboardTranslator(const KeyboardTranslator& other);
/** Returns the name of this keyboard translator */
QString name() const;
/** Sets the name of this keyboard translator */
void setName(const QString & name);
/** Returns the descriptive name of this keyboard translator */
QString description() const;
/** Sets the descriptive name of this keyboard translator */
void setDescription(const QString & description);
/**
* Looks for an entry in this keyboard translator which matches the given
* key code, keyboard modifiers and state flags.
*
* Returns the matching entry if found or a null Entry otherwise ( ie.
* entry.isNull() will return true )
*
* @param keyCode A key code from the Qt::Key enum
* @param modifiers A combination of modifiers
* @param state Optional flags which specify the current state of the terminal
*/
Entry findEntry(int keyCode ,
Qt::KeyboardModifiers modifiers ,
States state = NoState) const;
/**
* Adds an entry to this keyboard translator's table. Entries can be looked up according
* to their key sequence using findEntry()
*/
void addEntry(const Entry & entry);
/**
* Replaces an entry in the translator. If the @p existing entry is null,
* then this is equivalent to calling addEntry(@p replacement)
*/
void replaceEntry(const Entry & existing , const Entry & replacement);
/**
* Removes an entry from the table.
*/
void removeEntry(const Entry & entry);
/** Returns a list of all entries in the translator. */
QList<Entry> entries() const;
/** Returns a list of all entries in the translator. */
QList<Entry> entries() const;
private:
QHash<int,Entry> _entries; // entries in this keyboard translation,
// entries are indexed according to
// their keycode
QString _name;
QString _description;
QHash<int,Entry> _entries; // entries in this keyboard translation,
// entries are indexed according to
// their keycode
QString _name;
QString _description;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States)
Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands)
@@ -417,230 +421,249 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands)
* }
* @endcode
*/
class KeyboardTranslatorReader {
class KeyboardTranslatorReader
{
public:
/** Constructs a new reader which parses the given @p source */
KeyboardTranslatorReader( QIODevice * source );
/** Constructs a new reader which parses the given @p source */
KeyboardTranslatorReader( QIODevice * source );
/**
* Returns the description text.
* TODO: More documentation
*/
QString description() const;
/**
* Returns the description text.
* TODO: More documentation
*/
QString description() const;
/** Returns true if there is another entry in the source stream */
bool hasNextEntry();
/** Returns the next entry found in the source stream */
KeyboardTranslator::Entry nextEntry();
/** Returns true if there is another entry in the source stream */
bool hasNextEntry();
/** Returns the next entry found in the source stream */
KeyboardTranslator::Entry nextEntry();
/**
* Returns true if an error occurred whilst parsing the input or
* false if no error occurred.
*/
bool parseError();
/**
* Returns true if an error occurred whilst parsing the input or
* false if no error occurred.
*/
bool parseError();
/**
* Parses a condition and result string for a translator entry
* and produces a keyboard translator entry.
*
* The condition and result strings are in the same format as in
*/
static KeyboardTranslator::Entry createEntry( const QString & condition ,
const QString & result );
/**
* Parses a condition and result string for a translator entry
* and produces a keyboard translator entry.
*
* The condition and result strings are in the same format as in
*/
static KeyboardTranslator::Entry createEntry( const QString & condition ,
const QString & result );
private:
struct Token {
enum Type {
TitleKeyword,
TitleText,
KeyKeyword,
KeySequence,
Command,
OutputText
struct Token {
enum Type {
TitleKeyword,
TitleText,
KeyKeyword,
KeySequence,
Command,
OutputText
};
Type type;
QString text;
};
Type type;
QString text;
};
QList<Token> tokenize(const QString &);
void readNext();
bool decodeSequence(const QString & ,
int & keyCode,
Qt::KeyboardModifiers & modifiers,
Qt::KeyboardModifiers & modifierMask,
KeyboardTranslator::States & state,
KeyboardTranslator::States & stateFlags);
QList<Token> tokenize(const QString &);
void readNext();
bool decodeSequence(const QString & ,
int & keyCode,
Qt::KeyboardModifiers & modifiers,
Qt::KeyboardModifiers & modifierMask,
KeyboardTranslator::States & state,
KeyboardTranslator::States & stateFlags);
static bool parseAsModifier(const QString & item , Qt::KeyboardModifier & modifier);
static bool parseAsStateFlag(const QString & item , KeyboardTranslator::State & state);
static bool parseAsKeyCode(const QString & item , int & keyCode);
static bool parseAsCommand(const QString & text , KeyboardTranslator::Command & command);
static bool parseAsModifier(const QString & item , Qt::KeyboardModifier & modifier);
static bool parseAsStateFlag(const QString & item , KeyboardTranslator::State & state);
static bool parseAsKeyCode(const QString & item , int & keyCode);
static bool parseAsCommand(const QString & text , KeyboardTranslator::Command & command);
QIODevice * _source;
QString _description;
KeyboardTranslator::Entry _nextEntry;
bool _hasNext;
QIODevice * _source;
QString _description;
KeyboardTranslator::Entry _nextEntry;
bool _hasNext;
};
/** Writes a keyboard translation to disk. */
class KeyboardTranslatorWriter {
class KeyboardTranslatorWriter
{
public:
/**
* Constructs a new writer which saves data into @p destination.
* The caller is responsible for closing the device when writing is complete.
*/
KeyboardTranslatorWriter(QIODevice * destination);
~KeyboardTranslatorWriter();
/**
* Constructs a new writer which saves data into @p destination.
* The caller is responsible for closing the device when writing is complete.
*/
KeyboardTranslatorWriter(QIODevice * destination);
~KeyboardTranslatorWriter();
/**
* Writes the header for the keyboard translator.
* @param description Description of the keyboard translator.
*/
void writeHeader( const QString & description );
/** Writes a translator entry. */
void writeEntry( const KeyboardTranslator::Entry & entry );
/**
* Writes the header for the keyboard translator.
* @param description Description of the keyboard translator.
*/
void writeHeader( const QString & description );
/** Writes a translator entry. */
void writeEntry( const KeyboardTranslator::Entry & entry );
private:
QIODevice * _destination;
QTextStream * _writer;
QIODevice * _destination;
QTextStream * _writer;
};
/**
* Manages the keyboard translations available for use by terminal sessions,
* see KeyboardTranslator.
*/
class KeyboardTranslatorManager {
class KeyboardTranslatorManager
{
public:
/**
* Constructs a new KeyboardTranslatorManager and loads the list of
* available keyboard translations.
*
* The keyboard translations themselves are not loaded until they are
* first requested via a call to findTranslator()
*/
KeyboardTranslatorManager();
~KeyboardTranslatorManager();
/**
* Constructs a new KeyboardTranslatorManager and loads the list of
* available keyboard translations.
*
* The keyboard translations themselves are not loaded until they are
* first requested via a call to findTranslator()
*/
KeyboardTranslatorManager();
~KeyboardTranslatorManager();
/**
* Adds a new translator. If a translator with the same name
* already exists, it will be replaced by the new translator.
*
* TODO: More documentation.
*/
void addTranslator(KeyboardTranslator * translator);
/**
* Adds a new translator. If a translator with the same name
* already exists, it will be replaced by the new translator.
*
* TODO: More documentation.
*/
void addTranslator(KeyboardTranslator * translator);
/**
* Deletes a translator. Returns true on successful deletion or false otherwise.
*
* TODO: More documentation
*/
bool deleteTranslator(const QString & name);
/**
* Deletes a translator. Returns true on successful deletion or false otherwise.
*
* TODO: More documentation
*/
bool deleteTranslator(const QString & name);
/** Returns the default translator for Konsole. */
const KeyboardTranslator * defaultTranslator();
/** Returns the default translator for Konsole. */
const KeyboardTranslator * defaultTranslator();
/**
* Returns the keyboard translator with the given name or 0 if no translator
* with that name exists.
*
* The first time that a translator with a particular name is requested,
* the on-disk .keyboard file is loaded and parsed.
*/
const KeyboardTranslator * findTranslator(const QString & name);
/**
* Returns a list of the names of available keyboard translators.
*
* The first time this is called, a search for available
* translators is started.
*/
QList<QString> allTranslators();
/**
* Returns the keyboard translator with the given name or 0 if no translator
* with that name exists.
*
* The first time that a translator with a particular name is requested,
* the on-disk .keyboard file is loaded and parsed.
*/
const KeyboardTranslator * findTranslator(const QString & name);
/**
* Returns a list of the names of available keyboard translators.
*
* The first time this is called, a search for available
* translators is started.
*/
QList<QString> allTranslators();
/** Returns the global KeyboardTranslatorManager instance. */
static KeyboardTranslatorManager * instance();
/** Returns the global KeyboardTranslatorManager instance. */
static KeyboardTranslatorManager * instance();
private:
static const char * defaultTranslatorText;
static const char * defaultTranslatorText;
void findTranslators(); // locate the available translators
KeyboardTranslator * loadTranslator(const QString & name); // loads the translator
// with the given name
KeyboardTranslator * loadTranslator(QIODevice * device,const QString & name);
void findTranslators(); // locate the available translators
KeyboardTranslator * loadTranslator(const QString & name); // loads the translator
// with the given name
KeyboardTranslator * loadTranslator(QIODevice * device,const QString & name);
bool saveTranslator(const KeyboardTranslator * translator);
QString findTranslatorPath(const QString & name);
bool saveTranslator(const KeyboardTranslator * translator);
QString findTranslatorPath(const QString & name);
QHash<QString,KeyboardTranslator *> _translators; // maps translator-name -> KeyboardTranslator
// instance
bool _haveLoadedAll;
QHash<QString,KeyboardTranslator *> _translators; // maps translator-name -> KeyboardTranslator
// instance
bool _haveLoadedAll;
};
inline int KeyboardTranslator::Entry::keyCode() const {
return _keyCode;
inline int KeyboardTranslator::Entry::keyCode() const
{
return _keyCode;
}
inline void KeyboardTranslator::Entry::setKeyCode(int keyCode) {
_keyCode = keyCode;
inline void KeyboardTranslator::Entry::setKeyCode(int keyCode)
{
_keyCode = keyCode;
}
inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier ) {
_modifiers = modifier;
inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier )
{
_modifiers = modifier;
}
inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const {
return _modifiers;
inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const
{
return _modifiers;
}
inline void KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask ) {
_modifierMask = mask;
inline void KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask )
{
_modifierMask = mask;
}
inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const {
return _modifierMask;
inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const
{
return _modifierMask;
}
inline bool KeyboardTranslator::Entry::isNull() const {
return ( *this == Entry() );
inline bool KeyboardTranslator::Entry::isNull() const
{
return ( *this == Entry() );
}
inline void KeyboardTranslator::Entry::setCommand( Command command ) {
_command = command;
inline void KeyboardTranslator::Entry::setCommand( Command command )
{
_command = command;
}
inline KeyboardTranslator::Command KeyboardTranslator::Entry::command() const {
return _command;
inline KeyboardTranslator::Command KeyboardTranslator::Entry::command() const
{
return _command;
}
inline void KeyboardTranslator::Entry::setText( const QByteArray & text ) {
_text = unescape(text);
inline void KeyboardTranslator::Entry::setText( const QByteArray & text )
{
_text = unescape(text);
}
inline int oneOrZero(int value) {
return value ? 1 : 0;
inline int oneOrZero(int value)
{
return value ? 1 : 0;
}
inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const {
QByteArray expandedText = _text;
inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
{
QByteArray expandedText = _text;
if (expandWildCards) {
int modifierValue = 1;
modifierValue += oneOrZero(modifiers & Qt::ShiftModifier);
modifierValue += oneOrZero(modifiers & Qt::AltModifier) << 1;
modifierValue += oneOrZero(modifiers & Qt::ControlModifier) << 2;
if (expandWildCards) {
int modifierValue = 1;
modifierValue += oneOrZero(modifiers & Qt::ShiftModifier);
modifierValue += oneOrZero(modifiers & Qt::AltModifier) << 1;
modifierValue += oneOrZero(modifiers & Qt::ControlModifier) << 2;
for (int i=0; i<_text.length(); i++) {
if (expandedText[i] == '*') {
expandedText[i] = '0' + modifierValue;
}
for (int i=0; i<_text.length(); i++) {
if (expandedText[i] == '*') {
expandedText[i] = '0' + modifierValue;
}
}
}
}
return expandedText;
return expandedText;
}
inline void KeyboardTranslator::Entry::setState( States state ) {
_state = state;
inline void KeyboardTranslator::Entry::setState( States state )
{
_state = state;
}
inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const {
return _state;
inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const
{
return _state;
}
inline void KeyboardTranslator::Entry::setStateMask( States stateMask ) {
_stateMask = stateMask;
inline void KeyboardTranslator::Entry::setStateMask( States stateMask )
{
_stateMask = stateMask;
}
inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const {
return _stateMask;
inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const
{
return _stateMask;
}
}
+16 -16
View File
@@ -2,20 +2,20 @@
// You probably do not want to hand-edit this!
static const quint32 LineChars[] = {
0x00007c00, 0x000fffe0, 0x00421084, 0x00e739ce, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00427000, 0x004e7380, 0x00e77800, 0x00ef7bc0,
0x00421c00, 0x00439ce0, 0x00e73c00, 0x00e7bde0, 0x00007084, 0x000e7384, 0x000079ce, 0x000f7bce,
0x00001c84, 0x00039ce4, 0x00003dce, 0x0007bdee, 0x00427084, 0x004e7384, 0x004279ce, 0x00e77884,
0x00e779ce, 0x004f7bce, 0x00ef7bc4, 0x00ef7bce, 0x00421c84, 0x00439ce4, 0x00423dce, 0x00e73c84,
0x00e73dce, 0x0047bdee, 0x00e7bde4, 0x00e7bdee, 0x00427c00, 0x0043fce0, 0x004e7f80, 0x004fffe0,
0x004fffe0, 0x00e7fde0, 0x006f7fc0, 0x00efffe0, 0x00007c84, 0x0003fce4, 0x000e7f84, 0x000fffe4,
0x00007dce, 0x0007fdee, 0x000f7fce, 0x000fffee, 0x00427c84, 0x0043fce4, 0x004e7f84, 0x004fffe4,
0x00427dce, 0x00e77c84, 0x00e77dce, 0x0047fdee, 0x004e7fce, 0x00e7fde4, 0x00ef7f84, 0x004fffee,
0x00efffe4, 0x00e7fdee, 0x00ef7fce, 0x00efffee, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x000f83e0, 0x00a5294a, 0x004e1380, 0x00a57800, 0x00ad0bc0, 0x004390e0, 0x00a53c00, 0x00a5a1e0,
0x000e1384, 0x0000794a, 0x000f0b4a, 0x000390e4, 0x00003d4a, 0x0007a16a, 0x004e1384, 0x00a5694a,
0x00ad2b4a, 0x004390e4, 0x00a52d4a, 0x00a5a16a, 0x004f83e0, 0x00a57c00, 0x00ad83e0, 0x000f83e4,
0x00007d4a, 0x000f836a, 0x004f93e4, 0x00a57d4a, 0x00ad836a, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001c00, 0x00001084, 0x00007000, 0x00421000,
0x00039ce0, 0x000039ce, 0x000e7380, 0x00e73800, 0x000e7f80, 0x00e73884, 0x0003fce0, 0x004239ce
0x00007c00, 0x000fffe0, 0x00421084, 0x00e739ce, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00427000, 0x004e7380, 0x00e77800, 0x00ef7bc0,
0x00421c00, 0x00439ce0, 0x00e73c00, 0x00e7bde0, 0x00007084, 0x000e7384, 0x000079ce, 0x000f7bce,
0x00001c84, 0x00039ce4, 0x00003dce, 0x0007bdee, 0x00427084, 0x004e7384, 0x004279ce, 0x00e77884,
0x00e779ce, 0x004f7bce, 0x00ef7bc4, 0x00ef7bce, 0x00421c84, 0x00439ce4, 0x00423dce, 0x00e73c84,
0x00e73dce, 0x0047bdee, 0x00e7bde4, 0x00e7bdee, 0x00427c00, 0x0043fce0, 0x004e7f80, 0x004fffe0,
0x004fffe0, 0x00e7fde0, 0x006f7fc0, 0x00efffe0, 0x00007c84, 0x0003fce4, 0x000e7f84, 0x000fffe4,
0x00007dce, 0x0007fdee, 0x000f7fce, 0x000fffee, 0x00427c84, 0x0043fce4, 0x004e7f84, 0x004fffe4,
0x00427dce, 0x00e77c84, 0x00e77dce, 0x0047fdee, 0x004e7fce, 0x00e7fde4, 0x00ef7f84, 0x004fffee,
0x00efffe4, 0x00e7fdee, 0x00ef7fce, 0x00efffee, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x000f83e0, 0x00a5294a, 0x004e1380, 0x00a57800, 0x00ad0bc0, 0x004390e0, 0x00a53c00, 0x00a5a1e0,
0x000e1384, 0x0000794a, 0x000f0b4a, 0x000390e4, 0x00003d4a, 0x0007a16a, 0x004e1384, 0x00a5694a,
0x00ad2b4a, 0x004390e4, 0x00a52d4a, 0x00a5a16a, 0x004f83e0, 0x00a57c00, 0x00ad83e0, 0x000f83e4,
0x00007d4a, 0x000f836a, 0x004f93e4, 0x00a57d4a, 0x00ad836a, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001c00, 0x00001084, 0x00007000, 0x00421000,
0x00039ce0, 0x000039ce, 0x000e7380, 0x00e73800, 0x000e7f80, 0x00e73884, 0x0003fce0, 0x004239ce
};
+206 -187
View File
@@ -41,103 +41,111 @@
using namespace Konsole;
void Pty::donePty() {
emit done(exitStatus());
void Pty::donePty()
{
emit done(exitStatus());
}
void Pty::setWindowSize(int lines, int cols) {
_windowColumns = cols;
_windowLines = lines;
void Pty::setWindowSize(int lines, int cols)
{
_windowColumns = cols;
_windowLines = lines;
if (pty()->masterFd() >= 0) {
pty()->setWinSize(lines, cols);
}
}
QSize Pty::windowSize() const {
return QSize(_windowColumns,_windowLines);
}
void Pty::setXonXoff(bool enable) {
_xonXoff = enable;
if (pty()->masterFd() >= 0) {
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
if (!enable) {
ttmode.c_iflag &= ~(IXOFF | IXON);
} else {
ttmode.c_iflag |= (IXOFF | IXON);
if (pty()->masterFd() >= 0) {
pty()->setWinSize(lines, cols);
}
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
}
}
}
QSize Pty::windowSize() const
{
return QSize(_windowColumns,_windowLines);
}
void Pty::setUtf8Mode(bool enable) {
void Pty::setXonXoff(bool enable)
{
_xonXoff = enable;
if (pty()->masterFd() >= 0) {
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
if (!enable) {
ttmode.c_iflag &= ~(IXOFF | IXON);
} else {
ttmode.c_iflag |= (IXOFF | IXON);
}
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
}
}
}
void Pty::setUtf8Mode(bool enable)
{
#ifdef IUTF8 // XXX not a reasonable place to check it.
_utf8 = enable;
_utf8 = enable;
if (pty()->masterFd() >= 0) {
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
if (!enable) {
ttmode.c_iflag &= ~IUTF8;
} else {
ttmode.c_iflag |= IUTF8;
if (pty()->masterFd() >= 0) {
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
if (!enable) {
ttmode.c_iflag &= ~IUTF8;
} else {
ttmode.c_iflag |= IUTF8;
}
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
}
}
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
}
}
#endif
}
void Pty::setErase(char erase) {
_eraseChar = erase;
void Pty::setErase(char erase)
{
_eraseChar = erase;
if (pty()->masterFd() >= 0) {
struct ::termios ttmode;
if (pty()->masterFd() >= 0) {
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
pty()->tcGetAttr(&ttmode);
ttmode.c_cc[VERASE] = erase;
ttmode.c_cc[VERASE] = erase;
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
}
}
}
}
char Pty::erase() const {
if (pty()->masterFd() >= 0) {
qDebug() << "Getting erase char";
struct ::termios ttyAttributes;
pty()->tcGetAttr(&ttyAttributes);
return ttyAttributes.c_cc[VERASE];
}
char Pty::erase() const
{
if (pty()->masterFd() >= 0) {
qDebug() << "Getting erase char";
struct ::termios ttyAttributes;
pty()->tcGetAttr(&ttyAttributes);
return ttyAttributes.c_cc[VERASE];
}
return _eraseChar;
return _eraseChar;
}
void Pty::addEnvironmentVariables(const QStringList & environment) {
QListIterator<QString> iter(environment);
while (iter.hasNext()) {
QString pair = iter.next();
void Pty::addEnvironmentVariables(const QStringList & environment)
{
QListIterator<QString> iter(environment);
while (iter.hasNext()) {
QString pair = iter.next();
// split on the first '=' character
int pos = pair.indexOf('=');
// split on the first '=' character
int pos = pair.indexOf('=');
if ( pos >= 0 ) {
QString variable = pair.left(pos);
QString value = pair.mid(pos+1);
if ( pos >= 0 ) {
QString variable = pair.left(pos);
QString value = pair.mid(pos+1);
//kDebug() << "Setting environment pair" << variable <<
// " set to " << value;
//kDebug() << "Setting environment pair" << variable <<
// " set to " << value;
setEnvironment(variable,value);
setEnvironment(variable,value);
}
}
}
}
int Pty::start(const QString & program,
@@ -147,163 +155,174 @@ int Pty::start(const QString & program,
bool addToUtmp
// const QString& dbusService,
// const QString& dbusSession)
) {
clearArguments();
)
{
clearArguments();
setBinaryExecutable(program.toLatin1());
setBinaryExecutable(program.toLatin1());
addEnvironmentVariables(environment);
addEnvironmentVariables(environment);
QStringListIterator it( programArguments );
while (it.hasNext()) {
arguments.append( it.next().toUtf8() );
}
QStringListIterator it( programArguments );
while (it.hasNext()) {
arguments.append( it.next().toUtf8() );
}
// if ( !dbusService.isEmpty() )
// setEnvironment("KONSOLE_DBUS_SERVICE",dbusService);
// if ( !dbusSession.isEmpty() )
// setEnvironment("KONSOLE_DBUS_SESSION", dbusSession);
setEnvironment("WINDOWID", QString::number(winid));
setEnvironment("WINDOWID", QString::number(winid));
// unless the LANGUAGE environment variable has been set explicitly
// set it to a null string
// this fixes the problem where KCatalog sets the LANGUAGE environment
// variable during the application's startup to something which
// differs from LANG,LC_* etc. and causes programs run from
// the terminal to display mesages in the wrong language
//
// this can happen if LANG contains a language which KDE
// does not have a translation for
//
// BR:149300
if (!environment.contains("LANGUAGE")) {
setEnvironment("LANGUAGE",QString());
}
// unless the LANGUAGE environment variable has been set explicitly
// set it to a null string
// this fixes the problem where KCatalog sets the LANGUAGE environment
// variable during the application's startup to something which
// differs from LANG,LC_* etc. and causes programs run from
// the terminal to display mesages in the wrong language
//
// this can happen if LANG contains a language which KDE
// does not have a translation for
//
// BR:149300
if (!environment.contains("LANGUAGE")) {
setEnvironment("LANGUAGE",QString());
}
setUsePty(All, addToUtmp);
setUsePty(All, addToUtmp);
pty()->open();
pty()->open();
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
if (!_xonXoff) {
ttmode.c_iflag &= ~(IXOFF | IXON);
} else {
ttmode.c_iflag |= (IXOFF | IXON);
}
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
if (!_xonXoff) {
ttmode.c_iflag &= ~(IXOFF | IXON);
} else {
ttmode.c_iflag |= (IXOFF | IXON);
}
#ifdef IUTF8 // XXX not a reasonable place to check it.
if (!_utf8) {
ttmode.c_iflag &= ~IUTF8;
} else {
ttmode.c_iflag |= IUTF8;
}
if (!_utf8) {
ttmode.c_iflag &= ~IUTF8;
} else {
ttmode.c_iflag |= IUTF8;
}
#endif
if (_eraseChar != 0) {
ttmode.c_cc[VERASE] = _eraseChar;
}
if (_eraseChar != 0) {
ttmode.c_cc[VERASE] = _eraseChar;
}
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
}
if (!pty()->tcSetAttr(&ttmode)) {
qWarning("Unable to set terminal attributes.");
}
pty()->setWinSize(_windowLines, _windowColumns);
pty()->setWinSize(_windowLines, _windowColumns);
if ( K3Process::start(NotifyOnExit, (Communication) (Stdin | Stdout)) == false ) {
return -1;
}
if ( K3Process::start(NotifyOnExit, (Communication) (Stdin | Stdout)) == false ) {
return -1;
}
resume(); // Start...
return 0;
resume(); // Start...
return 0;
}
void Pty::setWriteable(bool writeable) {
struct stat sbuf;
stat(pty()->ttyName(), &sbuf);
if (writeable) {
chmod(pty()->ttyName(), sbuf.st_mode | S_IWGRP);
} else {
chmod(pty()->ttyName(), sbuf.st_mode & ~(S_IWGRP|S_IWOTH));
}
void Pty::setWriteable(bool writeable)
{
struct stat sbuf;
stat(pty()->ttyName(), &sbuf);
if (writeable) {
chmod(pty()->ttyName(), sbuf.st_mode | S_IWGRP);
} else {
chmod(pty()->ttyName(), sbuf.st_mode & ~(S_IWGRP|S_IWOTH));
}
}
Pty::Pty()
: _bufferFull(false),
_windowColumns(0),
_windowLines(0),
_eraseChar(0),
_xonXoff(true),
_utf8(true) {
connect(this, SIGNAL(receivedStdout(K3Process *, char *, int )),
this, SLOT(dataReceived(K3Process *,char *, int)));
connect(this, SIGNAL(processExited(K3Process *)),
this, SLOT(donePty()));
connect(this, SIGNAL(wroteStdin(K3Process *)),
this, SLOT(writeReady()));
_pty = new KPty;
: _bufferFull(false),
_windowColumns(0),
_windowLines(0),
_eraseChar(0),
_xonXoff(true),
_utf8(true)
{
connect(this, SIGNAL(receivedStdout(K3Process *, char *, int )),
this, SLOT(dataReceived(K3Process *,char *, int)));
connect(this, SIGNAL(processExited(K3Process *)),
this, SLOT(donePty()));
connect(this, SIGNAL(wroteStdin(K3Process *)),
this, SLOT(writeReady()));
_pty = new KPty;
setUsePty(All, false); // utmp will be overridden later
setUsePty(All, false); // utmp will be overridden later
}
Pty::~Pty() {
delete _pty;
Pty::~Pty()
{
delete _pty;
}
void Pty::writeReady() {
_pendingSendJobs.erase(_pendingSendJobs.begin());
_bufferFull = false;
doSendJobs();
}
void Pty::doSendJobs() {
if(_pendingSendJobs.isEmpty()) {
emit bufferEmpty();
return;
}
SendJob & job = _pendingSendJobs.first();
if (!writeStdin( job.data(), job.length() )) {
qWarning("Pty::doSendJobs - Could not send input data to terminal process.");
return;
}
_bufferFull = true;
}
void Pty::appendSendJob(const char * s, int len) {
_pendingSendJobs.append(SendJob(s,len));
}
void Pty::sendData(const char * s, int len) {
appendSendJob(s,len);
if (!_bufferFull) {
void Pty::writeReady()
{
_pendingSendJobs.erase(_pendingSendJobs.begin());
_bufferFull = false;
doSendJobs();
}
}
void Pty::dataReceived(K3Process *,char * buf, int len) {
emit receivedData(buf,len);
void Pty::doSendJobs()
{
if (_pendingSendJobs.isEmpty()) {
emit bufferEmpty();
return;
}
SendJob & job = _pendingSendJobs.first();
if (!writeStdin( job.data(), job.length() )) {
qWarning("Pty::doSendJobs - Could not send input data to terminal process.");
return;
}
_bufferFull = true;
}
void Pty::lockPty(bool lock) {
if (lock) {
suspend();
} else {
resume();
}
void Pty::appendSendJob(const char * s, int len)
{
_pendingSendJobs.append(SendJob(s,len));
}
int Pty::foregroundProcessGroup() const {
int pid = tcgetpgrp(pty()->masterFd());
void Pty::sendData(const char * s, int len)
{
appendSendJob(s,len);
if (!_bufferFull) {
doSendJobs();
}
}
if ( pid != -1 ) {
return pid;
}
void Pty::dataReceived(K3Process *,char * buf, int len)
{
emit receivedData(buf,len);
}
return 0;
void Pty::lockPty(bool lock)
{
if (lock) {
suspend();
} else {
resume();
}
}
int Pty::foregroundProcessGroup() const
{
int pid = tcgetpgrp(pty()->masterFd());
if ( pid != -1 ) {
return pid;
}
return 0;
}
//#include "moc_Pty.cpp"
+158 -155
View File
@@ -34,7 +34,8 @@
#include "k3process.h"
namespace Konsole {
namespace Konsole
{
/**
* The Pty class is used to start the terminal process,
@@ -49,196 +50,198 @@ namespace Konsole {
* To start the terminal process, call the start() method
* with the program name and appropriate arguments.
*/
class Pty: public K3Process {
Q_OBJECT
class Pty: public K3Process
{
Q_OBJECT
public:
/**
* Constructs a new Pty.
*
* Connect to the sendData() slot and receivedData() signal to prepare
* for sending and receiving data from the terminal process.
*
* To start the terminal process, call the run() method with the
* name of the program to start and appropriate arguments.
*/
Pty();
~Pty();
/**
* Constructs a new Pty.
*
* Connect to the sendData() slot and receivedData() signal to prepare
* for sending and receiving data from the terminal process.
*
* To start the terminal process, call the run() method with the
* name of the program to start and appropriate arguments.
*/
Pty();
~Pty();
/**
* Starts the terminal process.
*
* Returns 0 if the process was started successfully or non-zero
* otherwise.
*
* @param program Path to the program to start
* @param arguments Arguments to pass to the program being started
* @param environment A list of key=value pairs which will be added
* to the environment for the new process. At the very least this
* should include an assignment for the TERM environment variable.
* @param winid Specifies the value of the WINDOWID environment variable
* in the process's environment.
* @param addToUtmp Specifies whether a utmp entry should be created for
* the pty used. See K3Process::setUsePty()
* @param dbusService Specifies the value of the KONSOLE_DBUS_SERVICE
* environment variable in the process's environment.
* @param dbusSession Specifies the value of the KONSOLE_DBUS_SESSION
* environment variable in the process's environment.
*/
int start( const QString & program,
const QStringList & arguments,
const QStringList & environment,
ulong winid,
bool addToUtmp
/**
* Starts the terminal process.
*
* Returns 0 if the process was started successfully or non-zero
* otherwise.
*
* @param program Path to the program to start
* @param arguments Arguments to pass to the program being started
* @param environment A list of key=value pairs which will be added
* to the environment for the new process. At the very least this
* should include an assignment for the TERM environment variable.
* @param winid Specifies the value of the WINDOWID environment variable
* in the process's environment.
* @param addToUtmp Specifies whether a utmp entry should be created for
* the pty used. See K3Process::setUsePty()
* @param dbusService Specifies the value of the KONSOLE_DBUS_SERVICE
* environment variable in the process's environment.
* @param dbusSession Specifies the value of the KONSOLE_DBUS_SESSION
* environment variable in the process's environment.
*/
int start( const QString & program,
const QStringList & arguments,
const QStringList & environment,
ulong winid,
bool addToUtmp
// const QString& dbusService,
// const QString& dbusSession
);
);
/** TODO: Document me */
void setWriteable(bool writeable);
/** TODO: Document me */
void setWriteable(bool writeable);
/**
* Enables or disables Xon/Xoff flow control.
*/
void setXonXoff(bool on);
/**
* Enables or disables Xon/Xoff flow control.
*/
void setXonXoff(bool on);
/**
* Sets the size of the window (in lines and columns of characters)
* used by this teletype.
*/
void setWindowSize(int lines, int cols);
/**
* Sets the size of the window (in lines and columns of characters)
* used by this teletype.
*/
void setWindowSize(int lines, int cols);
/** Returns the size of the window used by this teletype. See setWindowSize() */
QSize windowSize() const;
/** Returns the size of the window used by this teletype. See setWindowSize() */
QSize windowSize() const;
/** TODO Document me */
void setErase(char erase);
/** TODO Document me */
void setErase(char erase);
/** */
char erase() const;
/** */
char erase() const;
/**
* Returns the process id of the teletype's current foreground
* process. This is the process which is currently reading
* input sent to the terminal via. sendData()
*
* If there is a problem reading the foreground process group,
* 0 will be returned.
*/
int foregroundProcessGroup() const;
/**
* Returns the process id of the teletype's current foreground
* process. This is the process which is currently reading
* input sent to the terminal via. sendData()
*
* If there is a problem reading the foreground process group,
* 0 will be returned.
*/
int foregroundProcessGroup() const;
/**
* Returns whether the buffer used to send data to the
* terminal process is full.
*/
bool bufferFull() const {
return _bufferFull;
}
/**
* Returns whether the buffer used to send data to the
* terminal process is full.
*/
bool bufferFull() const {
return _bufferFull;
}
public slots:
/**
* Put the pty into UTF-8 mode on systems which support it.
*/
void setUtf8Mode(bool on);
/**
* Put the pty into UTF-8 mode on systems which support it.
*/
void setUtf8Mode(bool on);
/**
* Suspend or resume processing of data from the standard
* output of the terminal process.
*
* See K3Process::suspend() and K3Process::resume()
*
* @param lock If true, processing of output is suspended,
* otherwise processing is resumed.
*/
void lockPty(bool lock);
/**
* Suspend or resume processing of data from the standard
* output of the terminal process.
*
* See K3Process::suspend() and K3Process::resume()
*
* @param lock If true, processing of output is suspended,
* otherwise processing is resumed.
*/
void lockPty(bool lock);
/**
* Sends data to the process currently controlling the
* teletype ( whose id is returned by foregroundProcessGroup() )
*
* @param buffer Pointer to the data to send.
* @param length Length of @p buffer.
*/
void sendData(const char * buffer, int length);
/**
* Sends data to the process currently controlling the
* teletype ( whose id is returned by foregroundProcessGroup() )
*
* @param buffer Pointer to the data to send.
* @param length Length of @p buffer.
*/
void sendData(const char * buffer, int length);
signals:
/**
* Emitted when the terminal process terminates.
*
* @param exitCode The status code which the process exited with.
*/
void done(int exitCode);
/**
* Emitted when the terminal process terminates.
*
* @param exitCode The status code which the process exited with.
*/
void done(int exitCode);
/**
* Emitted when a new block of data is received from
* the teletype.
*
* @param buffer Pointer to the data received.
* @param length Length of @p buffer
*/
void receivedData(const char * buffer, int length);
/**
* Emitted when a new block of data is received from
* the teletype.
*
* @param buffer Pointer to the data received.
* @param length Length of @p buffer
*/
void receivedData(const char * buffer, int length);
/**
* Emitted when the buffer used to send data to the terminal
* process becomes empty, i.e. all data has been sent.
*/
void bufferEmpty();
/**
* Emitted when the buffer used to send data to the terminal
* process becomes empty, i.e. all data has been sent.
*/
void bufferEmpty();
private slots:
// called when terminal process exits
void donePty();
// called when data is received from the terminal process
void dataReceived(K3Process *, char * buffer, int length);
// sends the first enqueued buffer of data to the
// terminal process
void doSendJobs();
// called when the terminal process is ready to
// receive more data
void writeReady();
// called when terminal process exits
void donePty();
// called when data is received from the terminal process
void dataReceived(K3Process *, char * buffer, int length);
// sends the first enqueued buffer of data to the
// terminal process
void doSendJobs();
// called when the terminal process is ready to
// receive more data
void writeReady();
private:
// takes a list of key=value pairs and adds them
// to the environment for the process
void addEnvironmentVariables(const QStringList & environment);
// takes a list of key=value pairs and adds them
// to the environment for the process
void addEnvironmentVariables(const QStringList & environment);
// enqueues a buffer of data to be sent to the
// terminal process
void appendSendJob(const char * buffer, int length);
// enqueues a buffer of data to be sent to the
// terminal process
void appendSendJob(const char * buffer, int length);
// a buffer of data in the queue to be sent to the
// terminal process
class SendJob {
public:
SendJob() {}
SendJob(const char * b, int len) : buffer(len) {
memcpy( buffer.data() , b , len );
}
// a buffer of data in the queue to be sent to the
// terminal process
class SendJob
{
public:
SendJob() {}
SendJob(const char * b, int len) : buffer(len) {
memcpy( buffer.data() , b , len );
}
const char * data() const {
return buffer.constData();
}
int length() const {
return buffer.size();
}
private:
QVector<char> buffer;
};
const char * data() const {
return buffer.constData();
}
int length() const {
return buffer.size();
}
private:
QVector<char> buffer;
};
QList<SendJob> _pendingSendJobs;
bool _bufferFull;
QList<SendJob> _pendingSendJobs;
bool _bufferFull;
int _windowColumns;
int _windowLines;
char _eraseChar;
bool _xonXoff;
bool _utf8;
KPty * _pty;
int _windowColumns;
int _windowLines;
char _eraseChar;
bool _xonXoff;
bool _utf8;
KPty * _pty;
};
}
+1020 -936
View File
File diff suppressed because it is too large Load Diff
+536 -534
View File
File diff suppressed because it is too large Load Diff
+181 -150
View File
@@ -31,62 +31,68 @@
using namespace Konsole;
ScreenWindow::ScreenWindow(QObject * parent)
: QObject(parent)
, _windowBuffer(0)
, _windowBufferSize(0)
, _bufferNeedsUpdate(true)
, _windowLines(1)
, _currentLine(0)
, _trackOutput(true)
, _scrollCount(0) {
: QObject(parent)
, _windowBuffer(0)
, _windowBufferSize(0)
, _bufferNeedsUpdate(true)
, _windowLines(1)
, _currentLine(0)
, _trackOutput(true)
, _scrollCount(0)
{
}
ScreenWindow::~ScreenWindow() {
delete[] _windowBuffer;
}
void ScreenWindow::setScreen(Screen * screen) {
Q_ASSERT( screen );
_screen = screen;
}
Screen * ScreenWindow::screen() const {
return _screen;
}
Character * ScreenWindow::getImage() {
// reallocate internal buffer if the window size has changed
int size = windowLines() * windowColumns();
if (_windowBuffer == 0 || _windowBufferSize != size) {
ScreenWindow::~ScreenWindow()
{
delete[] _windowBuffer;
_windowBufferSize = size;
_windowBuffer = new Character[size];
_bufferNeedsUpdate = true;
}
}
void ScreenWindow::setScreen(Screen * screen)
{
Q_ASSERT( screen );
if (!_bufferNeedsUpdate) {
return _windowBuffer;
}
_screen->getImage(_windowBuffer,size,
currentLine(),endWindowLine());
// this window may look beyond the end of the screen, in which
// case there will be an unused area which needs to be filled
// with blank characters
fillUnusedArea();
_bufferNeedsUpdate = false;
return _windowBuffer;
_screen = screen;
}
void ScreenWindow::fillUnusedArea() {
int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1;
int windowEndLine = currentLine() + windowLines() - 1;
Screen * ScreenWindow::screen() const
{
return _screen;
}
int unusedLines = windowEndLine - screenEndLine;
int charsToFill = unusedLines * windowColumns();
Character * ScreenWindow::getImage()
{
// reallocate internal buffer if the window size has changed
int size = windowLines() * windowColumns();
if (_windowBuffer == 0 || _windowBufferSize != size) {
delete[] _windowBuffer;
_windowBufferSize = size;
_windowBuffer = new Character[size];
_bufferNeedsUpdate = true;
}
Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill);
if (!_bufferNeedsUpdate) {
return _windowBuffer;
}
_screen->getImage(_windowBuffer,size,
currentLine(),endWindowLine());
// this window may look beyond the end of the screen, in which
// case there will be an unused area which needs to be filled
// with blank characters
fillUnusedArea();
_bufferNeedsUpdate = false;
return _windowBuffer;
}
void ScreenWindow::fillUnusedArea()
{
int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1;
int windowEndLine = currentLine() + windowLines() - 1;
int unusedLines = windowEndLine - screenEndLine;
int charsToFill = unusedLines * windowColumns();
Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill);
}
// return the index of the line at the end of this window, or if this window
@@ -96,166 +102,191 @@ void ScreenWindow::fillUnusedArea() {
// when passing a line number to a Screen method, the line number should
// never be more than endWindowLine()
//
int ScreenWindow::endWindowLine() const {
return qMin(currentLine() + windowLines() - 1,
lineCount() - 1);
int ScreenWindow::endWindowLine() const
{
return qMin(currentLine() + windowLines() - 1,
lineCount() - 1);
}
QVector<LineProperty> ScreenWindow::getLineProperties() {
QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine());
QVector<LineProperty> ScreenWindow::getLineProperties()
{
QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine());
if (result.count() != windowLines()) {
result.resize(windowLines());
}
if (result.count() != windowLines()) {
result.resize(windowLines());
}
return result;
return result;
}
QString ScreenWindow::selectedText( bool preserveLineBreaks ) const {
return _screen->selectedText( preserveLineBreaks );
QString ScreenWindow::selectedText( bool preserveLineBreaks ) const
{
return _screen->selectedText( preserveLineBreaks );
}
void ScreenWindow::getSelectionStart( int & column , int & line ) {
_screen->getSelectionStart(column,line);
line -= currentLine();
void ScreenWindow::getSelectionStart( int & column , int & line )
{
_screen->getSelectionStart(column,line);
line -= currentLine();
}
void ScreenWindow::getSelectionEnd( int & column , int & line ) {
_screen->getSelectionEnd(column,line);
line -= currentLine();
void ScreenWindow::getSelectionEnd( int & column , int & line )
{
_screen->getSelectionEnd(column,line);
line -= currentLine();
}
void ScreenWindow::setSelectionStart( int column , int line , bool columnMode ) {
_screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine()) , columnMode);
void ScreenWindow::setSelectionStart( int column , int line , bool columnMode )
{
_screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine()) , columnMode);
_bufferNeedsUpdate = true;
emit selectionChanged();
_bufferNeedsUpdate = true;
emit selectionChanged();
}
void ScreenWindow::setSelectionEnd( int column , int line ) {
_screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) );
void ScreenWindow::setSelectionEnd( int column , int line )
{
_screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) );
_bufferNeedsUpdate = true;
emit selectionChanged();
_bufferNeedsUpdate = true;
emit selectionChanged();
}
bool ScreenWindow::isSelected( int column , int line ) {
return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) );
bool ScreenWindow::isSelected( int column , int line )
{
return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) );
}
void ScreenWindow::clearSelection() {
_screen->clearSelection();
void ScreenWindow::clearSelection()
{
_screen->clearSelection();
emit selectionChanged();
emit selectionChanged();
}
void ScreenWindow::setWindowLines(int lines) {
Q_ASSERT(lines > 0);
_windowLines = lines;
void ScreenWindow::setWindowLines(int lines)
{
Q_ASSERT(lines > 0);
_windowLines = lines;
}
int ScreenWindow::windowLines() const {
return _windowLines;
int ScreenWindow::windowLines() const
{
return _windowLines;
}
int ScreenWindow::windowColumns() const {
return _screen->getColumns();
int ScreenWindow::windowColumns() const
{
return _screen->getColumns();
}
int ScreenWindow::lineCount() const {
return _screen->getHistLines() + _screen->getLines();
int ScreenWindow::lineCount() const
{
return _screen->getHistLines() + _screen->getLines();
}
int ScreenWindow::columnCount() const {
return _screen->getColumns();
int ScreenWindow::columnCount() const
{
return _screen->getColumns();
}
QPoint ScreenWindow::cursorPosition() const {
QPoint position;
QPoint ScreenWindow::cursorPosition() const
{
QPoint position;
position.setX( _screen->getCursorX() );
position.setY( _screen->getCursorY() );
position.setX( _screen->getCursorX() );
position.setY( _screen->getCursorY() );
return position;
return position;
}
int ScreenWindow::currentLine() const {
return qBound(0,_currentLine,lineCount()-windowLines());
int ScreenWindow::currentLine() const
{
return qBound(0,_currentLine,lineCount()-windowLines());
}
void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount ) {
if ( mode == ScrollLines ) {
scrollTo( currentLine() + amount );
} else if ( mode == ScrollPages ) {
scrollTo( currentLine() + amount * ( windowLines() / 2 ) );
}
void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount )
{
if ( mode == ScrollLines ) {
scrollTo( currentLine() + amount );
} else if ( mode == ScrollPages ) {
scrollTo( currentLine() + amount * ( windowLines() / 2 ) );
}
}
bool ScreenWindow::atEndOfOutput() const {
return currentLine() == (lineCount()-windowLines());
bool ScreenWindow::atEndOfOutput() const
{
return currentLine() == (lineCount()-windowLines());
}
void ScreenWindow::scrollTo( int line ) {
int maxCurrentLineNumber = lineCount() - windowLines();
line = qBound(0,line,maxCurrentLineNumber);
void ScreenWindow::scrollTo( int line )
{
int maxCurrentLineNumber = lineCount() - windowLines();
line = qBound(0,line,maxCurrentLineNumber);
const int delta = line - _currentLine;
_currentLine = line;
const int delta = line - _currentLine;
_currentLine = line;
// keep track of number of lines scrolled by,
// this can be reset by calling resetScrollCount()
_scrollCount += delta;
// keep track of number of lines scrolled by,
// this can be reset by calling resetScrollCount()
_scrollCount += delta;
_bufferNeedsUpdate = true;
_bufferNeedsUpdate = true;
emit scrolled(_currentLine);
emit scrolled(_currentLine);
}
void ScreenWindow::setTrackOutput(bool trackOutput) {
_trackOutput = trackOutput;
void ScreenWindow::setTrackOutput(bool trackOutput)
{
_trackOutput = trackOutput;
}
bool ScreenWindow::trackOutput() const {
return _trackOutput;
bool ScreenWindow::trackOutput() const
{
return _trackOutput;
}
int ScreenWindow::scrollCount() const {
return _scrollCount;
int ScreenWindow::scrollCount() const
{
return _scrollCount;
}
void ScreenWindow::resetScrollCount() {
_scrollCount = 0;
void ScreenWindow::resetScrollCount()
{
_scrollCount = 0;
}
QRect ScreenWindow::scrollRegion() const {
bool equalToScreenSize = windowLines() == _screen->getLines();
QRect ScreenWindow::scrollRegion() const
{
bool equalToScreenSize = windowLines() == _screen->getLines();
if ( atEndOfOutput() && equalToScreenSize ) {
return _screen->lastScrolledRegion();
} else {
return QRect(0,0,windowColumns(),windowLines());
}
if ( atEndOfOutput() && equalToScreenSize ) {
return _screen->lastScrolledRegion();
} else {
return QRect(0,0,windowColumns(),windowLines());
}
}
void ScreenWindow::notifyOutputChanged() {
// move window to the bottom of the screen and update scroll count
// if this window is currently tracking the bottom of the screen
if ( _trackOutput ) {
_scrollCount -= _screen->scrolledLines();
_currentLine = qMax(0,_screen->getHistLines() - (windowLines()-_screen->getLines()));
} else {
// if the history is not unlimited then it may
// have run out of space and dropped the oldest
// lines of output - in this case the screen
// window's current line number will need to
// be adjusted - otherwise the output will scroll
_currentLine = qMax(0,_currentLine -
_screen->droppedLines());
void ScreenWindow::notifyOutputChanged()
{
// move window to the bottom of the screen and update scroll count
// if this window is currently tracking the bottom of the screen
if ( _trackOutput ) {
_scrollCount -= _screen->scrolledLines();
_currentLine = qMax(0,_screen->getHistLines() - (windowLines()-_screen->getLines()));
} else {
// if the history is not unlimited then it may
// have run out of space and dropped the oldest
// lines of output - in this case the screen
// window's current line number will need to
// be adjusted - otherwise the output will scroll
_currentLine = qMax(0,_currentLine -
_screen->droppedLines());
// ensure that the screen window's current position does
// not go beyond the bottom of the screen
_currentLine = qMin( _currentLine , _screen->getHistLines() );
}
// ensure that the screen window's current position does
// not go beyond the bottom of the screen
_currentLine = qMin( _currentLine , _screen->getHistLines() );
}
_bufferNeedsUpdate = true;
_bufferNeedsUpdate = true;
emit outputChanged();
emit outputChanged();
}
//#include "moc_ScreenWindow.cpp"
+171 -169
View File
@@ -30,7 +30,8 @@
// Konsole
#include "Character.h"
namespace Konsole {
namespace Konsole
{
class Screen;
@@ -50,203 +51,204 @@ class Screen;
* be called. This in turn will update the window's position and emit the outputChanged() signal
* if necessary.
*/
class ScreenWindow : public QObject {
Q_OBJECT
class ScreenWindow : public QObject
{
Q_OBJECT
public:
/**
* Constructs a new screen window with the given parent.
* A screen must be specified by calling setScreen() before calling getImage() or getLineProperties().
*
* You should not call this constructor directly, instead use the Emulation::createWindow() method
* to create a window on the emulation which you wish to view. This allows the emulation
* to notify the window when the associated screen has changed and synchronize selection updates
* between all views on a session.
*/
ScreenWindow(QObject * parent = 0);
virtual ~ScreenWindow();
/**
* Constructs a new screen window with the given parent.
* A screen must be specified by calling setScreen() before calling getImage() or getLineProperties().
*
* You should not call this constructor directly, instead use the Emulation::createWindow() method
* to create a window on the emulation which you wish to view. This allows the emulation
* to notify the window when the associated screen has changed and synchronize selection updates
* between all views on a session.
*/
ScreenWindow(QObject * parent = 0);
virtual ~ScreenWindow();
/** Sets the screen which this window looks onto */
void setScreen(Screen * screen);
/** Returns the screen which this window looks onto */
Screen * screen() const;
/** Sets the screen which this window looks onto */
void setScreen(Screen * screen);
/** Returns the screen which this window looks onto */
Screen * screen() const;
/**
* Returns the image of characters which are currently visible through this window
* onto the screen.
*
* The buffer is managed by the ScreenWindow instance and does not need to be
* deleted by the caller.
*/
Character * getImage();
/**
* Returns the image of characters which are currently visible through this window
* onto the screen.
*
* The buffer is managed by the ScreenWindow instance and does not need to be
* deleted by the caller.
*/
Character * getImage();
/**
* Returns the line attributes associated with the lines of characters which
* are currently visible through this window
*/
QVector<LineProperty> getLineProperties();
/**
* Returns the line attributes associated with the lines of characters which
* are currently visible through this window
*/
QVector<LineProperty> getLineProperties();
/**
* Returns the number of lines which the region of the window
* specified by scrollRegion() has been scrolled by since the last call
* to resetScrollCount(). scrollRegion() is in most cases the
* whole window, but will be a smaller area in, for example, applications
* which provide split-screen facilities.
*
* This is not guaranteed to be accurate, but allows views to optimise
* rendering by reducing the amount of costly text rendering that
* needs to be done when the output is scrolled.
*/
int scrollCount() const;
/**
* Returns the number of lines which the region of the window
* specified by scrollRegion() has been scrolled by since the last call
* to resetScrollCount(). scrollRegion() is in most cases the
* whole window, but will be a smaller area in, for example, applications
* which provide split-screen facilities.
*
* This is not guaranteed to be accurate, but allows views to optimise
* rendering by reducing the amount of costly text rendering that
* needs to be done when the output is scrolled.
*/
int scrollCount() const;
/**
* Resets the count of scrolled lines returned by scrollCount()
*/
void resetScrollCount();
/**
* Resets the count of scrolled lines returned by scrollCount()
*/
void resetScrollCount();
/**
* Returns the area of the window which was last scrolled, this is
* usually the whole window area.
*
* Like scrollCount(), this is not guaranteed to be accurate,
* but allows views to optimise rendering.
*/
QRect scrollRegion() const;
/**
* Returns the area of the window which was last scrolled, this is
* usually the whole window area.
*
* Like scrollCount(), this is not guaranteed to be accurate,
* but allows views to optimise rendering.
*/
QRect scrollRegion() const;
/**
* Sets the start of the selection to the given @p line and @p column within
* the window.
*/
void setSelectionStart( int column , int line , bool columnMode );
/**
* Sets the end of the selection to the given @p line and @p column within
* the window.
*/
void setSelectionEnd( int column , int line );
/**
* Retrieves the start of the selection within the window.
*/
void getSelectionStart( int & column , int & line );
/**
* Retrieves the end of the selection within the window.
*/
void getSelectionEnd( int & column , int & line );
/**
* Returns true if the character at @p line , @p column is part of the selection.
*/
bool isSelected( int column , int line );
/**
* Clears the current selection
*/
void clearSelection();
/**
* Sets the start of the selection to the given @p line and @p column within
* the window.
*/
void setSelectionStart( int column , int line , bool columnMode );
/**
* Sets the end of the selection to the given @p line and @p column within
* the window.
*/
void setSelectionEnd( int column , int line );
/**
* Retrieves the start of the selection within the window.
*/
void getSelectionStart( int & column , int & line );
/**
* Retrieves the end of the selection within the window.
*/
void getSelectionEnd( int & column , int & line );
/**
* Returns true if the character at @p line , @p column is part of the selection.
*/
bool isSelected( int column , int line );
/**
* Clears the current selection
*/
void clearSelection();
/** Sets the number of lines in the window */
void setWindowLines(int lines);
/** Returns the number of lines in the window */
int windowLines() const;
/** Returns the number of columns in the window */
int windowColumns() const;
/** Sets the number of lines in the window */
void setWindowLines(int lines);
/** Returns the number of lines in the window */
int windowLines() const;
/** Returns the number of columns in the window */
int windowColumns() const;
/** Returns the total number of lines in the screen */
int lineCount() const;
/** Returns the total number of columns in the screen */
int columnCount() const;
/** Returns the total number of lines in the screen */
int lineCount() const;
/** Returns the total number of columns in the screen */
int columnCount() const;
/** Returns the index of the line which is currently at the top of this window */
int currentLine() const;
/** Returns the index of the line which is currently at the top of this window */
int currentLine() const;
/**
* Returns the position of the cursor
* within the window.
*/
QPoint cursorPosition() const;
/**
* Returns the position of the cursor
* within the window.
*/
QPoint cursorPosition() const;
/**
* Convenience method. Returns true if the window is currently at the bottom
* of the screen.
*/
bool atEndOfOutput() const;
/**
* Convenience method. Returns true if the window is currently at the bottom
* of the screen.
*/
bool atEndOfOutput() const;
/** Scrolls the window so that @p line is at the top of the window */
void scrollTo( int line );
/** Scrolls the window so that @p line is at the top of the window */
void scrollTo( int line );
enum RelativeScrollMode {
ScrollLines,
ScrollPages
};
enum RelativeScrollMode {
ScrollLines,
ScrollPages
};
/**
* Scrolls the window relative to its current position on the screen.
*
* @param mode Specifies whether @p amount refers to the number of lines or the number
* of pages to scroll.
* @param amount The number of lines or pages ( depending on @p mode ) to scroll by. If
* this number is positive, the view is scrolled down. If this number is negative, the view
* is scrolled up.
*/
void scrollBy( RelativeScrollMode mode , int amount );
/**
* Scrolls the window relative to its current position on the screen.
*
* @param mode Specifies whether @p amount refers to the number of lines or the number
* of pages to scroll.
* @param amount The number of lines or pages ( depending on @p mode ) to scroll by. If
* this number is positive, the view is scrolled down. If this number is negative, the view
* is scrolled up.
*/
void scrollBy( RelativeScrollMode mode , int amount );
/**
* Specifies whether the window should automatically move to the bottom
* of the screen when new output is added.
*
* If this is set to true, the window will be moved to the bottom of the associated screen ( see
* screen() ) when the notifyOutputChanged() method is called.
*/
void setTrackOutput(bool trackOutput);
/**
* Returns whether the window automatically moves to the bottom of the screen as
* new output is added. See setTrackOutput()
*/
bool trackOutput() const;
/**
* Specifies whether the window should automatically move to the bottom
* of the screen when new output is added.
*
* If this is set to true, the window will be moved to the bottom of the associated screen ( see
* screen() ) when the notifyOutputChanged() method is called.
*/
void setTrackOutput(bool trackOutput);
/**
* Returns whether the window automatically moves to the bottom of the screen as
* new output is added. See setTrackOutput()
*/
bool trackOutput() const;
/**
* Returns the text which is currently selected.
*
* @param preserveLineBreaks See Screen::selectedText()
*/
QString selectedText( bool preserveLineBreaks ) const;
/**
* Returns the text which is currently selected.
*
* @param preserveLineBreaks See Screen::selectedText()
*/
QString selectedText( bool preserveLineBreaks ) const;
public slots:
/**
* Notifies the window that the contents of the associated terminal screen have changed.
* This moves the window to the bottom of the screen if trackOutput() is true and causes
* the outputChanged() signal to be emitted.
*/
void notifyOutputChanged();
/**
* Notifies the window that the contents of the associated terminal screen have changed.
* This moves the window to the bottom of the screen if trackOutput() is true and causes
* the outputChanged() signal to be emitted.
*/
void notifyOutputChanged();
signals:
/**
* Emitted when the contents of the associated terminal screen ( see screen() ) changes.
*/
void outputChanged();
/**
* Emitted when the contents of the associated terminal screen ( see screen() ) changes.
*/
void outputChanged();
/**
* Emitted when the screen window is scrolled to a different position.
*
* @param line The line which is now at the top of the window.
*/
void scrolled(int line);
/**
* Emitted when the screen window is scrolled to a different position.
*
* @param line The line which is now at the top of the window.
*/
void scrolled(int line);
/**
* Emitted when the selection is changed.
*/
void selectionChanged();
/**
* Emitted when the selection is changed.
*/
void selectionChanged();
private:
int endWindowLine() const;
void fillUnusedArea();
int endWindowLine() const;
void fillUnusedArea();
Screen * _screen; // see setScreen() , screen()
Character * _windowBuffer;
int _windowBufferSize;
bool _bufferNeedsUpdate;
Screen * _screen; // see setScreen() , screen()
Character * _windowBuffer;
int _windowBufferSize;
bool _bufferNeedsUpdate;
int _windowLines;
int _currentLine; // see scrollTo() , currentLine()
bool _trackOutput; // see setTrackOutput() , trackOutput()
int _scrollCount; // count of lines which the window has been scrolled by since
// the last call to resetScrollCount()
int _windowLines;
int _currentLine; // see scrollTo() , currentLine()
bool _trackOutput; // see setTrackOutput() , trackOutput()
int _scrollCount; // count of lines which the window has been scrolled by since
// the last call to resetScrollCount()
};
}
+685 -611
View File
File diff suppressed because it is too large Load Diff
+452 -449
View File
File diff suppressed because it is too large Load Diff
+103 -93
View File
@@ -32,71 +32,80 @@ using namespace Konsole;
// function copied from kdelibs/kio/kio/kurlcompletion.cpp
static bool expandEnv(QString & text);
ShellCommand::ShellCommand(const QString & fullCommand) {
bool inQuotes = false;
ShellCommand::ShellCommand(const QString & fullCommand)
{
bool inQuotes = false;
QString builder;
QString builder;
for ( int i = 0 ; i < fullCommand.count() ; i++ ) {
QChar ch = fullCommand[i];
for ( int i = 0 ; i < fullCommand.count() ; i++ ) {
QChar ch = fullCommand[i];
const bool isLastChar = ( i == fullCommand.count() - 1 );
const bool isQuote = ( ch == '\'' || ch == '\"' );
const bool isLastChar = ( i == fullCommand.count() - 1 );
const bool isQuote = ( ch == '\'' || ch == '\"' );
if ( !isLastChar && isQuote ) {
inQuotes = !inQuotes;
} else {
if ( (!ch.isSpace() || inQuotes) && !isQuote ) {
builder.append(ch);
}
if ( !isLastChar && isQuote ) {
inQuotes = !inQuotes;
} else {
if ( (!ch.isSpace() || inQuotes) && !isQuote ) {
builder.append(ch);
}
if ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) ) {
_arguments << builder;
builder.clear();
}
if ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) ) {
_arguments << builder;
builder.clear();
}
}
}
}
}
ShellCommand::ShellCommand(const QString & command , const QStringList & arguments) {
_arguments = arguments;
ShellCommand::ShellCommand(const QString & command , const QStringList & arguments)
{
_arguments = arguments;
if ( !_arguments.isEmpty() ) {
_arguments[0] == command;
}
if ( !_arguments.isEmpty() ) {
_arguments[0] == command;
}
}
QString ShellCommand::fullCommand() const {
return _arguments.join(QChar(' '));
QString ShellCommand::fullCommand() const
{
return _arguments.join(QChar(' '));
}
QString ShellCommand::command() const {
if ( !_arguments.isEmpty() ) {
return _arguments[0];
} else {
return QString();
}
QString ShellCommand::command() const
{
if ( !_arguments.isEmpty() ) {
return _arguments[0];
} else {
return QString();
}
}
QStringList ShellCommand::arguments() const {
return _arguments;
QStringList ShellCommand::arguments() const
{
return _arguments;
}
bool ShellCommand::isRootCommand() const {
Q_ASSERT(0); // not implemented yet
return false;
bool ShellCommand::isRootCommand() const
{
Q_ASSERT(0); // not implemented yet
return false;
}
bool ShellCommand::isAvailable() const {
Q_ASSERT(0); // not implemented yet
return false;
bool ShellCommand::isAvailable() const
{
Q_ASSERT(0); // not implemented yet
return false;
}
QStringList ShellCommand::expand(const QStringList & items) {
QStringList result;
QStringList ShellCommand::expand(const QStringList & items)
{
QStringList result;
foreach( QString item , items )
result << expand(item);
foreach( QString item , items )
result << expand(item);
return result;
return result;
}
QString ShellCommand::expand(const QString & text) {
QString result = text;
expandEnv(result);
return result;
QString ShellCommand::expand(const QString & text)
{
QString result = text;
expandEnv(result);
return result;
}
/*
@@ -105,55 +114,56 @@ QString ShellCommand::expand(const QString & text) {
* Expand environment variables in text. Escaped '$' characters are ignored.
* Return true if any variables were expanded
*/
static bool expandEnv( QString & text ) {
// Find all environment variables beginning with '$'
//
int pos = 0;
bool expanded = false;
while ( (pos = text.indexOf(QLatin1Char('$'), pos)) != -1 ) {
// Skip escaped '$'
static bool expandEnv( QString & text )
{
// Find all environment variables beginning with '$'
//
if ( pos > 0 && text.at(pos-1) == QLatin1Char('\\') ) {
pos++;
}
// Variable found => expand
//
else {
// Find the end of the variable = next '/' or ' '
//
int pos2 = text.indexOf( QLatin1Char(' '), pos+1 );
int pos_tmp = text.indexOf( QLatin1Char('/'), pos+1 );
int pos = 0;
if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) ) {
pos2 = pos_tmp;
}
bool expanded = false;
if ( pos2 == -1 ) {
pos2 = text.length();
}
while ( (pos = text.indexOf(QLatin1Char('$'), pos)) != -1 ) {
// Replace if the variable is terminated by '/' or ' '
// and defined
//
if ( pos2 >= 0 ) {
int len = pos2 - pos;
QString key = text.mid( pos+1, len-1);
QString value =
QString::fromLocal8Bit( ::getenv(key.toLocal8Bit()) );
if ( !value.isEmpty() ) {
expanded = true;
text.replace( pos, len, value );
pos = pos + value.length();
} else {
pos = pos2;
// Skip escaped '$'
//
if ( pos > 0 && text.at(pos-1) == QLatin1Char('\\') ) {
pos++;
}
}
}
}
// Variable found => expand
//
else {
// Find the end of the variable = next '/' or ' '
//
int pos2 = text.indexOf( QLatin1Char(' '), pos+1 );
int pos_tmp = text.indexOf( QLatin1Char('/'), pos+1 );
return expanded;
if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) ) {
pos2 = pos_tmp;
}
if ( pos2 == -1 ) {
pos2 = text.length();
}
// Replace if the variable is terminated by '/' or ' '
// and defined
//
if ( pos2 >= 0 ) {
int len = pos2 - pos;
QString key = text.mid( pos+1, len-1);
QString value =
QString::fromLocal8Bit( ::getenv(key.toLocal8Bit()) );
if ( !value.isEmpty() ) {
expanded = true;
text.replace( pos, len, value );
pos = pos + value.length();
} else {
pos = pos2;
}
}
}
}
return expanded;
}
+31 -29
View File
@@ -25,7 +25,8 @@
// Qt
#include <QtCore/QStringList>
namespace Konsole {
namespace Konsole
{
/**
* A class to parse and extract information about shell commands.
@@ -48,42 +49,43 @@ namespace Konsole {
* </li>
* </ul>
*/
class ShellCommand {
class ShellCommand
{
public:
/**
* Constructs a ShellCommand from a command line.
*
* @param fullCommand The command line to parse.
*/
ShellCommand(const QString & fullCommand);
/**
* Constructs a ShellCommand with the specified @p command and @p arguments.
*/
ShellCommand(const QString & command , const QStringList & arguments);
/**
* Constructs a ShellCommand from a command line.
*
* @param fullCommand The command line to parse.
*/
ShellCommand(const QString & fullCommand);
/**
* Constructs a ShellCommand with the specified @p command and @p arguments.
*/
ShellCommand(const QString & command , const QStringList & arguments);
/** Returns the command. */
QString command() const;
/** Returns the arguments. */
QStringList arguments() const;
/** Returns the command. */
QString command() const;
/** Returns the arguments. */
QStringList arguments() const;
/**
* Returns the full command line.
*/
QString fullCommand() const;
/**
* Returns the full command line.
*/
QString fullCommand() const;
/** Returns true if this is a root command. */
bool isRootCommand() const;
/** Returns true if the program specified by @p command() exists. */
bool isAvailable() const;
/** Returns true if this is a root command. */
bool isRootCommand() const;
/** Returns true if the program specified by @p command() exists. */
bool isAvailable() const;
/** Expands environment variables in @p text .*/
static QString expand(const QString & text);
/** Expands environment variables in @p text .*/
static QString expand(const QString & text);
/** Expands environment variables in each string in @p list. */
static QStringList expand(const QStringList & items);
/** Expands environment variables in each string in @p list. */
static QStringList expand(const QStringList & items);
private:
QStringList _arguments;
QStringList _arguments;
};
}
+132 -119
View File
@@ -31,181 +31,194 @@
using namespace Konsole;
PlainTextDecoder::PlainTextDecoder()
: _output(0)
, _includeTrailingWhitespace(true) {
: _output(0)
, _includeTrailingWhitespace(true)
{
}
void PlainTextDecoder::setTrailingWhitespace(bool enable) {
_includeTrailingWhitespace = enable;
void PlainTextDecoder::setTrailingWhitespace(bool enable)
{
_includeTrailingWhitespace = enable;
}
bool PlainTextDecoder::trailingWhitespace() const {
return _includeTrailingWhitespace;
bool PlainTextDecoder::trailingWhitespace() const
{
return _includeTrailingWhitespace;
}
void PlainTextDecoder::begin(QTextStream * output) {
_output = output;
void PlainTextDecoder::begin(QTextStream * output)
{
_output = output;
}
void PlainTextDecoder::end() {
_output = 0;
void PlainTextDecoder::end()
{
_output = 0;
}
void PlainTextDecoder::decodeLine(const Character * const characters, int count, LineProperty /*properties*/
) {
Q_ASSERT( _output );
)
{
Q_ASSERT( _output );
//TODO should we ignore or respect the LINE_WRAPPED line property?
//TODO should we ignore or respect the LINE_WRAPPED line property?
//note: we build up a QString and send it to the text stream rather writing into the text
//stream a character at a time because it is more efficient.
//(since QTextStream always deals with QStrings internally anyway)
QString plainText;
plainText.reserve(count);
//note: we build up a QString and send it to the text stream rather writing into the text
//stream a character at a time because it is more efficient.
//(since QTextStream always deals with QStrings internally anyway)
QString plainText;
plainText.reserve(count);
int outputCount = count;
int outputCount = count;
// if inclusion of trailing whitespace is disabled then find the end of the
// line
if ( !_includeTrailingWhitespace ) {
for (int i = count-1 ; i >= 0 ; i--) {
if ( characters[i].character != ' ' ) {
break;
} else {
outputCount--;
}
// if inclusion of trailing whitespace is disabled then find the end of the
// line
if ( !_includeTrailingWhitespace ) {
for (int i = count-1 ; i >= 0 ; i--) {
if ( characters[i].character != ' ' ) {
break;
} else {
outputCount--;
}
}
}
}
for (int i=0; i<outputCount; i++) {
plainText.append( QChar(characters[i].character) );
}
for (int i=0; i<outputCount; i++) {
plainText.append( QChar(characters[i].character) );
}
*_output << plainText;
*_output << plainText;
}
HTMLDecoder::HTMLDecoder() :
_output(0)
,_colorTable(base_color_table)
,_innerSpanOpen(false)
,_lastRendition(DEFAULT_RENDITION) {
_output(0)
,_colorTable(base_color_table)
,_innerSpanOpen(false)
,_lastRendition(DEFAULT_RENDITION)
{
}
void HTMLDecoder::begin(QTextStream * output) {
_output = output;
void HTMLDecoder::begin(QTextStream * output)
{
_output = output;
QString text;
QString text;
//open monospace span
openSpan(text,"font-family:monospace");
//open monospace span
openSpan(text,"font-family:monospace");
*output << text;
*output << text;
}
void HTMLDecoder::end() {
Q_ASSERT( _output );
void HTMLDecoder::end()
{
Q_ASSERT( _output );
QString text;
QString text;
closeSpan(text);
closeSpan(text);
*_output << text;
*_output << text;
_output = 0;
_output = 0;
}
//TODO: Support for LineProperty (mainly double width , double height)
void HTMLDecoder::decodeLine(const Character * const characters, int count, LineProperty /*properties*/
) {
Q_ASSERT( _output );
)
{
Q_ASSERT( _output );
QString text;
QString text;
int spaceCount = 0;
int spaceCount = 0;
for (int i=0; i<count; i++) {
QChar ch(characters[i].character);
for (int i=0; i<count; i++) {
QChar ch(characters[i].character);
//check if appearance of character is different from previous char
if ( characters[i].rendition != _lastRendition ||
characters[i].foregroundColor != _lastForeColor ||
characters[i].backgroundColor != _lastBackColor ) {
if ( _innerSpanOpen ) {
closeSpan(text);
}
//check if appearance of character is different from previous char
if ( characters[i].rendition != _lastRendition ||
characters[i].foregroundColor != _lastForeColor ||
characters[i].backgroundColor != _lastBackColor ) {
if ( _innerSpanOpen ) {
closeSpan(text);
}
_lastRendition = characters[i].rendition;
_lastForeColor = characters[i].foregroundColor;
_lastBackColor = characters[i].backgroundColor;
_lastRendition = characters[i].rendition;
_lastForeColor = characters[i].foregroundColor;
_lastBackColor = characters[i].backgroundColor;
//build up style string
QString style;
//build up style string
QString style;
if ( _lastRendition & RE_BOLD ||
(_colorTable && characters[i].isBold(_colorTable)) ) {
style.append("font-weight:bold;");
}
if ( _lastRendition & RE_BOLD ||
(_colorTable && characters[i].isBold(_colorTable)) ) {
style.append("font-weight:bold;");
}
if ( _lastRendition & RE_UNDERLINE ) {
style.append("font-decoration:underline;");
}
if ( _lastRendition & RE_UNDERLINE ) {
style.append("font-decoration:underline;");
}
//colours - a colour table must have been defined first
if ( _colorTable ) {
style.append( QString("color:%1;").arg(_lastForeColor.color(_colorTable).name() ) );
//colours - a colour table must have been defined first
if ( _colorTable ) {
style.append( QString("color:%1;").arg(_lastForeColor.color(_colorTable).name() ) );
if (!characters[i].isTransparent(_colorTable)) {
style.append( QString("background-color:%1;").arg(_lastBackColor.color(_colorTable).name() ) );
if (!characters[i].isTransparent(_colorTable)) {
style.append( QString("background-color:%1;").arg(_lastBackColor.color(_colorTable).name() ) );
}
}
//open the span with the current style
openSpan(text,style);
_innerSpanOpen = true;
}
//handle whitespace
if (ch.isSpace()) {
spaceCount++;
} else {
spaceCount = 0;
}
//output current character
if (spaceCount < 2) {
//escape HTML tag characters and just display others as they are
if ( ch == '<' ) {
text.append("&lt;");
} else if (ch == '>') {
text.append("&gt;");
} else {
text.append(ch);
}
} else {
text.append("&nbsp;"); //HTML truncates multiple spaces, so use a space marker instead
}
}
//open the span with the current style
openSpan(text,style);
_innerSpanOpen = true;
}
//handle whitespace
if (ch.isSpace()) {
spaceCount++;
} else {
spaceCount = 0;
//close any remaining open inner spans
if ( _innerSpanOpen ) {
closeSpan(text);
}
//start new line
text.append("<br>");
//output current character
if (spaceCount < 2) {
//escape HTML tag characters and just display others as they are
if ( ch == '<' ) {
text.append("&lt;");
} else if (ch == '>') {
text.append("&gt;");
} else {
text.append(ch);
}
} else {
text.append("&nbsp;"); //HTML truncates multiple spaces, so use a space marker instead
}
}
//close any remaining open inner spans
if ( _innerSpanOpen ) {
closeSpan(text);
}
//start new line
text.append("<br>");
*_output << text;
*_output << text;
}
void HTMLDecoder::openSpan(QString & text , const QString & style) {
text.append( QString("<span style=\"%1\">").arg(style) );
void HTMLDecoder::openSpan(QString & text , const QString & style)
{
text.append( QString("<span style=\"%1\">").arg(style) );
}
void HTMLDecoder::closeSpan(QString & text) {
text.append("</span>");
void HTMLDecoder::closeSpan(QString & text)
{
text.append("</span>");
}
void HTMLDecoder::setColorTable(const ColorEntry * table) {
_colorTable = table;
void HTMLDecoder::setColorTable(const ColorEntry * table)
{
_colorTable = table;
}
+65 -61
View File
@@ -28,7 +28,8 @@
class QTextStream;
namespace Konsole {
namespace Konsole
{
/**
* Base class for terminal character decoders
@@ -39,94 +40,97 @@ namespace Konsole {
* Derived classes may produce either plain text with no other colour or appearance information, or
* they may produce text which incorporates these additional properties.
*/
class TerminalCharacterDecoder {
class TerminalCharacterDecoder
{
public:
virtual ~TerminalCharacterDecoder() {}
virtual ~TerminalCharacterDecoder() {}
/** Begin decoding characters. The resulting text is appended to @p output. */
virtual void begin(QTextStream * output) = 0;
/** End decoding. */
virtual void end() = 0;
/** Begin decoding characters. The resulting text is appended to @p output. */
virtual void begin(QTextStream * output) = 0;
/** End decoding. */
virtual void end() = 0;
/**
* Converts a line of terminal characters with associated properties into a text string
* and writes the string into an output QTextStream.
*
* @param characters An array of characters of length @p count.
* @param properties Additional properties which affect all characters in the line
* @param output The output stream which receives the decoded text
*/
virtual void decodeLine(const Character * const characters,
int count,
LineProperty properties) = 0;
/**
* Converts a line of terminal characters with associated properties into a text string
* and writes the string into an output QTextStream.
*
* @param characters An array of characters of length @p count.
* @param properties Additional properties which affect all characters in the line
* @param output The output stream which receives the decoded text
*/
virtual void decodeLine(const Character * const characters,
int count,
LineProperty properties) = 0;
};
/**
* A terminal character decoder which produces plain text, ignoring colours and other appearance-related
* properties of the original characters.
*/
class PlainTextDecoder : public TerminalCharacterDecoder {
class PlainTextDecoder : public TerminalCharacterDecoder
{
public:
PlainTextDecoder();
PlainTextDecoder();
/**
* Set whether trailing whitespace at the end of lines should be included
* in the output.
* Defaults to true.
*/
void setTrailingWhitespace(bool enable);
/**
* Returns whether trailing whitespace at the end of lines is included
* in the output.
*/
bool trailingWhitespace() const;
/**
* Set whether trailing whitespace at the end of lines should be included
* in the output.
* Defaults to true.
*/
void setTrailingWhitespace(bool enable);
/**
* Returns whether trailing whitespace at the end of lines is included
* in the output.
*/
bool trailingWhitespace() const;
virtual void begin(QTextStream * output);
virtual void end();
virtual void begin(QTextStream * output);
virtual void end();
virtual void decodeLine(const Character * const characters,
int count,
LineProperty properties);
virtual void decodeLine(const Character * const characters,
int count,
LineProperty properties);
private:
QTextStream * _output;
bool _includeTrailingWhitespace;
QTextStream * _output;
bool _includeTrailingWhitespace;
};
/**
* A terminal character decoder which produces pretty HTML markup
*/
class HTMLDecoder : public TerminalCharacterDecoder {
class HTMLDecoder : public TerminalCharacterDecoder
{
public:
/**
* Constructs an HTML decoder using a default black-on-white color scheme.
*/
HTMLDecoder();
/**
* Constructs an HTML decoder using a default black-on-white color scheme.
*/
HTMLDecoder();
/**
* Sets the colour table which the decoder uses to produce the HTML colour codes in its
* output
*/
void setColorTable( const ColorEntry * table );
/**
* Sets the colour table which the decoder uses to produce the HTML colour codes in its
* output
*/
void setColorTable( const ColorEntry * table );
virtual void decodeLine(const Character * const characters,
int count,
LineProperty properties);
virtual void decodeLine(const Character * const characters,
int count,
LineProperty properties);
virtual void begin(QTextStream * output);
virtual void end();
virtual void begin(QTextStream * output);
virtual void end();
private:
void openSpan(QString & text , const QString & style);
void closeSpan(QString & text);
void openSpan(QString & text , const QString & style);
void closeSpan(QString & text);
QTextStream * _output;
const ColorEntry * _colorTable;
bool _innerSpanOpen;
quint8 _lastRendition;
CharacterColor _lastForeColor;
CharacterColor _lastBackColor;
QTextStream * _output;
const ColorEntry * _colorTable;
bool _innerSpanOpen;
quint8 _lastRendition;
CharacterColor _lastForeColor;
CharacterColor _lastBackColor;
};
+2079 -1986
View File
File diff suppressed because it is too large Load Diff
+614 -612
View File
File diff suppressed because it is too large Load Diff
+1023 -981
View File
File diff suppressed because it is too large Load Diff
+87 -85
View File
@@ -47,20 +47,21 @@
#define MODE_Ansi (MODES_SCREEN+7)
#define MODE_total (MODES_SCREEN+8)
namespace Konsole {
namespace Konsole
{
struct DECpar {
bool mode[MODE_total];
bool mode[MODE_total];
};
struct CharCodes {
// coding info
char charset[4]; //
int cu_cs; // actual charset.
bool graphic; // Some VT100 tricks
bool pound ; // Some VT100 tricks
bool sa_graphic; // saved graphic
bool sa_pound; // saved pound
// coding info
char charset[4]; //
int cu_cs; // actual charset.
bool graphic; // Some VT100 tricks
bool pound ; // Some VT100 tricks
bool sa_graphic; // saved graphic
bool sa_pound; // saved pound
};
/**
@@ -73,113 +74,114 @@ struct CharCodes {
* sequences.
*
*/
class Vt102Emulation : public Emulation {
Q_OBJECT
class Vt102Emulation : public Emulation
{
Q_OBJECT
public:
/** Constructs a new emulation */
Vt102Emulation();
~Vt102Emulation();
/** Constructs a new emulation */
Vt102Emulation();
~Vt102Emulation();
// reimplemented
virtual void clearEntireScreen();
virtual void reset();
// reimplemented
virtual void clearEntireScreen();
virtual void reset();
// reimplemented
virtual char getErase() const;
// reimplemented
virtual char getErase() const;
public slots:
// reimplemented
virtual void sendString(const char *,int length = -1);
virtual void sendText(const QString & text);
virtual void sendKeyEvent(QKeyEvent *);
virtual void sendMouseEvent( int buttons, int column, int line , int eventType );
// reimplemented
virtual void sendString(const char *,int length = -1);
virtual void sendText(const QString & text);
virtual void sendKeyEvent(QKeyEvent *);
virtual void sendMouseEvent( int buttons, int column, int line , int eventType );
protected:
// reimplemented
virtual void setMode (int mode);
virtual void resetMode (int mode);
// reimplemented
virtual void setMode (int mode);
virtual void resetMode (int mode);
// reimplemented
virtual void receiveChar(int cc);
// reimplemented
virtual void receiveChar(int cc);
private slots:
//causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates
//used to buffer multiple title updates
void updateTitle();
//causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates
//used to buffer multiple title updates
void updateTitle();
private:
unsigned short applyCharset(unsigned short c);
void setCharset(int n, int cs);
void useCharset(int n);
void setAndUseCharset(int n, int cs);
void saveCursor();
void restoreCursor();
void resetCharset(int scrno);
unsigned short applyCharset(unsigned short c);
void setCharset(int n, int cs);
void useCharset(int n);
void setAndUseCharset(int n, int cs);
void saveCursor();
void restoreCursor();
void resetCharset(int scrno);
void setMargins(int top, int bottom);
//set margins for all screens back to their defaults
void setDefaultMargins();
void setMargins(int top, int bottom);
//set margins for all screens back to their defaults
void setDefaultMargins();
// returns true if 'mode' is set or false otherwise
bool getMode (int mode);
// saves the current boolean value of 'mode'
void saveMode (int mode);
// restores the boolean value of 'mode'
void restoreMode(int mode);
// resets all modes
void resetModes();
// returns true if 'mode' is set or false otherwise
bool getMode (int mode);
// saves the current boolean value of 'mode'
void saveMode (int mode);
// restores the boolean value of 'mode'
void restoreMode(int mode);
// resets all modes
void resetModes();
void resetToken();
void resetToken();
#define MAXPBUF 80
void pushToToken(int cc);
int pbuf[MAXPBUF]; //FIXME: overflow?
int ppos;
void pushToToken(int cc);
int pbuf[MAXPBUF]; //FIXME: overflow?
int ppos;
#define MAXARGS 15
void addDigit(int dig);
void addArgument();
int argv[MAXARGS];
int argc;
void initTokenizer();
int tbl[256];
void addDigit(int dig);
void addArgument();
int argv[MAXARGS];
int argc;
void initTokenizer();
int tbl[256];
void scan_buffer_report(); //FIXME: rename
void ReportErrorToken(); //FIXME: rename
void scan_buffer_report(); //FIXME: rename
void ReportErrorToken(); //FIXME: rename
void tau(int code, int p, int q);
void XtermHack();
void tau(int code, int p, int q);
void XtermHack();
void reportTerminalType();
void reportSecondaryAttributes();
void reportStatus();
void reportAnswerBack();
void reportCursorPosition();
void reportTerminalParms(int p);
void reportTerminalType();
void reportSecondaryAttributes();
void reportStatus();
void reportAnswerBack();
void reportCursorPosition();
void reportTerminalParms(int p);
void onScrollLock();
void scrollLock(const bool lock);
void onScrollLock();
void scrollLock(const bool lock);
// clears the screen and resizes it to the specified
// number of columns
void clearScreenAndSetColumns(int columnCount);
// clears the screen and resizes it to the specified
// number of columns
void clearScreenAndSetColumns(int columnCount);
CharCodes _charset[2];
CharCodes _charset[2];
DECpar _currParm;
DECpar _saveParm;
DECpar _currParm;
DECpar _saveParm;
//hash table and timer for buffering calls to the session instance
//to update the name of the session
//or window title.
//these calls occur when certain escape sequences are seen in the
//output from the terminal
QHash<int,QString> _pendingTitleUpdates;
QTimer * _titleUpdateTimer;
//hash table and timer for buffering calls to the session instance
//to update the name of the session
//or window title.
//these calls occur when certain escape sequences are seen in the
//output from the terminal
QHash<int,QString> _pendingTitleUpdates;
QTimer * _titleUpdateTimer;
};
+808 -756
View File
File diff suppressed because it is too large Load Diff
+648 -646
View File
File diff suppressed because it is too large Load Diff
+198 -181
View File
@@ -35,94 +35,100 @@
#include <QtCore/QSocketNotifier>
class K3ProcessController::Private {
class K3ProcessController::Private
{
public:
Private()
: needcheck( false ),
notifier( 0 ) {
}
Private()
: needcheck( false ),
notifier( 0 ) {
}
~Private() {
delete notifier;
}
~Private() {
delete notifier;
}
int fd[2];
bool needcheck;
QSocketNotifier * notifier;
QList<K3Process *> kProcessList;
QList<int> unixProcessList;
static struct sigaction oldChildHandlerData;
static bool handlerSet;
static int refCount;
static K3ProcessController * instance;
int fd[2];
bool needcheck;
QSocketNotifier * notifier;
QList<K3Process *> kProcessList;
QList<int> unixProcessList;
static struct sigaction oldChildHandlerData;
static bool handlerSet;
static int refCount;
static K3ProcessController * instance;
};
K3ProcessController * K3ProcessController::Private::instance = 0;
int K3ProcessController::Private::refCount = 0;
void K3ProcessController::ref() {
if ( !Private::refCount ) {
Private::instance = new K3ProcessController;
setupHandlers();
}
Private::refCount++;
void K3ProcessController::ref()
{
if ( !Private::refCount ) {
Private::instance = new K3ProcessController;
setupHandlers();
}
Private::refCount++;
}
void K3ProcessController::deref() {
Private::refCount--;
if( !Private::refCount ) {
resetHandlers();
delete Private::instance;
Private::instance = 0;
}
void K3ProcessController::deref()
{
Private::refCount--;
if ( !Private::refCount ) {
resetHandlers();
delete Private::instance;
Private::instance = 0;
}
}
K3ProcessController * K3ProcessController::instance() {
/*
* there were no safety guards in previous revisions, is that ok?
if ( !Private::instance ) {
ref();
}
*/
K3ProcessController * K3ProcessController::instance()
{
/*
* there were no safety guards in previous revisions, is that ok?
if ( !Private::instance ) {
ref();
}
*/
return Private::instance;
return Private::instance;
}
K3ProcessController::K3ProcessController()
: d( new Private ) {
if( pipe( d->fd ) ) {
perror( "pipe" );
abort();
}
: d( new Private )
{
if ( pipe( d->fd ) ) {
perror( "pipe" );
abort();
}
fcntl( d->fd[0], F_SETFL, O_NONBLOCK ); // in case slotDoHousekeeping is called without polling first
fcntl( d->fd[1], F_SETFL, O_NONBLOCK ); // in case it fills up
fcntl( d->fd[0], F_SETFD, FD_CLOEXEC );
fcntl( d->fd[1], F_SETFD, FD_CLOEXEC );
fcntl( d->fd[0], F_SETFL, O_NONBLOCK ); // in case slotDoHousekeeping is called without polling first
fcntl( d->fd[1], F_SETFL, O_NONBLOCK ); // in case it fills up
fcntl( d->fd[0], F_SETFD, FD_CLOEXEC );
fcntl( d->fd[1], F_SETFD, FD_CLOEXEC );
d->notifier = new QSocketNotifier( d->fd[0], QSocketNotifier::Read );
d->notifier->setEnabled( true );
QObject::connect( d->notifier, SIGNAL(activated(int)),
SLOT(slotDoHousekeeping()));
d->notifier = new QSocketNotifier( d->fd[0], QSocketNotifier::Read );
d->notifier->setEnabled( true );
QObject::connect( d->notifier, SIGNAL(activated(int)),
SLOT(slotDoHousekeeping()));
}
K3ProcessController::~K3ProcessController() {
K3ProcessController::~K3ProcessController()
{
#ifndef Q_OS_MAC
/* not sure why, but this is causing lockups */
close( d->fd[0] );
close( d->fd[1] );
/* not sure why, but this is causing lockups */
close( d->fd[0] );
close( d->fd[1] );
#else
#warning FIXME: why does close() freeze up destruction?
#endif
delete d;
delete d;
}
extern "C" {
static void theReaper( int num ) {
K3ProcessController::theSigCHLDHandler( num );
}
static void theReaper( int num ) {
K3ProcessController::theSigCHLDHandler( num );
}
}
#ifdef Q_OS_UNIX
@@ -130,182 +136,193 @@ struct sigaction K3ProcessController::Private::oldChildHandlerData;
#endif
bool K3ProcessController::Private::handlerSet = false;
void K3ProcessController::setupHandlers() {
if( Private::handlerSet ) {
return;
}
Private::handlerSet = true;
void K3ProcessController::setupHandlers()
{
if ( Private::handlerSet ) {
return;
}
Private::handlerSet = true;
#ifdef Q_OS_UNIX
struct sigaction act;
sigemptyset( &act.sa_mask );
struct sigaction act;
sigemptyset( &act.sa_mask );
act.sa_handler = SIG_IGN;
act.sa_flags = 0;
sigaction( SIGPIPE, &act, 0L );
act.sa_handler = SIG_IGN;
act.sa_flags = 0;
sigaction( SIGPIPE, &act, 0L );
act.sa_handler = theReaper;
act.sa_flags = SA_NOCLDSTOP;
// CC: take care of SunOS which automatically restarts interrupted system
// calls (and thus does not have SA_RESTART)
act.sa_handler = theReaper;
act.sa_flags = SA_NOCLDSTOP;
// CC: take care of SunOS which automatically restarts interrupted system
// calls (and thus does not have SA_RESTART)
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
act.sa_flags |= SA_RESTART;
#endif
sigaction( SIGCHLD, &act, &Private::oldChildHandlerData );
sigaction( SIGCHLD, &act, &Private::oldChildHandlerData );
sigaddset( &act.sa_mask, SIGCHLD );
// Make sure we don't block this signal. gdb tends to do that :-(
sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
sigaddset( &act.sa_mask, SIGCHLD );
// Make sure we don't block this signal. gdb tends to do that :-(
sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
#else
//TODO: win32
//TODO: win32
#endif
}
void K3ProcessController::resetHandlers() {
if( !Private::handlerSet ) {
return;
}
Private::handlerSet = false;
void K3ProcessController::resetHandlers()
{
if ( !Private::handlerSet ) {
return;
}
Private::handlerSet = false;
#ifdef Q_OS_UNIX
sigset_t mask, omask;
sigemptyset( &mask );
sigaddset( &mask, SIGCHLD );
sigprocmask( SIG_BLOCK, &mask, &omask );
sigset_t mask, omask;
sigemptyset( &mask );
sigaddset( &mask, SIGCHLD );
sigprocmask( SIG_BLOCK, &mask, &omask );
struct sigaction act;
sigaction( SIGCHLD, &Private::oldChildHandlerData, &act );
if (act.sa_handler != theReaper) {
sigaction( SIGCHLD, &act, 0 );
Private::handlerSet = true;
}
struct sigaction act;
sigaction( SIGCHLD, &Private::oldChildHandlerData, &act );
if (act.sa_handler != theReaper) {
sigaction( SIGCHLD, &act, 0 );
Private::handlerSet = true;
}
sigprocmask( SIG_SETMASK, &omask, 0 );
sigprocmask( SIG_SETMASK, &omask, 0 );
#else
//TODO: win32
//TODO: win32
#endif
// there should be no problem with SIGPIPE staying SIG_IGN
// there should be no problem with SIGPIPE staying SIG_IGN
}
// the pipe is needed to sync the child reaping with our event processing,
// as otherwise there are race conditions, locking requirements, and things
// generally get harder
void K3ProcessController::theSigCHLDHandler( int arg ) {
int saved_errno = errno;
void K3ProcessController::theSigCHLDHandler( int arg )
{
int saved_errno = errno;
char dummy = 0;
::write( instance()->d->fd[1], &dummy, 1 );
char dummy = 0;
::write( instance()->d->fd[1], &dummy, 1 );
#ifdef Q_OS_UNIX
if ( Private::oldChildHandlerData.sa_handler != SIG_IGN &&
Private::oldChildHandlerData.sa_handler != SIG_DFL ) {
Private::oldChildHandlerData.sa_handler( arg ); // call the old handler
}
if ( Private::oldChildHandlerData.sa_handler != SIG_IGN &&
Private::oldChildHandlerData.sa_handler != SIG_DFL ) {
Private::oldChildHandlerData.sa_handler( arg ); // call the old handler
}
#else
//TODO: win32
//TODO: win32
#endif
errno = saved_errno;
errno = saved_errno;
}
int K3ProcessController::notifierFd() const {
return d->fd[0];
int K3ProcessController::notifierFd() const
{
return d->fd[0];
}
void K3ProcessController::unscheduleCheck() {
char dummy[16]; // somewhat bigger - just in case several have queued up
if( ::read( d->fd[0], dummy, sizeof(dummy) ) > 0 ) {
d->needcheck = true;
}
void K3ProcessController::unscheduleCheck()
{
char dummy[16]; // somewhat bigger - just in case several have queued up
if ( ::read( d->fd[0], dummy, sizeof(dummy) ) > 0 ) {
d->needcheck = true;
}
}
void
K3ProcessController::rescheduleCheck() {
if( d->needcheck ) {
d->needcheck = false;
char dummy = 0;
::write( d->fd[1], &dummy, 1 );
}
K3ProcessController::rescheduleCheck()
{
if ( d->needcheck ) {
d->needcheck = false;
char dummy = 0;
::write( d->fd[1], &dummy, 1 );
}
}
void K3ProcessController::slotDoHousekeeping() {
char dummy[16]; // somewhat bigger - just in case several have queued up
::read( d->fd[0], dummy, sizeof(dummy) );
void K3ProcessController::slotDoHousekeeping()
{
char dummy[16]; // somewhat bigger - just in case several have queued up
::read( d->fd[0], dummy, sizeof(dummy) );
int status;
int status;
again:
QList<K3Process *>::iterator it( d->kProcessList.begin() );
QList<K3Process *>::iterator eit( d->kProcessList.end() );
while( it != eit ) {
K3Process * prc = *it;
if( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 ) {
prc->processHasExited( status );
// the callback can nuke the whole process list and even 'this'
if (!instance()) {
return;
}
goto again;
QList<K3Process *>::iterator it( d->kProcessList.begin() );
QList<K3Process *>::iterator eit( d->kProcessList.end() );
while ( it != eit ) {
K3Process * prc = *it;
if ( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 ) {
prc->processHasExited( status );
// the callback can nuke the whole process list and even 'this'
if (!instance()) {
return;
}
goto again;
}
++it;
}
++it;
}
QList<int>::iterator uit( d->unixProcessList.begin() );
QList<int>::iterator ueit( d->unixProcessList.end() );
while( uit != ueit ) {
if( waitpid( *uit, 0, WNOHANG ) > 0 ) {
uit = d->unixProcessList.erase( uit );
deref(); // counterpart to addProcess, can invalidate 'this'
} else {
++uit;
QList<int>::iterator uit( d->unixProcessList.begin() );
QList<int>::iterator ueit( d->unixProcessList.end() );
while ( uit != ueit ) {
if ( waitpid( *uit, 0, WNOHANG ) > 0 ) {
uit = d->unixProcessList.erase( uit );
deref(); // counterpart to addProcess, can invalidate 'this'
} else {
++uit;
}
}
}
}
bool K3ProcessController::waitForProcessExit( int timeout ) {
bool K3ProcessController::waitForProcessExit( int timeout )
{
#ifdef Q_OS_UNIX
for(;;) {
struct timeval tv, *tvp;
if (timeout < 0) {
tvp = 0;
} else {
tv.tv_sec = timeout;
tv.tv_usec = 0;
tvp = &tv;
}
fd_set fds;
FD_ZERO( &fds );
FD_SET( d->fd[0], &fds );
switch( select( d->fd[0]+1, &fds, 0, 0, tvp ) ) {
case -1:
if( errno == EINTR ) {
continue;
for (;;) {
struct timeval tv, *tvp;
if (timeout < 0) {
tvp = 0;
} else {
tv.tv_sec = timeout;
tv.tv_usec = 0;
tvp = &tv;
}
fd_set fds;
FD_ZERO( &fds );
FD_SET( d->fd[0], &fds );
switch ( select( d->fd[0]+1, &fds, 0, 0, tvp ) ) {
case -1:
if ( errno == EINTR ) {
continue;
}
// fall through; should never happen
case 0:
return false;
default:
slotDoHousekeeping();
return true;
}
// fall through; should never happen
case 0:
return false;
default:
slotDoHousekeeping();
return true;
}
}
#else
//TODO: win32
return false;
//TODO: win32
return false;
#endif
}
void K3ProcessController::addKProcess( K3Process * p ) {
d->kProcessList.append( p );
void K3ProcessController::addKProcess( K3Process * p )
{
d->kProcessList.append( p );
}
void K3ProcessController::removeKProcess( K3Process * p ) {
d->kProcessList.removeAll( p );
void K3ProcessController::removeKProcess( K3Process * p )
{
d->kProcessList.removeAll( p );
}
void K3ProcessController::addProcess( int pid ) {
d->unixProcessList.append( pid );
ref(); // make sure we stay around when the K3Process goes away
void K3ProcessController::addProcess( int pid )
{
d->unixProcessList.append( pid );
ref(); // make sure we stay around when the K3Process goes away
}
//#include "moc_k3processcontroller.cpp"
+77 -76
View File
@@ -36,100 +36,101 @@
*
* This class takes care of the actual (UN*X) signal handling.
*/
class K3ProcessController : public QObject {
Q_OBJECT
class K3ProcessController : public QObject
{
Q_OBJECT
public:
/**
* Create an instance if none exists yet.
* Called by KApplication::KApplication()
*/
static void ref();
/**
* Create an instance if none exists yet.
* Called by KApplication::KApplication()
*/
static void ref();
/**
* Destroy the instance if one exists and it is not referenced any more.
* Called by KApplication::~KApplication()
*/
static void deref();
/**
* Destroy the instance if one exists and it is not referenced any more.
* Called by KApplication::~KApplication()
*/
static void deref();
/**
* Only a single instance of this class is allowed at a time.
* This method provides access to that instance.
*/
static K3ProcessController * instance();
/**
* Only a single instance of this class is allowed at a time.
* This method provides access to that instance.
*/
static K3ProcessController * instance();
/**
* Automatically called upon SIGCHLD. Never call it directly.
* If your application (or some library it uses) redirects SIGCHLD,
* the new signal handler (and only it) should call the old handler
* returned by sigaction().
* @internal
*/
static void theSigCHLDHandler(int signal); // KDE4: private
/**
* Automatically called upon SIGCHLD. Never call it directly.
* If your application (or some library it uses) redirects SIGCHLD,
* the new signal handler (and only it) should call the old handler
* returned by sigaction().
* @internal
*/
static void theSigCHLDHandler(int signal); // KDE4: private
/**
* Wait for any process to exit and handle their exit without
* starting an event loop.
* This function may cause K3Process to emit any of its signals.
*
* @param timeout the timeout in seconds. -1 means no timeout.
* @return true if a process exited, false
* if no process exited within @p timeout seconds.
*/
bool waitForProcessExit(int timeout);
/**
* Wait for any process to exit and handle their exit without
* starting an event loop.
* This function may cause K3Process to emit any of its signals.
*
* @param timeout the timeout in seconds. -1 means no timeout.
* @return true if a process exited, false
* if no process exited within @p timeout seconds.
*/
bool waitForProcessExit(int timeout);
/**
* Call this function to defer processing of the data that became available
* on notifierFd().
*/
void unscheduleCheck();
/**
* Call this function to defer processing of the data that became available
* on notifierFd().
*/
void unscheduleCheck();
/**
* This function @em must be called at some point after calling
* unscheduleCheck().
*/
void rescheduleCheck();
/**
* This function @em must be called at some point after calling
* unscheduleCheck().
*/
void rescheduleCheck();
/*
* Obtain the file descriptor K3ProcessController uses to get notified
* about process exits. select() or poll() on it if you create a custom
* event loop that needs to act upon SIGCHLD.
* @return the file descriptor of the reading end of the notification pipe
*/
int notifierFd() const;
/*
* Obtain the file descriptor K3ProcessController uses to get notified
* about process exits. select() or poll() on it if you create a custom
* event loop that needs to act upon SIGCHLD.
* @return the file descriptor of the reading end of the notification pipe
*/
int notifierFd() const;
/**
* @internal
*/
void addKProcess( K3Process * );
/**
* @internal
*/
void removeKProcess( K3Process * );
/**
* @internal
*/
void addProcess( int pid );
/**
* @internal
*/
void addKProcess( K3Process * );
/**
* @internal
*/
void removeKProcess( K3Process * );
/**
* @internal
*/
void addProcess( int pid );
private Q_SLOTS:
void slotDoHousekeeping();
void slotDoHousekeeping();
private:
friend class I_just_love_gcc;
friend class I_just_love_gcc;
static void setupHandlers();
static void resetHandlers();
static void setupHandlers();
static void resetHandlers();
// Disallow instantiation
K3ProcessController();
~K3ProcessController();
// Disallow instantiation
K3ProcessController();
~K3ProcessController();
// Disallow assignment and copy-construction
K3ProcessController( const K3ProcessController & );
K3ProcessController & operator= ( const K3ProcessController & );
// Disallow assignment and copy-construction
K3ProcessController( const K3ProcessController & );
K3ProcessController & operator= ( const K3ProcessController & );
class Private;
Private * const d;
class Private;
Private * const d;
};
#endif
+150 -146
View File
@@ -10,30 +10,31 @@
#include "konsole_wcwidth.h"
struct interval {
unsigned short first;
unsigned short last;
unsigned short first;
unsigned short last;
};
/* auxiliary function for binary search in interval table */
static int bisearch(quint16 ucs, const struct interval * table, int max) {
int min = 0;
int mid;
static int bisearch(quint16 ucs, const struct interval * table, int max)
{
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last) {
return 0;
}
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last) {
min = mid + 1;
} else if (ucs < table[mid].first) {
max = mid - 1;
} else {
return 1;
if (ucs < table[0].first || ucs > table[max].last) {
return 0;
}
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last) {
min = mid + 1;
} else if (ucs < table[mid].first) {
max = mid - 1;
} else {
return 1;
}
}
}
return 0;
return 0;
}
@@ -67,71 +68,72 @@ static int bisearch(quint16 ucs, const struct interval * table, int max) {
* in ISO 10646.
*/
int konsole_wcwidth(quint16 ucs) {
/* sorted list of non-overlapping intervals of non-spacing characters */
static const struct interval combining[] = {
{ 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 },
{ 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 },
{ 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C },
{ 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 },
{ 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC },
{ 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 },
{ 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 },
{ 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 },
{ 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 },
{ 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 },
{ 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 },
{ 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 },
{ 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
{ 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA },
{ 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 },
{ 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 },
{ 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD },
{ 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 },
{ 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 },
{ 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC },
{ 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 },
{ 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 },
{ 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 },
{ 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F },
{ 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
{ 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF },
{ 0xFFF9, 0xFFFB }
};
int konsole_wcwidth(quint16 ucs)
{
/* sorted list of non-overlapping intervals of non-spacing characters */
static const struct interval combining[] = {
{ 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 },
{ 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 },
{ 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C },
{ 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 },
{ 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC },
{ 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 },
{ 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 },
{ 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 },
{ 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 },
{ 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 },
{ 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 },
{ 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 },
{ 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
{ 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA },
{ 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 },
{ 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 },
{ 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD },
{ 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 },
{ 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 },
{ 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC },
{ 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 },
{ 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 },
{ 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 },
{ 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F },
{ 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
{ 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF },
{ 0xFFF9, 0xFFFB }
};
/* test for 8-bit control characters */
if (ucs == 0) {
return 0;
}
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) {
return -1;
}
/* test for 8-bit control characters */
if (ucs == 0) {
return 0;
}
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) {
return -1;
}
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1)) {
return 0;
}
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1)) {
return 0;
}
/* if we arrive here, ucs is not a combining or C0/C1 control character */
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
(ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) /* do not compare UINT16 with 0x20000 ||
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
(ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) /* do not compare UINT16 with 0x20000 ||
(ucs >= 0x20000 && ucs <= 0x2ffff) */));
}
@@ -144,77 +146,79 @@ int konsole_wcwidth(quint16 ucs) {
* encodings who want to migrate to UCS. It is not otherwise
* recommended for general use.
*/
int konsole_wcwidth_cjk(quint16 ucs) {
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AD, 0x00AD }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014A }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, { 0x02CD, 0x02CD },
{ 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, { 0x02DD, 0x02DD },
{ 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 },
{ 0x03C3, 0x03C9 }, { 0x0401, 0x0401 }, { 0x0410, 0x044F },
{ 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2016 },
{ 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2021 },
{ 0x2025, 0x2027 }, { 0x2030, 0x2030 }, { 0x2032, 0x2033 },
{ 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 },
{ 0x212B, 0x212B }, { 0x2154, 0x2155 }, { 0x215B, 0x215B },
{ 0x215E, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 },
{ 0x2200, 0x2200 }, { 0x2202, 0x2203 }, { 0x2207, 0x2208 },
{ 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 },
{ 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x2220 },
{ 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x222C },
{ 0x222E, 0x222E }, { 0x2234, 0x2237 }, { 0x223C, 0x223D },
{ 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 },
{ 0x2260, 0x2261 }, { 0x2264, 0x2267 }, { 0x226A, 0x226B },
{ 0x226E, 0x226F }, { 0x2282, 0x2283 }, { 0x2286, 0x2287 },
{ 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 },
{ 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x24BF },
{ 0x24D0, 0x24E9 }, { 0x2500, 0x254B }, { 0x2550, 0x2574 },
{ 0x2580, 0x258F }, { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 },
{ 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 },
{ 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 },
{ 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 },
{ 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, { 0x2609, 0x2609 },
{ 0x260E, 0x260F }, { 0x261C, 0x261C }, { 0x261E, 0x261E },
{ 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2661 },
{ 0x2663, 0x2665 }, { 0x2667, 0x266A }, { 0x266C, 0x266D },
{ 0x266F, 0x266F }, { 0x300A, 0x300B }, { 0x301A, 0x301B },
{ 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD }
};
int konsole_wcwidth_cjk(quint16 ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AD, 0x00AD }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014A }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, { 0x02CD, 0x02CD },
{ 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, { 0x02DD, 0x02DD },
{ 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 },
{ 0x03C3, 0x03C9 }, { 0x0401, 0x0401 }, { 0x0410, 0x044F },
{ 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2016 },
{ 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2021 },
{ 0x2025, 0x2027 }, { 0x2030, 0x2030 }, { 0x2032, 0x2033 },
{ 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 },
{ 0x212B, 0x212B }, { 0x2154, 0x2155 }, { 0x215B, 0x215B },
{ 0x215E, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 },
{ 0x2200, 0x2200 }, { 0x2202, 0x2203 }, { 0x2207, 0x2208 },
{ 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 },
{ 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x2220 },
{ 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x222C },
{ 0x222E, 0x222E }, { 0x2234, 0x2237 }, { 0x223C, 0x223D },
{ 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 },
{ 0x2260, 0x2261 }, { 0x2264, 0x2267 }, { 0x226A, 0x226B },
{ 0x226E, 0x226F }, { 0x2282, 0x2283 }, { 0x2286, 0x2287 },
{ 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 },
{ 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x24BF },
{ 0x24D0, 0x24E9 }, { 0x2500, 0x254B }, { 0x2550, 0x2574 },
{ 0x2580, 0x258F }, { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 },
{ 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 },
{ 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 },
{ 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 },
{ 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, { 0x2609, 0x2609 },
{ 0x260E, 0x260F }, { 0x261C, 0x261C }, { 0x261E, 0x261E },
{ 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2661 },
{ 0x2663, 0x2665 }, { 0x2667, 0x266A }, { 0x266C, 0x266D },
{ 0x266F, 0x266F }, { 0x300A, 0x300B }, { 0x301A, 0x301B },
{ 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1)) {
return 2;
}
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1)) {
return 2;
}
return konsole_wcwidth(ucs);
return konsole_wcwidth(ucs);
}
#endif
// single byte char: +1, multi byte char: +2
int string_width( const QString & txt ) {
int w = 0;
for ( int i = 0; i < txt.length(); ++i ) {
w += konsole_wcwidth( txt[ i ].unicode() );
}
return w;
int string_width( const QString & txt )
{
int w = 0;
for ( int i = 0; i < txt.length(); ++i ) {
w += konsole_wcwidth( txt[ i ].unicode() );
}
return w;
}
+289 -271
View File
@@ -148,13 +148,15 @@ extern "C" {
//////////////////
KPtyPrivate::KPtyPrivate() :
masterFd(-1), slaveFd(-1) {
masterFd(-1), slaveFd(-1)
{
}
bool KPtyPrivate::chownpty(bool) {
bool KPtyPrivate::chownpty(bool)
{
// return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
// QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
return true;
return true;
}
/////////////////////////////
@@ -162,388 +164,397 @@ bool KPtyPrivate::chownpty(bool) {
/////////////////////////////
KPty::KPty() :
d_ptr(new KPtyPrivate) {
d_ptr->q_ptr = this;
d_ptr(new KPtyPrivate)
{
d_ptr->q_ptr = this;
}
KPty::KPty(KPtyPrivate * d) :
d_ptr(d) {
d_ptr->q_ptr = this;
d_ptr(d)
{
d_ptr->q_ptr = this;
}
KPty::~KPty() {
close();
delete d_ptr;
KPty::~KPty()
{
close();
delete d_ptr;
}
bool KPty::open() {
Q_D(KPty);
bool KPty::open()
{
Q_D(KPty);
if (d->masterFd >= 0) {
return true;
}
if (d->masterFd >= 0) {
return true;
}
QByteArray ptyName;
QByteArray ptyName;
// Find a master pty that we can open ////////////////////////////////
// Find a master pty that we can open ////////////////////////////////
// Because not all the pty animals are created equal, they want to
// be opened by several different methods.
// Because not all the pty animals are created equal, they want to
// be opened by several different methods.
// We try, as we know them, one by one.
// We try, as we know them, one by one.
#ifdef HAVE_OPENPTY
char ptsn[PATH_MAX];
if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0)) {
d->masterFd = -1;
d->slaveFd = -1;
qWarning(175) << "Can't open a pseudo teletype";
return false;
}
d->ttyName = ptsn;
char ptsn[PATH_MAX];
if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0)) {
d->masterFd = -1;
d->slaveFd = -1;
qWarning(175) << "Can't open a pseudo teletype";
return false;
}
d->ttyName = ptsn;
#else
#ifdef HAVE__GETPTY // irix
char * ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
if (ptsn) {
d->ttyName = ptsn;
goto grantedpt;
}
char * ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
if (ptsn) {
d->ttyName = ptsn;
goto grantedpt;
}
#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
#ifdef HAVE_POSIX_OPENPT
d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
#elif defined(HAVE_GETPT)
d->masterFd = ::getpt();
d->masterFd = ::getpt();
#elif defined(PTM_DEVICE)
d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
#else
# error No method to open a PTY master detected.
#endif
if (d->masterFd >= 0) {
if (d->masterFd >= 0) {
#ifdef HAVE_PTSNAME
char * ptsn = ptsname(d->masterFd);
if (ptsn) {
d->ttyName = ptsn;
char * ptsn = ptsname(d->masterFd);
if (ptsn) {
d->ttyName = ptsn;
#else
int ptyno;
if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
d->ttyName = QByteArray("/dev/pts/") + QByteArray::number(ptyno);
int ptyno;
if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
d->ttyName = QByteArray("/dev/pts/") + QByteArray::number(ptyno);
#endif
#ifdef HAVE_GRANTPT
if (!grantpt(d->masterFd)) {
goto grantedpt;
}
if (!grantpt(d->masterFd)) {
goto grantedpt;
}
#else
goto gotpty;
goto gotpty;
#endif
}
::close(d->masterFd);
d->masterFd = -1;
}
#endif // HAVE_PTSNAME || TIOCGPTN
// Linux device names, FIXME: Trouble on other systems?
for (const char * s3 = "pqrstuvwxyzabcde"; *s3; s3++) {
for (const char * s4 = "0123456789abcdef"; *s4; s4++) {
ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
d->masterFd = ::open(ptyName.data(), O_RDWR);
if (d->masterFd >= 0) {
#ifdef Q_OS_SOLARIS
/* Need to check the process group of the pty.
* If it exists, then the slave pty is in use,
* and we need to get another one.
*/
int pgrp_rtn;
if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
::close(d->masterFd);
d->masterFd = -1;
continue;
}
#endif /* Q_OS_SOLARIS */
if (!access(d->ttyName.data(),R_OK|W_OK)) { // checks availability based on permission bits
if (!geteuid()) {
struct group * p = getgrnam(TTY_GROUP);
if (!p) {
p = getgrnam("wheel");
}
gid_t gid = p ? p->gr_gid : getgid ();
chown(d->ttyName.data(), getuid(), gid);
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
}
goto gotpty;
}
::close(d->masterFd);
d->masterFd = -1;
}
}
}
#endif // HAVE_PTSNAME || TIOCGPTN
qWarning() << "Can't open a pseudo teletype";
return false;
// Linux device names, FIXME: Trouble on other systems?
for (const char * s3 = "pqrstuvwxyzabcde"; *s3; s3++) {
for (const char * s4 = "0123456789abcdef"; *s4; s4++) {
ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
d->masterFd = ::open(ptyName.data(), O_RDWR);
if (d->masterFd >= 0) {
#ifdef Q_OS_SOLARIS
/* Need to check the process group of the pty.
* If it exists, then the slave pty is in use,
* and we need to get another one.
*/
int pgrp_rtn;
if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
::close(d->masterFd);
d->masterFd = -1;
continue;
}
#endif /* Q_OS_SOLARIS */
if (!access(d->ttyName.data(),R_OK|W_OK)) { // checks availability based on permission bits
if (!geteuid()) {
struct group * p = getgrnam(TTY_GROUP);
if (!p) {
p = getgrnam("wheel");
}
gid_t gid = p ? p->gr_gid : getgid ();
chown(d->ttyName.data(), getuid(), gid);
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
}
goto gotpty;
}
::close(d->masterFd);
d->masterFd = -1;
}
}
}
qWarning() << "Can't open a pseudo teletype";
return false;
gotpty:
struct stat st;
if (stat(d->ttyName.data(), &st)) {
return false; // this just cannot happen ... *cough* Yeah right, I just
// had it happen when pty #349 was allocated. I guess
// there was some sort of leak? I only had a few open.
}
if (((st.st_uid != getuid()) ||
(st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
!d->chownpty(true)) {
qWarning()
struct stat st;
if (stat(d->ttyName.data(), &st)) {
return false; // this just cannot happen ... *cough* Yeah right, I just
// had it happen when pty #349 was allocated. I guess
// there was some sort of leak? I only had a few open.
}
if (((st.st_uid != getuid()) ||
(st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
!d->chownpty(true)) {
qWarning()
<< "chownpty failed for device " << ptyName << "::" << d->ttyName
<< "\nThis means the communication can be eavesdropped." << endl;
}
}
#if defined (HAVE__GETPTY) || defined (HAVE_GRANTPT)
grantedpt:
#endif
#ifdef HAVE_REVOKE
revoke(d->ttyName.data());
revoke(d->ttyName.data());
#endif
#ifdef HAVE_UNLOCKPT
unlockpt(d->masterFd);
unlockpt(d->masterFd);
#elif defined(TIOCSPTLCK)
int flag = 0;
ioctl(d->masterFd, TIOCSPTLCK, &flag);
int flag = 0;
ioctl(d->masterFd, TIOCSPTLCK, &flag);
#endif
d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
if (d->slaveFd < 0) {
qWarning() << "Can't open slave pseudo teletype";
::close(d->masterFd);
d->masterFd = -1;
return false;
}
d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
if (d->slaveFd < 0) {
qWarning() << "Can't open slave pseudo teletype";
::close(d->masterFd);
d->masterFd = -1;
return false;
}
#if (defined(__svr4__) || defined(__sgi__))
// Solaris
ioctl(d->slaveFd, I_PUSH, "ptem");
ioctl(d->slaveFd, I_PUSH, "ldterm");
// Solaris
ioctl(d->slaveFd, I_PUSH, "ptem");
ioctl(d->slaveFd, I_PUSH, "ldterm");
#endif
#endif /* HAVE_OPENPTY */
fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
return true;
return true;
}
void KPty::closeSlave() {
Q_D(KPty);
void KPty::closeSlave()
{
Q_D(KPty);
if (d->slaveFd < 0) {
return;
}
::close(d->slaveFd);
d->slaveFd = -1;
}
void KPty::close() {
Q_D(KPty);
if (d->masterFd < 0) {
return;
}
closeSlave();
// don't bother resetting unix98 pty, it will go away after closing master anyway.
if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
if (!geteuid()) {
struct stat st;
if (!stat(d->ttyName.data(), &st)) {
chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
}
} else {
fcntl(d->masterFd, F_SETFD, 0);
d->chownpty(false);
if (d->slaveFd < 0) {
return;
}
}
::close(d->masterFd);
d->masterFd = -1;
::close(d->slaveFd);
d->slaveFd = -1;
}
void KPty::setCTty() {
Q_D(KPty);
void KPty::close()
{
Q_D(KPty);
// Setup job control //////////////////////////////////
if (d->masterFd < 0) {
return;
}
closeSlave();
// don't bother resetting unix98 pty, it will go away after closing master anyway.
if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
if (!geteuid()) {
struct stat st;
if (!stat(d->ttyName.data(), &st)) {
chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
}
} else {
fcntl(d->masterFd, F_SETFD, 0);
d->chownpty(false);
}
}
::close(d->masterFd);
d->masterFd = -1;
}
// Become session leader, process group leader,
// and get rid of the old controlling terminal.
setsid();
void KPty::setCTty()
{
Q_D(KPty);
// make our slave pty the new controlling terminal.
// Setup job control //////////////////////////////////
// Become session leader, process group leader,
// and get rid of the old controlling terminal.
setsid();
// make our slave pty the new controlling terminal.
#ifdef TIOCSCTTY
ioctl(d->slaveFd, TIOCSCTTY, 0);
ioctl(d->slaveFd, TIOCSCTTY, 0);
#else
// __svr4__ hack: the first tty opened after setsid() becomes controlling tty
::close(::open(d->ttyName, O_WRONLY, 0));
// __svr4__ hack: the first tty opened after setsid() becomes controlling tty
::close(::open(d->ttyName, O_WRONLY, 0));
#endif
// make our new process group the foreground group on the pty
int pgrp = getpid();
// make our new process group the foreground group on the pty
int pgrp = getpid();
#if defined(_POSIX_VERSION) || defined(__svr4__)
tcsetpgrp(d->slaveFd, pgrp);
tcsetpgrp(d->slaveFd, pgrp);
#elif defined(TIOCSPGRP)
ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
#endif
}
void KPty::login(const char * user, const char * remotehost) {
void KPty::login(const char * user, const char * remotehost)
{
#ifdef HAVE_UTEMPTER
Q_D(KPty);
Q_D(KPty);
addToUtmp(d->ttyName, remotehost, d->masterFd);
Q_UNUSED(user);
addToUtmp(d->ttyName, remotehost, d->masterFd);
Q_UNUSED(user);
#else
# ifdef HAVE_UTMPX
struct utmpx l_struct;
struct utmpx l_struct;
# else
struct utmp l_struct;
struct utmp l_struct;
# endif
memset(&l_struct, 0, sizeof(l_struct));
// note: strncpy without terminators _is_ correct here. man 4 utmp
memset(&l_struct, 0, sizeof(l_struct));
// note: strncpy without terminators _is_ correct here. man 4 utmp
if (user) {
strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
}
if (user) {
strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
}
if (remotehost) {
strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
if (remotehost) {
strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
# endif
}
}
# ifndef __GLIBC__
Q_D(KPty);
const char * str_ptr = d->ttyName.data();
if (!memcmp(str_ptr, "/dev/", 5)) {
str_ptr += 5;
}
strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
Q_D(KPty);
const char * str_ptr = d->ttyName.data();
if (!memcmp(str_ptr, "/dev/", 5)) {
str_ptr += 5;
}
strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
# ifdef HAVE_STRUCT_UTMP_UT_ID
strncpy(l_struct.ut_id,
str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
sizeof(l_struct.ut_id));
strncpy(l_struct.ut_id,
str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
sizeof(l_struct.ut_id));
# endif
# endif
# ifdef HAVE_UTMPX
gettimeofday(&l_struct.ut_tv, 0);
gettimeofday(&l_struct.ut_tv, 0);
# else
l_struct.ut_time = time(0);
l_struct.ut_time = time(0);
# endif
# ifdef HAVE_LOGIN
# ifdef HAVE_LOGINX
::loginx(&l_struct);
::loginx(&l_struct);
# else
::login(&l_struct);
::login(&l_struct);
# endif
# else
# ifdef HAVE_STRUCT_UTMP_UT_TYPE
l_struct.ut_type = USER_PROCESS;
l_struct.ut_type = USER_PROCESS;
# endif
# ifdef HAVE_STRUCT_UTMP_UT_PID
l_struct.ut_pid = getpid();
l_struct.ut_pid = getpid();
# ifdef HAVE_STRUCT_UTMP_UT_SESSION
l_struct.ut_session = getsid(0);
l_struct.ut_session = getsid(0);
# endif
# endif
# ifdef HAVE_UTMPX
utmpxname(_PATH_UTMPX);
setutxent();
pututxline(&l_struct);
endutxent();
updwtmpx(_PATH_WTMPX, &l_struct);
utmpxname(_PATH_UTMPX);
setutxent();
pututxline(&l_struct);
endutxent();
updwtmpx(_PATH_WTMPX, &l_struct);
# else
utmpname(_PATH_UTMP);
setutent();
pututline(&l_struct);
endutent();
updwtmp(_PATH_WTMP, &l_struct);
utmpname(_PATH_UTMP);
setutent();
pututline(&l_struct);
endutent();
updwtmp(_PATH_WTMP, &l_struct);
# endif
# endif
#endif
}
void KPty::logout() {
void KPty::logout()
{
#ifdef HAVE_UTEMPTER
Q_D(KPty);
Q_D(KPty);
removeLineFromUtmp(d->ttyName, d->masterFd);
removeLineFromUtmp(d->ttyName, d->masterFd);
#else
Q_D(KPty);
Q_D(KPty);
const char * str_ptr = d->ttyName.data();
if (!memcmp(str_ptr, "/dev/", 5)) {
str_ptr += 5;
}
# ifdef __GLIBC__
else {
const char * sl_ptr = strrchr(str_ptr, '/');
if (sl_ptr) {
str_ptr = sl_ptr + 1;
const char * str_ptr = d->ttyName.data();
if (!memcmp(str_ptr, "/dev/", 5)) {
str_ptr += 5;
}
# ifdef __GLIBC__
else {
const char * sl_ptr = strrchr(str_ptr, '/');
if (sl_ptr) {
str_ptr = sl_ptr + 1;
}
}
}
# endif
# ifdef HAVE_LOGIN
# ifdef HAVE_LOGINX
::logoutx(str_ptr, 0, DEAD_PROCESS);
::logoutx(str_ptr, 0, DEAD_PROCESS);
# else
::logout(str_ptr);
::logout(str_ptr);
# endif
# else
# ifdef HAVE_UTMPX
struct utmpx l_struct, *ut;
struct utmpx l_struct, *ut;
# else
struct utmp l_struct, *ut;
struct utmp l_struct, *ut;
# endif
memset(&l_struct, 0, sizeof(l_struct));
memset(&l_struct, 0, sizeof(l_struct));
strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
# ifdef HAVE_UTMPX
utmpxname(_PATH_UTMPX);
setutxent();
if ((ut = getutxline(&l_struct))) {
utmpxname(_PATH_UTMPX);
setutxent();
if ((ut = getutxline(&l_struct))) {
# else
utmpname(_PATH_UTMP);
setutent();
if ((ut = getutline(&l_struct))) {
utmpname(_PATH_UTMP);
setutent();
if ((ut = getutline(&l_struct))) {
# endif
memset(ut->ut_name, 0, sizeof(*ut->ut_name));
memset(ut->ut_host, 0, sizeof(*ut->ut_host));
memset(ut->ut_name, 0, sizeof(*ut->ut_name));
memset(ut->ut_host, 0, sizeof(*ut->ut_host));
# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
ut->ut_syslen = 0;
ut->ut_syslen = 0;
# endif
# ifdef HAVE_STRUCT_UTMP_UT_TYPE
ut->ut_type = DEAD_PROCESS;
ut->ut_type = DEAD_PROCESS;
# endif
# ifdef HAVE_UTMPX
gettimeofday(ut->ut_tv, 0);
pututxline(ut);
}
endutxent();
gettimeofday(ut->ut_tv, 0);
pututxline(ut);
}
endutxent();
# else
ut->ut_time = time(0);
pututline(ut);
ut->ut_time = time(0);
pututline(ut);
}
endutent();
# endif
@@ -554,55 +565,62 @@ endutent();
// XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
// Please verify.
bool KPty::tcGetAttr(struct ::termios * ttmode) const {
Q_D(const KPty);
bool KPty::tcGetAttr(struct ::termios * ttmode) const
{
Q_D(const KPty);
return _tcgetattr(d->masterFd, ttmode) == 0;
return _tcgetattr(d->masterFd, ttmode) == 0;
}
bool KPty::tcSetAttr(struct ::termios * ttmode) {
Q_D(KPty);
bool KPty::tcSetAttr(struct ::termios * ttmode)
{
Q_D(KPty);
return _tcsetattr(d->masterFd, ttmode) == 0;
return _tcsetattr(d->masterFd, ttmode) == 0;
}
bool KPty::setWinSize(int lines, int columns) {
Q_D(KPty);
bool KPty::setWinSize(int lines, int columns)
{
Q_D(KPty);
struct winsize winSize;
memset(&winSize, 0, sizeof(winSize));
winSize.ws_row = (unsigned short)lines;
winSize.ws_col = (unsigned short)columns;
return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
struct winsize winSize;
memset(&winSize, 0, sizeof(winSize));
winSize.ws_row = (unsigned short)lines;
winSize.ws_col = (unsigned short)columns;
return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
}
bool KPty::setEcho(bool echo) {
struct ::termios ttmode;
if (!tcGetAttr(&ttmode)) {
return false;
}
if (!echo) {
ttmode.c_lflag &= ~ECHO;
} else {
ttmode.c_lflag |= ECHO;
}
return tcSetAttr(&ttmode);
bool KPty::setEcho(bool echo)
{
struct ::termios ttmode;
if (!tcGetAttr(&ttmode)) {
return false;
}
if (!echo) {
ttmode.c_lflag &= ~ECHO;
} else {
ttmode.c_lflag |= ECHO;
}
return tcSetAttr(&ttmode);
}
const char * KPty::ttyName() const {
Q_D(const KPty);
const char * KPty::ttyName() const
{
Q_D(const KPty);
return d->ttyName.data();
return d->ttyName.data();
}
int KPty::masterFd() const {
Q_D(const KPty);
int KPty::masterFd() const
{
Q_D(const KPty);
return d->masterFd;
return d->masterFd;
}
int KPty::slaveFd() const {
Q_D(const KPty);
int KPty::slaveFd() const
{
Q_D(const KPty);
return d->slaveFd;
return d->slaveFd;
}
+131 -130
View File
@@ -32,156 +32,157 @@ struct termios;
* Provides primitives for opening & closing a pseudo TTY pair, assigning the
* controlling TTY, utmp registration and setting various terminal attributes.
*/
class KPty {
Q_DECLARE_PRIVATE(KPty)
class KPty
{
Q_DECLARE_PRIVATE(KPty)
public:
/**
* Constructor
*/
KPty();
/**
* Constructor
*/
KPty();
/**
* Destructor:
*
* If the pty is still open, it will be closed. Note, however, that
* an utmp registration is @em not undone.
*/
~KPty();
/**
* Destructor:
*
* If the pty is still open, it will be closed. Note, however, that
* an utmp registration is @em not undone.
*/
~KPty();
/**
* Create a pty master/slave pair.
*
* @return true if a pty pair was successfully opened
*/
bool open();
/**
* Create a pty master/slave pair.
*
* @return true if a pty pair was successfully opened
*/
bool open();
/**
* Close the pty master/slave pair.
*/
void close();
/**
* Close the pty master/slave pair.
*/
void close();
/**
* Close the pty slave descriptor.
*
* When creating the pty, KPty also opens the slave and keeps it open.
* Consequently the master will never receive an EOF notification.
* Usually this is the desired behavior, as a closed pty slave can be
* reopened any time - unlike a pipe or socket. However, in some cases
* pipe-alike behavior might be desired.
*
* After this function was called, slaveFd() and setCTty() cannot be
* used.
*/
void closeSlave();
/**
* Close the pty slave descriptor.
*
* When creating the pty, KPty also opens the slave and keeps it open.
* Consequently the master will never receive an EOF notification.
* Usually this is the desired behavior, as a closed pty slave can be
* reopened any time - unlike a pipe or socket. However, in some cases
* pipe-alike behavior might be desired.
*
* After this function was called, slaveFd() and setCTty() cannot be
* used.
*/
void closeSlave();
/**
* Creates a new session and process group and makes this pty the
* controlling tty.
*/
void setCTty();
/**
* Creates a new session and process group and makes this pty the
* controlling tty.
*/
void setCTty();
/**
* Creates an utmp entry for the tty.
* This function must be called after calling setCTty and
* making this pty the stdin.
* @param user the user to be logged on
* @param remotehost the host from which the login is coming. This is
* @em not the local host. For remote logins it should be the hostname
* of the client. For local logins from inside an X session it should
* be the name of the X display. Otherwise it should be empty.
*/
void login(const char * user = 0, const char * remotehost = 0);
/**
* Creates an utmp entry for the tty.
* This function must be called after calling setCTty and
* making this pty the stdin.
* @param user the user to be logged on
* @param remotehost the host from which the login is coming. This is
* @em not the local host. For remote logins it should be the hostname
* of the client. For local logins from inside an X session it should
* be the name of the X display. Otherwise it should be empty.
*/
void login(const char * user = 0, const char * remotehost = 0);
/**
* Removes the utmp entry for this tty.
*/
void logout();
/**
* Removes the utmp entry for this tty.
*/
void logout();
/**
* Wrapper around tcgetattr(3).
*
* This function can be used only while the PTY is open.
* You will need an #include &lt;termios.h&gt; to do anything useful
* with it.
*
* @param ttmode a pointer to a termios structure.
* Note: when declaring ttmode, @c struct @c ::termios must be used -
* without the '::' some version of HP-UX thinks, this declares
* the struct in your class, in your method.
* @return @c true on success, false otherwise
*/
bool tcGetAttr(struct ::termios * ttmode) const;
/**
* Wrapper around tcgetattr(3).
*
* This function can be used only while the PTY is open.
* You will need an #include &lt;termios.h&gt; to do anything useful
* with it.
*
* @param ttmode a pointer to a termios structure.
* Note: when declaring ttmode, @c struct @c ::termios must be used -
* without the '::' some version of HP-UX thinks, this declares
* the struct in your class, in your method.
* @return @c true on success, false otherwise
*/
bool tcGetAttr(struct ::termios * ttmode) const;
/**
* Wrapper around tcsetattr(3) with mode TCSANOW.
*
* This function can be used only while the PTY is open.
*
* @param ttmode a pointer to a termios structure.
* @return @c true on success, false otherwise. Note that success means
* that @em at @em least @em one attribute could be set.
*/
bool tcSetAttr(struct ::termios * ttmode);
/**
* Wrapper around tcsetattr(3) with mode TCSANOW.
*
* This function can be used only while the PTY is open.
*
* @param ttmode a pointer to a termios structure.
* @return @c true on success, false otherwise. Note that success means
* that @em at @em least @em one attribute could be set.
*/
bool tcSetAttr(struct ::termios * ttmode);
/**
* Change the logical (screen) size of the pty.
* The default is 24 lines by 80 columns.
*
* This function can be used only while the PTY is open.
*
* @param lines the number of rows
* @param columns the number of columns
* @return @c true on success, false otherwise
*/
bool setWinSize(int lines, int columns);
/**
* Change the logical (screen) size of the pty.
* The default is 24 lines by 80 columns.
*
* This function can be used only while the PTY is open.
*
* @param lines the number of rows
* @param columns the number of columns
* @return @c true on success, false otherwise
*/
bool setWinSize(int lines, int columns);
/**
* Set whether the pty should echo input.
*
* Echo is on by default.
* If the output of automatically fed (non-interactive) PTY clients
* needs to be parsed, disabling echo often makes it much simpler.
*
* This function can be used only while the PTY is open.
*
* @param echo true if input should be echoed.
* @return @c true on success, false otherwise
*/
bool setEcho(bool echo);
/**
* Set whether the pty should echo input.
*
* Echo is on by default.
* If the output of automatically fed (non-interactive) PTY clients
* needs to be parsed, disabling echo often makes it much simpler.
*
* This function can be used only while the PTY is open.
*
* @param echo true if input should be echoed.
* @return @c true on success, false otherwise
*/
bool setEcho(bool echo);
/**
* @return the name of the slave pty device.
*
* This function should be called only while the pty is open.
*/
const char * ttyName() const;
/**
* @return the name of the slave pty device.
*
* This function should be called only while the pty is open.
*/
const char * ttyName() const;
/**
* @return the file descriptor of the master pty
*
* This function should be called only while the pty is open.
*/
int masterFd() const;
/**
* @return the file descriptor of the master pty
*
* This function should be called only while the pty is open.
*/
int masterFd() const;
/**
* @return the file descriptor of the slave pty
*
* This function should be called only while the pty slave is open.
*/
int slaveFd() const;
/**
* @return the file descriptor of the slave pty
*
* This function should be called only while the pty slave is open.
*/
int slaveFd() const;
protected:
/**
* @internal
*/
KPty(KPtyPrivate * d);
/**
* @internal
*/
KPty(KPtyPrivate * d);
/**
* @internal
*/
KPtyPrivate * const d_ptr;
/**
* @internal
*/
KPtyPrivate * const d_ptr;
};
#endif
+7 -7
View File
@@ -28,17 +28,17 @@
#include <QtCore/QByteArray>
struct KPtyPrivate {
Q_DECLARE_PUBLIC(KPty)
Q_DECLARE_PUBLIC(KPty)
KPtyPrivate();
bool chownpty(bool grant);
KPtyPrivate();
bool chownpty(bool grant);
int masterFd;
int slaveFd;
int masterFd;
int slaveFd;
QByteArray ttyName;
QByteArray ttyName;
KPty * q_ptr;
KPty * q_ptr;
};
#endif
+199 -169
View File
@@ -24,252 +24,282 @@
using namespace Konsole;
void * createTermWidget(int startnow, void * parent) {
return (void *) new QTermWidget(startnow, (QWidget *)parent);
void * createTermWidget(int startnow, void * parent)
{
return (void *) new QTermWidget(startnow, (QWidget *)parent);
}
struct TermWidgetImpl {
TermWidgetImpl(QWidget * parent = 0);
TermWidgetImpl(QWidget * parent = 0);
TerminalDisplay * m_terminalDisplay;
Session * m_session;
TerminalDisplay * m_terminalDisplay;
Session * m_session;
Session * createSession();
TerminalDisplay * createTerminalDisplay(Session * session, QWidget * parent);
Session * createSession();
TerminalDisplay * createTerminalDisplay(Session * session, QWidget * parent);
};
TermWidgetImpl::TermWidgetImpl(QWidget * parent) {
this->m_session = createSession();
this->m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
TermWidgetImpl::TermWidgetImpl(QWidget * parent)
{
this->m_session = createSession();
this->m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
}
Session * TermWidgetImpl::createSession() {
Session * session = new Session();
QStringList env("");
env.push_front("TERM=xterm");
session->setEnvironment(env);
session->setTitle(Session::NameRole, "QTermWidget");
session->setProgram("/bin/bash");
QStringList args("");
session->setArguments(args);
session->setAutoClose(true);
Session * TermWidgetImpl::createSession()
{
Session * session = new Session();
QStringList env("");
env.push_front("TERM=xterm");
session->setEnvironment(env);
session->setTitle(Session::NameRole, "QTermWidget");
session->setProgram("/bin/bash");
QStringList args("");
session->setArguments(args);
session->setAutoClose(true);
session->setCodec(QTextCodec::codecForName("UTF-8"));
session->setCodec(QTextCodec::codecForName("UTF-8"));
session->setFlowControlEnabled(true);
session->setHistoryType(HistoryTypeBuffer(1000));
session->setFlowControlEnabled(true);
session->setHistoryType(HistoryTypeBuffer(1000));
session->setDarkBackground(true);
session->setDarkBackground(true);
session->setKeyBindings("");
return session;
session->setKeyBindings("");
return session;
}
TerminalDisplay * TermWidgetImpl::createTerminalDisplay(Session * session, QWidget * parent) {
TerminalDisplay * TermWidgetImpl::createTerminalDisplay(Session * session, QWidget * parent)
{
// TerminalDisplay* display = new TerminalDisplay(this);
TerminalDisplay * display = new TerminalDisplay(parent);
TerminalDisplay * display = new TerminalDisplay(parent);
display->setBellMode(TerminalDisplay::NotifyBell);
display->setTerminalSizeHint(true);
display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
display->setTerminalSizeStartup(true);
display->setBellMode(TerminalDisplay::NotifyBell);
display->setTerminalSizeHint(true);
display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
display->setTerminalSizeStartup(true);
display->setRandomSeed(session->sessionId() * 31);
display->setRandomSeed(session->sessionId() * 31);
return display;
return display;
}
QTermWidget::QTermWidget(int startnow, QWidget * parent)
:QWidget(parent) {
m_impl = new TermWidgetImpl(this);
:QWidget(parent)
{
m_impl = new TermWidgetImpl(this);
init();
init();
if (startnow && m_impl->m_session) {
m_impl->m_session->run();
}
this->setFocus( Qt::OtherFocusReason );
m_impl->m_terminalDisplay->resize(this->size());
this->setFocusProxy(m_impl->m_terminalDisplay);
connect(m_impl->m_terminalDisplay, SIGNAL(copyAvailable(bool)),this, SLOT(selectionChanged(bool)));
}
void QTermWidget::selectionChanged(bool textSelected)
{
emit copyAvailable(textSelected);
}
int QTermWidget::getShellPID()
{
return m_impl->m_session->processId();
}
void QTermWidget::changeDir(const QString & dir)
{
/*
this is a very hackish way of trying to determine if the shell is in
the foreground before attempting to change the directory. It may not
be portable to anything other than Linux.
*/
QString strCmd;
strCmd.setNum(getShellPID());
strCmd.prepend("ps -j ");
strCmd.append(" | tail -1 | awk '{ print $5 }' | grep -q \\+");
int retval = system(strCmd.toStdString().c_str());
if (!retval) {
QString cmd = "cd " + dir + "\n";
sendText(cmd);
}
}
QSize QTermWidget::sizeHint() const
{
QSize size = m_impl->m_terminalDisplay->sizeHint();
size.rheight() = 150;
return size;
}
void QTermWidget::startShellProgram()
{
if ( m_impl->m_session->isRunning() ) {
return;
}
if (startnow && m_impl->m_session) {
m_impl->m_session->run();
}
this->setFocus( Qt::OtherFocusReason );
m_impl->m_terminalDisplay->resize(this->size());
this->setFocusProxy(m_impl->m_terminalDisplay);
connect(m_impl->m_terminalDisplay, SIGNAL(copyAvailable(bool)),this, SLOT(selectionChanged(bool)));
}
void QTermWidget::selectionChanged(bool textSelected) {
emit copyAvailable(textSelected);
}
void QTermWidget::init()
{
m_impl->m_terminalDisplay->setSize(80, 40);
int QTermWidget::getShellPID() {
return m_impl->m_session->processId();
}
QFont font = QApplication::font();
font.setFamily("Monospace");
font.setPointSize(10);
font.setStyleHint(QFont::TypeWriter);
setTerminalFont(font);
setScrollBarPosition(NoScrollBar);
void QTermWidget::changeDir(const QString & dir) {
/*
this is a very hackish way of trying to determine if the shell is in
the foreground before attempting to change the directory. It may not
be portable to anything other than Linux.
*/
QString strCmd;
strCmd.setNum(getShellPID());
strCmd.prepend("ps -j ");
strCmd.append(" | tail -1 | awk '{ print $5 }' | grep -q \\+");
int retval = system(strCmd.toStdString().c_str());
m_impl->m_session->addView(m_impl->m_terminalDisplay);
if (!retval) {
QString cmd = "cd " + dir + "\n";
sendText(cmd);
}
}
QSize QTermWidget::sizeHint() const {
QSize size = m_impl->m_terminalDisplay->sizeHint();
size.rheight() = 150;
return size;
}
void QTermWidget::startShellProgram() {
if ( m_impl->m_session->isRunning() ) {
return;
}
m_impl->m_session->run();
}
void QTermWidget::init() {
m_impl->m_terminalDisplay->setSize(80, 40);
QFont font = QApplication::font();
font.setFamily("Monospace");
font.setPointSize(10);
font.setStyleHint(QFont::TypeWriter);
setTerminalFont(font);
setScrollBarPosition(NoScrollBar);
m_impl->m_session->addView(m_impl->m_terminalDisplay);
connect(m_impl->m_session, SIGNAL(finished()), this, SLOT(sessionFinished()));
connect(m_impl->m_session, SIGNAL(finished()), this, SLOT(sessionFinished()));
}
QTermWidget::~QTermWidget() {
emit destroyed();
QTermWidget::~QTermWidget()
{
emit destroyed();
}
void QTermWidget::setTerminalFont(QFont & font) {
if (!m_impl->m_terminalDisplay) {
return;
}
m_impl->m_terminalDisplay->setVTFont(font);
void QTermWidget::setTerminalFont(QFont & font)
{
if (!m_impl->m_terminalDisplay) {
return;
}
m_impl->m_terminalDisplay->setVTFont(font);
}
void QTermWidget::setShellProgram(const QString & progname) {
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setProgram(progname);
void QTermWidget::setShellProgram(const QString & progname)
{
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setProgram(progname);
}
void QTermWidget::setWorkingDirectory(const QString & dir) {
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setInitialWorkingDirectory(dir);
void QTermWidget::setWorkingDirectory(const QString & dir)
{
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setInitialWorkingDirectory(dir);
}
void QTermWidget::setArgs(QStringList & args) {
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setArguments(args);
void QTermWidget::setArgs(QStringList & args)
{
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setArguments(args);
}
void QTermWidget::setTextCodec(QTextCodec * codec) {
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setCodec(codec);
void QTermWidget::setTextCodec(QTextCodec * codec)
{
if (!m_impl->m_session) {
return;
}
m_impl->m_session->setCodec(codec);
}
void QTermWidget::setColorScheme(int scheme) {
switch(scheme) {
void QTermWidget::setColorScheme(int scheme)
{
switch (scheme) {
case COLOR_SCHEME_WHITE_ON_BLACK:
m_impl->m_terminalDisplay->setColorTable(whiteonblack_color_table);
break;
m_impl->m_terminalDisplay->setColorTable(whiteonblack_color_table);
break;
case COLOR_SCHEME_GREEN_ON_BLACK:
m_impl->m_terminalDisplay->setColorTable(greenonblack_color_table);
break;
m_impl->m_terminalDisplay->setColorTable(greenonblack_color_table);
break;
case COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW:
m_impl->m_terminalDisplay->setColorTable(blackonlightyellow_color_table);
break;
m_impl->m_terminalDisplay->setColorTable(blackonlightyellow_color_table);
break;
default: //do nothing
break;
};
break;
};
}
void QTermWidget::setSize(int h, int v) {
if (!m_impl->m_terminalDisplay) {
return;
}
m_impl->m_terminalDisplay->setSize(h, v);
void QTermWidget::setSize(int h, int v)
{
if (!m_impl->m_terminalDisplay) {
return;
}
m_impl->m_terminalDisplay->setSize(h, v);
}
void QTermWidget::setHistorySize(int lines) {
if (lines < 0) {
m_impl->m_session->setHistoryType(HistoryTypeFile());
} else {
m_impl->m_session->setHistoryType(HistoryTypeBuffer(lines));
}
void QTermWidget::setHistorySize(int lines)
{
if (lines < 0) {
m_impl->m_session->setHistoryType(HistoryTypeFile());
} else {
m_impl->m_session->setHistoryType(HistoryTypeBuffer(lines));
}
}
void QTermWidget::setScrollBarPosition(ScrollBarPosition pos) {
if (!m_impl->m_terminalDisplay) {
return;
}
m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos);
void QTermWidget::setScrollBarPosition(ScrollBarPosition pos)
{
if (!m_impl->m_terminalDisplay) {
return;
}
m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos);
}
void QTermWidget::sendText(QString & text) {
m_impl->m_session->sendText(text);
void QTermWidget::sendText(QString & text)
{
m_impl->m_session->sendText(text);
}
void QTermWidget::resizeEvent(QResizeEvent *) {
void QTermWidget::resizeEvent(QResizeEvent *)
{
//qDebug("global window resizing...with %d %d", this->size().width(), this->size().height());
m_impl->m_terminalDisplay->resize(this->size());
m_impl->m_terminalDisplay->resize(this->size());
}
void QTermWidget::sessionFinished() {
emit finished();
void QTermWidget::sessionFinished()
{
emit finished();
}
void QTermWidget::copyClipboard() {
m_impl->m_terminalDisplay->copyClipboard();
void QTermWidget::copyClipboard()
{
m_impl->m_terminalDisplay->copyClipboard();
}
void QTermWidget::pasteClipboard() {
m_impl->m_terminalDisplay->pasteClipboard();
void QTermWidget::pasteClipboard()
{
m_impl->m_terminalDisplay->pasteClipboard();
}
void QTermWidget::setFlowControlEnabled(bool enabled) {
m_impl->m_session->setFlowControlEnabled(enabled);
void QTermWidget::setFlowControlEnabled(bool enabled)
{
m_impl->m_session->setFlowControlEnabled(enabled);
}
bool QTermWidget::flowControlEnabled(void) {
return m_impl->m_session->flowControlEnabled();
bool QTermWidget::flowControlEnabled(void)
{
return m_impl->m_session->flowControlEnabled();
}
void QTermWidget::setFlowControlWarningEnabled(bool enabled) {
if(flowControlEnabled()) {
// Do not show warning label if flow control is disabled
m_impl->m_terminalDisplay->setFlowControlWarningEnabled(enabled);
}
void QTermWidget::setFlowControlWarningEnabled(bool enabled)
{
if (flowControlEnabled()) {
// Do not show warning label if flow control is disabled
m_impl->m_terminalDisplay->setFlowControlWarningEnabled(enabled);
}
}
void QTermWidget::setEnvironment(const QStringList & environment) {
m_impl->m_session->setEnvironment(environment);
void QTermWidget::setEnvironment(const QStringList & environment)
{
m_impl->m_session->setEnvironment(environment);
}
+67 -66
View File
@@ -29,106 +29,107 @@ enum COLOR_SCHEME { COLOR_SCHEME_WHITE_ON_BLACK = 1,
COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW
};
class QTermWidget : public QWidget {
Q_OBJECT
class QTermWidget : public QWidget
{
Q_OBJECT
public:
enum ScrollBarPosition {
/** Do not show the scroll bar. */
NoScrollBar=0,
/** Show the scroll bar on the left side of the display. */
ScrollBarLeft=1,
/** Show the scroll bar on the right side of the display. */
ScrollBarRight=2
};
enum ScrollBarPosition {
/** Do not show the scroll bar. */
NoScrollBar=0,
/** Show the scroll bar on the left side of the display. */
ScrollBarLeft=1,
/** Show the scroll bar on the right side of the display. */
ScrollBarRight=2
};
//Creation of widget
QTermWidget(int startnow = 1, //start shell programm immediatelly
QWidget * parent = 0);
~QTermWidget();
//Creation of widget
QTermWidget(int startnow = 1, //start shell programm immediatelly
QWidget * parent = 0);
~QTermWidget();
//Initial size
QSize sizeHint() const;
//Initial size
QSize sizeHint() const;
//start shell program if it was not started in constructor
void startShellProgram();
//start shell program if it was not started in constructor
void startShellProgram();
int getShellPID();
int getShellPID();
void changeDir(const QString & dir);
void changeDir(const QString & dir);
//look-n-feel, if you don`t like defaults
//look-n-feel, if you don`t like defaults
// Terminal font
// Default is application font with family Monospace, size 10
// USE ONLY FIXED-PITCH FONT!
// otherwise symbols' position could be incorrect
void setTerminalFont(QFont & font);
// Terminal font
// Default is application font with family Monospace, size 10
// USE ONLY FIXED-PITCH FONT!
// otherwise symbols' position could be incorrect
void setTerminalFont(QFont & font);
//environment
void setEnvironment(const QStringList & environment);
//environment
void setEnvironment(const QStringList & environment);
// Shell program, default is /bin/bash
void setShellProgram(const QString & progname);
// Shell program, default is /bin/bash
void setShellProgram(const QString & progname);
//working directory
void setWorkingDirectory(const QString & dir);
//working directory
void setWorkingDirectory(const QString & dir);
// Shell program args, default is none
void setArgs(QStringList & args);
// Shell program args, default is none
void setArgs(QStringList & args);
//Text codec, default is UTF-8
void setTextCodec(QTextCodec * codec);
//Text codec, default is UTF-8
void setTextCodec(QTextCodec * codec);
//Color scheme, default is white on black
void setColorScheme(int scheme);
//Color scheme, default is white on black
void setColorScheme(int scheme);
//set size
void setSize(int h, int v);
//set size
void setSize(int h, int v);
// History size for scrolling
void setHistorySize(int lines); //infinite if lines < 0
// History size for scrolling
void setHistorySize(int lines); //infinite if lines < 0
// Presence of scrollbar
void setScrollBarPosition(ScrollBarPosition);
// Presence of scrollbar
void setScrollBarPosition(ScrollBarPosition);
// Send some text to terminal
void sendText(QString & text);
// Send some text to terminal
void sendText(QString & text);
// Sets whether flow control is enabled
void setFlowControlEnabled(bool enabled);
// Sets whether flow control is enabled
void setFlowControlEnabled(bool enabled);
// Returns whether flow control is enabled
bool flowControlEnabled(void);
// Returns whether flow control is enabled
bool flowControlEnabled(void);
/**
* Sets whether the flow control warning box should be shown
* when the flow control stop key (Ctrl+S) is pressed.
*/
void setFlowControlWarningEnabled(bool enabled);
/**
* Sets whether the flow control warning box should be shown
* when the flow control stop key (Ctrl+S) is pressed.
*/
void setFlowControlWarningEnabled(bool enabled);
signals:
void finished();
void copyAvailable(bool);
void finished();
void copyAvailable(bool);
public slots:
// Paste clipboard content to terminal
void copyClipboard();
// Paste clipboard content to terminal
void copyClipboard();
// Copies selection to clipboard
void pasteClipboard();
// Copies selection to clipboard
void pasteClipboard();
protected:
virtual void resizeEvent(QResizeEvent *);
virtual void resizeEvent(QResizeEvent *);
protected slots:
void sessionFinished();
void selectionChanged(bool textSelected);
void sessionFinished();
void selectionChanged(bool textSelected);
private:
void init();
TermWidgetImpl * m_impl;
void init();
TermWidgetImpl * m_impl;
};