Ahora el browser tiene consola en vez del output.

Pasado todo el sistema de compilacion a cmake.


git-svn-id: https://opengnsys.es/svn/trunk@408 a21b9725-9963-47de-94b9-378ad31fedc9
remotes/github/master
adelcastillo 2009-10-23 17:45:58 +00:00
parent 45157b354d
commit 050d67a7fc
62 changed files with 13954 additions and 4 deletions

17
CMakeLists.txt 100644
View File

@ -0,0 +1,17 @@
project(browser)
cmake_minimum_required(VERSION 2.6)
find_package(Qt4 REQUIRED)
include_directories(qtermwidget/src/ ${QT_INCLUDES} ${QT_QTWEBKIT_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(qtermwidget)
set(browser_SRCS main.cpp mainwindow.cpp)
qt4_automoc(${browser_SRCS})
add_executable(browser ${browser_SRCS})
target_link_libraries(browser qtermwidget ${QT_LIBRARIES} ${QT_QTWEBKIT_LIBRARIES} )

17
main.cpp 100644
View File

@ -0,0 +1,17 @@
#include <QtGui/QApplication>
#include <stdio.h>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
if(argc<=1)
{
printf("Usage: %s http://siteweb.com/\n",argv[0]);
return -1;
}
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

272
mainwindow.cpp 100644
View File

@ -0,0 +1,272 @@
#include "mainwindow.h"
#include "mainwindow.moc"
#include <QtWebKit>
#include <QStringList>
#include <QWebView>
#include <QDockWidget>
#include <QtDebug>
#include <QWebPage>
#include <QProcess>
#include <QTextEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QDateTime>
#include "qtermwidget.h"
#define BUFFERSIZE 2048
#define CURRENT_TIME() QDateTime::currentDateTime().toString("dd/MM/yy hh:mm:ss")
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),web(new QWebView()),text(new QTextEdit()),
process(new QProcess(this)),
logfile(NULL),logstream(NULL)
{
// Graphic
setCentralWidget(web);
dock=new QDockWidget(this);
dock->setAllowedAreas(Qt::BottomDockWidgetArea);
dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
console = new QTermWidget();
QFont font = QApplication::font();
font.setFamily("Terminus");
font.setPointSize(12);
console->setTerminalFont(font);
//console->setColorScheme(COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW);
console->setScrollBarPosition(QTermWidget::ScrollBarRight);
//showFullScreen();
dock->setWidget(console);
addDockWidget(Qt::BottomDockWidgetArea,dock);
text->setReadOnly(true);
web->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
// Web signals
connect(web->page(),SIGNAL(linkClicked(const QUrl&)),this,
SLOT(slotLinkHandle(const QUrl&)));
connect(web,SIGNAL(loadStarted()),this,SLOT(slotWebLoadStarted()));
connect(web,SIGNAL(loadFinished(bool)),this,SLOT(slotWebLoadFinished(bool)));
connect(web,SIGNAL(loadProgress(int)),this,SLOT(slotWebLoadProgress(int)));
QStringList arguments=QCoreApplication::arguments();
web->load(QUrl(arguments[1]));
// Process signals
connect(process,SIGNAL(started()),this,SLOT(slotProcessStarted()));
connect(process,SIGNAL(finished(int,QProcess::ExitStatus)),
this,SLOT(slotProcessFinished(int,QProcess::ExitStatus)));
connect(process,SIGNAL(error(QProcess::ProcessError)),
this,SLOT(slotProcessError(QProcess::ProcessError)));
connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(slotProcessOutput()));
connect(process,SIGNAL(readyReadStandardError()),
this,SLOT(slotProcessErrorOutput()));
// Set tittle
setWindowTitle(tr("OpenGNSys Browser"));
if(!readEnvironmentValues())
text->insertPlainText(tr("Any environment variable/s didn't be setted\n"));
if(env.contains("OGLOGFILE") && env["OGLOGFILE"]!="")
{
logfile=new QFile(env["OGLOGFILE"]);
if(!logfile->open(QIODevice::WriteOnly | QIODevice::Text |
QIODevice::Append))
{
text->insertPlainText(tr("The log file couldn't be opened: ")+logfile->fileName());
delete logfile;
logfile=NULL;
}
else
logstream=new QTextStream(logfile);
}
}
MainWindow::~MainWindow()
{
if(logfile)
{
logfile->close();
delete logfile;
}
if(logstream)
delete logstream;
}
void MainWindow::slotLinkHandle(const QUrl &url)
{
QString string = url.toString();
qDebug() << string;
// Si es un link del tipo PROTOCOL lo ejecutamos
if(string.startsWith(PROTOCOL))
{
string=string.remove(0,QString(PROTOCOL).length());
QStringList list=string.split(" ",QString::SkipEmptyParts);
QString command=list.takeFirst();
process->setReadChannel(QProcess::StandardOutput);
// Le ponemos el mismo entorno que tiene el browser ahora mismo
process->setEnvironment(QProcess::systemEnvironment());
process->start(command,list);
}
else
{
qDebug() << "Load URL: " << url <<endl;
web->load(url);
}
}
void MainWindow::slotWebLoadStarted()
{
qDebug()<<"Empieza la carga de la web";
}
void MainWindow::slotWebLoadProgress(int progress)
{
qDebug()<<"Progress "<<progress;
}
void MainWindow::slotWebLoadFinished(bool ok)
{
// If any error ocurred, show a pop up
// Sometimes when the url hasn't got a dot, i.e /var/www/pageweb,
// the return value is always true so we check the bytes received too
if(ok == false || web->page()->totalBytes() == 0)
{
qDebug()<<"Error accediendo a la web";
QMessageBox msgBox;
msgBox.setText(tr("The web page couldn't load. What do you want to do?"));
QPushButton *reloadButton = msgBox.addButton(tr("Reload"), QMessageBox::ActionRole);
msgBox.addButton(QMessageBox::Abort);
msgBox.exec();
if (msgBox.clickedButton() == reloadButton)
{
web->reload();
}
else
{
close();
}
}
else
qDebug()<<"Descarga finalizada satisfactoriamente";
}
void MainWindow::slotProcessStarted()
{
qDebug()<<"Proceso inicializado"<<endl;
}
void MainWindow::slotProcessOutput()
{
qDebug()<<"Output"<<endl;
process->setReadChannel(QProcess::StandardOutput);
char buf[BUFFERSIZE];
while((process->readLine(buf,BUFFERSIZE) > 0))
{
text->insertPlainText(buf);
/*
QString str="<b>";
str+=buf;
str+="</b>";
text->insertHtml(str);
*/
output<<buf;
if(logstream)
*logstream<<CURRENT_TIME()<<": "<<buf;
}
}
void MainWindow::slotProcessErrorOutput()
{
qDebug()<<"ErrorOutput"<<endl;
process->setReadChannel(QProcess::StandardError);
char buf[BUFFERSIZE];
while((process->readLine(buf,BUFFERSIZE) > 0))
{
text->insertPlainText(buf);
errors<<buf;
}
}
void MainWindow::slotProcessFinished(int code,QProcess::ExitStatus status)
{
if(status==QProcess::NormalExit)
{
qDebug()<<"Finished: "<<code<<" "<<status<<endl;
qDebug()<<"OUTPUT:"<<endl<<output<<endl<<"ERROR:"<<endl<<errors<<endl;
}
else
{
qDebug()<<"Ha petado"<<endl;
qDebug()<<"Finished: "<<code<<" "<<status<<endl;
qDebug()<<"OUTPUT:"<<endl<<output<<endl<<"ERROR:"<<endl<<errors<<endl;
}
}
void MainWindow::slotProcessError(QProcess::ProcessError error)
{
switch(error)
{
case QProcess::FailedToStart:
qDebug()<<"Imposible arrancar el programa"<<endl;
break;
// No capturo crashed porque la pillo por finished
case QProcess::Crashed:
case QProcess::Timedout:
case QProcess::WriteError:
case QProcess::ReadError:
case QProcess::UnknownError:
default:
qDebug()<<"Otro error"<<endl;
break;
}
}
int MainWindow::readEnvironmentValues()
{
// The return value
int ret=true;
// Get all environment variables
QStringList environmentlist=QProcess::systemEnvironment();
// This is the list of the important variables
QStringList variablelist=QString(ENVIRONMENT).split(",");
// This is an auxiliar variable
QStringList stringlist;
foreach (QString str,variablelist)
{
// Look for the variable in the environment
stringlist=environmentlist.filter(str+"=");
if(stringlist.isEmpty())
{
env[str]="";
ret=false;
}
else
{
// Get the first element and get the value part
env[str]=(stringlist.first().split("="))[1];
}
}
return ret;
}

67
mainwindow.h 100644
View File

@ -0,0 +1,67 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#define PROTOCOL "command:"
#define ENVIRONMENT "OGLOGFILE"
//#define ENVIRONMENT "OGIP,OGSERVER,OGLOG"
#include <QWidget>
#include <QProcess>
#include <QMap>
#include <QMainWindow>
class QWebView;
class QTextEdit;
class QVBoxLayout;
class QProcess;
class QStringList;
class QString;
class QUrl;
class QFile;
class QTextStream;
class QDockWidget;
class QTermWidget;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
// Funcion que maneja los links
void slotLinkHandle(const QUrl& url);
void slotWebLoadStarted();
void slotWebLoadFinished(bool ok);
void slotWebLoadProgress(int progress);
// Funciones que manejan cada vez que el proceso hace algo
void slotProcessStarted();
void slotProcessFinished(int code,QProcess::ExitStatus status);
void slotProcessError(QProcess::ProcessError error);
void slotProcessOutput();
void slotProcessErrorOutput();
//Functions
protected:
int readEnvironmentValues();
protected:
QWebView *web;
QTextEdit *text;
QDockWidget *dock;
QTermWidget *console;
QProcess *process;
QStringList output;
QStringList errors;
QMap<QString,QString> env;
QFile *logfile;
QTextStream *logstream;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,9 @@
add_definitions(-DHAVE_POSIX_OPENPT)
aux_source_directory(src qtermwidget_SRCS)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
qt4_automoc(${qtermwidget_SRCS})
add_library(qtermwidget STATIC ${qtermwidget_SRCS})

View File

@ -0,0 +1,19 @@
31.07.2008
Interface class from c-style conversions rewritten with pimpl support.
16.07.2008
Added optional scrollbar
06.06.2008
Some artefacts were removed, some added...
Also added support for color schemes, and 3 color schemes provided (classical - white on black, green on black, black on light yellow). Is it enough or not?
26.05.2008
Added file release as an archive with source code. But preferrable way is still getting code from CVS, cause file release can be outdated.
11.05.2008
Initial CVS import - first version comes with number 0.0.1

View File

@ -1,10 +1,8 @@
This is a external source gotten it from:
This is a external source gotten from:
http://www.qt-apps.org/content/show.php/QTermWidget?content=82832
Only library and headers needed. Compile with QtEmbedded-4.5.1.
**********************************************************************************
*************************************************************************************
QTermWidget
version 0.1.0

10
qtermwidget/TODO 100644
View File

@ -0,0 +1,10 @@
Global
- provide more compatibility for vttest
Package
- migrate to autotools if needed
Source
- provide more options for customization
- clean unused code
- add some QT3 support features if needed

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,337 @@
/*
This file is part of Konsole, an X terminal.
Copyright (C) 2000 by Stephan Kulow <coolo@kde.org>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "BlockArray.h"
#include <QtCore>
// System
#include <assert.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdio.h>
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();
}
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"); 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;
}
size_t BlockArray::newBlock()
{
if (!size)
return size_t(-1);
append(lastblock);
lastblock = new Block();
return index + 1;
}
Block *BlockArray::lastBlock() const
{
return lastblock;
}
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)
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 ;
assert(j < size);
unmap();
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");
}
lastmap = 0;
lastmap_index = size_t(-1);
}
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);
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 {
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");
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;
int offset = (current - (newsize - 1) + size) % size;
if (!offset)
return;
// 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;
delete [] buffer1;
fclose(fion);
}
void BlockArray::increaseBuffer()
{
if (index < size) // not even wrapped once
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];
int runs = 1;
int bpr = size; // blocks per run
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;
delete [] buffer1;
delete [] buffer2;
fclose(fion);
}

View File

@ -0,0 +1,544 @@
/*
This file is part of Konsole, an X terminal.
Copyright (C) 2007 Robert Knight <robertknight@gmail.com>
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
Copyright (C) 1996 by Matthias Ettrich <ettrich@kde.org>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "Emulation.h"
#include "Emulation.moc"
// System
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Qt
#include <QtGui/QApplication>
#include <QtGui/QClipboard>
#include <QtCore/QHash>
#include <QtGui/QKeyEvent>
#include <QtCore/QRegExp>
#include <QtCore/QTextStream>
#include <QtCore/QThread>
#include <QtCore/QTime>
// Konsole
#include "KeyboardTranslator.h"
#include "Screen.h"
#include "TerminalCharacterDecoder.h"
#include "ScreenWindow.h"
using namespace Konsole;
/* ------------------------------------------------------------------------- */
/* */
/* Emulation */
/* */
/* ------------------------------------------------------------------------- */
//#define CNTL(c) ((c)-'@')
/*!
*/
Emulation::Emulation() :
_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];
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)) );
}
bool Emulation::programUsesMouse() const
{
return _usesMouse;
}
void Emulation::usesMouseChanged(bool usesMouse)
{
_usesMouse = usesMouse;
}
ScreenWindow* Emulation::createWindow()
{
ScreenWindow* window = new ScreenWindow();
window->setScreen(_currentScreen);
_windows << window;
connect(window , SIGNAL(selectionChanged()),
this , SLOT(bufferedUpdate()));
connect(this , SIGNAL(outputChanged()),
window , SLOT(notifyOutputChanged()) );
return window;
}
/*!
*/
Emulation::~Emulation()
{
QListIterator<ScreenWindow*> windowIter(_windows);
while (windowIter.hasNext())
{
delete windowIter.next();
}
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);
// 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::setHistory(const HistoryType& t)
{
_screen[0]->setScroll(t);
showBulk();
}
const HistoryType& Emulation::history()
{
return _screen[0]->getScroll();
}
void Emulation::setCodec(const QTextCodec * qtc)
{
Q_ASSERT( qtc );
_codec = qtc;
delete _decoder;
_decoder = _codec->makeDecoder();
emit useUtf8Request(utf8());
}
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);
}
QString Emulation::keyBindings()
{
return _keyTranslator->name();
}
// Interpreting Codes ---------------------------------------------------------
/*
This section deals with decoding the incoming character stream.
Decoding means here, that the stream is first separated into `tokens'
which are then mapped to a `meaning' provided as operations by the
`Screen' class.
*/
/*!
*/
void Emulation::receiveChar(int c)
// process application unicode input to terminal
// this is a trivial scanner
{
c &= 0xff;
switch (c)
{
case '\b' : _currentScreen->BackSpace(); break;
case '\t' : _currentScreen->Tabulate(); break;
case '\n' : _currentScreen->NewLine(); break;
case '\r' : _currentScreen->Return(); break;
case 0x07 : emit stateSet(NOTIFYBELL);
break;
default : _currentScreen->ShowCharacter(c); break;
};
}
/* ------------------------------------------------------------------------- */
/* */
/* Keyboard Handling */
/* */
/* ------------------------------------------------------------------------- */
/*!
*/
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());
}
}
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
}
// Unblocking, Byte to Unicode translation --------------------------------- --
/*
We are doing code conversion from locale to unicode first.
TODO: Character composition from the old code. See #96536
*/
void Emulation::receiveData(const char* text, int length)
{
emit stateSet(NOTIFYACTIVITY);
bufferedUpdate();
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();
}
}
}
//OLDER VERSION
//This version of onRcvBlock was commented out because
// a) It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
// b) It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
// were not printed properly.
//
//There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
//which hasn't been ported into the newer function (above). Hopefully someone who understands this better
//can find an alternative way of handling the check.
/*void Emulation::onRcvBlock(const char *s, int len)
{
emit notifySessionState(NOTIFYACTIVITY);
bufferedUpdate();
for (int i = 0; i < len; i++)
{
QString result = _decoder->toUnicode(&s[i],1);
int reslen = result.length();
// If we get a control code halfway a multi-byte sequence
// we flush the _decoder and continue with the control code.
if ((s[i] < 32) && (s[i] > 0))
{
// Flush _decoder
while(!result.length())
result = _decoder->toUnicode(&s[i],1);
reslen = 1;
result.resize(reslen);
result[0] = QChar(s[i]);
}
for (int j = 0; j < reslen; j++)
{
if (result[j].characterategory() == QChar::Mark_NonSpacing)
_currentScreen->compose(result.mid(j,1));
else
onRcvChar(result[j].unicode());
}
if (s[i] == '\030')
{
if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
emit zmodemDetected();
}
}
}*/
// 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::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 Emulation::lineCount()
{
// sum number of lines currently on _screen plus number of lines in history
return _currentScreen->getLines() + _currentScreen->getHistLines();
}
// Refreshing -------------------------------------------------------------- --
#define BULK_TIMEOUT1 10
#define BULK_TIMEOUT2 40
/*!
*/
void Emulation::showBulk()
{
_bulkTimer1.stop();
_bulkTimer2.stop();
emit outputChanged();
_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;
}
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
{
length = 0;
return 0;
}
}
ExtendedCharTable::ExtendedCharTable()
{
}
ExtendedCharTable::~ExtendedCharTable()
{
// free all allocated character buffers
QHashIterator<ushort,ushort*> iter(extendedCharTable);
while ( iter.hasNext() )
{
iter.next();
delete[] iter.value();
}
}
// global instance
ExtendedCharTable ExtendedCharTable::instance;
//#include "moc_Emulation.cpp"

View File

@ -0,0 +1,564 @@
/*
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "Filter.h"
#include "Filter.moc"
// System
#include <iostream>
// Qt
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QClipboard>
#include <QtCore/QString>
#include <QtCore/QSharedData>
#include <QtCore>
// KDE
//#include <KLocale>
//#include <KRun>
// Konsole
#include "TerminalCharacterDecoder.h"
using namespace Konsole;
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;
}
}
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)
{
}
TerminalImageFilterChain::~TerminalImageFilterChain()
{
delete _buffer;
delete _linePositions;
}
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');
}
decoder.end();
// qDebug("%s %d", __FILE__, __LINE__);
}
Filter::Filter() :
_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);
}
// 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;
}
}
}
/*void Filter::addLine(const QString& text)
{
_linePositions << _buffer.length();
_buffer.append(text);
}*/
const QString* Filter::buffer()
{
return _buffer;
}
Filter::HotSpot::~HotSpot()
{
}
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;
if ( spot->endLine() == line && spot->endColumn() < column )
continue;
return spot;
}
return 0;
}
Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
: _startLine(startLine)
, _startColumn(startColumn)
, _endLine(endLine)
, _endColumn(endColumn)
, _type(NotSpecified)
{
}
QString Filter::HotSpot::tooltip() const
{
return QString();
}
QList<QAction*> Filter::HotSpot::actions()
{
return QList<QAction*>();
}
int Filter::HotSpot::startLine() const
{
return _startLine;
}
int Filter::HotSpot::endLine() const
{
return _endLine;
}
int Filter::HotSpot::startColumn() const
{
return _startColumn;
}
int Filter::HotSpot::endColumn() const
{
return _endColumn;
}
Filter::HotSpot::Type Filter::HotSpot::type() const
{
return _type;
}
void Filter::HotSpot::setType(Type type)
{
_type = type;
}
RegExpFilter::RegExpFilter()
{
}
RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
: Filter::HotSpot(startLine,startColumn,endLine,endColumn)
{
setType(Marker);
}
void RegExpFilter::HotSpot::activate(QObject*)
{
}
void RegExpFilter::HotSpot::setCapturedTexts(const QStringList& texts)
{
_capturedTexts = texts;
}
QStringList RegExpFilter::HotSpot::capturedTexts() const
{
return _capturedTexts;
}
void RegExpFilter::setRegExp(const QRegExp& regExp)
{
_searchText = regExp;
}
QRegExp RegExpFilter::regExp() const
{
return _searchText;
}
/*void RegExpFilter::reset(int)
{
_buffer = QString();
}*/
void RegExpFilter::process()
{
int pos = 0;
const QString* text = buffer();
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 );
}
}
}
RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
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);
}
UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
, _urlObject(new FilterObject(this))
{
setType(Link);
}
QString UrlFilter::HotSpot::tooltip() const
{
QString url = capturedTexts().first();
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://");
}
}
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
// used for finding URLs in the text, especially if they are very general and could match very long
// pieces of text.
// Please be careful when altering them.
//regexp matches:
// full url:
// protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot
const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
// email address:
// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
// matches full url or email address
const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
EmailAddressRegExp.pattern()+')');
UrlFilter::UrlFilter()
{
setRegExp( CompleteUrlRegExp );
}
UrlFilter::HotSpot::~HotSpot()
{
delete _urlObject;
}
void FilterObject::activated()
{
_filter->activate(sender());
}
QList<QAction*> UrlFilter::HotSpot::actions()
{
QList<QAction*> list;
const UrlType kind = urlType();
QAction* openAction = new QAction(_urlObject);
QAction* copyAction = new QAction(_urlObject);;
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"));
}
// 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()) );
list << openAction;
list << copyAction;
return list;
}
//#include "moc_Filter.cpp"

View File

@ -0,0 +1,698 @@
/*
This file is part of Konsole, an X terminal.
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "History.h"
// System
#include <iostream>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
// Reasonable line size
#define LINE_SIZE 1024
using namespace Konsole;
/*
An arbitrary long scroll.
One can modify the scroll only by adding either cells
or newlines, but access it randomly.
The model is that of an arbitrary wide typewriter scroll
in that the scroll is a serie of lines and each line is
a serie of cells with no overwriting permitted.
The implementation provides arbitrary length and numbers
of cells and line/column indexed read access to the scroll
at constant costs.
KDE4: Can we use QTemporaryFile here, instead of KTempFile?
FIXME: some complain about the history buffer comsuming the
memory of their machines. This problem is critical
since the history does not behave gracefully in cases
where the memory is used up completely.
I put in a workaround that should handle it problem
now gracefully. I'm not satisfied with the solution.
FIXME: Terminating the history is not properly indicated
in the menu. We should throw a signal.
FIXME: There is noticeable decrease in speed, also. Perhaps,
there whole feature needs to be revisited therefore.
Disadvantage of a more elaborated, say block-oriented
scheme with wrap around would be it's complexity.
*/
//FIXME: tempory replacement for tmpfile
// this is here one for debugging purpose.
//#define tmpfile xTmpFile
// History File ///////////////////////////////////////////
/*
A Row(X) data type which allows adding elements to the end.
*/
HistoryFile::HistoryFile()
: ion(-1),
length(0),
fileMap(0)
{
if (tmpFile.open())
{
tmpFile.setAutoRemove(true);
ion = tmpFile.handle();
}
}
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 );
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];
}
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;
}
// History Scroll abstract base class //////////////////////////////////////
HistoryScroll::HistoryScroll(HistoryType* t)
: m_histType(t)
{
}
HistoryScroll::~HistoryScroll()
{
delete m_histType;
}
bool HistoryScroll::hasScroll()
{
return true;
}
// History Scroll File //////////////////////////////////////
/*
The history scroll makes a Row(Row(Cell)) from
two history buffers. The index buffer contains
start of line positions which refere to the cells
buffer.
Note that index[0] addresses the second line
(line #1), while the first line (line #0) starts
at 0 in cells.
*/
HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
: HistoryScroll(new HistoryTypeFile(logFileName)),
m_logFileName(logFileName)
{
}
HistoryScrollFile::~HistoryScrollFile()
{
}
int HistoryScrollFile::getLines()
{
return index.len() / sizeof(int);
}
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;
}
int HistoryScrollFile::startOfLine(int lineno)
{
if (lineno <= 0) return 0;
if (lineno <= getLines())
{
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 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);
}
HistoryScrollBuffer::~HistoryScrollBuffer()
{
delete[] _historyBuffer;
}
void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
{
_head++;
if ( _usedLines < _maxLineCount )
_usedLines++;
if ( _head >= _maxLineCount )
{
_head = 0;
}
_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());
addCellsVector(newLine);
}
void HistoryScrollBuffer::addLine(bool previousWrapped)
{
_wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
}
int HistoryScrollBuffer::getLines()
{
return _usedLines;
}
int HistoryScrollBuffer::getLineLen(int lineNumber)
{
Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
if ( lineNumber < _usedLines )
{
return _historyBuffer[bufferIndex(lineNumber)].size();
}
else
{
return 0;
}
}
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;
}
void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character* buffer)
{
if ( count == 0 ) return;
Q_ASSERT( lineNumber < _maxLineCount );
if (lineNumber >= _usedLines)
{
memset(buffer, 0, count * sizeof(Character));
return;
}
const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
//kDebug() << "startCol " << startColumn;
//kDebug() << "line.size() " << line.size();
//kDebug() << "count " << count;
Q_ASSERT( startColumn <= line.size() - count );
memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
}
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)];
}
_usedLines = qMin(_usedLines,(int)lineCount);
_maxLineCount = lineCount;
_head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
_historyBuffer = newBuffer;
delete[] oldBuffer;
_wrappedLine.resize(lineCount);
}
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;
}
}
// History Scroll None //////////////////////////////////////
HistoryScrollNone::HistoryScrollNone()
: HistoryScroll(new HistoryTypeNone())
{
}
HistoryScrollNone::~HistoryScrollNone()
{
}
bool HistoryScrollNone::hasScroll()
{
return false;
}
int HistoryScrollNone::getLines()
{
return 0;
}
int HistoryScrollNone::getLineLen(int)
{
return 0;
}
bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
{
return false;
}
void HistoryScrollNone::getCells(int, int, int, Character [])
{
}
void HistoryScrollNone::addCells(const Character [], int)
{
}
void HistoryScrollNone::addLine(bool)
{
}
// History Scroll BlockArray //////////////////////////////////////
HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
: HistoryScroll(new HistoryTypeBlockArray(size))
{
m_blockArray.setHistorySize(size); // nb. of lines.
}
HistoryScrollBlockArray::~HistoryScrollBlockArray()
{
}
int HistoryScrollBlockArray::getLines()
{
return m_lineLengths.count();
}
int HistoryScrollBlockArray::getLineLen(int lineno)
{
if ( m_lineLengths.contains(lineno) )
return m_lineLengths[lineno];
else
return 0;
}
bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
{
return false;
}
void HistoryScrollBlockArray::getCells(int lineno, int colno,
int count, Character res[])
{
if (!count) return;
const Block *b = m_blockArray.at(lineno);
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));
}
void HistoryScrollBlockArray::addCells(const Character a[], int count)
{
Block *b = m_blockArray.lastBlock();
if (!b) return;
// put cells in block's data
assert((count * sizeof(Character)) < ENTRIES);
memset(b->data, 0, ENTRIES);
memcpy(b->data, a, count * sizeof(Character));
b->size = count * sizeof(Character);
size_t res = m_blockArray.newBlock();
assert (res > 0);
Q_UNUSED( res );
m_lineLengths.insert(m_blockArray.getCurrent(), count);
}
void HistoryScrollBlockArray::addLine(bool)
{
}
//////////////////////////////////////////////////////////////////////
// History Types
//////////////////////////////////////////////////////////////////////
HistoryType::HistoryType()
{
}
HistoryType::~HistoryType()
{
}
//////////////////////////////
HistoryTypeNone::HistoryTypeNone()
{
}
bool HistoryTypeNone::isEnabled() const
{
return false;
}
HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
{
delete old;
return new HistoryScrollNone();
}
int HistoryTypeNone::maximumLineCount() const
{
return 0;
}
//////////////////////////////
HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
: m_size(size)
{
}
bool HistoryTypeBlockArray::isEnabled() const
{
return true;
}
int HistoryTypeBlockArray::maximumLineCount() const
{
return m_size;
}
HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
{
delete old;
return new HistoryScrollBlockArray(m_size);
}
//////////////////////////////
HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
: m_nbLines(nbLines)
{
}
bool HistoryTypeBuffer::isEnabled() const
{
return true;
}
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 *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));
}
}
delete old;
return newScroll;
}
return new HistoryScrollBuffer(m_nbLines);
}
//////////////////////////////
HistoryTypeFile::HistoryTypeFile(const QString& fileName)
: m_fileName(fileName)
{
}
bool HistoryTypeFile::isEnabled() const
{
return true;
}
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));
}
}
delete old;
return newScroll;
}
int HistoryTypeFile::maximumLineCount() const
{
return 0;
}

View File

@ -0,0 +1,903 @@
/*
This source file was part of Konsole, a terminal emulator.
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "KeyboardTranslator.h"
// System
#include <ctype.h>
#include <stdio.h>
// Qt
#include <QtCore/QBuffer>
//#include <KDebug>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore>
#include <QtGui>
// KDE
//#include <KDebug>
//#include <KLocale>
//#include <KStandardDirs>
using namespace Konsole;
//this is for default REALLY fallback translator.
//const char* KeyboardTranslatorManager::defaultTranslatorText =
//#include "DefaultTranslatorText.h"
//;
//and this is default now translator - default.keytab from original Konsole
const char* KeyboardTranslatorManager::defaultTranslatorText =
#include "ExtendedDefaultTranslator.h"
;
KeyboardTranslatorManager::KeyboardTranslatorManager()
: _haveLoadedAll(false)
{
}
KeyboardTranslatorManager::~KeyboardTranslatorManager()
{
qDeleteAll(_translators.values());
}
QString KeyboardTranslatorManager::findTranslatorPath(const QString& name)
{
return QString("kb-layouts/" + name + ".keytab");
}
void KeyboardTranslatorManager::findTranslators()
{
QDir dir("kb-layouts/");
QStringList filters;
filters << "*.keytab";
dir.setNameFilters(filters);
QStringList list = dir.entryList(filters); //(".keytab"); // = KGlobal::dirs()->findAllResources("data",
// "konsole/*.keytab",
// KStandardDirs::NoDuplicates);
list = dir.entryList(filters);
// add the name of each translator to the list and associated
// the name with a null pointer to indicate that the translator
// has not yet been loaded from disk
QStringListIterator listIter(list);
while (listIter.hasNext())
{
QString translatorPath = listIter.next();
QString name = QFileInfo(translatorPath).baseName();
if ( !_translators.contains(name) ) {
_translators.insert(name,0);
}
}
_haveLoadedAll = true;
}
const KeyboardTranslator* KeyboardTranslatorManager::findTranslator(const QString& name)
{
if ( name.isEmpty() )
return defaultTranslator();
//here was smth wrong in original Konsole source
findTranslators();
if ( _translators.contains(name) && _translators[name] != 0 ) {
return _translators[name];
}
KeyboardTranslator* translator = loadTranslator(name);
if ( translator != 0 )
_translators[name] = translator;
else if ( !name.isEmpty() )
qWarning() << "Unable to load translator" << name;
return translator;
}
bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator)
{
const QString path = ".keytab";// = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
// +".keytab";
qDebug() << "Saving translator to" << path;
QFile destination(path);
if (!destination.open(QIODevice::WriteOnly | QIODevice::Text))
{
qWarning() << "Unable to save keyboard translation:"
<< destination.errorString();
return false;
}
{
KeyboardTranslatorWriter writer(&destination);
writer.writeHeader(translator->description());
QListIterator<KeyboardTranslator::Entry> iter(translator->entries());
while ( iter.hasNext() )
writer.writeEntry(iter.next());
}
destination.close();
return true;
}
KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(const QString& name)
{
const QString& path = findTranslatorPath(name);
QFile source(path);
if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text))
return 0;
return loadTranslator(&source,name);
}
const KeyboardTranslator* KeyboardTranslatorManager::defaultTranslator()
{
qDebug() << "Loading default translator from text";
QBuffer textBuffer;
textBuffer.setData(defaultTranslatorText,strlen(defaultTranslatorText));
if (!textBuffer.open(QIODevice::ReadOnly))
return 0;
return loadTranslator(&textBuffer,"fallback");
}
KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(QIODevice* source,const QString& name)
{
KeyboardTranslator* translator = new KeyboardTranslator(name);
KeyboardTranslatorReader reader(source);
translator->setDescription( reader.description() );
while ( reader.hasNextEntry() ) {
translator->addEntry(reader.nextEntry());
}
source->close();
if ( !reader.parseError() )
{
return translator;
}
else
{
delete translator;
return 0;
}
}
KeyboardTranslatorWriter::KeyboardTranslatorWriter(QIODevice* destination)
: _destination(destination)
{
Q_ASSERT( destination && destination->isWritable() );
_writer = new QTextStream(_destination);
}
KeyboardTranslatorWriter::~KeyboardTranslatorWriter()
{
delete _writer;
}
void KeyboardTranslatorWriter::writeHeader( const QString& description )
{
*_writer << "keyboard \"" << description << '\"' << '\n';
}
void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entry )
{
QString result;
if ( entry.command() != KeyboardTranslator::NoCommand )
result = entry.resultToString();
else
result = '\"' + entry.resultToString() + '\"';
*_writer << "key " << entry.conditionToString() << " : " << result << '\n';
}
// each line of the keyboard translation file is one of:
//
// - keyboard "name"
// - key KeySequence : "characters"
// - key KeySequence : CommandName
//
// KeySequence begins with the name of the key ( taken from the Qt::Key enum )
// and is followed by the keyboard modifiers and state flags ( with + or - in front
// of each modifier or flag to indicate whether it is required ). All keyboard modifiers
// and flags are optional, if a particular modifier or state is not specified it is
// assumed not to be a part of the sequence. The key sequence may contain whitespace
//
// eg: "key Up+Shift : scrollLineUp"
// "key Next-Shift : "\E[6~"
//
// (lines containing only whitespace are ignored, parseLine assumes that comments have
// already been removed)
//
KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice* source )
: _source(source)
, _hasNext(false)
{
// read input until we find the description
while ( _description.isEmpty() && !source->atEnd() )
{
const QList<Token>& tokens = tokenize( QString(source->readLine()) );
if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword )
{
_description = (tokens[1].text.toUtf8());
}
}
readNext();
}
void KeyboardTranslatorReader::readNext()
{
// find next entry
while ( !_source->atEnd() )
{
const QList<Token>& tokens = tokenize( QString(_source->readLine()) );
if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword )
{
KeyboardTranslator::States flags = KeyboardTranslator::NoState;
KeyboardTranslator::States flagMask = KeyboardTranslator::NoState;
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
Qt::KeyboardModifiers modifierMask = Qt::NoModifier;
int keyCode = Qt::Key_unknown;
decodeSequence(tokens[1].text.toLower(),
keyCode,
modifiers,
modifierMask,
flags,
flagMask);
KeyboardTranslator::Command command = KeyboardTranslator::NoCommand;
QByteArray text;
// get text or command
if ( tokens[2].type == Token::OutputText )
{
text = tokens[2].text.toLocal8Bit();
}
else if ( tokens[2].type == Token::Command )
{
// identify command
if (!parseAsCommand(tokens[2].text,command))
qWarning() << "Command" << tokens[2].text << "not understood.";
}
KeyboardTranslator::Entry newEntry;
newEntry.setKeyCode( keyCode );
newEntry.setState( flags );
newEntry.setStateMask( flagMask );
newEntry.setModifiers( modifiers );
newEntry.setModifierMask( modifierMask );
newEntry.setText( text );
newEntry.setCommand( command );
_nextEntry = newEntry;
_hasNext = true;
return;
}
}
_hasNext = false;
}
bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command)
{
if ( text.compare("erase",Qt::CaseInsensitive) == 0 )
command = KeyboardTranslator::EraseCommand;
else if ( text.compare("scrollpageup",Qt::CaseInsensitive) == 0 )
command = KeyboardTranslator::ScrollPageUpCommand;
else if ( text.compare("scrollpagedown",Qt::CaseInsensitive) == 0 )
command = KeyboardTranslator::ScrollPageDownCommand;
else if ( text.compare("scrolllineup",Qt::CaseInsensitive) == 0 )
command = KeyboardTranslator::ScrollLineUpCommand;
else if ( text.compare("scrolllinedown",Qt::CaseInsensitive) == 0 )
command = KeyboardTranslator::ScrollLineDownCommand;
else if ( text.compare("scrolllock",Qt::CaseInsensitive) == 0 )
command = KeyboardTranslator::ScrollLockCommand;
else
return false;
return true;
}
bool KeyboardTranslatorReader::decodeSequence(const QString& text,
int& keyCode,
Qt::KeyboardModifiers& modifiers,
Qt::KeyboardModifiers& modifierMask,
KeyboardTranslator::States& flags,
KeyboardTranslator::States& flagMask)
{
bool isWanted = true;
bool endOfItem = false;
QString buffer;
Qt::KeyboardModifiers tempModifiers = modifiers;
Qt::KeyboardModifiers tempModifierMask = modifierMask;
KeyboardTranslator::States tempFlags = flags;
KeyboardTranslator::States tempFlagMask = flagMask;
for ( int i = 0 ; i < text.count() ; i++ )
{
const QChar& ch = text[i];
bool isLastLetter = ( i == text.count()-1 );
endOfItem = true;
if ( ch.isLetterOrNumber() )
{
endOfItem = false;
buffer.append(ch);
}
if ( (endOfItem || isLastLetter) && !buffer.isEmpty() )
{
Qt::KeyboardModifier itemModifier = Qt::NoModifier;
int itemKeyCode = 0;
KeyboardTranslator::State itemFlag = KeyboardTranslator::NoState;
if ( parseAsModifier(buffer,itemModifier) )
{
tempModifierMask |= itemModifier;
if ( isWanted )
tempModifiers |= itemModifier;
}
else if ( parseAsStateFlag(buffer,itemFlag) )
{
tempFlagMask |= itemFlag;
if ( isWanted )
tempFlags |= itemFlag;
}
else if ( parseAsKeyCode(buffer,itemKeyCode) )
keyCode = itemKeyCode;
else
qDebug() << "Unable to parse key binding item:" << buffer;
buffer.clear();
}
// check if this is a wanted / not-wanted flag and update the
// state ready for the next item
if ( ch == '+' )
isWanted = true;
else if ( ch == '-' )
isWanted = false;
}
modifiers = tempModifiers;
modifierMask = tempModifierMask;
flags = tempFlags;
flagMask = tempFlagMask;
return true;
}
bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier)
{
if ( item == "shift" )
modifier = Qt::ShiftModifier;
else if ( item == "ctrl" || item == "control" )
modifier = Qt::ControlModifier;
else if ( item == "alt" )
modifier = Qt::AltModifier;
else if ( item == "meta" )
modifier = Qt::MetaModifier;
else if ( item == "keypad" )
modifier = Qt::KeypadModifier;
else
return false;
return true;
}
bool KeyboardTranslatorReader::parseAsStateFlag(const QString& item , KeyboardTranslator::State& flag)
{
if ( item == "appcukeys" )
flag = KeyboardTranslator::CursorKeysState;
else if ( item == "ansi" )
flag = KeyboardTranslator::AnsiState;
else if ( item == "newline" )
flag = KeyboardTranslator::NewLineState;
else if ( item == "appscreen" )
flag = KeyboardTranslator::AlternateScreenState;
else if ( item == "anymod" )
flag = KeyboardTranslator::AnyModifierState;
else
return false;
return true;
}
bool KeyboardTranslatorReader::parseAsKeyCode(const QString& item , int& keyCode)
{
QKeySequence sequence = QKeySequence::fromString(item);
if ( !sequence.isEmpty() )
{
keyCode = sequence[0];
if ( sequence.count() > 1 )
{
qDebug() << "Unhandled key codes in sequence: " << item;
}
}
// additional cases implemented for backwards compatibility with KDE 3
else if ( item == "prior" )
keyCode = Qt::Key_PageUp;
else if ( item == "next" )
keyCode = Qt::Key_PageDown;
else
return false;
return true;
}
QString KeyboardTranslatorReader::description() const
{
return _description;
}
bool KeyboardTranslatorReader::hasNextEntry()
{
return _hasNext;
}
KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition ,
const QString& result )
{
QString entryString("keyboard \"temporary\"\nkey ");
entryString.append(condition);
entryString.append(" : ");
// if 'result' is the name of a command then the entry result will be that command,
// otherwise the result will be treated as a string to echo when the key sequence
// specified by 'condition' is pressed
KeyboardTranslator::Command command;
if (parseAsCommand(result,command))
entryString.append(result);
else
entryString.append('\"' + result + '\"');
QByteArray array = entryString.toUtf8();
KeyboardTranslator::Entry entry;
QBuffer buffer(&array);
buffer.open(QIODevice::ReadOnly);
KeyboardTranslatorReader reader(&buffer);
if ( reader.hasNextEntry() )
entry = reader.nextEntry();
return entry;
}
KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry()
{
Q_ASSERT( _hasNext );
KeyboardTranslator::Entry entry = _nextEntry;
readNext();
return entry;
}
bool KeyboardTranslatorReader::parseError()
{
return false;
}
QList<KeyboardTranslatorReader::Token> KeyboardTranslatorReader::tokenize(const QString& line)
{
QString text = line.simplified();
// comment line: # comment
static QRegExp comment("\\#.*");
// title line: keyboard "title"
static QRegExp title("keyboard\\s+\"(.*)\"");
// key line: key KeySequence : "output"
// key line: key KeySequence : command
static QRegExp key("key\\s+([\\w\\+\\s\\-]+)\\s*:\\s*(\"(.*)\"|\\w+)");
QList<Token> list;
if ( text.isEmpty() || comment.exactMatch(text) )
{
return list;
}
if ( title.exactMatch(text) )
{
Token titleToken = { Token::TitleKeyword , QString() };
Token textToken = { Token::TitleText , title.capturedTexts()[1] };
list << titleToken << textToken;
}
else if ( key.exactMatch(text) )
{
Token keyToken = { Token::KeyKeyword , QString() };
Token sequenceToken = { Token::KeySequence , key.capturedTexts()[1].remove(' ') };
list << keyToken << sequenceToken;
if ( key.capturedTexts()[3].isEmpty() )
{
// capturedTexts()[2] is a command
Token commandToken = { Token::Command , key.capturedTexts()[2] };
list << commandToken;
}
else
{
// capturedTexts()[3] is the output string
Token outputToken = { Token::OutputText , key.capturedTexts()[3] };
list << outputToken;
}
}
else
{
qWarning() << "Line in keyboard translator file could not be understood:" << text;
}
return list;
}
QList<QString> KeyboardTranslatorManager::allTranslators()
{
if ( !_haveLoadedAll )
{
findTranslators();
}
return _translators.keys();
}
KeyboardTranslator::Entry::Entry()
: _keyCode(0)
, _modifiers(Qt::NoModifier)
, _modifierMask(Qt::NoModifier)
, _state(NoState)
, _stateMask(NoState)
, _command(NoCommand)
{
}
bool KeyboardTranslator::Entry::operator==(const Entry& rhs) const
{
return _keyCode == rhs._keyCode &&
_modifiers == rhs._modifiers &&
_modifierMask == rhs._modifierMask &&
_state == rhs._state &&
_stateMask == rhs._stateMask &&
_command == rhs._command &&
_text == rhs._text;
}
bool KeyboardTranslator::Entry::matches(int keyCode ,
Qt::KeyboardModifiers modifiers,
States state) const
{
if ( _keyCode != keyCode )
return false;
if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) )
return false;
// if modifiers is non-zero, the 'any modifier' state is implicit
if ( modifiers != 0 )
state |= AnyModifierState;
if ( (state & _stateMask) != (_state & _stateMask) )
return false;
// special handling for the 'Any Modifier' state, which checks for the presence of
// any or no modifiers. In this context, the 'keypad' modifier does not count.
bool anyModifiersSet = modifiers != 0 && modifiers != Qt::KeypadModifier;
if ( _stateMask & KeyboardTranslator::AnyModifierState )
{
// test fails if any modifier is required but none are set
if ( (_state & KeyboardTranslator::AnyModifierState) && !anyModifiersSet )
return false;
// test fails if no modifier is allowed but one or more are set
if ( !(_state & KeyboardTranslator::AnyModifierState) && anyModifiersSet )
return false;
}
return true;
}
QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
{
QByteArray result(text(expandWildCards,modifiers));
for ( int i = 0 ; i < result.count() ; i++ )
{
char ch = result[i];
char replacement = 0;
switch ( ch )
{
case 27 : replacement = 'E'; break;
case 8 : replacement = 'b'; break;
case 12 : replacement = 'f'; break;
case 9 : replacement = 't'; break;
case 13 : replacement = 'r'; break;
case 10 : replacement = 'n'; break;
default:
// any character which is not printable is replaced by an equivalent
// \xhh escape sequence (where 'hh' are the corresponding hex digits)
if ( !QChar(ch).isPrint() )
replacement = 'x';
}
if ( replacement == 'x' )
{
result.replace(i,1,"\\x"+QByteArray(1,ch).toInt(0, 16));
} else if ( replacement != 0 )
{
result.remove(i,1);
result.insert(i,'\\');
result.insert(i+1,replacement);
}
}
return result;
}
QByteArray KeyboardTranslator::Entry::unescape(const QByteArray& input) const
{
QByteArray result(input);
for ( int i = 0 ; i < result.count()-1 ; i++ )
{
QByteRef ch = result[i];
if ( ch == '\\' )
{
char replacement[2] = {0,0};
int charsToRemove = 2;
bool escapedChar = true;
switch ( result[i+1] )
{
case 'E' : replacement[0] = 27; break;
case 'b' : replacement[0] = 8 ; break;
case 'f' : replacement[0] = 12; break;
case 't' : replacement[0] = 9 ; break;
case 'r' : replacement[0] = 13; break;
case 'n' : replacement[0] = 10; break;
case 'x' :
{
// format is \xh or \xhh where 'h' is a hexadecimal
// digit from 0-9 or A-F which should be replaced
// with the corresponding character value
char hexDigits[3] = {0};
if ( (i < result.count()-2) && isxdigit(result[i+2]) )
hexDigits[0] = result[i+2];
if ( (i < result.count()-3) && isxdigit(result[i+3]) )
hexDigits[1] = result[i+3];
int charValue = 0;
sscanf(hexDigits,"%x",&charValue);
replacement[0] = (char)charValue;
charsToRemove = 2 + strlen(hexDigits);
}
break;
default:
escapedChar = false;
}
if ( escapedChar )
result.replace(i,charsToRemove,replacement);
}
}
return result;
}
void KeyboardTranslator::Entry::insertModifier( QString& item , int modifier ) const
{
if ( !(modifier & _modifierMask) )
return;
if ( modifier & _modifiers )
item += '+';
else
item += '-';
if ( modifier == Qt::ShiftModifier )
item += "Shift";
else if ( modifier == Qt::ControlModifier )
item += "Ctrl";
else if ( modifier == Qt::AltModifier )
item += "Alt";
else if ( modifier == Qt::MetaModifier )
item += "Meta";
else if ( modifier == Qt::KeypadModifier )
item += "KeyPad";
}
void KeyboardTranslator::Entry::insertState( QString& item , int state ) const
{
if ( !(state & _stateMask) )
return;
if ( state & _state )
item += '+' ;
else
item += '-' ;
if ( state == KeyboardTranslator::AlternateScreenState )
item += "AppScreen";
else if ( state == KeyboardTranslator::NewLineState )
item += "NewLine";
else if ( state == KeyboardTranslator::AnsiState )
item += "Ansi";
else if ( state == KeyboardTranslator::CursorKeysState )
item += "AppCuKeys";
else if ( state == KeyboardTranslator::AnyModifierState )
item += "AnyMod";
}
QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
{
if ( !_text.isEmpty() )
return escapedText(expandWildCards,modifiers);
else if ( _command == EraseCommand )
return "Erase";
else if ( _command == ScrollPageUpCommand )
return "ScrollPageUp";
else if ( _command == ScrollPageDownCommand )
return "ScrollPageDown";
else if ( _command == ScrollLineUpCommand )
return "ScrollLineUp";
else if ( _command == ScrollLineDownCommand )
return "ScrollLineDown";
else if ( _command == ScrollLockCommand )
return "ScrollLock";
return QString();
}
QString KeyboardTranslator::Entry::conditionToString() const
{
QString result = QKeySequence(_keyCode).toString();
// add modifiers
insertModifier( result , Qt::ShiftModifier );
insertModifier( result , Qt::ControlModifier );
insertModifier( result , Qt::AltModifier );
insertModifier( result , Qt::MetaModifier );
// add states
insertState( result , KeyboardTranslator::AlternateScreenState );
insertState( result , KeyboardTranslator::NewLineState );
insertState( result , KeyboardTranslator::AnsiState );
insertState( result , KeyboardTranslator::CursorKeysState );
insertState( result , KeyboardTranslator::AnyModifierState );
return result;
}
KeyboardTranslator::KeyboardTranslator(const QString& name)
: _name(name)
{
}
void KeyboardTranslator::setDescription(const QString& description)
{
_description = description;
}
QString KeyboardTranslator::description() const
{
return _description;
}
void KeyboardTranslator::setName(const QString& name)
{
_name = name;
}
QString KeyboardTranslator::name() const
{
return _name;
}
QList<KeyboardTranslator::Entry> KeyboardTranslator::entries() const
{
return _entries.values();
}
void KeyboardTranslator::addEntry(const Entry& entry)
{
const int keyCode = entry.keyCode();
_entries.insertMulti(keyCode,entry);
}
void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement)
{
if ( !existing.isNull() )
_entries.remove(existing.keyCode());
_entries.insertMulti(replacement.keyCode(),replacement);
}
void KeyboardTranslator::removeEntry(const Entry& entry)
{
_entries.remove(entry.keyCode());
}
KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
{
if ( _entries.contains(keyCode) )
{
QList<Entry> entriesForKey = _entries.values(keyCode);
QListIterator<Entry> iter(entriesForKey);
while (iter.hasNext())
{
const Entry& next = iter.next();
if ( next.matches(keyCode,modifiers,state) )
return next;
}
return Entry(); // entry not found
}
else
{
return Entry();
}
}
void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator)
{
_translators.insert(translator->name(),translator);
if ( !saveTranslator(translator) )
qWarning() << "Unable to save translator" << translator->name()
<< "to disk.";
}
bool KeyboardTranslatorManager::deleteTranslator(const QString& name)
{
Q_ASSERT( _translators.contains(name) );
// locate and delete
QString path = findTranslatorPath(name);
if ( QFile::remove(path) )
{
_translators.remove(name);
return true;
}
else
{
qWarning() << "Failed to remove translator - " << path;
return false;
}
}
K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
KeyboardTranslatorManager* KeyboardTranslatorManager::instance()
{
return theKeyboardTranslatorManager;
}

View File

@ -0,0 +1,321 @@
/*
This file is part of Konsole, an X terminal.
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "Pty.h"
#include "Pty.moc"
// System
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <termios.h>
// Qt
#include <QtCore>
// KDE
//#include <KStandardDirs>
//#include <KLocale>
//#include <KDebug>
#include "kpty.h"
using namespace Konsole;
void Pty::donePty()
{
emit done(exitStatus());
}
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()->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;
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.");
}
#endif
}
void Pty::setErase(char erase)
{
_eraseChar = erase;
if (pty()->masterFd() >= 0)
{
struct ::termios ttmode;
pty()->tcGetAttr(&ttmode);
ttmode.c_cc[VERASE] = erase;
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];
}
return _eraseChar;
}
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('=');
if ( pos >= 0 )
{
QString variable = pair.left(pos);
QString value = pair.mid(pos+1);
//kDebug() << "Setting environment pair" << variable <<
// " set to " << value;
setEnvironment(variable,value);
}
}
}
int Pty::start(const QString& program,
const QStringList& programArguments,
const QStringList& environment,
ulong winid,
bool addToUtmp
// const QString& dbusService,
// const QString& dbusSession)
)
{
clearArguments();
setBinaryExecutable(program.toLatin1());
addEnvironmentVariables(environment);
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));
// 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);
pty()->open();
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;
#endif
if (_eraseChar != 0)
ttmode.c_cc[VERASE] = _eraseChar;
if (!pty()->tcSetAttr(&ttmode))
qWarning("Unable to set terminal attributes.");
pty()->setWinSize(_windowLines, _windowColumns);
if ( K3Process::start(NotifyOnExit, (Communication) (Stdin | Stdout)) == false )
return -1;
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));
}
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;
setUsePty(All, false); // utmp will be overridden later
}
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)
doSendJobs();
}
void Pty::dataReceived(K3Process *,char *buf, int len)
{
emit receivedData(buf,len);
}
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"

View File

@ -0,0 +1,7 @@
lib.pro is a *.pro-file for qmake
It produces static lib (libqtermwidget.a) only.
For creating shared lib (*.so) uncomment "dll" in "CONFIG" line in *.pro-file
Library was tested both with HAVE_POSIX_OPENPT and HAVE_GETPT precompiler directives,
defined in "DEFINES" line. You should select variant which would be correct for your system.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,298 @@
/*
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "ScreenWindow.h"
#include "ScreenWindow.moc"
// Qt
#include <QtCore>
// Konsole
#include "Screen.h"
using namespace Konsole;
ScreenWindow::ScreenWindow(QObject* parent)
: 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)
{
delete[] _windowBuffer;
_windowBufferSize = size;
_windowBuffer = new Character[size];
_bufferNeedsUpdate = true;
}
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
// goes beyond the end of the screen, the index of the line at the end
// of the screen.
//
// 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);
}
QVector<LineProperty> ScreenWindow::getLineProperties()
{
QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine());
if (result.count() != windowLines())
result.resize(windowLines());
return result;
}
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::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);
_bufferNeedsUpdate = true;
emit selectionChanged();
}
void ScreenWindow::setSelectionEnd( int column , int line )
{
_screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) );
_bufferNeedsUpdate = true;
emit selectionChanged();
}
bool ScreenWindow::isSelected( int column , int line )
{
return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) );
}
void ScreenWindow::clearSelection()
{
_screen->clearSelection();
emit selectionChanged();
}
void ScreenWindow::setWindowLines(int lines)
{
Q_ASSERT(lines > 0);
_windowLines = lines;
}
int ScreenWindow::windowLines() const
{
return _windowLines;
}
int ScreenWindow::windowColumns() const
{
return _screen->getColumns();
}
int ScreenWindow::lineCount() const
{
return _screen->getHistLines() + _screen->getLines();
}
int ScreenWindow::columnCount() const
{
return _screen->getColumns();
}
QPoint ScreenWindow::cursorPosition() const
{
QPoint position;
position.setX( _screen->getCursorX() );
position.setY( _screen->getCursorY() );
return position;
}
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 ) );
}
}
bool ScreenWindow::atEndOfOutput() const
{
return currentLine() == (lineCount()-windowLines());
}
void ScreenWindow::scrollTo( int line )
{
int maxCurrentLineNumber = lineCount() - windowLines();
line = qBound(0,line,maxCurrentLineNumber);
const int delta = line - _currentLine;
_currentLine = line;
// keep track of number of lines scrolled by,
// this can be reset by calling resetScrollCount()
_scrollCount += delta;
_bufferNeedsUpdate = true;
emit scrolled(_currentLine);
}
void ScreenWindow::setTrackOutput(bool trackOutput)
{
_trackOutput = trackOutput;
}
bool ScreenWindow::trackOutput() const
{
return _trackOutput;
}
int ScreenWindow::scrollCount() const
{
return _scrollCount;
}
void ScreenWindow::resetScrollCount()
{
_scrollCount = 0;
}
QRect ScreenWindow::scrollRegion() const
{
bool equalToScreenSize = windowLines() == _screen->getLines();
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());
// ensure that the screen window's current position does
// not go beyond the bottom of the screen
_currentLine = qMin( _currentLine , _screen->getHistLines() );
}
_bufferNeedsUpdate = true;
emit outputChanged();
}
//#include "moc_ScreenWindow.cpp"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
/*
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "ShellCommand.h"
//some versions of gcc(4.3) require explicit include
#include <cstdlib>
using namespace Konsole;
// expands environment variables in 'text'
// function copied from kdelibs/kio/kio/kurlcompletion.cpp
static bool expandEnv(QString& text);
ShellCommand::ShellCommand(const QString& fullCommand)
{
bool inQuotes = false;
QString builder;
for ( int i = 0 ; i < fullCommand.count() ; i++ )
{
QChar ch = fullCommand[i];
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 ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) )
{
_arguments << builder;
builder.clear();
}
}
}
}
ShellCommand::ShellCommand(const QString& command , const QStringList& arguments)
{
_arguments = arguments;
if ( !_arguments.isEmpty() )
_arguments[0] == command;
}
QString ShellCommand::fullCommand() const
{
return _arguments.join(QChar(' '));
}
QString ShellCommand::command() const
{
if ( !_arguments.isEmpty() )
return _arguments[0];
else
return QString();
}
QStringList ShellCommand::arguments() const
{
return _arguments;
}
bool ShellCommand::isRootCommand() 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;
foreach( QString item , items )
result << expand(item);
return result;
}
QString ShellCommand::expand(const QString& text)
{
QString result = text;
expandEnv(result);
return result;
}
/*
* expandEnv
*
* 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 '$'
//
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 );
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;
}

View File

@ -0,0 +1,227 @@
/*
This file is part of Konsole, an X terminal.
Copyright (C) 2006 by Robert Knight <robertknight@gmail.com>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "TerminalCharacterDecoder.h"
// Qt
#include <QtCore/QTextStream>
using namespace Konsole;
PlainTextDecoder::PlainTextDecoder()
: _output(0)
, _includeTrailingWhitespace(true)
{
}
void PlainTextDecoder::setTrailingWhitespace(bool enable)
{
_includeTrailingWhitespace = enable;
}
bool PlainTextDecoder::trailingWhitespace() const
{
return _includeTrailingWhitespace;
}
void PlainTextDecoder::begin(QTextStream* output)
{
_output = output;
}
void PlainTextDecoder::end()
{
_output = 0;
}
void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
)
{
Q_ASSERT( _output );
//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);
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--;
}
}
for (int i=0;i<outputCount;i++)
{
plainText.append( QChar(characters[i].character) );
}
*_output << plainText;
}
HTMLDecoder::HTMLDecoder() :
_output(0)
,_colorTable(base_color_table)
,_innerSpanOpen(false)
,_lastRendition(DEFAULT_RENDITION)
{
}
void HTMLDecoder::begin(QTextStream* output)
{
_output = output;
QString text;
//open monospace span
openSpan(text,"font-family:monospace");
*output << text;
}
void HTMLDecoder::end()
{
Q_ASSERT( _output );
QString text;
closeSpan(text);
*_output << text;
_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 );
QString text;
int spaceCount = 0;
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);
_lastRendition = characters[i].rendition;
_lastForeColor = characters[i].foregroundColor;
_lastBackColor = characters[i].backgroundColor;
//build up style string
QString style;
if ( _lastRendition & RE_BOLD ||
(_colorTable && characters[i].isBold(_colorTable)) )
style.append("font-weight:bold;");
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() ) );
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
}
}
//close any remaining open inner spans
if ( _innerSpanOpen )
closeSpan(text);
//start new line
text.append("<br>");
*_output << text;
}
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::setColorTable(const ColorEntry* table)
{
_colorTable = table;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,336 @@
/* This file is part of the KDE libraries
Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "k3processcontroller.h"
#include "k3processcontroller.moc"
#include "k3process.h"
//#include <config.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <QtCore/QSocketNotifier>
class K3ProcessController::Private
{
public:
Private()
: needcheck( false ),
notifier( 0 )
{
}
~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;
};
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::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();
}
*/
return Private::instance;
}
K3ProcessController::K3ProcessController()
: 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 );
d->notifier = new QSocketNotifier( d->fd[0], QSocketNotifier::Read );
d->notifier->setEnabled( true );
QObject::connect( d->notifier, SIGNAL(activated(int)),
SLOT(slotDoHousekeeping()));
}
K3ProcessController::~K3ProcessController()
{
#ifndef Q_OS_MAC
/* 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;
}
extern "C" {
static void theReaper( int num )
{
K3ProcessController::theSigCHLDHandler( num );
}
}
#ifdef Q_OS_UNIX
struct sigaction K3ProcessController::Private::oldChildHandlerData;
#endif
bool K3ProcessController::Private::handlerSet = false;
void K3ProcessController::setupHandlers()
{
if( Private::handlerSet )
return;
Private::handlerSet = true;
#ifdef Q_OS_UNIX
struct sigaction act;
sigemptyset( &act.sa_mask );
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)
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
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 );
#else
//TODO: win32
#endif
}
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 );
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 );
#else
//TODO: win32
#endif
// 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;
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
}
#else
//TODO: win32
#endif
errno = saved_errno;
}
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::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) );
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;
}
++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;
}
}
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;
// fall through; should never happen
case 0:
return false;
default:
slotDoHousekeeping();
return true;
}
}
#else
//TODO: win32
return false;
#endif
}
void K3ProcessController::addKProcess( K3Process* p )
{
d->kProcessList.append( 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
}
//#include "moc_k3processcontroller.cpp"

View File

@ -0,0 +1,4 @@
/default.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
/linux.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
/vt420pc.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
D

View File

@ -0,0 +1 @@
qtermwidget/lib/kb-layouts

View File

@ -0,0 +1 @@
:ext:e_k@qtermwidget.cvs.sourceforge.net:/cvsroot/qtermwidget

View File

@ -0,0 +1,133 @@
# [README.default.Keytab] Buildin Keyboard Table
#
# To customize your keyboard, copy this file to something
# ending with .keytab and change it to meet you needs.
# Please read the README.KeyTab and the README.keyboard
# in this case.
#
# --------------------------------------------------------------
keyboard "Default (XFree 4)"
# --------------------------------------------------------------
#
# Note that this particular table is a "risc" version made to
# ease customization without bothering with obsolete details.
# See VT100.keytab for the more hairy stuff.
#
# --------------------------------------------------------------
# common keys
key Escape : "\E"
key Tab -Shift : "\t"
key Tab +Shift+Ansi : "\E[Z"
key Tab +Shift-Ansi : "\t"
key Backtab +Ansi : "\E[Z"
key Backtab -Ansi : "\t"
key Return-Shift-NewLine : "\r"
key Return-Shift+NewLine : "\r\n"
key Return+Shift : "\EOM"
# Backspace and Delete codes are preserving CTRL-H.
key Backspace : "\x7f"
# Arrow keys in VT52 mode
# shift up/down are reserved for scrolling.
# shift left/right are reserved for switching between tabs (this is hardcoded).
key Up -Shift-Ansi : "\EA"
key Down -Shift-Ansi : "\EB"
key Right-Shift-Ansi : "\EC"
key Left -Shift-Ansi : "\ED"
# Arrow keys in ANSI mode with Application - and Normal Cursor Mode)
key Up -Shift-AnyMod+Ansi+AppCuKeys : "\EOA"
key Down -Shift-AnyMod+Ansi+AppCuKeys : "\EOB"
key Right -Shift-AnyMod+Ansi+AppCuKeys : "\EOC"
key Left -Shift-AnyMod+Ansi+AppCuKeys : "\EOD"
key Up -Shift-AnyMod+Ansi-AppCuKeys : "\E[A"
key Down -Shift-AnyMod+Ansi-AppCuKeys : "\E[B"
key Right -Shift-AnyMod+Ansi-AppCuKeys : "\E[C"
key Left -Shift-AnyMod+Ansi-AppCuKeys : "\E[D"
key Up -Shift+AnyMod+Ansi : "\E[1;*A"
key Down -Shift+AnyMod+Ansi : "\E[1;*B"
key Right -Shift+AnyMod+Ansi : "\E[1;*C"
key Left -Shift+AnyMod+Ansi : "\E[1;*D"
# other grey PC keys
key Enter+NewLine : "\r\n"
key Enter-NewLine : "\r"
key Home -AnyMod -AppCuKeys : "\E[H"
key End -AnyMod -AppCuKeys : "\E[F"
key Home -AnyMod +AppCuKeys : "\EOH"
key End -AnyMod +AppCuKeys : "\EOF"
key Home +AnyMod : "\E[1;*H"
key End +AnyMod : "\E[1;*F"
key Insert -AnyMod : "\E[2~"
key Delete -AnyMod : "\E[3~"
key Insert +AnyMod : "\E[2;*~"
key Delete +AnyMod : "\E[3;*~"
key Prior -Shift-AnyMod : "\E[5~"
key Next -Shift-AnyMod : "\E[6~"
key Prior -Shift+AnyMod : "\E[5;*~"
key Next -Shift+AnyMod : "\E[6;*~"
# Function keys
key F1 -AnyMod : "\EOP"
key F2 -AnyMod : "\EOQ"
key F3 -AnyMod : "\EOR"
key F4 -AnyMod : "\EOS"
key F5 -AnyMod : "\E[15~"
key F6 -AnyMod : "\E[17~"
key F7 -AnyMod : "\E[18~"
key F8 -AnyMod : "\E[19~"
key F9 -AnyMod : "\E[20~"
key F10 -AnyMod : "\E[21~"
key F11 -AnyMod : "\E[23~"
key F12 -AnyMod : "\E[24~"
key F1 +AnyMod : "\EO*P"
key F2 +AnyMod : "\EO*Q"
key F3 +AnyMod : "\EO*R"
key F4 +AnyMod : "\EO*S"
key F5 +AnyMod : "\E[15;*~"
key F6 +AnyMod : "\E[17;*~"
key F7 +AnyMod : "\E[18;*~"
key F8 +AnyMod : "\E[19;*~"
key F9 +AnyMod : "\E[20;*~"
key F10 +AnyMod : "\E[21;*~"
key F11 +AnyMod : "\E[23;*~"
key F12 +AnyMod : "\E[24;*~"
# Work around dead keys
key Space +Control : "\x00"
# Some keys are used by konsole to cause operations.
# The scroll* operations refer to the history buffer.
key Up +Shift-AppScreen : scrollLineUp
key Prior +Shift-AppScreen : scrollPageUp
key Down +Shift-AppScreen : scrollLineDown
key Next +Shift-AppScreen : scrollPageDown
#key Up +Shift : scrollLineUp
#key Prior +Shift : scrollPageUp
#key Down +Shift : scrollLineDown
#key Next +Shift : scrollPageDown
key ScrollLock : scrollLock
# keypad characters are not offered differently by Qt.

View File

@ -0,0 +1,133 @@
# [linux.keytab] Konsole Keyboard Table (Linux console keys)
#
# --------------------------------------------------------------
# NOT TESTED, MAY NEED SOME CLEANUPS
keyboard "Linux console"
# --------------------------------------------------------------
#
# This configuration table allows to customize the
# meaning of the keys.
#
# The syntax is that each entry has the form :
#
# "key" Keyname { ("+"|"-") Modename } ":" (String|Operation)
#
# Keynames are those defined in <qnamespace.h> with the
# "Qt::Key_" removed. (We'd better insert the list here)
#
# Mode names are :
#
# - Shift
# - Alt
# - Control
#
# The VT100 emulation has two modes that can affect the
# sequences emitted by certain keys. These modes are
# under control of the client program.
#
# - Newline : effects Return and Enter key.
# - Application : effects Up and Down key.
#
# - Ansi : effects Up and Down key (This is for VT52, really).
#
# Operations are
#
# - scrollUpLine
# - scrollUpPage
# - scrollDownLine
# - scrollDownPage
#
# - emitSelection
#
# If the key is not found here, the text of the
# key event as provided by QT is emitted, possibly
# preceeded by ESC if the Alt key is pressed.
#
# --------------------------------------------------------------
key Escape : "\E"
key Tab : "\t"
# VT100 can add an extra \n after return.
# The NewLine mode is set by an escape sequence.
key Return-NewLine : "\r"
key Return+NewLine : "\r\n"
# Some desperately try to save the ^H.
key Backspace : "\x7f"
key Delete : "\E[3~"
# These codes are for the VT52 mode of VT100
# The Ansi mode (i.e. VT100 mode) is set by
# an escape sequence
key Up -Shift-Ansi : "\EA"
key Down -Shift-Ansi : "\EB"
key Right-Shift-Ansi : "\EC"
key Left -Shift-Ansi : "\ED"
# VT100 emits a mode bit together
# with the arrow keys.The AppCuKeys
# mode is set by an escape sequence.
key Up -Shift+Ansi+AppCuKeys : "\EOA"
key Down -Shift+Ansi+AppCuKeys : "\EOB"
key Right-Shift+Ansi+AppCuKeys : "\EOC"
key Left -Shift+Ansi+AppCuKeys : "\EOD"
key Up -Shift+Ansi-AppCuKeys : "\E[A"
key Down -Shift+Ansi-AppCuKeys : "\E[B"
key Right-Shift+Ansi-AppCuKeys : "\E[C"
key Left -Shift+Ansi-AppCuKeys : "\E[D"
# linux functions keys F1-F5 differ from xterm
key F1 : "\E[[A"
key F2 : "\E[[B"
key F3 : "\E[[C"
key F4 : "\E[[D"
key F5 : "\E[[E"
key F6 : "\E[17~"
key F7 : "\E[18~"
key F8 : "\E[19~"
key F9 : "\E[20~"
key F10 : "\E[21~"
key F11 : "\E[23~"
key F12 : "\E[24~"
key Home : "\E[1~"
key End : "\E[4~"
key Prior -Shift : "\E[5~"
key Next -Shift : "\E[6~"
key Insert-Shift : "\E[2~"
# Keypad-Enter. See comment on Return above.
key Enter+NewLine : "\r\n"
key Enter-NewLine : "\r"
key Space +Control : "\x00"
# some of keys are used by konsole.
key Up +Shift : scrollLineUp
key Prior +Shift : scrollPageUp
key Down +Shift : scrollLineDown
key Next +Shift : scrollPageDown
key ScrollLock : scrollLock
#----------------------------------------------------------
# keypad characters as offered by Qt
# cannot be recognized as such.
#----------------------------------------------------------
# Following other strings as emitted by konsole.

View File

@ -0,0 +1,163 @@
# [vt420pc.keytab] Konsole Keyboard Table (VT420pc keys)
# adapted by ferdinand gassauer f.gassauer@aon.at
# Nov 2000
#
################################################################
#
# The escape sequences emmited by the
# keys Shift+F1 to Shift+F12 might not fit your needs
#
################# IMPORTANT NOTICE #############################
# the key bindings (Kcontrol -> look and feel -> keybindgs)
# overrule the settings in this file. The key bindings might be
# changed by the user WITHOUT notification of the maintainer of
# the keytab file. Konsole will not work as expected by
# the maintainer of the keytab file.
################################################################
#
# --------------------------------------------------------------
keyboard "DEC VT420 Terminal"
# --------------------------------------------------------------
#
# This configuration table allows to customize the
# meaning of the keys.
#
# The syntax is that each entry has the form :
#
# "key" Keyname { ("+"|"-") Modename } ":" (String|Operation)
#
# Keynames are those defined in <qnamespace.h> with the
# "Qt::Key_" removed. (We'd better insert the list here)
#
# Mode names are :
#
# - Shift
# - Alt
# - Control
#
# The VT100 emulation has two modes that can affect the
# sequences emitted by certain keys. These modes are
# under control of the client program.
#
# - Newline : effects Return and Enter key.
# - Application : effects Up and Down key.
#
# - Ansi : effects Up and Down key (This is for VT52, really).
#
# Operations are
#
# - scrollUpLine
# - scrollUpPage
# - scrollDownLine
# - scrollDownPage
#
# - emitSelection
#
# If the key is not found here, the text of the
# key event as provided by QT is emitted, possibly
# preceeded by ESC if the Alt key is pressed.
#
# --------------------------------------------------------------
key Escape : "\E"
key Tab : "\t"
key Backtab: "\E[Z"
# VT100 can add an extra \n after return.
# The NewLine mode is set by an escape sequence.
key Return-NewLine : "\r"
key Return+NewLine : "\r\n"
# Some desperately try to save the ^H.
# may be not everyone wants this
key Backspace : "\x08" # Control H
key Delete : "\x7f"
# These codes are for the VT420pc
# The Ansi mode (i.e. VT100 mode) is set by
# an escape sequence
key Up -Shift-Ansi : "\EA"
key Down -Shift-Ansi : "\EB"
key Right-Shift-Ansi : "\EC"
key Left -Shift-Ansi : "\ED"
# VT100 emits a mode bit together
# with the arrow keys.The AppCuKeys
# mode is set by an escape sequence.
key Up -Shift+Ansi+AppCuKeys : "\EOA"
key Down -Shift+Ansi+AppCuKeys : "\EOB"
key Right-Shift+Ansi+AppCuKeys : "\EOC"
key Left -Shift+Ansi+AppCuKeys : "\EOD"
key Up -Shift+Ansi-AppCuKeys : "\E[A"
key Down -Shift+Ansi-AppCuKeys : "\E[B"
key Right-Shift+Ansi-AppCuKeys : "\E[C"
key Left -Shift+Ansi-AppCuKeys : "\E[D"
# function keys
key F1 -Shift : "\E[11~"
key F2 -Shift : "\E[12~"
key F3 -Shift : "\E[13~"
key F4 -Shift : "\E[14~"
key F5 -Shift : "\E[15~"
key F6 -Shift : "\E[17~"
key F7 -Shift : "\E[18~"
key F8 -Shift : "\E[19~"
key F9 -Shift : "\E[20~"
key F10-Shift : "\E[21~"
key F11-Shift : "\E[23~"
key F12-Shift : "\E[24~"
#
# Shift F1-F12
#
key F1 +Shift : "\E[11;2~"
key F2 +Shift : "\E[12;2~"
key F3 +Shift : "\E[13;2~"
key F4 +Shift : "\E[14;2~"
key F5 +Shift : "\E[15;2~"
key F6 +Shift : "\E[17;2~"
key F7 +Shift : "\E[18;2~"
key F8 +Shift : "\E[19;2~"
key F9 +Shift : "\E[20;2~"
key F10+Shift : "\E[21;2~"
key F11+Shift : "\E[23;2~"
key F12+Shift : "\E[24;2~"
key Home : "\E[H"
key End : "\E[F"
key Prior -Shift : "\E[5~"
key Next -Shift : "\E[6~"
key Insert-Shift : "\E[2~"
# Keypad-Enter. See comment on Return above.
key Enter+NewLine : "\r\n"
key Enter-NewLine : "\r"
key Space +Control : "\x00"
# some of keys are used by konsole.
key Up +Shift : scrollLineUp
key Prior +Shift : scrollPageUp
key Down +Shift : scrollLineDown
key Next +Shift : scrollPageDown
key ScrollLock : scrollLock
#----------------------------------------------------------
# keypad characters as offered by Qt
# cannot be recognized as such.
#----------------------------------------------------------
# Following other strings as emitted by konsole.

View File

@ -0,0 +1,216 @@
/* $XFree86: xc/programs/xterm/wcwidth.character,v 1.3 2001/07/29 22:08:16 tsi Exp $ */
/*
* This is an implementation of wcwidth() and wcswidth() as defined in
* "The Single UNIX Specification, Version 2, The Open Group, 1997"
* <http://www.UNIX-systems.org/online.html>
*
* Markus Kuhn -- 2001-01-12 -- public domain
*/
#include "konsole_wcwidth.h"
struct interval {
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;
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;
}
/* The following functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* FullWidth (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that quint16 characters are encoded
* 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 }
};
/* 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;
/* 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 ||
(ucs >= 0x20000 && ucs <= 0x2ffff) */));
}
#if 0
/*
* The following function is the same as konsole_wcwidth(), except that
* spacing characters in the East Asian Ambiguous (A) category as
* defined in Unicode Technical Report #11 have a column width of 2.
* This experimental variant might be useful for users of CJK legacy
* 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 }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
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;
}

View File

@ -0,0 +1,624 @@
/*
This file is part of the KDE libraries
Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
Copyright (C) 2002-2003,2007 Oswald Buddenhagen <ossi@kde.org>
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kpty_p.h"
#ifdef __sgi
#define __svr4__
#endif
#ifdef __osf__
#define _OSF_SOURCE
#include <float.h>
#endif
#ifdef _AIX
#define _ALL_SOURCE
#endif
// __USE_XOPEN isn't defined by default in ICC
// (needed for ptsname(), grantpt() and unlockpt())
#ifdef __INTEL_COMPILER
# ifndef __USE_XOPEN
# define __USE_XOPEN
# endif
#endif
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <grp.h>
#if defined(HAVE_PTY_H)
# include <pty.h>
#endif
#ifdef HAVE_LIBUTIL_H
# include <libutil.h>
#elif defined(HAVE_UTIL_H)
# include <util.h>
#endif
#ifdef HAVE_UTEMPTER
extern "C" {
# include <utempter.h>
}
#else
# include <utmp.h>
# ifdef HAVE_UTMPX
# include <utmpx.h>
# endif
# if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
# define _PATH_UTMPX _UTMPX_FILE
# endif
# if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
# define _PATH_WTMPX _WTMPX_FILE
# endif
#endif
/* for HP-UX (some versions) the extern C is needed, and for other
platforms it doesn't hurt */
extern "C" {
#include <termios.h>
#if defined(HAVE_TERMIO_H)
# include <termio.h> // struct winsize on some systems
#endif
}
#if defined (_HPUX_SOURCE)
# define _TERMIOS_INCLUDED
# include <bsdtty.h>
#endif
#ifdef HAVE_SYS_STROPTS_H
# include <sys/stropts.h> // Defines I_PUSH
# define _NEW_TTY_CTRL
#endif
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
#else
# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
# define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
# else
# define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
# endif
#endif
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
#else
# if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
# define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
# else
# define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
# endif
#endif
//#include <kdebug.h>
//#include <kstandarddirs.h> // findExe
#include <QtCore>
// not defined on HP-UX for example
#ifndef CTRL
# define CTRL(x) ((x) & 037)
#endif
#define TTY_GROUP "tty"
///////////////////////
// private functions //
///////////////////////
//////////////////
// private data //
//////////////////
KPtyPrivate::KPtyPrivate() :
masterFd(-1), slaveFd(-1)
{
}
bool KPtyPrivate::chownpty(bool)
{
// return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
// QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
return true;
}
/////////////////////////////
// public member functions //
/////////////////////////////
KPty::KPty() :
d_ptr(new KPtyPrivate)
{
d_ptr->q_ptr = this;
}
KPty::KPty(KPtyPrivate *d) :
d_ptr(d)
{
d_ptr->q_ptr = this;
}
KPty::~KPty()
{
close();
delete d_ptr;
}
bool KPty::open()
{
Q_D(KPty);
if (d->masterFd >= 0)
return true;
QByteArray ptyName;
// 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.
// 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;
kWarning(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;
}
#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
#ifdef HAVE_POSIX_OPENPT
d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
#elif defined(HAVE_GETPT)
d->masterFd = ::getpt();
#elif defined(PTM_DEVICE)
d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
#else
# error No method to open a PTY master detected.
#endif
if (d->masterFd >= 0)
{
#ifdef HAVE_PTSNAME
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);
#endif
#ifdef HAVE_GRANTPT
if (!grantpt(d->masterFd))
goto grantedpt;
#else
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;
}
}
}
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()
<< "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());
#endif
#ifdef HAVE_UNLOCKPT
unlockpt(d->masterFd);
#elif defined(TIOCSPTLCK)
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;
}
#if (defined(__svr4__) || defined(__sgi__))
// 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);
return true;
}
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);
}
}
::close(d->masterFd);
d->masterFd = -1;
}
void KPty::setCTty()
{
Q_D(KPty);
// 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);
#else
// __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();
#if defined(_POSIX_VERSION) || defined(__svr4__)
tcsetpgrp(d->slaveFd, pgrp);
#elif defined(TIOCSPGRP)
ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
#endif
}
void KPty::login(const char *user, const char *remotehost)
{
#ifdef HAVE_UTEMPTER
Q_D(KPty);
addToUtmp(d->ttyName, remotehost, d->masterFd);
Q_UNUSED(user);
#else
# ifdef HAVE_UTMPX
struct utmpx l_struct;
# else
struct utmp l_struct;
# endif
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 (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));
# 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));
# 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));
# endif
# endif
# ifdef HAVE_UTMPX
gettimeofday(&l_struct.ut_tv, 0);
# else
l_struct.ut_time = time(0);
# endif
# ifdef HAVE_LOGIN
# ifdef HAVE_LOGINX
::loginx(&l_struct);
# else
::login(&l_struct);
# endif
# else
# ifdef HAVE_STRUCT_UTMP_UT_TYPE
l_struct.ut_type = USER_PROCESS;
# endif
# ifdef HAVE_STRUCT_UTMP_UT_PID
l_struct.ut_pid = getpid();
# ifdef HAVE_STRUCT_UTMP_UT_SESSION
l_struct.ut_session = getsid(0);
# endif
# endif
# ifdef HAVE_UTMPX
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);
# endif
# endif
#endif
}
void KPty::logout()
{
#ifdef HAVE_UTEMPTER
Q_D(KPty);
removeLineFromUtmp(d->ttyName, d->masterFd);
#else
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;
}
# endif
# ifdef HAVE_LOGIN
# ifdef HAVE_LOGINX
::logoutx(str_ptr, 0, DEAD_PROCESS);
# else
::logout(str_ptr);
# endif
# else
# ifdef HAVE_UTMPX
struct utmpx l_struct, *ut;
# else
struct utmp l_struct, *ut;
# endif
memset(&l_struct, 0, sizeof(l_struct));
strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
# ifdef HAVE_UTMPX
utmpxname(_PATH_UTMPX);
setutxent();
if ((ut = getutxline(&l_struct))) {
# else
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));
# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
ut->ut_syslen = 0;
# endif
# ifdef HAVE_STRUCT_UTMP_UT_TYPE
ut->ut_type = DEAD_PROCESS;
# endif
# ifdef HAVE_UTMPX
gettimeofday(ut->ut_tv, 0);
pututxline(ut);
}
endutxent();
# else
ut->ut_time = time(0);
pututline(ut);
}
endutent();
# endif
# endif
#endif
}
// 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);
return _tcgetattr(d->masterFd, ttmode) == 0;
}
bool KPty::tcSetAttr(struct ::termios *ttmode)
{
Q_D(KPty);
return _tcsetattr(d->masterFd, ttmode) == 0;
}
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;
}
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);
return d->ttyName.data();
}
int KPty::masterFd() const
{
Q_D(const KPty);
return d->masterFd;
}
int KPty::slaveFd() const
{
Q_D(const KPty);
return d->slaveFd;
}

View File

@ -0,0 +1,224 @@
/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "qtermwidget.h"
#include "qtermwidget.moc"
#include "Session.h"
#include "TerminalDisplay.h"
using namespace Konsole;
void *createTermWidget(int startnow, void *parent)
{
return (void*) new QTermWidget(startnow, (QWidget*)parent);
}
struct TermWidgetImpl
{
TermWidgetImpl(QWidget* parent = 0);
TerminalDisplay *m_terminalDisplay;
Session *m_session;
Session* createSession();
TerminalDisplay* createTerminalDisplay(Session *session, QWidget* parent);
};
TermWidgetImpl::TermWidgetImpl(QWidget* parent)
{
this->m_session = createSession();
this->m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
}
Session *TermWidgetImpl::createSession()
{
Session *session = new Session();
session->setTitle(Session::NameRole, "QTermWidget");
session->setProgram("/bin/bash");
QStringList args("");
session->setArguments(args);
session->setAutoClose(true);
session->setCodec(QTextCodec::codecForName("UTF-8"));
session->setFlowControlEnabled(true);
session->setHistoryType(HistoryTypeBuffer(1000));
session->setDarkBackground(true);
session->setKeyBindings("");
return session;
}
TerminalDisplay *TermWidgetImpl::createTerminalDisplay(Session *session, QWidget* parent)
{
// TerminalDisplay* display = new TerminalDisplay(this);
TerminalDisplay* display = new TerminalDisplay(parent);
display->setBellMode(TerminalDisplay::NotifyBell);
display->setTerminalSizeHint(true);
display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
display->setTerminalSizeStartup(true);
display->setRandomSeed(session->sessionId() * 31);
return display;
}
QTermWidget::QTermWidget(int startnow, QWidget *parent)
:QWidget(parent)
{
m_impl = new TermWidgetImpl(this);
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);
}
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()));
}
QTermWidget::~QTermWidget()
{
emit destroyed();
}
void QTermWidget::setTerminalFont(QFont &font)
{
if (!m_impl->m_terminalDisplay)
return;
m_impl->m_terminalDisplay->setVTFont(font);
}
void QTermWidget::setShellProgram(QString &progname)
{
if (!m_impl->m_session)
return;
m_impl->m_session->setProgram(progname);
}
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::setColorScheme(int scheme)
{
switch(scheme) {
case COLOR_SCHEME_WHITE_ON_BLACK:
m_impl->m_terminalDisplay->setColorTable(whiteonblack_color_table);
break;
case COLOR_SCHEME_GREEN_ON_BLACK:
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;
default: //do nothing
break;
};
}
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::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::resizeEvent(QResizeEvent*)
{
//qDebug("global window resizing...with %d %d", this->size().width(), this->size().height());
m_impl->m_terminalDisplay->resize(this->size());
}
void QTermWidget::sessionFinished()
{
emit finished();
}
//#include "moc_consoleq.cpp"