From 15318cad33835e4e2dc620d033e43cd930676cdd Mon Sep 17 00:00:00 2001 From: kergoth Date: Fri, 25 Jan 2002 22:14:26 +0000 Subject: Initial revision --- (limited to 'core/apps') diff --git a/core/apps/calibrate/.cvsignore b/core/apps/calibrate/.cvsignore new file mode 100644 index 0000000..edfa921 --- a/dev/null +++ b/core/apps/calibrate/.cvsignore @@ -0,0 +1,3 @@ +moc_* +*.moc +Makefile diff --git a/core/apps/calibrate/calibrate.cpp b/core/apps/calibrate/calibrate.cpp new file mode 100644 index 0000000..96cd1ca --- a/dev/null +++ b/core/apps/calibrate/calibrate.cpp @@ -0,0 +1,243 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "calibrate.h" + +#include + +#include + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + +#include +#include +#include +#include + + +Calibrate::Calibrate(QWidget* parent, const char * name, WFlags wf) : + QDialog( parent, name, TRUE, wf | WStyle_Tool | WStyle_Customize | WStyle_StaysOnTop ) +{ + showCross = TRUE; + const int offset = 30; + QRect desk = qApp->desktop()->geometry(); + setGeometry( 0, 0, desk.width(), desk.height() ); + if ( desk.height() < 250 ) { + int w = desk.height()/3; + logo.convertFromImage(Resource::loadImage("qtlogo").smoothScale(w,w)); + } else { + logo = Resource::loadPixmap( "qtlogo" ); + } + cd.screenPoints[QWSPointerCalibrationData::TopLeft] = QPoint( offset, offset ); + cd.screenPoints[QWSPointerCalibrationData::BottomLeft] = QPoint( offset, qt_screen->deviceHeight() - offset ); + cd.screenPoints[QWSPointerCalibrationData::BottomRight] = QPoint( qt_screen->deviceWidth() - offset, qt_screen->deviceHeight() - offset ); + cd.screenPoints[QWSPointerCalibrationData::TopRight] = QPoint( qt_screen->deviceWidth() - offset, offset ); + cd.screenPoints[QWSPointerCalibrationData::Center] = QPoint( qt_screen->deviceWidth()/2, qt_screen->deviceHeight()/2 ); + goodcd = cd; + reset(); + + timer = new QTimer( this ); + connect( timer, SIGNAL(timeout()), this, SLOT(timeout()) ); +} + +Calibrate::~Calibrate() +{ + store(); +} + +void Calibrate::show() +{ + grabMouse(); + QWSServer::mouseHandler()->getCalibration(&goodcd); + QWSServer::mouseHandler()->clearCalibration(); + QDialog::show(); +} + +void Calibrate::store() +{ + QWSServer::mouseHandler()->calibrate( &goodcd ); +} + +void Calibrate::hide() +{ + if ( isVisible() ) + store(); + QDialog::hide(); +} + +void Calibrate::reset() +{ + penPos = QPoint(); + location = QWSPointerCalibrationData::TopLeft; + crossPos = fromDevice( cd.screenPoints[location] ); +} + +QPoint Calibrate::fromDevice( const QPoint &p ) +{ + return qt_screen->mapFromDevice( p, + QSize(qt_screen->deviceWidth(), qt_screen->deviceHeight()) ); +} + +bool Calibrate::sanityCheck() +{ + QPoint tl = cd.devPoints[QWSPointerCalibrationData::TopLeft]; + QPoint tr = cd.devPoints[QWSPointerCalibrationData::TopRight]; + QPoint bl = cd.devPoints[QWSPointerCalibrationData::BottomLeft]; + QPoint br = cd.devPoints[QWSPointerCalibrationData::BottomRight]; + + int vl = QABS( tl.y() - bl.y() ); + int vr = QABS( tr.y() - br.y() ); + int diff = QABS( vl - vr ); + int avg = ( vl + vr ) / 2; + if ( diff > avg / 20 ) // 5% leeway + return FALSE; + + int ht = QABS( tl.x() - tr.x() ); + int hb = QABS( br.x() - bl.x() ); + diff = QABS( ht - hb ); + avg = ( ht + hb ) / 2; + if ( diff > avg / 20 ) // 5% leeway + return FALSE; + + return TRUE; +} + +void Calibrate::moveCrosshair( QPoint pt ) +{ +/* + QPainter p( this ); + p.drawPixmap( crossPos.x()-8, crossPos.y()-8, saveUnder ); + saveUnder = QPixmap::grabWindow( winId(), pt.x()-8, pt.y()-8, 16, 16 ); + p.drawRect( pt.x()-1, pt.y()-8, 2, 7 ); + p.drawRect( pt.x()-1, pt.y()+1, 2, 7 ); + p.drawRect( pt.x()-8, pt.y()-1, 7, 2 ); + p.drawRect( pt.x()+1, pt.y()-1, 7, 2 ); +*/ + showCross = FALSE; + repaint( crossPos.x()-8, crossPos.y()-8, 16, 16 ); + showCross = TRUE; + crossPos = pt; + repaint( crossPos.x()-8, crossPos.y()-8, 16, 16 ); +} + +void Calibrate::paintEvent( QPaintEvent * ) +{ + QPainter p( this ); + + int y; + + if ( !logo.isNull() ) { + y = height() / 2 - logo.height() - 15; + p.drawPixmap( (width() - logo.width())/2, y, logo ); + } + + y = height() / 2 + 15; + + p.drawText( 0, y+height()/8, width(), height() - y, AlignHCenter, + tr("Touch the crosshairs firmly and\n" + "accurately to calibrate your screen.") ); + + QFont f = p.font(); f.setBold(TRUE); + p.setFont( f ); + p.drawText( 0, y, width(), height() - y, AlignHCenter|WordBreak, + tr("Welcome to Qtopia") ); + +/* + saveUnder = QPixmap::grabWindow( winId(), crossPos.x()-8, crossPos.y()-8, + 16, 16 ); + moveCrosshair( crossPos ); +*/ + if ( showCross ) { + p.drawRect( crossPos.x()-1, crossPos.y()-8, 2, 7 ); + p.drawRect( crossPos.x()-1, crossPos.y()+1, 2, 7 ); + p.drawRect( crossPos.x()-8, crossPos.y()-1, 7, 2 ); + p.drawRect( crossPos.x()+1, crossPos.y()-1, 7, 2 ); + } +} + +void Calibrate::mousePressEvent( QMouseEvent *e ) +{ + // map to device coordinates + QPoint devPos = qt_screen->mapToDevice( e->pos(), + QSize(qt_screen->width(), qt_screen->height()) ); + if ( penPos.isNull() ) + penPos = devPos; + else + penPos = QPoint( (penPos.x() + devPos.x())/2, + (penPos.y() + devPos.y())/2 ); +} + +void Calibrate::mouseReleaseEvent( QMouseEvent * ) +{ + if ( timer->isActive() ) + return; + + bool doMove = TRUE; + + cd.devPoints[location] = penPos; + if ( location < QWSPointerCalibrationData::LastLocation ) { + location = (QWSPointerCalibrationData::Location)((int)location + 1); + } else { + if ( sanityCheck() ) { + reset(); + goodcd = cd; + hide(); + emit accept(); + doMove = FALSE; + } else { + location = QWSPointerCalibrationData::TopLeft; + } + } + + if ( doMove ) { + QPoint target = fromDevice( cd.screenPoints[location] ); + dx = (target.x() - crossPos.x())/10; + dy = (target.y() - crossPos.y())/10; + timer->start( 30 ); + } +} + +void Calibrate::timeout() +{ + QPoint target = fromDevice( cd.screenPoints[location] ); + + bool doneX = FALSE; + bool doneY = FALSE; + QPoint newPos( crossPos.x() + dx, crossPos.y() + dy ); + + if ( QABS(crossPos.x() - target.x()) <= QABS(dx) ) { + newPos.setX( target.x() ); + doneX = TRUE; + } + + if ( QABS(crossPos.y() - target.y()) <= QABS(dy) ) { + newPos.setY(target.y()); + doneY = TRUE; + } + + if ( doneX && doneY ) { + penPos = QPoint(); + timer->stop(); + } + + moveCrosshair( newPos ); +} + +#endif // _WS_QWS_ diff --git a/core/apps/calibrate/calibrate.h b/core/apps/calibrate/calibrate.h new file mode 100644 index 0000000..97108c9 --- a/dev/null +++ b/core/apps/calibrate/calibrate.h @@ -0,0 +1,67 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include + +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + +#include +#include + +class QTimer; + +class Calibrate : public QDialog +{ + Q_OBJECT +public: + Calibrate(QWidget* parent=0, const char * name=0, WFlags=0); + ~Calibrate(); + + void show(); + void hide(); + +private: + QPoint fromDevice( const QPoint &p ); + bool sanityCheck(); + void moveCrosshair( QPoint pt ); + void paintEvent( QPaintEvent * ); + void mousePressEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + +private slots: + void timeout(); + +private: + void store(); + void reset(); + QPixmap logo; + QWSPointerCalibrationData goodcd,cd; + QWSPointerCalibrationData::Location location; + QPoint crossPos; + QPoint penPos; + QPixmap saveUnder; + QTimer *timer; + int dx; + int dy; + bool showCross; +}; + +#endif // _WS_QWS_ + diff --git a/core/apps/calibrate/calibrate.pro b/core/apps/calibrate/calibrate.pro new file mode 100644 index 0000000..9769ea6 --- a/dev/null +++ b/core/apps/calibrate/calibrate.pro @@ -0,0 +1 @@ +# This is part of the taskbar diff --git a/core/apps/embeddedkonsole/.cvsignore b/core/apps/embeddedkonsole/.cvsignore new file mode 100644 index 0000000..6fe2396 --- a/dev/null +++ b/core/apps/embeddedkonsole/.cvsignore @@ -0,0 +1,2 @@ +moc_* +Makefile diff --git a/core/apps/embeddedkonsole/Makefile.in b/core/apps/embeddedkonsole/Makefile.in new file mode 100644 index 0000000..b858cd4 --- a/dev/null +++ b/core/apps/embeddedkonsole/Makefile.in @@ -0,0 +1,285 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = embeddedkonsole +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = TEWidget.h \ + TEScreen.h \ + TECommon.h \ + TEHistory.h \ + TEmulation.h \ + TEmuVt102.h \ + session.h \ + keytrans.h \ + konsole.h \ + MyPty.h +SOURCES = TEScreen.cpp \ + TEWidget.cpp \ + TEHistory.cpp \ + TEmulation.cpp \ + TEmuVt102.cpp \ + session.cpp \ + keytrans.cpp \ + konsole.cpp \ + main.cpp \ + MyPty.cpp +OBJECTS = TEScreen.o \ + TEWidget.o \ + TEHistory.o \ + TEmulation.o \ + TEmuVt102.o \ + session.o \ + keytrans.o \ + konsole.o \ + main.o \ + MyPty.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_TEWidget.cpp \ + moc_TEmulation.cpp \ + moc_TEmuVt102.cpp \ + moc_session.cpp \ + moc_konsole.cpp \ + moc_MyPty.cpp +OBJMOC = moc_TEWidget.o \ + moc_TEmulation.o \ + moc_TEmuVt102.o \ + moc_session.o \ + moc_konsole.o \ + moc_MyPty.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake embeddedkonsole.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES=embeddedkonsole + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +TEScreen.o: TEScreen.cpp \ + TEScreen.h \ + TECommon.h \ + TEHistory.h + +TEWidget.o: TEWidget.cpp \ + TEWidget.h \ + TECommon.h \ + session.h \ + MyPty.h \ + TEmuVt102.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h + +TEHistory.o: TEHistory.cpp \ + TEHistory.h \ + TECommon.h + +TEmulation.o: TEmulation.cpp \ + TEmulation.h \ + TEWidget.h \ + TECommon.h \ + TEScreen.h \ + TEHistory.h \ + keytrans.h + +TEmuVt102.o: TEmuVt102.cpp \ + TEmuVt102.h \ + TEWidget.h \ + TECommon.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h + +session.o: session.cpp \ + session.h \ + MyPty.h \ + TEWidget.h \ + TECommon.h \ + TEmuVt102.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h + +keytrans.o: keytrans.cpp \ + keytrans.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + default.keytab.h + +konsole.o: konsole.cpp \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + konsole.h \ + MyPty.h \ + TEWidget.h \ + TECommon.h \ + TEmuVt102.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h \ + session.h + +main.o: main.cpp \ + konsole.h \ + MyPty.h \ + TEWidget.h \ + TECommon.h \ + TEmuVt102.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h \ + session.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +MyPty.o: MyPty.cpp \ + MyPty.h + +moc_TEWidget.o: moc_TEWidget.cpp \ + TEWidget.h \ + TECommon.h + +moc_TEmulation.o: moc_TEmulation.cpp \ + TEmulation.h \ + TEWidget.h \ + TECommon.h \ + TEScreen.h \ + TEHistory.h \ + keytrans.h + +moc_TEmuVt102.o: moc_TEmuVt102.cpp \ + TEmuVt102.h \ + TEWidget.h \ + TECommon.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h + +moc_session.o: moc_session.cpp \ + session.h \ + MyPty.h \ + TEWidget.h \ + TECommon.h \ + TEmuVt102.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h + +moc_konsole.o: moc_konsole.cpp \ + konsole.h \ + MyPty.h \ + TEWidget.h \ + TECommon.h \ + TEmuVt102.h \ + TEScreen.h \ + TEHistory.h \ + TEmulation.h \ + keytrans.h \ + session.h + +moc_MyPty.o: moc_MyPty.cpp \ + MyPty.h + +moc_TEWidget.cpp: TEWidget.h + $(MOC) TEWidget.h -o moc_TEWidget.cpp + +moc_TEmulation.cpp: TEmulation.h + $(MOC) TEmulation.h -o moc_TEmulation.cpp + +moc_TEmuVt102.cpp: TEmuVt102.h + $(MOC) TEmuVt102.h -o moc_TEmuVt102.cpp + +moc_session.cpp: session.h + $(MOC) session.h -o moc_session.cpp + +moc_konsole.cpp: konsole.h + $(MOC) konsole.h -o moc_konsole.cpp + +moc_MyPty.cpp: MyPty.h + $(MOC) MyPty.h -o moc_MyPty.cpp + + diff --git a/core/apps/embeddedkonsole/MyPty.cpp b/core/apps/embeddedkonsole/MyPty.cpp new file mode 100644 index 0000000..3622d48 --- a/dev/null +++ b/core/apps/embeddedkonsole/MyPty.cpp @@ -0,0 +1,279 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [MyPty.C] Pseudo Terminal Device */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* If you're compiling konsole on non-Linux platforms and find + problems that you can track down to this file, please have + a look into ../README.ports, too. +*/ + +/*! \file +*/ + +/*! \class TEPty + + \brief Ptys provide a pseudo terminal connection to a program. + + Although closely related to pipes, these pseudo terminal connections have + some ability, that makes it nessesary to uses them. Most importent, they + know about changing screen sizes and UNIX job control. + + Within the terminal emulation framework, this class represents the + host side of the terminal together with the connecting serial line. + + One can create many instances of this class within a program. + As a side effect of using this class, a signal(2) handler is + installed on SIGCHLD. + + \par FIXME + + [NOTE: much of the technical stuff below will be replaced by forkpty.] + + publish the SIGCHLD signal if not related to an instance. + + clearify TEPty::done vs. TEPty::~TEPty semantics. + check if pty is restartable via run after done. + + \par Pseudo terminals + + Pseudo terminals are a unique feature of UNIX, and always come in form of + pairs of devices (/dev/ptyXX and /dev/ttyXX), which are connected to each + other by the operating system. One may think of them as two serial devices + linked by a null-modem cable. Being based on devices the number of + simultanous instances of this class is (globally) limited by the number of + those device pairs, which is 256. + + Another technic are UNIX 98 PTY's. These are supported also, and prefered + over the (obsolete) predecessor. + + There's a sinister ioctl(2), signal(2) and job control stuff + nessesary to make everything work as it should. +*/ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_OPENPTY +#include +#endif + +#include "MyPty.h" + + +#undef VERBOSE_DEBUG + + +/* -------------------------------------------------------------------------- */ + +/*! + Informs the client program about the + actual size of the window. +*/ + +void MyPty::setSize(int lines, int columns) +{ + struct winsize wsize; + wsize.ws_row = (unsigned short)lines; + wsize.ws_col = (unsigned short)columns; + if(fd < 0) return; + ioctl(fd,TIOCSWINSZ,(char *)&wsize); +} + + +void MyPty::donePty() +{ + // This is code from the Qt DumbTerminal example + int status = 0; + + ::close(fd); + + if (cpid) { + kill(cpid, SIGHUP); + waitpid(cpid, &status, 0); + } + + emit done(status); +} + + +const char* MyPty::deviceName() +{ + return ttynam; +} + + +void MyPty::error() +{ + // This is code from the Qt DumbTerminal example + donePty(); +} + + +/*! + start the client program. +*/ +int MyPty::run(const char* cmd, QStrList &, const char*, int) +{ + // This is code from the Qt DumbTerminal example + cpid = fork(); + + if ( !cpid ) { + // child - exec shell on tty + for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL); + int ttyfd = open(ttynam, O_RDWR); + dup2(ttyfd, STDIN_FILENO); + dup2(ttyfd, STDOUT_FILENO); + dup2(ttyfd, STDERR_FILENO); + // should be done with tty, so close it + close(ttyfd); + static struct termios ttmode; + if ( setsid() < 0 ) + perror( "failed to set process group" ); +#if defined (TIOCSCTTY) + // grabbed from APUE by Stevens + ioctl(STDIN_FILENO, TIOCSCTTY, 0); +#endif + tcgetattr( STDIN_FILENO, &ttmode ); + ttmode.c_cc[VINTR] = 3; + ttmode.c_cc[VERASE] = 8; + tcsetattr( STDIN_FILENO, TCSANOW, &ttmode ); + setenv("TERM","vt100",1); + setenv("COLORTERM","0",1); + + if (getuid() == 0) { + char msg[] = "WARNING: You are running this shell as root!\n"; + write(ttyfd, msg, sizeof(msg)); + } + execl(cmd, cmd, 0); + + donePty(); + exit(-1); + } + + // parent - continue as a widget + QSocketNotifier* sn_r = new QSocketNotifier(fd,QSocketNotifier::Read,this); + QSocketNotifier* sn_e = new QSocketNotifier(fd,QSocketNotifier::Exception,this); + connect(sn_r,SIGNAL(activated(int)),this,SLOT(readPty())); + connect(sn_e,SIGNAL(activated(int)),this,SLOT(error())); + + return 0; +} + +int MyPty::openPty() +{ + // This is code from the Qt DumbTerminal example + int ptyfd = -1; + +#ifdef HAVE_OPENPTY + int ttyfd; + if ( openpty(&ptyfd,&ttyfd,ttynam,0,0) ) + ptyfd = -1; + else + close(ttyfd); // we open the ttynam ourselves. +#else + for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) { + for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) { + sprintf(ptynam,"/dev/pty%c%c",*c0,*c1); + sprintf(ttynam,"/dev/tty%c%c",*c0,*c1); + if ((ptyfd = ::open(ptynam,O_RDWR)) >= 0) { + if (geteuid() != 0 && !access(ttynam,R_OK|W_OK) == 0) { + ::close(ptyfd); + ptyfd = -1; + } + } + } + } +#endif + + if ( ptyfd < 0 ) { + qApp->exit(1); + return -1; + } + + return ptyfd; +} + +/*! + Create an instance. +*/ +MyPty::MyPty() : cpid(0) +{ + fd = openPty(); +} + +/*! + Destructor. + Note that the related client program is not killed + (yet) when a instance is deleted. +*/ +MyPty::~MyPty() +{ + donePty(); +} + + +/*! sends len bytes through the line */ +void MyPty::send_bytes(const char* s, int len) +{ + +#ifdef VERBOSE_DEBUG + // verbose debug + printf("sending bytes:\n"); + for (int i = 0; i < len; i++) + printf("%c", s[i]); + printf("\n"); +#endif + + ::write(fd, s, len); +} + +/*! indicates that a block of data is received */ +void MyPty::readPty() +{ + char buf[4096]; + + int len = ::read( fd, buf, 4096 ); + + if (len == -1) + donePty(); + + if (len < 0) + return; + + emit block_in(buf,len); + +#ifdef VERBOSE_DEBUG + // verbose debug + printf("read bytes:\n"); + for (int i = 0; i < len; i++) + printf("%c", buf[i]); + printf("\n"); +#endif + +} + diff --git a/core/apps/embeddedkonsole/MyPty.h b/core/apps/embeddedkonsole/MyPty.h new file mode 100644 index 0000000..b2a5b58 --- a/dev/null +++ b/core/apps/embeddedkonsole/MyPty.h @@ -0,0 +1,88 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [MyPty.h] Pseudo Terminal Device */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \file +*/ + +#ifndef MY_PTY_H +#define MY_PTY_H + +#include +#include + + +class MyPty : public QObject +{ +Q_OBJECT + + public: + + MyPty(); + ~MyPty(); + + /*! + having a `run' separate from the constructor allows to make + the necessary connections to the signals and slots of the + instance before starting the execution of the client. + */ + int run(const char* pgm, QStrList & args, const char* term, int addutmp); + + public slots: + + void send_bytes(const char* s, int len); + void setSize(int lines, int columns); + void error(); + + signals: + + /*! + emitted when the client program terminates. + \param status the wait(2) status code of the terminated client program. + */ + void done(int status); + + /*! + emitted when a new block of data comes in. + \param s - the data + \param len - the length of the block + */ + void block_in(const char* s, int len); + + public: + + void send_byte(char s); +// void send_string(const char* s); + + const char* deviceName(); + + protected slots: + void readPty(); + void donePty(); + + private: + int openPty(); + + private: + + char ptynam[16]; // "/dev/ptyxx" | "/dev/ptmx" + char ttynam[16]; // "/dev/ttyxx" | "/dev/pts/########..." + int fd; + int cpid; +}; + +#endif diff --git a/core/apps/embeddedkonsole/TECommon.h b/core/apps/embeddedkonsole/TECommon.h new file mode 100644 index 0000000..261d51b --- a/dev/null +++ b/core/apps/embeddedkonsole/TECommon.h @@ -0,0 +1,114 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TECommon.h] Common Definitions */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \file TECommon.h + \brief Definitions shared between TEScreen and TEWidget. +*/ + +#ifndef TECOMMON_H +#define TECOMMON_H + +#include + +#ifndef BOOL +typedef int BOOL; +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef UINT8 +typedef unsigned char UINT8; +#endif + +#ifndef UINT16 +typedef unsigned short UINT16; +#endif + +// Attributed Character Representations /////////////////////////////// + +// Colors + +#define BASE_COLORS (2+8) +#define INTENSITIES 2 +#define TABLE_COLORS (INTENSITIES*BASE_COLORS) + +#define DEFAULT_FORE_COLOR 0 +#define DEFAULT_BACK_COLOR 1 + +#define DEFAULT_RENDITION 0 +#define RE_BOLD (1 << 0) +#define RE_BLINK (1 << 1) +#define RE_UNDERLINE (1 << 2) +#define RE_REVERSE (1 << 3) // Screen only +#define RE_INTENSIVE (1 << 3) // Widget only + +/*! \class ca + * \brief a character with rendition attributes. +*/ + +class ca +{ +public: + inline ca(UINT16 _c = ' ', + UINT8 _f = DEFAULT_FORE_COLOR, + UINT8 _b = DEFAULT_BACK_COLOR, + UINT8 _r = DEFAULT_RENDITION) + : c(_c), f(_f), b(_b), r(_r) {} +public: + UINT16 c; // character + UINT8 f; // foreground color + UINT8 b; // background color + UINT8 r; // rendition +public: + friend BOOL operator == (ca a, ca b); + friend BOOL operator != (ca a, ca b); +}; + +inline BOOL operator == (ca a, ca b) +{ + return a.c == b.c && a.f == b.f && a.b == b.b && a.r == b.r; +} + +inline BOOL operator != (ca a, ca b) +{ + return a.c != b.c || a.f != b.f || a.b != b.b || a.r != b.r; +} + +/*! +*/ +struct ColorEntry +{ + ColorEntry(QColor c, bool tr, bool b) : color(c), transparent(tr), bold(b) {} + ColorEntry() : transparent(false), bold(false) {} // default constructors + void operator=(const ColorEntry& rhs) { + color = rhs.color; + transparent = rhs.transparent; + bold = rhs.bold; + } + QColor color; + bool transparent; // if used on bg + bool bold; // if used on fg +}; + +#endif // TECOMMON_H diff --git a/core/apps/embeddedkonsole/TEHistory.cpp b/core/apps/embeddedkonsole/TEHistory.cpp new file mode 100644 index 0000000..317ce57 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEHistory.cpp @@ -0,0 +1,212 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TEHistory.C] History Buffer */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#include "TEHistory.h" +#include +#include +#include +#include +#include +#include + +#define HERE printf("%s(%d): here\n",__FILE__,__LINE__) + +/* + 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. + +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 noticable 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 + +FILE* xTmpFile() +{ + static int fid = 0; + char fname[80]; + sprintf(fname,"TmpFile.%d",fid++); + return fopen(fname,"w"); +} + + +// History Buffer /////////////////////////////////////////// + +/* + A Row(X) data type which allows adding elements to the end. +*/ + +HistoryBuffer::HistoryBuffer() +{ + ion = -1; + length = 0; +} + +HistoryBuffer::~HistoryBuffer() +{ + setScroll(FALSE); +} + +void HistoryBuffer::setScroll(bool on) +{ + if (on == hasScroll()) return; + + if (on) + { + assert( ion < 0 ); + assert( length == 0); + FILE* tmp = tmpfile(); if (!tmp) { perror("konsole: cannot open temp file.\n"); return; } + ion = dup(fileno(tmp)); if (ion<0) perror("konsole: cannot dup temp file.\n"); + fclose(tmp); + } + else + { + assert( ion >= 0 ); + close(ion); + ion = -1; + length = 0; + } +} + +bool HistoryBuffer::hasScroll() +{ + return ion >= 0; +} + +void HistoryBuffer::add(const unsigned char* bytes, int len) +{ int rc; + assert(hasScroll()); + rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setScroll(FALSE); return; } + rc = write(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::add.write"); setScroll(FALSE); return; } + length += rc; +} + +void HistoryBuffer::get(unsigned char* bytes, int len, int loc) +{ int rc; + assert(hasScroll()); + 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("HistoryBuffer::get.seek"); setScroll(FALSE); return; } + rc = read(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::get.read"); setScroll(FALSE); return; } +} + +int HistoryBuffer::len() +{ + return length; +} + +// History Scroll ////////////////////////////////////// + +/* + 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. +*/ + +HistoryScroll::HistoryScroll() +{ +} + +HistoryScroll::~HistoryScroll() +{ +} + +void HistoryScroll::setScroll(bool on) +{ + index.setScroll(on); + cells.setScroll(on); +} + +bool HistoryScroll::hasScroll() +{ + return index.hasScroll() && cells.hasScroll(); +} + +int HistoryScroll::getLines() +{ + if (!hasScroll()) return 0; + return index.len() / sizeof(int); +} + +int HistoryScroll::getLineLen(int lineno) +{ + if (!hasScroll()) return 0; + return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(ca); +} + +int HistoryScroll::startOfLine(int lineno) +{ + if (lineno <= 0) return 0; + if (!hasScroll()) return 0; + if (lineno <= getLines()) + { int res; + index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int)); + return res; + } + return cells.len(); +} + +void HistoryScroll::getCells(int lineno, int colno, int count, ca res[]) +{ + assert(hasScroll()); + cells.get((unsigned char*)res,count*sizeof(ca),startOfLine(lineno)+colno*sizeof(ca)); +} + +void HistoryScroll::addCells(ca text[], int count) +{ + if (!hasScroll()) return; + cells.add((unsigned char*)text,count*sizeof(ca)); +} + +void HistoryScroll::addLine() +{ + if (!hasScroll()) return; + int locn = cells.len(); + index.add((unsigned char*)&locn,sizeof(int)); +} diff --git a/core/apps/embeddedkonsole/TEHistory.h b/core/apps/embeddedkonsole/TEHistory.h new file mode 100644 index 0000000..8339ec6 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEHistory.h @@ -0,0 +1,75 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TEHistory.H] History Buffer */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef TEHISTORY_H +#define TEHISTORY_H + +#include "TECommon.h" + +/* + An extendable tmpfile(1) based buffer. +*/ +class HistoryBuffer +{ +public: + HistoryBuffer(); + ~HistoryBuffer(); + +public: + void setScroll(bool on); + bool hasScroll(); + +public: + void add(const unsigned char* bytes, int len); + void get(unsigned char* bytes, int len, int loc); + int len(); + +private: + int ion; + int length; +}; + +class HistoryScroll +{ +public: + HistoryScroll(); + ~HistoryScroll(); + +public: + void setScroll(bool on); + bool hasScroll(); + +public: // access to history + int getLines(); + int getLineLen(int lineno); + void getCells(int lineno, int colno, int count, ca res[]); + +public: // backward compatibility (obsolete) + ca getCell(int lineno, int colno) { ca res; getCells(lineno,colno,1,&res); return res; } + +public: // adding lines. + void addCells(ca a[], int count); + void addLine(); + +private: + int startOfLine(int lineno); + HistoryBuffer index; // lines Row(int) + HistoryBuffer cells; // text Row(ca) +}; + +#endif // TEHISTORY_H diff --git a/core/apps/embeddedkonsole/TEScreen.cpp b/core/apps/embeddedkonsole/TEScreen.cpp new file mode 100644 index 0000000..a3d115d --- a/dev/null +++ b/core/apps/embeddedkonsole/TEScreen.cpp @@ -0,0 +1,1197 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TEScreen.C] Screen Data Type */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \file +*/ + +/*! \class TEScreen + + \brief The image manipulated by the emulation. + + This class implements the operations of the terminal emulation framework. + It is a complete passive device, driven by the emulation decoder + (TEmuVT102). By this it forms in fact an ADT, that defines operations + on a rectangular image. + + It does neither know how to display its image nor about escape sequences. + It is further independent of the underlying toolkit. By this, one can even + use this module for an ordinary text surface. + + Since the operations are called by a specific emulation decoder, one may + collect their different operations here. + + The state manipulated by the operations is mainly kept in `image', though + it is a little more complex bejond this. See the header file of the class. + + \sa TEWidget \sa VT102Emulation +*/ + +#include +#include +#include +// #include + +#include +#include +#include + +#include "TEScreen.h" + +#define HERE printf("%s(%d): here\n",__FILE__,__LINE__) + +//FIXME: this is emulation specific. Use FALSE for xterm, TRUE for ANSI. +//FIXME: see if we can get this from terminfo. +#define BS_CLEARS FALSE + +#define loc(X,Y) ((Y)*columns+(X)) + +/*! creates a `TEScreen' of `lines' lines and `columns' columns. +*/ + +TEScreen::TEScreen(int lines, int columns) +{ + this->lines = lines; + this->columns = columns; + + image = (ca*) malloc(lines*columns*sizeof(ca)); + tabstops = NULL; initTabStops(); + + histCursor = 0; + + clearSelection(); + reset(); +} + +/*! Destructor +*/ + +TEScreen::~TEScreen() +{ + free(image); + if (tabstops) free(tabstops); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Normalized Screen Operations */ +/* */ +/* ------------------------------------------------------------------------- */ + +// Cursor Setting -------------------------------------------------------------- + +/*! \section Cursor + + The `cursor' is a location within the screen that is implicitely used in + many operations. The operations within this section allow to manipulate + the cursor explicitly and to obtain it's value. + + The position of the cursor is guarantied to be between (including) 0 and + `columns-1' and `lines-1'. +*/ + +/*! + Move the cursor up. + + The cursor will not be moved beyond the top margin. +*/ + +void TEScreen::cursorUp(int n) +//=CUU +{ + if (n == 0) n = 1; // Default + int stop = cuY < tmargin ? 0 : tmargin; + cuX = QMIN(columns-1,cuX); // nowrap! + cuY = QMAX(stop,cuY-n); +} + +/*! + Move the cursor down. + + The cursor will not be moved beyond the bottom margin. +*/ + +void TEScreen::cursorDown(int n) +//=CUD +{ + if (n == 0) n = 1; // Default + int stop = cuY > bmargin ? lines-1 : bmargin; + cuX = QMIN(columns-1,cuX); // nowrap! + cuY = QMIN(stop,cuY+n); +} + +/*! + Move the cursor left. + + The cursor will not move beyond the first column. +*/ + +void TEScreen::cursorLeft(int n) +//=CUB +{ + if (n == 0) n = 1; // Default + cuX = QMIN(columns-1,cuX); // nowrap! + cuX = QMAX(0,cuX-n); +} + +/*! + Move the cursor left. + + The cursor will not move beyond the rightmost column. +*/ + +void TEScreen::cursorRight(int n) +//=CUF +{ + if (n == 0) n = 1; // Default + cuX = QMIN(columns-1,cuX+n); +} + +/*! + Set top and bottom margin. +*/ + +void TEScreen::setMargins(int top, int bot) +//=STBM +{ + if (top == 0) top = 1; // Default + if (bot == 0) bot = lines; // Default + top = top - 1; // Adjust to internal lineno + bot = bot - 1; // Adjust to internal lineno + if ( !( 0 <= top && top < bot && bot < lines ) ) + { fprintf(stderr,"%s(%d) : setRegion(%d,%d) : bad range.\n", + __FILE__,__LINE__,top,bot); + return; // Default error action: ignore + } + tmargin = top; + bmargin = bot; + cuX = 0; + cuY = getMode(MODE_Origin) ? top : 0; +} + +/*! + Move the cursor down one line. + + If cursor is on bottom margin, the region between the + actual top and bottom margin is scrolled up instead. +*/ + +void TEScreen::index() +//=IND +{ + if (cuY == bmargin) + { + if (tmargin == 0 && bmargin == lines-1) addHistLine(); // hist.history + scrollUp(tmargin,1); + } + else if (cuY < lines-1) + cuY += 1; +} + +/*! + Move the cursor up one line. + + If cursor is on the top margin, the region between the + actual top and bottom margin is scrolled down instead. +*/ + +void TEScreen::reverseIndex() +//=RI +{ + if (cuY == tmargin) + scrollDown(tmargin,1); + else if (cuY > 0) + cuY -= 1; +} + +/*! + Move the cursor to the begin of the next line. + + If cursor is on bottom margin, the region between the + actual top and bottom margin is scrolled up. +*/ + +void TEScreen::NextLine() +//=NEL +{ + Return(); index(); +} + +// Line Editing ---------------------------------------------------------------- + +/*! \section inserting / deleting characters +*/ + +/*! erase `n' characters starting from (including) the cursor position. + + The line is filled in from the right with spaces. +*/ + +void TEScreen::eraseChars(int n) +{ + if (n == 0) n = 1; // Default + int p = QMAX(0,QMIN(cuX+n-1,columns-1)); + clearImage(loc(cuX,cuY),loc(p,cuY),' '); +} + +/*! delete `n' characters starting from (including) the cursor position. + + The line is filled in from the right with spaces. +*/ + +void TEScreen::deleteChars(int n) +{ + if (n == 0) n = 1; // Default + int p = QMAX(0,QMIN(cuX+n,columns-1)); + moveImage(loc(cuX,cuY),loc(p,cuY),loc(columns-1,cuY)); + clearImage(loc(columns-n,cuY),loc(columns-1,cuY),' '); +} + +/*! insert `n' spaces at the cursor position. + + The cursor is not moved by the operation. +*/ + +void TEScreen::insertChars(int n) +{ + if (n == 0) n = 1; // Default + int p = QMAX(0,QMIN(columns-1-n,columns-1)); + int q = QMAX(0,QMIN(cuX+n,columns-1)); + moveImage(loc(q,cuY),loc(cuX,cuY),loc(p,cuY)); + clearImage(loc(cuX,cuY),loc(q-1,cuY),' '); +} + +/*! delete `n' lines starting from (including) the cursor position. + + The cursor is not moved by the operation. +*/ + +void TEScreen::deleteLines(int n) +{ + if (n == 0) n = 1; // Default + scrollUp(cuY,n); +} + +/*! insert `n' lines at the cursor position. + + The cursor is not moved by the operation. +*/ + +void TEScreen::insertLines(int n) +{ + if (n == 0) n = 1; // Default + scrollDown(cuY,n); +} + +// Mode Operations ----------------------------------------------------------- + +/*! Set a specific mode. */ + +void TEScreen::setMode(int m) +{ + currParm.mode[m] = TRUE; + switch(m) + { + case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home + } +} + +/*! Reset a specific mode. */ + +void TEScreen::resetMode(int m) +{ + currParm.mode[m] = FALSE; + switch(m) + { + case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home + } +} + +/*! Save a specific mode. */ + +void TEScreen::saveMode(int m) +{ + saveParm.mode[m] = currParm.mode[m]; +} + +/*! Restore a specific mode. */ + +void TEScreen::restoreMode(int m) +{ + currParm.mode[m] = saveParm.mode[m]; +} + +//NOTE: this is a helper function +/*! Return the setting a specific mode. */ +BOOL TEScreen::getMode(int m) +{ + return currParm.mode[m]; +} + +/*! Save the cursor position and the rendition attribute settings. */ + +void TEScreen::saveCursor() +{ + sa_cuX = cuX; + sa_cuY = cuY; + sa_cu_re = cu_re; + sa_cu_fg = cu_fg; + sa_cu_bg = cu_bg; +} + +/*! Restore the cursor position and the rendition attribute settings. */ + +void TEScreen::restoreCursor() +{ + cuX = QMIN(sa_cuX,columns-1); + cuY = QMIN(sa_cuY,lines-1); + cu_re = sa_cu_re; + cu_fg = sa_cu_fg; + cu_bg = sa_cu_bg; + effectiveRendition(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Screen Operations */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! Assing a new size to the screen. + + The topmost left position is maintained, while lower lines + or right hand side columns might be removed or filled with + spaces to fit the new size. + + The region setting is reset to the whole screen and the + tab positions reinitialized. +*/ + +void TEScreen::resizeImage(int new_lines, int new_columns) +{ + + if (cuY > new_lines-1) + { // attempt to preserve focus and lines + bmargin = lines-1; //FIXME: margin lost + for (int i = 0; i < cuY-(new_lines-1); i++) + { + addHistLine(); scrollUp(0,1); + } + } + + // make new image + ca* newimg = (ca*)malloc(new_lines*new_columns*sizeof(ca)); + + clearSelection(); + + // clear new image + for (int y = 0; y < new_lines; y++) + for (int x = 0; x < new_columns; x++) + { + newimg[y*new_columns+x].c = ' '; + newimg[y*new_columns+x].f = DEFAULT_FORE_COLOR; + newimg[y*new_columns+x].b = DEFAULT_BACK_COLOR; + newimg[y*new_columns+x].r = DEFAULT_RENDITION; + } + int cpy_lines = QMIN(new_lines, lines); + int cpy_columns = QMIN(new_columns,columns); + // copy to new image + for (int y = 0; y < cpy_lines; y++) + for (int x = 0; x < cpy_columns; x++) + { + newimg[y*new_columns+x].c = image[loc(x,y)].c; + newimg[y*new_columns+x].f = image[loc(x,y)].f; + newimg[y*new_columns+x].b = image[loc(x,y)].b; + newimg[y*new_columns+x].r = image[loc(x,y)].r; + } + free(image); + image = newimg; + lines = new_lines; + columns = new_columns; + cuX = QMIN(cuX,columns-1); + cuY = QMIN(cuY,lines-1); + + // FIXME: try to keep values, evtl. + tmargin=0; + bmargin=lines-1; + initTabStops(); + clearSelection(); +} + +/* + Clarifying rendition here and in TEWidget. + + currently, TEWidget's color table is + 0 1 2 .. 9 10 .. 17 + dft_fg, dft_bg, dim 0..7, intensive 0..7 + + cu_fg, cu_bg contain values 0..8; + - 0 = default color + - 1..8 = ansi specified color + + re_fg, re_bg contain values 0..17 + due to the TEWidget's color table + + rendition attributes are + + attr widget screen + -------------- ------ ------ + RE_UNDERLINE XX XX affects foreground only + RE_BLINK XX XX affects foreground only + RE_BOLD XX XX affects foreground only + RE_REVERSE -- XX + RE_TRANSPARENT XX -- affects background only + RE_INTENSIVE XX -- affects foreground only + + Note that RE_BOLD is used in both widget + and screen rendition. Since xterm/vt102 + is to poor to distinguish between bold + (which is a font attribute) and intensive + (which is a color attribute), we translate + this and RE_BOLD in falls eventually appart + into RE_BOLD and RE_INTENSIVE. +*/ + +void TEScreen::reverseRendition(ca* p) +{ UINT8 f = p->f; UINT8 b = p->b; + p->f = b; p->b = f; //p->r &= ~RE_TRANSPARENT; +} + +void TEScreen::effectiveRendition() +// calculate rendition +{ + ef_re = cu_re & (RE_UNDERLINE | RE_BLINK); + if (cu_re & RE_REVERSE) + { + ef_fg = cu_bg; + ef_bg = cu_fg; + } + else + { + ef_fg = cu_fg; + ef_bg = cu_bg; + } + if (cu_re & RE_BOLD) + { + if (ef_fg < BASE_COLORS) + ef_fg += BASE_COLORS; + else + ef_fg -= BASE_COLORS; + } +} + +/*! + returns the image. + + Get the size of the image by \sa getLines and \sa getColumns. + + NOTE that the image returned by this function must later be + freed. + +*/ + +ca* TEScreen::getCookedImage() +{ int x,y; + ca* merged = (ca*)malloc(lines*columns*sizeof(ca)); + ca dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION); + + for (y = 0; (y < lines) && (y < (hist.getLines()-histCursor)); y++) + { + int len = QMIN(columns,hist.getLineLen(y+histCursor)); + int yp = y*columns; + int yq = (y+histCursor)*columns; + + hist.getCells(y+histCursor,0,len,merged+yp); + for (x = len; x < columns; x++) merged[yp+x] = dft; + for (x = 0; x < columns; x++) + { int p=x + yp; int q=x + yq; + if ( ( q >= sel_TL ) && ( q <= sel_BR ) ) + reverseRendition(&merged[p]); // for selection + } + } + if (lines >= hist.getLines()-histCursor) + { + for (y = (hist.getLines()-histCursor); y < lines ; y++) + { + int yp = y*columns; + int yq = (y+histCursor)*columns; + int yr = (y-hist.getLines()+histCursor)*columns; + for (x = 0; x < columns; x++) + { int p = x + yp; int q = x + yq; int r = x + yr; + merged[p] = image[r]; + if ( q >= sel_TL && q <= sel_BR ) + reverseRendition(&merged[p]); // for selection + } + + } + } + // evtl. inverse display + if (getMode(MODE_Screen)) + { int i,n = lines*columns; + for (i = 0; i < n; i++) + reverseRendition(&merged[i]); // for reverse display + } + if (getMode(MODE_Cursor) && (cuY+(hist.getLines()-histCursor) < lines)) // cursor visible + reverseRendition(&merged[loc(cuX,cuY+(hist.getLines()-histCursor))]); + return merged; +} + + +/*! +*/ + +void TEScreen::reset() +{ + setMode(MODE_Wrap ); saveMode(MODE_Wrap ); // wrap at end of margin + resetMode(MODE_Origin); saveMode(MODE_Origin); // position refere to [1,1] + resetMode(MODE_Insert); saveMode(MODE_Insert); // overstroke + setMode(MODE_Cursor); // cursor visible + resetMode(MODE_Screen); // screen not inverse + resetMode(MODE_NewLine); + + tmargin=0; + bmargin=lines-1; + + setDefaultRendition(); + saveCursor(); + + clear(); +} + +/*! Clear the entire screen and home the cursor. +*/ + +void TEScreen::clear() +{ + clearEntireScreen(); + home(); +} + +/*! Moves the cursor left one column. +*/ + +void TEScreen::BackSpace() +{ + cuX = QMAX(0,cuX-1); + if (BS_CLEARS) image[loc(cuX,cuY)].c = ' '; +} + +/*! +*/ + +void TEScreen::Tabulate() +{ + // note that TAB is a format effector (does not write ' '); + cursorRight(1); while(cuX < columns-1 && !tabstops[cuX]) cursorRight(1); +} + +void TEScreen::clearTabStops() +{ + for (int i = 0; i < columns; i++) tabstops[i-1] = FALSE; +} + +void TEScreen::changeTabStop(bool set) +{ + if (cuX >= columns) return; + tabstops[cuX] = set; +} + +void TEScreen::initTabStops() +{ + if (tabstops) free(tabstops); + tabstops = (bool*)malloc(columns*sizeof(bool)); + // Arrg! The 1st tabstop has to be one longer than the other. + // i.e. the kids start counting from 0 instead of 1. + // Other programs might behave correctly. Be aware. + for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0); +} + +/*! + This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine) + depending on the NewLine Mode (LNM). This mode also + affects the key sequence returned for newline ([CR]LF). +*/ + +void TEScreen::NewLine() +{ + if (getMode(MODE_NewLine)) Return(); + index(); +} + +/*! put `c' literally onto the screen at the current cursor position. + + VT100 uses the convention to produce an automatic newline (am) + with the *first* character that would fall onto the next line (xenl). +*/ + +void TEScreen::checkSelection(int from, int to) +{ + if (sel_begin == -1) return; + int scr_TL = loc(0, hist.getLines()); + //Clear entire selection if it overlaps region [from, to] + if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) ) + { + clearSelection(); + } +} + +void TEScreen::ShowCharacter(unsigned short c) +{ + // Note that VT100 does wrapping BEFORE putting the character. + // This has impact on the assumption of valid cursor positions. + // We indicate the fact that a newline has to be triggered by + // putting the cursor one right to the last column of the screen. + + if (cuX >= columns) + { + if (getMode(MODE_Wrap)) NextLine(); else cuX = columns-1; + } + + if (getMode(MODE_Insert)) insertChars(1); + + int i = loc(cuX,cuY); + + checkSelection(i, i); // check if selection is still valid. + + image[i].c = c; + image[i].f = ef_fg; + image[i].b = ef_bg; + image[i].r = ef_re; + + cuX += 1; +} + +// Region commands ------------------------------------------------------------- + + +/*! scroll up `n' lines within current region. + The `n' new lines are cleared. + \sa setRegion \sa scrollDown +*/ + +void TEScreen::scrollUp(int from, int n) +{ + if (n <= 0 || from + n > bmargin) return; + //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. + moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin)); + clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' '); +} + +/*! scroll down `n' lines within current region. + The `n' new lines are cleared. + \sa setRegion \sa scrollUp +*/ + +void TEScreen::scrollDown(int from, int n) +{ +//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. + if (n <= 0) return; + if (from > bmargin) return; + if (from + n > bmargin) n = bmargin - from; + moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n)); + clearImage(loc(0,from),loc(columns-1,from+n-1),' '); +} + +/*! position the cursor to a specific line and column. */ +void TEScreen::setCursorYX(int y, int x) +{ + setCursorY(y); setCursorX(x); +} + +/*! Set the cursor to x-th line. */ + +void TEScreen::setCursorX(int x) +{ + if (x == 0) x = 1; // Default + x -= 1; // Adjust + cuX = QMAX(0,QMIN(columns-1, x)); +} + +/*! Set the cursor to y-th line. */ + +void TEScreen::setCursorY(int y) +{ + if (y == 0) y = 1; // Default + y -= 1; // Adjust + cuY = QMAX(0,QMIN(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) )); +} + +/*! set cursor to the `left upper' corner of the screen (1,1). +*/ + +void TEScreen::home() +{ + cuX = 0; + cuY = 0; +} + +/*! set cursor to the begin of the current line. +*/ + +void TEScreen::Return() +{ + cuX = 0; +} + +/*! returns the current cursor columns. +*/ + +int TEScreen::getCursorX() +{ + return cuX; +} + +/*! returns the current cursor line. +*/ + +int TEScreen::getCursorY() +{ + return cuY; +} + +// Erasing --------------------------------------------------------------------- + +/*! \section Erasing + + This group of operations erase parts of the screen contents by filling + it with spaces colored due to the current rendition settings. + + Althought the cursor position is involved in most of these operations, + it is never modified by them. +*/ + +/*! fill screen between (including) `loca' and `loce' with spaces. + + This is an internal helper functions. The parameter types are internal + addresses of within the screen image and make use of the way how the + screen matrix is mapped to the image vector. +*/ + +void TEScreen::clearImage(int loca, int loce, char c) +{ int i; + int scr_TL=loc(0,hist.getLines()); + //FIXME: check positions + + //Clear entire selection if it overlaps region to be moved... + if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) ) + { + clearSelection(); + } + for (i = loca; i <= loce; i++) + { + image[i].c = c; + image[i].f = ef_fg; //DEFAULT_FORE_COLOR; //FIXME: xterm and linux/ansi + image[i].b = ef_bg; //DEFAULT_BACK_COLOR; // many have different + image[i].r = ef_re; //DEFAULT_RENDITION; // ideas here. + } +} + +/*! move image between (including) `loca' and `loce' to 'dst'. + + This is an internal helper functions. The parameter types are internal + addresses of within the screen image and make use of the way how the + screen matrix is mapped to the image vector. +*/ + +void TEScreen::moveImage(int dst, int loca, int loce) +{ +//FIXME: check positions + if (loce < loca) { + // kdDebug() << "WARNING!!! call to TEScreen:moveImage with loce < loca!" << endl; + return; + } + memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(ca)); +} + +/*! clear from (including) current cursor position to end of screen. +*/ + +void TEScreen::clearToEndOfScreen() +{ + clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' '); +} + +/*! clear from begin of screen to (including) current cursor position. +*/ + +void TEScreen::clearToBeginOfScreen() +{ + clearImage(loc(0,0),loc(cuX,cuY),' '); +} + +/*! clear the entire screen. +*/ + +void TEScreen::clearEntireScreen() +{ + clearImage(loc(0,0),loc(columns-1,lines-1),' '); +} + +/*! fill screen with 'E' + This is to aid screen alignment +*/ + +void TEScreen::helpAlign() +{ + clearImage(loc(0,0),loc(columns-1,lines-1),'E'); +} + +/*! clear from (including) current cursor position to end of current cursor line. +*/ + +void TEScreen::clearToEndOfLine() +{ + clearImage(loc(cuX,cuY),loc(columns-1,cuY),' '); +} + +/*! clear from begin of current cursor line to (including) current cursor position. +*/ + +void TEScreen::clearToBeginOfLine() +{ + clearImage(loc(0,cuY),loc(cuX,cuY),' '); +} + +/*! clears entire current cursor line +*/ + +void TEScreen::clearEntireLine() +{ + clearImage(loc(0,cuY),loc(columns-1,cuY),' '); +} + +// Rendition ------------------------------------------------------------------ + +/*! + set rendition mode +*/ + +void TEScreen::setRendition(int re) +{ + cu_re |= re; + effectiveRendition(); +} + +/*! + reset rendition mode +*/ + +void TEScreen::resetRendition(int re) +{ + cu_re &= ~re; + effectiveRendition(); +} + +/*! +*/ + +void TEScreen::setDefaultRendition() +{ + setForeColorToDefault(); + setBackColorToDefault(); + cu_re = DEFAULT_RENDITION; + effectiveRendition(); +} + +/*! +*/ + +void TEScreen::setForeColor(int fgcolor) +{ + cu_fg = (fgcolor&7)+((fgcolor&8) ? 4+8 : 2); + effectiveRendition(); +} + +/*! +*/ + +void TEScreen::setBackColor(int bgcolor) +{ + cu_bg = (bgcolor&7)+((bgcolor&8) ? 4+8 : 2); + effectiveRendition(); +} + +/*! +*/ + +void TEScreen::setBackColorToDefault() +{ + cu_bg = DEFAULT_BACK_COLOR; + effectiveRendition(); +} + +/*! +*/ + +void TEScreen::setForeColorToDefault() +{ + cu_fg = DEFAULT_FORE_COLOR; + effectiveRendition(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Marking & Selection */ +/* */ +/* ------------------------------------------------------------------------- */ + +void TEScreen::clearSelection() +{ + sel_BR = -1; + sel_TL = -1; + sel_begin = -1; +} + +void TEScreen::setSelBeginXY(const int x, const int y) +{ + sel_begin = loc(x,y+histCursor) ; + sel_BR = sel_begin; + sel_TL = sel_begin; +} + +void TEScreen::setSelExtentXY(const int x, const int y) +{ + if (sel_begin == -1) return; + int l = loc(x,y + histCursor); + + if (l < sel_begin) + { + sel_TL = l; + sel_BR = sel_begin; + } + else + { + /* FIXME, HACK to correct for x too far to the right... */ + if (( x == columns )|| (x == 0)) l--; + + sel_TL = sel_begin; + sel_BR = l; + } +} + +QString TEScreen::getSelText(const BOOL preserve_line_breaks) +{ + if (sel_begin == -1) + return QString::null; // Selection got clear while selecting. + + int *m; // buffer to fill. + int s, d; // source index, dest. index. + int hist_BR = loc(0, hist.getLines()); + int hY = sel_TL / columns; + int hX = sel_TL % columns; + int eol; // end of line + + s = sel_TL; // tracks copy in source. + + // allocate buffer for maximum + // possible size... + d = (sel_BR - sel_TL) / columns + 1; + m = new int[d * (columns + 1) + 2]; + d = 0; + + while (s <= sel_BR) + { + if (s < hist_BR) + { // get lines from hist.history + // buffer. + eol = hist.getLineLen(hY); + + if ((hY == (sel_BR / columns)) && + (eol >= (sel_BR % columns))) + { + eol = sel_BR % columns + 1; + } + + while (hX < eol) + { + m[d++] = hist.getCell(hY, hX++).c; + s++; + } + + if (s <= sel_BR) + { + // The line break handling + // It's different from the screen + // image case! + if (eol % columns == 0) + { + // That's either a completely filled + // line or an empty line + if (eol == 0) + { + m[d++] = '\n'; + } + else + { + // We have a full line. + // FIXME: How can we handle newlines + // at this position?! + } + } + else if ((eol + 1) % columns == 0) + { + // FIXME: We don't know if this was a + // space at the last position or a + // short line!! + m[d++] = ' '; + } + else + { + // We have a short line here. Put a + // newline or a space into the + // buffer. + m[d++] = preserve_line_breaks ? '\n' : ' '; + } + } + + hY++; + hX = 0; + s = hY * columns; + } + else + { // or from screen image. + eol = (s / columns + 1) * columns - 1; + + if (eol < sel_BR) + { + while ((eol > s) && + isspace(image[eol - hist_BR].c)) + { + eol--; + } + } + else + { + eol = sel_BR; + } + + while (s <= eol) + { + m[d++] = image[s++ - hist_BR].c; + } + + if (eol < sel_BR) + { + // eol processing see below ... + if ((eol + 1) % columns == 0) + { + if (image[eol - hist_BR].c == ' ') + { + m[d++] = ' '; + } + } + else + { + m[d++] = ((preserve_line_breaks || + ((eol % columns) == 0)) ? + '\n' : ' '); + } + } + + s = (eol / columns + 1) * columns; + } + } + + QChar* qc = new QChar[d]; + + for (int i = 0; i < d; i++) + { + qc[i] = m[i]; + } + + QString res(qc, d); + + delete m; + delete qc; + + return res; +} +/* above ... end of line processing for selection -- psilva +cases: + +1) (eol+1)%columns == 0 --> the whole line is filled. + If the last char is a space, insert (preserve) space. otherwise + leave the text alone, so that words that are broken by linewrap + are preserved. + +FIXME: + * this suppresses \n for command output that is + sized to the exact column width of the screen. + +2) eol%columns == 0 --> blank line. + insert a \n unconditionally. + Do it either you would because you are in preserve_line_break mode, + or because it's an ASCII paragraph delimiter, so even when + not preserving line_breaks, you want to preserve paragraph breaks. + +3) else --> partially filled line + insert a \n in preserve line break mode, else a space + The space prevents concatenation of the last word of one + line with the first of the next. + +*/ + +void TEScreen::addHistLine() +{ + assert(hasScroll() || histCursor == 0); + + // add to hist buffer + // we have to take care about scrolling, too... + + if (hasScroll()) + { ca dft; + + int end = columns-1; + while (end >= 0 && image[end] == dft) + end -= 1; + + hist.addCells(image,end+1); + hist.addLine(); + + // adjust history cursor + histCursor += (hist.getLines()-1 == histCursor); + } + + if (!hasScroll()) histCursor = 0; //FIXME: a poor workaround +} + +void TEScreen::setHistCursor(int cursor) +{ + histCursor = cursor; //FIXME:rangecheck +} + +int TEScreen::getHistCursor() +{ + return histCursor; +} + +int TEScreen::getHistLines() +{ + return hist.getLines(); +} + +void TEScreen::setScroll(bool on) +{ + histCursor = 0; + clearSelection(); + hist.setScroll(on); +} + +bool TEScreen::hasScroll() +{ + return hist.hasScroll(); +} diff --git a/core/apps/embeddedkonsole/TEScreen.h b/core/apps/embeddedkonsole/TEScreen.h new file mode 100644 index 0000000..ba47ee5 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEScreen.h @@ -0,0 +1,259 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [te_screen.h] Screen Data Type */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef TESCREEN_H +#define TESCREEN_H + +/*! \file +*/ + +#include "TECommon.h" +#include "TEHistory.h" + +#define MODE_Origin 0 +#define MODE_Wrap 1 +#define MODE_Insert 2 +#define MODE_Screen 3 +#define MODE_Cursor 4 +#define MODE_NewLine 5 +#define MODES_SCREEN 6 + +/*! +*/ +struct ScreenParm +{ + int mode[MODES_SCREEN]; +}; + + +class TEScreen +{ +public: + TEScreen(int lines, int columns); + ~TEScreen(); + +public: // these are all `Screen' operations + // + // VT100/2 Operations ------------------ + // + // Cursor Movement + // + void cursorUp (int n); + void cursorDown (int n); + void cursorLeft (int n); + void cursorRight (int n); + void setCursorY (int y); + void setCursorX (int x); + void setCursorYX (int y, int x); + void setMargins (int t, int b); + // + // Cursor Movement with Scrolling + // + void NewLine (); + void NextLine (); + void index (); + void reverseIndex(); + // + void Return (); + void BackSpace (); + void Tabulate (); + // + // Editing + // + void eraseChars (int n); + void deleteChars (int n); + void insertChars (int n); + void deleteLines (int n); + void insertLines (int n); + // + // ------------------------------------- + // + void clearTabStops(); + void changeTabStop(bool set); + // + void resetMode (int n); + void setMode (int n); + void saveMode (int n); + void restoreMode (int n); + // + void saveCursor (); + void restoreCursor(); + // + // ------------------------------------- + // + void clearEntireScreen(); + void clearToEndOfScreen(); + void clearToBeginOfScreen(); + // + void clearEntireLine(); + void clearToEndOfLine(); + void clearToBeginOfLine(); + // + void helpAlign (); + // + // ------------------------------------- + // + void setRendition (int rendition); + void resetRendition(int rendition); + void setForeColor (int fgcolor); + void setBackColor (int bgcolor); + // + void setDefaultRendition(); + void setForeColorToDefault(); + void setBackColorToDefault(); + // + // ------------------------------------- + // + BOOL getMode (int n); + // + // only for report cursor position + // + int getCursorX(); + int getCursorY(); + // + // ------------------------------------- + // + void clear(); + void home(); + void reset(); + // + void ShowCharacter(unsigned short c); + // + void resizeImage(int new_lines, int new_columns); + // + ca* getCookedImage(); + + /*! return the number of lines. */ + int getLines() { return lines; } + /*! return the number of columns. */ + int getColumns() { return columns; } + + /*! set the position of the history cursor. */ + void setHistCursor(int cursor); + /*! return the position of the history cursor. */ + int getHistCursor(); + + int getHistLines (); + void setScroll(bool on); + bool hasScroll(); + + // + // Selection + // + void setSelBeginXY(const int x, const int y); + void setSelExtentXY(const int x, const int y); + void clearSelection(); + QString getSelText(const BOOL preserve_line_breaks); + + void checkSelection(int from, int to); + +private: // helper + + void clearImage(int loca, int loce, char c); + void moveImage(int dst, int loca, int loce); + + void scrollUp(int from, int i); + void scrollDown(int from, int i); + + void addHistLine(); + + void initTabStops(); + + void effectiveRendition(); + void reverseRendition(ca* p); + +private: + + /* + The state of the screen is more complex as one would + expect first. The screem does really do part of the + emulation providing state informations in form of modes, + margins, tabulators, cursor etc. + + Even more unexpected are variables to save and restore + parts of the state. + */ + + // screen image ---------------- + + int lines; + int columns; + ca *image; // [lines][columns] + + // history buffer --------------- + + int histCursor; // display position relative to start of the history buffer + HistoryScroll hist; + + // cursor location + + int cuX; + int cuY; + + // cursor color and rendition info + + UINT8 cu_fg; // foreground + UINT8 cu_bg; // background + UINT8 cu_re; // rendition + + // margins ---------------- + + int tmargin; // top margin + int bmargin; // bottom margin + + // states ---------------- + + ScreenParm currParm; + + // ---------------------------- + + bool* tabstops; + + // selection ------------------- + + int sel_begin; // The first location selected. + int sel_TL; // TopLeft Location. + int sel_BR; // Bottom Right Location. + + // effective colors and rendition ------------ + + UINT8 ef_fg; // These are derived from + UINT8 ef_bg; // the cu_* variables above + UINT8 ef_re; // to speed up operation + + // + // save cursor, rendition & states ------------ + // + + // cursor location + + int sa_cuX; + int sa_cuY; + + // rendition info + + UINT8 sa_cu_re; + UINT8 sa_cu_fg; + UINT8 sa_cu_bg; + + // modes + + ScreenParm saveParm; +}; + +#endif // TESCREEN_H diff --git a/core/apps/embeddedkonsole/TEWidget.cpp b/core/apps/embeddedkonsole/TEWidget.cpp new file mode 100644 index 0000000..dc83998 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEWidget.cpp @@ -0,0 +1,1243 @@ +/* ------------------------------------------------------------------------ */ +/* */ +/* [TEWidget.C] Terminal Emulation Widget */ +/* */ +/* ------------------------------------------------------------------------ */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* ------------------------------------------------------------------------ */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \class TEWidget + + \brief Visible screen contents + + This class is responsible to map the `image' of a terminal emulation to the + display. All the dependency of the emulation to a specific GUI or toolkit is + localized here. Further, this widget has no knowledge about being part of an + emulation, it simply work within the terminal emulation framework by exposing + size and key events and by being ordered to show a new image. + +
    +
  • The internal image has the size of the widget (evtl. rounded up) +
  • The external image used in setImage can have any size. +
  • (internally) the external image is simply copied to the internal + when a setImage happens. During a resizeEvent no painting is done + a paintEvent is expected to follow anyway. +
+ + \sa TEScreen \sa Emulation +*/ + +/* FIXME: + - 'image' may also be used uninitialized (it isn't in fact) in resizeEvent + - 'font_a' not used in mouse events + - add destructor +*/ + +/* TODO + - evtl. be sensitive to `paletteChange' while using default colors. + - set different 'rounding' styles? I.e. have a mode to show clipped chars? +*/ + +// #include "config.h" +#include "TEWidget.h" +#include "session.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +// #include "TEWidget.moc" +//#include +//#include +//#include +//#include +//#include + +#define HERE printf("%s(%d): %s\n",__FILE__,__LINE__,__FUNCTION__) +#define HCNT(Name) // { static int cnt = 1; printf("%s(%d): %s %d\n",__FILE__,__LINE__,Name,cnt++); } + +#define loc(X,Y) ((Y)*columns+(X)) + +//FIXME: the rim should normally be 1, 0 only when running in full screen mode. +#define rimX 0 // left/right rim width +#define rimY 0 // top/bottom rim high + +#define SCRWIDTH 16 // width of the scrollbar + +#define yMouseScroll 1 +// scroll increment used when dragging selection at top/bottom of window. + +/* ------------------------------------------------------------------------- */ +/* */ +/* Colors */ +/* */ +/* ------------------------------------------------------------------------- */ + +//FIXME: the default color table is in session.C now. +// We need a way to get rid of this one, here. +static const ColorEntry base_color_table[TABLE_COLORS] = +// The following are almost IBM standard color codes, with some slight +// gamma correction for the dim colors to compensate for bright X screens. +// It contains the 8 ansiterm/xterm colors in 2 intensities. +{ + // Fixme: could add faint colors here, also. + // normal + ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback + ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red + ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow + ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta + ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White + // intensiv + ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ), + ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ), + ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ), + ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ), + ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 ) +}; + +/* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb) + + Code 0 1 2 3 4 5 6 7 + ----------- ------- ------- ------- ------- ------- ------- ------- ------- + ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White + IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White +*/ + +QColor TEWidget::getDefaultBackColor() +{ + return color_table[DEFAULT_BACK_COLOR].color; +} + +const ColorEntry* TEWidget::getColorTable() const +{ + return color_table; +} + +const QPixmap *TEWidget::backgroundPixmap() +{ + static QPixmap *bg = new QPixmap("~/qpim/main/pics/faded_bg.xpm"); + const QPixmap *pm = bg; + return pm; +} + +void TEWidget::setColorTable(const ColorEntry table[]) +{ + for (int i = 0; i < TABLE_COLORS; i++) color_table[i] = table[i]; + + const QPixmap* pm = backgroundPixmap(); + if (!pm) setBackgroundColor(color_table[DEFAULT_BACK_COLOR].color); + update(); +} + +//FIXME: add backgroundPixmapChanged. + +/* ------------------------------------------------------------------------- */ +/* */ +/* Font */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* + The VT100 has 32 special graphical characters. The usual vt100 extended + xterm fonts have these at 0x00..0x1f. + + QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals + come in here as proper unicode characters. + + We treat non-iso10646 fonts as VT100 extended and do the requiered mapping + from unicode to 0x00..0x1f. The remaining translation is then left to the + QCodec. +*/ + +// assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. + +unsigned short vt100_graphics[32] = +{ // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15 + 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, + 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, + 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534, + 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7 +}; + +static QChar vt100extended(QChar c) +{ + switch (c.unicode()) + { + case 0x25c6 : return 1; + case 0x2592 : return 2; + case 0x2409 : return 3; + case 0x240c : return 4; + case 0x240d : return 5; + case 0x240a : return 6; + case 0x00b0 : return 7; + case 0x00b1 : return 8; + case 0x2424 : return 9; + case 0x240b : return 10; + case 0x2518 : return 11; + case 0x2510 : return 12; + case 0x250c : return 13; + case 0x2514 : return 14; + case 0x253c : return 15; + case 0xf800 : return 16; + case 0xf801 : return 17; + case 0x2500 : return 18; + case 0xf803 : return 19; + case 0xf804 : return 20; + case 0x251c : return 21; + case 0x2524 : return 22; + case 0x2534 : return 23; + case 0x252c : return 24; + case 0x2502 : return 25; + case 0x2264 : return 26; + case 0x2265 : return 27; + case 0x03c0 : return 28; + case 0x2260 : return 29; + case 0x00a3 : return 30; + case 0x00b7 : return 31; + } + return c; +} + +static QChar identicalMap(QChar c) +{ + return c; +} + +void TEWidget::fontChange(const QFont &) +{ + QFontMetrics fm(font()); + font_h = fm.height(); + font_w = fm.maxWidth(); + font_a = fm.ascent(); +//printf("font_h: %d\n",font_h); +//printf("font_w: %d\n",font_w); +//printf("font_a: %d\n",font_a); +//printf("charset: %s\n",QFont::encodingName(font().charSet()).ascii()); +//printf("rawname: %s\n",font().rawName().ascii()); + fontMap = +#if QT_VERSION < 300 + strcmp(QFont::encodingName(font().charSet()).ascii(),"iso10646") + ? vt100extended + : +#endif + identicalMap; + propagateSize(); + update(); +} + +void TEWidget::setVTFont(const QFont& f) +{ + QFrame::setFont(f); +} + +QFont TEWidget::getVTFont() +{ + return font(); +} + +void TEWidget::setFont(const QFont &) +{ + // ignore font change request if not coming from konsole itself +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Constructor / Destructor */ +/* */ +/* ------------------------------------------------------------------------- */ + +TEWidget::TEWidget(QWidget *parent, const char *name) : QFrame(parent,name) +{ +#ifndef QT_NO_CLIPBOARD + cb = QApplication::clipboard(); + QObject::connect( (QObject*)cb, SIGNAL(dataChanged()), + this, SLOT(onClearSelection()) ); +#endif + + scrollbar = new QScrollBar(this); + scrollbar->setCursor( arrowCursor ); + connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); + scrollLoc = SCRNONE; + + blinkT = new QTimer(this); + connect(blinkT, SIGNAL(timeout()), this, SLOT(blinkEvent())); + // blinking = FALSE; + blinking = TRUE; + + resizing = FALSE; + actSel = 0; + image = 0; + lines = 1; + columns = 1; + font_w = 1; + font_h = 1; + font_a = 1; + word_selection_mode = FALSE; + + setMouseMarks(TRUE); + setVTFont( QFont("fixed") ); + setColorTable(base_color_table); // init color table + + qApp->installEventFilter( this ); //FIXME: see below +// KCursor::setAutoHideCursor( this, true ); + + // Init DnD //////////////////////////////////////////////////////////////// + currentSession = NULL; +// setAcceptDrops(true); // attempt +// m_drop = new QPopupMenu(this); +// m_drop->insertItem( QString("Paste"), 0); +// m_drop->insertItem( QString("cd"), 1); +// connect(m_drop, SIGNAL(activated(int)), SLOT(drop_menu_activated(int))); + + // we need focus so that the auto-hide cursor feature works + setFocus(); + setFocusPolicy( WheelFocus ); +} + +//FIXME: make proper destructor +// Here's a start (David) +TEWidget::~TEWidget() +{ + qApp->removeEventFilter( this ); + if (image) free(image); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Display Operations */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! + attributed string draw primitive +*/ + +void TEWidget::drawAttrStr(QPainter &paint, QRect rect, + QString& str, ca attr, BOOL pm, BOOL clear) +{ + if (pm && color_table[attr.b].transparent) + { + paint.setBackgroundMode( TransparentMode ); + if (clear) erase(rect); + } + else + { + if (blinking) + paint.fillRect(rect, color_table[attr.b].color); + else + { + paint.setBackgroundMode( OpaqueMode ); + paint.setBackgroundColor( color_table[attr.b].color ); + } + } + + if (color_table[attr.f].bold) + paint.setPen(QColor( 0x8F, 0x00, 0x00 )); + else + paint.setPen(color_table[attr.f].color); + + paint.drawText(rect.x(),rect.y()+font_a, str); + + if (attr.r & RE_UNDERLINE) + paint.drawLine(rect.left(), rect.y()+font_a+1, rect.right(),rect.y()+font_a+1 ); +} + +/*! + The image can only be set completely. + + The size of the new image may or may not match the size of the widget. +*/ + +void TEWidget::setImage(const ca* const newimg, int lines, int columns) +{ int y,x,len; + const QPixmap* pm = backgroundPixmap(); + QPainter paint; + setUpdatesEnabled(FALSE); + paint.begin( this ); +HCNT("setImage"); + + QPoint tL = contentsRect().topLeft(); + int tLx = tL.x(); + int tLy = tL.y(); + hasBlinker = FALSE; + + int cf = -1; // undefined + int cb = -1; // undefined + int cr = -1; // undefined + + int lins = QMIN(this->lines, QMAX(0,lines )); + int cols = QMIN(this->columns,QMAX(0,columns)); + QChar *disstrU = new QChar[cols]; + +//{ static int cnt = 0; printf("setImage %d\n",cnt++); } + for (y = 0; y < lins; y++) + { + const ca* lcl = &image[y*this->columns]; + const ca* const ext = &newimg[y*columns]; + if (!resizing) // not while resizing, we're expecting a paintEvent + for (x = 0; x < cols; x++) + { + hasBlinker |= (ext[x].r & RE_BLINK); + if (ext[x] != lcl[x]) + { + cr = ext[x].r; + cb = ext[x].b; + if (ext[x].f != cf) cf = ext[x].f; + int lln = cols - x; + disstrU[0] = fontMap(ext[x+0].c); + for (len = 1; len < lln; len++) + { + if (ext[x+len].f != cf || ext[x+len].b != cb || ext[x+len].r != cr || + ext[x+len] == lcl[x+len] ) + break; + disstrU[len] = fontMap(ext[x+len].c); + } + QString unistr(disstrU,len); + drawAttrStr(paint, + QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h), + unistr, ext[x], pm != NULL, true); + x += len - 1; + } + } + // finally, make `image' become `newimg'. + memcpy((void*)lcl,(const void*)ext,cols*sizeof(ca)); + } + drawFrame( &paint ); + paint.end(); + setUpdatesEnabled(TRUE); + if ( hasBlinker && !blinkT->isActive()) blinkT->start(1000); // 1000 ms + if (!hasBlinker && blinkT->isActive()) { blinkT->stop(); blinking = FALSE; } + delete [] disstrU; +} + +// paint Event //////////////////////////////////////////////////// + +/*! + The difference of this routine vs. the `setImage' is, + that the drawing does not include a difference analysis + between the old and the new image. Instead, the internal + image is used and the painting bound by the PaintEvent box. +*/ + +void TEWidget::paintEvent( QPaintEvent* pe ) +{ + +//{ static int cnt = 0; printf("paint %d\n",cnt++); } + const QPixmap* pm = backgroundPixmap(); + QPainter paint; + setUpdatesEnabled(FALSE); + paint.begin( this ); + paint.setBackgroundMode( TransparentMode ); +HCNT("paintEvent"); + + // Note that the actual widget size can be slightly larger + // that the image (the size is truncated towards the smaller + // number of characters in `resizeEvent'. The paint rectangle + // can thus be larger than the image, but less then the size + // of one character. + + QRect rect = pe->rect().intersect(contentsRect()); + + QPoint tL = contentsRect().topLeft(); + int tLx = tL.x(); + int tLy = tL.y(); + + int lux = QMIN(columns-1, QMAX(0,(rect.left() - tLx - blX ) / font_w)); + int luy = QMIN(lines-1, QMAX(0,(rect.top() - tLy - bY ) / font_h)); + int rlx = QMIN(columns-1, QMAX(0,(rect.right() - tLx - blX ) / font_w)); + int rly = QMIN(lines-1, QMAX(0,(rect.bottom() - tLy - bY ) / font_h)); + + /* + printf("paintEvent: %d..%d, %d..%d (%d..%d, %d..%d)\n",lux,rlx,luy,rly, + rect.left(), rect.right(), rect.top(), rect.bottom()); + */ + + // if (pm != NULL && color_table[image->b].transparent) + // erase(rect); + // BL: I have no idea why we need this, and it breaks the refresh. + + QChar *disstrU = new QChar[columns]; + for (int y = luy; y <= rly; y++) + for (int x = lux; x <= rlx; x++) + { + int len = 1; + disstrU[0] = fontMap(image[loc(x,y)].c); + int cf = image[loc(x,y)].f; + int cb = image[loc(x,y)].b; + int cr = image[loc(x,y)].r; + while (x+len <= rlx && + image[loc(x+len,y)].f == cf && + image[loc(x+len,y)].b == cb && + image[loc(x+len,y)].r == cr ) + { + disstrU[len] = fontMap(image[loc(x+len,y)].c); + len += 1; + } + QString unistr(disstrU,len); + drawAttrStr(paint, + QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h), + unistr, image[loc(x,y)], pm != NULL, false); + x += len - 1; + } + delete [] disstrU; + drawFrame( &paint ); + paint.end(); + setUpdatesEnabled(TRUE); +} + +void TEWidget::blinkEvent() +{ + blinking = !blinking; + repaint(FALSE); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Resizing */ +/* */ +/* ------------------------------------------------------------------------- */ + +void TEWidget::resizeEvent(QResizeEvent* ev) +{ + //printf("resize: %d,%d\n",ev->size().width(),ev->size().height()); + //printf("approx: %d,%d\n",ev->size().width()/font_w,ev->size().height()/font_h); + //printf("leaves: %d,%d\n",ev->size().width()%font_w,ev->size().height()%font_h); + //printf("curren: %d,%d\n",width(),height()); +HCNT("resizeEvent"); + + // see comment in `paintEvent' concerning the rounding. + //FIXME: could make a routine here; check width(),height() + assert(ev->size().width() == width()); + assert(ev->size().height() == height()); + + propagateSize(); +} + +void TEWidget::propagateSize() +{ + ca* oldimg = image; + int oldlin = lines; + int oldcol = columns; + makeImage(); + // we copy the old image to reduce flicker + int lins = QMIN(oldlin,lines); + int cols = QMIN(oldcol,columns); + if (oldimg) + { + for (int lin = 0; lin < lins; lin++) + memcpy((void*)&image[columns*lin], + (void*)&oldimg[oldcol*lin],cols*sizeof(ca)); + free(oldimg); //FIXME: try new,delete + } + else + clearImage(); + + //NOTE: control flows from the back through the chest right into the eye. + // `emu' will call back via `setImage'. + + resizing = TRUE; + emit changedImageSizeSignal(lines, columns); // expose resizeEvent + resizing = FALSE; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Scrollbar */ +/* */ +/* ------------------------------------------------------------------------- */ + +void TEWidget::scrollChanged(int) +{ + emit changedHistoryCursor(scrollbar->value()); //expose +} + +void TEWidget::setScroll(int cursor, int slines) +{ + disconnect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); + scrollbar->setRange(0,slines); + scrollbar->setSteps(1,lines); + scrollbar->setValue(cursor); + connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); +} + +void TEWidget::setScrollbarLocation(int loc) +{ + if (scrollLoc == loc) return; // quickly + scrollLoc = loc; + propagateSize(); + update(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Mouse */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! + Three different operations can be performed using the mouse, and the + routines in this section serve all of them: + + 1) The press/release events are exposed to the application + 2) Marking (press and move left button) and Pasting (press middle button) + 3) The right mouse button is used from the configuration menu + + NOTE: During the marking process we attempt to keep the cursor within + the bounds of the text as being displayed by setting the mouse position + whenever the mouse has left the text area. + + Two reasons to do so: + 1) QT does not allow the `grabMouse' to confine-to the TEWidget. + Thus a `XGrapPointer' would have to be used instead. + 2) Even if so, this would not help too much, since the text area + of the TEWidget is normally not identical with it's bounds. + + The disadvantage of the current handling is, that the mouse can visibly + leave the bounds of the widget and is then moved back. Because of the + current construction, and the reasons mentioned above, we cannot do better + without changing the overall construction. +*/ + +/*! +*/ + +void TEWidget::mousePressEvent(QMouseEvent* ev) +{ +//printf("press [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button()); + if ( !contentsRect().contains(ev->pos()) ) return; + QPoint tL = contentsRect().topLeft(); + int tLx = tL.x(); + int tLy = tL.y(); + + word_selection_mode = FALSE; + +//printf("press top left [%d,%d] by=%d\n",tLx,tLy, bY); + if ( ev->button() == LeftButton) + { + QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); + + if ( ev->state() & ControlButton ) preserve_line_breaks = FALSE ; + + if (mouse_marks || (ev->state() & ShiftButton)) + { + emit clearSelectionSignal(); + iPntSel = pntSel = pos; + actSel = 1; // left mouse button pressed but nothing selected yet. + grabMouse( /*crossCursor*/ ); // handle with care! + } + else + { + emit mouseSignal( 0, pos.x() + 1, pos.y() + 1 ); // left button + } + } + if ( ev->button() == MidButton ) + { + emitSelection(); + } + if ( ev->button() == RightButton ) // Configure + { + emit configureRequest( this, ev->state()&(ShiftButton|ControlButton), ev->x(), ev->y() ); + } +} + +void TEWidget::mouseMoveEvent(QMouseEvent* ev) +{ + // for auto-hiding the cursor, we need mouseTracking + if (ev->state() == NoButton ) return; + + if (actSel == 0) return; + + // don't extend selection while pasting + if (ev->state() & MidButton) return; + + //if ( !contentsRect().contains(ev->pos()) ) return; + QPoint tL = contentsRect().topLeft(); + int tLx = tL.x(); + int tLy = tL.y(); + int scroll = scrollbar->value(); + + // we're in the process of moving the mouse with the left button pressed + // the mouse cursor will kept catched within the bounds of the text in + // this widget. + + // Adjust position within text area bounds. See FIXME above. + QPoint pos = ev->pos(); + if ( pos.x() < tLx+blX ) pos.setX( tLx+blX ); + if ( pos.x() > tLx+blX+columns*font_w-1 ) pos.setX( tLx+blX+columns*font_w ); + if ( pos.y() < tLy+bY ) pos.setY( tLy+bY ); + if ( pos.y() > tLy+bY+lines*font_h-1 ) pos.setY( tLy+bY+lines*font_h-1 ); + // check if we produce a mouse move event by this + if ( pos != ev->pos() ) cursor().setPos(mapToGlobal(pos)); + + if ( pos.y() == tLy+bY+lines*font_h-1 ) + { + scrollbar->setValue(scrollbar->value()+yMouseScroll); // scrollforward + } + if ( pos.y() == tLy+bY ) + { + scrollbar->setValue(scrollbar->value()-yMouseScroll); // scrollback + } + + QPoint here = QPoint((pos.x()-tLx-blX)/font_w,(pos.y()-tLy-bY)/font_h); + QPoint ohere; + bool swapping = FALSE; + + if ( word_selection_mode ) + { + // Extend to word boundaries + int i; + int selClass; + + bool left_not_right = ( here.y() < iPntSel.y() || + here.y() == iPntSel.y() && here.x() < iPntSel.x() ); + bool old_left_not_right = ( pntSel.y() < iPntSel.y() || + pntSel.y() == iPntSel.y() && pntSel.x() < iPntSel.x() ); + swapping = left_not_right != old_left_not_right; + + // Find left (left_not_right ? from here : from start) + QPoint left = left_not_right ? here : iPntSel; + i = loc(left.x(),left.y()); + selClass = charClass(image[i].c); + while ( left.x() > 0 && charClass(image[i-1].c) == selClass ) + { i--; left.rx()--; } + + // Find left (left_not_right ? from start : from here) + QPoint right = left_not_right ? iPntSel : here; + i = loc(right.x(),right.y()); + selClass = charClass(image[i].c); + while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass ) + { i++; right.rx()++; } + + // Pick which is start (ohere) and which is extension (here) + if ( left_not_right ) + { + here = left; ohere = right; + } + else + { + here = right; ohere = left; + } + } + + if (here == pntSel && scroll == scrollbar->value()) return; // not moved + + if ( word_selection_mode ) { + if ( actSel < 2 || swapping ) { + emit beginSelectionSignal( ohere.x(), ohere.y() ); + } + } else if ( actSel < 2 ) { + emit beginSelectionSignal( pntSel.x(), pntSel.y() ); + } + + actSel = 2; // within selection + pntSel = here; + emit extendSelectionSignal( here.x(), here.y() ); +} + +void TEWidget::mouseReleaseEvent(QMouseEvent* ev) +{ +//printf("release [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button()); + if ( ev->button() == LeftButton) + { + if ( actSel > 1 ) emit endSelectionSignal(preserve_line_breaks); + preserve_line_breaks = TRUE; + actSel = 0; + + //FIXME: emits a release event even if the mouse is + // outside the range. The procedure used in `mouseMoveEvent' + // applies here, too. + + QPoint tL = contentsRect().topLeft(); + int tLx = tL.x(); + int tLy = tL.y(); + + if (!mouse_marks && !(ev->state() & ShiftButton)) + emit mouseSignal( 3, // release + (ev->x()-tLx-blX)/font_w + 1, + (ev->y()-tLy-bY)/font_h + 1 ); + releaseMouse(); + } +} + +void TEWidget::mouseDoubleClickEvent(QMouseEvent* ev) +{ + if ( ev->button() != LeftButton) return; + + QPoint tL = contentsRect().topLeft(); + int tLx = tL.x(); + int tLy = tL.y(); + QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); + + // pass on double click as two clicks. + if (!mouse_marks && !(ev->state() & ShiftButton)) + { + emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button + emit mouseSignal( 3, pos.x()+1, pos.y()+1 ); // release + emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button + return; + } + + + emit clearSelectionSignal(); + QPoint bgnSel = pos; + QPoint endSel = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); + int i = loc(bgnSel.x(),bgnSel.y()); + iPntSel = bgnSel; + + word_selection_mode = TRUE; + + // find word boundaries... + int selClass = charClass(image[i].c); + { + // set the start... + int x = bgnSel.x(); + while ( x > 0 && charClass(image[i-1].c) == selClass ) + { i--; x--; } + bgnSel.setX(x); + emit beginSelectionSignal( bgnSel.x(), bgnSel.y() ); + + // set the end... + i = loc( endSel.x(), endSel.y() ); + x = endSel.x(); + while( x < columns-1 && charClass(image[i+1].c) == selClass ) + { i++; x++ ; } + endSel.setX(x); + actSel = 2; // within selection + emit extendSelectionSignal( endSel.x(), endSel.y() ); + emit endSelectionSignal(preserve_line_breaks); + preserve_line_breaks = TRUE; + } +} + +void TEWidget::focusInEvent( QFocusEvent * ) +{ + // do nothing, to prevent repainting +} + + +void TEWidget::focusOutEvent( QFocusEvent * ) +{ + // do nothing, to prevent repainting +} + +bool TEWidget::focusNextPrevChild( bool next ) +{ + if (next) + return false; // This disables changing the active part in konqueror + // when pressing Tab + return QFrame::focusNextPrevChild( next ); +} + + +int TEWidget::charClass(char ch) const +{ + // This might seem like overkill, but imagine if ch was a Unicode + // character (Qt 2.0 QChar) - it might then be sensible to separate + // the different language ranges, etc. + + if ( isspace(ch) ) return ' '; + + static const char *word_characters = ":@-./_~"; + if ( isalnum(ch) || strchr(word_characters, ch) ) + return 'a'; + + // Everything else is weird + return 1; +} + +void TEWidget::setMouseMarks(bool on) +{ + mouse_marks = on; + setCursor( mouse_marks ? ibeamCursor : arrowCursor ); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Clipboard */ +/* */ +/* ------------------------------------------------------------------------- */ + +#undef KeyPress + +void TEWidget::emitSelection() +// Paste Clipboard by simulating keypress events +{ +#ifndef QT_NO_CLIPBOARD + QString text = QApplication::clipboard()->text(); + if ( ! text.isNull() ) + { + text.replace(QRegExp("\n"), "\r"); + QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); + emit keyPressedSignal(&e); // expose as a big fat keypress event + emit clearSelectionSignal(); + } +#endif +} + +void TEWidget::emitText(QString text) +{ + QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); + emit keyPressedSignal(&e); // expose as a big fat keypress event +} + +void TEWidget::pasteClipboard( ) +{ + emitSelection(); +} + +void TEWidget::setSelection(const QString& t) +{ +#ifndef QT_NO_CLIPBOARD + // Disconnect signal while WE set the clipboard + QObject *cb = QApplication::clipboard(); + QObject::disconnect( cb, SIGNAL(dataChanged()), + this, SLOT(onClearSelection()) ); + + QApplication::clipboard()->setText(t); + + QObject::connect( cb, SIGNAL(dataChanged()), + this, SLOT(onClearSelection()) ); +#endif +} + +void TEWidget::onClearSelection() +{ + emit clearSelectionSignal(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Keyboard */ +/* */ +/* ------------------------------------------------------------------------- */ + +//FIXME: an `eventFilter' has been installed instead of a `keyPressEvent' +// due to a bug in `QT' or the ignorance of the author to prevent +// repaint events being emitted to the screen whenever one leaves +// or reenters the screen to/from another application. +// +// Troll says one needs to change focusInEvent() and focusOutEvent(), +// which would also let you have an in-focus cursor and an out-focus +// cursor like xterm does. + +// for the auto-hide cursor feature, I added empty focusInEvent() and +// focusOutEvent() so that update() isn't called. +// For auto-hide, we need to get keypress-events, but we only get them when +// we have focus. + +void TEWidget::doScroll(int lines) +{ + scrollbar->setValue(scrollbar->value()+lines); +} + +bool TEWidget::eventFilter( QObject *obj, QEvent *e ) +{ + if ( (e->type() == QEvent::Accel || + e->type() == QEvent::AccelAvailable ) && qApp->focusWidget() == this ) + { + static_cast( e )->ignore(); + return true; + } + if ( obj != this /* when embedded */ && obj != parent() /* when standalone */ ) + return FALSE; // not us + if ( e->type() == QEvent::Wheel) + { + QApplication::sendEvent(scrollbar, e); + } + +#ifdef FAKE_CTRL_AND_ALT + static bool control = FALSE; + static bool alt = FALSE; + // Has a keyboard with no CTRL and ALT keys, but we fake it: + bool dele=FALSE; + if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease ) { + QKeyEvent* ke = (QKeyEvent*)e; + bool keydown = e->type() == QEvent::KeyPress || ke->isAutoRepeat(); + switch (ke->key()) { + case Key_F9: // let this be "Control" + control = keydown; + e = new QKeyEvent(QEvent::KeyPress, Key_Control, 0, ke->state()); + dele=TRUE; + break; + case Key_F13: // let this be "Alt" + alt = keydown; + e = new QKeyEvent(QEvent::KeyPress, Key_Alt, 0, ke->state()); + dele=TRUE; + break; + default: + if ( control ) { + int a = toupper(ke->ascii())-64; + if ( a >= 0 && a < ' ' ) { + e = new QKeyEvent(e->type(), ke->key(), + a, ke->state()|ControlButton, QChar(a,0)); + dele=TRUE; + } + } + if ( alt ) { + e = new QKeyEvent(e->type(), ke->key(), + ke->ascii(), ke->state()|AltButton, ke->text()); + dele=TRUE; + } + } + } +#endif + + if ( e->type() == QEvent::KeyPress ) + { + QKeyEvent* ke = (QKeyEvent*)e; + + actSel=0; // Key stroke implies a screen update, so TEWidget won't + // know where the current selection is. + + emit keyPressedSignal(ke); // expose + ke->accept(); +#ifdef FAKE_CTRL_AND_ALT + if ( dele ) delete e; +#endif + return true; // stop the event + } + if ( e->type() == QEvent::Enter ) + { + QObject::disconnect( (QObject*)cb, SIGNAL(dataChanged()), + this, SLOT(onClearSelection()) ); + } + if ( e->type() == QEvent::Leave ) + { + QObject::connect( (QObject*)cb, SIGNAL(dataChanged()), + this, SLOT(onClearSelection()) ); + } + return QFrame::eventFilter( obj, e ); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Frame */ +/* */ +/* ------------------------------------------------------------------------- */ + +void TEWidget::frameChanged() +{ + propagateSize(); + update(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Sound */ +/* */ +/* ------------------------------------------------------------------------- */ + +void TEWidget::Bell() +{ + QApplication::beep(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Auxiluary */ +/* */ +/* ------------------------------------------------------------------------- */ + +void TEWidget::clearImage() +// initialize the image +// for internal use only +{ + for (int y = 0; y < lines; y++) + for (int x = 0; x < columns; x++) + { + image[loc(x,y)].c = 0xff; //' '; + image[loc(x,y)].f = 0xff; //DEFAULT_FORE_COLOR; + image[loc(x,y)].b = 0xff; //DEFAULT_BACK_COLOR; + image[loc(x,y)].r = 0xff; //DEFAULT_RENDITION; + } +} + +// Create Image /////////////////////////////////////////////////////// + +void TEWidget::calcGeometry() +{ + //FIXME: set rimX == rimY == 0 when running in full screen mode. + + scrollbar->resize(QApplication::style().scrollBarExtent().width(), + contentsRect().height()); + switch(scrollLoc) + { + case SCRNONE : + columns = ( contentsRect().width() - 2 * rimX ) / font_w; + blX = (contentsRect().width() - (columns*font_w) ) / 2; + brX = blX; + scrollbar->hide(); + break; + case SCRLEFT : + columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; + brX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; + blX = brX + scrollbar->width(); + scrollbar->move(contentsRect().topLeft()); + scrollbar->show(); + break; + case SCRRIGHT: + columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; + blX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; + brX = blX; + scrollbar->move(contentsRect().topRight() - QPoint(scrollbar->width()-1,0)); + scrollbar->show(); + break; + } + //FIXME: support 'rounding' styles + lines = ( contentsRect().height() - 2 * rimY ) / font_h; + bY = (contentsRect().height() - (lines *font_h)) / 2; +} + +void TEWidget::makeImage() +//FIXME: rename 'calcGeometry? +{ + calcGeometry(); + image = (ca*) malloc(lines*columns*sizeof(ca)); + clearImage(); +} + +// calculate the needed size +QSize TEWidget::calcSize(int cols, int lins) const +{ + int frw = width() - contentsRect().width(); + int frh = height() - contentsRect().height(); + int scw = (scrollLoc==SCRNONE?0:scrollbar->width()); + return QSize( font_w*cols + 2*rimX + frw + scw, font_h*lins + 2*rimY + frh ); +} + +QSize TEWidget::sizeHint() const +{ + return size(); +} + +void TEWidget::styleChange(QStyle &) +{ + propagateSize(); +} + +#ifndef QT_NO_DRAGANDDROP + +/* --------------------------------------------------------------------- */ +/* */ +/* Drag & Drop */ +/* */ +/* --------------------------------------------------------------------- */ + + +void TEWidget::dragEnterEvent(QDragEnterEvent* e) +{ + e->accept(QTextDrag::canDecode(e) || + QUriDrag::canDecode(e)); +} + +void TEWidget::dropEvent(QDropEvent* event) +{ + // The current behaviour when url(s) are dropped is + // * if there is only ONE url and if it's a LOCAL one, ask for paste or cd + // * in all other cases, just paste + // (for non-local ones, or for a list of URLs, 'cd' is nonsense) + QStrList strlist; + int file_count = 0; + dropText = ""; + bool bPopup = true; + + if(QUriDrag::decode(event, strlist)) { + if (strlist.count()) { + for(const char* p = strlist.first(); p; p = strlist.next()) { + if(file_count++ > 0) { + dropText += " "; + bPopup = false; // more than one file, don't popup + } + +/* + KURL url(p); + if (url.isLocalFile()) { + dropText += url.path(); // local URL : remove protocol + } + else { + dropText += url.prettyURL(); + bPopup = false; // a non-local file, don't popup + } +*/ + + } + + if (bPopup) + // m_drop->popup(pos() + event->pos()); + m_drop->popup(mapToGlobal(event->pos())); + else + { + if (currentSession) { + currentSession->getEmulation()->sendString(dropText.local8Bit()); + } +// kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; + } + } + } + else if(QTextDrag::decode(event, dropText)) { +// kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; + if (currentSession) { + currentSession->getEmulation()->sendString(dropText.local8Bit()); + } + // Paste it + } +} +#endif + + +void TEWidget::drop_menu_activated(int item) +{ +#ifndef QT_NO_DRAGANDDROP + switch (item) + { + case 0: // paste + currentSession->getEmulation()->sendString(dropText.local8Bit()); +// KWM::activate((Window)this->winId()); + break; + case 1: // cd ... + currentSession->getEmulation()->sendString("cd "); + struct stat statbuf; + if ( ::stat( QFile::encodeName( dropText ), &statbuf ) == 0 ) + { + if ( !S_ISDIR(statbuf.st_mode) ) + { +/* + KURL url; + url.setPath( dropText ); + dropText = url.directory( true, false ); // remove filename +*/ + } + } + dropText.replace(QRegExp(" "), "\\ "); // escape spaces + currentSession->getEmulation()->sendString(dropText.local8Bit()); + currentSession->getEmulation()->sendString("\n"); +// KWM::activate((Window)this->winId()); + break; + } +#endif +} + diff --git a/core/apps/embeddedkonsole/TEWidget.h b/core/apps/embeddedkonsole/TEWidget.h new file mode 100644 index 0000000..3f9f4ae --- a/dev/null +++ b/core/apps/embeddedkonsole/TEWidget.h @@ -0,0 +1,202 @@ +/* ----------------------------------------------------------------------- */ +/* */ +/* [te_widget.h] Terminal Emulation Widget */ +/* */ +/* ----------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* ----------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef TE_WIDGET_H +#define TE_WIDGET_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "TECommon.h" + +extern unsigned short vt100_graphics[32]; + +class TESession; + +// class Konsole; + +class TEWidget : public QFrame +// a widget representing attributed text +{ Q_OBJECT + +// friend class Konsole; + +public: + + TEWidget(QWidget *parent=0, const char *name=0); + virtual ~TEWidget(); + +public: + + QColor getDefaultBackColor(); + + const ColorEntry* getColorTable() const; + void setColorTable(const ColorEntry table[]); + + void setScrollbarLocation(int loc); + enum { SCRNONE=0, SCRLEFT=1, SCRRIGHT=2 }; + + void setScroll(int cursor, int lines); + void doScroll(int lines); + + void emitSelection(); + +public: + + void setImage(const ca* const newimg, int lines, int columns); + + int Lines() { return lines; } + int Columns() { return columns; } + + void calcGeometry(); + void propagateSize(); + QSize calcSize(int cols, int lins) const; + + QSize sizeHint() const; + +public: + + void Bell(); + void emitText(QString text); + void pasteClipboard(); + +signals: + + void keyPressedSignal(QKeyEvent *e); + void mouseSignal(int cb, int cx, int cy); + void changedImageSizeSignal(int lines, int columns); + void changedHistoryCursor(int value); + void configureRequest( TEWidget*, int state, int x, int y ); + + void clearSelectionSignal(); + void beginSelectionSignal( const int x, const int y ); + void extendSelectionSignal( const int x, const int y ); + void endSelectionSignal(const BOOL preserve_line_breaks); + + +protected: + + virtual void styleChange( QStyle& ); + + bool eventFilter( QObject *, QEvent * ); + + void drawAttrStr(QPainter &paint, QRect rect, + QString& str, ca attr, BOOL pm, BOOL clear); + void paintEvent( QPaintEvent * ); + + void resizeEvent(QResizeEvent*); + + void fontChange(const QFont &font); + void frameChanged(); + + void mouseDoubleClickEvent(QMouseEvent* ev); + void mousePressEvent( QMouseEvent* ); + void mouseReleaseEvent( QMouseEvent* ); + void mouseMoveEvent( QMouseEvent* ); + + void focusInEvent( QFocusEvent * ); + void focusOutEvent( QFocusEvent * ); + bool focusNextPrevChild( bool next ); + +#ifndef QT_NO_DRAGANDDROP + // Dnd + void dragEnterEvent(QDragEnterEvent* event); + void dropEvent(QDropEvent* event); +#endif + + virtual int charClass(char) const; + + void clearImage(); + +public: + const QPixmap *backgroundPixmap(); + + void setSelection(const QString &t); + + virtual void setFont(const QFont &); + void setVTFont(const QFont &); + QFont getVTFont(); + + void setMouseMarks(bool on); + +public slots: + + void onClearSelection(); + +protected slots: + + void scrollChanged(int value); + void blinkEvent(); + +private: + + QChar (*fontMap)(QChar); // possible vt100 font extention + + bool fixed_font; // has fixed pitch + int font_h; // height + int font_w; // width + int font_a; // ascend + + int blX; // actual offset (left) + int brX; // actual offset (right) + int bY; // actual offset + + int lines; + int columns; + ca *image; // [lines][columns] + + ColorEntry color_table[TABLE_COLORS]; + + BOOL resizing; + bool mouse_marks; + + void makeImage(); + + QPoint iPntSel; // initial selection point + QPoint pntSel; // current selection point + int actSel; // selection state + BOOL word_selection_mode; + BOOL preserve_line_breaks; + + QClipboard* cb; + QScrollBar* scrollbar; + int scrollLoc; + +//#define SCRNONE 0 +//#define SCRLEFT 1 +//#define SCRRIGHT 2 + + BOOL blinking; // hide text in paintEvent + BOOL hasBlinker; // has characters to blink + QTimer* blinkT; // active when hasBlinker + QPopupMenu* m_drop; + QString dropText; + public: + // current session in this widget + TESession *currentSession; +private slots: + void drop_menu_activated(int item); +}; + +#endif // TE_WIDGET_H diff --git a/core/apps/embeddedkonsole/TEmuVt102.cpp b/core/apps/embeddedkonsole/TEmuVt102.cpp new file mode 100644 index 0000000..752c49f --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmuVt102.cpp @@ -0,0 +1,991 @@ +/* ------------------------------------------------------------------------- */ +/* */ +/* [TEmuVt102.C] VT102 Terminal Emulation */ +/* */ +/* ------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* ------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \class TEmuVt102 + + \brief Actual Emulation for Konsole + + \sa TEWidget \sa TEScreen +*/ + +#include "TEmuVt102.h" +#include "TEWidget.h" +#include "TEScreen.h" +#include "keytrans.h" + +#include +#include +#include +#include + + +/* VT102 Terminal Emulation + + This class puts together the screens, the pty and the widget to a + complete terminal emulation. Beside combining it's componentes, it + handles the emulations's protocol. + + This module consists of the following sections: + + - Constructor/Destructor + - Incoming Bytes Event pipeline + - Outgoing Bytes + - Mouse Events + - Keyboard Events + - Modes and Charset State + - Diagnostics +*/ + + +/* ------------------------------------------------------------------------- */ +/* */ +/* Constructor / Destructor */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* + Nothing really intesting happens here. +*/ + +/*! +*/ + +TEmuVt102::TEmuVt102(TEWidget* gui) : TEmulation(gui) +{ + QObject::connect(gui,SIGNAL(mouseSignal(int,int,int)), + this,SLOT(onMouse(int,int,int))); + initTokenizer(); + reset(); +} + +/*! +*/ + +TEmuVt102::~TEmuVt102() +{ +} + +/*! +*/ + +void TEmuVt102::reset() +{ + resetToken(); + resetModes(); + resetCharset(0); screen[0]->reset(); + resetCharset(1); screen[0]->reset(); + setCodec(0); + setKeytrans("linux.keytab"); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Processing the incoming byte stream */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* Incoming Bytes Event pipeline + + This section deals with decoding the incoming character stream. + Decoding means here, that the stream is first seperated into `tokens' + which are then mapped to a `meaning' provided as operations by the + `TEScreen' class or by the emulation class itself. + + The pipeline proceeds as follows: + + - Tokenizing the ESC codes (onRcvChar) + - VT100 code page translation of plain characters (applyCharset) + - Interpretation of ESC codes (tau) + + The escape codes and their meaning are described in the + technical reference of this program. +*/ + +// Tokens ------------------------------------------------------------------ -- + +/* + Since the tokens are the central notion if this section, we've put them + in front. They provide the syntactical elements used to represent the + terminals operations as byte sequences. + + They are encodes here into a single machine word, so that we can later + switch over them easily. Depending on the token itself, additional + argument variables are filled with parameter values. + + The tokens are defined below: + + - CHR - Printable characters (32..255 but DEL (=127)) + - CTL - Control characters (0..31 but ESC (= 27), DEL) + - ESC - Escape codes of the form + - ESC_DE - Escape codes of the form C + - CSI_PN - Escape codes of the form '[' {Pn} ';' {Pn} C + - CSI_PS - Escape codes of the form '[' {Pn} ';' ... C + - CSI_PR - Escape codes of the form '[' '?' {Pn} ';' ... C + - VT52 - VT52 escape codes + - + - 'Y'{Pc}{Pc} + - XTE_HA - Xterm hacks `]' {Pn} `;' {Text} + note that this is handled differently + + The last two forms allow list of arguments. Since the elements of + the lists are treated individually the same way, they are passed + as individual tokens to the interpretation. Further, because the + meaning of the parameters are names (althought represented as numbers), + they are includes within the token ('N'). + +*/ + +#define TY_CONSTR(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) ) + +#define TY_CHR___( ) TY_CONSTR(0,0,0) +#define TY_CTL___(A ) TY_CONSTR(1,A,0) +#define TY_ESC___(A ) TY_CONSTR(2,A,0) +#define TY_ESC_CS(A,B) TY_CONSTR(3,A,B) +#define TY_ESC_DE(A ) TY_CONSTR(4,A,0) +#define TY_CSI_PS(A,N) TY_CONSTR(5,A,N) +#define TY_CSI_PN(A ) TY_CONSTR(6,A,0) +#define TY_CSI_PR(A,N) TY_CONSTR(7,A,N) + +#define TY_VT52__(A ) TY_CONSTR(8,A,0) + +// Tokenizer --------------------------------------------------------------- -- + +/* The tokenizers state + + The state is represented by the buffer (pbuf, ppos), + and accompanied by decoded arguments kept in (argv,argc). + Note that they are kept internal in the tokenizer. +*/ + +void TEmuVt102::resetToken() +{ + ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0; +} + +void TEmuVt102::addDigit(int dig) +{ + argv[argc] = 10*argv[argc] + dig; +} + +void TEmuVt102::addArgument() +{ + argc = QMIN(argc+1,MAXARGS-1); + argv[argc] = 0; +} + +void TEmuVt102::pushToToken(int cc) +{ + pbuf[ppos] = cc; + ppos = QMIN(ppos+1,MAXPBUF-1); +} + +// Character Classes used while decoding + +#define CTL 1 +#define CHR 2 +#define CPN 4 +#define DIG 8 +#define SCS 16 +#define GRP 32 + +void TEmuVt102::initTokenizer() +{ int i; UINT8* s; + for(i = 0; i < 256; i++) tbl[ i] = 0; + for(i = 0; i < 32; i++) tbl[ i] |= CTL; + for(i = 32; i < 256; i++) tbl[ i] |= CHR; + for(s = (UINT8*)"@ABCDGHLMPXcdfry"; *s; s++) tbl[*s] |= CPN; + for(s = (UINT8*)"0123456789" ; *s; s++) tbl[*s] |= DIG; + for(s = (UINT8*)"()+*%" ; *s; s++) tbl[*s] |= SCS; + for(s = (UINT8*)"()+*#[]%" ; *s; s++) tbl[*s] |= GRP; + resetToken(); +} + +/* Ok, here comes the nasty part of the decoder. + + Instead of keeping an explicit state, we deduce it from the + token scanned so far. It is then immediately combined with + the current character to form a scanning decision. + + This is done by the following defines. + + - P is the length of the token scanned so far. + - L (often P-1) is the position on which contents we base a decision. + - C is a character or a group of characters (taken from 'tbl'). + + Note that they need to applied in proper order. +*/ + +#define lec(P,L,C) (p == (P) && s[(L)] == (C)) +#define lun( ) (p == 1 && cc >= 32 ) +#define les(P,L,C) (p == (P) && s[L] < 256 && (tbl[s[(L)]] & (C)) == (C)) +#define eec(C) (p >= 3 && cc == (C)) +#define ees(C) (p >= 3 && cc < 256 && (tbl[ cc ] & (C)) == (C)) +#define eps(C) (p >= 3 && s[2] != '?' && cc < 256 && (tbl[ cc ] & (C)) == (C)) +#define epp( ) (p >= 3 && s[2] == '?' ) +#define egt( ) (p == 3 && s[2] == '>' ) +#define Xpe (ppos>=2 && pbuf[1] == ']' ) +#define Xte (Xpe && cc == 7 ) +#define ces(C) ( cc < 256 && (tbl[ cc ] & (C)) == (C) && !Xte) + +#define ESC 27 +#define CNTL(c) ((c)-'@') + +// process an incoming unicode character + +void TEmuVt102::onRcvChar(int cc) +{ int i; + + if (cc == 127) return; //VT100: ignore. + + if (ces( CTL)) + { // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100 + // This means, they do neither a resetToken nor a pushToToken. Some of them, do + // of course. Guess this originates from a weakly layered handling of the X-on + // X-off protocol, which comes really below this level. + if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) resetToken(); //VT100: CAN or SUB + if (cc != ESC) { tau( TY_CTL___(cc+'@' ), 0, 0); return; } + } + + pushToToken(cc); // advance the state + + int* s = pbuf; + int p = ppos; + + if (getMode(MODE_Ansi)) // decide on proper action + { + if (lec(1,0,ESC)) { return; } + if (les(2,1,GRP)) { return; } + if (Xte ) { XtermHack(); resetToken(); return; } + if (Xpe ) { return; } + if (lec(3,2,'?')) { return; } + if (lec(3,2,'>')) { return; } + if (lun( )) { tau( TY_CHR___(), applyCharset(cc), 0); resetToken(); return; } + if (lec(2,0,ESC)) { tau( TY_ESC___(s[1]), 0, 0); resetToken(); return; } + if (les(3,1,SCS)) { tau( TY_ESC_CS(s[1],s[2]), 0, 0); resetToken(); return; } + if (lec(3,1,'#')) { tau( TY_ESC_DE(s[2]), 0, 0); resetToken(); return; } +// if (egt( )) { tau( TY_CSI_PG(cc ), '>', 0); resetToken(); return; } + if (eps( CPN)) { tau( TY_CSI_PN(cc), argv[0],argv[1]); resetToken(); return; } + if (ees( DIG)) { addDigit(cc-'0'); return; } + if (eec( ';')) { addArgument(); return; } + for (i=0;i<=argc;i++) + if (epp( )) tau( TY_CSI_PR(cc,argv[i]), 0, 0); else + tau( TY_CSI_PS(cc,argv[i]), 0, 0); + resetToken(); + } + else // mode VT52 + { + if (lec(1,0,ESC)) return; + if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); resetToken(); return; } + if (lec(2,1,'Y')) return; + if (lec(3,1,'Y')) return; + if (p < 4) { tau( TY_VT52__(s[1] ), 0, 0); resetToken(); return; } + tau( TY_VT52__(s[1] ), s[2],s[3]); resetToken(); return; + } +} + +void TEmuVt102::XtermHack() +{ int i,arg = 0; + for (i = 2; i < ppos && '0'<=pbuf[i] && pbuf[i]<'9' ; i++) + arg = 10*arg + (pbuf[i]-'0'); + if (pbuf[i] != ';') { ReportErrorToken(); return; } + QChar *str = new QChar[ppos-i-2]; + for (int j = 0; j < ppos-i-2; j++) str[j] = pbuf[i+1+j]; + QString unistr(str,ppos-i-2); + // arg == 1 doesn't change the title. In XTerm it only changes the icon name + // (btw: arg=0 changes title and icon, arg=1 only icon, arg=2 only title + if (arg == 0 || arg == 2) emit changeTitle(arg,unistr); + delete [] str; +} + +// Interpreting Codes --------------------------------------------------------- + +/* + Now that the incoming character stream is properly tokenized, + meaning is assigned to them. These are either operations of + the current screen, or of the emulation class itself. + + The token to be interpreteted comes in as a machine word + possibly accompanied by two parameters. + + Likewise, the operations assigned to, come with up to two + arguments. One could consider to make up a proper table + from the function below. + + The technical reference manual provides more informations + about this mapping. +*/ + +void TEmuVt102::tau( int token, int p, int q ) +{ +//scan_buffer_report(); +//if (token == TY_CHR___()) printf("%c",p); else +//printf("tau(%d,%d,%d, %d,%d)\n",(token>>0)&0xff,(token>>8)&0xff,(token>>16)&0xffff,p,q); + switch (token) + { + + case TY_CHR___( ) : scr->ShowCharacter (p ); break; //UTF16 + + // 127 DEL : ignored on input + + case TY_CTL___('@' ) : /* NUL: ignored */ break; + case TY_CTL___('A' ) : /* SOH: ignored */ break; + case TY_CTL___('B' ) : /* STX: ignored */ break; + case TY_CTL___('C' ) : /* ETX: ignored */ break; + case TY_CTL___('D' ) : /* EOT: ignored */ break; + case TY_CTL___('E' ) : reportAnswerBack ( ); break; //VT100 + case TY_CTL___('F' ) : /* ACK: ignored */ break; + case TY_CTL___('G' ) : gui->Bell ( ); break; //VT100 + case TY_CTL___('H' ) : scr->BackSpace ( ); break; //VT100 + case TY_CTL___('I' ) : scr->Tabulate ( ); break; //VT100 + case TY_CTL___('J' ) : scr->NewLine ( ); break; //VT100 + case TY_CTL___('K' ) : scr->NewLine ( ); break; //VT100 + case TY_CTL___('L' ) : scr->NewLine ( ); break; //VT100 + case TY_CTL___('M' ) : scr->Return ( ); break; //VT100 + + case TY_CTL___('N' ) : useCharset ( 1); break; //VT100 + case TY_CTL___('O' ) : useCharset ( 0); break; //VT100 + + case TY_CTL___('P' ) : /* DLE: ignored */ break; + case TY_CTL___('Q' ) : /* DC1: XON continue */ break; //VT100 + case TY_CTL___('R' ) : /* DC2: ignored */ break; + case TY_CTL___('S' ) : /* DC3: XOFF halt */ break; //VT100 + case TY_CTL___('T' ) : /* DC4: ignored */ break; + case TY_CTL___('U' ) : /* NAK: ignored */ break; + case TY_CTL___('V' ) : /* SYN: ignored */ break; + case TY_CTL___('W' ) : /* ETB: ignored */ break; + case TY_CTL___('X' ) : scr->ShowCharacter ( 0x2592); break; //VT100 + case TY_CTL___('Y' ) : /* EM : ignored */ break; + case TY_CTL___('Z' ) : scr->ShowCharacter ( 0x2592); break; //VT100 + case TY_CTL___('[' ) : /* ESC: cannot be seen here. */ break; + case TY_CTL___('\\' ) : /* FS : ignored */ break; + case TY_CTL___(']' ) : /* GS : ignored */ break; + case TY_CTL___('^' ) : /* RS : ignored */ break; + case TY_CTL___('_' ) : /* US : ignored */ break; + + case TY_ESC___('D' ) : scr->index ( ); break; //VT100 + case TY_ESC___('E' ) : scr->NextLine ( ); break; //VT100 + case TY_ESC___('H' ) : scr->changeTabStop (TRUE ); break; //VT100 + case TY_ESC___('M' ) : scr->reverseIndex ( ); break; //VT100 + case TY_ESC___('Z' ) : reportTerminalType ( ); break; + case TY_ESC___('c' ) : reset ( ); break; + + case TY_ESC___('n' ) : useCharset ( 2); break; + case TY_ESC___('o' ) : useCharset ( 3); break; + case TY_ESC___('7' ) : saveCursor ( ); break; + case TY_ESC___('8' ) : restoreCursor ( ); break; + + case TY_ESC___('=' ) : setMode (MODE_AppKeyPad); break; + case TY_ESC___('>' ) : resetMode (MODE_AppKeyPad); break; + case TY_ESC___('<' ) : setMode (MODE_Ansi ); break; //VT100 + + case TY_ESC_CS('(', '0') : setCharset (0, '0'); break; //VT100 + case TY_ESC_CS('(', 'A') : setCharset (0, 'A'); break; //VT100 + case TY_ESC_CS('(', 'B') : setCharset (0, 'B'); break; //VT100 + + case TY_ESC_CS(')', '0') : setCharset (1, '0'); break; //VT100 + case TY_ESC_CS(')', 'A') : setCharset (1, 'A'); break; //VT100 + case TY_ESC_CS(')', 'B') : setCharset (1, 'B'); break; //VT100 + + case TY_ESC_CS('*', '0') : setCharset (2, '0'); break; //VT100 + case TY_ESC_CS('*', 'A') : setCharset (2, 'A'); break; //VT100 + case TY_ESC_CS('*', 'B') : setCharset (2, 'B'); break; //VT100 + + case TY_ESC_CS('+', '0') : setCharset (3, '0'); break; //VT100 + case TY_ESC_CS('+', 'A') : setCharset (3, 'A'); break; //VT100 + case TY_ESC_CS('+', 'B') : setCharset (3, 'B'); break; //VT100 + + case TY_ESC_CS('%', 'G') : setCodec (1 ); break; //LINUX + case TY_ESC_CS('%', '@') : setCodec (0 ); break; //LINUX + + case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break; + case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break; + case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break; + case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break; + case TY_ESC_DE('8' ) : scr->helpAlign ( ); break; + + case TY_CSI_PS('K', 0) : scr->clearToEndOfLine ( ); break; + case TY_CSI_PS('K', 1) : scr->clearToBeginOfLine ( ); break; + case TY_CSI_PS('K', 2) : scr->clearEntireLine ( ); break; + case TY_CSI_PS('J', 0) : scr->clearToEndOfScreen ( ); break; + case TY_CSI_PS('J', 1) : scr->clearToBeginOfScreen ( ); break; + case TY_CSI_PS('J', 2) : scr->clearEntireScreen ( ); break; + case TY_CSI_PS('g', 0) : scr->changeTabStop (FALSE ); break; //VT100 + case TY_CSI_PS('g', 3) : scr->clearTabStops ( ); break; //VT100 + case TY_CSI_PS('h', 4) : scr-> setMode (MODE_Insert ); break; + case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break; + case TY_CSI_PS('i', 0) : /* IGNORE: attached printer */ break; //VT100 + case TY_CSI_PS('l', 4) : scr-> resetMode (MODE_Insert ); break; + case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break; + + case TY_CSI_PS('m', 0) : scr->setDefaultRendition ( ); break; + case TY_CSI_PS('m', 1) : scr-> setRendition (RE_BOLD ); break; //VT100 + case TY_CSI_PS('m', 4) : scr-> setRendition (RE_UNDERLINE); break; //VT100 + case TY_CSI_PS('m', 5) : scr-> setRendition (RE_BLINK ); break; //VT100 + case TY_CSI_PS('m', 7) : scr-> setRendition (RE_REVERSE ); break; + case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX + case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX + case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX + case TY_CSI_PS('m', 22) : scr->resetRendition (RE_BOLD ); break; + case TY_CSI_PS('m', 24) : scr->resetRendition (RE_UNDERLINE); break; + case TY_CSI_PS('m', 25) : scr->resetRendition (RE_BLINK ); break; + case TY_CSI_PS('m', 27) : scr->resetRendition (RE_REVERSE ); break; + + case TY_CSI_PS('m', 30) : scr->setForeColor ( 0); break; + case TY_CSI_PS('m', 31) : scr->setForeColor ( 1); break; + case TY_CSI_PS('m', 32) : scr->setForeColor ( 2); break; + case TY_CSI_PS('m', 33) : scr->setForeColor ( 3); break; + case TY_CSI_PS('m', 34) : scr->setForeColor ( 4); break; + case TY_CSI_PS('m', 35) : scr->setForeColor ( 5); break; + case TY_CSI_PS('m', 36) : scr->setForeColor ( 6); break; + case TY_CSI_PS('m', 37) : scr->setForeColor ( 7); break; + case TY_CSI_PS('m', 39) : scr->setForeColorToDefault( ); break; + + case TY_CSI_PS('m', 40) : scr->setBackColor ( 0); break; + case TY_CSI_PS('m', 41) : scr->setBackColor ( 1); break; + case TY_CSI_PS('m', 42) : scr->setBackColor ( 2); break; + case TY_CSI_PS('m', 43) : scr->setBackColor ( 3); break; + case TY_CSI_PS('m', 44) : scr->setBackColor ( 4); break; + case TY_CSI_PS('m', 45) : scr->setBackColor ( 5); break; + case TY_CSI_PS('m', 46) : scr->setBackColor ( 6); break; + case TY_CSI_PS('m', 47) : scr->setBackColor ( 7); break; + case TY_CSI_PS('m', 49) : scr->setBackColorToDefault( ); break; + + case TY_CSI_PS('m', 90) : scr->setForeColor ( 8); break; + case TY_CSI_PS('m', 91) : scr->setForeColor ( 9); break; + case TY_CSI_PS('m', 92) : scr->setForeColor ( 10); break; + case TY_CSI_PS('m', 93) : scr->setForeColor ( 11); break; + case TY_CSI_PS('m', 94) : scr->setForeColor ( 12); break; + case TY_CSI_PS('m', 95) : scr->setForeColor ( 13); break; + case TY_CSI_PS('m', 96) : scr->setForeColor ( 14); break; + case TY_CSI_PS('m', 97) : scr->setForeColor ( 15); break; + + case TY_CSI_PS('m', 100) : scr->setBackColor ( 8); break; + case TY_CSI_PS('m', 101) : scr->setBackColor ( 9); break; + case TY_CSI_PS('m', 102) : scr->setBackColor ( 10); break; + case TY_CSI_PS('m', 103) : scr->setBackColor ( 11); break; + case TY_CSI_PS('m', 104) : scr->setBackColor ( 12); break; + case TY_CSI_PS('m', 105) : scr->setBackColor ( 13); break; + case TY_CSI_PS('m', 106) : scr->setBackColor ( 14); break; + case TY_CSI_PS('m', 107) : scr->setBackColor ( 15); break; + + case TY_CSI_PS('n', 5) : reportStatus ( ); break; + case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break; + case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100 + case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100 + case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100 + case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100 + case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100 + case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100 + case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100 + + case TY_CSI_PN('@' ) : scr->insertChars (p ); break; + case TY_CSI_PN('A' ) : scr->cursorUp (p ); break; //VT100 + case TY_CSI_PN('B' ) : scr->cursorDown (p ); break; //VT100 + case TY_CSI_PN('C' ) : scr->cursorRight (p ); break; //VT100 + case TY_CSI_PN('D' ) : scr->cursorLeft (p ); break; //VT100 + case TY_CSI_PN('G' ) : scr->setCursorX (p ); break; //LINUX + case TY_CSI_PN('H' ) : scr->setCursorYX (p, q); break; //VT100 + case TY_CSI_PN('L' ) : scr->insertLines (p ); break; + case TY_CSI_PN('M' ) : scr->deleteLines (p ); break; + case TY_CSI_PN('P' ) : scr->deleteChars (p ); break; + case TY_CSI_PN('X' ) : scr->eraseChars (p ); break; + case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100 + case TY_CSI_PN('d' ) : scr->setCursorY (p ); break; //LINUX + case TY_CSI_PN('f' ) : scr->setCursorYX (p, q); break; //VT100 + case TY_CSI_PN('r' ) : scr->setMargins (p, q); break; //VT100 + case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100 + + case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100 + case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100 + case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME + case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME + + case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100 + + case TY_CSI_PR('h', 3) : setColumns ( 132); break; //VT100 + case TY_CSI_PR('l', 3) : setColumns ( 80); break; //VT100 + + case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100 + case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100 + + case TY_CSI_PR('h', 5) : scr-> setMode (MODE_Screen ); break; //VT100 + case TY_CSI_PR('l', 5) : scr-> resetMode (MODE_Screen ); break; //VT100 + + case TY_CSI_PR('h', 6) : scr-> setMode (MODE_Origin ); break; //VT100 + case TY_CSI_PR('l', 6) : scr-> resetMode (MODE_Origin ); break; //VT100 + case TY_CSI_PR('s', 6) : scr-> saveMode (MODE_Origin ); break; //FIXME + case TY_CSI_PR('r', 6) : scr->restoreMode (MODE_Origin ); break; //FIXME + + case TY_CSI_PR('h', 7) : scr-> setMode (MODE_Wrap ); break; //VT100 + case TY_CSI_PR('l', 7) : scr-> resetMode (MODE_Wrap ); break; //VT100 + case TY_CSI_PR('s', 7) : scr-> saveMode (MODE_Wrap ); break; //FIXME + case TY_CSI_PR('r', 7) : scr->restoreMode (MODE_Wrap ); break; //FIXME + + case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100 + case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100 + + case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100 + case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100 + + case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100 + case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100 + + case TY_CSI_PR('h', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + case TY_CSI_PR('l', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + case TY_CSI_PR('s', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + case TY_CSI_PR('r', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + + case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100 + case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100 + + case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM + case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM + case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM + case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM + + case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + case TY_CSI_PR('l', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + + case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM + case TY_CSI_PR('l', 1047) : resetMode (MODE_AppScreen); break; //XTERM + + //FIXME: Unitoken: save translations + case TY_CSI_PR('h', 1048) : saveCursor ( ); break; //XTERM + case TY_CSI_PR('l', 1048) : restoreCursor ( ); break; //XTERM + + //FIXME: every once new sequences like this pop up in xterm. + // Here's a guess of what they could mean. + case TY_CSI_PR('h', 1049) : setMode (MODE_AppScreen); break; //XTERM + case TY_CSI_PR('l', 1049) : resetMode (MODE_AppScreen); break; //XTERM + + //FIXME: when changing between vt52 and ansi mode evtl do some resetting. + case TY_VT52__('A' ) : scr->cursorUp ( 1); break; //VT52 + case TY_VT52__('B' ) : scr->cursorDown ( 1); break; //VT52 + case TY_VT52__('C' ) : scr->cursorRight ( 1); break; //VT52 + case TY_VT52__('D' ) : scr->cursorLeft ( 1); break; //VT52 + + case TY_VT52__('F' ) : setAndUseCharset (0, '0'); break; //VT52 + case TY_VT52__('G' ) : setAndUseCharset (0, 'B'); break; //VT52 + + case TY_VT52__('H' ) : scr->setCursorYX (1,1 ); break; //VT52 + case TY_VT52__('I' ) : scr->reverseIndex ( ); break; //VT52 + case TY_VT52__('J' ) : scr->clearToEndOfScreen ( ); break; //VT52 + case TY_VT52__('K' ) : scr->clearToEndOfLine ( ); break; //VT52 + case TY_VT52__('Y' ) : scr->setCursorYX (p-31,q-31 ); break; //VT52 + case TY_VT52__('Z' ) : reportTerminalType ( ); break; //VT52 + case TY_VT52__('<' ) : setMode (MODE_Ansi ); break; //VT52 + case TY_VT52__('=' ) : setMode (MODE_AppKeyPad); break; //VT52 + case TY_VT52__('>' ) : resetMode (MODE_AppKeyPad); break; //VT52 + + default : ReportErrorToken(); break; + }; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Terminal to Host protocol */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* + Outgoing bytes originate from several sources: + + - Replies to Enquieries. + - Mouse Events + - Keyboard Events +*/ + +/*! +*/ + +void TEmuVt102::sendString(const char* s) +{ + emit sndBlock(s,strlen(s)); +} + +// Replies ----------------------------------------------------------------- -- + +// This section copes with replies send as response to an enquiery control code. + +/*! +*/ + +void TEmuVt102::reportCursorPosition() +{ char tmp[20]; + sprintf(tmp,"\033[%d;%dR",scr->getCursorY()+1,scr->getCursorX()+1); + sendString(tmp); +} + +/* + What follows here is rather obsolete and faked stuff. + The correspondent enquieries are neverthenless issued. +*/ + +/*! +*/ + +void TEmuVt102::reportTerminalType() +{ +//FIXME: should change? + if (getMode(MODE_Ansi)) +// sendString("\033[?1;2c"); // I'm a VT100 with AP0 //FIXME: send only in response to ^[[0c + sendString("\033[>0;115;0c"); // I'm a VT220 //FIXME: send only in response to ^[[>c + else + sendString("\033/Z"); // I'm a VT52 +} + +void TEmuVt102::reportTerminalParms(int p) +// DECREPTPARM +{ char tmp[100]; + sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true. + sendString(tmp); +} + +/*! +*/ + +void TEmuVt102::reportStatus() +{ + sendString("\033[0n"); //VT100. Device status report. 0 = Ready. +} + +/*! +*/ + +#define ANSWER_BACK "" // This is really obsolete VT100 stuff. + +void TEmuVt102::reportAnswerBack() +{ + sendString(ANSWER_BACK); +} + +// Mouse Handling ---------------------------------------------------------- -- + +/*! + Mouse clicks are possibly reported to the client + application if it has issued interest in them. + They are normally consumed by the widget for copy + and paste, but may be propagated from the widget + when gui->setMouseMarks is set via setMode(MODE_Mouse1000). + + `x',`y' are 1-based. + `ev' (event) indicates the button pressed (0-2) + or a general mouse release (3). +*/ + +void TEmuVt102::onMouse( int cb, int cx, int cy ) +{ char tmp[20]; + if (!connected) return; + sprintf(tmp,"\033[M%c%c%c",cb+040,cx+040,cy+040); + sendString(tmp); +} + +// Keyboard Handling ------------------------------------------------------- -- + +#define encodeMode(M,B) BITS(B,getMode(M)) +#define encodeStat(M,B) BITS(B,((ev->state() & (M)) == (M))) + +/* + Keyboard event handling has been simplified somewhat by pushing + the complications towards a configuration file [see KeyTrans class]. +*/ + +void TEmuVt102::onKeyPress( QKeyEvent* ev ) +{ + if (!connected) return; // someone else gets the keys + +//printf("State/Key: 0x%04x 0x%04x (%d,%d)\n",ev->state(),ev->key(),ev->text().length(),ev->text().length()?ev->text().ascii()[0]:0); + + // revert to non-history when typing + if (scr->getHistCursor() != scr->getHistLines()); + scr->setHistCursor(scr->getHistLines()); + + // lookup in keyboard translation table ... + int cmd; const char* txt; int len; + if (keytrans->findEntry(ev->key(), encodeMode(MODE_NewLine , BITS_NewLine ) + // OLD, + encodeMode(MODE_Ansi , BITS_Ansi ) + // OBSOLETE, + encodeMode(MODE_AppCuKeys, BITS_AppCuKeys ) + // VT100 stuff + encodeStat(ControlButton , BITS_Control ) + + encodeStat(ShiftButton , BITS_Shift ) + + encodeStat(AltButton , BITS_Alt ), + &cmd, &txt, &len )) +//printf("cmd: %d, %s, %d\n",cmd,txt,len); + switch(cmd) // ... and execute if found. + { + case CMD_emitSelection : gui->emitSelection(); return; + case CMD_scrollPageUp : gui->doScroll(-gui->Lines()/2); return; + case CMD_scrollPageDown : gui->doScroll(+gui->Lines()/2); return; + case CMD_scrollLineUp : gui->doScroll(-1 ); return; + case CMD_scrollLineDown : gui->doScroll(+1 ); return; + case CMD_send : emit sndBlock(txt,len); return; + case CMD_prevSession : emit prevSession(); return; + case CMD_nextSession : emit nextSession(); return; + } + + // fall back handling + if (!ev->text().isEmpty()) + { + if (ev->state() & AltButton) sendString("\033"); // ESC, this is the ALT prefix + QCString s = codec->fromUnicode(ev->text()); // encode for application + emit sndBlock(s.data(),s.length()); // we may well have s.length() > 1 + return; + } +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* VT100 Charsets */ +/* */ +/* ------------------------------------------------------------------------- */ + +// Character Set Conversion ------------------------------------------------ -- + +/* + The processing contains a VT100 specific code translation layer. + It's still in use and mainly responsible for the line drawing graphics. + + These and some other glyphs are assigned to codes (0x5f-0xfe) + normally occupied by the latin letters. Since this codes also + appear within control sequences, the extra code conversion + does not permute with the tokenizer and is placed behind it + in the pipeline. It only applies to tokens, which represent + plain characters. + + This conversion it eventually continued in TEWidget.C, since + it might involve VT100 enhanced fonts, which have these + particular glyphs allocated in (0x00-0x1f) in their code page. +*/ + +#define CHARSET charset[scr==screen[1]] + +// Apply current character map. + +unsigned short TEmuVt102::applyCharset(unsigned short c) +{ + if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f]; + if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete + return c; +} + +/* + "Charset" related part of the emulation state. + This configures the VT100 charset filter. + + While most operation work on the current screen, + the following two are different. +*/ + +void TEmuVt102::resetCharset(int scrno) +{ + charset[scrno].cu_cs = 0; + strncpy(charset[scrno].charset,"BBBB",4); + charset[scrno].sa_graphic = FALSE; + charset[scrno].sa_pound = FALSE; + charset[scrno].graphic = FALSE; + charset[scrno].pound = FALSE; +} + +/*! +*/ + +void TEmuVt102::setCharset(int n, int cs) // on both screens. +{ + charset[0].charset[n&3] = cs; useCharset(charset[0].cu_cs); + charset[1].charset[n&3] = cs; useCharset(charset[1].cu_cs); +} + +/*! +*/ + +void TEmuVt102::setAndUseCharset(int n, int cs) +{ + CHARSET.charset[n&3] = cs; + useCharset(n&3); +} + +/*! +*/ + +void TEmuVt102::useCharset(int n) +{ + CHARSET.cu_cs = n&3; + CHARSET.graphic = (CHARSET.charset[n&3] == '0'); + CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete +} + +/*! Save the cursor position and the rendition attribute settings. */ + +void TEmuVt102::saveCursor() +{ + CHARSET.sa_graphic = CHARSET.graphic; + CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete + // we are not clear about these + //sa_charset = charsets[cScreen->charset]; + //sa_charset_num = cScreen->charset; + scr->saveCursor(); +} + +/*! Restore the cursor position and the rendition attribute settings. */ + +void TEmuVt102::restoreCursor() +{ + CHARSET.graphic = CHARSET.sa_graphic; + CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete + scr->restoreCursor(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Mode Operations */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* + Some of the emulations state is either added to the state of the screens. + + This causes some scoping problems, since different emulations choose to + located the mode either to the current screen or to both. + + For strange reasons, the extend of the rendition attributes ranges over + all screens and not over the actual screen. + + We decided on the precise precise extend, somehow. +*/ + +// "Mode" related part of the state. These are all booleans. + +void TEmuVt102::resetModes() +{ + resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); + resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); + // here come obsolete modes + resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); + resetMode(MODE_NewLine ); + setMode(MODE_Ansi ); +} + +void TEmuVt102::setMode(int m) +{ + currParm.mode[m] = TRUE; + switch (m) + { + case MODE_Mouse1000 : gui->setMouseMarks(FALSE); + break; + case MODE_AppScreen : screen[1]->clearSelection(); + screen[1]->clearEntireScreen(); + setScreen(1); + break; + } + if (m < MODES_SCREEN || m == MODE_NewLine) + { + screen[0]->setMode(m); + screen[1]->setMode(m); + } +} + +void TEmuVt102::resetMode(int m) +{ + currParm.mode[m] = FALSE; + switch (m) + { + case MODE_Mouse1000 : gui->setMouseMarks(TRUE); + break; + case MODE_AppScreen : screen[0]->clearSelection(); + setScreen(0); + break; + } + if (m < MODES_SCREEN || m == MODE_NewLine) + { + screen[0]->resetMode(m); + screen[1]->resetMode(m); + } +} + +void TEmuVt102::saveMode(int m) +{ + saveParm.mode[m] = currParm.mode[m]; +} + +void TEmuVt102::restoreMode(int m) +{ + if(saveParm.mode[m]) setMode(m); else resetMode(m); +} + +BOOL TEmuVt102::getMode(int m) +{ + return currParm.mode[m]; +} + +void TEmuVt102::setConnect(bool c) +{ + TEmulation::setConnect(c); + if (c) + { // refresh mouse mode + if (getMode(MODE_Mouse1000)) + setMode(MODE_Mouse1000); + else + resetMode(MODE_Mouse1000); + } +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Diagnostic */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! shows the contents of the scan buffer. + + This functions is used for diagnostics. It is called by \e ReportErrorToken + to inform about strings that cannot be decoded or handled by the emulation. + + \sa ReportErrorToken +*/ + +/*! +*/ + +static void hexdump(int* s, int len) +{ int i; + for (i = 0; i < len; i++) + { + if (s[i] == '\\') + printf("\\\\"); + else + if ((s[i]) > 32 && s[i] < 127) + printf("%c",s[i]); + else + printf("\\%04x(hex)",s[i]); + } +} + +void TEmuVt102::scan_buffer_report() +{ + if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return; + printf("token: "); hexdump(pbuf,ppos); printf("\n"); +} + +/*! +*/ + +void TEmuVt102::ReportErrorToken() +{ + printf("undecodable "); scan_buffer_report(); +} diff --git a/core/apps/embeddedkonsole/TEmuVt102.h b/core/apps/embeddedkonsole/TEmuVt102.h new file mode 100644 index 0000000..a448a71 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmuVt102.h @@ -0,0 +1,135 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TEmuVt102.h] X Terminal Emulation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef VT102EMU_H +#define VT102EMU_H + +#include "TEWidget.h" +#include "TEScreen.h" +#include "TEmulation.h" +#include +#include + +// + +#define MODE_AppScreen (MODES_SCREEN+0) +#define MODE_AppCuKeys (MODES_SCREEN+1) +#define MODE_AppKeyPad (MODES_SCREEN+2) +#define MODE_Mouse1000 (MODES_SCREEN+3) +#define MODE_Ansi (MODES_SCREEN+4) +#define MODE_total (MODES_SCREEN+5) + +struct DECpar +{ + BOOL mode[MODE_total]; +}; + +struct CharCodes +{ + // coding info + char charset[4]; // + int cu_cs; // actual charset. + bool graphic; // Some VT100 tricks + bool pound ; // Some VT100 tricks + bool sa_graphic; // saved graphic + bool sa_pound; // saved pound +}; + +class TEmuVt102 : public TEmulation +{ Q_OBJECT + +public: + + TEmuVt102(TEWidget* gui); + ~TEmuVt102(); + +public slots: // signals incoming from TEWidget + + void onKeyPress(QKeyEvent*); + void onMouse(int cb, int cx, int cy); + +signals: + + void changeTitle(int,const QString&); + void prevSession(); + void nextSession(); + +public: + + void reset(); + + void onRcvChar(int cc); + void sendString(const char *); + +public: + + BOOL getMode (int m); + + void setMode (int m); + void resetMode (int m); + void saveMode (int m); + void restoreMode(int m); + void resetModes(); + + void setConnect(bool r); + +private: + + void resetToken(); +#define MAXPBUF 80 + void pushToToken(int cc); + int pbuf[MAXPBUF]; //FIXME: overflow? + int ppos; +#define MAXARGS 15 + void addDigit(int dig); + void addArgument(); + int argv[MAXARGS]; + int argc; + void initTokenizer(); + int tbl[256]; + + void scan_buffer_report(); //FIXME: rename + void ReportErrorToken(); //FIXME: rename + + void tau(int code, int p, int q); + void XtermHack(); + + // + + void reportTerminalType(); + void reportStatus(); + void reportAnswerBack(); + void reportCursorPosition(); + void reportTerminalParms(int p); + +protected: + + unsigned short applyCharset(unsigned short c); + void setCharset(int n, int cs); + void useCharset(int n); + void setAndUseCharset(int n, int cs); + void saveCursor(); + void restoreCursor(); + void resetCharset(int scrno); + CharCodes charset[2]; + + DECpar currParm; + DECpar saveParm; +}; + +#endif // ifndef ANSIEMU_H diff --git a/core/apps/embeddedkonsole/TEmulation.cpp b/core/apps/embeddedkonsole/TEmulation.cpp new file mode 100644 index 0000000..6f3ad32 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmulation.cpp @@ -0,0 +1,363 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TEmulation.cpp] Terminal Emulation Decoder */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \class TEmulation + + \brief Mediator between TEWidget and TEScreen. + + This class is responsible to scan the escapes sequences of the terminal + emulation and to map it to their corresponding semantic complements. + Thus this module knows mainly about decoding escapes sequences and + is a stateless device w.r.t. the semantics. + + It is also responsible to refresh the TEWidget by certain rules. + + \sa TEWidget \sa TEScreen + + \par A note on refreshing + + Although the modifications to the current screen image could immediately + be propagated via `TEWidget' to the graphical surface, we have chosen + another way here. + + The reason for doing so is twofold. + + First, experiments show that directly displaying the operation results + in slowing down the overall performance of emulations. Displaying + individual characters using X11 creates a lot of overhead. + + Second, by using the following refreshing method, the screen operations + can be completely separated from the displaying. This greatly simplifies + the programmer's task of coding and maintaining the screen operations, + since one need not worry about differential modifications on the + display affecting the operation of concern. + + We use a refreshing algorithm here that has been adoped from rxvt/kvt. + + By this, refreshing is driven by a timer, which is (re)started whenever + a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'. + As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger + refresh. This rule suits both bulk display operation as done by curses as + well as individual characters typed. + (BULK_TIMEOUT < 1000 / max characters received from keyboard per second). + + Additionally, we trigger refreshing by newlines comming in to make visual + snapshots of lists as produced by `cat', `ls' and likely programs, thereby + producing the illusion of a permanent and immediate display operation. + + As a sort of catch-all needed for cases where none of the above + conditions catch, the screen refresh is also triggered by a count + of incoming bulks (`bulk_incnt'). +*/ + +/* FIXME + - evtl. the bulk operations could be made more transparent. +*/ + +#include "TEmulation.h" +#include "TEWidget.h" +#include "TEScreen.h" +#include +#include +#include +#include + + +/* ------------------------------------------------------------------------- */ +/* */ +/* TEmulation */ +/* */ +/* ------------------------------------------------------------------------- */ + +#define CNTL(c) ((c)-'@') + +/*! +*/ + +TEmulation::TEmulation(TEWidget* gui) +: decoder((QTextDecoder*)NULL) +{ + this->gui = gui; + + screen[0] = new TEScreen(gui->Lines(),gui->Columns()); + screen[1] = new TEScreen(gui->Lines(),gui->Columns()); + scr = screen[0]; + + bulk_nlcnt = 0; // reset bulk newline counter + bulk_incnt = 0; // reset bulk counter + connected = FALSE; + + QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) ); + QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)), + this,SLOT(onImageSizeChange(int,int))); + QObject::connect(gui,SIGNAL(changedHistoryCursor(int)), + this,SLOT(onHistoryCursorChange(int))); + QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)), + this,SLOT(onKeyPress(QKeyEvent*))); + QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)), + this,SLOT(onSelectionBegin(const int,const int)) ); + QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)), + this,SLOT(onSelectionExtend(const int,const int)) ); + QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)), + this,SLOT(setSelection(const BOOL)) ); + QObject::connect(gui,SIGNAL(clearSelectionSignal()), + this,SLOT(clearSelection()) ); +} + +/*! +*/ + +TEmulation::~TEmulation() +{ + delete screen[0]; + delete screen[1]; + bulk_timer.stop(); +} + +/*! change between primary and alternate screen +*/ + +void TEmulation::setScreen(int n) +{ + scr = screen[n&1]; +} + +void TEmulation::setHistory(bool on) +{ + screen[0]->setScroll(on); + if (!connected) return; + showBulk(); +} + +bool TEmulation::history() +{ + return screen[0]->hasScroll(); +} + +void TEmulation::setCodec(int c) +{ + //FIXME: check whether we have to free codec + codec = c ? QTextCodec::codecForName("utf8") + : QTextCodec::codecForLocale(); + if (decoder) delete decoder; + decoder = codec->makeDecoder(); +} + +void TEmulation::setKeytrans(int no) +{ + keytrans = KeyTrans::find(no); +} + +void TEmulation::setKeytrans(const char * no) +{ + keytrans = KeyTrans::find(no); +} + +// Interpreting Codes --------------------------------------------------------- + +/* + This section deals with decoding the incoming character stream. + Decoding means here, that the stream is first seperated into `tokens' + which are then mapped to a `meaning' provided as operations by the + `Screen' class. +*/ + +/*! +*/ + +void TEmulation::onRcvChar(int c) +// process application unicode input to terminal +// this is a trivial scanner +{ + c &= 0xff; + switch (c) + { + case '\b' : scr->BackSpace(); break; + case '\t' : scr->Tabulate(); break; + case '\n' : scr->NewLine(); break; + case '\r' : scr->Return(); break; + case 0x07 : gui->Bell(); break; + default : scr->ShowCharacter(c); break; + }; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Keyboard Handling */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! +*/ + +void TEmulation::onKeyPress( QKeyEvent* ev ) +{ + if (!connected) return; // someone else gets the keys + if (scr->getHistCursor() != scr->getHistLines()); + scr->setHistCursor(scr->getHistLines()); + 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 sndBlock(ev->text().ascii(),ev->text().length()); + } + else if (ev->ascii()>0) + { unsigned char c[1]; + c[0] = ev->ascii(); + emit sndBlock((char*)c,1); + } +} + +// Unblocking, Byte to Unicode translation --------------------------------- -- + +/* + We are doing code conversion from locale to unicode first. +*/ + +void TEmulation::onRcvBlock(const char *s, int len) +{ + bulkStart(); + bulk_incnt += 1; + for (int i = 0; i < len; i++) + { + QString result = decoder->toUnicode(&s[i],1); + int reslen = result.length(); + for (int j = 0; j < reslen; j++) + onRcvChar(result[j].unicode()); + if (s[i] == '\n') bulkNewline(); + } + bulkEnd(); +} + +// Selection --------------------------------------------------------------- -- + +void TEmulation::onSelectionBegin(const int x, const int y) { + if (!connected) return; + scr->setSelBeginXY(x,y); + showBulk(); +} + +void TEmulation::onSelectionExtend(const int x, const int y) { + if (!connected) return; + scr->setSelExtentXY(x,y); + showBulk(); +} + +void TEmulation::setSelection(const BOOL preserve_line_breaks) { + if (!connected) return; + QString t = scr->getSelText(preserve_line_breaks); + if (!t.isNull()) gui->setSelection(t); +} + +void TEmulation::clearSelection() { + if (!connected) return; + scr->clearSelection(); + showBulk(); +} + +// Refreshing -------------------------------------------------------------- -- + +#define BULK_TIMEOUT 20 + +/*! + called when \n comes in. Evtl. triggers showBulk at endBulk +*/ + +void TEmulation::bulkNewline() +{ + bulk_nlcnt += 1; + bulk_incnt = 0; // reset bulk counter since `nl' rule applies +} + +/*! +*/ + +void TEmulation::showBulk() +{ + bulk_nlcnt = 0; // reset bulk newline counter + bulk_incnt = 0; // reset bulk counter + if (connected) + { + ca* image = scr->getCookedImage(); // get the image + gui->setImage(image, + scr->getLines(), + scr->getColumns()); // actual refresh + free(image); + //FIXME: check that we do not trigger other draw event here. + gui->setScroll(scr->getHistCursor(),scr->getHistLines()); + } +} + +void TEmulation::bulkStart() +{ + if (bulk_timer.isActive()) bulk_timer.stop(); +} + +void TEmulation::bulkEnd() +{ + if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 ) + showBulk(); // resets bulk_??cnt to 0, too. + else + bulk_timer.start(BULK_TIMEOUT,TRUE); +} + +void TEmulation::setConnect(bool c) +{ + connected = c; + if ( connected) + { + onImageSizeChange(gui->Lines(), gui->Columns()); + showBulk(); + } + else + { + scr->clearSelection(); + } +} + +// --------------------------------------------------------------------------- + +/*! triggered by image size change of the TEWidget `gui'. + + This event is simply propagated to the attached screens + and to the related serial line. +*/ + +void TEmulation::onImageSizeChange(int lines, int columns) +{ + if (!connected) return; + screen[0]->resizeImage(lines,columns); + screen[1]->resizeImage(lines,columns); + showBulk(); + emit ImageSizeChanged(lines,columns); // propagate event to serial line +} + +void TEmulation::onHistoryCursorChange(int cursor) +{ + if (!connected) return; + scr->setHistCursor(cursor); + showBulk(); +} + +void TEmulation::setColumns(int columns) +{ + //FIXME: this goes strange ways. + // Can we put this straight or explain it at least? + emit changeColumns(columns); +} diff --git a/core/apps/embeddedkonsole/TEmulation.h b/core/apps/embeddedkonsole/TEmulation.h new file mode 100644 index 0000000..ec15e7a --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmulation.h @@ -0,0 +1,117 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [emulation.h] Fundamental Terminal Emulation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef EMULATION_H +#define EMULATION_H + +#include "TEWidget.h" +#include "TEScreen.h" +#include +#include +#include +#include "keytrans.h" + +class TEmulation : public QObject +{ Q_OBJECT + +public: + + TEmulation(TEWidget* gui); + ~TEmulation(); + +public: + virtual void setHistory(bool on); + virtual bool history(); + +public slots: // signals incoming from TEWidget + + virtual void onImageSizeChange(int lines, int columns); + virtual void onHistoryCursorChange(int cursor); + virtual void onKeyPress(QKeyEvent*); + + virtual void clearSelection(); + virtual void onSelectionBegin(const int x, const int y); + virtual void onSelectionExtend(const int x, const int y); + virtual void setSelection(const BOOL preserve_line_breaks); + +public slots: // signals incoming from data source + + void onRcvBlock(const char* txt,int len); + +signals: + + void sndBlock(const char* txt,int len); + void ImageSizeChanged(int lines, int columns); + void changeColumns(int columns); + void changeTitle(int arg, const char* str); + +public: + + virtual void onRcvChar(int); + + virtual void setMode (int) = 0; + virtual void resetMode(int) = 0; + + virtual void sendString(const char*) = 0; + + virtual void setConnect(bool r); + void setColumns(int columns); + + void setKeytrans(int no); + void setKeytrans(const char * no); + +protected: + + TEWidget* gui; + TEScreen* scr; // referes to one `screen' + TEScreen* screen[2]; // 0 = primary, 1 = alternate + void setScreen(int n); // set `scr' to `screen[n]' + + bool connected; // communicate with widget + + void setCodec(int c); // codec number, 0 = locale, 1=utf8 + + QTextCodec* codec; + QTextCodec* localeCodec; + QTextDecoder* decoder; + + KeyTrans* keytrans; + +// refreshing related material. +// this is localized in the class. +private slots: // triggered by timer + + void showBulk(); + +private: + + void bulkNewline(); + void bulkStart(); + void bulkEnd(); + +private: + + QTimer bulk_timer; + int bulk_nlcnt; // bulk newline counter + char* SelectedText; + int bulk_incnt; // bulk counter + + +}; + +#endif // ifndef EMULATION_H diff --git a/core/apps/embeddedkonsole/default.keytab.h b/core/apps/embeddedkonsole/default.keytab.h new file mode 100644 index 0000000..503ea46 --- a/dev/null +++ b/core/apps/embeddedkonsole/default.keytab.h @@ -0,0 +1,103 @@ + /* generated by '../tests/quote ../other/default.Keytab' */ + + "# [default.Keytab] Buildin Keyboard Table\n" + "\n" + "# --------------------------------------------------------------\n" + "#\n" + "# This file in included only for reference purposes. \n" + "#\n" + "# Modifying it does not have any effect (unless you\n" + "# derive the default.keytab.h and recompile konsole).\n" + "#\n" + "# To customize your keyboard, copy this file to something\n" + "# ending with .keytab and change it to meet you needs.\n" + "#\n" + "# --------------------------------------------------------------\n" + "\n" + "keyboard \"xterm (default)\"\n" + "\n" + "# --------------------------------------------------------------\n" + "#\n" + "# The syntax of each entry has the form\n" + "#\n" + "# \"key\" Keyname { (\"+\"|\"-\") Modename } \":\" (String|Operation)\n" + "#\n" + "# Keynames are those defined in \n" + "# with the \"Qt::Key_\" prefix removed.\n" + "#\n" + "# Mode names are: Shift, Alt, Control.\n" + "#\n" + "# If the key is not found here, the text of the\n" + "# key event as provided by QT is emitted, possibly\n" + "# preceeded by ESC if the Alt key is pressed.\n" + "#\n" + "# --------------------------------------------------------------\n" + "#\n" + "# Note that this particular table is a \"risc\" version made to\n" + "# ease customization without bothering with obsolete details.\n" + "# See VT100.keytab for the more hairy stuff.\n" + "#\n" + "# --------------------------------------------------------------\n" + "\n" + "# common keys\n" + "\n" + "key Escape : \"\\E\"\n" + "key Tab : \"\\t\"\n" + "\n" + "key Return-Alt : \"\\r\"\n" + "key Return+Alt : \"\\E\\r\"\n" + "\n" + "# Backspace and Delete codes are preserving CTRL-H.\n" + "\n" + "key Backspace : \"\\x7f\"\n" + "\n" + "# cursor keys\n" + "\n" + "key Up -Shift : \"\\EOA\"\n" + "key Down -Shift : \"\\EOB\"\n" + "key Right -Shift : \"\\EOC\"\n" + "key Left -Shift : \"\\EOD\"\n" + "\n" + "# other grey PC keys\n" + "\n" + "key Enter : \"\\r\"\n" + "\n" + "key Home : \"\\E[1~\"\n" + "key Insert-Shift : \"\\E[2~\"\n" + "key Delete : \"\\E[3~\"\n" + "key End : \"\\E[4~\"\n" + "key Prior -Shift : \"\\E[5~\"\n" + "key Next -Shift : \"\\E[6~\"\n" + "\n" + "# function keys\n" + "\n" + "key F1 : \"\\E[11~\"\n" + "key F2 : \"\\E[12~\"\n" + "key F3 : \"\\E[13~\"\n" + "key F4 : \"\\E[14~\"\n" + "key F5 : \"\\E[15~\"\n" + "key F6 : \"\\E[17~\"\n" + "key F7 : \"\\E[18~\"\n" + "key F8 : \"\\E[19~\"\n" + "key F9 : \"\\E[20~\"\n" + "key F10 : \"\\E[21~\"\n" + "key F11 : \"\\E[23~\"\n" + "key F12 : \"\\E[24~\"\n" + "\n" + "# Work around dead keys\n" + "\n" + "key Space +Control : \"\\x00\"\n" + "\n" + "# Some keys are used by konsole to cause operations.\n" + "# The scroll* operations refer to the history buffer.\n" + "\n" + "key Left +Shift : prevSession\n" + "key Right +Shift : nextSession\n" + "key Up +Shift : scrollLineUp\n" + "key Prior +Shift : scrollPageUp\n" + "key Down +Shift : scrollLineDown\n" + "key Next +Shift : scrollPageDown\n" + "key Insert+Shift : emitSelection\n" + "\n" + "# keypad characters are not offered differently by Qt.\n" + "" diff --git a/core/apps/embeddedkonsole/embeddedkonsole.pro b/core/apps/embeddedkonsole/embeddedkonsole.pro new file mode 100755 index 0000000..b757ea5 --- a/dev/null +++ b/core/apps/embeddedkonsole/embeddedkonsole.pro @@ -0,0 +1,38 @@ +TEMPLATE = app + +CONFIG += qt warn_on release + +DESTDIR = $(QPEDIR)/bin + +HEADERS = TEWidget.h \ + TEScreen.h \ + TECommon.h \ + TEHistory.h \ + TEmulation.h \ + TEmuVt102.h \ + session.h \ + keytrans.h \ + konsole.h \ + MyPty.h + +SOURCES = TEScreen.cpp \ + TEWidget.cpp \ + TEHistory.cpp \ + TEmulation.cpp \ + TEmuVt102.cpp \ + session.cpp \ + keytrans.cpp \ + konsole.cpp \ + main.cpp \ + MyPty.cpp + +TARGET = embeddedkonsole + +INCLUDEPATH += $(QPEDIR)/include + +DEPENDPATH += $(QPEDIR)/include + +LIBS += -lqpe + +REQUIRES = embeddedkonsole + diff --git a/core/apps/embeddedkonsole/faded_bg.png b/core/apps/embeddedkonsole/faded_bg.png new file mode 100644 index 0000000..7dbf6b4 --- a/dev/null +++ b/core/apps/embeddedkonsole/faded_bg.png Binary files differ diff --git a/core/apps/embeddedkonsole/keytrans.cpp b/core/apps/embeddedkonsole/keytrans.cpp new file mode 100644 index 0000000..d569ae0 --- a/dev/null +++ b/core/apps/embeddedkonsole/keytrans.cpp @@ -0,0 +1,706 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [keytrans.C] Keyboard Translation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* + The keyboard translation table allows to configure konsoles behavior + on key strokes. + + FIXME: some bug crept in, disallowing '\0' to be emitted. +*/ + +#include "keytrans.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +//nclude + +#include + + +#undef USE_APPDATA_DIR + + +#define HERE printf("%s(%d): here\n",__FILE__,__LINE__) + +/* KeyEntry + + instances represent the individual assignments +*/ + +KeyTrans::KeyEntry::KeyEntry(int _ref, int _key, int _bits, int _mask, int _cmd, QString _txt) +: ref(_ref), key(_key), bits(_bits), mask(_mask), cmd(_cmd), txt(_txt) +{ +} + +KeyTrans::KeyEntry::~KeyEntry() +{ +} + +bool KeyTrans::KeyEntry::matches(int _key, int _bits, int _mask) +{ int m = mask & _mask; + return _key == key && (bits & m) == (_bits & m); +} + +QString KeyTrans::KeyEntry::text() +{ + return txt; +} + +/* KeyTrans + + combines the individual assignments to a proper map + Takes part in a collection themself. +*/ + +KeyTrans::KeyTrans() +{ + path = ""; + numb = 0; +} + +KeyTrans::~KeyTrans() +{ +} + +KeyTrans::KeyEntry* KeyTrans::addEntry(int ref, int key, int bits, int mask, int cmd, QString txt) +// returns conflicting entry +{ + for (QListIterator it(table); it.current(); ++it) + { + if (it.current()->matches(key,bits,mask)) + { + return it.current(); + } + } + table.append(new KeyEntry(ref,key,bits,mask,cmd,txt)); + return (KeyEntry*)NULL; +} + +bool KeyTrans::findEntry(int key, int bits, int* cmd, const char** txt, int* len) +{ + for (QListIterator it(table); it.current(); ++it) + if (it.current()->matches(key,bits,0xffff)) + { + *cmd = it.current()->cmd; + *txt = it.current()->txt.ascii(); + *len = it.current()->txt.length(); + return TRUE; + } + return FALSE; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Scanner for keyboard configuration */ +/* */ +/* ------------------------------------------------------------------------- */ + +// regular tokenizer +/* Tokens + - Spaces + - Name (A-Za-z0-9)+ + - String + - Opr on of +-: +*/ + +#define SYMName 0 +#define SYMString 1 +#define SYMEol 2 +#define SYMEof 3 +#define SYMOpr 4 +#define SYMError 5 + +#define inRange(L,X,H) ((L <= X) && (X <= H)) +#define isNibble(X) (inRange('A',X,'F')||inRange('a',X,'f')||inRange('0',X,'9')) +#define convNibble(X) (inRange('0',X,'9')?X-'0':X+10-(inRange('A',X,'F')?'A':'a')) + +class KeytabReader +{ +public: + KeytabReader(QString p, QIODevice &d); +public: + void getCc(); + void getSymbol(); + void parseTo(KeyTrans* kt); + void ReportError(const char* msg); + void ReportToken(); // diagnostic +private: + int sym; + QString res; + int len; + int slinno; + int scolno; +private: + int cc; + int linno; + int colno; + QIODevice* buf; + QString path; +}; + + +KeytabReader::KeytabReader(QString p, QIODevice &d) +{ + path = p; + buf = &d; + cc = 0; +} + +void KeytabReader::getCc() +{ + if (cc == '\n') { linno += 1; colno = 0; } + if (cc < 0) return; + cc = buf->getch(); + colno += 1; +} + +void KeytabReader::getSymbol() +{ + res = ""; len = 0; sym = SYMError; + while (cc == ' ') getCc(); // skip spaces + if (cc == '#') // skip comment + { + while (cc != '\n' && cc > 0) getCc(); + } + slinno = linno; + scolno = colno; + if (cc <= 0) + { + sym = SYMEof; return; // eos + } + if (cc == '\n') + { + getCc(); + sym = SYMEol; return; // eol + } + if (inRange('A',cc,'Z')||inRange('a',cc,'z')||inRange('0',cc,'9')) + { + while (inRange('A',cc,'Z') || inRange('a',cc,'z') || inRange('0',cc,'9')) + { + res = res + (char)cc; + getCc(); + } + sym = SYMName; + return; + } + if (strchr("+-:",cc)) + { + res = ""; + res = res + (char)cc; + getCc(); + sym = SYMOpr; return; + } + if (cc == '"') + { + getCc(); + while (cc >= ' ' && cc != '"') + { int sc; + if (cc == '\\') // handle quotation + { + getCc(); + switch (cc) + { + case 'E' : sc = 27; getCc(); break; + case 'b' : sc = 8; getCc(); break; + case 'f' : sc = 12; getCc(); break; + case 't' : sc = 9; getCc(); break; + case 'r' : sc = 13; getCc(); break; + case 'n' : sc = 10; getCc(); break; + case '\\' : // fall thru + case '"' : sc = cc; getCc(); break; + case 'x' : getCc(); + sc = 0; + if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); + if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); + break; + default : return; + } + } + else + { + // regular char + sc = cc; getCc(); + } + res = res + (char)sc; + len = len + 1; + } + if (cc != '"') return; + getCc(); + sym = SYMString; return; + } +} + +void KeytabReader::ReportToken() // diagnostic +{ + printf("sym(%d): ",slinno); + switch(sym) + { + case SYMEol : printf("End of line"); break; + case SYMEof : printf("End of file"); break; + case SYMName : printf("Name: %s",res.latin1()); break; + case SYMOpr : printf("Opr : %s",res.latin1()); break; + case SYMString : printf("String len %d,%d ",res.length(),len); + for (unsigned i = 0; i < res.length(); i++) + printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); + break; + } + printf("\n"); +} + +void KeytabReader::ReportError(const char* msg) // diagnostic +{ + fprintf(stderr,"%s(%d,%d):error: %s.\n",path.ascii(),slinno,scolno,msg); +} + +// local symbol tables --------------------------------------------------------------------- + +class KeyTransSymbols +{ +public: + KeyTransSymbols(); +protected: + void defOprSyms(); + void defModSyms(); + void defKeySyms(); + void defKeySym(const char* key, int val); + void defOprSym(const char* key, int val); + void defModSym(const char* key, int val); +public: + QDict keysyms; + QDict modsyms; + QDict oprsyms; +}; + +static KeyTransSymbols * syms = 0L; + +// parser ---------------------------------------------------------------------------------- +/* Syntax + - Line :: [KeyName { ("+" | "-") ModeName } ":" (String|CommandName)] "\n" + - Comment :: '#' (any but \n)* +*/ + +KeyTrans* KeyTrans::fromDevice(QString path, QIODevice &buf) +{ + KeyTrans* kt = new KeyTrans; + kt->path = path; + KeytabReader ktr(path,buf); ktr.parseTo(kt); + return kt; +} + + +#define assertSyntax(Cond,Message) if (!(Cond)) { ReportError(Message); goto ERROR; } + +void KeytabReader::parseTo(KeyTrans* kt) +{ + // Opening sequence + + buf->open(IO_ReadOnly); + getCc(); + linno = 1; + colno = 1; + getSymbol(); + +Loop: + // syntax: ["key" KeyName { ("+" | "-") ModeName } ":" String/CommandName] ["#" Comment] + if (sym == SYMName && !strcmp(res.latin1(),"keyboard")) + { + getSymbol(); assertSyntax(sym == SYMString, "Header expected") + kt->hdr = res.latin1(); + getSymbol(); assertSyntax(sym == SYMEol, "Text unexpected") + getSymbol(); // eoln + goto Loop; + } + if (sym == SYMName && !strcmp(res.latin1(),"key")) + { +//printf("line %3d: ",startofsym); + getSymbol(); assertSyntax(sym == SYMName, "Name expected") + assertSyntax(syms->keysyms[res], "Unknown key name") + int key = (int)syms->keysyms[res]-1; +//printf(" key %s (%04x)",res.latin1(),(int)syms->keysyms[res]-1); + getSymbol(); // + - : + int mode = 0; + int mask = 0; + while (sym == SYMOpr && (!strcmp(res.latin1(),"+") || !strcmp(res.latin1(),"-"))) + { + bool on = !strcmp(res.latin1(),"+"); + getSymbol(); + // mode name + assertSyntax(sym == SYMName, "Name expected") + assertSyntax(syms->modsyms[res], "Unknown mode name") + int bits = (int)syms->modsyms[res]-1; + if (mask & (1 << bits)) + { + fprintf(stderr,"%s(%d,%d): mode name used multible times.\n",path.ascii(),slinno,scolno); + } + else + { + mode |= (on << bits); + mask |= (1 << bits); + } +//printf(", mode %s(%d) %s",res.latin1(),(int)syms->modsyms[res]-1,on?"on":"off"); + getSymbol(); + } + assertSyntax(sym == SYMOpr && !strcmp(res.latin1(),":"), "':' expected") + getSymbol(); + // string or command + assertSyntax(sym == SYMName || sym == SYMString,"Command or string expected") + int cmd = 0; + if (sym == SYMName) + { + assertSyntax(syms->oprsyms[res], "Unknown operator name") + cmd = (int)syms->oprsyms[res]-1; +//printf(": do %s(%d)",res.latin1(),(int)syms->oprsyms[res]-1); + } + if (sym == SYMString) + { + cmd = CMD_send; +//printf(": send"); +//for (unsigned i = 0; i < res.length(); i++) +//printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); + } +//printf(". summary %04x,%02x,%02x,%d\n",key,mode,mask,cmd); + KeyTrans::KeyEntry* ke = kt->addEntry(slinno,key,mode,mask,cmd,res); + if (ke) + { + fprintf(stderr,"%s(%d): keystroke already assigned in line %d.\n",path.ascii(),slinno,ke->ref); + } + getSymbol(); + assertSyntax(sym == SYMEol, "Unexpected text") + goto Loop; + } + if (sym == SYMEol) + { + getSymbol(); + goto Loop; + } + + assertSyntax(sym == SYMEof, "Undecodable Line") + + buf->close(); + return; + +ERROR: + while (sym != SYMEol && sym != SYMEof) getSymbol(); // eoln + goto Loop; +} + + +KeyTrans* KeyTrans::defaultKeyTrans() +{ + QCString txt = +#include "default.keytab.h" + ; + QBuffer buf(txt); + return fromDevice("[buildin]",buf); +} + +KeyTrans* KeyTrans::fromFile(const char* path) +{ + QFile file(path); + return fromDevice(path,file); +} + +// local symbol tables --------------------------------------------------------------------- +// material needed for parsing the config file. +// This is incomplete work. + +void KeyTransSymbols::defKeySym(const char* key, int val) +{ + keysyms.insert(key,(QObject*)(val+1)); +} + +void KeyTransSymbols::defOprSym(const char* key, int val) +{ + oprsyms.insert(key,(QObject*)(val+1)); +} + +void KeyTransSymbols::defModSym(const char* key, int val) +{ + modsyms.insert(key,(QObject*)(val+1)); +} + +void KeyTransSymbols::defOprSyms() +{ + // Modifier + defOprSym("scrollLineUp", CMD_scrollLineUp ); + defOprSym("scrollLineDown",CMD_scrollLineDown); + defOprSym("scrollPageUp", CMD_scrollPageUp ); + defOprSym("scrollPageDown",CMD_scrollPageDown); + defOprSym("emitSelection", CMD_emitSelection ); + defOprSym("prevSession", CMD_prevSession ); + defOprSym("nextSession", CMD_nextSession ); +} + +void KeyTransSymbols::defModSyms() +{ + // Modifier + defModSym("Shift", BITS_Shift ); + defModSym("Control", BITS_Control ); + defModSym("Alt", BITS_Alt ); + // Modes + defModSym("BsHack", BITS_BsHack ); // deprecated + defModSym("Ansi", BITS_Ansi ); + defModSym("NewLine", BITS_NewLine ); + defModSym("AppCuKeys", BITS_AppCuKeys ); +} + +void KeyTransSymbols::defKeySyms() +{ + // Grey keys + defKeySym("Escape", Qt::Key_Escape ); + defKeySym("Tab", Qt::Key_Tab ); + defKeySym("Backtab", Qt::Key_Backtab ); + defKeySym("Backspace", Qt::Key_Backspace ); + defKeySym("Return", Qt::Key_Return ); + defKeySym("Enter", Qt::Key_Enter ); + defKeySym("Insert", Qt::Key_Insert ); + defKeySym("Delete", Qt::Key_Delete ); + defKeySym("Pause", Qt::Key_Pause ); + defKeySym("Print", Qt::Key_Print ); + defKeySym("SysReq", Qt::Key_SysReq ); + defKeySym("Home", Qt::Key_Home ); + defKeySym("End", Qt::Key_End ); + defKeySym("Left", Qt::Key_Left ); + defKeySym("Up", Qt::Key_Up ); + defKeySym("Right", Qt::Key_Right ); + defKeySym("Down", Qt::Key_Down ); + defKeySym("Prior", Qt::Key_Prior ); + defKeySym("Next", Qt::Key_Next ); + defKeySym("Shift", Qt::Key_Shift ); + defKeySym("Control", Qt::Key_Control ); + defKeySym("Meta", Qt::Key_Meta ); + defKeySym("Alt", Qt::Key_Alt ); + defKeySym("CapsLock", Qt::Key_CapsLock ); + defKeySym("NumLock", Qt::Key_NumLock ); + defKeySym("ScrollLock", Qt::Key_ScrollLock ); + defKeySym("F1", Qt::Key_F1 ); + defKeySym("F2", Qt::Key_F2 ); + defKeySym("F3", Qt::Key_F3 ); + defKeySym("F4", Qt::Key_F4 ); + defKeySym("F5", Qt::Key_F5 ); + defKeySym("F6", Qt::Key_F6 ); + defKeySym("F7", Qt::Key_F7 ); + defKeySym("F8", Qt::Key_F8 ); + defKeySym("F9", Qt::Key_F9 ); + defKeySym("F10", Qt::Key_F10 ); + defKeySym("F11", Qt::Key_F11 ); + defKeySym("F12", Qt::Key_F12 ); + defKeySym("F13", Qt::Key_F13 ); + defKeySym("F14", Qt::Key_F14 ); + defKeySym("F15", Qt::Key_F15 ); + defKeySym("F16", Qt::Key_F16 ); + defKeySym("F17", Qt::Key_F17 ); + defKeySym("F18", Qt::Key_F18 ); + defKeySym("F19", Qt::Key_F19 ); + defKeySym("F20", Qt::Key_F20 ); + defKeySym("F21", Qt::Key_F21 ); + defKeySym("F22", Qt::Key_F22 ); + defKeySym("F23", Qt::Key_F23 ); + defKeySym("F24", Qt::Key_F24 ); + defKeySym("F25", Qt::Key_F25 ); + defKeySym("F26", Qt::Key_F26 ); + defKeySym("F27", Qt::Key_F27 ); + defKeySym("F28", Qt::Key_F28 ); + defKeySym("F29", Qt::Key_F29 ); + defKeySym("F30", Qt::Key_F30 ); + defKeySym("F31", Qt::Key_F31 ); + defKeySym("F32", Qt::Key_F32 ); + defKeySym("F33", Qt::Key_F33 ); + defKeySym("F34", Qt::Key_F34 ); + defKeySym("F35", Qt::Key_F35 ); + defKeySym("Super_L", Qt::Key_Super_L ); + defKeySym("Super_R", Qt::Key_Super_R ); + defKeySym("Menu", Qt::Key_Menu ); + defKeySym("Hyper_L", Qt::Key_Hyper_L ); + defKeySym("Hyper_R", Qt::Key_Hyper_R ); + + // Regular keys + defKeySym("Space", Qt::Key_Space ); + defKeySym("Exclam", Qt::Key_Exclam ); + defKeySym("QuoteDbl", Qt::Key_QuoteDbl ); + defKeySym("NumberSign", Qt::Key_NumberSign ); + defKeySym("Dollar", Qt::Key_Dollar ); + defKeySym("Percent", Qt::Key_Percent ); + defKeySym("Ampersand", Qt::Key_Ampersand ); + defKeySym("Apostrophe", Qt::Key_Apostrophe ); + defKeySym("ParenLeft", Qt::Key_ParenLeft ); + defKeySym("ParenRight", Qt::Key_ParenRight ); + defKeySym("Asterisk", Qt::Key_Asterisk ); + defKeySym("Plus", Qt::Key_Plus ); + defKeySym("Comma", Qt::Key_Comma ); + defKeySym("Minus", Qt::Key_Minus ); + defKeySym("Period", Qt::Key_Period ); + defKeySym("Slash", Qt::Key_Slash ); + defKeySym("0", Qt::Key_0 ); + defKeySym("1", Qt::Key_1 ); + defKeySym("2", Qt::Key_2 ); + defKeySym("3", Qt::Key_3 ); + defKeySym("4", Qt::Key_4 ); + defKeySym("5", Qt::Key_5 ); + defKeySym("6", Qt::Key_6 ); + defKeySym("7", Qt::Key_7 ); + defKeySym("8", Qt::Key_8 ); + defKeySym("9", Qt::Key_9 ); + defKeySym("Colon", Qt::Key_Colon ); + defKeySym("Semicolon", Qt::Key_Semicolon ); + defKeySym("Less", Qt::Key_Less ); + defKeySym("Equal", Qt::Key_Equal ); + defKeySym("Greater", Qt::Key_Greater ); + defKeySym("Question", Qt::Key_Question ); + defKeySym("At", Qt::Key_At ); + defKeySym("A", Qt::Key_A ); + defKeySym("B", Qt::Key_B ); + defKeySym("C", Qt::Key_C ); + defKeySym("D", Qt::Key_D ); + defKeySym("E", Qt::Key_E ); + defKeySym("F", Qt::Key_F ); + defKeySym("G", Qt::Key_G ); + defKeySym("H", Qt::Key_H ); + defKeySym("I", Qt::Key_I ); + defKeySym("J", Qt::Key_J ); + defKeySym("K", Qt::Key_K ); + defKeySym("L", Qt::Key_L ); + defKeySym("M", Qt::Key_M ); + defKeySym("N", Qt::Key_N ); + defKeySym("O", Qt::Key_O ); + defKeySym("P", Qt::Key_P ); + defKeySym("Q", Qt::Key_Q ); + defKeySym("R", Qt::Key_R ); + defKeySym("S", Qt::Key_S ); + defKeySym("T", Qt::Key_T ); + defKeySym("U", Qt::Key_U ); + defKeySym("V", Qt::Key_V ); + defKeySym("W", Qt::Key_W ); + defKeySym("X", Qt::Key_X ); + defKeySym("Y", Qt::Key_Y ); + defKeySym("Z", Qt::Key_Z ); + defKeySym("BracketLeft", Qt::Key_BracketLeft ); + defKeySym("Backslash", Qt::Key_Backslash ); + defKeySym("BracketRight", Qt::Key_BracketRight); + defKeySym("AsciiCircum", Qt::Key_AsciiCircum ); + defKeySym("Underscore", Qt::Key_Underscore ); + defKeySym("QuoteLeft", Qt::Key_QuoteLeft ); + defKeySym("BraceLeft", Qt::Key_BraceLeft ); + defKeySym("Bar", Qt::Key_Bar ); + defKeySym("BraceRight", Qt::Key_BraceRight ); + defKeySym("AsciiTilde", Qt::Key_AsciiTilde ); +} + +KeyTransSymbols::KeyTransSymbols() +{ + defModSyms(); + defOprSyms(); + defKeySyms(); +} + +// Global material ----------------------------------------------------------- + +static int keytab_serial = 0; //FIXME: remove,localize + +static QIntDict * numb2keymap = 0L; +static QDict * path2keymap = 0L; + +KeyTrans* KeyTrans::find(int numb) +{ + KeyTrans* res = numb2keymap->find(numb); + return res ? res : numb2keymap->find(0); +} + +KeyTrans* KeyTrans::find(const char* path) +{ + KeyTrans* res = path2keymap->find(path); + return res ? res : numb2keymap->find(0); +} + +int KeyTrans::count() +{ + return numb2keymap->count(); +} + +void KeyTrans::addKeyTrans() +{ + this->numb = keytab_serial ++; + numb2keymap->insert(numb,this); + path2keymap->insert(path,this); +} + +void KeyTrans::loadAll() +{ + if (!numb2keymap) + numb2keymap = new QIntDict; + if (!path2keymap) + path2keymap = new QDict; + if (!syms) + syms = new KeyTransSymbols; + + defaultKeyTrans()->addKeyTrans(); + + + QString path = QPEApplication::qpeDir() + "etc/keytabs"; + QDir dir(path); + QStringList lst = dir.entryList("*.keytab"); + + for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { + QFile file(path + "/" + *it); + KeyTrans* sc = KeyTrans::fromDevice(*it, file); + if (sc) { + sc->addKeyTrans(); + } + } + +} + +// Debugging material ----------------------------------------------------------- +/* +void TestTokenizer(QBuffer &buf) +{ + // opening sequence + + buf.open(IO_ReadOnly); + cc = buf.getch(); + lineno = 1; + + // Test tokenizer + + while (getSymbol(buf)) ReportToken(); + + buf.close(); +} + +void test() +{ + // Opening sequence + + QCString txt = +#include "default.keytab.h" + ; + QBuffer buf(txt); + if (0) TestTokenizer(buf); + if (1) { KeyTrans kt; kt.scanTable(buf); } +} +*/ diff --git a/core/apps/embeddedkonsole/keytrans.h b/core/apps/embeddedkonsole/keytrans.h new file mode 100644 index 0000000..ef6ed15 --- a/dev/null +++ b/core/apps/embeddedkonsole/keytrans.h @@ -0,0 +1,93 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [keytrans.h] X Terminal Emulation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef KEYTRANS_H +#define KEYTRANS_H + +#include +#include +#include + +#define BITS_NewLine 0 +#define BITS_BsHack 1 +#define BITS_Ansi 2 +#define BITS_AppCuKeys 3 +#define BITS_Control 4 +#define BITS_Shift 5 +#define BITS_Alt 6 +#define BITS_COUNT 7 + +#define CMD_send 0 +#define CMD_emitSelection 1 +#define CMD_scrollPageUp 2 +#define CMD_scrollPageDown 3 +#define CMD_scrollLineUp 4 +#define CMD_scrollLineDown 5 +#define CMD_prevSession 6 +#define CMD_nextSession 7 + +#define BITS(x,v) ((((v)!=0)<<(x))) + + +class KeyTrans +{ +public: + KeyTrans(); + ~KeyTrans(); + static KeyTrans* defaultKeyTrans(); + static KeyTrans* fromFile(const char* path); + static KeyTrans* find(int numb); + static KeyTrans* find(const char* path); +public: + static int count(); + static void loadAll(); +public: + bool findEntry(int key, int bits, int* cmd, const char** txt, int* len); +private: + void addKeyTrans(); + static KeyTrans* fromDevice(QString path, QIODevice &buf); +public: + class KeyEntry + { + public: + KeyEntry(int ref, int key, int bits, int mask, int cmd, QString txt); + ~KeyEntry(); + public: + bool matches(int key, int bits, int mask); + QString text(); + public: + int ref; + private: + int key; + int bits; + int mask; + public: + int cmd; + QString txt; + }; +public: + KeyEntry* addEntry(int ref, int key, int bits, int mask, int cmd, QString txt); +private: + QList table; +public: //FIXME: we'd do better + QString hdr; + int numb; + QString path; +}; + +#endif diff --git a/core/apps/embeddedkonsole/konsole.cpp b/core/apps/embeddedkonsole/konsole.cpp new file mode 100644 index 0000000..7253baf --- a/dev/null +++ b/core/apps/embeddedkonsole/konsole.cpp @@ -0,0 +1,512 @@ +/* ---------------------------------------------------------------------- */ +/* */ +/* [main.C] Konsole */ +/* */ +/* ---------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole, an X terminal. */ +/* */ +/* The material contained in here more or less directly orginates from */ +/* kvt, which is copyright (c) 1996 by Matthias Ettrich */ +/* */ +/* ---------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "konsole.h" +#include "keytrans.h" + +class EKNumTabBar : public QTabBar { +public: + void numberTabs() + { + // Yes, it really is this messy. QTabWidget needs functions + // that provide acces to tabs in a sequential way. + int m=INT_MIN; + for (int i=0; i it(*tabList()); + int x=INT_MAX; + for( QTab* t; (t=it.current()); ++it ) { + int tx = t->rect().x(); + if ( txm ) { + x = tx; + left = t; + } + } + if ( left ) { + left->setText(QString::number(i+1)); + m = left->rect().x(); + } + } + } +}; + +class EKNumTabWidget : public QTabWidget { +public: + EKNumTabWidget(QWidget* parent) : QTabWidget(parent) + { + } + + void addTab(QWidget* w) + { + QTab* t = new QTab(QString::number(tabBar()->count()+1)); + QTabWidget::addTab(w,t); + } + + void removeTab(QWidget* w) + { + removePage(w); + ((EKNumTabBar*)tabBar())->numberTabs(); + } +}; + +// This could be configurable or dynamicly generated from the bash history +// file of the user +static const char *commonCmds[] = +{ + "ls ", + //"ls -la ", + "cd ", + "pwd", + //"cat", + //"less ", + //"vi ", + //"man ", + "echo ", + "set ", + //"ps", + "ps aux", + //"tar", + //"tar -zxf", + "grep ", + //"grep -i", + //"mkdir", + "cp ", + "mv ", + "rm ", + "rmdir ", + //"chmod", + //"su", +// "top", + //"find", + //"make", + //"tail", + "cardctl eject", + "ifconfig ", +// "iwconfig eth0 ", + "nc localhost 7777", + "nc localhost 7776", + //"mount /dev/hda1", + +/* + "gzip", + "gunzip", + "chgrp", + "chown", + "date", + "dd", + "df", + "dmesg", + "fuser", + "hostname", + "kill", + "killall", + "ln", + "ping", + "mount", + "more", + "sort", + "touch", + "umount", + "mknod", + "netstat", +*/ + + "exit", + NULL +}; + + +Konsole::Konsole(QWidget* parent, const char* name, WFlags fl) : + QMainWindow(parent, name, fl) +{ + QStrList args; + init("/bin/sh",args); +} + +Konsole::Konsole(const char* name, const char* _pgm, QStrList & _args, int) + : QMainWindow(0, name) +{ + init(_pgm,_args); +} + +void Konsole::init(const char* _pgm, QStrList & _args) +{ + b_scroll = TRUE; // histon; + n_keytab = 0; + n_render = 0; + + setCaption( tr("Terminal") ); + setIcon( Resource::loadPixmap( "konsole" ) ); + + Config cfg("Konsole"); + cfg.setGroup("Konsole"); + + // initialize the list of allowed fonts /////////////////////////////////// + cfont = cfg.readNumEntry("FontID", 1); + QFont f = QFont("Micro", 4, QFont::Normal); + f.setFixedPitch(TRUE); + fonts.append(new VTFont(tr("Micro"), f)); + + f = QFont("Fixed", 7, QFont::Normal); + f.setFixedPitch(TRUE); + fonts.append(new VTFont(tr("Small Fixed"), f)); + + f = QFont("Fixed", 12, QFont::Normal); + f.setFixedPitch(TRUE); + fonts.append(new VTFont(tr("Medium Fixed"), f)); + + // create terminal emulation framework //////////////////////////////////// + nsessions = 0; + tab = new EKNumTabWidget(this); + tab->setTabPosition(QTabWidget::Bottom); + connect(tab, SIGNAL(currentChanged(QWidget*)), this, SLOT(switchSession(QWidget*))); + + // create terminal toolbar //////////////////////////////////////////////// + setToolBarsMovable( FALSE ); + QPEToolBar *menuToolBar = new QPEToolBar( this ); + menuToolBar->setHorizontalStretchable( TRUE ); + + QPEMenuBar *menuBar = new QPEMenuBar( menuToolBar ); + + fontList = new QPopupMenu( this ); + for(uint i = 0; i < fonts.count(); i++) { + VTFont *fnt = fonts.at(i); + fontList->insertItem(fnt->getName(), i); + } + fontChanged(cfont); + + connect( fontList, SIGNAL( activated(int) ), this, SLOT( fontChanged(int) )); + + menuBar->insertItem( tr("Font"), fontList ); + + QPEToolBar *toolbar = new QPEToolBar( this ); + + QAction *a; + + // Button Commands + a = new QAction( tr("New"), Resource::loadPixmap( "konsole" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( newSession() ) ); a->addTo( toolbar ); + a = new QAction( tr("Enter"), Resource::loadPixmap( "konsole/enter" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitEnter() ) ); a->addTo( toolbar ); + a = new QAction( tr("Space"), Resource::loadPixmap( "konsole/space" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitSpace() ) ); a->addTo( toolbar ); + a = new QAction( tr("Tab"), Resource::loadPixmap( "konsole/tab" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitTab() ) ); a->addTo( toolbar ); + a = new QAction( tr("Up"), Resource::loadPixmap( "konsole/up" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitUp() ) ); a->addTo( toolbar ); + a = new QAction( tr("Down"), Resource::loadPixmap( "konsole/down" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitDown() ) ); a->addTo( toolbar ); + a = new QAction( tr("Paste"), Resource::loadPixmap( "paste" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitPaste() ) ); a->addTo( toolbar ); +/* + a = new QAction( tr("Up"), Resource::loadPixmap( "up" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitUp() ) ); a->addTo( toolbar ); + a = new QAction( tr("Down"), Resource::loadPixmap( "down" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( hitDown() ) ); a->addTo( toolbar ); +*/ + + QPEToolBar *secondToolBar = new QPEToolBar( this ); + secondToolBar->setHorizontalStretchable( TRUE ); + + QComboBox *commonCombo = new QComboBox( secondToolBar ); +// commonCombo->setEditable( TRUE ); + for (int i = 0; commonCmds[i] != NULL; i++) + commonCombo->insertItem( commonCmds[i], i ); + connect( commonCombo, SIGNAL( activated(int) ), this, SLOT( enterCommand(int) )); + + // create applications ///////////////////////////////////////////////////// + setCentralWidget(tab); + + // load keymaps //////////////////////////////////////////////////////////// + KeyTrans::loadAll(); + for (int i = 0; i < KeyTrans::count(); i++) + { KeyTrans* s = KeyTrans::find(i); + assert( s ); + } + + se_pgm = _pgm; + se_args = _args; + + // read and apply default values /////////////////////////////////////////// + resize(321, 321); // Dummy. + QSize currentSize = size(); + if (currentSize != size()) + defaultSize = size(); +} + +void Konsole::show() +{ + if ( !nsessions ) { + newSession(); + } + QMainWindow::show(); +} + +void Konsole::initSession(const char*, QStrList &) +{ + QMainWindow::show(); +} + +Konsole::~Konsole() +{ + while (nsessions > 0) { + doneSession(getTe()->currentSession, 0); + } + + Config cfg("Konsole"); + cfg.setGroup("Konsole"); + cfg.writeEntry("FontID", cfont); +} + +void Konsole::fontChanged(int f) +{ + VTFont* font = fonts.at(f); + if (font != 0) { + for(uint i = 0; i < fonts.count(); i++) { + fontList->setItemChecked(i, (i == (uint) f) ? TRUE : FALSE); + } + + cfont = f; + + TEWidget* te = getTe(); + if (te != 0) { + te->setVTFont(font->getFont()); + } + } +} + +void Konsole::enterCommand(int c) +{ + TEWidget* te = getTe(); + if (te != 0) { + QString text = commonCmds[c]; + te->emitText(text); + } +} + +void Konsole::hitEnter() +{ + TEWidget* te = getTe(); + if (te != 0) { + te->emitText(QString("\r")); + } +} + +void Konsole::hitSpace() +{ + TEWidget* te = getTe(); + if (te != 0) { + te->emitText(QString(" ")); + } +} + +void Konsole::hitTab() +{ + TEWidget* te = getTe(); + if (te != 0) { + te->emitText(QString("\t")); + } +} + +void Konsole::hitPaste() +{ + TEWidget* te = getTe(); + if (te != 0) { + te->pasteClipboard(); + } +} + +void Konsole::hitUp() +{ + TEWidget* te = getTe(); + if (te != 0) { + QKeyEvent ke( QKeyEvent::KeyPress, Qt::Key_Up, 0, 0); + QApplication::sendEvent( te, &ke ); + } +} + +void Konsole::hitDown() +{ + TEWidget* te = getTe(); + if (te != 0) { + QKeyEvent ke( QKeyEvent::KeyPress, Qt::Key_Down, 0, 0); + QApplication::sendEvent( te, &ke ); + } +} + +/** + This function calculates the size of the external widget + needed for the internal widget to be + */ +QSize Konsole::calcSize(int columns, int lines) { + TEWidget* te = getTe(); + if (te != 0) { + QSize size = te->calcSize(columns, lines); + return size; + } else { + QSize size; + return size; + } +} + +/** + sets application window to a size based on columns X lines of the te + guest widget. Call with (0,0) for setting default size. +*/ + +void Konsole::setColLin(int columns, int lines) +{ + if ((columns==0) || (lines==0)) + { + if (defaultSize.isEmpty()) // not in config file : set default value + { + defaultSize = calcSize(80,24); + // notifySize(24,80); // set menu items (strange arg order !) + } + resize(defaultSize); + } else { + resize(calcSize(columns, lines)); + // notifySize(lines,columns); // set menu items (strange arg order !) + } +} + +/* +void Konsole::setFont(int fontno) +{ + QFont f; + if (fontno == 0) + f = defaultFont = QFont( "Helvetica", 12 ); + else + if (fonts[fontno][0] == '-') + f.setRawName( fonts[fontno] ); + else + { + f.setFamily(fonts[fontno]); + f.setRawMode( TRUE ); + } + if ( !f.exactMatch() && fontno != 0) + { + QString msg = i18n("Font `%1' not found.\nCheck README.linux.console for help.").arg(fonts[fontno]); + QMessageBox(this, msg); + return; + } + if (se) se->setFontNo(fontno); + te->setVTFont(f); + n_font = fontno; +} +*/ + +// --| color selection |------------------------------------------------------- + +void Konsole::changeColumns(int columns) +{ + TEWidget* te = getTe(); + if (te != 0) { + setColLin(columns,te->Lines()); + te->update(); + } +} + +//FIXME: If a child dies during session swap, +// this routine might be called before +// session swap is completed. + +void Konsole::doneSession(TESession*, int ) +{ + TEWidget *te = getTe(); + if (te != 0) { + te->currentSession->setConnect(FALSE); + tab->removeTab(te); + delete te->currentSession; + delete te; + nsessions--; + } + + if (nsessions == 0) { + close(); + } +} + + +void Konsole::newSession() { + TEWidget* te = new TEWidget(tab); + te->setBackgroundMode(PaletteBase); + te->setVTFont(fonts.at(cfont)->getFont()); + tab->addTab(te); + TESession* se = new TESession(this, te, se_pgm, se_args, "xterm"); + te->currentSession = se; + connect( se, SIGNAL(done(TESession*,int)), this, SLOT(doneSession(TESession*,int)) ); + se->run(); + se->setConnect(TRUE); + se->setHistory(b_scroll); + tab->setCurrentPage(nsessions); + nsessions++; +} + +TEWidget* Konsole::getTe() { + if (nsessions) { + return (TEWidget *) tab->currentPage(); + } else { + return 0; + } + } + +void Konsole::switchSession(QWidget* w) { + TEWidget* te = (TEWidget *) w; + + QFont teFnt = te->getVTFont(); + for(uint i = 0; i < fonts.count(); i++) { + VTFont *fnt = fonts.at(i); + bool cf = fnt->getFont() == teFnt; + fontList->setItemChecked(i, cf); + if (cf) { + cfont = i; + } + } +} diff --git a/core/apps/embeddedkonsole/konsole.h b/core/apps/embeddedkonsole/konsole.h new file mode 100644 index 0000000..819ea5d --- a/dev/null +++ b/core/apps/embeddedkonsole/konsole.h @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------- */ +/* */ +/* [konsole.h] Konsole */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole, an X terminal. */ +/* */ +/* The material contained in here more or less directly orginates from */ +/* kvt, which is copyright (c) 1996 by Matthias Ettrich */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef KONSOLE_H +#define KONSOLE_H + + +#include +#include +#include +#include +#include +#include +#include + +#include "MyPty.h" +#include "TEWidget.h" +#include "TEmuVt102.h" +#include "session.h" + +class EKNumTabWidget; + +class Konsole : public QMainWindow +{ +Q_OBJECT + +public: + + Konsole(QWidget* parent = 0, const char* name = 0, WFlags fl = 0); + Konsole(const char * name, const char* pgm, QStrList & _args, int histon); + ~Konsole(); + void setColLin(int columns, int lines); + + void show(); + +private slots: + void doneSession(TESession*,int); + void changeColumns(int); + void fontChanged(int); + void enterCommand(int); + void hitEnter(); + void hitSpace(); + void hitTab(); + void hitPaste(); + void hitUp(); + void hitDown(); + void switchSession(QWidget *); + void newSession(); + +private: + void init(const char* _pgm, QStrList & _args); + void initSession(const char* _pgm, QStrList & _args); + void runSession(TESession* s); + void setColorPixmaps(); + void setHistory(bool); + QSize calcSize(int columns, int lines); + TEWidget* getTe(); + +private: + class VTFont + { + public: + VTFont(QString name, QFont& font) + { + this->name = name; + this->font = font; + } + + QFont& getFont() + { + return font; + } + + QString getName() + { + return name; + } + + private: + QString name; + QFont font; + }; + + EKNumTabWidget* tab; + int nsessions; + QList fonts; + int cfont; + QCString se_pgm; + QStrList se_args; + + QPopupMenu* fontList; + + // history scrolling I think + bool b_scroll; + + int n_keytab; + int n_scroll; + int n_render; + QString pmPath; // pixmap path + QString dropText; + QFont defaultFont; + QSize defaultSize; + +}; + +#endif + diff --git a/core/apps/embeddedkonsole/main.cpp b/core/apps/embeddedkonsole/main.cpp new file mode 100644 index 0000000..e3ba346 --- a/dev/null +++ b/core/apps/embeddedkonsole/main.cpp @@ -0,0 +1,60 @@ +/* ---------------------------------------------------------------------- */ +/* */ +/* [main.C] Konsole */ +/* */ +/* ---------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole, an X terminal. */ +/* */ +/* The material contained in here more or less directly orginates from */ +/* kvt, which is copyright (c) 1996 by Matthias Ettrich */ +/* */ +/* ---------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#include "konsole.h" + +#include + +#include + +#include +#include +#include + + +/* --| main |------------------------------------------------------ */ +int main(int argc, char* argv[]) +{ + setuid(getuid()); setgid(getgid()); // drop privileges + + QPEApplication a( argc, argv ); + +#ifdef FAKE_CTRL_AND_ALT + QPEApplication::grabKeyboard(); // for CTRL and ALT +#endif + + QStrList tmp; + const char* shell = getenv("SHELL"); + if (shell == NULL || *shell == '\0') + shell = "/bin/sh"; + + // sh is completely broken on familiar. Let's try to get something better + if ( qstrcmp( shell, "/bin/shell" ) == 0 && QFile::exists( "/bin/bash" ) ) + shell = "/bin/bash"; + + putenv((char*)"COLORTERM="); // to trigger mc's color detection + + Konsole m( "test", shell, tmp, TRUE ); + m.setCaption( Konsole::tr("Terminal") ); + a.showMainWidget( &m ); + + return a.exec(); +} diff --git a/core/apps/embeddedkonsole/qpe-embeddedkonsole.control b/core/apps/embeddedkonsole/qpe-embeddedkonsole.control new file mode 100644 index 0000000..9b7c355 --- a/dev/null +++ b/core/apps/embeddedkonsole/qpe-embeddedkonsole.control @@ -0,0 +1,9 @@ +Files: bin/embeddedkonsole apps/Applications/embeddedkonsole.desktop pics/konsole etc/keytabs/* +Priority: optional +Section: qpe/applications +Maintainer: Warwick Allison +Architecture: arm +Version: $QPE_VERSION-4 +Depends: qpe-base ($QPE_VERSION), ptydevs +Description: KDE's konsole (shell terminal) + Ported to the Qtopia environment. diff --git a/core/apps/embeddedkonsole/session.cpp b/core/apps/embeddedkonsole/session.cpp new file mode 100644 index 0000000..520af86 --- a/dev/null +++ b/core/apps/embeddedkonsole/session.cpp @@ -0,0 +1,157 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ +#include "session.h" +#include +// #include + +#include + +#define HERE fprintf(stderr,"%s(%d): here\n",__FILE__,__LINE__) + +/*! \class TESession + + Sessions are combinations of TEPTy and Emulations. + + The stuff in here does not belong to the terminal emulation framework, + but to main.C. It serves it's duty by providing a single reference + to TEPTy/Emulation pairs. In fact, it is only there to demonstrate one + of the abilities of the framework - multible sessions. +*/ + +TESession::TESession(QMainWindow* main, TEWidget* te, const char* _pgm, QStrList & _args, const char *_term) : schema_no(0), font_no(3), pgm(_pgm), args(_args) +{ + // sh = new TEPty(); + sh = new MyPty(); + em = new TEmuVt102(te); + + term = _term; + + sh->setSize(te->Lines(),te->Columns()); // not absolutely nessesary + QObject::connect( sh,SIGNAL(block_in(const char*,int)), + em,SLOT(onRcvBlock(const char*,int)) ); + QObject::connect( em,SIGNAL(ImageSizeChanged(int,int)), + sh,SLOT(setSize(int,int))); + + // 'main' should do those connects itself, somehow. + // These aren't KTMW's slots, but konsole's.(David) + +/* + QObject::connect( em,SIGNAL(ImageSizeChanged(int,int)), + main,SLOT(notifySize(int,int))); +*/ + QObject::connect( em,SIGNAL(sndBlock(const char*,int)), + sh,SLOT(send_bytes(const char*,int)) ); + QObject::connect( em,SIGNAL(changeColumns(int)), + main,SLOT(changeColumns(int)) ); +/* + QObject::connect( em,SIGNAL(changeTitle(int, const QString&)), + main,SLOT(changeTitle(int, const QString&)) ); +*/ + QObject::connect( sh,SIGNAL(done(int)), this,SLOT(done(int)) ); +} + + + +void TESession::run() +{ + //kdDebug() << "Running the session!" << pgm << "\n"; + sh->run(pgm,args,term.data(),FALSE); +} + +void TESession::kill(int ) // signal) +{ +// sh->kill(signal); +} + +TESession::~TESession() +{ + QObject::disconnect( sh, SIGNAL( done( int ) ), + this, SLOT( done( int ) ) ); + delete em; + delete sh; +} + +void TESession::setConnect(bool c) +{ + em->setConnect(c); +} + +void TESession::done(int status) +{ + emit done(this,status); +} + +void TESession::terminate() +{ + delete this; +} + +TEmulation* TESession::getEmulation() +{ + return em; +} + +// following interfaces might be misplaced /// + +int TESession::schemaNo() +{ + return schema_no; +} + +int TESession::keymap() +{ + return keymap_no; +} + +int TESession::fontNo() +{ + return font_no; +} + +const char* TESession::emuName() +{ + return term.data(); +} + +void TESession::setSchemaNo(int sn) +{ + schema_no = sn; +} + +void TESession::setKeymapNo(int kn) +{ + keymap_no = kn; + em->setKeytrans(kn); +} + +void TESession::setFontNo(int fn) +{ + font_no = fn; +} + +void TESession::setTitle(const QString& title) +{ + this->title = title; +} + +const QString& TESession::Title() +{ + return title; +} + +void TESession::setHistory(bool on) +{ + em->setHistory( on ); +} + +bool TESession::history() +{ + return em->history(); +} + +// #include "session.moc" diff --git a/core/apps/embeddedkonsole/session.h b/core/apps/embeddedkonsole/session.h new file mode 100644 index 0000000..4a61569 --- a/dev/null +++ b/core/apps/embeddedkonsole/session.h @@ -0,0 +1,93 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [session.h] Testbed for TE framework */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle */ +/* */ +/* This file is part of Konsole, an X terminal. */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef SESSION_H +#define SESSION_H + +#include +#include +#include + +#include "MyPty.h" +#include "TEWidget.h" +#include "TEmuVt102.h" + +class TESession : public QObject +{ Q_OBJECT + +public: + + TESession(QMainWindow* main, TEWidget* w, + const char* pgm, QStrList & _args, + const char* term); + ~TESession(); + +public: + + void setConnect(bool r); + TEmulation* getEmulation(); // to control emulation + bool isSecure(); + +public: + + int schemaNo(); + int fontNo(); + const char* emuName(); + const QString& Title(); + bool history(); + int keymap(); + + void setHistory(bool on); + void setSchemaNo(int sn); + void setKeymapNo(int kn); + void setFontNo(int fn); + void setTitle(const QString& title); + void kill(int signal); + +public slots: + + void run(); + void done(int status); + void terminate(); + +signals: + + void done(TESession*, int); + +private: + + // TEPty* sh; + MyPty* sh; + TEWidget* te; + TEmulation* em; + + //FIXME: using the indices here + // is propably very bad. We should + // use a persistent reference instead. + int schema_no; + int font_no; + int keymap_no; + QString title; + + const char* pgm; + QStrList args; + + QCString term; +}; + +#endif diff --git a/core/apps/helpbrowser/.cvsignore b/core/apps/helpbrowser/.cvsignore new file mode 100644 index 0000000..6fe2396 --- a/dev/null +++ b/core/apps/helpbrowser/.cvsignore @@ -0,0 +1,2 @@ +moc_* +Makefile diff --git a/core/apps/helpbrowser/Makefile.in b/core/apps/helpbrowser/Makefile.in new file mode 100644 index 0000000..8f0ce0e --- a/dev/null +++ b/core/apps/helpbrowser/Makefile.in @@ -0,0 +1,119 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = helpbrowser +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = helpbrowser.h +SOURCES = helpbrowser.cpp \ + main.cpp +OBJECTS = helpbrowser.o \ + main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_helpbrowser.cpp +OBJMOC = moc_helpbrowser.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake helpbrowser.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +helpbrowser.o: helpbrowser.cpp \ + helpbrowser.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +main.o: main.cpp \ + helpbrowser.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +moc_helpbrowser.o: moc_helpbrowser.cpp \ + helpbrowser.h + +moc_helpbrowser.cpp: helpbrowser.h + $(MOC) helpbrowser.h -o moc_helpbrowser.cpp + + diff --git a/core/apps/helpbrowser/helpbrowser.cpp b/core/apps/helpbrowser/helpbrowser.cpp new file mode 100644 index 0000000..d32fc0b --- a/dev/null +++ b/core/apps/helpbrowser/helpbrowser.cpp @@ -0,0 +1,227 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "helpbrowser.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +HelpBrowser::HelpBrowser( QWidget* parent, const char *name, WFlags f ) + : QMainWindow( parent, name, f ), + selectedURL() +{ + init( "index.html" ); +} + +void HelpBrowser::init( const QString& _home ) +{ + setIcon( Resource::loadPixmap( "help_icon" ) ); + + browser = new QTextBrowser( this ); + browser->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + connect( browser, SIGNAL( textChanged() ), + this, SLOT( textChanged() ) ); + + setCentralWidget( browser ); + setToolBarsMovable( FALSE ); + + if ( !_home.isEmpty() ) + browser->setSource( _home ); + + QPEToolBar* toolbar = new QPEToolBar( this ); + toolbar->setHorizontalStretchable( TRUE ); + QPEMenuBar *menu = new QPEMenuBar( toolbar ); + + toolbar = new QPEToolBar( this ); + // addToolBar( toolbar, "Toolbar"); + + //QPopupMenu* go = new QPopupMenu( this ); + backAction = new QAction( tr( "Backward" ), Resource::loadIconSet( "back" ), QString::null, 0, this, 0 ); + connect( backAction, SIGNAL( activated() ), browser, SLOT( backward() ) ); + connect( browser, SIGNAL( backwardAvailable( bool ) ), + backAction, SLOT( setEnabled( bool ) ) ); + //backAction->addTo( go ); + backAction->addTo( toolbar ); + backAction->setEnabled( FALSE ); + + forwardAction = new QAction( tr( "Forward" ), Resource::loadIconSet( "forward" ), QString::null, 0, this, 0 ); + connect( forwardAction, SIGNAL( activated() ), browser, SLOT( forward() ) ); + connect( browser, SIGNAL( forwardAvailable( bool ) ), + forwardAction, SLOT( setEnabled( bool ) ) ); + //forwardAction->addTo( go ); + forwardAction->addTo( toolbar ); + forwardAction->setEnabled( FALSE ); + + QAction *a = new QAction( tr( "Home" ), Resource::loadPixmap( "home" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), browser, SLOT( home() ) ); + //a->addTo( go ); + a->addTo( toolbar ); + + bookm = new QPopupMenu( this ); + bookm->insertItem( tr( "Add Bookmark" ), this, SLOT( addBookmark() ) ); + bookm->insertItem( tr( "Remove from Bookmarks" ), this, SLOT( removeBookmark() ) ); + bookm->insertSeparator(); + connect( bookm, SIGNAL( activated( int ) ), + this, SLOT( bookmChosen( int ) ) ); + + readBookmarks(); + + //menu->insertItem( tr("Go"), go ); + menu->insertItem( tr( "Bookmarks" ), bookm ); + + resize( 240, 300 ); + browser->setFocus(); + + connect( qApp, SIGNAL(appMessage(const QCString&, const QByteArray&)), + this, SLOT(appMessage(const QCString&, const QByteArray&)) ); +} + +void HelpBrowser::appMessage(const QCString& msg, const QByteArray& data) +{ + if ( msg == "showFile(QString)" ) { + QDataStream ds(data,IO_ReadOnly); + QString fn; + ds >> fn; + setDocument( fn ); + } +} + +void HelpBrowser::setDocument( const QString &doc ) +{ + if ( !doc.isEmpty() ) + browser->setSource( doc ); + raise(); +} + + +void HelpBrowser::textChanged() +{ + if ( browser->documentTitle().isNull() ) + setCaption( tr("Help Browser") ); + else + setCaption( browser->documentTitle() ) ; + + selectedURL = caption(); +} + +HelpBrowser::~HelpBrowser() +{ + QStringList bookmarks; + QMap::Iterator it2 = mBookmarks.begin(); + for ( ; it2 != mBookmarks.end(); ++it2 ) + bookmarks.append( (*it2).name + "=" + (*it2).file ); + + QFile f2( Global::applicationFileName("helpbrowser", "bookmarks") ); + if ( f2.open( IO_WriteOnly ) ) { + QDataStream s2( &f2 ); + s2 << bookmarks; + f2.close(); + } +} + +void HelpBrowser::pathSelected( const QString &_path ) +{ + browser->setSource( _path ); +} + +void HelpBrowser::readBookmarks() +{ + QString file = Global::applicationFileName("helpbrowser", "bookmarks"); + if ( QFile::exists( file ) ) { + QStringList bookmarks; + QFile f( file ); + if ( f.open( IO_ReadOnly ) ) { + QDataStream s( &f ); + s >> bookmarks; + f.close(); + } + QStringList::Iterator it = bookmarks.begin(); + for ( ; it != bookmarks.end(); ++it ) { + Bookmark b; + QString current = *it; + int equal = current.find( "=" ); + if ( equal < 1 || equal == (int)current.length() - 1 ) + continue; + b.name = current.left( equal ); + b.file = current.mid( equal + 1 ); + mBookmarks[ bookm->insertItem( b.name ) ] = b; + } + } +} + +void HelpBrowser::bookmChosen( int i ) +{ + if ( mBookmarks.contains( i ) ) + browser->setSource( mBookmarks[ i ].file ); +} + +void HelpBrowser::addBookmark() +{ + Bookmark b; + b.name = browser->documentTitle(); + b.file = browser->source(); + if (b.name.isEmpty() ) { + b.name = b.file.left( b.file.length() - 5 ); // remove .html + } + QMap::Iterator it; + for( it = mBookmarks.begin(); it != mBookmarks.end(); ++it ) + if ( (*it).file == b.file ) return; + mBookmarks[ bookm->insertItem( b.name ) ] = b; +} + +void HelpBrowser::removeBookmark() +{ + QString file = browser->source(); + QMap::Iterator it = mBookmarks.begin(); + for( ; it != mBookmarks.end(); ++it ) + if ( (*it).file == file ) { + bookm->removeItem( it.key() ); + mBookmarks.remove( it ); + break; + } +} diff --git a/core/apps/helpbrowser/helpbrowser.h b/core/apps/helpbrowser/helpbrowser.h new file mode 100644 index 0000000..2f7153a --- a/dev/null +++ b/core/apps/helpbrowser/helpbrowser.h @@ -0,0 +1,69 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef HELPWINDOW_H +#define HELPWINDOW_H + +#include +#include +#include +#include + +class QPopupMenu; +class QAction; + +class HelpBrowser : public QMainWindow +{ + Q_OBJECT +public: + HelpBrowser( QWidget* parent = 0, const char *name=0, WFlags f=0 ); + ~HelpBrowser(); + +public slots: + void setDocument( const QString &doc ); + +private slots: + void appMessage(const QCString& msg, const QByteArray& data); + void textChanged(); + + void pathSelected( const QString & ); + void bookmChosen( int ); + void addBookmark(); + void removeBookmark(); + +private: + void init( const QString & ); + void readBookmarks(); + + QTextBrowser* browser; + QAction *backAction; + QAction *forwardAction; + QString selectedURL; + struct Bookmark { + QString name; + QString file; + }; + QMap mBookmarks; + QMenuBar *menu; + QPopupMenu *bookm; +}; + +#endif + diff --git a/core/apps/helpbrowser/helpbrowser.pro b/core/apps/helpbrowser/helpbrowser.pro new file mode 100644 index 0000000..43230f1 --- a/dev/null +++ b/core/apps/helpbrowser/helpbrowser.pro @@ -0,0 +1,12 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = helpbrowser.h +SOURCES = helpbrowser.cpp \ + main.cpp +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe +INTERFACES = + +TRANSLATIONS = ../i18n/de/helpbrowser.ts diff --git a/core/apps/helpbrowser/main.cpp b/core/apps/helpbrowser/main.cpp new file mode 100644 index 0000000..1cb10b7 --- a/dev/null +++ b/core/apps/helpbrowser/main.cpp @@ -0,0 +1,34 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "helpbrowser.h" + +#include + +int main( int argc, char ** argv ) +{ + QPEApplication a( argc, argv ); + + HelpBrowser mw; + mw.setCaption( HelpBrowser::tr("HelpBrowser") ); + a.showMainDocumentWidget( &mw ); + + return a.exec(); +} diff --git a/core/apps/helpbrowser/qpe-helpbrowser.control b/core/apps/helpbrowser/qpe-helpbrowser.control new file mode 100644 index 0000000..b6e3404 --- a/dev/null +++ b/core/apps/helpbrowser/qpe-helpbrowser.control @@ -0,0 +1,10 @@ +Files: bin/helpbrowser apps/Applications/helpbrowser.desktop docs +Priority: optional +Section: qpe/applications +Maintainer: Warwick Allison +Architecture: arm +Arch: iPAQ +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Browse HTML help documents + The HTML help browser for the Qtopia environment. diff --git a/core/apps/qcop/.cvsignore b/core/apps/qcop/.cvsignore new file mode 100644 index 0000000..edfa921 --- a/dev/null +++ b/core/apps/qcop/.cvsignore @@ -0,0 +1,3 @@ +moc_* +*.moc +Makefile diff --git a/core/apps/qcop/Makefile.in b/core/apps/qcop/Makefile.in new file mode 100644 index 0000000..0a12320 --- a/dev/null +++ b/core/apps/qcop/Makefile.in @@ -0,0 +1,102 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = ../bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = qcop +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = +SOURCES = main.cpp +OBJECTS = main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = +OBJMOC = + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake qcop.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +main.o: main.cpp \ + $(QPEDIR)/include/qpe/qcopenvelope_qws.h + + diff --git a/core/apps/qcop/main.cpp b/core/apps/qcop/main.cpp new file mode 100644 index 0000000..73db0f6 --- a/dev/null +++ b/core/apps/qcop/main.cpp @@ -0,0 +1,85 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +static void usage() +{ + fprintf( stderr, "Usage: qcop channel command [parameters]\n" ); +} + +static void syntax( const QString &where, const QString &what ) +{ + fprintf( stderr, "Syntax error in %s: %s\n", where.latin1(), what.latin1() ); + exit(1); +} + +int main( int argc, char *argv[] ) +{ + QApplication app( argc, argv ); + + if ( argc < 3 ) { + usage(); + exit(1); + } + + QString channel = argv[1]; + QString command = argv[2]; + command.stripWhiteSpace(); + + int paren = command.find( "(" ); + if ( paren <= 0 ) + syntax( "command", command ); + + QString params = command.mid( paren + 1 ); + if ( params[params.length()-1] != ')' ) + syntax( "command", command ); + + params.truncate( params.length()-1 ); + QCopEnvelope env(channel.latin1(), command.latin1()); + + int argIdx = 3; + + QStringList paramList = QStringList::split( ",", params ); + QStringList::Iterator it; + for ( it = paramList.begin(); it != paramList.end(); ++it ) { + QString arg = argv[argIdx]; + if ( *it == "QString" ) { + env << arg; + } else if ( *it == "int" ) { + env << arg.toInt(); + } else { + syntax( "paramter type", *it ); + } + argIdx++; + } + + QTimer::singleShot( 0, &app, SLOT(quit()) ); + return app.exec(); +} + diff --git a/core/apps/qcop/qcop.pro b/core/apps/qcop/qcop.pro new file mode 100644 index 0000000..b52bfd8 --- a/dev/null +++ b/core/apps/qcop/qcop.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = ../bin +HEADERS = +SOURCES = main.cpp +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe +INTERFACES = +TARGET = qcop diff --git a/core/apps/qcop/qpe-qcop.control b/core/apps/qcop/qpe-qcop.control new file mode 100644 index 0000000..60107c4 --- a/dev/null +++ b/core/apps/qcop/qpe-qcop.control @@ -0,0 +1,9 @@ +Files: bin/qcop +Priority: required +Section: qpe/system +Maintainer: Martin Jones +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qt-embedded (>=$QTE_VERSION) +Description: Interprocess communication client + Interprocess communication client for the Qtopia environment. diff --git a/core/apps/textedit/.cvsignore b/core/apps/textedit/.cvsignore new file mode 100644 index 0000000..edfa921 --- a/dev/null +++ b/core/apps/textedit/.cvsignore @@ -0,0 +1,3 @@ +moc_* +*.moc +Makefile diff --git a/core/apps/textedit/Makefile.in b/core/apps/textedit/Makefile.in new file mode 100644 index 0000000..84542bb --- a/dev/null +++ b/core/apps/textedit/Makefile.in @@ -0,0 +1,125 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = textedit +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = textedit.h +SOURCES = main.cpp \ + textedit.cpp +OBJECTS = main.o \ + textedit.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_textedit.cpp +OBJMOC = moc_textedit.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake textedit.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +main.o: main.cpp \ + textedit.h \ + $(QPEDIR)/include/qpe/filemanager.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +textedit.o: textedit.cpp \ + textedit.h \ + $(QPEDIR)/include/qpe/filemanager.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/fileselector.h \ + $(QPEDIR)/include/qpe/applnk.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +moc_textedit.o: moc_textedit.cpp \ + textedit.h \ + $(QPEDIR)/include/qpe/filemanager.h + +moc_textedit.cpp: textedit.h + $(MOC) textedit.h -o moc_textedit.cpp + + diff --git a/core/apps/textedit/inserttable.ui b/core/apps/textedit/inserttable.ui new file mode 100644 index 0000000..09fe3c3 --- a/dev/null +++ b/core/apps/textedit/inserttable.ui @@ -0,0 +1,103 @@ + +InsertTable********************************************************************* +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +********************************************************************* + + QDialog + + name + InsertTable + + + geometry + + 0 + 0 + 165 + 79 + + + + caption + Insert Table + + + + margin + 11 + + + spacing + 6 + + + QLabel + + name + TextLabel1 + + + text + Rows: + + + + QSpinBox + + name + spinRows + + + minValue + 1 + + + value + 1 + + + + QSpinBox + + name + spinColumns + + + minValue + 1 + + + value + 1 + + + + QLabel + + name + TextLabel1_2 + + + text + Columns: + + + + + diff --git a/core/apps/textedit/main.cpp b/core/apps/textedit/main.cpp new file mode 100644 index 0000000..d0d37d2 --- a/dev/null +++ b/core/apps/textedit/main.cpp @@ -0,0 +1,35 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "textedit.h" + +#include + +int main( int argc, char **argv ) +{ + QPEApplication a( argc, argv ); + + TextEdit e; + a.showMainDocumentWidget(&e); + if ( argc == 3 && argv[1] == QCString("-f") ) + e.openFile(argv[2]); + + a.exec(); +} diff --git a/core/apps/textedit/qpe-textedit.control b/core/apps/textedit/qpe-textedit.control new file mode 100644 index 0000000..b0dad7d --- a/dev/null +++ b/core/apps/textedit/qpe-textedit.control @@ -0,0 +1,9 @@ +Files: bin/textedit apps/Applications/textedit.desktop +Priority: optional +Section: qpe/applications +Maintainer: Warwick Allison +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Text Editor + The text editor for the Qtopia environment. diff --git a/core/apps/textedit/qtextedit.h b/core/apps/textedit/qtextedit.h new file mode 100644 index 0000000..b29a728 --- a/dev/null +++ b/core/apps/textedit/qtextedit.h @@ -0,0 +1,282 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QTEXTEDIT_H +#define QTEXTEDIT_H + +#include +#include +#include + +class QPainter; +class QTextDocument; +class QTextCursor; +class QKeyEvent; +class QResizeEvent; +class QMouseEvent; +class QTimer; +class QTextString; +class QVBox; +class QListBox; +class QTextCommand; +class QTextParag; +class QTextFormat; +class QFont; +class QColor; + +class QTextEdit : public QScrollView +{ + Q_OBJECT + +public: + QTextEdit( QWidget *parent, const QString &fn, bool tabify = FALSE ); + QTextEdit( QWidget *parent = 0, const char *name = 0 ); + virtual ~QTextEdit(); + +#if defined(QTEXTEDIT_OPEN_API) + QTextDocument *document() const; + QTextCursor *textCursor() const; +#endif + + QString text() const; + QString text( int parag, bool formatted = FALSE ) const; + Qt::TextFormat textFormat() const; + QString fileName() const; + + void cursorPosition( int ¶g, int &index ); + void selection( int ¶g_from, int &index_from, + int ¶g_to, int &index_to ); + virtual bool find( const QString &expr, bool cs, bool wo, bool forward = TRUE, + int *parag = 0, int *index = 0 ); + void insert( const QString &text, bool indent = FALSE, bool checkNewLine = FALSE ); + + int paragraphs() const; + int lines() const; + int linesOfParagraph( int parag ) const; + int lineOfChar( int parag, int chr ); + + bool isModified() const; + + bool italic() const; + bool bold() const; + bool underline() const; + QString family() const; + int pointSize() const; + QColor color() const; + QFont font() const; + int alignment() const; + int maxLines() const; + + const QStyleSheet* styleSheet() const; + void setStyleSheet( const QStyleSheet* styleSheet ); + + void setPaper( const QBrush& pap); + QBrush paper() const; + + void setLinkColor( const QColor& ); + QColor linkColor() const; + + void setLinkUnderline( bool ); + bool linkUnderline() const; + + void setMimeSourceFactory( const QMimeSourceFactory* factory ); + const QMimeSourceFactory* mimeSourceFactory() const; + + int heightForWidth( int w ) const; + + void append( const QString& text ); + + bool hasSelectedText() const; + QString selectedText() const; + + QString context() const; + + QString documentTitle() const; + + void scrollToAnchor( const QString& name ); + QString anchorAt(const QPoint& pos); + +public slots: + virtual void undo(); + virtual void redo(); + + virtual void cut(); + virtual void copy(); + virtual void paste(); + + virtual void indent(); + + virtual void setItalic( bool b ); + virtual void setBold( bool b ); + virtual void setUnderline( bool b ); + virtual void setFamily( const QString &f ); + virtual void setPointSize( int s ); + virtual void setColor( const QColor &c ); + virtual void setFont( const QFont &f ); + + virtual void setAlignment( int ); + + virtual void setParagType( QStyleSheetItem::DisplayMode, int listStyle ); + + virtual void setTextFormat( Qt::TextFormat f ); + virtual void setText( const QString &txt, const QString &context = QString::null ) { setText( txt, context, FALSE ); } + virtual void setText( const QString &txt, const QString &context, bool tabify ); + + virtual void load( const QString &fn ) { load( fn, FALSE ); } + virtual void load( const QString &fn, bool tabify ); + virtual void save( bool untabify = FALSE ) { save( QString::null, untabify ); } + virtual void save( const QString &fn, bool untabify = FALSE ); + + virtual void setCursorPosition( int parag, int index ); + virtual void setSelection( int parag_from, int index_from, + int parag_to, int index_to ); + + virtual void setModified( bool m ); + virtual void selectAll( bool select ); + + virtual void setMaxLines( int l ); + virtual void resetFormat(); + +signals: + void currentFontChanged( const QFont &f ); + void currentColorChanged( const QColor &c ); + void currentAlignmentChanged( int ); + void textChanged(); + void highlighted( const QString& ); + void linkClicked( const QString& ); + +protected: + void setFormat( QTextFormat *f, int flags ); + void drawContents( QPainter *p, int cx, int cy, int cw, int ch ); + void keyPressEvent( QKeyEvent *e ); + void resizeEvent( QResizeEvent *e ); + void contentsMousePressEvent( QMouseEvent *e ); + void contentsMouseMoveEvent( QMouseEvent *e ); + void contentsMouseReleaseEvent( QMouseEvent *e ); + void contentsMouseDoubleClickEvent( QMouseEvent *e ); +#ifndef QT_NO_DRAGANDDROP + void contentsDragEnterEvent( QDragEnterEvent *e ); + void contentsDragMoveEvent( QDragMoveEvent *e ); + void contentsDragLeaveEvent( QDragLeaveEvent *e ); + void contentsDropEvent( QDropEvent *e ); +#endif + bool eventFilter( QObject *o, QEvent *e ); + bool focusNextPrevChild( bool next ); +#if !defined(QTEXTEDIT_OPEN_API) + QTextDocument *document() const; + QTextCursor *textCursor() const; +#endif + +private slots: + void formatMore(); + void doResize(); + void doAutoScroll(); + void doChangeInterval(); + void blinkCursor(); + void setModified(); + void startDrag(); + +private: + enum MoveDirection { + MoveLeft, + MoveRight, + MoveUp, + MoveDown, + MoveHome, + MoveEnd, + MovePgUp, + MovePgDown + }; + enum KeyboardAction { + ActionBackspace, + ActionDelete, + ActionReturn + }; + + struct UndoRedoInfo { + enum Type { Invalid, Insert, Delete, Backspace, Return, RemoveSelected }; + UndoRedoInfo( QTextDocument *d ) : type( Invalid ), doc( d ) + { text = QString::null; id = -1; index = -1; } + void clear(); + inline bool valid() const { return !text.isEmpty() && id >= 0&& index >= 0; } + + QString text; + int id; + int index; + Type type; + QTextDocument *doc; + }; + +private: + virtual bool isReadOnly() const { return FALSE; } + virtual bool linksEnabled() const { return TRUE; } + void init(); + void ensureCursorVisible(); + void drawCursor( bool visible ); + void placeCursor( const QPoint &pos, QTextCursor *c = 0 ); + void moveCursor( int direction, bool shift, bool control ); + void moveCursor( int direction, bool control ); + void removeSelectedText(); + void doKeyboardAction( int action ); + bool doCompletion(); + void checkUndoRedoInfo( UndoRedoInfo::Type t ); + void repaintChanged(); + void updateCurrentFormat(); + void handleReadOnlyKeyEvent( QKeyEvent *e ); + void makeParagVisible( QTextParag *p ); + +private: + QTextDocument *doc; + QTextCursor *cursor; + bool drawAll; + bool mousePressed; + QTimer *formatTimer, *scrollTimer, *changeIntervalTimer, *blinkTimer, *dragStartTimer, *resizeTimer; + QTextParag *lastFormatted; + int interval; + QVBox *completionPopup; + QListBox *completionListBox; + int completionOffset; + UndoRedoInfo undoRedoInfo; + QTextFormat *currentFormat; + QPainter painter; + int currentAlignment; + bool inDoubleClick; + QPoint oldMousePos, mousePos; + QPixmap *buf_pixmap; + bool cursorVisible, blinkCursorVisible; + bool readOnly, modified, mightStartDrag; + QPoint dragStartPos; + int mLines; + bool firstResize; + QString onLink; + +}; + +inline QTextDocument *QTextEdit::document() const +{ + return doc; +} + +inline QTextCursor *QTextEdit::textCursor() const +{ + return cursor; +} + +#endif diff --git a/core/apps/textedit/textedit.cpp b/core/apps/textedit/textedit.cpp new file mode 100644 index 0000000..867625e --- a/dev/null +++ b/core/apps/textedit/textedit.cpp @@ -0,0 +1,594 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "textedit.h" + +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //getenv + + +#if QT_VERSION < 300 + +class QpeEditor : public QMultiLineEdit +{ + // Q_OBJECT +public: + QpeEditor( QWidget *parent, const char * name = 0 ) + : QMultiLineEdit( parent, name ) {} + + //public slots: + void find( const QString &txt, bool caseSensitive, + bool backwards ); + /* +signals: + void notFound(); + void searchWrapped(); + */ + +private: + +}; + + +void QpeEditor::find ( const QString &txt, bool caseSensitive, + bool backwards ) +{ + static bool wrap = FALSE; + int line, col; + if ( wrap ) { + if ( !backwards ) + line = col = 0; + wrap = FALSE; + // emit searchWrapped(); + } else { + getCursorPosition( &line, &col ); + } + //ignore backwards for now.... + if ( !backwards ) { + for ( ; ; ) { + if ( line >= numLines() ) { + wrap = TRUE; + //emit notFound(); + break; + } + int findCol = getString( line )->find( txt, col, caseSensitive ); + if ( findCol >= 0 ) { + setCursorPosition( line, findCol, FALSE ); + col = findCol + txt.length(); + setCursorPosition( line, col, TRUE ); + + //found = TRUE; + break; + } + line++; + col = 0; + } + + } + +} + + +#else + +#error "Must make a QpeEditor that inherits QTextEdit" + +#endif + + + + +static int u_id = 1; +static int get_unique_id() +{ + return u_id++; +} + +static const int nfontsizes = 6; +static const int fontsize[nfontsizes] = {8,10,12,14,18,24}; + +TextEdit::TextEdit( QWidget *parent, const char *name, WFlags f ) + : QMainWindow( parent, name, f ), bFromDocView( FALSE ) +{ + doc = 0; + + QString lang = getenv( "LANG" ); + + setToolBarsMovable( FALSE ); + + setIcon( Resource::loadPixmap( "TextEditor" ) ); + + QPEToolBar *bar = new QPEToolBar( this ); + bar->setHorizontalStretchable( TRUE ); + menu = bar; + + QPEMenuBar *mb = new QPEMenuBar( bar ); + QPopupMenu *file = new QPopupMenu( this ); + QPopupMenu *edit = new QPopupMenu( this ); + QPopupMenu *font = new QPopupMenu( this ); + + bar = new QPEToolBar( this ); + editBar = bar; + + QAction *a = new QAction( tr( "New" ), Resource::loadPixmap( "new" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( fileNew() ) ); + a->addTo( bar ); + a->addTo( file ); + + a = new QAction( tr( "Open" ), Resource::loadPixmap( "fileopen" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( fileOpen() ) ); + a->addTo( bar ); + a->addTo( file ); + + a = new QAction( tr( "Cut" ), Resource::loadPixmap( "cut" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( editCut() ) ); + a->addTo( editBar ); + a->addTo( edit ); + + a = new QAction( tr( "Copy" ), Resource::loadPixmap( "copy" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( editCopy() ) ); + a->addTo( editBar ); + a->addTo( edit ); + + a = new QAction( tr( "Paste" ), Resource::loadPixmap( "paste" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( editPaste() ) ); + a->addTo( editBar ); + a->addTo( edit ); + + a = new QAction( tr( "Find..." ), Resource::loadPixmap( "find" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( editFind() ) ); + edit->insertSeparator(); + a->addTo( bar ); + a->addTo( edit ); + + int defsize; + bool defb, defi, wrap; + { + Config cfg("TextEdit"); + cfg.setGroup("View"); + defsize = cfg.readNumEntry("FontSize",10); + defb = cfg.readBoolEntry("Bold",FALSE); + defi = cfg.readBoolEntry("Italic",FALSE); + wrap = cfg.readBoolEntry("Wrap",TRUE); + } + + zin = new QAction( tr("Zoom in"), QString::null, 0, this, 0 ); + connect( zin, SIGNAL( activated() ), this, SLOT( zoomIn() ) ); + zin->addTo( font ); + + zout = new QAction( tr("Zoom out"), QString::null, 0, this, 0 ); + connect( zout, SIGNAL( activated() ), this, SLOT( zoomOut() ) ); + zout->addTo( font ); + + font->insertSeparator(); + +#if 0 + QAction *ba = new QAction( tr("Bold"), QString::null, 0, this, 0 ); + connect( ba, SIGNAL( toggled(bool) ), this, SLOT( setBold(bool) ) ); + ba->setToggleAction(TRUE); + ba->addTo( font ); + + QAction *ia = new QAction( tr("Italic"), QString::null, 0, this, 0 ); + connect( ia, SIGNAL( toggled(bool) ), this, SLOT( setItalic(bool) ) ); + ia->setToggleAction(TRUE); + ia->addTo( font ); + + ba->setOn(defb); + ia->setOn(defi); + + font->insertSeparator(); +#endif + + QAction *wa = new QAction( tr("Wrap lines"), QString::null, 0, this, 0 ); + connect( wa, SIGNAL( toggled(bool) ), this, SLOT( setWordWrap(bool) ) ); + wa->setToggleAction(TRUE); + wa->addTo( font ); + + mb->insertItem( tr( "File" ), file ); + mb->insertItem( tr( "Edit" ), edit ); + mb->insertItem( tr( "View" ), font ); + + searchBar = new QPEToolBar(this); + addToolBar( searchBar, "Search", QMainWindow::Top, TRUE ); + + searchBar->setHorizontalStretchable( TRUE ); + + searchEdit = new QLineEdit( searchBar, "searchEdit" ); + searchBar->setStretchableWidget( searchEdit ); + connect( searchEdit, SIGNAL( textChanged( const QString & ) ), + this, SLOT( search() ) ); + + a = new QAction( tr( "Find Next" ), Resource::loadPixmap( "next" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( findNext() ) ); + a->addTo( searchBar ); + a->addTo( edit ); + + a = new QAction( tr( "Close Find" ), Resource::loadPixmap( "close" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), this, SLOT( findClose() ) ); + a->addTo( searchBar ); + + searchBar->hide(); + + editorStack = new QWidgetStack( this ); + setCentralWidget( editorStack ); + + searchVisible = FALSE; + + fileSelector = new FileSelector( "text/*", editorStack, "fileselector" , + TRUE, FALSE ); + fileSelector->setCategoriesVisible(TRUE); + connect( fileSelector, SIGNAL( closeMe() ), this, SLOT( showEditTools() ) ); + connect( fileSelector, SIGNAL( newSelected( const DocLnk &) ), this, SLOT( newFile( const DocLnk & ) ) ); + connect( fileSelector, SIGNAL( fileSelected( const DocLnk &) ), this, SLOT( openFile( const DocLnk & ) ) ); + fileOpen(); + + editor = new QpeEditor( editorStack ); + editorStack->addWidget( editor, get_unique_id() ); + + resize( 200, 300 ); + + setFontSize(defsize,TRUE); + wa->setOn(wrap); +} + +TextEdit::~TextEdit() +{ + save(); + + Config cfg("TextEdit"); + cfg.setGroup("View"); + QFont f = editor->font(); + cfg.writeEntry("FontSize",f.pointSize()); + cfg.writeEntry("Bold",f.bold()); + cfg.writeEntry("Italic",f.italic()); + cfg.writeEntry("Wrap",editor->wordWrap() == QMultiLineEdit::WidgetWidth); +} + +void TextEdit::zoomIn() +{ + setFontSize(editor->font().pointSize()+1,FALSE); +} + +void TextEdit::zoomOut() +{ + setFontSize(editor->font().pointSize()-1,TRUE); +} + + +void TextEdit::setFontSize(int sz, bool round_down_not_up) +{ + int s=10; + for (int i=0; i sz ) { + s = fontsize[i]; + break; + } + } + } + + QFont f = editor->font(); + f.setPointSize(s); + editor->setFont(f); + + zin->setEnabled(s != fontsize[nfontsizes-1]); + zout->setEnabled(s != fontsize[0]); +} + +void TextEdit::setBold(bool y) +{ + QFont f = editor->font(); + f.setBold(y); + editor->setFont(f); +} + +void TextEdit::setItalic(bool y) +{ + QFont f = editor->font(); + f.setItalic(y); + editor->setFont(f); +} + +void TextEdit::setWordWrap(bool y) +{ + editor->setWordWrap(y ? QMultiLineEdit::WidgetWidth : QMultiLineEdit::NoWrap ); +} + +void TextEdit::fileNew() +{ + save(); + newFile(DocLnk()); +} + +void TextEdit::fileOpen() +{ + if ( !save() ) { + if ( QMessageBox::critical( this, tr( "Out of space" ), + tr( "Text Editor was unable to\n" + "save your changes.\n" + "Free some space and try again.\n" + "\nContinue anyway?" ), + QMessageBox::Yes|QMessageBox::Escape, + QMessageBox::No|QMessageBox::Default ) + != QMessageBox::Yes ) + return; + else { + delete doc; + doc = 0; + } + } + menu->hide(); + editBar->hide(); + searchBar->hide(); + clearWState (WState_Reserved1 ); + editorStack->raiseWidget( fileSelector ); + fileSelector->reread(); + updateCaption(); +} + + +#if 0 +void TextEdit::slotFind() +{ + FindDialog frmFind( "Text Editor", this ); + connect( &frmFind, SIGNAL(signalFindClicked(const QString &, bool, bool, int)), + editor, SLOT(slotDoFind( const QString&,bool,bool))); + + //case sensitive, backwards, [category] + + + connect( editor, SIGNAL(notFound()), + &frmFind, SLOT(slotNotFound()) ); + connect( editor, SIGNAL(searchWrapped()), + &frmFind, SLOT(slotWrapAround()) ); + + frmFind.exec(); + + +} +#endif + +void TextEdit::fileRevert() +{ + clear(); + fileOpen(); +} + +void TextEdit::editCut() +{ +#ifndef QT_NO_CLIPBOARD + editor->cut(); +#endif +} + +void TextEdit::editCopy() +{ +#ifndef QT_NO_CLIPBOARD + editor->copy(); +#endif +} + +void TextEdit::editPaste() +{ +#ifndef QT_NO_CLIPBOARD + editor->paste(); +#endif +} + +void TextEdit::editFind() +{ + searchBar->show(); + searchVisible = TRUE; + searchEdit->setFocus(); +} + +void TextEdit::findNext() +{ + editor->find( searchEdit->text(), FALSE, FALSE ); + +} + +void TextEdit::findClose() +{ + searchVisible = FALSE; + searchBar->hide(); +} + +void TextEdit::search() +{ + editor->find( searchEdit->text(), FALSE, FALSE ); +} + +void TextEdit::newFile( const DocLnk &f ) +{ + DocLnk nf = f; + nf.setType("text/plain"); + clear(); + editorStack->raiseWidget( editor ); + setWState (WState_Reserved1 ); + editor->setFocus(); + doc = new DocLnk(nf); + updateCaption(); +} + +void TextEdit::openFile( const QString &f ) +{ + bFromDocView = TRUE; + DocLnk nf; + nf.setType("text/plain"); + nf.setFile(f); + openFile(nf); + showEditTools(); + // Show filename in caption + QString name = f; + int sep = name.findRev( '/' ); + if ( sep > 0 ) + name = name.mid( sep+1 ); + updateCaption( name ); +} + +void TextEdit::openFile( const DocLnk &f ) +{ + clear(); + FileManager fm; + QString txt; + if ( !fm.loadFile( f, txt ) ) { + // ####### could be a new file + //qDebug( "Cannot open file" ); + //return; + } + fileNew(); + if ( doc ) + delete doc; + doc = new DocLnk(f); + editor->setText(txt); + editor->setEdited(FALSE); + updateCaption(); +} + +void TextEdit::showEditTools() +{ + if ( !doc ) + close(); + fileSelector->hide(); + menu->show(); + editBar->show(); + if ( searchVisible ) + searchBar->show(); + updateCaption(); +} + +bool TextEdit::save() +{ + // case of nothing to save... + if ( !doc ) + return true; + if ( !editor->edited() ) { + delete doc; + doc = 0; + return true; + } + + QString rt = editor->text(); + + if ( doc->name().isEmpty() ) { + QString pt = rt.simplifyWhiteSpace(); + int i = pt.find( ' ' ); + QString docname = pt; + if ( i > 0 ) + docname = pt.left( i ); + // remove "." at the beginning + while( docname.startsWith( "." ) ) + docname = docname.mid( 1 ); + docname.replace( QRegExp("/"), "_" ); + // cut the length. filenames longer than that don't make sense and something goes wrong when they get too long. + if ( docname.length() > 40 ) + docname = docname.left(40); + if ( docname.isEmpty() ) + docname = "Empty Text"; + doc->setName(docname); + + // append .txt to the file name + if ( doc->file().find(".txt") == -1 ) { + QString file = doc->file() + ".txt"; + doc->setFile( file ); + } + } + + + FileManager fm; + if ( !fm.saveFile( *doc, rt ) ) { + return false; + } + delete doc; + doc = 0; + editor->setEdited( false ); + return true; +} + +void TextEdit::clear() +{ + delete doc; + doc = 0; + editor->clear(); +} + +void TextEdit::updateCaption( const QString &name ) +{ + if ( !doc ) + setCaption( tr("Text Editor") ); + else { + QString s = name; + if ( s.isNull() ) + s = doc->name(); + if ( s.isEmpty() ) + s = tr( "Unnamed" ); + setCaption( s + " - " + tr("Text Editor") ); + } +} + +void TextEdit::setDocument(const QString& fileref) +{ + bFromDocView = TRUE; + openFile(DocLnk(fileref)); + showEditTools(); +} + +void TextEdit::closeEvent( QCloseEvent *e ) +{ + if ( editorStack->visibleWidget() == editor && !bFromDocView ) { + e->ignore(); + fileRevert(); + } else { + bFromDocView = FALSE; + e->accept(); + } +} + +void TextEdit::accept() +{ + fileOpen(); +} diff --git a/core/apps/textedit/textedit.h b/core/apps/textedit/textedit.h new file mode 100644 index 0000000..f7d1052 --- a/dev/null +++ b/core/apps/textedit/textedit.h @@ -0,0 +1,102 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef TEXTEDIT_H +#define TEXTEDIT_H + +#define QTEXTEDIT_OPEN_API + +#include + +#include +#include +#include +#include + +class QWidgetStack; +class QToolButton; +class QPopupMenu; +class QToolBar; +class QLineEdit; +class QAction; +class FileSelector; +class QpeEditor; + +class TextEdit : public QMainWindow +{ + Q_OBJECT + +public: + TextEdit( QWidget *parent = 0, const char *name = 0, WFlags f = 0 ); + ~TextEdit(); + + void openFile( const QString & ); + +protected: + void closeEvent( QCloseEvent *e ); + +private slots: + void setDocument(const QString&); + + void fileNew(); + void fileRevert(); + void fileOpen(); + + void editCut(); + void editCopy(); + void editPaste(); + void editFind(); + + void findNext(); + void findClose(); + + void search(); + void accept(); + + void newFile( const DocLnk & ); + void openFile( const DocLnk & ); + void showEditTools(); + + void zoomIn(); + void zoomOut(); + void setBold(bool y); + void setItalic(bool y); + void setWordWrap(bool y); + +private: + void colorChanged( const QColor &c ); + bool save(); + void clear(); + void updateCaption( const QString &name=QString::null ); + void setFontSize(int sz, bool round_down_not_up); + +private: + QWidgetStack *editorStack; + FileSelector *fileSelector; + QpeEditor* editor; + QToolBar *menu, *editBar, *searchBar; + QLineEdit *searchEdit; + DocLnk *doc; + bool searchVisible; + bool bFromDocView; + QAction *zin, *zout; +}; + +#endif diff --git a/core/apps/textedit/textedit.po b/core/apps/textedit/textedit.po new file mode 100644 index 0000000..683a5e3 --- a/dev/null +++ b/core/apps/textedit/textedit.po @@ -0,0 +1,108 @@ +# This is a Qt message file in .po format. Each msgid starts with +# a scope. This scope should *NOT* be translated - eg. translating +# from French to English, "Foo::Bar" would be translated to "Pub", +# not "Foo::Pub". +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2001-03-16 14:29:14 EST\n" +"PO-Revision-Date: YYYY-MM-DD\n" +"Last-Translator: FULLNAME \n" +"Content-Type: text/plain; charset=iso-8859-1\n" + +#: textedit.cpp:110 +msgid "TextEdit::&Edit" +msgstr "" + +#: textedit.cpp:109 +msgid "TextEdit::&File" +msgstr "" + +#: textedit.cpp:102 +msgid "TextEdit::&Insert" +msgstr "" + +#: textedit.cpp:115 +msgid "TextEdit::Bold" +msgstr "" + +#: textedit.cpp:191 +msgid "TextEdit::Bullet List" +msgstr "" + +#: textedit.cpp:140 +msgid "TextEdit::Center" +msgstr "" + +#: textedit.cpp:170 +msgid "TextEdit::Close Find" +msgstr "" + +#: textedit.cpp:69 +msgid "TextEdit::Close" +msgstr "" + +#: textedit.cpp:79 +msgid "TextEdit::Copy" +msgstr "" + +#: textedit.cpp:74 +msgid "TextEdit::Cut" +msgstr "" + +#: textedit.cpp:194 +msgid "TextEdit::Enumerated List" +msgstr "" + +#: textedit.cpp:94 +msgid "TextEdit::Find Next" +msgstr "" + +#: textedit.cpp:89 +msgid "TextEdit::Find..." +msgstr "" + +#: textedit.cpp:120 +msgid "TextEdit::Italic" +msgstr "" + +#: textedit.cpp:134 +msgid "TextEdit::Left" +msgstr "" + +#: textedit.cpp:61 +msgid "TextEdit::New" +msgstr "" + +#: textedit.cpp:65 +msgid "TextEdit::Open" +msgstr "" + +#: textedit.cpp:84 +msgid "TextEdit::Paste" +msgstr "" + +#: textedit.cpp:145 +msgid "TextEdit::Right" +msgstr "" + +#: textedit.cpp:188 +msgid "TextEdit::Standard" +msgstr "" + +#: textedit.cpp:104 +msgid "TextEdit::Table..." +msgstr "" + +#: textedit.cpp:570 +msgid "TextEdit::Text Editor" +msgstr "" + +#: textedit.cpp:125 +msgid "TextEdit::Underline" +msgstr "" + +#: textedit.cpp:569 +msgid "TextEdit::Unnamed" +msgstr "" + diff --git a/core/apps/textedit/textedit.pro b/core/apps/textedit/textedit.pro new file mode 100644 index 0000000..3f5473e --- a/dev/null +++ b/core/apps/textedit/textedit.pro @@ -0,0 +1,16 @@ +TEMPLATE = app +CONFIG += qt warn_on release + +DESTDIR = $(QPEDIR)/bin + +HEADERS = textedit.h + +SOURCES = main.cpp textedit.cpp + +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TARGET = textedit + +TRANSLATIONS = ../i18n/de/textedit.ts -- cgit v0.9.0.2