author | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
---|---|---|
committer | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
commit | 15318cad33835e4e2dc620d033e43cd930676cdd (patch) (side-by-side diff) | |
tree | c2fa0399a2c47fda8e2cd0092c73a809d17f68eb /core/apps/embeddedkonsole | |
download | opie-15318cad33835e4e2dc620d033e43cd930676cdd.zip opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2 |
Initial revision
26 files changed, 7458 insertions, 0 deletions
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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* 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 <qapplication.h> +#include <qsocketnotifier.h> +#include <qstring.h> + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <termios.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/wait.h> + +#ifdef HAVE_OPENPTY +#include <pty.h> +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \file +*/ + +#ifndef MY_PTY_H +#define MY_PTY_H + +#include <qobject.h> +#include <qstrlist.h> + + +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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \file TECommon.h + \brief Definitions shared between TEScreen and TEWidget. +*/ + +#ifndef TECOMMON_H +#define TECOMMON_H + +#include <qcolor.h> + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#include "TEHistory.h" +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +// #include <kdebug.h> + +#include <assert.h> +#include <string.h> +#include <ctype.h> + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* ------------------------------------------------------------------------ */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \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. + + <ul> + <li> The internal image has the size of the widget (evtl. rounded up) + <li> The external image used in setImage can have any size. + <li> (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. + </ul> + + \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 <qcursor.h> +#include <qregexp.h> +#include <qpainter.h> +#include <qclipboard.h> +#include <qstyle.h> +#include <qfile.h> +#include <qdragobject.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <signal.h> + +#include <assert.h> + +// #include "TEWidget.moc" +//#include <kapp.h> +//#include <kcursor.h> +//#include <kurl.h> +//#include <kdebug.h> +//#include <klocale.h> + +#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<QKeyEvent *>( 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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* ----------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef TE_WIDGET_H +#define TE_WIDGET_H + +#include <qwidget.h> +#include <qlabel.h> +#include <qtimer.h> +#include <qcolor.h> +#include <qkeycode.h> +#include <qscrollbar.h> + +#include <qpopupmenu.h> + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* ------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \class TEmuVt102 + + \brief Actual Emulation for Konsole + + \sa TEWidget \sa TEScreen +*/ + +#include "TEmuVt102.h" +#include "TEWidget.h" +#include "TEScreen.h" +#include "keytrans.h" + +#include <stdio.h> +#include <unistd.h> +#include <qkeycode.h> +#include <qtextcodec.h> + + +/* 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><CHR but `[]()+*#'> + - ESC_DE - Escape codes of the form <ESC><any of `()+*#%'> C + - CSI_PN - Escape codes of the form <ESC>'[' {Pn} ';' {Pn} C + - CSI_PS - Escape codes of the form <ESC>'[' {Pn} ';' ... C + - CSI_PR - Escape codes of the form <ESC>'[' '?' {Pn} ';' ... C + - VT52 - VT52 escape codes + - <ESC><Chr> + - <ESC>'Y'{Pc}{Pc} + - XTE_HA - Xterm hacks <ESC>`]' {Pn} `;' {Text} <BEL> + 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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef VT102EMU_H +#define VT102EMU_H + +#include "TEWidget.h" +#include "TEScreen.h" +#include "TEmulation.h" +#include <qtimer.h> +#include <stdio.h> + +// + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <qkeycode.h> + + +/* ------------------------------------------------------------------------- */ +/* */ +/* 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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef EMULATION_H +#define EMULATION_H + +#include "TEWidget.h" +#include "TEScreen.h" +#include <qtimer.h> +#include <stdio.h> +#include <qtextcodec.h> +#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 <qnamespace.h>\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 Binary files differnew file mode 100644 index 0000000..7dbf6b4 --- a/dev/null +++ b/core/apps/embeddedkonsole/faded_bg.png 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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* + 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 <qpe/qpeapplication.h> + +#include <qnamespace.h> +#include <qbuffer.h> +#include <qobject.h> +#include <qdict.h> +#include <qintdict.h> +#include <qfile.h> +#include <qglobal.h> +#include <qdir.h> + +//#include <kstddirs.h> +//nclude <klocale.h> + +#include <stdio.h> + + +#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<KeyEntry> 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<KeyEntry> 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<QObject> keysyms; + QDict<QObject> modsyms; + QDict<QObject> 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<KeyTrans> * numb2keymap = 0L; +static QDict<KeyTrans> * 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<KeyTrans>; + if (!path2keymap) + path2keymap = new QDict<KeyTrans>; + 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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef KEYTRANS_H +#define KEYTRANS_H + +#include <qstring.h> +#include <qlist.h> +#include <qiodevice.h> + +#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<KeyEntry> 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 <lars.doelle@on-line.de> */ +/* */ +/* 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 <ettrich@kde.org> */ +/* */ +/* ---------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#include <qpe/resource.h> + +#include <qdir.h> +#include <qevent.h> +#include <qdragobject.h> +#include <qobjectlist.h> +#include <qtoolbutton.h> +#include <qpe/qpetoolbar.h> +#include <qpushbutton.h> +#include <qfontdialog.h> +#include <qglobal.h> +#include <qpainter.h> +#include <qpe/qpemenubar.h> +#include <qmessagebox.h> +#include <qaction.h> +#include <qapplication.h> +#include <qfontmetrics.h> +#include <qcombobox.h> +#include <qevent.h> +#include <qtabwidget.h> +#include <qtabbar.h> +#include <qpe/config.h> + +#include <sys/wait.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#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<count(); i++) { + QTab* left=0; + QListIterator<QTab> it(*tabList()); + int x=INT_MAX; + for( QTab* t; (t=it.current()); ++it ) { + int tx = t->rect().x(); + if ( tx<x && tx>m ) { + 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 <lars.doelle@on-line.de> */ +/* */ +/* 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 <ettrich@kde.org> */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef KONSOLE_H +#define KONSOLE_H + + +#include <qmainwindow.h> +#include <qaction.h> +#include <qpopupmenu.h> +#include <qstrlist.h> +#include <qintdict.h> +#include <qptrdict.h> +#include <qtabwidget.h> + +#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<VTFont> 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 <lars.doelle@on-line.de> */ +/* */ +/* 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 <ettrich@kde.org> */ +/* */ +/* ---------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#include "konsole.h" + +#include <qpe/qpeapplication.h> + +#include <qfile.h> + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + + +/* --| 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 <warwick@trolltech.com> +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 <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ +#include "session.h" +#include <qpushbutton.h> +// #include <kdebug.h> + +#include <stdlib.h> + +#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 <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole, an X terminal. */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef SESSION_H +#define SESSION_H + +#include <qapplication.h> +#include <qmainwindow.h> +#include <qstrlist.h> + +#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 |